class Sexp::Matcher::Parser
Converts from a lispy string to Sexp matchers in a safe manner.
"(a 42 _ (c) [t x] ___)" => s{ s(:a, 42, _, s(:c), t(:x), ___) }
  Constants
- ALLOWED
- 
          A collection of allowed commands to convert into matchers. 
Attributes
The stream of tokens to parse. See lex.
Public Class Methods
Public Instance Methods
Source
# File lib/sexp_matcher.rb, line 416 def lex s s.scan %r%[()\[\]]|\"[^"]*\"|/[^/]*/|:?[\w?!=~-]+% end
Converts s into a stream of tokens and adds them to tokens.
Source
# File lib/sexp_matcher.rb, line 423 def next_token raise SyntaxError, "unbalanced input" if tokens.empty? tokens.shift end
Returns the next token and removes it from the stream or raises if empty.
Source
# File lib/sexp_matcher.rb, line 438 def parse result = parse_sexp until tokens.empty? result end
Parses tokens and returns a Matcher instance.
Source
# File lib/sexp_matcher.rb, line 515 def parse_cmd args = [] args << parse_sexp while peek_token && peek_token != "]" next_token # pop off "]" cmd = args.shift args = Sexp.q(*args) raise SyntaxError, "bad cmd: %p" % [cmd] unless ALLOWED.include? cmd result = Sexp.send cmd, *args result end
Parses a balanced command. A command is denoted by square brackets and must conform to a whitelisted set of allowed commands (see ALLOWED).
Source
# File lib/sexp_matcher.rb, line 496 def parse_list result = [] result << parse_sexp while peek_token && peek_token != ")" next_token # pop off ")" Sexp.q(*result) end
Parses a balanced list of expressions and returns the equivalent matcher.
Source
# File lib/sexp_matcher.rb, line 460 def parse_sexp token = next_token case token when "(" then parse_list when "[" then parse_cmd when "nil" then nil when /^\d+$/ then token.to_i when "___" then Sexp.___ when "_" then Sexp._ when %r%^/(.*)/$% then re = $1 raise SyntaxError, "Not allowed: /%p/" % [re] unless re =~ /\A([\w()|.*+^$]+)\z/ Regexp.new re when /^"(.*)"$/ then $1 when /^([A-Z]\w*)$/ then Object.const_get $1 when /^:?([\w?!=~-]+)$/ then $1.to_sym else raise SyntaxError, "unhandled token: %p" % [token] end end
Parses a string into a sexp matcher:
SEXP : "(" SEXP:args* ")"          => Sexp.q(*args)
     | "[" CMD:cmd sexp:args* "]"  => Sexp.cmd(*args)
     | "nil"                       => nil
     | /\d+/:n                     => n.to_i
     | "___"                       => Sexp.___
     | "_"                         => Sexp._
     | /^\/(.*)\/$/:re             => Regexp.new re[0]
     | /^"(.*)"$/:s                => String.new s[0]
     | UP_NAME:name                => Object.const_get name
     | NAME:name                   => name.to_sym
UP_NAME: /[A-Z]w*/
NAME : /:?[\w?!=~-]+/ CMD : t | k | m | atom | not? | - | any | child | include
Source
# File lib/sexp_matcher.rb, line 431 def peek_token tokens.first end
Returns the next token without removing it from the stream.