treetop 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -15,13 +15,13 @@ end
15
15
 
16
16
  gemspec = Gem::Specification.new do |s|
17
17
  s.name = "treetop"
18
- s.version = "1.0.2"
18
+ s.version = "1.1.0"
19
19
  s.author = "Nathan Sobo"
20
20
  s.email = "nathansobo@gmail.com"
21
21
  s.homepage = "http://functionalform.blogspot.com"
22
22
  s.platform = Gem::Platform::RUBY
23
23
  s.summary = "A Ruby-based text parsing and interpretation DSL"
24
- s.files = FileList["README", "Rakefile", "{test,lib,bin}/**/*"].to_a
24
+ s.files = FileList["README", "Rakefile", "{test,lib,bin,examples}/**/*"].to_a
25
25
  s.bindir = "bin"
26
26
  s.executables = ["tt"]
27
27
  s.require_path = "lib"
@@ -0,0 +1,33 @@
1
+ Before talk?
2
+ ------------
3
+ - non node-instantiating expressions extend their results with inline modules
4
+ - allow load_grammar and require statements at the top of treetop files
5
+ - deal with facets versioning issue
6
+
7
+
8
+
9
+ Function application... the left-recursion problem
10
+ --------------------------------------------------
11
+ f g x
12
+
13
+ rule expression
14
+ application / function / variable
15
+ end
16
+
17
+ rule application
18
+ expression space expression
19
+ end
20
+
21
+ Function application... how can we avoid left recursion?
22
+ --------------------------------------------------------
23
+ rule expression
24
+ application / function / variable
25
+ end
26
+
27
+ rule application
28
+ operator space expression
29
+ end
30
+
31
+ rule operator
32
+ function / variable
33
+ end
@@ -0,0 +1,99 @@
1
+ grammar Arithmetic
2
+ rule expression
3
+ comparative / additive
4
+ end
5
+
6
+ rule comparative
7
+ exp_1:additive space '==' space exp_2:additive {
8
+ def eval(env={})
9
+ exp_1.eval(env) == exp_2.eval(env)
10
+ end
11
+ }
12
+ end
13
+
14
+ rule additive
15
+ operand_1:multitive
16
+ space operator:additive_op space
17
+ operand_2:additive <BinaryOperation>
18
+ /
19
+ multitive
20
+ end
21
+
22
+ rule additive_op
23
+ '+' {
24
+ def apply(a, b)
25
+ a + b
26
+ end
27
+ }
28
+ /
29
+ '-' {
30
+ def apply(a, b)
31
+ a - b
32
+ end
33
+ }
34
+ end
35
+
36
+ rule multitive
37
+ operand_1:primary
38
+ space operator:multitive_op space
39
+ operand_2:multitive <BinaryOperation>
40
+ /
41
+ primary
42
+ end
43
+
44
+ rule multitive_op
45
+ '*' {
46
+ def apply(a, b)
47
+ a * b
48
+ end
49
+ }
50
+ /
51
+ '/' {
52
+ def apply(a, b)
53
+ a / b
54
+ end
55
+ }
56
+ end
57
+
58
+ rule primary
59
+ variable
60
+ /
61
+ number
62
+ /
63
+ '(' space expression space ')' {
64
+ def eval(env={})
65
+ expression.eval(env)
66
+ end
67
+ }
68
+ end
69
+
70
+ rule variable
71
+ [a-z] {
72
+ def eval(env={})
73
+ env[name]
74
+ end
75
+
76
+ def name
77
+ text_value
78
+ end
79
+ }
80
+ end
81
+
82
+ rule number
83
+ [1-9] [0-9]* {
84
+ def eval(env={})
85
+ text_value.to_i
86
+ end
87
+ }
88
+ /
89
+ '0' {
90
+ def eval(env={})
91
+ text_value.to_i
92
+ end
93
+ }
94
+ end
95
+
96
+ rule space
97
+ ' '*
98
+ end
99
+ end
@@ -0,0 +1,7 @@
1
+ module Arithmetic
2
+ class BinaryOperation < Treetop::Runtime::SyntaxNode
3
+ def eval(env={})
4
+ operator.apply(operand_1.eval(env), operand_2.eval(env))
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,54 @@
1
+ dir = File.dirname(__FILE__)
2
+ require File.expand_path("#{dir}/test_helper")
3
+
4
+ require File.expand_path("#{dir}/arithmetic_node_classes")
5
+ load_grammar File.expand_path("#{dir}/arithmetic")
6
+
7
+ class ArithmeticParserTest < Test::Unit::TestCase
8
+ include ParserTestHelper
9
+
10
+ def setup
11
+ @parser = ArithmeticParser.new
12
+ end
13
+
14
+ def test_number
15
+ assert_equal 0, parse('0').eval
16
+ assert_equal 1, parse('1').eval
17
+ assert_equal 123, parse('123').eval
18
+ end
19
+
20
+ def test_variable
21
+ assert_equal 0, parse('x').eval('x' => 0)
22
+ assert_equal 3, parse('x').eval('x' => 3)
23
+ assert_equal 10, parse('y').eval('y' => 10)
24
+ end
25
+
26
+ def test_addition
27
+ assert_equal 10, parse('x + 5').eval('x' => 5)
28
+ end
29
+
30
+ def test_subtraction
31
+ assert_equal 0, parse('x - 5').eval('x' => 5)
32
+ end
33
+
34
+ def test_multiplication
35
+ assert_equal 6, parse('x * 2').eval('x' => 3)
36
+ end
37
+
38
+ def test_division
39
+ assert_equal 3, parse('x / 2').eval('x' => 6)
40
+ end
41
+
42
+ def test_order_of_operations
43
+ assert_equal 11, parse('1 + 2 * 3 + 4').eval
44
+ end
45
+
46
+ def test_parentheses
47
+ assert_equal 25, parse('(5 + x) * (10 - y)').eval('x' => 0, 'y' => 5)
48
+ end
49
+
50
+ def test_equality
51
+ assert parse('4 == 4').eval
52
+ assert !parse('4 == 3').eval
53
+ end
54
+ end
@@ -0,0 +1,139 @@
1
+ grammar LambdaCalculus
2
+ include Arithmetic
3
+
4
+ rule program
5
+ expression more_expressions:(';' space expression)* {
6
+ def eval(env={})
7
+ env = env.clone
8
+ last_eval = nil
9
+ expressions.each do |exp|
10
+ last_eval = exp.eval(env)
11
+ end
12
+ last_eval
13
+ end
14
+
15
+ def expressions
16
+ [expression] + more_expressions.elements.map {|elt| elt.expression}
17
+ end
18
+ }
19
+ end
20
+
21
+ rule expression
22
+ definition / conditional / application / function / super
23
+ end
24
+
25
+ rule definition
26
+ 'def' space variable space expression {
27
+ def eval(env)
28
+ env[variable.name] = expression.eval(env)
29
+ end
30
+ }
31
+ end
32
+
33
+ rule conditional
34
+ 'if' space '(' space condition:expression space ')' space
35
+ true_case:expression space 'else' space false_case:expression {
36
+ def eval(env)
37
+ if condition.eval(env)
38
+ true_case.eval(env)
39
+ else
40
+ false_case.eval(env)
41
+ end
42
+ end
43
+ }
44
+ end
45
+
46
+ rule primary
47
+ application / super
48
+ end
49
+
50
+ rule application
51
+ operator space expression <Application> {
52
+ def eval(env={})
53
+ left_associative_apply(operator.eval(env), env)
54
+ end
55
+
56
+ def left_associative_apply(operator, env)
57
+ if expression.instance_of?(Application)
58
+ expression.left_associative_apply(operator.apply(expression.operator.eval(env)), env)
59
+ else
60
+ operator.apply(expression.eval(env))
61
+ end
62
+ end
63
+
64
+ def to_s(env={})
65
+ operator.to_s(env) + ' ' + expression.to_s(env)
66
+ end
67
+ }
68
+ end
69
+
70
+ rule operator
71
+ function / variable
72
+ end
73
+
74
+ rule non_application
75
+ function / variable
76
+ end
77
+
78
+ rule function
79
+ '\\' param:variable '(' body:expression ')' {
80
+ class Closure
81
+ attr_reader :env, :function
82
+
83
+ def initialize(function, env)
84
+ @function = function
85
+ @env = env
86
+ end
87
+
88
+ def apply(arg)
89
+ function.body.eval(function.param.bind(arg, env))
90
+ end
91
+
92
+ def to_s(other_env={})
93
+ "\\#{function.param.to_s}(#{function.body.to_s(other_env.merge(env))})"
94
+ end
95
+ end
96
+
97
+ def eval(env={})
98
+ Closure.new(self, env)
99
+ end
100
+
101
+ def to_s(env={})
102
+ eval(env).to_s
103
+ end
104
+ }
105
+ end
106
+
107
+ rule variable
108
+ !keyword [a-z]+ {
109
+ def eval(env={})
110
+ env.has_key?(name) ? env[name] : self
111
+ end
112
+
113
+ def bind(value, env)
114
+ env.merge(name => value)
115
+ end
116
+
117
+ def name
118
+ text_value
119
+ end
120
+
121
+ def to_s(env={})
122
+ env.has_key?(name) ? env[name].to_s : name
123
+ end
124
+ }
125
+ end
126
+
127
+ rule keyword
128
+ ('if' / 'else') !non_space_char
129
+ end
130
+
131
+ rule non_space_char
132
+ ![ \n] .
133
+ end
134
+
135
+
136
+ rule space
137
+ [ \n]*
138
+ end
139
+ end
@@ -0,0 +1,5 @@
1
+ module LambdaCalculus
2
+ class Application < Treetop::Runtime::SyntaxNode
3
+
4
+ end
5
+ end
@@ -0,0 +1,89 @@
1
+ dir = File.dirname(__FILE__)
2
+ require File.expand_path("#{dir}/test_helper")
3
+ require File.expand_path("#{dir}/arithmetic_node_classes")
4
+ require File.expand_path("#{dir}/lambda_calculus_node_classes")
5
+ load_grammar File.expand_path("#{dir}/arithmetic")
6
+ load_grammar File.expand_path("#{dir}/lambda_calculus")
7
+
8
+ class Treetop::Runtime::SyntaxNode
9
+ def method_missing(method, *args)
10
+ raise "Node representing #{text_value} does not respond to #{method}"
11
+ end
12
+ end
13
+
14
+ class LambdaCalculusParserTest < Test::Unit::TestCase
15
+ include ParserTestHelper
16
+
17
+ def setup
18
+ @parser = LambdaCalculusParser.new
19
+ end
20
+
21
+ def test_free_variable
22
+ assert_equal 'x', parse('x').eval.to_s
23
+ end
24
+
25
+ def test_variable_binding
26
+ variable = parse('x').eval
27
+ env = variable.bind(1, {})
28
+ assert_equal 1, env['x']
29
+ end
30
+
31
+ def test_bound_variable_evaluation
32
+ assert_equal 1, parse('x').eval({'x' => 1})
33
+ end
34
+
35
+ def test_identity_function
36
+ assert_equal '\x(x)', parse('\x(x)').eval.to_s
37
+ end
38
+
39
+ def test_function_returning_constant_function
40
+ assert_equal '\x(\y(x))', parse('\x(\y(x))').eval.to_s
41
+ end
42
+
43
+ def test_identity_function_application
44
+ assert_equal 1, parse('\x(x) 1').eval
45
+ assert_equal '\y(y)', parse('\x(x) \y(y)').eval.to_s
46
+ end
47
+
48
+ def test_constant_function_construction
49
+ assert_equal '\y(1)', parse('\x(\y(x)) 1').eval.to_s
50
+ end
51
+
52
+ def test_multiple_argument_application_is_left_associative
53
+ assert_equal '\b(b)', parse('\x(\y(x y)) \a(a) \b(b)').eval.to_s
54
+ end
55
+
56
+ def test_parentheses_override_application_order
57
+ assert_equal '\y(\b(b) y)', parse('\x(\y(x y)) (\a(a) \b(b))').eval.to_s
58
+ end
59
+
60
+ def test_arithmetic_in_function_body
61
+ assert_equal 10, parse('\x(x + 5) 5').eval
62
+ end
63
+
64
+ def test_addition_of_function_results
65
+ assert_equal 20, parse('\x(x + 5) 5 + \x(15 - x) 5').eval
66
+ end
67
+
68
+ def test_conditional
69
+ result = parse('if (x) 1 else 2')
70
+ assert_equal 1, result.eval({'x' => true})
71
+ assert_equal 2, result.eval({'x' => false})
72
+ end
73
+
74
+ def test_keyword
75
+ assert @parser.parse('if').failure?
76
+ assert @parser.parse('else').failure?
77
+ assert parse('elsee').success?
78
+ assert parse('iff').success?
79
+ end
80
+
81
+ def test_program
82
+ result = parse('def fact \x(if (x == 0)
83
+ 1
84
+ else
85
+ x * fact (x - 1));
86
+ fact(5)').eval
87
+ assert_equal 5 * 4 * 3 * 2, result
88
+ end
89
+ end
@@ -0,0 +1,18 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'treetop'
4
+
5
+ module ParserTestHelper
6
+ def assert_evals_to_self(input)
7
+ assert_evals_to(input, input)
8
+ end
9
+
10
+ def parse(input)
11
+ result = @parser.parse(input)
12
+ if result.failure?
13
+ puts result.nested_failures.join("\n")
14
+ end
15
+ assert result.success?
16
+ result
17
+ end
18
+ end
@@ -4,7 +4,12 @@ module Treetop
4
4
  include ::Treetop::Runtime
