antelope 0.2.0 → 0.2.2

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 (96) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +25 -23
  3. data/.rspec +3 -3
  4. data/.travis.yml +10 -9
  5. data/.yardopts +7 -7
  6. data/CONTRIBUTING.md +38 -38
  7. data/GENERATORS.md +124 -124
  8. data/Gemfile +7 -7
  9. data/LICENSE.txt +22 -22
  10. data/README.md +104 -104
  11. data/Rakefile +2 -2
  12. data/TODO.md +58 -58
  13. data/antelope.gemspec +28 -28
  14. data/bin/antelope +7 -7
  15. data/examples/deterministic.ace +35 -35
  16. data/examples/example.ace +51 -50
  17. data/examples/example.err +192 -0
  18. data/examples/{example.output → example.inf} +384 -385
  19. data/examples/liquidscript.ace +233 -162
  20. data/examples/simple.ace +22 -22
  21. data/lib/antelope/ace/compiler.rb +334 -334
  22. data/lib/antelope/ace/errors.rb +48 -48
  23. data/lib/antelope/ace/grammar/generation.rb +80 -80
  24. data/lib/antelope/ace/grammar/loading.rb +53 -53
  25. data/lib/antelope/ace/grammar/precedences.rb +68 -65
  26. data/lib/antelope/ace/grammar/productions.rb +156 -150
  27. data/lib/antelope/ace/grammar/symbols.rb +66 -66
  28. data/lib/antelope/ace/grammar.rb +69 -69
  29. data/lib/antelope/ace/precedence.rb +61 -61
  30. data/lib/antelope/ace/production.rb +57 -57
  31. data/lib/antelope/ace/scanner/argument.rb +57 -57
  32. data/lib/antelope/ace/scanner/first.rb +89 -89
  33. data/lib/antelope/ace/scanner/second.rb +177 -177
  34. data/lib/antelope/ace/scanner/third.rb +27 -27
  35. data/lib/antelope/ace/scanner.rb +134 -134
  36. data/lib/antelope/ace/token/epsilon.rb +24 -24
  37. data/lib/antelope/ace/token/error.rb +26 -26
  38. data/lib/antelope/ace/token/nonterminal.rb +17 -17
  39. data/lib/antelope/ace/token/terminal.rb +17 -17
  40. data/lib/antelope/ace/token.rb +238 -238
  41. data/lib/antelope/ace.rb +53 -53
  42. data/lib/antelope/cli.rb +55 -55
  43. data/lib/antelope/errors.rb +8 -8
  44. data/lib/antelope/generation/constructor/first.rb +88 -88
  45. data/lib/antelope/generation/constructor/follow.rb +103 -103
  46. data/lib/antelope/generation/constructor/nullable.rb +64 -64
  47. data/lib/antelope/generation/constructor.rb +126 -126
  48. data/lib/antelope/generation/errors.rb +17 -17
  49. data/lib/antelope/generation/null.rb +13 -13
  50. data/lib/antelope/generation/recognizer/rule.rb +216 -216
  51. data/lib/antelope/generation/recognizer/state.rb +130 -130
  52. data/lib/antelope/generation/recognizer.rb +180 -180
  53. data/lib/antelope/generation/tableizer.rb +175 -154
  54. data/lib/antelope/generation.rb +15 -15
  55. data/lib/antelope/generator/base.rb +264 -264
  56. data/lib/antelope/generator/c.rb +11 -11
  57. data/lib/antelope/generator/c_header.rb +105 -105
  58. data/lib/antelope/generator/c_source.rb +39 -39
  59. data/lib/antelope/generator/error.rb +34 -0
  60. data/lib/antelope/generator/group.rb +57 -57
  61. data/lib/antelope/generator/html.rb +51 -0
  62. data/lib/antelope/generator/info.rb +47 -0
  63. data/lib/antelope/generator/null.rb +18 -18
  64. data/lib/antelope/generator/output.rb +17 -49
  65. data/lib/antelope/generator/ruby.rb +79 -79
  66. data/lib/antelope/generator/templates/c_header.ant +36 -36
  67. data/lib/antelope/generator/templates/c_source.ant +202 -202
  68. data/lib/antelope/generator/templates/error.ant +33 -0
  69. data/lib/antelope/generator/templates/html/antelope.css +1 -0
  70. data/lib/antelope/generator/templates/html/antelope.html +1 -0
  71. data/lib/antelope/generator/templates/html/antelope.js +1 -0
  72. data/lib/antelope/generator/templates/html/css.ant +53 -0
  73. data/lib/antelope/generator/templates/html/html.ant +82 -0
  74. data/lib/antelope/generator/templates/html/js.ant +9 -0
  75. data/lib/antelope/generator/templates/info.ant +53 -0
  76. data/lib/antelope/generator/templates/ruby.ant +178 -146
  77. data/lib/antelope/generator.rb +66 -63
  78. data/lib/antelope/template/compiler.rb +78 -78
  79. data/lib/antelope/template/errors.rb +9 -9
  80. data/lib/antelope/template/scanner.rb +109 -109
  81. data/lib/antelope/template.rb +65 -60
  82. data/lib/antelope/version.rb +6 -6
  83. data/lib/antelope.rb +13 -13
  84. data/optimizations.txt +42 -0
  85. data/spec/antelope/ace/compiler_spec.rb +60 -60
  86. data/spec/antelope/ace/scanner_spec.rb +27 -27
  87. data/spec/antelope/constructor_spec.rb +133 -136
  88. data/spec/antelope/template_spec.rb +50 -49
  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 +15 -15
  93. data/subl/Ace (Ruby).JSON-tmLanguage +94 -94
  94. data/subl/Ace (Ruby).tmLanguage +153 -153
  95. metadata +17 -6
  96. data/lib/antelope/generator/templates/output.ant +0 -68
