First pass of rewriting the CSS parser.

The new parser uses way less confusing rule names, is a bit more strict and in
general much less of a pain to deal with.
This commit is contained in:
Yorick Peterse 2014-10-21 23:19:31 +02:00
parent e3de65a258
commit 851e7d6d0b
1 changed files with 85 additions and 106 deletions

View File

@ -13,67 +13,76 @@ options no_result_var
prechigh prechigh
left T_COLON T_HASH T_DOT left T_COLON T_HASH T_DOT
left T_CHILD T_FOLLOWING T_FOLLOWING_DIRECT left T_CHILD T_FOLLOWING T_FOLLOWING_DIRECT
left T_DOT T_HASH
preclow preclow
rule rule
css css
: expression { val[0] } : selectors { val[0] }
| /* none */ { nil } | /* none */ { nil }
; ;
expression selectors
: steps { s(:path, *val[0]) } : selector
| step | selectors_ { s(:path, *val[0]) }
; ;
steps selectors_
: step T_SPACE step { [val[0], val[2]] } : selectors_ T_SPACE selector { val[0] << val[2] }
| step T_SPACE steps { [val[0], *val[2]] } | selector T_SPACE selector { [val[0], val[2]] }
; ;
step selector
: step_test { s(:axis, 'descendant-or-self', val[0]) } : descendant_or_self
| axis
; ;
step_test descendant_or_self
: element_test { val[0] } : node_test { s(:axis, 'descendant-or-self', val[0]) }
| step_predicates { s(:test, nil, '*', val[0]) }
; ;
step_predicates axis
: step_predicate : T_CHILD axis_selector { s(:axis, 'child', val[1]) }
| step_predicates step_predicate { s(:and, val[0], val[1]) } | T_FOLLOWING axis_selector { s(:axis, 'following', val[1]) }
| T_FOLLOWING_DIRECT axis_selector { s(:axis, 'following-direct', val[1]) }
; ;
step_predicate axis_selector
: class | node_test
| id | axis
#| axis
#| pseudo_class
; ;
element_test node_test
# foo # foo
: node_name { s(:test, *val[0]) } : node_name
{
s(:test, *val[0])
}
# .foo, :root, etc
| predicates
{
s(:test, nil, '*', val[0])
}
# foo.bar
| node_name predicates
{
s(:test, *val[0], val[1])
}
# foo[bar] # foo[bar]
| node_name predicate { s(:test, *val[0], val[1]) } | node_name attribute_predicate
{
s(:test, *val[0], val[1])
}
# foo:root # foo[bar].baz
| node_name step_predicates { s(:test, *val[0], val[1]) } | node_name attribute_predicate predicates
# foo[bar]:root
| node_name predicate step_predicates
{ {
s(:test, *val[0], s(:and, val[1], val[2])) s(:test, *val[0], s(:and, val[1], val[2]))
} }
; ;
attribute_test
: node_name { s(:axis, 'attribute', s(:test, *val[0])) }
;
node_name node_name
# foo # foo
: T_IDENT { [nil, val[0]] } : T_IDENT { [nil, val[0]] }
@ -85,15 +94,34 @@ rule
| T_PIPE T_IDENT { [nil, val[1]] } | T_PIPE T_IDENT { [nil, val[1]] }
; ;
predicate predicates
: T_LBRACK predicate_members T_RBRACK { val[1] } : predicates predicate { s(:and, val[0], val[1]) }
| predicate
; ;
predicate_members predicate
: attribute_test : class
| id
| pseudo_class
;
attribute_predicate
: T_LBRACK attribute_predicate_members T_RBRACK { val[1] }
;
attribute_predicate_members
: attribute
| operator | operator
; ;
attribute
: node_name { s(:axis, 'attribute', s(:test, *val[0])) }
;
operator
: attribute T_EQ string { s(:eq, val[0], val[2]) }
;
class class
: T_DOT T_IDENT : T_DOT T_IDENT
{ {
@ -119,78 +147,29 @@ rule
} }
; ;
operator pseudo_class
: op_members T_EQ op_members { s(:eq, val[0], val[2]) } # :root
| op_members T_SPACE_IN op_members { s(:space_in, val[0], val[2]) } : pseudo_name { s(:pseudo, nil, val[0]) }
| 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]) } # :nth-child(2)
| op_members T_IN op_members { s(:in, val[0], val[2]) } | pseudo_name pseudo_args { s(:pseudo, nil, val[0], val[1]) }
| op_members T_HYPHEN_IN op_members { s(:hyphen_in, val[0],val[2]) }
; ;
op_members pseudo_name
: attribute_test : T_COLON T_IDENT { val[1] }
| string ;
pseudo_args
: T_LPAREN pseudo_arg T_RPAREN { val[1] }
;
pseudo_arg
: integer
#| odd
#| even
#| nth
| selector
; ;
#
# axis
# # x > y
# : step_member T_CHILD step_member { s(:child, val[0], val[2]) }
#
# # x + y
# | step_member T_FOLLOWING step_member { s(:following, val[0], val[2]) }
#
# # x ~ y
# | step_member T_FOLLOWING_DIRECT step_member
# {
# s(:following_direct, val[0], val[2])
# }
# ;
#
# pseudo_class
# # :root
# : pseudo_name { s(:pseudo, nil, val[0]) }
#
# # x:root
# | step_member pseudo_name { s(:pseudo, val[0], val[1]) }
#
# # :nth-child(2)
# | pseudo_name pseudo_args { s(:pseudo, nil, val[0], val[1]) }
#
# # x:nth-child(2)
# | step_member pseudo_name pseudo_args { s(:pseudo, val[0], val[1], val[2]) }
# ;
#
# pseudo_name
# : T_COLON T_IDENT { val[1] }
# ;
#
# pseudo_args
# : T_LPAREN pseudo_arg T_RPAREN { val[1] }
# ;
#
# pseudo_arg
# : integer
# | odd
# | even
# | nth
# | node_test
# ;
#
# odd
# : T_ODD { s(:odd) }
# ;
#
# even
# : T_EVEN { s(:even) }
# ;
#
# nth
# : T_NTH { s(:nth) }
# | T_MINUS T_NTH { s(:nth) }
# | integer T_NTH { s(:nth, val[0]) }
# | integer T_NTH integer { s(:nth, val[0], val[2]) }
# ;
string string
: T_STRING { s(:string, val[0]) } : T_STRING { s(:string, val[0]) }