132 lines
2.4 KiB
Plaintext
132 lines
2.4 KiB
Plaintext
##
|
|
# AST parser for CSS expressions.
|
|
#
|
|
class Oga::CSS::Parser
|
|
|
|
options no_result_var
|
|
|
|
rule
|
|
css
|
|
: expression { val[0] }
|
|
| /* none */ { nil }
|
|
;
|
|
|
|
expression
|
|
: path
|
|
| node_test
|
|
| node_operators
|
|
;
|
|
|
|
path_member
|
|
: node_test
|
|
;
|
|
|
|
path_members
|
|
: path_member path_member { [val[0], val[1]] }
|
|
| path_member path_members { [val[0], *val[1]] }
|
|
;
|
|
|
|
path
|
|
: path_members { s(:path, *val[0]) }
|
|
;
|
|
|
|
node_test
|
|
: node_name { s(:test, *val[0]) }
|
|
| node_name predicate { s(:test, *val[0], val[1]) }
|
|
;
|
|
|
|
node_name
|
|
# foo
|
|
: T_IDENT { [nil, val[0]] }
|
|
|
|
# ns|foo
|
|
| T_IDENT T_PIPE T_IDENT { [val[0], val[2]] }
|
|
|
|
# |foo
|
|
| T_PIPE T_IDENT { [nil, val[1]] }
|
|
;
|
|
|
|
predicate
|
|
: T_LBRACK predicate_members T_RBRACK { val[1] }
|
|
;
|
|
|
|
predicate_members
|
|
: expression { val[0] }
|
|
| operator { val[0] }
|
|
;
|
|
|
|
operator
|
|
: op_members T_EQ op_members { s(:eq, val[0], val[2]) }
|
|
| op_members T_SPACE_IN op_members { s(:space_in, val[0], val[2]) }
|
|
| op_members T_STARTS_WITH op_members { s(:starts_with, val[0], val[2]) }
|
|
| op_members T_ENDS_WITH op_members { s(:ends_with, val[0], val[2]) }
|
|
| op_members T_IN op_members { s(:in, val[0], val[2]) }
|
|
| op_members T_HYPHEN_IN op_members { s(:hyphen_in, val[0],val[2]) }
|
|
;
|
|
|
|
node_operators
|
|
: node_test T_CHILD node_test { s(:child, val[0], val[2]) }
|
|
| node_test T_FOLLOWING node_test { s(:following, val[0], val[2]) }
|
|
| node_test T_FOLLOWING_DIRECT node_test
|
|
{
|
|
s(:following_direct, val[0], val[2])
|
|
}
|
|
;
|
|
|
|
op_members
|
|
: node_test
|
|
| string
|
|
;
|
|
|
|
string
|
|
: T_STRING { s(:string, val[0]) }
|
|
;
|
|
end
|
|
|
|
---- inner
|
|
##
|
|
# @param [String] data The input to parse.
|
|
#
|
|
def initialize(data)
|
|
@lexer = Lexer.new(data)
|
|
end
|
|
|
|
##
|
|
# @param [Symbol] type
|
|
# @param [Array] children
|
|
# @return [AST::Node]
|
|
#
|
|
def s(type, *children)
|
|
return AST::Node.new(type, children)
|
|
end
|
|
|
|
##
|
|
# Yields the next token from the lexer.
|
|
#
|
|
# @yieldparam [Array]
|
|
#
|
|
def yield_next_token
|
|
@lexer.advance do |*args|
|
|
yield args
|
|
end
|
|
|
|
yield [false, false]
|
|
end
|
|
|
|
##
|
|
# Parses the input and returns the corresponding AST.
|
|
#
|
|
# @example
|
|
# parser = Oga::CSS::Parser.new('foo.bar')
|
|
# ast = parser.parse
|
|
#
|
|
# @return [AST::Node]
|
|
#
|
|
def parse
|
|
ast = yyparse(self, :yield_next_token)
|
|
|
|
return ast
|
|
end
|
|
|
|
# vim: set ft=racc:
|