treetop-1.6.3/0000755000004100000410000000000012552221265013235 5ustar www-datawww-datatreetop-1.6.3/Rakefile0000644000004100000410000000416412552221265014707 0ustar www-datawww-datarequire 'rubygems' require 'bundler' Bundler.setup(:default, :development) require 'rake' require 'jeweler' require 'rspec/core/rake_task' require File.expand_path("../lib/treetop/version", __FILE__) Jeweler::Tasks.new do |gem| gem.name = "treetop" gem.version = Treetop::VERSION::STRING gem.author = ["Nathan Sobo", "Clifford Heath"] gem.license = "MIT" gem.email = "cliffordheath@gmail.com" gem.homepage = "https://github.com/cjheath/treetop" gem.platform = Gem::Platform::RUBY gem.summary = "A Ruby-based text parsing and interpretation DSL" gem.description = "A Parsing Expression Grammar (PEG) Parser generator DSL for Ruby" gem.files = [ "LICENSE", "README.md", "Rakefile", "treetop.gemspec", "{spec,lib,bin,examples}/**/*", "doc/*" ].map{|p| Dir[p] }.flatten gem.bindir = "bin" gem.executables = ["tt"] gem.require_path = "lib" gem.has_rdoc = false end Jeweler::RubygemsDotOrgTasks.new task :default => :spec RSpec::Core::RakeTask.new do |t| t.pattern = 'spec/**/*spec.rb' # t.libs << 'spec' # @todo not sure what this did in the original rspec 1.3 end task :spec => 'lib/treetop/compiler/metagrammar.treetop' file 'lib/treetop/compiler/metagrammar.treetop' do |t| unless $bootstrapped_gen_1_metagrammar load File.expand_path('../lib/treetop/bootstrap_gen_1_metagrammar.rb', __FILE__) end Treetop::Compiler::GrammarCompiler.new.compile(METAGRAMMAR_PATH) end task :rebuild do $:.unshift "lib" require './lib/treetop' load File.expand_path('../lib/treetop/compiler/metagrammar.rb', __FILE__) Treetop::Compiler::GrammarCompiler.new.compile('lib/treetop/compiler/metagrammar.treetop') end task :version do puts RUBY_VERSION end desc 'Generate website files' task :website_generate do `cd doc; ruby ./site.rb` end desc 'Upload website files' task :website_upload do # The website is now done using gh-pages system <<-END git checkout gh-pages cp website/*.html . git add *.html git commit -m"Website update `date`" git push git checkout master END end desc 'Generate and upload website files' task :website => [:website_generate, :website_upload] treetop-1.6.3/bin/0000755000004100000410000000000012552221265014005 5ustar www-datawww-datatreetop-1.6.3/bin/tt0000755000004100000410000000671112552221265014367 0ustar www-datawww-data#!/usr/bin/env ruby require 'optparse' require 'rubygems' $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib")) require 'treetop' require 'treetop/version' require 'treetop/polyglot' options = {} parser = OptionParser.new do |opts| exts = Treetop::Polyglot::VALID_GRAMMAR_EXT.collect { |i| '.' + i } opts.banner = "Treetop Parsing Expression Grammar (PEG) Comand Line Compiler" opts.define_head "Usage: tt [options] grammar_file[#{exts.join('|')}] ..." opts.separator '' opts.separator 'Examples:' opts.separator ' tt foo.tt # 1 grammar -> 1 parser source' opts.separator ' tt foo bar.treetop # 2 grammars -> 2 separate parsers' opts.separator ' tt -o alt_name.rb foo # alternately named output file' opts.separator '' opts.separator '' opts.separator 'NOTE: while treetop grammar files *must* have one of the following' opts.separator 'filename extensions, the extension name is not required when calling' opts.separator 'the compiler with grammar file names.' opts.separator '' opts.separator " Valid extensions: #{exts.join(', ')}" opts.separator '' opts.separator '' opts.separator 'Options:' opts.on('-o', '--output FILENAME', 'Write parser source to FILENAME') do |fn| options[:out_file] = fn end opts.on('-f', '--force', 'Overwrite existing output file(s)') do options[:force] = true end opts.on_tail('-v', '--version', 'Show Treetop version') do puts "Treetop v#{Treetop::VERSION::STRING}" exit end opts.on_tail('-h', '--help', 'Show this help message') do puts opts exit end end file_list = parser.parse! # check options and arg constraints if file_list.empty? || (options[:out_file] && file_list.size > 1) puts parser exit 1 end def grammar_exist?(filename) if File.extname(filename).empty? Treetop::Polyglot::VALID_GRAMMAR_EXT.each do |ext| fn_ext = "#{filename}.#{ext}" return true if File.exist?(fn_ext) && !File.zero?(fn_ext) end end File.exist?(filename) && !File.zero?(filename) end def full_grammar_filename(filename) return filename if !File.extname(filename).empty? Treetop::Polyglot::VALID_GRAMMAR_EXT.each do |ext| fn_ext = "#{filename}.#{ext}" return fn_ext if File.exist?(fn_ext) && !File.zero?(fn_ext) end end def protect_output?(filename, forced=false) if !forced and File.exist?(filename) and File.open(filename) { |f| ![(f.gets rescue ''), (f.gets rescue '')].include? Treetop::Compiler::AUTOGENERATED } puts "ERROR: '#{filename}' output already exists; skipping compilation...\n" return true end false end compiler = Treetop::Compiler::GrammarCompiler.new while !file_list.empty? treetop_file = file_list.shift # handle nonexistent and existent grammar files mixed together if !grammar_exist?(treetop_file) puts "ERROR: input grammar file '#{treetop_file}' does not exist; continuing...\n" next end # try to compile treetop_file = full_grammar_filename(treetop_file) std_output_file = treetop_file.gsub(Treetop::Polyglot::VALID_GRAMMAR_EXT_REGEXP, '.rb') if options[:out_file] # explicit output file name option; never overwrite unless forced next if protect_output?(options[:out_file], options[:force]) compiler.compile(treetop_file, options[:out_file]) else # compile one input file from input file list option; never overwrite unless forced next if protect_output?(std_output_file, options[:force]) compiler.compile(treetop_file) end end treetop-1.6.3/examples/0000755000004100000410000000000012552221265015053 5ustar www-datawww-datatreetop-1.6.3/examples/numerals.tt0000644000004100000410000000041012552221265017245 0ustar www-datawww-datagrammar Numerals rule percentage (decimal "%") { def to_f decimal.to_f / 100 end } end rule decimal sign [0-9]+ '.' [0-9]* { def to_f text_value.to_f end } end rule sign ('+'/'-')? end end treetop-1.6.3/examples/indented_blocks/0000755000004100000410000000000012552221265020202 5ustar www-datawww-datatreetop-1.6.3/examples/indented_blocks/indented_blocks.tt0000644000004100000410000000306412552221265023705 0ustar www-datawww-datagrammar IndentedBlocks rule top # Initialise the indent stack with a sentinel: &{|s| @indents = [-1] } foo:('foo'?) nested_blocks { def inspect nested_blocks.inspect end } end rule nested_blocks ( # Do not try to extract this semantic predicate into a new rule. # It will be memo-ized incorrectly because @indents.last will change. !{|s| # Peek at the following indentation: save = index; i = _nt_indentation; index = save # We're closing if the indentation is less or the same as our enclosing block's: closing = i.text_value.length <= @indents.last } block )* { def inspect elements.map{|e| e.block.inspect}*"\n" end } end rule block indented_line # The block's opening line &{|s| # Push the indent level to the stack level = s[0].indentation.text_value.length @indents << level true } nested_blocks # Parse any nested blocks &{|s| # Pop the indent stack # Note that under no circumstances should "nested_blocks" fail, or the stack will be mis-aligned @indents.pop true } { def inspect indented_line.inspect + (nested_blocks.elements.size > 0 ? ( "\n{\n" + nested_blocks.elements.map { |content| content.block.inspect+"\n" }*'' + "}" ) : "") end } end rule indented_line indentation text:((!"\n" .)*) "\n" { def inspect text.text_value end } end rule indentation ' '* end end treetop-1.6.3/examples/indented_blocks/indented_blocks_test.rb0000644000004100000410000000072212552221265024716 0ustar www-datawww-datarequire 'polyglot' require 'byebug' require 'treetop' require 'indented_blocks' parser = IndentedBlocksParser.new input = < value) end def to_s(env={}) env.has_key?(name) ? env[name].to_s : name end end module Variable1 end def _nt_variable start_index = index cached = node_cache[:variable][index] if cached @index = cached.interval.end return cached end i0, s0 = index, [] i1 = index r2 = _nt_keyword if r2.success? r1 = ParseFailure.new(input, i1) else self.index = i1 r1 = SyntaxNode.new(input, index...index) end s0 << r1 if r1.success? r3 = super r3.extend(Variable0) s0 << r3 end if s0.last.success? r0 = (SyntaxNode).new(input, i0...index, s0) r0.extend(Variable1) else self.index = i0 r0 = ParseFailure.new(input, i0) end node_cache[:variable][start_index] = r0 return r0 end module Keyword0 end def _nt_keyword start_index = index cached = node_cache[:keyword][index] if cached @index = cached.interval.end return cached end i0, s0 = index, [] i1 = index r2 = parse_terminal('if', SyntaxNode) if r2.success? r1 = r2 else r3 = parse_terminal('else', SyntaxNode) if r3.success? r1 = r3 else self.index = i1 r1 = ParseFailure.new(input, i1) end end s0 << r1 if r1.success? i4 = index r5 = _nt_non_space_char if r5.success? r4 = ParseFailure.new(input, i4) else self.index = i4 r4 = SyntaxNode.new(input, index...index) end s0 << r4 end if s0.last.success? r0 = (SyntaxNode).new(input, i0...index, s0) r0.extend(Keyword0) else self.index = i0 r0 = ParseFailure.new(input, i0) end node_cache[:keyword][start_index] = r0 return r0 end module NonSpaceChar0 end def _nt_non_space_char start_index = index cached = node_cache[:non_space_char][index] if cached @index = cached.interval.end return cached end i0, s0 = index, [] i1 = index r2 = parse_char_class(/[ \n]/, ' \n', SyntaxNode) if r2.success? r1 = ParseFailure.new(input, i1) else self.index = i1 r1 = SyntaxNode.new(input, index...index) end s0 << r1 if r1.success? r3 = parse_anything(SyntaxNode) s0 << r3 end if s0.last.success? r0 = (SyntaxNode).new(input, i0...index, s0) r0.extend(NonSpaceChar0) else self.index = i0 r0 = ParseFailure.new(input, i0) end node_cache[:non_space_char][start_index] = r0 return r0 end def _nt_space start_index = index cached = node_cache[:space][index] if cached @index = cached.interval.end return cached end s0, i0 = [], index loop do r1 = parse_char_class(/[ \n]/, ' \n', SyntaxNode) if r1.success? s0 << r1 else break end end r0 = SyntaxNode.new(input, i0...index, s0) node_cache[:space][start_index] = r0 return r0 end end class LambdaCalculusParser < Treetop::Runtime::CompiledParser include LambdaCalculus end treetop-1.6.3/examples/lambda_calculus/lambda_calculus_node_classes.rb0000644000004100000410000000012712552221265026350 0ustar www-datawww-datamodule LambdaCalculus class Application < Treetop::Runtime::SyntaxNode end endtreetop-1.6.3/examples/lambda_calculus/test_helper.rb0000644000004100000410000000051212552221265023027 0ustar www-datawww-datarequire 'test/unit' require 'rubygems' require 'treetop' module ParserTestHelper def assert_evals_to_self(input) assert_evals_to(input, input) end def parse(input) result = @parser.parse(input) unless result puts @parser.terminal_failures.join("\n") end assert !result.nil? result end endtreetop-1.6.3/examples/lambda_calculus/arithmetic.treetop0000644000004100000410000000250512552221265023725 0ustar www-datawww-datagrammar Arithmetic rule expression comparative / additive end rule comparative head:additive tail:( space operator:equality_op space operand:additive)* end rule equality_op '==' { def apply(a, b) a == b end } end rule additive head:multitive tail:( space operator:additive_op space operand:multitive)* end rule additive_op '+' { def apply(a, b) a + b end } / '-' { def apply(a, b) a - b end } end rule multitive head:primary tail:( space operator:multitive_op space operand:primary)* end rule multitive_op '*' { def apply(a, b) a * b end } / '/' { def apply(a, b) a / b end } end rule primary variable / number / '(' space expression space ')' { def eval(env={}) expression.eval(env) end } end rule variable [a-z]+ { def eval(env={}) env[name] end def name text_value end } end rule number ([1-9] [0-9]* / '0') { def eval(env={}) text_value.to_i end } end rule space ' '* end end treetop-1.6.3/examples/lambda_calculus/lambda_calculus_test.rb0000644000004100000410000000464212552221265024673 0ustar www-datawww-datadir = File.dirname(__FILE__) require File.expand_path("#{dir}/test_helper") require File.expand_path("#{dir}/arithmetic_node_classes") require File.expand_path("#{dir}/lambda_calculus_node_classes") Treetop.load File.expand_path("#{dir}/arithmetic") Treetop.load File.expand_path("#{dir}/lambda_calculus") class Treetop::Runtime::SyntaxNode def method_missing(method, *args) raise "Node representing #{text_value} does not respond to #{method}" end end class LambdaCalculusParserTest < Test::Unit::TestCase include ParserTestHelper def setup @parser = LambdaCalculusParser.new end def test_free_variable assert_equal 'x', parse('x').eval.to_s end def test_variable_binding variable = parse('x').eval env = variable.bind(1, {}) assert_equal 1, env['x'] end def test_bound_variable_evaluation assert_equal 1, parse('x').eval({'x' => 1}) end def test_identity_function assert_equal '\x(x)', parse('\x(x)').eval.to_s end def test_function_returning_constant_function assert_equal '\x(\y(x))', parse('\x(\y(x))').eval.to_s end def test_identity_function_application assert_equal 1, parse('\x(x) 1').eval assert_equal '\y(y)', parse('\x(x) \y(y)').eval.to_s end def test_constant_function_construction assert_equal '\y(1)', parse('\x(\y(x)) 1').eval.to_s end def test_multiple_argument_application_is_left_associative assert_equal '\b(b)', parse('\x(\y(x y)) \a(a) \b(b)').eval.to_s end def test_parentheses_override_application_order assert_equal '\y(\b(b) y)', parse('\x(\y(x y)) (\a(a) \b(b))').eval.to_s end def test_arithmetic_in_function_body assert_equal 10, parse('\x(x + 5) 5').eval end def test_addition_of_function_results assert_equal 20, parse('\x(x + 5) 5 + \x(15 - x) 5').eval end def test_conditional result = parse('if (x) 1 else 2') assert_equal 1, result.eval({'x' => true}) assert_equal 2, result.eval({'x' => false}) end def test_keyword assert @parser.parse('if').failure? assert @parser.parse('else').failure? assert parse('elsee').success? assert parse('iff').success? end def test_program result = parse('def fact \x(if (x == 0) 1 else x * fact (x - 1)); fact(5)').eval assert_equal 5 * 4 * 3 * 2, result end end treetop-1.6.3/examples/lambda_calculus/lambda_calculus.treetop0000644000004100000410000000516512552221265024714 0ustar www-datawww-datagrammar LambdaCalculus include Arithmetic rule program expression more_expressions:(';' space expression)* { def eval(env={}) env = env.clone last_eval = nil expressions.each do |exp| last_eval = exp.eval(env) end last_eval end def expressions [expression] + more_expressions.elements.map {|elt| elt.expression} end } end rule expression definition / conditional / application / function / super end rule definition 'def' space variable space expression { def eval(env) env[variable.name] = expression.eval(env) end } end rule conditional 'if' space '(' space condition:expression space ')' space true_case:expression space 'else' space false_case:expression { def eval(env) if condition.eval(env) true_case.eval(env) else false_case.eval(env) end end } end rule primary application / super end rule application operator space expression { def eval(env={}) left_associative_apply(operator.eval(env), env) end def left_associative_apply(operator, env) if expression.instance_of?(Application) expression.left_associative_apply(operator.apply(expression.operator.eval(env)), env) else operator.apply(expression.eval(env)) end end def to_s(env={}) operator.to_s(env) + ' ' + expression.to_s(env) end } end rule operator function / variable end rule non_application function / variable end rule function '\\' param:variable '(' body:expression ')' { class Closure attr_reader :env, :function def initialize(function, env) @function = function @env = env end def apply(arg) function.body.eval(function.param.bind(arg, env)) end def to_s(other_env={}) "\\#{function.param.to_s}(#{function.body.to_s(other_env.merge(env))})" end end def eval(env={}) Closure.new(self, env) end def to_s(env={}) eval(env).to_s end } end rule variable !keyword ( super { def bind(value, env) env.merge(name => value) end def to_s(env={}) env.has_key?(name) ? env[name].to_s : name end } ) end rule keyword ('if' / 'else') !non_space_char end rule non_space_char ![ \n] . end rule space [ \n]* end endtreetop-1.6.3/examples/lambda_calculus/arithmetic_test.rb0000644000004100000410000000245612552221265023712 0ustar www-datawww-datadir = File.dirname(__FILE__) require File.expand_path("#{dir}/test_helper") require File.expand_path("#{dir}/arithmetic_node_classes") Treetop.load File.expand_path("#{dir}/arithmetic") class ArithmeticParserTest < Test::Unit::TestCase include ParserTestHelper def setup @parser = ArithmeticParser.new end def test_number assert_equal 0, parse('0').eval assert_equal 1, parse('1').eval assert_equal 123, parse('123').eval end def test_variable assert_equal 0, parse('x').eval('x' => 0) assert_equal 3, parse('x').eval('x' => 3) assert_equal 10, parse('y').eval('y' => 10) end def test_addition assert_equal 10, parse('x + 5').eval('x' => 5) end def test_subtraction assert_equal 0, parse('x - 5').eval('x' => 5) end def test_multiplication assert_equal 6, parse('x * 2').eval('x' => 3) end def test_division assert_equal 3, parse('x / 2').eval('x' => 6) end def test_order_of_operations assert_equal 11, parse('1 + 2 * 3 + 4').eval end def test_left_to_right assert_equal 2, parse('5 - 2 - 1').eval end def test_parentheses assert_equal 25, parse('(5 + x) * (10 - y)').eval('x' => 0, 'y' => 5) end def test_equality assert parse('4 == 4').eval assert !parse('4 == 3').eval end end treetop-1.6.3/examples/lambda_calculus/arithmetic.rb0000644000004100000410000002322212552221265022645 0ustar www-datawww-datamodule Arithmetic include Treetop::Runtime def root @root || :expression end def _nt_expression start_index = index cached = node_cache[:expression][index] if cached @index = cached.interval.end return cached end i0 = index r1 = _nt_comparative if r1.success? r0 = r1 else r2 = _nt_additive if r2.success? r0 = r2 else self.index = i0 r0 = ParseFailure.new(input, i0) end end node_cache[:expression][start_index] = r0 return r0 end module Comparative0 def operand_1 elements[0] end def space elements[1] end def operator elements[2] end def space elements[3] end def operand_2 elements[4] end end def _nt_comparative start_index = index cached = node_cache[:comparative][index] if cached @index = cached.interval.end return cached end i0, s0 = index, [] r1 = _nt_additive s0 << r1 if r1.success? r2 = _nt_space s0 << r2 if r2.success? r3 = _nt_equality_op s0 << r3 if r3.success? r4 = _nt_space s0 << r4 if r4.success? r5 = _nt_additive s0 << r5 end end end end if s0.last.success? r0 = (BinaryOperation).new(input, i0...index, s0) r0.extend(Comparative0) else self.index = i0 r0 = ParseFailure.new(input, i0) end node_cache[:comparative][start_index] = r0 return r0 end module EqualityOp0 def apply(a, b) a == b end end def _nt_equality_op start_index = index cached = node_cache[:equality_op][index] if cached @index = cached.interval.end return cached end r0 = parse_terminal('==', SyntaxNode, EqualityOp0) node_cache[:equality_op][start_index] = r0 return r0 end module Additive0 def operand_1 elements[0] end def space elements[1] end def operator elements[2] end def space elements[3] end def operand_2 elements[4] end end def _nt_additive start_index = index cached = node_cache[:additive][index] if cached @index = cached.interval.end return cached end i0 = index i1, s1 = index, [] r2 = _nt_multitive s1 << r2 if r2.success? r3 = _nt_space s1 << r3 if r3.success? r4 = _nt_additive_op s1 << r4 if r4.success? r5 = _nt_space s1 << r5 if r5.success? r6 = _nt_additive s1 << r6 end end end end if s1.last.success? r1 = (BinaryOperation).new(input, i1...index, s1) r1.extend(Additive0) else self.index = i1 r1 = ParseFailure.new(input, i1) end if r1.success? r0 = r1 else r7 = _nt_multitive if r7.success? r0 = r7 else self.index = i0 r0 = ParseFailure.new(input, i0) end end node_cache[:additive][start_index] = r0 return r0 end module AdditiveOp0 def apply(a, b) a + b end end module AdditiveOp1 def apply(a, b) a - b end end def _nt_additive_op start_index = index cached = node_cache[:additive_op][index] if cached @index = cached.interval.end return cached end i0 = index r1 = parse_terminal('+', SyntaxNode, AdditiveOp0) if r1.success? r0 = r1 else r2 = parse_terminal('-', SyntaxNode, AdditiveOp1) if r2.success? r0 = r2 else self.index = i0 r0 = ParseFailure.new(input, i0) end end node_cache[:additive_op][start_index] = r0 return r0 end module Multitive0 def operand_1 elements[0] end def space elements[1] end def operator elements[2] end def space elements[3] end def operand_2 elements[4] end end def _nt_multitive start_index = index cached = node_cache[:multitive][index] if cached @index = cached.interval.end return cached end i0 = index i1, s1 = index, [] r2 = _nt_primary s1 << r2 if r2.success? r3 = _nt_space s1 << r3 if r3.success? r4 = _nt_multitive_op s1 << r4 if r4.success? r5 = _nt_space s1 << r5 if r5.success? r6 = _nt_multitive s1 << r6 end end end end if s1.last.success? r1 = (BinaryOperation).new(input, i1...index, s1) r1.extend(Multitive0) else self.index = i1 r1 = ParseFailure.new(input, i1) end if r1.success? r0 = r1 else r7 = _nt_primary if r7.success? r0 = r7 else self.index = i0 r0 = ParseFailure.new(input, i0) end end node_cache[:multitive][start_index] = r0 return r0 end module MultitiveOp0 def apply(a, b) a * b end end module MultitiveOp1 def apply(a, b) a / b end end def _nt_multitive_op start_index = index cached = node_cache[:multitive_op][index] if cached @index = cached.interval.end return cached end i0 = index r1 = parse_terminal('*', SyntaxNode, MultitiveOp0) if r1.success? r0 = r1 else r2 = parse_terminal('/', SyntaxNode, MultitiveOp1) if r2.success? r0 = r2 else self.index = i0 r0 = ParseFailure.new(input, i0) end end node_cache[:multitive_op][start_index] = r0 return r0 end module Primary0 def space elements[1] end def expression elements[2] end def space elements[3] end end module Primary1 def eval(env={}) expression.eval(env) end end def _nt_primary start_index = index cached = node_cache[:primary][index] if cached @index = cached.interval.end return cached end i0 = index r1 = _nt_variable if r1.success? r0 = r1 else r2 = _nt_number if r2.success? r0 = r2 else i3, s3 = index, [] r4 = parse_terminal('(', SyntaxNode) s3 << r4 if r4.success? r5 = _nt_space s3 << r5 if r5.success? r6 = _nt_expression s3 << r6 if r6.success? r7 = _nt_space s3 << r7 if r7.success? r8 = parse_terminal(')', SyntaxNode) s3 << r8 end end end end if s3.last.success? r3 = (SyntaxNode).new(input, i3...index, s3) r3.extend(Primary0) r3.extend(Primary1) else self.index = i3 r3 = ParseFailure.new(input, i3) end if r3.success? r0 = r3 else self.index = i0 r0 = ParseFailure.new(input, i0) end end end node_cache[:primary][start_index] = r0 return r0 end module Variable0 def eval(env={}) env[name] end def name text_value end end def _nt_variable start_index = index cached = node_cache[:variable][index] if cached @index = cached.interval.end return cached end s0, i0 = [], index loop do r1 = parse_char_class(/[a-z]/, 'a-z', SyntaxNode) if r1.success? s0 << r1 else break end end if s0.empty? self.index = i0 r0 = ParseFailure.new(input, i0) else r0 = SyntaxNode.new(input, i0...index, s0) r0.extend(Variable0) end node_cache[:variable][start_index] = r0 return r0 end module Number0 end module Number1 def eval(env={}) text_value.to_i end end def _nt_number start_index = index cached = node_cache[:number][index] if cached @index = cached.interval.end return cached end i0 = index i1, s1 = index, [] r2 = parse_char_class(/[1-9]/, '1-9', SyntaxNode) s1 << r2 if r2.success? s3, i3 = [], index loop do r4 = parse_char_class(/[0-9]/, '0-9', SyntaxNode) if r4.success? s3 << r4 else break end end r3 = SyntaxNode.new(input, i3...index, s3) s1 << r3 end if s1.last.success? r1 = (SyntaxNode).new(input, i1...index, s1) r1.extend(Number0) else self.index = i1 r1 = ParseFailure.new(input, i1) end if r1.success? r0 = r1 r0.extend(Number1) else r5 = parse_terminal('0', SyntaxNode) if r5.success? r0 = r5 r0.extend(Number1) else self.index = i0 r0 = ParseFailure.new(input, i0) end end node_cache[:number][start_index] = r0 return r0 end def _nt_space start_index = index cached = node_cache[:space][index] if cached @index = cached.interval.end return cached end s0, i0 = [], index loop do r1 = parse_terminal(' ', SyntaxNode) if r1.success? s0 << r1 else break end end r0 = SyntaxNode.new(input, i0...index, s0) node_cache[:space][start_index] = r0 return r0 end end class ArithmeticParser < Treetop::Runtime::CompiledParser include Arithmetic end treetop-1.6.3/examples/lambda_calculus/arithmetic_node_classes.rb0000644000004100000410000000037212552221265025370 0ustar www-datawww-datamodule Arithmetic class BinaryOperation < Treetop::Runtime::SyntaxNode def eval(env={}) tail.elements.inject(head.eval(env)) do |value, element| element.operator.apply(value, element.operand.eval(env)) end end end end treetop-1.6.3/examples/numerals.rb0000644000004100000410000001036212552221265017230 0ustar www-datawww-data# Autogenerated from a Treetop grammar. Edits may be lost. module Numerals include Treetop::Runtime def root @root ||= :percentage end module Percentage0 def decimal elements[0] end end module Percentage1 def to_f decimal.to_f / 100 end end def _nt_percentage start_index = index if node_cache[:percentage].has_key?(index) cached = node_cache[:percentage][index] if cached node_cache[:percentage][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_decimal s0 << r1 if r1 if (match_len = has_terminal?("%", false, index)) r2 = true @index += match_len else terminal_parse_failure('"%"') r2 = nil end s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Percentage0) r0.extend(Percentage1) else @index = i0 r0 = nil end node_cache[:percentage][start_index] = r0 r0 end module Decimal0 def sign elements[0] end end module Decimal1 def to_f text_value.to_f end end def _nt_decimal start_index = index if node_cache[:decimal].has_key?(index) cached = node_cache[:decimal][index] if cached node_cache[:decimal][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_sign s0 << r1 if r1 s2, i2 = [], index loop do if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else terminal_parse_failure('[0-9]') r3 = nil end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 if r2 if (match_len = has_terminal?('.', false, index)) r4 = true @index += match_len else terminal_parse_failure('\'.\'') r4 = nil end s0 << r4 if r4 s5, i5 = [], index loop do if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r6 = true @index += 1 else terminal_parse_failure('[0-9]') r6 = nil end if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Decimal0) r0.extend(Decimal1) else @index = i0 r0 = nil end node_cache[:decimal][start_index] = r0 r0 end def _nt_sign start_index = index if node_cache[:sign].has_key?(index) cached = node_cache[:sign][index] if cached node_cache[:sign][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i1 = index if (match_len = has_terminal?('+', false, index)) r2 = true @index += match_len else terminal_parse_failure('\'+\'') r2 = nil end if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else if (match_len = has_terminal?('-', false, index)) r3 = true @index += match_len else terminal_parse_failure('\'-\'') r3 = nil end if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else @index = i1 r1 = nil end end if r1 r0 = r1 else r0 = instantiate_node(SyntaxNode,input, index...index) end node_cache[:sign][start_index] = r0 r0 end end class NumeralsParser < Treetop::Runtime::CompiledParser include Numerals end treetop-1.6.3/doc/0000755000004100000410000000000012552221265014002 5ustar www-datawww-datatreetop-1.6.3/doc/pitfalls_and_advanced_techniques.markdown0000644000004100000410000000577112552221265024275 0ustar www-datawww-data#Pitfalls ##Left Recursion An weakness shared by all recursive descent parsers is the inability to parse left-recursive rules. Consider the following rule: rule left_recursive left_recursive 'a' / 'a' end Logically it should match a list of 'a' characters. But it never consumes anything, because attempting to recognize `left_recursive` begins by attempting to recognize `left_recursive`, and so goes an infinite recursion. There's always a way to eliminate these types of structures from your grammar. There's a mechanistic transformation called _left factorization_ that can eliminate it, but it isn't always pretty, especially in combination with automatically constructed syntax trees. So far, I have found more thoughtful ways around the problem. For instance, in the interpreter example I interpret inherently left-recursive function application right recursively in syntax, then correct the directionality in my semantic interpretation. You may have to be clever. #Advanced Techniques Here are a few interesting problems I've encountered. I figure sharing them may give you insight into how these types of issues are addressed with the tools of parsing expressions. ##Matching a String rule string '"' ('\"' / !'"' .)* '"' end This expression says: Match a quote, then zero or more of, an escaped quote or any character but a quote, followed by a quote. Lookahead assertions are essential for these types of problems. ##Matching Nested Structures With Non-Unique Delimeters Say I want to parse a diabolical wiki syntax in which the following interpretations apply. ** *hello* ** --> hello * **hello** * --> hello rule strong '**' (em / !'*' . / '\*')+ '**' end rule em '*' (strong / !'*' . / '\*')+ '*' end Emphasized text is allowed within strong text by virtue of `em` being the first alternative. Since `em` will only successfully parse if a matching `*` is found, it is permitted, but other than that, no `*` characters are allowed unless they are escaped. ##Matching a Keyword But Not Words Prefixed Therewith Say I want to consider a given string a characters only when it occurs in isolation. Lets use the `end` keyword as an example. We don't want the prefix of `'enders_game'` to be considered a keyword. A naiive implementation might be the following. rule end_keyword 'end' &space end This says that `'end'` must be followed by a space, but this space is not consumed as part of the matching of `keyword`. This works in most cases, but is actually incorrect. What if `end` occurs at the end of the buffer? In that case, it occurs in isolation but will not match the above expression. What we really mean is that `'end'` cannot be followed by a _non-space_ character. rule end_keyword 'end' !(!' ' .) end In general, when the syntax gets tough, it helps to focus on what you really mean. A keyword is a character not followed by another character that isn't a space. treetop-1.6.3/doc/semantic_interpretation.markdown0000644000004100000410000001637512552221265022514 0ustar www-datawww-data#Semantic Interpretation Lets use the below grammar as an example. It describes parentheses wrapping a single character to an arbitrary depth. grammar ParenLanguage rule parenthesized_letter '(' parenthesized_letter ')' / [a-z] end end Matches: * `'a'` * `'(a)'` * `'((a))'` * etc. Output from a parser for this grammar looks like this: ![Tree Returned By ParenLanguageParser](./images/paren_language_output.png) This is a parse tree whose nodes are instances of `Treetop::Runtime::SyntaxNode`. What if we could define methods on these node objects? We would then have an object-oriented program whose structure corresponded to the structure of our language. Treetop provides two techniques for doing just this. ##Associating Methods with Node-Instantiating Expressions Sequences and all types of terminals are node-instantiating expressions. When they match, they create instances of `Treetop::Runtime::SyntaxNode`. Methods can be added to these nodes in the following ways: ###Inline Method Definition Methods can be added to the nodes instantiated by the successful match of an expression grammar ParenLanguage rule parenthesized_letter '(' parenthesized_letter ')' { def depth parenthesized_letter.depth + 1 end } / [a-z] { def depth 0 end } end end Note that each alternative expression is followed by a block containing a method definition. A `depth` method is defined on both expressions. The recursive `depth` method defined in the block following the first expression determines the depth of the nested parentheses and adds one to it. The base case is implemented in the block following the second expression; a single character has a depth of 0. ###Custom `SyntaxNode` Subclass Declarations You can instruct the parser to instantiate a custom subclass of Treetop::Runtime::SyntaxNode for an expression by following it by the name of that class enclosed in angle brackets (`<>`). The above inline method definitions could have been moved out into a single class like so. # in .treetop file grammar ParenLanguage rule parenthesized_letter '(' parenthesized_letter ')' / [a-z] end end # in separate .rb file class ParenNode < Treetop::Runtime::SyntaxNode def depth if nonterminal? parenthesized_letter.depth + 1 else 0 end end end ##Automatic Extension of Results Nonterminal and ordered choice expressions do not instantiate new nodes, but rather pass through nodes that are instantiated by other expressions. They can extend nodes they propagate with anonymous or declared modules, using similar constructs used with expressions that instantiate their own syntax nodes. ###Extending a Propagated Node with an Anonymous Module rule parenthesized_letter ('(' parenthesized_letter ')' / [a-z]) { def depth if nonterminal? parenthesized_letter.depth + 1 else 0 end end } end The parenthesized choice above can result in a node matching either of the two choices. The node will be extended with methods defined in the subsequent block. Note that a choice must always be parenthesized to be associated with a following block, otherwise the block will apply to just the last alternative. ###Extending A Propagated Node with a Declared Module # in .treetop file rule parenthesized_letter ('(' parenthesized_letter ')' / [a-z]) end # in separate .rb file module ParenNode def depth if nonterminal? parenthesized_letter.depth + 1 else 0 end end end Here the result is extended with the `ParenNode` module. Note the previous example for node-instantiating expressions, the constant in the declaration must be a module because the result is extended with it. ##Automatically-Defined Element Accessor Methods ###Default Accessors Nodes instantiated upon the matching of sequences have methods automatically defined for any nonterminals in the sequence. rule abc a b c { def to_s a.to_s + b.to_s + c.to_s end } end In the above code, the `to_s` method calls automatically-defined element accessors for the nodes returned by parsing nonterminals `a`, `b`, and `c`. ###Labels Subexpressions can be given an explicit label to have an element accessor method defined for them. This is useful in cases of ambiguity between two references to the same nonterminal or when you need to access an unnamed subexpression. rule labels first_letter:[a-z] rest_letters:(', ' letter:[a-z])* { def letters [first_letter] + rest_letters.elements.map do |comma_and_letter| comma_and_letter.letter end end } end The above grammar uses label-derived accessors to determine the letters in a comma-delimited list of letters. The labeled expressions _could_ have been extracted to their own rules, but if they aren't used elsewhere, labels still enable them to be referenced by a name within the expression's methods. ###Overriding Element Accessors The module containing automatically defined element accessor methods is an ancestor of the module in which you define your own methods, meaning you can override them with access to the `super` keyword. Here's an example of how this fact can improve the readability of the example above. rule labels first_letter:[a-z] rest_letters:(', ' letter:[a-z])* { def letters [first_letter] + rest_letters end def rest_letters super.elements.map { |comma_and_letter| comma_and_letter.letter } end } end ##Methods Available on `Treetop::Runtime::SyntaxNode`
terminal? Was this node produced by the matching of a terminal symbol?
nonterminal? Was this node produced by the matching of a nonterminal symbol?
text_value The substring of the input represented by this node.
elements Available only on nonterminal nodes, returns the nodes parsed by the elements of the matched sequence.
input The entire input string, which is useful mainly in conjunction with interval
interval The Range of characters in input matched by this rule
empty? returns true if this rule matched no characters of input
inspect Handy-dandy method that returns an indented subtree dump of the syntax tree starting here. This dump includes, for each node, the offset and a snippet of the text this rule matched, and the names of mixin modules and the accessor and extension methods.
treetop-1.6.3/doc/sitegen.rb0000644000004100000410000000251312552221265015766 0ustar www-datawww-dataclass Layout < Erector::Widget class << self def inherited(page_class) puts page_class (@@page_classes ||= []) << page_class end def generate_site FileUtils.mkdir_p(site_dir) @@page_classes.each do |page_class| page_class.generate_html unless page_class.abstract? puts page_class end end def generate_html File.open(absolute_path, 'w') do |file| file.write(new.to_html) end end def absolute_path absolutize(relative_path) end def relative_path "#{name.gsub('::', '_').underscore}.html" end def absolutize(relative_path) File.join(site_dir, relative_path) end def abstract @abstract = true end def abstract? @abstract end def site_dir File.join(File.dirname(__FILE__), "../website") end end def bluecloth(relative_path) File.open(File.join(File.dirname(__FILE__), relative_path)) do |file| rawtext BlueCloth.new(file.read).to_html end end def absolutize(relative_path) self.class.absolutize(relative_path) end def link_to(link_text, page_class, section_class=nil) if instance_of?(page_class) || section_class && is_a?(section_class) text link_text else a link_text, :href => page_class.relative_path end end end treetop-1.6.3/doc/using_in_ruby.markdown0000644000004100000410000001074312552221265020427 0ustar www-datawww-data#Using Treetop Grammars in Ruby ##Using the Command Line Compiler You can compile `.treetop` files into Ruby source code with the `tt` command line script. `tt` takes an list of files with a `.treetop` extension and compiles them into `.rb` files of the same name. You can then `require` these files like any other Ruby script. Alternately, you can supply just one `.treetop` file and a `-o` flag to name specify the name of the output file. Improvements to this compilation script are welcome. tt foo.treetop bar.treetop tt foo.treetop -o foogrammar.rb ##Loading A Grammar Directly The Polyglot gem makes it possible to load `.treetop` or `.tt` files directly with `require`. This will invoke `Treetop.load`, which automatically compiles the grammar to Ruby and then evaluates the Ruby source. If you are getting errors in methods you define on the syntax tree, try using the command line compiler for better stack trace feedback. A better solution to this issue is in the works. In order to use Polyglot dynamic loading of `.treetop` or `.tt` files though, you need to require the Polyglot gem before you require the Treetop gem as Treetop will only create hooks into Polyglot for the treetop files if Polyglot is already loaded. So you need to use: require 'polyglot' require 'treetop' in order to use Polyglot auto loading with Treetop in Ruby. ##Instantiating and Using Parsers If a grammar by the name of `Foo` is defined, the compiled Ruby source will define a `FooParser` class. To parse input, create an instance and call its `parse` method with a string. The parser will return the syntax tree of the match or `nil` if there is a failure. Note that by default, the parser will fail unless *all* input is consumed. Treetop.load "arithmetic" parser = ArithmeticParser.new if parser.parse('1+1') puts 'success' else puts 'failure' end ##Parser Options A Treetop parser has several options you may set. Some are settable permanently by methods on the parser, but all may be passed in as options to the `parse` method. parser = ArithmeticParser.new input = 'x = 2; y = x+3;' # Temporarily override an option: result1 = parser.parse(input, :consume_all_input => false) puts "consumed #{parser.index} characters" parser.consume_all_input = false result1 = parser.parse(input) puts "consumed #{parser.index} characters" # Continue the parse with the next character: result2 = parser.parse(input, :index => parser.index) # Parse, but match rule `variable` instead of the normal root rule: parser.parse(input, :root => :variable) parser.root = :variable # Permanent setting If you have a statement-oriented language, you can save memory by parsing just one statement at a time, and discarding the parse tree after each statement. ##Learning From Failure If a parse fails, it returns nil. In this case, you can ask the parser for an explanation. The failure reasons include the terminal nodes which were tried at the furthermost point the parse reached. parser = ArithmeticParser.new result = parser.parse('4+=3') if !result puts parser.failure_reason puts parser.failure_line puts parser.failure_column end => Expected one of (, - at line 1, column 3 (byte 3) after + 1 3 ##Using Parse Results Please don't try to walk down the syntax tree yourself, and please don't use the tree as your own convenient data structure. It contains many more nodes than your application needs, often even more than one for every character of input. parser = ArithmeticParser.new p parser.parse('2+3') => SyntaxNode+Additive1 offset=0, "2+3" (multitive): SyntaxNode+Multitive1 offset=0, "2" (primary): SyntaxNode+Number0 offset=0, "2": SyntaxNode offset=0, "" SyntaxNode offset=0, "2" SyntaxNode offset=1, "" SyntaxNode offset=1, "" SyntaxNode offset=1, "+3": SyntaxNode+Additive0 offset=1, "+3" (multitive): SyntaxNode offset=1, "+" SyntaxNode+Multitive1 offset=2, "3" (primary): SyntaxNode+Number0 offset=2, "3": SyntaxNode offset=2, "" SyntaxNode offset=2, "3" SyntaxNode offset=3, "" SyntaxNode offset=3, "" Instead, add methods to the root rule which return the information you require in a sensible form. Each rule can call its sub-rules, and this method of walking the syntax tree is much preferable to attempting to walk it from the outside. treetop-1.6.3/doc/index.markdown0000644000004100000410000000617312552221265016664 0ustar www-datawww-data

