# vim: syntax=ruby

class PuppetDB::Parser

token LPAREN RPAREN LBRACK RBRACK LBRACE RBRACE
token EQUALS NOTEQUALS MATCH NOTMATCH
token LESSTHAN LESSTHANEQ GREATERTHAN GREATERTHANEQ
token AT HASH ASTERISK DOT
token NOT AND OR
token NUMBER STRING BOOLEAN EXPORTED

prechigh
  right NOT
  left  EQUALS MATCH LESSTHAN GREATERTHAN
  left  AND
  left  OR
preclow

options no_result_var

rule

query
  : expression
  |

expression
  : identifier_path             { ASTNode.new :regexp_node_match, val[0] }
  |            NOT expression   { ASTNode.new :booleanop, :not, [val[1]] }
  | expression AND expression   { ASTNode.new :booleanop, :and, [val[0], val[2]] }
  | expression OR  expression   { ASTNode.new :booleanop, :or, [val[0], val[2]] }
  | LPAREN expression RPAREN    { val[1] }
  | resource_expression
  | comparison_expression
  | subquery

literal
  : boolean                     { ASTNode.new :boolean, val[0] }
  | string                      { ASTNode.new :string, val[0] }
  | integer                     { ASTNode.new :number, val[0] }
  | float                       { ASTNode.new :number, val[0] }
  | AT string                   { ASTNode.new :date, val[1] }

comparison_op
  : MATCH
  | NOTMATCH
  | EQUALS
  | NOTEQUALS
  | GREATERTHAN
  | GREATERTHANEQ
  | LESSTHAN
  | LESSTHANEQ

comparison_expression
  : identifier_path comparison_op literal { ASTNode.new :comparison, val[1], [val[0], val[2]] }

identifier
  : string                      { ASTNode.new :identifier, val[0] }
  | integer                     { ASTNode.new :identifier, val[0] }
  | MATCH string                { ASTNode.new :regexp_identifier, val[1] }
  | ASTERISK                    { ASTNode.new :regexp_identifier, '.*' }

identifier_path
  : identifier                     { ASTNode.new :identifier_path, nil, [val[0]] }
  | identifier_path DOT identifier { val[0].children.push val[2]; val[0] }

subquery
  : HASH string DOT comparison_expression { ASTNode.new :subquery, val[1], [val[3]] }
  | HASH string block_expression          { ASTNode.new :subquery, val[1], [val[2]] }

block_expression
  : LBRACE expression RBRACE    { val[1] }

resource_expression
  : string LBRACK identifier RBRACK
    { ASTNode.new :resource, {:type => val[0], :title => val[2], :exported => false} }
  | string LBRACK identifier RBRACK block_expression
    { ASTNode.new :resource, {:type => val[0], :title => val[2], :exported => false}, [val[4]] }
  | EXPORTED string LBRACK identifier RBRACK
    { ASTNode.new :resource, {:type => val[1], :title => val[3], :exported => true} }
  | EXPORTED string LBRACK identifier RBRACK block_expression
    { ASTNode.new :resource, {:type => val[1], :title => val[3], :exported => true}, [val[5]] }

boolean: BOOLEAN
integer: NUMBER
string: STRING
float: NUMBER DOT NUMBER        { "#{val[0]}.#{val[2]}".to_f }

end —- inner

include PuppetDB::ParserHelper

—- header require 'puppetdb' require 'puppetdb/lexer' require 'puppetdb/astnode' require 'puppetdb/parser_helper'