antelope 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +25 -25
  3. data/.rspec +3 -3
  4. data/.travis.yml +10 -10
  5. data/.yardopts +7 -7
  6. data/CONTRIBUTING.md +50 -38
  7. data/GENERATORS.md +180 -124
  8. data/Gemfile +7 -7
  9. data/LICENSE.txt +22 -22
  10. data/README.md +240 -104
  11. data/Rakefile +2 -2
  12. data/TODO.md +58 -58
  13. data/antelope.gemspec +29 -28
  14. data/bin/antelope +7 -7
  15. data/examples/deterministic.ace +35 -35
  16. data/examples/example.ace +52 -51
  17. data/examples/example.ace.err +192 -192
  18. data/examples/example.ace.inf +432 -432
  19. data/examples/example.ate +70 -70
  20. data/examples/example.ate.err +192 -192
  21. data/examples/example.ate.inf +432 -432
  22. data/examples/liquidscript.ace +233 -233
  23. data/examples/simple.ace +22 -22
  24. data/lib/antelope/ace/compiler.rb +334 -334
  25. data/lib/antelope/ace/errors.rb +30 -30
  26. data/lib/antelope/ace/scanner/argument.rb +57 -57
  27. data/lib/antelope/ace/scanner/first.rb +89 -89
  28. data/lib/antelope/ace/scanner/second.rb +178 -178
  29. data/lib/antelope/ace/scanner/third.rb +27 -27
  30. data/lib/antelope/ace/scanner.rb +144 -144
  31. data/lib/antelope/ace.rb +47 -47
  32. data/lib/antelope/cli.rb +60 -60
  33. data/lib/antelope/errors.rb +25 -25
  34. data/lib/antelope/generation/constructor/first.rb +86 -86
  35. data/lib/antelope/generation/constructor/follow.rb +105 -105
  36. data/lib/antelope/generation/constructor/nullable.rb +64 -64
  37. data/lib/antelope/generation/constructor.rb +127 -127
  38. data/lib/antelope/generation/errors.rb +17 -17
  39. data/lib/antelope/generation/null.rb +13 -13
  40. data/lib/antelope/generation/recognizer/rule.rb +216 -216
  41. data/lib/antelope/generation/recognizer/state.rb +129 -129
  42. data/lib/antelope/generation/recognizer.rb +177 -177
  43. data/lib/antelope/generation/tableizer.rb +176 -176
  44. data/lib/antelope/generation.rb +15 -15
  45. data/lib/antelope/generator/base/coerce.rb +115 -0
  46. data/lib/antelope/generator/base/extra.rb +50 -0
  47. data/lib/antelope/generator/base.rb +134 -264
  48. data/lib/antelope/generator/c.rb +11 -11
  49. data/lib/antelope/generator/c_header.rb +105 -105
  50. data/lib/antelope/generator/c_source.rb +39 -39
  51. data/lib/antelope/generator/error.rb +34 -34
  52. data/lib/antelope/generator/group.rb +60 -57
  53. data/lib/antelope/generator/html.rb +51 -51
  54. data/lib/antelope/generator/info.rb +47 -47
  55. data/lib/antelope/generator/null.rb +18 -18
  56. data/lib/antelope/generator/output.rb +17 -17
  57. data/lib/antelope/generator/ruby.rb +112 -79
  58. data/lib/antelope/generator/templates/c_header.ant +36 -36
  59. data/lib/antelope/generator/templates/c_source.ant +202 -202
  60. data/lib/antelope/generator/templates/error.erb +40 -0
  61. data/lib/antelope/generator/templates/html/antelope.css +53 -1
  62. data/lib/antelope/generator/templates/html/antelope.html +82 -1
  63. data/lib/antelope/generator/templates/html/antelope.js +9 -1
  64. data/lib/antelope/generator/templates/html/css.ant +53 -53
  65. data/lib/antelope/generator/templates/html/html.ant +82 -82
  66. data/lib/antelope/generator/templates/html/js.ant +9 -9
  67. data/lib/antelope/generator/templates/info.erb +61 -0
  68. data/lib/antelope/generator/templates/{ruby.ant → ruby.erb} +171 -178
  69. data/lib/antelope/generator.rb +62 -66
  70. data/lib/antelope/grammar/generation.rb +76 -76
  71. data/lib/antelope/grammar/loading.rb +84 -84
  72. data/lib/antelope/grammar/precedence.rb +59 -59
  73. data/lib/antelope/grammar/precedences.rb +64 -64
  74. data/lib/antelope/grammar/production.rb +56 -56
  75. data/lib/antelope/grammar/productions.rb +154 -154
  76. data/lib/antelope/grammar/symbols.rb +64 -64
  77. data/lib/antelope/grammar/token/epsilon.rb +23 -23
  78. data/lib/antelope/grammar/token/error.rb +24 -24
  79. data/lib/antelope/grammar/token/nonterminal.rb +15 -15
  80. data/lib/antelope/grammar/token/terminal.rb +15 -15
  81. data/lib/antelope/grammar/token.rb +231 -231
  82. data/lib/antelope/grammar.rb +68 -68
  83. data/lib/antelope/version.rb +6 -6
  84. data/lib/antelope.rb +18 -19
  85. data/optimizations.txt +42 -42
  86. data/spec/antelope/ace/compiler_spec.rb +60 -60
  87. data/spec/antelope/ace/scanner_spec.rb +27 -27
  88. data/spec/antelope/generation/constructor_spec.rb +131 -131
  89. data/spec/fixtures/simple.ace +22 -22
  90. data/spec/spec_helper.rb +39 -39
  91. data/spec/support/benchmark_helper.rb +5 -5
  92. data/spec/support/grammar_helper.rb +14 -14
  93. data/subl/Ace (Ruby).JSON-tmLanguage +94 -94
  94. data/subl/Ace (Ruby).tmLanguage +153 -153
  95. metadata +22 -11
  96. data/lib/antelope/generator/templates/error.ant +0 -34
  97. data/lib/antelope/generator/templates/info.ant +0 -53
  98. data/lib/antelope/template/compiler.rb +0 -78
  99. data/lib/antelope/template/errors.rb +0 -9
  100. data/lib/antelope/template/scanner.rb +0 -109
  101. data/lib/antelope/template.rb +0 -64
  102. data/spec/antelope/template_spec.rb +0 -50
