packcr 0.0.3

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