packcr 0.0.4 → 0.0.7

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