treetop 0.1.0 → 1.0.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.
Files changed (153) hide show
  1. data/README +3 -0
  2. data/Rakefile +35 -0
  3. data/bin/tt +25 -0
  4. data/lib/treetop.rb +10 -6
  5. data/lib/treetop/compiler.rb +7 -0
  6. data/lib/treetop/compiler/grammar_compiler.rb +21 -0
  7. data/lib/treetop/compiler/lexical_address_space.rb +17 -0
  8. data/lib/treetop/compiler/load_grammar.rb +7 -0
  9. data/lib/treetop/compiler/metagrammar.rb +2441 -0
  10. data/lib/treetop/compiler/metagrammar.treetop +384 -0
  11. data/lib/treetop/compiler/node_classes.rb +18 -0
  12. data/lib/treetop/compiler/node_classes/anything_symbol.rb +10 -0
  13. data/lib/treetop/compiler/node_classes/atomic_expression.rb +9 -0
  14. data/lib/treetop/compiler/node_classes/character_class.rb +10 -0
  15. data/lib/treetop/compiler/node_classes/choice.rb +31 -0
  16. data/lib/treetop/compiler/node_classes/declaration_sequence.rb +24 -0
  17. data/lib/treetop/compiler/node_classes/grammar.rb +28 -0
  18. data/lib/treetop/compiler/node_classes/inline_module.rb +27 -0
  19. data/lib/treetop/compiler/node_classes/nonterminal.rb +11 -0
  20. data/lib/treetop/compiler/node_classes/optional.rb +19 -0
  21. data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +9 -0
  22. data/lib/treetop/compiler/node_classes/parsing_expression.rb +132 -0
  23. data/lib/treetop/compiler/node_classes/parsing_rule.rb +55 -0
  24. data/lib/treetop/compiler/node_classes/predicate.rb +45 -0
  25. data/lib/treetop/compiler/node_classes/repetition.rb +56 -0
  26. data/lib/treetop/compiler/node_classes/sequence.rb +64 -0
  27. data/lib/treetop/compiler/node_classes/terminal.rb +10 -0
  28. data/lib/treetop/compiler/node_classes/treetop_file.rb +9 -0
  29. data/lib/treetop/compiler/ruby_builder.rb +109 -0
  30. data/lib/treetop/ruby_extensions.rb +2 -0
  31. data/lib/treetop/ruby_extensions/string.rb +19 -0
  32. data/lib/treetop/runtime.rb +9 -0
  33. data/lib/treetop/runtime/compiled_parser.rb +66 -0
  34. data/lib/treetop/runtime/node_cache.rb +27 -0
  35. data/lib/treetop/runtime/parse_cache.rb +19 -0
  36. data/lib/treetop/runtime/parse_failure.rb +32 -0
  37. data/lib/treetop/runtime/parse_result.rb +30 -0
  38. data/lib/treetop/runtime/syntax_node.rb +53 -0
  39. data/lib/treetop/runtime/terminal_parse_failure.rb +33 -0
  40. data/lib/treetop/runtime/terminal_syntax_node.rb +12 -0
  41. data/test/compilation_target/target.rb +143 -0
  42. data/test/compilation_target/target.treetop +15 -0
  43. data/test/compilation_target/target_test.rb +56 -0
  44. data/test/compiler/and_predicate_test.rb +33 -0
  45. data/test/compiler/anything_symbol_test.rb +24 -0
  46. data/test/compiler/character_class_test.rb +45 -0
  47. data/test/compiler/choice_test.rb +49 -0
  48. data/test/compiler/circular_compilation_test.rb +20 -0
  49. data/test/compiler/failure_propagation_functional_test.rb +20 -0
  50. data/test/compiler/grammar_compiler_test.rb +58 -0
  51. data/test/compiler/grammar_test.rb +33 -0
  52. data/test/compiler/nonterminal_symbol_test.rb +15 -0
  53. data/test/compiler/not_predicate_test.rb +35 -0
  54. data/test/compiler/one_or_more_test.rb +30 -0
  55. data/test/compiler/optional_test.rb +32 -0
  56. data/test/compiler/parsing_rule_test.rb +30 -0
  57. data/test/compiler/sequence_test.rb +68 -0
  58. data/test/compiler/terminal_symbol_test.rb +35 -0
  59. data/test/compiler/test_grammar.treetop +7 -0
  60. data/test/compiler/zero_or_more_test.rb +51 -0
  61. data/test/composition/a.treetop +11 -0
  62. data/test/composition/b.treetop +11 -0
  63. data/test/composition/c.treetop +10 -0
  64. data/test/composition/d.treetop +10 -0
  65. data/test/composition/grammar_composition_test.rb +23 -0
  66. data/test/parser/syntax_node_test.rb +53 -0
  67. data/test/parser/terminal_parse_failure_test.rb +22 -0
  68. data/test/ruby_extensions/string_test.rb +33 -0
  69. data/test/screw/Rakefile +16 -0
  70. data/test/screw/unit.rb +37 -0
  71. data/test/screw/unit/assertion_failed_error.rb +14 -0
  72. data/test/screw/unit/assertions.rb +615 -0
  73. data/test/screw/unit/auto_runner.rb +227 -0
  74. data/test/screw/unit/collector.rb +45 -0
  75. data/test/screw/unit/collector/dir.rb +107 -0
  76. data/test/screw/unit/collector/objectspace.rb +28 -0
  77. data/test/screw/unit/error.rb +48 -0
  78. data/test/screw/unit/failure.rb +45 -0
  79. data/test/screw/unit/sugar.rb +25 -0
  80. data/test/screw/unit/test_case.rb +176 -0
  81. data/test/screw/unit/test_result.rb +73 -0
  82. data/test/screw/unit/test_suite.rb +70 -0
  83. data/test/screw/unit/ui.rb +4 -0
  84. data/test/screw/unit/ui/console/test_runner.rb +118 -0
  85. data/test/screw/unit/ui/fox/test_runner.rb +268 -0
  86. data/test/screw/unit/ui/gtk/test_runner.rb +416 -0
  87. data/test/screw/unit/ui/gtk2/testrunner.rb +465 -0
  88. data/test/screw/unit/ui/test_runner_mediator.rb +58 -0
  89. data/test/screw/unit/ui/test_runner_utilities.rb +46 -0
  90. data/test/screw/unit/ui/tk/test_runner.rb +260 -0
  91. data/test/screw/unit/util.rb +4 -0
  92. data/test/screw/unit/util/backtrace_filter.rb +40 -0
  93. data/test/screw/unit/util/observable.rb +82 -0
  94. data/test/screw/unit/util/proc_wrapper.rb +48 -0
  95. data/test/test_helper.rb +89 -0
  96. metadata +127 -69
  97. data/lib/treetop/api.rb +0 -3
  98. data/lib/treetop/api/load_grammar.rb +0 -16
  99. data/lib/treetop/api/malformed_grammar_exception.rb +0 -9
  100. data/lib/treetop/grammar.rb +0 -7
  101. data/lib/treetop/grammar/grammar.rb +0 -48
  102. data/lib/treetop/grammar/grammar_builder.rb +0 -35
  103. data/lib/treetop/grammar/parsing_expression_builder.rb +0 -5
  104. data/lib/treetop/grammar/parsing_expression_builder_helper.rb +0 -121
  105. data/lib/treetop/grammar/parsing_expressions.rb +0 -18
  106. data/lib/treetop/grammar/parsing_expressions/and_predicate.rb +0 -17
  107. data/lib/treetop/grammar/parsing_expressions/anything_symbol.rb +0 -20
  108. data/lib/treetop/grammar/parsing_expressions/character_class.rb +0 -24
  109. data/lib/treetop/grammar/parsing_expressions/node_instantiating_parsing_expression.rb +0 -14
  110. data/lib/treetop/grammar/parsing_expressions/node_propagating_parsing_expression.rb +0 -4
  111. data/lib/treetop/grammar/parsing_expressions/nonterminal_symbol.rb +0 -42
  112. data/lib/treetop/grammar/parsing_expressions/not_predicate.rb +0 -18
  113. data/lib/treetop/grammar/parsing_expressions/one_or_more.rb +0 -12
  114. data/lib/treetop/grammar/parsing_expressions/optional.rb +0 -14
  115. data/lib/treetop/grammar/parsing_expressions/ordered_choice.rb +0 -27
  116. data/lib/treetop/grammar/parsing_expressions/parsing_expression.rb +0 -36
  117. data/lib/treetop/grammar/parsing_expressions/predicate.rb +0 -25
  118. data/lib/treetop/grammar/parsing_expressions/repeating_parsing_expression.rb +0 -29
  119. data/lib/treetop/grammar/parsing_expressions/sequence.rb +0 -41
  120. data/lib/treetop/grammar/parsing_expressions/terminal_parsing_expression.rb +0 -11
  121. data/lib/treetop/grammar/parsing_expressions/terminal_symbol.rb +0 -31
  122. data/lib/treetop/grammar/parsing_expressions/zero_or_more.rb +0 -11
  123. data/lib/treetop/grammar/parsing_rule.rb +0 -10
  124. data/lib/treetop/metagrammar.rb +0 -2
  125. data/lib/treetop/metagrammar/metagrammar.rb +0 -14
  126. data/lib/treetop/metagrammar/metagrammar.treetop +0 -320
  127. data/lib/treetop/parser.rb +0 -11
  128. data/lib/treetop/parser/node_cache.rb +0 -25
  129. data/lib/treetop/parser/parse_cache.rb +0 -17
  130. data/lib/treetop/parser/parse_failure.rb +0 -22
  131. data/lib/treetop/parser/parse_result.rb +0 -26
  132. data/lib/treetop/parser/parser.rb +0 -24
  133. data/lib/treetop/parser/sequence_syntax_node.rb +0 -14
  134. data/lib/treetop/parser/syntax_node.rb +0 -31
  135. data/lib/treetop/parser/terminal_parse_failure.rb +0 -18
  136. data/lib/treetop/parser/terminal_syntax_node.rb +0 -7
  137. data/lib/treetop/protometagrammar.rb +0 -16
  138. data/lib/treetop/protometagrammar/anything_symbol_expression_builder.rb +0 -13
  139. data/lib/treetop/protometagrammar/block_expression_builder.rb +0 -17
  140. data/lib/treetop/protometagrammar/character_class_expression_builder.rb +0 -25
  141. data/lib/treetop/protometagrammar/grammar_expression_builder.rb +0 -38
  142. data/lib/treetop/protometagrammar/nonterminal_symbol_expression_builder.rb +0 -45
  143. data/lib/treetop/protometagrammar/ordered_choice_expression_builder.rb +0 -21
  144. data/lib/treetop/protometagrammar/parsing_rule_expression_builder.rb +0 -23
  145. data/lib/treetop/protometagrammar/parsing_rule_sequence_expression_builder.rb +0 -14
  146. data/lib/treetop/protometagrammar/prefix_expression_builder.rb +0 -25
  147. data/lib/treetop/protometagrammar/primary_expression_builder.rb +0 -71
  148. data/lib/treetop/protometagrammar/protometagrammar.rb +0 -25
  149. data/lib/treetop/protometagrammar/sequence_expression_builder.rb +0 -37
  150. data/lib/treetop/protometagrammar/suffix_expression_builder.rb +0 -33
  151. data/lib/treetop/protometagrammar/terminal_symbol_expression_builder.rb +0 -52
  152. data/lib/treetop/protometagrammar/trailing_block_expression_builder.rb +0 -30
  153. data/lib/treetop/ruby_extension.rb +0 -11
