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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -3
  3. data/Gemfile.lock +4 -6
  4. data/README +11 -0
  5. data/README.md +18 -10
  6. data/bin/rlang +17 -5
  7. data/docs/RlangCompiler.md +5 -1
  8. data/docs/RlangManual.md +98 -20
  9. data/examples/fib/fib.rb +5 -1
  10. data/lib/builder/rlang/compiler.rb +2 -21
  11. data/lib/rlang/lib/array/array32.rb +59 -0
  12. data/lib/rlang/lib/array/array64.rb +56 -0
  13. data/lib/rlang/lib/array.rb +6 -0
  14. data/lib/rlang/lib/base64.rb +223 -0
  15. data/lib/rlang/lib/io.rb +75 -0
  16. data/lib/rlang/lib/kernel.rb +23 -0
  17. data/lib/rlang/lib/malloc.rb +12 -8
  18. data/lib/rlang/lib/memory.rb +102 -2
  19. data/lib/rlang/lib/object.rb +40 -4
  20. data/lib/rlang/lib/rlang.rb +29 -0
  21. data/lib/rlang/lib/rlang_core.rb +15 -0
  22. data/lib/rlang/lib/string.rb +106 -8
  23. data/lib/rlang/lib/type/i32.rb +43 -0
  24. data/lib/rlang/lib/type/i64.rb +2 -0
  25. data/lib/rlang/lib/unistd.rb +1 -2
  26. data/lib/rlang/lib/wasi.rb +184 -0
  27. data/lib/rlang/parser/attr.rb +9 -13
  28. data/lib/rlang/parser/const.rb +105 -1
  29. data/lib/rlang/parser/cvar.rb +11 -7
  30. data/lib/rlang/parser/data.rb +17 -6
  31. data/lib/rlang/parser/export.rb +4 -3
  32. data/lib/rlang/parser/ext/integer.rb +3 -1
  33. data/lib/rlang/parser/ext/type.rb +30 -1
  34. data/lib/rlang/parser/global.rb +10 -2
  35. data/lib/rlang/parser/ivar.rb +3 -7
  36. data/lib/rlang/parser/klass.rb +8 -35
  37. data/lib/rlang/parser/method.rb +36 -12
  38. data/lib/rlang/parser/module.rb +143 -0
  39. data/lib/rlang/parser/wgenerator.rb +462 -168
  40. data/lib/rlang/parser/wnode.rb +387 -142
  41. data/lib/rlang/parser/wtype.rb +30 -7
  42. data/lib/rlang/parser.rb +506 -231
  43. data/lib/rlang/version.rb +1 -1
  44. data/lib/rlang.rb +3 -0
  45. data/lib/ruby/mirror/rstring.rb +16 -0
  46. data/lib/utils/exceptions.rb +12 -0
  47. data/rlang.gemspec +4 -4
  48. metadata +25 -13
  49. 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
- raise "parse_file only acccepts absolute path (got #{file})" \
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
- ast = ::Parser::CurrentRuby.parse(source)
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
- raise "float instructions not supported"
189
+ rlse node, "float instructions not supported"
175
190
  #parse_float(node, wnode, keep_eval)
176
191
 
177
192
  when :nil
178
- raise "nil not supported"
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
- raise "Unknown node type: #{node.type} => #{node}"
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
- # [s(:const, nil, :Stack), nil, s(:begin ... body.... )]
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
- const_node = node.children.first
257
- body_node = node.children.last
258
- raise "expecting a constant for class name (got #{const_node})" \
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
- wn_class = @wgenerator.klass(wnode, const_node.children.last)
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) if body_node
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
- raise "Unknown global variable #{var_name}" unless gvar
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, gvar.wtype)
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
- raise "Unknown class variable #{var_name}" unless cvar
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, cvar.wtype)
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
- raise "Unknown local variable #{var_name}" unless lvar
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, lvar.wtype)
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
- raise "Instance variable can only be accessed in instance method scope" \
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
- raise "Unknown instance variable #{var_name}" unless ivar
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, ivar.wtype)
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.call(wnode, wn_recv.wtype.name, "#{method_name}=", :instance)
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, wn_recv.wtype)
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.call(wnode, wn_recv.wtype.name, "#{method_name}", :instance)
510
+ #@wgenerator.send_method(wnode, wn_recv.wtype.class_path, "#{method_name}", :instance)
456
511
  end
