packcr 0.0.8 → 0.1.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 +4 -4
- data/lib/packcr/context.rb +14 -5
- data/lib/packcr/generated/context.rb +189 -85
- data/lib/packcr/generated/node/action_node.rb +17 -0
- data/lib/packcr/generated/node/alternate_node.rb +52 -6
- data/lib/packcr/generated/node/capture_node.rb +15 -0
- data/lib/packcr/generated/node/charclass_node.rb +67 -0
- data/lib/packcr/generated/node/eof_node.rb +7 -0
- data/lib/packcr/generated/node/error_node.rb +7 -0
- data/lib/packcr/generated/node/expand_node.rb +7 -0
- data/lib/packcr/generated/node/predicate_node.rb +33 -0
- data/lib/packcr/generated/node/quantity_node.rb +54 -0
- data/lib/packcr/generated/node/reference_node.rb +14 -0
- data/lib/packcr/generated/node/rule_node.rb +31 -0
- data/lib/packcr/generated/node/sequence_node.rb +18 -0
- data/lib/packcr/generated/node/string_node.rb +24 -0
- data/lib/packcr/node/reference_node.rb +1 -0
- data/lib/packcr/node/rule_node.rb +2 -1
- data/lib/packcr/parser.rb +403 -254
- data/lib/packcr/stream.rb +1 -1
- data/lib/packcr/templates/context/source.c.erb +30 -26
- data/lib/packcr/templates/context/source.rb.erb +160 -159
- data/lib/packcr/templates/context/source.rs.erb +625 -0
- data/lib/packcr/templates/node/action.rs.erb +6 -0
- data/lib/packcr/templates/node/alternate.rs.erb +39 -0
- data/lib/packcr/templates/node/capture.rs.erb +13 -0
- data/lib/packcr/templates/node/charclass_utf8.rs.erb +41 -0
- data/lib/packcr/templates/node/predicate_neg.rs.erb +24 -0
- data/lib/packcr/templates/node/quantity_many.rs.erb +50 -0
- data/lib/packcr/templates/node/reference.rs.erb +3 -0
- data/lib/packcr/templates/node/rule.rs.erb +34 -0
- data/lib/packcr/templates/node/sequence.rs.erb +12 -0
- data/lib/packcr/templates/node/string_many.rs.erb +10 -0
- data/lib/packcr/templates/node/string_one.rs.erb +9 -0
- data/lib/packcr/util.rb +9 -0
- data/lib/packcr/version.rb +1 -1
- metadata +16 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1797f847b90f8c53e2745592691b7f7ae12a5e18a1861f25b7e84825278529d
|
4
|
+
data.tar.gz: f593a9234386b345f4af1de58467c31640ad2233918f3149f00d53c8df70c379
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba48fc2f71db11977fd9c1f12f520d639d9618383f08fcbe5b7e71930084f29f32e3fed2baac800ccedd8f3e50f026daf530636ebabd31e9bc682a4798e17b8e
|
7
|
+
data.tar.gz: 1cad26bb87e543e4404df9f5e491398655e3fdc36dbe50452a6805229c06db196ba7c2c2878e461e595321376f00c65110ccba78dad3474f8039991cdff0fd9b
|
data/lib/packcr/context.rb
CHANGED
@@ -40,9 +40,9 @@ class Packcr
|
|
40
40
|
get_header_code: @hname,
|
41
41
|
}
|
42
42
|
@hid = File.basename(@hname).upcase.gsub(/[^A-Z0-9]/, "_")
|
43
|
-
when :rb
|
43
|
+
when :rb, :rs
|
44
44
|
@patterns = {
|
45
|
-
get_source_code: "#{path}
|
45
|
+
get_source_code: "#{path}.#{@lang}",
|
46
46
|
}
|
47
47
|
else
|
48
48
|
raise "unexpected lang: #{@lang}"
|
@@ -96,6 +96,17 @@ class Packcr
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
def line_comment_code(line)
|
100
|
+
line = line.chomp
|
101
|
+
case @lang
|
102
|
+
when :c
|
103
|
+
line.gsub("*/", "* /")
|
104
|
+
"/* #{line} */"
|
105
|
+
when :rb
|
106
|
+
"# #{line}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
99
110
|
def class_name
|
100
111
|
prefix.gsub(/(?:_|^|(\W))([a-z])/) { "#{::Regexp.last_match(1)}#{::Regexp.last_match(2)}".upcase }
|
101
112
|
end
|
@@ -150,9 +161,7 @@ class Packcr
|
|
150
161
|
|
151
162
|
next if @errnum.zero?
|
152
163
|
|
153
|
-
results.
|
154
|
-
r.close
|
155
|
-
end
|
164
|
+
results.each_value(&:close)
|
156
165
|
return false
|
157
166
|
end
|
158
167
|
|
@@ -20,6 +20,8 @@ class Packcr
|
|
20
20
|
erbout << "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct #{prefix}_context_tag #{prefix}_context_t;\n\n#{prefix}_context_t *#{prefix}_create(#{auxil_def}auxil);\nint #{prefix}_parse(#{prefix}_context_t *ctx, #{value_def}*ret);\nvoid #{prefix}_destroy(#{prefix}_context_t *ctx);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* !PACKCR_INCLUDED_#{@hid} */\n".freeze
|
21
21
|
|
22
22
|
erbout
|
23
|
+
else
|
24
|
+
raise "unknown lang #{lang}"
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
@@ -29,10 +31,10 @@ class Packcr
|
|
29
31
|
erbout = +""
|
30
32
|
erbout << "/* A packrat parser generated by PackCR #{Packcr::VERSION} */\n\n".freeze
|
31
33
|
|
32
|
-
code(:esource).each do |code|
|
33
|
-
erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
|
34
|
-
end
|
35
34
|
if !code(:esource).empty?
|
35
|
+
code(:esource).each do |code|
|
36
|
+
erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
|
37
|
+
end
|
36
38
|
erbout << "\n".freeze
|
37
39
|
end
|
38
40
|
erbout << "#ifdef _MSC_VER\n#undef _CRT_SECURE_NO_WARNINGS\n#define _CRT_SECURE_NO_WARNINGS\n#endif /* _MSC_VER */\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifndef _MSC_VER\n#if defined __GNUC__ && defined _WIN32 /* MinGW */\n#ifndef PACKCR_USE_SYSTEM_STRNLEN\n#define strnlen(str, maxlen) packcr_strnlen(str, maxlen)\nstatic size_t packcr_strnlen(const char *str, size_t maxlen) {\n size_t i;\n for (i = 0; i < maxlen && str[i]; i++);\n return i;\n}\n#endif /* !PACKCR_USE_SYSTEM_STRNLEN */\n#endif /* defined __GNUC__ && defined _WIN32 */\n#endif /* !_MSC_VER */\n\n#include \"#{@hname}\"\n".freeze
|
@@ -191,7 +193,29 @@ class Packcr
|
|
191
193
|
if @location
|
192
194
|
erbout << " memo->offset_loc = ctx->position_offset_loc;\n".freeze
|
193
195
|
end
|
194
|
-
erbout << " }\n } else {\n c = packcr_get_rule_thunk_chunk(ctx, rule);\n }\n if (c == NULL) return PACKCR_FALSE;\n if (value == NULL) value = &null;\n memset(value, 0, sizeof(packcr_value_t)); /* in case */\n packcr_thunk_array__add(ctx->auxil, thunks, packcr_thunk__create_node(ctx->auxil, &c->thunks, value));\n return PACKCR_TRUE;\n}\n\nMARK_FUNC_AS_USED\nstatic void packcr_do_action(packcr_context_t *ctx, const packcr_thunk_array_t *thunks, packcr_value_t *value) {\n size_t i;\n for (i = 0; i < thunks->len; i++) {\n packcr_thunk_t *const thunk = thunks->buf[i];\n switch (thunk->type) {\n case PACKCR_THUNK_LEAF:\n thunk->data.leaf.action(ctx, thunk, value);\n break;\n case PACKCR_THUNK_NODE:\n packcr_do_action(ctx, thunk->data.node.thunks, thunk->data.node.value);\n break;\n default: /* unknown */\n break;\n }\n }\n}\n\n".freeze
|
196
|
+
erbout << " }\n } else {\n c = packcr_get_rule_thunk_chunk(ctx, rule);\n }\n if (c == NULL) return PACKCR_FALSE;\n if (value == NULL) value = &null;\n memset(value, 0, sizeof(packcr_value_t)); /* in case */\n packcr_thunk_array__add(ctx->auxil, thunks, packcr_thunk__create_node(ctx->auxil, &c->thunks, value));\n return PACKCR_TRUE;\n}\n\nMARK_FUNC_AS_USED\nstatic void packcr_do_action(packcr_context_t *ctx, const packcr_thunk_array_t *thunks, packcr_value_t *value) {\n size_t i;\n for (i = 0; i < thunks->len; i++) {\n packcr_thunk_t *const thunk = thunks->buf[i];\n switch (thunk->type) {\n case PACKCR_THUNK_LEAF:\n thunk->data.leaf.action(ctx, thunk, value);\n break;\n case PACKCR_THUNK_NODE:\n packcr_do_action(ctx, thunk->data.node.thunks, thunk->data.node.value);\n break;\n default: /* unknown */\n break;\n }\n }\n}\n\n#{prefix}_context_t *#{prefix}_create(#{auxil_def}auxil) {\n return packcr_context__create(auxil);\n}\n\nvoid #{prefix}_destroy(#{prefix}_context_t *ctx) {\n packcr_context__destroy(ctx);\n}\n".freeze
|
197
|
+
|
198
|
+
if !@root.rules.empty?
|
199
|
+
erbout << "\n".freeze
|
200
|
+
|
201
|
+
@root.rules.each do |rule|
|
202
|
+
erbout << "static packcr_thunk_chunk_t *packcr_evaluate_rule_#{rule.name}(packcr_context_t *ctx, size_t offset".freeze
|
203
|
+
if @location
|
204
|
+
erbout << ", packcr_location_t offset_loc".freeze
|
205
|
+
end
|
206
|
+
erbout << ", packcr_rule_set_t *limits);\n".freeze
|
207
|
+
end
|
208
|
+
end
|
209
|
+
erbout << "\nint #{prefix}_parse(#{prefix}_context_t *ctx, #{value_def}*ret) {\n size_t pos = ctx->buffer_start_position;\n".freeze
|
210
|
+
|
211
|
+
if !@root.rules.empty?
|
212
|
+
erbout << " if (packcr_apply_rule(ctx, packcr_evaluate_rule_#{@root.rules[0].name}, &ctx->thunks, ret, ctx->position_offset".freeze
|
213
|
+
if @location
|
214
|
+
erbout << ", ctx->position_offset_loc".freeze
|
215
|
+
end
|
216
|
+
erbout << ", NULL))\n packcr_do_action(ctx, &ctx->thunks, ret);\n else\n PACKCR_ERROR(ctx->auxil);\n packcr_commit_buffer(ctx);\n".freeze
|
217
|
+
end
|
218
|
+
erbout << " packcr_thunk_array__revert(ctx->auxil, &ctx->thunks, 0);\n return pos != ctx->buffer_start_position && packcr_refill_buffer(ctx, 1) >= 1;\n}\n\n".freeze
|
195
219
|
|
196
220
|
@root.rules.each do |rule|
|
197
221
|
rule.codes.each do |code|
|
@@ -233,30 +257,12 @@ class Packcr
|
|
233
257
|
erbout << "#undef __\n#undef auxil\n}\n\n".freeze
|
234
258
|
end
|
235
259
|
end
|
236
|
-
@root.rules.each do |rule|
|
237
|
-
erbout << "static packcr_thunk_chunk_t *packcr_evaluate_rule_#{rule.name}(packcr_context_t *ctx, size_t offset".freeze
|
238
|
-
if @location
|
239
|
-
erbout << ", packcr_location_t offset_loc".freeze
|
240
|
-
end
|
241
|
-
erbout << ", packcr_rule_set_t *limits);\n".freeze
|
242
|
-
end
|
243
260
|
erbout << "\n".freeze
|
244
261
|
|
245
262
|
@root.rules.each do |rule|
|
246
263
|
gen = ::Packcr::Generator.new(rule, @ascii, @location)
|
247
264
|
erbout << "#{gen.generate_code(rule, 0, 0, false)}\n".freeze
|
248
265
|
end
|
249
|
-
erbout << "#{prefix}_context_t *#{prefix}_create(#{auxil_def}auxil) {\n return packcr_context__create(auxil);\n}\n\nint #{prefix}_parse(#{prefix}_context_t *ctx, #{value_def}*ret) {\n size_t pos = ctx->buffer_start_position;\n".freeze
|
250
|
-
|
251
|
-
if !@root.rules.empty?
|
252
|
-
erbout << " if (packcr_apply_rule(ctx, packcr_evaluate_rule_#{@root.rules[0].name}, &ctx->thunks, ret, ctx->position_offset".freeze
|
253
|
-
if @location
|
254
|
-
erbout << ", ctx->position_offset_loc".freeze
|
255
|
-
end
|
256
|
-
erbout << ", NULL))\n packcr_do_action(ctx, &ctx->thunks, ret);\n else\n PACKCR_ERROR(ctx->auxil);\n packcr_commit_buffer(ctx);\n".freeze
|
257
|
-
end
|
258
|
-
erbout << " packcr_thunk_array__revert(ctx->auxil, &ctx->thunks, 0);\n return pos != ctx->buffer_start_position && packcr_refill_buffer(ctx, 1) >= 1;\n}\n\nvoid #{prefix}_destroy(#{prefix}_context_t *ctx) {\n packcr_context__destroy(ctx);\n}\n".freeze
|
259
|
-
|
260
266
|
if !code(:lsource).empty?
|
261
267
|
erbout << "\n".freeze
|
262
268
|
|
@@ -267,14 +273,13 @@ class Packcr
|
|
267
273
|
erbout
|
268
274
|
when :rb
|
269
275
|
erbout = +""
|
270
|
-
erbout << "# A packrat parser generated by PackCR #{Packcr::VERSION}\n".freeze
|
276
|
+
erbout << "# A packrat parser generated by PackCR #{Packcr::VERSION}\n\n".freeze
|
271
277
|
|
272
278
|
if !code(:esource).empty?
|
273
|
-
erbout << "\n".freeze
|
274
|
-
|
275
279
|
code(:esource).each do |code|
|
276
280
|
erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
|
277
281
|
end
|
282
|
+
erbout << "\n".freeze
|
278
283
|
end
|
279
284
|
erbout << "class #{class_name}\n".freeze
|
280
285
|
|
@@ -284,7 +289,40 @@ class Packcr
|
|
284
289
|
code(:source).each do |code|
|
285
290
|
erbout << " #{stream.get_code_block(code, 2, @iname)}\n".freeze
|
286
291
|
end
|
287
|
-
erbout << " def initialize(".freeze
|
292
|
+
erbout << " class LrMemoTable\n def initialize\n @memos = {}\n end\n\n def clear\n @memos.clear\n end\n\n def []=(index, rule_name, memo)\n entry = @memos[index] ||= {}\n entry[rule_name] = memo\n end\n\n def [](index, rule_name)\n @memos.dig(index, rule_name)\n end\n end\n\n class LrMemo\n attr_accessor :grow, :answer, :offset, :fail\n".freeze
|
293
|
+
|
294
|
+
if @location
|
295
|
+
erbout << " attr_accessor :offset_loc\n".freeze
|
296
|
+
end
|
297
|
+
erbout << "\n def initialize(offset".freeze
|
298
|
+
if @location
|
299
|
+
erbout << ", offset_loc".freeze
|
300
|
+
end
|
301
|
+
erbout << ")\n @offset = offset\n".freeze
|
302
|
+
|
303
|
+
if @location
|
304
|
+
erbout << " @offset_loc = offset_loc\n".freeze
|
305
|
+
end
|
306
|
+
erbout << " @fail = true\n @grow = false\n end\n\n def answer=(answer)\n @fail = nil\n @answer = answer\n end\n end\n\n class ThunkChunk\n attr_accessor :thunks, :capts, :pos, :values\n".freeze
|
307
|
+
|
308
|
+
if @location
|
309
|
+
erbout << " attr_accessor :pos_loc\n".freeze
|
310
|
+
end
|
311
|
+
erbout << "\n def initialize\n super\n @thunks = []\n @capts = {}\n @pos = 0\n @values = {}\n end\n\n def resize_captures(len)\n len.times do |i|\n @capts[i] = Capture.new\n end\n end\n end\n\n class ThunkLeaf\n attr_accessor :capt0, :capts, :value_refs, :action\n\n def initialize(action, capt0 = Capture.new, value_refs = {}, capts = {})\n @value_refs = value_refs\n @capts = capts\n @capt0 = capt0\n @action = action\n end\n\n def do_action(ctx, values, index)\n ctx.public_send(action, self, values, index)\n end\n end\n\n class ThunkNode\n attr_accessor :thunks, :values, :index\n\n def initialize(thunks, values, index)\n @thunks = thunks\n @values = values\n @index = index\n values[index] ||= Value.new if values\n end\n\n def do_action(ctx, _values, _index)\n @thunks.each do |thunk|\n thunk.do_action(ctx, @values, @index)\n end\n end\n\n def clear\n @thunks.clear\n end\n end\n\n class Capture\n attr_accessor :range_start, :range_end\n".freeze
|
312
|
+
|
313
|
+
if @location
|
314
|
+
erbout << " attr_accessor :start_loc, :end_loc\n".freeze
|
315
|
+
end
|
316
|
+
erbout << "\n def initialize(range_start = 0, range_end = 0".freeze
|
317
|
+
if @location
|
318
|
+
erbout << ", start_loc = nil, end_loc = nil".freeze
|
319
|
+
end
|
320
|
+
erbout << ")\n @range_start = range_start\n @range_end = range_end\n".freeze
|
321
|
+
|
322
|
+
if @location
|
323
|
+
erbout << " @start_loc = start_loc || Location.new\n @end_loc = end_loc || Location.new\n".freeze
|
324
|
+
end
|
325
|
+
erbout << " end\n\n def capture_string(buffer)\n @capture_string ||= buffer[@range_start, @range_end - @range_start]\n end\n end\n\n class Value\n attr_accessor :value\n end\n\n def initialize(".freeze
|
288
326
|
if @auxil_type
|
289
327
|
erbout << "#{auxil_type}, ".freeze
|
290
328
|
end
|
@@ -326,43 +364,7 @@ class Packcr
|
|
326
364
|
end
|
327
365
|
erbout << ")\n @thunk.do_action(self, nil, 0)\n else\n raise SyntaxError, \"can't parse\"\n end\n commit_buffer\n".freeze
|
328
366
|
end
|
329
|
-
erbout << " @thunk.clear\n refill_buffer(1) >= 1 && pos != @buffer_start_position\n end\n\n def run\n nil while parse\n end\n\n".freeze
|
330
|
-
|
331
|
-
@root.rules.each do |rule|
|
332
|
-
rule.codes.each do |code|
|
333
|
-
erbout << " def action_#{rule.name}_#{code.index}(__packcr_in, __packcr_vars, __packcr_index)\n ____ = (__packcr_vars[__packcr_index] ||= Value.new).value if __packcr_vars\n".freeze
|
334
|
-
|
335
|
-
code.vars.each do |ref|
|
336
|
-
erbout << " #{ref.var} = (__packcr_in.value_refs[#{ref.index}] ||= Value.new).value\n".freeze
|
337
|
-
end
|
338
|
-
erbout << " __0 = __packcr_in.capt0.capture_string(@buffer)\n __0s = @buffer_start_position + __packcr_in.capt0.range_start\n __0e = @buffer_start_position + __packcr_in.capt0.range_end\n".freeze
|
339
|
-
|
340
|
-
if @location
|
341
|
-
erbout << " __0sl = @buffer_start_position_loc + __packcr_in.capt0.start_loc\n __0el = @buffer_start_position_loc + __packcr_in.capt0.end_loc\n".freeze
|
342
|
-
end
|
343
|
-
if @capture_in_code
|
344
|
-
erbout << " __0c = __packcr_in.capt0\n".freeze
|
345
|
-
end
|
346
|
-
code.capts.each do |capture|
|
347
|
-
erbout << " __#{capture.index + 1} = __packcr_in.capts[#{capture.index}].capture_string(@buffer)\n __#{capture.index + 1}s = @buffer_start_position + __packcr_in.capts[#{capture.index}].range_start\n __#{capture.index + 1}e = @buffer_start_position + __packcr_in.capts[#{capture.index}].range_end\n".freeze
|
348
|
-
|
349
|
-
if @location
|
350
|
-
erbout << " __#{capture.index + 1}sl = @buffer_start_position_loc + __packcr_in.capts[#{capture.index}].start_loc\n __#{capture.index + 1}el = @buffer_start_position_loc + __packcr_in.capts[#{capture.index}].end_loc\n".freeze
|
351
|
-
end
|
352
|
-
next unless @capture_in_code
|
353
|
-
|
354
|
-
erbout << " __#{capture.index + 1}c = __packcr_in.capts[#{capture.index}]\n".freeze
|
355
|
-
end
|
356
|
-
|
357
|
-
erbout << "#{stream.get_code_block(code.code, 4, @iname)}\n __packcr_vars[__packcr_index].value = ____ if __packcr_vars\n end\n\n".freeze
|
358
|
-
end
|
359
|
-
end
|
360
|
-
@root.rules.each do |rule|
|
361
|
-
gen = ::Packcr::Generator.new(rule, @ascii, @location, :rb)
|
362
|
-
|
363
|
-
erbout << "#{gen.generate_code(rule, 0, 2, false)}\n".freeze
|
364
|
-
end
|
365
|
-
erbout << " def grow_lr(rule, offset".freeze
|
367
|
+
erbout << " @thunk.clear\n refill_buffer(1) >= 1 && pos != @buffer_start_position\n end\n\n def run\n nil while parse\n end\n\n def grow_lr(rule, offset".freeze
|
366
368
|
if @location
|
367
369
|
erbout << ", offset_loc".freeze
|
368
370
|
end
|
@@ -434,40 +436,140 @@ class Packcr
|
|
434
436
|
if @location
|
435
437
|
erbout << " memo.offset_loc = @position_offset_loc\n".freeze
|
436
438
|
end
|
437
|
-
erbout << " end\n else\n answer = rule_answer(rule)\n end\n\n if !answer\n return false\n end\n values ||= @global_values\n thunks << ThunkNode.new(answer.thunks, values, index)\n return true\n end\n\n def do_action(thunks, values, index)\n thunks.each do |thunk|\n thunk.do_action(self, values, index)\n end\n end\n
|
439
|
+
erbout << " end\n else\n answer = rule_answer(rule)\n end\n\n if !answer\n return false\n end\n values ||= @global_values\n thunks << ThunkNode.new(answer.thunks, values, index)\n return true\n end\n\n def do_action(thunks, values, index)\n thunks.each do |thunk|\n thunk.do_action(self, values, index)\n end\n end\n".freeze
|
438
440
|
|
439
|
-
|
440
|
-
|
441
|
+
@root.rules.each do |rule|
|
442
|
+
rule.codes.each do |code|
|
443
|
+
erbout << "\n def action_#{rule.name}_#{code.index}(__packcr_in, __packcr_vars, __packcr_index)\n ____ = (__packcr_vars[__packcr_index] ||= Value.new).value if __packcr_vars\n".freeze
|
444
|
+
|
445
|
+
code.vars.each do |ref|
|
446
|
+
erbout << " #{ref.var} = (__packcr_in.value_refs[#{ref.index}] ||= Value.new).value\n".freeze
|
447
|
+
end
|
448
|
+
erbout << " __0 = __packcr_in.capt0.capture_string(@buffer)\n __0s = @buffer_start_position + __packcr_in.capt0.range_start\n __0e = @buffer_start_position + __packcr_in.capt0.range_end\n".freeze
|
449
|
+
|
450
|
+
if @location
|
451
|
+
erbout << " __0sl = @buffer_start_position_loc + __packcr_in.capt0.start_loc\n __0el = @buffer_start_position_loc + __packcr_in.capt0.end_loc\n".freeze
|
452
|
+
end
|
453
|
+
if @capture_in_code
|
454
|
+
erbout << " __0c = __packcr_in.capt0\n".freeze
|
455
|
+
end
|
456
|
+
code.capts.each do |capture|
|
457
|
+
erbout << " __#{capture.index + 1} = __packcr_in.capts[#{capture.index}].capture_string(@buffer)\n __#{capture.index + 1}s = @buffer_start_position + __packcr_in.capts[#{capture.index}].range_start\n __#{capture.index + 1}e = @buffer_start_position + __packcr_in.capts[#{capture.index}].range_end\n".freeze
|
458
|
+
|
459
|
+
if @location
|
460
|
+
erbout << " __#{capture.index + 1}sl = @buffer_start_position_loc + __packcr_in.capts[#{capture.index}].start_loc\n __#{capture.index + 1}el = @buffer_start_position_loc + __packcr_in.capts[#{capture.index}].end_loc\n".freeze
|
461
|
+
end
|
462
|
+
next unless @capture_in_code
|
463
|
+
|
464
|
+
erbout << " __#{capture.index + 1}c = __packcr_in.capts[#{capture.index}]\n".freeze
|
465
|
+
end
|
466
|
+
|
467
|
+
erbout << "#{stream.get_code_block(code.code, 4, @iname)}\n __packcr_vars[__packcr_index].value = ____ if __packcr_vars\n end\n".freeze
|
468
|
+
end
|
441
469
|
end
|
442
|
-
|
443
|
-
|
444
|
-
|
470
|
+
@root.rules.each do |rule|
|
471
|
+
erbout << "\n".freeze
|
472
|
+
|
473
|
+
gen = ::Packcr::Generator.new(rule, @ascii, @location, :rb)
|
474
|
+
|
475
|
+
erbout << "#{gen.generate_code(rule, 0, 2, false)}".freeze
|
445
476
|
end
|
446
|
-
erbout << "
|
477
|
+
erbout << "end\n".freeze
|
447
478
|
|
448
|
-
if
|
449
|
-
erbout << "
|
479
|
+
if !code(:lsource).empty?
|
480
|
+
erbout << "\n".freeze
|
481
|
+
|
482
|
+
code(:lsource).each do |code|
|
483
|
+
erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
|
484
|
+
end
|
450
485
|
end
|
451
|
-
erbout
|
486
|
+
erbout
|
487
|
+
when :rs
|
488
|
+
erbout = +""
|
489
|
+
erbout << "/* A packrat parser generated by PackCR #{Packcr::VERSION} */\n\nuse std::cell::RefCell;\nuse std::collections::{HashMap, HashSet};\nuse std::io::Read;\nuse std::rc::Rc;\n\n".freeze
|
452
490
|
|
453
|
-
if
|
454
|
-
erbout << "
|
491
|
+
if !code(:esource).empty?
|
492
|
+
erbout << "\n".freeze
|
493
|
+
|
494
|
+
code(:esource).each do |code|
|
495
|
+
erbout << "#{stream.get_code_block(code, 0, @iname)}".freeze
|
496
|
+
end
|
455
497
|
end
|
456
|
-
|
498
|
+
use_value = @root.rules.map { |r| r.vars.size }.max > 0
|
499
|
+
erbout << "\nstruct LrMemoTable {\n memos: HashMap<usize, LrMemoMap>,\n}\nimpl LrMemoTable {\n fn new() -> Self {\n Self {\n memos: HashMap::new(),\n }\n }\n\n fn clear(&mut self) {\n self.memos.clear();\n }\n\n fn set(&mut self, index: usize, rule: Rule, memo: LrMemo) {\n let memo_map = self.memos.entry(index).or_default();\n memo_map.insert(rule, memo);\n }\n\n fn get(&mut self, index: usize, rule: Rule) -> &mut LrMemo {\n self.memos.get_mut(&index).unwrap().get_mut(&rule).unwrap()\n }\n fn has(&mut self, index: usize, rule: Rule) -> bool {\n let memo_opt = self.memos.get_mut(&index);\n if memo_opt.is_none() {\n return false;\n }\n memo_opt.unwrap().contains_key(&rule)\n }\n}\n\nstruct LrMemo {\n offset: usize,\n answer: Option<Rc<RefCell<ThunkChunk>>>,\n grow: bool,\n}\n\nimpl LrMemo {\n fn new(offset: usize) -> Self {\n Self {\n offset,\n answer: None,\n grow: false,\n }\n }\n\n fn start_grow(&mut self) -> bool {\n if self.grow || self.answer.is_some() {\n return false;\n }\n self.answer = None;\n self.grow = true;\n true\n }\n\n fn start_match(&mut self, answer: Option<ThunkChunk>, offset: usize) {\n self.answer = answer.map(|c| Rc::new(RefCell::new(c)));\n self.offset = offset;\n }\n\n fn answer_as_deref_mut(&mut self) -> Option<Rc<RefCell<ThunkChunk>>> {\n self.answer.as_ref()?;\n self.answer.as_ref().map(Rc::clone)\n }\n}\n\nstruct ThunkChunk {\n thunks: Rc<RefCell<Vec<Thunk>>>,\n capts: CaptureTable,\n pos: usize,\n values: ValueTable,\n}\n\nimpl ThunkChunk {\n fn new(pos: usize) -> Self {\n Self {\n values: ValueTable::new(),\n capts: CaptureTable::new(),\n thunks: Rc::new(RefCell::new(Vec::new())),\n pos,\n }\n }\n\n fn push_leaf(\n &self,\n action: Action,\n end: usize,\n value_indices: &[usize],\n capt_indices: &[usize],\n ) {\n {\n let start = self.pos;\n let mut value_refs = HashMap::new();\n for &index in value_indices {\n value_refs.insert(index, ValueRef::new(index, self.values.clone()));\n }\n let mut capts = HashMap::new();\n for &index in capt_indices {\n capts.insert(index, self.capts[index].clone());\n }\n let leaf = Thunk::Leaf(ThunkLeaf::new(action, start, end, value_refs, capts));\n self.thunks.borrow_mut().push(leaf);\n }\n }\n\n fn value_ref(&self, index: usize) -> ValueRef {\n ValueRef::new(index, self.values.clone())\n }\n}\n\nenum Thunk {\n Leaf(ThunkLeaf),\n Node(ThunkNode),\n}\nimpl Thunk {\n fn do_action(&self, processor: &ThunkProcessor, value: ValueRef) {\n match self {\n Thunk::Leaf(leaf) => leaf.do_action(processor, value),\n Thunk::Node(node) => node.do_action(processor),\n }\n }\n}\n\n#[allow(dead_code)]\nstruct ThunkLeaf {\n value_refs: HashMap<usize, ValueRef>,\n capts: HashMap<usize, Capture>,\n capt0: Capture,\n action: Action,\n}\nimpl ThunkLeaf {\n fn new(\n action: Action,\n start: usize,\n end: usize,\n value_refs: HashMap<usize, ValueRef>,\n capts: HashMap<usize, Capture>,\n ) -> Self {\n Self {\n value_refs,\n capts,\n capt0: Capture { start, end },\n action,\n }\n }\n\n fn do_action(&self, processor: &ThunkProcessor, mut value: ValueRef) {\n value.with_mut(|v| {\n processor.call_action(self.action, self, v);\n });\n }\n".freeze
|
457
500
|
|
458
|
-
if
|
459
|
-
erbout << "
|
501
|
+
if use_value
|
502
|
+
erbout << "\n fn values(&self) -> HashMap<usize, Value> {\n self.value_refs.iter().map(|(k, v)| (*k, v.get())).collect()\n }\n".freeze
|
460
503
|
end
|
461
|
-
erbout << "\n
|
462
|
-
|
463
|
-
|
504
|
+
erbout << "}\n\nstruct ThunkNode {\n thunks: Rc<RefCell<Vec<Thunk>>>,\n value: ValueRef,\n}\nimpl ThunkNode {\n fn do_action(&self, processor: &ThunkProcessor) {\n for thunk in self.thunks.borrow().iter() {\n thunk.do_action(processor, self.value.clone());\n }\n }\n}\n\n#[derive(Clone)]\nstruct Capture {\n start: usize,\n end: usize,\n}\n\ntype Value = i32;\n\nstruct ValueTable {\n table: Rc<RefCell<HashMap<usize, Value>>>,\n}\nimpl ValueTable {\n fn new() -> Self {\n Self {\n table: Rc::new(RefCell::new(HashMap::new())),\n }\n }\n".freeze
|
505
|
+
|
506
|
+
if use_value
|
507
|
+
erbout << "\n fn clear(&mut self) {\n self.table.borrow_mut().clear();\n }\n".freeze
|
464
508
|
end
|
465
|
-
erbout << ")\n
|
509
|
+
erbout << "\n fn with_mut<F>(&mut self, index: usize, f: F)\n where\n F: FnOnce(&mut Value),\n {\n let mut table = self.table.borrow_mut();\n let value = table.entry(index).or_insert(0);\n f(value);\n }\n}\nimpl Clone for ValueTable {\n fn clone(&self) -> Self {\n Self {\n table: self.table.clone(),\n }\n }\n}\n\nstruct ValueRef {\n values: ValueTable,\n index: usize,\n}\nimpl ValueRef {\n fn new(index: usize, values: ValueTable) -> Self {\n Self { index, values }\n }\n\n fn with_mut<F>(&mut self, f: F)\n where\n F: FnOnce(&mut i32),\n {\n self.values.with_mut(self.index, f);\n }\n\n".freeze
|
466
510
|
|
467
|
-
if
|
468
|
-
erbout << "
|
511
|
+
if use_value
|
512
|
+
erbout << " fn get(&self) -> i32 {\n *self.values.table.borrow().get(&self.index).unwrap_or(&0)\n }\n".freeze
|
513
|
+
end
|
514
|
+
erbout << "}\nimpl Clone for ValueRef {\n fn clone(&self) -> Self {\n Self {\n index: self.index,\n values: self.values.clone(),\n }\n }\n}\n\nstruct CaptureTable {\n table: HashMap<usize, Capture>,\n len: usize,\n}\n\ntype RuleSet = HashSet<Rule>;\n\ntype LrMemoMap = HashMap<Rule, LrMemo>;\n\nimpl CaptureTable {\n fn new() -> Self {\n Self {\n table: HashMap::new(),\n len: 0,\n }\n }\n\n fn resize(&mut self, len: usize) {\n let current_len = self.len;\n if len > current_len {\n for i in current_len..len {\n self.table.insert(i, Capture { start: 0, end: 0 });\n }\n } else if len < current_len {\n for i in len..current_len {\n self.table.remove(&i);\n }\n }\n self.len = len;\n }\n}\nimpl std::ops::Index<usize> for CaptureTable {\n type Output = Capture;\n\n fn index(&self, index: usize) -> &Self::Output {\n &self.table[&index]\n }\n}\nimpl std::ops::IndexMut<usize> for CaptureTable {\n fn index_mut(&mut self, index: usize) -> &mut Self::Output {\n if self.len <= index {\n self.resize(index + 1);\n }\n self.table.get_mut(&index).unwrap()\n }\n}\n\nstruct Input {\n input: Box<dyn std::io::Read>,\n start_position: usize,\n position_offset: usize,\n buffer: String,\n}\n\nimpl Input {\n fn new(input: impl std::io::Read + 'static) -> Self {\n Self {\n input: Box::new(input),\n start_position: 0,\n position_offset: 0,\n buffer: String::new(),\n }\n }\n\n fn refill_buffer(&mut self, num: usize) -> usize {\n let mut len = self.buffer.len();\n if len >= self.position_offset + num {\n return len - self.position_offset;\n }\n\n let mut input_buffer = [0u8; 1024];\n\n while len < self.position_offset + num {\n match self.input.read(&mut input_buffer) {\n Ok(0) => break,\n Ok(bytes_read) => {\n let s = std::string::String::from_utf8_lossy(&input_buffer[..bytes_read]);\n self.buffer.push_str(&s);\n }\n Err(_) => break,\n }\n len = self.buffer.len();\n }\n\n len - self.position_offset\n }\n\n fn commit_buffer(&mut self) {\n let position_offset = self.position_offset;\n\n self.buffer.drain(..position_offset);\n\n self.start_position += position_offset;\n self.position_offset = 0;\n }\n\n #[allow(dead_code)]\n fn get_char_as_utf32(&mut self) -> (i32, usize) {\n if self.refill_buffer(1) < 1 {\n return (0, 0);\n }\n\n let current_position = self.position_offset;\n let remaining_chars: &str = &self.buffer[current_position..];\n\n if let Some(ch) = remaining_chars.chars().next() {\n let bytes_used = ch.len_utf8();\n\n if self.refill_buffer(bytes_used) < bytes_used {\n return (0, 0);\n }\n\n let utf32_value = ch as u32 as i32;\n\n return (utf32_value, bytes_used);\n }\n\n (0, 0)\n }\n\n fn back_to(&mut self, memo: &mut LrMemo) -> Option<Rc<RefCell<ThunkChunk>>> {\n self.position_offset = memo.offset;\n memo.answer_as_deref_mut()\n }\n}\n\nstruct #{class_name} {\n level: usize,\n memos: LrMemoTable,\n input: Input,\n}\n\nimpl #{class_name} {\n fn new(input: impl std::io::Read + 'static) -> Self {\n Self {\n level: 0,\n memos: LrMemoTable::new(),\n input: Input::new(input),\n }\n }\n\n fn error(&self) -> ! {\n eprintln!(\"Syntax error\");\n std::process::exit(1);\n }\n\n fn refill_buffer(&mut self, num: usize) -> usize {\n self.input.refill_buffer(num)\n }\n\n fn commit_buffer(&mut self) {\n self.input.commit_buffer();\n self.memos.clear();\n }\n\n fn parse(&mut self) -> bool {\n let mut answer = ThunkChunk::new(0);\n let pos = self.input.start_position;\n\n".freeze
|
515
|
+
|
516
|
+
if !@root.rules.empty?
|
517
|
+
erbout << " let apply_result = self.apply_rule(\n Rule::#{Packcr.camelize(@root.rules[0].name)},\n &mut answer,\n 0,\n self.input.position_offset,\n None,\n );\n\n if apply_result {\n if let Thunk::Node(node) = answer.thunks.borrow_mut().last().unwrap() {\n node.do_action(&ThunkProcessor::new(&self.input.buffer));\n }\n } else {\n self.error();\n }\n\n".freeze
|
518
|
+
end
|
519
|
+
erbout << " self.commit_buffer();\n pos != self.input.start_position && self.refill_buffer(1) >= 1\n }\n\n #[allow(dead_code)]\n fn get_char_as_utf32(&mut self) -> (i32, usize) {\n self.input.get_char_as_utf32()\n }\n\n fn grow_lr(&mut self, rule: Rule, offset: usize) {\n loop {\n let old_offset = self.input.position_offset;\n self.input.position_offset = offset;\n\n let answer = self.call_rule(rule, offset, Some(RuleSet::new()));\n if answer.is_none() || self.input.position_offset <= old_offset {\n return;\n }\n\n let memo = self.memos.get(offset, rule);\n memo.start_match(answer, self.input.position_offset);\n }\n }\n\n fn rule_answer(&mut self, rule: Rule) -> Option<Rc<RefCell<ThunkChunk>>> {\n let offset = self.input.position_offset;\n if !self.memos.has(offset, rule) {\n let memo = LrMemo::new(offset);\n self.memos.set(offset, rule, memo);\n let answer = self.call_rule(rule, offset, None);\n\n let memo = self.memos.get(offset, rule);\n memo.start_match(answer, self.input.position_offset);\n if !memo.grow {\n return self.input.back_to(memo);\n }\n self.grow_lr(rule, offset);\n\n let memo = self.memos.get(offset, rule);\n memo.grow = false;\n return self.input.back_to(memo);\n }\n\n let memo = self.memos.get(offset, rule);\n if memo.start_grow() {\n return None;\n }\n self.input.back_to(memo)\n }\n\n fn rule_answer_with_limits(\n &mut self,\n rule: Rule,\n limits: RuleSet,\n ) -> Option<Rc<RefCell<ThunkChunk>>> {\n let offset = self.input.position_offset;\n let answer = self.call_rule(rule, offset, Some(limits));\n if !self.memos.has(offset, rule) {\n answer.as_ref()?;\n return Some(Rc::new(RefCell::new(answer.unwrap())));\n }\n let memo = self.memos.get(offset, rule);\n\n if self.input.position_offset > memo.offset {\n memo.start_match(answer, self.input.position_offset);\n return memo.answer_as_deref_mut();\n }\n\n self.input.back_to(memo)\n }\n\n fn apply_rule(\n &mut self,\n rule: Rule,\n parent: &mut ThunkChunk,\n value_index: usize,\n offset: usize,\n limits: Option<RuleSet>,\n ) -> bool {\n let answer = match &limits {\n Some(limit_set)\n if self.input.position_offset == offset && !limit_set.contains(&rule) =>\n {\n self.rule_answer_with_limits(rule, limits.unwrap())\n }\n _ => self.rule_answer(rule),\n };\n\n let Some(answer) = answer else {\n return false;\n };\n\n let new_node = Thunk::Node(ThunkNode {\n thunks: answer.borrow().thunks.clone(),\n value: parent.value_ref(value_index),\n });\n parent.thunks.borrow_mut().push(new_node);\n\n true\n }\n\n fn call_rule(\n &mut self,\n rule: Rule,\n offset: usize,\n mut limits: Option<RuleSet>,\n ) -> Option<ThunkChunk> {\n if let Some(ref mut limits) = limits {\n limits.insert(rule);\n }\n match rule {\n".freeze
|
520
|
+
|
521
|
+
@root.rules.each do |rule|
|
522
|
+
erbout << " Rule::#{Packcr.camelize(rule.name)} => self.evaluate_rule_#{rule.name}(offset, limits),\n".freeze
|
523
|
+
end
|
524
|
+
erbout << " }\n }\n\n".freeze
|
525
|
+
|
526
|
+
@root.rules.each do |rule|
|
527
|
+
erbout << "\n".freeze
|
528
|
+
|
529
|
+
gen = ::Packcr::Generator.new(rule, @ascii, @location, :rs)
|
530
|
+
|
531
|
+
erbout << "#{gen.generate_code(rule, 0, 4, false)}".freeze
|
532
|
+
end
|
533
|
+
erbout << "}\n\nstruct ThunkProcessor<'a> {\n buffer: &'a str,\n}\n\nimpl<'a> ThunkProcessor<'a> {\n fn new(buffer: &'a str) -> Self {\n Self { buffer }\n }\n\n fn call_action(&self, action: Action, thunk: &ThunkLeaf, value: &mut i32) {\n match action {\n".freeze
|
534
|
+
|
535
|
+
@root.rules.each do |rule|
|
536
|
+
rule.codes.each do |code|
|
537
|
+
erbout << " Action::#{Packcr.camelize(rule.name)}#{code.index} => self.action_#{rule.name}_#{code.index}(thunk, value),\n".freeze
|
538
|
+
end
|
539
|
+
end
|
540
|
+
erbout << " }\n }\n".freeze
|
541
|
+
|
542
|
+
@root.rules.each do |rule|
|
543
|
+
rule.codes.each do |code|
|
544
|
+
erbout << "\n #[allow(unused_variables,non_snake_case)]\n fn action_#{rule.name}_#{code.index}(&self, leaf: &ThunkLeaf, out: &mut i32) {\n".freeze
|
545
|
+
|
546
|
+
code.vars.each_with_index do |ref, i|
|
547
|
+
if i == 0
|
548
|
+
erbout << " let values = leaf.values();\n".freeze
|
549
|
+
end
|
550
|
+
erbout << " let #{ref.var} = values[&#{ref.index}];\n".freeze
|
551
|
+
end
|
552
|
+
erbout << " let _0 = {\n let capt = &leaf.capt0;\n &self.buffer[(capt.start)..(capt.end)]\n };\n".freeze
|
553
|
+
|
554
|
+
code.capts.size.times do |i|
|
555
|
+
erbout << " let _#{i + 1} = {\n let capt = &leaf.capts[&#{i}];\n &self.buffer[(capt.start)..(capt.end)]\n };\n".freeze
|
556
|
+
end
|
557
|
+
erbout << " #{stream.get_code_block(code.code, 4, @iname)} }\n".freeze
|
558
|
+
end
|
559
|
+
end
|
560
|
+
erbout << "}\n\n#[derive(Copy, Clone)]\nenum Action {\n".freeze
|
561
|
+
|
562
|
+
@root.rules.each do |rule|
|
563
|
+
rule.codes.each do |code|
|
564
|
+
erbout << " #{Packcr.camelize(rule.name)}#{code.index},\n".freeze
|
565
|
+
end
|
566
|
+
end
|
567
|
+
erbout << "}\n\n#[derive(Copy, Clone, PartialEq, Eq, Hash)]\nenum Rule {\n".freeze
|
568
|
+
|
569
|
+
@root.rules.each do |rule|
|
570
|
+
erbout << " #{Packcr.camelize(rule.name)},\n".freeze
|
469
571
|
end
|
470
|
-
erbout << "
|
572
|
+
erbout << "}\n".freeze
|
471
573
|
|
472
574
|
if !code(:lsource).empty?
|
473
575
|
erbout << "\n".freeze
|
@@ -477,6 +579,8 @@ class Packcr
|
|
477
579
|
end
|
478
580
|
end
|
479
581
|
erbout
|
582
|
+
else
|
583
|
+
raise "unknown lang #{lang}"
|
480
584
|
end
|
481
585
|
end
|
482
586
|
end
|
@@ -53,6 +53,23 @@ class Packcr
|
|
53
53
|
erbout << " )\n)\n".freeze
|
54
54
|
|
55
55
|
erbout
|
56
|
+
when :rs
|
57
|
+
erbout = +""
|
58
|
+
erbout << "answer.push_leaf(\n Action::#{Packcr.camelize(gen.rule.name)}#{index},\n self.input.position_offset,\n &[".freeze
|
59
|
+
|
60
|
+
vars.each_with_index do |var, i|
|
61
|
+
erbout << "#{", " if i > 0}#{var.index}".freeze
|
62
|
+
end
|
63
|
+
erbout << "],\n &[".freeze
|
64
|
+
|
65
|
+
capts.each_with_index do |capt, i|
|
66
|
+
erbout << "#{", " if i > 0}#{capt.index}".freeze
|
67
|
+
end
|
68
|
+
erbout << "],\n);\n".freeze
|
69
|
+
|
70
|
+
erbout
|
71
|
+
else
|
72
|
+
raise "unknown lang #{gen.lang}"
|
56
73
|
end
|
57
74
|
end
|
58
75
|
end
|
@@ -19,13 +19,12 @@ class Packcr
|
|
19
19
|
r = expr.reachability
|
20
20
|
|
21
21
|
erbout << "#{gen.generate_code(expr, l, 4, false)}".freeze
|
22
|
-
|
23
|
-
when Packcr::CODE_REACH__ALWAYS_SUCCEED
|
22
|
+
if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
|
24
23
|
if c
|
25
24
|
erbout << " /* unreachable codes omitted */\n".freeze
|
26
25
|
end
|
27
26
|
break
|
28
|
-
|
27
|
+
elsif r == Packcr::CODE_REACH__BOTH
|
29
28
|
erbout << " goto L#{format("%04d", m)};\n".freeze
|
30
29
|
end
|
31
30
|
erbout << "L#{format("%04d", l)}:;\n ctx->position_offset = p;\n".freeze
|
@@ -64,15 +63,14 @@ class Packcr
|
|
64
63
|
r = expr.reachability
|
65
64
|
|
66
65
|
erbout << "#{gen.generate_code(expr, l, 4, false, oncut: onfail)}".freeze
|
67
|
-
|
68
|
-
when Packcr::CODE_REACH__ALWAYS_SUCCEED
|
66
|
+
if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
|
69
67
|
if c
|
70
68
|
erbout << " # unreachable codes omitted\n".freeze
|
71
69
|
end
|
72
70
|
erbout << " end\n".freeze
|
73
71
|
|
74
72
|
break
|
75
|
-
|
73
|
+
elsif r == Packcr::CODE_REACH__BOTH
|
76
74
|
erbout << " throw(#{m})\n".freeze
|
77
75
|
end
|
78
76
|
erbout << " end\n".freeze
|
@@ -91,6 +89,54 @@ class Packcr
|
|
91
89
|
erbout << "end\n".freeze
|
92
90
|
|
93
91
|
erbout
|
92
|
+
when :rs
|
93
|
+
erbout = +""
|
94
|
+
m = gen.next_label
|
95
|
+
erbout << "'L#{format("%04d", m)}: {\n let p = self.input.position_offset;\n".freeze
|
96
|
+
|
97
|
+
if gen.location
|
98
|
+
erbout << " TODO\n".freeze
|
99
|
+
end
|
100
|
+
nodes.each_with_index do |expr, i|
|
101
|
+
erbout << " {\n".freeze
|
102
|
+
|
103
|
+
c = i + 1 < nodes.length
|
104
|
+
if expr.reversible?(gen)
|
105
|
+
|
106
|
+
erbout << "#{gen.generate_code(expr, m, 8, false, reverse: true, oncut: onfail)}".freeze
|
107
|
+
else
|
108
|
+
l = gen.next_label
|
109
|
+
erbout << " 'L#{format("%04d", l)}: {\n".freeze
|
110
|
+
|
111
|
+
r = expr.reachability
|
112
|
+
|
113
|
+
erbout << "#{gen.generate_code(expr, l, 12, false, oncut: onfail)}".freeze
|
114
|
+
if r == Packcr::CODE_REACH__ALWAYS_SUCCEED
|
115
|
+
if c
|
116
|
+
erbout << " // unreachable codes omitted\n".freeze
|
117
|
+
end
|
118
|
+
erbout << " }\n".freeze
|
119
|
+
|
120
|
+
break
|
121
|
+
elsif r == Packcr::CODE_REACH__BOTH
|
122
|
+
erbout << " break 'L#{format("%04d", m)};\n".freeze
|
123
|
+
end
|
124
|
+
erbout << " }\n".freeze
|
125
|
+
end
|
126
|
+
erbout << " }\n self.input.position_offset = p;\n".freeze
|
127
|
+
|
128
|
+
if gen.location
|
129
|
+
erbout << " TODO\n".freeze
|
130
|
+
end
|
131
|
+
next if c
|
132
|
+
|
133
|
+
erbout << " break 'L#{format("%04d", onfail)};\n".freeze
|
134
|
+
end
|
135
|
+
erbout << "} // 'L#{format("%04d", m)}\n".freeze
|
136
|
+
|
137
|
+
erbout
|
138
|
+
else
|
139
|
+
raise "unknown lang #{gen.lang}"
|
94
140
|
end
|
95
141
|
end
|
96
142
|
end
|
@@ -32,6 +32,21 @@ class Packcr
|
|
32
32
|
erbout << "q_loc#{gen.level} = @position_offset_loc\ncapt#{gen.level}.start_loc = p_loc#{gen.level}\ncapt#{gen.level}.end_loc = q_loc#{gen.level}\n".freeze
|
33
33
|
end
|
34
34
|
erbout
|
35
|
+
when :rs
|
36
|
+
erbout = +""
|
37
|
+
erbout << "let p_inner = self.input.position_offset;\n".freeze
|
38
|
+
|
39
|
+
if gen.location
|
40
|
+
erbout << "TODO\n".freeze
|
41
|
+
end
|
42
|
+
erbout << "{\n#{gen.generate_code(expr, onfail, 4, false)}}\nlet q = self.input.position_offset;\nanswer.capts[#{index}].start = p_inner;\nanswer.capts[#{index}].end = q;\n".freeze
|
43
|
+
|
44
|
+
if gen.location
|
45
|
+
erbout << "TODO\n".freeze
|
46
|
+
end
|
47
|
+
erbout
|
48
|
+
else
|
49
|
+
raise "unknown lang #{gen.lang}"
|
35
50
|
end
|
36
51
|
end
|
37
52
|
end
|