5
5
 
6
6
  def root
7
- _nt_treetop_file
7
+ result = _nt_treetop_file
8
+ if index == input.size
9
+ return result
10
+ else
11
+ return ParseFailure.new(input, index, result.nested_failures)
12
+ end
8
13
  end
9
14
 
10
15
  module TreetopFile0
@@ -928,8 +933,8 @@ module Treetop
928
933
  atomic
929
934
  end
930
935
 
931
- def node_class
932
- node_class_declarations.node_class
936
+ def node_class_name
937
+ node_class_declarations.node_class_name
933
938
  end
934
939
 
935
940
  def inline_modules
@@ -956,8 +961,8 @@ module Treetop
956
961
  atomic.compile(address, builder, self)
957
962
  end
958
963
 
959
- def node_class
960
- node_class_declarations.node_class
964
+ def node_class_name
965
+ node_class_declarations.node_class_name
961
966
  end
962
967
 
963
968
  def inline_modules
@@ -1245,8 +1250,8 @@ module Treetop
1245
1250
  suffix.compile(lexical_address, builder, self)
1246
1251
  end
1247
1252
 
1248
- def node_class
1249
- 'SyntaxNode'
1253
+ def node_class_name
1254
+ nil
1250
1255
  end
1251
1256
 
1252
1257
  def inline_modules
