lib/crass/parser.rb in crass-0.0.1 vs lib/crass/parser.rb in crass-0.0.2
- old
+ new
@@ -26,11 +26,11 @@
rules = parser.consume_rules(:top_level => true)
rules.map do |rule|
case rule[:node]
# TODO: handle at-rules
- when :qualified_rule then parser.parse_style_rule(rule)
+ when :qualified_rule then parser.create_style_rule(rule)
else rule
end
end
end
@@ -89,69 +89,73 @@
@tokens = TokenScanner.new(input)
end
# Consumes an at-rule and returns it.
#
- # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-an-at-rule0
- def consume_at_rule(tokens = @tokens)
- rule = {:prelude => []}
+ # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-an-at-rule
+ def consume_at_rule(input = @tokens)
+ rule = {}
- rule[:tokens] = tokens.collect do
- while token = tokens.consume
+ rule[:tokens] = input.collect do
+ rule[:name] = parse_value(input.consume)
+ rule[:prelude] = []
+
+ while token = input.consume
case token[:node]
when :comment then next
when :semicolon, :eof then break
when :'{' then
- rule[:block] = consume_simple_block(tokens)
+ rule[:block] = consume_simple_block(input)
break
- # TODO: At this point, the spec says we should check for a "simple block
- # with an associated token of <<{-token>>", but isn't that exactly what
- # we just did above? And the tokenizer only ever produces standalone
- # <<{-token>>s, so how could the token stream ever contain one that's
- # already associated with a simple block? What am I missing?
+ # TODO: At this point, the spec says we should check for a "simple
+ # block with an associated token of <<{-token>>", but isn't that
+ # exactly what we just did above? And the tokenizer only ever produces
+ # standalone <<{-token>>s, so how could the token stream ever contain
+ # one that's already associated with a simple block? What am I
+ # missing?
else
- tokens.reconsume
- rule[:prelude] << consume_component_value(tokens)
+ input.reconsume
+ rule[:prelude] << consume_component_value(input)
end
end
end
create_node(:at_rule, rule)
end
# Consumes a component value and returns it.
#
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-component-value0
- def consume_component_value(tokens = @tokens)
- return nil unless token = tokens.consume
+ def consume_component_value(input = @tokens)
+ return nil unless token = input.consume
case token[:node]
- when :'{', :'[', :'(' then consume_simple_block(tokens)
- when :function then consume_function(tokens)
+ when :'{', :'[', :'(' then consume_simple_block(input)
+ when :function then consume_function(input)
else token
end
end
# Consumes a declaration and returns it, or `nil` on parse error.
#
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-declaration0
- def consume_declaration(tokens = @tokens)
+ def consume_declaration(input = @tokens)
declaration = {}
- declaration[:tokens] = tokens.collect do
- declaration[:name] = tokens.consume[:value]
+ declaration[:tokens] = input.collect do
+ declaration[:name] = input.consume[:value]
value = []
- token = tokens.consume
- token = tokens.consume while token[:node] == :whitespace
+ token = input.consume
+ token = input.consume while token[:node] == :whitespace
return nil if token[:node] != :colon # TODO: parse error
- value << token while token = tokens.consume
+ value << token while token = input.consume
declaration[:value] = value
maybe_important = value.reject {|v| v[:node] == :whitespace }[-2, 2]
if maybe_important &&
@@ -171,67 +175,70 @@
#
# NOTE: The returned list may include `:comment`, `:semicolon`, and
# `:whitespace` nodes, which is non-standard.
#
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-list-of-declarations0
- def consume_declarations(tokens = @tokens)
+ def consume_declarations(input = @tokens)
declarations = []
- while token = tokens.consume
+ while token = input.consume
case token[:node]
when :comment, :semicolon, :whitespace
declarations << token
when :at_keyword
# TODO: this is technically a parse error when parsing a style rule,
# but not necessarily at other times.
- declarations << consume_at_rule(tokens)
+ # TODO: It seems like we should reconsume the current token here,
+ # since that's what happens when consuming a list of rules.
+ declarations << consume_at_rule(input)
+
when :ident
decl_tokens = [token]
- tokens.consume
+ input.consume
- while tokens.current
- decl_tokens << tokens.current
- break if tokens.current[:node] == :semicolon
- tokens.consume
+ while input.current
+ decl_tokens << input.current
+ break if input.current[:node] == :semicolon
+ input.consume
end
if decl = consume_declaration(TokenScanner.new(decl_tokens))
declarations << decl
end
else
# TODO: parse error (invalid property name, etc.)
while token && token[:node] != :semicolon
- token = consume_component_value(tokens)
+ token = consume_component_value(input)
end
end
end
declarations
end
# Consumes a function and returns it.
#
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-function
- def consume_function(tokens = @tokens)
+ def consume_function(input = @tokens)
function = {
- :name => tokens.current[:value],
+ :name => input.current[:value],
:value => [],
- :tokens => [tokens.current]
+ :tokens => [input.current]
}
- function[:tokens].concat(tokens.collect do
- while token = tokens.consume
+ function[:tokens].concat(input.collect do
+ while token = input.consume
case token[:node]
when :')', :eof then break
when :comment then next
else
- tokens.reconsume
- function[:value] << consume_component_value(tokens)
+ input.reconsume
+ function[:value] << consume_component_value(input)
end
end
end)
create_node(:function, function)
@@ -239,19 +246,19 @@
# Consumes a qualified rule and returns it, or `nil` if a parse error
# occurs.
#
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-qualified-rule0
- def consume_qualified_rule(tokens = @tokens)
+ def consume_qualified_rule(input = @tokens)
rule = {:prelude => []}
- rule[:tokens] = tokens.collect do
+ rule[:tokens] = input.collect do
while true
- return nil unless token = tokens.consume
+ return nil unless token = input.consume
if token[:node] == :'{'
- rule[:block] = consume_simple_block(tokens)
+ rule[:block] = consume_simple_block(input)
break
# elsif [simple block with an associated <<{-token>>??]
# TODO: At this point, the spec says we should check for a "simple block
@@ -259,12 +266,12 @@
# we just did above? And the tokenizer only ever produces standalone
# <<{-token>>s, so how could the token stream ever contain one that's
# already associated with a simple block? What am I missing?
else
- tokens.reconsume
- rule[:prelude] << consume_component_value(tokens)
+ input.reconsume
+ rule[:prelude] << consume_component_value(input)
end
end
end
create_node(:qualified_rule, rule)
@@ -305,27 +312,27 @@
# Consumes and returns a simple block associated with the current input
# token.
#
# http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-simple-block0
- def consume_simple_block(tokens = @tokens)
- start_token = tokens.current[:node]
+ def consume_simple_block(input = @tokens)
+ start_token = input.current[:node]
end_token = BLOCK_END_TOKENS[start_token]
block = {
:start => start_token.to_s,
:end => end_token.to_s,
:value => [],
- :tokens => [tokens.current]
+ :tokens => [input.current]
}
- block[:tokens].concat(tokens.collect do
- while token = tokens.consume
+ block[:tokens].concat(input.collect do
+ while token = input.consume
break if token[:node] == end_token || token[:node] == :eof
- tokens.reconsume
- block[:value] << consume_component_value(tokens)
+ input.reconsume
+ block[:value] << consume_component_value(input)
end
end)
create_node(:simple_block, block)
end
@@ -333,25 +340,26 @@
# Creates and returns a new parse node with the given _properties_.
def create_node(type, properties = {})
{:node => type}.merge!(properties)
end
- # Parses the given _tokens_ into a selector node and returns it.
+ # Parses the given _input_ tokens into a selector node and returns it.
#
# Doesn't bother splitting the selector list into individual selectors or
# validating them. Feel free to do that yourself! It'll be fun!
- def parse_selector(tokens)
+ def create_selector(input)
create_node(:selector,
- :value => parse_value(tokens),
- :tokens => tokens)
+ :value => parse_value(input),
+ :tokens => input)
end
- # Parses a style rule and returns the result.
+ # Creates a `:style_rule` node from the given qualified _rule_, and returns
+ # it.
#
- # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#style-rules
- # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-list-of-declarations0
- def parse_style_rule(rule)
+ # * http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#style-rules
+ # * http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#consume-a-list-of-declarations0
+ def create_style_rule(rule)
children = []
tokens = TokenScanner.new(rule[:block][:value])
consume_declarations(tokens).each do |decl|
unless decl[:node] == :declaration
@@ -364,22 +372,26 @@
:value => parse_value(decl[:value]),
:tokens => decl[:tokens])
end
create_node(:style_rule,
- :selector => parse_selector(rule[:prelude]),
+ :selector => create_selector(rule[:prelude]),
:children => children
)
end
# Returns the unescaped value of a selector name or property declaration.
def parse_value(nodes)
string = ''
+ nodes = [nodes] unless nodes.is_a?(Array)
+
nodes.each do |node|
case node[:node]
when :comment, :semicolon then next
- when :ident then string << node[:value]
+
+ when :at_keyword, :ident
+ string << node[:value]
when :function
if node[:value].is_a?(String)
string << node[:value]
else