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,178 +1,178 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Antelope
|
4
|
-
module Ace
|
5
|
-
class Scanner
|
6
|
-
|
7
|
-
# Scans the second part of the file. The second part of the
|
8
|
-
# file _only_ contains productions (or rules). Rules have a
|
9
|
-
# label and a body; the label may be any lowercase alphabetical
|
10
|
-
# identifier followed by a colon; the body consists of "parts",
|
11
|
-
# an "or", a "prec", and/or a "block". The part may consist
|
12
|
-
# of any alphabetical characters. An or is just a vertical bar
|
13
|
-
# (`|`). A prec is a precedence declaraction, which is `%prec `
|
14
|
-
# followed by any alphabetical characters. A block is a `{`,
|
15
|
-
# followed by code, followed by a terminating `}`. Rules _may_
|
16
|
-
# be terminated by a semicolon, but this is optional.
|
17
|
-
module Second
|
18
|
-
|
19
|
-
# Scans the second part of the file. This should be from just
|
20
|
-
# before the first content boundry; if the scanner doesn't
|
21
|
-
# find a content boundry, it will error. It will then check
|
22
|
-
# for a rule.
|
23
|
-
#
|
24
|
-
# @raise [SyntaxError] if no content boundry was found, or if
|
25
|
-
# the scanner encounters anything but a rule or whitespace.
|
26
|
-
# @return [void]
|
27
|
-
# @see #scan_second_rule
|
28
|
-
# @see #scan_whitespace
|
29
|
-
# @see #error!
|
30
|
-
def scan_second_part
|
31
|
-
scanner.scan(CONTENT_BOUNDRY) or error!
|
32
|
-
tokens << [:second]
|
33
|
-
|
34
|
-
until @scanner.check(CONTENT_BOUNDRY)
|
35
|
-
scan_second_rule || scan_whitespace || scan_comment ||
|
36
|
-
error!
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# Scans a rule. A rule consists of a label (the nonterminal
|
41
|
-
# the production is for), a body, and a block; and then,
|
42
|
-
# an optional semicolon.
|
43
|
-
#
|
44
|
-
# @return [Boolean] if it matched
|
45
|
-
# @see #scan_second_rule_label
|
46
|
-
# @see #scan_second_rule_body
|
47
|
-
# @see #error!
|
48
|
-
def scan_second_rule
|
49
|
-
if @scanner.check(/(#{IDENTIFIER})(\[#{IDENTIFIER}\])?:/)
|
50
|
-
scan_second_rule_label or error!
|
51
|
-
scan_second_rule_body
|
52
|
-
true
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Scans the label for a rule. It should contain only lower
|
57
|
-
# case letters and a colon.
|
58
|
-
#
|
59
|
-
# @return [Boolean] if it matched.
|
60
|
-
def scan_second_rule_label
|
61
|
-
if @scanner.scan(/(#{IDENTIFIER})(?:\[(#{IDENTIFIER})\])?: ?/)
|
62
|
-
tokens << [:label, @scanner[1], @scanner[2]]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# The body can contain parts, ors, precs, or blocks (or
|
67
|
-
# whitespaces). Scans all of them, and then attempts to
|
68
|
-
# scan a semicolon.
|
69
|
-
#
|
70
|
-
# @return [void]
|
71
|
-
# @see #scan_second_rule_part
|
72
|
-
# @see #scan_second_rule_or
|
73
|
-
# @see #scan_second_rule_prec
|
74
|
-
# @see #scan_second_rule_block
|
75
|
-
# @see #scan_whitespace
|
76
|
-
def scan_second_rule_body
|
77
|
-
body = true
|
78
|
-
while body
|
79
|
-
scan_second_rule_prec || scan_second_rule_part ||
|
80
|
-
scan_second_rule_or || scan_second_rule_block ||
|
81
|
-
scan_whitespace || scan_comment || (body = false)
|
82
|
-
end
|
83
|
-
@scanner.scan(/;/)
|
84
|
-
end
|
85
|
-
|
86
|
-
# Attempts to scan a "part". A part is any series of
|
87
|
-
# alphabetical characters that are not followed by a
|
88
|
-
# colon.
|
89
|
-
#
|
90
|
-
# @return [Boolean] if it matched.
|
91
|
-
def scan_second_rule_part
|
92
|
-
if @scanner.scan(/(%?#{IDENTIFIER})(?:\[(#{IDENTIFIER})\])?(?!\:|[A-Za-z._])/)
|
93
|
-
tokens << [:part, @scanner[1], @scanner[2]]
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# Attempts to scan an "or". It's just a vertical bar.
|
98
|
-
#
|
99
|
-
# @return [Boolean] if it matched.
|
100
|
-
def scan_second_rule_or
|
101
|
-
if @scanner.scan(/\|/)
|
102
|
-
tokens << [:or]
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# Attempts to scan a precedence definition. A precedence
|
107
|
-
# definition is "%prec " followed by a terminal or nonterminal.
|
108
|
-
#
|
109
|
-
# @return [Boolean] if it matched.
|
110
|
-
def scan_second_rule_prec
|
111
|
-
if @scanner.scan(/%prec (#{IDENTIFIER})/)
|
112
|
-
tokens << [:prec, @scanner[1]]
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Attempts to scan a block. This correctly balances brackets;
|
117
|
-
# however, if a bracket is opened/closed within a string, it
|
118
|
-
# still counts that as a bracket that needs to be balanced.
|
119
|
-
# So, having extensive code within a block is not a good idea.
|
120
|
-
#
|
121
|
-
# @return [Boolean] if it matched.
|
122
|
-
def scan_second_rule_block
|
123
|
-
if @scanner.scan(/\{/)
|
124
|
-
tokens << [:block, _scan_block]
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
private
|
129
|
-
|
130
|
-
# Scans the block; it scans until it encounters enough closing
|
131
|
-
# brackets to match the opening brackets. If it encounters
|
132
|
-
# an opening brackets, it increments the bracket counter by
|
133
|
-
# one; if it encounters a closing bracket, it decrements by
|
134
|
-
# one. It will error if it reaches the end before the
|
135
|
-
# brackets are fully closed.
|
136
|
-
#
|
137
|
-
# @return [String] the block's body.
|
138
|
-
# @raise [SyntaxError] if it reaches the end before the final
|
139
|
-
# bracket is closed.
|
140
|
-
def _scan_block
|
141
|
-
brack = 1
|
142
|
-
body = "{"
|
143
|
-
scan_for = %r{
|
144
|
-
(
|
145
|
-
(?: " ( \\\\ | \\" | [^"] )* "? )
|
146
|
-
| (?: ' ( \\\\ | \\' | [^'] )* '? )
|
147
|
-
| (?: // .*? \n )
|
148
|
-
| (?: \# .*? \n )
|
149
|
-
| (?: /\* [\s\S]+? \*/ )
|
150
|
-
| (?: \} )
|
151
|
-
| (?: \{ )
|
152
|
-
)
|
153
|
-
}x
|
154
|
-
|
155
|
-
until brack.zero?
|
156
|
-
if part = @scanner.scan_until(scan_for)
|
157
|
-
body << part
|
158
|
-
|
159
|
-
|
160
|
-
if @scanner[1] == "}"
|
161
|
-
brack -= 1
|
162
|
-
elsif @scanner[1] == "{"
|
163
|
-
brack += 1
|
164
|
-
end
|
165
|
-
else
|
166
|
-
if @scanner.scan(/(.+)/m)
|
167
|
-
@line += @scanner[1].count("\n")
|
168
|
-
end
|
169
|
-
error!
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
body
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Antelope
|
4
|
+
module Ace
|
5
|
+
class Scanner
|
6
|
+
|
7
|
+
# Scans the second part of the file. The second part of the
|
8
|
+
# file _only_ contains productions (or rules). Rules have a
|
9
|
+
# label and a body; the label may be any lowercase alphabetical
|
10
|
+
# identifier followed by a colon; the body consists of "parts",
|
11
|
+
# an "or", a "prec", and/or a "block". The part may consist
|
12
|
+
# of any alphabetical characters. An or is just a vertical bar
|
13
|
+
# (`|`). A prec is a precedence declaraction, which is `%prec `
|
14
|
+
# followed by any alphabetical characters. A block is a `{`,
|
15
|
+
# followed by code, followed by a terminating `}`. Rules _may_
|
16
|
+
# be terminated by a semicolon, but this is optional.
|
17
|
+
module Second
|
18
|
+
|
19
|
+
# Scans the second part of the file. This should be from just
|
20
|
+
# before the first content boundry; if the scanner doesn't
|
21
|
+
# find a content boundry, it will error. It will then check
|
22
|
+
# for a rule.
|
23
|
+
#
|
24
|
+
# @raise [SyntaxError] if no content boundry was found, or if
|
25
|
+
# the scanner encounters anything but a rule or whitespace.
|
26
|
+
# @return [void]
|
27
|
+
# @see #scan_second_rule
|
28
|
+
# @see #scan_whitespace
|
29
|
+
# @see #error!
|
30
|
+
def scan_second_part
|
31
|
+
scanner.scan(CONTENT_BOUNDRY) or error!
|
32
|
+
tokens << [:second]
|
33
|
+
|
34
|
+
until @scanner.check(CONTENT_BOUNDRY)
|
35
|
+
scan_second_rule || scan_whitespace || scan_comment ||
|
36
|
+
error!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Scans a rule. A rule consists of a label (the nonterminal
|
41
|
+
# the production is for), a body, and a block; and then,
|
42
|
+
# an optional semicolon.
|
43
|
+
#
|
44
|
+
# @return [Boolean] if it matched
|
45
|
+
# @see #scan_second_rule_label
|
46
|
+
# @see #scan_second_rule_body
|
47
|
+
# @see #error!
|
48
|
+
def scan_second_rule
|
49
|
+
if @scanner.check(/(#{IDENTIFIER})(\[#{IDENTIFIER}\])?:/)
|
50
|
+
scan_second_rule_label or error!
|
51
|
+
scan_second_rule_body
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Scans the label for a rule. It should contain only lower
|
57
|
+
# case letters and a colon.
|
58
|
+
#
|
59
|
+
# @return [Boolean] if it matched.
|
60
|
+
def scan_second_rule_label
|
61
|
+
if @scanner.scan(/(#{IDENTIFIER})(?:\[(#{IDENTIFIER})\])?: ?/)
|
62
|
+
tokens << [:label, @scanner[1], @scanner[2]]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# The body can contain parts, ors, precs, or blocks (or
|
67
|
+
# whitespaces). Scans all of them, and then attempts to
|
68
|
+
# scan a semicolon.
|
69
|
+
#
|
70
|
+
# @return [void]
|
71
|
+
# @see #scan_second_rule_part
|
72
|
+
# @see #scan_second_rule_or
|
73
|
+
# @see #scan_second_rule_prec
|
74
|
+
# @see #scan_second_rule_block
|
75
|
+
# @see #scan_whitespace
|
76
|
+
def scan_second_rule_body
|
77
|
+
body = true
|
78
|
+
while body
|
79
|
+
scan_second_rule_prec || scan_second_rule_part ||
|
80
|
+
scan_second_rule_or || scan_second_rule_block ||
|
81
|
+
scan_whitespace || scan_comment || (body = false)
|
82
|
+
end
|
83
|
+
@scanner.scan(/;/)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Attempts to scan a "part". A part is any series of
|
87
|
+
# alphabetical characters that are not followed by a
|
88
|
+
# colon.
|
89
|
+
#
|
90
|
+
# @return [Boolean] if it matched.
|
91
|
+
def scan_second_rule_part
|
92
|
+
if @scanner.scan(/(%?#{IDENTIFIER})(?:\[(#{IDENTIFIER})\])?(?!\:|[A-Za-z._])/)
|
93
|
+
tokens << [:part, @scanner[1], @scanner[2]]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Attempts to scan an "or". It's just a vertical bar.
|
98
|
+
#
|
99
|
+
# @return [Boolean] if it matched.
|
100
|
+
def scan_second_rule_or
|
101
|
+
if @scanner.scan(/\|/)
|
102
|
+
tokens << [:or]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Attempts to scan a precedence definition. A precedence
|
107
|
+
# definition is "%prec " followed by a terminal or nonterminal.
|
108
|
+
#
|
109
|
+
# @return [Boolean] if it matched.
|
110
|
+
def scan_second_rule_prec
|
111
|
+
if @scanner.scan(/%prec (#{IDENTIFIER})/)
|
112
|
+
tokens << [:prec, @scanner[1]]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Attempts to scan a block. This correctly balances brackets;
|
117
|
+
# however, if a bracket is opened/closed within a string, it
|
118
|
+
# still counts that as a bracket that needs to be balanced.
|
119
|
+
# So, having extensive code within a block is not a good idea.
|
120
|
+
#
|
121
|
+
# @return [Boolean] if it matched.
|
122
|
+
def scan_second_rule_block
|
123
|
+
if @scanner.scan(/\{/)
|
124
|
+
tokens << [:block, _scan_block]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
# Scans the block; it scans until it encounters enough closing
|
131
|
+
# brackets to match the opening brackets. If it encounters
|
132
|
+
# an opening brackets, it increments the bracket counter by
|
133
|
+
# one; if it encounters a closing bracket, it decrements by
|
134
|
+
# one. It will error if it reaches the end before the
|
135
|
+
# brackets are fully closed.
|
136
|
+
#
|
137
|
+
# @return [String] the block's body.
|
138
|
+
# @raise [SyntaxError] if it reaches the end before the final
|
139
|
+
# bracket is closed.
|
140
|
+
def _scan_block
|
141
|
+
brack = 1
|
142
|
+
body = "{"
|
143
|
+
scan_for = %r{
|
144
|
+
(
|
145
|
+
(?: " ( \\\\ | \\" | [^"] )* "? )
|
146
|
+
| (?: ' ( \\\\ | \\' | [^'] )* '? )
|
147
|
+
| (?: // .*? \n )
|
148
|
+
| (?: \# .*? \n )
|
149
|
+
| (?: /\* [\s\S]+? \*/ )
|
150
|
+
| (?: \} )
|
151
|
+
| (?: \{ )
|
152
|
+
)
|
153
|
+
}x
|
154
|
+
|
155
|
+
until brack.zero?
|
156
|
+
if part = @scanner.scan_until(scan_for)
|
157
|
+
body << part
|
158
|
+
|
159
|
+
|
160
|
+
if @scanner[1] == "}"
|
161
|
+
brack -= 1
|
162
|
+
elsif @scanner[1] == "{"
|
163
|
+
brack += 1
|
164
|
+
end
|
165
|
+
else
|
166
|
+
if @scanner.scan(/(.+)/m)
|
167
|
+
@line += @scanner[1].count("\n")
|
168
|
+
end
|
169
|
+
error!
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
body
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -1,27 +1,27 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Antelope
|
4
|
-
module Ace
|
5
|
-
class Scanner
|
6
|
-
|
7
|
-
# Scans the third part. Everything after the content
|
8
|
-
# boundry is copied directly into the output.
|
9
|
-
module Third
|
10
|
-
|
11
|
-
# Scans the third part. It should start with a content
|
12
|
-
# boundry; raises an error if it does not. It then scans
|
13
|
-
# until the end of the file.
|
14
|
-
#
|
15
|
-
# @raise [SyntaxError] if somehow there is no content
|
16
|
-
# boundry.
|
17
|
-
# @return [void]
|
18
|
-
def scan_third_part
|
19
|
-
@scanner.scan(CONTENT_BOUNDRY) or error!
|
20
|
-
|
21
|
-
tokens << [:third]
|
22
|
-
tokens << [:copy, @scanner.scan(/[\s\S]+/m) || ""]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Antelope
|
4
|
+
module Ace
|
5
|
+
class Scanner
|
6
|
+
|
7
|
+
# Scans the third part. Everything after the content
|
8
|
+
# boundry is copied directly into the output.
|
9
|
+
module Third
|
10
|
+
|
11
|
+
# Scans the third part. It should start with a content
|
12
|
+
# boundry; raises an error if it does not. It then scans
|
13
|
+
# until the end of the file.
|
14
|
+
#
|
15
|
+
# @raise [SyntaxError] if somehow there is no content
|
16
|
+
# boundry.
|
17
|
+
# @return [void]
|
18
|
+
def scan_third_part
|
19
|
+
@scanner.scan(CONTENT_BOUNDRY) or error!
|
20
|
+
|
21
|
+
tokens << [:third]
|
22
|
+
tokens << [:copy, @scanner.scan(/[\s\S]+/m) || ""]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|