457
512
  else
458
- raise "op_asgn not supported for #{node.children.first}"
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
- 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
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(constant_name, nil, 0, WType::DEFAULT)
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.warning "Already initialized constant #{const.name}"
563
+ logger.warn "Already initialized constant #{const.name}"
502
564
  end
503
565
  else
504
- raise "Constant #{const_name} not declared before" unless const
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
- raise "Constant initializer initializer can only be an int or a constant/class (got #{wn_exp}" \
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.create_const(constant_name, nil, wn_exp.wargs[:value], wn_exp.wtype)
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 #{constant_name} initialized with value #{const.value} and wtype #{const.wtype}"
591
+ logger.debug "Constant #{const_path} initialized with value #{const.value} and wtype #{const.wtype}"
592
+ return nil
524
593
  else
525
- raise "Constant can only be defined in method or class scope"
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
- raise "Global variable #{cv_name} not declared before" unless gvar
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
- raise "Global op_asgn can only happen in method scope" unless exp_node
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
- raise "Global initializer can only be a int or a constant/class (got #{wn_exp})" \
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
- raise "Global can only be defined in method or class scope"
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
- raise "Instance variable #{iv_name} can only used in instance method scope" \
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
- raise "Class variable #{cv_name} not declared before" unless cvar
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
- raise "Class variable #{cv_name} already declared" if cvar
676
- raise "Class variable op_asgn can only happen in method scope" unless exp_node
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
- raise "Class variable initializer can only be an int or a constant/class (got #{wn_exp}" \
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
- raise "Class variable can only be defined in method or class scope"
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
- raise "Local variable #{cv_name} not declared before" unless lvar
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
- raise "Unknown Global variable #{gv_name}" unless gvar
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
- raise "Instance variable can only be accessed in instance method scope" \
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
- raise "unknown instance variable #{ivar_name}"
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
- raise "Class variable can only be accessed in method scope" \
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
- raise "unknown class variable #{cv_name}"
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
- raise "unknown local variable #{lv_name}"
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
- # Whenever a string literal is used in Rlang
833
- # in whatever scope (root, class or method scope)
834
- # the string literal must be allocated
835
- # statically.
836
- # Then if the literal is used in a method scope
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 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
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(const_name, class_name))
880
- raise "unknown constant #{full_const_name}"
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
- raise "only regular method argument is supported (got #{arg_node.type})" if arg_node.type != :arg
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
- 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
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
- 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)
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
- # reset export toggle
946
- @@export = false
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 "method_name: #{method_name}"
1070
+ logger.debug "Defining instance method: #{method_name}"
963
1071
 
964
1072
  # 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)
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
- # reset export toggle
995
- @@export = false
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
- raise LoadError, "no such file to load: #{full_path_file}" unless full_path_file
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
- raise "DAta address must be an integer" unless value_node.type == :int
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
- raise "DAta alignment argument must be an integer" unless value_node.type == :int
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
- raise "Data label must be a symbol (got #{data_label_node}"
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
- raise "Unsupported DAta method #{method_name}"
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(:begin,
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
- raise "cast_to expects a symbol argument (got #{class_name_node}" unless class_name_node.type == :sym
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
- # Type cast directives specific for native types
1192
- # can pass the signed argument wheres cast_to cannot
1193
- # this must be processed at compile time. It's not dynamic
1312
+ # Explicit type cast directives for native types.
1313
+ # Used at compile time
1314
+ #
1194
1315
  # Example
1195
- # (recv).to_Ixx(true|fasle) where xx is 64 or 32
1316
+ # (recv).to_xxxx where xxxx can be [U]I[32|64]
1196
1317
  # -----
1197
- # s(:begin,
1318
+ # s(:send,
1198
1319
  # s(expression),
1199
- # :to_I64, [true|false])
1200
- # the signed argument true|false is optional and
1201
- # it defaults to false
1202
- if method_name == :to_I64 || method_name == :to_I32
1203
- tgt_wtype = (method_name == :to_I64) ? WType.new(:I64) : WType.new(:I32)
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
- raise "receiver should be nil here (got #{recv_node})" \
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
- raise "require must be used at root level" \
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
- raise "require only accepts a string argument (got #{file_node})" \
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
- raise "require_relative must be used at root level" \
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
- raise "require only accepts a string argument (got #{file_node})" \
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
- raise "export must be used in class scope" unless wnode.in_class_scope?
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
- raise "local declaration can only be used in methods" \
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
- raise "couldn't find or create local variable #{name}" unless lvar
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
- raise "arg declaration can only be used in methods" \
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
- raise "couldn't find method argument #{name}" unless marg
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 :class_name, :method_name, :I64
1662
+ # result :MyClass, :split, :I64
1663
+ # result :"ClassA::MyClass", :split, :Header
1387
1664
  # ---------
1388
1665
  # s(:send, nil, :result,
1389
- # s(:sym, :class_name),
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
- raise "result directive expects a symbol argument (got #{result_type})" \
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
- cn_name, = *node.children[2]
1404
- mn_name, = *node.children[3]
1681
+ class_path_name, = *node.children[2]
1682
+ method_name, = *node.children[3]
1405
1683
  result_type, = *node.children[4]
1406
- raise "result directive expects a symbol argument (got #{result_type}) in node #{node}" \
1684
+ rlse node, "result directive expects a symbol argument (got #{result_type}) in node #{node}" \
1407
1685
  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}"