@@ -0,0 +1,143 @@
1
+ class Target < Treetop::Runtime::CompiledParser
2
+ class Bar < SyntaxNode
3
+
4
+ end
5
+
6
+
7
+ attr_accessor :root
8
+
9
+ def initialize
10
+ self.root = :foo
11
+ end
12
+
13
+ def parse(input)
14
+ prepare_to_parse(input)
15
+ return self.send("_nt_#{root}".to_sym)
16
+ end
17
+
18
+
19
+ module FooInlineModule
20
+ def foo
21
+ 'foo'
22
+ end
23
+ end
24
+
25
+ # parsing expression:
26
+ # 'a' ('b' 'c' / 'b' 'd')+ 'e'
27
+
28
+ # lexical address assignment for results
29
+ # 'a' ('b' 'c' / 'b' 'd')+ 'e'
30
+ # 5 6 8 9 10
31
+ # 4 7
32
+ # 3
33
+ # 1 2
34
+ # 0
35
+ def _nt_foo
36
+ s0, i0 = [], index
37
+
38
+ r1 = parse_terminal('a')
39
+
40
+ s0 << r1
41
+ if s0.last.success?
42
+ # begin + closure
43
+ s2, nr2, i2 = [], [], index
44
+ loop do
45
+ # begin ('b' 'c' / 'b' 'd')
46
+ nr3, i3 = [], index
47
+ # begin 'b' 'c'
48
+ s4, i4 = [], index
49
+ r5 = parse_terminal('b')
50
+ s4 << r5
51
+ if s4.last.success?
52
+ r6 = parse_terminal('c')
53
+ s4 << r6
54
+ end
55
+
56
+ if s4.last.success?
57
+ r4 = SyntaxNode.new(input, i4...index, s4)
58
+ else
59
+ self.index = i4
60
+ r4 = ParseFailure.new(input, i4, s4)
61
+ end
62
+ # end 'b' 'c'; result in r4
63
+
64
+ nr3 << r4
65
+
66
+ # test if we need to try expression 3's next alternative
67
+ if r4.success?
68
+ r3 = r4
69
+ else
70
+ # begin 'b' 'd'
71
+ s7, i7 = [], index
72
+ r8 = parse_terminal('b')
73
+ s7 << r8
74
+ if s7.last.success?
75
+ r9 = parse_terminal('d')
76
+ s7 << r9
77
+ end
78
+
79
+ if s7.last.success?
80
+ r7 = SyntaxNode.new(input, i7...index, s7)
81
+ else
82
+ self.index = i7
83
+ r7 = ParseFailure.new(input, i7, s7)
84
+ end
85
+ # end 'b' 'c'; result in r7
86
+
87
+ nr3 << r7
88
+
89
+ if r7.success?
90
+ r3 = r7
91
+ else
92
+ self.index = i3
93
+ r3 = ParseFailure.new(input, i3, nr3)
94
+ end
95
+ end
96
+ # end ('b' 'c' / 'b' 'd'); result in r3
97
+ nr2 << r3
98
+ if r3.success?
99
+ s2 << r3
100
+ else
101
+ break
102
+ end
103
+ end
104
+
105
+ # s2 has intermediate results of the + closure
106
+ if s2.empty?
107
+ self.index = i2
108
+ r2 = ParseFailure.new(input, i2, nr2)
109
+ else
110
+ r2 = SyntaxNode.new(input, i2...index, s2, nr2)
111
+ end
112
+ # end + closure; results in r2
113
+
114
+ s0 << r2 # put r2 on sequence
115
+
116
+ if s0.last.success?
117
+ r10 = parse_terminal('e')
118
+ s0 << r10
119
+ end
120
+
121
+ if s0.last.success?
122
+ r0 = Bar.new(input, i0...index, s0)
123
+ else
124
+ self.index = i0
125
+ r0 = ParseFailure.new(input, i0, s0)
126
+ end
127
+ # end of the sequence... r0 has a value
128
+
129
+ r0.extend(FooInlineModule)
130
+
131
+ return r0
132
+ end
133
+ end
134
+
135
+ def _nt_optional
136
+ r1 = parse_terminal('foo')
137
+ if r1.success?
138
+ r0 = r1
139
+ else
140
+ r0 = SyntaxNode.new(input, index...index, r1.nested_failures)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,15 @@
1
+ module Target
2
+ class Bar < Treetop::Runtime::SyntaxNode
3
+
4
+ end
5
+
6
+ grammar Foo
7
+ rule foo
8
+ 'a' ('b' 'c' / 'b' 'd')+ 'e' <Bar> {
9
+ def foo
10
+ 'foo'
11
+ end
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,56 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/../test_helper"
3
+
4
+ require "#{dir}/target"
5
+
6
+ describe "An instance of a hand-built Bar parser" do
7
+
8
+ def setup
9
+ @parser = Target.new
10
+ end
11
+
12
+ it "can parse matching input, associating it with the correct node class and that can respond to methods from the inlined module" do
13
+ result = @parser.parse('abce')
14
+ result.should be_success
15
+ result.should be_an_instance_of(Target::Bar)
16
+ result.foo.should == 'foo'
17
+ end
18
+
19
+ it "can parse matching input that exercises foo's positive closure" do
20
+ @parser.parse('abcbcbce').should be_success
21
+ end
22
+
23
+ it "can parse matching input that exercises foo's second alternative" do
24
+ @parser.parse('abde').should be_success
25
+ end
26
+
27
+ it "fails to parse ae and returns the failure to match 'b' as its sole nested failure" do
28
+ result = @parser.parse('ae')
29
+ result.should be_failure
30
+
31
+ result.nested_failures.size.should == 1
32
+ nested_failure = result.nested_failures.first
33
+ nested_failure.index.should == 1
34
+ nested_failure.expected_string.should == 'b'
35
+ end
36
+
37
+ it "fails to parse abe and returns the failure to match 'c' or 'd' as its nested failures" do
38
+ result = @parser.parse('abe')
39
+ result.should be_failure
40
+ result.nested_failures.size.should == 2
41
+
42
+ nested_failure = result.nested_failures[0]
43
+ nested_failure.index.should == 2
44
+ nested_failure.expected_string.should == 'c'
45
+
46
+ nested_failure = result.nested_failures[1]
47
+ nested_failure.index.should == 2
48
+ nested_failure.expected_string.should == 'd'
49
+ end
50
+
51
+ it "parses the optional expression or epsilon" do
52
+ @parser.root = :optional
53
+ @parser.parse('foo').should be_success
54
+ @parser.parse('').should be_success
55
+ end
56
+ end
@@ -0,0 +1,33 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ describe "An &-predicated terminal symbol", :extend => CompilerTestCase do
4
+ testing_expression '&"foo"'
5
+
6
+ it "successfully parses input matching the terminal symbol, returning an epsilon syntax node" do
7
+ parse('foo') do |result|
8
+ result.should be_success
9
+ result.interval.should == (0...0)
10
+ end
11
+ end
12
+ end
13
+
14
+ describe "A sequence of a terminal and an and another &-predicated terminal", :extend => CompilerTestCase do
15
+ testing_expression '"foo" &"bar"'
16
+
17
+ it "matches input matching both terminals, but only consumes the first" do
18
+ parse('foobar') do |result|
19
+ result.should be_success
20
+ result.text_value.should == 'foo'
21
+ end
22
+ end
23
+
24
+ it "fails to parse input matching only the first terminal, with the nested failure of the second" do
25
+ parse('foo') do |result|
26
+ result.should be_failure
27
+ result.nested_failures.size.should == 1
28
+ nested_failure = result.nested_failures[0]
29
+ nested_failure.index.should == 3
30
+ nested_failure.expected_string.should == 'bar'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/../test_helper"
3
+
4
+ class AnythingSymbolTest < CompilerTestCase
5
+ class Foo < Treetop::Runtime::SyntaxNode
6
+ end
7
+
8
+ testing_expression '. <Foo> { def a_method; end }'
9
+
10
+ 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
11
+ (33..127).each do |digit|
12
+ parse(digit.chr) do |result|
13
+ result.should be_success
14
+ result.should be_an_instance_of(Foo)
15
+ result.should respond_to(:a_method)
16
+ result.interval.should == (0...1)
17
+ end
18
+ end
19
+ end
20
+
21
+ it "fails to parse epsilon" do
22
+ parse('').should be_failure
23
+ end
24
+ end
@@ -0,0 +1,45 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ class CharacterClassTest < CompilerTestCase
4
+ class Foo < Treetop::Runtime::SyntaxNode
5
+ end
6
+
7
+ testing_expression "[A-Z] <Foo> { def a_method; end }"
8
+
9
+ 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
10
+ result = parse('A')
11
+ result.should be_an_instance_of(Foo)
12
+ result.should respond_to(:a_method)
13
+ result = parse('N')
14
+ result.should be_an_instance_of(Foo)
15
+ result.should respond_to(:a_method)
16
+ result = parse('Z')
17
+ result.should be_an_instance_of(Foo)
18
+ result.should respond_to(:a_method)
19
+ end
20
+
21
+ it "does not match single characters outside of that range" do
22
+ parse('8').should be_failure
23
+ parse('a').should be_failure
24
+ end
25
+
26
+ it "matches a single character within that range at index 1" do
27
+ parse(' A', :at_index => 1).should be_success
28
+ end
29
+
30
+ it "fails to match a single character out of that range at index 1" do
31
+ parse(' 1', :at_index => 1).should be_failure
32
+ end
33
+ end
34
+
35
+ describe "A character class containing quotes", :extend => CompilerTestCase do
36
+ testing_expression "[\"']"
37
+
38
+ it "matches a quote" do
39
+ parse("'").should be_success
40
+ end
41
+
42
+ it "matches a double-quote" do
43
+ parse('"').should be_success
44
+ end
45
+ end
@@ -0,0 +1,49 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ describe "A choice between terminal symbols", :extend => CompilerTestCase do
4
+ testing_expression '"foo" { def foo_method; end } / "bar" { def bar_method; end } / "baz" { def baz_method; end }'
5
+
6
+ it "successfully parses input matching any of the alternatives, returning a node that responds to methods defined in its respective inline module" do
7
+ result = parse('foo')
8
+ result.should be_success
9
+ result.should respond_to(:foo_method)
10
+
11
+ result = parse('bar')
12
+ result.should be_success
13
+ result.should respond_to(:bar_method)
14
+
15
+ result = parse('baz')
16
+ result.should be_success
17
+ result.should respond_to(:baz_method)
18
+ end
19
+
20
+ it "attaches the nested failure of the first terminal to a successful parsing of input matching the second" do
21
+ result = parse('bar')
22
+ result.nested_failures.size.should == 1
23
+ nested_failure = result.nested_failures[0]
24
+ nested_failure.expected_string.should == 'foo'
25
+ nested_failure.index.should == 0
26
+ end
27
+
28
+ it "attaches the nested failure of the first and second terminal to a successful parsing of input matching the third" do
29
+ result = parse('baz')
30
+ result.nested_failures.size.should == 2
31
+
32
+ first_nested_failure = result.nested_failures[0]
33
+ first_nested_failure.expected_string == 'foo'
34
+ first_nested_failure.index.should == 0
35
+
36
+ first_nested_failure = result.nested_failures[1]
37
+ first_nested_failure.expected_string == 'bar'
38
+ first_nested_failure.index.should == 0
39
+ end
40
+ end
41
+
42
+ describe "A choice between sequences", :extend => CompilerTestCase do
43
+ testing_expression "'foo' 'bar' 'baz'\n/\n'bing' 'bang' 'boom'"
44
+
45
+ it "successfully parses input matching any of the alternatives" do
46
+ parse('foobarbaz').should be_success
47
+ parse('bingbangboom').should be_success
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+ require 'benchmark'
3
+
4
+ class CircularCompilationTest < CompilerTestCase
5
+ test "the generated metagrammar parser can parse the treetop file whence it came" do
6
+ File.open(METAGRAMMAR_PATH, 'r') do |file|
7
+ input = file.read
8
+ result = Treetop::Compiler::MetagrammarParser.new.parse(input)
9
+ result.should be_success
10
+
11
+ Treetop::Compiler.send(:remove_const, :Metagrammar)
12
+ parser_code = result.compile
13
+
14
+ Object.class_eval(parser_code)
15
+
16
+ r = Treetop::Compiler::MetagrammarParser.new.parse(input)
17
+ r.should be_success
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ describe "An expression for braces surrounding zero or more letters followed by semicolons", :extend => CompilerTestCase do
4
+ testing_expression "'{' ([a-z] ';')* '}'"
5
+
6
+ it "parses matching input successfully" do
7
+ parse('{a;b;c;}').should be_success
8
+ end
9
+
10
+ it "fails to parse input with an expression that is missing a semicolon, reporting the correct nested failure" do
11
+ parse('{a;b;c}') do |result|
12
+ result.should be_failure
13
+
14
+ result.nested_failures.size.should == 1
15
+ nested_failure = result.nested_failures[0]
16
+ nested_failure.index.should == 6
17
+ nested_failure.expected_string.should == ';'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,58 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ class GrammarCompilerTest < Screw::Unit::TestCase
4
+
5
+ def setup
6
+ @compiler = Compiler::GrammarCompiler.new
7
+ @source_path = File.join(File.dirname(__FILE__), 'test_grammar.treetop')
8
+ @target_path = File.join(File.dirname(__FILE__), 'test_grammar.rb')
9
+ @alternate_target_path = File.join(File.dirname(__FILE__), 'test_grammar_alt.rb')
10
+ delete_target_files
11
+ end
12
+
13
+ def teardown
14
+ delete_target_files
15
+ Object.class_eval do
16
+ remove_const(:Test) if const_defined?(:Test)
17
+ end
18
+ end
19
+
20
+ test "compilation of a single file to a default file name" do
21
+ assert !File.exists?(@target_path)
22
+ @compiler.compile(@source_path)
23
+ assert File.exists?(@target_path)
24
+ require @target_path
25
+ Test::GrammarParser.new.parse('foo').should be_success
26
+ end
27
+
28
+ test "compilation of a single file to an explicit file name" do
29
+ assert !File.exists?(@alternate_target_path)
30
+ @compiler.compile(@source_path, @alternate_target_path)
31
+ assert File.exists?(@alternate_target_path)
32
+ require @alternate_target_path
33
+ Test::GrammarParser.new.parse('foo').should be_success
34
+ end
35
+
36
+ test "compilation of a single file without writing it to an output file" do
37
+ @compiler.ruby_source(@source_path).should_not be_nil
38
+ end
39
+
40
+ test "load_grammar compiles and evaluates source grammar with extension" do
41
+ load_grammar @source_path
42
+ Test::GrammarParser.new.parse('foo').should be_success
43
+ end
44
+
45
+ test "load_grammar compiles and evaluates source grammar with no extension" do
46
+ path_without_extension = @source_path.gsub(/\.treetop\Z/, '')
47
+ load_grammar path_without_extension
48
+ Test::GrammarParser.new.parse('foo').should be_success
49
+ end
50
+
51
+
52
+ def delete_target_files
53
+ File.delete(@target_path) if File.exists?(@target_path)
54
+ File.delete(@alternate_target_path) if File.exists?(@alternate_target_path)
55
+ end
56
+
57
+ end
58
+