riml 0.1.3
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.
- data/LICENSE +20 -0
- data/README.md +148 -0
- data/bin/riml +69 -0
- data/config/environment.rb +10 -0
- data/lib/ast_rewriter.rb +268 -0
- data/lib/class_map.rb +46 -0
- data/lib/compiler.rb +579 -0
- data/lib/constants.rb +280 -0
- data/lib/errors.rb +4 -0
- data/lib/grammar.y +485 -0
- data/lib/helper.rb +45 -0
- data/lib/lexer.rb +276 -0
- data/lib/nodes.rb +723 -0
- data/lib/parser.rb +2748 -0
- data/lib/walker.rb +15 -0
- data/version.rb +4 -0
- metadata +75 -0
data/lib/grammar.y
ADDED
@@ -0,0 +1,485 @@
|
|
1
|
+
class Riml::Parser
|
2
|
+
|
3
|
+
token IF ELSE ELSEIF THEN UNLESS END
|
4
|
+
token WHILE UNTIL BREAK CONTINUE
|
5
|
+
token TRY CATCH ENSURE
|
6
|
+
token FOR IN
|
7
|
+
token DEF DEF_BANG SPLAT CALL BUILTIN_COMMAND # such as echo "hi"
|
8
|
+
token CLASS NEW DEFM DEFM_BANG SUPER
|
9
|
+
token RETURN
|
10
|
+
token NEWLINE
|
11
|
+
token NUMBER
|
12
|
+
token STRING_D STRING_S # single- and double-quoted
|
13
|
+
token HEREDOC EX_LITERAL
|
14
|
+
token REGEXP
|
15
|
+
token TRUE FALSE NIL
|
16
|
+
token LET UNLET UNLET_BANG IDENTIFIER
|
17
|
+
token DICT_VAL # like dict.key, 'key' is a DICT_VAL
|
18
|
+
token SCOPE_MODIFIER SCOPE_MODIFIER_LITERAL SPECIAL_VAR_PREFIX
|
19
|
+
token FINISH
|
20
|
+
|
21
|
+
prechigh
|
22
|
+
right '!'
|
23
|
+
left '*' '/' '%'
|
24
|
+
left '+' '+=' '-' '-=' '.'
|
25
|
+
left '>' '>#' '>?' '<' '<#' '<?' '>=' '>=#' '>=?' '<=' '<=#' '<=?'
|
26
|
+
left '==' '==?' '==#' '=~' '=~?' '=~#' '!~' '!~?' '!~#' '!=' '!=?' '!=#'
|
27
|
+
left IS ISNOT
|
28
|
+
left '&&'
|
29
|
+
left '||'
|
30
|
+
right '?'
|
31
|
+
right '='
|
32
|
+
left ','
|
33
|
+
left IF UNLESS
|
34
|
+
preclow
|
35
|
+
|
36
|
+
# All rules
|
37
|
+
rule
|
38
|
+
|
39
|
+
Root:
|
40
|
+
/* nothing */ { result = Nodes.new([]) }
|
41
|
+
| Expressions { result = val[0] }
|
42
|
+
;
|
43
|
+
|
44
|
+
# any list of expressions
|
45
|
+
Expressions:
|
46
|
+
Expression { result = Nodes.new([ val[0] ]) }
|
47
|
+
| Expressions Terminator Expression { result = val[0] << val[2] }
|
48
|
+
| Expressions Terminator { result = val[0] }
|
49
|
+
| Terminator { result = Nodes.new([]) }
|
50
|
+
;
|
51
|
+
|
52
|
+
# All types of expressions in Riml
|
53
|
+
Expression:
|
54
|
+
BinaryOperator { result = val[0] }
|
55
|
+
| UnaryOperator { result = val[0] }
|
56
|
+
| Call { result = val[0] }
|
57
|
+
| Assign { result = val[0] }
|
58
|
+
| DictGet { result = val[0] }
|
59
|
+
| ListOrDictGet { result = val[0] }
|
60
|
+
| Def { result = val[0] }
|
61
|
+
| Return { result = val[0] }
|
62
|
+
| VariableRetrieval { result = val[0] }
|
63
|
+
| UnletVariable { result = val[0] }
|
64
|
+
| Literal { result = val[0] }
|
65
|
+
| ExLiteral { result = val[0] }
|
66
|
+
| Heredoc { result = val[0] }
|
67
|
+
| If { result = val[0] }
|
68
|
+
| Unless { result = val[0] }
|
69
|
+
| Ternary { result = val[0] }
|
70
|
+
| While { result = val[0] }
|
71
|
+
| Until { result = val[0] }
|
72
|
+
| For { result = val[0] }
|
73
|
+
| Try { result = val[0] }
|
74
|
+
| ClassDefinition { result = val[0] }
|
75
|
+
| ObjectInstantiation { result = val[0] }
|
76
|
+
| Super { result = val[0] }
|
77
|
+
| LoopKeyword { result = val[0] }
|
78
|
+
| EndScript { result = val[0] }
|
79
|
+
| '(' Expression ')' { result = val[1] }
|
80
|
+
;
|
81
|
+
|
82
|
+
Terminator:
|
83
|
+
NEWLINE { result = nil }
|
84
|
+
| ';' { result = nil }
|
85
|
+
| '|' { result = nil }
|
86
|
+
;
|
87
|
+
|
88
|
+
# All hard-coded values
|
89
|
+
Literal:
|
90
|
+
Number { result = val[0] }
|
91
|
+
| String { result = val[0] }
|
92
|
+
| Regexp { result = val[0] }
|
93
|
+
| List { result = val[0] }
|
94
|
+
| Dictionary { result = val[0] }
|
95
|
+
| ScopeModifierLiteral { result = val[0] }
|
96
|
+
| TRUE { result = TrueNode.new }
|
97
|
+
| FALSE { result = FalseNode.new }
|
98
|
+
| NIL { result = NilNode.new }
|
99
|
+
;
|
100
|
+
|
101
|
+
Number:
|
102
|
+
NUMBER { result = NumberNode.new(val[0]) }
|
103
|
+
| '-' NUMBER { result = NumberNode.new(val[1].insert(0, val[0])) }
|
104
|
+
| '+' NUMBER { result = NumberNode.new(val[1].insert(0, val[0])) }
|
105
|
+
;
|
106
|
+
|
107
|
+
String:
|
108
|
+
STRING_S { result = StringNode.new(val[0], :s) }
|
109
|
+
| STRING_D { result = StringNode.new(val[0], :d) }
|
110
|
+
;
|
111
|
+
|
112
|
+
Heredoc:
|
113
|
+
HEREDOC String { result = HeredocNode.new(val[0], val[1]) }
|
114
|
+
;
|
115
|
+
|
116
|
+
Regexp:
|
117
|
+
REGEXP { result = RegexpNode.new(val[0]) }
|
118
|
+
;
|
119
|
+
|
120
|
+
ScopeModifierLiteral:
|
121
|
+
SCOPE_MODIFIER_LITERAL { result = ScopeModifierLiteralNode.new(val[0]) }
|
122
|
+
;
|
123
|
+
|
124
|
+
List:
|
125
|
+
ListLiteral { result = ListNode.new(val[0]) }
|
126
|
+
;
|
127
|
+
|
128
|
+
ListLiteral:
|
129
|
+
'[' ListItems ']' { result = val[1] }
|
130
|
+
| '[' ListItems ',' ']' { result = val[1] }
|
131
|
+
;
|
132
|
+
|
133
|
+
ListItems:
|
134
|
+
/* nothing */ { result = [] }
|
135
|
+
| Expression { result = [val[0]] }
|
136
|
+
| ListItems ',' Expression { result = val[0] << val[2] }
|
137
|
+
;
|
138
|
+
|
139
|
+
Dictionary:
|
140
|
+
DictionaryLiteral { result = DictionaryNode.new(val[0]) }
|
141
|
+
;
|
142
|
+
|
143
|
+
# {'key': 'value', 'key': 'value'}
|
144
|
+
DictionaryLiteral:
|
145
|
+
'{' DictItems '}' { result = Hash[val[1]] }
|
146
|
+
| '{' DictItems ',' '}' { result = Hash[val[1]] }
|
147
|
+
;
|
148
|
+
|
149
|
+
# [[key, value], [key, value]]
|
150
|
+
DictItems:
|
151
|
+
/* nothing */ { result = [] }
|
152
|
+
| DictItem { result = val }
|
153
|
+
| DictItems ',' DictItem { result = val[0] << val[2] }
|
154
|
+
;
|
155
|
+
|
156
|
+
# [key, value]
|
157
|
+
DictItem:
|
158
|
+
Literal ':' Literal { result = [val[0], val[2]] }
|
159
|
+
;
|
160
|
+
|
161
|
+
DictGet:
|
162
|
+
Dictionary ListOrDictGetWithBrackets { result = DictGetBracketNode.new(val[0], val[1]) }
|
163
|
+
| Dictionary DictGetWithDotLiteral { result = DictGetDotNode.new(val[0], val[1]) }
|
164
|
+
| VariableRetrieval DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
|
165
|
+
| ListOrDictGet DictGetWithDot { result = DictGetDotNode.new(val[0], val[1]) }
|
166
|
+
;
|
167
|
+
|
168
|
+
ListOrDictGet:
|
169
|
+
VariableRetrieval ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
|
170
|
+
| DictGet ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
|
171
|
+
| Call ListOrDictGetWithBrackets { result = ListOrDictGetNode.new(val[0], val[1]) }
|
172
|
+
;
|
173
|
+
|
174
|
+
ListOrDictGetWithBrackets:
|
175
|
+
'[' Expression ']' { result = [val[1]] }
|
176
|
+
| '[' SubList ']' { result = [val[1]] }
|
177
|
+
| ListOrDictGetWithBrackets '[' Expression ']' { result = val[0] << val[2] }
|
178
|
+
| ListOrDictGetWithBrackets '[' SubList ']' { result = val[0] << val[2] }
|
179
|
+
;
|
180
|
+
|
181
|
+
SubList:
|
182
|
+
Expression ':' Expression { result = Nodes.new([val[0], LiteralNode.new(' : '), val[2]]) }
|
183
|
+
| Expression ':' { result = Nodes.new([val[0], LiteralNode.new(' :')]) }
|
184
|
+
| ':' Expression { result = Nodes.new([LiteralNode.new(': '), val[1]]) }
|
185
|
+
| ':' { result = Nodes.new([LiteralNode.new(':')]) }
|
186
|
+
;
|
187
|
+
|
188
|
+
DictGetWithDot:
|
189
|
+
DICT_VAL { result = [val[0]]}
|
190
|
+
| DictGetWithDot DICT_VAL { result = val[0] << val[1] }
|
191
|
+
;
|
192
|
+
|
193
|
+
DictGetWithDotLiteral:
|
194
|
+
'.' IDENTIFIER { result = [val[1]] }
|
195
|
+
| DictGetWithDotLiteral DICT_VAL { result = val[0] << val[1] }
|
196
|
+
;
|
197
|
+
|
198
|
+
Call:
|
199
|
+
Scope DefCallIdentifier '(' ArgList ')' { result = CallNode.new(val[0], val[1], val[3]) }
|
200
|
+
| DictGet '(' ArgList ')' { result = CallNode.new(nil, val[0], val[2]) }
|
201
|
+
| CALL Scope DefCallIdentifier '(' ArgList ')' { result = ExplicitCallNode.new(val[1], val[2], val[4]) }
|
202
|
+
| CALL DictGet '(' ArgList ')' { result = ExplicitCallNode.new(nil, val[1], val[3]) }
|
203
|
+
| BUILTIN_COMMAND '(' ArgList ')' { result = CallNode.new(nil, val[0], val[2]) }
|
204
|
+
| BUILTIN_COMMAND ArgList { result = CallNode.new(nil, val[0], val[1]) }
|
205
|
+
;
|
206
|
+
|
207
|
+
Scope:
|
208
|
+
SCOPE_MODIFIER { result = val[0] }
|
209
|
+
| /* nothing */ { result = nil }
|
210
|
+
;
|
211
|
+
|
212
|
+
ArgList:
|
213
|
+
/* nothing */ { result = [] }
|
214
|
+
| Expression { result = val }
|
215
|
+
| ArgList "," Expression { result = val[0] << val[2] }
|
216
|
+
;
|
217
|
+
|
218
|
+
BinaryOperator:
|
219
|
+
Expression '||' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
220
|
+
| Expression '&&' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
221
|
+
|
222
|
+
| Expression '==' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
223
|
+
| Expression '==#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
224
|
+
| Expression '==?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
225
|
+
|
226
|
+
# added by riml
|
227
|
+
| Expression '===' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
228
|
+
|
229
|
+
| Expression '!=' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
230
|
+
| Expression '!=#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
231
|
+
| Expression '!=?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
232
|
+
|
233
|
+
| Expression '=~' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
234
|
+
| Expression '=~#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
235
|
+
| Expression '=~?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
236
|
+
|
237
|
+
| Expression '!~' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
238
|
+
| Expression '!~#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
239
|
+
| Expression '!~?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
240
|
+
|
241
|
+
| Expression '>' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
242
|
+
| Expression '>#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
243
|
+
| Expression '>?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
244
|
+
|
245
|
+
| Expression '>=' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
246
|
+
| Expression '>=#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
247
|
+
| Expression '>=?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
248
|
+
|
249
|
+
| Expression '<' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
250
|
+
| Expression '<#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
251
|
+
| Expression '<?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
252
|
+
|
253
|
+
| Expression '<=' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
254
|
+
| Expression '<=#' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
255
|
+
| Expression '<=?' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
256
|
+
|
257
|
+
| Expression '+' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
258
|
+
| Expression '-' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
259
|
+
| Expression '*' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
260
|
+
| Expression '/' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
261
|
+
| Expression '.' Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
262
|
+
|
263
|
+
| Expression IS Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
264
|
+
| Expression ISNOT Expression { result = BinaryOperatorNode.new(val[1], [val[0], val[2]]) }
|
265
|
+
;
|
266
|
+
|
267
|
+
UnaryOperator:
|
268
|
+
'!' Expression { result = UnaryOperatorNode.new(val[0], val[1]) }
|
269
|
+
;
|
270
|
+
|
271
|
+
# ['=', LHS, RHS]
|
272
|
+
Assign:
|
273
|
+
LET AssignExpression { result = AssignNode.new(val[1][0], val[1][1], val[1][2]) }
|
274
|
+
| AssignExpression { result = AssignNode.new(val[0][0], val[0][1], val[0][2]) }
|
275
|
+
;
|
276
|
+
|
277
|
+
# ['=', AssignLHS, Expression]
|
278
|
+
AssignExpression:
|
279
|
+
AssignLHS '=' Expression { result = [val[1], val[0], val[2]] }
|
280
|
+
| AssignLHS '+=' Expression { result = [val[1], val[0], val[2]] }
|
281
|
+
| AssignLHS '-=' Expression { result = [val[1], val[0], val[2]] }
|
282
|
+
| AssignLHS '.=' Expression { result = [val[1], val[0], val[2]] }
|
283
|
+
;
|
284
|
+
|
285
|
+
AssignLHS:
|
286
|
+
VariableRetrieval { result = val[0] }
|
287
|
+
| DictGet { result = val[0] }
|
288
|
+
| List { result = val[0] }
|
289
|
+
| ListOrDictGet { result = val[0] }
|
290
|
+
;
|
291
|
+
|
292
|
+
# retrieving the value of a variable
|
293
|
+
VariableRetrieval:
|
294
|
+
Scope IDENTIFIER { result = GetVariableNode.new(val[0], val[1]) }
|
295
|
+
| SPECIAL_VAR_PREFIX IDENTIFIER { result = GetSpecialVariableNode.new(val[0], val[1]) }
|
296
|
+
| Scope CurlyBraceName { result = GetCurlyBraceNameNode.new(val[0], val[1])}
|
297
|
+
;
|
298
|
+
|
299
|
+
UnletVariable:
|
300
|
+
UNLET VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
|
301
|
+
| UNLET_BANG VariableRetrieval { result = UnletVariableNode.new('!', [ val[1] ]) }
|
302
|
+
| UnletVariable VariableRetrieval { result = val[0] << val[1] }
|
303
|
+
;
|
304
|
+
|
305
|
+
CurlyBraceName:
|
306
|
+
IDENTIFIER '{' VariableRetrieval '}' { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[0]), CurlyBracePart.new(val[2]) ]) }
|
307
|
+
| '{' VariableRetrieval '}' IDENTIFIER { result = CurlyBraceVariable.new([ CurlyBracePart.new(val[1]), CurlyBracePart.new(val[3]) ]) }
|
308
|
+
| CurlyBraceName IDENTIFIER { result = val[0] << CurlyBracePart.new(val[1]) }
|
309
|
+
;
|
310
|
+
|
311
|
+
# Method definition
|
312
|
+
# [scope_modifier, name, parameters, keyword, expressions]
|
313
|
+
Def:
|
314
|
+
FunctionType Scope DefCallIdentifier Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], [], val[3], val[4]) }
|
315
|
+
| FunctionType Scope DefCallIdentifier '(' ParamList ')' Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], val[4], val[6], val[7]) }
|
316
|
+
| FunctionType Scope DefCallIdentifier '(' SPLAT ')' Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], [val[4]], val[6], val[7]) }
|
317
|
+
| FunctionType Scope DefCallIdentifier '(' ParamList ',' SPLAT ')' Keyword Block END { result = Object.const_get(val[0]).new('!', val[1], val[2], val[4] << val[6], val[8], val[9]) }
|
318
|
+
;
|
319
|
+
|
320
|
+
FunctionType:
|
321
|
+
DEF { result = "DefNode" }
|
322
|
+
| DEF_BANG { result = "DefNode" }
|
323
|
+
| DEFM { result = "DefMethodNode" }
|
324
|
+
;
|
325
|
+
|
326
|
+
DefCallIdentifier:
|
327
|
+
# use '' for first argument instead of nil in order to avoid a double scope-modifier
|
328
|
+
CurlyBraceName { result = GetCurlyBraceNameNode.new('', val[0])}
|
329
|
+
| IDENTIFIER { result = val[0] }
|
330
|
+
;
|
331
|
+
|
332
|
+
# Example: 'range' or 'dict' after function definition
|
333
|
+
Keyword:
|
334
|
+
IDENTIFIER { result = val[0] }
|
335
|
+
| /* nothing */ { result = nil }
|
336
|
+
;
|
337
|
+
|
338
|
+
ParamList:
|
339
|
+
/* nothing */ { result = [] }
|
340
|
+
| IDENTIFIER { result = val }
|
341
|
+
| ParamList ',' IDENTIFIER { result = val[0] << val[2] }
|
342
|
+
;
|
343
|
+
|
344
|
+
Return:
|
345
|
+
RETURN Expression { result = ReturnNode.new(val[1]) }
|
346
|
+
| RETURN Terminator { result = ReturnNode.new(nil) }
|
347
|
+
;
|
348
|
+
|
349
|
+
EndScript:
|
350
|
+
FINISH { result = FinishNode.new }
|
351
|
+
;
|
352
|
+
|
353
|
+
# [expression, expressions]
|
354
|
+
If:
|
355
|
+
IF Expression IfBlock END { result = IfNode.new(val[1], val[2]) }
|
356
|
+
| IF Expression THEN Expression END { result = IfNode.new(val[1], Nodes.new([val[3]])) }
|
357
|
+
| Expression IF Expression { result = IfNode.new(val[2], Nodes.new([val[0]])) }
|
358
|
+
;
|
359
|
+
|
360
|
+
Unless:
|
361
|
+
UNLESS Expression IfBlock END { result = UnlessNode.new(val[1], val[2]) }
|
362
|
+
| UNLESS Expression THEN Expression END { result = UnlessNode.new(val[1], Nodes.new([val[3]])) }
|
363
|
+
| Expression UNLESS Expression { result = UnlessNode.new(val[2], Nodes.new([val[0]])) }
|
364
|
+
;
|
365
|
+
|
366
|
+
Ternary:
|
367
|
+
Expression '?' Expression ':' Expression { result = TernaryOperatorNode.new([val[0], val[2], val[4]]) }
|
368
|
+
;
|
369
|
+
|
370
|
+
While:
|
371
|
+
WHILE Expression Block END { result = WhileNode.new(val[1], val[2]) }
|
372
|
+
;
|
373
|
+
|
374
|
+
LoopKeyword:
|
375
|
+
BREAK { result = BreakNode.new }
|
376
|
+
| CONTINUE { result = ContinueNode.new }
|
377
|
+
;
|
378
|
+
|
379
|
+
Until:
|
380
|
+
UNTIL Expression Block END { result = UntilNode.new(val[1], val[2]) }
|
381
|
+
;
|
382
|
+
|
383
|
+
For:
|
384
|
+
FOR IDENTIFIER IN Expression Block END { result = ForNode.new(val[1], val[3], val[4]) }
|
385
|
+
| FOR List IN Expression Block END { result = ForNode.new(val[1], val[3], val[4]) }
|
386
|
+
;
|
387
|
+
|
388
|
+
Try:
|
389
|
+
TRY Block END { result = TryNode.new(val[1], nil, nil) }
|
390
|
+
| TRY Block Catch END { result = TryNode.new(val[1], val[2], nil) }
|
391
|
+
| TRY Block Catch ENSURE Block END { result = TryNode.new(val[1], val[2], val[4]) }
|
392
|
+
;
|
393
|
+
|
394
|
+
Catch:
|
395
|
+
/* nothing */ { result = nil }
|
396
|
+
| CATCH Block { result = [ CatchNode.new(nil, val[1]) ] }
|
397
|
+
| CATCH Regexp Block { result = [ CatchNode.new(val[1], val[2]) ] }
|
398
|
+
| Catch CATCH Block { result = val[0] << CatchNode.new(nil, val[2]) }
|
399
|
+
| Catch CATCH Regexp Block { result = val[0] << CatchNode.new(val[2], val[3]) }
|
400
|
+
;
|
401
|
+
|
402
|
+
# [expressions]
|
403
|
+
# expressions list could contain an ElseNode, which contains expressions
|
404
|
+
# itself
|
405
|
+
Block:
|
406
|
+
NEWLINE Expressions { result = val[1] }
|
407
|
+
| NEWLINE { result = Nodes.new([]) }
|
408
|
+
;
|
409
|
+
|
410
|
+
IfBlock:
|
411
|
+
Block { result = val[0] }
|
412
|
+
| NEWLINE Expressions ElseBlock { result = val[1].concat(val[2]) }
|
413
|
+
;
|
414
|
+
|
415
|
+
ElseBlock:
|
416
|
+
ElseifBlock ELSE NEWLINE Expressions { result = [val[0], ElseNode.new(val[3])].compact }
|
417
|
+
;
|
418
|
+
|
419
|
+
ElseifBlock:
|
420
|
+
ELSEIF Expression NEWLINE Expressions { result = Nodes.new([ElseifNode.new(val[1], val[3])]) }
|
421
|
+
| ElseifBlock ELSEIF Expression NEWLINE Expressions { result = val[0] << ElseifNode.new(val[2], val[4]) }
|
422
|
+
| /* nothing */ { result = nil }
|
423
|
+
;
|
424
|
+
|
425
|
+
ClassDefinition:
|
426
|
+
CLASS IDENTIFIER Block END { result = ClassDefinitionNode.new(val[1], nil, val[2]) }
|
427
|
+
| CLASS IDENTIFIER '<' IDENTIFIER Block END { result = ClassDefinitionNode.new(val[1], val[3], val[4]) }
|
428
|
+
;
|
429
|
+
|
430
|
+
ObjectInstantiation:
|
431
|
+
NEW Call { result = ObjectInstantiationNode.new(val[1]) }
|
432
|
+
;
|
433
|
+
|
434
|
+
Super:
|
435
|
+
SUPER '(' ArgList ')' { result = SuperNode.new(val[2], true) }
|
436
|
+
| SUPER { result = SuperNode.new([], false) }
|
437
|
+
;
|
438
|
+
|
439
|
+
ExLiteral:
|
440
|
+
EX_LITERAL { result = ExLiteralNode.new(val[0])}
|
441
|
+
;
|
442
|
+
end
|
443
|
+
|
444
|
+
---- header
|
445
|
+
require File.expand_path("../lexer", __FILE__)
|
446
|
+
require File.expand_path("../nodes", __FILE__)
|
447
|
+
require File.expand_path("../ast_rewriter", __FILE__)
|
448
|
+
require File.expand_path("../errors", __FILE__)
|
449
|
+
---- inner
|
450
|
+
# This code will be put as-is in the parser class
|
451
|
+
|
452
|
+
# parses tokens or code into output nodes
|
453
|
+
def parse(object, rewrite_ast = true)
|
454
|
+
if tokens?(object)
|
455
|
+
@tokens = object
|
456
|
+
elsif code?(object)
|
457
|
+
@lexer = Riml::Lexer.new(object)
|
458
|
+
end
|
459
|
+
ast = do_parse
|
460
|
+
return ast if rewrite_ast == false
|
461
|
+
AST_Rewriter.new(ast).rewrite
|
462
|
+
end
|
463
|
+
|
464
|
+
alias do_parse_without_error_handling do_parse
|
465
|
+
def do_parse_with_error_handling
|
466
|
+
do_parse_without_error_handling
|
467
|
+
rescue Racc::ParseError => e
|
468
|
+
raise unless @lexer
|
469
|
+
raise Riml::ParseError, "line #{@lexer.lineno}: #{e.message}"
|
470
|
+
end
|
471
|
+
alias do_parse do_parse_with_error_handling
|
472
|
+
|
473
|
+
def next_token
|
474
|
+
return @tokens.shift unless @lexer
|
475
|
+
@lexer.next_token
|
476
|
+
end
|
477
|
+
|
478
|
+
private
|
479
|
+
def tokens?(object)
|
480
|
+
Array === object
|
481
|
+
end
|
482
|
+
|
483
|
+
def code?(object)
|
484
|
+
String === object
|
485
|
+
end
|
data/lib/helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path('../../config/environment', __FILE__)
|
2
|
+
require 'nodes'
|
3
|
+
require 'lexer'
|
4
|
+
require 'parser'
|
5
|
+
require 'compiler'
|
6
|
+
|
7
|
+
module Riml
|
8
|
+
# lex code into tokens
|
9
|
+
def self.lex(code)
|
10
|
+
Lexer.new(code).tokenize
|
11
|
+
end
|
12
|
+
|
13
|
+
# parse code (or tokens) into nodes
|
14
|
+
def self.parse(input, rewrite_ast = true)
|
15
|
+
unless input.is_a?(Array) || input.is_a?(String)
|
16
|
+
raise ArgumentError, "input must be tokens or code, is #{input.class}"
|
17
|
+
end
|
18
|
+
Parser.new.parse(input, rewrite_ast)
|
19
|
+
end
|
20
|
+
|
21
|
+
# compile nodes (or tokens or code) into output code
|
22
|
+
def self.compile(input)
|
23
|
+
if input.is_a?(Nodes)
|
24
|
+
nodes = input
|
25
|
+
elsif input.is_a?(String) || input.is_a?(Array)
|
26
|
+
nodes = parse(input)
|
27
|
+
else
|
28
|
+
raise ArgumentError, "input must be nodes, tokens or code, is #{input.class}"
|
29
|
+
end
|
30
|
+
Compiler.new.compile(nodes)
|
31
|
+
end
|
32
|
+
|
33
|
+
# expects `file_name` to be readable file
|
34
|
+
def self.compile_file(file_name)
|
35
|
+
input = File.read(file_name)
|
36
|
+
output = compile(input)
|
37
|
+
file_basename = File.basename(file_name)
|
38
|
+
unless File.extname(file_basename).empty?
|
39
|
+
file_basename = file_basename.split(".").tap {|parts| parts.pop}.join(".")
|
40
|
+
end
|
41
|
+
File.open("#{file_basename}.vim", 'w') do |f|
|
42
|
+
f.write output
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|