packcr 0.0.4 → 0.0.7

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.
Files changed (88) 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 +27 -0
  5. data/lib/packcr/code_block.rb +2 -4
  6. data/lib/packcr/context.rb +66 -61
  7. data/lib/packcr/generated/context.rb +440 -0
  8. data/lib/packcr/generated/node/action_node.rb +60 -0
  9. data/lib/packcr/generated/node/alternate_node.rb +98 -0
  10. data/lib/packcr/generated/node/capture_node.rb +39 -0
  11. data/lib/packcr/generated/node/charclass_node.rb +372 -0
  12. data/lib/packcr/generated/node/eof_node.rb +20 -0
  13. data/lib/packcr/generated/node/error_node.rb +67 -0
  14. data/lib/packcr/generated/node/expand_node.rb +30 -0
  15. data/lib/packcr/generated/node/predicate_node.rb +140 -0
  16. data/lib/packcr/generated/node/quantity_node.rb +167 -0
  17. data/lib/packcr/generated/node/reference_node.rb +70 -0
  18. data/lib/packcr/generated/node/rule_node.rb +63 -0
  19. data/lib/packcr/generated/node/sequence_node.rb +42 -0
  20. data/lib/packcr/generated/node/string_node.rb +60 -0
  21. data/lib/packcr/generator.rb +14 -11
  22. data/lib/packcr/node/action_node.rb +18 -7
  23. data/lib/packcr/node/alternate_node.rb +22 -12
  24. data/lib/packcr/node/capture_node.rb +14 -12
  25. data/lib/packcr/node/charclass_node.rb +44 -24
  26. data/lib/packcr/node/eof_node.rb +25 -0
  27. data/lib/packcr/node/error_node.rb +20 -13
  28. data/lib/packcr/node/expand_node.rb +18 -9
  29. data/lib/packcr/node/predicate_node.rb +19 -26
  30. data/lib/packcr/node/quantity_node.rb +31 -24
  31. data/lib/packcr/node/reference_node.rb +31 -9
  32. data/lib/packcr/node/root_node.rb +61 -0
  33. data/lib/packcr/node/rule_node.rb +29 -3
  34. data/lib/packcr/node/sequence_node.rb +48 -31
  35. data/lib/packcr/node/string_node.rb +19 -16
  36. data/lib/packcr/node.rb +34 -5
  37. data/lib/packcr/parser.rb +4493 -3896
  38. data/lib/packcr/stream.rb +22 -22
  39. data/lib/packcr/templates/context/header.c.erb +29 -0
  40. data/lib/packcr/templates/context/source.c.erb +1069 -0
  41. data/lib/packcr/templates/context/source.rb.erb +341 -0
  42. data/lib/packcr/templates/node/action.c.erb +16 -0
  43. data/lib/packcr/templates/node/action.rb.erb +21 -0
  44. data/lib/packcr/templates/node/alternate.c.erb +34 -0
  45. data/lib/packcr/templates/node/alternate.rb.erb +39 -0
  46. data/lib/packcr/templates/node/capture.c.erb +17 -0
  47. data/lib/packcr/templates/node/capture.rb.erb +14 -0
  48. data/lib/packcr/templates/node/charclass.c.erb +47 -0
  49. data/lib/packcr/templates/node/charclass.rb.erb +49 -0
  50. data/lib/packcr/templates/node/charclass_any.c.erb +5 -0
  51. data/lib/packcr/templates/node/charclass_any.rb.erb +7 -0
  52. data/lib/packcr/templates/node/charclass_fail.c.erb +1 -0
  53. data/lib/packcr/templates/node/charclass_fail.rb.erb +1 -0
  54. data/lib/packcr/templates/node/charclass_one.c.erb +19 -0
  55. data/lib/packcr/templates/node/charclass_one.rb.erb +23 -0
  56. data/lib/packcr/templates/node/charclass_utf8.c.erb +49 -0
  57. data/lib/packcr/templates/node/charclass_utf8.rb.erb +50 -0
  58. data/lib/packcr/templates/node/charclass_utf8_reverse.rb.erb +51 -0
  59. data/lib/packcr/templates/node/eof.c.erb +1 -0
  60. data/lib/packcr/templates/node/eof.rb.erb +3 -0
  61. data/lib/packcr/templates/node/error.c.erb +28 -0
  62. data/lib/packcr/templates/node/error.rb.erb +34 -0
  63. data/lib/packcr/templates/node/expand.c.erb +16 -0
  64. data/lib/packcr/templates/node/expand.rb.erb +16 -0
  65. data/lib/packcr/templates/node/predicate.c.erb +30 -0
  66. data/lib/packcr/templates/node/predicate.rb.erb +28 -0
  67. data/lib/packcr/templates/node/predicate_neg.c.erb +23 -0
  68. data/lib/packcr/templates/node/predicate_neg.rb.erb +22 -0
  69. data/lib/packcr/templates/node/quantity_many.c.erb +45 -0
  70. data/lib/packcr/templates/node/quantity_many.rb.erb +47 -0
  71. data/lib/packcr/templates/node/quantity_one.c.erb +21 -0
  72. data/lib/packcr/templates/node/quantity_one.rb.erb +23 -0
  73. data/lib/packcr/templates/node/reference.c.erb +17 -0
  74. data/lib/packcr/templates/node/reference.rb.erb +21 -0
  75. data/lib/packcr/templates/node/reference_reverse.rb.erb +21 -0
  76. data/lib/packcr/templates/node/rule.c.erb +26 -0
  77. data/lib/packcr/templates/node/rule.rb.erb +30 -0
  78. data/lib/packcr/templates/node/sequence.c.erb +12 -0
  79. data/lib/packcr/templates/node/sequence.rb.erb +12 -0
  80. data/lib/packcr/templates/node/string_many.c.erb +11 -0
  81. data/lib/packcr/templates/node/string_many.rb.erb +10 -0
  82. data/lib/packcr/templates/node/string_one.c.erb +8 -0
  83. data/lib/packcr/templates/node/string_one.rb.erb +10 -0
  84. data/lib/packcr/util.rb +21 -24
  85. data/lib/packcr/version.rb +1 -1
  86. data/lib/packcr.rb +9 -13
  87. metadata +117 -10
  88. data/lib/packcr/buffer.rb +0 -47
