class Fast::ExpressionParser

ExpressionParser empowers the AST search in Ruby. All classes inheriting Fast::Find have a grammar shortcut that is processed here.

@example find a simple int node

Fast.expression("int")
# => #<Fast::Find:0x00007ffae39274e0 @token="int">

@example parens make the expression an array of Fast::Find and children classes

Fast.expression("(int _)")
# => [#<Fast::Find:0x00007ffae3a860e8 @token="int">, #<Fast::Find:0x00007ffae3a86098 @token="_">]

@example not int token

Fast.expression("!int")
# => #<Fast::Not:0x00007ffae43f35b8 @token=#<Fast::Find:0x00007ffae43f35e0 @token="int">>

@example int or float token

Fast.expression("{int float}")
# => #<Fast::Any:0x00007ffae43bbf00 @token=[
#      #<Fast::Find:0x00007ffae43bbfa0 @token="int">,
#      #<Fast::Find:0x00007ffae43bbf50 @token="float">
#     #]>

@example capture something not nil

Fast.expression("$_")
# => #<Fast::Capture:0x00007ffae433a860 @captures=[], @token=#<Fast::Find:0x00007ffae433a888 @token="_">>

@example capture a hash with keys that all are not string and not symbols

Fast.expression("(hash (pair ([!sym !str] _))")
# => [#<Fast::Find:0x00007ffae3b45010 @token="hash">,
#      [#<Fast::Find:0x00007ffae3b44f70 @token="pair">,
#       [#<Fast::All:0x00007ffae3b44cf0 @token=[
#         #<Fast::Not:0x00007ffae3b44e30 @token=#<Fast::Find:0x00007ffae3b44e80 @token="sym">>,
#         #<Fast::Not:0x00007ffae3b44d40 @token=#<Fast::Find:0x00007ffae3b44d68 @token="str">>]>,
#         #<Fast::Find:0x00007ffae3b44ca0 @token="_">]]]")")

@example of match using string expression

Fast.match?(Fast.ast("{1 => 1}"),"(hash (pair ([!sym !str] _))") => true")")

Public Class Methods

new(expression) click to toggle source

@param expression [String]

# File lib/fast.rb, line 363
def initialize(expression)
  @tokens = expression.scan TOKENIZER
end

Public Instance Methods

parse() click to toggle source

rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/AbcSize rubocop:disable Metrics/MethodLength

# File lib/fast.rb, line 370
def parse
  case (token = next_token)
  when '(' then parse_until_peek(')')
  when '{' then Any.new(parse_until_peek('}'))
  when '[' then All.new(parse_until_peek(']'))
  when /^"/ then FindString.new(token[1..-2])
  when /^#\w/ then MethodCall.new(token[1..])
  when /^\.\w[\w\d_]+\?/ then InstanceMethodCall.new(token[1..])
  when '$' then Capture.new(parse)
  when '!' then (@tokens.any? ? Not.new(parse) : Find.new(token))
  when '?' then Maybe.new(parse)
  when '^' then Parent.new(parse)
  when '\\' then FindWithCapture.new(parse)
  when /^%\d/ then FindFromArgument.new(token[1..])
  else Find.new(token)
  end
end

Private Instance Methods

next_token() click to toggle source

rubocop:enable Metrics/CyclomaticComplexity rubocop:enable Metrics/AbcSize rubocop:enable Metrics/MethodLength

# File lib/fast.rb, line 394
def next_token
  @tokens.shift
end
parse_until_peek(token) click to toggle source
# File lib/fast.rb, line 398
def parse_until_peek(token)
  list = []
  list << parse until @tokens.empty? || @tokens.first == token
  next_token
  list
end