Skip to content

Instantly share code, notes, and snippets.

@jimweirich
Last active December 16, 2015 22:49
Show Gist options
  • Save jimweirich/5510037 to your computer and use it in GitHub Desktop.
Save jimweirich/5510037 to your computer and use it in GitHub Desktop.
Simple example of Parslet.
require 'parslet'
class Expressions < Parslet::Parser
rule(:operator) { match("[+*/-]").as(:op) }
rule(:operation) { operator >> space >> vector.as(:args) }
rule(:space) { match('\s').repeat(1) }
rule(:numbers) { space >> number }
rule(:vector) { (number >> numbers.repeat(1)).as(:vec) }
rule(:number) { match("[0-9]").repeat(1).as(:number) }
rule(:expr) { vector | number | operation }
root :expr
end
def parse(str)
c = Expressions.new
c.parse(str)
rescue Parslet::ParseFailed => failure
puts failure.cause.ascii_tree
end
parse("12") # => {:number=>"12"@0}
parse("12 34 56") # => {:vec=>[{:number=>"12"@0}, {:number=>"34"@3}, {:number=>"56"@6}]}
parse("+ 1 2 3") # => {:op=>"+"@0, :args=>{:vec=>[{:number=>"1"@2}, {:number=>"2"@4}, {:number=>"3"@6}]}}
parse("* 1 2 3") # => {:op=>"*"@0, :args=>{:vec=>[{:number=>"1"@2}, {:number=>"2"@4}, {:number=>"3"@6}]}}
def expr_eval(tree)
if tree[:number]
tree[:number].to_i
elsif tree[:vec]
tree[:vec].map { |item| expr_eval(item) }
elsif tree[:op]
apply_op(tree[:op], expr_eval(tree[:args]))
end
end
def apply_op(op, vec)
vec.inject { |s, n| s.send(op, n) }
end
expr_eval(parse("12")) # => 12
expr_eval(parse("12 34 56")) # => [12, 34, 56]
expr_eval(parse("+ 12 34 56")) # => 102
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment