packcr 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/packcr/buffer.rb +47 -0
- data/lib/packcr/code_block.rb +13 -0
- data/lib/packcr/context.rb +982 -0
- data/lib/packcr/generator.rb +35 -0
- data/lib/packcr/node/action_node.rb +52 -0
- data/lib/packcr/node/alternate_node.rb +71 -0
- data/lib/packcr/node/capture_node.rb +34 -0
- data/lib/packcr/node/charclass_node.rb +75 -0
- data/lib/packcr/node/error_node.rb +52 -0
- data/lib/packcr/node/expand_node.rb +36 -0
- data/lib/packcr/node/predicate_node.rb +51 -0
- data/lib/packcr/node/quantity_node.rb +55 -0
- data/lib/packcr/node/reference_node.rb +46 -0
- data/lib/packcr/node/rule_node.rb +30 -0
- data/lib/packcr/node/sequence_node.rb +61 -0
- data/lib/packcr/node/string_node.rb +43 -0
- data/lib/packcr/node.rb +17 -0
- data/lib/packcr/stream.rb +101 -0
- data/lib/packcr/util.rb +94 -0
- data/lib/packcr/version.rb +3 -0
- data/lib/packcr.rb +33 -0
- metadata +77 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
class Packcr
|
3
|
+
class Generator
|
4
|
+
attr_reader :ascii, :rule, :location, :lang
|
5
|
+
|
6
|
+
def initialize(rule, ascii, location, lang = :c)
|
7
|
+
@rule = rule
|
8
|
+
@label = 0
|
9
|
+
@ascii = !!ascii
|
10
|
+
@location = !!location
|
11
|
+
@lang = lang
|
12
|
+
end
|
13
|
+
|
14
|
+
def next_label
|
15
|
+
@label += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_code(node, onfail, indent, bare)
|
19
|
+
node.generate_code(self, onfail, indent, bare)
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate_code_str(node, onfail, indent, bare)
|
23
|
+
@stream, stream = StringIO.new, @stream
|
24
|
+
begin
|
25
|
+
return generate_code(node, onfail, indent, bare), @stream.string
|
26
|
+
ensure
|
27
|
+
@stream = stream
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def write(str)
|
32
|
+
@stream.write(str)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class ActionNode < Packcr::Node
|
4
|
+
attr_accessor :code, :index, :vars, :capts
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.vars = []
|
9
|
+
self.capts = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def debug_dump(indent = 0)
|
13
|
+
$stdout.print "#{" " * indent}Action(index:"
|
14
|
+
Packcr.dump_integer_value(index)
|
15
|
+
$stdout.print ", code:{"
|
16
|
+
Packcr.dump_escaped_string(code.text)
|
17
|
+
$stdout.print "}, vars:"
|
18
|
+
|
19
|
+
vars = self.vars
|
20
|
+
capts = self.capts
|
21
|
+
if vars.length + capts.length > 0
|
22
|
+
$stdout.print "\n"
|
23
|
+
vars.each do |ref|
|
24
|
+
$stdout.print "#{" " * (indent + 2)}'#{ref.var}'\n"
|
25
|
+
end
|
26
|
+
capts.each do |capt|
|
27
|
+
$stdout.print "#{" " * (indent + 2)}$#{capt.index + 1}\n"
|
28
|
+
end
|
29
|
+
$stdout.print "#{" " * indent})\n"
|
30
|
+
else
|
31
|
+
$stdout.print "none)\n"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate_code(gen, onfail, indent, bare)
|
36
|
+
gen.write Packcr.template("node/action.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
37
|
+
return Packcr::CODE_REACH__ALWAYS_SUCCEED
|
38
|
+
end
|
39
|
+
|
40
|
+
def verify_variables(vars)
|
41
|
+
@vars = vars
|
42
|
+
end
|
43
|
+
|
44
|
+
def verify_captures(ctx, capts)
|
45
|
+
@capts = capts
|
46
|
+
end
|
47
|
+
|
48
|
+
def link_references(ctx)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class AlternateNode < Packcr::Node
|
4
|
+
attr_accessor :nodes
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.nodes = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def debug_dump(indent = 0)
|
12
|
+
$stdout.print "#{" " * indent}Alternate(max:#{max}, len:#{nodes.length}) {\n"
|
13
|
+
nodes.each do |node|
|
14
|
+
node.debug_dump(indent + 2)
|
15
|
+
end
|
16
|
+
$stdout.print "#{" " * indent}}\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def max
|
20
|
+
m = 1
|
21
|
+
m <<= 1 while m < @nodes.length
|
22
|
+
m
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_code(gen, onfail, indent, bare)
|
26
|
+
b = false
|
27
|
+
m = gen.next_label
|
28
|
+
|
29
|
+
reach = nil
|
30
|
+
gen.write Packcr.template("node/alternate.#{gen.lang}.erb", binding, indent: indent - 4, unwrap: bare)
|
31
|
+
|
32
|
+
reach || Packcr::CODE_REACH__ALWAYS_FAIL
|
33
|
+
end
|
34
|
+
|
35
|
+
def verify_variables(vars)
|
36
|
+
m = vars.length
|
37
|
+
v = vars.dup
|
38
|
+
nodes.each do |node|
|
39
|
+
v = v[0, m]
|
40
|
+
node.verify_variables(v)
|
41
|
+
v[m...-1].each do |added_node|
|
42
|
+
found = vars[m...-1].any? do |added_var|
|
43
|
+
added_node.index == added_var.index
|
44
|
+
end
|
45
|
+
if !found
|
46
|
+
vars.push(added_node)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def verify_captures(ctx, capts)
|
53
|
+
m = capts.length
|
54
|
+
v = capts.dup
|
55
|
+
nodes.each do |node|
|
56
|
+
v = v[0, m]
|
57
|
+
node.verify_captures(ctx, v)
|
58
|
+
v[m...-1].each do |added_node|
|
59
|
+
capts.push(added_node)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def link_references(ctx)
|
65
|
+
nodes.each do |node|
|
66
|
+
node.link_references(ctx)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class CaptureNode < Packcr::Node
|
4
|
+
attr_accessor :expr, :index
|
5
|
+
|
6
|
+
def debug_dump(indent = 0)
|
7
|
+
$stdout.print "#{" " * indent}Capture(index:"
|
8
|
+
Packcr.dump_integer_value(index)
|
9
|
+
$stdout.print ") {\n"
|
10
|
+
expr.debug_dump(indent + 2)
|
11
|
+
$stdout.print "#{" " * indent}}\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_code(gen, onfail, indent, bare)
|
15
|
+
r = nil
|
16
|
+
gen.write Packcr.template("node/capture.#{gen.lang}.erb", binding, indent: indent)
|
17
|
+
return r
|
18
|
+
end
|
19
|
+
|
20
|
+
def verify_variables(vars)
|
21
|
+
expr.verify_variables(vars)
|
22
|
+
end
|
23
|
+
|
24
|
+
def verify_captures(ctx, capts)
|
25
|
+
expr.verify_captures(ctx, capts)
|
26
|
+
capts.push(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
def link_references(ctx)
|
30
|
+
expr.link_references(ctx)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class CharclassNode < Packcr::Node
|
4
|
+
attr_accessor :value
|
5
|
+
|
6
|
+
def debug_dump(indent = 0)
|
7
|
+
$stdout.print "#{" " * indent}Charclass(value:'"
|
8
|
+
Packcr.dump_escaped_string(value)
|
9
|
+
$stdout.print "')\n"
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_code(gen, onfail, indent, bare)
|
13
|
+
if gen.ascii
|
14
|
+
return generate_ascii_code(gen, onfail, indent, bare)
|
15
|
+
else
|
16
|
+
return generate_utf8_charclass_code(gen, onfail, indent, bare)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def verify_variables(vars)
|
21
|
+
end
|
22
|
+
|
23
|
+
def verify_captures(ctx, capts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def link_references(ctx)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def generate_utf8_charclass_code(gen, onfail, indent, bare)
|
32
|
+
charclass = self.value
|
33
|
+
if charclass && charclass.encoding != Encoding::UTF_8
|
34
|
+
charclass = charclass.dup.force_encoding(Encoding::UTF_8)
|
35
|
+
end
|
36
|
+
n = charclass&.length || 0
|
37
|
+
if charclass.nil? || n > 0
|
38
|
+
a = charclass && charclass[0] == '^'
|
39
|
+
i = a ? 1 : 0
|
40
|
+
gen.write Packcr.template("node/charclass_utf8.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
41
|
+
return Packcr::CODE_REACH__BOTH
|
42
|
+
else
|
43
|
+
gen.write Packcr.template("node/charclass_fail.#{gen.lang}.erb", binding, indent: indent)
|
44
|
+
return Packcr::CODE_REACH__ALWAYS_FAIL
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def generate_ascii_code(gen, onfail, indent, bare)
|
49
|
+
charclass = self.value
|
50
|
+
if charclass
|
51
|
+
n = charclass.length
|
52
|
+
a = charclass[0] == "^"
|
53
|
+
if a
|
54
|
+
n -= 1
|
55
|
+
charclass = charclass[1..-1]
|
56
|
+
end
|
57
|
+
if n > 0
|
58
|
+
if n > 1
|
59
|
+
gen.write Packcr.template("node/charclass.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
60
|
+
else
|
61
|
+
gen.write Packcr.template("node/charclass_one.#{gen.lang}.erb", binding, indent: indent)
|
62
|
+
end
|
63
|
+
return Packcr::CODE_REACH__BOTH
|
64
|
+
else
|
65
|
+
gen.write Packcr.template("node/charclass_fail.#{gen.lang}.erb", binding, indent: indent)
|
66
|
+
return Packcr::CODE_REACH__ALWAYS_FAIL
|
67
|
+
end
|
68
|
+
else
|
69
|
+
gen.write Packcr.template("node/charclass_any.#{gen.lang}.erb", binding, indent: indent)
|
70
|
+
return Packcr::CODE_REACH__BOTH
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class ErrorNode < Packcr::Node
|
4
|
+
attr_accessor :expr, :code, :index, :vars, :capts
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.vars = []
|
9
|
+
self.capts = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def debug_dump(indent = 0)
|
13
|
+
$stdout.print "#{" " * indent}Error(index:"
|
14
|
+
Packcr.dump_integer_value(index)
|
15
|
+
$stdout.print ", code:{"
|
16
|
+
Packcr.dump_escaped_string(code.text)
|
17
|
+
$stdout.print "}, vars:\n"
|
18
|
+
vars.each do |ref|
|
19
|
+
$stdout.print "#{" " * (indent + 2)}'#{ref.var}'\n"
|
20
|
+
end
|
21
|
+
capts.each do |capt|
|
22
|
+
$stdout.print "#{" " * (indent + 2)}$#{capt.index + 1}\n"
|
23
|
+
end
|
24
|
+
$stdout.print "#{" " * indent}) {\n"
|
25
|
+
expr.debug_dump(indent + 2)
|
26
|
+
$stdout.print "#{" " * indent}}\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_code(gen, onfail, indent, bare)
|
30
|
+
l = gen.next_label
|
31
|
+
m = gen.next_label
|
32
|
+
r, code = gen.generate_code_str(expr, l, 4, true)
|
33
|
+
gen.write Packcr.template("node/error.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
34
|
+
return r
|
35
|
+
end
|
36
|
+
|
37
|
+
def verify_variables(vars)
|
38
|
+
@vars = vars
|
39
|
+
expr.verify_variables(vars)
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_captures(ctx, capts)
|
43
|
+
@capts = capts
|
44
|
+
expr.verify_captures(ctx, capts)
|
45
|
+
end
|
46
|
+
|
47
|
+
def link_references(ctx)
|
48
|
+
expr.link_references(ctx)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class ExpandNode < Packcr::Node
|
4
|
+
attr_accessor :index, :line, :col
|
5
|
+
|
6
|
+
def debug_dump(indent = 0)
|
7
|
+
$stdout.print "#{" " * indent}Expand(index:"
|
8
|
+
Packcr.dump_integer_value(index)
|
9
|
+
$stdout.print ")\n"
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_code(gen, onfail, indent, bare)
|
13
|
+
gen.write Packcr.template("node/expand.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
14
|
+
return Packcr::CODE_REACH__BOTH
|
15
|
+
end
|
16
|
+
|
17
|
+
def verify_variables(vars)
|
18
|
+
end
|
19
|
+
|
20
|
+
def verify_captures(ctx, capts)
|
21
|
+
found = capts.any? do |capt|
|
22
|
+
unless capt.is_a?(Packcr::Node::CaptureNode)
|
23
|
+
raise "unexpected capture: #{capt.class}"
|
24
|
+
end
|
25
|
+
index == capt.index
|
26
|
+
end
|
27
|
+
if !found && index != nil
|
28
|
+
ctx.error line + 1, col + 1, "Capture #{index + 1} not available at this position"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def link_references(ctx)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class PredicateNode < Packcr::Node
|
4
|
+
attr_accessor :neg, :expr
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.neg = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def debug_dump(indent = 0)
|
12
|
+
$stdout.print "#{" " * indent}Predicate(neg:#{neg ? 1 : 0}) {\n"
|
13
|
+
expr.debug_dump(indent + 2)
|
14
|
+
$stdout.print "#{" " * indent}}\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_code(gen, onfail, indent, bare)
|
18
|
+
r = nil
|
19
|
+
if neg
|
20
|
+
l = gen.next_label
|
21
|
+
r, code = gen.generate_code_str(expr, l, 4, false)
|
22
|
+
gen.write Packcr.template("node/predicate_neg.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
23
|
+
case r
|
24
|
+
when Packcr::CODE_REACH__ALWAYS_SUCCEED
|
25
|
+
r = Packcr::CODE_REACH__ALWAYS_FAIL
|
26
|
+
when Packcr::CODE_REACH__ALWAYS_FAIL
|
27
|
+
r = Packcr::CODE_REACH__ALWAYS_SUCCEED
|
28
|
+
end
|
29
|
+
else
|
30
|
+
l = gen.next_label
|
31
|
+
m = gen.next_label
|
32
|
+
r, code = gen.generate_code_str(expr, l, 4, false)
|
33
|
+
gen.write Packcr.template("node/predicate.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
34
|
+
end
|
35
|
+
return r
|
36
|
+
end
|
37
|
+
|
38
|
+
def verify_variables(vars)
|
39
|
+
expr.verify_variables(vars)
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_captures(ctx, capts)
|
43
|
+
expr.verify_captures(ctx, capts)
|
44
|
+
end
|
45
|
+
|
46
|
+
def link_references(ctx)
|
47
|
+
expr.link_references(ctx)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class QuantityNode < Packcr::Node
|
4
|
+
attr_accessor :min, :max, :expr
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.min = 0
|
9
|
+
self.max = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def debug_dump(indent = 0)
|
13
|
+
$stdout.print "#{" " * indent}Quantity(min:#{min}, max:#{max}) {\n"
|
14
|
+
expr.debug_dump(indent + 2)
|
15
|
+
$stdout.print "#{" " * indent}}\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_code(gen, onfail, indent, bare)
|
19
|
+
if max > 1 || max < 0
|
20
|
+
r = nil
|
21
|
+
gen.write Packcr.template("node/quantify_many.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
22
|
+
if min <= 0
|
23
|
+
return Packcr::CODE_REACH__ALWAYS_SUCCEED
|
24
|
+
end
|
25
|
+
if r == Packcr::CODE_REACH__ALWAYS_FAIL
|
26
|
+
return Packcr::CODE_REACH__ALWAYS_FAIL
|
27
|
+
end
|
28
|
+
return Packcr::CODE_REACH__BOTH
|
29
|
+
elsif max == 1
|
30
|
+
if min > 0
|
31
|
+
return gen.generate_code(expr, onfail, indent, bare)
|
32
|
+
else
|
33
|
+
gen.write Packcr.template("node/quantify_one.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
|
34
|
+
return Packcr::CODE_REACH__ALWAYS_SUCCEED
|
35
|
+
end
|
36
|
+
else
|
37
|
+
# no code to generate
|
38
|
+
return Packcr::CODE_REACH__ALWAYS_SUCCEED
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_variables(vars)
|
43
|
+
expr.verify_variables(vars)
|
44
|
+
end
|
45
|
+
|
46
|
+
def verify_captures(ctx, capts)
|
47
|
+
expr.verify_captures(ctx, capts)
|
48
|
+
end
|
49
|
+
|
50
|
+
def link_references(ctx)
|
51
|
+
expr.link_references(ctx)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class ReferenceNode < Packcr::Node
|
4
|
+
attr_accessor :var, :index, :name, :rule, :line, :col
|
5
|
+
|
6
|
+
def debug_dump(indent = 0)
|
7
|
+
$stdout.print "#{" " * indent}Reference(var:'#{var || "(null)"}', index:"
|
8
|
+
Packcr.dump_integer_value(index)
|
9
|
+
$stdout.print ", name:'#{name}', rule:'#{rule&.name || "(null)"}')\n"
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_code(gen, onfail, indent, bare)
|
13
|
+
gen.write Packcr.template("node/reference.#{gen.lang}.erb", binding, indent: indent)
|
14
|
+
Packcr::CODE_REACH__BOTH
|
15
|
+
end
|
16
|
+
|
17
|
+
def verify_variables(vars)
|
18
|
+
return if index.nil?
|
19
|
+
|
20
|
+
found = vars.any? do |var|
|
21
|
+
unless var.is_a?(Packcr::Node::ReferenceNode)
|
22
|
+
raise "unexpected var: #{var.class}"
|
23
|
+
end
|
24
|
+
index == var.index
|
25
|
+
end
|
26
|
+
vars.push(self) if !found
|
27
|
+
end
|
28
|
+
|
29
|
+
def verify_captures(ctx, capts)
|
30
|
+
end
|
31
|
+
|
32
|
+
def link_references(ctx)
|
33
|
+
rule = ctx.rule(name)
|
34
|
+
if !rule
|
35
|
+
ctx.error line + 1, col + 1, "No definition of rule '#{name}'"
|
36
|
+
else
|
37
|
+
unless rule.is_a?(Packcr::Node::RuleNode)
|
38
|
+
raise "unexpected node type #{rule.class}"
|
39
|
+
end
|
40
|
+
rule.add_ref
|
41
|
+
self.rule = rule
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class RuleNode < Packcr::Node
|
4
|
+
attr_accessor :codes, :name, :expr, :ref, :vars, :capts, :line, :col
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.ref = 0
|
9
|
+
self.vars = []
|
10
|
+
self.capts = []
|
11
|
+
self.codes = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def debug_dump(indent = 0)
|
15
|
+
$stdout.print "#{" " * indent}Rule(name:'#{name}', ref:#{ref}, vars.len:#{vars.length}, capts.len:#{capts.length}, codes.len:#{codes.length}) {\n"
|
16
|
+
expr.debug_dump(indent + 2)
|
17
|
+
$stdout.print "#{" " * indent}}\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
def verify(ctx)
|
21
|
+
expr.verify_variables([])
|
22
|
+
expr.verify_captures(ctx, [])
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_ref
|
26
|
+
@ref += 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class SequenceNode < Packcr::Node
|
4
|
+
attr_accessor :nodes
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
self.nodes = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def debug_dump(indent = 0)
|
12
|
+
$stdout.print "#{" " * indent}Sequence(max:#{max}, len:#{nodes.length}) {\n"
|
13
|
+
nodes.each do |child_node|
|
14
|
+
child_node.debug_dump(indent + 2)
|
15
|
+
end
|
16
|
+
$stdout.print "#{" " * indent}}\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def max
|
20
|
+
m = 1
|
21
|
+
m <<= 1 while m < @nodes.length
|
22
|
+
m
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate_code(gen, onfail, indent, bare)
|
26
|
+
b = false
|
27
|
+
nodes.each_with_index do |expr, i|
|
28
|
+
case gen.generate_code(expr, onfail, indent, false)
|
29
|
+
when Packcr::CODE_REACH__ALWAYS_FAIL
|
30
|
+
if i + 1 < nodes.length
|
31
|
+
gen.write Packcr.template("node/sequence_unreachable.#{gen.lang}.erb", binding, indent: indent)
|
32
|
+
end
|
33
|
+
return Packcr::CODE_REACH__ALWAYS_FAIL
|
34
|
+
when Packcr::CODE_REACH__ALWAYS_SUCCEED
|
35
|
+
else
|
36
|
+
b = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return b ? Packcr::CODE_REACH__BOTH : Packcr::CODE_REACH__ALWAYS_SUCCEED
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify_variables(vars)
|
43
|
+
nodes.each do |node|
|
44
|
+
node.verify_variables(vars)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def verify_captures(ctx, capts)
|
49
|
+
nodes.each do |node|
|
50
|
+
node.verify_captures(ctx, capts)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def link_references(ctx)
|
55
|
+
nodes.each do |node|
|
56
|
+
node.link_references(ctx)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
class StringNode < Packcr::Node
|
4
|
+
attr_accessor :value
|
5
|
+
|
6
|
+
def value=(value)
|
7
|
+
@value = value&.b
|
8
|
+
end
|
9
|
+
|
10
|
+
def debug_dump(indent = 0)
|
11
|
+
$stdout.print "#{" " * indent}String(value:'"
|
12
|
+
Packcr.dump_escaped_string(value)
|
13
|
+
$stdout.print "')\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_code(gen, onfail, indent, bare)
|
17
|
+
n = value&.length || 0
|
18
|
+
if n > 0
|
19
|
+
if n > 1
|
20
|
+
gen.write Packcr.template("node/string_many.#{gen.lang}.erb", binding, indent: indent)
|
21
|
+
return Packcr::CODE_REACH__BOTH
|
22
|
+
else
|
23
|
+
gen.write Packcr.template("node/string_one.#{gen.lang}.erb", binding, indent: indent)
|
24
|
+
return Packcr::CODE_REACH__BOTH
|
25
|
+
end
|
26
|
+
else
|
27
|
+
# no code to generate
|
28
|
+
return Packcr::CODE_REACH__ALWAYS_SUCCEED
|
29
|
+
end
|
30
|
+
Packcr::CODE_REACH__BOTH
|
31
|
+
end
|
32
|
+
|
33
|
+
def verify_variables(vars)
|
34
|
+
end
|
35
|
+
|
36
|
+
def verify_captures(ctx, capts)
|
37
|
+
end
|
38
|
+
|
39
|
+
def link_references(ctx)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/packcr/node.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Packcr
|
2
|
+
class Node
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require "packcr/node/rule_node"
|
7
|
+
require "packcr/node/reference_node"
|
8
|
+
require "packcr/node/string_node"
|
9
|
+
require "packcr/node/charclass_node"
|
10
|
+
require "packcr/node/quantity_node"
|
11
|
+
require "packcr/node/predicate_node"
|
12
|
+
require "packcr/node/sequence_node"
|
13
|
+
require "packcr/node/alternate_node"
|
14
|
+
require "packcr/node/capture_node"
|
15
|
+
require "packcr/node/expand_node"
|
16
|
+
require "packcr/node/action_node"
|
17
|
+
require "packcr/node/error_node"
|