grammar 0.5 → 0.8

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,521 @@
1
+ require 'thread'
2
+
3
+ class Grammar
4
+ class Ruby0
5
+
6
+ def self.compile(gram)
7
+ lambda { |output, input| gram[new(output, &input)] }
8
+ end
9
+
10
+ def [](object, clone=false)
11
+ clone ? object.clone : object
12
+ rescue
13
+ object
14
+ end
15
+ def steps(*steps)
16
+ steps[-1]
17
+ end
18
+ def or(first) # :yield:
19
+ first || yield
20
+ end
21
+ def and(first) # :yield:
22
+ first && yield
23
+ end
24
+ def not(operand)
25
+ !operand
26
+ end
27
+ def if(condition, yes, &no)
28
+ condition ? yes[] : no[]
29
+ end
30
+ def send(obj, method, *args, &block)
31
+ obj.__send__(method, *args, &block)
32
+ end
33
+ def send_splat(obj, method, *args, &block)
34
+ args.concat(args.pop)
35
+ obj.__send__(method, *args, &block)
36
+ end
37
+ def <<(item)
38
+ @output << item
39
+ end
40
+ def output # :yield: buf
41
+ block_given? ? (@output = yield(@output)) : @output
42
+ end
43
+
44
+ # these are mainly for internal usage
45
+ attr_reader(:input, :lookahead, :error)
46
+
47
+ class Void
48
+ def concat(other);self;end
49
+ def <<(other);self;end
50
+ end
51
+
52
+ class Error < Exception
53
+ attr_reader(:consumed)
54
+ attr_reader(:expected)
55
+ attr_reader(:list)
56
+ attr_accessor(:raise)
57
+ def initialize(raise=true)
58
+ @list = []
59
+ @expected = []
60
+ @consumed = 0
61
+ @raise = raise
62
+ end
63
+ def [](expected, found)
64
+ @expected << expected if expected
65
+ if @raise
66
+ @list << [@expected, found]
67
+ @expected = []
68
+ Kernel.raise(self)
69
+ end
70
+ end
71
+ def noraise
72
+ @raise
73
+ ensure
74
+ @raise = false
75
+ end
76
+ def concat(other)
77
+ @expected.concat(other.expected)
78
+ @list.concat(other.list)
79
+ end
80
+ def clear
81
+ @consumed += 1
82
+ @raise = true
83
+ @expected.clear
84
+ @list.clear
85
+ end
86
+ def each # :yield: expected, found
87
+ @list.each { |err|
88
+ yield(*err)
89
+ }
90
+ end
91
+ def to_str
92
+ s = ""
93
+ first = true
94
+ @list.each { |err|
95
+ s.concat(first ? "expected: " : "\nor: ")
96
+ first = true
97
+ err[0].each { |e|
98
+ s << ?| unless first
99
+ s.concat(e.to_s)
100
+ first = false
101
+ }
102
+ s.concat(", found: ").concat(err[1].to_s)
103
+ first = false
104
+ }
105
+ s
106
+ end
107
+ def to_s
108
+ to_str
109
+ end
110
+ end
111
+
112
+ def initialize(output=nil, lookahead=nil, input_buffer=[],
113
+ error=self.class::Error.new, followed = 0, hold = false,
114
+ &input)
115
+ @output = output
116
+ @input = input
117
+ @lookahead = lookahead || (input && input[])
118
+ @input_buffer = input_buffer
119
+ @hold = hold
120
+ @followed = followed
121
+ @error = error
122
+ end
123
+
124
+ def fork(buf)
125
+ self.class.new(buf, @lookahead, @input_buffer,
126
+ @error.clone, @followed, @hold, &@input)
127
+ end
128
+
129
+ def join(engine)
130
+ @input = engine.input
131
+ @lookahead = engine.lookahead
132
+ @error = engine.error
133
+ end
134
+
135
+ def alternation(gram1) # :yield: engine
136
+ raise = @error.noraise
137
+ @followed += 1
138
+ begin
139
+ gram1[self]
140
+ ensure
141
+ @followed -= 1
142
+ raise1 = @error.raise
143
+ @error.raise = raise
144
+ end or yield(self)
145
+ ensure
146
+ @error.raise ||= raise1
147
+ end
148
+
149
+ def sequence(gram1) # :yield: engine
150
+ @followed += 1
151
+ begin
152
+ gram1[self]
153
+ ensure
154
+ @followed -= 1
155
+ end and begin
156
+ # TODO: keep going with hold if nothing expected yet
157
+ @hold ? true : yield(self)
158
+ end
159
+ end
160
+
161
+ def positive # :yield: engine
162
+ hold = @hold
163
+ begin
164
+ @hold = true
165
+ yield(self)
166
+ ensure
167
+ @hold = hold
168
+ end
169
+ end
170
+
171
+ def negative # :yield: engine
172
+ hold = @hold
173
+ raise = @error.noraise
174
+ begin
175
+ @hold = true
176
+ not yield(self)
177
+ ensure
178
+ @error.raise = raise
179
+ @hold = hold
180
+ end or failure("something else")
181
+ end
182
+
183
+ # atomic parsing
184
+
185
+ def failure(expected=nil)
186
+ @error[expected, @lookahead]
187
+ end
188
+ def consume
189
+ @hold or (
190
+ @error.clear
191
+ @output << @lookahead
192
+ @lookahead = @input[]
193
+ true
194
+ )
195
+ end
196
+ def eof
197
+ !@lookahead or failure("EOF")
198
+ end
199
+ def any
200
+ @lookahead ? consume : failure("ANY")
201
+ end
202
+ def match(pattern)
203
+ (pattern===@lookahead) ? consume : failure(pattern)
204
+ end
205
+ def always # :yield: engine
206
+ yield(self)
207
+ end
208
+
209
+ # variables and objects
210
+
211
+ class Var
212
+ def initialize(val=nil)
213
+ @var = val
214
+ end
215
+ def []
216
+ @var
217
+ end
218
+ def <<(val)
219
+ @var = val
220
+ end
221
+ end
222
+ def variables(n=nil, &block) # :yield: *vars
223
+ vars = (0...(n||block.arity)).map { Var.new }
224
+ yield(*vars)[self]
225
+ end
226
+
227
+ def recurse(inner, &outer) # :yield: engine
228
+ inner0 = inner.to_proc
229
+ left = false
230
+ right = false
231
+ lloop = false
232
+ followed = @followed
233
+ consumed = @error.consumed
234
+ inner << Proc.new {
235
+ if @error.consumed==consumed
236
+ @followed!=followed or raise("something must follow left recursion")
237
+ left = true
238
+ lloop ? (@error.raise = true) : failure(nil)
239
+ elsif @followed==followed
240
+ right = true
241
+ true
242
+ else
243
+ recurse(inner, &outer)
244
+ end
245
+ }
246
+ yield(self) or return
247
+ @hold and return(true)
248
+ while true
249
+ while right
250
+ consumed = @error.consumed
251
+ right = false
252
+ @error.raise = true
253
+ yield(self) or raise("should have raised")
254
+ end
255
+ left or begin
256
+ !lloop or raise("left recursion not first")
257
+ return(true)
258
+ end
259
+ lloop = true
260
+ consumed = @error.consumed
261
+ begin
262
+ yield(self) or raise("should have raised")
263
+ rescue self.class::Error => err
264
+ err.equal?(@error) && err.consumed==consumed or raise(err)
265
+ return(true)
266
+ end
267
+ @error.consumed!=consumed or raise("infinite loop detected")
268
+ end
269
+ ensure
270
+ inner << inner0
271
+ end
272
+
273
+ def redirect(gram, buf0, &block) # :yield: buf[, engine]
274
+ buf = buf0.clone
275
+ output = @output
276
+ @followed += 1 if block_given?
277
+ begin
278
+ @output = buf
279
+ gram[self]
280
+ ensure
281
+ buf = @output
282
+ @followed -= 1 if block_given?
283
+ @output = output
284
+ end or return
285
+ if !@hold && block_given?
286
+ block.arity==1 ? yield(buf) : yield(buf, self)
287
+ end
288
+ true
289
+ end
290
+
291
+ def discard(gram) # :yield: engine
292
+ buf = Void.new
293
+ output = @output
294
+ @followed += 1 if block_given?
295
+ begin
296
+ @output = buf
297
+ gram[self]
298
+ ensure
299
+ @followed -= 1 if block_given?
300
+ @output = output
301
+ end or return
302
+ if !@hold && block_given?
303
+ @output << yield(self)
304
+ end
305
+ true
306
+ end
307
+
308
+ def backref(gram, &block) # :yield: n[, engine]
309
+ tainted = @output.tainted?
310
+ size0 = @output.taint.size
311
+ @followed += 1 if block_given?
312
+ begin
313
+ ret = gram[self]
314
+ ensure
315
+ @followed -= 1 if block_given?
316
+ n = @output.size-size0
317
+ if @hold || !ret
318
+ @output.slice!(size0, n)
319
+ end
320
+ end or return
321
+ if !@hold && block_given?
322
+ block.arity==1 ? yield(n) : yield(n, self)
323
+ end
324
+ true
325
+ ensure
326
+ @output.untaint unless tainted
327
+ end
328
+
329
+ def backtrack(gram, len=nil) # :yield: n[, engine]
330
+ tainted = @output.tainted?
331
+ return gram[self] if @error.raise
332
+ len ||= -1
333
+ hold = @hold
334
+ lookahead = @lookahead
335
+ error = @error.clone
336
+ buffer = @input_buffer.clone
337
+ size0 = @output.taint.size
338
+ @followed += 1 if block_given?
339
+ begin
340
+ len = -1 if hold
341
+ @hold = false
342
+ input = @input
343
+ len += 1
344
+ @input = lambda {
345
+ begin
346
+ c = input[]
347
+ ensure
348
+ if (len-=1).zero?
349
+ @input = input
350
+ buffer = nil
351
+ else
352
+ buffer << c
353
+ end
354
+ end
355
+ }
356
+ ret = gram[self]
357
+ rescue self.class::Error => err
358
+ @error = err
359
+ raise(err) if !buffer
360
+ ensure
361
+ @followed -= 1 if block_given?
362
+ @hold = hold
363
+ n = @output.size-size0
364
+ if hold || !ret
365
+ if buffer
366
+ error.concat(@error) if !ret
367
+ @lookahead = lookahead
368
+ @error = error
369
+ index = -1
370
+ @input = lambda { buffer[index+=1] || (@input=input)[] }
371
+ end
372
+ @output.slice!(size0, n)
373
+ return ret
374
+ end
375
+ end or return
376
+ if !@hold && block_given?
377
+ block.arity==1 ? yield(n) : yield(n, self)
378
+ end
379
+ true
380
+ ensure
381
+ @output.untaint unless tainted
382
+ end
383
+
384
+ def supply(tokenizer, parser, buf0, &block) # :yield: buf[, engine]
385
+ !@hold or raise("can't hold supply")
386
+ buf = buf0.clone
387
+ engine = fork(buf)
388
+ @followed += 1 if block_given?
389
+ begin
390
+ index = -1
391
+ @input = lambda {
392
+ buf[index+=1] or begin
393
+ buf.slice!(0, buf.size)
394
+ tokenizer[engine]
395
+ buf[index = 0]
396
+ end
397
+ }
398
+ @lookahead = input[]
399
+ parser[self]
400
+ ensure
401
+ @followed -= 1 if block_given?
402
+ lookahead = @lookahead
403
+ join(engine)
404
+ end or return
405
+ if block_given?
406
+ buf.slice!(0, index+1)
407
+ buf << lookahead
408
+ block.arity==1 ? yield(buf) : yield(buf, self)
409
+ end
410
+ true
411
+ end
412
+
413
+ class PipeBuffer
414
+ attr_accessor(:max_size)
415
+ def initialize(buf, mutex, cvar, max_size)
416
+ @buf = buf
417
+ @tmp_buf = nil
418
+ @mutex = mutex
419
+ @cvar = cvar
420
+ @max_size = max_size || -1
421
+ end
422
+ def _produce(arg)
423
+ @mutex.lock
424
+ begin
425
+ @buf << arg
426
+ @cvar.signal
427
+ ensure
428
+ @cvar.wait(@mutex) if @buf.size==@max_size
429
+ @mutex.unlock
430
+ end
431
+ self
432
+ end
433
+ alias_method(:<<, :_produce)
434
+ def taint
435
+ @tmp_buf ||= @buf.class.new
436
+ class << self
437
+ remove_method(:<<)
438
+ end
439
+ super
440
+ end
441
+ def untaint
442
+ class << self
443
+ alias_method(:<<, :_produce)
444
+ end
445
+ @tmp_buf.size.times { |i| self << @tmp_buf[i] }
446
+ @tmp_buf.slice!(0, @tmp_buf.size)
447
+ super
448
+ end
449
+ def method_missing(meth, *args, &block)
450
+ @tmp_buf.send(meth, *args, &block)
451
+ end
452
+ end
453
+
454
+ def pipe(lexer, parser, buf0, max_size=nil) # :yield: buf[, engine]
455
+ !@hold or raise("can't hold pipe")
456
+ buf = buf0.clone
457
+ mutex = Mutex.new
458
+ cvar = ConditionVariable.new
459
+ pbuf = PipeBuffer.new(buf, mutex, cvar, max_size)
460
+ engine = fork(pbuf)
461
+ producer = Thread.new {
462
+ begin
463
+ lexer[engine]
464
+ ensure
465
+ mutex.lock
466
+ cvar.signal
467
+ cvar = nil
468
+ mutex.unlock
469
+ end
470
+ }
471
+ @followed += 1 if block_given?
472
+ begin
473
+ index = 0
474
+ @input = lambda {
475
+ mutex.lock
476
+ begin
477
+ buf[index]
478
+ ensure
479
+ begin
480
+ if 2*(index+=1)>buf.size
481
+ buf.slice!(0, index)
482
+ index = 0
483
+ end
484
+ if cvar
485
+ cvar.signal
486
+ cvar.wait(mutex) if buf.empty?
487
+ end
488
+ ensure
489
+ mutex.unlock
490
+ end
491
+ end
492
+ }
493
+ mutex.lock
494
+ #mutex.sleep if buf.empty?
495
+ cvar.wait(mutex) if cvar && buf.empty?
496
+ mutex.unlock
497
+ @lookahead = input[]
498
+ parser[self]
499
+ ensure
500
+ @followed -= 1 if block_given?
501
+ mutex.lock
502
+ if cvar
503
+ pbuf.max_size = 1
504
+ cvar.wait(mutex) unless producer.stop?
505
+ producer.kill
506
+ end
507
+ mutex.unlock
508
+ lookahead = @lookahead
509
+ join(engine)
510
+ end or return
511
+ if block_given?
512
+ buf[0, index] = (buf.class.new << lookahead)
513
+ block.arity==1 ? yield(buf) : yield(buf, self)
514
+ end
515
+ true
516
+ end
517
+
518
+ end
519
+ end
520
+
521
+