kpeg 0.9.0 → 1.2.0
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.
- checksums.yaml +7 -0
- data/.hoeignore +12 -0
- data/Gemfile +2 -11
- data/History.txt +22 -1
- data/Manifest.txt +10 -3
- data/README.rdoc +40 -8
- data/Rakefile +12 -3
- data/bin/kpeg +9 -2
- data/examples/lua_string/lua_string.kpeg.rb +0 -2
- data/examples/tiny_markdown/Rakefile +3 -0
- data/examples/tiny_markdown/driver.rb +10 -0
- data/examples/tiny_markdown/node.rb +107 -0
- data/examples/tiny_markdown/sample.md +51 -0
- data/examples/tiny_markdown/tiny_markdown.kpeg +199 -0
- data/examples/tiny_markdown/tiny_markdown.kpeg.rb +3892 -0
- data/kpeg.gemspec +20 -20
- data/lib/hoe/kpeg.rb +6 -5
- data/lib/kpeg/code_generator.rb +81 -45
- data/lib/kpeg/compiled_parser.rb +32 -28
- data/lib/kpeg/format_parser.kpeg +22 -10
- data/lib/kpeg/format_parser.rb +94 -73
- data/lib/kpeg/grammar.rb +2 -2
- data/lib/kpeg/grammar_renderer.rb +14 -0
- data/lib/kpeg/position.rb +25 -8
- data/lib/kpeg/string_escape.kpeg +1 -0
- data/lib/kpeg/string_escape.rb +399 -13
- data/lib/kpeg.rb +1 -1
- data/test/test_kpeg.rb +1 -1
- data/test/test_kpeg_code_generator.rb +186 -14
- data/test/test_kpeg_compiled_parser.rb +1 -1
- data/test/test_kpeg_format.rb +25 -6
- data/test/{test_file_parser_roundtrip.rb → test_kpeg_format_parser_round_trip.rb} +1 -1
- data/test/{test_gen_calc.rb → test_kpeg_grammar.rb} +48 -5
- data/test/test_kpeg_grammar_renderer.rb +47 -6
- data/test/test_kpeg_string_escape.rb +42 -0
- metadata +90 -101
- data/.gemtest +0 -0
- data/test/test_left_recursion.rb +0 -50
data/kpeg.gemspec
CHANGED
@@ -1,42 +1,42 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: kpeg 1.0.0.20140103162640 ruby lib
|
2
3
|
|
3
4
|
Gem::Specification.new do |s|
|
4
5
|
s.name = "kpeg"
|
5
|
-
s.version = "0.
|
6
|
+
s.version = "1.0.0.20140103162640"
|
6
7
|
|
7
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.authors = ["
|
9
|
-
s.
|
10
|
-
s.date = "2012-03-07"
|
9
|
+
s.authors = ["Evan Phoenix"]
|
10
|
+
s.date = "2014-01-04"
|
11
11
|
s.description = "KPeg is a simple PEG library for Ruby. It provides an API as well as native\ngrammar to build the grammar.\n\nKPeg strives to provide a simple, powerful API without being too exotic.\n\nKPeg supports direct left recursion of rules via the\n{OMeta memoization}[http://www.vpri.org/pdf/tr2008003_experimenting.pdf] trick."
|
12
|
-
s.email = ["
|
12
|
+
s.email = ["evan@fallingsnow.net"]
|
13
13
|
s.executables = ["kpeg"]
|
14
|
-
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
|
15
|
-
s.files = [".autotest", "
|
14
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc", "examples/phone_number/README.md", "examples/upper/README.md"]
|
15
|
+
s.files = [".autotest", ".travis.yml", "History.txt", "LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "bin/kpeg", "examples/calculator/calculator.kpeg", "examples/calculator/calculator.rb", "examples/foreign_reference/literals.kpeg", "examples/foreign_reference/matcher.kpeg", "examples/foreign_reference/matcher.rb", "examples/lua_string/driver.rb", "examples/lua_string/lua_string.kpeg", "examples/lua_string/lua_string.kpeg.rb", "examples/phone_number/README.md", "examples/phone_number/phone_number.kpeg", "examples/phone_number/phone_number.rb", "examples/upper/README.md", "examples/upper/upper.kpeg", "examples/upper/upper.rb", "kpeg.gemspec", "lib/hoe/kpeg.rb", "lib/kpeg.rb", "lib/kpeg/code_generator.rb", "lib/kpeg/compiled_parser.rb", "lib/kpeg/format_parser.kpeg", "lib/kpeg/format_parser.rb", "lib/kpeg/grammar.rb", "lib/kpeg/grammar_renderer.rb", "lib/kpeg/match.rb", "lib/kpeg/parser.rb", "lib/kpeg/position.rb", "lib/kpeg/string_escape.kpeg", "lib/kpeg/string_escape.rb", "test/inputs/comments.kpeg", "test/test_kpeg.rb", "test/test_kpeg_code_generator.rb", "test/test_kpeg_compiled_parser.rb", "test/test_kpeg_format.rb", "test/test_kpeg_format_parser_round_trip.rb", "test/test_kpeg_grammar.rb", "test/test_kpeg_grammar_renderer.rb", "vim/syntax_kpeg/ftdetect/kpeg.vim", "vim/syntax_kpeg/syntax/kpeg.vim", "test/test_kpeg_string_escape.rb", ".gemtest"]
|
16
16
|
s.homepage = "https://github.com/evanphx/kpeg"
|
17
|
+
s.licenses = ["MIT"]
|
17
18
|
s.rdoc_options = ["--main", "README.rdoc"]
|
18
19
|
s.require_paths = ["lib"]
|
19
20
|
s.rubyforge_project = "kpeg"
|
20
|
-
s.rubygems_version = "1.
|
21
|
-
s.signing_key = "/Users/drbrain/.gem/gem-private_key.pem"
|
21
|
+
s.rubygems_version = "2.1.10"
|
22
22
|
s.summary = "KPeg is a simple PEG library for Ruby"
|
23
|
-
s.test_files = ["test/
|
23
|
+
s.test_files = ["test/test_kpeg.rb", "test/test_kpeg_code_generator.rb", "test/test_kpeg_compiled_parser.rb", "test/test_kpeg_format.rb", "test/test_kpeg_format_parser_round_trip.rb", "test/test_kpeg_grammar.rb", "test/test_kpeg_grammar_renderer.rb", "test/test_kpeg_string_escape.rb"]
|
24
24
|
|
25
25
|
if s.respond_to? :specification_version then
|
26
|
-
s.specification_version =
|
26
|
+
s.specification_version = 4
|
27
27
|
|
28
28
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
29
|
-
s.add_development_dependency(%q<minitest>, ["~> 2
|
30
|
-
s.add_development_dependency(%q<rdoc>, ["~>
|
31
|
-
s.add_development_dependency(%q<hoe>, ["~>
|
29
|
+
s.add_development_dependency(%q<minitest>, ["~> 5.2"])
|
30
|
+
s.add_development_dependency(%q<rdoc>, ["~> 4.0"])
|
31
|
+
s.add_development_dependency(%q<hoe>, ["~> 3.7"])
|
32
32
|
else
|
33
|
-
s.add_dependency(%q<minitest>, ["~> 2
|
34
|
-
s.add_dependency(%q<rdoc>, ["~>
|
35
|
-
s.add_dependency(%q<hoe>, ["~>
|
33
|
+
s.add_dependency(%q<minitest>, ["~> 5.2"])
|
34
|
+
s.add_dependency(%q<rdoc>, ["~> 4.0"])
|
35
|
+
s.add_dependency(%q<hoe>, ["~> 3.7"])
|
36
36
|
end
|
37
37
|
else
|
38
|
-
s.add_dependency(%q<minitest>, ["~> 2
|
39
|
-
s.add_dependency(%q<rdoc>, ["~>
|
40
|
-
s.add_dependency(%q<hoe>, ["~>
|
38
|
+
s.add_dependency(%q<minitest>, ["~> 5.2"])
|
39
|
+
s.add_dependency(%q<rdoc>, ["~> 4.0"])
|
40
|
+
s.add_dependency(%q<hoe>, ["~> 3.7"])
|
41
41
|
end
|
42
42
|
end
|
data/lib/hoe/kpeg.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
# license:
|
11
11
|
#
|
12
12
|
# Copyright (c) Ryan Davis, seattle.rb
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# Permission is hereby granted, free of charge, to any person obtaining
|
15
15
|
# a copy of this software and associated documentation files (the
|
16
16
|
# "Software"), to deal in the Software without restriction, including
|
@@ -18,10 +18,10 @@
|
|
18
18
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
19
19
|
# permit persons to whom the Software is furnished to do so, subject to
|
20
20
|
# the following conditions:
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# The above copyright notice and this permission notice shall be
|
23
23
|
# included in all copies or substantial portions of the Software.
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
26
26
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
27
27
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
@@ -55,9 +55,10 @@ module Hoe::Kpeg
|
|
55
55
|
def initialize_kpeg
|
56
56
|
self.kpeg_tasks = [:multi, :test, :check_manifest]
|
57
57
|
|
58
|
-
# -
|
58
|
+
# -f = overwrite existing file
|
59
59
|
# -s = parser does not require runtime
|
60
|
-
|
60
|
+
# -v = verbose
|
61
|
+
self.kpeg_flags ||= "-s -v -f"
|
61
62
|
|
62
63
|
dependency 'kpeg', '~> 0.9', :development
|
63
64
|
end
|
data/lib/kpeg/code_generator.rb
CHANGED
@@ -83,18 +83,21 @@ module KPeg
|
|
83
83
|
|
84
84
|
if output_node
|
85
85
|
code << " end\n"
|
86
|
+
code << " module #{root}Construction\n"
|
86
87
|
methods.each do |short, name, attrs|
|
87
|
-
code << "
|
88
|
-
code << "
|
89
|
-
code << "
|
88
|
+
code << " def #{short}(#{attrs.join(', ')})\n"
|
89
|
+
code << " #{root}::#{name}.new(#{attrs.join(', ')})\n"
|
90
|
+
code << " end\n"
|
90
91
|
end
|
92
|
+
code << " end\n"
|
93
|
+
code << " include #{root}Construction\n"
|
91
94
|
end
|
92
95
|
end
|
93
|
-
|
96
|
+
|
94
97
|
def indentify(code, indent)
|
95
98
|
"#{" " * indent}#{code}"
|
96
99
|
end
|
97
|
-
|
100
|
+
|
98
101
|
# Default indent is 4 spaces (indent=2)
|
99
102
|
def output_op(code, op, indent=2)
|
100
103
|
case op
|
@@ -109,7 +112,7 @@ module KPeg
|
|
109
112
|
# Let default ruby string handling figure it out
|
110
113
|
lang = ""
|
111
114
|
end
|
112
|
-
code << indentify("_tmp = scan(/\\
|
115
|
+
code << indentify("_tmp = scan(/\\G#{op.regexp}/#{lang})\n", indent)
|
113
116
|
when CharRange
|
114
117
|
ss = save()
|
115
118
|
if op.start.bytesize == 1 and op.fin.bytesize == 1
|
@@ -124,7 +127,7 @@ module KPeg
|
|
124
127
|
left = op.start[0]
|
125
128
|
right = op.fin[0]
|
126
129
|
end
|
127
|
-
|
130
|
+
|
128
131
|
code << indentify(" unless _tmp >= #{left} and _tmp <= #{right}\n", indent)
|
129
132
|
code << indentify(" self.pos = #{ss}\n", indent)
|
130
133
|
code << indentify(" _tmp = nil\n", indent)
|
@@ -140,7 +143,7 @@ module KPeg
|
|
140
143
|
code << indentify("while true # choice\n", indent)
|
141
144
|
op.ops.each_with_index do |n,idx|
|
142
145
|
output_op code, n, (indent+1)
|
143
|
-
|
146
|
+
|
144
147
|
code << indentify(" break if _tmp\n", indent)
|
145
148
|
code << indentify(" self.pos = #{ss}\n", indent)
|
146
149
|
if idx == op.ops.size - 1
|
@@ -309,15 +312,23 @@ module KPeg
|
|
309
312
|
else
|
310
313
|
raise "Unknown op - #{op.class}"
|
311
314
|
end
|
312
|
-
|
313
315
|
end
|
314
316
|
|
315
|
-
def standalone_region(path)
|
316
|
-
|
317
|
-
|
318
|
-
|
317
|
+
def standalone_region(path, marker = "STANDALONE")
|
318
|
+
expanded_path = File.expand_path("../#{path}", __FILE__)
|
319
|
+
cp = File.read(expanded_path)
|
320
|
+
|
321
|
+
start_marker = "# #{marker} START"
|
322
|
+
end_marker = /^\s*# #{Regexp.escape marker} END/
|
323
|
+
|
324
|
+
start = cp.index(start_marker) + start_marker.length + 1 # \n
|
325
|
+
fin = cp.index(end_marker)
|
326
|
+
|
327
|
+
unless start and fin
|
328
|
+
abort("#{marker} boundaries in #{path} missing " \
|
329
|
+
"for standalone generation")
|
330
|
+
end
|
319
331
|
|
320
|
-
return nil unless start and fin
|
321
332
|
cp[start..fin]
|
322
333
|
end
|
323
334
|
|
@@ -326,37 +337,29 @@ module KPeg
|
|
326
337
|
|
327
338
|
code = []
|
328
339
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
end
|
340
|
+
output_header(code)
|
341
|
+
output_grammar(code)
|
342
|
+
output_footer(code)
|
333
343
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
unless cp = standalone_region(
|
338
|
-
File.expand_path("../compiled_parser.rb", __FILE__))
|
344
|
+
@output = code.join
|
345
|
+
end
|
339
346
|
|
340
|
-
|
341
|
-
|
342
|
-
end
|
347
|
+
##
|
348
|
+
# Output of class end and footer
|
343
349
|
|
344
|
-
|
345
|
-
|
346
|
-
puts "Standalone failure. Check position.rb for proper boundary comments"
|
347
|
-
end
|
350
|
+
def output_footer(code)
|
351
|
+
code << "end\n"
|
348
352
|
|
349
|
-
|
350
|
-
code <<
|
351
|
-
else
|
352
|
-
code << "require 'kpeg/compiled_parser'\n\n"
|
353
|
-
code << "class #{@name} < KPeg::CompiledParser\n"
|
353
|
+
if footer = @grammar.directives['footer']
|
354
|
+
code << footer.action
|
354
355
|
end
|
356
|
+
end
|
355
357
|
|
356
|
-
|
357
|
-
|
358
|
-
end
|
358
|
+
##
|
359
|
+
# Output of grammar and rules
|
359
360
|
|
361
|
+
def output_grammar(code)
|
362
|
+
code << " # :stopdoc:\n"
|
360
363
|
handle_ast(code)
|
361
364
|
|
362
365
|
fg = @grammar.foreign_grammars
|
@@ -418,24 +421,57 @@ module KPeg
|
|
418
421
|
|
419
422
|
code << "\n Rules = {}\n"
|
420
423
|
@grammar.rule_order.each do |name|
|
421
|
-
rule = @grammar.rules[name]
|
422
|
-
|
423
424
|
rend = GrammarRenderer.escape renderings[name], true
|
424
425
|
code << " Rules[:#{method_name name}] = rule_info(\"#{name}\", \"#{rend}\")\n"
|
425
426
|
end
|
426
427
|
|
427
|
-
code << "
|
428
|
+
code << " # :startdoc:\n"
|
429
|
+
end
|
428
430
|
|
429
|
-
|
430
|
-
|
431
|
+
##
|
432
|
+
# Output up to the user-defined setup actions
|
433
|
+
|
434
|
+
def output_header(code)
|
435
|
+
if header = @grammar.directives['header']
|
436
|
+
code << header.action.strip
|
437
|
+
code << "\n"
|
431
438
|
end
|
432
439
|
|
433
|
-
|
440
|
+
pre_class = @grammar.directives['pre-class']
|
441
|
+
|
442
|
+
if @standalone
|
443
|
+
if pre_class
|
444
|
+
code << pre_class.action.strip
|
445
|
+
code << "\n"
|
446
|
+
end
|
447
|
+
code << "class #{@name}\n"
|
448
|
+
|
449
|
+
cp = standalone_region("compiled_parser.rb")
|
450
|
+
cpi = standalone_region("compiled_parser.rb", "INITIALIZE")
|
451
|
+
pp = standalone_region("position.rb")
|
452
|
+
|
453
|
+
cp.gsub!(/^\s*include Position/, pp)
|
454
|
+
code << " # :stopdoc:\n"
|
455
|
+
code << cpi << "\n" unless @grammar.variables['custom_initialize']
|
456
|
+
code << cp << "\n"
|
457
|
+
code << " # :startdoc:\n"
|
458
|
+
else
|
459
|
+
code << "require 'kpeg/compiled_parser'\n\n"
|
460
|
+
if pre_class
|
461
|
+
code << pre_class.action.strip
|
462
|
+
code << "\n"
|
463
|
+
end
|
464
|
+
code << "class #{@name} < KPeg::CompiledParser\n"
|
465
|
+
end
|
466
|
+
|
467
|
+
@grammar.setup_actions.each do |act|
|
468
|
+
code << "\n#{act.action}\n\n"
|
469
|
+
end
|
434
470
|
end
|
435
471
|
|
436
472
|
def make(str)
|
437
473
|
m = Module.new
|
438
|
-
m.module_eval output
|
474
|
+
m.module_eval output, "(kpeg parser #{@name})"
|
439
475
|
|
440
476
|
cls = m.const_get(@name)
|
441
477
|
cls.new(str)
|
data/lib/kpeg/compiled_parser.rb
CHANGED
@@ -10,27 +10,33 @@ module KPeg
|
|
10
10
|
|
11
11
|
# Leave these markers in! They allow us to generate standalone
|
12
12
|
# code automatically!
|
13
|
-
|
13
|
+
|
14
|
+
# INITIALIZE START
|
15
|
+
|
16
|
+
# This is distinct from setup_parser so that a standalone parser
|
17
|
+
# can redefine #initialize and still have access to the proper
|
18
|
+
# parser setup code.
|
19
|
+
def initialize(str, debug=false)
|
20
|
+
setup_parser(str, debug)
|
21
|
+
end
|
22
|
+
|
23
|
+
# INITIALIZE END
|
24
|
+
|
14
25
|
# STANDALONE START
|
26
|
+
|
27
|
+
# Prepares for parsing +str+. If you define a custom initialize you must
|
28
|
+
# call this method before #parse
|
15
29
|
def setup_parser(str, debug=false)
|
16
|
-
|
17
|
-
@pos = 0
|
30
|
+
set_string str, 0
|
18
31
|
@memoizations = Hash.new { |h,k| h[k] = {} }
|
19
32
|
@result = nil
|
20
33
|
@failed_rule = nil
|
21
34
|
@failing_rule_offset = -1
|
35
|
+
@line_offsets = nil
|
22
36
|
|
23
37
|
setup_foreign_grammar
|
24
38
|
end
|
25
39
|
|
26
|
-
# This is distinct from setup_parser so that a standalone parser
|
27
|
-
# can redefine #initialize and still have access to the proper
|
28
|
-
# parser setup code.
|
29
|
-
#
|
30
|
-
def initialize(str, debug=false)
|
31
|
-
setup_parser(str, debug)
|
32
|
-
end
|
33
|
-
|
34
40
|
attr_reader :string
|
35
41
|
attr_reader :failing_rule_offset
|
36
42
|
attr_accessor :result, :pos
|
@@ -41,6 +47,13 @@ module KPeg
|
|
41
47
|
@string[start..@pos-1]
|
42
48
|
end
|
43
49
|
|
50
|
+
# Sets the string and current parsing position for the parser.
|
51
|
+
def set_string string, pos
|
52
|
+
@string = string
|
53
|
+
@string_size = string ? string.size : 0
|
54
|
+
@pos = pos
|
55
|
+
end
|
56
|
+
|
44
57
|
def show_pos
|
45
58
|
width = 10
|
46
59
|
if @pos < width
|
@@ -138,28 +151,27 @@ module KPeg
|
|
138
151
|
end
|
139
152
|
|
140
153
|
def scan(reg)
|
141
|
-
if m = reg.match(@string
|
142
|
-
|
143
|
-
@pos += width
|
154
|
+
if m = reg.match(@string, @pos)
|
155
|
+
@pos = m.end(0)
|
144
156
|
return true
|
145
157
|
end
|
146
158
|
|
147
159
|
return nil
|
148
160
|
end
|
149
161
|
|
150
|
-
if "".respond_to? :
|
162
|
+
if "".respond_to? :ord
|
151
163
|
def get_byte
|
152
|
-
if @pos >= @
|
164
|
+
if @pos >= @string_size
|
153
165
|
return nil
|
154
166
|
end
|
155
167
|
|
156
|
-
s = @string
|
168
|
+
s = @string[@pos].ord
|
157
169
|
@pos += 1
|
158
170
|
s
|
159
171
|
end
|
160
172
|
else
|
161
173
|
def get_byte
|
162
|
-
if @pos >= @
|
174
|
+
if @pos >= @string_size
|
163
175
|
return nil
|
164
176
|
end
|
165
177
|
|
@@ -208,8 +220,7 @@ module KPeg
|
|
208
220
|
old_pos = @pos
|
209
221
|
old_string = @string
|
210
222
|
|
211
|
-
|
212
|
-
@string = other.string
|
223
|
+
set_string other.string, other.pos
|
213
224
|
|
214
225
|
begin
|
215
226
|
if val = __send__(rule, *args)
|
@@ -220,15 +231,13 @@ module KPeg
|
|
220
231
|
end
|
221
232
|
val
|
222
233
|
ensure
|
223
|
-
|
224
|
-
@string = old_string
|
234
|
+
set_string old_string, old_pos
|
225
235
|
end
|
226
236
|
end
|
227
237
|
|
228
238
|
def apply_with_args(rule, *args)
|
229
239
|
memo_key = [rule, args]
|
230
240
|
if m = @memoizations[memo_key][@pos]
|
231
|
-
prev = @pos
|
232
241
|
@pos = m.pos
|
233
242
|
if !m.set
|
234
243
|
m.left_rec = true
|
@@ -256,14 +265,11 @@ module KPeg
|
|
256
265
|
else
|
257
266
|
return ans
|
258
267
|
end
|
259
|
-
|
260
|
-
return ans
|
261
268
|
end
|
262
269
|
end
|
263
270
|
|
264
271
|
def apply(rule)
|
265
272
|
if m = @memoizations[rule][@pos]
|
266
|
-
prev = @pos
|
267
273
|
@pos = m.pos
|
268
274
|
if !m.set
|
269
275
|
m.left_rec = true
|
@@ -291,8 +297,6 @@ module KPeg
|
|
291
297
|
else
|
292
298
|
return ans
|
293
299
|
end
|
294
|
-
|
295
|
-
return ans
|
296
300
|
end
|
297
301
|
end
|
298
302
|
|
data/lib/kpeg/format_parser.kpeg
CHANGED
@@ -1,14 +1,25 @@
|
|
1
1
|
%% name = KPeg::FormatParser
|
2
|
+
%% custom_initialize = true
|
3
|
+
|
4
|
+
%% pre-class {
|
5
|
+
require 'kpeg/grammar'
|
6
|
+
}
|
2
7
|
|
3
8
|
%% {
|
4
|
-
|
9
|
+
|
10
|
+
##
|
11
|
+
# Creates a new kpeg format parser for +str+.
|
5
12
|
|
6
13
|
def initialize(str, debug=false)
|
7
14
|
setup_parser(str, debug)
|
8
15
|
@g = KPeg::Grammar.new
|
9
16
|
end
|
10
17
|
|
18
|
+
##
|
19
|
+
# The parsed grammar
|
20
|
+
|
11
21
|
attr_reader :g
|
22
|
+
|
12
23
|
alias_method :grammar, :g
|
13
24
|
}
|
14
25
|
|
@@ -22,8 +33,8 @@
|
|
22
33
|
kleene = "*"
|
23
34
|
|
24
35
|
# Allow - by itself, but not at the beginning
|
25
|
-
var = < "-" | /[a-
|
26
|
-
method = < /[a-
|
36
|
+
var = < "-" | /[a-z][\w-]*/i > { text }
|
37
|
+
method = < /[a-z_]\w*/i > { text }
|
27
38
|
|
28
39
|
dbl_escapes = "n" { "\n" }
|
29
40
|
| "s" { " " }
|
@@ -39,7 +50,8 @@
|
|
39
50
|
| num_escapes
|
40
51
|
| < . > { text }
|
41
52
|
num_escapes = < /[0-7]{1,3}/ > { [text.to_i(8)].pack("U") }
|
42
|
-
| "x" < /[
|
53
|
+
| "x" < /[a-f\d]{2}/i > { [text.to_i(16)].pack("U") }
|
54
|
+
# TODO use /\h{2}/ after 1.8 support is dropped
|
43
55
|
dbl_seq = < /[^\\"]+/ > { text }
|
44
56
|
dbl_not_quote = ("\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }
|
45
57
|
dbl_string = "\"" dbl_not_quote:s "\"" { @g.str(s.join) }
|
@@ -55,17 +67,17 @@ sgl_escape_quote = "\\'" { "'" }
|
|
55
67
|
regexp = "/" not_slash:body "/" regexp_opts:opts
|
56
68
|
{ @g.reg body, opts }
|
57
69
|
|
58
|
-
char = < /[a-
|
70
|
+
char = < /[a-z\d]/i > { text }
|
59
71
|
char_range = "[" char:l "-" char:r "]" { @g.range(l,r) }
|
60
72
|
|
61
|
-
range_num = < /[1-9]
|
73
|
+
range_num = < /[1-9]\d*/ > { text }
|
62
74
|
range_elem = < range_num|kleene > { text }
|
63
75
|
mult_range = "[" - range_elem:l - "," - range_elem:r - "]"
|
64
76
|
{ [l == "*" ? nil : l.to_i, r == "*" ? nil : r.to_i] }
|
65
77
|
| "[" - range_num:e - "]" { [e.to_i, e.to_i] }
|
66
78
|
|
67
79
|
curly_block = curly
|
68
|
-
curly = "{" < (/[^{}"']+/ | string | curly)* > "}" { @g.action(text) }
|
80
|
+
curly = "{" < (spaces | /[^{}"']+/ | string | curly)* > "}" { @g.action(text) }
|
69
81
|
nested_paren = "(" (/[^()"']+/ | string | nested_paren)* ")"
|
70
82
|
|
71
83
|
value = value:v ":" var:n { @g.t(v,n) }
|
@@ -105,7 +117,7 @@ sgl_escape_quote = "\\'" { "'" }
|
|
105
117
|
| - var:n - { [n] }
|
106
118
|
statement = - var:v "(" args:a ")" - "=" - expression:o { @g.set(v, o, a) }
|
107
119
|
| - var:v - "=" - expression:o { @g.set(v, o) }
|
108
|
-
| - "%" var:name - "=" - < /[
|
120
|
+
| - "%" var:name - "=" - < /[:\w]+/ >
|
109
121
|
{ @g.add_foreign_grammar(name, text) }
|
110
122
|
| - "%%" - curly:act { @g.add_setup act }
|
111
123
|
| - "%%" - var:name - curly:act { @g.add_directive name, act }
|
@@ -117,8 +129,8 @@ sgl_escape_quote = "\\'" { "'" }
|
|
117
129
|
|
118
130
|
# These are a seperate set of rules used to parse an ast declaration
|
119
131
|
|
120
|
-
ast_constant = < /[A-Z]
|
121
|
-
ast_word = < /[
|
132
|
+
ast_constant = < /[A-Z]\w*/ > { text }
|
133
|
+
ast_word = < /[a-z_]\w*/i > { text }
|
122
134
|
|
123
135
|
ast_sp = (" " | "\t")*
|
124
136
|
|