@@ -13,44 +13,58 @@ class Packcr
13
13
  $stdout.print "')\n"
14
14
  end
15
15
 
16
- def generate_code(gen, onfail, indent, bare)
17
- if gen.ascii
18
- return generate_ascii_code(gen, onfail, indent, bare)
19
- else
20
- return generate_utf8_charclass_code(gen, onfail, indent, bare)
21
- end
16
+ def reversible?(gen)
17
+ gen.lang == :rb && !gen.ascii
22
18
  end
23
19
 
24
- def verify_variables(vars)
20
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
21
+ return generate_ascii_code(gen, onfail, indent, bare) if gen.ascii
22
+
23
+ generate_utf8_charclass_code(gen, onfail, indent, bare)
25
24
  end
26
25
 
27
- def verify_captures(ctx, capts)
26
+ def generate_reverse_code(gen, onsuccess, indent, bare, oncut: nil)
27
+ raise "unexpected" if gen.ascii
28
+
29
+ generate_utf8_charclass_reverse_code(gen, onsuccess, indent, bare)
28
30
  end
29
31
 
30
- def link_references(ctx)
32
+ def reachability
33
+ charclass = value
34
+ n = charclass&.length || 0
35
+ return Packcr::CODE_REACH__BOTH if charclass.nil? || n > 0
36
+
37
+ Packcr::CODE_REACH__ALWAYS_FAIL
31
38
  end
32
39
 
33
40
  private
34
41
 
35
42
  def generate_utf8_charclass_code(gen, onfail, indent, bare)
36
- charclass = self.value
43
+ charclass = value
37
44
  if charclass && charclass.encoding != Encoding::UTF_8
38
45
  charclass = charclass.dup.force_encoding(Encoding::UTF_8)
39
46
  end
40
47
  n = charclass&.length || 0
41
48
  if charclass.nil? || n > 0
