packcr 0.0.3 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/exe/packcr +3 -0
  3. data/lib/packcr/broadcast.rb +17 -0
  4. data/lib/packcr/cli.rb +25 -0
  5. data/lib/packcr/code_block.rb +2 -3
  6. data/lib/packcr/context.rb +58 -872
  7. data/lib/packcr/generator.rb +13 -10
  8. data/lib/packcr/node/action_node.rb +20 -5
  9. data/lib/packcr/node/alternate_node.rb +27 -14
  10. data/lib/packcr/node/capture_node.rb +22 -8
  11. data/lib/packcr/node/charclass_node.rb +41 -13
  12. data/lib/packcr/node/eof_node.rb +23 -0
  13. data/lib/packcr/node/error_node.rb +29 -11
  14. data/lib/packcr/node/expand_node.rb +14 -4
  15. data/lib/packcr/node/predicate_node.rb +19 -23
  16. data/lib/packcr/node/quantity_node.rb +28 -18
  17. data/lib/packcr/node/reference_node.rb +43 -5
  18. data/lib/packcr/node/root_node.rb +60 -0
  19. data/lib/packcr/node/rule_node.rb +38 -3
  20. data/lib/packcr/node/sequence_node.rb +51 -31
  21. data/lib/packcr/node/string_node.rb +16 -12
  22. data/lib/packcr/node.rb +48 -0
  23. data/lib/packcr/parser.rb +4570 -0
  24. data/lib/packcr/stream.rb +9 -13
  25. data/lib/packcr/templates/context/header.c.erb +29 -0
  26. data/lib/packcr/templates/context/source.c.erb +1292 -0
  27. data/lib/packcr/templates/context/source.rb.erb +406 -0
  28. data/lib/packcr/templates/node/action.c.erb +16 -0
  29. data/lib/packcr/templates/node/action.rb.erb +21 -0
  30. data/lib/packcr/templates/node/alternate.c.erb +34 -0
  31. data/lib/packcr/templates/node/alternate.rb.erb +40 -0
  32. data/lib/packcr/templates/node/capture.c.erb +17 -0
  33. data/lib/packcr/templates/node/capture.rb.erb +14 -0
  34. data/lib/packcr/templates/node/charclass.c.erb +47 -0
  35. data/lib/packcr/templates/node/charclass.rb.erb +49 -0
  36. data/lib/packcr/templates/node/charclass_any.c.erb +5 -0
  37. data/lib/packcr/templates/node/charclass_any.rb.erb +7 -0
  38. data/lib/packcr/templates/node/charclass_fail.c.erb +1 -0
  39. data/lib/packcr/templates/node/charclass_fail.rb.erb +1 -0
  40. data/lib/packcr/templates/node/charclass_one.c.erb +19 -0
  41. data/lib/packcr/templates/node/charclass_one.rb.erb +23 -0
  42. data/lib/packcr/templates/node/charclass_utf8.c.erb +49 -0
  43. data/lib/packcr/templates/node/charclass_utf8.rb.erb +50 -0
  44. data/lib/packcr/templates/node/charclass_utf8_reverse.rb.erb +51 -0
  45. data/lib/packcr/templates/node/eof.c.erb +1 -0
  46. data/lib/packcr/templates/node/eof.rb.erb +3 -0
  47. data/lib/packcr/templates/node/error.c.erb +28 -0
  48. data/lib/packcr/templates/node/error.rb.erb +34 -0
  49. data/lib/packcr/templates/node/expand.c.erb +16 -0
  50. data/lib/packcr/templates/node/expand.rb.erb +16 -0
  51. data/lib/packcr/templates/node/predicate.c.erb +30 -0
  52. data/lib/packcr/templates/node/predicate.rb.erb +28 -0
  53. data/lib/packcr/templates/node/predicate_neg.c.erb +23 -0
  54. data/lib/packcr/templates/node/predicate_neg.rb.erb +22 -0
  55. data/lib/packcr/templates/node/quantify_many.c.erb +45 -0
  56. data/lib/packcr/templates/node/quantify_many.rb.erb +47 -0
  57. data/lib/packcr/templates/node/quantify_one.c.erb +21 -0
  58. data/lib/packcr/templates/node/quantify_one.rb.erb +23 -0
  59. data/lib/packcr/templates/node/reference.c.erb +5 -0
  60. data/lib/packcr/templates/node/reference.rb.erb +9 -0
  61. data/lib/packcr/templates/node/reference_reverse.rb.erb +9 -0
  62. data/lib/packcr/templates/node/rule.c.erb +19 -0
  63. data/lib/packcr/templates/node/rule.rb.erb +23 -0
  64. data/lib/packcr/templates/node/sequence.c.erb +12 -0
  65. data/lib/packcr/templates/node/sequence.rb.erb +12 -0
  66. data/lib/packcr/templates/node/string_many.c.erb +11 -0
  67. data/lib/packcr/templates/node/string_many.rb.erb +10 -0
  68. data/lib/packcr/templates/node/string_one.c.erb +8 -0
  69. data/lib/packcr/templates/node/string_one.rb.erb +10 -0
  70. data/lib/packcr/tokenizer.rb +2948 -0
  71. data/lib/packcr/util.rb +3 -8
  72. data/lib/packcr/version.rb +1 -1
  73. data/lib/packcr.rb +1 -2
  74. metadata +88 -8
  75. data/lib/packcr/buffer.rb +0 -47
