antelope 0.3.2 → 0.4.0
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.
- checksums.yaml +4 -4
- data/.gitignore +25 -25
- data/.rspec +3 -3
- data/.travis.yml +10 -10
- data/.yardopts +7 -7
- data/CONTRIBUTING.md +50 -38
- data/GENERATORS.md +180 -124
- data/Gemfile +7 -7
- data/LICENSE.txt +22 -22
- data/README.md +240 -104
- data/Rakefile +2 -2
- data/TODO.md +58 -58
- data/antelope.gemspec +29 -28
- data/bin/antelope +7 -7
- data/examples/deterministic.ace +35 -35
- data/examples/example.ace +52 -51
- data/examples/example.ace.err +192 -192
- data/examples/example.ace.inf +432 -432
- data/examples/example.ate +70 -70
- data/examples/example.ate.err +192 -192
- data/examples/example.ate.inf +432 -432
- data/examples/liquidscript.ace +233 -233
- data/examples/simple.ace +22 -22
- data/lib/antelope/ace/compiler.rb +334 -334
- data/lib/antelope/ace/errors.rb +30 -30
- data/lib/antelope/ace/scanner/argument.rb +57 -57
- data/lib/antelope/ace/scanner/first.rb +89 -89
- data/lib/antelope/ace/scanner/second.rb +178 -178
- data/lib/antelope/ace/scanner/third.rb +27 -27
- data/lib/antelope/ace/scanner.rb +144 -144
- data/lib/antelope/ace.rb +47 -47
- data/lib/antelope/cli.rb +60 -60
- data/lib/antelope/errors.rb +25 -25
- data/lib/antelope/generation/constructor/first.rb +86 -86
- data/lib/antelope/generation/constructor/follow.rb +105 -105
- data/lib/antelope/generation/constructor/nullable.rb +64 -64
- data/lib/antelope/generation/constructor.rb +127 -127
- data/lib/antelope/generation/errors.rb +17 -17
- data/lib/antelope/generation/null.rb +13 -13
- data/lib/antelope/generation/recognizer/rule.rb +216 -216
- data/lib/antelope/generation/recognizer/state.rb +129 -129
- data/lib/antelope/generation/recognizer.rb +177 -177
- data/lib/antelope/generation/tableizer.rb +176 -176
- data/lib/antelope/generation.rb +15 -15
- data/lib/antelope/generator/base/coerce.rb +115 -0
- data/lib/antelope/generator/base/extra.rb +50 -0
- data/lib/antelope/generator/base.rb +134 -264
- data/lib/antelope/generator/c.rb +11 -11
- data/lib/antelope/generator/c_header.rb +105 -105
- data/lib/antelope/generator/c_source.rb +39 -39
- data/lib/antelope/generator/error.rb +34 -34
- data/lib/antelope/generator/group.rb +60 -57
- data/lib/antelope/generator/html.rb +51 -51
- data/lib/antelope/generator/info.rb +47 -47
- data/lib/antelope/generator/null.rb +18 -18
- data/lib/antelope/generator/output.rb +17 -17
- data/lib/antelope/generator/ruby.rb +112 -79
- data/lib/antelope/generator/templates/c_header.ant +36 -36
- data/lib/antelope/generator/templates/c_source.ant +202 -202
- data/lib/antelope/generator/templates/error.erb +40 -0
- data/lib/antelope/generator/templates/html/antelope.css +53 -1
- data/lib/antelope/generator/templates/html/antelope.html +82 -1
- data/lib/antelope/generator/templates/html/antelope.js +9 -1
- data/lib/antelope/generator/templates/html/css.ant +53 -53
- data/lib/antelope/generator/templates/html/html.ant +82 -82
- data/lib/antelope/generator/templates/html/js.ant +9 -9
- data/lib/antelope/generator/templates/info.erb +61 -0
- data/lib/antelope/generator/templates/{ruby.ant → ruby.erb} +171 -178
- data/lib/antelope/generator.rb +62 -66
- data/lib/antelope/grammar/generation.rb +76 -76
- data/lib/antelope/grammar/loading.rb +84 -84
- data/lib/antelope/grammar/precedence.rb +59 -59
- data/lib/antelope/grammar/precedences.rb +64 -64
- data/lib/antelope/grammar/production.rb +56 -56
- data/lib/antelope/grammar/productions.rb +154 -154
- data/lib/antelope/grammar/symbols.rb +64 -64
- data/lib/antelope/grammar/token/epsilon.rb +23 -23
- data/lib/antelope/grammar/token/error.rb +24 -24
- data/lib/antelope/grammar/token/nonterminal.rb +15 -15
- data/lib/antelope/grammar/token/terminal.rb +15 -15
- data/lib/antelope/grammar/token.rb +231 -231
- data/lib/antelope/grammar.rb +68 -68
- data/lib/antelope/version.rb +6 -6
- data/lib/antelope.rb +18 -19
- data/optimizations.txt +42 -42
- data/spec/antelope/ace/compiler_spec.rb +60 -60
- data/spec/antelope/ace/scanner_spec.rb +27 -27
- data/spec/antelope/generation/constructor_spec.rb +131 -131
- data/spec/fixtures/simple.ace +22 -22
- data/spec/spec_helper.rb +39 -39
- data/spec/support/benchmark_helper.rb +5 -5
- data/spec/support/grammar_helper.rb +14 -14
- data/subl/Ace (Ruby).JSON-tmLanguage +94 -94
- data/subl/Ace (Ruby).tmLanguage +153 -153
- metadata +22 -11
- data/lib/antelope/generator/templates/error.ant +0 -34
- data/lib/antelope/generator/templates/info.ant +0 -53
- data/lib/antelope/template/compiler.rb +0 -78
- data/lib/antelope/template/errors.rb +0 -9
- data/lib/antelope/template/scanner.rb +0 -109
- data/lib/antelope/template.rb +0 -64
- data/spec/antelope/template_spec.rb +0 -50
@@ -1,176 +1,176 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Antelope
|
4
|
-
module Generation
|
5
|
-
|
6
|
-
# Constructs the table required for the parser.
|
7
|
-
class Tableizer
|
8
|
-
|
9
|
-
# The grammar that the table is based off of.
|
10
|
-
#
|
11
|
-
# @return [Grammar]
|
12
|
-
attr_accessor :grammar
|
13
|
-
|
14
|
-
# The table itself.
|
15
|
-
#
|
16
|
-
# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
|
17
|
-
attr_accessor :table
|
18
|
-
|
19
|
-
# All rules in the grammar.
|
20
|
-
#
|
21
|
-
# @return [Hash<(Numeric, Recognizer::Rule)>]
|
22
|
-
attr_accessor :rules
|
23
|
-
|
24
|
-
attr_reader :conflicts
|
25
|
-
|
26
|
-
# Initialize.
|
27
|
-
#
|
28
|
-
# @param grammar [Grammar]
|
29
|
-
def initialize(grammar)
|
30
|
-
@grammar = grammar
|
31
|
-
end
|
32
|
-
|
33
|
-
# Construct the table, and then check the table for conflicts.
|
34
|
-
#
|
35
|
-
# @return [void]
|
36
|
-
# @see #tablize
|
37
|
-
# @see #conflictize
|
38
|
-
def call
|
39
|
-
tablize
|
40
|
-
conflictize
|
41
|
-
defaultize
|
42
|
-
end
|
43
|
-
|
44
|
-
# Construct a table based on the grammar. The table itself is
|
45
|
-
# an array whose elements are hashes; the index of the array
|
46
|
-
# corresponds to the state ID, and the keys of the hashes
|
47
|
-
# correspond to acceptable tokens. The values of the hashes
|
48
|
-
# should be an array of arrays (at this point).
|
49
|
-
#
|
50
|
-
# @return [void]
|
51
|
-
def tablize
|
52
|
-
@table = Array.new(grammar.states.size) do
|
53
|
-
Hash.new { |h, k| h[k] = [] }
|
54
|
-
end
|
55
|
-
@rules = []
|
56
|
-
|
57
|
-
grammar.states.each do |state|
|
58
|
-
state.transitions.each do |on, to|
|
59
|
-
table[state.id][on] << [:state, to.id]
|
60
|
-
end
|
61
|
-
|
62
|
-
state.rules.each do |rule|
|
63
|
-
@rules[rule.production.id] = rule.production
|
64
|
-
if rule.final?
|
65
|
-
rule.lookahead.each do |look|
|
66
|
-
table[state.id][look.name] <<
|
67
|
-
[:reduce, rule.production.id]
|
68
|
-
end
|
69
|
-
|
70
|
-
if rule.production.id.zero?
|
71
|
-
table[state.id][:$end] =
|
72
|
-
[[:accept, rule.production.id]]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
table
|
79
|
-
end
|
80
|
-
|
81
|
-
# Resolve any conflicts through precedence, if we can. If we
|
82
|
-
# can't, let the user know. This makes sure that every value
|
83
|
-
# of the hashes is a single array.
|
84
|
-
#
|
85
|
-
# @raise [UnresolvableConflictError] if a conflict could not be
|
86
|
-
# resolved using precedence rules.
|
87
|
-
# @return [void]
|
88
|
-
def conflictize
|
89
|
-
states = grammar.states.to_a.sort_by(&:id)
|
90
|
-
@conflicts = Hash.new { |h, k| h[k] = {} }
|
91
|
-
@table.each_with_index do |v, state|
|
92
|
-
v.each do |on, data|
|
93
|
-
if data.size == 1
|
94
|
-
@table[state][on] = data[0]
|
95
|
-
next
|
96
|
-
end
|
97
|
-
|
98
|
-
terminal = if states[state].transitions.key?(on)
|
99
|
-
states[state].rules.
|
100
|
-
detect { |rule| rule.active.name == on }.precedence
|
101
|
-
end
|
102
|
-
rule_part, other_part = data.sort_by { |(t, _)| t }
|
103
|
-
|
104
|
-
conflict = proc do |result|
|
105
|
-
hash = { result: result,
|
106
|
-
terminal: terminal,
|
107
|
-
prec: @rules[rule_part[1]].prec,
|
108
|
-
data: data,
|
109
|
-
rules: [], transitions: [] }
|
110
|
-
|
111
|
-
hash[:rules].concat(data.select { |part|
|
112
|
-
part[0] == :reduce || part[0] == :accept
|
113
|
-
}.map { |(_, id)|
|
114
|
-
states[state].rules.select(&:final?).
|
115
|
-
detect { |rule| rule.production.id == id }
|
116
|
-
})
|
117
|
-
hash[:transitions].concat(data.select { |part|
|
118
|
-
part[0] == :state
|
119
|
-
}.map { |_|
|
120
|
-
states[state].rules.
|
121
|
-
detect { |rule| rule.active.name == on }
|
122
|
-
})
|
123
|
-
|
124
|
-
conflicts[state][on] = hash
|
125
|
-
end
|
126
|
-
|
127
|
-
unless other_part[0] == :state
|
128
|
-
conflict.call(0)
|
129
|
-
$stderr.puts \
|
130
|
-
"Could not determine move for #{on} in state " \
|
131
|
-
"#{state} (reduce/reduce conflict)"
|
132
|
-
next
|
133
|
-
end
|
134
|
-
|
135
|
-
result = @rules[rule_part[1]].prec <=> terminal
|
136
|
-
conflict.call(result)
|
137
|
-
|
138
|
-
case result
|
139
|
-
when 0
|
140
|
-
@table[state][on] = nil
|
141
|
-
$stderr.puts \
|
142
|
-
"Could not determine move for #{on} in state " \
|
143
|
-
"#{state} (shift/reduce conflict)"
|
144
|
-
when 1
|
145
|
-
@table[state][on] = rule_part
|
146
|
-
when -1
|
147
|
-
@table[state][on] = other_part
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
# Reduce many transitions into a single `$default` transition.
|
154
|
-
# This only works if there is no `$empty` transition; if there
|
155
|
-
# is an `$empty` transition, then the `$default` transition is
|
156
|
-
# set to be the `$empty` transition.
|
157
|
-
#
|
158
|
-
# @return [void]
|
159
|
-
def defaultize
|
160
|
-
max = @table.map { |s| s.keys.size }.max
|
161
|
-
@table.each_with_index do |state|
|
162
|
-
common = state.group_by { |k, v| v }.values.
|
163
|
-
sort_by(&:size).first
|
164
|
-
|
165
|
-
if common.size > (max / 2)
|
166
|
-
action = common[0][1]
|
167
|
-
|
168
|
-
keys = common.map(&:first)
|
169
|
-
state.delete_if { |k, _| keys.include?(k) }
|
170
|
-
state[:$default] = action
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Antelope
|
4
|
+
module Generation
|
5
|
+
|
6
|
+
# Constructs the table required for the parser.
|
7
|
+
class Tableizer
|
8
|
+
|
9
|
+
# The grammar that the table is based off of.
|
10
|
+
#
|
11
|
+
# @return [Grammar]
|
12
|
+
attr_accessor :grammar
|
13
|
+
|
14
|
+
# The table itself.
|
15
|
+
#
|
16
|
+
# @return [Array<Hash<(Symbol, Array<(Symbol, Numeric)>)>>]
|
17
|
+
attr_accessor :table
|
18
|
+
|
19
|
+
# All rules in the grammar.
|
20
|
+
#
|
21
|
+
# @return [Hash<(Numeric, Recognizer::Rule)>]
|
22
|
+
attr_accessor :rules
|
23
|
+
|
24
|
+
attr_reader :conflicts
|
25
|
+
|
26
|
+
# Initialize.
|
27
|
+
#
|
28
|
+
# @param grammar [Grammar]
|
29
|
+
def initialize(grammar)
|
30
|
+
@grammar = grammar
|
31
|
+
end
|
32
|
+
|
33
|
+
# Construct the table, and then check the table for conflicts.
|
34
|
+
#
|
35
|
+
# @return [void]
|
36
|
+
# @see #tablize
|
37
|
+
# @see #conflictize
|
38
|
+
def call
|
39
|
+
tablize
|
40
|
+
conflictize
|
41
|
+
defaultize
|
42
|
+
end
|
43
|
+
|
44
|
+
# Construct a table based on the grammar. The table itself is
|
45
|
+
# an array whose elements are hashes; the index of the array
|
46
|
+
# corresponds to the state ID, and the keys of the hashes
|
47
|
+
# correspond to acceptable tokens. The values of the hashes
|
48
|
+
# should be an array of arrays (at this point).
|
49
|
+
#
|
50
|
+
# @return [void]
|
51
|
+
def tablize
|
52
|
+
@table = Array.new(grammar.states.size) do
|
53
|
+
Hash.new { |h, k| h[k] = [] }
|
54
|
+
end
|
55
|
+
@rules = []
|
56
|
+
|
57
|
+
grammar.states.each do |state|
|
58
|
+
state.transitions.each do |on, to|
|
59
|
+
table[state.id][on] << [:state, to.id]
|
60
|
+
end
|
61
|
+
|
62
|
+
state.rules.each do |rule|
|
63
|
+
@rules[rule.production.id] = rule.production
|
64
|
+
if rule.final?
|
65
|
+
rule.lookahead.each do |look|
|
66
|
+
table[state.id][look.name] <<
|
67
|
+
[:reduce, rule.production.id]
|
68
|
+
end
|
69
|
+
|
70
|
+
if rule.production.id.zero?
|
71
|
+
table[state.id][:$end] =
|
72
|
+
[[:accept, rule.production.id]]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
table
|
79
|
+
end
|
80
|
+
|
81
|
+
# Resolve any conflicts through precedence, if we can. If we
|
82
|
+
# can't, let the user know. This makes sure that every value
|
83
|
+
# of the hashes is a single array.
|
84
|
+
#
|
85
|
+
# @raise [UnresolvableConflictError] if a conflict could not be
|
86
|
+
# resolved using precedence rules.
|
87
|
+
# @return [void]
|
88
|
+
def conflictize
|
89
|
+
states = grammar.states.to_a.sort_by(&:id)
|
90
|
+
@conflicts = Hash.new { |h, k| h[k] = {} }
|
91
|
+
@table.each_with_index do |v, state|
|
92
|
+
v.each do |on, data|
|
93
|
+
if data.size == 1
|
94
|
+
@table[state][on] = data[0]
|
95
|
+
next
|
96
|
+
end
|
97
|
+
|
98
|
+
terminal = if states[state].transitions.key?(on)
|
99
|
+
states[state].rules.
|
100
|
+
detect { |rule| rule.active.name == on }.precedence
|
101
|
+
end
|
102
|
+
rule_part, other_part = data.sort_by { |(t, _)| t }
|
103
|
+
|
104
|
+
conflict = proc do |result|
|
105
|
+
hash = { result: result,
|
106
|
+
terminal: terminal,
|
107
|
+
prec: @rules[rule_part[1]].prec,
|
108
|
+
data: data,
|
109
|
+
rules: [], transitions: [] }
|
110
|
+
|
111
|
+
hash[:rules].concat(data.select { |part|
|
112
|
+
part[0] == :reduce || part[0] == :accept
|
113
|
+
}.map { |(_, id)|
|
114
|
+
states[state].rules.select(&:final?).
|
115
|
+
detect { |rule| rule.production.id == id }
|
116
|
+
})
|
117
|
+
hash[:transitions].concat(data.select { |part|
|
118
|
+
part[0] == :state
|
119
|
+
}.map { |_|
|
120
|
+
states[state].rules.
|
121
|
+
detect { |rule| rule.active.name == on }
|
122
|
+
})
|
123
|
+
|
124
|
+
conflicts[state][on] = hash
|
125
|
+
end
|
126
|
+
|
127
|
+
unless other_part[0] == :state
|
128
|
+
conflict.call(0)
|
129
|
+
$stderr.puts \
|
130
|
+
"Could not determine move for #{on} in state " \
|
131
|
+
"#{state} (reduce/reduce conflict)"
|
132
|
+
next
|
133
|
+
end
|
134
|
+
|
135
|
+
result = @rules[rule_part[1]].prec <=> terminal
|
136
|
+
conflict.call(result)
|
137
|
+
|
138
|
+
case result
|
139
|
+
when 0
|
140
|
+
@table[state][on] = nil
|
141
|
+
$stderr.puts \
|
142
|
+
"Could not determine move for #{on} in state " \
|
143
|
+
"#{state} (shift/reduce conflict)"
|
144
|
+
when 1
|
145
|
+
@table[state][on] = rule_part
|
146
|
+
when -1
|
147
|
+
@table[state][on] = other_part
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Reduce many transitions into a single `$default` transition.
|
154
|
+
# This only works if there is no `$empty` transition; if there
|
155
|
+
# is an `$empty` transition, then the `$default` transition is
|
156
|
+
# set to be the `$empty` transition.
|
157
|
+
#
|
158
|
+
# @return [void]
|
159
|
+
def defaultize
|
160
|
+
max = @table.map { |s| s.keys.size }.max
|
161
|
+
@table.each_with_index do |state|
|
162
|
+
common = state.group_by { |k, v| v }.values.
|
163
|
+
sort_by(&:size).first
|
164
|
+
|
165
|
+
if common.size > (max / 2)
|
166
|
+
action = common[0][1]
|
167
|
+
|
168
|
+
keys = common.map(&:first)
|
169
|
+
state.delete_if { |k, _| keys.include?(k) }
|
170
|
+
state[:$default] = action
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/lib/antelope/generation.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "antelope/generation/errors"
|
4
|
-
require "antelope/generation/constructor"
|
5
|
-
require "antelope/generation/recognizer"
|
6
|
-
require "antelope/generation/tableizer"
|
7
|
-
require "antelope/generation/null"
|
8
|
-
|
9
|
-
module Antelope
|
10
|
-
|
11
|
-
# Contains the generation mods.
|
12
|
-
module Generation
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "antelope/generation/errors"
|
4
|
+
require "antelope/generation/constructor"
|
5
|
+
require "antelope/generation/recognizer"
|
6
|
+
require "antelope/generation/tableizer"
|
7
|
+
require "antelope/generation/null"
|
8
|
+
|
9
|
+
module Antelope
|
10
|
+
|
11
|
+
# Contains the generation mods.
|
12
|
+
module Generation
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Antelope
|
2
|
+
module Generator
|
3
|
+
class Base
|
4
|
+
# Handles coercion of directives and their values.
|
5
|
+
module Coerce
|
6
|
+
# Retrieves all directives from the grammar, and giving them
|
7
|
+
# the proper values for this instance.
|
8
|
+
#
|
9
|
+
# @see .directive?
|
10
|
+
# @see #coerce_directive_value
|
11
|
+
# @return [Hash]
|
12
|
+
def directives
|
13
|
+
@_directives ||= begin
|
14
|
+
hash = Hashie::Mash.new
|
15
|
+
|
16
|
+
self.class.directives.each do |key, (_, definition)|
|
17
|
+
directive_value =
|
18
|
+
coerce_directive_value(grammar.options.key?(key),
|
19
|
+
grammar.options[key], definition)
|
20
|
+
value = coerce_nested_hash(key, directive_value)
|
21
|
+
hash.deep_merge!(value)
|
22
|
+
end
|
23
|
+
|
24
|
+
hash
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Coerces a key of the format `<name>[.<name>]*` into a full
|
29
|
+
# hash accessable by ruby.
|
30
|
+
#
|
31
|
+
# @param key [String] the key of the directive.
|
32
|
+
# @param value [String] the value of the directive.
|
33
|
+
# @return [Hash] the resultant hash.
|
34
|
+
def coerce_nested_hash(key, value)
|
35
|
+
parts = key.split('.').map { |p| p.gsub(/-/, '_') }
|
36
|
+
top = {}
|
37
|
+
hash = top
|
38
|
+
parts.each do |part|
|
39
|
+
hash[part] = if parts.last == part
|
40
|
+
value
|
41
|
+
else
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
hash = hash[part]
|
45
|
+
end
|
46
|
+
|
47
|
+
top[key] = value
|
48
|
+
top
|
49
|
+
end
|
50
|
+
|
51
|
+
# Coerce the given directive value to the given type. For the
|
52
|
+
# type `nil`, it checks the size of the values; for no values,
|
53
|
+
# it returns true; for one value, it returns that one value;
|
54
|
+
# for any other size value, it returns the values. For the
|
55
|
+
# type `Boolean`, if no values were given, or if the first
|
56
|
+
# value isn't "false", it returns true. For the type
|
57
|
+
# `:single` (or `:one`), it returns the first value. For the
|
58
|
+
# type `Array`, it returns the values. For any other type
|
59
|
+
# that is a class, it tries to initialize the class with the
|
60
|
+
# given arguments.
|
61
|
+
#
|
62
|
+
# @param defined [Boolean] Whether or not the value was
|
63
|
+
# actively defined in the grammar.
|
64
|
+
# @param values [Array<String>] The values that the directive
|
65
|
+
# was defined with.
|
66
|
+
# @param type [Object?] The type expected of the arguments
|
67
|
+
# given.
|
68
|
+
# @return [Object?]
|
69
|
+
def coerce_directive_value(defined, values, type)
|
70
|
+
return nil unless defined || type.is_a?(Array)
|
71
|
+
|
72
|
+
case type
|
73
|
+
when nil
|
74
|
+
values.any? ? values[0] : true
|
75
|
+
when :single, :one
|
76
|
+
values[0]
|
77
|
+
when Boolean
|
78
|
+
values[0].to_s != 'false'
|
79
|
+
when Array
|
80
|
+
values.zip(type).map do |value, t|
|
81
|
+
coerce_directive_value(defined, [value], t)
|
82
|
+
end
|
83
|
+
when Class
|
84
|
+
coerce_directive_class(values, type)
|
85
|
+
else
|
86
|
+
raise UnknownTypeError, "unknown type #{type}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# If the expected of the directive is a Class, then we try to
|
91
|
+
# determine which class is expected, and return the proper
|
92
|
+
# values.
|
93
|
+
#
|
94
|
+
# @param values [Array<String>] The values that the directive
|
95
|
+
# was defined with.
|
96
|
+
# @param type [Class] The type expected of the arguments
|
97
|
+
# given.
|
98
|
+
# @return [Object]
|
99
|
+
def coerce_directive_class(values, type)
|
100
|
+
if type == Array
|
101
|
+
values
|
102
|
+
elsif type == String
|
103
|
+
values[0].to_s
|
104
|
+
elsif type == Fixnum || type == Integer || type == Numeric
|
105
|
+
values[0].to_i
|
106
|
+
elsif type == Float
|
107
|
+
values[0].to_f
|
108
|
+
else
|
109
|
+
type.new(*values)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Antelope
|
2
|
+
module Generator
|
3
|
+
class Base
|
4
|
+
# Includes some extra processed information about the grammar
|
5
|
+
# to be provided to general generators.
|
6
|
+
module Extra
|
7
|
+
# The actual table that is used for parsing. This returns an
|
8
|
+
# array of hashes; the array index corresponds to the state
|
9
|
+
# number, and the hash keys correspond to the lookahead tokens.
|
10
|
+
# The hash values are an array; the first element of that array
|
11
|
+
# is the action to be taken, and the second element of the
|
12
|
+
# array is the argument for that action. Possible actions
|
13
|
+
# include `:accept`, `:reduce`, and `:state`; `:accept` means
|
14
|
+
# to accept the string; `:reduce` means to perform the given
|
15
|
+
# reduction; and `:state` means to transition to the given
|
16
|
+
# state.
|
17
|
+
#
|
18
|
+
# @return [Array<Hash<Symbol => Array<(Symbol, Numeric)>>>]
|
19
|
+
def table
|
20
|
+
if mods[:tableizer].is_a? Generation::Tableizer
|
21
|
+
mods[:tableizer].table
|
22
|
+
else
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns an array of the production information of each
|
28
|
+
# production needed by the parser. The first element of any
|
29
|
+
# element in the array is an {Ace::Token::Nonterminal} that
|
30
|
+
# that specific production reduces to; the second element
|
31
|
+
# is a number describing the number of items in the right hand
|
32
|
+
# side of the production; the string represents the action
|
33
|
+
# that should be taken on reduction.
|
34
|
+
#
|
35
|
+
# This information is used for `:reduce` actions in the parser;
|
36
|
+
# the value of the `:reduce` action corresponds to the array
|
37
|
+
# index of the production in this array.
|
38
|
+
#
|
39
|
+
# @return [Array<Array<(Ace::Token::Nonterminal, Numeric, String)>]
|
40
|
+
def productions
|
41
|
+
grammar.all_productions.map do |production|
|
42
|
+
[production[:label],
|
43
|
+
production[:items].size,
|
44
|
+
production[:block]]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|