rlang 0.4.1 → 0.6.0
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.
- 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
|