poetics 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.rbc
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake", ">= 0.8.7"
6
+ gem "kpeg", "~> 0.8.2"
7
+ gem "mspec", "~> 1.5.17"
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2011 Brian Ford. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,87 @@
1
+ A native implementation of CoffeeScript [1] that runs on the Rubinius VM [2].
2
+
3
+ Q. Whence comes the name Poetics?
4
+ A. Poetics is a partial anagram of the word CoffeeScript. It is also a nod to
5
+ Jeremy Ashkenas, the author of CoffeeScript, and his interest in code as
6
+ literature.
7
+
8
+ Q. Why a native implementation?
9
+ A. CoffeeScript is an interesting language in its own right. Rather than
10
+ merely being a syntax layer on top of Javascript, and bound to expressing
11
+ its semantics in those of Javascript, it deserves its own implementation.
12
+ Many of the reasons to use CoffeeScript in Node.js would also apply to
13
+ using this native implementation.
14
+
15
+
16
+ Installation
17
+
18
+ First, install Rubinius:
19
+
20
+ 1. Using RVM (http://rvm.beginrescueend.com).
21
+
22
+ rvm install rbx
23
+
24
+ 2. Or directly (http://rubini.us/doc/en/what-is-rubinius/).
25
+
26
+ Second, install Poetics:
27
+
28
+ rbx -S gem install poetics
29
+
30
+
31
+ Running Poetics
32
+
33
+ Poetics provides a REPL for exploratory programming or runs CoffeeScript
34
+ scripts.
35
+
36
+ rbx -S poetics -h
37
+
38
+ The REPL presently just parses code and returns an S-Expression
39
+ representation:
40
+
41
+ $ rbx -S poetics
42
+ > 42
43
+ [:number, 42.0, 1, 1]
44
+ > "hello, y'all"
45
+ [:string, "hello, y'all", 1, 1]
46
+ >
47
+
48
+
49
+ Getting Help
50
+
51
+ Poetics is a work in progress. If you encounter trouble, please file an issue
52
+ at https://github.com/brixen/poetics/issues
53
+
54
+
55
+ Contributing
56
+
57
+ If you find Poetics interesting and would like to help out, fork the project
58
+ on Github and submit a pull request.
59
+
60
+
61
+ People
62
+
63
+ Poetics was created by Brian Ford (brixen) to force him to really learn
64
+ Javascript and CoffeeScript.
65
+
66
+ <add your name here>
67
+
68
+
69
+ License
70
+
71
+ Poetics is MIT licensed. See the LICENSE file.
72
+
73
+
74
+ Credits
75
+
76
+ Jeremy has created an very interesting language in CoffeeScript. This
77
+ implementation steals bits and pieces from other projects:
78
+
79
+ Rubinius (https://github.com/evanphx/rubinius/)
80
+ KPeg (https://github.com/evanphx/kpeg/)
81
+ Atomy (https://github.com/vito/atomy/)
82
+ Poison (https://github.com/brixen/poison/)
83
+ Talon (https://github.com/evanphx/talon/)
84
+
85
+
86
+ [1] CoffeeScript (http://jashkenas.github.com/coffee-script/)
87
+ [2] Rubinius (http://rubini.us)
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ task :default => :spec
5
+
6
+ base = File.expand_path '../lib/poetics/parser', __FILE__
7
+
8
+ grammar = "#{base}/poetics.kpeg"
9
+ parser = "#{base}/parser.rb"
10
+
11
+ file parser => grammar do
12
+ sh "rbx -S kpeg -f -s #{base}/poetics.kpeg -o #{base}/parser.rb"
13
+ end
14
+
15
+ desc "Convert the grammar description to a parser"
16
+ task :parser => parser
17
+
18
+ desc "Run the specs (default)"
19
+ task :spec => :parser do
20
+ sh "mspec spec"
21
+ end
data/bin/poetics ADDED
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env rbx
2
+ #
3
+ # vim: filetype=ruby
4
+
5
+ $:.unshift File.expand_path('../../lib', __FILE__)
6
+
7
+ require 'readline'
8
+ require 'poetics'
9
+
10
+ class Poetics::Script
11
+ HISTORY = File.expand_path "~/.poetics_history"
12
+
13
+ attr_accessor :prompt
14
+
15
+ def initialize
16
+ @evals = []
17
+ @script = nil
18
+ @history = []
19
+ end
20
+
21
+ def options(argv=ARGV)
22
+ options = Rubinius::Options.new "Usage: poetics [options] [script]", 20
23
+
24
+ options.on "-", "Read and evaluate code from STDIN" do
25
+ @evals << STDIN.read
26
+ end
27
+
28
+ options.on "-c", "FILE", "Check the syntax of FILE" do |f|
29
+ begin
30
+ begin
31
+ Poetics::Parser.parse_file f
32
+ rescue => e
33
+ e.render
34
+ exit 1
35
+ end
36
+
37
+ puts "Syntax OK"
38
+ exit 0
39
+ end
40
+ end
41
+
42
+ options.on "-e", "CODE", "Execute CODE" do |e|
43
+ @evals << e
44
+ end
45
+
46
+ options.on "-v", "--version", "Display the version" do
47
+ puts Poetics::COMMAND_VERSION
48
+ end
49
+
50
+ options.on "-h", "--help", "Display this help" do
51
+ puts options
52
+ exit 0
53
+ end
54
+
55
+ options.doc ""
56
+
57
+ rest = options.parse(argv)
58
+ @script ||= rest.first
59
+ end
60
+
61
+ def evals
62
+ return if @evals.empty?
63
+
64
+ Poetics::CodeLoader.evaluate @evals.join("\n")
65
+ end
66
+
67
+ def script
68
+ return unless @script
69
+
70
+ if File.exists? @script
71
+ Poetics::CodeLoader.execute_file @script
72
+ else
73
+ STDERR.puts "Unable to find '#{@script}' to run"
74
+ exit 1
75
+ end
76
+ end
77
+
78
+ def load_history
79
+ return unless File.exists? HISTORY
80
+
81
+ File.open HISTORY, "r" do |f|
82
+ f.each { |l| Readline::HISTORY << l }
83
+ end
84
+ end
85
+
86
+ def save_history
87
+ File.open HISTORY, "w" do |f|
88
+ @history.last(100).map { |s| f.puts s }
89
+ end
90
+ end
91
+
92
+ def record_history(str)
93
+ @history << str
94
+ end
95
+
96
+ def start_prompt
97
+ @prompt = "> "
98
+ end
99
+
100
+ def continue_prompt
101
+ @prompt = ". "
102
+ end
103
+
104
+ def repl
105
+ return if @script
106
+ load_history
107
+ start_prompt
108
+
109
+ begin
110
+ snippet = ""
111
+ while str = Readline.readline(prompt)
112
+ break if str.nil? and snippet.empty?
113
+ next if str.empty?
114
+
115
+ snippet << str
116
+ begin
117
+ value = Poetics::CodeLoader.evaluate snippet
118
+ p value
119
+
120
+ record_history snippet
121
+ snippet = ""
122
+ start_prompt
123
+ rescue => e
124
+ STDERR.puts e
125
+ end
126
+ end
127
+ ensure
128
+ save_history
129
+ end
130
+ end
131
+
132
+ def main
133
+ options
134
+ evals
135
+ script
136
+ repl
137
+ end
138
+ end
139
+
140
+ Poetics::Script.new.main
data/lib/poetics.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'poetics/version'
2
+ require 'poetics/syntax'
3
+ require 'poetics/parser'
4
+ require 'poetics/library'
@@ -0,0 +1 @@
1
+ require 'poetics/library/code_loader'
@@ -0,0 +1,13 @@
1
+ module Poetics
2
+ class CodeLoader
3
+ def self.evaluate(string)
4
+ # We're just parsing for now
5
+ Poetics::Parser.parse_to_sexp string
6
+ end
7
+
8
+ def self.execute_file(name)
9
+ value = Poetics::Parser.parse_to_sexp IO.read(name)
10
+ p value
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ require 'poetics/parser/parser'
2
+
3
+ class Poetics::Parser
4
+ include Poetics::Syntax
5
+
6
+ def self.parse_to_sexp(string)
7
+ parser = new string
8
+ unless parser.parse
9
+ parser.raise_error
10
+ end
11
+
12
+ parser.result.to_sexp
13
+ end
14
+
15
+ attr_reader :line, :column
16
+
17
+ def position(line, column)
18
+ @line = line
19
+ @column = column
20
+ end
21
+ end
@@ -0,0 +1,875 @@
1
+ class Poetics::Parser
2
+ # STANDALONE START
3
+ def setup_parser(str, debug=false)
4
+ @string = str
5
+ @pos = 0
6
+ @memoizations = Hash.new { |h,k| h[k] = {} }
7
+ @result = nil
8
+ @failed_rule = nil
9
+ @failing_rule_offset = -1
10
+
11
+ setup_foreign_grammar
12
+ end
13
+
14
+ # This is distinct from setup_parser so that a standalone parser
15
+ # can redefine #initialize and still have access to the proper
16
+ # parser setup code.
17
+ #
18
+ def initialize(str, debug=false)
19
+ setup_parser(str, debug)
20
+ end
21
+
22
+ attr_reader :string
23
+ attr_reader :result, :failing_rule_offset
24
+ attr_accessor :pos
25
+
26
+ # STANDALONE START
27
+ def current_column(target=pos)
28
+ if c = string.rindex("\n", target-1)
29
+ return target - c - 1
30
+ end
31
+
32
+ target + 1
33
+ end
34
+
35
+ def current_line(target=pos)
36
+ cur_offset = 0
37
+ cur_line = 0
38
+
39
+ string.each_line do |line|
40
+ cur_line += 1
41
+ cur_offset += line.size
42
+ return cur_line if cur_offset >= target
43
+ end
44
+
45
+ -1
46
+ end
47
+
48
+ def lines
49
+ lines = []
50
+ string.each_line { |l| lines << l }
51
+ lines
52
+ end
53
+
54
+ #
55
+
56
+ def get_text(start)
57
+ @string[start..@pos-1]
58
+ end
59
+
60
+ def show_pos
61
+ width = 10
62
+ if @pos < width
63
+ "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
64
+ else
65
+ "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
66
+ end
67
+ end
68
+
69
+ def failure_info
70
+ l = current_line @failing_rule_offset
71
+ c = current_column @failing_rule_offset
72
+
73
+ if @failed_rule.kind_of? Symbol
74
+ info = self.class::Rules[@failed_rule]
75
+ "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
76
+ else
77
+ "line #{l}, column #{c}: failed rule '#{@failed_rule}'"
78
+ end
79
+ end
80
+
81
+ def failure_caret
82
+ l = current_line @failing_rule_offset
83
+ c = current_column @failing_rule_offset
84
+
85
+ line = lines[l-1]
86
+ "#{line}\n#{' ' * (c - 1)}^"
87
+ end
88
+
89
+ def failure_character
90
+ l = current_line @failing_rule_offset
91
+ c = current_column @failing_rule_offset
92
+ lines[l-1][c-1, 1]
93
+ end
94
+
95
+ def failure_oneline
96
+ l = current_line @failing_rule_offset
97
+ c = current_column @failing_rule_offset
98
+
99
+ char = lines[l-1][c-1, 1]
100
+
101
+ if @failed_rule.kind_of? Symbol
102
+ info = self.class::Rules[@failed_rule]
103
+ "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
104
+ else
105
+ "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
106
+ end
107
+ end
108
+
109
+ class ParseError < RuntimeError
110
+ end
111
+
112
+ def raise_error
113
+ raise ParseError, failure_oneline
114
+ end
115
+
116
+ def show_error(io=STDOUT)
117
+ error_pos = @failing_rule_offset
118
+ line_no = current_line(error_pos)
119
+ col_no = current_column(error_pos)
120
+
121
+ io.puts "On line #{line_no}, column #{col_no}:"
122
+
123
+ if @failed_rule.kind_of? Symbol
124
+ info = self.class::Rules[@failed_rule]
125
+ io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
126
+ else
127
+ io.puts "Failed to match rule '#{@failed_rule}'"
128
+ end
129
+
130
+ io.puts "Got: #{string[error_pos,1].inspect}"
131
+ line = lines[line_no-1]
132
+ io.puts "=> #{line}"
133
+ io.print(" " * (col_no + 3))
134
+ io.puts "^"
135
+ end
136
+
137
+ def set_failed_rule(name)
138
+ if @pos > @failing_rule_offset
139
+ @failed_rule = name
140
+ @failing_rule_offset = @pos
141
+ end
142
+ end
143
+
144
+ attr_reader :failed_rule
145
+
146
+ def match_string(str)
147
+ len = str.size
148
+ if @string[pos,len] == str
149
+ @pos += len
150
+ return str
151
+ end
152
+
153
+ return nil
154
+ end
155
+
156
+ def scan(reg)
157
+ if m = reg.match(@string[@pos..-1])
158
+ width = m.end(0)
159
+ @pos += width
160
+ return true
161
+ end
162
+
163
+ return nil
164
+ end
165
+
166
+ if "".respond_to? :getbyte
167
+ def get_byte
168
+ if @pos >= @string.size
169
+ return nil
170
+ end
171
+
172
+ s = @string.getbyte @pos
173
+ @pos += 1
174
+ s
175
+ end
176
+ else
177
+ def get_byte
178
+ if @pos >= @string.size
179
+ return nil
180
+ end
181
+
182
+ s = @string[@pos]
183
+ @pos += 1
184
+ s
185
+ end
186
+ end
187
+
188
+ def parse(rule=nil)
189
+ if !rule
190
+ _root ? true : false
191
+ else
192
+ # This is not shared with code_generator.rb so this can be standalone
193
+ method = rule.gsub("-","_hyphen_")
194
+ __send__("_#{method}") ? true : false
195
+ end
196
+ end
197
+
198
+ class LeftRecursive
199
+ def initialize(detected=false)
200
+ @detected = detected
201
+ end
202
+
203
+ attr_accessor :detected
204
+ end
205
+
206
+ class MemoEntry
207
+ def initialize(ans, pos)
208
+ @ans = ans
209
+ @pos = pos
210
+ @uses = 1
211
+ @result = nil
212
+ end
213
+
214
+ attr_reader :ans, :pos, :uses, :result
215
+
216
+ def inc!
217
+ @uses += 1
218
+ end
219
+
220
+ def move!(ans, pos, result)
221
+ @ans = ans
222
+ @pos = pos
223
+ @result = result
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
+ else
238
+ other.set_failed_rule "#{self.class}##{rule}"
239
+ end
240
+ val
241
+ ensure
242
+ @pos = old_pos
243
+ @string = old_string
244
+ end
245
+ end
246
+
247
+ def apply(rule)
248
+ if m = @memoizations[rule][@pos]
249
+ m.inc!
250
+
251
+ prev = @pos
252
+ @pos = m.pos
253
+ if m.ans.kind_of? LeftRecursive
254
+ m.ans.detected = true
255
+ return nil
256
+ end
257
+
258
+ @result = m.result
259
+
260
+ return m.ans
261
+ else
262
+ lr = LeftRecursive.new(false)
263
+ m = MemoEntry.new(lr, @pos)
264
+ @memoizations[rule][@pos] = m
265
+ start_pos = @pos
266
+
267
+ ans = __send__ rule
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.detected
274
+ return grow_lr(rule, start_pos, m)
275
+ else
276
+ return ans
277
+ end
278
+
279
+ return ans
280
+ end
281
+ end
282
+
283
+ def grow_lr(rule, start_pos, m)
284
+ while true
285
+ @pos = start_pos
286
+ @result = m.result
287
+
288
+ ans = __send__ rule
289
+ return nil unless ans
290
+
291
+ break if @pos <= m.pos
292
+
293
+ m.move! ans, @pos, @result
294
+ end
295
+
296
+ @result = m.result
297
+ @pos = m.pos
298
+ return m.ans
299
+ end
300
+
301
+ class RuleInfo
302
+ def initialize(name, rendered)
303
+ @name = name
304
+ @rendered = rendered
305
+ end
306
+
307
+ attr_reader :name, :rendered
308
+ end
309
+
310
+ def self.rule_info(name, rendered)
311
+ RuleInfo.new(name, rendered)
312
+ end
313
+
314
+ #
315
+ def setup_foreign_grammar; end
316
+
317
+ # root = - value? - end
318
+ def _root
319
+
320
+ _save = self.pos
321
+ while true # sequence
322
+ _tmp = apply(:__hyphen_)
323
+ unless _tmp
324
+ self.pos = _save
325
+ break
326
+ end
327
+ _save1 = self.pos
328
+ _tmp = apply(:_value)
329
+ unless _tmp
330
+ _tmp = true
331
+ self.pos = _save1
332
+ end
333
+ unless _tmp
334
+ self.pos = _save
335
+ break
336
+ end
337
+ _tmp = apply(:__hyphen_)
338
+ unless _tmp
339
+ self.pos = _save
340
+ break
341
+ end
342
+ _tmp = apply(:_end)
343
+ unless _tmp
344
+ self.pos = _save
345
+ end
346
+ break
347
+ end # end sequence
348
+
349
+ set_failed_rule :_root unless _tmp
350
+ return _tmp
351
+ end
352
+
353
+ # end = !.
354
+ def _end
355
+ _save = self.pos
356
+ _tmp = get_byte
357
+ _tmp = _tmp ? nil : true
358
+ self.pos = _save
359
+ set_failed_rule :_end unless _tmp
360
+ return _tmp
361
+ end
362
+
363
+ # - = (" " | "\t" | "\n")*
364
+ def __hyphen_
365
+ while true
366
+
367
+ _save1 = self.pos
368
+ while true # choice
369
+ _tmp = match_string(" ")
370
+ break if _tmp
371
+ self.pos = _save1
372
+ _tmp = match_string("\t")
373
+ break if _tmp
374
+ self.pos = _save1
375
+ _tmp = match_string("\n")
376
+ break if _tmp
377
+ self.pos = _save1
378
+ break
379
+ end # end choice
380
+
381
+ break unless _tmp
382
+ end
383
+ _tmp = true
384
+ set_failed_rule :__hyphen_ unless _tmp
385
+ return _tmp
386
+ end
387
+
388
+ # value = (string | number | boolean)
389
+ def _value
390
+
391
+ _save = self.pos
392
+ while true # choice
393
+ _tmp = apply(:_string)
394
+ break if _tmp
395
+ self.pos = _save
396
+ _tmp = apply(:_number)
397
+ break if _tmp
398
+ self.pos = _save
399
+ _tmp = apply(:_boolean)
400
+ break if _tmp
401
+ self.pos = _save
402
+ break
403
+ end # end choice
404
+
405
+ set_failed_rule :_value unless _tmp
406
+ return _tmp
407
+ end
408
+
409
+ # boolean = position (true | false | null | undefined)
410
+ def _boolean
411
+
412
+ _save = self.pos
413
+ while true # sequence
414
+ _tmp = apply(:_position)
415
+ unless _tmp
416
+ self.pos = _save
417
+ break
418
+ end
419
+
420
+ _save1 = self.pos
421
+ while true # choice
422
+ _tmp = apply(:_true)
423
+ break if _tmp
424
+ self.pos = _save1
425
+ _tmp = apply(:_false)
426
+ break if _tmp
427
+ self.pos = _save1
428
+ _tmp = apply(:_null)
429
+ break if _tmp
430
+ self.pos = _save1
431
+ _tmp = apply(:_undefined)
432
+ break if _tmp
433
+ self.pos = _save1
434
+ break
435
+ end # end choice
436
+
437
+ unless _tmp
438
+ self.pos = _save
439
+ end
440
+ break
441
+ end # end sequence
442
+
443
+ set_failed_rule :_boolean unless _tmp
444
+ return _tmp
445
+ end
446
+
447
+ # true = "true" {true_value}
448
+ def _true
449
+
450
+ _save = self.pos
451
+ while true # sequence
452
+ _tmp = match_string("true")
453
+ unless _tmp
454
+ self.pos = _save
455
+ break
456
+ end
457
+ @result = begin; true_value; end
458
+ _tmp = true
459
+ unless _tmp
460
+ self.pos = _save
461
+ end
462
+ break
463
+ end # end sequence
464
+
465
+ set_failed_rule :_true unless _tmp
466
+ return _tmp
467
+ end
468
+
469
+ # false = "false" {false_value}
470
+ def _false
471
+
472
+ _save = self.pos
473
+ while true # sequence
474
+ _tmp = match_string("false")
475
+ unless _tmp
476
+ self.pos = _save
477
+ break
478
+ end
479
+ @result = begin; false_value; end
480
+ _tmp = true
481
+ unless _tmp
482
+ self.pos = _save
483
+ end
484
+ break
485
+ end # end sequence
486
+
487
+ set_failed_rule :_false unless _tmp
488
+ return _tmp
489
+ end
490
+
491
+ # null = "null" {null_value}
492
+ def _null
493
+
494
+ _save = self.pos
495
+ while true # sequence
496
+ _tmp = match_string("null")
497
+ unless _tmp
498
+ self.pos = _save
499
+ break
500
+ end
501
+ @result = begin; null_value; end
502
+ _tmp = true
503
+ unless _tmp
504
+ self.pos = _save
505
+ end
506
+ break
507
+ end # end sequence
508
+
509
+ set_failed_rule :_null unless _tmp
510
+ return _tmp
511
+ end
512
+
513
+ # undefined = "undefined" {undefined_value}
514
+ def _undefined
515
+
516
+ _save = self.pos
517
+ while true # sequence
518
+ _tmp = match_string("undefined")
519
+ unless _tmp
520
+ self.pos = _save
521
+ break
522
+ end
523
+ @result = begin; undefined_value; end
524
+ _tmp = true
525
+ unless _tmp
526
+ self.pos = _save
527
+ end
528
+ break
529
+ end # end sequence
530
+
531
+ set_failed_rule :_undefined unless _tmp
532
+ return _tmp
533
+ end
534
+
535
+ # number = position (real | hex | int)
536
+ def _number
537
+
538
+ _save = self.pos
539
+ while true # sequence
540
+ _tmp = apply(:_position)
541
+ unless _tmp
542
+ self.pos = _save
543
+ break
544
+ end
545
+
546
+ _save1 = self.pos
547
+ while true # choice
548
+ _tmp = apply(:_real)
549
+ break if _tmp
550
+ self.pos = _save1
551
+ _tmp = apply(:_hex)
552
+ break if _tmp
553
+ self.pos = _save1
554
+ _tmp = apply(:_int)
555
+ break if _tmp
556
+ self.pos = _save1
557
+ break
558
+ end # end choice
559
+
560
+ unless _tmp
561
+ self.pos = _save
562
+ end
563
+ break
564
+ end # end sequence
565
+
566
+ set_failed_rule :_number unless _tmp
567
+ return _tmp
568
+ end
569
+
570
+ # hexdigits = /[0-9A-Fa-f]/
571
+ def _hexdigits
572
+ _tmp = scan(/\A(?-mix:[0-9A-Fa-f])/)
573
+ set_failed_rule :_hexdigits unless _tmp
574
+ return _tmp
575
+ end
576
+
577
+ # hex = "0x" < hexdigits+ > {hexadecimal(text)}
578
+ def _hex
579
+
580
+ _save = self.pos
581
+ while true # sequence
582
+ _tmp = match_string("0x")
583
+ unless _tmp
584
+ self.pos = _save
585
+ break
586
+ end
587
+ _text_start = self.pos
588
+ _save1 = self.pos
589
+ _tmp = apply(:_hexdigits)
590
+ if _tmp
591
+ while true
592
+ _tmp = apply(:_hexdigits)
593
+ break unless _tmp
594
+ end
595
+ _tmp = true
596
+ else
597
+ self.pos = _save1
598
+ end
599
+ if _tmp
600
+ text = get_text(_text_start)
601
+ end
602
+ unless _tmp
603
+ self.pos = _save
604
+ break
605
+ end
606
+ @result = begin; hexadecimal(text); end
607
+ _tmp = true
608
+ unless _tmp
609
+ self.pos = _save
610
+ end
611
+ break
612
+ end # end sequence
613
+
614
+ set_failed_rule :_hex unless _tmp
615
+ return _tmp
616
+ end
617
+
618
+ # digits = ("0" | /[1-9]/ /[0-9]/*)
619
+ def _digits
620
+
621
+ _save = self.pos
622
+ while true # choice
623
+ _tmp = match_string("0")
624
+ break if _tmp
625
+ self.pos = _save
626
+
627
+ _save1 = self.pos
628
+ while true # sequence
629
+ _tmp = scan(/\A(?-mix:[1-9])/)
630
+ unless _tmp
631
+ self.pos = _save1
632
+ break
633
+ end
634
+ while true
635
+ _tmp = scan(/\A(?-mix:[0-9])/)
636
+ break unless _tmp
637
+ end
638
+ _tmp = true
639
+ unless _tmp
640
+ self.pos = _save1
641
+ end
642
+ break
643
+ end # end sequence
644
+
645
+ break if _tmp
646
+ self.pos = _save
647
+ break
648
+ end # end choice
649
+
650
+ set_failed_rule :_digits unless _tmp
651
+ return _tmp
652
+ end
653
+
654
+ # int = < digits > {number(text)}
655
+ def _int
656
+
657
+ _save = self.pos
658
+ while true # sequence
659
+ _text_start = self.pos
660
+ _tmp = apply(:_digits)
661
+ if _tmp
662
+ text = get_text(_text_start)
663
+ end
664
+ unless _tmp
665
+ self.pos = _save
666
+ break
667
+ end
668
+ @result = begin; number(text); end
669
+ _tmp = true
670
+ unless _tmp
671
+ self.pos = _save
672
+ end
673
+ break
674
+ end # end sequence
675
+
676
+ set_failed_rule :_int unless _tmp
677
+ return _tmp
678
+ end
679
+
680
+ # real = < digits "." digits ("e" /[-+]/? /[0-9]/+)? > {number(text)}
681
+ def _real
682
+
683
+ _save = self.pos
684
+ while true # sequence
685
+ _text_start = self.pos
686
+
687
+ _save1 = self.pos
688
+ while true # sequence
689
+ _tmp = apply(:_digits)
690
+ unless _tmp
691
+ self.pos = _save1
692
+ break
693
+ end
694
+ _tmp = match_string(".")
695
+ unless _tmp
696
+ self.pos = _save1
697
+ break
698
+ end
699
+ _tmp = apply(:_digits)
700
+ unless _tmp
701
+ self.pos = _save1
702
+ break
703
+ end
704
+ _save2 = self.pos
705
+
706
+ _save3 = self.pos
707
+ while true # sequence
708
+ _tmp = match_string("e")
709
+ unless _tmp
710
+ self.pos = _save3
711
+ break
712
+ end
713
+ _save4 = self.pos
714
+ _tmp = scan(/\A(?-mix:[-+])/)
715
+ unless _tmp
716
+ _tmp = true
717
+ self.pos = _save4
718
+ end
719
+ unless _tmp
720
+ self.pos = _save3
721
+ break
722
+ end
723
+ _save5 = self.pos
724
+ _tmp = scan(/\A(?-mix:[0-9])/)
725
+ if _tmp
726
+ while true
727
+ _tmp = scan(/\A(?-mix:[0-9])/)
728
+ break unless _tmp
729
+ end
730
+ _tmp = true
731
+ else
732
+ self.pos = _save5
733
+ end
734
+ unless _tmp
735
+ self.pos = _save3
736
+ end
737
+ break
738
+ end # end sequence
739
+
740
+ unless _tmp
741
+ _tmp = true
742
+ self.pos = _save2
743
+ end
744
+ unless _tmp
745
+ self.pos = _save1
746
+ end
747
+ break
748
+ end # end sequence
749
+
750
+ if _tmp
751
+ text = get_text(_text_start)
752
+ end
753
+ unless _tmp
754
+ self.pos = _save
755
+ break
756
+ end
757
+ @result = begin; number(text); end
758
+ _tmp = true
759
+ unless _tmp
760
+ self.pos = _save
761
+ end
762
+ break
763
+ end # end sequence
764
+
765
+ set_failed_rule :_real unless _tmp
766
+ return _tmp
767
+ end
768
+
769
+ # string = position "\"" < /[^\\"]*/ > "\"" {string_value(text)}
770
+ def _string
771
+
772
+ _save = self.pos
773
+ while true # sequence
774
+ _tmp = apply(:_position)
775
+ unless _tmp
776
+ self.pos = _save
777
+ break
778
+ end
779
+ _tmp = match_string("\"")
780
+ unless _tmp
781
+ self.pos = _save
782
+ break
783
+ end
784
+ _text_start = self.pos
785
+ _tmp = scan(/\A(?-mix:[^\\"]*)/)
786
+ if _tmp
787
+ text = get_text(_text_start)
788
+ end
789
+ unless _tmp
790
+ self.pos = _save
791
+ break
792
+ end
793
+ _tmp = match_string("\"")
794
+ unless _tmp
795
+ self.pos = _save
796
+ break
797
+ end
798
+ @result = begin; string_value(text); end
799
+ _tmp = true
800
+ unless _tmp
801
+ self.pos = _save
802
+ end
803
+ break
804
+ end # end sequence
805
+
806
+ set_failed_rule :_string unless _tmp
807
+ return _tmp
808
+ end
809
+
810
+ # line = { current_line }
811
+ def _line
812
+ @result = begin; current_line ; end
813
+ _tmp = true
814
+ set_failed_rule :_line unless _tmp
815
+ return _tmp
816
+ end
817
+
818
+ # column = { current_column }
819
+ def _column
820
+ @result = begin; current_column ; end
821
+ _tmp = true
822
+ set_failed_rule :_column unless _tmp
823
+ return _tmp
824
+ end
825
+
826
+ # position = line:l column:c { position(l, c) }
827
+ def _position
828
+
829
+ _save = self.pos
830
+ while true # sequence
831
+ _tmp = apply(:_line)
832
+ l = @result
833
+ unless _tmp
834
+ self.pos = _save
835
+ break
836
+ end
837
+ _tmp = apply(:_column)
838
+ c = @result
839
+ unless _tmp
840
+ self.pos = _save
841
+ break
842
+ end
843
+ @result = begin; position(l, c) ; end
844
+ _tmp = true
845
+ unless _tmp
846
+ self.pos = _save
847
+ end
848
+ break
849
+ end # end sequence
850
+
851
+ set_failed_rule :_position unless _tmp
852
+ return _tmp
853
+ end
854
+
855
+ Rules = {}
856
+ Rules[:_root] = rule_info("root", "- value? - end")
857
+ Rules[:_end] = rule_info("end", "!.")
858
+ Rules[:__hyphen_] = rule_info("-", "(\" \" | \"\\t\" | \"\\n\")*")
859
+ Rules[:_value] = rule_info("value", "(string | number | boolean)")
860
+ Rules[:_boolean] = rule_info("boolean", "position (true | false | null | undefined)")
861
+ Rules[:_true] = rule_info("true", "\"true\" {true_value}")
862
+ Rules[:_false] = rule_info("false", "\"false\" {false_value}")
863
+ Rules[:_null] = rule_info("null", "\"null\" {null_value}")
864
+ Rules[:_undefined] = rule_info("undefined", "\"undefined\" {undefined_value}")
865
+ Rules[:_number] = rule_info("number", "position (real | hex | int)")
866
+ Rules[:_hexdigits] = rule_info("hexdigits", "/[0-9A-Fa-f]/")
867
+ Rules[:_hex] = rule_info("hex", "\"0x\" < hexdigits+ > {hexadecimal(text)}")
868
+ Rules[:_digits] = rule_info("digits", "(\"0\" | /[1-9]/ /[0-9]/*)")
869
+ Rules[:_int] = rule_info("int", "< digits > {number(text)}")
870
+ Rules[:_real] = rule_info("real", "< digits \".\" digits (\"e\" /[-+]/? /[0-9]/+)? > {number(text)}")
871
+ Rules[:_string] = rule_info("string", "position \"\\\"\" < /[^\\\\\"]*/ > \"\\\"\" {string_value(text)}")
872
+ Rules[:_line] = rule_info("line", "{ current_line }")
873
+ Rules[:_column] = rule_info("column", "{ current_column }")
874
+ Rules[:_position] = rule_info("position", "line:l column:c { position(l, c) }")
875
+ end