@@ -0,0 +1,40 @@
1
+ Productions:
2
+ <%
3
+ len = grammar.all_productions.size.to_s.size
4
+ productions = recognizer.states.map(&:rules).inject(:merge).
5
+ select(&:final?).map { |x| [x.to_s(false), x.production.block] }
6
+ body = productions.map { |_| _[0].size }.max
7
+ productions.each do |prod|
8
+ -%>
9
+ <%= sprintf("%-#{body}s", prod[0]) %> <%= prod[1] %>
10
+ <% end -%>
11
+
12
+ <%
13
+ if table.each_with_index.any? { |_, i| tableizer.conflicts[i].each.
14
+ select { |(_, v)| v[:result] == 0 || directives.output.verbose }.any? }
15
+ -%>
16
+ Error:
17
+ <%
18
+ table.each_with_index do |_, i|
19
+ conflicts = tableizer.conflicts[i].each.
20
+ select { |(_, v)| v[:result] == 0 || directives.output.verbose }
21
+ next unless conflicts.any?
22
+ -%>
23
+ Conflicts in State <%= i %>:
24
+ <%- conflicts.each do |token, value| -%>
25
+ On <%= token %><%= ' (resolved)' if value[:result] != 0 %>:
26
+ <%= value[:data][0].join(' ') %>/<%= value[:data][1].join(' ') %> (<%= value[:prec] %> vs <%= value[:terminal] %>, <%= value[:result] %>)
27
+ Rules:
28
+ <%- value[:rules].each do |rule| -%>
29
+ <%= rule %>
30
+ {<%= rule.lookahead.to_a.join(', ') %>}
31
+ <%- end -%>
32
+ Transitions:
33
+ <%- value[:transitions].each do |transition| -%>
34
+ <%= transition %>
35
+ <%- end -%>
36
+ <%- end -%>
37
+ <%- end -%>
38
+ <%- else -%>
39
+ No errors :)
40
+ <%- end -%>
@@ -1 +1,53 @@
1
- css.ant
1
+ body {
2
+ font-family: sans-serif;
3
+ color: #696265;
4
+ background-color: #fefefe;
5
+ }
6
+
7
+ h1, h2, h3, h4, h5, h6 {
8
+ font-family: serif;
9
+ color: #327CCB;
10
+ margin: 0;
11
+ }
12
+
13
+ code, kbd, pre {
14
+ font-family: monospace;
15
+ }
16
+
17
+ .body .section {
18
+ background-color: #f9f9f9;
19
+ padding: 0.5em;
20
+ }
21
+
22
+ .body .section h2 {
23
+ font-size: 1.5em;
24
+ }
25
+
26
+ .body .section h2, .body .section h3, .body .section h4,
27
+ .body .section h5, .body .section h6 {
28
+ padding: 0;
29
+ cursor: pointer;
30
+
31
+ }
32
+
33
+ .body .section .section-data {
34
+ display: none;
35
+ padding: 0.3em 2em;
36
+ }
37
+
38
+ .body .section .section-data.display {
39
+ display: block;
40
+ }
41
+
42
+ .body .section ul {
43
+ list-style-type: none;
44
+ }
45
+
46
+ .body .section ul, .body .section ol {
47
+ margin: 0;
48
+ padding: 0;
49
+ }
50
+
51
+ .conflict.resolved { color: #d9d9d9; }
52
+ .conflict.resolved:before { content: "resolved: "; color: #00B057; }
53
+ code.block { display: block; }
@@ -1 +1,82 @@
1
- html.ant
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <title>Antelope State Data</title>
6
+
7
+ <meta charset="utf-8">
8
+ <link rel="stylesheet" type="text/css" href="%{file}.css">
9
+ </head>
10
+
11
+ <body>
12
+
13
+ <div class="body">
14
+ <div class="section productions">
15
+ <h2>Productions</h2>
16
+ <ol class="rules section-data">
17
+ {{ grammar.all_productions.each do |prod| }}
18
+ <li>
19
+ <code>{{= prod.label }}: {{= prod.items.join(' ') }}</code>
20
+ <code class="block">{{= prod.block }}</code>
21
+ </li>
22
+ {{ end }}
23
+ </ol>
24
+ </div>
25
+
26
+ <div class="section states">
27
+ <h2>States</h2>
28
+ <ul class="section-data">
29
+ {{ states = grammar.states.to_a }}
30
+ {{ table.each_with_index do |v, i| }}
31
+ <li class="section state">
32
+ {{ state = states[i] }}
33
+ <h3>State %{i}</h3>
34
+ <div class="section-data">
35
+ {{ state.rules.each do |rule| }}
36
+ <pre>{{= rule }}
37
+ {{= "{" << rule.lookahead.to_a.join(", ") << "}" }}</pre>
38
+ {{ end }}
39
+ {{
40
+ transitions = v.each.select { |_, a| a && a[0] == :state }
41
+ reductions = v.each.select { |_, a| a && a[0] == :reduce}
42
+ accepting = v.each.select { |_, a| a && a[0] == :accept}
43
+ conflicts = tableizer.conflicts[i].each
44
+ thing = [:transitions, :reductions, :accepting]
45
+ num_type = {
46
+ transitions: "State",
47
+ reductions: "Rule",
48
+ accepting: "Rule"
49
+ }
50
+ h = Hash[thing.zip([transitions, reductions, accepting])]
51
+ }}
52
+ {{ h.each do |key, value| }}
53
+ {{ next unless value.any? }}
54
+ <div class="part">
55
+ <h4>{{= key }}</h4>
56
+ {{ value.each do |token, (_, name)| }}
57
+ {{ token_value = grammar.terminals.find { |_| _.name == token } || token }}
58
+ <div>
59
+ <code>{{= token_value}}: {{= num_type[key] }} {{= name }}</code class="block"></div>
60
+ {{ end }}
61
+ </div>
62
+ {{ end }}
63
+ {{ if conflicts.any? }}
64
+ <div class="part">
65
+ <h4>Conflicts</h4>
66
+ {{ conflicts.each do |token, (value, first, second, rule, terminal)| }}
67
+ <div class="conflict {{ if value != 0 }}resolved{{ end }}">
68
+ <code>{{= token }}: {{= first.join(" ") }}/{{= second.join(" ") }} ({{= rule }} vs {{= terminal }})</code>
69
+ </div>
70
+ {{ end }}
71
+ </div>
72
+ {{ end }}
73
+ </div>
74
+ </li>
75
+ {{ end }}
76
+ </ul>
77
+ </div>
78
+ </div>
79
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
80
+ <script src="%{file}.js"></script>
81
+ </body>
82
+ </html>
@@ -1 +1,9 @@
1
- js.ant
1
+ $(function() {
2
+ $(".section").each(function(i, element) {
3
+ var $element = $(element);
4
+
5
+ $(element).children("h2, h3, h4, h5, h6").on("click", function() {
6
+ $(element).children(".section-data").toggleClass("display");
7
+ });
8
+ });
9
+ });
@@ -1,53 +1,53 @@
1
- body {
2
- font-family: sans-serif;
3
- color: #696265;
4
- background-color: #fefefe;
5
- }
6
-
7
- h1, h2, h3, h4, h5, h6 {
8
- font-family: serif;
9
- color: #327CCB;
10
- margin: 0;
11
- }
12
-
13
- code, kbd, pre {
14
- font-family: monospace;
15
- }
16
-
17
- .body .section {
18
- background-color: #f9f9f9;
19
- padding: 0.5em;
20
- }
21
-
22
- .body .section h2 {
23
- font-size: 1.5em;
24
- }
25
-
26
- .body .section h2, .body .section h3, .body .section h4,
27
- .body .section h5, .body .section h6 {
28
- padding: 0;
29
- cursor: pointer;
30
-
31
- }
32
-
33
- .body .section .section-data {
34
- display: none;
35
- padding: 0.3em 2em;
36
- }
37
-
38
- .body .section .section-data.display {
39
- display: block;
40
- }
41
-
42
- .body .section ul {
43
- list-style-type: none;
44
- }
45
-
46
- .body .section ul, .body .section ol {
47
- margin: 0;
48
- padding: 0;
49
- }
50
-
51
- .conflict.resolved { color: #d9d9d9; }
52
- .conflict.resolved:before { content: "resolved: "; color: #00B057; }
53
- code.block { display: block; }
1
+ body {
2
+ font-family: sans-serif;
3
+ color: #696265;
4
+ background-color: #fefefe;
5
+ }
6
+
7
+ h1, h2, h3, h4, h5, h6 {
8
+ font-family: serif;
9
+ color: #327CCB;
10
+ margin: 0;
11
+ }
12
+
13
+ code, kbd, pre {
14
+ font-family: monospace;
15
+ }
16
+
17
+ .body .section {
18
+ background-color: #f9f9f9;
19
+ padding: 0.5em;
20
+ }
21
+
22
+ .body .section h2 {
23
+ font-size: 1.5em;
24
+ }
25
+
26
+ .body .section h2, .body .section h3, .body .section h4,
27
+ .body .section h5, .body .section h6 {
28
+ padding: 0;
29
+ cursor: pointer;
30
+
31
+ }
32
+
33
+ .body .section .section-data {
34
+ display: none;
35
+ padding: 0.3em 2em;
36
+ }
37
+
38
+ .body .section .section-data.display {
39
+ display: block;
40
+ }
41
+
42
+ .body .section ul {
43
+ list-style-type: none;
44
+ }
45
+
46
+ .body .section ul, .body .section ol {
47
+ margin: 0;
48
+ padding: 0;
49
+ }
50
+
51
+ .conflict.resolved { color: #d9d9d9; }
52
+ .conflict.resolved:before { content: "resolved: "; color: #00B057; }
53
+ code.block { display: block; }
@@ -1,82 +1,82 @@
1
- <!DOCTYPE html>
2
-
3
- <html>
4
- <head>
5
- <title>Antelope State Data</title>
6
-
7
- <meta charset="utf-8">
8
- <link rel="stylesheet" type="text/css" href="%{file}.css">
9
- </head>
10
-
11
- <body>
12
-
13
- <div class="body">
14
- <div class="section productions">
15
- <h2>Productions</h2>
16
- <ol class="rules section-data">
17
- {{ grammar.all_productions.each do |prod| }}
18
- <li>
19
- <code>{{= prod.label }}: {{= prod.items.join(' ') }}</code>
20
- <code class="block">{{= prod.block }}</code>
21
- </li>
22
- {{ end }}
23
- </ol>
24
- </div>
25
-
26
- <div class="section states">
27
- <h2>States</h2>
28
- <ul class="section-data">
29
- {{ states = grammar.states.to_a }}
30
- {{ table.each_with_index do |v, i| }}
31
- <li class="section state">
32
- {{ state = states[i] }}
33
- <h3>State %{i}</h3>
34
- <div class="section-data">
35
- {{ state.rules.each do |rule| }}
36
- <pre>{{= rule }}
37
- {{= "{" << rule.lookahead.to_a.join(", ") << "}" }}</pre>
38
- {{ end }}
39
- {{
40
- transitions = v.each.select { |_, a| a && a[0] == :state }
41
- reductions = v.each.select { |_, a| a && a[0] == :reduce}
42
- accepting = v.each.select { |_, a| a && a[0] == :accept}
43
- conflicts = tableizer.conflicts[i].each
44
- thing = [:transitions, :reductions, :accepting]
45
- num_type = {
46
- transitions: "State",
47
- reductions: "Rule",
48
- accepting: "Rule"
49
- }
50
- h = Hash[thing.zip([transitions, reductions, accepting])]
51
- }}
52
- {{ h.each do |key, value| }}
53
- {{ next unless value.any? }}
54
- <div class="part">
55
- <h4>{{= key }}</h4>
56
- {{ value.each do |token, (_, name)| }}
57
- {{ token_value = grammar.terminals.find { |_| _.name == token } || token }}
58
- <div>
59
- <code>{{= token_value}}: {{= num_type[key] }} {{= name }}</code class="block"></div>
60
- {{ end }}
61
- </div>
62
- {{ end }}
63
- {{ if conflicts.any? }}
64
- <div class="part">
65
- <h4>Conflicts</h4>
66
- {{ conflicts.each do |token, (value, first, second, rule, terminal)| }}
67
- <div class="conflict {{ if value != 0 }}resolved{{ end }}">
68
- <code>{{= token }}: {{= first.join(" ") }}/{{= second.join(" ") }} ({{= rule }} vs {{= terminal }})</code>
69
- </div>
70
- {{ end }}
71
- </div>
72
- {{ end }}
73
- </div>
74
- </li>
75
- {{ end }}
76
- </ul>
77
- </div>
78
- </div>
79
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
80
- <script src="%{file}.js"></script>
81
- </body>
82
- </html>
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <title>Antelope State Data</title>
6
+
7
+ <meta charset="utf-8">
8
+ <link rel="stylesheet" type="text/css" href="%{file}.css">
9
+ </head>
10
+
11
+ <body>
12
+
13
+ <div class="body">
14
+ <div class="section productions">
15
+ <h2>Productions</h2>
16
+ <ol class="rules section-data">
17
+ {{ grammar.all_productions.each do |prod| }}
18
+ <li>
19
+ <code>{{= prod.label }}: {{= prod.items.join(' ') }}</code>
20
+ <code class="block">{{= prod.block }}</code>
21
+ </li>
22
+ {{ end }}
23
+ </ol>
24
+ </div>
25
+
26
+ <div class="section states">
27
+ <h2>States</h2>
28
+ <ul class="section-data">
29
+ {{ states = grammar.states.to_a }}
30
+ {{ table.each_with_index do |v, i| }}
31
+ <li class="section state">
32
+ {{ state = states[i] }}
33
+ <h3>State %{i}</h3>
34
+ <div class="section-data">
35
+ {{ state.rules.each do |rule| }}
36
+ <pre>{{= rule }}
37
+ {{= "{" << rule.lookahead.to_a.join(", ") << "}" }}</pre>
38
+ {{ end }}
39
+ {{
40
+ transitions = v.each.select { |_, a| a && a[0] == :state }
41
+ reductions = v.each.select { |_, a| a && a[0] == :reduce}
42
+ accepting = v.each.select { |_, a| a && a[0] == :accept}
43
+ conflicts = tableizer.conflicts[i].each
44
+ thing = [:transitions, :reductions, :accepting]
45
+ num_type = {
46
+ transitions: "State",
47
+ reductions: "Rule",
48
+ accepting: "Rule"
49
+ }
50
+ h = Hash[thing.zip([transitions, reductions, accepting])]
51
+ }}
52
+ {{ h.each do |key, value| }}
53
+ {{ next unless value.any? }}
54
+ <div class="part">
55
+ <h4>{{= key }}</h4>
56
+ {{ value.each do |token, (_, name)| }}
57
+ {{ token_value = grammar.terminals.find { |_| _.name == token } || token }}
58
+ <div>
59
+ <code>{{= token_value}}: {{= num_type[key] }} {{= name }}</code class="block"></div>
60
+ {{ end }}
61
+ </div>
62
+ {{ end }}
63
+ {{ if conflicts.any? }}
64
+ <div class="part">
65
+ <h4>Conflicts</h4>
66
+ {{ conflicts.each do |token, (value, first, second, rule, terminal)| }}
67
+ <div class="conflict {{ if value != 0 }}resolved{{ end }}">
68
+ <code>{{= token }}: {{= first.join(" ") }}/{{= second.join(" ") }} ({{= rule }} vs {{= terminal }})</code>
69
+ </div>
70
+ {{ end }}
71
+ </div>
72
+ {{ end }}
73
+ </div>
74
+ </li>
75
+ {{ end }}
76
+ </ul>
77
+ </div>
78
+ </div>
79
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
80
+ <script src="%{file}.js"></script>
81
+ </body>
82
+ </html>
@@ -1,9 +1,9 @@
1
- $(function() {
2
- $(".section").each(function(i, element) {
3
- var $element = $(element);
4
-
5
- $(element).children("h2, h3, h4, h5, h6").on("click", function() {
6
- $(element).children(".section-data").toggleClass("display");
7
- });
8
- });
9
- });
1
+ $(function() {
2
+ $(".section").each(function(i, element) {
3
+ var $element = $(element);
4
+
5
+ $(element).children("h2, h3, h4, h5, h6").on("click", function() {
6
+ $(element).children(".section-data").toggleClass("display");
7
+ });
8
+ });
9
+ });
@@ -0,0 +1,61 @@
1
+ Productions:
2
+ <%
3
+ len = grammar.all_productions.size.to_s.size
4
+ productions = recognizer.states.map(&:rules).inject(:merge).
5
+ select(&:final?).map { |x| [x.to_s(false), x.production.block] }
6
+ body = productions.map { |_| _[0].size }.max
7
+ productions.each do |prod|
8
+ -%>
9
+ <%= sprintf("%-#{body}s", prod[0]) %> <%= prod[1] %>
10
+ <% end -%>
11
+
12
+ <% if unused_symbols.any? -%>
13
+ Symbols unused in grammar:
14
+ <%- unused_symbols.each do |sym| -%>
15
+ <%= sym %>
16
+ <%- end -%>
17
+ <%- end -%>
18
+
19
+ Precedence:
20
+ --- highest
21
+ <% grammar.precedence.each do |pr| -%>
22
+ <%= format("%-8s", pr.type) %> <%= pr.level %>:
23
+ <%= "{" << pr.tokens.to_a.join(", ") << "}" %>
24
+ <%- end -%>
25
+ --- lowest
26
+
27
+ <%
28
+ states = grammar.states.to_a
29
+ table.each_with_index do |v, i|
30
+ state = states[i]
31
+ -%>
32
+ State <%= i %>:
33
+ <%- state.rules.each do |rule| -%>
34
+ <%= rule %>
35
+ {<%= rule.lookahead.to_a.join(", ") %>}
36
+ <%
37
+ end
38
+ transitions = v.each.select { |_, a| a && a[0] == :state }
39
+ reductions = v.each.select { |_, a| a && a[0] == :reduce}
40
+ accepting = v.each.select { |_, a| a && a[0] == :accept}
41
+ thing = [:transitions, :reductions, :accepting]
42
+ num_type = {
43
+ transitions: "State",
44
+ reductions: "Rule",
45
+ accepting: "Rule"
46
+ }
47
+ h = Hash[thing.zip([transitions, reductions, accepting])]
48
+ h.each do |key, value|
49
+ next unless value.any?
50
+ -%>
51
+ <%= key %>:
52
+ <%
53
+ value.each do |token, (_, name)|
54
+ token_value = grammar.terminals.
55
+ find { |_| _.name == token } || token
56
+ -%>
57
+ <%= token_value %>: <%= num_type[key] %> <%= name %>
58
+ <%- end -%>
59
+ <%- end -%>
60
+
61
+ <%- end -%>