lunokhod 0.0.1.pre

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.
@@ -0,0 +1,44 @@
1
+ require 'lunokhod/verifier'
2
+ require 'stringio'
3
+
4
+ module Lunokhod
5
+ class ErrorReport
6
+ attr_reader :errors
7
+ attr_reader :surveys
8
+
9
+ def initialize(surveys)
10
+ @errors = []
11
+ @surveys = surveys
12
+ end
13
+
14
+ def errors?
15
+ !errors.empty?
16
+ end
17
+
18
+ def run
19
+ surveys.each do |s|
20
+ v = Verifier.new(s)
21
+ v.run { |error| errors << error }
22
+ end
23
+ end
24
+
25
+ def to_s
26
+ io = StringIO.new("")
27
+
28
+ errors.each do |e|
29
+ source = e.survey.source
30
+
31
+ if e.bad_tag?
32
+ io.puts "#{source}:#{e.at_fault.line}: #{e.node_type} #{e.key} is not defined"
33
+ elsif e.duplicate_question?
34
+ io.puts "#{source}: question tag #{e.key} is used multiple times"
35
+ e.at_fault.each do |n|
36
+ io.puts " at #{file}:#{n.line}"
37
+ end
38
+ end
39
+ end
40
+
41
+ io.string
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,208 @@
1
+ require 'lunokhod/ast'
2
+ require 'case'
3
+
4
+ module Lunokhod
5
+ class Parser < BasicObject
6
+ attr_reader :data
7
+ attr_reader :source
8
+ attr_reader :surveys
9
+
10
+ def initialize(data, source = '(input)')
11
+ @data = data
12
+ @source = source
13
+ @surveys = []
14
+ end
15
+
16
+ def parse
17
+ instance_eval(data, source)
18
+ end
19
+
20
+ def survey(name, options = {}, &block)
21
+ survey = Ast::Survey.new(sline, name, options)
22
+ survey.source = source
23
+ @surveys << survey
24
+
25
+ _with_unwind do
26
+ @current_node = survey
27
+ instance_eval(&block)
28
+ end
29
+ end
30
+
31
+ def translations(spec)
32
+ spec.each do |lang, path|
33
+ translation = Ast::Translation.new(sline, lang, path)
34
+ translation.parent = @current_node
35
+ @current_node.translations << translation
36
+ end
37
+ end
38
+
39
+ def dependency(options = {})
40
+ rule = options[:rule]
41
+ dependency = Ast::Dependency.new(sline, rule)
42
+
43
+ # Does this apply to a question? If not, we'll apply it to the current
44
+ # node.
45
+ if @current_question
46
+ dependency.parent = @current_question
47
+ @current_question.dependencies << dependency
48
+ else
49
+ dependency.parent = @current_node
50
+ @current_node.dependencies << dependency
51
+ end
52
+
53
+ dependency.parse_rule
54
+ @current_dependency = dependency
55
+ end
56
+
57
+ def validation(options = {})
58
+ rule = options[:rule]
59
+ validation = Ast::Validation.new(sline, rule)
60
+ validation.parent = @current_dependency
61
+ validation.parse_rule
62
+ @current_answer.validations << validation
63
+ @current_dependency = validation
64
+ end
65
+
66
+ def _grid(tag, text, &block)
67
+ grid = Ast::Grid.new(sline, tag.to_s, text)
68
+ grid.parent = @current_node
69
+ @current_node.questions << grid
70
+
71
+ _with_unwind do
72
+ @current_question = grid
73
+ @current_node = grid
74
+ instance_eval(&block)
75
+ end
76
+ end
77
+
78
+ def _repeater(tag, text, &block)
79
+ repeater = Ast::Repeater.new(sline, tag.to_s, text)
80
+ repeater.parent = @current_node
81
+ @current_node.questions << repeater
82
+
83
+ _with_unwind do
84
+ @current_question = nil
85
+ @current_node = repeater
86
+ instance_eval(&block)
87
+ end
88
+ end
89
+
90
+ def _label(tag, text, options = {})
91
+ question = Ast::Label.new(sline, text, tag.to_s, options)
92
+ question.parent = @current_node
93
+ @current_node.questions << question
94
+ @current_question = question
95
+ end
96
+
97
+ def _question(tag, text, options = {})
98
+ question = Ast::Question.new(sline, text, tag.to_s, options)
99
+ question.parent = @current_node
100
+ @current_node.questions << question
101
+ @current_question = question
102
+ end
103
+
104
+ def _answer(tag, t1, t2 = nil, options = {})
105
+ text, type, other, options = _disambiguate_answer(t1, t2, options)
106
+ answer = Ast::Answer.new(sline, text, type, other, tag.to_s, [], options)
107
+
108
+ answer.parent = @current_question
109
+ @current_question.answers << answer
110
+ @current_answer = answer
111
+ end
112
+
113
+ def _disambiguate_answer(t1, t2, options)
114
+ c = ::Case
115
+
116
+ case c[t1, t2]
117
+ when c[::String, ::NilClass]
118
+ [t1, nil, false, options] # text, type, other, options
119
+ when c[::String, ::Hash]
120
+ [t1, nil, false, t2]
121
+ when c[::String, ::Symbol]
122
+ [t1, t2, false, options]
123
+ when c[::Symbol, ::Hash]
124
+ [nil, t1, false, t2]
125
+ when c[::Symbol, ::NilClass]
126
+ [nil, t1, false, options]
127
+ when c[:other, ::Symbol]
128
+ [nil, t2, true, options]
129
+ else ::Kernel.raise "Unknown case #{[t1, t2].inspect}"
130
+ end
131
+ end
132
+
133
+ def _condition(label, *predicate)
134
+ condition = Ast::Condition.new(sline, label, predicate)
135
+ condition.parent = @current_dependency
136
+ condition.parse_condition
137
+ @current_dependency.conditions << condition
138
+ end
139
+
140
+ def _group(tag, name = nil, options = {}, &block)
141
+ group = Ast::Group.new(sline, tag.to_s, name, options)
142
+ group.parent = @current_node
143
+ @current_node.questions << group
144
+
145
+ _with_unwind do
146
+ @current_question = nil
147
+ @current_node = group
148
+ instance_eval(&block)
149
+ end
150
+ end
151
+
152
+ def _section(tag, name, options = {}, &block)
153
+ section = Ast::Section.new(sline, tag.to_s, name, options)
154
+ section.parent = @current_node
155
+ @current_node.sections << section
156
+
157
+ _with_unwind do
158
+ @current_node = section
159
+ instance_eval(&block)
160
+ end
161
+ end
162
+
163
+ def _with_unwind
164
+ old_dependency = @current_dependency
165
+ old_node = @current_node
166
+ old_question = @current_question
167
+ old_answer = @current_answer
168
+
169
+ yield
170
+
171
+ @current_dependency = old_dependency
172
+ @current_node = old_node
173
+ @current_question = old_question
174
+ @current_answer = old_answer
175
+ end
176
+
177
+ # Current line in the survey.
178
+ def sline
179
+ ::Kernel.caller(1).detect { |l| l.include?(source) }.split(':')[1]
180
+ end
181
+
182
+ # Intercept DSL keywords that may be suffixed with tags.
183
+ def method_missing(m, *args, &block)
184
+ case m
185
+ when /^q(?:uestion)?(?:_(.+))?$/
186
+ _question(*args.unshift($1), &block)
187
+ when /^a(?:nswer)?(?:_(.+))?$/
188
+ _answer(*args.unshift($1), &block)
189
+ when /^l(?:abel)?(?:_(.+))?$/
190
+ _label(*args.unshift($1), &block)
191
+ when /^g(?:roup)?(?:_(.+))?$/
192
+ _group(*args.unshift($1), &block)
193
+ when /^s(?:ection)?(?:_(.+))?$/
194
+ _section(*args.unshift($1), &block)
195
+ when /^grid(?:_(.+))?$/
196
+ _grid(*args.unshift($1), &block)
197
+ when /^repeater(?:_(.+))?$/
198
+ _repeater(*args.unshift($1), &block)
199
+ when /^dependency_.+$/
200
+ dependency(*args)
201
+ when /^condition(?:_(.+))$/
202
+ _condition(*args.unshift($1), &block)
203
+ else
204
+ super
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,19 @@
1
+ %% name = RuleParser
2
+ %% ctag_node = ast Tag(name)
3
+ %% conj_node = ast Conj(op)
4
+ %% phrase_node = ast Phrase(left, conj, right)
5
+
6
+ %%{
7
+ attr_reader :ast
8
+ }
9
+
10
+ lp = "("
11
+ rp = ")"
12
+ space = /\s/
13
+ term = < /\w+/ > ~ctag_node(text)
14
+ and = "and" ~conj_node("and")
15
+ or = "or" ~conj_node("or")
16
+ conj = and | or
17
+ phrase = (phrase:l space+ conj:c space+ phrase:r) ~phrase_node(l, c, r) | lp phrase rp | term
18
+
19
+ root = phrase:t { @ast = t }
@@ -0,0 +1,638 @@
1
+ class RuleParser
2
+ # :stopdoc:
3
+
4
+ # This is distinct from setup_parser so that a standalone parser
5
+ # can redefine #initialize and still have access to the proper
6
+ # parser setup code.
7
+ def initialize(str, debug=false)
8
+ setup_parser(str, debug)
9
+ end
10
+
11
+
12
+
13
+ # Prepares for parsing +str+. If you define a custom initialize you must
14
+ # call this method before #parse
15
+ def setup_parser(str, debug=false)
16
+ @string = str
17
+ @pos = 0
18
+ @memoizations = Hash.new { |h,k| h[k] = {} }
19
+ @result = nil
20
+ @failed_rule = nil
21
+ @failing_rule_offset = -1
22
+
23
+ setup_foreign_grammar
24
+ end
25
+
26
+ attr_reader :string
27
+ attr_reader :failing_rule_offset
28
+ attr_accessor :result, :pos
29
+
30
+
31
+ def current_column(target=pos)
32
+ if c = string.rindex("\n", target-1)
33
+ return target - c - 1
34
+ end
35
+
36
+ target + 1
37
+ end
38
+
39
+ def current_line(target=pos)
40
+ cur_offset = 0
41
+ cur_line = 0
42
+
43
+ string.each_line do |line|
44
+ cur_line += 1
45
+ cur_offset += line.size
46
+ return cur_line if cur_offset >= target
47
+ end
48
+
49
+ -1
50
+ end
51
+
52
+ def lines
53
+ lines = []
54
+ string.each_line { |l| lines << l }
55
+ lines
56
+ end
57
+
58
+
59
+
60
+ def get_text(start)
61
+ @string[start..@pos-1]
62
+ end
63
+
64
+ def show_pos
65
+ width = 10
66
+ if @pos < width
67
+ "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
68
+ else
69
+ "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
70
+ end
71
+ end
72
+
73
+ def failure_info
74
+ l = current_line @failing_rule_offset
75
+ c = current_column @failing_rule_offset
76
+
77
+ if @failed_rule.kind_of? Symbol
78
+ info = self.class::Rules[@failed_rule]
79
+ "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
80
+ else
81
+ "line #{l}, column #{c}: failed rule '#{@failed_rule}'"
82
+ end
83
+ end
84
+
85
+ def failure_caret
86
+ l = current_line @failing_rule_offset
87
+ c = current_column @failing_rule_offset
88
+
89
+ line = lines[l-1]
90
+ "#{line}\n#{' ' * (c - 1)}^"
91
+ end
92
+
93
+ def failure_character
94
+ l = current_line @failing_rule_offset
95
+ c = current_column @failing_rule_offset
96
+ lines[l-1][c-1, 1]
97
+ end
98
+
99
+ def failure_oneline
100
+ l = current_line @failing_rule_offset
101
+ c = current_column @failing_rule_offset
102
+
103
+ char = lines[l-1][c-1, 1]
104
+
105
+ if @failed_rule.kind_of? Symbol
106
+ info = self.class::Rules[@failed_rule]
107
+ "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
108
+ else
109
+ "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
110
+ end
111
+ end
112
+
113
+ class ParseError < RuntimeError
114
+ end
115
+
116
+ def raise_error
117
+ raise ParseError, failure_oneline
118
+ end
119
+
120
+ def show_error(io=STDOUT)
121
+ error_pos = @failing_rule_offset
122
+ line_no = current_line(error_pos)
123
+ col_no = current_column(error_pos)
124
+
125
+ io.puts "On line #{line_no}, column #{col_no}:"
126
+
127
+ if @failed_rule.kind_of? Symbol
128
+ info = self.class::Rules[@failed_rule]
129
+ io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
130
+ else
131
+ io.puts "Failed to match rule '#{@failed_rule}'"
132
+ end
133
+
134
+ io.puts "Got: #{string[error_pos,1].inspect}"
135
+ line = lines[line_no-1]
136
+ io.puts "=> #{line}"
137
+ io.print(" " * (col_no + 3))
138
+ io.puts "^"
139
+ end
140
+
141
+ def set_failed_rule(name)
142
+ if @pos > @failing_rule_offset
143
+ @failed_rule = name
144
+ @failing_rule_offset = @pos
145
+ end
146
+ end
147
+
148
+ attr_reader :failed_rule
149
+
150
+ def match_string(str)
151
+ len = str.size
152
+ if @string[pos,len] == str
153
+ @pos += len
154
+ return str
155
+ end
156
+
157
+ return nil
158
+ end
159
+
160
+ def scan(reg)
161
+ if m = reg.match(@string[@pos..-1])
162
+ width = m.end(0)
163
+ @pos += width
164
+ return true
165
+ end
166
+
167
+ return nil
168
+ end
169
+
170
+ if "".respond_to? :getbyte
171
+ def get_byte
172
+ if @pos >= @string.size
173
+ return nil
174
+ end
175
+
176
+ s = @string.getbyte @pos
177
+ @pos += 1
178
+ s
179
+ end
180
+ else
181
+ def get_byte
182
+ if @pos >= @string.size
183
+ return nil
184
+ end
185
+
186
+ s = @string[@pos]
187
+ @pos += 1
188
+ s
189
+ end
190
+ end
191
+
192
+ def parse(rule=nil)
193
+ # We invoke the rules indirectly via apply
194
+ # instead of by just calling them as methods because
195
+ # if the rules use left recursion, apply needs to
196
+ # manage that.
197
+
198
+ if !rule
199
+ apply(:_root)
200
+ else
201
+ method = rule.gsub("-","_hyphen_")
202
+ apply :"_#{method}"
203
+ end
204
+ end
205
+
206
+ class MemoEntry
207
+ def initialize(ans, pos)
208
+ @ans = ans
209
+ @pos = pos
210
+ @result = nil
211
+ @set = false
212
+ @left_rec = false
213
+ end
214
+
215
+ attr_reader :ans, :pos, :result, :set
216
+ attr_accessor :left_rec
217
+
218
+ def move!(ans, pos, result)
219
+ @ans = ans
220
+ @pos = pos
221
+ @result = result
222
+ @set = true
223
+ @left_rec = false
224
+ end
225
+ end
226
+
227
+ def external_invoke(other, rule, *args)
228
+ old_pos = @pos
229
+ old_string = @string
230
+
231
+ @pos = other.pos
232
+ @string = other.string
233
+
234
+ begin
235
+ if val = __send__(rule, *args)
236
+ other.pos = @pos
237
+ other.result = @result
238
+ else
239
+ other.set_failed_rule "#{self.class}##{rule}"
240
+ end
241
+ val
242
+ ensure
243
+ @pos = old_pos
244
+ @string = old_string
245
+ end
246
+ end
247
+
248
+ def apply_with_args(rule, *args)
249
+ memo_key = [rule, args]
250
+ if m = @memoizations[memo_key][@pos]
251
+ @pos = m.pos
252
+ if !m.set
253
+ m.left_rec = true
254
+ return nil
255
+ end
256
+
257
+ @result = m.result
258
+
259
+ return m.ans
260
+ else
261
+ m = MemoEntry.new(nil, @pos)
262
+ @memoizations[memo_key][@pos] = m
263
+ start_pos = @pos
264
+
265
+ ans = __send__ rule, *args
266
+
267
+ lr = m.left_rec
268
+
269
+ m.move! ans, @pos, @result
270
+
271
+ # Don't bother trying to grow the left recursion
272
+ # if it's failing straight away (thus there is no seed)
273
+ if ans and lr
274
+ return grow_lr(rule, args, start_pos, m)
275
+ else
276
+ return ans
277
+ end
278
+
279
+ return ans
280
+ end
281
+ end
282
+
283
+ def apply(rule)
284
+ if m = @memoizations[rule][@pos]
285
+ @pos = m.pos
286
+ if !m.set
287
+ m.left_rec = true
288
+ return nil
289
+ end
290
+
291
+ @result = m.result
292
+
293
+ return m.ans
294
+ else
295
+ m = MemoEntry.new(nil, @pos)
296
+ @memoizations[rule][@pos] = m
297
+ start_pos = @pos
298
+
299
+ ans = __send__ rule
300
+
301
+ lr = m.left_rec
302
+
303
+ m.move! ans, @pos, @result
304
+
305
+ # Don't bother trying to grow the left recursion
306
+ # if it's failing straight away (thus there is no seed)
307
+ if ans and lr
308
+ return grow_lr(rule, nil, start_pos, m)
309
+ else
310
+ return ans
311
+ end
312
+
313
+ return ans
314
+ end
315
+ end
316
+
317
+ def grow_lr(rule, args, start_pos, m)
318
+ while true
319
+ @pos = start_pos
320
+ @result = m.result
321
+
322
+ if args
323
+ ans = __send__ rule, *args
324
+ else
325
+ ans = __send__ rule
326
+ end
327
+ return nil unless ans
328
+
329
+ break if @pos <= m.pos
330
+
331
+ m.move! ans, @pos, @result
332
+ end
333
+
334
+ @result = m.result
335
+ @pos = m.pos
336
+ return m.ans
337
+ end
338
+
339
+ class RuleInfo
340
+ def initialize(name, rendered)
341
+ @name = name
342
+ @rendered = rendered
343
+ end
344
+
345
+ attr_reader :name, :rendered
346
+ end
347
+
348
+ def self.rule_info(name, rendered)
349
+ RuleInfo.new(name, rendered)
350
+ end
351
+
352
+
353
+ # :startdoc:
354
+
355
+
356
+ attr_reader :ast
357
+
358
+
359
+ # :stopdoc:
360
+
361
+ module AST
362
+ class Node; end
363
+ class Conj < Node
364
+ def initialize(op)
365
+ @op = op
366
+ end
367
+ attr_reader :op
368
+ end
369
+ class Tag < Node
370
+ def initialize(name)
371
+ @name = name
372
+ end
373
+ attr_reader :name
374
+ end
375
+ class Phrase < Node
376
+ def initialize(left, conj, right)
377
+ @left = left
378
+ @conj = conj
379
+ @right = right
380
+ end
381
+ attr_reader :left
382
+ attr_reader :conj
383
+ attr_reader :right
384
+ end
385
+ end
386
+ def conj_node(op)
387
+ AST::Conj.new(op)
388
+ end
389
+ def ctag_node(name)
390
+ AST::Tag.new(name)
391
+ end
392
+ def phrase_node(left, conj, right)
393
+ AST::Phrase.new(left, conj, right)
394
+ end
395
+ def setup_foreign_grammar; end
396
+
397
+ # lp = "("
398
+ def _lp
399
+ _tmp = match_string("(")
400
+ set_failed_rule :_lp unless _tmp
401
+ return _tmp
402
+ end
403
+
404
+ # rp = ")"
405
+ def _rp
406
+ _tmp = match_string(")")
407
+ set_failed_rule :_rp unless _tmp
408
+ return _tmp
409
+ end
410
+
411
+ # space = /\s/
412
+ def _space
413
+ _tmp = scan(/\A(?-mix:\s)/)
414
+ set_failed_rule :_space unless _tmp
415
+ return _tmp
416
+ end
417
+
418
+ # term = < /\w+/ > {ctag_node(text)}
419
+ def _term
420
+
421
+ _save = self.pos
422
+ while true # sequence
423
+ _text_start = self.pos
424
+ _tmp = scan(/\A(?-mix:\w+)/)
425
+ if _tmp
426
+ text = get_text(_text_start)
427
+ end
428
+ unless _tmp
429
+ self.pos = _save
430
+ break
431
+ end
432
+ @result = begin; ctag_node(text); end
433
+ _tmp = true
434
+ unless _tmp
435
+ self.pos = _save
436
+ end
437
+ break
438
+ end # end sequence
439
+
440
+ set_failed_rule :_term unless _tmp
441
+ return _tmp
442
+ end
443
+
444
+ # and = "and" {conj_node("and")}
445
+ def _and
446
+
447
+ _save = self.pos
448
+ while true # sequence
449
+ _tmp = match_string("and")
450
+ unless _tmp
451
+ self.pos = _save
452
+ break
453
+ end
454
+ @result = begin; conj_node("and"); end
455
+ _tmp = true
456
+ unless _tmp
457
+ self.pos = _save
458
+ end
459
+ break
460
+ end # end sequence
461
+
462
+ set_failed_rule :_and unless _tmp
463
+ return _tmp
464
+ end
465
+
466
+ # or = "or" {conj_node("or")}
467
+ def _or
468
+
469
+ _save = self.pos
470
+ while true # sequence
471
+ _tmp = match_string("or")
472
+ unless _tmp
473
+ self.pos = _save
474
+ break
475
+ end
476
+ @result = begin; conj_node("or"); end
477
+ _tmp = true
478
+ unless _tmp
479
+ self.pos = _save
480
+ end
481
+ break
482
+ end # end sequence
483
+
484
+ set_failed_rule :_or unless _tmp
485
+ return _tmp
486
+ end
487
+
488
+ # conj = (and | or)
489
+ def _conj
490
+
491
+ _save = self.pos
492
+ while true # choice
493
+ _tmp = apply(:_and)
494
+ break if _tmp
495
+ self.pos = _save
496
+ _tmp = apply(:_or)
497
+ break if _tmp
498
+ self.pos = _save
499
+ break
500
+ end # end choice
501
+
502
+ set_failed_rule :_conj unless _tmp
503
+ return _tmp
504
+ end
505
+
506
+ # phrase = (phrase:l space+ conj:c space+ phrase:r {phrase_node(l, c, r)} | lp phrase rp | term)
507
+ def _phrase
508
+
509
+ _save = self.pos
510
+ while true # choice
511
+
512
+ _save1 = self.pos
513
+ while true # sequence
514
+ _tmp = apply(:_phrase)
515
+ l = @result
516
+ unless _tmp
517
+ self.pos = _save1
518
+ break
519
+ end
520
+ _save2 = self.pos
521
+ _tmp = apply(:_space)
522
+ if _tmp
523
+ while true
524
+ _tmp = apply(:_space)
525
+ break unless _tmp
526
+ end
527
+ _tmp = true
528
+ else
529
+ self.pos = _save2
530
+ end
531
+ unless _tmp
532
+ self.pos = _save1
533
+ break
534
+ end
535
+ _tmp = apply(:_conj)
536
+ c = @result
537
+ unless _tmp
538
+ self.pos = _save1
539
+ break
540
+ end
541
+ _save3 = self.pos
542
+ _tmp = apply(:_space)
543
+ if _tmp
544
+ while true
545
+ _tmp = apply(:_space)
546
+ break unless _tmp
547
+ end
548
+ _tmp = true
549
+ else
550
+ self.pos = _save3
551
+ end
552
+ unless _tmp
553
+ self.pos = _save1
554
+ break
555
+ end
556
+ _tmp = apply(:_phrase)
557
+ r = @result
558
+ unless _tmp
559
+ self.pos = _save1
560
+ break
561
+ end
562
+ @result = begin; phrase_node(l, c, r); end
563
+ _tmp = true
564
+ unless _tmp
565
+ self.pos = _save1
566
+ end
567
+ break
568
+ end # end sequence
569
+
570
+ break if _tmp
571
+ self.pos = _save
572
+
573
+ _save4 = self.pos
574
+ while true # sequence
575
+ _tmp = apply(:_lp)
576
+ unless _tmp
577
+ self.pos = _save4
578
+ break
579
+ end
580
+ _tmp = apply(:_phrase)
581
+ unless _tmp
582
+ self.pos = _save4
583
+ break
584
+ end
585
+ _tmp = apply(:_rp)
586
+ unless _tmp
587
+ self.pos = _save4
588
+ end
589
+ break
590
+ end # end sequence
591
+
592
+ break if _tmp
593
+ self.pos = _save
594
+ _tmp = apply(:_term)
595
+ break if _tmp
596
+ self.pos = _save
597
+ break
598
+ end # end choice
599
+
600
+ set_failed_rule :_phrase unless _tmp
601
+ return _tmp
602
+ end
603
+
604
+ # root = phrase:t { @ast = t }
605
+ def _root
606
+
607
+ _save = self.pos
608
+ while true # sequence
609
+ _tmp = apply(:_phrase)
610
+ t = @result
611
+ unless _tmp
612
+ self.pos = _save
613
+ break
614
+ end
615
+ @result = begin; @ast = t ; end
616
+ _tmp = true
617
+ unless _tmp
618
+ self.pos = _save
619
+ end
620
+ break
621
+ end # end sequence
622
+
623
+ set_failed_rule :_root unless _tmp
624
+ return _tmp
625
+ end
626
+
627
+ Rules = {}
628
+ Rules[:_lp] = rule_info("lp", "\"(\"")
629
+ Rules[:_rp] = rule_info("rp", "\")\"")
630
+ Rules[:_space] = rule_info("space", "/\\s/")
631
+ Rules[:_term] = rule_info("term", "< /\\w+/ > {ctag_node(text)}")
632
+ Rules[:_and] = rule_info("and", "\"and\" {conj_node(\"and\")}")
633
+ Rules[:_or] = rule_info("or", "\"or\" {conj_node(\"or\")}")
634
+ Rules[:_conj] = rule_info("conj", "(and | or)")
635
+ Rules[:_phrase] = rule_info("phrase", "(phrase:l space+ conj:c space+ phrase:r {phrase_node(l, c, r)} | lp phrase rp | term)")
636
+ Rules[:_root] = rule_info("root", "phrase:t { @ast = t }")
637
+ # :startdoc:
638
+ end