treetop 1.6.6 → 1.6.11
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.
- checksums.yaml +5 -5
- data/Gemfile +18 -0
- data/History.txt +18 -0
- data/README.md +2 -0
- data/Rakefile +10 -43
- data/Treetop.tmbundle/Preferences/Comments.tmPreferences +28 -0
- data/Treetop.tmbundle/Snippets/grammar ___ end.tmSnippet +20 -0
- data/Treetop.tmbundle/Snippets/rule ___ end.tmSnippet +18 -0
- data/Treetop.tmbundle/Support/nibs/SyntaxTreeViewer.nib/designable.nib +1524 -0
- data/Treetop.tmbundle/Support/nibs/SyntaxTreeViewer.nib/keyedobjects.nib +0 -0
- data/Treetop.tmbundle/Support/syntax_tree_viewer.rb +117 -0
- data/Treetop.tmbundle/Syntaxes/Treetop Grammar.tmLanguage +358 -0
- data/Treetop.tmbundle/info.plist +10 -0
- data/doc/pitfalls_and_advanced_techniques.markdown +6 -0
- data/doc/syntactic_recognition.markdown +2 -2
- data/lib/treetop/compiler/grammar_compiler.rb +6 -3
- data/lib/treetop/compiler/metagrammar.rb +97 -77
- data/lib/treetop/compiler/metagrammar.treetop +1 -1
- data/lib/treetop/compiler/ruby_builder.rb +2 -2
- data/lib/treetop/ruby_extensions/string.rb +0 -6
- data/lib/treetop/runtime/compiled_parser.rb +15 -2
- data/lib/treetop/version.rb +1 -1
- data/treetop.gemspec +25 -157
- metadata +15 -61
- data/doc/site.rb +0 -112
- data/doc/sitegen.rb +0 -65
- data/spec/compiler/and_predicate_spec.rb +0 -36
- data/spec/compiler/anything_symbol_spec.rb +0 -47
- data/spec/compiler/character_class_spec.rb +0 -304
- data/spec/compiler/choice_spec.rb +0 -89
- data/spec/compiler/circular_compilation_spec.rb +0 -30
- data/spec/compiler/failure_propagation_functional_spec.rb +0 -21
- data/spec/compiler/grammar_compiler_spec.rb +0 -113
- data/spec/compiler/grammar_spec.rb +0 -44
- data/spec/compiler/multibyte_chars_spec.rb +0 -38
- data/spec/compiler/namespace_spec.rb +0 -42
- data/spec/compiler/nonterminal_symbol_spec.rb +0 -40
- data/spec/compiler/not_predicate_spec.rb +0 -52
- data/spec/compiler/occurrence_range_spec.rb +0 -186
- data/spec/compiler/one_or_more_spec.rb +0 -35
- data/spec/compiler/optional_spec.rb +0 -37
- data/spec/compiler/parenthesized_expression_spec.rb +0 -34
- data/spec/compiler/parsing_rule_spec.rb +0 -61
- data/spec/compiler/repeated_subrule_spec.rb +0 -29
- data/spec/compiler/semantic_predicate_spec.rb +0 -176
- data/spec/compiler/sequence_spec.rb +0 -129
- data/spec/compiler/terminal_spec.rb +0 -177
- data/spec/compiler/terminal_symbol_spec.rb +0 -40
- data/spec/compiler/test_grammar.treetop +0 -7
- data/spec/compiler/test_grammar.tt +0 -7
- data/spec/compiler/test_grammar_do.treetop +0 -7
- data/spec/compiler/test_grammar_magic_coding.treetop +0 -8
- data/spec/compiler/test_grammar_magic_encoding.treetop +0 -8
- data/spec/compiler/tt_compiler_spec.rb +0 -224
- data/spec/compiler/zero_or_more_spec.rb +0 -58
- data/spec/composition/a.treetop +0 -11
- data/spec/composition/b.treetop +0 -11
- data/spec/composition/c.treetop +0 -10
- data/spec/composition/d.treetop +0 -10
- data/spec/composition/f.treetop +0 -17
- data/spec/composition/grammar_composition_spec.rb +0 -40
- data/spec/composition/subfolder/e_includes_c.treetop +0 -15
- data/spec/ruby_extensions/string_spec.rb +0 -32
- data/spec/runtime/compiled_parser_spec.rb +0 -153
- data/spec/runtime/syntax_node_spec.rb +0 -77
- data/spec/spec_helper.rb +0 -123
@@ -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,177 +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
|
-
parser.terminal_failures.size.should == 1
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
it "fails to match the input string in the wrong case" do
|
26
|
-
parse "foo", :index => 0 do |result|
|
27
|
-
result.should be_nil
|
28
|
-
parser.terminal_failures.size.should == 1
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
describe "a terminal symbol with case-insensitive matching" do
|
34
|
-
testing_expression "'Foo'i"
|
35
|
-
|
36
|
-
it "matches the input string in the same case" do
|
37
|
-
parse "Foo", :index => 0 do |result|
|
38
|
-
result.should_not be_nil
|
39
|
-
result.interval.should == (0...3)
|
40
|
-
result.text_value.should == 'Foo'
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
it "matches the input string in varied case" do
|
45
|
-
parse "foO", :index => 0 do |result|
|
46
|
-
result.should_not be_nil
|
47
|
-
result.interval.should == (0...3)
|
48
|
-
result.text_value.should == 'foO'
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe "a terminal symbol followed by a node class declaration and a block" do
|
54
|
-
testing_expression "'foo' <TerminalSymbolSpec::Foo> { def a_method; end }"
|
55
|
-
|
56
|
-
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
|
57
|
-
parse "foo", :index => 0 do |result|
|
58
|
-
result.should be_an_instance_of(Foo)
|
59
|
-
result.should respond_to(:a_method)
|
60
|
-
result.interval.should == (0...3)
|
61
|
-
result.text_value.should == 'foo'
|
62
|
-
end
|
63
|
-
|
64
|
-
parse "xfoo", :index => 1 do |result|
|
65
|
-
result.should be_an_instance_of(Foo)
|
66
|
-
result.should respond_to(:a_method)
|
67
|
-
result.interval.should == (1...4)
|
68
|
-
result.text_value.should == 'foo'
|
69
|
-
end
|
70
|
-
|
71
|
-
parse "---foo", :index => 3 do |result|
|
72
|
-
result.should be_an_instance_of(Foo)
|
73
|
-
result.should respond_to(:a_method)
|
74
|
-
result.interval.should == (3...6)
|
75
|
-
result.text_value.should == 'foo'
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
it "fails to parse nonmatching input at the index even if a match occurs later" do
|
80
|
-
parse(" foo", :index => 0) do |result|
|
81
|
-
result.should be_nil
|
82
|
-
parser.terminal_failures.size.should == 1
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
module ModFoo
|
88
|
-
end
|
89
|
-
|
90
|
-
describe "a terminal symbol followed by a node class declaration and a block" do
|
91
|
-
testing_expression "'foo' <TerminalSymbolSpec::ModFoo> { def a_method; end }"
|
92
|
-
|
93
|
-
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
|
94
|
-
parse "foo", :index => 0 do |result|
|
95
|
-
result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
|
96
|
-
result.should be_a_kind_of(ModFoo)
|
97
|
-
result.should respond_to(:a_method)
|
98
|
-
result.interval.should == (0...3)
|
99
|
-
result.text_value.should == 'foo'
|
100
|
-
end
|
101
|
-
|
102
|
-
parse "xfoo", :index => 1 do |result|
|
103
|
-
result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
|
104
|
-
result.should be_a_kind_of(ModFoo)
|
105
|
-
result.should respond_to(:a_method)
|
106
|
-
result.interval.should == (1...4)
|
107
|
-
result.text_value.should == 'foo'
|
108
|
-
end
|
109
|
-
|
110
|
-
parse "---foo", :index => 3 do |result|
|
111
|
-
result.should be_an_instance_of(Treetop::Runtime::SyntaxNode)
|
112
|
-
result.should be_a_kind_of(ModFoo)
|
113
|
-
result.should respond_to(:a_method)
|
114
|
-
result.interval.should == (3...6)
|
115
|
-
result.text_value.should == 'foo'
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
describe "a terminal regexp" do
|
121
|
-
testing_expression "'Fo+'r"
|
122
|
-
|
123
|
-
it "matches the input string" do
|
124
|
-
parse "Fooo", :index => 0 do |result|
|
125
|
-
result.should_not be_nil
|
126
|
-
result.interval.should == (0...4)
|
127
|
-
result.text_value.should == 'Fooo'
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
it "fails to match the input string other than at the start" do
|
132
|
-
parse " Foo", :index => 0 do |result|
|
133
|
-
result.should be_nil
|
134
|
-
parser.terminal_failures.size.should == 1
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
it "fails to match the input string in the wrong case" do
|
139
|
-
parse "foo", :index => 0 do |result|
|
140
|
-
result.should be_nil
|
141
|
-
parser.terminal_failures.size.should == 1
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
describe "a case-insensitive terminal regexp" do
|
147
|
-
testing_expression "'Fo+'ri"
|
148
|
-
|
149
|
-
it "matches the input string in the same case" do
|
150
|
-
parse "Fooo", :index => 0 do |result|
|
151
|
-
result.should_not be_nil
|
152
|
-
result.interval.should == (0...4)
|
153
|
-
result.text_value.should == 'Fooo'
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
it "matches the input string in the same case" do
|
158
|
-
parse "foOo", :index => 0 do |result|
|
159
|
-
result.should_not be_nil
|
160
|
-
result.interval.should == (0...4)
|
161
|
-
result.text_value.should == 'foOo'
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
# Transient symbols were part of some idea of Nathan's that I no longer recall
|
167
|
-
# describe "a transient terminal symbol" do
|
168
|
-
# testing_expression "~'foo'"
|
169
|
-
#
|
170
|
-
# it "returns true upon parsing matching input prefixes at various indices" do
|
171
|
-
# pending "transient terminal expressions"
|
172
|
-
# parse("foo", :index => 0).should be_truthy
|
173
|
-
# parse("-foo", :index => 1).should be_truthy
|
174
|
-
# parse("---foo", :index => 3).should be_truthy
|
175
|
-
# end
|
176
|
-
# end
|
177
|
-
end
|
@@ -1,40 +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) do |result|
|
35
|
-
result.should be_nil
|
36
|
-
parser.terminal_failures.size.should == 1
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
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_truthy
|
38
|
-
|
39
|
-
File.exists?(@test_ruby).should be_truthy
|
40
|
-
File.zero?(@test_ruby).should_not be_truthy
|
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_truthy
|
48
|
-
|
49
|
-
File.exists?(@test_ruby).should be_truthy
|
50
|
-
File.zero?(@test_ruby).should_not be_truthy
|
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_truthy
|
56
|
-
|
57
|
-
File.exists?(@test_ruby).should be_truthy
|
58
|
-
File.zero?(@test_ruby).should_not be_truthy
|
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_truthy
|
64
|
-
|
65
|
-
File.exists?(@test_ruby).should be_truthy
|
66
|
-
File.zero?(@test_ruby).should_not be_truthy
|
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_falsey
|
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_truthy
|
83
|
-
|
84
|
-
File.exists?(pf).should be_truthy
|
85
|
-
File.zero?(pf).should_not be_truthy
|
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_truthy
|
96
|
-
|
97
|
-
File.exists?(pf).should be_truthy
|
98
|
-
File.zero?(pf).should_not be_truthy
|
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_truthy
|
125
|
-
|
126
|
-
File.exists?(pf).should be_truthy
|
127
|
-
File.zero?(pf).should_not be_truthy
|
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_truthy
|
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_truthy
|
143
|
-
|
144
|
-
File.exists?(pf).should be_truthy
|
145
|
-
File.zero?(pf).should_not be_truthy
|
146
|
-
orig_file_hash = Digest::SHA1.hexdigest(File.read(pf))
|
147
|
-
|
148
|
-
system("ruby -S tt -f #{@test_path}").should be_truthy
|
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_truthy
|
183
|
-
|
184
|
-
@test_bases.each do |f|
|
185
|
-
pf = "#{f}.rb"
|
186
|
-
File.exists?(pf).should be_truthy
|
187
|
-
File.zero?(pf).should_not be_truthy
|
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_truthy
|
194
|
-
|
195
|
-
@test_bases.each do |f|
|
196
|
-
pf = "#{f}.rb"
|
197
|
-
File.exists?(pf).should be_truthy
|
198
|
-
File.zero?(pf).should_not be_truthy
|
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_truthy
|
205
|
-
|
206
|
-
File.exists?('not_here.rb').should_not be_truthy
|
207
|
-
File.exists?('bad_ext.rb').should_not be_truthy
|
208
|
-
|
209
|
-
@test_bases.each do |f|
|
210
|
-
pf = "#{f}.rb"
|
211
|
-
File.exists?(pf).should be_truthy
|
212
|
-
File.zero?(pf).should_not be_truthy
|
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_falsey
|
220
|
-
File.exists?(pf).should be_falsey
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
end
|