mix-language 1.0.0 → 1.0.1
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/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] }
|