Skip to content
Browse files

Got rid of old SVN tags and trunk dirs and moved everything to root.

  • Loading branch information...
1 parent 3f649be commit a524b9ba1d00980104ce2dd3118be3540c0d7517 @nathansobo committed Jan 11, 2008
Showing with 12,550 additions and 0 deletions.
  1. +118 −0 README
  2. +36 −0 Rakefile
  3. +25 −0 bin/tt
  4. +106 −0 doc/contributing_and_planned_features.markdown
  5. +65 −0 doc/grammar_composition.markdown
  6. BIN doc/images/bottom_background.png
  7. BIN doc/images/middle_backgound.png
  8. BIN doc/images/middle_background.png
  9. BIN doc/images/paren_language_output.png
  10. BIN doc/images/top_background.png
  11. +29 −0 doc/index.markdown
  12. +51 −0 doc/pitfalls_and_advanced_techniques.markdown
  13. +52 −0 doc/screen.css
  14. +187 −0 doc/semantic_interpretation.markdown
  15. +34 −0 doc/site.html
  16. +41 −0 doc/site.rb
  17. +103 −0 doc/syntactic_recognition.markdown
  18. +17 −0 doc/using_in_ruby.markdown
  19. +551 −0 examples/lambda_calculus/arithmetic.rb
  20. +97 −0 examples/lambda_calculus/arithmetic.treetop
  21. +7 −0 examples/lambda_calculus/arithmetic_node_classes.rb
  22. +54 −0 examples/lambda_calculus/arithmetic_test.rb
  23. 0 examples/lambda_calculus/lambda_calculus
  24. +718 −0 examples/lambda_calculus/lambda_calculus.rb
  25. +132 −0 examples/lambda_calculus/lambda_calculus.treetop
  26. +5 −0 examples/lambda_calculus/lambda_calculus_node_classes.rb
  27. +89 −0 examples/lambda_calculus/lambda_calculus_test.rb
  28. +18 −0 examples/lambda_calculus/test_helper.rb
  29. +13 −0 lib/treetop.rb
  30. +45 −0 lib/treetop/bootstrap_gen_1_metagrammar.rb
  31. +6 −0 lib/treetop/compiler.rb
  32. +28 −0 lib/treetop/compiler/grammar_compiler.rb
  33. +17 −0 lib/treetop/compiler/lexical_address_space.rb
  34. +2,830 −0 lib/treetop/compiler/metagrammar.rb
  35. +404 −0 lib/treetop/compiler/metagrammar.treetop
  36. +18 −0 lib/treetop/compiler/node_classes.rb
  37. +18 −0 lib/treetop/compiler/node_classes/anything_symbol.rb
  38. +13 −0 lib/treetop/compiler/node_classes/atomic_expression.rb
  39. +19 −0 lib/treetop/compiler/node_classes/character_class.rb
  40. +31 −0 lib/treetop/compiler/node_classes/choice.rb
  41. +24 −0 lib/treetop/compiler/node_classes/declaration_sequence.rb
  42. +28 −0 lib/treetop/compiler/node_classes/grammar.rb
  43. +27 −0 lib/treetop/compiler/node_classes/inline_module.rb
  44. +13 −0 lib/treetop/compiler/node_classes/nonterminal.rb
  45. +19 −0 lib/treetop/compiler/node_classes/optional.rb
  46. +9 −0 lib/treetop/compiler/node_classes/parenthesized_expression.rb
  47. +138 −0 lib/treetop/compiler/node_classes/parsing_expression.rb
  48. +55 −0 lib/treetop/compiler/node_classes/parsing_rule.rb
  49. +45 −0 lib/treetop/compiler/node_classes/predicate.rb
  50. +55 −0 lib/treetop/compiler/node_classes/repetition.rb
  51. +68 −0 lib/treetop/compiler/node_classes/sequence.rb
  52. +20 −0 lib/treetop/compiler/node_classes/terminal.rb
  53. +9 −0 lib/treetop/compiler/node_classes/treetop_file.rb
  54. +113 −0 lib/treetop/compiler/ruby_builder.rb
  55. +2 −0 lib/treetop/ruby_extensions.rb
  56. +19 −0 lib/treetop/ruby_extensions/string.rb
  57. +6 −0 lib/treetop/runtime.rb
  58. +87 −0 lib/treetop/runtime/compiled_parser.rb
  59. +27 −0 lib/treetop/runtime/node_cache.rb
  60. +19 −0 lib/treetop/runtime/parse_cache.rb
  61. +72 −0 lib/treetop/runtime/syntax_node.rb
  62. +16 −0 lib/treetop/runtime/terminal_parse_failure.rb
  63. +17 −0 lib/treetop/runtime/terminal_syntax_node.rb
  64. BIN pkg/treetop-1.1.6.gem
  65. +14 −0 script/generate_metagrammar.rb
  66. +11 −0 script/svnadd
  67. +11 −0 script/svnrm
  68. +36 −0 spec/compiler/and_predicate_spec.rb
  69. +25 −0 spec/compiler/anything_symbol_spec.rb
  70. +48 −0 spec/compiler/character_class_spec.rb
  71. +80 −0 spec/compiler/choice_spec.rb
  72. +28 −0 spec/compiler/circular_compilation_spec.rb
  73. +21 −0 spec/compiler/failure_propagation_functional_spec.rb
  74. +67 −0 spec/compiler/grammar_compiler_spec.rb
  75. +40 −0 spec/compiler/grammar_spec.rb
  76. +40 −0 spec/compiler/nonterminal_symbol_spec.rb
  77. +38 −0 spec/compiler/not_predicate_spec.rb
  78. +35 −0 spec/compiler/one_or_more_spec.rb
  79. +37 −0 spec/compiler/optional_spec.rb
  80. +19 −0 spec/compiler/parenthesized_expression_spec.rb
  81. +32 −0 spec/compiler/parsing_rule_spec.rb
  82. +94 −0 spec/compiler/sequence_spec.rb
  83. +37 −0 spec/compiler/terminal_spec.rb
  84. +37 −0 spec/compiler/terminal_symbol_spec.rb
  85. +7 −0 spec/compiler/test_grammar.treetop
  86. +7 −0 spec/compiler/test_grammar.tt
  87. +56 −0 spec/compiler/zero_or_more_spec.rb
  88. +11 −0 spec/composition/a.treetop
  89. +11 −0 spec/composition/b.treetop
  90. +10 −0 spec/composition/c.treetop
  91. +10 −0 spec/composition/d.treetop
  92. +27 −0 spec/composition/grammar_composition_spec.rb
  93. +101 −0 spec/parser/compiled_parser_spec.rb
  94. +43 −0 spec/parser/syntax_node_spec.rb
  95. +32 −0 spec/ruby_extensions/string_spec.rb
  96. +96 −0 spec/spec_helper.rb
  97. +990 −0 vendor/rspec/CHANGES
  98. +20 −0 vendor/rspec/MIT-LICENSE
  99. +72 −0 vendor/rspec/README
  100. +281 −0 vendor/rspec/Rakefile
  101. +88 −0 vendor/rspec/TODO
  102. +31 −0 vendor/rspec/UPGRADE
  103. +6 −0 vendor/rspec/autotest/discover.rb
  104. +1 −0 vendor/rspec/autotest/rspec.rb
  105. +3 −0 vendor/rspec/bin/spec
  106. +8 −0 vendor/rspec/bin/spec_translator
  107. +19 −0 vendor/rspec/examples/pure/auto_spec_description_example.rb
  108. +40 −0 vendor/rspec/examples/pure/before_and_after_example.rb
  109. +45 −0 vendor/rspec/examples/pure/behave_as_example.rb
  110. +54 −0 vendor/rspec/examples/pure/custom_expectation_matchers.rb
  111. +12 −0 vendor/rspec/examples/pure/custom_formatter.rb
  112. +9 −0 vendor/rspec/examples/pure/dynamic_spec.rb
  113. +19 −0 vendor/rspec/examples/pure/file_accessor.rb
  114. +38 −0 vendor/rspec/examples/pure/file_accessor_spec.rb
  115. +31 −0 vendor/rspec/examples/pure/greeter_spec.rb
  116. +11 −0 vendor/rspec/examples/pure/helper_method_example.rb
  117. +8 −0 vendor/rspec/examples/pure/io_processor.rb
  118. +21 −0 vendor/rspec/examples/pure/io_processor_spec.rb
  119. +11 −0 vendor/rspec/examples/pure/legacy_spec.rb
  120. +27 −0 vendor/rspec/examples/pure/mocking_example.rb
  121. +28 −0 vendor/rspec/examples/pure/multi_threaded_behaviour_runner.rb
  122. +51 −0 vendor/rspec/examples/pure/nested_classes_example.rb
  123. +36 −0 vendor/rspec/examples/pure/nested_example.rb
  124. +28 −0 vendor/rspec/examples/pure/partial_mock_example.rb
  125. +20 −0 vendor/rspec/examples/pure/pending_example.rb
  126. +27 −0 vendor/rspec/examples/pure/predicate_example.rb
  127. +1 −0 vendor/rspec/examples/pure/priority.txt
  128. +66 −0 vendor/rspec/examples/pure/shared_example_group_example.rb
  129. +3 −0 vendor/rspec/examples/pure/spec_helper.rb
  130. +36 −0 vendor/rspec/examples/pure/stack.rb
  131. +97 −0 vendor/rspec/examples/pure/stack_spec.rb
  132. +69 −0 vendor/rspec/examples/pure/stubbing_example.rb
  133. +13 −0 vendor/rspec/examples/stories/adder.rb
  134. +34 −0 vendor/rspec/examples/stories/addition
  135. +9 −0 vendor/rspec/examples/stories/addition.rb
  136. +65 −0 vendor/rspec/examples/stories/calculator.rb
  137. +5 −0 vendor/rspec/examples/stories/game-of-life/.loadpath
  138. +21 −0 vendor/rspec/examples/stories/game-of-life/README.txt
  139. +6 −0 vendor/rspec/examples/stories/game-of-life/behaviour/everything.rb
  140. +3 −0 vendor/rspec/examples/stories/game-of-life/behaviour/examples/examples.rb
  141. +35 −0 vendor/rspec/examples/stories/game-of-life/behaviour/examples/game_behaviour.rb
  142. +66 −0 vendor/rspec/examples/stories/game-of-life/behaviour/examples/grid_behaviour.rb
  143. +21 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/CellsWithLessThanTwoNeighboursDie.story
  144. +21 −0 ...r/rspec/examples/stories/game-of-life/behaviour/stories/CellsWithMoreThanThreeNeighboursDie.story
  145. +42 −0 ...c/examples/stories/game-of-life/behaviour/stories/EmptySpacesWithThreeNeighboursCreateACell.story
  146. +42 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/ICanCreateACell.story
  147. +17 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/ICanKillACell.story
  148. +53 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/TheGridWraps.story
  149. +52 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/create_a_cell.rb
  150. +6 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/helper.rb
  151. +26 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/kill_a_cell.rb
  152. +5 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/steps.rb
  153. +3 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/stories.rb
  154. +22 −0 vendor/rspec/examples/stories/game-of-life/behaviour/stories/stories.txt
  155. +3 −0 vendor/rspec/examples/stories/game-of-life/life.rb
  156. +23 −0 vendor/rspec/examples/stories/game-of-life/life/game.rb
  157. +43 −0 vendor/rspec/examples/stories/game-of-life/life/grid.rb
  158. +9 −0 vendor/rspec/examples/stories/helper.rb
  159. +18 −0 vendor/rspec/examples/stories/steps/addition_steps.rb
  160. +36 −0 vendor/rspec/failing_examples/diffing_spec.rb
  161. +10 −0 vendor/rspec/failing_examples/failure_in_setup.rb
  162. +10 −0 vendor/rspec/failing_examples/failure_in_teardown.rb
  163. +40 −0 vendor/rspec/failing_examples/mocking_example.rb
  164. +26 −0 vendor/rspec/failing_examples/mocking_with_flexmock.rb
  165. +25 −0 vendor/rspec/failing_examples/mocking_with_mocha.rb
  166. +27 −0 vendor/rspec/failing_examples/mocking_with_rr.rb
  167. +20 −0 vendor/rspec/failing_examples/partial_mock_example.rb
  168. +29 −0 vendor/rspec/failing_examples/predicate_example.rb
  169. +47 −0 vendor/rspec/failing_examples/raising_example.rb
  170. +3 −0 vendor/rspec/failing_examples/spec_helper.rb
  171. +7 −0 vendor/rspec/failing_examples/syntax_error_example.rb
  172. +44 −0 vendor/rspec/failing_examples/team_spec.rb
  173. +7 −0 vendor/rspec/failing_examples/timeout_behaviour.rb
  174. +9 −0 vendor/rspec/init.rb
  175. +3 −0 vendor/rspec/lib/autotest/discover.rb
  176. +94 −0 vendor/rspec/lib/autotest/rspec.rb
  177. +37 −0 vendor/rspec/lib/spec.rb
  178. +14 −0 vendor/rspec/lib/spec/example.rb
  179. +144 −0 vendor/rspec/lib/spec/example/configuration.rb
  180. +9 −0 vendor/rspec/lib/spec/example/errors.rb
  181. +25 −0 vendor/rspec/lib/spec/example/example.rb
  182. +16 −0 vendor/rspec/lib/spec/example/example_group.rb
  183. +88 −0 vendor/rspec/lib/spec/example/example_group_description.rb
  184. +98 −0 vendor/rspec/lib/spec/example/example_group_factory.rb
  185. +407 −0 vendor/rspec/lib/spec/example/example_group_methods.rb
  186. +42 −0 vendor/rspec/lib/spec/example/example_matcher.rb
  187. +83 −0 vendor/rspec/lib/spec/example/example_methods.rb
  188. +21 −0 vendor/rspec/lib/spec/example/module_reopening_fix.rb
  189. +18 −0 vendor/rspec/lib/spec/example/pending.rb
  190. +59 −0 vendor/rspec/lib/spec/example/shared_example_group.rb
  191. +56 −0 vendor/rspec/lib/spec/expectations.rb
