poetics 0.0.1

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.
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