antelope 0.0.1

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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +3 -0
  4. data/.yardopts +4 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +2 -0
  9. data/antelope.gemspec +30 -0
  10. data/bin/antelope +24 -0
  11. data/examples/deterministic.ace +27 -0
  12. data/examples/deterministic.output +229 -0
  13. data/examples/example.ace +45 -0
  14. data/examples/example.output +610 -0
  15. data/examples/simple.ace +26 -0
  16. data/examples/simple.output +194 -0
  17. data/lib/antelope/ace/compiler.rb +290 -0
  18. data/lib/antelope/ace/errors.rb +27 -0
  19. data/lib/antelope/ace/grammar/generation.rb +47 -0
  20. data/lib/antelope/ace/grammar/loading.rb +51 -0
  21. data/lib/antelope/ace/grammar/presidence.rb +59 -0
  22. data/lib/antelope/ace/grammar/production.rb +47 -0
  23. data/lib/antelope/ace/grammar/productions.rb +119 -0
  24. data/lib/antelope/ace/grammar/terminals.rb +41 -0
  25. data/lib/antelope/ace/grammar.rb +59 -0
  26. data/lib/antelope/ace/presidence.rb +51 -0
  27. data/lib/antelope/ace/scanner/first.rb +61 -0
  28. data/lib/antelope/ace/scanner/second.rb +160 -0
  29. data/lib/antelope/ace/scanner/third.rb +25 -0
  30. data/lib/antelope/ace/scanner.rb +110 -0
  31. data/lib/antelope/ace/token/epsilon.rb +22 -0
  32. data/lib/antelope/ace/token/error.rb +24 -0
  33. data/lib/antelope/ace/token/nonterminal.rb +15 -0
  34. data/lib/antelope/ace/token/terminal.rb +15 -0
  35. data/lib/antelope/ace/token.rb +171 -0
  36. data/lib/antelope/ace.rb +50 -0
  37. data/lib/antelope/automaton.rb +36 -0
  38. data/lib/antelope/generation/conflictor/conflict.rb +7 -0
  39. data/lib/antelope/generation/conflictor.rb +45 -0
  40. data/lib/antelope/generation/constructor/first.rb +52 -0
  41. data/lib/antelope/generation/constructor/follow.rb +46 -0
  42. data/lib/antelope/generation/constructor/lookahead.rb +42 -0
  43. data/lib/antelope/generation/constructor/nullable.rb +40 -0
  44. data/lib/antelope/generation/constructor.rb +81 -0
  45. data/lib/antelope/generation/recognizer/rule.rb +93 -0
  46. data/lib/antelope/generation/recognizer/state.rb +56 -0
  47. data/lib/antelope/generation/recognizer.rb +152 -0
  48. data/lib/antelope/generation/tableizer.rb +80 -0
  49. data/lib/antelope/generation.rb +12 -0
  50. data/lib/antelope/generator/output.rb +30 -0
  51. data/lib/antelope/generator/ruby.rb +57 -0
  52. data/lib/antelope/generator/templates/output.erb +49 -0
  53. data/lib/antelope/generator/templates/ruby.erb +62 -0
  54. data/lib/antelope/generator.rb +84 -0
  55. data/lib/antelope/version.rb +4 -0
  56. data/lib/antelope.rb +9 -0
  57. data/spec/antelope/ace/compiler_spec.rb +50 -0
  58. data/spec/antelope/ace/scanner_spec.rb +27 -0
  59. data/spec/antelope/automaton_spec.rb +29 -0
  60. data/spec/spec_helper.rb +38 -0
  61. data/spec/support/benchmark_helper.rb +5 -0
  62. metadata +223 -0
