antelope 0.0.1

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