rlang 0.4.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -3
- data/Gemfile.lock +4 -6
- data/README +11 -0
- data/README.md +18 -10
- data/bin/rlang +17 -5
- data/docs/RlangCompiler.md +5 -1
- data/docs/RlangManual.md +98 -20
- data/examples/fib/fib.rb +5 -1
- data/lib/builder/rlang/compiler.rb +2 -21
- data/lib/rlang/lib/array/array32.rb +59 -0
- data/lib/rlang/lib/array/array64.rb +56 -0
- data/lib/rlang/lib/array.rb +6 -0
- data/lib/rlang/lib/base64.rb +223 -0
- data/lib/rlang/lib/io.rb +75 -0
- data/lib/rlang/lib/kernel.rb +23 -0
- data/lib/rlang/lib/malloc.rb +12 -8
- data/lib/rlang/lib/memory.rb +102 -2
- data/lib/rlang/lib/object.rb +40 -4
- data/lib/rlang/lib/rlang.rb +29 -0
- data/lib/rlang/lib/rlang_core.rb +15 -0
- data/lib/rlang/lib/string.rb +106 -8
- data/lib/rlang/lib/type/i32.rb +43 -0
- data/lib/rlang/lib/type/i64.rb +2 -0
- data/lib/rlang/lib/unistd.rb +1 -2
- data/lib/rlang/lib/wasi.rb +184 -0
- data/lib/rlang/parser/attr.rb +9 -13
- data/lib/rlang/parser/const.rb +105 -1
- data/lib/rlang/parser/cvar.rb +11 -7
- data/lib/rlang/parser/data.rb +17 -6
- data/lib/rlang/parser/export.rb +4 -3
- data/lib/rlang/parser/ext/integer.rb +3 -1
- data/lib/rlang/parser/ext/type.rb +30 -1
- data/lib/rlang/parser/global.rb +10 -2
- data/lib/rlang/parser/ivar.rb +3 -7
- data/lib/rlang/parser/klass.rb +8 -35
- data/lib/rlang/parser/method.rb +36 -12
- data/lib/rlang/parser/module.rb +143 -0
- data/lib/rlang/parser/wgenerator.rb +462 -168
- data/lib/rlang/parser/wnode.rb +387 -142
- data/lib/rlang/parser/wtype.rb +30 -7
- data/lib/rlang/parser.rb +506 -231
- data/lib/rlang/version.rb +1 -1
- data/lib/rlang.rb +3 -0
- data/lib/ruby/mirror/rstring.rb +16 -0
- data/lib/utils/exceptions.rb +12 -0
- data/rlang.gemspec +4 -4
- metadata +25 -13
- data/lib/rlang/lib.rb +0 -11
data/lib/rlang/parser.rb
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
require 'parser/current'
|
14
14
|
require 'pathname'
|
15
15
|
require_relative '../utils/log'
|
16
|
+
require_relative '../utils/exceptions'
|
16
17
|
require_relative './parser/wtype'
|
17
18
|
require_relative './parser/wtree'
|
18
19
|
require_relative './parser/wnode'
|
@@ -29,23 +30,19 @@ module Rlang::Parser
|
|
29
30
|
|
30
31
|
include Log
|
31
32
|
|
32
|
-
ARITHMETIC_OPS = [:+, :-, :*, :/, :%, :&, :|, :^, :>>, :<<]
|
33
|
-
RELATIONAL_OPS = [:==, :!=, :>, :<, :>=, :<=, :'>s', :'<s', :'>=s', :'>=s']
|
34
|
-
UNARY_OPS = [:'!']
|
35
|
-
|
36
|
-
# Type cast order in decreading order of precedence
|
37
|
-
TYPE_CAST_PRECEDENCE = [Type::F64, Type::F32, Type::I64, Type::I32]
|
38
|
-
|
39
33
|
# WARNING!! THIS IS A **VERY** NASTY HACK PRETENDING
|
40
34
|
# THAT THIS int VALUE means NIL. It's totally unsafe
|
41
35
|
# of course as an expression could end up evaluating
|
42
36
|
# to this value and not be nil at all. But I'm using
|
43
37
|
# it for now in the xxxx_with_result_type variants of
|
44
38
|
# some parsing methods (if, while,...)
|
39
|
+
# NOTE: those variants with result type are **NOT** the
|
40
|
+
# ones used by Rlang right now
|
45
41
|
NIL = 999999999
|
46
42
|
|
47
|
-
# export toggle for method declaration
|
48
|
-
@@export = false
|
43
|
+
# export and import toggle for method declaration
|
44
|
+
@@export, @@export_name = false, nil
|
45
|
+
@@import, @@import_module_name, @@import_function_name = false, nil, nil
|
49
46
|
|
50
47
|
|
51
48
|
attr_accessor :wgenerator, :source, :config
|
@@ -81,7 +78,7 @@ module Rlang::Parser
|
|
81
78
|
# Note : this method can be called recursively
|
82
79
|
# through require statements
|
83
80
|
def parse_file(file)
|
84
|
-
|
81
|
+
rlse node, "parse_file only acccepts absolute path (got #{file})" \
|
85
82
|
unless Pathname.new(file).absolute? || file.nil?
|
86
83
|
# Already parsed. Ignore.
|
87
84
|
if self.config[:LOADED_FEATURES].include? file
|
@@ -107,7 +104,14 @@ module Rlang::Parser
|
|
107
104
|
end
|
108
105
|
|
109
106
|
def parse(source, wnode=nil)
|
110
|
-
|
107
|
+
if config[:comments]
|
108
|
+
ast, comments = ::Parser::CurrentRuby.parse_with_comments(source)
|
109
|
+
@associated_comments = ::Parser::Source::Comment.associate(ast, comments)
|
110
|
+
else
|
111
|
+
ast = ::Parser::CurrentRuby.parse(source)
|
112
|
+
@associated_comments = {}
|
113
|
+
end
|
114
|
+
|
111
115
|
parse_node(ast, wnode || @wgenerator.root) if ast
|
112
116
|
end
|
113
117
|
|
@@ -118,8 +122,16 @@ module Rlang::Parser
|
|
118
122
|
# - keep_eval: whether to keep the value of the evaluated
|
119
123
|
# WAT expression on stock or not
|
120
124
|
def parse_node(node, wnode, keep_eval=true)
|
125
|
+
rlse node, "wnode type is incorrect (got #{wnode})" unless wnode.is_a?(WNode) || wnode.nil?
|
121
126
|
logger.debug "\n---------------------->>\n" +
|
122
|
-
"Parsing node: #{node}, wnode: #{wnode}, keep_eval: #{keep_eval}"
|
127
|
+
"Parsing node: #{node}, wnode: #{wnode.head}, keep_eval: #{keep_eval}"
|
128
|
+
# Nothing to parse
|
129
|
+
return if node.nil?
|
130
|
+
|
131
|
+
# check if there is a comment
|
132
|
+
if config[:comments] && (comments = @associated_comments[node])
|
133
|
+
@wgenerator.comments(wnode, comments)
|
134
|
+
end
|
123
135
|
|
124
136
|
case node.type
|
125
137
|
when :self
|
@@ -128,6 +140,9 @@ module Rlang::Parser
|
|
128
140
|
when :class
|
129
141
|
wn = parse_class(node, wnode)
|
130
142
|
|
143
|
+
when :module
|
144
|
+
wn = parse_module(node, wnode)
|
145
|
+
|
131
146
|
when :defs
|
132
147
|
wn = parse_defs(node, wnode, keep_eval)
|
133
148
|
|
@@ -171,11 +186,11 @@ module Rlang::Parser
|
|
171
186
|
wn = parse_int(node, wnode, keep_eval)
|
172
187
|
|
173
188
|
when :float
|
174
|
-
|
189
|
+
rlse node, "float instructions not supported"
|
175
190
|
#parse_float(node, wnode, keep_eval)
|
176
191
|
|
177
192
|
when :nil
|
178
|
-
|
193
|
+
rlse node, "nil not supported"
|
179
194
|
|
180
195
|
when :const
|
181
196
|
wn = parse_const(node, wnode, keep_eval)
|
@@ -216,11 +231,15 @@ module Rlang::Parser
|
|
216
231
|
when :str
|
217
232
|
wn = parse_string(node, wnode, keep_eval)
|
218
233
|
|
234
|
+
when :array
|
235
|
+
wn = parse_array(node, wnode, keep_eval)
|
236
|
+
|
219
237
|
else
|
220
|
-
|
238
|
+
rlse node, "Unknown node type: #{node.type} => #{node}"
|
221
239
|
end
|
240
|
+
rlse node, "wnode type is incorrect (got #{wn}) at node #{node}" unless wn.is_a?(WNode) || wn.nil?
|
222
241
|
logger.debug "\n----------------------<<\n" +
|
223
|
-
"End parsing node: #{node}, parent wnode: #{wnode}, keep_eval: #{keep_eval}\n generated wnode #{wn}" +
|
242
|
+
"End parsing node: #{node}, parent wnode: #{wnode&.head}, keep_eval: #{keep_eval}\n generated wnode #{wn&.head}" +
|
224
243
|
"\n----------------------<<\n"
|
225
244
|
wn
|
226
245
|
end
|
@@ -240,7 +259,7 @@ module Rlang::Parser
|
|
240
259
|
end
|
241
260
|
logger.debug "node idx: #{idx}/#{child_count-1}, wnode type: #{wnode.type}, keep_eval: #{keep_eval}, local_keep_eval: #{local_keep_eval}"
|
242
261
|
wn = parse_node(n, wnode, local_keep_eval)
|
243
|
-
logger.debug "in begin: parsing node #{n} gives wnode #{wn}"
|
262
|
+
logger.debug "in begin: parsing node #{n} gives wnode #{wn&.head}"
|
244
263
|
end
|
245
264
|
return wn # return last wnode
|
246
265
|
end
|
@@ -250,19 +269,31 @@ module Rlang::Parser
|
|
250
269
|
# ... body ...
|
251
270
|
# end
|
252
271
|
# -----
|
253
|
-
#
|
272
|
+
# (class
|
273
|
+
# (const nil :Stack) nil (begin ....)))
|
254
274
|
#
|
275
|
+
# class Stack < Array
|
276
|
+
# ... body ...
|
277
|
+
# end
|
278
|
+
# -----
|
279
|
+
# (class
|
280
|
+
# (const nil :Stack) (const nil :Array) (begin ....)))
|
255
281
|
def parse_class(node, wnode)
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
unless const_node.type == :const
|
282
|
+
class_const_node, super_class_const_node, body_node = *node.children
|
283
|
+
rlse node, "expecting a constant for class name (got #{const_node})" \
|
284
|
+
unless class_const_node.type == :const
|
260
285
|
|
261
286
|
# create the class wnode
|
262
|
-
|
287
|
+
class_path = _build_const_path(class_const_node)
|
288
|
+
super_class_path = _build_const_path(super_class_const_node)
|
289
|
+
wn_class = @wgenerator.klass(wnode, class_path, super_class_path)
|
290
|
+
|
291
|
+
# If body node is nil then this must be interpreted as
|
292
|
+
# a class declaration (no implementation yet)
|
293
|
+
return wn_class unless body_node
|
263
294
|
|
264
295
|
# Parse the body of the class
|
265
|
-
parse_node(body_node, wn_class)
|
296
|
+
parse_node(body_node, wn_class)
|
266
297
|
|
267
298
|
# We finished parsing the class body so
|
268
299
|
# 1) postprocess instance variables
|
@@ -275,6 +306,29 @@ module Rlang::Parser
|
|
275
306
|
wn_class
|
276
307
|
end
|
277
308
|
|
309
|
+
# Example:
|
310
|
+
# module Kernel
|
311
|
+
# ... body ...
|
312
|
+
# end
|
313
|
+
# -----
|
314
|
+
# (module
|
315
|
+
# (const nil :Kernel) nil (begin ....)))
|
316
|
+
#
|
317
|
+
def parse_module(node, wnode)
|
318
|
+
const_node = node.children.first
|
319
|
+
body_node = node.children.last
|
320
|
+
rlse node, "expecting a constant for module name (got #{const_node})" \
|
321
|
+
unless const_node.type == :const
|
322
|
+
|
323
|
+
module_path = _build_const_path(const_node)
|
324
|
+
|
325
|
+
# create the module wnode
|
326
|
+
wn_module = @wgenerator.module(wnode, module_path)
|
327
|
+
# Parse the body of the module
|
328
|
+
parse_node(body_node, wn_module) if body_node
|
329
|
+
wn_module
|
330
|
+
end
|
331
|
+
|
278
332
|
# TODO: the code for op_asgn is quite murky but I thought
|
279
333
|
# we would use quite often so I implemented it. We could do
|
280
334
|
# without it though..
|
@@ -325,7 +379,7 @@ module Rlang::Parser
|
|
325
379
|
#
|
326
380
|
def parse_op_asgn(node, wnode, keep_eval)
|
327
381
|
op_asgn_type = node.children.first.type
|
328
|
-
logger.debug "op_asgn on #{op_asgn_type} / wnode: #{wnode}, keep_eval: #{keep_eval}"
|
382
|
+
logger.debug "op_asgn on #{op_asgn_type} / wnode: #{wnode.head}, keep_eval: #{keep_eval}"
|
329
383
|
|
330
384
|
case op_asgn_type
|
331
385
|
# Global variable case
|
@@ -338,10 +392,11 @@ module Rlang::Parser
|
|
338
392
|
# wnode as a child of wnode
|
339
393
|
wn_var_set = parse_node(var_asgn_node, wnode, keep_eval)
|
340
394
|
gvar = Global.find(var_name)
|
341
|
-
|
395
|
+
# \nline #{node.location.line}: #{node.location.expression.range.source}
|
396
|
+
rlse node, "Unknown global variable #{var_name}" unless gvar
|
342
397
|
|
343
398
|
# Create the operator node (infer operator type from variable)
|
344
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
399
|
+
wn_op = @wgenerator.send_method(wn_var_set, gvar.wtype.class_path, op, :instance)
|
345
400
|
# Create the var getter node as a child of operator node
|
346
401
|
wn_var_get = @wgenerator.gvar(wn_op, gvar)
|
347
402
|
|
@@ -355,10 +410,10 @@ module Rlang::Parser
|
|
355
410
|
# wnode as a child of wnode
|
356
411
|
wn_var_set = parse_node(var_asgn_node, wnode, keep_eval)
|
357
412
|
cvar = wnode.find_cvar(var_name)
|
358
|
-
|
413
|
+
rlse node, "Unknown class variable #{var_name}" unless cvar
|
359
414
|
|
360
415
|
# Create the operator node (infer operator type from variable)
|
361
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
416
|
+
wn_op = @wgenerator.send_method(wn_var_set, cvar.wtype.class_path, op, :instance)
|
362
417
|
# Create the var getter node as a child of operator node
|
363
418
|
wn_var_get = @wgenerator.cvar(wn_op, cvar)
|
364
419
|
|
@@ -372,10 +427,10 @@ module Rlang::Parser
|
|
372
427
|
# wnode as a child of wnode
|
373
428
|
wn_var_set = parse_node(var_asgn_node, wnode, keep_eval)
|
374
429
|
lvar = wnode.find_lvar(var_name) || wnode.find_marg(var_name)
|
375
|
-
|
430
|
+
rlse node, "Unknown local variable #{var_name}" unless lvar
|
376
431
|
|
377
432
|
# Create the operator node (infer operator type from variable)
|
378
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
433
|
+
wn_op = @wgenerator.send_method(wn_var_set, lvar.wtype.class_path, op, :instance)
|
379
434
|
# Create the var getter node as a child of operator node
|
380
435
|
wn_var_get = @wgenerator.lvar(wn_op, lvar)
|
381
436
|
|
@@ -386,14 +441,14 @@ module Rlang::Parser
|
|
386
441
|
# s(:op_asgn,
|
387
442
|
# s(:ivasgn, :@stack_ptr), :-, s(:lvar, :nbytes))
|
388
443
|
when :ivasgn
|
389
|
-
|
444
|
+
rlse node, "Instance variable can only be accessed in instance method scope" \
|
390
445
|
unless wnode.in_instance_method_scope?
|
391
446
|
var_asgn_node, operator, exp_node = *node.children
|
392
447
|
var_name = var_asgn_node.children.last
|
393
448
|
|
394
449
|
# To op_asgn to work, ivar must already be declared
|
395
450
|
ivar = wnode.find_ivar(var_name)
|
396
|
-
|
451
|
+
rlse node, "Unknown instance variable #{var_name}" unless ivar
|
397
452
|
|
398
453
|
# Create the top level variable setter node
|
399
454
|
wn_var_set = @wgenerator.ivasgn(wnode, ivar)
|
@@ -401,7 +456,7 @@ module Rlang::Parser
|
|
401
456
|
# Second argument of the setter is the operator wnode
|
402
457
|
# Create it with wtype of receiver by default. We may
|
403
458
|
# change that wtype with the operands call later on
|
404
|
-
wn_op = @wgenerator.send_method(wn_var_set, operator,
|
459
|
+
wn_op = @wgenerator.send_method(wn_var_set, ivar.wtype.class_path, operator, :instance)
|
405
460
|
|
406
461
|
# now create the getter node as a child of the
|
407
462
|
# operator
|
@@ -431,7 +486,7 @@ module Rlang::Parser
|
|
431
486
|
wn_recv = parse_node(recv_node, wnode, true)
|
432
487
|
|
433
488
|
# Create the top level setter call
|
434
|
-
wn_var_set = @wgenerator.
|
489
|
+
wn_var_set = @wgenerator.send_method(wnode, wn_recv.wtype.class_path, :"#{method_name}=", :instance)
|
435
490
|
|
436
491
|
# First argument of the setter must be the recv_node
|
437
492
|
wn_recv.reparent_to(wn_var_set)
|
@@ -439,7 +494,7 @@ module Rlang::Parser
|
|
439
494
|
# Second argument of the setter is the operator wnode
|
440
495
|
# Create it with wtype of receiver by default. We may
|
441
496
|
# change that wtype with the operands call later on
|
442
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
497
|
+
wn_op = @wgenerator.send_method(wn_var_set, wn_recv.wtype.class_path, op, :instance)
|
443
498
|
|
444
499
|
# Parsing the send node will create the getter wnode
|
445
500
|
# this is the first argument of the operator wnode,
|
@@ -452,10 +507,10 @@ module Rlang::Parser
|
|
452
507
|
# must be ignored then drop it
|
453
508
|
unless (keep_eval || wn_var_set.wtype.blank?)
|
454
509
|
@wgenerator.drop(wnode)
|
455
|
-
#@wgenerator.
|
510
|
+
#@wgenerator.send_method(wnode, wn_recv.wtype.class_path, "#{method_name}", :instance)
|
456
511
|
end
|
457
512
|
else
|
458
|
-
|
513
|
+
rlse node, "op_asgn not supported for #{node.children.first}"
|
459
514
|
end
|
460
515
|
|
461
516
|
# Finally, parse the expression node and make it
|
@@ -475,20 +530,27 @@ module Rlang::Parser
|
|
475
530
|
# (casgn nil :MYCONST
|
476
531
|
# (int 2000))
|
477
532
|
def parse_casgn(node, wnode, keep_eval)
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
533
|
+
class_path_node, constant_name, exp_node = *node.children
|
534
|
+
const_path = _build_const_path(class_path_node) << constant_name
|
535
|
+
|
536
|
+
# rlse node, "dynamic constant assignment" unless wnode.in_class_scope?
|
537
|
+
# unless class_path_node.nil?
|
538
|
+
# rlse node, "constant assignment with class path not supported (got #{class_name_node})"
|
539
|
+
# end
|
540
|
+
|
541
|
+
# find the scope class
|
542
|
+
k = wnode.find_current_class_or_module()
|
483
543
|
|
484
544
|
if wnode.in_method_scope?
|
485
545
|
# if exp_node is nil then this is the form of
|
486
546
|
# :casgn that comes from op_asgn
|
547
|
+
const = wnode.find_const(const_path)
|
487
548
|
if exp_node
|
488
549
|
if const.nil?
|
489
550
|
# first constant occurence
|
490
551
|
# type cast the constant to the wtype of the expression
|
491
|
-
const = wnode.create_const(
|
552
|
+
const = wnode.create_const(const_path, nil, 0, WType::DEFAULT)
|
553
|
+
k.consts << const
|
492
554
|
wn_casgn = @wgenerator.casgn(wnode, const)
|
493
555
|
wn_exp = parse_node(exp_node, wn_casgn)
|
494
556
|
const.wtype = wn_exp.wtype
|
@@ -498,10 +560,10 @@ module Rlang::Parser
|
|
498
560
|
wn_casgn = @wgenerator.casgn(wnode, const)
|
499
561
|
wn_exp = parse_node(exp_node, wn_casgn)
|
500
562
|
@wgenerator.cast(wn_exp, const.wtype, false)
|
501
|
-
logger.
|
563
|
+
logger.warn "Already initialized constant #{const.name}"
|
502
564
|
end
|
503
565
|
else
|
504
|
-
|
566
|
+
rlse node, "Constant #{const_path} not declared before" unless const
|
505
567
|
wn_casgn = @wgenerator.casgn(wnode, const)
|
506
568
|
end
|
507
569
|
# to mimic Ruby push the constant value on stack if needed
|
@@ -516,13 +578,20 @@ module Rlang::Parser
|
|
516
578
|
# executing this code. Just statically initiliazing the
|
517
579
|
# const with the value
|
518
580
|
wn_exp = parse_node(exp_node, wnode)
|
519
|
-
|
581
|
+
rlse node, "Constant initializer can only be an int or a constant/class (got #{wn_exp}" \
|
520
582
|
unless wn_exp.const?
|
521
|
-
const = wnode.
|
583
|
+
if (const = wnode.find_const(const_path))
|
584
|
+
logger.warn "already initialized constant #{const.path}"
|
585
|
+
const.value = wn_exp.wargs[:value]
|
586
|
+
else
|
587
|
+
const = wnode.create_const(const_path, wn_exp.wargs[:value], wn_exp.wtype)
|
588
|
+
k.consts << const
|
589
|
+
end
|
522
590
|
wnode.remove_child(wn_exp)
|
523
|
-
logger.debug "Constant #{
|
591
|
+
logger.debug "Constant #{const_path} initialized with value #{const.value} and wtype #{const.wtype}"
|
592
|
+
return nil
|
524
593
|
else
|
525
|
-
|
594
|
+
rlse node, "Constant can only be defined in method or class scope"
|
526
595
|
end
|
527
596
|
end
|
528
597
|
|
@@ -562,7 +631,7 @@ module Rlang::Parser
|
|
562
631
|
@wgenerator.cast(wn_exp, gvar.wtype, false)
|
563
632
|
end
|
564
633
|
else
|
565
|
-
|
634
|
+
rlse node, "Global variable #{gv_name} not declared before" unless gvar
|
566
635
|
wn_gvasgn = @wgenerator.gvasgn(wnode, gvar)
|
567
636
|
end
|
568
637
|
# to mimic Ruby push the variable value on stack if needed
|
@@ -571,7 +640,7 @@ module Rlang::Parser
|
|
571
640
|
elsif true #wnode.in_class_scope?
|
572
641
|
# If we are at root or in class scope
|
573
642
|
# then it is a global variable initialization
|
574
|
-
|
643
|
+
rlse node, "Global op_asgn can only happen in method scope" unless exp_node
|
575
644
|
# In the class or root scope
|
576
645
|
# it can only be a Global var **declaration**
|
577
646
|
# In this case the expression has to reduce
|
@@ -581,7 +650,7 @@ module Rlang::Parser
|
|
581
650
|
# Then remove the generated wnode because it is not for
|
582
651
|
# execution. It is just to get the init value
|
583
652
|
wn_exp = parse_node(exp_node, wnode)
|
584
|
-
|
653
|
+
rlse node, "Global initializer can only be a int or a constant/class (got #{wn_exp})" \
|
585
654
|
unless wn_exp.const?
|
586
655
|
wnode.remove_child(wn_exp)
|
587
656
|
if gvar
|
@@ -591,8 +660,9 @@ module Rlang::Parser
|
|
591
660
|
end
|
592
661
|
# Do not export global for now
|
593
662
|
#gvar.export! if self.config[:export_all]
|
663
|
+
return nil
|
594
664
|
else
|
595
|
-
|
665
|
+
rlse node, "Global can only be defined in method or class scope"
|
596
666
|
end
|
597
667
|
end
|
598
668
|
|
@@ -604,7 +674,7 @@ module Rlang::Parser
|
|
604
674
|
def parse_ivasgn(node, wnode, keep_eval)
|
605
675
|
iv_name, exp_node = *node.children
|
606
676
|
|
607
|
-
|
677
|
+
rlse node, "Instance variable #{iv_name} can only used in instance method scope" \
|
608
678
|
unless wnode.in_instance_method_scope?
|
609
679
|
|
610
680
|
if (ivar = wnode.find_ivar(iv_name))
|
@@ -662,7 +732,7 @@ module Rlang::Parser
|
|
662
732
|
@wgenerator.cast(wn_exp, cvar.wtype, false)
|
663
733
|
end
|
664
734
|
else
|
665
|
-
|
735
|
+
rlse node, "Class variable #{cv_name} not declared before" unless cvar
|
666
736
|
wn_cvasgn = @wgenerator.cvasgn(wnode, cvar)
|
667
737
|
end
|
668
738
|
# to mimic Ruby push the variable value on stack if needed
|
@@ -672,20 +742,22 @@ module Rlang::Parser
|
|
672
742
|
elsif wnode.in_class_scope?
|
673
743
|
# If we are in class scope
|
674
744
|
# then it is a class variable initialization
|
675
|
-
|
676
|
-
|
745
|
+
rlse node, "Class variable #{cv_name} already declared" if cvar
|
746
|
+
rlse node, "Class variable op_asgn can only happen in method scope" unless exp_node
|
677
747
|
# Parse the expression node to see if it's a ixx.const
|
678
748
|
# in the end but get rid of it then because we are not
|
679
749
|
# executing this code. Just statically initiliazing the
|
680
750
|
# cvar with the value
|
681
751
|
wn_exp = parse_node(exp_node, wnode)
|
682
|
-
|
752
|
+
rlse node, "Class variable initializer can only be an int or a constant/class (got #{wn_exp}" \
|
683
753
|
unless wn_exp.const?
|
684
754
|
cvar = wnode.create_cvar(cv_name, wn_exp.wargs[:value], wn_exp.wtype)
|
685
755
|
wnode.remove_child(wn_exp)
|
686
756
|
logger.debug "Class variable #{cv_name} initialized with value #{cvar.value} and wtype #{cvar.wtype}"
|
757
|
+
return
|
758
|
+
|
687
759
|
else
|
688
|
-
|
760
|
+
rlse node, "Class variable can only be defined in method or class scope"
|
689
761
|
end
|
690
762
|
end
|
691
763
|
|
@@ -723,7 +795,7 @@ module Rlang::Parser
|
|
723
795
|
@wgenerator.cast(wn_exp, lvar.wtype, false)
|
724
796
|
end
|
725
797
|
else
|
726
|
-
|
798
|
+
rlse node, "Local variable #{cv_name} not declared before" unless lvar
|
727
799
|
wn_lvasgn = @wgenerator.lvasgn(wnode, lvar)
|
728
800
|
end
|
729
801
|
# to mimic Ruby push the variable value on stack if needed
|
@@ -738,7 +810,7 @@ module Rlang::Parser
|
|
738
810
|
def parse_gvar(node, wnode, keep_eval)
|
739
811
|
gv_name, = *node.children
|
740
812
|
gvar = Global.find(gv_name)
|
741
|
-
|
813
|
+
rlse node, "Unknown Global variable #{gv_name}" unless gvar
|
742
814
|
wn_gvar = @wgenerator.gvar(wnode, gvar)
|
743
815
|
# Drop last evaluated result if asked to
|
744
816
|
@wgenerator.drop(wnode) unless keep_eval
|
@@ -750,13 +822,13 @@ module Rlang::Parser
|
|
750
822
|
# ---
|
751
823
|
# ... s(:ivar, :@stack_ptr)
|
752
824
|
def parse_ivar(node, wnode, keep_eval)
|
753
|
-
|
825
|
+
rlse node, "Instance variable can only be accessed in instance method scope" \
|
754
826
|
unless wnode.in_instance_method_scope?
|
755
827
|
iv_name, = *node.children
|
756
828
|
if (ivar = wnode.find_ivar(iv_name))
|
757
829
|
wn_ivar = @wgenerator.ivar(wnode, ivar)
|
758
830
|
else
|
759
|
-
|
831
|
+
rlse node, "unknown instance variable #{ivar_name}"
|
760
832
|
end
|
761
833
|
# Drop last evaluated result if asked to
|
762
834
|
@wgenerator.drop(wnode) unless keep_eval
|
@@ -768,13 +840,13 @@ module Rlang::Parser
|
|
768
840
|
# ---
|
769
841
|
# ... s(:cvar, :@@stack_ptr)
|
770
842
|
def parse_cvar(node, wnode, keep_eval)
|
771
|
-
|
843
|
+
rlse node, "Class variable can only be accessed in method scope" \
|
772
844
|
unless wnode.in_method_scope?
|
773
845
|
cv_name, = *node.children
|
774
846
|
if (cvar = wnode.find_cvar(cv_name))
|
775
847
|
wn_cvar = @wgenerator.cvar(wnode, cvar)
|
776
848
|
else
|
777
|
-
|
849
|
+
rlse node, "unknown class variable #{cv_name}"
|
778
850
|
end
|
779
851
|
# Drop last evaluated result if asked to
|
780
852
|
@wgenerator.drop(wnode) unless keep_eval
|
@@ -786,15 +858,14 @@ module Rlang::Parser
|
|
786
858
|
# ---
|
787
859
|
# ... s(:lvar, :nbytes)
|
788
860
|
def parse_lvar(node, wnode, keep_eval)
|
789
|
-
logger.debug("node: #{node}, wnode: #{wnode}, keep_eval: #{keep_eval}")
|
861
|
+
logger.debug("node: #{node}, wnode: #{wnode.head}, keep_eval: #{keep_eval}")
|
790
862
|
|
791
863
|
lv_name, = *node.children
|
792
864
|
if (lvar = wnode.find_lvar(lv_name) || wnode.find_marg(lv_name))
|
793
865
|
wn_lvar = @wgenerator.lvar(wnode, lvar)
|
794
866
|
else
|
795
|
-
|
867
|
+
rlse node, "unknown local variable #{lv_name}"
|
796
868
|
end
|
797
|
-
logger.debug "wnode: #{wnode}"
|
798
869
|
# Drop last evaluated result if asked to
|
799
870
|
@wgenerator.drop(wnode) unless keep_eval
|
800
871
|
return wn_lvar
|
@@ -802,7 +873,7 @@ module Rlang::Parser
|
|
802
873
|
|
803
874
|
def parse_int(node, wnode, keep_eval)
|
804
875
|
value, = *node.children
|
805
|
-
logger.debug "int: #{value} for parent wnode #{wnode} keep_eval:#{keep_eval}"
|
876
|
+
logger.debug "int: #{value} for parent wnode #{wnode.head} keep_eval:#{keep_eval}"
|
806
877
|
wn_int = @wgenerator.int(wnode, WType::DEFAULT, value)
|
807
878
|
# Drop last evaluated result if asked to
|
808
879
|
@wgenerator.drop(wnode) unless keep_eval
|
@@ -829,12 +900,11 @@ module Rlang::Parser
|
|
829
900
|
return wn_false
|
830
901
|
end
|
831
902
|
|
832
|
-
#
|
833
|
-
# in
|
834
|
-
#
|
835
|
-
#
|
836
|
-
#
|
837
|
-
# we must instantiate a dynamic string object
|
903
|
+
# When a string literal initializer is used
|
904
|
+
# in root or class scope, the string literal is
|
905
|
+
# allocated statically.
|
906
|
+
# If the initializer is used in a method scope
|
907
|
+
# we instantiate a dynamic string object
|
838
908
|
# and copy the initial static value in it
|
839
909
|
def parse_string(node, wnode, keep_eval)
|
840
910
|
string = node.children.last
|
@@ -852,32 +922,57 @@ module Rlang::Parser
|
|
852
922
|
return wn_string
|
853
923
|
end
|
854
924
|
|
925
|
+
# Example
|
926
|
+
# [1, -2, 5]
|
927
|
+
# -------
|
928
|
+
# (array
|
929
|
+
# (int 1)
|
930
|
+
# (int -2)
|
931
|
+
# (int 5)
|
932
|
+
# )
|
933
|
+
#
|
934
|
+
# When an array literal initializer is used
|
935
|
+
# in root or class scope, the array literal is
|
936
|
+
# allocated statically.
|
937
|
+
# If the initializer is used in a method scope
|
938
|
+
# we instantiate a dynamic string object
|
939
|
+
# and copy the initial static value in it
|
940
|
+
#
|
941
|
+
def parse_array(node, wnode, keep_eval)
|
942
|
+
# check that all array elements are of type int
|
943
|
+
# this is the only initializer type we support for
|
944
|
+
# now. Collect int values.
|
945
|
+
array = node.children.collect do |wn|
|
946
|
+
rlse node, "Array initializer can only be of type int (got #{wn}" unless wn.type == :int
|
947
|
+
wn.children.last
|
948
|
+
end
|
949
|
+
|
950
|
+
if wnode.in_method_scope?
|
951
|
+
# allocate array dynamically
|
952
|
+
wn_array = @wgenerator.array_dynamic_new(wnode, array)
|
953
|
+
else
|
954
|
+
# allocate array statically
|
955
|
+
wn_array = @wgenerator.array_static_new(wnode, array)
|
956
|
+
end
|
957
|
+
# Drop last evaluated result if asked to
|
958
|
+
@wgenerator.drop(wnode) unless keep_eval
|
959
|
+
|
960
|
+
logger.debug "wn_array:#{wn_array} wtype:#{wn_array.wtype} keep_eval:#{keep_eval}"
|
961
|
+
return wn_array
|
962
|
+
end
|
963
|
+
|
855
964
|
# Example
|
856
965
|
# TestA::C::MYCONST
|
857
966
|
# -------
|
858
967
|
# (const (const (const nil :TESTA) :C) :MYCONST))
|
859
968
|
def parse_const(node, wnode, keep_eval)
|
860
|
-
# Build constant path from
|
861
|
-
const_path =
|
862
|
-
n = node
|
863
|
-
while n
|
864
|
-
logger.debug "adding #{n.children.last} to constant path"
|
865
|
-
const_path.unshift(n.children.last)
|
866
|
-
n = n.children.first
|
867
|
-
end
|
969
|
+
# Build constant path from embedded const sexp
|
970
|
+
const_path = _build_const_path(node)
|
868
971
|
full_const_name = const_path.join('::')
|
869
|
-
if const_path.size == 1
|
870
|
-
class_name = wnode.class_name
|
871
|
-
const_name = const_path.first
|
872
|
-
elsif const_path.size == 2
|
873
|
-
class_name, const_name = *const_path
|
874
|
-
else
|
875
|
-
raise "only constant of the form X or X::Y is supported (got #{full_const_name}"
|
876
|
-
end
|
877
972
|
|
878
973
|
# See if constant exists. It should at this point
|
879
|
-
unless (const = wnode.find_const(
|
880
|
-
|
974
|
+
unless (const = wnode.find_const(const_path))
|
975
|
+
rlse node, "unknown constant #{full_const_name}"
|
881
976
|
end
|
882
977
|
wn_const = @wgenerator.const(wnode, const)
|
883
978
|
|
@@ -890,7 +985,7 @@ module Rlang::Parser
|
|
890
985
|
def parse_args(node, wnode)
|
891
986
|
# collect method arguments
|
892
987
|
node.children.each do |arg_node|
|
893
|
-
|
988
|
+
rlse node, "only regular method argument is supported (got #{arg_node.type})" if arg_node.type != :arg
|
894
989
|
# keep track of method arguments. Do not generate wasm code yet
|
895
990
|
# as 'arg' directives may later affect argument types (see parse_send)
|
896
991
|
wnode.create_marg(arg_node.children.last)
|
@@ -908,23 +1003,33 @@ module Rlang::Parser
|
|
908
1003
|
# ...
|
909
1004
|
# end
|
910
1005
|
def parse_defs(node, wnode, keep_eval)
|
911
|
-
logger.debug "node: #{node}\nwnode: #{wnode}"
|
912
|
-
|
913
|
-
|
1006
|
+
logger.debug "node: #{node}\nwnode: #{wnode.head}"
|
1007
|
+
if node.type == :def
|
1008
|
+
# we are being called from parse_def to define
|
1009
|
+
# a class method in addition to an instance method
|
1010
|
+
method_name, arg_nodes, body_node = *node.children
|
1011
|
+
recv_node = nil
|
1012
|
+
else
|
1013
|
+
recv_node, method_name, arg_nodes, body_node = *node.children
|
1014
|
+
rlse node, "only class method is supported. Wrong receiver at #{recv_node.loc.expression}" \
|
1015
|
+
if recv_node.type != :self
|
1016
|
+
end
|
1017
|
+
logger.debug "Defining class method: #{method_name}"
|
914
1018
|
logger.debug "recv_node: #{recv_node}\nmethod_name: #{method_name}"
|
915
1019
|
|
916
1020
|
# create corresponding func node
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
1021
|
+
wn_method = @wgenerator.def_method(wnode, method_name, :class)
|
1022
|
+
if @@import
|
1023
|
+
wn_import = @wgenerator.import_method(wn_method, @@import_module_name, @@import_function_name)
|
1024
|
+
end
|
1025
|
+
|
921
1026
|
# collect method arguments
|
922
1027
|
parse_args(arg_nodes, wn_method)
|
923
1028
|
# Look for any result directive and parse it so
|
924
1029
|
# that we know what the return type is in advance
|
925
1030
|
# If :nil for instance then it may change the way
|
926
1031
|
# we generate code in the body of the method
|
927
|
-
if (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
1032
|
+
if body_node && (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
928
1033
|
logger.debug "result directive found: #{result_node}"
|
929
1034
|
parse_node(result_node, wn_method, keep_eval)
|
930
1035
|
end
|
@@ -941,9 +1046,12 @@ module Rlang::Parser
|
|
941
1046
|
@wgenerator.locals(wn_method)
|
942
1047
|
@wgenerator.result(wn_method)
|
943
1048
|
@wgenerator.params(wn_method)
|
1049
|
+
@wgenerator.export_method(wn_method, @@export_name) if (@@export || self.config[:export_all])
|
944
1050
|
logger.debug "Full method wnode: #{wn_method}"
|
945
|
-
|
946
|
-
|
1051
|
+
|
1052
|
+
# reset method toggles
|
1053
|
+
self.class._reset_toggles
|
1054
|
+
|
947
1055
|
return wn_method
|
948
1056
|
end
|
949
1057
|
|
@@ -957,23 +1065,24 @@ module Rlang::Parser
|
|
957
1065
|
# ...
|
958
1066
|
# end
|
959
1067
|
def parse_def(node, wnode, keep_eval)
|
960
|
-
logger.debug "node: #{node}\nwnode: #{wnode}"
|
1068
|
+
logger.debug "node: #{node}\nwnode: #{wnode.head}"
|
961
1069
|
method_name, arg_nodes, body_node = *node.children
|
962
|
-
logger.debug "
|
1070
|
+
logger.debug "Defining instance method: #{method_name}"
|
963
1071
|
|
964
1072
|
# create corresponding func node
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
1073
|
+
wn_method = @wgenerator.def_method(wnode, method_name, :instance)
|
1074
|
+
if @@import
|
1075
|
+
wn_import = @wgenerator.import_method(wn_method, @@import_module_name, @@import_function_name)
|
1076
|
+
end
|
969
1077
|
|
970
1078
|
# collect method arguments
|
971
|
-
parse_args(arg_nodes, wn_method)
|
1079
|
+
wn_args = parse_args(arg_nodes, wn_method)
|
1080
|
+
|
972
1081
|
# Look for any result directive and parse it so
|
973
1082
|
# that we know what the return type is in advance
|
974
1083
|
# If :nil for instance then it may change the way
|
975
1084
|
# we generate code in the body of the method
|
976
|
-
if (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
1085
|
+
if body_node && (result_node = body_node.children.find {|n| n.respond_to?(:type) && n.type == :send && n.children[1] == :result})
|
977
1086
|
logger.debug "result directive found: #{result_node}"
|
978
1087
|
parse_node(result_node, wn_method, keep_eval)
|
979
1088
|
end
|
@@ -990,9 +1099,18 @@ module Rlang::Parser
|
|
990
1099
|
@wgenerator.locals(wn_method)
|
991
1100
|
@wgenerator.result(wn_method)
|
992
1101
|
@wgenerator.params(wn_method)
|
1102
|
+
@wgenerator.export_method(wn_method, @@export_name) if (@@export || self.config[:export_all])
|
993
1103
|
logger.debug "Full method wnode: #{wn_method}"
|
994
|
-
|
995
|
-
|
1104
|
+
|
1105
|
+
# reset method toggles
|
1106
|
+
self.class._reset_toggles
|
1107
|
+
|
1108
|
+
# if we are in a module then also define
|
1109
|
+
# the class method because we don't know
|
1110
|
+
# whether the module will be included or extended
|
1111
|
+
if wnode.in_module_scope?
|
1112
|
+
self.parse_defs(node, wnode, keep_eval)
|
1113
|
+
end
|
996
1114
|
return wn_method
|
997
1115
|
end
|
998
1116
|
|
@@ -1014,10 +1132,12 @@ module Rlang::Parser
|
|
1014
1132
|
when /^\./
|
1015
1133
|
# If file starts with . then look for file in pwd
|
1016
1134
|
load_path = [Dir.pwd]
|
1135
|
+
=begin
|
1017
1136
|
when /^rlang/
|
1018
1137
|
# If it starts with rlang then look for it in the
|
1019
1138
|
# installed rlang gem in addition to load path
|
1020
1139
|
load_path = self.config[:LOAD_PATH] + $LOAD_PATH
|
1140
|
+
=end
|
1021
1141
|
else
|
1022
1142
|
load_path = self.config[:LOAD_PATH]
|
1023
1143
|
load_path = [Dir.pwd] if self.config[:LOAD_PATH].empty?
|
@@ -1037,7 +1157,7 @@ module Rlang::Parser
|
|
1037
1157
|
end
|
1038
1158
|
end
|
1039
1159
|
end
|
1040
|
-
|
1160
|
+
rlse node, LoadError, "no such file to load: #{file}" unless full_path_file
|
1041
1161
|
|
1042
1162
|
# Now load the file
|
1043
1163
|
if File.extname(full_path_file) == '.wat'
|
@@ -1138,22 +1258,22 @@ module Rlang::Parser
|
|
1138
1258
|
case method_name
|
1139
1259
|
when :address=
|
1140
1260
|
value_node = node.children[2]
|
1141
|
-
|
1261
|
+
rlse node, "DAta address must be an integer" unless value_node.type == :int
|
1142
1262
|
DAta.address = value_node.children.last
|
1143
1263
|
when :align
|
1144
1264
|
value_node = node.children[2]
|
1145
|
-
|
1265
|
+
rlse node, "DAta alignment argument must be an integer" unless value_node.type == :int
|
1146
1266
|
DAta.align(value_node.children.last)
|
1147
1267
|
when :[]=
|
1148
1268
|
if (data_label_node = node.children[2]).type == :sym
|
1149
1269
|
label = data_label_node.children.last
|
1150
1270
|
else
|
1151
|
-
|
1271
|
+
rlse node, "Data label must be a symbol (got #{data_label_node}"
|
1152
1272
|
end
|
1153
1273
|
arg_node = node.children[3]
|
1154
1274
|
parse_data_value(label, arg_node)
|
1155
1275
|
else
|
1156
|
-
|
1276
|
+
rlse node, "Unsupported DAta method #{method_name}"
|
1157
1277
|
end
|
1158
1278
|
return
|
1159
1279
|
end
|
@@ -1166,14 +1286,15 @@ module Rlang::Parser
|
|
1166
1286
|
# Example
|
1167
1287
|
# (expression).cast_to(class_name, argument)
|
1168
1288
|
# -----
|
1169
|
-
# s(:
|
1289
|
+
# s(:send,
|
1170
1290
|
# s(expression),
|
1171
1291
|
# :cast_to, s(sym, :Class_name))
|
1172
1292
|
# the signed argument true|false is optional and
|
1173
1293
|
# it defaults to false
|
1294
|
+
# Class_name is a symbol like :A or :"A:B" or :"A:B:C"
|
1174
1295
|
if method_name == :cast_to
|
1175
1296
|
class_name_node = node.children.last
|
1176
|
-
|
1297
|
+
rlse node, "cast_to expects a symbol argument (got #{class_name_node}" unless class_name_node.type == :sym
|
1177
1298
|
tgt_wtype = WType.new(class_name_node.children.first)
|
1178
1299
|
logger.debug "in cast_to: target type #{tgt_wtype}"
|
1179
1300
|
|
@@ -1188,26 +1309,23 @@ module Rlang::Parser
|
|
1188
1309
|
end
|
1189
1310
|
|
1190
1311
|
|
1191
|
-
#
|
1192
|
-
#
|
1193
|
-
#
|
1312
|
+
# Explicit type cast directives for native types.
|
1313
|
+
# Used at compile time
|
1314
|
+
#
|
1194
1315
|
# Example
|
1195
|
-
# (recv).
|
1316
|
+
# (recv).to_xxxx where xxxx can be [U]I[32|64]
|
1196
1317
|
# -----
|
1197
|
-
# s(:
|
1318
|
+
# s(:send,
|
1198
1319
|
# s(expression),
|
1199
|
-
# :to_I64
|
1200
|
-
#
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
if (cnt = node.children.count) == 3
|
1205
|
-
signed = true if node.children.last.type == :true
|
1206
|
-
elsif cnt == 2
|
1207
|
-
signed = false
|
1208
|
-
else
|
1209
|
-
raise "cast directive should have 0 or 1 argument (got #{cnt - 2})"
|
1320
|
+
# :to_I64)
|
1321
|
+
#
|
1322
|
+
if [:to_UI64, :to_I64, :to_UI32, :to_I32].include? method_name
|
1323
|
+
if (cnt = node.children.count) > 2
|
1324
|
+
rlse node, "cast directive should have no argument (got #{cnt - 2})"
|
1210
1325
|
end
|
1326
|
+
tgt_rlang_type = method_name.to_s.scan(/to_(.+)$/).first.first
|
1327
|
+
tgt_wtype = WType.new(tgt_rlang_type)
|
1328
|
+
signed = tgt_wtype.signed?
|
1211
1329
|
logger.debug "in cast section: child count #{cnt}, tgt_wtype #{tgt_wtype}, signed: #{signed}"
|
1212
1330
|
|
1213
1331
|
# Parse the expression and cast it
|
@@ -1220,6 +1338,49 @@ module Rlang::Parser
|
|
1220
1338
|
return wn_cast
|
1221
1339
|
end
|
1222
1340
|
|
1341
|
+
# addr method applied to statically allocated variables
|
1342
|
+
# only constant and class variables returns their address
|
1343
|
+
# in memory
|
1344
|
+
#
|
1345
|
+
# Example
|
1346
|
+
# @@argv_bu_size.addr
|
1347
|
+
# ---
|
1348
|
+
# (send (cvar :@@argv_buf_size) :addr)
|
1349
|
+
#
|
1350
|
+
if method_name == :addr
|
1351
|
+
if recv_node.type == :const
|
1352
|
+
# Build constant path from embedded const sexp
|
1353
|
+
const_path = _build_const_path(recv_node)
|
1354
|
+
full_const_name = const_path.join('::')
|
1355
|
+
|
1356
|
+
# See if constant exists. It should at this point
|
1357
|
+
unless (const = wnode.find_const(const_path))
|
1358
|
+
rlse node, "unknown constant #{full_const_name}"
|
1359
|
+
end
|
1360
|
+
wn_const_addr = @wgenerator.const_addr(wnode, const)
|
1361
|
+
|
1362
|
+
# Drop last evaluated result if asked to
|
1363
|
+
@wgenerator.drop(wnode) unless keep_eval
|
1364
|
+
return wn_const_addr
|
1365
|
+
|
1366
|
+
elsif recv_node.type == :cvar
|
1367
|
+
rlse node, "Class variable can only be accessed in method scope" \
|
1368
|
+
unless wnode.in_method_scope?
|
1369
|
+
cv_name = recv_node.children.first
|
1370
|
+
if (cvar = wnode.find_cvar(cv_name))
|
1371
|
+
wn_cvar_addr = @wgenerator.cvar_addr(wnode, cvar)
|
1372
|
+
else
|
1373
|
+
rlse node, "unknown class variable #{cv_name}"
|
1374
|
+
end
|
1375
|
+
# Drop last evaluated result if asked to
|
1376
|
+
@wgenerator.drop(wnode) unless keep_eval
|
1377
|
+
return wn_cvar_addr
|
1378
|
+
|
1379
|
+
else
|
1380
|
+
# Do nothing. This will be treated as a regular method call
|
1381
|
+
end
|
1382
|
+
end
|
1383
|
+
|
1223
1384
|
# A that stage it's a method call of some sort
|
1224
1385
|
# (call on class or instance)
|
1225
1386
|
return parse_send_method_lookup(node, wnode, keep_eval)
|
@@ -1229,7 +1390,7 @@ module Rlang::Parser
|
|
1229
1390
|
def parse_send_nil_receiver(node, wnode, keep_eval)
|
1230
1391
|
recv_node = node.children[0]
|
1231
1392
|
method_name = node.children[1]
|
1232
|
-
|
1393
|
+
rlse node, "receiver should be nil here (got #{recv_node})" \
|
1233
1394
|
unless recv_node.nil?
|
1234
1395
|
|
1235
1396
|
if recv_node.nil? && method_name == :require
|
@@ -1240,10 +1401,26 @@ module Rlang::Parser
|
|
1240
1401
|
return parse_send_require_relative(node, wnode, keep_eval)
|
1241
1402
|
end
|
1242
1403
|
|
1404
|
+
if recv_node.nil? && method_name == :include
|
1405
|
+
return parse_send_include(node, wnode, keep_eval)
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
if recv_node.nil? && method_name == :prepend
|
1409
|
+
return parse_send_prepend(node, wnode, keep_eval)
|
1410
|
+
end
|
1411
|
+
|
1412
|
+
if recv_node.nil? && method_name == :extend
|
1413
|
+
return parse_send_extend(node, wnode, keep_eval)
|
1414
|
+
end
|
1415
|
+
|
1243
1416
|
if recv_node.nil? && method_name == :export
|
1244
1417
|
return parse_send_export(node, wnode, keep_eval)
|
1245
1418
|
end
|
1246
1419
|
|
1420
|
+
if recv_node.nil? && method_name == :import
|
1421
|
+
return parse_send_import(node, wnode, keep_eval)
|
1422
|
+
end
|
1423
|
+
|
1247
1424
|
if recv_node.nil? && method_name == :local
|
1248
1425
|
return parse_send_local(node, wnode, keep_eval)
|
1249
1426
|
end
|
@@ -1277,10 +1454,10 @@ module Rlang::Parser
|
|
1277
1454
|
# (send nil :require
|
1278
1455
|
# (str "test5"))
|
1279
1456
|
def parse_send_require(node, wnode, keep_eval)
|
1280
|
-
|
1457
|
+
rlse node, "require must be used at root level" \
|
1281
1458
|
unless wnode.in_root_scope?
|
1282
1459
|
file_node = node.children.last
|
1283
|
-
|
1460
|
+
rlse node, "require only accepts a string argument (got #{file_node})" \
|
1284
1461
|
unless file_node.type == :str
|
1285
1462
|
parse_require(wnode, file_node.children.last)
|
1286
1463
|
return
|
@@ -1292,20 +1469,119 @@ module Rlang::Parser
|
|
1292
1469
|
# (send nil :require_relative
|
1293
1470
|
# (str "test5"))
|
1294
1471
|
def parse_send_require_relative(node, wnode, keep_eval)
|
1295
|
-
|
1472
|
+
rlse node, "require_relative must be used at root level" \
|
1296
1473
|
unless wnode.in_root_scope?
|
1297
1474
|
file_node = node.children.last
|
1298
|
-
|
1475
|
+
rlse node, "require only accepts a string argument (got #{file_node})" \
|
1299
1476
|
unless file_node.type == :str
|
1300
1477
|
parse_require_relative(wnode, file_node.children.last)
|
1301
1478
|
return
|
1302
1479
|
end
|
1303
1480
|
|
1481
|
+
# Directive to include a module
|
1482
|
+
# current file
|
1483
|
+
# Example
|
1484
|
+
# include Kernel
|
1485
|
+
# ----
|
1486
|
+
# (send nil :include
|
1487
|
+
# (const nil :Kernel))
|
1488
|
+
def parse_send_include(node, wnode, keep_eval)
|
1489
|
+
const_node = node.children.last
|
1490
|
+
module_path = _build_const_path(const_node)
|
1491
|
+
rlse node, "expecting a constant for include (got #{const_node})" \
|
1492
|
+
unless const_node.type == :const
|
1493
|
+
rlse node, "include must be used in class scope" \
|
1494
|
+
unless wnode.in_class_scope?
|
1495
|
+
@wgenerator.include(wnode, module_path)
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
# Directive to prepend a module
|
1499
|
+
# current file
|
1500
|
+
# Example
|
1501
|
+
# prepend MyModule
|
1502
|
+
# ----
|
1503
|
+
# (send nil :prepend
|
1504
|
+
# (const nil :MyModule))
|
1505
|
+
def parse_send_prepend(node, wnode, keep_eval)
|
1506
|
+
const_node = node.children.last
|
1507
|
+
module_path = _build_const_path(const_node)
|
1508
|
+
rlse node, "expecting a constant for prepend (got #{const_node})" \
|
1509
|
+
unless const_node.type == :const
|
1510
|
+
rlse node, "prepend must be used in class scope" \
|
1511
|
+
unless wnode.in_class_scope?
|
1512
|
+
@wgenerator.prepend(wnode, module_path)
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
# Directive to extend a module
|
1516
|
+
# current file
|
1517
|
+
# Example
|
1518
|
+
# extend Kernel
|
1519
|
+
# ----
|
1520
|
+
# (send nil :extend
|
1521
|
+
# (const nil :Kernel))
|
1522
|
+
def parse_send_extend(node, wnode, keep_eval)
|
1523
|
+
const_node = node.children.last
|
1524
|
+
module_path = _build_const_path(const_node)
|
1525
|
+
rlse node, "expecting a constant for extend (got #{const_node})" \
|
1526
|
+
unless const_node.type == :const
|
1527
|
+
rlse node, "extend must be used in class scope" \
|
1528
|
+
unless wnode.in_class_scope?
|
1529
|
+
@wgenerator.extend(wnode, module_path)
|
1530
|
+
end
|
1531
|
+
|
1304
1532
|
# Directive to declare the current method
|
1305
1533
|
# in the WASM exports
|
1534
|
+
# Example
|
1535
|
+
#
|
1536
|
+
# export
|
1537
|
+
# ---
|
1538
|
+
# (send nil :export)
|
1539
|
+
# OR
|
1540
|
+
# export :function_name
|
1541
|
+
# ---
|
1542
|
+
# (send nil :export
|
1543
|
+
# (sym :function_name))
|
1544
|
+
#
|
1545
|
+
# With out an explicit function name, the export name
|
1546
|
+
# will be automatically built from the class/method names
|
1306
1547
|
def parse_send_export(node, wnode, keep_eval)
|
1307
|
-
|
1548
|
+
logger.debug "Export directive found for..."
|
1549
|
+
rlse node, "export must be used in class scope" unless wnode.in_class_or_module_scope?
|
1308
1550
|
@@export = true
|
1551
|
+
if (function_node = node.children[2])
|
1552
|
+
rlse node, "export function name must be a symbol (got #{function_node})" \
|
1553
|
+
unless function_node.type == :sym
|
1554
|
+
@@export_name = function_node.children.last
|
1555
|
+
end
|
1556
|
+
logger.debug "... #{@@export_name}"
|
1557
|
+
return
|
1558
|
+
end
|
1559
|
+
|
1560
|
+
# Directive to declare the current method
|
1561
|
+
# in the WASM imports
|
1562
|
+
# Example
|
1563
|
+
#
|
1564
|
+
# import :module_name, :function_name
|
1565
|
+
# ---
|
1566
|
+
# (send nil :import
|
1567
|
+
# (sym :mod)
|
1568
|
+
# (sym :func))
|
1569
|
+
#
|
1570
|
+
def parse_send_import(node, wnode, keep_eval)
|
1571
|
+
logger.debug "Import directive found for..."
|
1572
|
+
rlse node, "export must be used in class scope" unless wnode.in_class_or_module_scope?
|
1573
|
+
rlse node, "import expects 2 arguments (got #{node.children.count - 2})" \
|
1574
|
+
unless node.children.count == 4
|
1575
|
+
|
1576
|
+
module_node, function_node = node.children[2..-1]
|
1577
|
+
rlse node, "import module name must be a symbol (got #{module_node})" \
|
1578
|
+
unless module_node.type == :sym
|
1579
|
+
rlse node, "import function name must be a symbol (got #{function_node})" \
|
1580
|
+
unless function_node.type == :sym
|
1581
|
+
@@import = true
|
1582
|
+
@@import_module_name = module_node.children.last
|
1583
|
+
@@import_function_name = function_node.children.last
|
1584
|
+
logger.debug "... #{@@import_module_name}, #{@@import_function_name}"
|
1309
1585
|
return
|
1310
1586
|
end
|
1311
1587
|
|
@@ -1322,13 +1598,13 @@ module Rlang::Parser
|
|
1322
1598
|
# s(:sym, :I64))
|
1323
1599
|
# ))
|
1324
1600
|
def parse_send_local(node, wnode, keep_eval)
|
1325
|
-
|
1601
|
+
rlse node, "local declaration can only be used in methods" \
|
1326
1602
|
unless wnode.in_method_scope?
|
1327
1603
|
hash_node = node.children.last
|
1328
1604
|
local_types = parse_type_args(hash_node, :local)
|
1329
1605
|
local_types.each do |name, wtype|
|
1330
1606
|
lvar = wnode.find_or_create_lvar(name)
|
1331
|
-
|
1607
|
+
rlse node, "couldn't find or create local variable #{name}" unless lvar
|
1332
1608
|
lvar.wtype = WType.new(wtype)
|
1333
1609
|
end
|
1334
1610
|
return
|
@@ -1347,13 +1623,13 @@ module Rlang::Parser
|
|
1347
1623
|
# s(:sym, :I64))
|
1348
1624
|
# ))
|
1349
1625
|
def parse_send_arg(node, wnode, keep_eval)
|
1350
|
-
|
1626
|
+
rlse node, "arg declaration can only be used in methods" \
|
1351
1627
|
unless wnode.in_method_scope?
|
1352
1628
|
hash_node = node.children.last
|
1353
1629
|
marg_types = parse_type_args(hash_node, :argument)
|
1354
1630
|
marg_types.each do |name, wtype|
|
1355
1631
|
marg = wnode.find_marg(name)
|
1356
|
-
|
1632
|
+
rlse node, "couldn't find method argument #{name}" unless marg
|
1357
1633
|
marg.wtype = WType.new(wtype)
|
1358
1634
|
end
|
1359
1635
|
return
|
@@ -1383,42 +1659,33 @@ module Rlang::Parser
|
|
1383
1659
|
# (:none means no value is returned)
|
1384
1660
|
#
|
1385
1661
|
# Example
|
1386
|
-
# result :
|
1662
|
+
# result :MyClass, :split, :I64
|
1663
|
+
# result :"ClassA::MyClass", :split, :Header
|
1387
1664
|
# ---------
|
1388
1665
|
# s(:send, nil, :result,
|
1389
|
-
# s(:sym, :
|
1666
|
+
# s(:sym, :class_path),
|
1390
1667
|
# s(:sym, :method_name),
|
1391
1668
|
# s(:sym, :I64))
|
1392
1669
|
#
|
1393
1670
|
# if name starts with # it's a n instance method,
|
1394
1671
|
# otherwise a class method
|
1672
|
+
# Note: class path can be either A or A::B
|
1395
1673
|
def parse_send_result(node, wnode, keep_eval)
|
1396
1674
|
if wnode.in_method_scope?
|
1397
1675
|
result_type, = *node.children[2]
|
1398
|
-
|
1676
|
+
rlse node, "result directive expects a symbol argument (got #{result_type})" \
|
1399
1677
|
unless result_type.is_a? Symbol
|
1400
1678
|
wnode.method_wnode.wtype = WType.new(result_type)
|
1401
1679
|
logger.debug "result_type #{result_type} updated for method #{wnode.method_wnode.method}"
|
1402
1680
|
elsif wnode.in_class_scope?
|
1403
|
-
|
1404
|
-
|
1681
|
+
class_path_name, = *node.children[2]
|
1682
|
+
method_name, = *node.children[3]
|
1405
1683
|
result_type, = *node.children[4]
|
1406
|
-
|
1684
|
+
rlse node, "result directive expects a symbol argument (got #{result_type}) in node #{node}" \
|
1407
1685
|
unless result_type.is_a? Symbol
|
1408
|
-
|
1409
|
-
# be calling them later on
|
1410
|
-
WNode.root.find_or_create_class(cn_name)
|
1411
|
-
if mn_name[0] == '#'
|
1412
|
-
method_type = :instance
|
1413
|
-
mth_name = mn_name[1..-1].to_sym
|
1414
|
-
else
|
1415
|
-
method_type = :class
|
1416
|
-
mth_name = mn_name.to_sym
|
1417
|
-
end
|
1418
|
-
(mth = wnode.find_or_create_method(mth_name, cn_name, nil, method_type)).wtype = WType.new(result_type)
|
1419
|
-
logger.debug "Declared #{method_type} method #{mth.name} in class #{mth.class_name} with wtype #{mth.wtype.name}"
|
1686
|
+
@wgenerator.declare_method(wnode, WType.new(class_path_name), method_name.to_sym, result_type)
|
1420
1687
|
else
|
1421
|
-
|
1688
|
+
rlse node, "result declaration not supported #{wn.scope} scope"
|
1422
1689
|
end
|
1423
1690
|
return
|
1424
1691
|
end
|
@@ -1437,21 +1704,21 @@ module Rlang::Parser
|
|
1437
1704
|
# s(:sym, :ptr),
|
1438
1705
|
# s(:sym, :size))
|
1439
1706
|
def parse_send_attr(node, wnode, keep_eval)
|
1440
|
-
|
1707
|
+
rlse node, "attr directives can only happen in class scope" \
|
1441
1708
|
unless wnode.in_class_scope?
|
1442
1709
|
|
1443
1710
|
# check accessor directive is valid
|
1444
1711
|
attr_access = node.children[1].to_s
|
1445
|
-
|
1712
|
+
rlse node, "Unknown kind of attribute accessor: #{attr_access}" \
|
1446
1713
|
unless ['attr_reader', 'attr_writer', 'attr_accessor'].include? attr_access
|
1447
1714
|
# scan through all attributes
|
1448
1715
|
attr_nodes = node.children[2..-1]
|
1449
1716
|
attr_nodes.each do |an|
|
1450
1717
|
logger.debug "processing attr node #{an}"
|
1451
|
-
|
1718
|
+
rlse node, "attribute name must be a symbol (got #{an})" unless an.type == :sym
|
1452
1719
|
attr_name = an.children.last
|
1453
1720
|
if (attr = wnode.find_attr(attr_name))
|
1454
|
-
|
1721
|
+
rlse node, "attribute #{attr_name} already declared" if attr
|
1455
1722
|
else
|
1456
1723
|
attr = wnode.create_attr(attr_name)
|
1457
1724
|
attr.export!
|
@@ -1465,29 +1732,29 @@ module Rlang::Parser
|
|
1465
1732
|
# in case it's not the default type
|
1466
1733
|
#
|
1467
1734
|
# Example
|
1468
|
-
# attr_type ptr: :
|
1735
|
+
# attr_type ptr: :Header, size: :I32
|
1469
1736
|
# ---------
|
1470
1737
|
# s(:send, nil, :attr_type,
|
1471
1738
|
# (hash
|
1472
1739
|
# (pair
|
1473
1740
|
# s(:sym, :ptr)
|
1474
|
-
# s(:sym, :
|
1741
|
+
# s(:sym, :Header))
|
1475
1742
|
# (pair
|
1476
1743
|
# s(:sym, :size)
|
1477
1744
|
# s(:sym, :I32)) ))
|
1478
1745
|
#
|
1479
1746
|
def parse_send_attr_type(node, wnode, keep_eval)
|
1480
|
-
|
1747
|
+
rlse node, "attr directives can only happen in class scope" \
|
1481
1748
|
unless wnode.in_class_scope?
|
1482
1749
|
hash_node = node.children.last
|
1483
1750
|
attr_types = parse_type_args(hash_node, :attribute)
|
1484
1751
|
attr_types.each do |name, wtype|
|
1752
|
+
logger.debug "Setting attr #{name} type to #{wtype}"
|
1485
1753
|
if (attr = wnode.find_attr(name))
|
1486
|
-
logger.debug "Setting attr #{name} type to #{wtype}"
|
1487
1754
|
# TODO find a way to update both wtype at once
|
1488
1755
|
attr.wtype = WType.new(wtype)
|
1489
1756
|
else
|
1490
|
-
|
1757
|
+
rlse node, "Unknown class attribute #{name} in #{wnode.head}"
|
1491
1758
|
end
|
1492
1759
|
end
|
1493
1760
|
return
|
@@ -1525,17 +1792,17 @@ module Rlang::Parser
|
|
1525
1792
|
# (str "call_indirect(state, cf, opcodes, opcode)"))
|
1526
1793
|
#
|
1527
1794
|
def parse_send_inline(node, wnode, keep_eval)
|
1528
|
-
|
1795
|
+
rlse node, "inline can only happen in a method body or at root" \
|
1529
1796
|
unless wnode.in_method_scope? || wnode.in_root_scope?
|
1530
1797
|
hash_node = node.children.last
|
1531
|
-
|
1798
|
+
rlse node, "inline expects a hash argument (got #{hash_node.type}" \
|
1532
1799
|
unless hash_node.type == :hash
|
1533
1800
|
|
1534
1801
|
# Find the :wat entry in hash
|
1535
1802
|
logger.debug "Hash node: #{hash_node} "
|
1536
1803
|
wat_node = hash_node.children.\
|
1537
1804
|
find {|pair| sym_node, = *pair.children; sym_node.children.last == :wat}
|
1538
|
-
|
1805
|
+
rlse node, "inline has no wat: hash entry" unless wat_node
|
1539
1806
|
logger.debug "inline wat entry: #{wat_node}"
|
1540
1807
|
|
1541
1808
|
# Find the :wtype entry in hash if any
|
@@ -1550,7 +1817,7 @@ module Rlang::Parser
|
|
1550
1817
|
logger.debug "wtype: #{wtype} "
|
1551
1818
|
|
1552
1819
|
# Now extract the WAT code itself
|
1553
|
-
|
1820
|
+
rlse node, "inline has no wat: hash entry" unless wat_node
|
1554
1821
|
wcode_node = wat_node.children.last
|
1555
1822
|
if wcode_node.type == :dstr
|
1556
1823
|
# iterate over str children
|
@@ -1558,7 +1825,7 @@ module Rlang::Parser
|
|
1558
1825
|
elsif wcode_node.type == :str
|
1559
1826
|
wat_code = wcode_node.children.last
|
1560
1827
|
else
|
1561
|
-
|
1828
|
+
rlse node, "inline WAT code must be a string (got #{wcode_node})"
|
1562
1829
|
end
|
1563
1830
|
wn_inline = @wgenerator.inline(wnode, wat_code, wtype)
|
1564
1831
|
# Drop last evaluated result if asked to
|
@@ -1567,40 +1834,31 @@ module Rlang::Parser
|
|
1567
1834
|
end
|
1568
1835
|
|
1569
1836
|
# Determine whether it's an instance or class method call
|
1837
|
+
# TODO : see how to remove identical code between class
|
1838
|
+
# and instance method calls below
|
1570
1839
|
def parse_send_method_lookup(node, wnode, keep_eval)
|
1571
1840
|
recv_node = node.children[0]
|
1572
1841
|
#method_name = node.children[1]
|
1573
|
-
if wnode.in_class_scope? || wnode.in_class_method_scope? || wnode.in_root_scope?
|
1574
|
-
if recv_node.nil? || recv_node.type == :self
|
1575
|
-
|
1576
|
-
elsif recv_node.type == :const
|
1577
|
-
const_name = recv_node.children.last
|
1578
|
-
# if this is a Constant, not a class
|
1579
|
-
# then it's actually an instance method call
|
1580
|
-
if wnode.find_const(const_name)
|
1842
|
+
#if wnode.in_class_scope? || wnode.in_class_method_scope? || wnode.in_root_scope?
|
1843
|
+
if recv_node.nil? || recv_node.type == :self
|
1844
|
+
if wnode.in_instance_method_scope?
|
1581
1845
|
return parse_send_instance_method_call(node, wnode, keep_eval)
|
1582
1846
|
else
|
1583
1847
|
return parse_send_class_method_call(node, wnode, keep_eval)
|
1584
1848
|
end
|
1585
|
-
|
1586
|
-
|
1587
|
-
end
|
1588
|
-
elsif wnode.in_instance_method_scope?
|
1589
|
-
if recv_node&.type == :const
|
1590
|
-
recv_name = recv_node.children.last
|
1849
|
+
elsif recv_node.type == :const
|
1850
|
+
const_path = _build_const_path(recv_node)
|
1591
1851
|
# if this is a Constant, not a class
|
1592
1852
|
# then it's actually an instance method call
|
1593
|
-
|
1594
|
-
|
1595
|
-
else
|
1853
|
+
rlse node, "Unknown constant #{const_path}" unless (c = wnode.find_const(const_path))
|
1854
|
+
if (c.class? || c.module?)
|
1596
1855
|
return parse_send_class_method_call(node, wnode, keep_eval)
|
1597
|
-
|
1856
|
+
else
|
1857
|
+
return parse_send_instance_method_call(node, wnode, keep_eval)
|
1858
|
+
end
|
1598
1859
|
else
|
1599
1860
|
return parse_send_instance_method_call(node, wnode, keep_eval)
|
1600
1861
|
end
|
1601
|
-
else
|
1602
|
-
raise "Don't know how to call method in scope #{wnode.scope} from node #{recv_node}"
|
1603
|
-
end
|
1604
1862
|
end
|
1605
1863
|
|
1606
1864
|
# Regular class Method call to self class
|
@@ -1638,26 +1896,27 @@ module Rlang::Parser
|
|
1638
1896
|
# (const nil :Header) :new) )
|
1639
1897
|
#
|
1640
1898
|
def parse_send_class_method_call(node, wnode, keep_eval)
|
1641
|
-
logger.debug "Parsing class method call
|
1899
|
+
logger.debug "Parsing class method call..."
|
1642
1900
|
recv_node = node.children[0]
|
1643
1901
|
method_name = node.children[1]
|
1644
1902
|
if recv_node.nil? || recv_node.type == :self
|
1645
|
-
class_name
|
1903
|
+
# differ class_name identification to
|
1904
|
+
class_path = []
|
1646
1905
|
elsif recv_node.type == :const
|
1647
|
-
|
1906
|
+
class_path = _build_const_path(recv_node)
|
1648
1907
|
else
|
1649
|
-
|
1908
|
+
rlse node, "Can only call method class on self or class objects (got #{recv_node} in node #{node})"
|
1650
1909
|
end
|
1651
|
-
logger.debug "...#{
|
1910
|
+
logger.debug "...#{class_path}::#{method_name}"
|
1652
1911
|
if method_name == :new && (wnode.in_class_scope? || wnode.in_root_scope?)
|
1653
1912
|
# This is class object instantiation. Statically
|
1654
1913
|
# allocated though. So it can only happen in the
|
1655
1914
|
# class scope for a class variable or a constant
|
1656
1915
|
# Returns a wnode with a i32.const containing the address
|
1657
|
-
wn_addr = @wgenerator.static_new(wnode,
|
1916
|
+
wn_addr = @wgenerator.static_new(wnode, class_path)
|
1658
1917
|
return wn_addr
|
1659
1918
|
else
|
1660
|
-
wn_call = @wgenerator.
|
1919
|
+
wn_call = @wgenerator.send_method(wnode, class_path, method_name, :class)
|
1661
1920
|
arg_nodes = node.children[2..-1]
|
1662
1921
|
arg_nodes.each { |node| parse_node(node, wn_call) }
|
1663
1922
|
# Drop last evaluated result if asked to or if
|
@@ -1665,7 +1924,7 @@ module Rlang::Parser
|
|
1665
1924
|
@wgenerator.drop(wnode) unless (keep_eval || wn_call.wtype.blank?)
|
1666
1925
|
return wn_call
|
1667
1926
|
end
|
1668
|
-
|
1927
|
+
rlse node, "FATAL ERROR!! Unreachable point at end of parse_send_class_method_call (node: #{node})"
|
1669
1928
|
end
|
1670
1929
|
|
1671
1930
|
# Instance Method lookup and native operator
|
@@ -1709,6 +1968,7 @@ module Rlang::Parser
|
|
1709
1968
|
# ) :!)
|
1710
1969
|
#
|
1711
1970
|
def parse_send_instance_method_call(node, wnode, keep_eval)
|
1971
|
+
logger.debug "Parsing instance method call..."
|
1712
1972
|
recv_node = node.children[0]
|
1713
1973
|
method_name = node.children[1]
|
1714
1974
|
# Parse receiver node and temporarily attach it
|
@@ -1717,31 +1977,28 @@ module Rlang::Parser
|
|
1717
1977
|
logger.debug "Parsing instance method call #{method_name}, keep_eval: #{keep_eval}..."
|
1718
1978
|
logger.debug "... on receiver #{recv_node}..."
|
1719
1979
|
|
1720
|
-
# parse the receiver node just to
|
1721
|
-
# if nil it means self
|
1980
|
+
# parse the receiver node just to determine its wtype
|
1981
|
+
# if receiver node is nil it means the receiver is self
|
1722
1982
|
wn_phony = @wgenerator.phony(wnode)
|
1723
|
-
|
1724
1983
|
wn_recv = recv_node.nil? ? parse_self(recv_node, wn_phony) : parse_node(recv_node, wn_phony)
|
1725
1984
|
logger.debug "Parsed receiver : #{wn_recv} / wtype: #{wn_recv.wtype}"
|
1726
1985
|
|
1727
|
-
#
|
1728
|
-
|
1729
|
-
# then generate native operator Wasm code instead of
|
1730
|
-
# a method call
|
1731
|
-
wn_op = @wgenerator.send_method(wnode, method_name, wn_recv.wtype)
|
1986
|
+
# Generate method call code
|
1987
|
+
wn_op = @wgenerator.send_method(wnode, wn_recv.wtype.class_path, method_name, :instance)
|
1732
1988
|
|
1733
1989
|
# reparent the receiver wnode(s) to operator wnode
|
1734
1990
|
wn_phony.reparent_children_to(wn_op)
|
1735
1991
|
wnode.remove_child(wn_phony)
|
1736
1992
|
|
1737
|
-
# Grab all
|
1993
|
+
# Grab all argument nodes, parse them and add them as child
|
1994
|
+
# to the method call node
|
1738
1995
|
arg_nodes = node.children[2..-1]
|
1739
1996
|
wn_args = arg_nodes.collect do |n|
|
1740
1997
|
logger.debug "...with arg #{n}"
|
1741
1998
|
parse_node(n, wn_op, true)
|
1742
1999
|
end
|
1743
2000
|
|
1744
|
-
# now
|
2001
|
+
# now process operands (e.g. cast them if needed)
|
1745
2002
|
@wgenerator.operands(wn_op, wn_recv, wn_args)
|
1746
2003
|
logger.debug "After operands, call wnode: #{wn_op} wtype: #{wn_op.wtype}, wn_op children types: #{wn_op.children.map(&:wtype)}"
|
1747
2004
|
|
@@ -1756,14 +2013,14 @@ module Rlang::Parser
|
|
1756
2013
|
types = {}
|
1757
2014
|
# Is this a hash Node ?
|
1758
2015
|
unless hash_node.respond_to?(:type) && hash_node.type == :hash
|
1759
|
-
|
2016
|
+
rlse hash_node, "#{entity} expects a hash argument (got #{hash_node}" \
|
1760
2017
|
end
|
1761
2018
|
logger.debug "#{entity} hash node: #{hash_node}"
|
1762
2019
|
hash_node.children.each do |pair_node|
|
1763
2020
|
name_node, type_node = pair_node.children
|
1764
|
-
|
2021
|
+
rlse name_node, "The name of an #{entity} must be a symbol (got #{name_node})" \
|
1765
2022
|
unless name_node.type == :sym
|
1766
|
-
|
2023
|
+
rlse type_node, "The type of an #{entity} must be a symbol (got #{type_node})" \
|
1767
2024
|
unless type_node.type == :sym
|
1768
2025
|
name = name_node.children.last
|
1769
2026
|
type = type_node.children.last
|
@@ -1787,7 +2044,7 @@ module Rlang::Parser
|
|
1787
2044
|
# TODO: not sure this is the right thing to do. Double check
|
1788
2045
|
logger.debug "self in class definition scope. Nothing to do."
|
1789
2046
|
else
|
1790
|
-
|
2047
|
+
rlse node, "Don't know what self means in this context: #{wnode.head}"
|
1791
2048
|
end
|
1792
2049
|
wn
|
1793
2050
|
end
|
@@ -1806,27 +2063,27 @@ module Rlang::Parser
|
|
1806
2063
|
logger.debug "in send: recv_node #{recv_node}, method_name #{method_name}"
|
1807
2064
|
case method_name
|
1808
2065
|
when :to_I64
|
1809
|
-
|
2066
|
+
rlse node, "Data type casting can only apply to int (got #{recv_node}" \
|
1810
2067
|
unless recv_node.type == :int
|
1811
2068
|
value = recv_node.children.last
|
1812
2069
|
DAta.append(label, value, Type::I64)
|
1813
2070
|
when :[]
|
1814
|
-
|
2071
|
+
rlse node, "Initializer can only be a Data address (got #{node})" \
|
1815
2072
|
unless recv_node.children.last == :DAta
|
1816
|
-
|
2073
|
+
rlse node, "Initializer expects a symbol (got #{arg_node})" \
|
1817
2074
|
unless arg_node.type == :sym
|
1818
2075
|
DAta.append(label, DAta[arg_node.children.last])
|
1819
2076
|
else
|
1820
|
-
|
2077
|
+
rlse node, "Unknow data initializer #{node}"
|
1821
2078
|
end
|
1822
2079
|
else
|
1823
|
-
|
2080
|
+
rlse node, "Unknow data initializer #{node}"
|
1824
2081
|
end
|
1825
2082
|
end
|
1826
2083
|
|
1827
2084
|
def parse_return(node, wnode, keep_eval)
|
1828
2085
|
ret_count = node.children.count
|
1829
|
-
|
2086
|
+
rlse node, "only one or no value can be returned (got #{ret_count})" if ret_count > 1
|
1830
2087
|
exp_node = node.children.first
|
1831
2088
|
wn_ret = @wgenerator.return(wnode)
|
1832
2089
|
if exp_node
|
@@ -1936,7 +2193,7 @@ module Rlang::Parser
|
|
1936
2193
|
parse_node(else_node, wn_else, keep_eval)
|
1937
2194
|
wn_else.wtype = wn_else.children.last.wtype
|
1938
2195
|
if wn_then.wtype != wn_else.wtype
|
1939
|
-
|
2196
|
+
rlse node, "then and else clauses must return same wtype (got #{wn_then.wtype} and #{wn_else.wtype}"
|
1940
2197
|
end
|
1941
2198
|
else
|
1942
2199
|
# if the else clause doesn't exist in Ruby we still
|
@@ -2034,6 +2291,24 @@ module Rlang::Parser
|
|
2034
2291
|
return wn_op
|
2035
2292
|
end
|
2036
2293
|
|
2294
|
+
def _build_const_path(node)
|
2295
|
+
logger.debug "Building constant path..."
|
2296
|
+
const_path = []; n = node
|
2297
|
+
while n
|
2298
|
+
rlse node, "expecting a const node (got #{n})" unless n.type == :const
|
2299
|
+
logger.debug "adding #{n.children.last} to constant path"
|
2300
|
+
const_path.unshift(n.children.last)
|
2301
|
+
n = n.children.first
|
2302
|
+
end
|
2303
|
+
logger.debug "... #{const_path}"
|
2304
|
+
const_path
|
2305
|
+
end
|
2306
|
+
|
2307
|
+
def self._reset_toggles
|
2308
|
+
@@export, @@export_name = false, nil
|
2309
|
+
@@import, @@import_module_name, @@import_function_name = false, nil, nil
|
2310
|
+
end
|
2311
|
+
|
2037
2312
|
def dump
|
2038
2313
|
@ast
|
2039
2314
|
end
|