citrus 2.3.2 → 2.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|