Treetop is a language for describing languages. Combining the elegance of Ruby with cutting-edge parsing expression grammars, it helps you analyze syntax with revolutionary ease.

sudo gem install treetop #Intuitive Grammar Specifications Parsing expression grammars (PEGs) are simple to write and easy to maintain. They are a simple but powerful generalization of regular expressions that are easier to work with than the LALR or LR-1 grammars of traditional parser generators. There's no need for a tokenization phase, and _lookahead assertions_ can be used for a limited degree of context-sensitivity. Here's an extremely simple Treetop grammar that matches a subset of arithmetic, respecting operator precedence: grammar Arithmetic rule additive multitive ( '+' multitive )* end rule multitive primary ( [*/%] primary )* end rule primary '(' additive ')' / number end rule number '-'? [1-9] [0-9]* end end #Syntax-Oriented Programming Rather than implementing semantic actions that construct parse trees, Treetop lets you define methods on trees that it constructs for you automatically. You can define these methods directly within the grammar... grammar Arithmetic rule additive multitive a:( '+' multitive )* { def value a.elements.inject(multitive.value) { |sum, e| sum+e.multitive.value } end } end # other rules below ... end ...or associate rules with classes of nodes you wish your parsers to instantiate upon matching a rule. grammar Arithmetic rule additive multitive ('+' multitive)* end # other rules below ... end #Reusable, Composable Language Descriptions Because PEGs are closed under composition, Treetop grammars can be treated like Ruby modules. You can mix them into one another and override rules with access to the `super` keyword. You can break large grammars down into coherent units or make your language's syntax modular. This is especially useful if you want other programmers to be able to reuse your work. grammar RubyWithEmbeddedSQL include SQL rule string quote sql_expression quote / super end end #Acknowledgements First, thank you to my employer Rob Mee of Pivotal Labs for funding a substantial portion of Treetop's development. He gets it. I'd also like to thank: * Damon McCormick for several hours of pair programming. * Nick Kallen for lots of well-considered feedback and a few afternoons of programming. * Brian Takita for a night of pair programming. * Eliot Miranda for urging me rewrite as a compiler right away rather than putting it off. * Ryan Davis and Eric Hodel for hurting my code. * Dav Yaginuma for kicking me into action on my idea. * Bryan Ford for his seminal work on Packrat Parsers. * The editors of Lambda the Ultimate, where I discovered parsing expression grammars. treetop-1.6.3/doc/syntactic_recognition.markdown0000644000004100000410000002013012552221265022143 0ustar www-datawww-data#Syntactic Recognition Treetop grammars are written in a custom language based on parsing expression grammars. Literature on the subject of parsing expression grammars (PEGs) is useful in writing Treetop grammars. PEGs have no separate lexical analyser (since the algorithm has the same time-complexity guarantees as the best lexical analysers) so all whitespace and other lexical niceties (like comments) must be explicitly handled in the grammar. A further benefit is that multiple PEG grammars may be seamlessly composed into a single parser. #Grammar Structure Treetop grammars look like this: require "my_stuff" grammar GrammarName include Module::Submodule rule rule_name ... end rule rule_name ... end ... end The main keywords are: * `grammar` : This introduces a new grammar. It is followed by a constant name to which the grammar will be bound when it is loaded. * `include`: This causes the generated parser to include the referenced Ruby module (which may be another parser) * `require`: This must be at the start of the file, and is passed through to the emitted Ruby grammar * `rule` : This defines a parsing rule within the grammar. It is followed by a name by which this rule can be referenced within other rules. It is then followed by a parsing expression defining the rule. A grammar may be surrounded by one or more nested `module` statements, which provides a namespace for the generated Ruby parser. Treetop will emit a module called `GrammarName` and a parser class called `GrammarNameParser` (in the module namespace, if specified). #Parsing Expressions Each rule associates a name with a _parsing expression_. Parsing expressions are a generalization of vanilla regular expressions. Their key feature is the ability to reference other expressions in the grammar by name. Treetop parsers will try to match the first rule defined in the grammar, unless you pass an optional parameter to set a different top rule. ##Terminal Symbols ###Strings Strings are surrounded in double or single quotes and must be matched exactly. * `"foo"` * `'foo'` ###Character Classes Character classes are surrounded by brackets. Their semantics are identical to those used in Ruby's regular expressions. * `[a-zA-Z]` * `[0-9]` ###The Anything Symbol The anything symbol is represented by a dot (`.`) and matches any single character. ###Ellipsis An empty string matches at any position and consumes no input. It's useful when you wish to treat a single symbol as part of a sequence, for example when an alternate rule will be processed using shared code.
    rule alts
      ( foo bar / baz '' )
      {
        def value
          elements.map{|e| e.text_value }
        end
      }
    end