@@ -0,0 +1,194 @@
1
+ Productions:
2
+ 0/n0: $start(0) → e(0:1) $
3
+ 1/n1: e(0:1) → l(0:2) "=" r(8:10)
4
+ 2/n1: e(0:1) → r(0:3)
5
+ 3/n1: l(8:2) → IDENT
6
+ 4/n1: l(8:2) → "*" r(5:9)
7
+ 5/n1: r(8:10) → l(0:2)
8
+ 12/n1: r(8:10) → l(5:2)
9
+ 18/n1: r(8:10) → l(8:2)
10
+
11
+ Original Productions:
12
+ e → l "=" r
13
+
14
+ e → r
15
+
16
+ l → IDENT
17
+
18
+ l → "*" r
19
+
20
+ r → l
21
+
22
+ $start → e $
23
+
24
+
25
+ Conflicts:
26
+
27
+ Presidence:
28
+ --- highest
29
+ nonassoc 1:
30
+ {_}
31
+ nonassoc 0:
32
+ {$}
33
+ --- lowest
34
+
35
+ Table:
36
+ {0=>
37
+ {:e=>[:state, 1],
38
+ :l=>[:state, 2],
39
+ :r=>[:state, 3],
40
+ :IDENT=>[:state, 4],
41
+ :STAR=>[:state, 5]},
42
+ 1=>{:"$"=>[:state, 7]},
43
+ 2=>{:EQUALS=>[:state, 8], :"$"=>[:reduce, 5]},
44
+ 3=>{:"$"=>[:reduce, 2]},
45
+ 4=>{:EQUALS=>[:reduce, 3], :"$"=>[:reduce, 3]},
46
+ 5=>
47
+ {:r=>[:state, 9], :l=>[:state, 2], :IDENT=>[:state, 4], :STAR=>[:state, 5]},
48
+ 6=>{:"$"=>[:reduce, 5]},
49
+ 7=>{:"$"=>[:accept, 0]},
50
+ 8=>
51
+ {:r=>[:state, 10], :l=>[:state, 2], :IDENT=>[:state, 4], :STAR=>[:state, 5]},
52
+ 9=>{:EQUALS=>[:reduce, 4], :"$"=>[:reduce, 4]},
53
+ 10=>{:"$"=>[:reduce, 1]}}
54
+
55
+ [#<Antelope::Generation::Recognizer::Rule id=0 left=$start(0) right=[e(0:1) $] position=0>,
56
+ #<Antelope::Generation::Recognizer::Rule id=1 left=e(0:1) right=[l(0:2) "=" r(8:10)] position=0>,
57
+ #<Antelope::Generation::Recognizer::Rule id=2 left=e(0:1) right=[r(0:3)] position=0>,
58
+ #<Antelope::Generation::Recognizer::Rule id=3 left=l(8:2) right=[IDENT] position=0>,
59
+ #<Antelope::Generation::Recognizer::Rule id=4 left=l(8:2) right=["*" r(5:9)] position=0>,
60
+ #<Antelope::Generation::Recognizer::Rule id=5 left=r(8:10) right=[l(0:2)] position=0>,
61
+ #<Antelope::Generation::Recognizer::Rule id=6 left=$start(0) right=[e $] position=1>,
62
+ #<Antelope::Generation::Recognizer::Rule id=7 left=e(0:1) right=[l "=" r] position=1>,
63
+ nil,
64
+ #<Antelope::Generation::Recognizer::Rule id=9 left=e(0:1) right=[r] position=1>,
65
+ #<Antelope::Generation::Recognizer::Rule id=10 left=l(8:2) right=[IDENT] position=1>,
66
+ #<Antelope::Generation::Recognizer::Rule id=11 left=l(8:2) right=["*" r] position=1>,
67
+ #<Antelope::Generation::Recognizer::Rule id=12 left=r(8:10) right=[l(5:2)] position=0>,
68
+ #<Antelope::Generation::Recognizer::Rule id=13 left=l(8:2) right=[IDENT] position=0>,
69
+ #<Antelope::Generation::Recognizer::Rule id=14 left=l(8:2) right=["*" r(5:9)] position=0>,
70
+ #<Antelope::Generation::Recognizer::Rule id=15 left=r(8:10) right=[l] position=1>,
71
+ #<Antelope::Generation::Recognizer::Rule id=16 left=$start(0) right=[e $] position=2>,
72
+ #<Antelope::Generation::Recognizer::Rule id=17 left=e(0:1) right=[l "=" r] position=2>,
73
+ #<Antelope::Generation::Recognizer::Rule id=18 left=r(8:10) right=[l(8:2)] position=0>,
74
+ #<Antelope::Generation::Recognizer::Rule id=19 left=l(8:2) right=[IDENT] position=0>,
75
+ #<Antelope::Generation::Recognizer::Rule id=20 left=l(8:2) right=["*" r(5:9)] position=0>,
76
+ #<Antelope::Generation::Recognizer::Rule id=21 left=l(8:2) right=["*" r] position=2>,
77
+ #<Antelope::Generation::Recognizer::Rule id=22 left=e(0:1) right=[l "=" r] position=3>]
78
+
79
+ State 0:
80
+ rules:
81
+ 0/n0: $start(0) → • e(0:1) $
82
+ {}
83
+ 1/n1: e(0:1) → • l(0:2) "=" r(8:10)
84
+ {}
85
+ 2/n1: e(0:1) → • r(0:3)
86
+ {}
87
+ 3/n1: l(8:2) → • IDENT
88
+ {}
89
+ 4/n1: l(8:2) → • "*" r(5:9)
90
+ {}
91
+ 5/n1: r(8:10) → • l(0:2)
92
+ {}
93
+
94
+ transitions:
95
+ e : State 1
96
+ l : State 2
97
+ r : State 3
98
+ IDENT: State 4
99
+ STAR : State 5
100
+
101
+ State 1:
102
+ rules:
103
+ 6/n0: $start(0) → e • $
104
+ {}
105
+
106
+ transitions:
107
+ $: State 7
108
+
109
+ State 2:
110
+ rules:
111
+ 7/n1: e(0:1) → l • "=" r
112
+ {}
113
+ 15/n1: r(8:10) → l •
114
+ {$}
115
+
116
+ transitions:
117
+ EQUALS: State 8
118
+
119
+ State 3:
120
+ rules:
121
+ 9/n1: e(0:1) → r •
122
+ {$}
123
+
124
+ transitions:
125
+
126
+ State 4:
127
+ rules:
128
+ 10/n1: l(8:2) → IDENT •
129
+ {"=", $}
130
+
131
+ transitions:
132
+
133
+ State 5:
134
+ rules:
135
+ 11/n1: l(8:2) → "*" • r
136
+ {}
137
+ 12/n1: r(8:10) → • l(5:2)
138
+ {}
139
+ 13/n1: l(8:2) → • IDENT
140
+ {}
141
+ 14/n1: l(8:2) → • "*" r(5:9)
142
+ {}
143
+
144
+ transitions:
145
+ r : State 9
146
+ l : State 2
147
+ IDENT: State 4
148
+ STAR : State 5
149
+
150
+ State 6:
151
+ rules:
152
+ 15/n1: r(8:10) → l •
153
+ {$}
154
+
155
+ transitions:
156
+
157
+ State 7:
158
+ rules:
159
+ 16/n0: $start(0) → e $ •
160
+ {}
161
+
162
+ transitions:
163
+
164
+ State 8:
165
+ rules:
166
+ 17/n1: e(0:1) → l "=" • r
167
+ {}
168
+ 18/n1: r(8:10) → • l(8:2)
169
+ {}
170
+ 19/n1: l(8:2) → • IDENT
171
+ {}
172
+ 20/n1: l(8:2) → • "*" r(5:9)
173
+ {}
174
+
175
+ transitions:
176
+ r : State 10
177
+ l : State 2
178
+ IDENT: State 4
179
+ STAR : State 5
180
+
181
+ State 9:
182
+ rules:
183
+ 21/n1: l(8:2) → "*" r •
184
+ {"=", $}
185
+
186
+ transitions:
187
+
188
+ State 10:
189
+ rules:
190
+ 22/n1: e(0:1) → l "=" r •
191
+ {$}
192
+
193
+ transitions:
194
+
@@ -0,0 +1,290 @@
1
+ require "rubygems/requirement"
2
+
3
+ module Antelope
4
+ module Ace
5
+
6
+ # Compiles a set of tokens generated by {Scanner}. These tokens
7
+ # may not nessicarily have been generated by {Scanner}, however
8
+ # the tokens must follow the same rules even still.
9
+ #
10
+ # A list of all tokens that this compiler accepts:
11
+ #
12
+ # - `:directive` (2 arguments)
13
+ # - `:copy` (1 argument)
14
+ # - `:second` (no arguments)
15
+ # - `:label` (1 argument)
16
+ # - `:part` (1 argument)
17
+ # - `:or` (no arguments)
18
+ # - `:prec` (1 argument)
19
+ # - `:block` (1 argument)
20
+ # - `:third` (no arguments)
21
+ # - `:body` (1 argument)
22
+ #
23
+ # The tokens are handled by methods that follow the rule
24
+ # `compile_<token name>`.
25
+ class Compiler
26
+
27
+ # The body of the output compiler. This should be formatted in
28
+ # the language that the parser is to be written in. Some output
29
+ # generators may have special syntax that allows the parser to
30
+ # be put in the body; see the output generators for more.
31
+ #
32
+ # @return [String]
33
+ attr_accessor :body
34
+
35
+ # A list of all the rules that are defined in the file. The
36
+ # rules are defined as such:
37
+ #
38
+ # - **`label`** (`Symbol`) &mdash; The left-hand side of the rule;
39
+ # this is the nonterminal that the right side reduces to.
40
+ # - **`set`** (`Array<Symbol>`) &mdash; The right-hand side of the
41
+ # rule. This is a combination of terminals and nonterminals.
42
+ # - **`block`** (`String`) &mdash; The code to be run on a reduction.
43
+ # this should be formatted in the language that the output
44
+ # parser is written in. Optional; default value is `""`.
45
+ # - **`prec`** (`String`) &mdash; The presidence level for the
46
+ # rule. This should be a nonterminal or terminal. Optional;
47
+ # default value is `""`.
48
+ #
49
+ # @return [Array<Hash>]
50
+ attr_accessor :rules
51
+
52
+ # Options defined by directives in the first part of the file.
53
+ #
54
+ # - **`:terminals`** (`Array<Symbol, String?)>)` &mdash; A list
55
+ # of all of the terminals in the language. If this is not
56
+ # properly defined, the grammar will throw an error saying
57
+ # that a symbol used in the grammar is not defined.
58
+ # - **`:prec`** (`Array<(Symbol, Array<Symbol>)>`) &mdash; A list
59
+ # of the presidence rules of the grammar. The first element
60
+ # of each element is the _type_ of presidence (and should be
61
+ # any of `:left`, `:right`, or `:nonassoc`), and the second
62
+ # element should be the symbols that are on that level.
63
+ # - **`:type`** (`String`) &mdash; The type of generator to
64
+ # generate; this should be a language. It's currently
65
+ # ineffective.
66
+ # - **`:extra`** (`Hash<Symbol, Array<Object>>`) &mdash; Extra
67
+ # options that are not defined here.
68
+ # @return [Hash]
69
+ attr_accessor :options
70
+
71
+ # Creates a compiler, and then runs the compiler.
72
+ #
73
+ # @param (see #initialize)
74
+ # @see #compile
75
+ # @return [Compiler] the compiler.
76
+ def self.compile(tokens)
77
+ new(tokens).compile
78
+ end
79
+
80
+ # Initialize the compiler. The compiler keeps track of a state;
81
+ # this state is basically which part of the file we're in. The
82
+ # state can be `:first`, `:second`, or `:third`; some tokens
83
+ # may not exist in certain states.
84
+ #
85
+ # @param tokens [Array<Array<(Symbol, Object, ...)>>] the tokens
86
+ # from the {Scanner}.
87
+ def initialize(tokens)
88
+ @tokens = tokens
89
+ @body = ""
90
+ @state = :first
91
+ @rules = []
92
+ @current = nil
93
+ @current_label = nil
94
+ @options = { :terminals => [], :prec => [], :extra => {} }
95
+ end
96
+
97
+ # Runs the compiler on the input tokens. For each token,
98
+ # it calls `compile_<type>` with `<type>` being the first
99
+ # element of the token, with the remaining part of the array
100
+ # passed as arguments.
101
+ #
102
+ # @return [self]
103
+ def compile
104
+ @tokens.each do |token|
105
+ send(:"compile_#{token[0]}", *token[1..-1])
106
+ end
107
+
108
+ self
109
+ end
110
+
111
+ # Compiles a directive. This may only be triggered in the first
112
+ # section of the file. The directive accepts two arguments. The
113
+ # directive name can be any of the following:
114
+ #
115
+ # - `:terminal` &mdash; adds a terminal. Requires 1-2
116
+ # arguments; the first argument is the terminal name, and the
117
+ # second argument is a string that can represent the terminal.
118
+ # - `:require` &mdash; requires a certain version of Antelope.
119
+ # Requires 1 argument. If the first argument is a version
120
+ # greater than the current version of Antelope, it raises
121
+ # an error.
122
+ # - `:left` &mdash; creates a new presidence level, with the
123
+ # argument values being the symbols. The presidence level
124
+ # is left associative.
125
+ # - `:right` &mdash; creates a new presidence level, with the
126
+ # argument valeus being the symbols. The presidence level
127
+ # is right associative.
128
+ # - `:nonassoc` &mdash; creates a nre presidence level, with the
129
+ # argument values being the symbols. The presidence level
130
+ # is nonassociative.
131
+ # - `:type` &mdash; the type of parser to generate. This should
132
+ # correspond to the output language of the parser. Currently
133
+ # ineffective.
134
+ #
135
+ # @param name [String, Symbol] the name of the directive.
136
+ # Accepts any of `:terminal`, `:require`, `:left`, `:right`,
137
+ # `:nonassoc`, and `:type`. Any other values produce an
138
+ # error on stderr and are put in the `:extra` hash on
139
+ # {#options}.
140
+ # @param args [Array<String>] the arguments to the directive.
141
+ # @return [void]
142
+ # @see #options
143
+ def compile_directive(name, args)
144
+ require_state! :first
145
+ name = name.intern
146
+ case name
147
+ when :terminal
148
+ @options[:terminals] << [args[0].intern, args[1]]
149
+ when :require
150
+ compare_versions(args[0])
151
+ when :left, :right, :nonassoc
152
+ @options[:prec] << [name, *args.map(&:intern)]
153
+ when :type
154
+ @options[:type] = args[0]
155
+ else
156
+ @options[:extra][name] = args
157
+ $stderr.puts "Unknown Directive: #{name}"
158
+ end
159
+ end
160
+
161
+ # Compiles a copy token. A copy token basically copies its
162
+ # argument directly into the body. Used in both the first
163
+ # and third parts.
164
+ #
165
+ # @param body [String] the string to copy into the body.
166
+ # @return [void]
167
+ def compile_copy(body)
168
+ require_state! :first, :third
169
+ @body << body
170
+ end
171
+
172
+ # Sets the state to the second part.
173
+ #
174
+ # @return [void]
175
+ def compile_second
176
+ @state = :second
177
+ end
178
+
179
+ # Compiles a label. This starts a rule definition. The token
180
+ # should only exist in the second part. A rule definition
181
+ # occurs by setting the `@current_label` to the first argument,
182
+ # and `@current` to a blank rule save the label set. If a
183
+ # rule definition was already in progress, it is completed.
184
+ #
185
+ # @param label [String] the left-hand side of the rule; it
186
+ # should be a nonterminal.
187
+ # @return [void]
188
+ def compile_label(label)
189
+ require_state! :second
190
+ if @current
191
+ @rules << @current
192
+ end
193
+
194
+ @current_label = label.intern
195
+
196
+ @current = {
197
+ label: @current_label,
198
+ set: [],
199
+ block: "",
200
+ prec: ""
201
+ }
202
+ end
203
+
204
+ # Compiles a part. This should only occur during a rule
205
+ # definition. The token should only exist in the second part.
206
+ # It adds the first argument to the set of the current rule.
207
+ #
208
+ # @param text [String] the symbol to append to the current rule.
209
+ def compile_part(text)
210
+ require_state! :second
211
+ @current[:set] << text.intern
212
+ end
213
+
214
+ # Compiles an or. This should only occur in a rule definition,
215
+ # and in the second part. It starts a new rule definition by
216
+ # calling {#compile_label} with the current label.
217
+ #
218
+ # @return [void]
219
+ # @see #compile_label
220
+ def compile_or
221
+ compile_label(@current_label)
222
+ end
223
+
224
+ # Compiles the presidence operator. This should only occur in a
225
+ # rule definition, and in the second part. It sets the
226
+ # presidence definition on the current rule.
227
+ #
228
+ # @param prec [String] the presidence of the rule.
229
+ # @return [void]
230
+ def compile_prec(prec)
231
+ require_state! :second
232
+ @current[:prec] = prec
233
+ end
234
+
235
+ # Compiles a block. This should only occur in a rule
236
+ # definition, and in the second part. It sets the block on the
237
+ # current rule.
238
+ #
239
+ # @param block [String] the block.
240
+ # @return [void]
241
+ def compile_block(block)
242
+ require_state! :second
243
+ @current[:block] = block
244
+ end
245
+
246
+ # Sets the state to the third part. If a rule definition was
247
+ # in progress, it finishes the rule.
248
+ #
249
+ # @return [void]
250
+ def compile_third
251
+ if @current
252
+ @rules << @current
253
+ @current_label = @current = nil
254
+ end
255
+
256
+ @state = :third
257
+ end
258
+
259
+ private
260
+
261
+ # Checks the current state against the given states.
262
+ #
263
+ # @raise [InvalidStateError] if none of the given states match
264
+ # the current state.
265
+ # @return [void]
266
+ def require_state!(*state)
267
+ raise InvalidStateError,
268
+ "In state #{@state}, " \
269
+ "required state #{state.join(", ")}" \
270
+ unless state.include?(@state)
271
+ end
272
+
273
+ # Compares the required version and the Antelope version.
274
+ #
275
+ # @raise [IncompatibleVersionError] if the Antelope version
276
+ # doesn't meet the requirement.
277
+ # @return [void]
278
+ def compare_versions(required)
279
+ antelope_version = Gem::Version.new(Antelope::VERSION)
280
+ required_version = Gem::Requirement.new(required)
281
+
282
+ unless required_version =~ antelope_version
283
+ raise IncompatibleVersionError,
284
+ "Grammar requires #{args[0]}, " \
285
+ "have #{Antelope::VERSION}"
286
+ end
287
+ end
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,27 @@
1
+ module Antelope
2
+ module Ace
3
+
4
+ # Defines an error that can occur within the Ace module. All
5
+ # errors that are raised within the Ace module are subclasses of
6
+ # this.
7
+ class Error < StandardError
8
+ end
9
+
10
+ # Used primarily in the {Scanner}, this is raised when an input
11
+ # is malformed. The message should contain a snippet of the input
12
+ # which caused the error.
13
+ class SyntaxError < Error
14
+ end
15
+
16
+ # This is used primarily in the {Grammar}; if a rule references a
17
+ # token (a nonterminal or a terminal) that was not previously
18
+ # defined, this is raised.
19
+ class UndefinedTokenError < Error
20
+ end
21
+
22
+ # Pimarily used in the {Compiler}, if a scanner token appears that
23
+ # should not be in the current state, this is raised.
24
+ class InvalidStateError < Error
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,47 @@
1
+ module Antelope
2
+ module Ace
3
+ class Grammar
4
+
5
+ # The default modifiers for generation. It's not really
6
+ # recommended to (heh) modify this; however, adding your own
7
+ # modifier is always acceptable.
8
+ DEFAULT_MODIFIERS = [
9
+ [:recognizer, Generation::Recognizer ],
10
+ [:constructor, Generation::Constructor],
11
+ [:conflictor, Generation::Conflictor ],
12
+ [:tableizer, Generation::Tableizer ]
13
+ ].freeze
14
+
15
+ # The (as of right now) default generators. Later on, the
16
+ # grammar will guess which generators are needed for the
17
+ # specific ace file.
18
+ DEFAULT_GENERATORS = [Generator::Output, Generator::Ruby].freeze
19
+
20
+ # Handles the generation of output for the grammar.
21
+ module Generation
22
+
23
+ # Generates the output. First, it runs through every given
24
+ # modifier, and instintates it. It then calls every modifier,
25
+ # turns it into a hash, and passes that hash to each of the
26
+ # given generators.
27
+ #
28
+ # @param generators [Array<Generator>] a list of generators
29
+ # to use in generation.
30
+ # @param modifiers [Array<Array<(Symbol, #call)>>] a list of
31
+ # modifiers to apply to the grammar.
32
+ # @return [void]
33
+ def generate(generators = DEFAULT_GENERATORS,
34
+ modifiers = DEFAULT_MODIFIERS)
35
+ mods = modifiers.map(&:last).
36
+ map { |x| x.new(self) }
37
+ mods.map(&:call)
38
+ hash = Hash[modifiers.map(&:first).zip(mods)]
39
+ # This is when we'd generate
40
+ generators.each do |gen|
41
+ gen.new(self, hash).generate
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,51 @@
1
+ module Antelope
2
+ module Ace
3
+ class Grammar
4
+
5
+ # Handles loading to and from files and strings.
6
+ module Loading
7
+
8
+ # Defines class methods on the grammar.
9
+ module ClassMethods
10
+
11
+ # Loads a grammar from a file. Assumes the output
12
+ # directory and name from the file name.
13
+ #
14
+ # @param file_name [String] the file name.
15
+ # @return [Grammar]
16
+ # @see #from_string
17
+ def from_file(file_name)
18
+ body = File.read(file_name)
19
+ output = File.dirname(file_name)
20
+ name = File.basename(file_name).gsub(/\.[A-Za-z]+/, "")
21
+ from_string(name, output, body)
22
+ end
23
+
24
+ # Loads a grammar from a string. First runs the scanner and
25
+ # compiler over the string, and then instantiates a new
26
+ # Grammar from the resultant.
27
+ #
28
+ # @param name [String] the name of the grammar.
29
+ # @param output [String] the output directory.
30
+ # @param string [String] the grammar body.
31
+ # @return [Grammar]
32
+ # @see Ace::Scanner
33
+ # @see Ace::Compiler
34
+ def from_string(name, output, string)
35
+ scanner = Ace::Scanner.scan(string)
36
+ compiler = Ace::Compiler.compile(scanner)
37
+ new(name, output, compiler)
38
+ end
39
+ end
40
+
41
+ # Extends the grammar with the class methods.
42
+ #
43
+ # @param receiver [Grammar]
44
+ # @see ClassMethods
45
+ def self.included(receiver)
46
+ receiver.extend ClassMethods
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,59 @@
1
+ require "set"
2
+
3
+ module Antelope
4
+ module Ace
5
+ class Grammar
6
+
7
+ # Manages presidence for tokens.
8
+ module Presidence
9
+
10
+ # Accesses the generated presidence list. Lazily generates
11
+ # the presidence rules on the go, and then caches it.
12
+ #
13
+ # @return [Array<Ace::Presidence>]
14
+ def presidence
15
+ @_presidence ||= generate_presidence
16
+ end
17
+
18
+ # Finds a presidence rule for a given token. If no direct
19
+ # rule is defined for that token, it will check for a rule
20
+ # defined for the special symbol, `:_`. By default, there
21
+ # is always a rule defined for `:_`.
22
+ #
23
+ # @param token [Ace::Token, Symbol]
24
+ # @return [Ace::Presidence]
25
+ def presidence_for(token)
26
+ token = token.name if token.is_a?(Token)
27
+
28
+ set = Set.new([token, :_])
29
+
30
+ presidence.
31
+ select { |pr| set.intersect?(pr.tokens) }.
32
+ first
33
+ end
34
+
35
+ private
36
+
37
+ # Generates the presidence rules. Loops through the compiler
38
+ # given presidence settings, and then adds two default
39
+ # presidence rules; one for `:$` (level 0, nonassoc), and one
40
+ # for `:_` (level 1, nonassoc).
41
+ #
42
+ # @return [Array<Ace::Presidence>]
43
+ def generate_presidence
44
+ size = @compiler.options[:prec].size + 1
45
+ presidence = @compiler.options[:prec].
46
+ each_with_index.map do |prec, i|
47
+ Ace::Presidence.new(prec[0], prec[1..-1].to_set, size - i)
48
+ end
49
+
50
+ presidence <<
51
+ Ace::Presidence.new(:nonassoc, [:"$"].to_set, 0) <<
52
+ Ace::Presidence.new(:nonassoc, [:_].to_set, 1)
53
+ presidence.sort_by { |_| _.level }.reverse
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end