packcr 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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"