mix-language 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/mix-compile +3 -14
- data/lib/javascript/base/array.js +1 -1
- data/lib/javascript/base/env.js +2 -1
- data/lib/javascript/base/eval.js +6 -7
- data/lib/javascript/base/false.js +1 -1
- data/lib/javascript/base/function.js +1 -1
- data/lib/javascript/base/null.js +1 -1
- data/lib/javascript/base/number.js +1 -1
- data/lib/javascript/base/object.js +1 -1
- data/lib/javascript/base/string.js +1 -1
- data/lib/javascript/base/true.js +1 -1
- data/lib/javascript/dom/div.js +1 -1
- data/lib/javascript/dom/drag.js +1 -1
- data/lib/javascript/dom/element.js +1 -1
- data/lib/javascript/dom/event.js +1 -1
- data/lib/javascript/dom/mouse.js +1 -1
- data/lib/javascript/dom/table.js +1 -1
- data/lib/javascript/dom/td.js +1 -1
- data/lib/javascript/dom/text.js +1 -1
- data/lib/javascript/dom/tr.js +1 -1
- data/lib/ruby/compiler.rb +38 -501
- data/lib/ruby/mix.grammar +13 -13
- data/lib/ruby/mix.tab.rb +453 -464
- data/lib/ruby/new_tokenizer.rb +290 -0
- data/lib/ruby/parser.rb +71 -0
- data/lib/ruby/precompiler.rb +106 -0
- data/lib/ruby/tokenizer.rb +268 -0
- data/lib/ruby/translator.rb +179 -0
- metadata +7 -2
data/lib/ruby/compiler.rb
CHANGED
@@ -1,528 +1,65 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
#
|
3
|
-
# Copyright © 2011 Jesse Sielaff
|
3
|
+
# Copyright © 2011-2012 Jesse Sielaff
|
4
4
|
#
|
5
|
+
require_relative './precompiler.rb'
|
6
|
+
require_relative './tokenizer.rb'
|
5
7
|
require_relative './mix.tab.rb'
|
8
|
+
require_relative './parser.rb'
|
9
|
+
require_relative './translator.rb'
|
6
10
|
|
7
11
|
class MixCompiler
|
8
|
-
def initialize
|
9
|
-
@
|
12
|
+
def initialize
|
13
|
+
@precompiler = MixPrecompiler.new
|
14
|
+
@tokenizer = MixTokenizer.new
|
15
|
+
@parser = MixParser.new
|
16
|
+
@translator = MixTranslator.new
|
10
17
|
end
|
11
18
|
|
12
|
-
|
13
|
-
|
14
|
-
access_brackets access_colon
|
15
|
-
access_hash and app array
|
16
|
-
break call false function if
|
17
|
-
mix mixin newline not null
|
18
|
-
number object op or return
|
19
|
-
self set statement string
|
20
|
-
switch true variable while
|
21
|
-
:
|
22
|
-
.each_with_index {|t,i| NODE_TYPES[t.to_sym] = i + 1 }
|
23
|
-
|
24
|
-
OPERATORS =
|
25
|
-
{
|
26
|
-
'+' => :plus, '-' => :minus,
|
27
|
-
'*' => :star, '/' => :slash, '%' => :percent,
|
28
|
-
'>' => :gt, '>>' => :gtgt, '>=' => :gteq,
|
29
|
-
'<' => :lt, '<<' => :ltlt, '<=' => :lteq,
|
30
|
-
'==' => :eq, '!=' => :neq
|
31
|
-
}
|
32
|
-
|
33
|
-
def append_statement (outermost_statement, final_statement)
|
34
|
-
current = outermost_statement
|
35
|
-
|
36
|
-
current = current[:values][1] while current[:values][1]
|
37
|
-
current[:values][1] = final_statement
|
38
|
-
|
39
|
-
outermost_statement
|
40
|
-
end
|
41
|
-
|
42
|
-
def build_script
|
43
|
-
script = File.open(@primary_filename) {|f| "#{f.read}\n" }
|
44
|
-
files = {'mix' => [], 'js' => %w[base/env.js base/eval.js base/object.js base/array.js base/false.js base/function.js base/null.js base/number.js base/string.js base/true.js]}
|
45
|
-
|
46
|
-
@unordered_mix_filenames = [@primary_filename]
|
47
|
-
|
48
|
-
scan_includes(script, files)
|
49
|
-
files['mix'].push [@primary_filename, script]
|
50
|
-
|
51
|
-
@js_filenames = files['js']
|
52
|
-
@filenames = files['mix'].map {|name,*| name }
|
53
|
-
@script = files['mix'].map {|*,script| script }.join("\034")
|
19
|
+
def basename (filename)
|
20
|
+
filename.match(/(.*?)(\.mix$|$)/)[1]
|
54
21
|
end
|
55
22
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
js_file_string.gsub!("#{t}_TYPE","#{i}")
|
61
|
-
end
|
62
|
-
|
63
|
-
js_file_string.gsub!(/\s*\/\*.*?\*\/\s*/m,"\n").gsub!(/\s*\n\s*/,?\n).gsub!(/\s*([{;:,=])\s*/,'\1').gsub!("\n}",'}')
|
23
|
+
def combine_strings (js_string, ast_string, symbol_string)
|
24
|
+
js_string
|
25
|
+
.sub(%%'...Replace with AST nodes...'%, ast_string)
|
26
|
+
.sub(%%'...Replace with symbol table...'%, symbol_string)
|
64
27
|
end
|
65
28
|
|
66
|
-
def compile
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
symbol_string =
|
71
|
-
|
72
|
-
|
73
|
-
File.read(File.expand_path('../../javascript/' + filename, __FILE__))
|
74
|
-
end.join ?\n
|
75
|
-
|
76
|
-
precompile(js_file_string)
|
77
|
-
|
78
|
-
<<-JAVASCRIPT
|
79
|
-
mix_result_should_be_undefined = function ()
|
80
|
-
{
|
81
|
-
|
82
|
-
var HTML_TYPES = {};
|
83
|
-
var SYMBOLS = [#{symbol_string.force_encoding('US-ASCII')}];
|
84
|
-
#{js_file_string}
|
85
|
-
|
86
|
-
window.onload = function ()
|
87
|
-
{
|
88
|
-
startup();
|
89
|
-
evaluate(#{node_string});
|
90
|
-
}
|
91
|
-
|
92
|
-
}();
|
93
|
-
JAVASCRIPT
|
29
|
+
def compile (filename)
|
30
|
+
mix_files, js_string = precompile_js(filename)
|
31
|
+
mix_tokens = tokenize_mix_files(mix_files)
|
32
|
+
mix_node = parse_token_stream(mix_tokens)
|
33
|
+
ast_string, symbol_string = translate_to_js(mix_node)
|
34
|
+
js_output_string = combine_strings(js_string, ast_string, symbol_string)
|
35
|
+
write_js_file(filename, js_output_string)
|
94
36
|
|
95
37
|
rescue SyntaxError => e
|
96
|
-
"window.onload = function () { if (console && console.log) console.log(\"SyntaxError: #{e.message}\"); };"
|
97
|
-
end
|
98
|
-
|
99
|
-
def getch
|
100
|
-
@script[@pointer += 1]
|
101
|
-
end
|
102
|
-
|
103
|
-
def js (node)
|
104
|
-
return "0" unless node
|
105
|
-
|
106
|
-
t = node[:type]
|
107
|
-
a, b, c = node[:values]
|
108
|
-
args = [NODE_TYPES[t]]
|
109
|
-
|
110
|
-
case (t = node[:type])
|
111
|
-
when :access_brackets, :and, :or, :set, :statement, :while
|
112
|
-
args << js(a) << js(b)
|
113
|
-
|
114
|
-
when :access_colon, :access_hash, :mix
|
115
|
-
args << js(a) << @symbols[b.to_sym]
|
116
|
-
|
117
|
-
when :app, :false, :null, :self, :true
|
118
|
-
nil
|
119
|
-
|
120
|
-
when :array
|
121
|
-
items = a.map {|x| js(x) }.join ?,
|
122
|
-
args << "[#{items}]"
|
123
|
-
|
124
|
-
when :break, :not, :return
|
125
|
-
args << js(a)
|
126
|
-
|
127
|
-
when :call
|
128
|
-
function = js(a)
|
129
|
-
arguments = b.map {|x| js(x) }.join ?,
|
130
|
-
|
131
|
-
args << function << "[#{arguments}]"
|
132
|
-
|
133
|
-
when :function
|
134
|
-
parameters = a[0].map {|x| @symbols[x.to_sym] }.join ?,
|
135
|
-
variables = a[1].map {|x| @symbols[x.to_sym] }.join ?,
|
136
|
-
body = js(b)
|
137
|
-
|
138
|
-
args << "[[#{parameters}],[#{variables}]]" << body
|
139
|
-
|
140
|
-
when :if
|
141
|
-
args << js(a) << js(b) << js(c)
|
142
|
-
|
143
|
-
when :mixin
|
144
|
-
name = @symbols[a.to_sym]
|
145
|
-
init_statement = js(b[0])
|
146
|
-
definitions = b[1].map {|s| js(s) }.join ?,
|
147
|
-
|
148
|
-
args << name << init_statement << "[#{definitions}]"
|
149
|
-
|
150
|
-
when :newline
|
151
|
-
file, line = @symbols[a[0].to_sym], a[1]
|
152
|
-
statement = js(b)
|
153
|
-
|
154
|
-
args << file << line << statement
|
155
|
-
|
156
|
-
when :number
|
157
|
-
args << a
|
158
|
-
|
159
|
-
when :object
|
160
|
-
entries = a.map {|kv| "[#{@symbols[kv[0].to_sym]},#{js(kv[1])}]" }.join ?,
|
161
|
-
mixins = b.map {|x| @symbols[x.to_sym] }.join ?,
|
162
|
-
|
163
|
-
args << "[#{entries}]" << "[#{mixins}]"
|
164
|
-
|
165
|
-
when :op
|
166
|
-
args << @symbols[OPERATORS[a]] << js(b) << js(c)
|
167
|
-
|
168
|
-
when :string, :variable
|
169
|
-
args << @symbols[a.to_sym]
|
170
|
-
|
171
|
-
when :switch
|
172
|
-
condition = js(a)
|
173
|
-
cases = b.map {|x| "[#{js(x[0])},#{js(x[1])}]" }.join ?,
|
174
|
-
else_case = js(c)
|
175
|
-
|
176
|
-
args << condition << cases << else_case
|
177
|
-
|
178
|
-
else
|
179
|
-
raise "BUG: node type :#{t} not implemented in MixCompiler#js"
|
180
|
-
end
|
181
|
-
|
182
|
-
return "[#{args.join ?,}]"
|
183
|
-
end
|
184
|
-
|
185
|
-
def newline (statement_node)
|
186
|
-
statement_node[:values][0] = node(:newline, @location, statement_node[:values][0])
|
187
|
-
statement_node
|
38
|
+
write_js_file("window.onload = function () { if (console && console.log) console.log(\"SyntaxError: #{e.message}\"); };")
|
188
39
|
end
|
189
40
|
|
190
|
-
def
|
191
|
-
@
|
41
|
+
def parse_token_stream (mix_tokens)
|
42
|
+
@parser.parse(mix_tokens)
|
192
43
|
end
|
193
44
|
|
194
|
-
def
|
195
|
-
|
45
|
+
def precompile_js (filename)
|
46
|
+
mix_filename = basename(filename) + '.mix'
|
47
|
+
@precompiler.precompile(mix_filename)
|
196
48
|
end
|
197
49
|
|
198
|
-
def
|
199
|
-
|
200
|
-
|
201
|
-
else
|
202
|
-
value, file, line = 'EOF', @primary_filename, @line
|
50
|
+
def tokenize_mix_files (mix_files)
|
51
|
+
mix_files.each_with_object([]) do |(filename, script), tokens|
|
52
|
+
@tokenizer.tokenize(filename, script, tokens)
|
203
53
|
end
|
204
|
-
|
205
|
-
raise SyntaxError, "Unexpected token #{token_to_str(token)} (#{value}): #{file}:#{line}".gsub(?",'\"')
|
206
|
-
end
|
207
|
-
|
208
|
-
def parameter (name)
|
209
|
-
@variables[:parameters] << name
|
210
|
-
@variables[:local] << name
|
211
|
-
end
|
212
|
-
|
213
|
-
def parse
|
214
|
-
tokenize
|
215
|
-
symbol_index = -1
|
216
|
-
@symbols = Hash.new {|h,k| h[k] = (symbol_index += 1) }
|
217
|
-
@variables = { parameters: [], local: [], embedded: [], prev: nil }
|
218
|
-
|
219
|
-
return do_parse
|
220
|
-
end
|
221
|
-
|
222
|
-
def pop_variables
|
223
|
-
vars = [@variables[:parameters], @variables[:embedded]]
|
224
|
-
@variables = @variables[:prev]
|
225
|
-
|
226
|
-
return vars
|
227
|
-
end
|
228
|
-
|
229
|
-
def push_variables
|
230
|
-
embedded = @variables[:local] + @variables[:embedded]
|
231
|
-
@variables = { parameters: [], local: [], embedded: embedded, prev: @variables }
|
232
54
|
end
|
233
55
|
|
234
|
-
def
|
235
|
-
|
236
|
-
@variables[:local] << name
|
237
|
-
end
|
238
|
-
|
239
|
-
node :variable, name
|
240
|
-
end
|
241
|
-
|
242
|
-
def scan_includes (script, files)
|
243
|
-
require 'strscan'
|
244
|
-
|
245
|
-
ss = StringScanner.new(script)
|
246
|
-
js_filenames = []
|
247
|
-
|
248
|
-
while ss.scan(/~~\s+(.*\.(js|mix))\s*\n/)
|
249
|
-
name = ss[1]
|
250
|
-
type = ss[2]
|
251
|
-
|
252
|
-
if type == 'mix'
|
253
|
-
unless @unordered_mix_filenames.include?(name)
|
254
|
-
script = File.open(name) {|f| "#{f.read}\n" }
|
255
|
-
@unordered_mix_filenames << name
|
256
|
-
scan_includes(script, files)
|
257
|
-
files['mix'].push [name,script]
|
258
|
-
end
|
259
|
-
else
|
260
|
-
js_filenames << name
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
files['js'] |= js_filenames
|
265
|
-
end
|
266
|
-
|
267
|
-
def token (token, value = token)
|
268
|
-
@tokens << [token, [value, [@filename, @line]]]
|
269
|
-
end
|
270
|
-
|
271
|
-
def tokenize
|
272
|
-
@filename = @filenames[file_index = 0]
|
273
|
-
@line = 1
|
274
|
-
@pointer = -1
|
275
|
-
@indent_stack = [0]
|
276
|
-
@state = :newline
|
277
|
-
@tokens = []
|
278
|
-
|
279
|
-
empty_lines = 0
|
280
|
-
|
281
|
-
while c = getch
|
282
|
-
case c
|
283
|
-
when ?\034
|
284
|
-
@filename = @filenames[file_index += 1]
|
285
|
-
@line = 1
|
286
|
-
|
287
|
-
when ?~
|
288
|
-
if getch == ?~
|
289
|
-
:skip until getch =~ /\n/
|
290
|
-
unscan
|
291
|
-
next
|
292
|
-
end
|
293
|
-
|
294
|
-
unscan
|
295
|
-
:skip while getch =~ /\s/
|
296
|
-
unscan
|
297
|
-
|
298
|
-
when ' ', ?\t
|
299
|
-
@state = :space if @state == :reference
|
300
|
-
|
301
|
-
when ?\n
|
302
|
-
if @state == :newline
|
303
|
-
empty_lines += 1
|
304
|
-
next
|
305
|
-
end
|
306
|
-
|
307
|
-
current_indent = 0
|
308
|
-
previous_indent = @indent_stack.last
|
309
|
-
|
310
|
-
while (c = getch) == ' '
|
311
|
-
current_indent += 1
|
312
|
-
end
|
313
|
-
|
314
|
-
unscan
|
315
|
-
|
316
|
-
if c == ?\n
|
317
|
-
empty_lines += 1
|
318
|
-
next
|
319
|
-
end
|
320
|
-
|
321
|
-
@state = :newline
|
322
|
-
token :NEWLINE
|
323
|
-
|
324
|
-
@line += (empty_lines + 1)
|
325
|
-
empty_lines = 0
|
326
|
-
|
327
|
-
if current_indent > previous_indent
|
328
|
-
@indent_stack << current_indent
|
329
|
-
token :INDENT
|
330
|
-
elsif current_indent < previous_indent
|
331
|
-
unless @indent_stack.include?(current_indent)
|
332
|
-
raise(SyntaxError, "Indent error: #{@filename}:#{@line}")
|
333
|
-
end
|
334
|
-
|
335
|
-
until @indent_stack.last == current_indent
|
336
|
-
@indent_stack.pop
|
337
|
-
token :OUTDENT
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
when ?!, ?=
|
342
|
-
@state = :begin
|
343
|
-
|
344
|
-
if getch == ?=
|
345
|
-
token c + '='
|
346
|
-
else
|
347
|
-
unscan
|
348
|
-
token c
|
349
|
-
end
|
350
|
-
|
351
|
-
when ?+, ?*, ?/, ?%
|
352
|
-
@state = :begin
|
353
|
-
|
354
|
-
if getch == ?=
|
355
|
-
token '·=', c
|
356
|
-
else
|
357
|
-
unscan
|
358
|
-
token c
|
359
|
-
end
|
360
|
-
|
361
|
-
when ?-
|
362
|
-
if getch == ?=
|
363
|
-
token '·=', c
|
364
|
-
elsif c =~ /[0-9]/
|
365
|
-
token '-1'
|
366
|
-
unscan
|
367
|
-
else
|
368
|
-
unscan
|
369
|
-
|
370
|
-
if @state == :begin || @state == :newline
|
371
|
-
token '-·'
|
372
|
-
else
|
373
|
-
token '-'
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
@state = :begin
|
378
|
-
|
379
|
-
when ??, ?., ?;, ?,, ?(, ?{
|
380
|
-
@state = :begin
|
381
|
-
token c
|
382
|
-
|
383
|
-
when ?'
|
384
|
-
@state = :reference
|
385
|
-
|
386
|
-
s = ""
|
387
|
-
|
388
|
-
until (c = getch) == ?'
|
389
|
-
s << c
|
390
|
-
end
|
391
|
-
|
392
|
-
token '\''
|
393
|
-
token :STRING, s
|
394
|
-
token '\''
|
395
|
-
|
396
|
-
when ?>, ?<
|
397
|
-
@state = :begin
|
398
|
-
|
399
|
-
if getch == c
|
400
|
-
if getch == ?=
|
401
|
-
token '·=', c * 2
|
402
|
-
else
|
403
|
-
unscan
|
404
|
-
token c * 2
|
405
|
-
end
|
406
|
-
else
|
407
|
-
unscan
|
408
|
-
|
409
|
-
if getch == ?=
|
410
|
-
token c + '='
|
411
|
-
else
|
412
|
-
unscan
|
413
|
-
token c
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
when ?&, ?|
|
418
|
-
@state = :begin
|
419
|
-
|
420
|
-
if getch == c
|
421
|
-
if getch == ?=
|
422
|
-
token c + c + '='
|
423
|
-
else
|
424
|
-
unscan
|
425
|
-
token c + c
|
426
|
-
end
|
427
|
-
else
|
428
|
-
unscan
|
429
|
-
token c
|
430
|
-
end
|
431
|
-
|
432
|
-
when /[0-9]/
|
433
|
-
@state = :reference
|
434
|
-
value = c
|
435
|
-
|
436
|
-
while (c = getch) =~ /[0-9]/
|
437
|
-
value << c
|
438
|
-
end
|
439
|
-
|
440
|
-
unscan
|
441
|
-
|
442
|
-
token :NUMBER, value.to_i
|
443
|
-
|
444
|
-
when ?], ?}, ?)
|
445
|
-
@state = :reference
|
446
|
-
token c
|
447
|
-
|
448
|
-
when ?:, ?[, ?#
|
449
|
-
if @state == :reference
|
450
|
-
token '·' + c
|
451
|
-
else
|
452
|
-
token c
|
453
|
-
end
|
454
|
-
|
455
|
-
@state = :begin
|
456
|
-
|
457
|
-
when /[A-Z]/
|
458
|
-
@state = :begin
|
459
|
-
value = c
|
460
|
-
|
461
|
-
while (c = getch) =~ /[_a-zA-Z0-9]/
|
462
|
-
value << c
|
463
|
-
end
|
464
|
-
|
465
|
-
unscan
|
466
|
-
|
467
|
-
token :MIXIN, value.to_sym
|
468
|
-
|
469
|
-
when /[_a-z]/
|
470
|
-
@state = :reference
|
471
|
-
value = c
|
472
|
-
|
473
|
-
while (c = getch) =~ /[_a-zA-Z0-9]/
|
474
|
-
value << c
|
475
|
-
end
|
476
|
-
|
477
|
-
if c == ?:
|
478
|
-
if getch =~ /[a-z]/
|
479
|
-
unscan
|
480
|
-
else
|
481
|
-
@state = :begin
|
482
|
-
token :KEY, value.to_sym
|
483
|
-
unscan
|
484
|
-
next
|
485
|
-
end
|
486
|
-
|
487
|
-
unscan
|
488
|
-
elsif c == ?? || c == ?!
|
489
|
-
value << c
|
490
|
-
else
|
491
|
-
unscan
|
492
|
-
end
|
493
|
-
|
494
|
-
if %w:
|
495
|
-
app break case
|
496
|
-
elsif else false if
|
497
|
-
null return self
|
498
|
-
switch true unless
|
499
|
-
until while
|
500
|
-
:
|
501
|
-
.include?(value)
|
502
|
-
token value.upcase.to_sym
|
503
|
-
else
|
504
|
-
token :IDENTIFIER, value.to_sym
|
505
|
-
end
|
506
|
-
|
507
|
-
case c = getch
|
508
|
-
when ?:, ?#
|
509
|
-
token '·' + c
|
510
|
-
when ?[
|
511
|
-
token '·['
|
512
|
-
@state = :begin
|
513
|
-
else
|
514
|
-
unscan
|
515
|
-
end
|
516
|
-
|
517
|
-
else
|
518
|
-
raise SyntaxError, "Invalid token `#{c}': #{@filename}:#{@line}"
|
519
|
-
end
|
520
|
-
end
|
521
|
-
|
522
|
-
@tokens << [false, false]
|
56
|
+
def translate_to_js (node)
|
57
|
+
@translator.translate(node)
|
523
58
|
end
|
524
59
|
|
525
|
-
def
|
526
|
-
|
60
|
+
def write_js_file (filename, js_output_string)
|
61
|
+
js_filename = basename(filename) + '.js'
|
62
|
+
File.open(js_filename,'w') {|f| f.write(js_output_string) }
|
63
|
+
puts "Writing to #{js_filename}"
|
527
64
|
end
|
528
65
|
end
|
data/lib/ruby/mix.grammar
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
#
|
3
|
-
# Copyright © 2011 Jesse Sielaff
|
3
|
+
# Copyright © 2011-2012 Jesse Sielaff
|
4
4
|
#
|
5
5
|
|
6
|
-
class
|
6
|
+
class MixParser
|
7
7
|
options no_result_var
|
8
8
|
|
9
9
|
prechigh
|
10
10
|
right '!'
|
11
|
-
right '-·'
|
11
|
+
right '-·' NEGATIVE
|
12
12
|
left '*' '/' '%'
|
13
13
|
left '+' '-'
|
14
14
|
left '<<' '>>'
|
@@ -43,7 +43,7 @@ class MixCompiler
|
|
43
43
|
| function_statement
|
44
44
|
|
45
45
|
mixin_statement
|
46
|
-
: MIXIN ':' newline INDENT mixin_body OUTDENT { node :mixin, val[0][0], val[4] }
|
46
|
+
: MIXIN ':' newline INDENT mixin_body OUTDENT { node :mixin, val[0][0], val[4][0], val[4][1] }
|
47
47
|
|
48
48
|
mixin_body
|
49
49
|
: statements { [val[0], []] }
|
@@ -56,10 +56,10 @@ class MixCompiler
|
|
56
56
|
|
57
57
|
definition
|
58
58
|
: IDENTIFIER function_block { node :set, node(:access_hash, node(:self), val[0][0]), val[1] }
|
59
|
-
| IDENTIFIER inline_function newline { node :newline,
|
59
|
+
| IDENTIFIER inline_function newline { node :newline, *@location, node(:set, node(:access_hash, node(:self), val[0][0]), val[1]) }
|
60
60
|
|
61
61
|
function_block
|
62
|
-
: parameter_list indent_block { node :function, pop_variables, val[1] }
|
62
|
+
: parameter_list indent_block { node :function, *pop_variables, val[1] }
|
63
63
|
|
64
64
|
parameter_list
|
65
65
|
: '#' { push_variables; nil }
|
@@ -92,8 +92,8 @@ class MixCompiler
|
|
92
92
|
| cases case { val[0] << val[1] }
|
93
93
|
|
94
94
|
case
|
95
|
-
: CASE exp indent_block { [node(:newline,
|
96
|
-
| CASE exp ':' inline_statements newline { [node(:newline,
|
95
|
+
: CASE exp indent_block { [node(:newline, *@location, val[1]), val[2]] }
|
96
|
+
| CASE exp ':' inline_statements newline { [node(:newline, *@location, val[1]), val[3]] }
|
97
97
|
|
98
98
|
inline_statements
|
99
99
|
: inline_statement { node :statement, val[0], nil }
|
@@ -112,8 +112,8 @@ class MixCompiler
|
|
112
112
|
| inline_statement UNTIL exp { node :while, node(:not, val[2]), val[0] }
|
113
113
|
|
114
114
|
mix_statement
|
115
|
-
: '+' MIXIN object { node :mix, val[
|
116
|
-
| '+' MIXIN { node :mix,
|
115
|
+
: '+' MIXIN object { node :mix, val[1][0], val[2] }
|
116
|
+
| '+' MIXIN { node :mix, val[1][0], node(:self) }
|
117
117
|
|
118
118
|
keyword_statement
|
119
119
|
: BREAK exp { node :break, val[1] }
|
@@ -184,10 +184,10 @@ class MixCompiler
|
|
184
184
|
|
185
185
|
literal_number
|
186
186
|
: NUMBER { node :number, val[0][0] }
|
187
|
-
|
|
187
|
+
| NEGATIVE NUMBER { node :number, -val[1][0] }
|
188
188
|
|
189
189
|
literal_string
|
190
|
-
:
|
190
|
+
: STRING { node :string, val[0][0] }
|
191
191
|
|
192
192
|
literal_constant
|
193
193
|
: APP { node :app }
|
@@ -223,7 +223,7 @@ class MixCompiler
|
|
223
223
|
: '(' inline_statements ')' { val[1] }
|
224
224
|
|
225
225
|
inline_function
|
226
|
-
: parameter_list curly_brace_block { node :function, pop_variables, val[1] }
|
226
|
+
: parameter_list curly_brace_block { node :function, *pop_variables, val[1] }
|
227
227
|
|
228
228
|
curly_brace_block
|
229
229
|
: '{' inline_statements '}' { val[1] }
|