##Nonterminal Symbols Nonterminal symbols are unquoted references to other named rules. They are equivalent to an inline substitution of the named expression. rule foo "the dog " bar end rule bar "jumped" end The above grammar is equivalent to: rule foo "the dog jumped" end ##Ordered Choice Parsers attempt to match ordered choices in left-to-right order, and stop after the first successful match. "foobar" / "foo" / "bar" Note that if `"foo"` in the above expression came first, `"foobar"` would never be matched. Note also that the above rule will match `"bar"` as a prefix of `"barbie"`. Care is required when it's desired to match language keywords exactly. ##Sequences Sequences are a space-separated list of parsing expressions. They have higher precedence than choices, so choices must be parenthesized to be used as the elements of a sequence. "foo" "bar" ("baz" / "bop") ##Zero or More Parsers will greedily match an expression zero or more times if it is followed by the star (`*`) symbol. * `'foo'*` matches the empty string, `"foo"`, `"foofoo"`, etc. ##One or More Parsers will greedily match an expression one or more times if it is followed by the plus (`+`) symbol. * `'foo'+` does not match the empty string, but matches `"foo"`, `"foofoo"`, etc. ##Optional Expressions An expression can be declared optional by following it with a question mark (`?`). * `'foo'?` matches `"foo"` or the empty string. ##Repetition count A generalised repetition count (minimum, maximum) is also available. * `'foo' 2..` matches `'foo'` two or more times * `'foo' 3..5` matches `'foo'` from three to five times * `'foo' ..4` matches `'foo'` from zero to four times ##Lookahead Assertions Lookahead assertions can be used to make parsing expressions context-sensitive. The parser will look ahead into the buffer and attempt to match an expression without consuming input. ###Positive Lookahead Assertion Preceding an expression with an ampersand `(&)` indicates that it must match, but no input will be consumed in the process of determining whether this is true. * `"foo" &"bar"` matches `"foobar"` but only consumes up to the end `"foo"`. It will not match `"foobaz"`. ###Negative Lookahead Assertion Preceding an expression with a bang `(!)` indicates that the expression must not match, but no input will be consumed in the process of determining whether this is true. * `"foo" !"bar"` matches `"foobaz"` but only consumes up to the end `"foo"`. It will not match `"foobar"`. Note that a lookahead assertion may be used on any rule, not just a string terminal. rule things thing (!(disallowed / ',') following)* end Here's a common use case: rule word [a-zA-Z]+ end rule conjunction primitive ('and' ' '+ primitive)* end rule primitive (!'and' word ' '+)* end Here's the easiest way to handle C-style comments: rule c_comment '/*' ( !'*/' (. / "\n") )* '*/' end ##Semantic predicates (positive and negative) Sometimes you must execute Ruby code during parsing in order to decide how to proceed. This is an advanced feature, and must be used with great care, because it can change the way a Treetop parser backtracks in a way that breaks the parsing algorithm. See the notes below on how to use this feature safely. The code block is the body of a Ruby lambda block, and should return true or false, to cause this parse rule to continue or fail (for positive sempreds), fail or continue (for negative sempreds). * `&{ ... }` Evaluate the block and fail this rule if the result is false or nil * `!{ ... }` Evaluate the block and fail this rule if the result is not false or nil The lambda is passed a single argument which is the array of syntax nodes matched so far in the current sequence. Note that because the current rule has not yet succeeded, no syntax node has yet been constructed, and so the lambda block is being run in a context where the `names` of the preceding rules (or as assigned by labels) are not available to access the sub-rules. rule id [a-zA-Z][a-zA-Z0-9]* { def is_reserved ReservedSymbols.include? text_value end } end rule foo_rule foo id &{|seq| seq[1].is_reserved } baz end Match "foo id baz" only if `id.is_reserved`. Note that `id` cannot be referenced by name from `foo_rule`, since that rule has not yet succeeded, but `id` has completed and so its added methods are available. rule test_it foo bar &{|s| debugger; true } baz end Match `foo` then `bar`, stop to enter the debugger (make sure you have said `require "ruby-debug"` somewhere), then continue by trying to match `baz`. Treetop, like other PEG parsers, achieves its performance guarantee by remembering which rules it has tried at which locations in the input, and what the result was. This process, called memoization, requires that the rule would produce the same result (if run again) as it produced the first time when the result was remembered. If you violate this principle in your semantic predicates, be prepared to fight Cerberus before you're allowed out of Hades again. There's an example of how to use semantic predicates to parse a language with white-space indented blocks in the examples directory. treetop-1.6.3/doc/site.rb0000644000004100000410000000444412552221265015301 0ustar www-datawww-datarequire 'rubygems' require 'erector' require "#{File.dirname(__FILE__)}/sitegen" require 'fileutils' require 'bluecloth' class Layout < Erector::Widget def content html do head do link :rel => "stylesheet", :type => "text/css", :href => "./screen.css" rawtext %( ) end body do div :id => 'top' do div :id => 'main_navigation' do main_navigation end end div :id => 'middle' do div :id => 'main_content' do main_content end end div :id => 'bottom' do end end end end def main_navigation ul do li { link_to "Documentation", SyntacticRecognition, Documentation } li { link_to "Contribute", Contribute } li { link_to "Home", Index } end end def main_content end end class Index < Layout def main_content bluecloth "index.markdown" end end class Documentation < Layout abstract def main_content div :id => 'secondary_navigation' do ul do li { link_to 'Syntax', SyntacticRecognition } li { link_to 'Semantics', SemanticInterpretation } li { link_to 'Using In Ruby', UsingInRuby } li { link_to 'Advanced Techniques', PitfallsAndAdvancedTechniques } end end div :id => 'documentation_content' do documentation_content end end end class SyntacticRecognition < Documentation def documentation_content bluecloth "syntactic_recognition.markdown" end end class SemanticInterpretation < Documentation def documentation_content bluecloth "semantic_interpretation.markdown" end end class UsingInRuby < Documentation def documentation_content bluecloth "using_in_ruby.markdown" end end class PitfallsAndAdvancedTechniques < Documentation def documentation_content bluecloth "pitfalls_and_advanced_techniques.markdown" end end class Contribute < Layout def main_content bluecloth "contributing_and_planned_features.markdown" end end Layout.generate_sitetreetop-1.6.3/doc/tt.10000644000004100000410000000461312552221265014517 0ustar www-datawww-data.\" treetop - Bringing the simplicity of Ruby to syntactic analysis .\" .\" Copyright (c) 2007 Nathan Sobo. .\" .\" Permission is hereby granted, free of charge, to any person obtaining a copy .\" of this software and associated documentation files (the "Software"), to deal .\" in the Software without restriction, including without limitation the rights .\" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell .\" copies of the Software, and to permit persons to whom the Software is .\" furnished to do so, subject to the following conditions: .\" .\" The above copyright notice and this permission notice shall be included in .\" all copies or substantial portions of the Software. .\" .\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR .\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, .\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE .\" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER .\" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, .\" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN .\" THE SOFTWARE. .TH tt 1 2013-06-19 Treetop "Treetop v1.4.14" .SH NAME tt \- Compile a treetop grammar file to ruby source code .SH SYNOPSIS .B tt .RI [ options "] " grammar_file "[.treetop|.tt] ..." .SH DESCRIPTION The .B tt program is a command-line script to compile .treetop files into Ruby source code. The .B tt program takes a list of files with a .treetop extension and compiles them into .rb files of the same name. You can then require these files like any other Ruby script. Alternately, you can supply just one .treetop file and a \-o flag to specify the name of the output file. Note: while treetop grammar files .B must have a supported filename extensions, (.treetop or .tt), the extension name is not required when calling the compiler with grammar file names. .SH OPTIONS .TP 4 .BI "\-o, \-\-output" " FILENAME" Write parser source to .I FILENAME. .TP 4 .B \-f, \-\-force Overwrite existing output file(s) .TP 4 .B \-v, \-\-version Show Treetop version .TP 4 .B \-h, \-\-help .SH EXAMPLES .TP 4 1 grammar -> 1 parser source tt foo.tt .TP 4 2 grammars -> 2 separate parsers tt foo bar.treetop .TP 4 Alternately named output file tt \-o alterate_name.rb foo .SH SEE ALSO The treetop website: .B http://cjheath.github.io/treetop/ treetop-1.6.3/doc/contributing_and_planned_features.markdown0000644000004100000410000001306712552221265024505 0ustar www-datawww-data#Google Group I've created a Google Group as a better place to organize discussion and development. treetop-dev@google-groups.com #Contributing Visit the Treetop repository page on GitHub in your browser for more information about checking out the source code. I like to try Rubinius's policy regarding commit rights. If you submit one patch worth integrating, I'll give you commit rights. We'll see how this goes, but I think it's a good policy. ##Getting Started with the Code Treetop compiler is interesting in that it is implemented in itself. Its functionality revolves around `metagrammar.treetop`, which specifies the grammar for Treetop grammars. I took a hybrid approach with regard to definition of methods on syntax nodes in the metagrammar. Methods that are more syntactic in nature, like those that provide access to elements of the syntax tree, are often defined inline, directly in the grammar. More semantic methods are defined in custom node classes. Iterating on the metagrammar is tricky. The current testing strategy uses the last stable version of Treetop to parse the version under test. Then the version under test is used to parse and functionally test the various pieces of syntax it should recognize and translate to Ruby. As you change `metagrammar.treetop` and its associated node classes, note that the node classes you are changing are also used to support the previous stable version of the metagrammar, so must be kept backward compatible until such time as a new stable version can be produced to replace it. ##Tests Most of the compiler's tests are functional in nature. The grammar under test is used to parse and compile piece of sample code. Then I attempt to parse input with the compiled output and test its results. #What Needs to be Done ##Small Stuff * Improve the `tt` command line tool to allow `.treetop` extensions to be elided in its arguments. * Generate and load temp files with `Treetop.load` rather than evaluating strings to improve stack trace readability. * Allow `do/end` style blocks as well as curly brace blocks. This was originally omitted because I thought it would be confusing. It probably isn't. ##Big Stuff ####Transient Expressions Currently, every parsing expression instantiates a syntax node. This includes even very simple parsing expressions, like single characters. It is probably unnecessary for every single expression in the parse to correspond to its own syntax node, so much savings could be garnered from a transient declaration that instructs the parser only to attempt a match without instantiating nodes. ###Generate Rule Implementations in C Parsing expressions are currently compiled into simple Ruby source code that comprises the body of parsing rules, which are translated into Ruby methods. The generator could produce C instead of Ruby in the body of these method implementations. ###Global Parsing State and Semantic Backtrack Triggering Some programming language grammars are not entirely context-free, requiring that global state dictate the behavior of the parser in certain circumstances. Treetop does not currently expose explicit parser control to the grammar writer, and instead automatically constructs the syntax tree for them. A means of semantic parser control compatible with this approach would involve callback methods defined on parsing nodes. Each time a node is successfully parsed it will be given an opportunity to set global state and optionally trigger a parse failure on _extrasyntactic_ grounds. Nodes will probably need to define an additional method that undoes their changes to global state when there is a parse failure and they are backtracked. Here is a sketch of the potential utility of such mechanisms. Consider the structure of YAML, which uses indentation to indicate block structure. level_1: level_2a: level_2b: level_3a: level_2c: Imagine a grammar like the following: rule yaml_element name ':' block / name ':' value end rule block indent yaml_elements outdent end rule yaml_elements yaml_element (samedent yaml_element)* end rule samedent newline spaces { def after_success(parser_state) spaces.length == parser_state.indent_level end } end rule indent newline spaces { def after_success(parser_state) if spaces.length == parser_state.indent_level + 2 parser_state.indent_level += 2 true else false # fail the parse on extrasyntactic grounds end end def undo_success(parser_state) parser_state.indent_level -= 2 end } end rule outdent newline spaces { def after_success(parser_state) if spaces.length == parser_state.indent_level - 2 parser_state.indent_level -= 2 true else false # fail the parse on extrasyntactic grounds end end def undo_success(parser_state) parser_state.indent_level += 2 end } end In this case a block will be detected only if a change in indentation warrants it. Note that this change in the state of indentation must be undone if a subsequent failure causes this node not to ultimately be incorporated into a successful result. I am by no means sure that the above sketch is free of problems, or even that this overall strategy is sound, but it seems like a promising path. treetop-1.6.3/doc/grammar_composition.markdown0000644000004100000410000000435212552221265021623 0ustar www-datawww-data#Grammar Composition A unique property of parsing expression grammars is that they are _closed under composition_. This means that when you compose two grammars they yield another grammar that can be composed yet again. This is a radical departure from parsing frameworks require on lexical scanning, which makes compositionally impossible. Treetop's facilities for composition are built upon those of Ruby. ##The Mapping of Treetop Constructs to Ruby Constructs When Treetop compiles a grammar definition, it produces a module and a class. The module contains methods implementing all of the rules defined in the grammar. The generated class is a subclass of Treetop::Runtime::CompiledParser and includes the module. For example: grammar Foo ... end results in a Ruby module named `Foo` and a Ruby class named `FooParser` that `include`s the `Foo` module. ##Using Mixin Semantics to Compose Grammars Because grammars are just modules, they can be mixed into one another. This enables grammars to share rules. grammar A rule a 'a' end end grammar B include A rule ab a 'b' end end Grammar `B` above references rule `a` defined in a separate grammar that it includes. Because module inclusion places modules in the ancestor chain, rules may also be overridden with the use of the `super` keyword accessing the overridden rule. grammar A rule a 'a' end end grammar B include A rule a super / 'b' end end Now rule `a` in grammar `B` matches either `'a'` or `'b'`. ##Motivation Imagine a grammar for Ruby that took account of SQL queries embedded in strings within the language. That could be achieved by combining two existing grammars. grammar RubyPlusSQL include Ruby include SQL rule expression ruby_expression end rule ruby_string ruby_quote sql_expression ruby_quote / ruby_string end end ##Work to be Done It has become clear that the include facility in grammars would be more useful if it had the ability to name prefix all rules from the included grammar to avoid collision. This is a planned but currently unimplemented feature.treetop-1.6.3/spec/0000755000004100000410000000000012552221265014167 5ustar www-datawww-datatreetop-1.6.3/spec/compiler/0000755000004100000410000000000012552221265016001 5ustar www-datawww-datatreetop-1.6.3/spec/compiler/not_predicate_spec.rb0000644000004100000410000000254012552221265022161 0ustar www-datawww-datarequire 'spec_helper' module NotPredicateSpec describe "A !-predicated terminal symbol" do testing_expression '!"foo"' it "fails to parse input matching the terminal symbol" do parse('foo') do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end describe "A !-predicated character class symbol" do testing_expression '![aeiou]' it "fails to parse input matching the terminal symbol" do parse('e') do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end describe "A sequence of a terminal and an and another !-predicated terminal" do testing_expression '"foo" !"bar"' it "fails to match input matching both terminals" do parse('foobar').should be_nil end it "successfully parses input matching the first terminal and not the second, reporting the parse failure of the second terminal" do parse('foo') do |result| result.should_not be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 0 end end end describe "A !-predicated sequence" do testing_expression '!("a" "b" "cc")' it "fails to parse matching input" do parse('abcc') do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end end treetop-1.6.3/spec/compiler/and_predicate_spec.rb0000644000004100000410000000221612552221265022123 0ustar www-datawww-datarequire 'spec_helper' module AndPredicateSpec describe "An &-predicated terminal symbol" do testing_expression '&"foo"' it "successfully parses input matching the terminal symbol, returning an epsilon syntax node" do parse('foo', :consume_all_input => false) do |result| result.should_not be_nil result.interval.should == (0...0) end end end describe "A sequence of a terminal and an and another &-predicated terminal" do testing_expression '"foo" &"bar"' it "matches input matching both terminals, but only consumes the first" do parse('foobar', :consume_all_input => false) do |result| result.should_not be_nil result.text_value.should == 'foo' end end it "fails to parse input matching only the first terminal, with a terminal failure recorded at index 3" do parse('foo') do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures[0] failure.index.should == 3 failure.expected_string.should == '"bar"' end end end end treetop-1.6.3/spec/compiler/optional_spec.rb0000644000004100000410000000213612552221265021167 0ustar www-datawww-datarequire 'spec_helper' module OptionalSpec describe "An optional terminal symbol" do testing_expression '"foo"?' it "parses input matching the terminal" do parse('foo').should_not be_nil end it "parses epsilon, recording a failure" do parse('') do |result| result.should_not be_nil result.interval.should == (0...0) terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 0 failure.expected_string.should == '"foo"' end end it "parses input not matching the terminal, returning an epsilon result and recording a failure" do parse('bar', :consume_all_input => false) do |result| result.should_not be_nil result.interval.should == (0...0) terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 0 failure.expected_string.should == '"foo"' end end end end treetop-1.6.3/spec/compiler/test_grammar_do.treetop0000644000004100000410000000011712552221265022553 0ustar www-datawww-datamodule Test grammar Grammar do rule foo do 'foo' end end end treetop-1.6.3/spec/compiler/grammar_compiler_spec.rb0000644000004100000410000001104112552221265022655 0ustar www-datawww-datarequire 'spec_helper' require 'tmpdir' describe Compiler::GrammarCompiler do attr_reader :compiler, :source_path_with_treetop_extension, :source_path_with_tt_extension, :target_path, :alternate_target_path before do @compiler = Compiler::GrammarCompiler.new dir = File.dirname(__FILE__) @tmpdir = Dir.tmpdir @source_path_with_treetop_extension = "#{dir}/test_grammar.treetop" @source_path_with_do = "#{dir}/test_grammar_do.treetop" @source_path_with_tt_extension = "#{dir}/test_grammar.tt" @source_path_with_magic_coding = "#{dir}/test_grammar_magic_coding.treetop" @source_path_with_magic_encoding = "#{dir}/test_grammar_magic_encoding.treetop" @target_path = "#{@tmpdir}/test_grammar.rb" @target_path_with_do = "#{@tmpdir}/test_grammar_do.rb" @target_path_with_magic_coding = "#{@tmpdir}/test_grammar_magic_coding.rb" @target_path_with_magic_encoding = "#{@tmpdir}/test_grammar_magic_encoding.rb" @alternate_target_path = "#{@tmpdir}/test_grammar_alt.rb" delete_target_files end after do delete_target_files Object.class_eval do remove_const(:Test) if const_defined?(:Test) end end specify "compilation of a single file to a default file name" do src_copy = "#{@tmpdir}/test_grammar.treetop" File.open(source_path_with_treetop_extension) { |f| File.open(src_copy,'w'){|o|o.write(f.read)} } File.exists?(target_path).should be_falsey compiler.compile(src_copy) File.exists?(target_path).should be_truthy require target_path Test::GrammarParser.new.parse('foo').should_not be_nil end specify "compilation of a single file to an explicit file name" do File.exists?(alternate_target_path).should be_falsy compiler.compile(source_path_with_treetop_extension, alternate_target_path) File.exists?(alternate_target_path).should be_truthy require alternate_target_path Test::GrammarParser.new.parse('foo').should_not be_nil end specify "compilation of a single file without writing it to an output file" do compiler.ruby_source(source_path_with_treetop_extension).should_not be_nil end specify "ruby_source_from_string compiles a grammar stored in string" do compiler.ruby_source_from_string(File.read(source_path_with_treetop_extension)).should_not be_nil end specify "Treetop.load_from_string compiles and evaluates a source grammar stored in string" do Treetop.load_from_string File.read(source_path_with_treetop_extension) Test::GrammarParser.new.parse('foo').should_not be_nil end specify "Treetop.load compiles and evaluates a source grammar with a .treetop extension" do Treetop.load source_path_with_treetop_extension Test::GrammarParser.new.parse('foo').should_not be_nil end specify "Treetop.load compiles and evaluates a source grammar with a .tt extension" do path_without_extension = source_path_with_tt_extension Treetop.load path_without_extension Test::GrammarParser.new.parse('foo').should_not be_nil end specify "Treetop.load compiles and evaluates source grammar with no extension" do path_without_extension = source_path_with_treetop_extension.gsub(/\.treetop\Z/, '') Treetop.load path_without_extension Test::GrammarParser.new.parse('foo').should_not be_nil end specify "grammars with 'do' compile" do src_copy = "#{@tmpdir}/test_grammar_do.treetop" File.open(@source_path_with_do) { |f| File.open(src_copy,'w'){|o|o.write(f.read)} } compiler.compile(src_copy) require @target_path_with_do Test::GrammarParser.new.parse('foo').should_not be_nil end specify "grammars with magic 'encoding' comments keep those comments at the top" do src_copy = "#{@tmpdir}/test_grammar_magic_encoding.treetop" File.open(@source_path_with_magic_encoding) do |f| File.open(src_copy,'w'){|o|o.write(f.read)} end compiler.compile(src_copy) File.open(@target_path_with_magic_encoding).readline.should == "# encoding: UTF-8\n" end specify "grammars with magic 'coding' comments keep those comments at the top" do src_copy = "#{@tmpdir}/test_grammar_magic_coding.treetop" File.open(@source_path_with_magic_coding) do |f| File.open(src_copy,'w'){|o|o.write(f.read)} end compiler.compile(src_copy) File.open(@target_path_with_magic_coding).readline.should == "# coding: UTF-8\n" end def delete_target_files File.delete(target_path) if File.exists?(target_path) File.delete(@target_path_with_do) if File.exists?(@target_path_with_do) File.delete(alternate_target_path) if File.exists?(alternate_target_path) end end treetop-1.6.3/spec/compiler/failure_propagation_functional_spec.rb0000644000004100000410000000127212552221265025616 0ustar www-datawww-datarequire 'spec_helper' describe "An expression for braces surrounding zero or more letters followed by semicolons" do testing_expression "'{' ([a-z] ';')* '}'" it "parses matching input successfully" do parse('{a;b;c;}').should_not be_nil end it "fails to parse input with an expression that is missing a semicolon, reporting the terminal failure occurring at the maximum index" do parse('{a;b;c}') do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures[0] failure.index.should == 6 failure.expected_string.should == "';'" end end end treetop-1.6.3/spec/compiler/test_grammar.treetop0000644000004100000410000000011012552221265022062 0ustar www-datawww-datamodule Test grammar Grammar rule foo 'foo' end end endtreetop-1.6.3/spec/compiler/anything_symbol_spec.rb0000644000004100000410000000303612552221265022550 0ustar www-datawww-datarequire 'spec_helper' module AnythingSymbolSpec class Foo < Treetop::Runtime::SyntaxNode end describe "an anything symbol followed by a node class declaration and a block" do testing_expression '. { def a_method; end }' it "matches any single character in a big range, returning an instance of the declared node class that responds to methods defined in the inline module" do (33..127).each do |digit| parse(digit.chr) do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.interval.should == (0...1) end end end it "fails to parse epsilon" do parse('') do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end module ModFoo end describe "an anything symbol followed by a module declaration and a block" do testing_expression '. { def a_method; end }' it "matches any single character in a big range, returning an instance of SyntaxNode extended by the declared module that responds to methods defined in the inline module" do (33..127).each do |digit| parse(digit.chr) do |result| result.should_not be_nil result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result.interval.should == (0...1) end end end end end treetop-1.6.3/spec/compiler/tt_compiler_spec.rb0000644000004100000410000001707212552221265021670 0ustar www-datawww-datarequire 'digest/sha1' require 'tmpdir' # ensure the Kernel.system and Kernel.open's always use the correct tt and # Treetop library versions, not a previously installed gem ENV['PATH'] = File.expand_path(File.dirname(__FILE__) + '../../../bin' + File::PATH_SEPARATOR + ENV['PATH']) $LOAD_PATH.unshift(File.expand_path('../../../../lib', __FILE__)) describe "The 'tt' comand line compiler" do before(:each) do @tmpdir = Dir.tmpdir end context 'when processing a single grammar file' do before(:each) do # create a fresh but dumb grammar file for each example @test_base = "dumb-#{rand(1000)}" @test_path = "#{@tmpdir}/#{@test_base}" @test_grammar = "#{@test_path}.tt" @test_ruby = "#{@test_path}.rb" File.open(@test_grammar, 'w+') do |f| f.print("# Encoding: UTF-8\n") f.print("grammar Dumb\n") f.print("end\n") end unless File.exists?(@test_grammar) end after(:each) do # cleanup test grammar and parser output files File.delete(@test_grammar) if File.exists?(@test_grammar) File.delete(@test_ruby) if File.exists?(@test_ruby) end it 'can compile a grammar file' do # puts %q{emulate 'tt dumb.tt'} system("ruby -S tt #{@test_grammar}").should be_truthy File.exists?(@test_ruby).should be_truthy File.zero?(@test_ruby).should_not be_truthy end it 'can compile a relative pathed grammar file' do dir = File.basename(File.expand_path(File.dirname(@test_grammar))) # puts %q{emulate 'tt "..//dumb.tt"'} system("cd #{@tmpdir}/..; ruby -S tt \"./#{dir}/#{@test_base}.tt\"").should be_truthy File.exists?(@test_ruby).should be_truthy File.zero?(@test_ruby).should_not be_truthy end it 'can compile an absolute pathed grammar file' do # puts %q{emulate 'tt "/path/to/dumb.tt"'} system("ruby -S tt \"#{File.expand_path(@test_grammar)}\"").should be_truthy File.exists?(@test_ruby).should be_truthy File.zero?(@test_ruby).should_not be_truthy end it 'can compile without explicit file extensions' do # puts %q{emulate 'tt dumb'} system("ruby -S tt #{@test_path}").should be_truthy File.exists?(@test_ruby).should be_truthy File.zero?(@test_ruby).should_not be_truthy end it 'skips nonexistent grammar file without failing or creating bogus output' do # puts %q{emulate 'tt dumb.bad'} Kernel.open("|ruby -S tt #{@test_base}.bad") do |io| (io.read =~ /ERROR.*?not exist.*?continuing/).should_not be_nil end File.exists?("#{@test_base}.rb").should be_falsy end it 'can compile to a specified parser source file' do # puts %q{emulate 'tt -o my_dumb_test_parser.rb dumb'} pf = "#{@tmpdir}/my_dumb_test_parser.rb" begin system("ruby -S tt -o #{pf} #{@test_path}").should be_truthy File.exists?(pf).should be_truthy File.zero?(pf).should_not be_truthy ensure File.delete(pf) if File.exists?(pf) end end it 'by default, does not overwrite an existing file without an autogenerated header' do # puts %q{emulate 'tt -o must_save_parser.rb dumb'} pf = "#{@tmpdir}/must_save_parser.rb" begin system("ruby -S tt -o #{pf} #{@test_path}").should be_truthy File.exists?(pf).should be_truthy File.zero?(pf).should_not be_truthy # Check that the magic comment is preserved: written = File.open(pf, "r") { |f| s = f.read } written.should =~ /\A# Encoding: UTF-8/ # Modify the file's auto-generated comment and make sure it doesn't get overwritten: written.sub!(/generated/, 'broken'); File.open(pf, "w") { |f| f.write(written) } # File.open(pf, "r+") { |f| s = f.read; s.sub!(/generated/, 'broken'); f.rewind; f.write(s) } orig_file_hash = Digest::SHA1.hexdigest(File.read(pf)) Kernel.open("|ruby -S tt -o #{pf} #{@test_path}") do |io| (io.read =~ /ERROR.*?already exists.*?skipping/).should_not be_nil end Digest::SHA1.hexdigest(File.read(pf)).should == orig_file_hash ensure File.delete(pf) if File.exists?(pf) end end it 'by default, overwrites a changed file with an intact autogenerated header' do # puts %q{emulate 'tt -o must_save_parser.rb dumb'} pf = "#{@tmpdir}/must_save_parser.rb" begin system("ruby -S tt -o #{pf} #{@test_path}").should be_truthy File.exists?(pf).should be_truthy File.zero?(pf).should_not be_truthy orig_file_hash = Digest::SHA1.hexdigest(File.read(pf)) # Modify the file and make sure it gets reverted: File.open(pf, "r+") { |f| f.gets; f.write("#") } system("ruby -S tt -o #{pf} #{@test_path}").should be_truthy Digest::SHA1.hexdigest(File.read(pf)).should == orig_file_hash ensure File.delete(pf) if File.exists?(pf) end end it 'can be forced to overwrite existing file #{@test_path}' do pf = "#{@test_path}.rb" system("echo some junk >#{pf}").should be_truthy File.exists?(pf).should be_truthy File.zero?(pf).should_not be_truthy orig_file_hash = Digest::SHA1.hexdigest(File.read(pf)) system("ruby -S tt -f #{@test_path}").should be_truthy Digest::SHA1.hexdigest(File.read(pf)).should_not == orig_file_hash end end context 'when processing multiple grammar files' do before(:each) do # provide fresh but dumb grammar files for each test @test_bases = [] @test_grammars = [] %w[dumb1 dumb2].each do |e| base = "#{@tmpdir}/#{e}-#{rand(1000)}" grammar_file = "#{base}.tt" @test_bases << base @test_grammars << grammar_file File.open(grammar_file, 'w+') do |f| f.print("grammar #{e.capitalize}\n") f.print("end\n") end unless File.exists?(grammar_file) end end after(:each) do # cleanup test grammar and output parser files @test_grammars.each { |f| File.delete(f) if File.exists?(f) } @test_bases.each { |f| File.delete("#{f}.rb") if File.exists?("#{f}.rb") } end it 'can compile them in one invocation' do # puts %q{emulate 'tt dumb1.tt dumb2.tt'} system("ruby -S tt #{@test_grammars.join(' ')}").should be_truthy @test_bases.each do |f| pf = "#{f}.rb" File.exists?(pf).should be_truthy File.zero?(pf).should_not be_truthy end end it 'can compile them without explicit file extenstions' do # puts %q{emulate 'tt dumb1 dumb2'} system("ruby -S tt #{@test_bases.join(' ')}").should be_truthy @test_bases.each do |f| pf = "#{f}.rb" File.exists?(pf).should be_truthy File.zero?(pf).should_not be_truthy end end it 'can skip nonexistent and invalid extension named grammar files' do # puts %q{emulate 'tt not_here bad_ext.ttg dumb1 dumb2'} system("ruby -S tt not_here bad_ext.ttg #{@test_bases.join(' ')} >/dev/null 2>&1").should be_truthy File.exists?('not_here.rb').should_not be_truthy File.exists?('bad_ext.rb').should_not be_truthy @test_bases.each do |f| pf = "#{f}.rb" File.exists?(pf).should be_truthy File.zero?(pf).should_not be_truthy end end it 'can not specify an output file' do # puts %q{emulate 'tt -o my_bogus_test_parser.rb dumb1 dumb2'} pf = 'my_bogus_test_parser.rb' system("ruby -S tt -o #{pf} #{@test_bases.join(' ')} >/dev/null 2>&1").should be_falsy File.exists?(pf).should be_falsy end end end treetop-1.6.3/spec/compiler/occurrence_range_spec.rb0000644000004100000410000001437312552221265022654 0ustar www-datawww-datarequire 'spec_helper' module OccurrenceRangeSpec class Foo < Treetop::Runtime::SyntaxNode end describe "zero to two of a terminal symbol followed by a node class declaration and a block" do testing_expression '"foo"..2 { def a_method; end }' it "successfully parses epsilon, reporting a failure" do parse('') do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 0 end end it "successfully parses epsilon, returning an instance declared node class and recording a terminal failure" do parse('') do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 0 end end it "successfully parses one of that terminal, returning an instance of the declared node class and recording a terminal failure" do parse("foo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 0 end end it "successfully parses two of that terminal, returning an instance of the declared node class and reporting no failure" do parse("foofoo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 0 end end it "fails to parses two of that terminal but fails because of an extra one" do parse("foofoofoo") do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end it "parses two of three of that terminal, reporting no failure" do parse("foofoofoo", :consume_all_input => false) do |result| result.should_not be_nil result.elements.size.should == 2 parser.terminal_failures.size.should == 0 end end end describe "two to four of a terminal symbol followed by a node class declaration and a block" do testing_expression '"foo" 2..4 { def a_method; end }' it "fails to parse epsilon, reporting a failure" do parse('') do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 0 failure.expected_string.should == '"foo"' end end it "fails to parse one of that terminal, returning an instance of the declared node class and recording a terminal failure" do parse("foo") do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 3 failure.expected_string.should == '"foo"' end end it "successfully parses two of that terminal, returning an instance of the declared node class and reporting no failure" do parse("foofoo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 0 end end it "successfully parses four of that terminal, returning an instance of the declared node class and reporting no failure" do parse("foofoofoofoo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 0 end end it "fails to parses four of that terminal because there's an extra unconsumed one" do parse("foofoofoofoofoo") do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 end end end describe "two to any number of a terminal symbol followed by a node class declaration and a block" do testing_expression '"foo" 2.. { def a_method; end }' it "fails to parse epsilon, reporting a failure" do parse('') do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 0 failure.expected_string.should == '"foo"' end end it "fails to parse one of that terminal, returning an instance of the declared node class and recording a terminal failure" do parse("foo") do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 3 failure.expected_string.should == '"foo"' end end it "successfully parses two of that terminal, returning an instance of the declared node class and reporting no failure" do parse("foofoo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 6 failure.expected_string.should == '"foo"' end end it "successfully parses four of that terminal, returning an instance of the declared node class and reporting a failure on the fifth" do parse("foofoofoofoo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 12 failure.expected_string.should == '"foo"' end end end end treetop-1.6.3/spec/compiler/nonterminal_symbol_spec.rb0000644000004100000410000000176012552221265023257 0ustar www-datawww-datarequire 'spec_helper' module NonterminalSymbolSpec describe "A nonterminal symbol followed by a block" do testing_expression 'foo { def a_method; end }' parser_class_under_test.class_eval do def _nt_foo '_nt_foo called' end end it "compiles to a method call, extending its results with the anonymous module for the block" do result = parse('') result.should == '_nt_foo called' result.should respond_to(:a_method) end end module TestModule def a_method end end describe "a non-terminal followed by a module declaration" do testing_expression 'foo ' parser_class_under_test.class_eval do def _nt_foo '_nt_foo called' end end it "compiles to a method call, extending its results with the anonymous module for the block" do result = parse('') result.should == '_nt_foo called' result.should respond_to(:a_method) end end end treetop-1.6.3/spec/compiler/terminal_symbol_spec.rb0000644000004100000410000000251712552221265022545 0ustar www-datawww-datarequire 'spec_helper' module TerminalSymbolSpec class Foo < Treetop::Runtime::SyntaxNode end describe "a terminal symbol followed by a node class declaration and a block" do testing_expression "'foo' { def a_method; end }" it "correctly parses matching input prefixes at various indices, returning an instance of the declared class that can respond to methods defined in the inline module" do parse "foo", :index => 0 do |result| result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.interval.should == (0...3) result.text_value.should == 'foo' end parse "xfoo", :index => 1 do |result| result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.interval.should == (1...4) result.text_value.should == 'foo' end parse "---foo", :index => 3 do |result| result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.interval.should == (3...6) result.text_value.should == 'foo' end end it "fails to parse nonmatching input at the index even if a match occurs later" do parse(" foo", :index => 0) do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end end treetop-1.6.3/spec/compiler/test_grammar_magic_encoding.treetop0000644000004100000410000000014112552221265025074 0ustar www-datawww-data# encoding: UTF-8 module Test grammar Grammar do rule foo do 'foo' end end end treetop-1.6.3/spec/compiler/terminal_spec.rb0000644000004100000410000001276012552221265021161 0ustar www-datawww-datarequire 'spec_helper' module TerminalSymbolSpec class Foo < Treetop::Runtime::SyntaxNode end describe "a terminal symbol" do testing_expression "'Foo'" it "matches the input string" do parse "Foo", :index => 0 do |result| result.should_not be_nil result.interval.should == (0...3) result.text_value.should == 'Foo' end end it "fails to match the input string other than at the start" do parse " Foo", :index => 0 do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end it "fails to match the input string in the wrong case" do parse "foo", :index => 0 do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end describe "a terminal symbol with case-insensitive matching" do testing_expression "'Foo'i" it "matches the input string in the same case" do parse "Foo", :index => 0 do |result| result.should_not be_nil result.interval.should == (0...3) result.text_value.should == 'Foo' end end it "matches the input string in varied case" do parse "foO", :index => 0 do |result| result.should_not be_nil result.interval.should == (0...3) result.text_value.should == 'foO' end end end describe "a terminal symbol followed by a node class declaration and a block" do testing_expression "'foo' { def a_method; end }" it "correctly parses matching input prefixes at various indices, returning an instance of the declared class that can respond to methods defined in the inline module" do parse "foo", :index => 0 do |result| result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.interval.should == (0...3) result.text_value.should == 'foo' end parse "xfoo", :index => 1 do |result| result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.interval.should == (1...4) result.text_value.should == 'foo' end parse "---foo", :index => 3 do |result| result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.interval.should == (3...6) result.text_value.should == 'foo' end end it "fails to parse nonmatching input at the index even if a match occurs later" do parse(" foo", :index => 0) do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end module ModFoo end describe "a terminal symbol followed by a node class declaration and a block" do testing_expression "'foo' { def a_method; end }" it "correctly parses matching input prefixes at various indices, returning an instance of SyntaxNode extended with the declared module that can respond to methods defined in the inline module" do parse "foo", :index => 0 do |result| result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result.interval.should == (0...3) result.text_value.should == 'foo' end parse "xfoo", :index => 1 do |result| result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result.interval.should == (1...4) result.text_value.should == 'foo' end parse "---foo", :index => 3 do |result| result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result.interval.should == (3...6) result.text_value.should == 'foo' end end end describe "a terminal regexp" do testing_expression "'Fo+'r" it "matches the input string" do parse "Fooo", :index => 0 do |result| result.should_not be_nil result.interval.should == (0...4) result.text_value.should == 'Fooo' end end it "fails to match the input string other than at the start" do parse " Foo", :index => 0 do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end it "fails to match the input string in the wrong case" do parse "foo", :index => 0 do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end describe "a case-insensitive terminal regexp" do testing_expression "'Fo+'ri" it "matches the input string in the same case" do parse "Fooo", :index => 0 do |result| result.should_not be_nil result.interval.should == (0...4) result.text_value.should == 'Fooo' end end it "matches the input string in the same case" do parse "foOo", :index => 0 do |result| result.should_not be_nil result.interval.should == (0...4) result.text_value.should == 'foOo' end end end # Transient symbols were part of some idea of Nathan's that I no longer recall # describe "a transient terminal symbol" do # testing_expression "~'foo'" # # it "returns true upon parsing matching input prefixes at various indices" do # pending "transient terminal expressions" # parse("foo", :index => 0).should be_true # parse("-foo", :index => 1).should be_true # parse("---foo", :index => 3).should be_true # end # end end treetop-1.6.3/spec/compiler/parsing_rule_spec.rb0000644000004100000410000000266612552221265022044 0ustar www-datawww-datarequire 'spec_helper' module ParsingRuleSpec describe "a grammar with one parsing rule" do testing_grammar %{ grammar Foo rule bar "baz" end end } it "stores and retrieves nodes in its node cache" do parser = self.class.const_get(:FooParser).new parser.send(:prepare_to_parse, 'baz') node_cache = parser.send(:node_cache) node_cache[:bar][0].should be_nil parser._nt_bar cached_node = node_cache[:bar][0] cached_node.should be_an_instance_of(Runtime::SyntaxNode) cached_node.text_value.should == 'baz' parser.instance_eval { @index = 0 } parser._nt_bar.should equal(cached_node) parser.index.should == cached_node.interval.end end end describe "a grammar with choice that uses the cache and has a subsequent expression" do testing_grammar %{ grammar Logic rule expression value_plus / value end rule value_plus value "something else" end rule value [a-z] / "foobar" # the subsequent expression that needs cached.interval.end end end } it "parses a single-character value and generates a node from the cache" do result = parse('a') result.should be_a(Treetop::Runtime::SyntaxNode) result.elements.should be_nil end end end treetop-1.6.3/spec/compiler/character_class_spec.rb0000644000004100000410000002351312552221265022465 0ustar www-datawww-datarequire 'spec_helper' module CharacterClassSpec class Foo < Treetop::Runtime::SyntaxNode end describe "a character class followed by a node class declaration and a block" do testing_expression "[A-Z] { def a_method; end }" it "matches single characters within that range, returning instances of the declared node class that respond to the method defined in the inline module" do result = parse('A') result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result = parse('N') result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result = parse('Z') result.should be_an_instance_of(Foo) result.should respond_to(:a_method) end it "does not match single characters outside of that range" do parse('8') do |result| result.should be_nil parser.terminal_failures.size.should == 1 end parse('a').should be_nil end it "matches a single character within that range at index 1" do parse(' A', :index => 1).should_not be_nil end it "fails to match a single character out of that range at index 1" do parse(' 1', :index => 1).should be_nil end end module ModFoo end describe "a character class followed by a node module declaration and a block" do testing_expression "[A-Z] { def a_method; end }" it "matches single characters within that range, returning instances of SyntaxNode extended by the specified module" do result = parse('A') result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result = parse('N') result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result = parse('Z') result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) end it "does not match single characters outside of that range" do parse('8').should be_nil parse('a').should be_nil end it "matches a single character within that range at index 1" do parse(' A', :index => 1).should_not be_nil end it "fails to match a single character out of that range at index 1" do parse(' 1', :index => 1).should be_nil end end describe "a character class with a POSIX bracket expression" do testing_expression "[[:digit:]]" it "matches a single character within the class" do parse('1').should_not be_nil end it "does not match a single character outside the class" do parse('a').should be_nil parse('-').should be_nil end testing_expression "[[:digit:][:space:]]+" it "matches a string with a mix of two character classes" do parse('1 4 9').should_not be_nil end end describe "a character class with a negated POSIX bracket expression" do testing_expression "[^[:space:]]" it "matches a character outside the negated class" do parse('a').should_not be_nil end it "doesn't match a character within the negated class" do parse(' ').should be_nil end end describe "a character class followed by a node class declaration and a block" do testing_expression "[A-Z] " it "actively generates nodes for the character when it is the primary node" do result = parse('A') result.should be_a(Treetop::Runtime::SyntaxNode) result.elements.should be_nil end end describe "A character class containing quotes" do testing_expression "[\"']" it "matches a quote" do parse("'").should_not be_nil end it "matches a double-quote" do parse('"').should_not be_nil end end describe "A character class containing a special character" do testing_expression "[\t]" it "matches that character only" do parse("\t").should_not be_nil parse('t').should be_nil end end describe "A character class containing an escaped backslash" do slash = "\\" # Make it explicit that there are *two* backslashes here testing_expression "[#{slash}#{slash}]" it "matches a backslash only" do parse("\\").should_not be_nil parse('t').should be_nil end end describe "A character class containing a hex escape" do slash = "\\" testing_expression "[#{slash}x41]" it "matches that character only" do parse('A').should_not be_nil parse('\\').should be_nil parse('x').should be_nil parse('4').should be_nil parse('1').should be_nil end end describe "A character class containing an octal escape" do slash = "\\" testing_expression "[#{slash}101]" it "matches that character only" do parse('A').should_not be_nil parse('\\').should be_nil parse('1').should be_nil parse('0').should be_nil end end describe "A character class containing a \\c control-char escape" do slash = "\\" testing_expression "[#{slash}cC]" it "matches that character only" do parse("\003").should_not be_nil parse('\\').should be_nil parse('c').should be_nil parse('C').should be_nil end end describe "A character class containing a \\C- control-char escape" do slash = "\\" testing_expression "[#{slash}C-C]" it "matches that character only" do parse("\003").should_not be_nil parse('\\').should be_nil parse('C').should be_nil parse('-').should be_nil end end if RUBY_VERSION =~ /\A1\.8\./ describe "A character class containing a \\M- meta-char escape" do slash = "\\" testing_expression "[#{slash}M- ]" it "matches that character only" do parse("\240").should_not be_nil parse('\\').should be_nil parse('M').should be_nil parse('-').should be_nil parse(' ').should be_nil end end end describe "A character class containing an escaped non-special character" do slash = "\\" testing_expression "[#{slash}y]" it "matches that character only" do parse("y").should_not be_nil parse('\\').should be_nil end end describe "A character class containing an \#{...} insertion" do testing_expression "[\#{raise 'error'}]" it "doesn't evaluate the insertion" do x = true lambda{ x = parse("y") }.should_not raise_error x.should be_nil parse('#').should_not be_nil parse("'").should_not be_nil parse("0").should be_nil end end describe "a character class" do testing_expression "[A-Z]" it "actively generates a node for the character because it is the primary node" do result = parse('A') result.should be_a(Treetop::Runtime::SyntaxNode) result.elements.should be_nil end end describe "a character class mixed with other expressions" do testing_expression '[A-Z] "a" "bc"' it "lazily instantiates a node for the character" do result = parse('Aabc') result.instance_variable_get("@elements").should include(true) result.elements.should_not include(true) result.elements.size.should == 3 end end describe "a character class with a node class declaration mixed with other expressions" do testing_expression '([A-Z] ) "ab"' it "actively generates a node for the character because it has a node class declared" do result = parse('Aab') result.instance_variable_get("@elements").should_not include(true) result.elements.should_not include(true) result.elements.size.should == 2 end end describe "a character class with a node module declaration mixed with other expressions" do testing_expression '([A-Z] ) "ab"' it "actively generates a node for the character because it has a node module declared" do result = parse('Aab') result.instance_variable_get("@elements").should_not include(true) result.elements.should_not include(true) result.elements.size.should == 2 end end describe "a character class with an inline block mixed with other expressions" do testing_expression '([A-Z] { def a_method; end }) "ab"' it "actively generates a node for the character because it has an inline block" do result = parse('Aab') result.instance_variable_get("@elements").should_not include(true) result.elements.should_not include(true) result.elements.size.should == 2 end end describe "a character class with a label mixed with other expressions" do testing_expression 'upper:([A-Z]) "b" "cd"' it "returns the correct element for the labeled expression" do result = parse('Abcd') result.upper.text_value.should == "A" result.elements.size.should == 3 end end describe "a character class repetition mixed with other expressions" do testing_expression '[A-Z]+ "a" "bc"' it "lazily instantiates a node for the character" do result = parse('ABCabc') result.elements[0].instance_variable_get("@elements").should include(true) result.elements[0].elements.should_not include(true) result.elements[0].elements.size.should == 3 result.elements.size.should == 3 result.elements.inspect.should == %Q{[SyntaxNode offset=0, "ABC":\n SyntaxNode offset=0, "A"\n SyntaxNode offset=1, "B"\n SyntaxNode offset=2, "C", SyntaxNode offset=3, "a", SyntaxNode offset=4, "bc"]} end end describe "a character class that gets cached because of a choice" do testing_expression "[A-Z] 'a' 'bc' / [A-Z]" it "generates a node for the lazily-instantiated character when it is the primary node" do result = parse('A') result.should be_a(Treetop::Runtime::SyntaxNode) result.elements.should be_nil end end end treetop-1.6.3/spec/compiler/semantic_predicate_spec.rb0000644000004100000410000001357212552221265023173 0ustar www-datawww-datarequire 'spec_helper' module SemanticPredicateSpec describe "An &-predicate block" do testing_expression '& {|| $ok_to_succeed}' it "succeeds if it returns true, returning an epsilon syntax node" do $ok_to_succeed = true parse('foo', :consume_all_input => false) do |result| result.should_not be_nil result.interval.should == (0...0) end end it "fails if it returns false" do $ok_to_succeed = false parse('foo', :consume_all_input => false) do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 end end end describe "A sequence of a terminal and an &-predicate block" do testing_expression '"prior " &{|s| $value = s[0].text_value; $ok_to_succeed }' it "matches the input terminal and consumes it if the block returns true, seeing the terminal in the sequence" do $ok_to_succeed = true $value = nil parse('prior foo', :consume_all_input => false) do |result| result.should_not be_nil result.elements[0].text_value.should == "prior " result.text_value.should == 'prior ' $value.should == 'prior ' end end it "fails if the block returns false, but sees the terminal in the sequence" do $ok_to_succeed = false $value = nil parse('prior foo', :consume_all_input => false) do |result| result.should be_nil $value.should == 'prior ' terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 end end end describe "A sequence of an optional terminal and an &-predicate block" do testing_expression '"prior "? &{|s| $value = s[0].text_value; $ok_to_succeed}' it "matches the input terminal and consumes it if the block returns true" do $ok_to_succeed = true parse('prior foo', :consume_all_input => false) do |result| result.should_not be_nil result.elements[0].text_value.should == "prior " result.text_value.should == 'prior ' $value.should == 'prior ' end end it "fails with one terminal_failure if the block returns false" do $ok_to_succeed = false parse('prior foo', :consume_all_input => false) do |result| result.should be_nil $value.should == 'prior ' terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 end end it "fail and return the expected optional preceeding terminal as expected input if the block returns false" do $ok_to_succeed = false parse('foo', :consume_all_input => false) do |result| result.should be_nil terminal_failures = parser.terminal_failures # We should get "prior " failed, and also the predicate block terminal_failures.size.should == 2 terminal_failures[0].index.should == 0 terminal_failures[0].expected_string.should == '"prior "' terminal_failures[1].index.should == 0 terminal_failures[1].expected_string.should == '' end end end describe "A !-predicate block" do testing_expression '! {|| $ok_to_succeed}' it "succeeds if it returns false, returning an epsilon syntax node" do $ok_to_succeed = false parse('foo', :consume_all_input => false) do |result| result.should_not be_nil result.interval.should == (0...0) end end it "fails if it returns true" do $ok_to_succeed = true parse('foo', :consume_all_input => false) do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 end end end describe "A sequence of a terminal and an !-predicate block" do testing_expression '"prior " !{|s| $value = s[0].text_value; $ok_to_succeed }' it "matches the input terminal and consumes it if the block returns false, seeing the terminal in the sequence" do $ok_to_succeed = false $value = nil parse('prior foo', :consume_all_input => false) do |result| result.should_not be_nil result.elements[0].text_value.should == "prior " result.text_value.should == 'prior ' $value.should == 'prior ' end end it "fails if the block returns true, but sees the terminal in the sequence" do $ok_to_succeed = true $value = nil parse('prior foo', :consume_all_input => false) do |result| result.should be_nil $value.should == 'prior ' terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 end end end describe "A sequence of an optional terminal and an !-predicate block" do testing_expression '"prior "? !{|s| $value = s[0].text_value; $ok_to_succeed}' it "matches the input terminal and consumes it if the block returns false" do $ok_to_succeed = false parse('prior foo', :consume_all_input => false) do |result| result.should_not be_nil result.elements[0].text_value.should == "prior " result.text_value.should == 'prior ' $value.should == 'prior ' end end it "fails with one terminal_failure if the block returns true" do $ok_to_succeed = true parse('prior foo', :consume_all_input => false) do |result| result.should be_nil $value.should == 'prior ' terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 end end it "fail and return the expected optional preceeding terminal as expected input if the block returns true" do $ok_to_succeed = true parse('foo', :consume_all_input => false) do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 2 terminal_failures[0].index.should == 0 terminal_failures[0].expected_string.should == '"prior "' end end end end treetop-1.6.3/spec/compiler/zero_or_more_spec.rb0000644000004100000410000000343212552221265022043 0ustar www-datawww-datarequire 'spec_helper' module ZeroOrMoreSpec class Foo < Treetop::Runtime::SyntaxNode end describe "zero or more of a terminal symbol followed by a node class declaration and a block" do testing_expression '"foo"* { def a_method; end }' it "successfully parses epsilon, returning an instance declared node class and recording a terminal failure" do parse('') do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 0 failure.expected_string.should == '"foo"' end end it "successfully parses two of that terminal in a row, returning an instance of the declared node class and recording a failure representing the third attempt " do parse("foofoo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 6 failure.expected_string.should == '"foo"' end end end describe "Zero or more of a sequence" do testing_expression '("foo" "bar")*' it "resets the index appropriately following partially matcing input" do parse('foobarfoo', :consume_all_input => false) do |result| result.should_not be_nil result.interval.should == (0...6) end end end describe "Zero or more of a choice" do testing_expression '("a" / "bb")*' it "successfully parses matching input" do parse('abba').should_not be_nil end end end treetop-1.6.3/spec/compiler/test_grammar_magic_coding.treetop0000644000004100000410000000013712552221265024556 0ustar www-datawww-data# coding: UTF-8 module Test grammar Grammar do rule foo do 'foo' end end end treetop-1.6.3/spec/compiler/choice_spec.rb0000644000004100000410000000500712552221265020574 0ustar www-datawww-datarequire 'spec_helper' module ChoiceSpec describe "A choice between terminal symbols" do testing_expression '"foo" { def foo_method; end } / "bar" { def bar_method; end } / "baz" { def baz_method; end }' it "successfully parses input matching any of the alternatives, returning a node that responds to methods defined in its respective inline module" do result = parse('foo') result.should_not be_nil result.should respond_to(:foo_method) result = parse('bar') result.should_not be_nil result.should respond_to(:bar_method) result = parse('baz') result.should_not be_nil result.should respond_to(:baz_method) end it "upon parsing a string matching the second alternative, records the failure of the first terminal" do result = parse('bar') terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures[0] failure.expected_string.should == '"foo"' failure.index.should == 0 end it "upon parsing a string matching the third alternative, records the failure of the first two terminals" do result = parse('baz') terminal_failures = parser.terminal_failures terminal_failures.size.should == 2 failure_1 = terminal_failures[0] failure_1.expected_string == 'foo' failure_1.index.should == 0 failure_2 = terminal_failures[1] failure_2.expected_string == 'bar' failure_2.index.should == 0 end end describe "A choice between sequences" do testing_expression "'foo' 'bar' 'baz'\n/\n'bing' 'bang' 'boom'" it "successfully parses input matching any of the alternatives" do parse('foobarbaz').should_not be_nil parse('bingbangboom').should_not be_nil end end describe "A choice between terminals followed by a block" do testing_expression "('a'/ 'bb' / [c]) { def a_method; end }" it "extends a match of any of its subexpressions with a module created from the block" do ['a', 'bb', 'c'].each do |letter| parse(letter).should respond_to(:a_method) end end end module TestModule def a_method end end describe "a choice followed by a declared module" do testing_expression "('a'/ 'bb' / [c]) " it "extends a match of any of its subexpressions with a module created from the block" do ['a', 'bb', 'c'].each do |letter| parse(letter).should respond_to(:a_method) end end end end treetop-1.6.3/spec/compiler/parenthesized_expression_spec.rb0000644000004100000410000000076512552221265024474 0ustar www-datawww-datarequire 'spec_helper' module ParenthesizedExpressionSpec describe "An unadorned expression inside of parentheses" do testing_expression '("foo")' it "should behave as normal" do parse('foo').should_not be_nil end end describe "A prefixed-expression inside of parentheses" do testing_expression '(!"foo")' it "should behave as normal" do parse('foo') do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end end end treetop-1.6.3/spec/compiler/sequence_spec.rb0000644000004100000410000001121412552221265021147 0ustar www-datawww-datarequire 'spec_helper' module SequenceSpec class Foo < Treetop::Runtime::SyntaxNode end describe "a sequence of labeled terminal symbols followed by a node class declaration and a block" do testing_expression 'foo:"foo" bar:"bar" baz:"baz" { def a_method; end }' it "upon successfully matching input, instantiates an instance of the declared node class with element accessor methods and the method from the inline module" do parse('foobarbaz') do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) result.foo.text_value.should == 'foo' result.bar.text_value.should == 'bar' result.baz.text_value.should == 'baz' end end it "successfully matches at a non-zero index" do parse('---foobarbaz', :index => 3) do |result| result.should_not be_nil result.should be_nonterminal (result.elements.map {|elt| elt.text_value}).join.should == 'foobarbaz' end end it "fails to match non-matching input, recording the parse failure of first non-matching terminal" do parse('---foobazbaz', :index => 3) do |result| result.should be_nil parser.index.should == 3 terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 6 failure.expected_string.should == '"bar"' end end end module ModFoo def mod_method; end end describe "a sequence of labeled terminal symbols followed by a node module declaration and a block" do testing_expression 'foo:"foo" bar:"bar" baz:"baz" { def a_method; end }' it "upon successfully matching input, instantiates a syntax node and extends it with the declared module, element accessor methods, and the method from the inline module" do parse('foobarbaz') do |result| result.should_not be_nil result.should respond_to(:mod_method) result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result.foo.text_value.should == 'foo' result.bar.text_value.should == 'bar' result.baz.text_value.should == 'baz' end end end describe "a labeled single element sequence followed by a node module declaration and a block" do testing_expression 'foo:"foo"+ { def a_method; end }' it "upon successfully matching input, instantiates a syntax node and extends it with the declared module, element accessor methods, and the method from the inline module" do parse('foofoofoo') do |result| result.should_not be_nil result.should respond_to(:mod_method) result.should be_an_instance_of(Treetop::Runtime::SyntaxNode) result.should be_a_kind_of(ModFoo) result.should respond_to(:a_method) result.foo.text_value.should == 'foofoofoo' end end end describe "a sequence of non-terminals" do testing_grammar %{ grammar TestGrammar rule sequence foo bar baz { def baz 'override' + super.text_value end } end rule foo 'foo' end rule bar 'bar' end rule baz 'baz' end end } it "defines accessors for non-terminals automatically that can be overridden in the inline block" do parse('foobarbaz') do |result| result.foo.text_value.should == 'foo' result.bar.text_value.should == 'bar' result.baz.should == 'overridebaz' end end end describe "Compiling a sequence containing various white-space errors" do it "should succeed on a valid sequence" do compiling_expression('foo:"foo" "bar" { def a_method; end }').should_not raise_error end it "rejects space after a label" do compiling_expression('foo :"foo" "bar"').should raise_error(RuntimeError) end it "rejects space after label's colon" do compiling_expression('foo: "foo" "bar"').should raise_error(RuntimeError) end it "rejects missing space after a primary" do compiling_expression('foo:"foo""bar"').should raise_error(RuntimeError) end it "rejects missing space before node class declaration" do compiling_expression('foo:"foo" "bar"').should raise_error(RuntimeError) end it "rejects missing space before inline module" do compiling_expression('foo:"foo" "bar" {def a_method; end}').should raise_error(RuntimeError) end end end treetop-1.6.3/spec/compiler/circular_compilation_spec.rb0000644000004100000410000000156712552221265023553 0ustar www-datawww-datarequire 'spec_helper' BENCHMARK = false METAGRAMMAR_PATH = File.expand_path('../../../lib/treetop/compiler/metagrammar.treetop', __FILE__) module CircularCompilationSpec describe "a parser for the metagrammar" do attr_reader :parser before do @parser = Treetop::Compiler::MetagrammarParser.new end it "can parse the metagrammar.treetop whence it was generated" do File.open(METAGRAMMAR_PATH, 'r') do |f| metagrammar_source = f.read result = parser.parse(metagrammar_source) result.should_not be_nil # generated_parser = result.compile # Object.class_eval(generated_parser) # parser_2 = Treetop::Compiler::MetagrammarParser.new # optionally_benchmark do # result = parser_2.parse(metagrammar_source) # result.should_not be_nil # end end end end end treetop-1.6.3/spec/compiler/one_or_more_spec.rb0000644000004100000410000000226312552221265021646 0ustar www-datawww-datarequire 'spec_helper' module OneOrMoreSpec class Foo < Treetop::Runtime::SyntaxNode end describe "one or more of a terminal symbol followed by a node class declaration and a block" do testing_expression '"foo"+ { def a_method; end }' it "fails to parse epsilon, reporting a failure" do parse('') do |result| result.should be_nil terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 0 failure.expected_string.should == '"foo"' end end it "successfully parses two of that terminal in a row, returning an instance of the declared node class and reporting the failure the third parsing attempt" do parse("foofoo") do |result| result.should_not be_nil result.should be_an_instance_of(Foo) result.should respond_to(:a_method) terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 6 failure.expected_string.should == '"foo"' end end end end treetop-1.6.3/spec/compiler/multibyte_chars_spec.rb0000644000004100000410000000253212552221265022540 0ustar www-datawww-data# encoding: utf-8 require 'spec_helper' module MultibyteCharsSpec describe "an anything symbol", :multibyte => true do testing_expression '.' it "matches an UTF-8 character" do parse_multibyte("ø").should_not be_nil end end describe "A character class containing UTF-8 characters", :multibyte => true do testing_expression "[æøå]" it "recognizes the UTF-8 characters" do parse_multibyte("ø").should_not be_nil end end describe( "a character class repetition containing UTF-8 characters mixed with other expressions", :multibyte => true ) do testing_expression '[æøå]+ "a"' it "lazily instantiates a node for the character" do result = parse_multibyte('æøåa') pending "Multibyte support is not supported in Ruby 1.8.6" if RUBY_VERSION =~ /^1\.8.6/ result.elements[0].instance_variable_get("@elements").should include(true) result.elements[0].elements.should_not include(true) result.elements[0].elements.size.should == 3 result.elements.size.should == 2 result.elements[0].text_value.should == "æøå" result.elements[0].elements[0].text_value.should == "æ" result.elements[0].elements[1].text_value.should == "ø" result.elements[0].elements[2].text_value.should == "å" result.elements[1].text_value == "a" end end end treetop-1.6.3/spec/compiler/namespace_spec.rb0000644000004100000410000000153112552221265021274 0ustar www-datawww-datarequire 'spec_helper' module NamespaceSpec describe "a grammar" do class_eval("module Foo; end") testing_grammar %{ module Foo::Bar module Baz grammar Bat rule foo bar / baz end rule bar 'bar' 'bar' end rule baz 'baz' 'baz' end end end end } it "parses matching input" do parse('barbar').should_not be_nil parse('bazbaz').should_not be_nil end it "mixes in included modules" do foo = self.class.const_get(:Foo) bar = foo.const_get(:Bar) baz = bar.const_get(:Baz) baz.class.should == Module bat = baz.const_get(:Bat) bat.class.should == Module baz.const_get(:BatParser).class.should == Class end end end treetop-1.6.3/spec/compiler/grammar_spec.rb0000644000004100000410000000155212552221265020771 0ustar www-datawww-datarequire 'spec_helper' module GrammarSpec module Bar end describe "a grammar" do testing_grammar %{ grammar Foo # This comment should not cause a syntax error, nor should the following empty one # include GrammarSpec::Bar rule foo bar / baz end rule bar 'bar' 'bar' end rule baz 'baz' 'baz' end end } it "parses matching input" do parse('barbar').should_not be_nil parse('bazbaz').should_not be_nil end it "fails if it does not parse all input" do parse('barbarbazbaz') do |result| result.should be_nil parser.terminal_failures.size.should == 1 end end it "mixes in included modules" do self.class.const_get(:Foo).ancestors.should include(GrammarSpec::Bar) end end end treetop-1.6.3/spec/compiler/repeated_subrule_spec.rb0000644000004100000410000000125112552221265022671 0ustar www-datawww-datarequire 'spec_helper' module RepeatedSubruleSpec describe "a repeated subrule" do testing_grammar %{ grammar Foo rule foo a:'a' space b:'b' space 'cc' end rule space ' ' end end } it "should produce a parser having sequence-numbered node accessor methods" do parse("a b cc") do |result| result.should_not be_nil result.should respond_to(:space1) result.should respond_to(:space2) result.should_not respond_to(:space) result.should respond_to(:a) result.should respond_to(:b) result.should_not respond_to(:c) end end end end treetop-1.6.3/spec/compiler/test_grammar.tt0000644000004100000410000000011012552221265021027 0ustar www-datawww-datamodule Test grammar Grammar rule foo 'foo' end end endtreetop-1.6.3/spec/ruby_extensions/0000755000004100000410000000000012552221265017427 5ustar www-datawww-datatreetop-1.6.3/spec/ruby_extensions/string_spec.rb0000644000004100000410000000142512552221265022276 0ustar www-datawww-datarequire 'spec_helper' describe String do before do @string = %{ 0123456789 012345 01234567 0123 }.tabto(0).strip end it "can translate indices to column numbers" do @string.column_of(0).should == 1 @string.column_of(5).should == 6 @string.column_of(10).should == 11 @string.column_of(11).should == 1 @string.column_of(17).should == 7 @string.column_of(18).should == 1 @string.column_of(24).should == 7 end it "can translate indices to line numbers" do @string.line_of(0).should == 1 @string.line_of(5).should == 1 @string.line_of(10).should == 1 @string.line_of(11).should == 2 @string.line_of(17).should == 2 @string.line_of(18).should == 3 @string.line_of(24).should == 3 end end treetop-1.6.3/spec/spec_helper.rb0000644000004100000410000000551112552221265017007 0ustar www-datawww-datarequire 'rubygems' require 'benchmark' require 'rspec' require 'rspec/core/shared_context' require 'polyglot' $LOAD_PATH.unshift File.expand_path('../../lib') require 'treetop' include Treetop module Treetop module ExampleGroupInstanceMethods module ClassMethods attr_accessor :parser_class_under_test def testing_expression(expression_under_test) testing_grammar(%{ grammar Test rule expression_under_test }+expression_under_test+%{ end end }.tabto(0)) end def testing_grammar(grammar_under_test) grammar_node = parse_with_metagrammar(grammar_under_test.strip, :module_or_grammar) parser_code = grammar_node.compile class_eval(parser_code) self.parser_class_under_test = class_eval(grammar_node.parser_name) end def parse_with_metagrammar(input, root) parser = Treetop::Compiler::MetagrammarParser.new parser.root = root node = parser.parse(input) raise parser.failure_reason unless node node end end attr_reader :parser def parse_with_metagrammar(input, root) self.class.parse_with_metagrammar(input, root) end def parser_class_under_test self.class.parser_class_under_test end def parse(input, options = {}) @parser = parser_class_under_test.new unless options[:consume_all_input].nil? parser.consume_all_input = options.delete(:consume_all_input) end result = parser.parse(input, options) yield result if block_given? result end def parse_multibyte(input, options = {}) require 'active_support/all' if RUBY_VERSION !~ /^(1\.9|2\.)/ && 'NONE' == $KCODE then $KCODE = 'UTF8' end # rspec 1.3 used to do something similar (set it to 'u') that we need # for activerecord multibyte wrapper to kick in (1.8 only? @todo) parse(input.mb_chars, options) end def compiling_grammar(grammar_under_test) lambda { grammar_node = parse_with_metagrammar(grammar_under_test.strip, :grammar) parser_code = grammar_node.compile [grammar_node, parser_code] } end def compiling_expression(expression_under_test) compiling_grammar(%{ grammar Test rule expression_under_test #{expression_under_test} end end }.tabto(0)) end def optionally_benchmark(&block) if BENCHMARK Benchmark.bm do |x| x.report(&block) end else yield end end end end RSpec.configure do |c| c.mock_with :rr c.extend Treetop::ExampleGroupInstanceMethods::ClassMethods c.include Treetop::ExampleGroupInstanceMethods end class Symbol def to_proc lambda do |x| x.send(self) end end unless method_defined?(:to_proc) end treetop-1.6.3/spec/composition/0000755000004100000410000000000012552221265016532 5ustar www-datawww-datatreetop-1.6.3/spec/composition/subfolder/0000755000004100000410000000000012552221265020517 5ustar www-datawww-datatreetop-1.6.3/spec/composition/subfolder/e_includes_c.treetop0000644000004100000410000000025012552221265024534 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/../c" module Test grammar E include C rule e 'e' end rule inherit 'super' end end end treetop-1.6.3/spec/composition/b.treetop0000644000004100000410000000016412552221265020360 0ustar www-datawww-datamodule Test grammar B rule b 'bb' end rule inherit super 'keyword' end end end treetop-1.6.3/spec/composition/a.treetop0000644000004100000410000000015212552221265020354 0ustar www-datawww-datamodule Test grammar A rule a 'a' end rule inherit 'super' end end endtreetop-1.6.3/spec/composition/f.treetop0000644000004100000410000000034212552221265020362 0ustar www-datawww-data require "a" require File.dirname(__FILE__) + "/b" require File.dirname(__FILE__) + "/subfolder/e_includes_c" module Test grammar F include A include B include E rule f c e 'f' end end end treetop-1.6.3/spec/composition/d.treetop0000644000004100000410000000015712552221265020364 0ustar www-datawww-datamodule Test grammar D include A include B rule inherit super 'works' end end endtreetop-1.6.3/spec/composition/grammar_composition_spec.rb0000644000004100000410000000202012552221265024134 0ustar www-datawww-datarequire 'spec_helper' module GrammarCompositionSpec describe "several composed grammars" do before do dir = File.dirname(__FILE__) Treetop.load File.join(dir, 'a') Treetop.load File.join(dir, 'b') Treetop.load File.join(dir, 'c') # Check that polyglot finds d.treetop and loads it: $: << dir require 'd' @c = ::Test::CParser.new @d = ::Test::DParser.new end specify "rules in C have access to rules defined in A and B" do @c.parse('abbc').should_not be_nil end specify "rules in C can override rules in A and B with super semantics" do @d.parse('superkeywordworks').should_not be_nil end end describe "composed grammar chaining with require" do before do # Load f with polyglot without using the load path: require File.dirname(__FILE__) + '/f' @f = ::Test::FParser.new end specify "rules in F have access to rule defined in E" do @f.parse('abbcef').should_not be_nil end end end treetop-1.6.3/spec/composition/c.treetop0000644000004100000410000000014312552221265020356 0ustar www-datawww-datamodule Test grammar C include A include B rule c a b 'c' end end endtreetop-1.6.3/spec/runtime/0000755000004100000410000000000012552221265015652 5ustar www-datawww-datatreetop-1.6.3/spec/runtime/compiled_parser_spec.rb0000644000004100000410000000723312552221265022366 0ustar www-datawww-datarequire 'spec_helper' module CompiledParserSpec describe Runtime::CompiledParser, "for a grammar with two rules" do attr_reader :parser testing_grammar %{ grammar TwoRules rule a 'a' end rule b 'bb' end end } before do @parser = parser_class_under_test.new end it "allows its root to be specified" do parser.parse('a').should_not be_nil parser.parse('b').should be_nil # Check that the temporary-override works: parser.parse('bb', :root => :b).should_not be_nil parser.parse('a', :root => :b).should be_nil # Check that the temporary-override isn't sticky: parser.parse('a').should_not be_nil # Try a permanent override: parser.root = :b parser.parse('bb').should_not be_nil parser.parse('a').should be_nil end it "allows the requirement that all input be consumed to be disabled" do parser.parse('ab').should be_nil # Try a temporary override, and check it's not sticky: result = parser.parse('ab', :consume_all_input => false) result.should_not be_nil result.interval.should == (0...1) parser.parse('ab').should be_nil # Now a permanent override: parser.consume_all_input = false result = parser.parse('ab') result.should_not be_nil result.interval.should == (0...1) end it "allows input to be parsed at a given index" do parser.parse('ba').should be_nil parser.parse('ba', :index => 1).should_not be_nil # Check that the index defaults again to zero: parser.parse('a').should_not be_nil result = parser.parse('ba', :consume_all_input => false, :index => 1) result.should_not be_nil result.interval.should == (1...2) end end describe Runtime::CompiledParser, "for a grammar with a choice between terminals" do attr_reader :parser testing_grammar %{ grammar Choice rule choice 'a' / 'b' / 'c' end end } before do @parser = parser_class_under_test.new end it "provides #failure_reason, #failure_column, and #failure_line when there is a parse failure" do parser.parse('z').should be_nil parser.failure_reason.should == "Expected one of 'a', 'b', 'c' at line 1, column 1 (byte 1)" parser.failure_line.should == 1 parser.failure_column.should == 1 end end describe Runtime::CompiledParser, "#terminal_failures" do attr_reader:parser testing_grammar %{ grammar SequenceOfTerminals rule foo 'a' 'b' 'c' end end } before do @parser = parser_class_under_test.new end it "is reset between parses" do parser.parse('ac') terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 1 failure.expected_string.should == "'b'" parser.parse('b') terminal_failures = parser.terminal_failures terminal_failures.size.should == 1 failure = terminal_failures.first failure.index.should == 0 failure.expected_string.should == "'a'" end end describe "a SyntaxNode" do attr_reader :parser testing_grammar %{ grammar Alternates rule main aa &{|s| s[0].elements[0].parent.should == s[0] } / ab &{|s| s[0].elements[0].parent.should == s[0] } end rule aa 'a' 'a' end rule ab 'a' 'b' end end } before do @parser = parser_class_under_test.new end it "should have its parent set and reset" do parser.parse('ab') end end end treetop-1.6.3/spec/runtime/interval_skip_list/0000755000004100000410000000000012552221265021557 5ustar www-datawww-datatreetop-1.6.3/spec/runtime/interval_skip_list/palindromic_fixture.rb0000644000004100000410000000144212552221265026154 0ustar www-datawww-datamodule PalindromicFixtureSharedContext extend RSpec::Core::SharedContext include IntervalSkipListSpecHelper attr_reader :list, :node def construct_interval_skip_list @list = IntervalSkipList.new end def expected_node_heights [3, 2, 1, 3, 1, 2, 3] end def populate_interval_skip_list @list.insert(1..3, :a) @list.insert(1..5, :b) @list.insert(1..7, :c) @list.insert(1..9, :d) @list.insert(1..11, :e) @list.insert(1..13, :f) @list.insert(5..13, :g) end def make_it_determinisitic extend NextNodeHeightIsDeterministicSharedContext # use the method without getting the filter next_node_height_is_deterministic end before :each do construct_interval_skip_list make_it_determinisitic populate_interval_skip_list end end treetop-1.6.3/spec/runtime/interval_skip_list/spec_helper.rb0000644000004100000410000000431312552221265024376 0ustar www-datawww-datarequire 'spec_helper' class IntervalSkipList public :insert_node, :delete_node, :nodes, :head, :next_node_height end module NextNodeHeightIsDeterministicSharedContext extend RSpec::Core::SharedContext before :each do next_node_height_is_deterministic end # @todo we call this in one place other than here. cleanup? def next_node_height_is_deterministic node_heights = expected_node_heights.dup stub(list).next_node_height { node_heights.shift } end end module IntervalSkipListSpecHelper def contain_marker(marker) ContainMarkers.new(list, [marker]) end def contain_markers(*markers) ContainMarkers.new(list, markers) end class ContainMarkers attr_reader :failure_message def initialize(list, expected_markers) @list = list @expected_markers = expected_markers end def matches?(target_range) @target_range = target_range @target_range.each do |i| markers = @list.containing(i) @expected_markers.each do |expected_marker| unless markers.include?(expected_marker) @failure_message = "Expected #{expected_marker.inspect} to contain #{i}, but it doesn't. #{i} is contained by: #{markers.inspect}." return false end end markers.each do |marker| unless @expected_markers.include?(marker) @failure_message = "Did not expect #{marker.inspect} to contain #{i}. Only expected #{@expected_markers.inspect}." return false end end end true end end def have_markers(*markers) HaveMarkers.new(markers) end def have_marker(marker) HaveMarkers.new([marker]) end class HaveMarkers def initialize(expected_markers) @expected_markers = expected_markers end def matches?(target) @target = target return false unless @target.size == @expected_markers.size @expected_markers.each do |expected_marker| return false unless @target.include?(expected_marker) end true end def failure_message "Expected #{@target.inspect} to include only #{@expected_markers.inspect}" end end end require 'runtime/interval_skip_list/palindromic_fixture' treetop-1.6.3/spec/runtime/interval_skip_list/palindromic_fixture_spec.rb0000644000004100000410000000757212552221265027200 0ustar www-datawww-datarequire 'runtime/interval_skip_list/spec_helper' describe "The palindromic fixture", :palindromic => true do include PalindromicFixtureSharedContext describe " #nodes" do describe "[0]" do before do @node = list.nodes[0] end it "has a key of 1 and a height of 3" do node.key.should == 1 node.height.should == 3 end it "has :c, :d, :e, and :f as its only forward markers at level 2" do node.forward_markers[2].should have_markers(:c, :d, :e, :f) end it "has :a, :b as its only forward markers at level 1" do node.forward_markers[1].should have_markers(:a, :b) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has no markers" do node.markers.should be_empty end end describe "[1]" do before do @node = list.nodes[1] end it "has a key of 3 and a height of 2" do node.key.should == 3 node.height.should == 2 end it "has no forward markers at level 1" do node.forward_markers[1].should be_empty end it "has :b as its only forward marker at level 0" do node.forward_markers[0].should have_marker(:b) end it "has :a and :b as its only markers" do node.markers.should have_markers(:a, :b) end end describe "[2]" do before do @node = list.nodes[2] end it "has a key of 5 and a height of 1" do node.key.should == 5 node.height.should == 1 end it "has :g as its only forward marker at level 0" do node.forward_markers[0].should have_marker(:g) end it "has :b as its only marker" do node.markers.should have_marker(:b) end end describe "[3]" do before do @node = list.nodes[3] end it "has a key of 7 and a height of 3" do node.key.should == 7 node.height.should == 3 end it "has :f and :g as its only forward markers at level 2" do node.forward_markers[2].should have_markers(:f, :g) end it "has :e as its only forward markers at level 1" do node.forward_markers[1].should have_marker(:e) end it "has :d as its only forward marker at level 0" do node.forward_markers[0].should have_markers(:d) end it "has :c, :d, :e, :f and :g as its only markers" do node.markers.should have_markers(:c, :d, :e, :f, :g) end end describe "[4]" do before do @node = list.nodes[4] end it "has a key of 9 and a height of 1" do node.key.should == 9 node.height.should == 1 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty end it "has :d as its only marker" do node.markers.should have_markers(:d) end end describe "[5]" do before do @node = list.nodes[5] end it "has a key of 11 and a height of 2" do node.key.should == 11 node.height.should == 2 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty end it "has :e as its only marker" do node.markers.should have_markers(:e) end end describe "[6]" do before do @node = list.nodes[6] end it "has a key of 13 and a height of 3" do node.key.should == 13 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :f and :g as its only markers" do node.markers.should have_markers(:f, :g) end end end end treetop-1.6.3/spec/runtime/interval_skip_list/interval_skip_list_spec.graffle0000644000004100000410000044417112552221265030041 0ustar www-datawww-data CreationDate 2008-01-23 19:21:27 -0800 Creator pivotal GraphDocumentVersion 5 GuidesLocked NO GuidesVisible YES ImageCounter 1 LinksVisible NO MagnetsVisible NO MasterSheets ActiveLayerIndex 0 AutoAdjust CanvasColor w 1 CanvasOrigin {0, 0} CanvasScale 1 ColumnAlign 1 ColumnSpacing 36 DisplayScale 1 in = 1 in GraphicsList Bounds {{676.1, 164.06}, {24, 14}} Class ShapedGraphic FitText YES Flow Resize ID 209 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 13} Wrap NO Bounds {{566.114, 164.06}, {23, 14}} Class ShapedGraphic FitText YES Flow Resize ID 207 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 11} Wrap NO Bounds {{463.723, 164.06}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 206 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 9} Wrap NO Bounds {{359.775, 164.06}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 205 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 7} Wrap NO Bounds {{264.057, 164.06}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 204 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 5} Wrap NO Bounds {{160.599, 164.06}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 203 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 3} Wrap NO Bounds {{51.8613, 164.06}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 202 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 1} Wrap NO Bounds {{311.301, 122.432}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 100 Line ID 45 Position 0.49750059843063354 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 g} Bounds {{411.092, 122.432}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 91 Line ID 46 Position 0.4975009560585022 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 d} Bounds {{461.295, 81.4593}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 90 Line ID 40 Position 0.48428341746330261 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 e} Bounds {{501.164, 40.4863}, {24, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 89 Line ID 36 Position 0.44795909523963928 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 f g} Bounds {{194.113, 40.4863}, {43, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 88 Line ID 35 Position 0.50672364234924316 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 c d e f} Bounds {{212.329, 122.432}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 86 Line ID 44 Position 0.49750003218650818 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b} Bounds {{97.2116, 81.4594}, {27, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 85 Line ID 37 Position 0.43750011920928955 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b} Class LineGraphic Head ID 32 ID 48 Points {598.785, 129.432} {667.238, 129.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 30 Class LineGraphic Head ID 30 ID 47 Points {493.394, 129.432} {556.752, 129.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 16 Class LineGraphic Head ID 16 ID 46 Points {388.138, 129.432} {451.361, 129.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 25 Class LineGraphic Head ID 25 ID 45 Points {293.698, 129.432} {346.165, 129.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 6 Class LineGraphic Head ID 6 ID 44 Points {190.24, 129.432} {251.725, 129.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 19 Class LineGraphic Head ID 19 ID 42 Points {81.5016, 129.432} {148.267, 129.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 21 Class LineGraphic Head ID 33 ID 41 Points {598.785, 88.4593} {667.238, 88.4593} Style stroke HeadArrow 0 TailArrow 0 Tail ID 29 Class LineGraphic Head ID 29 ID 40 Points {388.138, 88.4593} {556.752, 88.4593} Style stroke HeadArrow 0 TailArrow 0 Tail ID 26 Class LineGraphic Head ID 26 ID 38 Points {190.24, 88.4593} {346.165, 88.4593} Style stroke HeadArrow 0 TailArrow 0 Tail ID 18 Class LineGraphic Head ID 18 ID 37 Points {81.5016, 88.4594} {148.267, 88.4594} Style stroke HeadArrow 0 TailArrow 0 Tail ID 22 Class LineGraphic Head ID 34 ID 36 Points {388.138, 47.4863} {667.238, 47.4863} Style stroke HeadArrow 0 TailArrow 0 Tail ID 27 Class LineGraphic Head ID 27 ID 35 Points {81.5016, 47.4863} {346.165, 47.4863} Style stroke HeadArrow 0 TailArrow 0 Tail ID 23 Bounds {{451.861, 108.946}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 16 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 d} Class Group Graphics Bounds {{557.252, 67.973}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 29 Shape Rectangle Bounds {{557.252, 108.946}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 30 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 e} ID 28 Class Group Graphics Bounds {{667.738, 108.946}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 32 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 f g} Bounds {{667.738, 67.973}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 33 Shape Rectangle Bounds {{667.738, 27}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 34 Shape Rectangle ID 31 Class Group Graphics Bounds {{346.665, 108.946}, {40.9727, 40.9726}} Class ShapedGraphic ID 25 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 c d e f g} Bounds {{346.665, 67.973}, {40.9727, 40.9726}} Class ShapedGraphic ID 26 Shape Rectangle Bounds {{346.665, 27}, {40.9727, 40.9726}} Class ShapedGraphic ID 27 Shape Rectangle ID 24 Bounds {{252.225, 108.946}, {40.9727, 40.9726}} Class ShapedGraphic ID 6 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b} Class Group Graphics Bounds {{148.767, 67.973}, {40.9727, 40.9727}} Class ShapedGraphic ID 18 Shape Rectangle Bounds {{148.767, 108.946}, {40.9727, 40.9727}} Class ShapedGraphic ID 19 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b} ID 17 Class Group Graphics Bounds {{40.0289, 108.946}, {40.9727, 40.9727}} Class ShapedGraphic ID 21 Shape Rectangle Bounds {{40.0289, 67.973}, {40.9727, 40.9727}} Class ShapedGraphic ID 22 Shape Rectangle Bounds {{40.0289, 27}, {40.9727, 40.9727}} Class ShapedGraphic ID 23 Shape Rectangle ID 20 GridInfo HPages 1 IsPalette NO KeepToScale Layers Lock NO Name Layer 1 Print YES View YES LayoutInfo Orientation 2 OutlineStyle Basic RowAlign 1 RowSpacing 36 SheetTitle Master 1 UniqueID 1 VPages 1 ModificationDate 2008-01-25 12:52:43 -0800 Modifier pivotal NotesVisible NO OriginVisible NO PageBreaks YES PrintInfo NSBottomMargin float 0 NSLeftMargin float 0 NSOrientation int 1 NSPaperSize size {792, 612} NSRightMargin float 0 NSTopMargin float 0 ReadOnly NO Sheets ActiveLayerIndex 0 AutoAdjust CanvasColor w 1 CanvasOrigin {0, 0} CanvasScale 1 ColumnAlign 1 ColumnSpacing 36 DisplayScale 1 in = 1 in GraphicsList Bounds {{337.9, 223.864}, {73, 18}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica Size 15 ID 210 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs30 \cf0 delete(:c)} Wrap NO Bounds {{617.836, 328.64}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 103 Line ID 74 Position 0.49193865060806274 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 g} Bounds {{509.836, 369.613}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 101 Line ID 79 Position 0.49032312631607056 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 g} Bounds {{356.356, 369.613}, {27, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 99 Line ID 83 Position 0.52189022302627563 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 d g} Bounds {{360.246, 328.64}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 96 Line ID 82 Position 0.50374859571456909 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 e} Bounds {{360.548, 287.667}, {14, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 95 Line ID 81 Position 0.49880927801132202 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 f} Bounds {{201.204, 369.613}, {27, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 94 Line ID 76 Position 0.4975002110004425 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b d} Bounds {{84.0915, 328.64}, {47, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 93 Line ID 71 Position 0.4825001060962677 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b d e} Class LineGraphic Head ID 68 ID 83 Points {287.573, 376.612} {445.237, 376.613} Style stroke HeadArrow 0 TailArrow 0 Tail ID 56 Class LineGraphic Head ID 66 ID 82 Points {184.115, 335.64} {550.629, 335.64} Style stroke HeadArrow 0 TailArrow 0 Tail ID 54 Class LineGraphic Head ID 64 ID 81 Points {75.3772, 294.667} {661.114, 294.667} Style stroke HeadArrow 0 TailArrow 0 Tail ID 52 Class LineGraphic Head ID 62 ID 80 Points {592.661, 376.612} {661.114, 376.612} Style stroke HeadArrow 0 TailArrow 0 Tail ID 67 Class LineGraphic Head ID 67 ID 79 Points {487.269, 376.613} {550.629, 376.612} Style stroke HeadArrow 0 TailArrow 0 Tail ID 68 Class LineGraphic Head ID 56 ID 76 Points {184.115, 376.613} {245.601, 376.612} Style stroke HeadArrow 0 TailArrow 0 Tail ID 55 Class LineGraphic Head ID 55 ID 75 Points {75.3772, 376.612} {142.143, 376.613} Style stroke HeadArrow 0 TailArrow 0 Tail ID 50 Class LineGraphic Head ID 63 ID 74 Points {592.661, 335.64} {661.114, 335.64} Style stroke HeadArrow 0 TailArrow 0 Tail ID 66 Class LineGraphic Head ID 54 ID 71 Points {75.3772, 335.639} {142.143, 335.64} Style stroke HeadArrow 0 TailArrow 0 Tail ID 51 Bounds {{445.737, 356.127}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 68 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 d g} Class Group Graphics Bounds {{551.129, 315.154}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 66 Shape Rectangle Bounds {{551.129, 356.126}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 67 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 e g} ID 65 Class Group Graphics Bounds {{661.614, 356.126}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 62 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 f g} Bounds {{661.614, 315.154}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 63 Shape Rectangle Bounds {{661.614, 274.181}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 64 Shape Rectangle ID 61 Bounds {{246.101, 356.126}, {40.9727, 40.9726}} Class ShapedGraphic ID 56 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b d} Class Group Graphics Bounds {{142.643, 315.154}, {40.9727, 40.9726}} Class ShapedGraphic ID 54 Shape Rectangle Bounds {{142.643, 356.127}, {40.9727, 40.9726}} Class ShapedGraphic ID 55 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b e d} ID 53 Class Group Graphics Bounds {{33.9045, 356.126}, {40.9727, 40.9726}} Class ShapedGraphic ID 50 Shape Rectangle Bounds {{33.9045, 315.153}, {40.9727, 40.9726}} Class ShapedGraphic ID 51 Shape Rectangle Bounds {{33.9045, 274.181}, {40.9727, 40.9726}} Class ShapedGraphic ID 52 Shape Rectangle ID 49 GridInfo HPages 1 IsPalette NO KeepToScale Layers Lock NO Name Layer 1 Print YES View YES LayoutInfo MasterSheet Master 1 Orientation 2 OutlineStyle Basic RowAlign 1 RowSpacing 36 SheetTitle delete(:c) UniqueID 1 VPages 1 ActiveLayerIndex 0 AutoAdjust CanvasColor w 1 CanvasOrigin {0, 0} CanvasScale 1 ColumnAlign 1 ColumnSpacing 36 DisplayScale 1 in = 1 in GraphicsList Bounds {{183.062, 227}, {128, 23}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica Size 18 ID 206 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs38 \cf0 expire(7..7, 0)} Wrap NO Bounds {{265.352, 437.939}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 204 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 5} Wrap NO Bounds {{161.894, 437.939}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 203 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 3} Wrap NO Bounds {{53.1566, 437.939}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 202 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 1} Wrap NO Bounds {{212.329, 383.432}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 195 Line ID 189 Position 0.49750003218650818 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b} Bounds {{97.2119, 342.459}, {27, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 194 Line ID 184 Position 0.43750011920928955 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b} Class LineGraphic Head ID 169 ID 189 Points {190.24, 390.432} {251.725, 390.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 168 Class LineGraphic Head ID 168 ID 188 Points {81.5021, 390.432} {148.267, 390.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 163 Class LineGraphic Head ID 167 ID 184 Points {81.5021, 349.459} {148.267, 349.459} Style stroke HeadArrow 0 TailArrow 0 Tail ID 164 Bounds {{252.225, 369.946}, {40.9727, 40.9726}} Class ShapedGraphic ID 169 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b} Class Group Graphics Bounds {{148.767, 328.973}, {40.9727, 40.9727}} Class ShapedGraphic ID 167 Shape Rectangle Bounds {{148.767, 369.946}, {40.9727, 40.9727}} Class ShapedGraphic ID 168 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b} ID 166 Class Group Graphics Bounds {{40.0294, 369.946}, {40.9727, 40.9727}} Class ShapedGraphic ID 163 Shape Rectangle Bounds {{40.0294, 328.973}, {40.9727, 40.9727}} Class ShapedGraphic ID 164 Shape Rectangle Bounds {{40.0294, 288}, {40.9727, 40.9727}} Class ShapedGraphic ID 165 Shape Rectangle ID 162 GridInfo HPages 1 IsPalette NO KeepToScale Layers Lock NO Name Layer 1 Print YES View YES LayoutInfo MasterSheet Master 1 Orientation 2 OutlineStyle Basic RowAlign 1 RowSpacing 36 SheetTitle expire(7..7, 0) UniqueID 2 VPages 1 ActiveLayerIndex 0 AutoAdjust CanvasColor w 1 CanvasOrigin {0, 0} CanvasScale 1 ColumnAlign 1 ColumnSpacing 36 DisplayScale 1 in = 1 in GraphicsList Bounds {{265.638, 219.932}, {122, 22}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica Size 17 ID 272 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs36 \cf0 expire(4..4, 2)} Wrap NO Class LineGraphic Head ID 224 ID 271 Points {190.24, 291.459} {667.238, 291.459} Style stroke HeadArrow 0 TailArrow 0 Tail ID 215 Bounds {{483.529, 325.432}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 270 Line ID 269 Position 0.46961680054664612 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 g} Class LineGraphic Head ID 223 ID 269 Points {336.894, 332.432} {667.238, 332.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 217 Bounds {{666.254, 363}, {44, 14}} Class ShapedGraphic FitText YES Flow Resize ID 255 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 13 + 2} Wrap NO Bounds {{296.907, 363}, {38, 14}} Class ShapedGraphic FitText YES Flow Resize ID 251 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 5 + 2} Wrap NO Bounds {{160.753, 363}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 250 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 3} Wrap NO Bounds {{52.0152, 363}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 249 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 1} Wrap NO Bounds {{102.211, 284.459}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica-Oblique Size 12 ID 242 Line ID 232 Position 0.43750011920928955 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a} Class LineGraphic FontInfo Font Helvetica Size 12 Head ID 217 ID 237 Points {190.24, 332.432} {294.921, 332.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 216 Class LineGraphic FontInfo Font Helvetica Size 12 Head ID 216 ID 236 Points {81.5016, 332.432} {148.267, 332.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 211 Class LineGraphic FontInfo Font Helvetica Size 12 Head ID 215 ID 232 Points {81.5016, 291.459} {148.267, 291.459} Style stroke HeadArrow 0 TailArrow 0 Tail ID 212 Class Group Graphics Bounds {{667.738, 311.946}, {41.0327, 40.9726}} Class ShapedGraphic FontInfo Font Helvetica Size 12 HFlip YES ID 223 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 g} Bounds {{667.738, 270.973}, {41.0327, 40.9726}} Class ShapedGraphic FontInfo Font Helvetica Size 12 HFlip YES ID 224 Shape Rectangle Bounds {{667.738, 230}, {41.0327, 40.9726}} Class ShapedGraphic FontInfo Font Helvetica Size 12 HFlip YES ID 225 Shape Rectangle ID 222 Bounds {{295.421, 311.946}, {40.9727, 40.9726}} Class ShapedGraphic FontInfo Font Helvetica Size 12 ID 217 Shape Rectangle Class Group Graphics Bounds {{148.767, 270.973}, {40.9727, 40.9727}} Class ShapedGraphic FontInfo Font Helvetica Size 12 ID 215 Shape Rectangle Bounds {{148.767, 311.946}, {40.9727, 40.9727}} Class ShapedGraphic FontInfo Font Helvetica Size 12 ID 216 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a} ID 214 Class Group Graphics Bounds {{40.0289, 311.946}, {40.9727, 40.9727}} Class ShapedGraphic FontInfo Font Helvetica Size 12 ID 211 Shape Rectangle Bounds {{40.0289, 270.973}, {40.9727, 40.9727}} Class ShapedGraphic FontInfo Font Helvetica Size 12 ID 212 Shape Rectangle Bounds {{40.0289, 230}, {40.9727, 40.9727}} Class ShapedGraphic FontInfo Font Helvetica Size 12 ID 213 Shape Rectangle ID 210 GridInfo HPages 1 IsPalette NO KeepToScale Layers Lock NO Name Layer 1 Print YES View YES LayoutInfo MasterSheet Master 1 Orientation 2 OutlineStyle Basic RowAlign 1 RowSpacing 36 SheetTitle expire(4..4, 2) UniqueID 3 VPages 1 ActiveLayerIndex 0 AutoAdjust CanvasColor w 1 CanvasOrigin {0, 0} CanvasScale 1 ColumnAlign 1 ColumnSpacing 36 DisplayScale 1 in = 1 in GraphicsList Bounds {{468.5, 194}, {111, 18}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica Size 14 ID 269 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs30 \cf0 insert(9..13, :z)} Wrap NO Class LineGraphic Head ID 227 ID 268 Points {190.24, 479.459} {667.238, 479.459} Style stroke HeadArrow 0 TailArrow 0 Tail ID 218 Class LineGraphic Head ID 228 ID 267 Points {81.502, 438.486} {667.238, 438.486} Style stroke HeadArrow 0 TailArrow 0 Tail ID 216 Class LineGraphic Head ID 232 ID 266 Points {190.24, 520.432} {451.361, 520.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 219 Bounds {{570, 513.432}, {16, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 265 Line ID 264 Position 0.48667857050895691 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 z} Class LineGraphic Head ID 226 ID 264 Points {493.394, 520.432} {667.238, 520.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 232 Bounds {{623, 274.12}, {16, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 261 Line ID 41 Position 0.47061088681221008 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 z} Bounds {{516, 315.093}, {16, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 260 Line ID 47 Position 0.48306027054786682 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 z} Bounds {{313.152, 395}, {108, 18}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica Size 14 ID 259 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs30 \cf0 expire(4..8, -3)} Wrap NO Bounds {{667.6, 555.06}, {41, 14}} Class ShapedGraphic FitText YES Flow Resize ID 258 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 13 - 3} Wrap NO Bounds {{454.723, 555.06}, {35, 14}} Class ShapedGraphic FitText YES Flow Resize ID 256 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 9 - 3} Wrap NO Bounds {{160.599, 555.06}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 253 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 3} Wrap NO Bounds {{51.8617, 555.06}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 252 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 1} Wrap NO Bounds {{102.212, 472.459}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 245 Line ID 235 Position 0.43750011920928955 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a} Class LineGraphic Head ID 219 ID 239 Points {81.502, 520.432} {148.267, 520.432} Style stroke HeadArrow 0 TailArrow 0 Tail ID 214 Class LineGraphic Head ID 218 ID 235 Points {81.502, 479.459} {148.267, 479.459} Style stroke HeadArrow 0 TailArrow 0 Tail ID 215 Bounds {{451.861, 499.946}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 232 Shape Rectangle Class Group Graphics Bounds {{667.738, 499.946}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 226 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 z} Bounds {{667.738, 458.973}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 227 Shape Rectangle Bounds {{667.738, 418}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 228 Shape Rectangle ID 225 Class Group Graphics Bounds {{148.767, 458.973}, {40.9727, 40.9727}} Class ShapedGraphic ID 218 Shape Rectangle Bounds {{148.767, 499.946}, {40.9727, 40.9727}} Class ShapedGraphic ID 219 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a} ID 217 Class Group Graphics Bounds {{40.0293, 499.946}, {40.9727, 40.9727}} Class ShapedGraphic ID 214 Shape Rectangle Bounds {{40.0293, 458.973}, {40.9727, 40.9727}} Class ShapedGraphic ID 215 Shape Rectangle Bounds {{40.0293, 418}, {40.9727, 40.9727}} Class ShapedGraphic ID 216 Shape Rectangle ID 213 Bounds {{311.301, 194}, {109, 18}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica Size 14 ID 212 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs30 \cf0 insert(7..11, :y)} Wrap NO Bounds {{145.062, 194}, {102, 18}} Class ShapedGraphic FitText YES Flow Resize FontInfo Font Helvetica Size 14 ID 211 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs30 \cf0 insert(1..5, :x)} Wrap NO Bounds {{676.1, 354.579}, {24, 14}} Class ShapedGraphic FitText YES Flow Resize ID 209 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 13} Wrap NO Bounds {{566.114, 354.579}, {23, 14}} Class ShapedGraphic FitText YES Flow Resize ID 207 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 11} Wrap NO Bounds {{463.723, 354.579}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 206 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 9} Wrap NO Bounds {{359.775, 354.579}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 205 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 7} Wrap NO Bounds {{264.057, 354.579}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 204 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 5} Wrap NO Bounds {{160.599, 354.579}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 203 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 3} Wrap NO Bounds {{51.8617, 354.579}, {17, 14}} Class ShapedGraphic FitText YES Flow Resize ID 202 Shape Rectangle Style fill Draws NO shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 1} Wrap NO Bounds {{311.301, 315.093}, {17, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 100 Line ID 45 Position 0.49750059843063354 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 g} Bounds {{406.092, 315.093}, {27, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 91 Line ID 46 Position 0.4975009560585022 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 d y} Bounds {{456.295, 274.12}, {27, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 90 Line ID 40 Position 0.48428341746330261 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 e y} Bounds {{501.164, 233.147}, {24, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 89 Line ID 36 Position 0.44795909523963928 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 f g} Bounds {{194.113, 233.147}, {43, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 88 Line ID 35 Position 0.50672364234924316 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 c d e f} Bounds {{207.329, 315.093}, {27, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 86 Line ID 44 Position 0.49750003218650818 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b x} Bounds {{92.2119, 274.12}, {37, 14}} Class ShapedGraphic FitText YES FontInfo Color w 0 Font Helvetica Size 12 ID 85 Line ID 37 Position 0.43750011920928955 RotationType 0 Shape Rectangle Style shadow Draws NO stroke Draws NO Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b x} Class LineGraphic Head ID 32 ID 48 Points {598.785, 322.093} {667.238, 322.093} Style stroke HeadArrow 0 TailArrow 0 Tail ID 30 Class LineGraphic Head ID 30 ID 47 Points {493.394, 322.093} {556.752, 322.093} Style stroke HeadArrow 0 TailArrow 0 Tail ID 16 Class LineGraphic Head ID 16 ID 46 Points {388.138, 322.093} {451.361, 322.093} Style stroke HeadArrow 0 TailArrow 0 Tail ID 25 Class LineGraphic Head ID 25 ID 45 Points {293.698, 322.093} {346.165, 322.093} Style stroke HeadArrow 0 TailArrow 0 Tail ID 6 Class LineGraphic Head ID 6 ID 44 Points {190.24, 322.093} {251.725, 322.093} Style stroke HeadArrow 0 TailArrow 0 Tail ID 19 Class LineGraphic Head ID 19 ID 42 Points {81.502, 322.093} {148.267, 322.093} Style stroke HeadArrow 0 TailArrow 0 Tail ID 21 Class LineGraphic Head ID 33 ID 41 Points {598.785, 281.12} {667.238, 281.12} Style stroke HeadArrow 0 TailArrow 0 Tail ID 29 Class LineGraphic Head ID 29 ID 40 Points {388.138, 281.12} {556.752, 281.12} Style stroke HeadArrow 0 TailArrow 0 Tail ID 26 Class LineGraphic Head ID 26 ID 38 Points {190.24, 281.12} {346.165, 281.12} Style stroke HeadArrow 0 TailArrow 0 Tail ID 18 Class LineGraphic Head ID 18 ID 37 Points {81.502, 281.12} {148.267, 281.12} Style stroke HeadArrow 0 TailArrow 0 Tail ID 22 Class LineGraphic Head ID 34 ID 36 Points {388.138, 240.147} {667.238, 240.147} Style stroke HeadArrow 0 TailArrow 0 Tail ID 27 Class LineGraphic Head ID 27 ID 35 Points {81.502, 240.147} {346.165, 240.147} Style stroke HeadArrow 0 TailArrow 0 Tail ID 23 Bounds {{451.861, 301.607}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 16 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 d} Class Group Graphics Bounds {{557.252, 260.634}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 29 Shape Rectangle Bounds {{557.252, 301.607}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 30 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 e y z} ID 28 Class Group Graphics Bounds {{667.738, 301.607}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 32 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 f g z} Bounds {{667.738, 260.634}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 33 Shape Rectangle Bounds {{667.738, 219.661}, {41.0327, 40.9726}} Class ShapedGraphic HFlip YES ID 34 Shape Rectangle ID 31 Class Group Graphics Bounds {{346.665, 301.607}, {40.9727, 40.9726}} Class ShapedGraphic ID 25 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 c d e f g} Bounds {{346.665, 260.634}, {40.9727, 40.9726}} Class ShapedGraphic ID 26 Shape Rectangle Bounds {{346.665, 219.661}, {40.9727, 40.9726}} Class ShapedGraphic ID 27 Shape Rectangle ID 24 Bounds {{252.225, 301.607}, {40.9727, 40.9726}} Class ShapedGraphic ID 6 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 b x} Class Group Graphics Bounds {{148.767, 260.634}, {40.9727, 40.9727}} Class ShapedGraphic ID 18 Shape Rectangle Bounds {{148.767, 301.607}, {40.9727, 40.9727}} Class ShapedGraphic ID 19 Shape Rectangle Text Text {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf440 {\fonttbl\f0\fswiss\fcharset77 Helvetica;} {\colortbl;\red255\green255\blue255;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural \f0\fs24 \cf0 a b x} ID 17 Class Group Graphics Bounds {{40.0293, 301.607}, {40.9727, 40.9727}} Class ShapedGraphic ID 21 Shape Rectangle Bounds {{40.0293, 260.634}, {40.9727, 40.9727}} Class ShapedGraphic ID 22 Shape Rectangle Bounds {{40.0293, 219.661}, {40.9727, 40.9727}} Class ShapedGraphic ID 23 Shape Rectangle ID 20 GridInfo HPages 1 IsPalette NO KeepToScale Layers Lock NO Name Layer 1 Print YES View YES LayoutInfo MasterSheet Master 1 Orientation 2 OutlineStyle Basic RowAlign 1 RowSpacing 36 SheetTitle expire(4..8, -3) UniqueID 4 VPages 1 SmartAlignmentGuidesActive YES SmartDistanceGuidesActive YES UseEntirePage WindowInfo CurrentSheet 3 DrawerOpen DrawerTab Canvases DrawerWidth 209 FitInWindow Frame {{294, 134}, {1014, 944}} ShowRuler ShowStatusBar VisibleRegion {{-125, -118}, {999, 830}} Zoom 1 treetop-1.6.3/spec/runtime/interval_skip_list/expire_range_spec.rb0000644000004100000410000002051012552221265025564 0ustar www-datawww-datarequire 'runtime/interval_skip_list/spec_helper' describe IntervalSkipList, :palindromic => true do include PalindromicFixtureSharedContext describe "#overlapping" do it "returns intervals :d, :e, :f, and :g for 7..9" do list.overlapping(7..9)[0].should have_markers(:d, :e, :f, :g) end it "returns intervals :b, :c, :d, :e, :f, and :g for 3..7" do list.overlapping(3..7)[0].should have_markers(:b, :c, :d, :e, :f, :g ) end it "returns intervals :b, :c, :d, :e, :f, and :g for 3..6" do list.overlapping(3..6)[0].should have_markers(:b, :c, :d, :e, :f, :g ) end describe ", when :x is inserted on 3..7" do before do list.insert(3..7, :x) end it "returns intervals :b, :c, :d, :e, :f, :x for 3..5" do list.overlapping(3..5)[0].should have_markers(:b, :c, :d, :e, :f, :x) end end end describe "when 7..7 is expired with a length change of 0" do before do list.expire(7..7, 0) end describe " #nodes" do attr_reader :nodes, :node before do @nodes = list.nodes end it "has a size of 4" do nodes.size.should == 4 end describe "[0]" do before do @node = nodes[0] end it "has a key of 1 and a height of 3" do node.key.should == 1 node.height.should == 3 end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :a and :b as its only forward markers on level 1" do node.forward_markers[1].should have_markers(:a, :b) end it "has :c as its only forward marker on level 2" do node.forward_markers[2].should have_markers(:c) end it "has no markers" do node.markers.should be_empty end end describe "[1]" do before do @node = nodes[1] end it "has a key of 3 and a height of 2" do node.key.should == 3 node.height.should == 2 end it "has :b as its only forward marker on level 0" do node.forward_markers[0].should have_markers(:b) end it "has no forward markers on level 1" do node.forward_markers[1].should be_empty end it "has :a and :b as its only markers" do node.markers.should have_markers(:a, :b) end end describe "[2]" do before do @node = nodes[2] end it "has a key of 5 and a height of 1" do node.key.should == 5 node.height.should == 1 end it "has no forward markers on level 0" do node.forward_markers[0].should be_empty end it "has :b as its only marker" do node.markers.should have_markers(:b) end end describe "[3]" do before do @node = nodes[3] end it "has a key of 7 and a height of 3" do node.key.should == 7 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :c as its only marker" do node.markers.should have_markers(:c) end end end end describe "when 4..4 is expired with a length change of 2" do before do list.expire(4..4, 2) end describe " #nodes" do attr_reader :nodes, :node before do @nodes = list.nodes end it "has a size of 4" do nodes.size.should == 4 end describe "[0]" do before do @node = nodes[0] end it "has a key of 1 and a height of 3" do node.key.should == 1 node.height.should == 3 end it "has no forward markers at level 0 and 2" do node.forward_markers[0].should be_empty node.forward_markers[2].should be_empty end it "has :a as its only forward marker on level 1" do node.forward_markers[1].should have_markers(:a) end it "has no markers" do node.markers.should be_empty end end describe "[1]" do before do @node = nodes[1] end it "has a key of 3 and a height of 2" do node.key.should == 3 node.height.should == 2 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty end it "has :a as its only marker" do node.markers.should have_markers(:a) end end describe "[2]" do before do @node = nodes[2] end it "has a key of 7 and a height of 1" do node.key.should == 7 node.height.should == 1 end it "has :g as its only forward marker at level 0" do node.forward_markers[0].should have_markers(:g) end it "has no markers" do node.markers.should be_empty end end describe "[3]" do before do @node = nodes[3] end it "has a key of 15 and a height of 3" do node.key.should == 15 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :g as its only marker" do node.markers.should have_markers(:g) end end end end describe "when :x is inserted on 1..5, :y on 7..11, and :z on 9..13" do before do list.insert(1..5, :x) list.insert(7..11, :y) list.insert(9..13, :z) end describe "when 4..8 is expired with a length change of -3" do before do list.expire(4..8, -3) end describe "#nodes" do attr_reader :nodes, :node before do @nodes = list.nodes end it "has a size of 4" do nodes.size.should == 4 end describe "[0]" do before do @node = nodes[0] end it "has a key of 1 and height of 3" do node.key.should == 1 node.height.should == 3 end it "has :a as its only forward marker on level 1" do node.forward_markers[1].should have_markers(:a) end it "has no forward markers at level 0 and 2" do node.forward_markers[0].should be_empty node.forward_markers[2].should be_empty end it "has no markers" do node.markers.should be_empty end end describe "[1]" do before do @node = nodes[1] end it "has a key of 3 and height of 2" do node.key.should == 3 node.height.should == 2 end it "has no forward markers" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty end it "has :a as its only marker" do node.markers.should have_markers(:a) end end describe "[2]" do before do @node = nodes[2] end it "has a key of 6 and a height of 1" do node.key.should == 6 node.height.should == 1 end it "has :z as its only forward marker at level 0" do node.forward_markers[0].should have_markers(:z) end it "has no markers" do node.markers.should be_empty end end describe "[3]" do before do @node = nodes[3] end it "has a key of 10 and height of 3" do node.key.should == 10 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :z as its only marker" do node.markers.should have_markers(:z) end end end end end end treetop-1.6.3/spec/runtime/interval_skip_list/delete_spec.rb0000644000004100000410000000672712552221265024374 0ustar www-datawww-datarequire 'runtime/interval_skip_list/spec_helper' class IntervalSkipList public :insert_node, :delete_node, :head, :nodes end describe IntervalSkipList, :palindromic => true do include PalindromicFixtureSharedContext describe " when :c is deleted" do before do list.delete(:c) end describe "[0]" do before do @node = list.nodes[0] end it "has a key of 1 and a height of 3" do node.key.should == 1 node.height.should == 3 end it "has :f as its only forward marker at level 2" do node.forward_markers[2].should have_markers(:f) end it "has :a, :b, :d, and :e as its only forward markers at level 1" do node.forward_markers[1].should have_markers(:a, :b, :d, :e) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has no markers" do node.markers.should be_empty end end describe "[1]" do before do @node = list.nodes[1] end it "has a key of 3 and a height of 2" do node.key.should == 3 node.height.should == 2 end it "has :e as its only forward marker at level 1" do node.forward_markers[1].should have_markers(:e) end it "has :b and :d as its only forward markers at level 0" do node.forward_markers[0].should have_markers(:b, :d) end it "has :a, :b, :d, and :e as its only markers" do node.markers.should have_markers(:a, :b, :d, :e) end end describe "[2]" do before do @node = list.nodes[2] end it "has a key of 5 and a height of 1" do node.key.should == 5 node.height.should == 1 end it "has :d and :g as its only forward markers at level 0" do node.forward_markers[0].should have_markers(:d, :g) end it "has :b and :d as its only markers" do node.markers.should have_markers(:b, :d) end end describe "[3]" do before do @node = list.nodes[3] end it "has a key of 9 and a height of 1" do node.key.should == 9 node.height.should == 1 end it "has :g as its only forward marker at level 0" do node.forward_markers[0].should have_markers(:g) end it "has :d and :g as its only markers" do node.markers.should have_markers(:d, :g) end end describe "[4]" do before do @node = list.nodes[4] end it "has a key of 11 and a height of 2" do node.key.should == 11 node.height.should == 2 end it "has :g as its only forward marker at level 1" do node.forward_markers[1].should have_markers(:g) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :e and :g as its only markers" do node.markers.should have_markers(:e, :g) end end describe "[5]" do before do @node = list.nodes[5] end it "has a key of 13 and a height of 3" do node.key.should == 13 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :f and :g as its only markers" do node.markers.should have_markers(:f, :g) end end end end treetop-1.6.3/spec/runtime/interval_skip_list/insert_and_delete_node_spec.rb0000644000004100000410000002240612552221265027577 0ustar www-datawww-datarequire 'runtime/interval_skip_list/spec_helper' shared_examples_for "it is non-empty" do specify "#empty? returns false" do list.should_not be_empty end end shared_examples_for "#nodes is an array of the three inserted nodes in key order" do specify "#nodes is an array of the three inserted nodes in key order" do list.nodes.should == inserted_nodes.sort_by(&:key) end end shared_examples_for "it has nil forward pointers" do it "has nil forward pointers" do inserted_node.forward.each do |next_pointer| next_pointer.should be_nil end end end describe IntervalSkipList do attr_reader :list before do @list = IntervalSkipList.new end describe " when nothing has been inserted" do specify "#empty? returns true" do list.should be_empty end specify "#nodes returns an empty array" do list.nodes.should == [] end describe "#head" do attr_reader :head before do @head = list.head end it "#has a height of #max_height" do head.height.should == list.max_height end it "has nil forward pointers" do 0.upto(list.max_height - 1) do |i| head.forward[i].should be_nil end end end end describe " when 1 has been inserted", :deterministic => true do attr_reader :inserted_node, :inserted_nodes def expected_node_heights [1] end include NextNodeHeightIsDeterministicSharedContext before do @inserted_node = list.insert_node(1) @inserted_nodes = [@inserted_node] end it_should_behave_like "it is non-empty" it_should_behave_like "#nodes is an array of the three inserted nodes in key order" describe "#head" do attr_reader :head before do @head = list.head end it "has inserted_node.height forward pointers pointing at the inserted node" do 0.upto(inserted_node.height - 1) do |i| head.forward[i].should == inserted_node end end it "has the rest of its forward pointers pointing at nil" do inserted_node.height.upto(list.max_height - 1) do |i| head.forward[i].should == nil end end end describe "the inserted node" do it_should_behave_like "it has nil forward pointers" it "has a height of the expected_node_heights.first" do inserted_node.height.should == expected_node_heights.first end it "has a key of 1" do inserted_node.key.should == 1 end end describe "and subsequently deleted" do before do list.delete_node(1) end specify "#empty? returns true" do list.should be_empty end end end describe " when 1 and 3 have been inserted in order", :deterministic => true do attr_reader :inserted_nodes def expected_node_heights [1, 2] end include NextNodeHeightIsDeterministicSharedContext before do @inserted_nodes = [] inserted_nodes << list.insert_node(1) inserted_nodes << list.insert_node(3) end it_should_behave_like "it is non-empty" it_should_behave_like "#nodes is an array of the three inserted nodes in key order" describe "the first inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[0] end it "has a key of 1" do inserted_node.key.should == 1 end it "has a height of the first expected node height" do inserted_node.height.should == expected_node_heights[0] end it "has its single forward pointer pointing at the second inserted node" do inserted_node.forward[0].should == inserted_nodes[1] end end describe "the second inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[1] end it_should_behave_like "it has nil forward pointers" it "has a key of 3" do inserted_node.key.should == 3 end it "has a height of the second expected node height" do inserted_node.height.should == expected_node_heights[1] end end describe "and 1 is subsequently deleted" do before do list.delete_node(1) end describe "the remaining node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[1] end it "is the first node in the list" do inserted_node.should == list.nodes[0] end it_should_behave_like "it has nil forward pointers" end end describe "and 3 is subsequently deleted" do before do list.delete_node(3) end describe "the remaining node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[0] end it "is the first node in the list" do inserted_node.should == list.nodes[0] end it_should_behave_like "it has nil forward pointers" end end end describe " when 1, 3 and 7 have been inserted in order", :deterministic => true do attr_reader :inserted_nodes def expected_node_heights [1, 2, 1] end include NextNodeHeightIsDeterministicSharedContext before do @inserted_nodes = [] inserted_nodes << list.insert_node(1) inserted_nodes << list.insert_node(3) inserted_nodes << list.insert_node(7) end it_should_behave_like "it is non-empty" it_should_behave_like "#nodes is an array of the three inserted nodes in key order" describe "the first inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[0] end it "has a key of 1" do inserted_node.key.should == 1 end it "has a height of the first expected node height" do inserted_node.height.should == expected_node_heights[0] end it "has its single forward pointer pointing at the second inserted node" do inserted_node.forward[0].should == inserted_nodes[1] end end describe "the second inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[1] end it "has a key of 3" do inserted_node.key.should == 3 end it "has a height of the second expected node height" do inserted_node.height.should == expected_node_heights[1] end it "has a forward pointer at level 0 pointing to the third inserted node" do inserted_node.forward[0].should == inserted_nodes[2] end it "has nil forward pointer at level 1" do inserted_node.forward[1].should be_nil end end describe "the third inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[2] end it_should_behave_like "it has nil forward pointers" it "has a key of 3" do inserted_node.key.should == 7 end it "has a height of the third expected node height" do inserted_node.height.should == expected_node_heights[2] end end describe "and 3 is subsequently deleted" do before do list.delete_node(3) end specify "#head points at nil at levels 1 and 2" do list.head.forward[1].should be_nil list.head.forward[2].should be_nil end specify "#nodes contains the remaining nodes in order" do list.nodes.should == [inserted_nodes[0], inserted_nodes[2]] end end end describe " when 7, 1 and 3 have been inserted in order", :deterministic => true do attr_reader :inserted_nodes def expected_node_heights [1, 1, 2] end include NextNodeHeightIsDeterministicSharedContext before do @inserted_nodes = [] inserted_nodes << list.insert_node(7) inserted_nodes << list.insert_node(1) inserted_nodes << list.insert_node(3) end it_should_behave_like "it is non-empty" it_should_behave_like "#nodes is an array of the three inserted nodes in key order" describe "the first inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[0] end it_should_behave_like "it has nil forward pointers" it "has a key of 7" do inserted_node.key.should == 7 end it "has a height of the first expected node height" do inserted_node.height.should == expected_node_heights[0] end end describe "the second inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[1] end it "has a key of 1" do inserted_node.key.should == 1 end it "has a height of the second expected node height" do inserted_node.height.should == expected_node_heights[1] end it "has a forward pointer at level 0 pointing to the second node in the list" do inserted_node.forward[0].should == list.nodes[1] end end describe "the third inserted node" do attr_reader :inserted_node before do @inserted_node = inserted_nodes[2] end it "has a key of 3" do inserted_node.key.should == 3 end it "has a height of the third expected node height" do inserted_node.height.should == expected_node_heights[2] end end end endtreetop-1.6.3/spec/runtime/interval_skip_list/interval_skip_list_spec.rb0000644000004100000410000000345412552221265027031 0ustar www-datawww-data#require 'runtime/interval_skip_list/spec_helper' # #MAX_INTERVAL = 100000 # #describe IntervalSkipList do # describe "#next_node_height" do # attr_reader :list # # before do # @list = IntervalSkipList.new # end # # it "returns a number between 1 and the max_height of the list" do # height = list.next_node_height # height.should be <= list.max_height # height.should be > 0 # end # end # # describe "a list with 1000 random intervals" do # attr_reader :list, :inserted_ranges # # before do # @list = IntervalSkipList.new # @inserted_ranges = [] # # 0.upto(10) do |i| # first, last = [rand(MAX_INTERVAL), rand(MAX_INTERVAL)].sort # range = first..last # list.insert(range, i) # inserted_ranges.push(range) # end # end # # it "functions correctly for stabbing queries" do # 10000.times do # n = rand(MAX_INTERVAL) # ranges = list.containing(n).sort # # expected_ranges = [] # inserted_ranges.each_with_index do |range,i| # expected_ranges.push(i) if n > range.first && n < range.last # end # expected_ranges.sort! # unless ranges == expected_ranges # puts "N = #{n}" # puts "Expected: " + expected_ranges.inspect # puts "Actual: " + ranges.inspect # expected_ranges.size.should be <= ranges.size # puts "Missing containers: #{(expected_ranges.map {|o| o.object_id} - ranges.map {|o| o.object_id}).inspect}" # puts "Unexpected containers: #{(ranges.map {|o| o.object_id} - expected_ranges.map {|o| o.object_id}).inspect}" # puts "Inserted Ranges: #{inserted_ranges.inspect}" # puts "Expected Ranges: #{expected_ranges.map {|i| inserted_ranges[i]}.inspect}" # end # end # end # end #end treetop-1.6.3/spec/runtime/interval_skip_list/insert_spec.rb0000644000004100000410000004371012552221265024427 0ustar www-datawww-datarequire 'runtime/interval_skip_list/spec_helper' describe IntervalSkipList, " when #next_node_height returns 1, 3, 2, 3, 1 in order", :deterministic => true do include IntervalSkipListSpecHelper attr_reader :list, :node before do @list = IntervalSkipList.new end include NextNodeHeightIsDeterministicSharedContext def expected_node_heights [1, 3, 2, 3, 1] end describe ", when :a is inserted on 1..7" do before do list.insert(1..7, :a) end describe ", #containing" do it "returns only :a from 2 through 6" do (2..6).should contain_marker(:a) end it "returns nothing at 1 and 7" do list.containing(1).should be_empty list.containing(7).should be_empty end end describe " #nodes[0]" do before do @node = list.nodes[0] end it "has a key of 1 and height of 1" do node.key.should == 1 node.height.should == 1 end it "has :a as its only marker at level 0" do node.forward_markers[0].should have_marker(:a) end it "has no markers" do node.markers.should be_empty end it "is an endpoint of only :a" do node.endpoint_of.should have_marker(:a) end end describe " #nodes[1]" do before do @node = list.nodes[1] end it "has a key of 7 and height of 3" do node.key.should == 7 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :a as its only marker" do node.markers.should have_marker(:a) end it "is an endpoint of only :a" do node.endpoint_of.should have_marker(:a) end end describe ", and then :b is inserted on 1..5" do before do list.insert(1..5, :b) end describe ", #containing" do it "returns only :a and :b from 2 through 4" do (2..4).should contain_markers(:a, :b) end it "returns only :a from 5 through 6" do (5..6).should contain_marker(:a) end it "returns nothing at 1 and 7" do list.containing(1).should be_empty list.containing(7).should be_empty end end describe " #nodes[0]" do before do @node = list.nodes[0] end it "has a key of 1 and height of 1" do node.key.should == 1 node.height.should == 1 end it "has :a and :b as its only forward markers at level 0" do node.forward_markers[0].should have_markers(:a, :b) end it "has no markers" do node.markers.should be_empty end it "is an endpoint of only :a and :b" do node.endpoint_of.should have_markers(:a, :b) end end describe " #nodes[1]" do before do @node = list.nodes[1] end it "has a key of 5 and height of 2" do node.key.should == 5 node.height.should == 2 end it "has :a as its only forward marker at level 1" do node.forward_markers[1].should have_marker(:a) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :a and :b as its only markers" do node.markers.should have_markers(:a, :b) end it "is an endpoint of only :b" do node.endpoint_of.should have_marker(:b) end end describe " #nodes[2]" do before do @node = list.nodes[2] end it "has a key of 7 and height of 3" do node.key.should == 7 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :a its only marker" do node.markers.should have_marker(:a) end it "is an endpoint of only :a" do node.endpoint_of.should have_marker(:a) end end describe ", and then :c is inserted on 1..3" do before do list.insert(1..3, :c) end describe ", #containing" do it "returns only :a, :b, and :c for 2" do (2..2).should contain_markers(:a, :b, :c) end it "returns only :a, :b from 3..4" do (3..4).should contain_markers(:a, :b) end it "returns only :a from 5..6" do (5..6).should contain_markers(:a) end it "returns nothing at 1 and 7" do list.containing(1).should be_empty list.containing(7).should be_empty end end describe " #nodes[0]" do before do @node = list.nodes[0] end it "has a key of 1 and height of 1" do node.key.should == 1 node.height.should == 1 end it "has :a, :b, :c as its only forward markers at level 0" do node.forward_markers[0].should have_markers(:a, :b, :c) end it "has no markers" do node.markers.should be_empty end it "is an endpoint of only :a, :b, :c" do node.endpoint_of.should have_markers(:a, :b, :c) end end describe " #nodes[1]" do before do @node = list.nodes[1] end it "has a key of 3 and height of 3" do node.key.should == 3 node.height.should == 3 end it "has :a as its only forward marker at level 2" do node.forward_markers[2].should have_marker(:a) end it "has :b as its only forward marker at level 1" do node.forward_markers[1].should have_marker(:b) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :a, :b, and :c as its only markers" do node.markers.should have_markers(:a, :b, :c) end it "is an endpoint of only :c" do node.endpoint_of.should have_marker(:c) end end describe " #nodes[2]" do before do @node = list.nodes[2] end it "has a key of 5 and height of 2" do node.key.should == 5 node.height.should == 2 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty end it "has :b as its only markers" do node.markers.should have_marker(:b) end it "is an endpoint of only :b" do node.endpoint_of.should have_marker(:b) end end describe " #nodes[3]" do before do @node = list.nodes[3] end it "has a key of 7 and height of 3" do node.key.should == 7 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :a as its only marker" do node.markers.should have_marker(:a) end it "is an endpoint of only :a" do node.endpoint_of.should have_marker(:a) end end describe ", and then :d is inserted on 1..9" do before do list.insert(1..9, :d) end describe ", #containing" do it "returns only :a, :b, :c, and :d for 2" do (2..2).should contain_markers(:a, :b, :c, :d) end it "returns only :a, :b from 3..4" do (3..4).should contain_markers(:a, :b, :d) end it "returns only :a from 5..6" do (5..6).should contain_markers(:a, :d) end it "returns only :a from 7..8" do (7..8).should contain_markers(:d) end it "returns nothing at 1 and 9" do list.containing(1).should be_empty list.containing(9).should be_empty end it "returns nothing for -1, 0, and 10" do list.containing(-1).should be_empty list.containing(0).should be_empty list.containing(10).should be_empty end end describe " #nodes[0]" do before do @node = list.nodes[0] end it "has a key of 1 and height of 1" do node.key.should == 1 node.height.should == 1 end it "has :a, :b, :c, :d as its only forward markers at level 0" do node.forward_markers[0].should have_markers(:a, :b, :c, :d) end it "has no markers" do node.markers.should be_empty end it "is an endpoint of only :a, :b, :c, and :d" do node.endpoint_of.should have_markers(:a, :b, :c, :d) end end describe " #nodes[1]" do before do @node = list.nodes[1] end it "has a key of 3 and height of 3" do node.key.should == 3 node.height.should == 3 end it "has :a and :d as its only forward markers at level 2" do node.forward_markers[2].should have_markers(:a, :d) end it "has :b as its only marker at level 1" do node.forward_markers[1].should have_marker(:b) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :a, :b, :c, :d as its only markers" do node.markers.should have_markers(:a, :b, :c, :d) end it "is an endpoint of only :c" do node.endpoint_of.should have_marker(:c) end end describe " #nodes[2]" do before do @node = list.nodes[2] end it "has a key of 5 and height of 2" do node.key.should == 5 node.height.should == 2 end it "has no markers on any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty end it "has :b as its only marker" do node.markers.should have_marker(:b) end it "is an endpoint of only :b" do node.endpoint_of.should have_marker(:b) end end describe " #nodes[3]" do before do @node = list.nodes[3] end it "has a key of 7 and height of 3" do node.key.should == 7 node.height.should == 3 end it "has :d as its only marker at level 0" do node.forward_markers[0].should have_marker(:d) end it "has no forward markers at levels 1 and 2" do node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :a, :d as its only markers" do node.markers.should have_markers(:a, :d) end it "is an endpoint of only :a" do node.endpoint_of.should have_marker(:a) end end describe " #nodes[4]" do before do @node = list.nodes[4] end it "has a key of 9 and height of 1" do node.key.should == 9 node.height.should == 1 end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :d as its only marker" do node.markers.should have_marker(:d) end it "is an endpoint of only :d" do node.endpoint_of.should have_marker(:d) end end describe ", and then :d is deleted" do before do list.delete(:d) end it "has only 4 nodes" do list.nodes.size.should == 4 end describe " #nodes[0]" do before do @node = list.nodes[0] end it "has a key of 1 and height of 1" do node.key.should == 1 node.height.should == 1 end it "has :a, :b, and :c as its only forward markers at level 0" do node.forward_markers[0].should have_markers(:a, :b, :c) end end describe " #nodes[1]" do before do @node = list.nodes[1] end it "has a key of 3 and height of 3" do node.key.should == 3 node.height.should == 3 end it "has :a as its only forward marker at level 2" do node.forward_markers[2].should have_marker(:a) end it "has :b as its only forward marker at level 1" do node.forward_markers[1].should have_marker(:b) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :a, :b, and :c as its only markers" do node.markers.should have_markers(:a, :b, :c) end it "is the endpoint of only :c" do node.endpoint_of.should have_marker(:c) end end describe " #nodes[2]" do before do @node = list.nodes[2] end it "has a key of 5 and height of 2" do node.key.should == 5 node.height.should == 2 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty end it "has :b as its only marker" do node.markers.should have_marker(:b) end it "is the endpoint of only :b" do node.endpoint_of.should have_marker(:b) end end describe " #nodes[3]" do before do @node = list.nodes[3] end it "has a key of 7 and height of 3" do node.key.should == 7 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :a as its only marker" do node.markers.should have_marker(:a) end it "is the endpoint of only :a" do node.endpoint_of.should have_marker(:a) end end describe ", and then :c is deleted" do before do list.delete(:c) end it "has only 3 nodes" do list.nodes.size.should == 3 end describe " #nodes[0]" do before do @node = list.nodes[0] end it "has a key of 1 and height of 1" do node.key.should == 1 node.height.should == 1 end it "has :a and :b as its only forward markers at level 0" do node.forward_markers[0].should have_markers(:a, :b) end it "has no markers" do node.markers.should be_empty end it "is an endpoint of only :a and :b" do node.endpoint_of.should have_markers(:a, :b) end end describe " #nodes[1]" do before do @node = list.nodes[1] end it "has a key of 5 and height of 2" do node.key.should == 5 node.height.should == 2 end it "has :a as its only forward marker at level 1" do node.forward_markers[1].should have_marker(:a) end it "has no forward markers at level 0" do node.forward_markers[0].should be_empty end it "has :a and :b as its only markers" do node.markers.should have_markers(:a, :b) end it "is an endpoint of only :b" do node.endpoint_of.should have_marker(:b) end end describe " #nodes[2]" do before do @node = list.nodes[2] end it "has a key of 7 and height of 3" do node.key.should == 7 node.height.should == 3 end it "has no forward markers at any level" do node.forward_markers[0].should be_empty node.forward_markers[1].should be_empty node.forward_markers[2].should be_empty end it "has :a its only marker" do node.markers.should have_marker(:a) end it "is an endpoint of only :a" do node.endpoint_of.should have_marker(:a) end end end end end end end end end treetop-1.6.3/spec/runtime/syntax_node_spec.rb0000644000004100000410000000417512552221265021553 0ustar www-datawww-datarequire 'spec_helper' module SyntaxNodeSpec describe "A new terminal syntax node" do attr_reader :node before do @node = Runtime::SyntaxNode.new("input", 0...3) end it "reports itself as terminal" do node.should be_terminal node.should_not be_nonterminal end it "has a text value based on the input and the interval" do node.text_value.should == "inp" end it "has itself as its only element" do node.elements.should be_nil end end describe "A new nonterminal syntax node" do attr_reader :node before do @elements = [Runtime::SyntaxNode.new('input', 0...3)] @node = Runtime::SyntaxNode.new('input', 0...3, @elements) end it "reports itself as nonterminal" do node.should be_nonterminal node.should_not be_terminal end it "has a text value based on the input and the interval" do node.text_value.should == "inp" end it "has the elements with which it was instantiated" do node.elements.should == @elements end it "sets itself as the parent of its elements" do node.elements.each do |element| element.parent.should == node end end end describe "A new nonterminal syntax node with all children lazily instantiated" do attr_reader :node it "should lazily instantiate its child nodes" do @node = Runtime::SyntaxNode.new('input', 0...3, [true, true, true]) node.elements.size.should == 3 node.elements.first.interval.should == (0...1) node.elements.first.parent.should == node end it "should lazily replace stand-in child nodes around real ones" do @input = "input" child1 = Runtime::SyntaxNode.new(@input, 1...2) child2 = Runtime::SyntaxNode.new(@input, 3...4) @node = Runtime::SyntaxNode.new(@input, 0...5, [true, child1, true, child2, true]) node.elements.size.should == 5 node.elements[0].interval.should == (0...1) node.elements[0].parent.should == node 0.upto(4) do |index| node.elements[index].text_value.should == @input[index, 1] end end end end treetop-1.6.3/lib/0000755000004100000410000000000012552221265014003 5ustar www-datawww-datatreetop-1.6.3/lib/treetop.rb0000644000004100000410000000012012552221265016003 0ustar www-datawww-datarequire 'treetop/runtime' require 'treetop/compiler' require 'treetop/polyglot' treetop-1.6.3/lib/treetop/0000755000004100000410000000000012552221265015465 5ustar www-datawww-datatreetop-1.6.3/lib/treetop/compiler/0000755000004100000410000000000012552221265017277 5ustar www-datawww-datatreetop-1.6.3/lib/treetop/compiler/metagrammar.rb0000644000004100000410000033213412552221265022127 0ustar www-datawww-data# Autogenerated from a Treetop grammar. Edits may be lost. module Treetop module Compiler module Metagrammar include Treetop::Runtime def root @root ||= :treetop_file end module TreetopFile0 def require_statement elements[1] end end module TreetopFile1 def requires elements[0] end def spacing elements[1] end def module_or_grammar elements[2] end def suffix elements[3] end end module TreetopFile2 def compile requires.text_value + spacing.text_value + module_or_grammar.compile + suffix.text_value end end def _nt_treetop_file start_index = index if node_cache[:treetop_file].has_key?(index) cached = node_cache[:treetop_file][index] if cached node_cache[:treetop_file][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] s1, i1 = [], index loop do i2, s2 = index, [] r4 = _nt_space if r4 r3 = r4 else r3 = instantiate_node(SyntaxNode,input, index...index) end s2 << r3 if r3 r5 = _nt_require_statement s2 << r5 end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(TreetopFile0) else @index = i2 r2 = nil end if r2 s1 << r2 else break end end r1 = instantiate_node(SyntaxNode,input, i1...index, s1) s0 << r1 if r1 r7 = _nt_space if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 if r6 r8 = _nt_module_or_grammar s0 << r8 if r8 r10 = _nt_space if r10 r9 = r10 else r9 = instantiate_node(SyntaxNode,input, index...index) end s0 << r9 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(TreetopFile1) r0.extend(TreetopFile2) else @index = i0 r0 = nil end node_cache[:treetop_file][start_index] = r0 r0 end module RequireStatement0 def spacing elements[0] end end def _nt_require_statement start_index = index if node_cache[:require_statement].has_key?(index) cached = node_cache[:require_statement][index] if cached node_cache[:require_statement][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_space if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 if (match_len = has_terminal?("require", false, index)) r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure("require") r3 = nil end s0 << r3 if r3 s4, i4 = [], index loop do if has_terminal?(@regexps[gr = '\A[ \\t]'] ||= Regexp.new(gr), :regexp, index) r5 = true @index += 1 else terminal_parse_failure('[ \\t]') r5 = nil end if r5 s4 << r5 else break end end if s4.empty? @index = i4 r4 = nil else r4 = instantiate_node(SyntaxNode,input, i4...index, s4) end s0 << r4 if r4 s6, i6 = [], index loop do if has_terminal?(@regexps[gr = '\A[^\\n\\r]'] ||= Regexp.new(gr), :regexp, index) r7 = true @index += 1 else terminal_parse_failure('[^\\n\\r]') r7 = nil end if r7 s6 << r7 else break end end if s6.empty? @index = i6 r6 = nil else r6 = instantiate_node(SyntaxNode,input, i6...index, s6) end s0 << r6 if r6 if has_terminal?(@regexps[gr = '\A[\\n\\r]'] ||= Regexp.new(gr), :regexp, index) r8 = true @index += 1 else terminal_parse_failure('[\\n\\r]') r8 = nil end s0 << r8 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(RequireStatement0) else @index = i0 r0 = nil end node_cache[:require_statement][start_index] = r0 r0 end def _nt_module_or_grammar start_index = index if node_cache[:module_or_grammar].has_key?(index) cached = node_cache[:module_or_grammar][index] if cached node_cache[:module_or_grammar][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_module_declaration if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_grammar if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:module_or_grammar][start_index] = r0 r0 end module ModuleDeclaration0 end module ModuleDeclaration1 end module ModuleDeclaration2 def space1 elements[1] end def name elements[2] end def space2 elements[3] end end module ModuleDeclaration3 def space elements[0] end end module ModuleDeclaration4 def module_prefix elements[0] end def module_contents elements[1] end def suffix elements[2] end end module ModuleDeclaration5 def compile module_prefix.text_value + module_contents.compile + suffix.text_value end def parser_name module_prefix.name.text_value+'::'+module_contents.parser_name end end def _nt_module_declaration start_index = index if node_cache[:module_declaration].has_key?(index) cached = node_cache[:module_declaration][index] if cached node_cache[:module_declaration][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i1, s1 = index, [] if (match_len = has_terminal?('module', false, index)) r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('module') r2 = nil end s1 << r2 if r2 r3 = _nt_space s1 << r3 if r3 i4, s4 = index, [] if has_terminal?(@regexps[gr = '\A[A-Z]'] ||= Regexp.new(gr), :regexp, index) r5 = true @index += 1 else terminal_parse_failure('[A-Z]') r5 = nil end s4 << r5 if r5 s6, i6 = [], index loop do r7 = _nt_alphanumeric_char if r7 s6 << r7 else break end end r6 = instantiate_node(SyntaxNode,input, i6...index, s6) s4 << r6 if r6 s8, i8 = [], index loop do i9, s9 = index, [] if (match_len = has_terminal?('::', false, index)) r10 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('::') r10 = nil end s9 << r10 if r10 if has_terminal?(@regexps[gr = '\A[A-Z]'] ||= Regexp.new(gr), :regexp, index) r11 = true @index += 1 else terminal_parse_failure('[A-Z]') r11 = nil end s9 << r11 if r11 s12, i12 = [], index loop do r13 = _nt_alphanumeric_char if r13 s12 << r13 else break end end r12 = instantiate_node(SyntaxNode,input, i12...index, s12) s9 << r12 end end if s9.last r9 = instantiate_node(SyntaxNode,input, i9...index, s9) r9.extend(ModuleDeclaration0) else @index = i9 r9 = nil end if r9 s8 << r9 else break end end r8 = instantiate_node(SyntaxNode,input, i8...index, s8) s4 << r8 end end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(ModuleDeclaration1) else @index = i4 r4 = nil end s1 << r4 if r4 r14 = _nt_space s1 << r14 end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(ModuleDeclaration2) else @index = i1 r1 = nil end s0 << r1 if r1 i15 = index r16 = _nt_module_declaration if r16 r16 = SyntaxNode.new(input, (index-1)...index) if r16 == true r15 = r16 else r17 = _nt_grammar if r17 r17 = SyntaxNode.new(input, (index-1)...index) if r17 == true r15 = r17 else @index = i15 r15 = nil end end s0 << r15 if r15 i18, s18 = index, [] r19 = _nt_space s18 << r19 if r19 if (match_len = has_terminal?('end', false, index)) r20 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('end') r20 = nil end s18 << r20 end if s18.last r18 = instantiate_node(SyntaxNode,input, i18...index, s18) r18.extend(ModuleDeclaration3) else @index = i18 r18 = nil end s0 << r18 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ModuleDeclaration4) r0.extend(ModuleDeclaration5) else @index = i0 r0 = nil end node_cache[:module_declaration][start_index] = r0 r0 end module Grammar0 def space elements[1] end end module Grammar1 def space1 elements[1] end def grammar_name elements[2] end def space2 elements[3] end def declaration_sequence elements[5] end end def _nt_grammar start_index = index if node_cache[:grammar].has_key?(index) cached = node_cache[:grammar][index] if cached node_cache[:grammar][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('grammar', false, index)) r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('grammar') r1 = nil end s0 << r1 if r1 r2 = _nt_space s0 << r2 if r2 r3 = _nt_grammar_name s0 << r3 if r3 r4 = _nt_space s0 << r4 if r4 i6, s6 = index, [] if (match_len = has_terminal?('do', false, index)) r7 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('do') r7 = nil end s6 << r7 if r7 r8 = _nt_space s6 << r8 end if s6.last r6 = instantiate_node(SyntaxNode,input, i6...index, s6) r6.extend(Grammar0) else @index = i6 r6 = nil end if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s0 << r5 if r5 r9 = _nt_declaration_sequence s0 << r9 if r9 r11 = _nt_space if r11 r10 = r11 else r10 = instantiate_node(SyntaxNode,input, index...index) end s0 << r10 if r10 if (match_len = has_terminal?('end', false, index)) r12 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('end') r12 = nil end s0 << r12 end end end end end end end if s0.last r0 = instantiate_node(Grammar,input, i0...index, s0) r0.extend(Grammar1) else @index = i0 r0 = nil end node_cache[:grammar][start_index] = r0 r0 end module GrammarName0 end def _nt_grammar_name start_index = index if node_cache[:grammar_name].has_key?(index) cached = node_cache[:grammar_name][index] if cached node_cache[:grammar_name][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?(@regexps[gr = '\A[A-Z]'] ||= Regexp.new(gr), :regexp, index) r1 = true @index += 1 else terminal_parse_failure('[A-Z]') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_alphanumeric_char if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(GrammarName0) else @index = i0 r0 = nil end node_cache[:grammar_name][start_index] = r0 r0 end module DeclarationSequence0 def space elements[0] end def declaration elements[1] end end module DeclarationSequence1 def head elements[0] end def tail elements[1] end end module DeclarationSequence2 def declarations [head] + tail end def tail super.elements.map { |elt| elt.declaration } end end module DeclarationSequence3 def compile(builder) end end def _nt_declaration_sequence start_index = index if node_cache[:declaration_sequence].has_key?(index) cached = node_cache[:declaration_sequence][index] if cached node_cache[:declaration_sequence][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_declaration s1 << r2 if r2 s3, i3 = [], index loop do i4, s4 = index, [] r5 = _nt_space s4 << r5 if r5 r6 = _nt_declaration s4 << r6 end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(DeclarationSequence0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s1 << r3 end if s1.last r1 = instantiate_node(DeclarationSequence,input, i1...index, s1) r1.extend(DeclarationSequence1) r1.extend(DeclarationSequence2) else @index = i1 r1 = nil end if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else if (match_len = has_terminal?('', false, index)) r7 = instantiate_node(SyntaxNode,input, index...(index + match_len)) r7.extend(DeclarationSequence3) @index += match_len else terminal_parse_failure('') r7 = nil end if r7 r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r0 = r7 else @index = i0 r0 = nil end end node_cache[:declaration_sequence][start_index] = r0 r0 end def _nt_declaration start_index = index if node_cache[:declaration].has_key?(index) cached = node_cache[:declaration][index] if cached node_cache[:declaration][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_parsing_rule if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_include_declaration if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:declaration][start_index] = r0 r0 end module IncludeDeclaration0 def space elements[1] end end module IncludeDeclaration1 def compile(builder) builder << text_value end end def _nt_include_declaration start_index = index if node_cache[:include_declaration].has_key?(index) cached = node_cache[:include_declaration][index] if cached node_cache[:include_declaration][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('include', false, index)) r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('include') r1 = nil end s0 << r1 if r1 r2 = _nt_space s0 << r2 if r2 if has_terminal?(@regexps[gr = '\A[A-Z]'] ||= Regexp.new(gr), :regexp, index) r3 = true @index += 1 else terminal_parse_failure('[A-Z]') r3 = nil end s0 << r3 if r3 s4, i4 = [], index loop do i5 = index r6 = _nt_alphanumeric_char if r6 r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r5 = r6 else if (match_len = has_terminal?('::', false, index)) r7 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('::') r7 = nil end if r7 r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r5 = r7 else @index = i5 r5 = nil end end if r5 s4 << r5 else break end end r4 = instantiate_node(SyntaxNode,input, i4...index, s4) s0 << r4 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(IncludeDeclaration0) r0.extend(IncludeDeclaration1) else @index = i0 r0 = nil end node_cache[:include_declaration][start_index] = r0 r0 end module ParsingRule0 def space elements[1] end end module ParsingRule1 def space1 elements[1] end def nonterminal elements[2] end def space2 elements[3] end def parsing_expression elements[5] end def space3 elements[6] end end def _nt_parsing_rule start_index = index if node_cache[:parsing_rule].has_key?(index) cached = node_cache[:parsing_rule][index] if cached node_cache[:parsing_rule][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('rule', false, index)) r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('rule') r1 = nil end s0 << r1 if r1 r2 = _nt_space s0 << r2 if r2 r3 = _nt_nonterminal s0 << r3 if r3 r4 = _nt_space s0 << r4 if r4 i6, s6 = index, [] if (match_len = has_terminal?('do', false, index)) r7 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('do') r7 = nil end s6 << r7 if r7 r8 = _nt_space s6 << r8 end if s6.last r6 = instantiate_node(SyntaxNode,input, i6...index, s6) r6.extend(ParsingRule0) else @index = i6 r6 = nil end if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s0 << r5 if r5 r9 = _nt_parsing_expression s0 << r9 if r9 r10 = _nt_space s0 << r10 if r10 if (match_len = has_terminal?('end', false, index)) r11 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('end') r11 = nil end s0 << r11 end end end end end end end if s0.last r0 = instantiate_node(ParsingRule,input, i0...index, s0) r0.extend(ParsingRule1) else @index = i0 r0 = nil end node_cache[:parsing_rule][start_index] = r0 r0 end def _nt_parsing_expression start_index = index if node_cache[:parsing_expression].has_key?(index) cached = node_cache[:parsing_expression][index] if cached node_cache[:parsing_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_choice if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_sequence if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_primary if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 r0 = nil end end end node_cache[:parsing_expression][start_index] = r0 r0 end module Choice0 def alternative elements[3] end end module Choice1 def head elements[0] end def tail elements[1] end end module Choice2 def alternatives [head] + tail end def tail super.elements.map {|elt| elt.alternative} end def inline_modules (alternatives.map {|alt| alt.inline_modules }).flatten end end def _nt_choice start_index = index if node_cache[:choice].has_key?(index) cached = node_cache[:choice][index] if cached node_cache[:choice][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_alternative s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] r5 = _nt_space if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s3 << r4 if r4 if (match_len = has_terminal?('/', false, index)) r6 = true @index += match_len else terminal_parse_failure('/') r6 = nil end s3 << r6 if r6 r8 = _nt_space if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end s3 << r7 if r7 r9 = _nt_alternative s3 << r9 end end end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(Choice0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 end if s0.last r0 = instantiate_node(Choice,input, i0...index, s0) r0.extend(Choice1) r0.extend(Choice2) else @index = i0 r0 = nil end node_cache[:choice][start_index] = r0 r0 end module Sequence0 def sequence_body elements[0] end def node_class_declarations elements[1] end end module Sequence1 def sequence_elements [sequence_body.head] + tail end def tail sequence_body.tail end def inline_modules (sequence_elements.map {|elt| elt.inline_modules}).flatten + [sequence_element_accessor_module] + node_class_declarations.inline_modules end def inline_module_name node_class_declarations.inline_module_name end end def _nt_sequence start_index = index if node_cache[:sequence].has_key?(index) cached = node_cache[:sequence][index] if cached node_cache[:sequence][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_sequence_body s0 << r1 if r1 r2 = _nt_node_class_declarations s0 << r2 end if s0.last r0 = instantiate_node(Sequence,input, i0...index, s0) r0.extend(Sequence0) r0.extend(Sequence1) else @index = i0 r0 = nil end node_cache[:sequence][start_index] = r0 r0 end def _nt_sequence_body start_index = index if node_cache[:sequence_body].has_key?(index) cached = node_cache[:sequence_body][index] if cached node_cache[:sequence_body][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_variable_length_sequence_body if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_labeled_expression_sequence_body if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:sequence_body][start_index] = r0 r0 end module VariableLengthSequenceBody0 def space elements[0] end def optionally_labeled_sequence_primary elements[1] end end module VariableLengthSequenceBody1 def head elements[0] end def tail elements[1] end end module VariableLengthSequenceBody2 def tail super.elements.map {|elt| elt.optionally_labeled_sequence_primary } end end def _nt_variable_length_sequence_body start_index = index if node_cache[:variable_length_sequence_body].has_key?(index) cached = node_cache[:variable_length_sequence_body][index] if cached node_cache[:variable_length_sequence_body][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_optionally_labeled_sequence_primary s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] r4 = _nt_space s3 << r4 if r4 r5 = _nt_optionally_labeled_sequence_primary s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(VariableLengthSequenceBody0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(VariableLengthSequenceBody1) r0.extend(VariableLengthSequenceBody2) else @index = i0 r0 = nil end node_cache[:variable_length_sequence_body][start_index] = r0 r0 end module LabeledExpressionSequenceBody0 def head self end def tail [] end end def _nt_labeled_expression_sequence_body start_index = index if node_cache[:labeled_expression_sequence_body].has_key?(index) cached = node_cache[:labeled_expression_sequence_body][index] if cached node_cache[:labeled_expression_sequence_body][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_labeled_sequence_primary r0.extend(LabeledExpressionSequenceBody0) node_cache[:labeled_expression_sequence_body][start_index] = r0 r0 end def _nt_alternative start_index = index if node_cache[:alternative].has_key?(index) cached = node_cache[:alternative][index] if cached node_cache[:alternative][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_sequence if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_primary if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:alternative][start_index] = r0 r0 end module Primary0 def prefix elements[0] end def atomic elements[1] end end module Primary1 def compile(address, builder, parent_expression=nil) prefix.compile(address, builder, self) end def prefixed_expression atomic end def inline_modules atomic.inline_modules end def inline_module_name nil end end module Primary2 def prefix elements[0] end def atomic elements[2] end end module Primary3 def compile(address, builder, parent_expression=nil) prefix.compile(address, builder, self) end def prefixed_expression atomic end def inline_modules [] end end module Primary4 def atomic elements[0] end def suffix elements[1] end def node_class_declarations elements[2] end end module Primary5 def compile(address, builder, parent_expression=nil) suffix.compile(address, builder, self) end def optional_expression atomic end def node_class_name node_class_declarations.node_class_name end def inline_modules atomic.inline_modules + node_class_declarations.inline_modules end def inline_module_name node_class_declarations.inline_module_name end end module Primary6 def atomic elements[0] end def node_class_declarations elements[1] end end module Primary7 def compile(address, builder, parent_expression=nil) atomic.compile(address, builder, self) end def node_class_name node_class_declarations.node_class_name end def inline_modules atomic.inline_modules + node_class_declarations.inline_modules end def inline_module_name node_class_declarations.inline_module_name end end def _nt_primary start_index = index if node_cache[:primary].has_key?(index) cached = node_cache[:primary][index] if cached node_cache[:primary][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_prefix s1 << r2 if r2 r3 = _nt_atomic s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Primary0) r1.extend(Primary1) else @index = i1 r1 = nil end if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else i4, s4 = index, [] r5 = _nt_prefix s4 << r5 if r5 r7 = _nt_space if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s4 << r6 if r6 r8 = _nt_predicate_block s4 << r8 end end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(Primary2) r4.extend(Primary3) else @index = i4 r4 = nil end if r4 r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else i9, s9 = index, [] r10 = _nt_atomic s9 << r10 if r10 r11 = _nt_suffix s9 << r11 if r11 r12 = _nt_node_class_declarations s9 << r12 end end if s9.last r9 = instantiate_node(SyntaxNode,input, i9...index, s9) r9.extend(Primary4) r9.extend(Primary5) else @index = i9 r9 = nil end if r9 r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r0 = r9 else i13, s13 = index, [] r14 = _nt_atomic s13 << r14 if r14 r15 = _nt_node_class_declarations s13 << r15 end if s13.last r13 = instantiate_node(SyntaxNode,input, i13...index, s13) r13.extend(Primary6) r13.extend(Primary7) else @index = i13 r13 = nil end if r13 r13 = SyntaxNode.new(input, (index-1)...index) if r13 == true r0 = r13 else @index = i0 r0 = nil end end end end node_cache[:primary][start_index] = r0 r0 end def _nt_optionally_labeled_sequence_primary start_index = index if node_cache[:optionally_labeled_sequence_primary].has_key?(index) cached = node_cache[:optionally_labeled_sequence_primary][index] if cached node_cache[:optionally_labeled_sequence_primary][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_labeled_sequence_primary if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_unlabeled_sequence_primary if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:optionally_labeled_sequence_primary][start_index] = r0 r0 end module LabeledSequencePrimary0 def named_label elements[0] end def sequence_primary elements[1] end end module LabeledSequencePrimary1 def compile(lexical_address, builder) sequence_primary.compile(lexical_address, builder) end def inline_modules sequence_primary.inline_modules end def label_name named_label.name end end def _nt_labeled_sequence_primary start_index = index if node_cache[:labeled_sequence_primary].has_key?(index) cached = node_cache[:labeled_sequence_primary][index] if cached node_cache[:labeled_sequence_primary][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_named_label s0 << r1 if r1 r2 = _nt_sequence_primary s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(LabeledSequencePrimary0) r0.extend(LabeledSequencePrimary1) else @index = i0 r0 = nil end node_cache[:labeled_sequence_primary][start_index] = r0 r0 end module UnlabeledSequencePrimary0 def null_label elements[0] end def sequence_primary elements[1] end end module UnlabeledSequencePrimary1 def compile(lexical_address, builder) sequence_primary.compile(lexical_address, builder) end def inline_modules sequence_primary.inline_modules end def label_name if sequence_primary.instance_of?(Nonterminal) sequence_primary.text_value else nil end end end def _nt_unlabeled_sequence_primary start_index = index if node_cache[:unlabeled_sequence_primary].has_key?(index) cached = node_cache[:unlabeled_sequence_primary][index] if cached node_cache[:unlabeled_sequence_primary][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_null_label s0 << r1 if r1 r2 = _nt_sequence_primary s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(UnlabeledSequencePrimary0) r0.extend(UnlabeledSequencePrimary1) else @index = i0 r0 = nil end node_cache[:unlabeled_sequence_primary][start_index] = r0 r0 end def _nt_label start_index = index if node_cache[:label].has_key?(index) cached = node_cache[:label][index] if cached node_cache[:label][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_named_label if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_null_label if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:label][start_index] = r0 r0 end module NamedLabel0 def alpha_char elements[0] end end module NamedLabel1 end module NamedLabel2 def name elements[0].text_value end end def _nt_named_label start_index = index if node_cache[:named_label].has_key?(index) cached = node_cache[:named_label][index] if cached node_cache[:named_label][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i1, s1 = index, [] r2 = _nt_alpha_char s1 << r2 if r2 s3, i3 = [], index loop do r4 = _nt_alphanumeric_char if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(NamedLabel0) else @index = i1 r1 = nil end s0 << r1 if r1 if (match_len = has_terminal?(':', false, index)) r5 = true @index += match_len else terminal_parse_failure(':') r5 = nil end s0 << r5 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(NamedLabel1) r0.extend(NamedLabel2) else @index = i0 r0 = nil end node_cache[:named_label][start_index] = r0 r0 end module NullLabel0 def name nil end end def _nt_null_label start_index = index if node_cache[:null_label].has_key?(index) cached = node_cache[:null_label][index] if cached node_cache[:null_label][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if (match_len = has_terminal?('', false, index)) r0 = instantiate_node(SyntaxNode,input, index...(index + match_len)) r0.extend(NullLabel0) @index += match_len else terminal_parse_failure('') r0 = nil end node_cache[:null_label][start_index] = r0 r0 end module SequencePrimary0 def prefix elements[0] end def atomic elements[1] end end module SequencePrimary1 def compile(lexical_address, builder) prefix.compile(lexical_address, builder, self) end def prefixed_expression elements[1] end def inline_modules atomic.inline_modules end def inline_module_name nil end end module SequencePrimary2 def prefix elements[0] end def atomic elements[2] end end module SequencePrimary3 def compile(address, builder, parent_expression=nil) prefix.compile(address, builder, self) end def prefixed_expression atomic end def inline_modules [] end end module SequencePrimary4 def atomic elements[0] end def suffix elements[1] end end module SequencePrimary5 def compile(lexical_address, builder) suffix.compile(lexical_address, builder, self) end def node_class_name nil end def inline_modules atomic.inline_modules end def inline_module_name nil end end def _nt_sequence_primary start_index = index if node_cache[:sequence_primary].has_key?(index) cached = node_cache[:sequence_primary][index] if cached node_cache[:sequence_primary][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_prefix s1 << r2 if r2 r3 = _nt_atomic s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(SequencePrimary0) r1.extend(SequencePrimary1) else @index = i1 r1 = nil end if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else i4, s4 = index, [] r5 = _nt_prefix s4 << r5 if r5 r7 = _nt_space if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s4 << r6 if r6 r8 = _nt_predicate_block s4 << r8 end end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(SequencePrimary2) r4.extend(SequencePrimary3) else @index = i4 r4 = nil end if r4 r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else i9, s9 = index, [] r10 = _nt_atomic s9 << r10 if r10 r11 = _nt_suffix s9 << r11 end if s9.last r9 = instantiate_node(SyntaxNode,input, i9...index, s9) r9.extend(SequencePrimary4) r9.extend(SequencePrimary5) else @index = i9 r9 = nil end if r9 r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r0 = r9 else r12 = _nt_atomic if r12 r12 = SyntaxNode.new(input, (index-1)...index) if r12 == true r0 = r12 else @index = i0 r0 = nil end end end end node_cache[:sequence_primary][start_index] = r0 r0 end def _nt_suffix start_index = index if node_cache[:suffix].has_key?(index) cached = node_cache[:suffix][index] if cached node_cache[:suffix][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_repetition_suffix if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_optional_suffix if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:suffix][start_index] = r0 r0 end def _nt_optional_suffix start_index = index if node_cache[:optional_suffix].has_key?(index) cached = node_cache[:optional_suffix][index] if cached node_cache[:optional_suffix][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if (match_len = has_terminal?('?', false, index)) r0 = instantiate_node(Optional,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('?') r0 = nil end node_cache[:optional_suffix][start_index] = r0 r0 end module NodeClassDeclarations0 def node_class_expression elements[0] end def trailing_inline_module elements[1] end end module NodeClassDeclarations1 def node_class_name node_class_expression.node_class_name end def inline_modules trailing_inline_module.inline_modules end def inline_module trailing_inline_module.inline_module end def inline_module_name inline_module.module_name if inline_module end end def _nt_node_class_declarations start_index = index if node_cache[:node_class_declarations].has_key?(index) cached = node_cache[:node_class_declarations][index] if cached node_cache[:node_class_declarations][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_node_class_expression s0 << r1 if r1 r2 = _nt_trailing_inline_module s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(NodeClassDeclarations0) r0.extend(NodeClassDeclarations1) else @index = i0 r0 = nil end node_cache[:node_class_declarations][start_index] = r0 r0 end def _nt_repetition_suffix start_index = index if node_cache[:repetition_suffix].has_key?(index) cached = node_cache[:repetition_suffix][index] if cached node_cache[:repetition_suffix][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if (match_len = has_terminal?('+', false, index)) r1 = instantiate_node(OneOrMore,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('+') r1 = nil end if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else if (match_len = has_terminal?('*', false, index)) r2 = instantiate_node(ZeroOrMore,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('*') r2 = nil end if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_occurrence_range if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 r0 = nil end end end node_cache[:repetition_suffix][start_index] = r0 r0 end module OccurrenceRange0 def min elements[1] end def max elements[3] end end def _nt_occurrence_range start_index = index if node_cache[:occurrence_range].has_key?(index) cached = node_cache[:occurrence_range][index] if cached node_cache[:occurrence_range][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_space if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 s3, i3 = [], index loop do if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r4 = true @index += 1 else terminal_parse_failure('[0-9]') r4 = nil end if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s0 << r3 if r3 if (match_len = has_terminal?('..', false, index)) r5 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('..') r5 = nil end s0 << r5 if r5 s6, i6 = [], index loop do if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r7 = true @index += 1 else terminal_parse_failure('[0-9]') r7 = nil end if r7 s6 << r7 else break end end r6 = instantiate_node(SyntaxNode,input, i6...index, s6) s0 << r6 end end end if s0.last r0 = instantiate_node(OccurrenceRange,input, i0...index, s0) r0.extend(OccurrenceRange0) else @index = i0 r0 = nil end node_cache[:occurrence_range][start_index] = r0 r0 end def _nt_prefix start_index = index if node_cache[:prefix].has_key?(index) cached = node_cache[:prefix][index] if cached node_cache[:prefix][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if (match_len = has_terminal?('&', false, index)) r1 = instantiate_node(AndPredicate,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('&') r1 = nil end if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else if (match_len = has_terminal?('!', false, index)) r2 = instantiate_node(NotPredicate,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('!') r2 = nil end if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else if (match_len = has_terminal?('~', false, index)) r3 = instantiate_node(TransientPrefix,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('~') r3 = nil end if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 r0 = nil end end end node_cache[:prefix][start_index] = r0 r0 end def _nt_atomic start_index = index if node_cache[:atomic].has_key?(index) cached = node_cache[:atomic][index] if cached node_cache[:atomic][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_terminal if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_nonterminal if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_parenthesized_expression if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 r0 = nil end end end node_cache[:atomic][start_index] = r0 r0 end module ParenthesizedExpression0 def parsing_expression elements[2] end end module ParenthesizedExpression1 def inline_modules parsing_expression.inline_modules end end def _nt_parenthesized_expression start_index = index if node_cache[:parenthesized_expression].has_key?(index) cached = node_cache[:parenthesized_expression][index] if cached node_cache[:parenthesized_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('(', false, index)) r1 = true @index += match_len else terminal_parse_failure('(') r1 = nil end s0 << r1 if r1 r3 = _nt_space if r3 r2 = r3 else r2 = instantiate_node(SyntaxNode,input, index...index) end s0 << r2 if r2 r4 = _nt_parsing_expression s0 << r4 if r4 r6 = _nt_space if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s0 << r5 if r5 if (match_len = has_terminal?(')', false, index)) r7 = true @index += match_len else terminal_parse_failure(')') r7 = nil end s0 << r7 end end end end if s0.last r0 = instantiate_node(ParenthesizedExpression,input, i0...index, s0) r0.extend(ParenthesizedExpression0) r0.extend(ParenthesizedExpression1) else @index = i0 r0 = nil end node_cache[:parenthesized_expression][start_index] = r0 r0 end module Nonterminal0 def alpha_char elements[0] end end module Nonterminal1 end def _nt_nonterminal start_index = index if node_cache[:nonterminal].has_key?(index) cached = node_cache[:nonterminal][index] if cached node_cache[:nonterminal][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i1 = index r2 = _nt_keyword_inside_grammar if r2 r1 = nil else @index = i1 r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 i3, s3 = index, [] r4 = _nt_alpha_char s3 << r4 if r4 s5, i5 = [], index loop do r6 = _nt_alphanumeric_char if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(Nonterminal0) else @index = i3 r3 = nil end s0 << r3 end if s0.last r0 = instantiate_node(Nonterminal,input, i0...index, s0) r0.extend(Nonterminal1) else @index = i0 r0 = nil end node_cache[:nonterminal][start_index] = r0 r0 end def _nt_terminal start_index = index if node_cache[:terminal].has_key?(index) cached = node_cache[:terminal][index] if cached node_cache[:terminal][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_quoted_string if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else r2 = _nt_character_class if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else r3 = _nt_anything_symbol if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r0 = r3 else @index = i0 r0 = nil end end end node_cache[:terminal][start_index] = r0 r0 end module QuotedString0 def qs elements[0] end def modifiers elements[1] end end module QuotedString1 def string qs.text_value end end def _nt_quoted_string start_index = index if node_cache[:quoted_string].has_key?(index) cached = node_cache[:quoted_string][index] if cached node_cache[:quoted_string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i1 = index r2 = _nt_single_quoted_string if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else r3 = _nt_double_quoted_string if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else @index = i1 r1 = nil end end s0 << r1 if r1 s4, i4 = [], index loop do if has_terminal?(@regexps[gr = '\A[ir]'] ||= Regexp.new(gr), :regexp, index) r5 = true @index += 1 else terminal_parse_failure('[ir]') r5 = nil end if r5 s4 << r5 else break end end r4 = instantiate_node(SyntaxNode,input, i4...index, s4) s0 << r4 end if s0.last r0 = instantiate_node(Terminal,input, i0...index, s0) r0.extend(QuotedString0) r0.extend(QuotedString1) else @index = i0 r0 = nil end node_cache[:quoted_string][start_index] = r0 r0 end module DoubleQuotedString0 end module DoubleQuotedString1 def string elements[1] end end def _nt_double_quoted_string start_index = index if node_cache[:double_quoted_string].has_key?(index) cached = node_cache[:double_quoted_string][index] if cached node_cache[:double_quoted_string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('"', false, index)) r1 = true @index += match_len else terminal_parse_failure('"') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] i4 = index if (match_len = has_terminal?('"', false, index)) r5 = true @index += match_len else terminal_parse_failure('"') r5 = nil end if r5 r4 = nil else @index = i4 r4 = instantiate_node(SyntaxNode,input, index...index) end s3 << r4 if r4 i6 = index if (match_len = has_terminal?("\\\\", false, index)) r7 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure("\\\\") r7 = nil end if r7 r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r6 = r7 else if (match_len = has_terminal?('\"', false, index)) r8 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('\"') r8 = nil end if r8 r8 = SyntaxNode.new(input, (index-1)...index) if r8 == true r6 = r8 else if index < input_length r9 = true @index += 1 else terminal_parse_failure("any character") r9 = nil end if r9 r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r6 = r9 else @index = i6 r6 = nil end end end s3 << r6 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(DoubleQuotedString0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if (match_len = has_terminal?('"', false, index)) r10 = true @index += match_len else terminal_parse_failure('"') r10 = nil end s0 << r10 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(DoubleQuotedString1) else @index = i0 r0 = nil end node_cache[:double_quoted_string][start_index] = r0 r0 end module SingleQuotedString0 end module SingleQuotedString1 def string elements[1] end end def _nt_single_quoted_string start_index = index if node_cache[:single_quoted_string].has_key?(index) cached = node_cache[:single_quoted_string][index] if cached node_cache[:single_quoted_string][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?("'", false, index)) r1 = true @index += match_len else terminal_parse_failure("'") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] i4 = index if (match_len = has_terminal?("'", false, index)) r5 = true @index += match_len else terminal_parse_failure("'") r5 = nil end if r5 r4 = nil else @index = i4 r4 = instantiate_node(SyntaxNode,input, index...index) end s3 << r4 if r4 i6 = index if (match_len = has_terminal?("\\\\", false, index)) r7 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure("\\\\") r7 = nil end if r7 r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r6 = r7 else if (match_len = has_terminal?("\\'", false, index)) r8 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure("\\'") r8 = nil end if r8 r8 = SyntaxNode.new(input, (index-1)...index) if r8 == true r6 = r8 else if index < input_length r9 = true @index += 1 else terminal_parse_failure("any character") r9 = nil end if r9 r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r6 = r9 else @index = i6 r6 = nil end end end s3 << r6 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(SingleQuotedString0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if (match_len = has_terminal?("'", false, index)) r10 = true @index += match_len else terminal_parse_failure("'") r10 = nil end s0 << r10 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(SingleQuotedString1) else @index = i0 r0 = nil end node_cache[:single_quoted_string][start_index] = r0 r0 end module CharacterClass0 end module CharacterClass1 end module CharacterClass2 end module CharacterClass3 def characters elements[1] end end module CharacterClass4 def characters super.text_value end end def _nt_character_class start_index = index if node_cache[:character_class].has_key?(index) cached = node_cache[:character_class][index] if cached node_cache[:character_class][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('[', false, index)) r1 = true @index += match_len else terminal_parse_failure('[') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] i4 = index if (match_len = has_terminal?(']', false, index)) r5 = true @index += match_len else terminal_parse_failure(']') r5 = nil end if r5 r4 = nil else @index = i4 r4 = instantiate_node(SyntaxNode,input, index...index) end s3 << r4 if r4 i6 = index i7, s7 = index, [] if (match_len = has_terminal?('\\', false, index)) r8 = true @index += match_len else terminal_parse_failure('\\') r8 = nil end s7 << r8 if r8 if index < input_length r9 = true @index += 1 else terminal_parse_failure("any character") r9 = nil end s7 << r9 end if s7.last r7 = instantiate_node(SyntaxNode,input, i7...index, s7) r7.extend(CharacterClass0) else @index = i7 r7 = nil end if r7 r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r6 = r7 else r10 = _nt_bracket_expression if r10 r10 = SyntaxNode.new(input, (index-1)...index) if r10 == true r6 = r10 else i11, s11 = index, [] i12 = index if (match_len = has_terminal?('\\', false, index)) r13 = true @index += match_len else terminal_parse_failure('\\') r13 = nil end if r13 r12 = nil else @index = i12 r12 = instantiate_node(SyntaxNode,input, index...index) end s11 << r12 if r12 if index < input_length r14 = true @index += 1 else terminal_parse_failure("any character") r14 = nil end s11 << r14 end if s11.last r11 = instantiate_node(SyntaxNode,input, i11...index, s11) r11.extend(CharacterClass1) else @index = i11 r11 = nil end if r11 r11 = SyntaxNode.new(input, (index-1)...index) if r11 == true r6 = r11 else @index = i6 r6 = nil end end end s3 << r6 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(CharacterClass2) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 if r2 if (match_len = has_terminal?(']', false, index)) r15 = true @index += match_len else terminal_parse_failure(']') r15 = nil end s0 << r15 end end if s0.last r0 = instantiate_node(CharacterClass,input, i0...index, s0) r0.extend(CharacterClass3) r0.extend(CharacterClass4) else @index = i0 r0 = nil end node_cache[:character_class][start_index] = r0 r0 end module BracketExpression0 end def _nt_bracket_expression start_index = index if node_cache[:bracket_expression].has_key?(index) cached = node_cache[:bracket_expression][index] if cached node_cache[:bracket_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('[:', false, index)) r1 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('[:') r1 = nil end s0 << r1 if r1 if (match_len = has_terminal?('^', false, index)) r3 = true @index += match_len else terminal_parse_failure('^') r3 = nil end if r3 r2 = r3 else r2 = instantiate_node(SyntaxNode,input, index...index) end s0 << r2 if r2 i4 = index if (match_len = has_terminal?('alnum', false, index)) r5 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('alnum') r5 = nil end if r5 r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r4 = r5 else if (match_len = has_terminal?('alpha', false, index)) r6 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('alpha') r6 = nil end if r6 r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true r4 = r6 else if (match_len = has_terminal?('blank', false, index)) r7 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('blank') r7 = nil end if r7 r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true r4 = r7 else if (match_len = has_terminal?('cntrl', false, index)) r8 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('cntrl') r8 = nil end if r8 r8 = SyntaxNode.new(input, (index-1)...index) if r8 == true r4 = r8 else if (match_len = has_terminal?('digit', false, index)) r9 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('digit') r9 = nil end if r9 r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true r4 = r9 else if (match_len = has_terminal?('graph', false, index)) r10 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('graph') r10 = nil end if r10 r10 = SyntaxNode.new(input, (index-1)...index) if r10 == true r4 = r10 else if (match_len = has_terminal?('lower', false, index)) r11 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('lower') r11 = nil end if r11 r11 = SyntaxNode.new(input, (index-1)...index) if r11 == true r4 = r11 else if (match_len = has_terminal?('print', false, index)) r12 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('print') r12 = nil end if r12 r12 = SyntaxNode.new(input, (index-1)...index) if r12 == true r4 = r12 else if (match_len = has_terminal?('punct', false, index)) r13 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('punct') r13 = nil end if r13 r13 = SyntaxNode.new(input, (index-1)...index) if r13 == true r4 = r13 else if (match_len = has_terminal?('space', false, index)) r14 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('space') r14 = nil end if r14 r14 = SyntaxNode.new(input, (index-1)...index) if r14 == true r4 = r14 else if (match_len = has_terminal?('upper', false, index)) r15 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('upper') r15 = nil end if r15 r15 = SyntaxNode.new(input, (index-1)...index) if r15 == true r4 = r15 else if (match_len = has_terminal?('xdigit', false, index)) r16 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('xdigit') r16 = nil end if r16 r16 = SyntaxNode.new(input, (index-1)...index) if r16 == true r4 = r16 else if (match_len = has_terminal?('word', false, index)) r17 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('word') r17 = nil end if r17 r17 = SyntaxNode.new(input, (index-1)...index) if r17 == true r4 = r17 else @index = i4 r4 = nil end end end end end end end end end end end end end s0 << r4 if r4 if (match_len = has_terminal?(':]', false, index)) r18 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure(':]') r18 = nil end s0 << r18 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(BracketExpression0) else @index = i0 r0 = nil end node_cache[:bracket_expression][start_index] = r0 r0 end def _nt_anything_symbol start_index = index if node_cache[:anything_symbol].has_key?(index) cached = node_cache[:anything_symbol][index] if cached node_cache[:anything_symbol][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if (match_len = has_terminal?('.', false, index)) r0 = instantiate_node(AnythingSymbol,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('.') r0 = nil end node_cache[:anything_symbol][start_index] = r0 r0 end module NodeClassExpression0 end module NodeClassExpression1 def space elements[0] end end module NodeClassExpression2 def node_class_name elements[2].text_value end end module NodeClassExpression3 def node_class_name nil end end def _nt_node_class_expression start_index = index if node_cache[:node_class_expression].has_key?(index) cached = node_cache[:node_class_expression][index] if cached node_cache[:node_class_expression][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_space s1 << r2 if r2 if (match_len = has_terminal?('<', false, index)) r3 = true @index += match_len else terminal_parse_failure('<') r3 = nil end s1 << r3 if r3 s4, i4 = [], index loop do i5, s5 = index, [] i6 = index if (match_len = has_terminal?('>', false, index)) r7 = true @index += match_len else terminal_parse_failure('>') r7 = nil end if r7 r6 = nil else @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length r8 = true @index += 1 else terminal_parse_failure("any character") r8 = nil end s5 << r8 end if s5.last r5 = instantiate_node(SyntaxNode,input, i5...index, s5) r5.extend(NodeClassExpression0) else @index = i5 r5 = nil end if r5 s4 << r5 else break end end if s4.empty? @index = i4 r4 = nil else r4 = instantiate_node(SyntaxNode,input, i4...index, s4) end s1 << r4 if r4 if (match_len = has_terminal?('>', false, index)) r9 = true @index += match_len else terminal_parse_failure('>') r9 = nil end s1 << r9 end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(NodeClassExpression1) r1.extend(NodeClassExpression2) else @index = i1 r1 = nil end if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else if (match_len = has_terminal?('', false, index)) r10 = instantiate_node(SyntaxNode,input, index...(index + match_len)) r10.extend(NodeClassExpression3) @index += match_len else terminal_parse_failure('') r10 = nil end if r10 r10 = SyntaxNode.new(input, (index-1)...index) if r10 == true r0 = r10 else @index = i0 r0 = nil end end node_cache[:node_class_expression][start_index] = r0 r0 end module TrailingInlineModule0 def space elements[0] end def inline_module elements[1] end end module TrailingInlineModule1 def inline_modules [inline_module] end def inline_module_name inline_module.module_name end end module TrailingInlineModule2 def inline_modules [] end def inline_module nil end def inline_module_name nil end end def _nt_trailing_inline_module start_index = index if node_cache[:trailing_inline_module].has_key?(index) cached = node_cache[:trailing_inline_module][index] if cached node_cache[:trailing_inline_module][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_space s1 << r2 if r2 r3 = _nt_inline_module s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(TrailingInlineModule0) r1.extend(TrailingInlineModule1) else @index = i1 r1 = nil end if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else if (match_len = has_terminal?('', false, index)) r4 = instantiate_node(SyntaxNode,input, index...(index + match_len)) r4.extend(TrailingInlineModule2) @index += match_len else terminal_parse_failure('') r4 = nil end if r4 r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r0 = r4 else @index = i0 r0 = nil end end node_cache[:trailing_inline_module][start_index] = r0 r0 end module PredicateBlock0 def inline_module elements[1] end end def _nt_predicate_block start_index = index if node_cache[:predicate_block].has_key?(index) cached = node_cache[:predicate_block][index] if cached node_cache[:predicate_block][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('', false, index)) r1 = true @index += match_len else terminal_parse_failure('') r1 = nil end s0 << r1 if r1 r2 = _nt_inline_module s0 << r2 end if s0.last r0 = instantiate_node(PredicateBlock,input, i0...index, s0) r0.extend(PredicateBlock0) else @index = i0 r0 = nil end node_cache[:predicate_block][start_index] = r0 r0 end module InlineModule0 end module InlineModule1 end def _nt_inline_module start_index = index if node_cache[:inline_module].has_key?(index) cached = node_cache[:inline_module][index] if cached node_cache[:inline_module][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('{', false, index)) r1 = true @index += match_len else terminal_parse_failure('{') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do i3 = index r4 = _nt_inline_module if r4 r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true r3 = r4 else i5, s5 = index, [] i6 = index if has_terminal?(@regexps[gr = '\A[{}]'] ||= Regexp.new(gr), :regexp, index) r7 = true @index += 1 else terminal_parse_failure('[{}]') r7 = nil end if r7 r6 = nil else @index = i6 r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 if index < input_length r8 = true @index += 1 else terminal_parse_failure("any character") r8 = nil end s5 << r8 end if s5.last r5 = instantiate_node(SyntaxNode,input, i5...index, s5) r5.extend(InlineModule0) else @index = i5 r5 = nil end if r5 r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true r3 = r5 else @index = i3 r3 = nil end end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if (match_len = has_terminal?('}', false, index)) r9 = true @index += match_len else terminal_parse_failure('}') r9 = nil end s0 << r9 end end if s0.last r0 = instantiate_node(InlineModule,input, i0...index, s0) r0.extend(InlineModule1) else @index = i0 r0 = nil end node_cache[:inline_module][start_index] = r0 r0 end module KeywordInsideGrammar0 end def _nt_keyword_inside_grammar start_index = index if node_cache[:keyword_inside_grammar].has_key?(index) cached = node_cache[:keyword_inside_grammar][index] if cached node_cache[:keyword_inside_grammar][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i1 = index if (match_len = has_terminal?('rule', false, index)) r2 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('rule') r2 = nil end if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else if (match_len = has_terminal?('end', false, index)) r3 = instantiate_node(SyntaxNode,input, index...(index + match_len)) @index += match_len else terminal_parse_failure('end') r3 = nil end if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else @index = i1 r1 = nil end end s0 << r1 if r1 i4 = index r5 = _nt_non_space_char if r5 r4 = nil else @index = i4 r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(KeywordInsideGrammar0) else @index = i0 r0 = nil end node_cache[:keyword_inside_grammar][start_index] = r0 r0 end module NonSpaceChar0 end def _nt_non_space_char start_index = index if node_cache[:non_space_char].has_key?(index) cached = node_cache[:non_space_char][index] if cached node_cache[:non_space_char][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i1 = index r2 = _nt_space if r2 r1 = nil else @index = i1 r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 if index < input_length r3 = true @index += 1 else terminal_parse_failure("any character") r3 = nil end s0 << r3 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(NonSpaceChar0) else @index = i0 r0 = nil end node_cache[:non_space_char][start_index] = r0 r0 end def _nt_alpha_char start_index = index if node_cache[:alpha_char].has_key?(index) cached = node_cache[:alpha_char][index] if cached node_cache[:alpha_char][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?(@regexps[gr = '\A[A-Za-z_]'] ||= Regexp.new(gr), :regexp, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure('[A-Za-z_]') r0 = nil end node_cache[:alpha_char][start_index] = r0 r0 end def _nt_alphanumeric_char start_index = index if node_cache[:alphanumeric_char].has_key?(index) cached = node_cache[:alphanumeric_char][index] if cached node_cache[:alphanumeric_char][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_alpha_char if r1 r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true r0 = r1 else if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index) r2 = true @index += 1 else terminal_parse_failure('[0-9]') r2 = nil end if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r0 = r2 else @index = i0 r0 = nil end end node_cache[:alphanumeric_char][start_index] = r0 r0 end def _nt_space start_index = index if node_cache[:space].has_key?(index) cached = node_cache[:space][index] if cached node_cache[:space][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do i1 = index r2 = _nt_white if r2 r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true r1 = r2 else r3 = _nt_comment_to_eol if r3 r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true r1 = r3 else @index = i1 r1 = nil end end if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:space][start_index] = r0 r0 end module CommentToEol0 end module CommentToEol1 end def _nt_comment_to_eol start_index = index if node_cache[:comment_to_eol].has_key?(index) cached = node_cache[:comment_to_eol][index] if cached node_cache[:comment_to_eol][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if (match_len = has_terminal?('#', false, index)) r1 = true @index += match_len else terminal_parse_failure('#') r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] i4 = index if (match_len = has_terminal?("\n", false, index)) r5 = true @index += match_len else terminal_parse_failure("\n") r5 = nil end if r5 r4 = nil else @index = i4 r4 = instantiate_node(SyntaxNode,input, index...index) end s3 << r4 if r4 if index < input_length r6 = true @index += 1 else terminal_parse_failure("any character") r6 = nil end s3 << r6 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(CommentToEol0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(CommentToEol1) else @index = i0 r0 = nil end node_cache[:comment_to_eol][start_index] = r0 r0 end def _nt_white start_index = index if node_cache[:white].has_key?(index) cached = node_cache[:white][index] if cached node_cache[:white][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?(@regexps[gr = '\A[ \\t\\n\\r]'] ||= Regexp.new(gr), :regexp, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure('[ \\t\\n\\r]') r0 = nil end node_cache[:white][start_index] = r0 r0 end end class MetagrammarParser < Treetop::Runtime::CompiledParser include Metagrammar end end end treetop-1.6.3/lib/treetop/compiler/metagrammar.treetop0000644000004100000410000002640612552221265023210 0ustar www-datawww-datamodule Treetop module Compiler grammar Metagrammar rule treetop_file requires:(space? require_statement)* spacing:space? module_or_grammar suffix:space? { def compile requires.text_value + spacing.text_value + module_or_grammar.compile + suffix.text_value end } end rule require_statement spacing:space? "require" [ \t]+ [^\n\r]+ [\n\r] end rule module_or_grammar module_declaration / grammar end rule module_declaration module_prefix:('module' space name:([A-Z] alphanumeric_char* ('::' [A-Z] alphanumeric_char*)*) space) module_contents:(module_declaration / grammar) suffix:(space 'end') { def compile module_prefix.text_value + module_contents.compile + suffix.text_value end def parser_name module_prefix.name.text_value+'::'+module_contents.parser_name end } end rule grammar 'grammar' space grammar_name space ('do' space)? declaration_sequence space? 'end' end rule grammar_name ([A-Z] alphanumeric_char*) end rule declaration_sequence head:declaration tail:(space declaration)* { def declarations [head] + tail end def tail super.elements.map { |elt| elt.declaration } end } / '' { def compile(builder) end } end rule declaration parsing_rule / include_declaration end rule include_declaration 'include' space [A-Z] (alphanumeric_char / '::')* { def compile(builder) builder << text_value end } end rule parsing_rule 'rule' space nonterminal space ('do' space)? parsing_expression space 'end' end rule parsing_expression choice / sequence / primary end rule choice head:alternative tail:(space? '/' space? alternative)+ { def alternatives [head] + tail end def tail super.elements.map {|elt| elt.alternative} end def inline_modules (alternatives.map {|alt| alt.inline_modules }).flatten end } end rule sequence sequence_body node_class_declarations { def sequence_elements [sequence_body.head] + tail end def tail sequence_body.tail end def inline_modules (sequence_elements.map {|elt| elt.inline_modules}).flatten + [sequence_element_accessor_module] + node_class_declarations.inline_modules end def inline_module_name node_class_declarations.inline_module_name end } end rule sequence_body variable_length_sequence_body / labeled_expression_sequence_body end rule variable_length_sequence_body head:optionally_labeled_sequence_primary tail:(space optionally_labeled_sequence_primary)+ { def tail super.elements.map {|elt| elt.optionally_labeled_sequence_primary } end } end rule labeled_expression_sequence_body labeled_sequence_primary { def head self end def tail [] end } end rule alternative sequence / primary end rule primary prefix atomic { def compile(address, builder, parent_expression=nil) prefix.compile(address, builder, self) end def prefixed_expression atomic end def inline_modules atomic.inline_modules end def inline_module_name nil end } / prefix space? atomic:predicate_block { def compile(address, builder, parent_expression=nil) prefix.compile(address, builder, self) end def prefixed_expression atomic end def inline_modules [] end } / atomic suffix node_class_declarations { def compile(address, builder, parent_expression=nil) suffix.compile(address, builder, self) end def optional_expression atomic end def node_class_name node_class_declarations.node_class_name end def inline_modules atomic.inline_modules + node_class_declarations.inline_modules end def inline_module_name node_class_declarations.inline_module_name end } / atomic node_class_declarations { def compile(address, builder, parent_expression=nil) atomic.compile(address, builder, self) end def node_class_name node_class_declarations.node_class_name end def inline_modules atomic.inline_modules + node_class_declarations.inline_modules end def inline_module_name node_class_declarations.inline_module_name end } end rule optionally_labeled_sequence_primary labeled_sequence_primary / unlabeled_sequence_primary end rule labeled_sequence_primary named_label sequence_primary { def compile(lexical_address, builder) sequence_primary.compile(lexical_address, builder) end def inline_modules sequence_primary.inline_modules end def label_name named_label.name end } end rule unlabeled_sequence_primary null_label sequence_primary { def compile(lexical_address, builder) sequence_primary.compile(lexical_address, builder) end def inline_modules sequence_primary.inline_modules end def label_name if sequence_primary.instance_of?(Nonterminal) sequence_primary.text_value else nil end end } end rule label named_label / null_label end rule named_label (alpha_char alphanumeric_char*) ':' { def name elements[0].text_value end } end rule null_label '' { def name nil end } end rule sequence_primary prefix atomic { def compile(lexical_address, builder) prefix.compile(lexical_address, builder, self) end def prefixed_expression elements[1] end def inline_modules atomic.inline_modules end def inline_module_name nil end } / prefix space? atomic:predicate_block { def compile(address, builder, parent_expression=nil) prefix.compile(address, builder, self) end def prefixed_expression atomic end def inline_modules [] end } / atomic suffix { def compile(lexical_address, builder) suffix.compile(lexical_address, builder, self) end def node_class_name nil end def inline_modules atomic.inline_modules end def inline_module_name nil end } / atomic end rule suffix repetition_suffix / optional_suffix end rule optional_suffix '?' end rule node_class_declarations node_class_expression trailing_inline_module { def node_class_name node_class_expression.node_class_name end def inline_modules trailing_inline_module.inline_modules end def inline_module trailing_inline_module.inline_module end def inline_module_name inline_module.module_name if inline_module end } end rule repetition_suffix '+' / '*' / occurrence_range end rule occurrence_range space? min:([0-9])* '..' max:([0-9])* end rule prefix '&' / '!' / '~' end rule atomic terminal / nonterminal / parenthesized_expression end rule parenthesized_expression '(' space? parsing_expression space? ')' { def inline_modules parsing_expression.inline_modules end } end rule nonterminal !keyword_inside_grammar (alpha_char alphanumeric_char*) end rule terminal quoted_string / character_class / anything_symbol end rule quoted_string qs:(single_quoted_string / double_quoted_string) modifiers:([ir]*) { def string qs.text_value end } end rule double_quoted_string '"' string:(!'"' ("\\\\" / '\"' / .))* '"' end rule single_quoted_string "'" string:(!"'" ("\\\\" / "\\'" / .))* "'" end rule character_class '[' characters:(!']' ('\\' . / bracket_expression / !'\\' .))+ ']' { def characters super.text_value end } end rule bracket_expression '[:' '^'? ( 'alnum' / 'alpha' / 'blank' / 'cntrl' / 'digit' / 'graph' / 'lower' / 'print' / 'punct' / 'space' / 'upper' / 'xdigit' / 'word' ) ':]' end rule anything_symbol '.' end rule node_class_expression space '<' (!'>' .)+ '>' { def node_class_name elements[2].text_value end } / '' { def node_class_name nil end } end rule trailing_inline_module space inline_module { def inline_modules [inline_module] end def inline_module_name inline_module.module_name end } / '' { def inline_modules [] end def inline_module nil end def inline_module_name nil end } end rule predicate_block '' inline_module end rule inline_module '{' (inline_module / ![{}] .)* '}' end rule keyword_inside_grammar ('rule' / 'end') !non_space_char end rule non_space_char !space . end rule alpha_char [A-Za-z_] end rule alphanumeric_char alpha_char / [0-9] end rule space (white / comment_to_eol)+ end rule comment_to_eol '#' (!"\n" .)* end rule white [ \t\n\r] end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/0000755000004100000410000000000012552221265021741 5ustar www-datawww-datatreetop-1.6.3/lib/treetop/compiler/node_classes/grammar.rb0000644000004100000410000000144512552221265023720 0ustar www-datawww-datamodule Treetop module Compiler class Grammar < Runtime::SyntaxNode def compile builder = RubyBuilder.new builder.module_declaration "#{grammar_name.text_value}" do builder.in(indent_level) # account for initial indentation of grammar declaration builder << "include Treetop::Runtime" builder.newline declaration_sequence.compile(builder) end builder.newline builder.class_declaration "#{parser_name} < Treetop::Runtime::CompiledParser" do builder << "include #{grammar_name.text_value}" end end def indent_level input.column_of(interval.begin) - 1 end def parser_name grammar_name.text_value + 'Parser' end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/character_class.rb0000644000004100000410000000174512552221265025416 0ustar www-datawww-datamodule Treetop module Compiler class CharacterClass < AtomicExpression def compile(address, builder, parent_expression = nil) super builder.if__ "has_terminal?(@regexps[gr = #{grounded_regexp(text_value)}] ||= Regexp.new(gr), :regexp, index)" do if address == 0 || decorated? assign_result "instantiate_node(#{node_class_name},input, index...(index + 1))" extend_result_with_inline_module else assign_lazily_instantiated_node end builder << "@index += 1" # Always one character end builder.else_ do builder << "terminal_parse_failure(#{expected})" assign_result 'nil' end end def expected single_quote('['+characters+']') end def grounded_regexp(string) # Double any backslashes, then backslash any single-quotes: "'\\A#{string.gsub(/\\/) { '\\\\' }.gsub(/'/) { "\\'"}}'" end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/optional.rb0000644000004100000410000000076212552221265024120 0ustar www-datawww-datamodule Treetop module Compiler class Optional < ParsingExpression def compile(address, builder, parent_expression) super use_vars :result obtain_new_subexpression_address parent_expression.atomic.compile(subexpression_address, builder) builder.if__ subexpression_success? do assign_result subexpression_result_var end builder.else_ do assign_result epsilon_node end end end end endtreetop-1.6.3/lib/treetop/compiler/node_classes/parsing_expression.rb0000644000004100000410000000721012552221265026210 0ustar www-datawww-datamodule Treetop module Compiler class ParsingExpression < Runtime::SyntaxNode attr_reader :address, :builder, :subexpression_address, :var_symbols, :parent_expression def compile(address, builder, parent_expression) @address = address @builder = builder @parent_expression = parent_expression end def node_class_name parent_expression && parent_expression.node_class_name || 'SyntaxNode' end def declared_module_name parent_expression && parent_expression.node_class_name end def inline_module_name parent_expression && parent_expression.inline_module_name end def decorated? parent_expression && (parent_expression.node_class_name || parent_expression.node_class_name || parent_expression.inline_module_name) end def optional_arg(arg) if arg ", #{arg}" else '' end end def use_vars(*var_symbols) @var_symbols = var_symbols builder << var_initialization end def result_var var(:result) end def accumulator_var var(:accumulator) end def start_index_var var(:start_index) end def subexpression_result_var "r#{subexpression_address}" end def subexpression_success? subexpression_result_var end def obtain_new_subexpression_address @subexpression_address = builder.next_address end def accumulate_subexpression_result builder.accumulate accumulator_var, subexpression_result_var end def assign_result(value_ruby) builder.assign result_var, value_ruby end def extend_result(module_name) builder.extend result_var, module_name end def extend_result_with_declared_module extend_result declared_module_name if declared_module_name end def extend_result_with_inline_module extend_result inline_module_name if inline_module_name end def reset_index builder.assign '@index', start_index_var end def epsilon_node "instantiate_node(SyntaxNode,input, index...index)" end def assign_failure(start_index_var) assign_result("nil") end def assign_lazily_instantiated_node assign_result("true") end def var_initialization left, right = [], [] var_symbols.each do |symbol| if init_value(symbol) left << var(symbol) right << init_value(symbol) end end if left.empty? "" else left.join(', ') + ' = ' + right.join(', ') end end def var(var_symbol) case var_symbol when :result then "r#{address}" when :accumulator then "s#{address}" when :start_index then "i#{address}" else raise "Unknown var symbol #{var_symbol}." end end def init_value(var_symbol) case var_symbol when :accumulator then '[]' when :start_index then 'index' else nil end end def begin_comment(expression) #builder << "# begin #{on_one_line(expression)}" end def end_comment(expression) #builder << "# end #{on_one_line(expression)}" end def on_one_line(expression) expression.text_value.tr("\n", ' ') end def expected nil # Overridden for terminal parse failures end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/declaration_sequence.rb0000644000004100000410000000107212552221265026443 0ustar www-datawww-datamodule Treetop module Compiler class DeclarationSequence < Runtime::SyntaxNode def compile(builder) unless rules.empty? builder.method_declaration("root") do builder << "@root ||= :#{rules.first.name}" end builder.newline end declarations.each do |declaration| declaration.compile(builder) builder.newline end end def rules declarations.select { |declaration| declaration.instance_of?(ParsingRule) } end end end endtreetop-1.6.3/lib/treetop/compiler/node_classes/terminal.rb0000644000004100000410000000250012552221265024076 0ustar www-datawww-datamodule Treetop module Compiler class Terminal < AtomicExpression def compile(address, builder, parent_expression = nil) super # Handle modifiers: insensitive = modifiers.text_value.include? 'i' re = modifiers.text_value.include? 'r' if re grounded_regexp = "#{('\A'+eval(string)).inspect}" cache_key = "'__#{modifiers.text_value}__'+(gr = #{grounded_regexp})" re_modifiers = "#{insensitive ? 'Regexp::IGNORECASE' : 0}" str = "@regexps[#{cache_key}] ||= Regexp.new(gr, #{re_modifiers})" mode = ':regexp' elsif insensitive str = string.downcase string_length = eval(str).length mode = ':insens' else str = string string_length = eval(str).length mode = 'false' end builder.if__ "(match_len = has_terminal?(#{str}, #{mode}, index))" do if address == 0 || decorated? || mode != 'false' || string_length > 1 assign_result "instantiate_node(#{node_class_name},input, index...(index + match_len))" extend_result_with_inline_module else assign_lazily_instantiated_node end builder << "@index += match_len" end builder.else_ do builder << "terminal_parse_failure(#{expected})" assign_result 'nil' end end def expected single_quote(string) end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/atomic_expression.rb0000644000004100000410000000046512552221265026026 0ustar www-datawww-datamodule Treetop module Compiler class AtomicExpression < ParsingExpression def inline_modules [] end def single_quote(string) # Double any backslashes, then backslash any single-quotes: "'#{string.gsub(/\\/) { '\\\\' }.gsub(/'/) { "\\'"}}'" end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/repetition.rb0000644000004100000410000000551612552221265024457 0ustar www-datawww-datamodule Treetop module Compiler class Repetition < ParsingExpression def compile(address, builder, parent_expression) super repeated_expression = parent_expression.atomic begin_comment(parent_expression) use_vars :result, :accumulator, :start_index builder.loop do obtain_new_subexpression_address repeated_expression.compile(subexpression_address, builder) builder.if__ subexpression_success? do accumulate_subexpression_result end builder.else_ do builder.break end if max && !max.empty? builder.if_ "#{accumulator_var}.size == #{max.text_value}" do builder.break end end end end def inline_module_name parent_expression.inline_module_name end def assign_and_extend_result assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})" extend_result_with_inline_module end end class ZeroOrMore < Repetition def compile(address, builder, parent_expression) super assign_and_extend_result end_comment(parent_expression) end def max nil end end class OneOrMore < Repetition def compile(address, builder, parent_expression) super builder.if__ "#{accumulator_var}.empty?" do reset_index assign_failure start_index_var end builder.else_ do assign_and_extend_result end end_comment(parent_expression) end def max nil end def expected parent_expression.atomic.expected && '"at least one "+'+parent_expression.atomic.expected end end class OccurrenceRange < Repetition def compile(address, builder, parent_expression) super if !min.empty? && min.text_value.to_i != 0 # We got some, but fewer than we wanted. There'll be a failure reported already builder.if__ "#{accumulator_var}.size < #{min.text_value}" do reset_index assign_failure start_index_var end builder.else_ do clean_unsaturated assign_and_extend_result end else clean_unsaturated assign_and_extend_result end end_comment(parent_expression) end # remove the last terminal_failure if we merely failed to reach the maximum def clean_unsaturated if !max.empty? && max.text_value.to_i > 0 builder.if_ "#{accumulator_var}.size < #{max.text_value}" do builder << 'terminal_failures.pop' # Ignore the last failure. end end end def expected parent_expression.atomic.expected && "at least #{min.text_value} "+parent_expression.atomic.expected end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/nonterminal.rb0000644000004100000410000000055512552221265024621 0ustar www-datawww-datamodule Treetop module Compiler class Nonterminal < AtomicExpression def compile(address, builder, parent_expression = nil) super use_vars :result assign_result text_value == 'super' ? 'super' : "_nt_#{text_value}" extend_result_with_declared_module extend_result_with_inline_module end end end endtreetop-1.6.3/lib/treetop/compiler/node_classes/choice.rb0000644000004100000410000000212312552221265023516 0ustar www-datawww-datamodule Treetop module Compiler class Choice < ParsingExpression def compile(address, builder, parent_expression = nil) super begin_comment(self) use_vars :result, :start_index compile_alternatives(alternatives) end_comment(self) end def compile_alternatives(alternatives) obtain_new_subexpression_address alternatives.first.compile(subexpression_address, builder) builder.if__ subexpression_success? do # Undo lazy instantiation: builder << "#{subexpression_result_var} = SyntaxNode.new(input, (index-1)...index) if #{subexpression_result_var} == true" assign_result subexpression_result_var extend_result_with_declared_module extend_result_with_inline_module end builder.else_ do if alternatives.size == 1 reset_index assign_failure start_index_var else compile_alternatives(alternatives[1..-1]) end end end def expected '"(any alternative)"' end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/predicate.rb0000644000004100000410000000226012552221265024226 0ustar www-datawww-datamodule Treetop module Compiler class Predicate < ParsingExpression def compile(address, builder, parent_expression) super begin_comment(parent_expression) use_vars :result, :start_index obtain_new_subexpression_address parent_expression.prefixed_expression.compile(subexpression_address, builder) builder.if__(subexpression_success?) { when_success } builder.else_ { when_failure } end_comment(parent_expression) end def assign_failure reset_index super(start_index_var) end def assign_success reset_index assign_result epsilon_node end end class AndPredicate < Predicate def when_success assign_success end def when_failure assign_failure end end class NotPredicate < Predicate def when_success assign_failure if (e = parent.atomic.expected) builder << "terminal_parse_failure(#{e}, true)" end end def when_failure if (e = parent.atomic.expected) builder << "terminal_failures.pop" end assign_success end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/transient_prefix.rb0000644000004100000410000000035112552221265025651 0ustar www-datawww-datamodule Treetop module Compiler class TransientPrefix < ParsingExpression def compile(address, builder, parent_expression) parent_expression.prefixed_expression.compile(address, builder) end end end endtreetop-1.6.3/lib/treetop/compiler/node_classes/parenthesized_expression.rb0000644000004100000410000000045112552221265027412 0ustar www-datawww-datamodule Treetop module Compiler class ParenthesizedExpression < ParsingExpression def compile(address, builder, parent_expression = nil) elements[2].compile(address, builder, parent_expression) end def expected elements[2].expected end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/anything_symbol.rb0000644000004100000410000000126512552221265025500 0ustar www-datawww-datamodule Treetop module Compiler class AnythingSymbol < AtomicExpression def compile(address, builder, parent_expression = nil) super builder.if__ "index < input_length" do if address == 0 || decorated? assign_result "instantiate_node(#{node_class_name},input, index...(index + 1))" extend_result_with_inline_module else assign_lazily_instantiated_node end builder << "@index += 1" end builder.else_ do builder << 'terminal_parse_failure("any character")' assign_result 'nil' end end def expected '"any character"' end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/sequence.rb0000644000004100000410000000474412552221265024107 0ustar www-datawww-datamodule Treetop module Compiler class Sequence < ParsingExpression def compile(address, builder, parent_expression = nil) super begin_comment(self) use_vars :result, :start_index, :accumulator compile_sequence_elements(sequence_elements) builder.if__ "#{accumulator_var}.last" do assign_result "instantiate_node(#{node_class_name},input, #{start_index_var}...index, #{accumulator_var})" extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name extend_result_with_inline_module end builder.else_ do reset_index assign_failure start_index_var end end_comment(self) end def node_class_name node_class_declarations.node_class_name || 'SyntaxNode' end def compile_sequence_elements(elements) obtain_new_subexpression_address elements.first.compile(subexpression_address, builder) accumulate_subexpression_result if elements.size > 1 builder.if_ subexpression_success? do compile_sequence_elements(elements[1..-1]) end end end def sequence_element_accessor_module @sequence_element_accessor_module ||= SequenceElementAccessorModule.new(sequence_elements) end def sequence_element_accessor_module_name sequence_element_accessor_module.module_name end def expected '""' end end class SequenceElementAccessorModule include InlineModuleMixin attr_reader :sequence_elements def initialize(sequence_elements) @sequence_elements = sequence_elements end def compile(idx, builder, rule) super builder.module_declaration(module_name) do elements_by_name = sequence_elements.inject({}){|h,e| (h[e.label_name.to_s] ||= []) << e; h} sequence_elements.each_with_index do |element, index| if element.label_name repetitions = elements_by_name[element.label_name.to_s] label_name = element.label_name + (repetitions.size > 1 ? (repetitions.index(element)+1).to_s : "") builder.method_declaration(label_name) do builder << "elements[#{index}]" end builder.newline unless index == sequence_elements.size - 1 end end end end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/treetop_file.rb0000644000004100000410000000025212552221265024746 0ustar www-datawww-datamodule Treetop module Compiler class TreetopFile < Runtime::SyntaxNode def compile (elements.map {|elt| elt.compile}).join end end end endtreetop-1.6.3/lib/treetop/compiler/node_classes/inline_module.rb0000644000004100000410000000110312552221265025104 0ustar www-datawww-datamodule Treetop module Compiler module InlineModuleMixin attr_reader :module_name def compile(index, builder, rule) @module_name = "#{rule.name.treetop_camelize}#{index}" end end class InlineModule < Runtime::SyntaxNode include InlineModuleMixin def compile(index, builder, rule) super builder.module_declaration(module_name) do builder << ruby_code.gsub(/\A\n/, '').rstrip end end def ruby_code elements[1].text_value end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/parsing_rule.rb0000644000004100000410000000350112552221265024757 0ustar www-datawww-datamodule Treetop module Compiler class ParsingRule < Runtime::SyntaxNode def compile(builder) compile_inline_module_declarations(builder) generate_method_definition(builder) end def compile_inline_module_declarations(builder) parsing_expression.inline_modules.each_with_index do |inline_module, i| inline_module.compile(i, builder, self) builder.newline end end def generate_method_definition(builder) builder.reset_addresses expression_address = builder.next_address result_var = "r#{expression_address}" builder.method_declaration(method_name) do builder.assign 'start_index', 'index' generate_cache_lookup(builder) builder.newline parsing_expression.compile(expression_address, builder) builder.newline generate_cache_storage(builder, result_var) builder.newline builder << result_var end end def generate_cache_lookup(builder) builder.if_ "node_cache[:#{name}].has_key?(index)" do cache_address = "node_cache[:#{name}][index]" builder.assign 'cached', cache_address builder.if_ "cached" do # Handle lazily instantiated nodes: builder << "#{cache_address} = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true" builder << '@index = cached.interval.end' end builder << 'return cached' end end def generate_cache_storage(builder, result_var) builder.assign "node_cache[:#{name}][start_index]", result_var end def method_name "_nt_#{name}" end def name nonterminal.text_value end end end end treetop-1.6.3/lib/treetop/compiler/node_classes/predicate_block.rb0000644000004100000410000000152712552221265025405 0ustar www-datawww-datamodule Treetop module Compiler class PredicateBlock < ParsingExpression def compile(index, builder, parent_expression = nil) super # REVISIT: This is distinctly dodgey, but since we can only be called from # two contexts, and it works in both those, I'm going with it for now, as # opposed to doing the major refactor of providing a proper way of accessing # the parent's accumulator variable. p = parent p = p.parent while p && !p.respond_to?(:accumulator_var) assign_result "lambda #{text_value}.call(#{p ? p.accumulator_var : ""})" builder.if_ '!'+result_var do builder << "terminal_parse_failure(#{expected})" end end def expected '""' # Should I include (some of) the text_value here? end end end end treetop-1.6.3/lib/treetop/compiler/ruby_builder.rb0000644000004100000410000000436212552221265022320 0ustar www-datawww-datarequire 'treetop/ruby_extensions/string' module Treetop module Compiler class RubyBuilder attr_reader :level, :address_space, :ruby def initialize @level = 0 @address_space = LexicalAddressSpace.new @ruby = "" end def <<(ruby_line) return if ruby_line.blank? ruby << ruby_line.tabto(level) << "\n" end def newline ruby << "\n" end def indented(depth = 2) self.in(depth) yield self.out(depth) end def class_declaration(name, &block) self << "class #{name}" indented(&block) self << "end" end def module_declaration(name, &block) self << "module #{name}" indented(&block) self << "end" end def method_declaration(name, &block) self << "def #{name}" indented(&block) self << "end" end def assign(left, right) if left.instance_of? Array self << "#{left.join(', ')} = #{right.join(', ')}" else self << "#{left} = #{right}" end end def extend(var, module_name) self << "#{var}.extend(#{module_name})" end def accumulate(left, right) self << "#{left} << #{right}" end def if__(condition, &block) self << "if #{condition}" indented(&block) end def if_(condition, &block) if__(condition, &block) self << 'end' end def else_(&block) self << 'else' indented(&block) self << 'end' end def loop(&block) self << 'loop do' indented(&block) self << 'end' end def break self << 'break' end def in(depth = 2) @level += depth self end def out(depth = 2) @level -= depth self end def next_address address_space.next_address end def reset_addresses address_space.reset_addresses end private def indent " " * level end end end end treetop-1.6.3/lib/treetop/compiler/node_classes.rb0000644000004100000410000000177712552221265022302 0ustar www-datawww-datarequire 'treetop/compiler/node_classes/parsing_expression' require 'treetop/compiler/node_classes/atomic_expression' require 'treetop/compiler/node_classes/inline_module' require 'treetop/compiler/node_classes/predicate_block' require 'treetop/compiler/node_classes/treetop_file' require 'treetop/compiler/node_classes/grammar' require 'treetop/compiler/node_classes/declaration_sequence' require 'treetop/compiler/node_classes/parsing_rule' require 'treetop/compiler/node_classes/parenthesized_expression' require 'treetop/compiler/node_classes/nonterminal' require 'treetop/compiler/node_classes/terminal' require 'treetop/compiler/node_classes/anything_symbol' require 'treetop/compiler/node_classes/character_class' require 'treetop/compiler/node_classes/sequence' require 'treetop/compiler/node_classes/choice' require 'treetop/compiler/node_classes/repetition' require 'treetop/compiler/node_classes/optional' require 'treetop/compiler/node_classes/predicate' require 'treetop/compiler/node_classes/transient_prefix' treetop-1.6.3/lib/treetop/compiler/grammar_compiler.rb0000644000004100000410000000276212552221265023153 0ustar www-datawww-datamodule Treetop module Compiler AUTOGENERATED = "# Autogenerated from a Treetop grammar. Edits may be lost.\n" class GrammarCompiler def compile(source_path, target_path = source_path.gsub(/\.(treetop|tt)\Z/, '.rb')) File.open(target_path, 'w') do |target_file| ruby = ruby_source(source_path) if ruby =~ /\A#.*\n/ ruby.sub!(/\n/, "\n"+AUTOGENERATED+"\n\n") else ruby = AUTOGENERATED+"\n\n"+ruby end target_file.write(ruby) end end # compile a treetop file into ruby def ruby_source(source_path) ruby_source_from_string(File.read(source_path)) end # compile a string containing treetop source into ruby def ruby_source_from_string(s) parser = MetagrammarParser.new result = parser.parse(s) unless result raise RuntimeError.new(parser.failure_reason) end result.compile end end end # compile a treetop source file and load it def self.load(path) adjusted_path = path =~ /\.(treetop|tt)\Z/ ? path : path + '.treetop' File.open(adjusted_path) do |source_file| source = source_file.read source.gsub!(/\b__FILE__\b/, %Q{"#{adjusted_path}"}) load_from_string(source) end end # compile a treetop source string and load it def self.load_from_string(s) compiler = Treetop::Compiler::GrammarCompiler.new Object.class_eval(compiler.ruby_source_from_string(s)) end end treetop-1.6.3/lib/treetop/compiler/lexical_address_space.rb0000644000004100000410000000042012552221265024121 0ustar www-datawww-datamodule Treetop module Compiler class LexicalAddressSpace def initialize reset_addresses end def next_address @next_address += 1 end def reset_addresses @next_address = -1 end end end endtreetop-1.6.3/lib/treetop/ruby_extensions/0000755000004100000410000000000012552221265020725 5ustar www-datawww-datatreetop-1.6.3/lib/treetop/ruby_extensions/string.rb0000644000004100000410000000141312552221265022557 0ustar www-datawww-dataclass String def column_of(index) return 1 if index == 0 newline_index = rindex("\n", index - 1) if newline_index index - newline_index else index + 1 end end def line_of(index) self[0...index].count("\n") + 1 end unless method_defined?(:blank?) def blank? self == "" end end # The following methods are lifted from Facets 2.0.2 def tabto(n) if self =~ /^( *)\S/ # Inlined due to collision with ActiveSupport 4.0: indent(n - $1.length) m = n - $1.length if m >= 0 gsub(/^/, ' ' * m) else gsub(/^ {0,#{-m}}/, "") end else self end end def treetop_camelize to_s.gsub(/\/(.?)/){ "::" + $1.upcase }.gsub(/(^|_)(.)/){ $2.upcase } end end treetop-1.6.3/lib/treetop/runtime.rb0000644000004100000410000000032112552221265017471 0ustar www-datawww-datarequire 'treetop/ruby_extensions' require 'treetop/runtime/compiled_parser' require 'treetop/runtime/syntax_node' require 'treetop/runtime/terminal_parse_failure' require 'treetop/runtime/interval_skip_list' treetop-1.6.3/lib/treetop/ruby_extensions.rb0000644000004100000410000000005112552221265021246 0ustar www-datawww-datarequire 'treetop/ruby_extensions/string' treetop-1.6.3/lib/treetop/bootstrap_gen_1_metagrammar.rb0000644000004100000410000000366312552221265023465 0ustar www-datawww-data# This file's job is to load a Treetop::Compiler::Metagrammar and Treetop::Compiler::MetagrammarParser # into the environment by compiling the current metagrammar.treetop using a trusted version of Treetop. require 'rubygems' TREETOP_VERSION_REQUIRED_TO_BOOTSTRAP = '>= 1.1.5' # Loading trusted version of Treetop to compile the compiler gem_spec = Gem.source_index.find_name('treetop', TREETOP_VERSION_REQUIRED_TO_BOOTSTRAP).last raise "Install a Treetop Gem version #{TREETOP_VERSION_REQUIRED_TO_BOOTSTRAP} to bootstrap." unless gem_spec require "#{gem_spec.full_gem_path}/lib/treetop" # Relocating trusted version of Treetop to Trusted::Treetop Trusted = Module.new Trusted::Treetop = Treetop Object.send(:remove_const, :Treetop) # Requiring version of Treetop that is under test $exclude_metagrammar = true require File.expand_path('../treetop') # Compile and evaluate freshly generated metagrammar source METAGRAMMAR_PATH = File.expand_path('../compiler/metagrammar.treetop', __FILE__) compiled_metagrammar_source = Trusted::Treetop::Compiler::GrammarCompiler.new.ruby_source(METAGRAMMAR_PATH) Object.class_eval(compiled_metagrammar_source) # The compiler under test was compiled with the trusted grammar and therefore depends on its runtime # But the runtime in the global namespace is the new runtime. We therefore inject the trusted runtime # into the compiler so its parser functions correctly. It will still not work for custom classes that # explicitly subclass the wrong runtime. For now I am working around this by keeping 1 generation of # backward compatibility in these cases. # Treetop::Compiler::Metagrammar.module_eval do # include Trusted::Treetop::Runtime # end # # Treetop::Compiler.send(:remove_const, :MetagrammarParser) # class Treetop::Compiler::MetagrammarParser < Trusted::Treetop::Runtime::CompiledParser # include Treetop::Compiler::Metagrammar # include Trusted::Treetop::Runtime # end $bootstrapped_gen_1_metagrammar = true treetop-1.6.3/lib/treetop/version.rb0000644000004100000410000000022312552221265017474 0ustar www-datawww-datamodule Treetop #:nodoc: module VERSION #:nodoc: MAJOR = 1 MINOR = 6 TINY = 3 STRING = [MAJOR, MINOR, TINY].join('.') end end treetop-1.6.3/lib/treetop/runtime/0000755000004100000410000000000012552221265017150 5ustar www-datawww-datatreetop-1.6.3/lib/treetop/runtime/compiled_parser.rb0000644000004100000410000001001012552221265022635 0ustar www-datawww-datamodule Treetop module Runtime class CompiledParser include Treetop::Runtime attr_reader :input, :index, :max_terminal_failure_index attr_writer :root attr_accessor :consume_all_input alias :consume_all_input? :consume_all_input def initialize self.consume_all_input = true end def parse(input, options = {}) prepare_to_parse(input) @index = options[:index] if options[:index] result = send("_nt_#{options[:root] || root}") should_consume_all = options.include?(:consume_all_input) ? options[:consume_all_input] : consume_all_input? if (should_consume_all && index != input.size) if index > max_terminal_failure_index # Otherwise the failure is already explained terminal_parse_failure('', true) end return nil end return SyntaxNode.new(input, index...(index + 1)) if result == true return result end def failure_index max_terminal_failure_index end def failure_line @terminal_failures && input.line_of(failure_index) end def failure_column @terminal_failures && input.column_of(failure_index) end OtherThan = 'something other than ' def failure_reason return nil unless (tf = terminal_failures) && tf.size > 0 "Expected " + (tf.size == 1 ? (tf[0].unexpected ? OtherThan : '')+tf[0].expected_string : "one of #{tf.map{|f| (f.unexpected ? OtherThan : '')+f.expected_string}.uniq*', '}" ) + " at line #{failure_line}, column #{failure_column} (byte #{failure_index+1})" + (failure_index > 0 ? " after #{input[index...failure_index]}" : '') end def terminal_failures if @terminal_failures.empty? || @terminal_failures[0].is_a?(TerminalParseFailure) @terminal_failures else @terminal_failures.map! {|tf_ary| TerminalParseFailure.new(*tf_ary) } end end protected attr_reader :node_cache, :input_length attr_writer :index def prepare_to_parse(input) @input = input @input_length = input.length reset_index @node_cache = Hash.new {|hash, key| hash[key] = Hash.new} @regexps = {} @terminal_failures = [] @max_terminal_failure_index = 0 end def reset_index @index = 0 end def parse_anything(node_class = SyntaxNode, inline_module = nil) if index < input.length result = instantiate_node(node_class,input, index...(index + 1)) result.extend(inline_module) if inline_module @index += 1 result else terminal_parse_failure("any character") end end def instantiate_node(node_type,*args) if node_type.respond_to? :new node_type.new(*args) else SyntaxNode.new(*args).extend(node_type) end end def has_terminal?(terminal, mode, index) case mode when :regexp # A Regexp has been passed in, either a character class or a literel regex 'foo'r (terminal =~ input[index..-1]) == 0 && $&.length when false # The terminal is a string which must match exactly input[index, terminal.size] == terminal && terminal.size when :insens # The terminal is a downcased string which must match input downcased input[index, terminal.size].downcase == terminal && terminal.size when true # Only occurs with old compiled grammars, for character classes rx = @regexps[terminal] ||= Regexp.new(terminal) input.index(rx, index) == index && $&.length end end def terminal_parse_failure(expected_string, unexpected = false) return nil if index < max_terminal_failure_index if index > max_terminal_failure_index @max_terminal_failure_index = index @terminal_failures = [] end @terminal_failures << [index, expected_string, unexpected] return nil end end end end treetop-1.6.3/lib/treetop/runtime/syntax_node.rb0000644000004100000410000000562612552221265022041 0ustar www-datawww-datamodule Treetop module Runtime class SyntaxNode attr_reader :input, :interval attr_accessor :parent def initialize(input, interval, elements = nil) @input = input @interval = interval if (@elements = elements) @elements.each { |e| e.equal?(true) or e.parent = self } end end def elements return @elements if terminal? # replace the character class placeholders in the sequence (lazy instantiation) last_element = nil @comprehensive_elements ||= @elements.map do |element| if element == true index = last_element ? last_element.interval.last : interval.first element = SyntaxNode.new(input, index...(index + 1)) element.parent = self end last_element = element end @comprehensive_elements end def terminal? @elements.nil? end def nonterminal? !terminal? end def text_value input[interval] end def empty? interval.first == interval.last && interval.exclude_end? end def <=>(other) self.interval.first <=> other.interval.first end def extension_modules local_extensions = class < 0 local_extensions else [] # There weren't any; must be a literal node end end def inspect(indent="") em = extension_modules interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : "" tv = text_value tv = "...#{tv[-20..-1]}" if tv.size > 20 indent + self.class.to_s.sub(/.*:/,'') + em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" + " offset=#{interval.first}" + ", #{tv.inspect}" + im + (elements && elements.size > 0 ? ":" + (elements||[]).map{|e| begin "\n"+e.inspect(indent+" ") rescue # Defend against inspect not taking a parameter "\n"+indent+" "+e.inspect end }.join("") : "" ) end @@dot_id_counter = 0 def dot_id @dot_id ||= @@dot_id_counter += 1 end def write_dot(io) io.puts "node#{dot_id} [label=\"'#{text_value}'\"];" if nonterminal? then elements.each do |x| io.puts "node#{dot_id} -> node#{x.dot_id};" x.write_dot(io) end end end def write_dot_file(fname) File.open(fname + ".dot","w") do |file| file.puts "digraph G {" write_dot(file) file.puts "}" end end end end end treetop-1.6.3/lib/treetop/runtime/terminal_parse_failure.rb0000644000004100000410000000062712552221265024216 0ustar www-datawww-datamodule Treetop module Runtime class TerminalParseFailure attr_reader :index, :expected_string, :unexpected def initialize(index, expected_string, unexpected = false) @index = index @expected_string = expected_string @unexpected = unexpected end def to_s "String matching #{expected_string} #{@unexpected ? 'not ' : ''}expected." end end end end treetop-1.6.3/lib/treetop/runtime/interval_skip_list/0000755000004100000410000000000012552221265023055 5ustar www-datawww-datatreetop-1.6.3/lib/treetop/runtime/interval_skip_list/interval_skip_list.rb0000644000004100000410000001207612552221265027315 0ustar www-datawww-dataclass IntervalSkipList attr_reader :probability def initialize @head = HeadNode.new(max_height) @ranges = {} @probability = 0.5 end def max_height 3 end def empty? head.forward[0].nil? end def expire(range, length_change) expired_markers, first_node_after_range = overlapping(range) expired_markers.each { |marker| delete(marker) } first_node_after_range.propagate_length_change(length_change) end def overlapping(range) markers, first_node = containing_with_node(range.first) cur_node = first_node begin markers.concat(cur_node.forward_markers.flatten) cur_node = cur_node.forward[0] end while cur_node.key < range.last return markers.uniq, cur_node end def containing(n) containing_with_node(n).first end def insert(range, marker) ranges[marker] = range first_node = insert_node(range.first) first_node.endpoint_of.push(marker) last_node = insert_node(range.last) last_node.endpoint_of.push(marker) cur_node = first_node cur_level = first_node.top_level while next_node_at_level_inside_range?(cur_node, cur_level, range) while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range) cur_level += 1 end cur_node = mark_forward_path_at_level(cur_node, cur_level, marker) end while node_inside_range?(cur_node, range) while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range) cur_level -= 1 end cur_node = mark_forward_path_at_level(cur_node, cur_level, marker) end end def delete(marker) range = ranges[marker] path_to_first_node = make_path first_node = find(range.first, path_to_first_node) cur_node = first_node cur_level = first_node.top_level while next_node_at_level_inside_range?(cur_node, cur_level, range) while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range) cur_level += 1 end cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker) end while node_inside_range?(cur_node, range) while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range) cur_level -= 1 end cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker) end last_node = cur_node first_node.endpoint_of.delete(marker) if first_node.endpoint_of.empty? first_node.delete(path_to_first_node) end last_node.endpoint_of.delete(marker) if last_node.endpoint_of.empty? path_to_last_node = make_path find(range.last, path_to_last_node) last_node.delete(path_to_last_node) end end protected attr_reader :head, :ranges def insert_node(key) path = make_path found_node = find(key, path) if found_node && found_node.key == key return found_node else return Node.new(key, next_node_height, path) end end def containing_with_node(n) containing = [] cur_node = head (max_height - 1).downto(0) do |cur_level| while (next_node = cur_node.forward[cur_level]) && next_node.key <= n cur_node = next_node if cur_node.key == n return containing + (cur_node.markers - cur_node.endpoint_of), cur_node end end containing.concat(cur_node.forward_markers[cur_level]) end return containing, cur_node end def delete_node(key) path = make_path found_node = find(key, path) found_node.delete(path) if found_node.key == key end def find(key, path) cur_node = head (max_height - 1).downto(0) do |cur_level| while (next_node = cur_node.forward[cur_level]) && next_node.key < key cur_node = next_node end path[cur_level] = cur_node end cur_node.forward[0] end def make_path Array.new(max_height, nil) end def next_node_height height = 1 while rand < probability && height < max_height height += 1 end height end def can_ascend_from?(node, level) level < node.top_level end def can_descend_from?(level) level > 0 end def node_inside_range?(node, range) node.key < range.last end def next_node_at_level_inside_range?(node, level, range) node.forward[level] && node.forward[level].key <= range.last end def next_node_at_level_outside_range?(node, level, range) (node.forward[level].nil? || node.forward[level].key > range.last) end def mark_forward_path_at_level(node, level, marker) node.forward_markers[level].push(marker) next_node = node.forward[level] next_node.markers.push(marker) node = next_node end def unmark_forward_path_at_level(node, level, marker) node.forward_markers[level].delete(marker) next_node = node.forward[level] next_node.markers.delete(marker) node = next_node end def nodes nodes = [] cur_node = head.forward[0] until cur_node.nil? nodes << cur_node cur_node = cur_node.forward[0] end nodes end endtreetop-1.6.3/lib/treetop/runtime/interval_skip_list/head_node.rb0000644000004100000410000000045012552221265025307 0ustar www-datawww-dataclass IntervalSkipList class HeadNode attr_reader :height, :forward, :forward_markers def initialize(height) @height = height @forward = Array.new(height, nil) @forward_markers = Array.new(height) {|i| []} end def top_level height - 1 end end endtreetop-1.6.3/lib/treetop/runtime/interval_skip_list/node.rb0000644000004100000410000001026712552221265024335 0ustar www-datawww-dataclass IntervalSkipList class Node < HeadNode attr_accessor :key attr_reader :markers, :endpoint_of def initialize(key, height, path) super(height) @key = key @markers = [] @endpoint_of = [] update_forward_pointers(path) promote_markers(path) end def all_forward_markers markers.flatten end def delete(path) 0.upto(top_level) do |i| path[i].forward[i] = forward[i] end demote_markers(path) end def propagate_length_change(length_change) cur_node = self while cur_node do cur_node.key += length_change cur_node = cur_node.forward[0] end end protected def update_forward_pointers(path) 0.upto(top_level) do |i| forward[i] = path[i].forward[i] path[i].forward[i] = self end end def promote_markers(path) promoted = [] new_promoted = [] 0.upto(top_level) do |i| incoming_markers = path[i].forward_markers[i] markers.concat(incoming_markers) incoming_markers.each do |marker| if can_be_promoted_higher?(marker, i) new_promoted.push(marker) forward[i].delete_marker_from_path(marker, i, forward[i+1]) else forward_markers[i].push(marker) end end promoted.each do |marker| if can_be_promoted_higher?(marker, i) new_promoted.push(marker) forward[i].delete_marker_from_path(marker, i, forward[i+1]) else forward_markers[i].push(marker) end end promoted = new_promoted new_promoted = [] end end def can_be_promoted_higher?(marker, level) level < top_level && forward[level + 1] && forward[level + 1].markers.include?(marker) end def delete_marker_from_path(marker, level, terminus) cur_node = self until cur_node == terminus cur_node.forward_markers[level].delete(marker) cur_node.markers.delete(marker) cur_node = cur_node.forward[level] end end def demote_markers(path) demote_inbound_markers(path) demote_outbound_markers(path) end def demote_inbound_markers(path) demoted = [] new_demoted = [] top_level.downto(0) do |i| incoming_markers = path[i].forward_markers[i].dup incoming_markers.each do |marker| unless forward_node_with_marker_at_or_above_level?(marker, i) path[i].forward_markers[i].delete(marker) new_demoted.push(marker) end end demoted.each do |marker| path[i + 1].place_marker_on_inbound_path(marker, i, path[i]) if forward[i].markers.include?(marker) path[i].forward_markers[i].push(marker) else new_demoted.push(marker) end end demoted = new_demoted new_demoted = [] end end def demote_outbound_markers(path) demoted = [] new_demoted = [] top_level.downto(0) do |i| forward_markers[i].each do |marker| new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker) end demoted.each do |marker| forward[i].place_marker_on_outbound_path(marker, i, forward[i + 1]) new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker) end demoted = new_demoted new_demoted = [] end end def forward_node_with_marker_at_or_above_level?(marker, level) level.upto(top_level) do |i| return true if forward[i].markers.include?(marker) end false end def place_marker_on_outbound_path(marker, level, terminus) cur_node = self until cur_node == terminus cur_node.forward_markers[level].push(marker) cur_node.markers.push(marker) cur_node = cur_node.forward[level] end end def place_marker_on_inbound_path(marker, level, terminus) cur_node = self until cur_node == terminus cur_node.forward_markers[level].push(marker) cur_node = cur_node.forward[level] cur_node.markers.push(marker) end end end endtreetop-1.6.3/lib/treetop/runtime/interval_skip_list.rb0000644000004100000410000000025112552221265023400 0ustar www-datawww-datarequire 'treetop/runtime/interval_skip_list/interval_skip_list' require 'treetop/runtime/interval_skip_list/head_node' require 'treetop/runtime/interval_skip_list/node' treetop-1.6.3/lib/treetop/runtime/terminal_syntax_node.rb0000644000004100000410000000050112552221265023717 0ustar www-datawww-datamodule Treetop module Runtime class TerminalSyntaxNode < SyntaxNode def initialize(input, interval) super(input, interval, []) end def inspect(indent="") indent+ self.class.to_s.sub(/.*:/,'') + " offset=#{interval.first}" + " #{text_value.inspect}" end end end end treetop-1.6.3/lib/treetop/compiler.rb0000644000004100000410000000043512552221265017626 0ustar www-datawww-datarequire 'treetop/ruby_extensions' require 'treetop/compiler/lexical_address_space' require 'treetop/compiler/ruby_builder' require 'treetop/compiler/node_classes' require 'treetop/compiler/metagrammar' unless defined?($exclude_metagrammar) require 'treetop/compiler/grammar_compiler' treetop-1.6.3/lib/treetop/polyglot.rb0000644000004100000410000000036112552221265017663 0ustar www-datawww-datamodule Treetop module Polyglot VALID_GRAMMAR_EXT = ['treetop', 'tt'] VALID_GRAMMAR_EXT_REGEXP = /\.(#{VALID_GRAMMAR_EXT.join('|')})\Z/o end end require 'polyglot' Polyglot.register(Treetop::Polyglot::VALID_GRAMMAR_EXT, Treetop) treetop-1.6.3/metadata.yml0000644000004100000410000002036612552221265015547 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: treetop version: !ruby/object:Gem::Version version: 1.6.3 platform: ruby authors: - Nathan Sobo - Clifford Heath autorequire: bindir: bin cert_chain: [] date: 2015-06-30 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: polyglot requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.3' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.3' - !ruby/object:Gem::Dependency name: jeweler requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2.0' - !ruby/object:Gem::Dependency name: activesupport requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '4.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '4.0' - !ruby/object:Gem::Dependency name: i18n requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.6' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '0.6' - !ruby/object:Gem::Dependency name: rr requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.0' - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '2' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '10' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '10' description: A Parsing Expression Grammar (PEG) Parser generator DSL for Ruby email: cliffordheath@gmail.com executables: - tt extensions: [] extra_rdoc_files: - LICENSE - README.md files: - LICENSE - README.md - Rakefile - bin/tt - doc/contributing_and_planned_features.markdown - doc/grammar_composition.markdown - doc/index.markdown - doc/pitfalls_and_advanced_techniques.markdown - doc/semantic_interpretation.markdown - doc/site.rb - doc/sitegen.rb - doc/syntactic_recognition.markdown - doc/tt.1 - doc/using_in_ruby.markdown - examples/indented_blocks/indented_blocks.tt - examples/indented_blocks/indented_blocks_test.rb - examples/inner_outer.rb - examples/inner_outer.tt - examples/lambda_calculus/arithmetic.rb - examples/lambda_calculus/arithmetic.treetop - examples/lambda_calculus/arithmetic_node_classes.rb - examples/lambda_calculus/arithmetic_test.rb - examples/lambda_calculus/lambda_calculus.rb - examples/lambda_calculus/lambda_calculus.treetop - examples/lambda_calculus/lambda_calculus_node_classes.rb - examples/lambda_calculus/lambda_calculus_test.rb - examples/lambda_calculus/test_helper.rb - examples/numerals.rb - examples/numerals.tt - lib/treetop.rb - lib/treetop/bootstrap_gen_1_metagrammar.rb - lib/treetop/compiler.rb - lib/treetop/compiler/grammar_compiler.rb - lib/treetop/compiler/lexical_address_space.rb - lib/treetop/compiler/metagrammar.rb - lib/treetop/compiler/metagrammar.treetop - lib/treetop/compiler/node_classes.rb - lib/treetop/compiler/node_classes/anything_symbol.rb - lib/treetop/compiler/node_classes/atomic_expression.rb - lib/treetop/compiler/node_classes/character_class.rb - lib/treetop/compiler/node_classes/choice.rb - lib/treetop/compiler/node_classes/declaration_sequence.rb - lib/treetop/compiler/node_classes/grammar.rb - lib/treetop/compiler/node_classes/inline_module.rb - lib/treetop/compiler/node_classes/nonterminal.rb - lib/treetop/compiler/node_classes/optional.rb - lib/treetop/compiler/node_classes/parenthesized_expression.rb - lib/treetop/compiler/node_classes/parsing_expression.rb - lib/treetop/compiler/node_classes/parsing_rule.rb - lib/treetop/compiler/node_classes/predicate.rb - lib/treetop/compiler/node_classes/predicate_block.rb - lib/treetop/compiler/node_classes/repetition.rb - lib/treetop/compiler/node_classes/sequence.rb - lib/treetop/compiler/node_classes/terminal.rb - lib/treetop/compiler/node_classes/transient_prefix.rb - lib/treetop/compiler/node_classes/treetop_file.rb - lib/treetop/compiler/ruby_builder.rb - lib/treetop/polyglot.rb - lib/treetop/ruby_extensions.rb - lib/treetop/ruby_extensions/string.rb - lib/treetop/runtime.rb - lib/treetop/runtime/compiled_parser.rb - lib/treetop/runtime/interval_skip_list.rb - lib/treetop/runtime/interval_skip_list/head_node.rb - lib/treetop/runtime/interval_skip_list/interval_skip_list.rb - lib/treetop/runtime/interval_skip_list/node.rb - lib/treetop/runtime/syntax_node.rb - lib/treetop/runtime/terminal_parse_failure.rb - lib/treetop/runtime/terminal_syntax_node.rb - lib/treetop/version.rb - spec/compiler/and_predicate_spec.rb - spec/compiler/anything_symbol_spec.rb - spec/compiler/character_class_spec.rb - spec/compiler/choice_spec.rb - spec/compiler/circular_compilation_spec.rb - spec/compiler/failure_propagation_functional_spec.rb - spec/compiler/grammar_compiler_spec.rb - spec/compiler/grammar_spec.rb - spec/compiler/multibyte_chars_spec.rb - spec/compiler/namespace_spec.rb - spec/compiler/nonterminal_symbol_spec.rb - spec/compiler/not_predicate_spec.rb - spec/compiler/occurrence_range_spec.rb - spec/compiler/one_or_more_spec.rb - spec/compiler/optional_spec.rb - spec/compiler/parenthesized_expression_spec.rb - spec/compiler/parsing_rule_spec.rb - spec/compiler/repeated_subrule_spec.rb - spec/compiler/semantic_predicate_spec.rb - spec/compiler/sequence_spec.rb - spec/compiler/terminal_spec.rb - spec/compiler/terminal_symbol_spec.rb - spec/compiler/test_grammar.treetop - spec/compiler/test_grammar.tt - spec/compiler/test_grammar_do.treetop - spec/compiler/test_grammar_magic_coding.treetop - spec/compiler/test_grammar_magic_encoding.treetop - spec/compiler/tt_compiler_spec.rb - spec/compiler/zero_or_more_spec.rb - spec/composition/a.treetop - spec/composition/b.treetop - spec/composition/c.treetop - spec/composition/d.treetop - spec/composition/f.treetop - spec/composition/grammar_composition_spec.rb - spec/composition/subfolder/e_includes_c.treetop - spec/ruby_extensions/string_spec.rb - spec/runtime/compiled_parser_spec.rb - spec/runtime/interval_skip_list/delete_spec.rb - spec/runtime/interval_skip_list/expire_range_spec.rb - spec/runtime/interval_skip_list/insert_and_delete_node_spec.rb - spec/runtime/interval_skip_list/insert_spec.rb - spec/runtime/interval_skip_list/interval_skip_list_spec.graffle - spec/runtime/interval_skip_list/interval_skip_list_spec.rb - spec/runtime/interval_skip_list/palindromic_fixture.rb - spec/runtime/interval_skip_list/palindromic_fixture_spec.rb - spec/runtime/interval_skip_list/spec_helper.rb - spec/runtime/syntax_node_spec.rb - spec/spec_helper.rb - treetop.gemspec homepage: https://github.com/cjheath/treetop licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.2.2 signing_key: specification_version: 4 summary: A Ruby-based text parsing and interpretation DSL test_files: [] treetop-1.6.3/LICENSE0000644000004100000410000000204012552221265014236 0ustar www-datawww-dataCopyright (c) 2007 Nathan Sobo. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. treetop-1.6.3/treetop.gemspec0000644000004100000410000001665012552221265016274 0ustar www-datawww-data# Generated by jeweler # DO NOT EDIT THIS FILE DIRECTLY # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' # -*- encoding: utf-8 -*- # stub: treetop 1.6.3 ruby lib Gem::Specification.new do |s| s.name = "treetop" s.version = "1.6.3" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Nathan Sobo", "Clifford Heath"] s.date = "2015-06-30" s.description = "A Parsing Expression Grammar (PEG) Parser generator DSL for Ruby" s.email = "cliffordheath@gmail.com" s.executables = ["tt"] s.extra_rdoc_files = [ "LICENSE", "README.md" ] s.files = [ "LICENSE", "README.md", "Rakefile", "bin/tt", "doc/contributing_and_planned_features.markdown", "doc/grammar_composition.markdown", "doc/index.markdown", "doc/pitfalls_and_advanced_techniques.markdown", "doc/semantic_interpretation.markdown", "doc/site.rb", "doc/sitegen.rb", "doc/syntactic_recognition.markdown", "doc/tt.1", "doc/using_in_ruby.markdown", "examples/indented_blocks/indented_blocks.tt", "examples/indented_blocks/indented_blocks_test.rb", "examples/inner_outer.rb", "examples/inner_outer.tt", "examples/lambda_calculus/arithmetic.rb", "examples/lambda_calculus/arithmetic.treetop", "examples/lambda_calculus/arithmetic_node_classes.rb", "examples/lambda_calculus/arithmetic_test.rb", "examples/lambda_calculus/lambda_calculus.rb", "examples/lambda_calculus/lambda_calculus.treetop", "examples/lambda_calculus/lambda_calculus_node_classes.rb", "examples/lambda_calculus/lambda_calculus_test.rb", "examples/lambda_calculus/test_helper.rb", "examples/numerals.rb", "examples/numerals.tt", "lib/treetop.rb", "lib/treetop/bootstrap_gen_1_metagrammar.rb", "lib/treetop/compiler.rb", "lib/treetop/compiler/grammar_compiler.rb", "lib/treetop/compiler/lexical_address_space.rb", "lib/treetop/compiler/metagrammar.rb", "lib/treetop/compiler/metagrammar.treetop", "lib/treetop/compiler/node_classes.rb", "lib/treetop/compiler/node_classes/anything_symbol.rb", "lib/treetop/compiler/node_classes/atomic_expression.rb", "lib/treetop/compiler/node_classes/character_class.rb", "lib/treetop/compiler/node_classes/choice.rb", "lib/treetop/compiler/node_classes/declaration_sequence.rb", "lib/treetop/compiler/node_classes/grammar.rb", "lib/treetop/compiler/node_classes/inline_module.rb", "lib/treetop/compiler/node_classes/nonterminal.rb", "lib/treetop/compiler/node_classes/optional.rb", "lib/treetop/compiler/node_classes/parenthesized_expression.rb", "lib/treetop/compiler/node_classes/parsing_expression.rb", "lib/treetop/compiler/node_classes/parsing_rule.rb", "lib/treetop/compiler/node_classes/predicate.rb", "lib/treetop/compiler/node_classes/predicate_block.rb", "lib/treetop/compiler/node_classes/repetition.rb", "lib/treetop/compiler/node_classes/sequence.rb", "lib/treetop/compiler/node_classes/terminal.rb", "lib/treetop/compiler/node_classes/transient_prefix.rb", "lib/treetop/compiler/node_classes/treetop_file.rb", "lib/treetop/compiler/ruby_builder.rb", "lib/treetop/polyglot.rb", "lib/treetop/ruby_extensions.rb", "lib/treetop/ruby_extensions/string.rb", "lib/treetop/runtime.rb", "lib/treetop/runtime/compiled_parser.rb", "lib/treetop/runtime/interval_skip_list.rb", "lib/treetop/runtime/interval_skip_list/head_node.rb", "lib/treetop/runtime/interval_skip_list/interval_skip_list.rb", "lib/treetop/runtime/interval_skip_list/node.rb", "lib/treetop/runtime/syntax_node.rb", "lib/treetop/runtime/terminal_parse_failure.rb", "lib/treetop/runtime/terminal_syntax_node.rb", "lib/treetop/version.rb", "spec/compiler/and_predicate_spec.rb", "spec/compiler/anything_symbol_spec.rb", "spec/compiler/character_class_spec.rb", "spec/compiler/choice_spec.rb", "spec/compiler/circular_compilation_spec.rb", "spec/compiler/failure_propagation_functional_spec.rb", "spec/compiler/grammar_compiler_spec.rb", "spec/compiler/grammar_spec.rb", "spec/compiler/multibyte_chars_spec.rb", "spec/compiler/namespace_spec.rb", "spec/compiler/nonterminal_symbol_spec.rb", "spec/compiler/not_predicate_spec.rb", "spec/compiler/occurrence_range_spec.rb", "spec/compiler/one_or_more_spec.rb", "spec/compiler/optional_spec.rb", "spec/compiler/parenthesized_expression_spec.rb", "spec/compiler/parsing_rule_spec.rb", "spec/compiler/repeated_subrule_spec.rb", "spec/compiler/semantic_predicate_spec.rb", "spec/compiler/sequence_spec.rb", "spec/compiler/terminal_spec.rb", "spec/compiler/terminal_symbol_spec.rb", "spec/compiler/test_grammar.treetop", "spec/compiler/test_grammar.tt", "spec/compiler/test_grammar_do.treetop", "spec/compiler/test_grammar_magic_coding.treetop", "spec/compiler/test_grammar_magic_encoding.treetop", "spec/compiler/tt_compiler_spec.rb", "spec/compiler/zero_or_more_spec.rb", "spec/composition/a.treetop", "spec/composition/b.treetop", "spec/composition/c.treetop", "spec/composition/d.treetop", "spec/composition/f.treetop", "spec/composition/grammar_composition_spec.rb", "spec/composition/subfolder/e_includes_c.treetop", "spec/ruby_extensions/string_spec.rb", "spec/runtime/compiled_parser_spec.rb", "spec/runtime/interval_skip_list/delete_spec.rb", "spec/runtime/interval_skip_list/expire_range_spec.rb", "spec/runtime/interval_skip_list/insert_and_delete_node_spec.rb", "spec/runtime/interval_skip_list/insert_spec.rb", "spec/runtime/interval_skip_list/interval_skip_list_spec.graffle", "spec/runtime/interval_skip_list/interval_skip_list_spec.rb", "spec/runtime/interval_skip_list/palindromic_fixture.rb", "spec/runtime/interval_skip_list/palindromic_fixture_spec.rb", "spec/runtime/interval_skip_list/spec_helper.rb", "spec/runtime/syntax_node_spec.rb", "spec/spec_helper.rb", "treetop.gemspec" ] s.homepage = "https://github.com/cjheath/treetop" s.licenses = ["MIT"] s.rubygems_version = "2.2.2" s.summary = "A Ruby-based text parsing and interpretation DSL" if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_runtime_dependency(%q, ["~> 0.3"]) s.add_development_dependency(%q, ["~> 2.0"]) s.add_development_dependency(%q, ["~> 4.0"]) s.add_development_dependency(%q, ["~> 0.6"]) s.add_development_dependency(%q, ["~> 1.0"]) s.add_development_dependency(%q, ["~> 2"]) s.add_development_dependency(%q, ["~> 10"]) else s.add_dependency(%q, ["~> 0.3"]) s.add_dependency(%q, ["~> 2.0"]) s.add_dependency(%q, ["~> 4.0"]) s.add_dependency(%q, ["~> 0.6"]) s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, ["~> 2"]) s.add_dependency(%q, ["~> 10"]) end else s.add_dependency(%q, ["~> 0.3"]) s.add_dependency(%q, ["~> 2.0"]) s.add_dependency(%q, ["~> 4.0"]) s.add_dependency(%q, ["~> 0.6"]) s.add_dependency(%q, ["~> 1.0"]) s.add_dependency(%q, ["~> 2"]) s.add_dependency(%q, ["~> 10"]) end end treetop-1.6.3/README.md0000644000004100000410000002740012552221265014517 0ustar www-datawww-dataSupport ======= Support for Treetop is provided through the mailing list you can join or browse here: http://groups.google.com/group/treetop-dev Tutorial ======== Languages can be split into two components, their *syntax* and their *semantics*. It's your understanding of English syntax that tells you the stream of words "Sleep furiously green ideas colorless" is not a valid sentence. Semantics is deeper. Even if we rearrange the above sentence to be "Colorless green ideas sleep furiously", which is syntactically correct, it remains nonsensical on a semantic level. With Treetop, you'll be dealing with languages that are much simpler than English, but these basic concepts apply. Your programs will need to address both the syntax and the semantics of the languages they interpret. Treetop equips you with powerful tools for each of these two aspects of interpreter writing. You'll describe the syntax of your language with a *parsing expression grammar*. From this description, Treetop will generate a Ruby parser that transforms streams of characters written into your language into *abstract syntax trees* representing their structure. You'll then describe the semantics of your language in Ruby by defining methods on the syntax trees the parser generates. Parsing Expression Grammars, The Basics ======================================= The first step in using Treetop is defining a grammar in a file with the `.treetop` extension. Here's a grammar that's useless because it's empty: # my_grammar.treetop grammar MyGrammar end Next, you start filling your grammar with rules. Each rule associates a name with a parsing expression, like the following: # my_grammar.treetop # You can use a .tt extension instead if you wish grammar MyGrammar rule hello 'hello chomsky' end end The first rule becomes the *root* of the grammar, causing its expression to be matched when a parser for the grammar is fed a string. The above grammar can now be used in a Ruby program. Notice how a string matching the first rule parses successfully, but a second nonmatching string does not. ```ruby # use_grammar.rb require 'rubygems' require 'treetop' Treetop.load 'my_grammar' # or just: # require 'my_grammar' # This works because Polyglot hooks "require" to find and load Treetop files parser = MyGrammarParser.new puts parser.parse('hello chomsky') # => Treetop::Runtime::SyntaxNode puts parser.parse('silly generativists!') # => nil ``` Users of *regular expressions* will find parsing expressions familiar. They share the same basic purpose, matching strings against patterns. However, parsing expressions can recognize a broader category of languages than their less expressive brethren. Before we get into demonstrating that, lets cover some basics. At first parsing expressions won't seem much different. Trust that they are. Terminal Symbols ---------------- The expression in the grammar above is a terminal symbol. It will only match a string that matches it exactly. There are two other kinds of terminal symbols, which we'll revisit later. Terminals are called *atomic expressions* because they aren't composed of smaller expressions. A terminal symbol may use either double or single quotes. If the closing quote is immediately followed by the modifier 'i', the string is matched without case-sensitivity, that is, the input.downcase matches the terminal.downcase Treetop now also supports regular expressions as terminals. Use a string as before, but append the modifier character 'r' (you can combine this with 'i' to get case-insensitive regular expressions). Regular expressions are generally faster than the equivalent parsing expressions, but may have polynomial worst-case behaviour, which is worse than parsing expressions. Your regular expression will always be anchored (by prepending \A) to test the current location of the input, so some special expressions like \b for word boundaries may give unexpected results. Ordered Choices --------------- Ordered choices are *composite expressions*, which allow for any of several subexpressions to be matched. These should be familiar from regular expressions, but in parsing expressions, they are delimited by the `/` character. Its important to note that the choices are prioritized in the order they appear. If an earlier expression is matched, no subsequent expressions are tried. Here's an example: # my_grammar.treetop grammar MyGrammar rule hello 'hello chomsky' / 'hello lambek' end end ```ruby # fragment of use_grammar.rb puts parser.parse('hello chomsky') # => Treetop::Runtime::SyntaxNode puts parser.parse('hello lambek') # => Treetop::Runtime::SyntaxNode puts parser.parse('silly generativists!') # => nil ``` Note that once a choice rule has matched the text using a particular alternative at a particular location in the input and hence has succeeded, that choice will never be reconsidered, even if the chosen alternative causes another rule to fail where a later alternative wouldn't have. It's always a later alternative, since the first to succeed is final - why keep looking when you've found what you wanted? This is a feature of PEG parsers that you need to understand if you're going to succeed in using Treetop. In order to memoize success and failures, such decisions cannot be reversed. Luckily Treetop provides a variety of clever ways you can tell it to avoid making the wrong decisions. But more on that later. Sequences --------- Sequences are composed of other parsing expressions separated by spaces. Using sequences, we can tighten up the above grammar. # my_grammar.treetop grammar MyGrammar rule hello 'hello ' ('chomsky' / 'lambek') end end Note the use of parentheses to override the default precedence rules, which bind sequences more tightly than choices. Once the whole sequence has been matched, the result is memoized and the details of the match will not be reconsidered for that location in the input. Nonterminal Symbols ------------------- Here we leave regular expressions behind. Nonterminals allow expressions to refer to other expressions by name. A trivial use of this facility would allow us to make the above grammar more readable should the list of names grow longer. # my_grammar.treetop grammar MyGrammar rule hello 'hello ' linguist end rule linguist 'chomsky' / 'lambek' / 'jacobsen' / 'frege' end end The true power of this facility, however, is unleashed when writing *recursive expressions*. Here is a self-referential expression that can match any number of open parentheses followed by any number of closed parentheses. This is theoretically impossible with regular expressions due to the *pumping lemma*. # parentheses.treetop grammar Parentheses rule parens '(' parens ')' / '' end end The `parens` expression simply states that a `parens` is a set of parentheses surrounding another `parens` expression or, if that doesn't match, the empty string. If you are uncomfortable with recursion, its time to get comfortable, because it is the basis of language. Here's a tip: Don't try and imagine the parser circling round and round through the same rule. Instead, imagine the rule is *already* defined while you are defining it. If you imagine that `parens` already matches a string of matching parentheses, then its easy to think of `parens` as an open and closing parentheses around another set of matching parentheses, which conveniently, you happen to be defining. You know that `parens` is supposed to represent a string of matched parentheses, so trust in that meaning, even if you haven't fully implemented it yet. Repetition ---------- Any item in a rule may be followed by a '+' or a '*' character, signifying one-or-more and zero-or-more occurrences of that item. Beware though; the match is greedy, and if it matches too many items and causes subsequent items in the sequence to fail, the number matched will never be reconsidered. Here's a simple example of a rule that will never succeed: # toogreedy.treetop grammar TooGreedy rule a_s 'a'* 'a' end end The 'a'* will always eat up any 'a's that follow, and the subsequent 'a' will find none there, so the whole rule will fail. You might need to use lookahead to avoid matching too much. Alternatively, you can use an occurrence range: # toogreedy.treetop grammar TooGreedy rule two_to_four_as 'a' 2..4 end end In an occurrence range, you may omit either the minimum count or the maximum count, so that "0.. " works like "*" and "1.. " works like '+'. Negative Lookahead ------------------ When you need to ensure that the following item *doesn't* match in some case where it might otherwise, you can use negat!ve lookahead, which is an item preceeded by a ! - here's an example: # postcondition.treetop grammar PostCondition rule conditional_sentence ( !conditional_keyword word )+ conditional_keyword [ \t]+ word* end rule word ([a-zA-Z]+ [ \t]+) end rule conditional_keyword 'if' / 'while' / 'until' end end Even though the rule `word` would match any of the conditional keywords, the first words of a conditional_sentence must not be conditional_keywords. The negative lookahead prevents that matching, and prevents the repetition from matching too much input. Note that the lookahead may be a grammar rule of any complexity, including one that isn't used elsewhere in your grammar. Positive lookahead ------------------ Sometimes you want an item to match, but only if the *following* text would match some pattern. You don't want to consume that following text, but if it's not there, you want this rule to fail. You can append a positive lookahead like this to a rule by appending the lookahead rule preceeded by an & character. Semantic predicates ------------------- Warning: This is an advanced feature. You need to understand the way a packrat parser operates to use it correctly. The result of computing a rule containing a semantic predicate will be memoized, even if the same rule, applied later at the same location in the input, would work differently due to a semantic predicate returning a different value. If you don't understand the previous sentence yet still use this feature, you're on your own, so test carefully! Sometimes, you need to run external Ruby code to decide whether this syntax rule should continue or should fail. You can do this using either positive or negative semantic predicates. These are Ruby code blocks (lambdas) which are called when the parser reaches that location. For this rule to succeed, the value must be true for a positive predicate (a block like &{ ... }), or false for a negative predicate (a block like !{ ... }). The block is called with one argument, the array containing the preceding syntax nodes in the current sequence. Within the block, you cannot use node names or labels for the preceding nodes, as the node for the current rule does not yet exist. You must refer to preceding nodes using their position in the sequence. grammar Keywords rule sequence_of_reserved_and_nonreserved_words ( reserved / word )* end rule reserved word &{ |s| symbol_reserved?(s[0].text_value) } end rule word ([a-zA-Z]+ [ \t]+) end end One case where it is always safe to use a semantic predicate is to invoke the Ruby debugger, but don't forget to return true so the rule succeeds! Assuming you have required the 'ruby-debug' module somewhere, it looks like this: rule problems word &{ |s| debugger; true } end When the debugger stops here, you can inspect the contents of the SyntaxNode for "word" by looking at s[0], and the stack trace will show how you got there.