42
- a = charclass && charclass[0] == '^'
43
- i = a ? 1 : 0
44
- gen.write Packcr.template("node/charclass_utf8.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
45
- return Packcr::CODE_REACH__BOTH
49
+ gen.write Packcr.format_code(get_utf8_code(gen, onfail, indent, bare, charclass, n), indent: indent, unwrap: bare)
46
50
  else
47
- gen.write Packcr.template("node/charclass_fail.#{gen.lang}.erb", binding, indent: indent)
48
- return Packcr::CODE_REACH__ALWAYS_FAIL
51
+ gen.write Packcr.format_code(get_fail_code(gen, onfail, indent, bare), indent: indent)
52
+ end
53
+ end
54
+
55
+ def generate_utf8_charclass_reverse_code(gen, onsuccess, indent, bare)
56
+ charclass = value
57
+ if charclass && charclass.encoding != Encoding::UTF_8
58
+ charclass = charclass.dup.force_encoding(Encoding::UTF_8)
49
59
  end
60
+ n = charclass&.length || 0
61
+ return unless charclass.nil? || n > 0
62
+
63
+ gen.write Packcr.format_code(get_utf8_reverse_code(gen, onsuccess, indent, bare, charclass, n), indent: indent, unwrap: bare)
50
64
  end
51
65
 
52
66
  def generate_ascii_code(gen, onfail, indent, bare)
53
- charclass = self.value
67
+ charclass = value
54
68
  if charclass
55
69
  n = charclass.length
56
70
  a = charclass[0] == "^"
@@ -60,20 +74,26 @@ class Packcr
60
74
  end
61
75
  if n > 0
62
76
  if n > 1
63
- gen.write Packcr.template("node/charclass.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
77
+ gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, charclass, n, a), indent: indent, unwrap: bare)
64
78
  else
65
- gen.write Packcr.template("node/charclass_one.#{gen.lang}.erb", binding, indent: indent)
79
+ gen.write Packcr.format_code(get_one_code(gen, onfail, indent, bare, charclass, n, a), indent: indent)
66
80
  end
67
- return Packcr::CODE_REACH__BOTH
68
81
  else
69
- gen.write Packcr.template("node/charclass_fail.#{gen.lang}.erb", binding, indent: indent)
70
- return Packcr::CODE_REACH__ALWAYS_FAIL
82
+ gen.write Packcr.format_code(get_fail_code(gen, onfail, indent, bare), indent: indent)
71
83
  end
72
84
  else
73
- gen.write Packcr.template("node/charclass_any.#{gen.lang}.erb", binding, indent: indent)
74
- return Packcr::CODE_REACH__BOTH
85
+ gen.write Packcr.format_code(get_any_code(gen, onfail, indent, bare, charclass), indent: indent)
75
86
  end
76
87
  end
88
+
89
+ def to_h
90
+ {
91
+ type: :charclass,
92
+ value: value,
93
+ }
94
+ end
77
95
  end
78
96
  end
79
97
  end