@@ -1,7 +1,6 @@
1
-
2
1
  class Packcr
3
2
  class Generator
4
- attr_reader :ascii, :rule, :location, :lang
3
+ attr_reader :ascii, :rule, :location, :lang, :level
5
4
 
6
5
  def initialize(rule, ascii, location, lang = :c)
7
6
  @rule = rule
@@ -9,27 +8,31 @@ class Packcr
9
8
  @ascii = !!ascii
10
9
  @location = !!location
11
10
  @lang = lang
11
+ @level = 0
12
12
  end
13
13
 
14
14
  def next_label
15
15
  @label += 1
16
16
  end
17
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
18
+ def generate_code(node, onescape, indent, bare, reverse: false, oncut: nil)
19
+ @stream, stream = +"", @stream
20
+ @level += 1
24
21
  begin
25
- return generate_code(node, onfail, indent, bare), @stream.string
22
+ if reverse
23
+ node.generate_reverse_code(self, onescape, indent, bare, oncut: oncut)
24
+ else
25
+ node.generate_code(self, onescape, indent, bare, oncut: oncut)
26
+ end
27
+ @stream
26
28
  ensure
29
+ @level -= 1
27
30
  @stream = stream
28
31
  end
29
32
  end
30
33
 
31
34
  def write(str)
32
- @stream.write(str)
35
+ @stream << str
33
36
  end
34
37
  end
35
38
  end
@@ -3,8 +3,9 @@ class Packcr
3
3
  class ActionNode < Packcr::Node
4
4
  attr_accessor :code, :index, :vars, :capts
5
5
 
6
- def initialize
7
- super
6
+ def initialize(code = nil)
7
+ super()
8
+ @code = code
8
9
  self.vars = []
9
10
  self.capts = []
10
11
  end
@@ -32,9 +33,12 @@ class Packcr
32
33
  end
33
34
  end
34
35
 
35
- def generate_code(gen, onfail, indent, bare)
36
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
36
37
  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 reachability
41
+ Packcr::CODE_REACH__ALWAYS_SUCCEED
38
42
  end
39
43
 
40
44
  def verify_variables(vars)
@@ -45,7 +49,18 @@ class Packcr
45
49
  @capts = capts
46
50
  end
47
51
 
48
- def link_references(ctx)
52
+ def setup_rule(rule)
53
+ @index = rule.codes.length
54
+ rule.codes.push(self)
55
+ end
56
+
57
+ def to_h
58
+ {
59
+ type: :action,
60
+ code: code&.text,
61
+ vars: vars&.map(&:to_h),
62
+ capts: capts&.map(&:to_h),
63
+ }
49
64
  end
50
65
  end
51
66
  end
@@ -3,9 +3,14 @@ class Packcr
3
3
  class AlternateNode < Packcr::Node
4
4
  attr_accessor :nodes
5
5
 
6
- def initialize
7
- super
8
- self.nodes = []
6
+ def initialize(*nodes)
7
+ super()
8
+ self.nodes = nodes
9
+ end
10
+
11
+ def alt(node)
12
+ @nodes << node if node
13
+ self
9
14
  end
10
15
 
11
16
  def debug_dump(indent = 0)
