class HtmlConditionalComment::Parser
Parse tokens into a tree of nodes Pseudo grammar
template = { html | statement } statement = “<!” , [ “–” ] , “if” , expression , “]” , [ “–” ] , “>” , template , “<!” , [ “–” ] , “endif” , “]” , [ “–” ] , “>” expression = term [ “|” , term ] term = factor [ “&” , factor ] factor = subexpression | “!” , factor | “(” , expression , “)” subexpression = [ operator ] browser | boolean operator = “gt” | “gte” | “lt” | “lte” boolean = “true” | “false” browser = feature [ version_vector ]
Constants
- CLOSE
- OPEN
Public Class Methods
new(tokens)
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 28 def initialize(tokens) @symbol = nil @tokens = tokens @max_pos = tokens.size() - 1 @pos = -1 end
Public Instance Methods
parse()
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 35 def parse() self.next() nodes = template() #Tokens left, syntax error error() if @pos < @max_pos nodes end
Protected Instance Methods
accept(symbol)
click to toggle source
Accept the symbol and move on or not
# File lib/html-conditional-comment/parser.rb, line 206 def accept(symbol) if(symbol == @symbol) self.next() return true else return false end end
boolean()
click to toggle source
True or false
# File lib/html-conditional-comment/parser.rb, line 65 def boolean() if accept(:boolean_true) Nodes::True.instance() elsif accept(:boolean_false) Nodes::False.instance() else error() end end
browser()
click to toggle source
Browser is combination of feature and optional version
# File lib/html-conditional-comment/parser.rb, line 49 def browser() node = Nodes::Browser.new() node.feature = @value expect(:feature) if current(:version_vector) node.version_vector = VersionVector.new(@value) accept(:version_vector) else node.version_vector = VersionVector.new(nil) end node end
condition()
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 153 def condition() node = Nodes::Condition.new() expect(:open) expect(:if) node.left = expression() #TODO Goofy confirmation of non-closing HTML comment if current(:close) error() if @value =~ OPEN end expect(:close) unless current(:open) && peek(:endif) node.right = template() end #TODO More goofyness if current(:open) error() if @value =~ CLOSE end expect(:open) expect(:endif) expect(:close) node end
current(symbol)
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 220 def current(symbol) @symbol == symbol end
error()
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 237 def error() raise HtmlConditionalComment::ParseError.new("Syntax error", @value) end
expect(symbol)
click to toggle source
Expect a current symbol or raise
# File lib/html-conditional-comment/parser.rb, line 216 def expect(symbol) raise HtmlConditionalComment::ParseError.new("Expected #{symbol}, received #{@symbol}", @value) unless accept(symbol) end
expression()
click to toggle source
Or
# File lib/html-conditional-comment/parser.rb, line 141 def expression() node = term() while accept(:operator_or) branch_node = Nodes::Or.new() branch_node.left = node branch_node.right = term() node = branch_node end node end
factor()
click to toggle source
Negated self or paranthesised expression
# File lib/html-conditional-comment/parser.rb, line 111 def factor() node = nil if accept(:operator_not) node = Nodes::Not.new() node.child = factor() elsif accept(:paren_open) node = expression() expect(:paren_close) else node = subexpression() end node end
html()
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 182 def html() node = Nodes::Html.new() node.content = @value expect(:html) node end
next()
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 228 def next() @pos += 1 #raise HtmlConditionalComment::ParserError.new('EOF') if @pos >= @max_pos token = @tokens[@pos] || [] @symbol = token[0] @value = token[1] token end
operator()
click to toggle source
Comparison operators
# File lib/html-conditional-comment/parser.rb, line 76 def operator() if accept(:operator_less_than) Nodes::LessThan.new() elsif accept(:operator_less_than_equal) Nodes::LessThanEqual.new() elsif accept(:operator_greater_than) Nodes::GreaterThan.new() elsif accept(:operator_greater_than_equal) Nodes::GreaterThanEqual.new() else error() end end
peek(symbol)
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 224 def peek(symbol) @tokens[@pos+1][0] == symbol end
subexpression()
click to toggle source
Either a comparison with the browser, boolean, or simply just the browser
# File lib/html-conditional-comment/parser.rb, line 91 def subexpression() node = nil if current(:operator_less_than) || current(:operator_less_than_equal) || current(:operator_greater_than) || current(:operator_greater_than_equal) node = operator() node.child = browser() elsif current(:boolean_true) || current(:boolean_false) node = boolean() else #No comparison operator is assuming equals node = Nodes::Equal.new() node.child = browser() end node end
template()
click to toggle source
# File lib/html-conditional-comment/parser.rb, line 189 def template() nodes = Nodes::Nodes.new() while current(:html) || (current(:open) && peek(:if)) nodes << if current(:html) html() elsif current(:open) && peek(:if) condition() end end nodes end
term()
click to toggle source
And
# File lib/html-conditional-comment/parser.rb, line 128 def term() node = factor() while accept(:operator_and) branch_node = Nodes::And.new() branch_node.left = node branch_node.right = factor() node = branch_node end node end