From b9a1f914bd9eb8f128955facff74a0e3e2f9247d Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 2 Oct 2014 23:31:58 +0200 Subject: [PATCH] Basic CSS parser boilerplate. This currently only parses single node tests (e.g. just "foo"). --- .gitignore | 1 + lib/oga.rb | 1 + lib/oga/css/parser.y | 84 ++++++++++++++++++++++++++++++++++++++++++++ task/parser.rake | 6 +++- 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 lib/oga/css/parser.y diff --git a/.gitignore b/.gitignore index d14b3c1..c83d889 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ lib/oga/xml/parser.rb lib/oga/xpath/lexer.rb lib/oga/xpath/parser.rb lib/oga/css/lexer.rb +lib/oga/css/parser.rb lib/liboga.* diff --git a/lib/oga.rb b/lib/oga.rb index 0549640..a8e940f 100644 --- a/lib/oga.rb +++ b/lib/oga.rb @@ -49,3 +49,4 @@ require_relative 'oga/xpath/parser' require_relative 'oga/xpath/evaluator' require_relative 'oga/css/lexer' +require_relative 'oga/css/parser' diff --git a/lib/oga/css/parser.y b/lib/oga/css/parser.y new file mode 100644 index 0000000..a663097 --- /dev/null +++ b/lib/oga/css/parser.y @@ -0,0 +1,84 @@ +## +# AST parser for CSS expressions. +# +class Oga::CSS::Parser + +options no_result_var + +rule + css + : selectors { val[0] } + | /* none */ { nil } + ; + + selectors + : selectors selector { val[0] << val[1] } + | selector { val[0] } + ; + + selector + : node_test + ; + + node_test + : node_name { s(:test, *val[0]) } + ; + + 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]] } + ; +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: diff --git a/task/parser.rake b/task/parser.rake index 562a025..553d599 100644 --- a/task/parser.rake +++ b/task/parser.rake @@ -3,4 +3,8 @@ rule '.rb' => '.y' do |task| end desc 'Generates the parser' -task :parser => ['lib/oga/xml/parser.rb', 'lib/oga/xpath/parser.rb'] +task :parser => [ + 'lib/oga/xml/parser.rb', + 'lib/oga/xpath/parser.rb', + 'lib/oga/css/parser.rb' +]