rlang 0.4.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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