lib/cucumber/cucumber_expressions/ast.rb
# frozen_string_literal: true module Cucumber module CucumberExpressions ESCAPE_CHARACTER = '\\' ALTERNATION_CHARACTER = '/' BEGIN_PARAMETER_CHARACTER = '{' END_PARAMETER_CHARACTER = '}' BEGIN_OPTIONAL_CHARACTER = '(' END_OPTIONAL_CHARACTER = ')' class Node attr_reader :type, :nodes, :token, :start, :end def initialize(type, nodes, token, start, ending) raise 'Either nodes or token must be defined' if nodes.nil? && token.nil? @type = type @nodes = nodes @token = token @start = start @end = ending end def text return @nodes.map { |value| value.text }.join('') if @token.nil? @token end def to_hash hash = Hash.new hash['type'] = @type hash['nodes'] = @nodes.map { |node| node.to_hash } unless @nodes.nil? hash['token'] = @token unless @token.nil? hash['start'] = @start hash['end'] = @end hash end end module NodeType TEXT = 'TEXT_NODE' OPTIONAL = 'OPTIONAL_NODE' ALTERNATION = 'ALTERNATION_NODE' ALTERNATIVE = 'ALTERNATIVE_NODE' PARAMETER = 'PARAMETER_NODE' EXPRESSION = 'EXPRESSION_NODE' end class Token attr_reader :type, :text, :start, :end def initialize(type, text, start, ending) @type, @text, @start, @end = type, text, start, ending end def self.is_escape_character(codepoint) codepoint.chr(Encoding::UTF_8) == ESCAPE_CHARACTER end def self.can_escape(codepoint) c = codepoint.chr(Encoding::UTF_8) if c == ' ' # TODO: Unicode whitespace? return true end case c when ESCAPE_CHARACTER true when ALTERNATION_CHARACTER true when BEGIN_PARAMETER_CHARACTER true when END_PARAMETER_CHARACTER true when BEGIN_OPTIONAL_CHARACTER true when END_OPTIONAL_CHARACTER true else false end end def self.type_of(codepoint) c = codepoint.chr(Encoding::UTF_8) if c == ' ' # TODO: Unicode whitespace? return TokenType::WHITE_SPACE end case c when ALTERNATION_CHARACTER TokenType::ALTERNATION when BEGIN_PARAMETER_CHARACTER TokenType::BEGIN_PARAMETER when END_PARAMETER_CHARACTER TokenType::END_PARAMETER when BEGIN_OPTIONAL_CHARACTER TokenType::BEGIN_OPTIONAL when END_OPTIONAL_CHARACTER TokenType::END_OPTIONAL else TokenType::TEXT end end def self.symbol_of(token) case token when TokenType::BEGIN_OPTIONAL return BEGIN_OPTIONAL_CHARACTER when TokenType::END_OPTIONAL return END_OPTIONAL_CHARACTER when TokenType::BEGIN_PARAMETER return BEGIN_PARAMETER_CHARACTER when TokenType::END_PARAMETER return END_PARAMETER_CHARACTER when TokenType::ALTERNATION return ALTERNATION_CHARACTER else return '' end end def self.purpose_of(token) case token when TokenType::BEGIN_OPTIONAL return 'optional text' when TokenType::END_OPTIONAL return 'optional text' when TokenType::BEGIN_PARAMETER return 'a parameter' when TokenType::END_PARAMETER return 'a parameter' when TokenType::ALTERNATION return 'alternation' else return '' end end def to_hash { 'type' => @type, 'text' => @text, 'start' => @start, 'end' => @end } end end module TokenType START_OF_LINE = 'START_OF_LINE' END_OF_LINE = 'END_OF_LINE' WHITE_SPACE = 'WHITE_SPACE' BEGIN_OPTIONAL = 'BEGIN_OPTIONAL' END_OPTIONAL = 'END_OPTIONAL' BEGIN_PARAMETER = 'BEGIN_PARAMETER' END_PARAMETER = 'END_PARAMETER' ALTERNATION = 'ALTERNATION' TEXT = 'TEXT' end end end