treetop 1.5.3 → 1.6.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +5 -13
  2. data/Gemfile +12 -0
  3. data/History.txt +18 -0
  4. data/README.md +4 -0
  5. data/Rakefile +20 -40
  6. data/Treetop.tmbundle/Preferences/Comments.tmPreferences +28 -0
  7. data/Treetop.tmbundle/Snippets/grammar ___ end.tmSnippet +20 -0
  8. data/Treetop.tmbundle/Snippets/rule ___ end.tmSnippet +18 -0
  9. data/Treetop.tmbundle/Support/nibs/SyntaxTreeViewer.nib/designable.nib +1524 -0
  10. data/Treetop.tmbundle/Support/nibs/SyntaxTreeViewer.nib/keyedobjects.nib +0 -0
  11. data/Treetop.tmbundle/Support/syntax_tree_viewer.rb +117 -0
  12. data/Treetop.tmbundle/Syntaxes/Treetop Grammar.tmLanguage +358 -0
  13. data/Treetop.tmbundle/info.plist +10 -0
  14. data/doc/pitfalls_and_advanced_techniques.markdown +7 -1
  15. data/doc/syntactic_recognition.markdown +7 -2
  16. data/doc/tt.1 +1 -1
  17. data/examples/indented_blocks/indented_blocks.tt +73 -0
  18. data/examples/indented_blocks/indented_blocks_test.rb +24 -0
  19. data/lib/treetop/compiler/grammar_compiler.rb +6 -3
  20. data/lib/treetop/compiler/metagrammar.rb +301 -159
  21. data/lib/treetop/compiler/metagrammar.treetop +96 -13
  22. data/lib/treetop/compiler/node_classes/anything_symbol.rb +10 -2
  23. data/lib/treetop/compiler/node_classes/atomic_expression.rb +2 -2
  24. data/lib/treetop/compiler/node_classes/character_class.rb +10 -2
  25. data/lib/treetop/compiler/node_classes/choice.rb +11 -7
  26. data/lib/treetop/compiler/node_classes/nonterminal.rb +6 -2
  27. data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +5 -1
  28. data/lib/treetop/compiler/node_classes/parsing_expression.rb +10 -1
  29. data/lib/treetop/compiler/node_classes/parsing_rule.rb +1 -1
  30. data/lib/treetop/compiler/node_classes/predicate.rb +8 -1
  31. data/lib/treetop/compiler/node_classes/predicate_block.rb +7 -0
  32. data/lib/treetop/compiler/node_classes/repetition.rb +28 -8
  33. data/lib/treetop/compiler/node_classes/sequence.rb +5 -1
  34. data/lib/treetop/compiler/node_classes/terminal.rb +36 -22
  35. data/lib/treetop/compiler/ruby_builder.rb +2 -2
  36. data/lib/treetop/ruby_extensions/string.rb +0 -6
  37. data/lib/treetop/runtime/compiled_parser.rb +33 -14
  38. data/lib/treetop/runtime/syntax_node.rb +24 -15
  39. data/lib/treetop/runtime/terminal_parse_failure.rb +4 -3
  40. data/lib/treetop/runtime/terminal_syntax_node.rb +4 -4
  41. data/lib/treetop/version.rb +2 -2
  42. data/treetop.gemspec +25 -165
  43. metadata +43 -98
  44. data/doc/site.rb +0 -112
  45. data/doc/sitegen.rb +0 -65
  46. data/examples/lambda_calculus/lambda_calculus +0 -0
  47. data/spec/compiler/and_predicate_spec.rb +0 -36
  48. data/spec/compiler/anything_symbol_spec.rb +0 -44
  49. data/spec/compiler/character_class_spec.rb +0 -301
  50. data/spec/compiler/choice_spec.rb +0 -80
  51. data/spec/compiler/circular_compilation_spec.rb +0 -30
  52. data/spec/compiler/failure_propagation_functional_spec.rb +0 -21
  53. data/spec/compiler/grammar_compiler_spec.rb +0 -113
  54. data/spec/compiler/grammar_spec.rb +0 -41
  55. data/spec/compiler/multibyte_chars_spec.rb +0 -38
  56. data/spec/compiler/namespace_spec.rb +0 -42
  57. data/spec/compiler/nonterminal_symbol_spec.rb +0 -40
  58. data/spec/compiler/not_predicate_spec.rb +0 -38
  59. data/spec/compiler/occurrence_range_spec.rb +0 -189
  60. data/spec/compiler/one_or_more_spec.rb +0 -35
  61. data/spec/compiler/optional_spec.rb +0 -37
  62. data/spec/compiler/parenthesized_expression_spec.rb +0 -19
  63. data/spec/compiler/parsing_rule_spec.rb +0 -61
  64. data/spec/compiler/repeated_subrule_spec.rb +0 -29
  65. data/spec/compiler/semantic_predicate_spec.rb +0 -175
  66. data/spec/compiler/sequence_spec.rb +0 -129
  67. data/spec/compiler/terminal_spec.rb +0 -170
  68. data/spec/compiler/terminal_symbol_spec.rb +0 -37
  69. data/spec/compiler/test_grammar.treetop +0 -7
  70. data/spec/compiler/test_grammar.tt +0 -7
  71. data/spec/compiler/test_grammar_do.treetop +0 -7
  72. data/spec/compiler/test_grammar_magic_coding.treetop +0 -8
  73. data/spec/compiler/test_grammar_magic_encoding.treetop +0 -8
  74. data/spec/compiler/tt_compiler_spec.rb +0 -224
  75. data/spec/compiler/zero_or_more_spec.rb +0 -56
  76. data/spec/composition/a.treetop +0 -11
  77. data/spec/composition/b.treetop +0 -11
  78. data/spec/composition/c.treetop +0 -10
  79. data/spec/composition/d.treetop +0 -10
  80. data/spec/composition/f.treetop +0 -17
  81. data/spec/composition/grammar_composition_spec.rb +0 -40
  82. data/spec/composition/subfolder/e_includes_c.treetop +0 -15
  83. data/spec/ruby_extensions/string_spec.rb +0 -32
  84. data/spec/runtime/compiled_parser_spec.rb +0 -123
  85. data/spec/runtime/interval_skip_list/delete_spec.rb +0 -147
  86. data/spec/runtime/interval_skip_list/expire_range_spec.rb +0 -349
  87. data/spec/runtime/interval_skip_list/insert_and_delete_node_spec.rb +0 -385
  88. data/spec/runtime/interval_skip_list/insert_spec.rb +0 -660
  89. data/spec/runtime/interval_skip_list/interval_skip_list_spec.graffle +0 -6175
  90. data/spec/runtime/interval_skip_list/interval_skip_list_spec.rb +0 -58
  91. data/spec/runtime/interval_skip_list/palindromic_fixture.rb +0 -35
  92. data/spec/runtime/interval_skip_list/palindromic_fixture_spec.rb +0 -163
  93. data/spec/runtime/interval_skip_list/spec_helper.rb +0 -91
  94. data/spec/runtime/syntax_node_spec.rb +0 -77
  95. data/spec/spec_helper.rb +0 -115
