rlang 0.4.1 → 0.5.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 +4 -1
- data/Gemfile.lock +1 -1
- data/README.md +15 -9
- data/docs/RlangManual.md +26 -4
- data/lib/rlang/lib/array/array32.rb +43 -0
- data/lib/rlang/lib/array/array64.rb +43 -0
- data/lib/rlang/lib/array.rb +6 -0
- data/lib/rlang/lib/kernel.rb +18 -0
- data/lib/rlang/lib/malloc.rb +5 -3
- data/lib/rlang/lib/memory.rb +102 -2
- data/lib/rlang/lib/object.rb +11 -4
- data/lib/rlang/lib/string.rb +1 -0
- data/lib/rlang/lib/unistd.rb +1 -2
- data/lib/rlang/lib.rb +4 -2
- data/lib/rlang/parser/attr.rb +9 -13
- data/lib/rlang/parser/const.rb +105 -1
- data/lib/rlang/parser/cvar.rb +10 -6
- data/lib/rlang/parser/data.rb +5 -2
- data/lib/rlang/parser/ivar.rb +3 -7
- data/lib/rlang/parser/klass.rb +8 -35
- data/lib/rlang/parser/method.rb +22 -11
- data/lib/rlang/parser/module.rb +143 -0
- data/lib/rlang/parser/wgenerator.rb +190 -90
- data/lib/rlang/parser/wnode.rb +296 -121
- data/lib/rlang/parser/wtype.rb +18 -1
- data/lib/rlang/parser.rb +224 -113
- data/lib/rlang/version.rb +1 -1
- metadata +7 -2
data/lib/rlang/parser.rb
CHANGED
@@ -118,8 +118,9 @@ module Rlang::Parser
|
|
118
118
|
# - keep_eval: whether to keep the value of the evaluated
|
119
119
|
# WAT expression on stock or not
|
120
120
|
def parse_node(node, wnode, keep_eval=true)
|
121
|
+
raise "wnode type is incorrect (got #{wnode})" unless wnode.is_a?(WNode) || wnode.nil?
|
121
122
|
logger.debug "\n---------------------->>\n" +
|
122
|
-
"Parsing node: #{node}, wnode: #{wnode}, keep_eval: #{keep_eval}"
|
123
|
+
"Parsing node: #{node}, wnode: #{wnode.head}, keep_eval: #{keep_eval}"
|
123
124
|
|
124
125
|
case node.type
|
125
126
|
when :self
|
@@ -128,6 +129,9 @@ module Rlang::Parser
|
|
128
129
|
when :class
|
129
130
|
wn = parse_class(node, wnode)
|
130
131
|
|
132
|
+
when :module
|
133
|
+
wn = parse_module(node, wnode)
|
134
|
+
|
131
135
|
when :defs
|
132
136
|
wn = parse_defs(node, wnode, keep_eval)
|
133
137
|
|
@@ -219,8 +223,9 @@ module Rlang::Parser
|
|
219
223
|
else
|
220
224
|
raise "Unknown node type: #{node.type} => #{node}"
|
221
225
|
end
|
226
|
+
raise "wnode type is incorrect (got #{wn}) at node #{node}" unless wn.is_a?(WNode) || wn.nil?
|
222
227
|
logger.debug "\n----------------------<<\n" +
|
223
|
-
"End parsing node: #{node}, parent wnode: #{wnode}, keep_eval: #{keep_eval}\n generated wnode #{wn}" +
|
228
|
+
"End parsing node: #{node}, parent wnode: #{wnode&.head}, keep_eval: #{keep_eval}\n generated wnode #{wn&.head}" +
|
224
229
|
"\n----------------------<<\n"
|
225
230
|
wn
|
226
231
|
end
|
@@ -240,7 +245,7 @@ module Rlang::Parser
|
|
240
245
|
end
|
241
246
|
logger.debug "node idx: #{idx}/#{child_count-1}, wnode type: #{wnode.type}, keep_eval: #{keep_eval}, local_keep_eval: #{local_keep_eval}"
|
242
247
|
wn = parse_node(n, wnode, local_keep_eval)
|
243
|
-
logger.debug "in begin: parsing node #{n} gives wnode #{wn}"
|
248
|
+
logger.debug "in begin: parsing node #{n} gives wnode #{wn&.head}"
|
244
249
|
end
|
245
250
|
return wn # return last wnode
|
246
251
|
end
|
@@ -250,16 +255,24 @@ module Rlang::Parser
|
|
250
255
|
# ... body ...
|
251
256
|
# end
|
252
257
|
# -----
|
253
|
-
#
|
258
|
+
# (class
|
259
|
+
# (const nil :Stack) nil (begin ....)))
|
254
260
|
#
|
261
|
+
# class Stack < Array
|
262
|
+
# ... body ...
|
263
|
+
# end
|
264
|
+
# -----
|
265
|
+
# (class
|
266
|
+
# (const nil :Stack) (const nil :Array) (begin ....)))
|
255
267
|
def parse_class(node, wnode)
|
256
|
-
|
257
|
-
body_node = node.children.last
|
268
|
+
class_const_node, super_class_const_node, body_node = *node.children
|
258
269
|
raise "expecting a constant for class name (got #{const_node})" \
|
259
|
-
unless
|
270
|
+
unless class_const_node.type == :const
|
260
271
|
|
261
272
|
# create the class wnode
|
262
|
-
|
273
|
+
class_path = _build_const_path(class_const_node)
|
274
|
+
super_class_path = _build_const_path(super_class_const_node)
|
275
|
+
wn_class = @wgenerator.klass(wnode, class_path, super_class_path)
|
263
276
|
|
264
277
|
# Parse the body of the class
|
265
278
|
parse_node(body_node, wn_class) if body_node
|
@@ -275,6 +288,29 @@ module Rlang::Parser
|
|
275
288
|
wn_class
|
276
289
|
end
|
277
290
|
|
291
|
+
# Example:
|
292
|
+
# module Kernel
|
293
|
+
# ... body ...
|
294
|
+
# end
|
295
|
+
# -----
|
296
|
+
# (module
|
297
|
+
# (const nil :Kernel) nil (begin ....)))
|
298
|
+
#
|
299
|
+
def parse_module(node, wnode)
|
300
|
+
const_node = node.children.first
|
301
|
+
body_node = node.children.last
|
302
|
+
raise "expecting a constant for module name (got #{const_node})" \
|
303
|
+
unless const_node.type == :const
|
304
|
+
|
305
|
+
module_path = _build_const_path(const_node)
|
306
|
+
|
307
|
+
# create the module wnode
|
308
|
+
wn_module = @wgenerator.module(wnode, module_path)
|
309
|
+
# Parse the body of the module
|
310
|
+
parse_node(body_node, wn_module) if body_node
|
311
|
+
wn_module
|
312
|
+
end
|
313
|
+
|
278
314
|
# TODO: the code for op_asgn is quite murky but I thought
|
279
315
|
# we would use quite often so I implemented it. We could do
|
280
316
|
# without it though..
|
@@ -325,7 +361,7 @@ module Rlang::Parser
|
|
325
361
|
#
|
326
362
|
def parse_op_asgn(node, wnode, keep_eval)
|
327
363
|
op_asgn_type = node.children.first.type
|
328
|
-
logger.debug "op_asgn on #{op_asgn_type} / wnode: #{wnode}, keep_eval: #{keep_eval}"
|
364
|
+
logger.debug "op_asgn on #{op_asgn_type} / wnode: #{wnode.head}, keep_eval: #{keep_eval}"
|
329
365
|
|
330
366
|
case op_asgn_type
|
331
367
|
# Global variable case
|
@@ -341,7 +377,7 @@ module Rlang::Parser
|
|
341
377
|
raise "Unknown global variable #{var_name}" unless gvar
|
342
378
|
|
343
379
|
# Create the operator node (infer operator type from variable)
|
344
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
380
|
+
wn_op = @wgenerator.send_method(wn_var_set, gvar.wtype.class_path, op, :instance)
|
345
381
|
# Create the var getter node as a child of operator node
|
346
382
|
wn_var_get = @wgenerator.gvar(wn_op, gvar)
|
347
383
|
|
@@ -358,7 +394,7 @@ module Rlang::Parser
|
|
358
394
|
raise "Unknown class variable #{var_name}" unless cvar
|
359
395
|
|
360
396
|
# Create the operator node (infer operator type from variable)
|
361
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
397
|
+
wn_op = @wgenerator.send_method(wn_var_set, cvar.wtype.class_path, op, :instance)
|
362
398
|
# Create the var getter node as a child of operator node
|
363
399
|
wn_var_get = @wgenerator.cvar(wn_op, cvar)
|
364
400
|
|
@@ -375,7 +411,7 @@ module Rlang::Parser
|
|
375
411
|
raise "Unknown local variable #{var_name}" unless lvar
|
376
412
|
|
377
413
|
# Create the operator node (infer operator type from variable)
|
378
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
414
|
+
wn_op = @wgenerator.send_method(wn_var_set, lvar.wtype.class_path, op, :instance)
|
379
415
|
# Create the var getter node as a child of operator node
|
380
416
|
wn_var_get = @wgenerator.lvar(wn_op, lvar)
|
381
417
|
|
@@ -401,7 +437,7 @@ module Rlang::Parser
|
|
401
437
|
# Second argument of the setter is the operator wnode
|
402
438
|
# Create it with wtype of receiver by default. We may
|
403
439
|
# change that wtype with the operands call later on
|
404
|
-
wn_op = @wgenerator.send_method(wn_var_set, operator,
|
440
|
+
wn_op = @wgenerator.send_method(wn_var_set, ivar.wtype.class_path, operator, :instance)
|
405
441
|
|
406
442
|
# now create the getter node as a child of the
|
407
443
|
# operator
|
@@ -431,7 +467,7 @@ module Rlang::Parser
|
|
431
467
|
wn_recv = parse_node(recv_node, wnode, true)
|
432
468
|
|
433
469
|
# Create the top level setter call
|
434
|
-
wn_var_set = @wgenerator.
|
470
|
+
wn_var_set = @wgenerator.send_method(wnode, wn_recv.wtype.class_path, :"#{method_name}=", :instance)
|
435
471
|
|
436
472
|
# First argument of the setter must be the recv_node
|
437
473
|
wn_recv.reparent_to(wn_var_set)
|
@@ -439,7 +475,7 @@ module Rlang::Parser
|
|
439
475
|
# Second argument of the setter is the operator wnode
|
440
476
|
# Create it with wtype of receiver by default. We may
|
441
477
|
# change that wtype with the operands call later on
|
442
|
-
wn_op = @wgenerator.send_method(wn_var_set, op,
|
478
|
+
wn_op = @wgenerator.send_method(wn_var_set, wn_recv.wtype.class_path, op, :instance)
|
443
479
|
|
444
480
|
# Parsing the send node will create the getter wnode
|
445
481
|
# this is the first argument of the operator wnode,
|
@@ -452,7 +488,7 @@ module Rlang::Parser
|
|
452
488
|
# must be ignored then drop it
|
453
489
|
unless (keep_eval || wn_var_set.wtype.blank?)
|
454
490
|
@wgenerator.drop(wnode)
|
455
|
-
#@wgenerator.
|
491
|
+
#@wgenerator.send_method(wnode, wn_recv.wtype.class_path, "#{method_name}", :instance)
|
456
492
|
end
|
457
493
|
else
|
458
494
|
raise "op_asgn not supported for #{node.children.first}"
|
@@ -475,20 +511,27 @@ module Rlang::Parser
|
|
475
511
|
# (casgn nil :MYCONST
|
476
512
|
# (int 2000))
|
477
513
|
def parse_casgn(node, wnode, keep_eval)
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
514
|
+
class_path_node, constant_name, exp_node = *node.children
|
515
|
+
const_path = _build_const_path(class_path_node) << constant_name
|
516
|
+
|
517
|
+
# raise "dynamic constant assignment" unless wnode.in_class_scope?
|
518
|
+
# unless class_path_node.nil?
|
519
|
+
# raise "constant assignment with class path not supported (got #{class_name_node})"
|
520
|
+
# end
|
521
|
+
|
522
|
+
# find the scope class
|
523
|
+
k = wnode.find_current_class_or_module()
|
483
524
|
|
484
525
|
if wnode.in_method_scope?
|
485
526
|
# if exp_node is nil then this is the form of
|
486
527
|
# :casgn that comes from op_asgn
|
528
|
+
const = wnode.find_const(const_path)
|
487
529
|
if exp_node
|
488
530
|
if const.nil?
|
489
531
|
# first constant occurence
|
490
532
|
# type cast the constant to the wtype of the expression
|
491
|
-
const = wnode.create_const(
|
533
|
+
const = wnode.create_const(const_path, nil, 0, WType::DEFAULT)
|
534
|
+
k.consts << const
|
492
535
|
wn_casgn = @wgenerator.casgn(wnode, const)
|
493
536
|
wn_exp = parse_node(exp_node, wn_casgn)
|
494
537
|
const.wtype = wn_exp.wtype
|
@@ -501,7 +544,7 @@ module Rlang::Parser
|
|
501
544
|
logger.warning "Already initialized constant #{const.name}"
|
502
545
|
end
|
503
546
|
else
|
504
|
-
raise "Constant #{
|
547
|
+
raise "Constant #{const_path} not declared before" unless const
|
505
548
|
wn_casgn = @wgenerator.casgn(wnode, const)
|
506
549
|
end
|
507
550
|
# to mimic Ruby push the constant value on stack if needed
|
@@ -516,11 +559,18 @@ module Rlang::Parser
|
|
516
559
|
# executing this code. Just statically initiliazing the
|
517
560
|
# const with the value
|
518
561
|
wn_exp = parse_node(exp_node, wnode)
|
519
|
-
raise "Constant initializer
|
562
|
+
raise "Constant initializer can only be an int or a constant/class (got #{wn_exp}" \
|
520
563
|
unless wn_exp.const?
|
521
|
-
const = wnode.
|
564
|
+
if (const = wnode.find_const(const_path))
|
565
|
+
logger.warn "already initialized constant #{const.path}"
|
566
|
+
const.value = wn_exp.wargs[:value]
|
567
|
+
else
|
568
|
+
const = wnode.create_const(const_path, wn_exp.wargs[:value], wn_exp.wtype)
|
569
|
+
k.consts << const
|
570
|
+
end
|
522
571
|
wnode.remove_child(wn_exp)
|
523
|
-
logger.debug "Constant #{
|
572
|
+
logger.debug "Constant #{const_path} initialized with value #{const.value} and wtype #{const.wtype}"
|
573
|
+
return nil
|
524
574
|
else
|
525
575
|
raise "Constant can only be defined in method or class scope"
|
526
576
|
end
|
@@ -591,6 +641,7 @@ module Rlang::Parser
|
|
591
641
|
end
|
592
642
|
# Do not export global for now
|
593
643
|
#gvar.export! if self.config[:export_all]
|
644
|
+
return nil
|
594
645
|
else
|
595
646
|
raise "Global can only be defined in method or class scope"
|
596
647
|
end
|
@@ -684,6 +735,8 @@ module Rlang::Parser
|
|
684
735
|
cvar = wnode.create_cvar(cv_name, wn_exp.wargs[:value], wn_exp.wtype)
|
685
736
|
wnode.remove_child(wn_exp)
|
686
737
|
logger.debug "Class variable #{cv_name} initialized with value #{cvar.value} and wtype #{cvar.wtype}"
|
738
|
+
return
|
739
|
+
|
687
740
|
else
|
688
741
|
raise "Class variable can only be defined in method or class scope"
|
689
742
|
end
|
@@ -786,7 +839,7 @@ module Rlang::Parser
|
|
786
839
|
# ---
|
787
840
|
# ... s(:lvar, :nbytes)
|
788
841
|
def parse_lvar(node, wnode, keep_eval)
|
789
|
-
logger.debug("node: #{node}, wnode: #{wnode}, keep_eval: #{keep_eval}")
|
842
|
+
logger.debug("node: #{node}, wnode: #{wnode.head}, keep_eval: #{keep_eval}")
|
790
843
|
|
791
844
|
lv_name, = *node.children
|
792
845
|
if (lvar = wnode.find_lvar(lv_name) || wnode.find_marg(lv_name))
|
@@ -794,7 +847,6 @@ module Rlang::Parser
|
|
794
847
|
else
|
795
848
|
raise "unknown local variable #{lv_name}"
|
796
849
|
end
|
797
|
-
logger.debug "wnode: #{wnode}"
|
798
850
|
# Drop last evaluated result if asked to
|
799
851
|
@wgenerator.drop(wnode) unless keep_eval
|
800
852
|
return wn_lvar
|
@@ -802,7 +854,7 @@ module Rlang::Parser
|
|
802
854
|
|
803
855
|
def parse_int(node, wnode, keep_eval)
|
804
856
|
value, = *node.children
|
805
|
-
logger.debug "int: #{value} for parent wnode #{wnode} keep_eval:#{keep_eval}"
|
857
|
+
logger.debug "int: #{value} for parent wnode #{wnode.head} keep_eval:#{keep_eval}"
|
806
858
|
wn_int = @wgenerator.int(wnode, WType::DEFAULT, value)
|
807
859
|
# Drop last evaluated result if asked to
|
808
860
|
@wgenerator.drop(wnode) unless keep_eval
|
@@ -857,26 +909,12 @@ module Rlang::Parser
|
|
857
909
|
# -------
|
858
910
|
# (const (const (const nil :TESTA) :C) :MYCONST))
|
859
911
|
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
|
912
|
+
# Build constant path from embedded const sexp
|
913
|
+
const_path = _build_const_path(node)
|
868
914
|
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
915
|
|
878
916
|
# See if constant exists. It should at this point
|
879
|
-
unless (const = wnode.find_const(
|
917
|
+
unless (const = wnode.find_const(const_path))
|
880
918
|
raise "unknown constant #{full_const_name}"
|
881
919
|
end
|
882
920
|
wn_const = @wgenerator.const(wnode, const)
|
@@ -908,16 +946,24 @@ module Rlang::Parser
|
|
908
946
|
# ...
|
909
947
|
# end
|
910
948
|
def parse_defs(node, wnode, keep_eval)
|
911
|
-
logger.debug "node: #{node}\nwnode: #{wnode}"
|
912
|
-
|
913
|
-
|
949
|
+
logger.debug "node: #{node}\nwnode: #{wnode.head}"
|
950
|
+
if node.type == :def
|
951
|
+
# we are being called from parse_def to define
|
952
|
+
# a class method in addition to an instance method
|
953
|
+
method_name, arg_nodes, body_node = *node.children
|
954
|
+
recv_node = nil
|
955
|
+
else
|
956
|
+
recv_node, method_name, arg_nodes, body_node = *node.children
|
957
|
+
raise "only class method is supported. Wrong receiver at #{recv_node.loc.expression}" \
|
958
|
+
if recv_node.type != :self
|
959
|
+
end
|
960
|
+
logger.debug "Defining class method: #{method_name}"
|
914
961
|
logger.debug "recv_node: #{recv_node}\nmethod_name: #{method_name}"
|
915
962
|
|
916
963
|
# create corresponding func node
|
917
|
-
|
918
|
-
method.export! if (@@export || self.config[:export_all])
|
919
|
-
|
920
|
-
wn_method = @wgenerator.class_method(wnode, method)
|
964
|
+
wn_method = @wgenerator.def_method(wnode, method_name, :class)
|
965
|
+
wn_method.method.export! if (@@export || self.config[:export_all])
|
966
|
+
|
921
967
|
# collect method arguments
|
922
968
|
parse_args(arg_nodes, wn_method)
|
923
969
|
# Look for any result directive and parse it so
|
@@ -957,18 +1003,18 @@ module Rlang::Parser
|
|
957
1003
|
# ...
|
958
1004
|
# end
|
959
1005
|
def parse_def(node, wnode, keep_eval)
|
960
|
-
logger.debug "node: #{node}\nwnode: #{wnode}"
|
1006
|
+
logger.debug "node: #{node}\nwnode: #{wnode.head}"
|
961
1007
|
method_name, arg_nodes, body_node = *node.children
|
962
|
-
logger.debug "
|
1008
|
+
logger.debug "Defining instance method: #{method_name}"
|
963
1009
|
|
964
1010
|
# create corresponding func node
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
wn_method
|
1011
|
+
# Note: because module inclusion generate both instance
|
1012
|
+
# and class methods we may get two methods wnode
|
1013
|
+
wn_method = @wgenerator.def_method(wnode, method_name, :instance)
|
1014
|
+
wn_method.method.export! if (@@export || self.config[:export_all])
|
969
1015
|
|
970
1016
|
# collect method arguments
|
971
|
-
parse_args(arg_nodes, wn_method)
|
1017
|
+
wn_args = parse_args(arg_nodes, wn_method)
|
972
1018
|
# Look for any result directive and parse it so
|
973
1019
|
# that we know what the return type is in advance
|
974
1020
|
# If :nil for instance then it may change the way
|
@@ -993,6 +1039,13 @@ module Rlang::Parser
|
|
993
1039
|
logger.debug "Full method wnode: #{wn_method}"
|
994
1040
|
# reset export toggle
|
995
1041
|
@@export = false
|
1042
|
+
|
1043
|
+
# if we are in a module then also define
|
1044
|
+
# the class method because we don't know
|
1045
|
+
# whether the module will be included or extended
|
1046
|
+
if wnode.in_module_scope?
|
1047
|
+
self.parse_defs(node, wnode, keep_eval)
|
1048
|
+
end
|
996
1049
|
return wn_method
|
997
1050
|
end
|
998
1051
|
|
@@ -1171,6 +1224,7 @@ module Rlang::Parser
|
|
1171
1224
|
# :cast_to, s(sym, :Class_name))
|
1172
1225
|
# the signed argument true|false is optional and
|
1173
1226
|
# it defaults to false
|
1227
|
+
# Class_name is a symbol like :A or :"A:B" or :"A:B:C"
|
1174
1228
|
if method_name == :cast_to
|
1175
1229
|
class_name_node = node.children.last
|
1176
1230
|
raise "cast_to expects a symbol argument (got #{class_name_node}" unless class_name_node.type == :sym
|
@@ -1240,6 +1294,18 @@ module Rlang::Parser
|
|
1240
1294
|
return parse_send_require_relative(node, wnode, keep_eval)
|
1241
1295
|
end
|
1242
1296
|
|
1297
|
+
if recv_node.nil? && method_name == :include
|
1298
|
+
return parse_send_include(node, wnode, keep_eval)
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
if recv_node.nil? && method_name == :prepend
|
1302
|
+
return parse_send_prepend(node, wnode, keep_eval)
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
if recv_node.nil? && method_name == :extend
|
1306
|
+
return parse_send_extend(node, wnode, keep_eval)
|
1307
|
+
end
|
1308
|
+
|
1243
1309
|
if recv_node.nil? && method_name == :export
|
1244
1310
|
return parse_send_export(node, wnode, keep_eval)
|
1245
1311
|
end
|
@@ -1301,6 +1367,57 @@ module Rlang::Parser
|
|
1301
1367
|
return
|
1302
1368
|
end
|
1303
1369
|
|
1370
|
+
# Directive to include a module
|
1371
|
+
# current file
|
1372
|
+
# Example
|
1373
|
+
# include Kernel
|
1374
|
+
# ----
|
1375
|
+
# (send nil :include
|
1376
|
+
# (const nil :Kernel))
|
1377
|
+
def parse_send_include(node, wnode, keep_eval)
|
1378
|
+
const_node = node.children.last
|
1379
|
+
module_path = _build_const_path(const_node)
|
1380
|
+
raise "expecting a constant for include (got #{const_node})" \
|
1381
|
+
unless const_node.type == :const
|
1382
|
+
raise "include must be used in class scope" \
|
1383
|
+
unless wnode.in_class_scope?
|
1384
|
+
@wgenerator.include(wnode, module_path)
|
1385
|
+
end
|
1386
|
+
|
1387
|
+
# Directive to prepend a module
|
1388
|
+
# current file
|
1389
|
+
# Example
|
1390
|
+
# prepend MyModule
|
1391
|
+
# ----
|
1392
|
+
# (send nil :prepend
|
1393
|
+
# (const nil :MyModule))
|
1394
|
+
def parse_send_prepend(node, wnode, keep_eval)
|
1395
|
+
const_node = node.children.last
|
1396
|
+
module_path = _build_const_path(const_node)
|
1397
|
+
raise "expecting a constant for prepend (got #{const_node})" \
|
1398
|
+
unless const_node.type == :const
|
1399
|
+
raise "prepend must be used in class scope" \
|
1400
|
+
unless wnode.in_class_scope?
|
1401
|
+
@wgenerator.prepend(wnode, module_path)
|
1402
|
+
end
|
1403
|
+
|
1404
|
+
# Directive to extend a module
|
1405
|
+
# current file
|
1406
|
+
# Example
|
1407
|
+
# extend Kernel
|
1408
|
+
# ----
|
1409
|
+
# (send nil :extend
|
1410
|
+
# (const nil :Kernel))
|
1411
|
+
def parse_send_extend(node, wnode, keep_eval)
|
1412
|
+
const_node = node.children.last
|
1413
|
+
module_path = _build_const_path(const_node)
|
1414
|
+
raise "expecting a constant for extend (got #{const_node})" \
|
1415
|
+
unless const_node.type == :const
|
1416
|
+
raise "extend must be used in class scope" \
|
1417
|
+
unless wnode.in_class_scope?
|
1418
|
+
@wgenerator.extend(wnode, module_path)
|
1419
|
+
end
|
1420
|
+
|
1304
1421
|
# Directive to declare the current method
|
1305
1422
|
# in the WASM exports
|
1306
1423
|
def parse_send_export(node, wnode, keep_eval)
|
@@ -1383,15 +1500,17 @@ module Rlang::Parser
|
|
1383
1500
|
# (:none means no value is returned)
|
1384
1501
|
#
|
1385
1502
|
# Example
|
1386
|
-
# result :
|
1503
|
+
# result :MyClass, :split, :I64
|
1504
|
+
# result :"ClassA::MyClass", :split, :Header
|
1387
1505
|
# ---------
|
1388
1506
|
# s(:send, nil, :result,
|
1389
|
-
# s(:sym, :
|
1507
|
+
# s(:sym, :class_path),
|
1390
1508
|
# s(:sym, :method_name),
|
1391
1509
|
# s(:sym, :I64))
|
1392
1510
|
#
|
1393
1511
|
# if name starts with # it's a n instance method,
|
1394
1512
|
# otherwise a class method
|
1513
|
+
# Note: class path can be either A or A::B
|
1395
1514
|
def parse_send_result(node, wnode, keep_eval)
|
1396
1515
|
if wnode.in_method_scope?
|
1397
1516
|
result_type, = *node.children[2]
|
@@ -1400,23 +1519,12 @@ module Rlang::Parser
|
|
1400
1519
|
wnode.method_wnode.wtype = WType.new(result_type)
|
1401
1520
|
logger.debug "result_type #{result_type} updated for method #{wnode.method_wnode.method}"
|
1402
1521
|
elsif wnode.in_class_scope?
|
1403
|
-
|
1404
|
-
|
1522
|
+
class_path_name, = *node.children[2]
|
1523
|
+
method_name, = *node.children[3]
|
1405
1524
|
result_type, = *node.children[4]
|
1406
1525
|
raise "result directive expects a symbol argument (got #{result_type}) in node #{node}" \
|
1407
1526
|
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}"
|
1527
|
+
@wgenerator.declare_method(wnode, WType.new(class_path_name), method_name.to_sym, result_type)
|
1420
1528
|
else
|
1421
1529
|
raise "result declaration not supported #{wn.scope} scope"
|
1422
1530
|
end
|
@@ -1465,13 +1573,13 @@ module Rlang::Parser
|
|
1465
1573
|
# in case it's not the default type
|
1466
1574
|
#
|
1467
1575
|
# Example
|
1468
|
-
# attr_type ptr: :
|
1576
|
+
# attr_type ptr: :Header, size: :I32
|
1469
1577
|
# ---------
|
1470
1578
|
# s(:send, nil, :attr_type,
|
1471
1579
|
# (hash
|
1472
1580
|
# (pair
|
1473
1581
|
# s(:sym, :ptr)
|
1474
|
-
# s(:sym, :
|
1582
|
+
# s(:sym, :Header))
|
1475
1583
|
# (pair
|
1476
1584
|
# s(:sym, :size)
|
1477
1585
|
# s(:sym, :I32)) ))
|
@@ -1482,12 +1590,12 @@ module Rlang::Parser
|
|
1482
1590
|
hash_node = node.children.last
|
1483
1591
|
attr_types = parse_type_args(hash_node, :attribute)
|
1484
1592
|
attr_types.each do |name, wtype|
|
1593
|
+
logger.debug "Setting attr #{name} type to #{wtype}"
|
1485
1594
|
if (attr = wnode.find_attr(name))
|
1486
|
-
logger.debug "Setting attr #{name} type to #{wtype}"
|
1487
1595
|
# TODO find a way to update both wtype at once
|
1488
1596
|
attr.wtype = WType.new(wtype)
|
1489
1597
|
else
|
1490
|
-
raise "Unknown class attribute #{name} in #{wnode}"
|
1598
|
+
raise "Unknown class attribute #{name} in #{wnode.head}"
|
1491
1599
|
end
|
1492
1600
|
end
|
1493
1601
|
return
|
@@ -1567,40 +1675,31 @@ module Rlang::Parser
|
|
1567
1675
|
end
|
1568
1676
|
|
1569
1677
|
# Determine whether it's an instance or class method call
|
1678
|
+
# TODO : see how to remove identical code between class
|
1679
|
+
# and instance method calls below
|
1570
1680
|
def parse_send_method_lookup(node, wnode, keep_eval)
|
1571
1681
|
recv_node = node.children[0]
|
1572
1682
|
#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)
|
1683
|
+
#if wnode.in_class_scope? || wnode.in_class_method_scope? || wnode.in_root_scope?
|
1684
|
+
if recv_node.nil? || recv_node.type == :self
|
1685
|
+
if wnode.in_instance_method_scope?
|
1581
1686
|
return parse_send_instance_method_call(node, wnode, keep_eval)
|
1582
1687
|
else
|
1583
1688
|
return parse_send_class_method_call(node, wnode, keep_eval)
|
1584
1689
|
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
|
1690
|
+
elsif recv_node.type == :const
|
1691
|
+
const_path = _build_const_path(recv_node)
|
1591
1692
|
# if this is a Constant, not a class
|
1592
1693
|
# then it's actually an instance method call
|
1593
|
-
|
1594
|
-
|
1595
|
-
else
|
1694
|
+
raise "Unknown constant #{const_path}" unless (c = wnode.find_const(const_path))
|
1695
|
+
if (c.class? || c.module?)
|
1596
1696
|
return parse_send_class_method_call(node, wnode, keep_eval)
|
1597
|
-
|
1697
|
+
else
|
1698
|
+
return parse_send_instance_method_call(node, wnode, keep_eval)
|
1699
|
+
end
|
1598
1700
|
else
|
1599
1701
|
return parse_send_instance_method_call(node, wnode, keep_eval)
|
1600
1702
|
end
|
1601
|
-
else
|
1602
|
-
raise "Don't know how to call method in scope #{wnode.scope} from node #{recv_node}"
|
1603
|
-
end
|
1604
1703
|
end
|
1605
1704
|
|
1606
1705
|
# Regular class Method call to self class
|
@@ -1638,26 +1737,27 @@ module Rlang::Parser
|
|
1638
1737
|
# (const nil :Header) :new) )
|
1639
1738
|
#
|
1640
1739
|
def parse_send_class_method_call(node, wnode, keep_eval)
|
1641
|
-
logger.debug "Parsing class method call
|
1740
|
+
logger.debug "Parsing class method call..."
|
1642
1741
|
recv_node = node.children[0]
|
1643
1742
|
method_name = node.children[1]
|
1644
1743
|
if recv_node.nil? || recv_node.type == :self
|
1645
|
-
class_name
|
1744
|
+
# differ class_name identification to
|
1745
|
+
class_path = []
|
1646
1746
|
elsif recv_node.type == :const
|
1647
|
-
|
1747
|
+
class_path = _build_const_path(recv_node)
|
1648
1748
|
else
|
1649
1749
|
raise "Can only call method class on self or class objects (got #{recv_node} in node #{node})"
|
1650
1750
|
end
|
1651
|
-
logger.debug "...#{
|
1751
|
+
logger.debug "...#{class_path}::#{method_name}"
|
1652
1752
|
if method_name == :new && (wnode.in_class_scope? || wnode.in_root_scope?)
|
1653
1753
|
# This is class object instantiation. Statically
|
1654
1754
|
# allocated though. So it can only happen in the
|
1655
1755
|
# class scope for a class variable or a constant
|
1656
1756
|
# Returns a wnode with a i32.const containing the address
|
1657
|
-
wn_addr = @wgenerator.static_new(wnode,
|
1757
|
+
wn_addr = @wgenerator.static_new(wnode, class_path)
|
1658
1758
|
return wn_addr
|
1659
1759
|
else
|
1660
|
-
wn_call = @wgenerator.
|
1760
|
+
wn_call = @wgenerator.send_method(wnode, class_path, method_name, :class)
|
1661
1761
|
arg_nodes = node.children[2..-1]
|
1662
1762
|
arg_nodes.each { |node| parse_node(node, wn_call) }
|
1663
1763
|
# Drop last evaluated result if asked to or if
|
@@ -1709,6 +1809,7 @@ module Rlang::Parser
|
|
1709
1809
|
# ) :!)
|
1710
1810
|
#
|
1711
1811
|
def parse_send_instance_method_call(node, wnode, keep_eval)
|
1812
|
+
logger.debug "Parsing instance method call..."
|
1712
1813
|
recv_node = node.children[0]
|
1713
1814
|
method_name = node.children[1]
|
1714
1815
|
# Parse receiver node and temporarily attach it
|
@@ -1724,11 +1825,8 @@ module Rlang::Parser
|
|
1724
1825
|
wn_recv = recv_node.nil? ? parse_self(recv_node, wn_phony) : parse_node(recv_node, wn_phony)
|
1725
1826
|
logger.debug "Parsed receiver : #{wn_recv} / wtype: #{wn_recv.wtype}"
|
1726
1827
|
|
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)
|
1828
|
+
# Invoke method call
|
1829
|
+
wn_op = @wgenerator.send_method(wnode, wn_recv.wtype.class_path, method_name, :instance)
|
1732
1830
|
|
1733
1831
|
# reparent the receiver wnode(s) to operator wnode
|
1734
1832
|
wn_phony.reparent_children_to(wn_op)
|
@@ -1787,7 +1885,7 @@ module Rlang::Parser
|
|
1787
1885
|
# TODO: not sure this is the right thing to do. Double check
|
1788
1886
|
logger.debug "self in class definition scope. Nothing to do."
|
1789
1887
|
else
|
1790
|
-
raise "Don't know what self means in this context: #{wnode}"
|
1888
|
+
raise "Don't know what self means in this context: #{wnode.head}"
|
1791
1889
|
end
|
1792
1890
|
wn
|
1793
1891
|
end
|
@@ -2034,6 +2132,19 @@ module Rlang::Parser
|
|
2034
2132
|
return wn_op
|
2035
2133
|
end
|
2036
2134
|
|
2135
|
+
def _build_const_path(node)
|
2136
|
+
logger.debug "Building constant path..."
|
2137
|
+
const_path = []; n = node
|
2138
|
+
while n
|
2139
|
+
raise "expecting a const node (got #{n})" unless n.type == :const
|
2140
|
+
logger.debug "adding #{n.children.last} to constant path"
|
2141
|
+
const_path.unshift(n.children.last)
|
2142
|
+
n = n.children.first
|
2143
|
+
end
|
2144
|
+
logger.debug "... #{const_path}"
|
2145
|
+
const_path
|
2146
|
+
end
|
2147
|
+
|
2037
2148
|
def dump
|
2038
2149
|
@ast
|
2039
2150
|
end
|
data/lib/rlang/version.rb
CHANGED