citrus 2.3.2 → 2.3.3
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/README +30 -10
- data/Rakefile +1 -1
- data/citrus.gemspec +1 -1
- data/doc/syntax.markdown +9 -9
- data/examples/calc.citrus +2 -3
- data/examples/calc.rb +79 -72
- data/examples/ipaddress.citrus +16 -0
- data/examples/ipaddress.rb +23 -0
- data/examples/ipv4address.citrus +26 -0
- data/examples/ipv4address.rb +49 -0
- data/examples/{ip.citrus → ipv6address.citrus} +1 -40
- data/examples/ipv6address.rb +55 -0
- data/lib/citrus.rb +267 -157
- data/lib/citrus/file.rb +58 -64
- data/lib/citrus/version.rb +9 -0
- data/test/alias_test.rb +1 -1
- data/test/file_test.rb +101 -139
- data/test/helper.rb +0 -116
- data/test/match_test.rb +0 -1
- data/test/memoized_input_test.rb +1 -1
- data/test/multibyte_test.rb +57 -6
- data/test/parse_error_test.rb +4 -2
- metadata +112 -108
- data/examples/ip.rb +0 -77
- data/test/calc_file_test.rb +0 -16
- data/test/calc_test.rb +0 -11
data/lib/citrus/file.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require 'citrus'
|
2
4
|
|
3
5
|
module Citrus
|
@@ -9,7 +11,7 @@ module Citrus
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def module_namespace
|
12
|
-
module_segments[0
|
14
|
+
module_segments[0...-1].inject(Object) do |namespace, constant|
|
13
15
|
constant.empty? ? namespace : namespace.const_get(constant)
|
14
16
|
end
|
15
17
|
end
|
@@ -28,88 +30,71 @@ module Citrus
|
|
28
30
|
|
29
31
|
rule :file do
|
30
32
|
all(:space, zero_or_more(any(:require, :grammar))) {
|
31
|
-
|
32
|
-
|
33
|
+
captures[:require].each do |req|
|
34
|
+
file = req.value
|
35
|
+
begin
|
36
|
+
require file
|
37
|
+
rescue ::LoadError => e
|
38
|
+
begin
|
39
|
+
Citrus.require(file)
|
40
|
+
rescue LoadError
|
41
|
+
# Re-raise the original LoadError.
|
42
|
+
raise e
|
43
|
+
end
|
44
|
+
end
|
33
45
|
end
|
34
46
|
|
35
|
-
|
47
|
+
captures[:grammar].map {|g| g.value }
|
36
48
|
}
|
37
49
|
end
|
38
50
|
|
39
51
|
rule :grammar do
|
40
|
-
mod all(:grammar_keyword, :module_name, :
|
52
|
+
mod all(:grammar_keyword, :module_name, zero_or_more(any(:include, :root, :rule)), :end_keyword) do
|
41
53
|
include ModuleNameHelpers
|
42
54
|
|
43
55
|
def value
|
44
|
-
module_namespace.const_set(module_basename,
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
rule :grammar_body do
|
50
|
-
zero_or_more(any(:include, :root, :rule)) {
|
51
|
-
grammar = Grammar.new
|
56
|
+
grammar = module_namespace.const_set(module_basename, Grammar.new)
|
52
57
|
|
53
|
-
if captures[:include]
|
54
58
|
captures[:include].each {|inc| grammar.include(inc.value) }
|
55
|
-
|
59
|
+
captures[:rule].each {|r| grammar.rule(r.rule_name.value, r.value) }
|
56
60
|
|
57
|
-
|
61
|
+
grammar.root(root.value) if root
|
58
62
|
|
59
|
-
|
60
|
-
captures[:rule].each {|r| grammar.rule(r.rule_name.value, r.value) }
|
63
|
+
grammar
|
61
64
|
end
|
62
|
-
|
63
|
-
grammar
|
64
|
-
}
|
65
|
+
end
|
65
66
|
end
|
66
67
|
|
67
68
|
rule :rule do
|
68
|
-
all(:rule_keyword, :rule_name, :
|
69
|
-
rule_body.value
|
70
|
-
}
|
71
|
-
end
|
72
|
-
|
73
|
-
rule :rule_body do
|
74
|
-
zero_or_one(:choice) {
|
69
|
+
all(:rule_keyword, :rule_name, zero_or_one(:expression), :end_keyword) {
|
75
70
|
# An empty rule definition matches the empty string.
|
76
|
-
|
71
|
+
expression ? expression.value : Rule.for('')
|
77
72
|
}
|
78
73
|
end
|
79
74
|
|
80
|
-
rule :
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
def value
|
87
|
-
rules.length > 1 ? Choice.new(rules) : rules.first
|
88
|
-
end
|
89
|
-
end
|
75
|
+
rule :expression do
|
76
|
+
all(:sequence, zero_or_more([ :bar, :sequence ])) {
|
77
|
+
rules = captures[:sequence].map {|s| s.value }
|
78
|
+
rules.length > 1 ? Choice.new(rules) : rules.first
|
79
|
+
}
|
90
80
|
end
|
91
81
|
|
92
82
|
rule :sequence do
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
def value
|
99
|
-
rules.length > 1 ? Sequence.new(rules) : rules.first
|
100
|
-
end
|
101
|
-
end
|
83
|
+
one_or_more(:labelled) {
|
84
|
+
rules = captures[:labelled].map {|l| l.value }
|
85
|
+
rules.length > 1 ? Sequence.new(rules) : rules.first
|
86
|
+
}
|
102
87
|
end
|
103
88
|
|
104
|
-
rule :
|
105
|
-
all(zero_or_one(:label), :
|
106
|
-
rule =
|
89
|
+
rule :labelled do
|
90
|
+
all(zero_or_one(:label), :extended) {
|
91
|
+
rule = extended.value
|
107
92
|
rule.label = label.value if label
|
108
93
|
rule
|
109
94
|
}
|
110
95
|
end
|
111
96
|
|
112
|
-
rule :
|
97
|
+
rule :extended do
|
113
98
|
all(:prefix, zero_or_one(:extension)) {
|
114
99
|
rule = prefix.value
|
115
100
|
rule.extension = extension.value if extension
|
@@ -138,8 +123,8 @@ module Citrus
|
|
138
123
|
end
|
139
124
|
|
140
125
|
rule :grouping do
|
141
|
-
all(:lparen, :
|
142
|
-
|
126
|
+
all(:lparen, :expression, :rparen) {
|
127
|
+
expression.value
|
143
128
|
}
|
144
129
|
end
|
145
130
|
|
@@ -192,12 +177,14 @@ module Citrus
|
|
192
177
|
end
|
193
178
|
|
194
179
|
rule :terminal do
|
195
|
-
any(:
|
196
|
-
|
180
|
+
any(:quoted_string, :case_insensitive_string, :regular_expression, :character_class, :dot) {
|
181
|
+
primitive = super()
|
197
182
|
|
198
|
-
|
199
|
-
|
200
|
-
|
183
|
+
if String === primitive
|
184
|
+
StringTerminal.new(primitive, flags)
|
185
|
+
else
|
186
|
+
Terminal.new(primitive)
|
187
|
+
end
|
201
188
|
}
|
202
189
|
end
|
203
190
|
|
@@ -227,19 +214,19 @@ module Citrus
|
|
227
214
|
|
228
215
|
rule :regular_expression do
|
229
216
|
all(/\/(?:\\?.)*?\/[imxouesn]*/, :space) {
|
230
|
-
|
217
|
+
eval(first.to_s)
|
231
218
|
}
|
232
219
|
end
|
233
220
|
|
234
221
|
rule :character_class do
|
235
222
|
all(/\[(?:\\?.)*?\]/, :space) {
|
236
|
-
|
223
|
+
eval("/#{first.to_s}/")
|
237
224
|
}
|
238
225
|
end
|
239
226
|
|
240
227
|
rule :dot do
|
241
228
|
all('.', :space) {
|
242
|
-
|
229
|
+
DOT
|
243
230
|
}
|
244
231
|
end
|
245
232
|
|
@@ -317,8 +304,8 @@ module Citrus
|
|
317
304
|
|
318
305
|
rule :star do
|
319
306
|
all(/[0-9]*/, '*', /[0-9]*/, :space) { |rule|
|
320
|
-
min = captures[
|
321
|
-
max = captures[
|
307
|
+
min = captures[1] == '' ? 0 : captures[1].to_i
|
308
|
+
max = captures[3] == '' ? Infinity : captures[3].to_i
|
322
309
|
Repeat.new(rule, min, max)
|
323
310
|
}
|
324
311
|
end
|
@@ -348,4 +335,11 @@ module Citrus
|
|
348
335
|
rule :comment, /#.*/
|
349
336
|
rule :space, zero_or_more(any(:white, :comment))
|
350
337
|
end
|
338
|
+
|
339
|
+
def File.parse(*args) # :nodoc:
|
340
|
+
super
|
341
|
+
rescue ParseError => e
|
342
|
+
# Raise SyntaxError when a parse fails.
|
343
|
+
raise SyntaxError, e
|
344
|
+
end
|
351
345
|
end
|
data/test/alias_test.rb
CHANGED
data/test/file_test.rb
CHANGED
@@ -21,194 +21,189 @@ class CitrusFileTest < Test::Unit::TestCase
|
|
21
21
|
|
22
22
|
## Hierarchical syntax
|
23
23
|
|
24
|
-
def
|
25
|
-
|
24
|
+
def test_expression_empty
|
25
|
+
assert_raise SyntaxError do
|
26
|
+
File.parse('', :root => :expression)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_expression_alias
|
31
|
+
match = File.parse('rule_name', :root => :expression)
|
26
32
|
assert(match)
|
27
33
|
assert_instance_of(Alias, match.value)
|
28
34
|
end
|
29
35
|
|
30
|
-
def
|
31
|
-
match = File.parse('.', :root => :
|
36
|
+
def test_expression_dot
|
37
|
+
match = File.parse('.', :root => :expression)
|
32
38
|
assert(match)
|
33
39
|
assert_instance_of(Terminal, match.value)
|
34
40
|
end
|
35
41
|
|
36
|
-
def
|
37
|
-
match = File.parse('[a-z]', :root => :
|
42
|
+
def test_expression_character_range
|
43
|
+
match = File.parse('[a-z]', :root => :expression)
|
38
44
|
assert(match)
|
39
45
|
assert_instance_of(Terminal, match.value)
|
40
46
|
end
|
41
47
|
|
42
|
-
def
|
43
|
-
match = File.parse('/./', :root => :
|
48
|
+
def test_expression_terminal
|
49
|
+
match = File.parse('/./', :root => :expression)
|
44
50
|
assert(match)
|
45
51
|
assert_instance_of(Terminal, match.value)
|
46
52
|
end
|
47
53
|
|
48
|
-
def
|
49
|
-
match = File.parse('""', :root => :
|
54
|
+
def test_expression_string_terminal_empty
|
55
|
+
match = File.parse('""', :root => :expression)
|
50
56
|
assert(match)
|
51
57
|
assert_instance_of(StringTerminal, match.value)
|
52
58
|
end
|
53
59
|
|
54
|
-
def
|
55
|
-
match = File.parse('"a"', :root => :
|
60
|
+
def test_expression_string_terminal
|
61
|
+
match = File.parse('"a"', :root => :expression)
|
56
62
|
assert(match)
|
57
63
|
assert_instance_of(StringTerminal, match.value)
|
58
64
|
end
|
59
65
|
|
60
|
-
def
|
61
|
-
match = File.parse('"" {}', :root => :
|
66
|
+
def test_expression_string_terminal_empty_block
|
67
|
+
match = File.parse('"" {}', :root => :expression)
|
62
68
|
assert(match)
|
63
69
|
assert_instance_of(StringTerminal, match.value)
|
64
70
|
end
|
65
71
|
|
66
|
-
def
|
67
|
-
match = File.parse('"a"*', :root => :
|
72
|
+
def test_expression_repeat_string_terminal
|
73
|
+
match = File.parse('"a"*', :root => :expression)
|
68
74
|
assert(match)
|
69
75
|
assert_instance_of(Repeat, match.value)
|
70
76
|
end
|
71
77
|
|
72
|
-
def
|
73
|
-
match = File.parse('""* {}', :root => :
|
78
|
+
def test_expression_repeat_empty_string_terminal_block
|
79
|
+
match = File.parse('""* {}', :root => :expression)
|
74
80
|
assert(match)
|
75
81
|
assert_instance_of(Repeat, match.value)
|
76
82
|
end
|
77
83
|
|
78
|
-
def
|
79
|
-
match = File.parse('("a" "b")*', :root => :
|
84
|
+
def test_expression_repeat_sequence
|
85
|
+
match = File.parse('("a" "b")*', :root => :expression)
|
80
86
|
assert(match)
|
81
87
|
assert_instance_of(Repeat, match.value)
|
82
88
|
end
|
83
89
|
|
84
|
-
def
|
85
|
-
match = File.parse('("a" | "b")*', :root => :
|
90
|
+
def test_expression_repeat_choice
|
91
|
+
match = File.parse('("a" | "b")*', :root => :expression)
|
86
92
|
assert(match)
|
87
93
|
assert_instance_of(Repeat, match.value)
|
88
94
|
end
|
89
95
|
|
90
|
-
def
|
91
|
-
match = File.parse('("a" "b")* {}', :root => :
|
96
|
+
def test_expression_repeat_sequence_block
|
97
|
+
match = File.parse('("a" "b")* {}', :root => :expression)
|
92
98
|
assert(match)
|
93
99
|
assert_instance_of(Repeat, match.value)
|
94
100
|
end
|
95
101
|
|
96
|
-
def
|
97
|
-
match = File.parse('("a" | "b")* {}', :root => :
|
102
|
+
def test_expression_repeat_choice_block
|
103
|
+
match = File.parse('("a" | "b")* {}', :root => :expression)
|
98
104
|
assert(match)
|
99
105
|
assert_instance_of(Repeat, match.value)
|
100
106
|
end
|
101
107
|
|
102
|
-
def
|
103
|
-
match = File.parse('("a" "b")* <Module>', :root => :
|
108
|
+
def test_expression_repeat_sequence_extension
|
109
|
+
match = File.parse('("a" "b")* <Module>', :root => :expression)
|
104
110
|
assert(match)
|
105
111
|
assert_instance_of(Repeat, match.value)
|
106
112
|
end
|
107
113
|
|
108
|
-
def
|
109
|
-
match = File.parse('( "a" "b" )* <Module>', :root => :
|
114
|
+
def test_expression_repeat_sequence_extension_spaced
|
115
|
+
match = File.parse('( "a" "b" )* <Module>', :root => :expression)
|
110
116
|
assert(match)
|
111
117
|
assert_instance_of(Repeat, match.value)
|
112
118
|
end
|
113
119
|
|
114
|
-
def
|
115
|
-
match = File.parse('("a" | "b")* <Module>', :root => :
|
120
|
+
def test_expression_repeat_choice_extension
|
121
|
+
match = File.parse('("a" | "b")* <Module>', :root => :expression)
|
116
122
|
assert(match)
|
117
123
|
assert_instance_of(Repeat, match.value)
|
118
124
|
end
|
119
125
|
|
120
|
-
def
|
121
|
-
match = File.parse('/./ | /./', :root => :
|
126
|
+
def test_expression_choice_terminal
|
127
|
+
match = File.parse('/./ | /./', :root => :expression)
|
128
|
+
assert(match)
|
129
|
+
assert_instance_of(Choice, match.value)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_expression_choice_string_terminal
|
133
|
+
match = File.parse('"a" | "b"', :root => :expression)
|
122
134
|
assert(match)
|
123
135
|
assert_instance_of(Choice, match.value)
|
124
136
|
end
|
125
137
|
|
126
|
-
def
|
127
|
-
match = File.parse('"a" | "b"', :root => :
|
138
|
+
def test_expression_choice_embedded_sequence
|
139
|
+
match = File.parse('"a" | ("b" "c")', :root => :expression)
|
128
140
|
assert(match)
|
129
141
|
assert_instance_of(Choice, match.value)
|
130
142
|
end
|
131
143
|
|
132
|
-
def
|
133
|
-
match = File.parse('("a" | /./)', :root => :
|
144
|
+
def test_expression_choice_mixed
|
145
|
+
match = File.parse('("a" | /./)', :root => :expression)
|
134
146
|
assert(match)
|
135
147
|
assert_instance_of(Choice, match.value)
|
136
148
|
end
|
137
149
|
|
138
|
-
def
|
139
|
-
match = File.parse('("a" | "b") <Module>', :root => :
|
150
|
+
def test_expression_choice_extended
|
151
|
+
match = File.parse('("a" | "b") <Module>', :root => :expression)
|
140
152
|
assert(match)
|
141
153
|
assert_instance_of(Choice, match.value)
|
142
154
|
end
|
143
155
|
|
144
|
-
def
|
145
|
-
match = File.parse('/./ /./', :root => :
|
156
|
+
def test_expression_sequence_terminal
|
157
|
+
match = File.parse('/./ /./', :root => :expression)
|
146
158
|
assert(match)
|
147
159
|
assert_instance_of(Sequence, match.value)
|
148
160
|
end
|
149
161
|
|
150
|
-
def
|
151
|
-
match = File.parse('"a" "b"', :root => :
|
162
|
+
def test_expression_sequence_string_terminal
|
163
|
+
match = File.parse('"a" "b"', :root => :expression)
|
152
164
|
assert(match)
|
153
165
|
assert_instance_of(Sequence, match.value)
|
154
166
|
end
|
155
167
|
|
156
|
-
def
|
157
|
-
match = File.parse('( "a" "b" ) <Module>', :root => :
|
168
|
+
def test_expression_sequence_extension
|
169
|
+
match = File.parse('( "a" "b" ) <Module>', :root => :expression)
|
158
170
|
assert(match)
|
159
171
|
assert_instance_of(Sequence, match.value)
|
160
172
|
end
|
161
173
|
|
162
|
-
def
|
163
|
-
match = File.parse('"a" ("b" | /./)* <Module>', :root => :
|
174
|
+
def test_expression_sequence_mixed
|
175
|
+
match = File.parse('"a" ("b" | /./)* <Module>', :root => :expression)
|
164
176
|
assert(match)
|
165
177
|
assert_instance_of(Sequence, match.value)
|
166
178
|
end
|
167
179
|
|
168
|
-
def
|
169
|
-
match = File.parse('"a" ("b" | /./)* {}', :root => :
|
180
|
+
def test_expression_sequence_block
|
181
|
+
match = File.parse('"a" ("b" | /./)* {}', :root => :expression)
|
170
182
|
assert(match)
|
171
183
|
assert_instance_of(Sequence, match.value)
|
172
184
|
end
|
173
185
|
|
174
186
|
def test_precedence_sequence_before_choice
|
175
187
|
# Sequence should bind more tightly than Choice.
|
176
|
-
match = File.parse('"a" "b" | "c"', :root => :
|
188
|
+
match = File.parse('"a" "b" | "c"', :root => :expression)
|
177
189
|
assert(match)
|
178
190
|
assert_instance_of(Choice, match.value)
|
179
191
|
end
|
180
192
|
|
181
193
|
def test_precedence_parentheses
|
182
194
|
# Parentheses should change binding precedence.
|
183
|
-
match = File.parse('"a" ("b" | "c")', :root => :
|
195
|
+
match = File.parse('"a" ("b" | "c")', :root => :expression)
|
184
196
|
assert(match)
|
185
197
|
assert_instance_of(Sequence, match.value)
|
186
198
|
end
|
187
199
|
|
188
200
|
def test_precedence_repeat_before_predicate
|
189
201
|
# Repeat should bind more tightly than AndPredicate.
|
190
|
-
match = File.parse("&'a'+", :root => :
|
202
|
+
match = File.parse("&'a'+", :root => :expression)
|
191
203
|
assert(match)
|
192
204
|
assert_instance_of(AndPredicate, match.value)
|
193
205
|
end
|
194
206
|
|
195
|
-
def test_rule_body_empty
|
196
|
-
match = File.parse('', :root => :rule_body)
|
197
|
-
assert(match)
|
198
|
-
end
|
199
|
-
|
200
|
-
def test_choice
|
201
|
-
match = File.parse('"a" | "b"', :root => :choice)
|
202
|
-
assert(match)
|
203
|
-
assert_instance_of(Choice, match.value)
|
204
|
-
end
|
205
|
-
|
206
|
-
def test_choice_embedded_sequence
|
207
|
-
match = File.parse('"a" | ("b" "c")', :root => :choice)
|
208
|
-
assert(match)
|
209
|
-
assert_instance_of(Choice, match.value)
|
210
|
-
end
|
211
|
-
|
212
207
|
def test_sequence
|
213
208
|
match = File.parse('"" ""', :root => :sequence)
|
214
209
|
assert(match)
|
@@ -221,34 +216,21 @@ class CitrusFileTest < Test::Unit::TestCase
|
|
221
216
|
assert_instance_of(Sequence, match.value)
|
222
217
|
end
|
223
218
|
|
224
|
-
def
|
225
|
-
match = File.parse('label:""', :root => :
|
219
|
+
def test_labelled
|
220
|
+
match = File.parse('label:""', :root => :labelled)
|
226
221
|
assert(match)
|
227
222
|
assert_instance_of(StringTerminal, match.value)
|
228
223
|
end
|
229
224
|
|
230
|
-
def
|
231
|
-
match = File.parse('
|
232
|
-
assert(match)
|
233
|
-
assert_instance_of(StringTerminal, match.value)
|
234
|
-
end
|
235
|
-
|
236
|
-
def test_expression_tag
|
237
|
-
match = File.parse('"" <Module>', :root => :expression)
|
225
|
+
def test_extended_tag
|
226
|
+
match = File.parse('"" <Module>', :root => :extended)
|
238
227
|
assert(match)
|
239
228
|
assert_kind_of(Rule, match.value)
|
240
229
|
assert_kind_of(Module, match.value.extension)
|
241
230
|
end
|
242
231
|
|
243
|
-
def
|
244
|
-
match = File.parse('"" {}', :root => :
|
245
|
-
assert(match)
|
246
|
-
assert_kind_of(Rule, match.value)
|
247
|
-
assert_kind_of(Module, match.value.extension)
|
248
|
-
end
|
249
|
-
|
250
|
-
def test_expression_block_space
|
251
|
-
match = File.parse('"" {} ', :root => :expression)
|
232
|
+
def test_extended_block
|
233
|
+
match = File.parse('"" {}', :root => :extended)
|
252
234
|
assert(match)
|
253
235
|
assert_kind_of(Rule, match.value)
|
254
236
|
assert_kind_of(Module, match.value.extension)
|
@@ -361,7 +343,7 @@ class CitrusFileTest < Test::Unit::TestCase
|
|
361
343
|
end
|
362
344
|
|
363
345
|
def test_root_invalid
|
364
|
-
assert_raise
|
346
|
+
assert_raise SyntaxError do
|
365
347
|
File.parse('root :a_root', :root => :root)
|
366
348
|
end
|
367
349
|
end
|
@@ -378,40 +360,40 @@ class CitrusFileTest < Test::Unit::TestCase
|
|
378
360
|
assert('some_rule', match.value)
|
379
361
|
end
|
380
362
|
|
381
|
-
def
|
382
|
-
match = File.parse('
|
363
|
+
def test_terminal_single_quoted_string
|
364
|
+
match = File.parse("'a'", :root => :terminal)
|
383
365
|
assert(match)
|
384
|
-
assert_instance_of(
|
366
|
+
assert_instance_of(StringTerminal, match.value)
|
385
367
|
end
|
386
368
|
|
387
|
-
def
|
388
|
-
match = File.parse('
|
369
|
+
def test_terminal_double_quoted_string
|
370
|
+
match = File.parse('"a"', :root => :terminal)
|
389
371
|
assert(match)
|
390
|
-
assert_instance_of(
|
372
|
+
assert_instance_of(StringTerminal, match.value)
|
391
373
|
end
|
392
374
|
|
393
|
-
def
|
394
|
-
match = File.parse('
|
375
|
+
def test_terminal_case_insensitive_string
|
376
|
+
match = File.parse('`a`', :root => :terminal)
|
395
377
|
assert(match)
|
396
|
-
assert_instance_of(
|
378
|
+
assert_instance_of(StringTerminal, match.value)
|
397
379
|
end
|
398
380
|
|
399
|
-
def
|
400
|
-
match = File.parse(
|
381
|
+
def test_terminal_regular_expression
|
382
|
+
match = File.parse('/./', :root => :terminal)
|
401
383
|
assert(match)
|
402
|
-
assert_instance_of(
|
384
|
+
assert_instance_of(Terminal, match.value)
|
403
385
|
end
|
404
386
|
|
405
|
-
def
|
406
|
-
match = File.parse('
|
387
|
+
def test_terminal_character_class
|
388
|
+
match = File.parse('[a-z]', :root => :terminal)
|
407
389
|
assert(match)
|
408
|
-
assert_instance_of(
|
390
|
+
assert_instance_of(Terminal, match.value)
|
409
391
|
end
|
410
392
|
|
411
|
-
def
|
412
|
-
match = File.parse('
|
393
|
+
def test_terminal_dot
|
394
|
+
match = File.parse('.', :root => :terminal)
|
413
395
|
assert(match)
|
414
|
-
assert_instance_of(
|
396
|
+
assert_instance_of(Terminal, match.value)
|
415
397
|
end
|
416
398
|
|
417
399
|
def test_single_quoted_string
|
@@ -483,81 +465,61 @@ class CitrusFileTest < Test::Unit::TestCase
|
|
483
465
|
def test_regular_expression
|
484
466
|
match = File.parse('/./', :root => :regular_expression)
|
485
467
|
assert(match)
|
486
|
-
|
487
|
-
assert_instance_of(Terminal, rule)
|
488
|
-
assert_equal(/./, rule.regexp)
|
468
|
+
assert_equal(/./, match.value)
|
489
469
|
end
|
490
470
|
|
491
471
|
def test_regular_expression_escaped_forward_slash
|
492
472
|
match = File.parse('/\\//', :root => :regular_expression)
|
493
473
|
assert(match)
|
494
|
-
|
495
|
-
assert_instance_of(Terminal, rule)
|
496
|
-
assert_equal(/\//, rule.regexp)
|
474
|
+
assert_equal(/\//, match.value)
|
497
475
|
end
|
498
476
|
|
499
477
|
def test_regular_expression_escaped_backslash
|
500
478
|
match = File.parse('/\\\\/', :root => :regular_expression)
|
501
479
|
assert(match)
|
502
|
-
|
503
|
-
assert_instance_of(Terminal, rule)
|
504
|
-
assert_equal(/\\/, rule.regexp)
|
480
|
+
assert_equal(/\\/, match.value)
|
505
481
|
end
|
506
482
|
|
507
483
|
def test_regular_expression_hex
|
508
484
|
match = File.parse('/\\x26/', :root => :regular_expression)
|
509
485
|
assert(match)
|
510
|
-
|
511
|
-
assert_instance_of(Terminal, rule)
|
512
|
-
assert_equal(/\x26/, rule.regexp)
|
486
|
+
assert_equal(/\x26/, match.value)
|
513
487
|
end
|
514
488
|
|
515
489
|
def test_regular_expression_with_flag
|
516
490
|
match = File.parse('/a/i', :root => :regular_expression)
|
517
491
|
assert(match)
|
518
|
-
|
519
|
-
assert_instance_of(Terminal, rule)
|
520
|
-
assert_equal(/a/i, rule.regexp)
|
492
|
+
assert_equal(/a/i, match.value)
|
521
493
|
end
|
522
494
|
|
523
495
|
def test_character_class
|
524
496
|
match = File.parse('[_]', :root => :character_class)
|
525
497
|
assert(match)
|
526
|
-
|
527
|
-
assert_instance_of(Terminal, rule)
|
528
|
-
assert_equal(/[_]/n, rule.regexp)
|
498
|
+
assert_equal(/[_]/n, match.value)
|
529
499
|
end
|
530
500
|
|
531
501
|
def test_character_class_a_z
|
532
502
|
match = File.parse('[a-z]', :root => :character_class)
|
533
503
|
assert(match)
|
534
|
-
|
535
|
-
assert_instance_of(Terminal, rule)
|
536
|
-
assert_equal(/[a-z]/n, rule.regexp)
|
504
|
+
assert_equal(/[a-z]/n, match.value)
|
537
505
|
end
|
538
506
|
|
539
507
|
def test_character_class_nested_square_brackets
|
540
508
|
match = File.parse('[\[-\]]', :root => :character_class)
|
541
509
|
assert(match)
|
542
|
-
|
543
|
-
assert_instance_of(Terminal, rule)
|
544
|
-
assert_equal(/[\[-\]]/n, rule.regexp)
|
510
|
+
assert_equal(/[\[-\]]/n, match.value)
|
545
511
|
end
|
546
512
|
|
547
513
|
def test_character_class_hex_range
|
548
514
|
match = File.parse('[\\x26-\\x29]', :root => :character_class)
|
549
515
|
assert(match)
|
550
|
-
|
551
|
-
assert_instance_of(Terminal, rule)
|
552
|
-
assert_equal(/[\x26-\x29]/, rule.regexp)
|
516
|
+
assert_equal(/[\x26-\x29]/, match.value)
|
553
517
|
end
|
554
518
|
|
555
519
|
def test_dot
|
556
520
|
match = File.parse('.', :root => :dot)
|
557
521
|
assert(match)
|
558
|
-
|
559
|
-
assert_instance_of(Terminal, rule)
|
560
|
-
assert_equal(DOT, rule.regexp)
|
522
|
+
assert_equal(DOT, match.value)
|
561
523
|
end
|
562
524
|
|
563
525
|
def test_label
|
@@ -847,7 +809,7 @@ class CitrusFileTest < Test::Unit::TestCase
|
|
847
809
|
end
|
848
810
|
|
849
811
|
def test_constant_invalid
|
850
|
-
assert_raise
|
812
|
+
assert_raise SyntaxError do
|
851
813
|
File.parse('math', :root => :constant)
|
852
814
|
end
|
853
815
|
end
|