From 2c4aa50463ed411b14003f9d929c1e03518953bf Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 21 Feb 2018 13:38:37 +0100 Subject: Implement pipeline expressions parser --- lib/gitlab/ci/pipeline/expression/lexeme.rb | 4 ++++ lib/gitlab/ci/pipeline/expression/lexer.rb | 3 ++- lib/gitlab/ci/pipeline/expression/statement.rb | 33 ++++++++++++++++++++++++-- lib/gitlab/ci/pipeline/expression/string.rb | 1 + lib/gitlab/ci/pipeline/expression/token.rb | 5 ++++ lib/gitlab/ci/pipeline/expression/variable.rb | 8 +++++-- 6 files changed, 49 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/ci/pipeline/expression/lexeme.rb b/lib/gitlab/ci/pipeline/expression/lexeme.rb index bbf3fec7407..91ba333d8dd 100644 --- a/lib/gitlab/ci/pipeline/expression/lexeme.rb +++ b/lib/gitlab/ci/pipeline/expression/lexeme.rb @@ -7,6 +7,10 @@ module Gitlab raise NotImplementedError end + def self.build(token) + raise NotImplementedError + end + def self.scan(scanner) if scanner.scan(self::PATTERN) Expression::Token.new(scanner.matched, self) diff --git a/lib/gitlab/ci/pipeline/expression/lexer.rb b/lib/gitlab/ci/pipeline/expression/lexer.rb index 8432b36b066..ee202ebce69 100644 --- a/lib/gitlab/ci/pipeline/expression/lexer.rb +++ b/lib/gitlab/ci/pipeline/expression/lexer.rb @@ -5,7 +5,8 @@ module Gitlab class Lexer LEXEMES = [ Expression::Variable, - Expression::String + Expression::String, + Expression::Equals ] MAX_CYCLES = 5 diff --git a/lib/gitlab/ci/pipeline/expression/statement.rb b/lib/gitlab/ci/pipeline/expression/statement.rb index 91d91195f5a..417b3f806b1 100644 --- a/lib/gitlab/ci/pipeline/expression/statement.rb +++ b/lib/gitlab/ci/pipeline/expression/statement.rb @@ -3,6 +3,8 @@ module Gitlab module Pipeline module Expression class Statement + ParserError = Class.new(StandardError) + GRAMMAR = [ %w[variable equals string], %w[variable equals variable], @@ -12,14 +14,41 @@ module Gitlab %w[variable] ] - def initialize(pipeline, statement) + def initialize(statement, pipeline) @pipeline = pipeline - @statement = statement + @lexer = Expression::Lexer.new(statement) end def variables end + def tokens + @lexer.tokenize + end + + def lexemes + @lexemes ||= tokens.map(&:to_lexeme) + end + + ## + # Our syntax is very simple, so we don't need yet to implement a + # recurisive parser, we can use the most simple approach to create + # a reverse descent parse tree "by hand". + # + def parse_tree + raise ParserError if lexemes.empty? + + unless GRAMMAR.find { |syntax| syntax == lexemes } + raise ParserError, 'Unknown pipeline expression!' + end + + if lexemes.many? + Expression::Equals.new(tokens.first.build, tokens.last.build) + else + tokens.first.build + end + end + def evaluate end end diff --git a/lib/gitlab/ci/pipeline/expression/string.rb b/lib/gitlab/ci/pipeline/expression/string.rb index e6cc50c56d8..6a59b81467c 100644 --- a/lib/gitlab/ci/pipeline/expression/string.rb +++ b/lib/gitlab/ci/pipeline/expression/string.rb @@ -14,6 +14,7 @@ module Gitlab end def self.build(string) + new(string.match(PATTERN)[:string]) end end end diff --git a/lib/gitlab/ci/pipeline/expression/token.rb b/lib/gitlab/ci/pipeline/expression/token.rb index 03a47a17d40..3b957c83016 100644 --- a/lib/gitlab/ci/pipeline/expression/token.rb +++ b/lib/gitlab/ci/pipeline/expression/token.rb @@ -10,7 +10,12 @@ module Gitlab @type = type end + def build + @type.build(@value) + end + def to_lexeme + type.name.demodulize.downcase end end end diff --git a/lib/gitlab/ci/pipeline/expression/variable.rb b/lib/gitlab/ci/pipeline/expression/variable.rb index ec6c03d336a..d6a7a655220 100644 --- a/lib/gitlab/ci/pipeline/expression/variable.rb +++ b/lib/gitlab/ci/pipeline/expression/variable.rb @@ -5,12 +5,16 @@ module Gitlab class Variable < Expression::Lexeme PATTERN = /\$(?\w+)/.freeze - def initialize(value) - @value = value + def initialize(name) + @name = name end def evaluate(**variables) end + + def self.build(string) + new(string.match(PATTERN)[:name]) + end end end end -- cgit v1.2.1