Basic XPath parser setup.
This commit is contained in:
parent
54de2df0c7
commit
e11b9ed32c
|
@ -5,6 +5,7 @@ Gemfile.lock
|
|||
|
||||
lib/oga/xml/parser.rb
|
||||
lib/oga/xpath/lexer.rb
|
||||
lib/oga/xpath/parser.rb
|
||||
|
||||
lib/liboga.*
|
||||
|
||||
|
|
5
Rakefile
5
Rakefile
|
@ -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.*',
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
module Oga
|
||||
module XPath
|
||||
##
|
||||
# AST node for XPath expressions.
|
||||
#
|
||||
class Node < AST::Node
|
||||
|
||||
end # Node
|
||||
end # XPath
|
||||
end # Oga
|
|
@ -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:
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Oga::XPath::Parser do
|
||||
pending 'Write me!'
|
||||
end
|
|
@ -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']
|
||||
|
|
Loading…
Reference in New Issue