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
@@ -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