@@ -1,129 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module SequenceSpec
4
- class Foo < Treetop::Runtime::SyntaxNode
5
- end
6
-
7
- describe "a sequence of labeled terminal symbols followed by a node class declaration and a block" do
8
- testing_expression 'foo:"foo" bar:"bar" baz:"baz" <SequenceSpec::Foo> { def a_method; end }'
9
-
10
- it "upon successfully matching input, instantiates an instance of the declared node class with element accessor methods and the method from the inline module" do
11
- parse('foobarbaz') do |result|
12
- result.should_not be_nil
13
- result.should be_an_instance_of(Foo)
14
- result.should respond_to(:a_method)
15
- result.foo.text_value.should == 'foo'
16
- result.bar.text_value.should == 'bar'
17
- result.baz.text_value.should == 'baz'
18
- end
19
- end
20
-
21
- it "successfully matches at a non-zero index" do
22
- parse('---foobarbaz', :index => 3) do |result|
23
- result.should_not be_nil
24
- result.should be_nonterminal
25
- (result.elements.map {|elt| elt.text_value}).join.should == 'foobarbaz'
26
- end
27
- end
28
-
29
- it "fails to match non-matching input, recording the parse failure of first non-matching terminal" do
30
- parse('---foobazbaz', :index => 3) do |result|
31
- result.should be_nil
32
- parser.index.should == 3
33
- terminal_failures = parser.terminal_failures
34
- terminal_failures.size.should == 1
35
- failure = terminal_failures.first
36
- failure.index.should == 6
37
- failure.expected_string.should == 'bar'
38
- end
39
- end
40
- end
41
-
42
- module ModFoo
43
- def mod_method; end
44
- end
45
-
46
- describe "a sequence of labeled terminal symbols followed by a node module declaration and a block" do
47
- testing_expression 'foo:"foo" bar:"bar" baz:"baz" <SequenceSpec::ModFoo> { def a_method; end }'
48
-
49
- it "upon successfully matching input, instantiates a syntax node and extends it with the declared module, element accessor methods, and the method from the inline module" do
50
- parse('foobarbaz') do |result|
51
- result.should_not be_nil
52
- result.should respond_to(:mod_method)
53
- result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
54
- result.should be_a_kind_of(ModFoo)
55
- result.should respond_to(:a_method)
56
- result.foo.text_value.should == 'foo'
57
- result.bar.text_value.should == 'bar'
58
- result.baz.text_value.should == 'baz'
59
- end
60
- end
61
- end
62
-
63
- describe "a labeled single element sequence followed by a node module declaration and a block" do
64
- testing_expression 'foo:"foo"+ <SequenceSpec::ModFoo> { def a_method; end }'
65
- it "upon successfully matching input, instantiates a syntax node and extends it with the declared module, element accessor methods, and the method from the inline module" do
66
- parse('foofoofoo') do |result|
67
- result.should_not be_nil
68
- result.should respond_to(:mod_method)
69
- result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
70
- result.should be_a_kind_of(ModFoo)
71
- result.should respond_to(:a_method)
72
- result.foo.text_value.should == 'foofoofoo'
73
- end
74
- end
75
- end
76
-
77
- describe "a sequence of non-terminals" do
78
- testing_grammar %{
79
- grammar TestGrammar
80
- rule sequence
81
- foo bar baz {
82
- def baz
83
- 'override' + super.text_value
84
- end
85
- }
86
- end
87
-
88
- rule foo 'foo' end
89
- rule bar 'bar' end
90
- rule baz 'baz' end
91
- end
92
- }
93
-
94
- it "defines accessors for non-terminals automatically that can be overridden in the inline block" do
95
- parse('foobarbaz') do |result|
96
- result.foo.text_value.should == 'foo'
97
- result.bar.text_value.should == 'bar'
98
- result.baz.should == 'overridebaz'
99
- end
100
- end
101
- end
102
-
103
- describe "Compiling a sequence containing various white-space errors" do
104
- it "should succeed on a valid sequence" do
105
- compiling_expression('foo:"foo" "bar" <SequenceSpec::Foo> { def a_method; end }').should_not raise_error
106
- end
107
-
108
- it "rejects space after a label" do
109
- compiling_expression('foo :"foo" "bar"').should raise_error(RuntimeError)
110
- end
111
-
112
- it "rejects space after label's colon" do
113
- compiling_expression('foo: "foo" "bar"').should raise_error(RuntimeError)
114
- end
115
-
116
- it "rejects missing space after a primary" do
117
- compiling_expression('foo:"foo""bar"').should raise_error(RuntimeError)
118
- end
119
-
120
- it "rejects missing space before node class declaration" do
121
- compiling_expression('foo:"foo" "bar"<SequenceSpec::Foo>').should raise_error(RuntimeError)
122
- end
123
-
124
- it "rejects missing space before inline module" do
125
- compiling_expression('foo:"foo" "bar" <SequenceSpec::Foo>{def a_method; end}').should raise_error(RuntimeError)
126
- end
127
- end
128
-
129
- end
@@ -1,170 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module TerminalSymbolSpec
4
- class Foo < Treetop::Runtime::SyntaxNode
5
- end
6
-
7
- describe "a terminal symbol" do
8
- testing_expression "'Foo'"
9
-
10
- it "matches the input string" do
11
- parse "Foo", :index => 0 do |result|
12
- result.should_not be_nil
13
- result.interval.should == (0...3)
14
- result.text_value.should == 'Foo'
15
- end
16
- end
17
-
18
- it "fails to match the input string other than at the start" do
19
- parse " Foo", :index => 0 do |result|
20
- result.should be_nil
21
- end
22
- end
23
-
24
- it "fails to match the input string in the wrong case" do
25
- parse "foo", :index => 0 do |result|
26
- result.should be_nil
27
- end
28
- end
29
- end
30
-
31
- describe "a terminal symbol with case-insensitive matching" do
32
- testing_expression "'Foo'i"
33
-
34
- it "matches the input string in the same case" do
35
- parse "Foo", :index => 0 do |result|
36
- result.should_not be_nil
37
- result.interval.should == (0...3)
38
- result.text_value.should == 'Foo'
39
- end
40
- end
41
-
42
- it "matches the input string in varied case" do
43
- parse "foO", :index => 0 do |result|
44
- result.should_not be_nil
45
- result.interval.should == (0...3)
46
- result.text_value.should == 'foO'
47
- end
48
- end
49
- end
50
-
51
- describe "a terminal symbol followed by a node class declaration and a block" do
52
- testing_expression "'foo' <TerminalSymbolSpec::Foo> { def a_method; end }"
53
-
54
- it "correctly parses matching input prefixes at various indices, returning an instance of the declared class that can respond to methods defined in the inline module" do
55
- parse "foo", :index => 0 do |result|
56
- result.should be_an_instance_of(Foo)
57
- result.should respond_to(:a_method)
58
- result.interval.should == (0...3)
59
- result.text_value.should == 'foo'
60
- end
61
-
62
- parse "xfoo", :index => 1 do |result|
63
- result.should be_an_instance_of(Foo)
64
- result.should respond_to(:a_method)
65
- result.interval.should == (1...4)
66
- result.text_value.should == 'foo'
67
- end
68
-
69
- parse "---foo", :index => 3 do |result|
70
- result.should be_an_instance_of(Foo)
71
- result.should respond_to(:a_method)
72
- result.interval.should == (3...6)
73
- result.text_value.should == 'foo'
74
- end
75
- end
76
-
77
- it "fails to parse nonmatching input at the index even if a match occurs later" do
78
- parse(" foo", :index => 0).should be_nil
79
- end
80
- end
81
-
82
- module ModFoo
83
- end
84
-
85
- describe "a terminal symbol followed by a node class declaration and a block" do
86
- testing_expression "'foo' <TerminalSymbolSpec::ModFoo> { def a_method; end }"
87
-
88
- it "correctly parses matching input prefixes at various indices, returning an instance of SyntaxNode extended with the declared module that can respond to methods defined in the inline module" do
89
- parse "foo", :index => 0 do |result|
90
- result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
91
- result.should be_a_kind_of(ModFoo)
92
- result.should respond_to(:a_method)
93
- result.interval.should == (0...3)
94
- result.text_value.should == 'foo'
95
- end
96
-
97
- parse "xfoo", :index => 1 do |result|
98
- result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
99
- result.should be_a_kind_of(ModFoo)
100
- result.should respond_to(:a_method)
101
- result.interval.should == (1...4)
102
- result.text_value.should == 'foo'
103
- end
104
-
105
- parse "---foo", :index => 3 do |result|
106
- result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
107
- result.should be_a_kind_of(ModFoo)
108
- result.should respond_to(:a_method)
109
- result.interval.should == (3...6)
110
- result.text_value.should == 'foo'
111
- end
112
- end
113
- end
114
-
115
- describe "a terminal regexp" do
116
- testing_expression "'Fo+'r"
117
-
118
- it "matches the input string" do
119
- parse "Fooo", :index => 0 do |result|
120
- result.should_not be_nil
121
- result.interval.should == (0...4)
122
- result.text_value.should == 'Fooo'
123
- end
124
- end
125
-
126
- it "fails to match the input string other than at the start" do
127
- parse " Foo", :index => 0 do |result|
128
- result.should be_nil
129
- end
130
- end
131
-
132
- it "fails to match the input string in the wrong case" do
133
- parse "foo", :index => 0 do |result|
134
- result.should be_nil
135
- end
136
- end
137
- end
138
-
139
- describe "a case-insensitive terminal regexp" do
140
- testing_expression "'Fo+'ri"
141
-
142
- it "matches the input string in the same case" do
143
- parse "Fooo", :index => 0 do |result|
144
- result.should_not be_nil
145
- result.interval.should == (0...4)
146
- result.text_value.should == 'Fooo'
147
- end
148
- end
149
-
150
- it "matches the input string in the same case" do
151
- parse "foOo", :index => 0 do |result|
152
- result.should_not be_nil
153
- result.interval.should == (0...4)
154
- result.text_value.should == 'foOo'
155
- end
156
- end
157
- end
158
-
159
- # Transient symbols were part of some idea of Nathan's that I no longer recall
160
- # describe "a transient terminal symbol" do
161
- # testing_expression "~'foo'"
162
- #
163
- # it "returns true upon parsing matching input prefixes at various indices" do
164
- # pending "transient terminal expressions"
165
- # parse("foo", :index => 0).should be_true
166
- # parse("-foo", :index => 1).should be_true
167
- # parse("---foo", :index => 3).should be_true
168
- # end
169
- # end
170
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module TerminalSymbolSpec
4
- class Foo < Treetop::Runtime::SyntaxNode
5
- end
6
-
7
- describe "a terminal symbol followed by a node class declaration and a block" do
8
- testing_expression "'foo' <TerminalSymbolSpec::Foo> { def a_method; end }"
9
-
10
- it "correctly parses matching input prefixes at various indices, returning an instance of the declared class that can respond to methods defined in the inline module" do
11
- parse "foo", :index => 0 do |result|
12
- result.should be_an_instance_of(Foo)
13
- result.should respond_to(:a_method)
14
- result.interval.should == (0...3)
15
- result.text_value.should == 'foo'
16
- end
17
-
18
- parse "xfoo", :index => 1 do |result|
19
- result.should be_an_instance_of(Foo)
20
- result.should respond_to(:a_method)
21
- result.interval.should == (1...4)
22
- result.text_value.should == 'foo'
23
- end
24
-
25
- parse "---foo", :index => 3 do |result|
26
- result.should be_an_instance_of(Foo)
27
- result.should respond_to(:a_method)
28
- result.interval.should == (3...6)
29
- result.text_value.should == 'foo'
30
- end
31
- end
32
-
33
- it "fails to parse nonmatching input at the index even if a match occurs later" do
34
- parse(" foo", :index => 0).should be_nil
35
- end
36
- end
37
- end
@@ -1,7 +0,0 @@
1
- module Test
2
- grammar Grammar
3
- rule foo
4
- 'foo'
5
- end
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- module Test
2
- grammar Grammar
3
- rule foo
4
- 'foo'
5
- end
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- module Test
2
- grammar Grammar do
3
- rule foo do
4
- 'foo'
5
- end
6
- end
7
- end
@@ -1,8 +0,0 @@
1
- # coding: UTF-8
2
- module Test
3
- grammar Grammar do
4
- rule foo do
5
- 'foo'
6
- end
7
- end
8
- end
@@ -1,8 +0,0 @@
1
- # encoding: UTF-8
2
- module Test
3
- grammar Grammar do
4
- rule foo do
5
- 'foo'
6
- end
7
- end
8
- end
@@ -1,224 +0,0 @@
1
- require 'digest/sha1'
2
- require 'tmpdir'
3
-
4
- # ensure the Kernel.system and Kernel.open's always use the correct tt and
5
- # Treetop library versions, not a previously installed gem
6
- ENV['PATH'] = File.expand_path(File.dirname(__FILE__) + '../../../bin' +
7
- File::PATH_SEPARATOR + ENV['PATH'])
8
- $LOAD_PATH.unshift(File.expand_path('../../../../lib', __FILE__))
9
-
10
- describe "The 'tt' comand line compiler" do
11
- before(:each) do
12
- @tmpdir = Dir.tmpdir
13
- end
14
-
15
- context 'when processing a single grammar file' do
16
- before(:each) do
17
- # create a fresh but dumb grammar file for each example
18
- @test_base = "dumb-#{rand(1000)}"
19
- @test_path = "#{@tmpdir}/#{@test_base}"
20
- @test_grammar = "#{@test_path}.tt"
21
- @test_ruby = "#{@test_path}.rb"
22
- File.open(@test_grammar, 'w+') do |f|
23
- f.print("# Encoding: UTF-8\n")
24
- f.print("grammar Dumb\n")
25
- f.print("end\n")
26
- end unless File.exists?(@test_grammar)
27
- end
28
-
29
- after(:each) do
30
- # cleanup test grammar and parser output files
31
- File.delete(@test_grammar) if File.exists?(@test_grammar)
32
- File.delete(@test_ruby) if File.exists?(@test_ruby)
33
- end
34
-
35
- it 'can compile a grammar file' do
36
- # puts %q{emulate 'tt dumb.tt'}
37
- system("ruby -S tt #{@test_grammar}").should be_true
38
-
39
- File.exists?(@test_ruby).should be_true
40
- File.zero?(@test_ruby).should_not be_true
41
- end
42
-
43
- it 'can compile a relative pathed grammar file' do
44
- dir = File.basename(File.expand_path(File.dirname(@test_grammar)))
45
-
46
- # puts %q{emulate 'tt "../<current_dir>/dumb.tt"'}
47
- system("cd #{@tmpdir}/..; ruby -S tt \"./#{dir}/#{@test_base}.tt\"").should be_true
48
-
49
- File.exists?(@test_ruby).should be_true
50
- File.zero?(@test_ruby).should_not be_true
51
- end
52
-
53
- it 'can compile an absolute pathed grammar file' do
54
- # puts %q{emulate 'tt "/path/to/dumb.tt"'}
55
- system("ruby -S tt \"#{File.expand_path(@test_grammar)}\"").should be_true
56
-
57
- File.exists?(@test_ruby).should be_true
58
- File.zero?(@test_ruby).should_not be_true
59
- end
60
-
61
- it 'can compile without explicit file extensions' do
62
- # puts %q{emulate 'tt dumb'}
63
- system("ruby -S tt #{@test_path}").should be_true
64
-
65
- File.exists?(@test_ruby).should be_true
66
- File.zero?(@test_ruby).should_not be_true
67
- end
68
-
69
- it 'skips nonexistent grammar file without failing or creating bogus output' do
70
- # puts %q{emulate 'tt dumb.bad'}
71
- Kernel.open("|ruby -S tt #{@test_base}.bad") do |io|
72
- (io.read =~ /ERROR.*?not exist.*?continuing/).should_not be_nil
73
- end
74
-
75
- File.exists?("#{@test_base}.rb").should be_false
76
- end
77
-
78
- it 'can compile to a specified parser source file' do
79
- # puts %q{emulate 'tt -o my_dumb_test_parser.rb dumb'}
80
- pf = "#{@tmpdir}/my_dumb_test_parser.rb"
81
- begin
82
- system("ruby -S tt -o #{pf} #{@test_path}").should be_true
83
-
84
- File.exists?(pf).should be_true
85
- File.zero?(pf).should_not be_true
86
- ensure
87
- File.delete(pf) if File.exists?(pf)
88
- end
89
- end
90
-
91
- it 'by default, does not overwrite an existing file without an autogenerated header' do
92
- # puts %q{emulate 'tt -o must_save_parser.rb dumb'}
93
- pf = "#{@tmpdir}/must_save_parser.rb"
94
- begin
95
- system("ruby -S tt -o #{pf} #{@test_path}").should be_true
96
-
97
- File.exists?(pf).should be_true
98
- File.zero?(pf).should_not be_true
99
-
100
- # Check that the magic comment is preserved:
101
- written = File.open(pf, "r") { |f| s = f.read }
102
- written.should =~ /\A# Encoding: UTF-8/
103
-
104
- # Modify the file's auto-generated comment and make sure it doesn't get overwritten:
105
- written.sub!(/generated/, 'broken');
106
- File.open(pf, "w") { |f| f.write(written) }
107
- # File.open(pf, "r+") { |f| s = f.read; s.sub!(/generated/, 'broken'); f.rewind; f.write(s) }
108
- orig_file_hash = Digest::SHA1.hexdigest(File.read(pf))
109
-
110
- Kernel.open("|ruby -S tt -o #{pf} #{@test_path}") do |io|
111
- (io.read =~ /ERROR.*?already exists.*?skipping/).should_not be_nil
112
- end
113
-
114
- Digest::SHA1.hexdigest(File.read(pf)).should == orig_file_hash
115
- ensure
116
- File.delete(pf) if File.exists?(pf)
117
- end
118
- end
119
-
120
- it 'by default, overwrites a changed file with an intact autogenerated header' do
121
- # puts %q{emulate 'tt -o must_save_parser.rb dumb'}
122
- pf = "#{@tmpdir}/must_save_parser.rb"
123
- begin
124
- system("ruby -S tt -o #{pf} #{@test_path}").should be_true
125
-
126
- File.exists?(pf).should be_true
127
- File.zero?(pf).should_not be_true
128
- orig_file_hash = Digest::SHA1.hexdigest(File.read(pf))
129
-
130
- # Modify the file and make sure it gets reverted:
131
- File.open(pf, "r+") { |f| f.gets; f.write("#") }
132
-
133
- system("ruby -S tt -o #{pf} #{@test_path}").should be_true
134
- Digest::SHA1.hexdigest(File.read(pf)).should == orig_file_hash
135
- ensure
136
- File.delete(pf) if File.exists?(pf)
137
- end
138
- end
139
-
140
- it 'can be forced to overwrite existing file #{@test_path}' do
141
- pf = "#{@test_path}.rb"
142
- system("echo some junk >#{pf}").should be_true
143
-
144
- File.exists?(pf).should be_true
145
- File.zero?(pf).should_not be_true
146
- orig_file_hash = Digest::SHA1.hexdigest(File.read(pf))
147
-
148
- system("ruby -S tt -f #{@test_path}").should be_true
149
- Digest::SHA1.hexdigest(File.read(pf)).should_not == orig_file_hash
150
- end
151
-
152
- end
153
-
154
- context 'when processing multiple grammar files' do
155
-
156
- before(:each) do
157
- # provide fresh but dumb grammar files for each test
158
- @test_bases = []
159
- @test_grammars = []
160
-
161
- %w[dumb1 dumb2].each do |e|
162
- base = "#{@tmpdir}/#{e}-#{rand(1000)}"
163
- grammar_file = "#{base}.tt"
164
- @test_bases << base
165
- @test_grammars << grammar_file
166
-
167
- File.open(grammar_file, 'w+') do |f|
168
- f.print("grammar #{e.capitalize}\n")
169
- f.print("end\n")
170
- end unless File.exists?(grammar_file)
171
- end
172
- end
173
-
174
- after(:each) do
175
- # cleanup test grammar and output parser files
176
- @test_grammars.each { |f| File.delete(f) if File.exists?(f) }
177
- @test_bases.each { |f| File.delete("#{f}.rb") if File.exists?("#{f}.rb") }
178
- end
179
-
180
- it 'can compile them in one invocation' do
181
- # puts %q{emulate 'tt dumb1.tt dumb2.tt'}
182
- system("ruby -S tt #{@test_grammars.join(' ')}").should be_true
183
-
184
- @test_bases.each do |f|
185
- pf = "#{f}.rb"
186
- File.exists?(pf).should be_true
187
- File.zero?(pf).should_not be_true
188
- end
189
- end
190
-
191
- it 'can compile them without explicit file extenstions' do
192
- # puts %q{emulate 'tt dumb1 dumb2'}
193
- system("ruby -S tt #{@test_bases.join(' ')}").should be_true
194
-
195
- @test_bases.each do |f|
196
- pf = "#{f}.rb"
197
- File.exists?(pf).should be_true
198
- File.zero?(pf).should_not be_true
199
- end
200
- end
201
-
202
- it 'can skip nonexistent and invalid extension named grammar files' do
203
- # puts %q{emulate 'tt not_here bad_ext.ttg dumb1 dumb2'}
204
- system("ruby -S tt not_here bad_ext.ttg #{@test_bases.join(' ')} >/dev/null 2>&1").should be_true
205
-
206
- File.exists?('not_here.rb').should_not be_true
207
- File.exists?('bad_ext.rb').should_not be_true
208
-
209
- @test_bases.each do |f|
210
- pf = "#{f}.rb"
211
- File.exists?(pf).should be_true
212
- File.zero?(pf).should_not be_true
213
- end
214
- end
215
-
216
- it 'can not specify an output file' do
217
- # puts %q{emulate 'tt -o my_bogus_test_parser.rb dumb1 dumb2'}
218
- pf = 'my_bogus_test_parser.rb'
219
- system("ruby -S tt -o #{pf} #{@test_bases.join(' ')} >/dev/null 2>&1").should be_false
220
- File.exists?(pf).should be_false
221
- end
222
- end
223
-
224
- end
@@ -1,56 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module ZeroOrMoreSpec
4
- class Foo < Treetop::Runtime::SyntaxNode
5
- end
6
-
7
- describe "zero or more of a terminal symbol followed by a node class declaration and a block" do
8
- testing_expression '"foo"* <ZeroOrMoreSpec::Foo> { def a_method; end }'
9
-
10
- it "successfully parses epsilon, returning an instance declared node class and recording a terminal failure" do
11
- parse('') do |result|
12
- result.should_not be_nil
13
- result.should be_an_instance_of(Foo)
14
- result.should respond_to(:a_method)
15
-
16
- terminal_failures = parser.terminal_failures
17
- terminal_failures.size.should == 1
18
- failure = terminal_failures.first
19
- failure.index.should == 0
20
- failure.expected_string.should == 'foo'
21
- end
22
- end
23
-
24
- it "successfully parses two of that terminal in a row, returning an instance of the declared node class and recording a failure representing the third attempt " do
25
- parse("foofoo") do |result|
26
- result.should_not be_nil
27
- result.should be_an_instance_of(Foo)
28
-
29
- terminal_failures = parser.terminal_failures
30
- terminal_failures.size.should == 1
31
- failure = terminal_failures.first
32
- failure.index.should == 6
33
- failure.expected_string.should == 'foo'
34
- end
35
- end
36
- end
37
-
38
- describe "Zero or more of a sequence" do
39
- testing_expression '("foo" "bar")*'
40
-
41
- it "resets the index appropriately following partially matcing input" do
42
- parse('foobarfoo', :consume_all_input => false) do |result|
43
- result.should_not be_nil
44
- result.interval.should == (0...6)
45
- end
46
- end
47
- end
48
-
49
- describe "Zero or more of a choice" do
50
- testing_expression '("a" / "bb")*'
51
-
52
- it "successfully parses matching input" do
53
- parse('abba').should_not be_nil
54
- end
55
- end
56
- end
@@ -1,11 +0,0 @@
1
- module Test
2
- grammar A
3
- rule a
4
- 'a'
5
- end
6
-
7
- rule inherit
8
- 'super'
9
- end
10
- end
11
- end
@@ -1,11 +0,0 @@
1
- module Test
2
- grammar B
3
- rule b
4
- 'bb'
5
- end
6
-
7
- rule inherit
8
- super 'keyword'
9
- end
10
- end
11
- end