@@ -22,14 +27,21 @@ class Packcr
22
27
  m
23
28
  end
24
29
 
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)
30
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
31
+ gen.write Packcr.template("node/alternate.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
32
+ end
31
33
 
32
- reach || Packcr::CODE_REACH__ALWAYS_FAIL
34
+ def reachability
35
+ r = Packcr::CODE_REACH__ALWAYS_FAIL
36
+ nodes.each do |expr|
37
+ case expr.reachability
38
+ when Packcr::CODE_REACH__ALWAYS_SUCCEED
39
+ return Packcr::CODE_REACH__ALWAYS_SUCCEED
40
+ when Packcr::CODE_REACH__BOTH
41
+ r = Packcr::CODE_REACH__BOTH
42
+ end
43
+ end
44
+ r
33
45
  end
34
46
 
35
47
  def verify_variables(vars)
@@ -61,10 +73,11 @@ class Packcr
61
73
  end
62
74
  end
63
75
 
64
- def link_references(ctx)
65
- nodes.each do |node|
66
- node.link_references(ctx)
67
- end
76
+ def to_h
77
+ {
78
+ type: :alternate,
79
+ nodes: nodes&.map(&:to_h),
80
+ }
68
81
  end
69
82
  end
70
83
  end
@@ -3,6 +3,10 @@ class Packcr
3
3
  class CaptureNode < Packcr::Node
4
4
  attr_accessor :expr, :index
5
5
 
6
+ def initialize(expr = nil)
7
+ @expr = expr
8
+ end
9
+
6
10
  def debug_dump(indent = 0)
7
11
  $stdout.print "#{" " * indent}Capture(index:"
8
12
  Packcr.dump_integer_value(index)
@@ -11,23 +15,33 @@ class Packcr
11
15
  $stdout.print "#{" " * indent}}\n"
12
16
  end
13
17
 
14
- def generate_code(gen, onfail, indent, bare)
15
- r = nil
18
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
16
19
  gen.write Packcr.template("node/capture.#{gen.lang}.erb", binding, indent: indent)
17
- return r
18
20
  end
19
21
 
20
- def verify_variables(vars)
21
- expr.verify_variables(vars)
22
+ def reachability
23
+ expr.reachability
22
24
  end
23
25
 
24
26
  def verify_captures(ctx, capts)
25
- expr.verify_captures(ctx, capts)
27
+ super
26
28
  capts.push(self)
27
29
  end
28
30
 
29
- def link_references(ctx)
30
- expr.link_references(ctx)
31
+ def nodes
32
+ [expr]
33
+ end
34
+
35
+ def setup_rule(rule)
36
+ @index = rule.capts.length
37
+ rule.capts << self
38
+ end
39
+
40
+ def to_h
41
+ {
42
+ type: :capture,
43
+ expr: expr&.to_h,
44
+ }
31
45
  end
32
46
  end
33
47
  end
@@ -3,13 +3,21 @@ class Packcr
3
3
  class CharclassNode < Packcr::Node
4
4
  attr_accessor :value
5
5
 
6
+ def initialize(value = nil)
7
+ @value = value
8
+ end
9
+
6
10
  def debug_dump(indent = 0)
7
11
  $stdout.print "#{" " * indent}Charclass(value:'"
8
12
  Packcr.dump_escaped_string(value)
9
13
  $stdout.print "')\n"
10
14
  end
11
15
 
12
- def generate_code(gen, onfail, indent, bare)
16
+ def reversible?(gen)
17
+ gen.lang == :rb && !gen.ascii
18
+ end
19
+
20
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
13
21
  if gen.ascii
14
22
  return generate_ascii_code(gen, onfail, indent, bare)
15
23
  else
@@ -17,13 +25,22 @@ class Packcr
17
25
  end
18
26
  end
19
27
 
20
- def verify_variables(vars)
21
- end
22
-
23
- def verify_captures(ctx, capts)
28
+ def generate_reverse_code(gen, onsuccess, indent, bare, oncut: nil)
29
+ if gen.ascii
30
+ raise "unexpected"
31
+ else
32
+ return generate_utf8_charclass_reverse_code(gen, onsuccess, indent, bare)
33
+ end
24
34
  end
25
35
 
26
- def link_references(ctx)
36
+ def reachability
37
+ charclass = self.value
38
+ n = charclass&.length || 0
39
+ if charclass.nil? || n > 0
40
+ return Packcr::CODE_REACH__BOTH
41
+ else
42
+ return Packcr::CODE_REACH__ALWAYS_FAIL
43
+ end
27
44
  end
28
45
 
29
46
  private
@@ -35,13 +52,20 @@ class Packcr
35
52
  end
36
53
  n = charclass&.length || 0
37
54
  if charclass.nil? || n > 0
38
- a = charclass && charclass[0] == '^'
39
- i = a ? 1 : 0
40
55
  gen.write Packcr.template("node/charclass_utf8.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
41
- return Packcr::CODE_REACH__BOTH
42
56
  else
43
57
  gen.write Packcr.template("node/charclass_fail.#{gen.lang}.erb", binding, indent: indent)
44
- return Packcr::CODE_REACH__ALWAYS_FAIL
58
+ end
59
+ end
60
+
61
+ def generate_utf8_charclass_reverse_code(gen, onsuccess, indent, bare)
62
+ charclass = self.value
63
+ if charclass && charclass.encoding != Encoding::UTF_8
64
+ charclass = charclass.dup.force_encoding(Encoding::UTF_8)
65
+ end
66
+ n = charclass&.length || 0
67
+ if charclass.nil? || n > 0
68
+ gen.write Packcr.template("node/charclass_utf8_reverse.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
45
69
  end
46
70
  end
47
71
 
@@ -60,16 +84,20 @@ class Packcr
60
84
  else
61
85
  gen.write Packcr.template("node/charclass_one.#{gen.lang}.erb", binding, indent: indent)
62
86
  end
63
- return Packcr::CODE_REACH__BOTH
64
87
  else
65
88
  gen.write Packcr.template("node/charclass_fail.#{gen.lang}.erb", binding, indent: indent)
66
- return Packcr::CODE_REACH__ALWAYS_FAIL
67
89
  end
68
90
  else
69
91
  gen.write Packcr.template("node/charclass_any.#{gen.lang}.erb", binding, indent: indent)
70
- return Packcr::CODE_REACH__BOTH
71
92
  end
72
93
  end
94
+
95
+ def to_h
96
+ {
97
+ type: :charclass,
98
+ value: value,
99
+ }
100
+ end
73
101
  end
74
102
  end
75
103
  end
@@ -0,0 +1,23 @@
1
+ class Packcr
2
+ class Node
3
+ class EofNode < Packcr::Node
4
+ def debug_dump(indent = 0)
5
+ $stdout.print "#{" " * indent}Eof()\n"
6
+ end
7
+
8
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
9
+ gen.write Packcr.template("node/eof.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
10
+ end
11
+
12
+ def reachability
13
+ return Packcr::CODE_REACH__BOTH
14
+ end
15
+
16
+ def to_h
17
+ {
18
+ type: :eof,
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,8 +3,11 @@ class Packcr
3
3
  class ErrorNode < Packcr::Node
4
4
  attr_accessor :expr, :code, :index, :vars, :capts
5
5
 
6
- def initialize
7
- super
6
+ def initialize(expr = nil, code = nil, index = nil)
7
+ super()
8
+ @expr = expr
9
+ @code = code
10
+ @index = index
8
11
  self.vars = []
9
12
  self.capts = []
10
13
  end
@@ -26,26 +29,41 @@ class Packcr
26
29
  $stdout.print "#{" " * indent}}\n"
27
30
  end
28
31
 
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)
32
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
33
33
  gen.write Packcr.template("node/error.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
34
- return r
34
+ end
35
+
36
+ def reachability
37
+ expr.reachability
35
38
  end
36
39
 
37
40
  def verify_variables(vars)
38
41
  @vars = vars
39
- expr.verify_variables(vars)
42
+ super
40
43
  end
41
44
 
42
45
  def verify_captures(ctx, capts)
43
46
  @capts = capts
44
- expr.verify_captures(ctx, capts)
47
+ super
48
+ end
49
+
50
+ def nodes
51
+ [expr]
52
+ end
53
+
54
+ def setup_rule(rule)
55
+ @index = rule.codes.length
56
+ rule.codes.push(self)
45
57
  end
46
58
 
47
- def link_references(ctx)
48
- expr.link_references(ctx)
59
+ def to_h
60
+ {
61
+ type: :error,
62
+ code: code&.text,
63
+ vars: vars&.map(&:to_h),
64
+ capts: capts&.map(&:to_h),
65
+ index: @index,
66
+ }
49
67
  end
50
68
  end
51
69
  end
@@ -3,18 +3,24 @@ class Packcr
3
3
  class ExpandNode < Packcr::Node
4
4
  attr_accessor :index, :line, :col
5
5
 
6
+ def initialize(index = nil, line = nil, col = nil)
7
+ @index = index
8
+ @line = line
9
+ @col = col
10
+ end
11
+
6
12
  def debug_dump(indent = 0)
7
13
  $stdout.print "#{" " * indent}Expand(index:"
8
14
  Packcr.dump_integer_value(index)
9
15
  $stdout.print ")\n"
10
16
  end
11
17
 
12
- def generate_code(gen, onfail, indent, bare)
18
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
13
19
  gen.write Packcr.template("node/expand.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
14
- return Packcr::CODE_REACH__BOTH
15
20
  end
16
21
 
17
- def verify_variables(vars)
22
+ def reachability
23
+ return Packcr::CODE_REACH__BOTH
18
24
  end
19
25
 
20
26
  def verify_captures(ctx, capts)
@@ -29,7 +35,11 @@ class Packcr
29
35
  end
30
36
  end
31
37
 
32
- def link_references(ctx)
38
+ def to_h
39
+ {
40
+ type: :expand,
41
+ index: index,
42
+ }
33
43
  end
34
44
  end
35
45
  end
@@ -3,9 +3,10 @@ class Packcr
3
3
  class PredicateNode < Packcr::Node
4
4
  attr_accessor :neg, :expr
5
5
 
6
- def initialize
7
- super
8
- self.neg = false
6
+ def initialize(expr = nil, neg = false)
7
+ super()
8
+ @expr = expr
9
+ @neg = neg
9
10
  end
10
11
 
11
12
  def debug_dump(indent = 0)
@@ -14,37 +15,32 @@ class Packcr
14
15
  $stdout.print "#{" " * indent}}\n"
15
16
  end
16
17
 
17
- def generate_code(gen, onfail, indent, bare)
18
- r = nil
18
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
19
19
  if neg
20
- l = gen.next_label
21
- r, code = gen.generate_code_str(expr, l, 4, false)
22
20
  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
21
  else
30
- l = gen.next_label
31
- m = gen.next_label
32
- r, code = gen.generate_code_str(expr, l, 4, false)
33
22
  gen.write Packcr.template("node/predicate.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
34
23
  end
35
- return r
36
24
  end
37
25
 
38
- def verify_variables(vars)
39
- expr.verify_variables(vars)
26
+ def reachability
27
+ if neg
28
+ -expr.reachability
29
+ else
30
+ expr.reachability
31
+ end
40
32
  end
41
33
 
42
- def verify_captures(ctx, capts)
43
- expr.verify_captures(ctx, capts)
34
+ def nodes
35
+ [expr]
44
36
  end
45
37
 
46
- def link_references(ctx)
47
- expr.link_references(ctx)
38
+ def to_h
39
+ {
40
+ type: :predicate,
41
+ expr: expr&.to_h,
42
+ neg: neg,
43
+ }
48
44
  end
49
45
  end
50
46
  end
@@ -3,10 +3,11 @@ class Packcr
3
3
  class QuantityNode < Packcr::Node
4
4
  attr_accessor :min, :max, :expr
5
5
 
6
- def initialize
7
- super
8
- self.min = 0
9
- self.max = 0
6
+ def initialize(expr = nil, min = 0, max = 0)
7
+ super()
8
+ @expr = expr
9
+ @min = min
10
+ @max = max
10
11
  end
11
12
 
12
13
  def debug_dump(indent = 0)
@@ -15,40 +16,49 @@ class Packcr
15
16
  $stdout.print "#{" " * indent}}\n"
16
17
  end
17
18
 
18
- def generate_code(gen, onfail, indent, bare)
19
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
19
20
  if max > 1 || max < 0
20
- r = nil
21
21
  gen.write Packcr.template("node/quantify_many.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
22
+ elsif max == 1
23
+ if min > 0
24
+ gen.write gen.generate_code(expr, onfail, indent, bare)
25
+ else
26
+ gen.write Packcr.template("node/quantify_one.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
27
+ end
28
+ end
29
+ end
30
+
31
+ def reachability
32
+ if max > 1 || max < 0
22
33
  if min <= 0
23
34
  return Packcr::CODE_REACH__ALWAYS_SUCCEED
24
35
  end
25
- if r == Packcr::CODE_REACH__ALWAYS_FAIL
36
+ if expr.reachability == Packcr::CODE_REACH__ALWAYS_FAIL
26
37
  return Packcr::CODE_REACH__ALWAYS_FAIL
27
38
  end
28
39
  return Packcr::CODE_REACH__BOTH
29
40
  elsif max == 1
30
41
  if min > 0
31
- return gen.generate_code(expr, onfail, indent, bare)
42
+ return expr.reachability
32
43
  else
33
- gen.write Packcr.template("node/quantify_one.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
34
44
  return Packcr::CODE_REACH__ALWAYS_SUCCEED
35
45
  end
36
46
  else
37
- # no code to generate
38
47
  return Packcr::CODE_REACH__ALWAYS_SUCCEED
39
48
  end
40
49
  end
41
50
 
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)
51
+ def nodes
52
+ [expr]
48
53
  end
49
54
 
50
- def link_references(ctx)
51
- expr.link_references(ctx)
55
+ def to_h
56
+ {
57
+ type: :predicate,
58
+ expr: expr&.to_h,
59
+ min: min,
60
+ max: max,
61
+ }
52
62
  end
53
63
  end
54
64
  end
@@ -3,17 +3,50 @@ class Packcr
3
3
  class ReferenceNode < Packcr::Node
4
4
  attr_accessor :var, :index, :name, :rule, :line, :col
5
5
 
6
+ def initialize(name = nil, var = nil, line = nil, col = nil)
7
+ @name = name
8
+ @var = var
9
+ @line = line
10
+ @col = col
11
+ end
12
+
6
13
  def debug_dump(indent = 0)
7
14
  $stdout.print "#{" " * indent}Reference(var:'#{var || "(null)"}', index:"
8
15
  Packcr.dump_integer_value(index)
9
16
  $stdout.print ", name:'#{name}', rule:'#{rule&.name || "(null)"}')\n"
10
17
  end
11
18
 
12
- def generate_code(gen, onfail, indent, bare)
19
+ def reversible?(gen)
20
+ gen.lang == :rb
21
+ end
22
+
23
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
13
24
  gen.write Packcr.template("node/reference.#{gen.lang}.erb", binding, indent: indent)
25
+ end
26
+
27
+ def generate_reverse_code(gen, onsuccess, indent, bare, oncut: nil)
28
+ gen.write Packcr.template("node/reference_reverse.#{gen.lang}.erb", binding, indent: indent)
29
+ end
30
+
31
+ def reachability
14
32
  Packcr::CODE_REACH__BOTH
15
33
  end
16
34
 
35
+ def setup_rule(rule)
36
+ return unless var
37
+ i = rule.vars.index do |ref|
38
+ unless ref.is_a?(Packcr::Node::ReferenceNode)
39
+ raise "Unexpected node type: #{ref.class}"
40
+ end
41
+ var == ref.var
42
+ end
43
+ if !i
44
+ i = rule.vars.length
45
+ rule.vars << self
46
+ end
47
+ @index = i
48
+ end
49
+
17
50
  def verify_variables(vars)
18
51
  return if index.nil?
19
52
 
@@ -26,11 +59,8 @@ class Packcr
26
59
  vars.push(self) if !found
27
60
  end
28
61
 
29
- def verify_captures(ctx, capts)
30
- end
31
-
32
62
  def link_references(ctx)
33
- rule = ctx.rule(name)
63
+ rule = ctx.root.rule(name)
34
64
  if !rule
35
65
  ctx.error line + 1, col + 1, "No definition of rule '#{name}'"
36
66
  else
@@ -41,6 +71,14 @@ class Packcr
41
71
  self.rule = rule
42
72
  end
43
73
  end
74
+
75
+ def to_h
76
+ {
77
+ type: :reference,
78
+ name: name,
79
+ var: var,
80
+ }
81
+ end
44
82
  end
45
83
  end
46
84
  end