98
+
99
+ require "packcr/generated/node/charclass_node"
@@ -0,0 +1,25 @@
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.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
10
+ end
11
+
12
+ def reachability
13
+ Packcr::CODE_REACH__BOTH
14
+ end
15
+
16
+ def to_h
17
+ {
18
+ type: :eof,
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ require "packcr/generated/node/eof_node"
@@ -29,26 +29,22 @@ class Packcr
29
29
  $stdout.print "#{" " * indent}}\n"
30
30
  end
31
31
 
32
- def generate_code(gen, onfail, indent, bare)
33
- l = gen.next_label
34
- m = gen.next_label
35
- r, code = gen.generate_code_str(expr, l, 4, true)
36
- gen.write Packcr.template("node/error.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
37
- return r
32
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
33
+ gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
34
+ end
35
+
36
+ def reachability
37
+ expr.reachability
38
38
  end
39
39
 
40
40
  def verify_variables(vars)
41
41
  @vars = vars
42
- expr.verify_variables(vars)
42
+ super
43
43
  end
44
44
 
45
45
  def verify_captures(ctx, capts)
46
46
  @capts = capts
47
- expr.verify_captures(ctx, capts)
48
- end
49
-
50
- def link_references(ctx)
51
- expr.link_references(ctx)
47
+ super
52
48
  end
53
49
 
54
50
  def nodes
@@ -58,8 +54,19 @@ class Packcr
58
54
  def setup_rule(rule)
59
55
  @index = rule.codes.length
60
56
  rule.codes.push(self)
61
- super
57
+ end
58
+
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
+ }
62
67
  end
63
68
  end
64
69
  end
65
70
  end
71
+
72
+ require "packcr/generated/node/error_node"
@@ -3,8 +3,10 @@ class Packcr
3
3
  class ExpandNode < Packcr::Node
4
4
  attr_accessor :index, :line, :col
5
5
 
6
- def initialize(index = nil)
6
+ def initialize(index = nil, line = nil, col = nil)
7
7
  @index = index
8
+ @line = line
9
+ @col = col
8
10
  end
9
11
 
10
12
  def debug_dump(indent = 0)
@@ -13,12 +15,12 @@ class Packcr
13
15
  $stdout.print ")\n"
14
16
  end
15
17
 
16
- def generate_code(gen, onfail, indent, bare)
17
- gen.write Packcr.template("node/expand.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
18
- return Packcr::CODE_REACH__BOTH
18
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
19
+ gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
19
20
  end
20
21
 
21
- def verify_variables(vars)
22
+ def reachability
23
+ Packcr::CODE_REACH__BOTH
22
24
  end
23
25
 
24
26
  def verify_captures(ctx, capts)
@@ -26,15 +28,22 @@ class Packcr
26
28
  unless capt.is_a?(Packcr::Node::CaptureNode)
27
29
  raise "unexpected capture: #{capt.class}"
28
30
  end
31
+
29
32
  index == capt.index
30
33
  end
31
- if !found && index != nil
32
- ctx.error line + 1, col + 1, "Capture #{index + 1} not available at this position"
33
- end
34
+ return if found || index.nil?
35
+
36
+ ctx.error line + 1, col + 1, "Capture #{index + 1} not available at this position"
34
37
  end
35
38
 
36
- def link_references(ctx)
39
+ def to_h
40
+ {
41
+ type: :expand,
42
+ index: index,
43
+ }
37
44
  end
38
45
  end
39
46
  end
40
47
  end
48
+
49
+ require "packcr/generated/node/expand_node"
@@ -15,42 +15,35 @@ class Packcr
15
15
  $stdout.print "#{" " * indent}}\n"
16
16
  end
17
17
 
18
- def generate_code(gen, onfail, indent, bare)
19
- r = nil
18
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
20
19
  if neg
21
- l = gen.next_label
22
- r, code = gen.generate_code_str(expr, l, 4, false)
23
- gen.write Packcr.template("node/predicate_neg.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
24
- case r
25
- when Packcr::CODE_REACH__ALWAYS_SUCCEED
26
- r = Packcr::CODE_REACH__ALWAYS_FAIL
27
- when Packcr::CODE_REACH__ALWAYS_FAIL
28
- r = Packcr::CODE_REACH__ALWAYS_SUCCEED
29
- end
20
+ gen.write Packcr.format_code(get_neg_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
30
21
  else
31
- l = gen.next_label
32
- m = gen.next_label
33
- r, code = gen.generate_code_str(expr, l, 4, false)
34
- gen.write Packcr.template("node/predicate.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
22
+ gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
35
23
  end
36
- return r
37
24
  end
38
25
 
39
- def verify_variables(vars)
40
- expr.verify_variables(vars)
41
- end
42
-
43
- def verify_captures(ctx, capts)
44
- expr.verify_captures(ctx, capts)
45
- end
46
-
47
- def link_references(ctx)
48
- expr.link_references(ctx)
26
+ def reachability
27
+ if neg
28
+ -expr.reachability
29
+ else
30
+ expr.reachability
31
+ end
49
32
  end
50
33
 
51
34
  def nodes
52
35
  [expr]
53
36
  end
37
+
38
+ def to_h
39
+ {
40
+ type: :predicate,
41
+ expr: expr&.to_h,
42
+ neg: neg,
43
+ }
44
+ end
54
45
  end
55
46
  end
56
47
  end
48
+
49
+ require "packcr/generated/node/predicate_node"
@@ -16,45 +16,52 @@ class Packcr
16
16
  $stdout.print "#{" " * indent}}\n"
17
17
  end
18
18
 
19
- def generate_code(gen, onfail, indent, bare)
19
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
20
20
  if max > 1 || max < 0
21
- r = nil
22
- gen.write Packcr.template("node/quantify_many.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
23
- if min <= 0
24
- return Packcr::CODE_REACH__ALWAYS_SUCCEED
25
- end
26
- if r == Packcr::CODE_REACH__ALWAYS_FAIL
27
- return Packcr::CODE_REACH__ALWAYS_FAIL
28
- end
29
- return Packcr::CODE_REACH__BOTH
21
+ gen.write Packcr.format_code(get_many_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
30
22
  elsif max == 1
31
23
  if min > 0
32
- return gen.generate_code(expr, onfail, indent, bare)
24
+ gen.write gen.generate_code(expr, onfail, indent, bare, oncut: oncut)
33
25
  else
34
- gen.write Packcr.template("node/quantify_one.#{gen.lang}.erb", binding, indent: indent, unwrap: bare)
35
- return Packcr::CODE_REACH__ALWAYS_SUCCEED
26
+ gen.write Packcr.format_code(get_one_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
36
27
  end
37
- else
38
- # no code to generate
39
- return Packcr::CODE_REACH__ALWAYS_SUCCEED
40
28
  end
41
29
  end
42
30
 
43
- def verify_variables(vars)
44
- expr.verify_variables(vars)
45
- end
31
+ def reachability
32
+ if max > 1 || max < 0
33
+ if min <= 0
34
+ return Packcr::CODE_REACH__ALWAYS_SUCCEED
35
+ end
36
+ if expr.reachability == Packcr::CODE_REACH__ALWAYS_FAIL
37
+ return Packcr::CODE_REACH__ALWAYS_FAIL
38
+ end
46
39
 
47
- def verify_captures(ctx, capts)
48
- expr.verify_captures(ctx, capts)
49
- end
40
+ Packcr::CODE_REACH__BOTH
41
+ elsif max == 1
42
+ return expr.reachability if min > 0
43
+
44
+ Packcr::CODE_REACH__ALWAYS_SUCCEED
50
45
 
51
- def link_references(ctx)
52
- expr.link_references(ctx)
46
+ else
47
+ Packcr::CODE_REACH__ALWAYS_SUCCEED
48
+ end
53
49
  end
54
50
 
55
51
  def nodes
56
52
  [expr]
57
53
  end
54
+
55
+ def to_h
56
+ {
57
+ type: :predicate,
58
+ expr: expr&.to_h,
59
+ min: min,
60
+ max: max,
61
+ }
62
+ end
58
63
  end
59
64
  end
60
65
  end
66
+
67
+ require "packcr/generated/node/quantity_node"
@@ -16,17 +16,30 @@ class Packcr
16
16
  $stdout.print ", name:'#{name}', rule:'#{rule&.name || "(null)"}')\n"
17
17
  end
18
18
 
19
- def generate_code(gen, onfail, indent, bare)
20
- gen.write Packcr.template("node/reference.#{gen.lang}.erb", binding, indent: indent)
19
+ def reversible?(gen)
20
+ gen.lang == :rb
21
+ end
22
+
23
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
24
+ gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
25
+ end
26
+
27
+ def generate_reverse_code(gen, onsuccess, indent, bare, oncut: nil)
28
+ gen.write Packcr.format_code(get_reverse_code(gen, onsuccess, indent, bare, oncut), indent: indent)
29
+ end
30
+
31
+ def reachability
21
32
  Packcr::CODE_REACH__BOTH
22
33
  end
23
34
 
24
35
  def setup_rule(rule)
25
36
  return unless var
37
+
26
38
  i = rule.vars.index do |ref|
27
39
  unless ref.is_a?(Packcr::Node::ReferenceNode)
28
40
  raise "Unexpected node type: #{ref.class}"
29
41
  end
42
+
30
43
  var == ref.var
31
44
  end
32
45
  if !i
@@ -43,26 +56,35 @@ class Packcr
43
56
  unless var.is_a?(Packcr::Node::ReferenceNode)
44
57
  raise "unexpected var: #{var.class}"
45
58
  end
59
+
46
60
  index == var.index
47
61
  end
48
62
  vars.push(self) if !found
49
63
  end
50
64
 
51
- def verify_captures(ctx, capts)
52
- end
53
-
54
65
  def link_references(ctx)
55
- rule = ctx.rule(name)
56
- if !rule
57
- ctx.error line + 1, col + 1, "No definition of rule '#{name}'"
58
- else
66
+ rule = ctx.root.rule(name)
67
+ if rule
59
68
  unless rule.is_a?(Packcr::Node::RuleNode)
60
69
  raise "unexpected node type #{rule.class}"
61
70
  end
71
+
62
72
  rule.add_ref
63
73
  self.rule = rule
74
+ else
75
+ ctx.error line + 1, col + 1, "No definition of rule '#{name}'"
64
76
  end
65
77
  end
78
+
79
+ def to_h
80
+ {
81
+ type: :reference,
82
+ name: name,
83
+ var: var,
84
+ }
85
+ end
66
86
  end
67
87
  end
68
88
  end
89
+
90
+ require "packcr/generated/node/reference_node"
@@ -0,0 +1,61 @@
1
+ class Packcr
2
+ class Node
3
+ class RootNode < Packcr::Node
4
+ attr_accessor :rules
5
+ attr_reader :rulehash
6
+
7
+ def initialize
8
+ @rules = []
9
+ @rulehash = {}
10
+ @implicit_rules = []
11
+ end
12
+
13
+ def debug_dump
14
+ @rules.each(&:debug_dump)
15
+ end
16
+
17
+ def make_rulehash(ctx)
18
+ @rules.each do |rule|
19
+ if @rulehash[rule.name]
20
+ ctx.error rule.line + 1, rule.col + 1, "Multiple definition of rule '#{rule.name}'"
21
+ else
22
+ @rulehash[rule.name] = rule
23
+ end
24
+ end
25
+ end
26
+
27
+ def setup(ctx)
28
+ make_rulehash(ctx)
29
+ @rules.first&.top = true
30
+ @rules.each do |rule|
31
+ rule.setup(ctx)
32
+ end
33
+ @rules.each do |rule|
34
+ rule.verify(ctx)
35
+ end
36
+ end
37
+
38
+ def rule(name)
39
+ rule = @rulehash[name]
40
+ return rule if rule
41
+
42
+ case name
43
+ when "EOF"
44
+ expr = Packcr::Node::EofNode.new
45
+ else
46
+ return nil
47
+ end
48
+ rule = Packcr::Node::RuleNode.new(expr, name)
49
+ @rules << rule
50
+ @rulehash[name] = rule
51
+ end
52
+
53
+ def to_h
54
+ {
55
+ type: :root,
56
+ rules: rules.map(&:to_h),
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,7 +1,7 @@
1
1
  class Packcr
2
2
  class Node
3
3
  class RuleNode < Packcr::Node
4
- attr_accessor :codes, :name, :expr, :ref, :vars, :capts, :line, :col
4
+ attr_accessor :codes, :name, :expr, :ref, :vars, :capts, :line, :col, :top
5
5
 
6
6
  def initialize(expr = nil, name = nil, line = nil, col = nil)
7
7
  super()
@@ -21,22 +21,48 @@ class Packcr
21
21
  $stdout.print "#{" " * indent}}\n"
22
22
  end
23
23
 
24
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
25
+ gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent, unwrap: bare)
26
+ end
27
+
28
+ def reachability
29
+ expr.reachability
30
+ end
31
+
24
32
  def verify(ctx)
25
33
  expr.verify_variables([])
26
34
  expr.verify_captures(ctx, [])
35
+ verify_rule_reference(ctx)
36
+ end
37
+
38
+ def verify_rule_reference(ctx)
39
+ return if top
40
+
41
+ return unless ref == 0
42
+
43
+ ctx.error line + 1, col + 1, "Never used rule '#{name}'"
27
44
  end
28
45
 
29
46
  def add_ref
30
47
  @ref += 1
31
48
  end
32
49
 
33
- def setup
34
- setup_rule(self)
50
+ def setup(ctx)
51
+ super(ctx, self)
35
52
  end
36
53
 
37
54
  def nodes
38
55
  [expr]
39
56
  end
57
+
58
+ def to_h
59
+ {
60
+ type: :rule,
61
+ expr: expr&.to_h,
62
+ }
63
+ end
40
64
  end
41
65
  end
42
66
  end
67
+
68
+ require "packcr/generated/node/rule_node"
@@ -3,18 +3,44 @@ class Packcr
3
3
  class SequenceNode < Packcr::Node
4
4
  attr_accessor :nodes
5
5
 
6
- def initialize(*nodes)
6
+ def initialize(*nodes, cut: false)
7
7
  super()
8
8
  self.nodes = nodes
9
+ @cut = cut
9
10
  end
10
11
 
11
- def seq(node)
12
- @nodes << node
12
+ def sequence?
13
+ true
14
+ end
15
+
16
+ def seq(node, cut: false)
17
+ if node&.sequence?
18
+ node.nodes.each do |child|
19
+ seq(child, cut: cut)
20
+ cut = false
21
+ end
22
+ return self
23
+ end
24
+
25
+ if cut
26
+ if node
27
+ node = Packcr::Node::SequenceNode.new(node, cut: true)
28
+ else
29
+ node = Packcr::Node::SequenceNode.new(cut: true)
30
+ end
31
+ end
32
+ if node
33
+ if @nodes.last.sequence?
34
+ @nodes.last.seq(node)
35
+ else
36
+ @nodes << node
37
+ end
38
+ end
13
39
  self
14
40
  end
15
41
 
16
42
  def debug_dump(indent = 0)
17
- $stdout.print "#{" " * indent}Sequence(max:#{max}, len:#{nodes.length}) {\n"
43
+ $stdout.print "#{" " * indent}Sequence(max:#{max}, len:#{nodes.length}#{@cut ? ", cut: true" : ""}) {\n"
18
44
  nodes.each do |child_node|
19
45
  child_node.debug_dump(indent + 2)
20
46
  end
@@ -27,40 +53,31 @@ class Packcr
27
53
  m
28
54
  end
29
55
 
30
- def generate_code(gen, onfail, indent, bare)
31
- b = false
32
- nodes.each_with_index do |expr, i|
33
- case gen.generate_code(expr, onfail, indent, false)
56
+ def generate_code(gen, onfail, indent, bare, oncut: nil)
57
+ gen.write Packcr.format_code(get_code(gen, onfail, indent, bare, oncut), indent: indent)
58
+ end
59
+
60
+ def reachability
61
+ r = Packcr::CODE_REACH__ALWAYS_SUCCEED
62
+ nodes.each do |expr|
63
+ case expr.reachability
34
64
  when Packcr::CODE_REACH__ALWAYS_FAIL
35
- if i + 1 < nodes.length
36
- gen.write Packcr.template("node/sequence_unreachable.#{gen.lang}.erb", binding, indent: indent)
37
- end
38
65
  return Packcr::CODE_REACH__ALWAYS_FAIL
39
- when Packcr::CODE_REACH__ALWAYS_SUCCEED
40
- else
41
- b = true
66
+ when Packcr::CODE_REACH__BOTH
67
+ r = Packcr::CODE_REACH__BOTH
42
68
  end
43
69
  end
44
- return b ? Packcr::CODE_REACH__BOTH : Packcr::CODE_REACH__ALWAYS_SUCCEED
70
+ r
45
71
  end
46
72
 
47
- def verify_variables(vars)
48
- nodes.each do |node|
49
- node.verify_variables(vars)
50
- end
51
- end
52
-
53
- def verify_captures(ctx, capts)
54
- nodes.each do |node|
55
- node.verify_captures(ctx, capts)
56
- end
57
- end
58
-
59
- def link_references(ctx)
60
- nodes.each do |node|
61
- node.link_references(ctx)
62
- end
73
+ def to_h
74
+ {
75
+ type: :sequence,
76
+ nodes: nodes.map(&:to_h),
77
+ }
63
78
  end
64
79
  end
65
80
  end
66
81
  end
82
+
83
+ require "packcr/generated/node/sequence_node"