@@ -1,334 +1,334 @@
1
- # encoding: utf-8
2
-
3
- require "rubygems/requirement"
4
-
5
- module Antelope
6
- module Ace
7
-
8
- # Compiles a set of tokens generated by {Scanner}. These tokens
9
- # may not nessicarily have been generated by {Scanner}, however
10
- # the tokens must follow the same rules even still.
11
- #
12
- # A list of all tokens that this compiler accepts:
13
- #
14
- # - `:directive` (2 arguments)
15
- # - `:copy` (1 argument)
16
- # - `:second` (no arguments)
17
- # - `:label` (2 arguments)
18
- # - `:part` (2 arguments)
19
- # - `:or` (no arguments)
20
- # - `:prec` (1 argument)
21
- # - `:block` (1 argument)
22
- # - `:third` (no arguments)
23
- # - `:body` (1 argument)
24
- #
25
- # The tokens are handled by methods that follow the rule
26
- # `compile_<token name>`.
27
- class Compiler
28
-
29
- # The body of the output compiler. This should be formatted in
30
- # the language that the parser is to be written in. Some output
31
- # generators may have special syntax that allows the parser to
32
- # be put in the body; see the output generators for more.
33
- #
34
- # @return [String]
35
- attr_accessor :body
36
-
37
- # A list of all the rules that are defined in the file. The
38
- # rules are defined as such:
39
- #
40
- # - **`label`** (`Symbol`) &mdash; The left-hand side of the rule;
41
- # this is the nonterminal that the right side reduces to.
42
- # - **`set`** (`Array<Symbol>`) &mdash; The right-hand side of the
43
- # rule. This is a combination of terminals and nonterminals.
44
- # - **`block`** (`String`) &mdash; The code to be run on a reduction.
45
- # this should be formatted in the language that the output
46
- # parser is written in. Optional; default value is `""`.
47
- # - **`prec`** (`String`) &mdash; The precedence level for the
48
- # rule. This should be a nonterminal or terminal. Optional;
49
- # default value is `""`.
50
- #
51
- # @return [Array<Hash>]
52
- attr_accessor :rules
53
-
54
- # Options defined by directives in the first part of the file.
55
- #
56
- # - **`:terminals`** (`Array<Symbol, String?)>)` &mdash; A list
57
- # of all of the terminals in the language. If this is not
58
- # properly defined, the grammar will throw an error saying
59
- # that a symbol used in the grammar is not defined.
60
- # - **`:prec`** (`Array<(Symbol, Array<Symbol>)>`) &mdash; A list
61
- # of the precedence rules of the grammar. The first element
62
- # of each element is the _type_ of precedence (and should be
63
- # any of `:left`, `:right`, or `:nonassoc`), and the second
64
- # element should be the symbols that are on that level.
65
- # - **`:type`** (`String`) &mdash; The type of generator to
66
- # generate; this should be a language.
67
- # - **`:extra`** (`Hash<Symbol, Array<Object>>`) &mdash; Extra
68
- # options that are not defined here.
69
- # @return [Hash]
70
- attr_accessor :options
71
-
72
- # Creates a compiler, and then runs the compiler.
73
- #
74
- # @param (see #initialize)
75
- # @see #compile
76
- # @return [Compiler] the compiler.
77
- def self.compile(tokens)
78
- new(tokens).compile
79
- end
80
-
81
- # Initialize the compiler. The compiler keeps track of a state;
82
- # this state is basically which part of the file we're in. The
83
- # state can be `:first`, `:second`, or `:third`; some tokens
84
- # may not exist in certain states.
85
- #
86
- # @param tokens [Array<Array<(Symbol, Object, ...)>>] the tokens
87
- # from the {Scanner}.
88
- def initialize(tokens)
89
- @tokens = tokens
90
- @body = ""
91
- @state = :first
92
- @rules = []
93
- @current = nil
94
- @current_label = nil
95
- @options = {
96
- :terminals => [],
97
- :nonterminals => [],
98
- :prec => [],
99
- :type => nil,
100
- :extra => Hashie::Extensions::IndifferentAccess.
101
- inject!({})
102
- }
103
- end
104
-
105
- # Pretty inspect.
106
- #
107
- # @return [String]
108
- def inspect
109
- "#<#{self.class} state=#{@state.inspect} options=#{options.inspect}>"
110
- end
111
-
112
- # Runs the compiler on the input tokens. For each token,
113
- # it calls `compile_<type>` with `<type>` being the first
114
- # element of the token, with the remaining part of the array
115
- # passed as arguments.
116
- #
117
- # @return [self]
118
- def compile
119
- @tokens.each do |token|
120
- send(:"compile_#{token[0]}", *token[1..-1])
121
- end
122
-
123
- self
124
- end
125
-
126
- # Compiles a directive. This may only be triggered in the first
127
- # section of the file. The directive accepts two arguments. The
128
- # directive name can be any of the following:
129
- #
130
- # - `:terminal` &mdash; adds a terminal. Requires 1-2
131
- # arguments; the first argument is the terminal name, and the
132
- # second argument is a string that can represent the terminal.
133
- # - `:require` &mdash; requires a certain version of Antelope.
134
- # Requires 1 argument. If the first argument is a version
135
- # greater than the current version of Antelope, it raises
136
- # an error.
137
- # - `:left` &mdash; creates a new precedence level, with the
138
- # argument values being the symbols. The precedence level
139
- # is left associative.
140
- # - `:right` &mdash; creates a new precedence level, with the
141
- # argument valeus being the symbols. The precedence level
142
- # is right associative.
143
- # - `:nonassoc` &mdash; creates a nre precedence level, with the
144
- # argument values being the symbols. The precedence level
145
- # is nonassociative.
146
- # - `:type` &mdash; the type of parser to generate. This should
147
- # correspond to the output language of the parser.
148
- #
149
- # @param name [String, Symbol] the name of the directive.
150
- # Accepts any of `:terminal`, `:require`, `:left`, `:right`,
151
- # `:nonassoc`, and `:type`. Any other values produce an
152
- # error on stderr and are put in the `:extra` hash on
153
- # {#options}.
154
- # @param args [Array<String>] the arguments to the directive.
155
- # @return [void]
156
- # @see #options
157
- def compile_directive(name, args)
158
- require_state! :first
159
- name = name.intern
160
- case name
161
- when :terminal, :token
162
- handle_token(args)
163
- when :require
164
- compare_versions(args[0])
165
- when :left, :right, :nonassoc
166
- options[:prec] << [name, *args.map(&:intern)]
167
- when :language, :generator, :"grammar.type"
168
- options[:type] = args[0].downcase
169
- when :type
170
- raise SyntaxError, "%type directive requires first " \
171
- "argument to be caret" unless args[0].caret?
172
-
173
- options[:nonterminals] <<
174
- [args[0], args[1..-1].map(&:intern)]
175
- when :define
176
- compile_extra(args[0], args[1..-1])
177
- else
178
- compile_extra(name, args)
179
- end
180
- end
181
-
182
- def compile_extra(name, args)
183
- matching = Generator.directives[name.to_s]
184
-
185
- raise NoDirectiveError, "no directive named #{name}" \
186
- unless matching
187
-
188
- options[:extra][name] = args
189
- end
190
-
191
- # Compiles a copy token. A copy token basically copies its
192
- # argument directly into the body. Used in both the first
193
- # and third parts.
194
- #
195
- # @param body [String] the string to copy into the body.
196
- # @return [void]
197
- def compile_copy(body)
198
- require_state! :first, :third
199
- @body << body
200
- end
201
-
202
- # Sets the state to the second part.
203
- #
204
- # @return [void]
205
- def compile_second
206
- @state = :second
207
- end
208
-
209
- # Compiles a label. This starts a rule definition. The token
210
- # should only exist in the second part. A rule definition
211
- # occurs by setting the `@current_label` to the first argument,
212
- # and `@current` to a blank rule save the label set. If a
213
- # rule definition was already in progress, it is completed.
214
- #
215
- # @param label [String] the left-hand side of the rule; it
216
- # should be a nonterminal.
217
- # @return [void]
218
- def compile_label(label, val)
219
- require_state! :second
220
- if @current
221
- @rules << @current
222
- end
223
-
224
- label = label.intern
225
- @current_label = [label, val]
226
-
227
- @current = {
228
- label: label,
229
- label_id: val,
230
- set: [],
231
- block: "",
232
- prec: ""
233
- }
234
- end
235
-
236
- # Compiles a part. This should only occur during a rule
237
- # definition. The token should only exist in the second part.
238
- # It adds the first argument to the set of the current rule.
239
- #
240
- # @param text [String] the symbol to append to the current rule.
241
- def compile_part(text, val)
242
- require_state! :second
243
- @current[:set] << [text.intern, val]
244
- end
245
-
246
- # Compiles an or. This should only occur in a rule definition,
247
- # and in the second part. It starts a new rule definition by
248
- # calling {#compile_label} with the current label.
249
- #
250
- # @return [void]
251
- # @see #compile_label
252
- def compile_or
253
- compile_label(*@current_label)
254
- end
255
-
256
- # Compiles the precedence operator. This should only occur in a
257
- # rule definition, and in the second part. It sets the
258
- # precedence definition on the current rule.
259
- #
260
- # @param prec [String] the precedence of the rule.
261
- # @return [void]
262
- def compile_prec(prec)
263
- require_state! :second
264
- @current[:prec] = prec
265
- end
266
-
267
- # Compiles a block. This should only occur in a rule
268
- # definition, and in the second part. It sets the block on the
269
- # current rule.
270
- #
271
- # @param block [String] the block.
272
- # @return [void]
273
- def compile_block(block)
274
- require_state! :second
275
- @current[:block] = block
276
- end
277
-
278
- # Sets the state to the third part. If a rule definition was
279
- # in progress, it finishes the rule.
280
- #
281
- # @return [void]
282
- def compile_third
283
- if @current
284
- @rules << @current
285
- @current_label = @current = nil
286
- end
287
-
288
- @state = :third
289
- end
290
-
291
- private
292
-
293
- def handle_token(args)
294
- type = ""
295
- if args[0].caret?
296
- type = args.shift
297
- end
298
-
299
- name = args.shift
300
- value = args.shift
301
-
302
- options[:terminals] << [name.intern, type, nil, value]
303
- end
304
-
305
- # Checks the current state against the given states.
306
- #
307
- # @raise [InvalidStateError] if none of the given states match
308
- # the current state.
309
- # @return [void]
310
- def require_state!(*state)
311
- raise InvalidStateError,
312
- "In state #{@state}, " \
313
- "required state #{state.join(", ")}" \
314
- unless state.include?(@state)
315
- end
316
-
317
- # Compares the required version and the Antelope version.
318
- #
319
- # @raise [IncompatibleVersionError] if the Antelope version
320
- # doesn't meet the requirement.
321
- # @return [void]
322
- def compare_versions(required)
323
- antelope_version = Gem::Version.new(Antelope::VERSION)
324
- required_version = Gem::Requirement.new(required)
325
-
326
- unless required_version =~ antelope_version
327
- raise IncompatibleVersionError,
328
- "Grammar requires #{required}, " \
329
- "have #{Antelope::VERSION}"
330
- end
331
- end
332
- end
333
- end
334
- end
1
+ # encoding: utf-8
2
+
3
+ require "rubygems/requirement"
4
+
5
+ module Antelope
6
+ module Ace
7
+
8
+ # Compiles a set of tokens generated by {Scanner}. These tokens
9
+ # may not nessicarily have been generated by {Scanner}, however
10
+ # the tokens must follow the same rules even still.
11
+ #
12
+ # A list of all tokens that this compiler accepts:
13
+ #
14
+ # - `:directive` (2 arguments)
15
+ # - `:copy` (1 argument)
16
+ # - `:second` (no arguments)
17
+ # - `:label` (2 arguments)
18
+ # - `:part` (2 arguments)
19
+ # - `:or` (no arguments)
20
+ # - `:prec` (1 argument)
21
+ # - `:block` (1 argument)
22
+ # - `:third` (no arguments)
23
+ # - `:body` (1 argument)
24
+ #
25
+ # The tokens are handled by methods that follow the rule
26
+ # `compile_<token name>`.
27
+ class Compiler
28
+
29
+ # The body of the output compiler. This should be formatted in
30
+ # the language that the parser is to be written in. Some output
31
+ # generators may have special syntax that allows the parser to
32
+ # be put in the body; see the output generators for more.
33
+ #
34
+ # @return [String]
35
+ attr_accessor :body
36
+
37
+ # A list of all the rules that are defined in the file. The
38
+ # rules are defined as such:
39
+ #
40
+ # - **`label`** (`Symbol`) &mdash; The left-hand side of the rule;
41
+ # this is the nonterminal that the right side reduces to.
42
+ # - **`set`** (`Array<Symbol>`) &mdash; The right-hand side of the
43
+ # rule. This is a combination of terminals and nonterminals.
44
+ # - **`block`** (`String`) &mdash; The code to be run on a reduction.
45
+ # this should be formatted in the language that the output
46
+ # parser is written in. Optional; default value is `""`.
47
+ # - **`prec`** (`String`) &mdash; The precedence level for the
48
+ # rule. This should be a nonterminal or terminal. Optional;
49
+ # default value is `""`.
50
+ #
51
+ # @return [Array<Hash>]
52
+ attr_accessor :rules
53
+
54
+ # Options defined by directives in the first part of the file.
55
+ #
56
+ # - **`:terminals`** (`Array<Symbol, String?)>)` &mdash; A list
57
+ # of all of the terminals in the language. If this is not
58
+ # properly defined, the grammar will throw an error saying
59
+ # that a symbol used in the grammar is not defined.
60
+ # - **`:prec`** (`Array<(Symbol, Array<Symbol>)>`) &mdash; A list
61
+ # of the precedence rules of the grammar. The first element
62
+ # of each element is the _type_ of precedence (and should be
63
+ # any of `:left`, `:right`, or `:nonassoc`), and the second
64
+ # element should be the symbols that are on that level.
65
+ # - **`:type`** (`String`) &mdash; The type of generator to
66
+ # generate; this should be a language.
67
+ # - **`:extra`** (`Hash<Symbol, Array<Object>>`) &mdash; Extra
68
+ # options that are not defined here.
69
+ # @return [Hash]
70
+ attr_accessor :options
71
+
72
+ # Creates a compiler, and then runs the compiler.
73
+ #
74
+ # @param (see #initialize)
75
+ # @see #compile
76
+ # @return [Compiler] the compiler.
77
+ def self.compile(tokens)
78
+ new(tokens).compile
79
+ end
80
+
81
+ # Initialize the compiler. The compiler keeps track of a state;
82
+ # this state is basically which part of the file we're in. The
83
+ # state can be `:first`, `:second`, or `:third`; some tokens
84
+ # may not exist in certain states.
85
+ #
86
+ # @param tokens [Array<Array<(Symbol, Object, ...)>>] the tokens
87
+ # from the {Scanner}.
88
+ def initialize(tokens)
89
+ @tokens = tokens
90
+ @body = ""
91
+ @state = :first
92
+ @rules = []
93
+ @current = nil
94
+ @current_label = nil
95
+ @options = {
96
+ :terminals => [],
97
+ :nonterminals => [],
98
+ :prec => [],
99
+ :type => nil,
100
+ :extra => Hashie::Extensions::IndifferentAccess.
101
+ inject!({})
102
+ }
103
+ end
104
+
105
+ # Pretty inspect.
106
+ #
107
+ # @return [String]
108
+ def inspect
109
+ "#<#{self.class} state=#{@state.inspect} options=#{options.inspect}>"
110
+ end
111
+
112
+ # Runs the compiler on the input tokens. For each token,
113
+ # it calls `compile_<type>` with `<type>` being the first
114
+ # element of the token, with the remaining part of the array
115
+ # passed as arguments.
116
+ #
117
+ # @return [self]
118
+ def compile
119
+ @tokens.each do |token|
120
+ send(:"compile_#{token[0]}", *token[1..-1])
121
+ end
122
+
123
+ self
124
+ end
125
+
126
+ # Compiles a directive. This may only be triggered in the first
127
+ # section of the file. The directive accepts two arguments. The
128
+ # directive name can be any of the following:
129
+ #
130
+ # - `:terminal` &mdash; adds a terminal. Requires 1-2
131
+ # arguments; the first argument is the terminal name, and the
132
+ # second argument is a string that can represent the terminal.
133
+ # - `:require` &mdash; requires a certain version of Antelope.
134
+ # Requires 1 argument. If the first argument is a version
135
+ # greater than the current version of Antelope, it raises
136
+ # an error.
137
+ # - `:left` &mdash; creates a new precedence level, with the
138
+ # argument values being the symbols. The precedence level
139
+ # is left associative.
140
+ # - `:right` &mdash; creates a new precedence level, with the
141
+ # argument valeus being the symbols. The precedence level
142
+ # is right associative.
143
+ # - `:nonassoc` &mdash; creates a nre precedence level, with the
144
+ # argument values being the symbols. The precedence level
145
+ # is nonassociative.
146
+ # - `:type` &mdash; the type of parser to generate. This should
147
+ # correspond to the output language of the parser.
148
+ #
149
+ # @param name [String, Symbol] the name of the directive.
150
+ # Accepts any of `:terminal`, `:require`, `:left`, `:right`,
151
+ # `:nonassoc`, and `:type`. Any other values produce an
152
+ # error on stderr and are put in the `:extra` hash on
153
+ # {#options}.
154
+ # @param args [Array<String>] the arguments to the directive.
155
+ # @return [void]
156
+ # @see #options
157
+ def compile_directive(name, args)
158
+ require_state! :first
159
+ name = name.intern
160
+ case name
161
+ when :terminal, :token
162
+ handle_token(args)
163
+ when :require
164
+ compare_versions(args[0])
165
+ when :left, :right, :nonassoc
166
+ options[:prec] << [name, *args.map(&:intern)]
167
+ when :language, :generator, :"grammar.type"
168
+ options[:type] = args[0].downcase
169
+ when :type
170
+ raise SyntaxError, "%type directive requires first " \
171
+ "argument to be caret" unless args[0].caret?
172
+
173
+ options[:nonterminals] <<
174
+ [args[0], args[1..-1].map(&:intern)]
175
+ when :define
176
+ compile_extra(args[0], args[1..-1])
177
+ else
178
+ compile_extra(name, args)
179
+ end
180
+ end
181
+
182
+ def compile_extra(name, args)
183
+ matching = Generator.directives[name.to_s]
184
+
185
+ raise NoDirectiveError, "no directive named #{name}" \
186
+ unless matching
187
+
188
+ options[:extra][name] = args
189
+ end
190
+
191
+ # Compiles a copy token. A copy token basically copies its
192
+ # argument directly into the body. Used in both the first
193
+ # and third parts.
194
+ #
195
+ # @param body [String] the string to copy into the body.
196
+ # @return [void]
197
+ def compile_copy(body)
198
+ require_state! :first, :third
199
+ @body << body
200
+ end
201
+
202
+ # Sets the state to the second part.
203
+ #
204
+ # @return [void]
205
+ def compile_second
206
+ @state = :second
207
+ end
208
+
209
+ # Compiles a label. This starts a rule definition. The token
210
+ # should only exist in the second part. A rule definition
211
+ # occurs by setting the `@current_label` to the first argument,
212
+ # and `@current` to a blank rule save the label set. If a
213
+ # rule definition was already in progress, it is completed.
214
+ #
215
+ # @param label [String] the left-hand side of the rule; it
216
+ # should be a nonterminal.
217
+ # @return [void]
218
+ def compile_label(label, val)
219
+ require_state! :second
220
+ if @current
221
+ @rules << @current
222
+ end
223
+
224
+ label = label.intern
225
+ @current_label = [label, val]
226
+
227
+ @current = {
228
+ label: label,
229
+ label_id: val,
230
+ set: [],
231
+ block: "",
232
+ prec: ""
233
+ }
234
+ end
235
+
236
+ # Compiles a part. This should only occur during a rule
237
+ # definition. The token should only exist in the second part.
238
+ # It adds the first argument to the set of the current rule.
239
+ #
240
+ # @param text [String] the symbol to append to the current rule.
241
+ def compile_part(text, val)
242
+ require_state! :second
243
+ @current[:set] << [text.intern, val]
244
+ end
245
+
246
+ # Compiles an or. This should only occur in a rule definition,
247
+ # and in the second part. It starts a new rule definition by
248
+ # calling {#compile_label} with the current label.
249
+ #
250
+ # @return [void]
251
+ # @see #compile_label
252
+ def compile_or
253
+ compile_label(*@current_label)
254
+ end
255
+
256
+ # Compiles the precedence operator. This should only occur in a
257
+ # rule definition, and in the second part. It sets the
258
+ # precedence definition on the current rule.
259
+ #
260
+ # @param prec [String] the precedence of the rule.
261
+ # @return [void]
262
+ def compile_prec(prec)
263
+ require_state! :second
264
+ @current[:prec] = prec
265
+ end
266
+
267
+ # Compiles a block. This should only occur in a rule
268
+ # definition, and in the second part. It sets the block on the
269
+ # current rule.
270
+ #
271
+ # @param block [String] the block.
272
+ # @return [void]
273
+ def compile_block(block)
274
+ require_state! :second
275
+ @current[:block] = block
276
+ end
277
+
278
+ # Sets the state to the third part. If a rule definition was
279
+ # in progress, it finishes the rule.
280
+ #
281
+ # @return [void]
282
+ def compile_third
283
+ if @current
284
+ @rules << @current
285
+ @current_label = @current = nil
286
+ end
287
+
288
+ @state = :third
289
+ end
290
+
291
+ private
292
+
293
+ def handle_token(args)
294
+ type = ""
295
+ if args[0].caret?
296
+ type = args.shift
297
+ end
298
+
299
+ name = args.shift
300
+ value = args.shift
301
+
302
+ options[:terminals] << [name.intern, type, nil, value]
303
+ end
304
+
305
+ # Checks the current state against the given states.
306
+ #
307
+ # @raise [InvalidStateError] if none of the given states match
308
+ # the current state.
309
+ # @return [void]
310
+ def require_state!(*state)
311
+ raise InvalidStateError,
312
+ "In state #{@state}, " \
313
+ "required state #{state.join(", ")}" \
314
+ unless state.include?(@state)
315
+ end
316
+
317
+ # Compares the required version and the Antelope version.
318
+ #
319
+ # @raise [IncompatibleVersionError] if the Antelope version
320
+ # doesn't meet the requirement.
321
+ # @return [void]
322
+ def compare_versions(required)
323
+ antelope_version = Gem::Version.new(Antelope::VERSION)
324
+ required_version = Gem::Requirement.new(required)
325
+
326
+ unless required_version =~ antelope_version
327
+ raise IncompatibleVersionError,
328
+ "Grammar requires #{required}, " \
329
+ "have #{Antelope::VERSION}"
330
+ end
331
+ end
332
+ end
333
+ end
334
+ end