riml 0.1.3

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