@@ -1381,8 +1386,8 @@ module Treetop
1381
1386
  end
1382
1387
 
1383
1388
  module NodeClassDeclarations1
1384
- def node_class
1385
- node_class_expression.node_class
1389
+ def node_class_name
1390
+ node_class_expression.node_class_name
1386
1391
  end
1387
1392
 
1388
1393
  def inline_modules
@@ -2001,14 +2006,14 @@ module Treetop
2001
2006
  end
2002
2007
 
2003
2008
  module NodeClassExpression2
2004
- def node_class
2009
+ def node_class_name
2005
2010
  elements[2].text_value
2006
2011
  end
2007
2012
  end
2008
2013
 
2009
2014
  module NodeClassExpression3
2010
- def node_class
2011
- 'SyntaxNode'
2015
+ def node_class_name
2016
+ nil
2012
2017
  end
2013
2018
  end
2014
2019
 
@@ -132,8 +132,8 @@ module Treetop
132
132
  atomic
133
133
  end
134
134
 
135
- def node_class
136
- node_class_declarations.node_class
135
+ def node_class_name
136
+ node_class_declarations.node_class_name
137
137
  end
138
138
 
139
139
  def inline_modules
@@ -150,8 +150,8 @@ module Treetop
150
150
  atomic.compile(address, builder, self)