Sorry, we could not display the entire diff because too many files (455) changed.
View
118 README
@@ -0,0 +1,118 @@
+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
+ 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.
+
+ # use_grammar.rb
+ require 'rubygems'
+ require 'treetop'
+ Treetop.load 'my_grammar'
+
+ parser = MyGrammarParser.new
+ puts parser.parse('hello chomsky').success? # => true
+ puts parser.parse('silly generativists!').success? # => false
+
+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.
+
+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
+
+ # fragment of use_grammar.rb
+ puts parser.parse('hello chomsky').success? # => true
+ puts parser.parse('hello lambek').success? # => true
+ puts parser.parse('silly generativists!').success? # => false
+
+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
+
+Node the use of parentheses to override the default precedence rules, which bind sequences more tightly than choices.
+
+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.
+
+
+Features to cover in the talk
+=============================
+
+* Treetop files
+* Grammar definition
+* Rules
+* Loading a grammar
+* Compiling a grammar with the `tt` command
+* Accessing a parser for the grammar from Ruby
+* Parsing Expressions of all kinds
+? Left recursion and factorization
+ - Here I can talk about function application, discussing how the operator
+ could be an arbitrary expression
+* Inline node class eval blocks
+* Node class declarations
+* Labels
+* Use of super within within labels
+* Grammar composition with include
+* Use of super with grammar composition
+
+
View
36 Rakefile
@@ -0,0 +1,36 @@
+dir = File.dirname(__FILE__)
+require 'rubygems'
+require 'rake'
+$LOAD_PATH.unshift(File.join(dir, 'vendor', 'rspec', 'lib'))
+require 'spec/rake/spectask'
+
+Gem::manage_gems
+require 'rake/gempackagetask'
+
+task :default => :spec
+
+Spec::Rake::SpecTask.new do |t|
+ t.pattern = 'spec/**/*spec.rb'
+end
+
+gemspec = Gem::Specification.new do |s|
+ s.name = "treetop"
+ s.version = "1.1.6"
+ s.author = "Nathan Sobo"
+ s.email = "nathansobo@gmail.com"
+ s.homepage = "http://functionalform.blogspot.com"
+ s.platform = Gem::Platform::RUBY
+ s.summary = "A Ruby-based text parsing and interpretation DSL"
+ s.files = FileList["README", "Rakefile", "{test,lib,bin,doc,examples}/**/*"].to_a
+ s.bindir = "bin"
+ s.executables = ["tt"]
+ s.require_path = "lib"
+ s.autorequire = "treetop"
+ s.has_rdoc = false
+ s.add_dependency "facets", ">=2.0.2"
+ s.add_dependency "polyglot"
+end
+
+Rake::GemPackageTask.new(gemspec) do |pkg|
+ pkg.need_tar = true
+end
View
25 bin/tt
@@ -0,0 +1,25 @@
+#!/usr/bin/env ruby
+require 'rubygems'
+gem 'treetop'
+
+$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
+require 'treetop'
+
+if ARGV.empty?
+ puts "Usage:\n\ntt foo.treetop bar.treetop ...\n or\ntt foo.treetop -o alternate_name.rb\n\n"
+ exit
+end
+
+compiler = Treetop::Compiler::GrammarCompiler.new
+
+# explicit output file name option
+if ARGV.size == 3 && ARGV[1] == '-o'
+ compiler.compile(ARGV[0], ARGV[2])
+ exit
+end
+
+# list of input files option
+treetop_files = ARGV
+treetop_files.each do |treetop_file_path|
+ compiler.compile(treetop_file_path)
+end
View
106 doc/contributing_and_planned_features.markdown
@@ -0,0 +1,106 @@
+#Contributing
+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 the metagrammar 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. This became an issue fairly recently when I closed the loop on the bootstrap. Serious iteration on the metagrammar will probably necessitate a more robust testing strategy, perhaps one that relies on the Treetop gem for compiling the metagrammar under test. I haven't done this because my changes since closing the metacircular loop have been minor enough to deal with the issue, but let me know if you need help on this front.
+
+##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.
+
+Due to shortcomings in Ruby's semantics that scope constant definitions in a block's lexical environment rather than the environment in which it is module evaluated, I was unable to use Rspec without polluting a global namespace with const definitions. Rspec has recently improved to allow specs to reside within standard Ruby classes, but I have not yet migrated the tests back. Instead, they are built on a modified version of Test::Unit that allows tests to be defined as strings. It's not ideal but it worked at the time.
+
+#What Needs to be Done
+##Small Stuff
+* Migrate the tests back to RSpec.
+* 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.
+* Allow the root of a grammar to be dynamically set for testing purposes.
+
+##Big Stuff
+###Avoiding Excessive Object Instantiation
+Based on some preliminary profiling work, it is pretty apparent that a large percentage of a typical parse's time is spent instantiating objects. This needs to be avoided if parsing is to be more performant.
+
+####Avoiding Failure Result Instantiation
+Currently, every parse failure instantiates a failure object. Both success and failure objects propagate an array of the furthest-advanced terminal failures encountered during the parse. These are used to give feedback to the user in the event of a parse failure as to where the most likely source of the error was located. Rather than propagate them upward in the failure objects, it would be faster to just return false in the event of failure and instead write terminal failures to a mutable data structure that is global to the parse. Even this can be done only in the event that the index of the failure is greater than or equal to the current maximal failure index. In addition to minimizing failure object instantiation, this will probably reduce the time spent sorting propagated failures.
+
+####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.
View
65 doc/grammar_composition.markdown
@@ -0,0 +1,65 @@
+#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.
View
BIN doc/images/bottom_background.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN doc/images/middle_backgound.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN doc/images/middle_background.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN doc/images/paren_language_output.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN doc/images/top_background.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
29 doc/index.markdown
@@ -0,0 +1,29 @@
+<p class="intro_text">
+
+Treetop is a language for describing languages. Combining the elegance of Ruby with cutting-edge <em>parsing expression grammars</em>, it helps you analyze syntax with revolutionarily ease.
+
+</p>
+
+
+#Intuitive Grammar Specifications
+Treetop's packrat parsers use _memoization_ to make the backtracking possible in linear time. This cuts the gordian knot of grammar design. There's no need to look ahead and no need to lex. Worry about the structure of the language, not the idiosyncrasies of the parser.
+
+#Syntax-Oriented Programming
+Rather than implementing semantic actions that construct parse trees, define methods on the trees that Treetop automatically constructs–and write this code directly inside the grammar.
+
+#Reusable, Composable Language Descriptions
+Break grammars into modules and compose them via Ruby's mixin semantics. Or combine grammars written by others in novel ways. Or extend existing grammars with your own syntactic constructs by overriding rules with access to a `super` keyword. Compositionally means your investment of time into grammar writing is secure–you can always extend and reuse your code.
+
+#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.
View
51 doc/pitfalls_and_advanced_techniques.markdown
@@ -0,0 +1,51 @@
+#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 any character but a quote or an escaped 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* ** --> <strong><em>hello</em></strong>
+ * **hello** * --> <em><strong>hello</strong></em>
+
+ 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.
View
52 doc/screen.css
@@ -0,0 +1,52 @@
+body {
+ margin: 0;
+ padding: 0;
+ background: #666666;
+ font-family: "Lucida Grande", Geneva, Arial, Verdana, sans-serif;
+ color: #333333;
+}
+
+div {
+ margin: 0;
+ background-position: center;
+ background-repeat: none;
+}
+
+h1 {
+ font-size: 120%;
+ margin-top: 1.5em;
+ margin-bottom: .5em;
+}
+
+div#top {
+ background-image: url("images/top_background.png");
+ height: 200px;
+ width: 100%;
+}
+
+div#middle {
+ padding-top: 10px;
+ background-image: url("images/middle_background.png");
+ background-repeat: repeat-y;
+}
+
+div#bottom {
+ background-image: url("images/bottom_background.png");
+ height: 42px;
+ margin-bottom: 30px;
+}
+
+div#content {
+ width: 481px;
+ margin: 0 auto 0 auto;
+ padding: 0 60px 25px 60px;
+}
+
+p {
+ line-height: 150%;
+}
+
+p.intro_text {
+ color: #C45900;
+ font-size: 115%;
+}
View
187 doc/semantic_interpretation.markdown
@@ -0,0 +1,187 @@
+#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 two 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 ')' <ParenNode>
+ /
+ [a-z] <ParenNode>
+ 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. Than 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.
+
+###Extending A Propagated Node with a Declared Module
+ # in .treetop file
+ rule parenthesized_letter
+ ('(' parenthesized_letter ')' / [a-z]) <ParenNode>
+ 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.map { |comma_and_letter| comma_and_letter.letter }
+ 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.map { |comma_and_letter| comma_and_letter.letter }
+ end
+ }
+ end
+
+
+##Methods Available on `Treetop::Runtime::SyntaxNode`
+
+<table>
+ <tr>
+ <td>
+ <code>terminal?</code>
+ </td>
+ <td>
+ Was this node produced by the matching of a terminal symbol?
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <code>nonterminal?</code>
+ </td>
+ <td>
+ Was this node produced by the matching of a nonterminal symbol?
+ </td>
+ <tr>
+ <td>
+ <code>text_value</code>
+ </td>
+ <td>
+ The substring of the input represented by this node.
+ </td>
+ <tr>
+ <td>
+ <code>elements</code>
+ </td>
+ <td>
+ Available only on nonterminal nodes, returns the nodes parsed by the elements of the matched sequence.
+ </td>
+ </tr>
+</table>
View
34 doc/site.html
@@ -0,0 +1,34 @@
+<html><head><link type="text/css" href="./screen.css" rel="stylesheet"></link></head><body><div id="top"></div><div id="middle"><div id="content"><p class="intro_text">
+
+Treetop is a language for describing languages. Combining the elegance of Ruby with cutting-edge <em>parsing expression grammars</em>, it helps you analyze syntax with revolutionarily ease.
+
+</p>
+
+<h1>Intuitive Grammar Specifications</h1>
+
+<p>Treetop's packrat parsers use <em>memoization</em> to make the backtracking possible in linear time. This cuts the gordian knot of grammar design. There's no need to look ahead and no need to lex. Worry about the structure of the language, not the idiosyncrasies of the parser.</p>
+
+<h1>Syntax-Oriented Programming</h1>
+
+<p>Rather than implementing semantic actions that construct parse trees, define methods on the trees that Treetop automatically constructs–and write this code directly inside the grammar.</p>
+
+<h1>Reusable, Composable Language Descriptions</h1>
+
+<p>Break grammars into modules and compose them via Ruby's mixin semantics. Or combine grammars written by others in novel ways. Or extend existing grammars with your own syntactic constructs by overriding rules with access to a <code>super</code> keyword. Compositionally means your investment of time into grammar writing is secure–you can always extend and reuse your code.</p>
+
+<h1>Acknowledgements</h1>
+
+<p>First, thank you to my employer Rob Mee of Pivotal Labs for funding a substantial portion of Treetop's development. He gets it.</p>
+
+<p>I'd also like to thank:</p>
+
+<ul>
+<li>Damon McCormick for several hours of pair programming.</li>
+<li>Nick Kallen for lots of well-considered feedback and a few afternoons of programming.</li>
+<li>Brian Takita for a night of pair programming.</li>
+<li>Eliot Miranda for urging me rewrite as a compiler right away rather than putting it off.</li>
+<li>Ryan Davis and Eric Hodel for hurting my code.</li>
+<li>Dav Yaginuma for kicking me into action on my idea.</li>
+<li>Bryan Ford for his seminal work on Packrat Parsers.</li>
+<li>The editors of Lambda the Ultimate, where I discovered parsing expression grammars.</li>
+</ul></div></div><div id="bottom"></div></body></html>
View
41 doc/site.rb
@@ -0,0 +1,41 @@
+require 'rubygems'
+require 'erector'
+
+class Layout < Erector::Widget
+ def render
+ html do
+ head do
+ link :rel => "stylesheet",
+ :type => "text/css",
+ :href => "./screen.css"
+ end
+
+ body do
+ div :id => 'top' do
+ end
+ div :id => 'middle' do
+ div :id => 'content' do
+ content
+ end
+ end
+ div :id => 'bottom' do
+
+ end
+ end
+ end
+ end
+
+ def bluecloth(path)
+ File.open(path) do |file|
+ text BlueCloth.new(file.read).to_html
+ end
+ end
+end
+
+class Index < Layout
+ def content
+ bluecloth "index.markdown"
+ end
+end
+
+puts Index.new.to_s
View
103 doc/syntactic_recognition.markdown
@@ -0,0 +1,103 @@
+#Syntactic Recognition
+Treetop grammars are written in a custom language based on parsing expression grammars. Literature on the subject of parsing expression grammars is useful in writing Treetop grammars.
+
+#Grammar Structure
+Treetop grammars look like this:
+
+ grammar GrammarName
+ 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.
+
+* `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.
+
+#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.
+
+##Atomic Expressions
+###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.
+
+###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
+
+##Composite Expressions
+###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.
+
+###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")
+
+###Repetitions
+####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 star (`+`) 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.
+
+##Lookahead Assertions
+Lookahead assertions can be used to give parsing expressions a limited degree of context-sensitivity. 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"`.
View
17 doc/using_in_ruby.markdown
@@ -0,0 +1,17 @@
+#Using Treetop Grammars in Ruby
+##Using the Command Line Compiler
+You can `.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 `Treetop.load` method takes the path to a `.treetop` file (where the extension is optional), and automatically compiles and 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. The need to do this is being addressed.
+
+##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.
+
+ Treetop.load "arithmetic"
+
+ parser = ArithmeticParser.new
+ puts parser.parse('1+1').success?
View
551 examples/lambda_calculus/arithmetic.rb
@@ -0,0 +1,551 @@
+module 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
View
97 examples/lambda_calculus/arithmetic.treetop
@@ -0,0 +1,97 @@
+grammar Arithmetic
+ rule expression
+ comparative / additive
+ end
+
+ rule comparative
+ operand_1:additive space operator:equality_op space operand_2:additive <BinaryOperation>
+ end
+
+ rule equality_op
+ '==' {
+ def apply(a, b)
+ a == b
+ end
+ }
+ end
+
+ rule additive
+ operand_1:multitive
+ space operator:additive_op space
+ operand_2:additive <BinaryOperation>
+ /
+ multitive
+ end
+
+ rule additive_op
+ '+' {
+ def apply(a, b)
+ a + b
+ end
+ }
+ /
+ '-' {
+ def apply(a, b)
+ a - b
+ end
+ }
+ end
+
+ rule multitive
+ operand_1:primary
+ space operator:multitive_op space
+ operand_2:multitive <BinaryOperation>
+ /
+ 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
View
7 examples/lambda_calculus/arithmetic_node_classes.rb
@@ -0,0 +1,7 @@
+module Arithmetic
+ class BinaryOperation < Treetop::Runtime::SyntaxNode
+ def eval(env={})
+ operator.apply(operand_1.eval(env), operand_2.eval(env))
+ end
+ end
+end
View
54 examples/lambda_calculus/arithmetic_test.rb
@@ -0,0 +1,54 @@
+dir = 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_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
View
0 examples/lambda_calculus/lambda_calculus
No changes.
View
718 examples/lambda_calculus/lambda_calculus.rb
@@ -0,0 +1,718 @@
+module LambdaCalculus
+ include Treetop::Runtime
+
+ def root
+ @root || :program
+ end
+
+ include Arithmetic
+
+ module Program0
+ def space
+ elements[1]
+ end
+
+ def expression
+ elements[2]
+ end
+ end
+
+ module Program1
+ def expression
+ elements[0]
+ end
+
+ def more_expressions
+ elements[1]
+ end
+ end
+
+ module Program2
+ 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
+
+ def _nt_program
+ start_index = index
+ cached = node_cache[:program][index]
+ if cached
+ @index = cached.interval.end
+ return cached
+ end
+
+ i0, s0 = index, []
+ r1 = _nt_expression
+ s0 << r1
+ if r1.success?
+ s2, i2 = [], index
+ loop do
+ 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
+ end
+ end
+ if s3.last.success?
+ r3 = (SyntaxNode).new(input, i3...index, s3)
+ r3.extend(Program0)
+ else
+ self.index = i3
+ r3 = ParseFailure.new(input, i3)
+ end
+ if r3.success?
+ s2 << r3
+ else
+ break
+ end
+ end
+ r2 = SyntaxNode.new(input, i2...index, s2)
+ s0 << r2
+ end
+ if s0.last.success?
+ r0 = (SyntaxNode).new(input, i0...index, s0)
+ r0.extend(Program1)
+ r0.extend(Program2)
+ else
+ self.index = i0
+ r0 = ParseFailure.new(input, i0)
+ end
+
+ node_cache[:program][start_index] = r0
+
+ return r0
+ 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_definition
+ if r1.success?
+ r0 = r1
+ else
+ r2 = _nt_conditional
+ if r2.success?
+ r0 = r2
+ else
+ r3 = _nt_application
+ if r3.success?
+ r0 = r3
+ else
+ r4 = _nt_function
+ if r4.success?
+ r0 = r4
+ else
+ r5 = super
+ if r5.success?
+ r0 = r5
+ else
+ self.index = i0
+ r0 = ParseFailure.new(input, i0)
+ end
+ end
+ end
+ end
+ end
+
+ node_cache[:expression][start_index] = r0
+
+ return r0
+ end
+
+ module Definition0
+ def space
+ elements[1]
+ end
+
+ def variable
+ elements[2]
+ end
+
+ def space
+ elements[3]
+ end
+
+ def expression
+ elements[4]
+ end
+ end
+
+ module Definition1
+ def eval(env)
+ env[variable.name] = expression.eval(env)
+ end
+ end
+
+ def _nt_definition
+ start_index = index
+ cached = node_cache[:definition][index]
+ if cached
+ @index = cached.interval.end
+ return cached
+ end
+
+ i0, s0 = index, []
+ r1 = parse_terminal('def', SyntaxNode)
+ s0 << r1
+ if r1.success?
+ r2 = _nt_space
+ s0 << r2
+ if r2.success?
+ r3 = _nt_variable
+ s0 << r3
+ if r3.success?
+ r4 = _nt_space
+ s0 << r4
+ if r4.success?
+ r5 = _nt_expression
+ s0 << r5
+ end
+ end
+ end
+ end
+ if s0.last.success?
+ r0 = (SyntaxNode).new(input, i0...index, s0)
+ r0.extend(Definition0)
+ r0.extend(Definition1)
+ else
+ self.index = i0
+ r0 = ParseFailure.new(input, i0)
+ end
+
+ node_cache[:definition][start_index] = r0
+
+ return r0
+ end
+
+ module Conditional0
+ def space
+ elements[1]
+ end
+
+ def space
+ elements[3]
+ end
+
+ def condition
+ elements[4]
+ end
+
+ def space
+ elements[5]
+ end
+
+ def space
+ elements[7]
+ end
+
+ def true_case
+ elements[8]
+ end
+
+ def space
+ elements[9]
+ end
+
+ def space
+ elements[11]
+ end
+
+ def false_case
+ elements[12]
+ end
+ end
+
+ module Conditional1
+ def eval(env)
+ if condition.eval(env)
+ true_case.eval(env)
+ else
+ false_case.eval(env)
+ end
+ end
+ end
+
+ def _nt_conditional
+ start_index = index
+ cached = node_cache[:conditional][index]
+ if cached
+ @index = cached.interval.end
+ return cached
+ end
+
+ i0, s0 = index, []
+ r1 = parse_terminal('if', SyntaxNode)
+ s0 << r1
+ if r1.success?
+ r2 = _nt_space
+ s0 << r2
+ if r2.success?
+ r3 = parse_terminal('(', SyntaxNode)
+ s0 << r3
+ if r3.success?
+ r4 = _nt_space
+ s0 << r4
+ if r4.success?
+ r5 = _nt_expression
+ s0 << r5
+ if r5.success?
+ r6 = _nt_space
+ s0 << r6
+ if r6.success?
+ r7 = parse_terminal(')', SyntaxNode)
+ s0 << r7
+ if r7.success?
+ r8 = _nt_space
+ s0 << r8
+ if r8.success?
+ r9 = _nt_expression
+ s0 << r9
+ if r9.success?
+ r10 = _nt_space
+ s0 << r10
+ if r10.success?
+ r11 = parse_terminal('else', SyntaxNode)
+ s0 << r11
+ if r11.success?
+ r12 = _nt_space
+ s0 << r12
+ if r12.success?
+ r13 = _nt_expression
+ s0 << r13
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ if s0.last.success?
+ r0 = (SyntaxNode).new(input, i0...index, s0)
+ r0.extend(Conditional0)
+ r0.extend(Conditional1)
+ else
+ self.index = i0
+ r0 = ParseFailure.new(input, i0)
+ end
+
+ node_cache[:conditional][start_index] = r0
+
+ return r0
+ 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_application
+ if r1.success?
+ r0 = r1
+ else
+ r2 = super
+ if r2.success?
+ r0 = r2
+ else
+ self.index = i0
+ r0 = ParseFailure.new(input, i0)
+ end
+ end
+
+ node_cache[:primary][start_index] = r0
+
+ return r0
+ end
+
+ module Application0
+ def operator
+ elements[0]
+ end
+
+ def space
+ elements[1]
+ end
+
+ def expression
+ elements[2]
+ end
+ end
+
+ module Application1
+ 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
+
+ def _nt_application
+ start_index = index
+ cached = node_cache[:application][index]
+ if cached
+ @index = cached.interval.end
+ return cached
+ end
+
+ i0, s0 = index, []
+ r1 = _nt_operator
+ s0 << r1
+ if r1.success?
+ r2 = _nt_space
+ s0 << r2
+ if r2.success?
+ r3 = _nt_expression
+ s0 << r3
+ end
+ end
+ if s0.last.success?
+ r0 = (Application).new(input, i0...index, s0)
+ r0.extend(Application0)
+ r0.extend(Application1)
+ else
+ self.index = i0
+ r0 = ParseFailure.new(input, i0)
+ end
+
+ node_cache[:application][start_index] = r0
+
+ return r0
+ end
+
+ def _nt_operator
+ start_index = index
+ cached = node_cache[:operator][index]
+ if cached
+ @index = cached.interval.end
+ return cached
+ end
+
+ i0 = index
+ r1 = _nt_function
+ if r1.success?
+ r0 = r1
+ else
+ r2 = _nt_variable
+ if r2.success?
+ r0 = r2
+ else
+ self.index = i0
+ r0 = ParseFailure.new(input, i0)
+ end
+ end
+
+ node_cache[:operator][start_index] = r0
+
+ return r0
+ end
+
+ def _nt_non_application
+ start_index = index
+ cached = node_cache[:non_application][index]
+ if cached