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.
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
- # [s(:const, nil, :Stack), nil, s(:begin ... body.... )]
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
- const_node = node.children.first
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 const_node.type == :const
270
+ unless class_const_node.type == :const
260
271
 
261
272
  # create the class wnode
262
- wn_class = @wgenerator.klass(wnode, const_node.children.last)
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, gvar.wtype)
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, cvar.wtype)
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, lvar.wtype)
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, ivar.wtype)
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.call(wnode, wn_recv.wtype.name, "#{method_name}=", :instance)
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, wn_recv.wtype)
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.call(wnode, wn_recv.wtype.name, "#{method_name}", :instance)
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
- class_name_node, constant_name, exp_node = *node.children
479
- # raise "dynamic constant assignment" unless wnode.in_class_scope?
480
- unless class_name_node.nil?
481
- raise "constant assignment with class path not supported (got #{class_name_node})"
482
- end
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(constant_name, nil, 0, WType::DEFAULT)
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 #{const_name} not declared before" unless const
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 initializer can only be an int or a constant/class (got #{wn_exp}" \
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.create_const(constant_name, nil, wn_exp.wargs[:value], wn_exp.wtype)
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 #{constant_name} initialized with value #{const.value} and wtype #{const.wtype}"
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 embeddec const sexp
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(const_name, class_name))
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
- recv_node, method_name, arg_nodes, body_node = *node.children
913
- raise "only class method is supported. Wrong receiver at #{recv_node.loc.expression}" if recv_node.type != :self
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
- method = wnode.find_or_create_method(method_name, nil, nil, :class)
918
- method.export! if (@@export || self.config[:export_all])
919
- logger.debug "Method object : #{method}"
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 "method_name: #{method_name}"
1008
+ logger.debug "Defining instance method: #{method_name}"
963
1009
 
964
1010
  # create corresponding func node
965
- method = wnode.find_or_create_method(method_name, nil, nil, :instance)
966
- method.export! if (@@export || self.config[:export_all])
967
- logger.debug "Method object : #{method}"
968
- wn_method = @wgenerator.instance_method(wnode, 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 :class_name, :method_name, :I64
1503
+ # result :MyClass, :split, :I64
1504
+ # result :"ClassA::MyClass", :split, :Header
1387
1505
  # ---------
1388
1506
  # s(:send, nil, :result,
1389
- # s(:sym, :class_name),
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
- cn_name, = *node.children[2]
1404
- mn_name, = *node.children[3]
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
- # Create class and method objects as we known we'll
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: :I64, size: :I32
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, :I64))
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
- return parse_send_class_method_call(node, wnode, keep_eval)
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
- else
1586
- return parse_send_instance_method_call(node, wnode, keep_eval)
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
- if wnode.find_const(recv_name)
1594
- return parse_send_instance_method_call(node, wnode, keep_eval)
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
- end
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 = wnode.class_name
1744
+ # differ class_name identification to
1745
+ class_path = []
1646
1746
  elsif recv_node.type == :const
1647
- class_name = recv_node.children.last
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 "...#{class_name}::#{method_name}"
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, class_name)
1757
+ wn_addr = @wgenerator.static_new(wnode, class_path)
1658
1758
  return wn_addr
1659
1759
  else
1660
- wn_call = @wgenerator.call(wnode, class_name, method_name, :class)
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
- # If it's a Wasm natively supported operator and it
1728
- # is not overloaded by the receiver's class
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
@@ -1,3 +1,3 @@
1
1
  module Rlang
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end