1686
+ @wgenerator.declare_method(wnode, WType.new(class_path_name), method_name.to_sym, result_type)
1420
1687
  else
1421
- raise "result declaration not supported #{wn.scope} scope"
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
- raise "attr directives can only happen in class scope" \
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
- raise "Unknown kind of attribute accessor: #{attr_access}" \
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
- raise "attribute name must be a symbol (got #{an})" unless an.type == :sym
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
- raise "attribute #{attr_name} already declared" if attr
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: :I64, size: :I32
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, :I64))
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
- raise "attr directives can only happen in class scope" \
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
- raise "Unknown class attribute #{name} in #{wnode}"
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
- raise "inline can only happen in a method body or at root" \
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
- raise "inline expects a hash argument (got #{hash_node.type}" \
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
- raise "inline has no wat: hash entry" unless wat_node
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
- raise "inline has no wat: hash entry" unless wat_node
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
- raise "inline WAT code must be a string (got #{wcode_node})"
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
- 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)
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
- 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
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
- if wnode.find_const(recv_name)
1594
- return parse_send_instance_method_call(node, wnode, keep_eval)
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
- end
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 = wnode.class_name
1903
+ # differ class_name identification to
1904
+ class_path = []
1646
1905
  elsif recv_node.type == :const
1647
- class_name = recv_node.children.last
1906
+ class_path = _build_const_path(recv_node)
1648
1907
  else
1649
- raise "Can only call method class on self or class objects (got #{recv_node} in node #{node})"
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 "...#{class_name}::#{method_name}"
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, class_name)
1916
+ wn_addr = @wgenerator.static_new(wnode, class_path)
1658
1917
  return wn_addr
1659
1918
  else
1660
- wn_call = @wgenerator.call(wnode, class_name, method_name, :class)
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
- raise "FATAL ERROR!! Unreachable point at end of parse_send_class_method_call (node: #{node})"
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 know its wtype
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
- # 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)
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 arguments and add them as child of the call node
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 cast operands (will do nothing if it's a method call)
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
- raise "#{entity} expects a hash argument (got #{hash_node}" \
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
- raise "The name of an #{entity} must be a symbol (got #{name_node})" \
2021
+ rlse name_node, "The name of an #{entity} must be a symbol (got #{name_node})" \
1765
2022
  unless name_node.type == :sym
1766
- raise "The type of an #{entity} must be a symbol (got #{type_node})" \
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
- raise "Don't know what self means in this context: #{wnode}"
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
- raise "Data type casting can only apply to int (got #{recv_node}" \
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
- raise "Initializer can only be a Data address (got #{node})" \
2071
+ rlse node, "Initializer can only be a Data address (got #{node})" \
1815
2072
  unless recv_node.children.last == :DAta
1816
- raise "Initializer expects a symbol (got #{arg_node})" \
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
- raise "Unknow data initializer #{node}"
2077
+ rlse node, "Unknow data initializer #{node}"
1821
2078
  end
1822
2079
  else
1823
- raise "Unknow data initializer #{node}"
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
- raise "only one or no value can be returned (got #{ret_count})" if ret_count > 1
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
- raise "then and else clauses must return same wtype (got #{wn_then.wtype} and #{wn_else.wtype}"
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