Class: KPeg::StringEscape
- Inherits:
-
Object
- Object
- KPeg::StringEscape
show all
- Defined in:
- lib/kpeg/string_escape.rb
Defined Under Namespace
Classes: KpegPosInfo, MemoEntry, ParseError, RuleInfo
Constant Summary
collapse
- Rules =
{}
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(str, debug = false) ⇒ StringEscape
This is distinct from setup_parser so that a standalone parser can redefine #initialize and still have access to the proper parser setup code.
7
8
9
|
# File 'lib/kpeg/string_escape.rb', line 7
def initialize(str, debug=false)
setup_parser(str, debug)
end
|
Instance Attribute Details
#failed_rule ⇒ Object
Returns the value of attribute failed_rule.
190
191
192
|
# File 'lib/kpeg/string_escape.rb', line 190
def failed_rule
@failed_rule
end
|
#failing_rule_offset ⇒ Object
Returns the value of attribute failing_rule_offset.
27
28
29
|
# File 'lib/kpeg/string_escape.rb', line 27
def failing_rule_offset
@failing_rule_offset
end
|
#pos ⇒ Object
Returns the value of attribute pos.
28
29
30
|
# File 'lib/kpeg/string_escape.rb', line 28
def pos
@pos
end
|
#result ⇒ Object
Returns the value of attribute result.
28
29
30
|
# File 'lib/kpeg/string_escape.rb', line 28
def result
@result
end
|
#string ⇒ Object
Returns the value of attribute string.
26
27
28
|
# File 'lib/kpeg/string_escape.rb', line 26
def string
@string
end
|
#text ⇒ Object
Returns the value of attribute text.
393
394
395
|
# File 'lib/kpeg/string_escape.rb', line 393
def text
@text
end
|
Class Method Details
.rule_info(name, rendered) ⇒ Object
385
386
387
|
# File 'lib/kpeg/string_escape.rb', line 385
def self.rule_info(name, rendered)
RuleInfo.new(name, rendered)
end
|
Instance Method Details
#_embed ⇒ Object
embed = embed_seg*:s { @text = s.join }
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
|
# File 'lib/kpeg/string_escape.rb', line 627
def _embed
_save = self.pos
while true _ary = []
while true
_tmp = apply(:_embed_seg)
_ary << @result if _tmp
break unless _tmp
end
_tmp = true
@result = _ary
s = @result
unless _tmp
self.pos = _save
break
end
@result = begin; @text = s.join ; end
_tmp = true
unless _tmp
self.pos = _save
end
break
end
set_failed_rule :_embed unless _tmp
return _tmp
end
|
#_embed_seg ⇒ Object
embed_seg = (“#” { “\#” } | segment)
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
|
# File 'lib/kpeg/string_escape.rb', line 594
def _embed_seg
_save = self.pos
while true
_save1 = self.pos
while true _tmp = match_string("#")
unless _tmp
self.pos = _save1
break
end
@result = begin; "\\#" ; end
_tmp = true
unless _tmp
self.pos = _save1
end
break
end
break if _tmp
self.pos = _save
_tmp = apply(:_segment)
break if _tmp
self.pos = _save
break
end
set_failed_rule :_embed_seg unless _tmp
return _tmp
end
|
#_root ⇒ Object
root = segment*:s { @text = s.join }
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
|
# File 'lib/kpeg/string_escape.rb', line 564
def _root
_save = self.pos
while true _ary = []
while true
_tmp = apply(:_segment)
_ary << @result if _tmp
break unless _tmp
end
_tmp = true
@result = _ary
s = @result
unless _tmp
self.pos = _save
break
end
@result = begin; @text = s.join ; end
_tmp = true
unless _tmp
self.pos = _save
end
break
end
set_failed_rule :_root unless _tmp
return _tmp
end
|
#_segment ⇒ Object
segment = (< /[w ]+/ > { text } | “\” { “\\” } | “n” { “\n” } | “r” { “\r” } | “t” { “\t” } | “b” { “\b” } | “"” { “\"” } | < . > { text })
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
|
# File 'lib/kpeg/string_escape.rb', line 400
def _segment
_save = self.pos
while true
_save1 = self.pos
while true _text_start = self.pos
_tmp = scan(/\G(?-mix:[\w ]+)/)
if _tmp
text = get_text(_text_start)
end
unless _tmp
self.pos = _save1
break
end
@result = begin; text ; end
_tmp = true
unless _tmp
self.pos = _save1
end
break
end
break if _tmp
self.pos = _save
_save2 = self.pos
while true _tmp = match_string("\\")
unless _tmp
self.pos = _save2
break
end
@result = begin; "\\\\" ; end
_tmp = true
unless _tmp
self.pos = _save2
end
break
end
break if _tmp
self.pos = _save
_save3 = self.pos
while true _tmp = match_string("\n")
unless _tmp
self.pos = _save3
break
end
@result = begin; "\\n" ; end
_tmp = true
unless _tmp
self.pos = _save3
end
break
end
break if _tmp
self.pos = _save
_save4 = self.pos
while true _tmp = match_string("\r")
unless _tmp
self.pos = _save4
break
end
@result = begin; "\\r" ; end
_tmp = true
unless _tmp
self.pos = _save4
end
break
end
break if _tmp
self.pos = _save
_save5 = self.pos
while true _tmp = match_string("\t")
unless _tmp
self.pos = _save5
break
end
@result = begin; "\\t" ; end
_tmp = true
unless _tmp
self.pos = _save5
end
break
end
break if _tmp
self.pos = _save
_save6 = self.pos
while true _tmp = match_string("\b")
unless _tmp
self.pos = _save6
break
end
@result = begin; "\\b" ; end
_tmp = true
unless _tmp
self.pos = _save6
end
break
end
break if _tmp
self.pos = _save
_save7 = self.pos
while true _tmp = match_string("\"")
unless _tmp
self.pos = _save7
break
end
@result = begin; "\\\"" ; end
_tmp = true
unless _tmp
self.pos = _save7
end
break
end
break if _tmp
self.pos = _save
_save8 = self.pos
while true _text_start = self.pos
_tmp = get_byte
if _tmp
text = get_text(_text_start)
end
unless _tmp
self.pos = _save8
break
end
@result = begin; text ; end
_tmp = true
unless _tmp
self.pos = _save8
end
break
end
break if _tmp
self.pos = _save
break
end
set_failed_rule :_segment unless _tmp
return _tmp
end
|
#apply(rule) ⇒ Object
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
|
# File 'lib/kpeg/string_escape.rb', line 321
def apply(rule)
@result = nil
if m = @memoizations[rule][@pos]
@pos = m.pos
if !m.set
m.left_rec = true
return nil
end
@result = m.result
return m.ans
else
m = MemoEntry.new(nil, @pos)
@memoizations[rule][@pos] = m
start_pos = @pos
ans = __send__ rule
lr = m.left_rec
m.move! ans, @pos, @result
if ans and lr
return grow_lr(rule, nil, start_pos, m)
else
return ans
end
end
end
|
#apply_with_args(rule, *args) ⇒ Object
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
|
# File 'lib/kpeg/string_escape.rb', line 287
def apply_with_args(rule, *args)
@result = nil
memo_key = [rule, args]
if m = @memoizations[memo_key][@pos]
@pos = m.pos
if !m.set
m.left_rec = true
return nil
end
@result = m.result
return m.ans
else
m = MemoEntry.new(nil, @pos)
@memoizations[memo_key][@pos] = m
start_pos = @pos
ans = __send__ rule, *args
lr = m.left_rec
m.move! ans, @pos, @result
if ans and lr
return grow_lr(rule, args, start_pos, m)
else
return ans
end
end
end
|
#current_character(target = pos) ⇒ Object
69
70
71
72
73
74
|
# File 'lib/kpeg/string_escape.rb', line 69
def current_character(target=pos)
if target < 0 || target >= string.size
raise "Target position #{target} is outside of string"
end
string[target, 1]
end
|
#current_column(target = pos) ⇒ Object
30
31
32
33
34
35
36
37
38
|
# File 'lib/kpeg/string_escape.rb', line 30
def current_column(target=pos)
if string[target] == "\n" && (c = string.rindex("\n", target-1) || -1)
return target - c
elsif c = string.rindex("\n", target)
return target - c
end
target + 1
end
|
#current_line(target = pos) ⇒ Object
53
54
55
56
57
58
|
# File 'lib/kpeg/string_escape.rb', line 53
def current_line(target=pos)
if line = position_line_offsets.bsearch_index {|x| x > target }
return line + 1
end
raise "Target position #{target} is outside of string"
end
|
#current_pos_info(target = pos) ⇒ Object
78
79
80
81
82
83
84
|
# File 'lib/kpeg/string_escape.rb', line 78
def current_pos_info(target=pos)
l = current_line target
c = current_column target
ln = get_line(l-1)
chr = string[target,1]
KpegPosInfo.new(target, l, c, ln, chr)
end
|
#external_invoke(other, rule, *args) ⇒ Object
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
|
# File 'lib/kpeg/string_escape.rb', line 268
def external_invoke(other, rule, *args)
old_pos = @pos
old_string = @string
set_string other.string, other.pos
begin
if val = __send__(rule, *args)
other.pos = @pos
other.result = @result
else
other.set_failed_rule "#{self.class}##{rule}"
end
val
ensure
set_string old_string, old_pos
end
end
|
#failure_caret ⇒ Object
137
138
139
140
|
# File 'lib/kpeg/string_escape.rb', line 137
def failure_caret
p = current_pos_info @failing_rule_offset
"#{p.line.chomp}\n#{' ' * (p.col - 1)}^"
end
|
#failure_character ⇒ Object
142
143
144
|
# File 'lib/kpeg/string_escape.rb', line 142
def failure_character
current_character @failing_rule_offset
end
|
#failure_info ⇒ Object
125
126
127
128
129
130
131
132
133
134
135
|
# File 'lib/kpeg/string_escape.rb', line 125
def failure_info
l = current_line @failing_rule_offset
c = current_column @failing_rule_offset
if @failed_rule.kind_of? Symbol
info = self.class::Rules[@failed_rule]
"line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
else
"line #{l}, column #{c}: failed rule '#{@failed_rule}'"
end
end
|
#failure_oneline ⇒ Object
146
147
148
149
150
151
152
153
154
155
|
# File 'lib/kpeg/string_escape.rb', line 146
def failure_oneline
p = current_pos_info @failing_rule_offset
if @failed_rule.kind_of? Symbol
info = self.class::Rules[@failed_rule]
"@#{p.lno}:#{p.col} failed rule '#{info.name}', got '#{p.char}'"
else
"@#{p.lno}:#{p.col} failed rule '#{@failed_rule}', got '#{p.char}'"
end
end
|
#get_byte ⇒ Object
212
213
214
215
216
217
218
219
220
|
# File 'lib/kpeg/string_escape.rb', line 212
def get_byte
if @pos >= @string_size
return nil
end
s = @string[@pos].ord
@pos += 1
s
end
|
#get_line(no) ⇒ Object
90
91
92
93
94
95
96
97
98
99
100
|
# File 'lib/kpeg/string_escape.rb', line 90
def get_line(no)
loff = position_line_offsets
if no < 0
raise "Line No is out of range: #{no} < 0"
elsif no >= loff.size
raise "Line No is out of range: #{no} >= #{loff.size}"
end
lend = loff[no]-1
lstart = no > 0 ? loff[no-1] : 0
string[lstart..lend]
end
|
#get_text(start) ⇒ Object
104
105
106
|
# File 'lib/kpeg/string_escape.rb', line 104
def get_text(start)
@string[start..@pos-1]
end
|
#grow_lr(rule, args, start_pos, m) ⇒ Object
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
|
# File 'lib/kpeg/string_escape.rb', line 354
def grow_lr(rule, args, start_pos, m)
while true
@pos = start_pos
@result = m.result
if args
ans = __send__ rule, *args
else
ans = __send__ rule
end
return nil unless ans
break if @pos <= m.pos
m.move! ans, @pos, @result
end
@result = m.result
@pos = m.pos
return m.ans
end
|
#lines ⇒ Object
86
87
88
|
# File 'lib/kpeg/string_escape.rb', line 86
def lines
string.lines
end
|
#match_string(str) ⇒ Object
192
193
194
195
196
197
198
199
200
|
# File 'lib/kpeg/string_escape.rb', line 192
def match_string(str)
len = str.size
if @string[pos,len] == str
@pos += len
return str
end
return nil
end
|
#parse(rule = nil) ⇒ Object
233
234
235
236
237
238
239
240
241
242
243
244
245
|
# File 'lib/kpeg/string_escape.rb', line 233
def parse(rule=nil)
if !rule
apply(:_root)
else
method = rule.gsub("-","_hyphen_")
apply :"_#{method}"
end
end
|
#position_line_offsets ⇒ Object
40
41
42
43
44
45
46
47
48
49
50
|
# File 'lib/kpeg/string_escape.rb', line 40
def position_line_offsets
unless @position_line_offsets
@position_line_offsets = []
total = 0
string.each_line do |line|
total += line.size
@position_line_offsets << total
end
end
@position_line_offsets
end
|
#raise_error ⇒ Object
160
161
162
|
# File 'lib/kpeg/string_escape.rb', line 160
def raise_error
raise ParseError, failure_oneline
end
|
#scan(reg) ⇒ Object
202
203
204
205
206
207
208
209
|
# File 'lib/kpeg/string_escape.rb', line 202
def scan(reg)
if m = reg.match(@string, @pos)
@pos = m.end(0)
return true
end
return nil
end
|
#set_failed_rule(name) ⇒ Object
183
184
185
186
187
188
|
# File 'lib/kpeg/string_escape.rb', line 183
def set_failed_rule(name)
if @pos > @failing_rule_offset
@failed_rule = name
@failing_rule_offset = @pos
end
end
|
#set_string(string, pos) ⇒ Object
Sets the string and current parsing position for the parser.
109
110
111
112
113
114
|
# File 'lib/kpeg/string_escape.rb', line 109
def set_string string, pos
@string = string
@string_size = string ? string.size : 0
@pos = pos
@position_line_offsets = nil
end
|
#setup_foreign_grammar ⇒ Object
397
|
# File 'lib/kpeg/string_escape.rb', line 397
def setup_foreign_grammar; end
|
#setup_parser(str, debug = false) ⇒ Object
Prepares for parsing str
. If you define a custom initialize you must call this method before #parse
15
16
17
18
19
20
21
22
23
24
|
# File 'lib/kpeg/string_escape.rb', line 15
def setup_parser(str, debug=false)
set_string str, 0
@memoizations = Hash.new { |h,k| h[k] = {} }
@result = nil
@failed_rule = nil
@failing_rule_offset = -1
@line_offsets = nil
setup_foreign_grammar
end
|
#show_error(io = STDOUT) ⇒ Object
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
# File 'lib/kpeg/string_escape.rb', line 164
def show_error(io=STDOUT)
error_pos = @failing_rule_offset
p = current_pos_info(error_pos)
io.puts "On line #{p.lno}, column #{p.col}:"
if @failed_rule.kind_of? Symbol
info = self.class::Rules[@failed_rule]
io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
else
io.puts "Failed to match rule '#{@failed_rule}'"
end
io.puts "Got: #{p.char.inspect}"
io.puts "=> #{p.line}"
io.print(" " * (p.col + 2))
io.puts "^"
end
|
#show_pos ⇒ Object
116
117
118
119
120
121
122
123
|
# File 'lib/kpeg/string_escape.rb', line 116
def show_pos
width = 10
if @pos < width
"#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
else
"#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
end
end
|