Basic XPath parser setup.

This commit is contained in:
Yorick Peterse 2014-06-01 23:02:28 +02:00
parent 54de2df0c7
commit e11b9ed32c
7 changed files with 103 additions and 4 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ Gemfile.lock
lib/oga/xml/parser.rb
lib/oga/xpath/lexer.rb
lib/oga/xpath/parser.rb
lib/liboga.*

View File

@ -18,13 +18,12 @@ else
end
end
PARSER_OUTPUT = 'lib/oga/xml/parser.rb'
CLEAN.include(
'coverage',
'yardoc',
PARSER_OUTPUT,
'lib/oga/xml/parser.rb',
'lib/oga/xpath/lexer.rb',
'lib/oga/xpath/parser.rb',
'benchmark/fixtures/big.xml',
'profile/samples/**/*.txt',
'lib/liboga.*',

View File

@ -1,3 +1,4 @@
require 'ast'
require 'set'
# Load these first so that the native extensions don't have to define the
@ -23,4 +24,6 @@ require_relative 'oga/xml/doctype'
require_relative 'oga/html/parser'
require_relative 'oga/xpath/node'
require_relative 'oga/xpath/lexer'
require_relative 'oga/xpath/parser'

10
lib/oga/xpath/node.rb Normal file
View File

@ -0,0 +1,10 @@
module Oga
module XPath
##
# AST node for XPath expressions.
#
class Node < AST::Node
end # Node
end # XPath
end # Oga

81
lib/oga/xpath/parser.y Normal file
View File

@ -0,0 +1,81 @@
##
# Parser for XPath expressions.
#
class Oga::XPath::Parser
token T_AXIS T_COLON T_COMMA T_FLOAT T_INT T_IDENT T_OP
token T_LBRACK T_RBRACK T_LPAREN T_RPAREN T_SLASH T_STRING
options no_result_var
rule
expressions
: expressions_ { s(:xpath, *val[0]) }
| /* none */ { s(:xpath) }
;
expressions_
: expressions_ expression { val[0] << val[1] }
| expression { val }
;
expression
: node_test
;
node_test
: T_IDENT { s(:node, nil, val[0]) }
| T_IDENT T_COLON T_IDENT { s(:node, val[0], val[2]) }
;
end
---- inner
##
# @param [String] data The input to parse.
#
# @param [Hash] options
#
def initialize(data)
@data = data
@lexer = Lexer.new(data)
end
##
# Creates a new XPath node.
#
# @param [Symbol] type
# @param [Array] children
# @return [Oga::XPath::Node]
#
def s(type, *children)
return 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::XPath::Parser.new('//foo')
# ast = parser.parse
#
# @return [Oga::AST::Node]
#
def parse
ast = yyparse(self, :yield_next_token)
return ast
end
# vim: set ft=racc:

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe Oga::XPath::Parser do
pending 'Write me!'
end

View File

@ -3,4 +3,4 @@ rule '.rb' => '.y' do |task|
end
desc 'Generates the parser'
task :parser => [PARSER_OUTPUT]
task :parser => ['lib/oga/xml/parser.rb', 'lib/oga/xpath/parser.rb']