151
151
  end
152
152
 
153
- def node_class
154
- node_class_declarations.node_class
153
+ def node_class_name
154
+ node_class_declarations.node_class_name
155
155
  end
156
156
 
157
157
  def inline_modules
@@ -224,8 +224,8 @@ module Treetop
224
224
  suffix.compile(lexical_address, builder, self)
225
225
  end
226
226
 
227
- def node_class
228
- 'SyntaxNode'
227
+ def node_class_name
228
+ nil
229
229
  end
230
230
 
231
231
  def inline_modules
@@ -250,8 +250,8 @@ module Treetop
250
250
 
251
251
  rule node_class_declarations
252
252
  node_class_expression trailing_inline_module {
253
- def node_class
254
- node_class_expression.node_class
253
+ def node_class_name
254
+ node_class_expression.node_class_name
255
255
  end
256
256
 
257
257
  def inline_modules
@@ -318,14 +318,14 @@ module Treetop
318
318
 
319
319
  rule node_class_expression
320
320
  space '<' (!'>' .)+ '>' {
321
- def node_class
321
+ def node_class_name
322
322
  elements[2].text_value
323
323
  end
324
324
  }
325
325
  /
326
326
  '' {
327
- def node_class
328
- 'SyntaxNode'
327
+ def node_class_name
328
+ nil
329
329
  end
330
330
  }
331
331
  end
@@ -3,7 +3,7 @@ module Treetop
3
3
  class AnythingSymbol < AtomicExpression
4
4
  def compile(address, builder, parent_expression = nil)
5
5
  super
6
- assign_result "parse_anything(#{node_class}#{optional_arg(inline_module_name)})"
6
+ assign_result "parse_anything(#{node_class_name}#{optional_arg(inline_module_name)})"
7
7
  end
8
8
  end
9
9
  end
@@ -3,7 +3,7 @@ module Treetop
3
3
  class CharacterClass < AtomicExpression
4
4
  def compile(address, builder, parent_expression = nil)
5
5
  super
6
- assign_result "parse_char_class(/#{text_value}/, '#{elements[1].text_value.gsub(/'$/, "\\\\'")}', #{node_class}#{optional_arg(inline_module_name)})"
6
+ assign_result "parse_char_class(/#{text_value}/, '#{elements[1].text_value.gsub(/'$/, "\\\\'")}', #{node_class_name}#{optional_arg(inline_module_name)})"
7
7
  end
8
8
  end
9
9
  end
@@ -15,6 +15,8 @@ module Treetop
15
15
  accumulate_nested_result
16
16
  builder.if__ subexpression_success? do
17
17
  assign_result subexpression_result_var
18
+ extend_result_with_declared_module
19
+ extend_result_with_inline_module
18
20
  builder << "#{subexpression_result_var}.update_nested_results(#{nested_results_var})"
19
21
  end
20
22
  builder.else_ do
@@ -5,6 +5,8 @@ module Treetop
5
5
  super
6
6
  use_vars :result
7
7
  assign_result text_value == 'super' ? 'super' : "_nt_#{text_value}"
8
+ extend_result_with_declared_module
9
+ extend_result_with_inline_module
8
10
  end
9
11
  end
10
12
  end
@@ -2,7 +2,7 @@ module Treetop
2
2
  module Compiler
3
3
  class ParenthesizedExpression < ParsingExpression
4
4
  def compile(address, builder, parent_expression = nil)
5
- elements[2].compile(address, builder)
5
+ elements[2].compile(address, builder, parent_expression)
6
6
  end
7
7
  end
8
8
  end
@@ -9,13 +9,16 @@ module Treetop
9
9
  @parent_expression = parent_expression
10
10
  end
11
11
 
12
- def node_class
13
- parent_expression && parent_expression.node_class || 'SyntaxNode'
12
+ def node_class_name
13
+ parent_expression && parent_expression.node_class_name || 'SyntaxNode'
14
+ end
15
+
16
+ def declared_module_name
17
+ parent_expression && parent_expression.node_class_name
14
18
  end
15
19
 
16
20
  def inline_module_name
17
- return nil unless parent_expression
18
- parent_expression.inline_module_name
21
+ parent_expression && parent_expression.inline_module_name
19
22
  end
20
23
 
21
24
  def optional_arg(arg)
@@ -70,6 +73,18 @@ module Treetop
70
73
  def assign_result(value_ruby)
71
74
  builder.assign result_var, value_ruby
72
75
  end
76
+
77
+ def extend_result(module_name)
78
+ builder.extend result_var, module_name
79
+ end
80
+
81
+ def extend_result_with_declared_module
82
+ extend_result declared_module_name if declared_module_name
83
+ end
84
+
85
+ def extend_result_with_inline_module
86
+ extend_result inline_module_name if inline_module_name
87
+ end
73
88
 
74
89
  def reset_index
75
90
  builder.assign 'self.index', start_index_var
@@ -25,8 +25,8 @@ module Treetop
25
25
  end
26
26
 
27
27
  def assign_and_extend_result
28
- assign_result "#{node_class}.new(input, #{start_index_var}...index, #{accumulator_var}, #{nested_results_var})"
29
- builder << "#{result_var}.extend(#{inline_module_name})" if inline_module_name
28
+ assign_result "#{node_class_name}.new(input, #{start_index_var}...index, #{accumulator_var}, #{nested_results_var})"
29
+ extend_result_with_inline_module
30
30
  end
31
31
  end
32
32
 
@@ -7,9 +7,9 @@ module Treetop
7
7
  use_vars :result, :start_index, :accumulator, :nested_results
8
8
  compile_sequence_elements(sequence_elements)
9
9
  builder.if__ "#{accumulator_var}.last.success?" do
10
- assign_result "(#{node_class_declarations.node_class}).new(input, #{start_index_var}...index, #{accumulator_var})"
11
- builder << "#{result_var}.extend(#{sequence_element_accessor_module_name})" if sequence_element_accessor_module_name
12
- builder << "#{result_var}.extend(#{inline_module_name})" if inline_module_name
10
+ assign_result "(#{node_class_name}).new(input, #{start_index_var}...index, #{accumulator_var})"
11
+ extend_result sequence_element_accessor_module_name if sequence_element_accessor_module_name
12
+ extend_result_with_inline_module
13
13
  end
14
14
  builder.else_ do
15
15
  reset_index
@@ -18,6 +18,10 @@ module Treetop
18
18
  end_comment(self)
19
19
  end
20
20
 
21
+ def node_class_name
22
+ node_class_declarations.node_class_name || 'SyntaxNode'
23
+ end
24
+
21
25
  def compile_sequence_elements(elements)
22
26
  obtain_new_subexpression_address
23
27
  elements.first.compile(subexpression_address, builder)
@@ -3,7 +3,7 @@ module Treetop
3
3
  class Terminal < AtomicExpression
4
4
  def compile(address, builder, parent_expression = nil)
5
5
  super
6
- assign_result "parse_terminal(#{text_value}, #{node_class}#{optional_arg(inline_module_name)})"
6
+ assign_result "parse_terminal(#{text_value}, #{node_class_name}#{optional_arg(inline_module_name)})"
7
7
  end
8
8
  end
9
9
  end
@@ -51,6 +51,10 @@ module Treetop
51
51
  end
52
52
  end
53
53
 
54
+ def extend(var, module_name)
55
+ self << "#{var}.extend(#{module_name})"
56
+ end
57
+
54
58
  def accumulate(left, right)
55
59
  self << "#{left} << #{right}"
56
60
  end
@@ -46,4 +46,29 @@ describe "A choice between sequences", :extend => CompilerTestCase do
46
46
  parse('foobarbaz').should be_success
47
47
  parse('bingbangboom').should be_success
48
48
  end
49
- end
49
+ end
50
+
51
+ describe "A choice between terminals followed by a block", :extend => CompilerTestCase do
52
+ testing_expression "('a'/ 'b' / 'c') { def a_method; end }"
53
+
54
+ it "extends a match of any of its subexpressions with a module created from the block" do
55
+ ['a', 'b', 'c'].each do |letter|
56
+ parse(letter).should respond_to(:a_method)
57
+ end
58
+ end
59
+ end
60
+
61
+ class ChoiceWithDeclaredModuleTest < CompilerTestCase
62
+ module TestModule
63
+ def a_method
64
+ end
65
+ end
66
+
67
+ testing_expression "('a'/ 'b' / 'c') <TestModule>"
68
+
69
+ it "extends a match of any of its subexpressions with a module created from the block" do
70
+ ['a', 'b', 'c'].each do |letter|
71
+ parse(letter).should respond_to(:a_method)
72
+ end
73
+ end
74
+ end
@@ -1,7 +1,7 @@
1
1
  require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
2
 
3
- describe "A nonterminal symbol", :extend => CompilerTestCase do
4
- testing_expression 'foo'
3
+ describe "A nonterminal symbol followed by a block", :extend => CompilerTestCase do
4
+ testing_expression 'foo { def a_method; end }'
5
5
 
6
6
  parser_class_under_test.class_eval do
7
7
  def _nt_foo
@@ -9,7 +9,30 @@ describe "A nonterminal symbol", :extend => CompilerTestCase do
9
9
  end
10
10
  end
11
11
 
12
- it "compiles to a message send" do
13
- parse('').should == '_nt_foo called'
12
+ it "compiles to a method call, extending its results with the anonymous module for the block" do
13
+ result = parse('')
14
+ result.should == '_nt_foo called'
15
+ result.should respond_to(:a_method)
14
16
  end
15
- end
17
+ end
18
+
19
+ class NonterminalWithModuleDeclationTest < CompilerTestCase
20
+ module TestModule
21
+ def a_method
22
+ end
23
+ end
24
+
25
+ testing_expression 'foo <TestModule>'
26
+
27
+ parser_class_under_test.class_eval do
28
+ def _nt_foo
29
+ '_nt_foo called'
30
+ end
31
+ end
32
+
33
+ it "compiles to a method call, extending its results with the anonymous module for the block" do
34
+ result = parse('')
35
+ result.should == '_nt_foo called'
36
+ result.should respond_to(:a_method)
37
+ end
38
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: treetop
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.2
7
- date: 2007-10-22 00:00:00 -07:00
6
+ version: 1.1.0
7
+ date: 2007-10-25 00:00:00 -07:00
8
8
  summary: A Ruby-based text parsing and interpretation DSL
9
9
  require_paths:
10
10
  - lib
@@ -144,6 +144,15 @@ files:
144
144
  - lib/treetop/runtime.rb
145
145
  - lib/treetop.rb
146
146
  - bin/tt
147
+ - examples/lambda_calculus
148
+ - examples/lambda_calculus/arithmetic.treetop
149
+ - examples/lambda_calculus/arithmetic_node_classes.rb
150
+ - examples/lambda_calculus/arithmetic_test.rb
151
+ - examples/lambda_calculus/lambda_calculus.treetop
152
+ - examples/lambda_calculus/lambda_calculus_node_classes.rb
153
+ - examples/lambda_calculus/lambda_calculus_test.rb
154
+ - examples/lambda_calculus/test_helper.rb
155
+ - examples/TALK
147
156
  test_files: []
148
157
 
149
158
  rdoc_options: []