rlang 0.5.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.
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'
@@ -77,7 +78,7 @@ module Rlang::Parser
77
78
  # Note : this method can be called recursively
78
79
  # through require statements
79
80
  def parse_file(file)
80
- raise "parse_file only acccepts absolute path (got #{file})" \
81
+ rlse node, "parse_file only acccepts absolute path (got #{file})" \
81
82
  unless Pathname.new(file).absolute? || file.nil?
82
83
  # Already parsed. Ignore.
83
84
  if self.config[:LOADED_FEATURES].include? file
@@ -103,7 +104,14 @@ module Rlang::Parser
103
104
  end
104
105
 
105
106
  def parse(source, wnode=nil)
106
- 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
+
107
115
  parse_node(ast, wnode || @wgenerator.root) if ast
108
116
  end
109
117
 
@@ -114,11 +122,16 @@ module Rlang::Parser
114
122
  # - keep_eval: whether to keep the value of the evaluated
115
123
  # WAT expression on stock or not
116
124
  def parse_node(node, wnode, keep_eval=true)
117
- raise "wnode type is incorrect (got #{wnode})" unless wnode.is_a?(WNode) || wnode.nil?
125
+ rlse node, "wnode type is incorrect (got #{wnode})" unless wnode.is_a?(WNode) || wnode.nil?
118
126
  logger.debug "\n---------------------->>\n" +
119
127
  "Parsing node: #{node}, wnode: #{wnode.head}, keep_eval: #{keep_eval}"
120
128
  # Nothing to parse
121
- return if node.nil?
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
122
135
 
123
136
  case node.type
124
137
  when :self
@@ -173,11 +186,11 @@ module Rlang::Parser
173
186
  wn = parse_int(node, wnode, keep_eval)
174
187
 
175
188
  when :float
176
- raise "float instructions not supported"
189
+ rlse node, "float instructions not supported"
177
190
  #parse_float(node, wnode, keep_eval)
178
191
 
179
192
  when :nil
180
- raise "nil not supported"
193
+ rlse node, "nil not supported"
181
194
 
182
195
  when :const
183
196
  wn = parse_const(node, wnode, keep_eval)
@@ -218,10 +231,13 @@ module Rlang::Parser
218
231
  when :str
219
232
  wn = parse_string(node, wnode, keep_eval)
220
233
 
234
+ when :array
235
+ wn = parse_array(node, wnode, keep_eval)
236
+
221
237
  else
222
- raise "Unknown node type: #{node.type} => #{node}"
238
+ rlse node, "Unknown node type: #{node.type} => #{node}"
223
239
  end
224
- raise "wnode type is incorrect (got #{wn}) at node #{node}" unless wn.is_a?(WNode) || wn.nil?
240
+ rlse node, "wnode type is incorrect (got #{wn}) at node #{node}" unless wn.is_a?(WNode) || wn.nil?
225
241
  logger.debug "\n----------------------<<\n" +
226
242
  "End parsing node: #{node}, parent wnode: #{wnode&.head}, keep_eval: #{keep_eval}\n generated wnode #{wn&.head}" +
227
243
  "\n----------------------<<\n"
@@ -264,7 +280,7 @@ module Rlang::Parser
264
280
  # (const nil :Stack) (const nil :Array) (begin ....)))
265
281
  def parse_class(node, wnode)
266
282
  class_const_node, super_class_const_node, body_node = *node.children
267
- raise "expecting a constant for class name (got #{const_node})" \
283
+ rlse node, "expecting a constant for class name (got #{const_node})" \
268
284
  unless class_const_node.type == :const
269
285
 
270
286
  # create the class wnode
@@ -301,7 +317,7 @@ module Rlang::Parser
301
317
  def parse_module(node, wnode)
302
318
  const_node = node.children.first
303
319
  body_node = node.children.last
304
- raise "expecting a constant for module name (got #{const_node})" \
320
+ rlse node, "expecting a constant for module name (got #{const_node})" \
305
321
  unless const_node.type == :const
306
322
 
307
323
  module_path = _build_const_path(const_node)
@@ -376,7 +392,8 @@ module Rlang::Parser
376
392
  # wnode as a child of wnode
377
393
  wn_var_set = parse_node(var_asgn_node, wnode, keep_eval)
378
394
  gvar = Global.find(var_name)
379
- 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
380
397
 
381
398
  # Create the operator node (infer operator type from variable)
382
399
  wn_op = @wgenerator.send_method(wn_var_set, gvar.wtype.class_path, op, :instance)
@@ -393,7 +410,7 @@ module Rlang::Parser
393
410
  # wnode as a child of wnode
394
411
  wn_var_set = parse_node(var_asgn_node, wnode, keep_eval)
395
412
  cvar = wnode.find_cvar(var_name)
396
- raise "Unknown class variable #{var_name}" unless cvar
413
+ rlse node, "Unknown class variable #{var_name}" unless cvar
397
414
 
398
415
  # Create the operator node (infer operator type from variable)
399
416
  wn_op = @wgenerator.send_method(wn_var_set, cvar.wtype.class_path, op, :instance)
@@ -410,7 +427,7 @@ module Rlang::Parser
410
427
  # wnode as a child of wnode
411
428
  wn_var_set = parse_node(var_asgn_node, wnode, keep_eval)
412
429
  lvar = wnode.find_lvar(var_name) || wnode.find_marg(var_name)
413
- raise "Unknown local variable #{var_name}" unless lvar
430
+ rlse node, "Unknown local variable #{var_name}" unless lvar
414
431
 
415
432
  # Create the operator node (infer operator type from variable)
416
433
  wn_op = @wgenerator.send_method(wn_var_set, lvar.wtype.class_path, op, :instance)
@@ -424,14 +441,14 @@ module Rlang::Parser
424
441
  # s(:op_asgn,
425
442
  # s(:ivasgn, :@stack_ptr), :-, s(:lvar, :nbytes))
426
443
  when :ivasgn
427
- raise "Instance variable can only be accessed in instance method scope" \
444
+ rlse node, "Instance variable can only be accessed in instance method scope" \
428
445
  unless wnode.in_instance_method_scope?
429
446
  var_asgn_node, operator, exp_node = *node.children
430
447
  var_name = var_asgn_node.children.last
431
448
 
432
449
  # To op_asgn to work, ivar must already be declared
433
450
  ivar = wnode.find_ivar(var_name)
434
- raise "Unknown instance variable #{var_name}" unless ivar
451
+ rlse node, "Unknown instance variable #{var_name}" unless ivar
435
452
 
436
453
  # Create the top level variable setter node
437
454
  wn_var_set = @wgenerator.ivasgn(wnode, ivar)
@@ -493,7 +510,7 @@ module Rlang::Parser
493
510
  #@wgenerator.send_method(wnode, wn_recv.wtype.class_path, "#{method_name}", :instance)
494
511
  end
495
512
  else
496
- raise "op_asgn not supported for #{node.children.first}"
513
+ rlse node, "op_asgn not supported for #{node.children.first}"
497
514
  end
498
515
 
499
516
  # Finally, parse the expression node and make it
@@ -516,9 +533,9 @@ module Rlang::Parser
516
533
  class_path_node, constant_name, exp_node = *node.children
517
534
  const_path = _build_const_path(class_path_node) << constant_name
518
535
 
519
- # raise "dynamic constant assignment" unless wnode.in_class_scope?
536
+ # rlse node, "dynamic constant assignment" unless wnode.in_class_scope?
520
537
  # unless class_path_node.nil?
521
- # raise "constant assignment with class path not supported (got #{class_name_node})"
538
+ # rlse node, "constant assignment with class path not supported (got #{class_name_node})"
522
539
  # end
523
540
 
524
541
  # find the scope class
@@ -543,10 +560,10 @@ module Rlang::Parser
543
560
  wn_casgn = @wgenerator.casgn(wnode, const)
544
561
  wn_exp = parse_node(exp_node, wn_casgn)
545
562
  @wgenerator.cast(wn_exp, const.wtype, false)
546
- logger.warning "Already initialized constant #{const.name}"
563
+ logger.warn "Already initialized constant #{const.name}"
547
564
  end
548
565
  else
549
- raise "Constant #{const_path} not declared before" unless const
566
+ rlse node, "Constant #{const_path} not declared before" unless const
550
567
  wn_casgn = @wgenerator.casgn(wnode, const)
551
568
  end
552
569
  # to mimic Ruby push the constant value on stack if needed
@@ -561,7 +578,7 @@ module Rlang::Parser
561
578
  # executing this code. Just statically initiliazing the
562
579
  # const with the value
563
580
  wn_exp = parse_node(exp_node, wnode)
564
- raise "Constant 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}" \
565
582
  unless wn_exp.const?
566
583
  if (const = wnode.find_const(const_path))
567
584
  logger.warn "already initialized constant #{const.path}"
@@ -574,7 +591,7 @@ module Rlang::Parser
574
591
  logger.debug "Constant #{const_path} initialized with value #{const.value} and wtype #{const.wtype}"
575
592
  return nil
576
593
  else
577
- raise "Constant can only be defined in method or class scope"
594
+ rlse node, "Constant can only be defined in method or class scope"
578
595
  end
579
596
  end
580
597
 
@@ -614,7 +631,7 @@ module Rlang::Parser
614
631
  @wgenerator.cast(wn_exp, gvar.wtype, false)
615
632
  end
616
633
  else
617
- raise "Global variable #{cv_name} not declared before" unless gvar
634
+ rlse node, "Global variable #{gv_name} not declared before" unless gvar
618
635
  wn_gvasgn = @wgenerator.gvasgn(wnode, gvar)
619
636
  end
620
637
  # to mimic Ruby push the variable value on stack if needed
@@ -623,7 +640,7 @@ module Rlang::Parser
623
640
  elsif true #wnode.in_class_scope?
624
641
  # If we are at root or in class scope
625
642
  # then it is a global variable initialization
626
- 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
627
644
  # In the class or root scope
628
645
  # it can only be a Global var **declaration**
629
646
  # In this case the expression has to reduce
@@ -633,7 +650,7 @@ module Rlang::Parser
633
650
  # Then remove the generated wnode because it is not for
634
651
  # execution. It is just to get the init value
635
652
  wn_exp = parse_node(exp_node, wnode)
636
- 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})" \
637
654
  unless wn_exp.const?
638
655
  wnode.remove_child(wn_exp)
639
656
  if gvar
@@ -645,7 +662,7 @@ module Rlang::Parser
645
662
  #gvar.export! if self.config[:export_all]
646
663
  return nil
647
664
  else
648
- raise "Global can only be defined in method or class scope"
665
+ rlse node, "Global can only be defined in method or class scope"
649
666
  end
650
667
  end
651
668
 
@@ -657,7 +674,7 @@ module Rlang::Parser
657
674
  def parse_ivasgn(node, wnode, keep_eval)
658
675
  iv_name, exp_node = *node.children
659
676
 
660
- 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" \
661
678
  unless wnode.in_instance_method_scope?
662
679
 
663
680
  if (ivar = wnode.find_ivar(iv_name))
@@ -715,7 +732,7 @@ module Rlang::Parser
715
732
  @wgenerator.cast(wn_exp, cvar.wtype, false)
716
733
  end
717
734
  else
718
- raise "Class variable #{cv_name} not declared before" unless cvar
735
+ rlse node, "Class variable #{cv_name} not declared before" unless cvar
719
736
  wn_cvasgn = @wgenerator.cvasgn(wnode, cvar)
720
737
  end
721
738
  # to mimic Ruby push the variable value on stack if needed
@@ -725,14 +742,14 @@ module Rlang::Parser
725
742
  elsif wnode.in_class_scope?
726
743
  # If we are in class scope
727
744
  # then it is a class variable initialization
728
- raise "Class variable #{cv_name} already declared" if cvar
729
- 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
730
747
  # Parse the expression node to see if it's a ixx.const
731
748
  # in the end but get rid of it then because we are not
732
749
  # executing this code. Just statically initiliazing the
733
750
  # cvar with the value
734
751
  wn_exp = parse_node(exp_node, wnode)
735
- 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}" \
736
753
  unless wn_exp.const?
737
754
  cvar = wnode.create_cvar(cv_name, wn_exp.wargs[:value], wn_exp.wtype)
738
755
  wnode.remove_child(wn_exp)
@@ -740,7 +757,7 @@ module Rlang::Parser
740
757
  return
741
758
 
742
759
  else
743
- 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"
744
761
  end
745
762
  end
746
763
 
@@ -778,7 +795,7 @@ module Rlang::Parser
778
795
  @wgenerator.cast(wn_exp, lvar.wtype, false)
779
796
  end
780
797
  else
781
- raise "Local variable #{cv_name} not declared before" unless lvar
798
+ rlse node, "Local variable #{cv_name} not declared before" unless lvar
782
799
  wn_lvasgn = @wgenerator.lvasgn(wnode, lvar)
783
800
  end
784
801
  # to mimic Ruby push the variable value on stack if needed
@@ -793,7 +810,7 @@ module Rlang::Parser
793
810
  def parse_gvar(node, wnode, keep_eval)
794
811
  gv_name, = *node.children
795
812
  gvar = Global.find(gv_name)
796
- raise "Unknown Global variable #{gv_name}" unless gvar
813
+ rlse node, "Unknown Global variable #{gv_name}" unless gvar
797
814
  wn_gvar = @wgenerator.gvar(wnode, gvar)
798
815
  # Drop last evaluated result if asked to
799
816
  @wgenerator.drop(wnode) unless keep_eval
@@ -805,13 +822,13 @@ module Rlang::Parser
805
822
  # ---
806
823
  # ... s(:ivar, :@stack_ptr)
807
824
  def parse_ivar(node, wnode, keep_eval)
808
- raise "Instance variable can only be accessed in instance method scope" \
825
+ rlse node, "Instance variable can only be accessed in instance method scope" \
809
826
  unless wnode.in_instance_method_scope?
810
827
  iv_name, = *node.children
811
828
  if (ivar = wnode.find_ivar(iv_name))
812
829
  wn_ivar = @wgenerator.ivar(wnode, ivar)
813
830
  else
814
- raise "unknown instance variable #{ivar_name}"
831
+ rlse node, "unknown instance variable #{ivar_name}"
815
832
  end
816
833
  # Drop last evaluated result if asked to
817
834
  @wgenerator.drop(wnode) unless keep_eval
@@ -823,13 +840,13 @@ module Rlang::Parser
823
840
  # ---
824
841
  # ... s(:cvar, :@@stack_ptr)
825
842
  def parse_cvar(node, wnode, keep_eval)
826
- raise "Class variable can only be accessed in method scope" \
843
+ rlse node, "Class variable can only be accessed in method scope" \
827
844
  unless wnode.in_method_scope?
828
845
  cv_name, = *node.children
829
846
  if (cvar = wnode.find_cvar(cv_name))
830
847
  wn_cvar = @wgenerator.cvar(wnode, cvar)
831
848
  else
832
- raise "unknown class variable #{cv_name}"
849
+ rlse node, "unknown class variable #{cv_name}"
833
850
  end
834
851
  # Drop last evaluated result if asked to
835
852
  @wgenerator.drop(wnode) unless keep_eval
@@ -847,7 +864,7 @@ module Rlang::Parser
847
864
  if (lvar = wnode.find_lvar(lv_name) || wnode.find_marg(lv_name))
848
865
  wn_lvar = @wgenerator.lvar(wnode, lvar)
849
866
  else
850
- raise "unknown local variable #{lv_name}"
867
+ rlse node, "unknown local variable #{lv_name}"
851
868
  end
852
869
  # Drop last evaluated result if asked to
853
870
  @wgenerator.drop(wnode) unless keep_eval
@@ -883,12 +900,11 @@ module Rlang::Parser
883
900
  return wn_false
884
901
  end
885
902
 
886
- # Whenever a string literal is used in Rlang
887
- # in whatever scope (root, class or method scope)
888
- # the string literal must be allocated
889
- # statically.
890
- # Then if the literal is used in a method scope
891
- # 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
892
908
  # and copy the initial static value in it
893
909
  def parse_string(node, wnode, keep_eval)
894
910
  string = node.children.last
@@ -906,6 +922,45 @@ module Rlang::Parser
906
922
  return wn_string
907
923
  end
908
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
+
909
964
  # Example
910
965
  # TestA::C::MYCONST
911
966
  # -------
@@ -917,7 +972,7 @@ module Rlang::Parser
917
972
 
918
973
  # See if constant exists. It should at this point
919
974
  unless (const = wnode.find_const(const_path))
920
- raise "unknown constant #{full_const_name}"
975
+ rlse node, "unknown constant #{full_const_name}"
921
976
  end
922
977
  wn_const = @wgenerator.const(wnode, const)
923
978
 
@@ -930,7 +985,7 @@ module Rlang::Parser
930
985
  def parse_args(node, wnode)
931
986
  # collect method arguments
932
987
  node.children.each do |arg_node|
933
- 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
934
989
  # keep track of method arguments. Do not generate wasm code yet
935
990
  # as 'arg' directives may later affect argument types (see parse_send)
936
991
  wnode.create_marg(arg_node.children.last)
@@ -956,7 +1011,7 @@ module Rlang::Parser
956
1011
  recv_node = nil
957
1012
  else
958
1013
  recv_node, method_name, arg_nodes, body_node = *node.children
959
- raise "only class method is supported. Wrong receiver at #{recv_node.loc.expression}" \
1014
+ rlse node, "only class method is supported. Wrong receiver at #{recv_node.loc.expression}" \
960
1015
  if recv_node.type != :self
961
1016
  end
962
1017
  logger.debug "Defining class method: #{method_name}"
@@ -1102,7 +1157,7 @@ module Rlang::Parser
1102
1157
  end
1103
1158
  end
1104
1159
  end
1105
- raise LoadError, "no such file to load: #{file}" unless full_path_file
1160
+ rlse node, LoadError, "no such file to load: #{file}" unless full_path_file
1106
1161
 
1107
1162
  # Now load the file
1108
1163
  if File.extname(full_path_file) == '.wat'
@@ -1203,22 +1258,22 @@ module Rlang::Parser
1203
1258
  case method_name
1204
1259
  when :address=
1205
1260
  value_node = node.children[2]
1206
- 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
1207
1262
  DAta.address = value_node.children.last
1208
1263
  when :align
1209
1264
  value_node = node.children[2]
1210
- 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
1211
1266
  DAta.align(value_node.children.last)
1212
1267
  when :[]=
1213
1268
  if (data_label_node = node.children[2]).type == :sym
1214
1269
  label = data_label_node.children.last
1215
1270
  else
1216
- raise "Data label must be a symbol (got #{data_label_node}"
1271
+ rlse node, "Data label must be a symbol (got #{data_label_node}"
1217
1272
  end
1218
1273
  arg_node = node.children[3]
1219
1274
  parse_data_value(label, arg_node)
1220
1275
  else
1221
- raise "Unsupported DAta method #{method_name}"
1276
+ rlse node, "Unsupported DAta method #{method_name}"
1222
1277
  end
1223
1278
  return
1224
1279
  end
@@ -1231,7 +1286,7 @@ module Rlang::Parser
1231
1286
  # Example
1232
1287
  # (expression).cast_to(class_name, argument)
1233
1288
  # -----
1234
- # s(:begin,
1289
+ # s(:send,
1235
1290
  # s(expression),
1236
1291
  # :cast_to, s(sym, :Class_name))
1237
1292
  # the signed argument true|false is optional and
@@ -1239,7 +1294,7 @@ module Rlang::Parser
1239
1294
  # Class_name is a symbol like :A or :"A:B" or :"A:B:C"
1240
1295
  if method_name == :cast_to
1241
1296
  class_name_node = node.children.last
1242
- 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
1243
1298
  tgt_wtype = WType.new(class_name_node.children.first)
1244
1299
  logger.debug "in cast_to: target type #{tgt_wtype}"
1245
1300
 
@@ -1254,26 +1309,23 @@ module Rlang::Parser
1254
1309
  end
1255
1310
 
1256
1311
 
1257
- # Type cast directives specific for native types
1258
- # can pass the signed argument wheres cast_to cannot
1259
- # 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
+ #
1260
1315
  # Example
1261
- # (recv).to_Ixx(true|fasle) where xx is 64 or 32
1316
+ # (recv).to_xxxx where xxxx can be [U]I[32|64]
1262
1317
  # -----
1263
- # s(:begin,
1318
+ # s(:send,
1264
1319
  # s(expression),
1265
- # :to_I64, [true|false])
1266
- # the signed argument true|false is optional and
1267
- # it defaults to false
1268
- if method_name == :to_I64 || method_name == :to_I32
1269
- tgt_wtype = (method_name == :to_I64) ? WType.new(:I64) : WType.new(:I32)
1270
- if (cnt = node.children.count) == 3
1271
- signed = true if node.children.last.type == :true
1272
- elsif cnt == 2
1273
- signed = false
1274
- else
1275
- 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})"
1276
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?
1277
1329
  logger.debug "in cast section: child count #{cnt}, tgt_wtype #{tgt_wtype}, signed: #{signed}"
1278
1330
 
1279
1331
  # Parse the expression and cast it
@@ -1303,7 +1355,7 @@ module Rlang::Parser
1303
1355
 
1304
1356
  # See if constant exists. It should at this point
1305
1357
  unless (const = wnode.find_const(const_path))
1306
- raise "unknown constant #{full_const_name}"
1358
+ rlse node, "unknown constant #{full_const_name}"
1307
1359
  end
1308
1360
  wn_const_addr = @wgenerator.const_addr(wnode, const)
1309
1361
 
@@ -1312,13 +1364,13 @@ module Rlang::Parser
1312
1364
  return wn_const_addr
1313
1365
 
1314
1366
  elsif recv_node.type == :cvar
1315
- raise "Class variable can only be accessed in method scope" \
1367
+ rlse node, "Class variable can only be accessed in method scope" \
1316
1368
  unless wnode.in_method_scope?
1317
1369
  cv_name = recv_node.children.first
1318
1370
  if (cvar = wnode.find_cvar(cv_name))
1319
1371
  wn_cvar_addr = @wgenerator.cvar_addr(wnode, cvar)
1320
1372
  else
1321
- raise "unknown class variable #{cv_name}"
1373
+ rlse node, "unknown class variable #{cv_name}"
1322
1374
  end
1323
1375
  # Drop last evaluated result if asked to
1324
1376
  @wgenerator.drop(wnode) unless keep_eval
@@ -1338,7 +1390,7 @@ module Rlang::Parser
1338
1390
  def parse_send_nil_receiver(node, wnode, keep_eval)
1339
1391
  recv_node = node.children[0]
1340
1392
  method_name = node.children[1]
1341
- raise "receiver should be nil here (got #{recv_node})" \
1393
+ rlse node, "receiver should be nil here (got #{recv_node})" \
1342
1394
  unless recv_node.nil?
1343
1395
 
1344
1396
  if recv_node.nil? && method_name == :require
@@ -1402,10 +1454,10 @@ module Rlang::Parser
1402
1454
  # (send nil :require
1403
1455
  # (str "test5"))
1404
1456
  def parse_send_require(node, wnode, keep_eval)
1405
- raise "require must be used at root level" \
1457
+ rlse node, "require must be used at root level" \
1406
1458
  unless wnode.in_root_scope?
1407
1459
  file_node = node.children.last
1408
- raise "require only accepts a string argument (got #{file_node})" \
1460
+ rlse node, "require only accepts a string argument (got #{file_node})" \
1409
1461
  unless file_node.type == :str
1410
1462
  parse_require(wnode, file_node.children.last)
1411
1463
  return
@@ -1417,10 +1469,10 @@ module Rlang::Parser
1417
1469
  # (send nil :require_relative
1418
1470
  # (str "test5"))
1419
1471
  def parse_send_require_relative(node, wnode, keep_eval)
1420
- raise "require_relative must be used at root level" \
1472
+ rlse node, "require_relative must be used at root level" \
1421
1473
  unless wnode.in_root_scope?
1422
1474
  file_node = node.children.last
1423
- raise "require only accepts a string argument (got #{file_node})" \
1475
+ rlse node, "require only accepts a string argument (got #{file_node})" \
1424
1476
  unless file_node.type == :str
1425
1477
  parse_require_relative(wnode, file_node.children.last)
1426
1478
  return
@@ -1436,9 +1488,9 @@ module Rlang::Parser
1436
1488
  def parse_send_include(node, wnode, keep_eval)
1437
1489
  const_node = node.children.last
1438
1490
  module_path = _build_const_path(const_node)
1439
- raise "expecting a constant for include (got #{const_node})" \
1491
+ rlse node, "expecting a constant for include (got #{const_node})" \
1440
1492
  unless const_node.type == :const
1441
- raise "include must be used in class scope" \
1493
+ rlse node, "include must be used in class scope" \
1442
1494
  unless wnode.in_class_scope?
1443
1495
  @wgenerator.include(wnode, module_path)
1444
1496
  end
@@ -1453,9 +1505,9 @@ module Rlang::Parser
1453
1505
  def parse_send_prepend(node, wnode, keep_eval)
1454
1506
  const_node = node.children.last
1455
1507
  module_path = _build_const_path(const_node)
1456
- raise "expecting a constant for prepend (got #{const_node})" \
1508
+ rlse node, "expecting a constant for prepend (got #{const_node})" \
1457
1509
  unless const_node.type == :const
1458
- raise "prepend must be used in class scope" \
1510
+ rlse node, "prepend must be used in class scope" \
1459
1511
  unless wnode.in_class_scope?
1460
1512
  @wgenerator.prepend(wnode, module_path)
1461
1513
  end
@@ -1470,9 +1522,9 @@ module Rlang::Parser
1470
1522
  def parse_send_extend(node, wnode, keep_eval)
1471
1523
  const_node = node.children.last
1472
1524
  module_path = _build_const_path(const_node)
1473
- raise "expecting a constant for extend (got #{const_node})" \
1525
+ rlse node, "expecting a constant for extend (got #{const_node})" \
1474
1526
  unless const_node.type == :const
1475
- raise "extend must be used in class scope" \
1527
+ rlse node, "extend must be used in class scope" \
1476
1528
  unless wnode.in_class_scope?
1477
1529
  @wgenerator.extend(wnode, module_path)
1478
1530
  end
@@ -1494,10 +1546,10 @@ module Rlang::Parser
1494
1546
  # will be automatically built from the class/method names
1495
1547
  def parse_send_export(node, wnode, keep_eval)
1496
1548
  logger.debug "Export directive found for..."
1497
- raise "export must be used in class scope" unless wnode.in_class_or_module_scope?
1549
+ rlse node, "export must be used in class scope" unless wnode.in_class_or_module_scope?
1498
1550
  @@export = true
1499
1551
  if (function_node = node.children[2])
1500
- raise "export function name must be a symbol (got #{function_node})" \
1552
+ rlse node, "export function name must be a symbol (got #{function_node})" \
1501
1553
  unless function_node.type == :sym
1502
1554
  @@export_name = function_node.children.last
1503
1555
  end
@@ -1517,14 +1569,14 @@ module Rlang::Parser
1517
1569
  #
1518
1570
  def parse_send_import(node, wnode, keep_eval)
1519
1571
  logger.debug "Import directive found for..."
1520
- raise "export must be used in class scope" unless wnode.in_class_or_module_scope?
1521
- raise "import expects 2 arguments (got #{node.children.count - 2})" \
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})" \
1522
1574
  unless node.children.count == 4
1523
1575
 
1524
1576
  module_node, function_node = node.children[2..-1]
1525
- raise "import module name must be a symbol (got #{module_node})" \
1577
+ rlse node, "import module name must be a symbol (got #{module_node})" \
1526
1578
  unless module_node.type == :sym
1527
- raise "import function name must be a symbol (got #{function_node})" \
1579
+ rlse node, "import function name must be a symbol (got #{function_node})" \
1528
1580
  unless function_node.type == :sym
1529
1581
  @@import = true
1530
1582
  @@import_module_name = module_node.children.last
@@ -1546,13 +1598,13 @@ module Rlang::Parser
1546
1598
  # s(:sym, :I64))
1547
1599
  # ))
1548
1600
  def parse_send_local(node, wnode, keep_eval)
1549
- raise "local declaration can only be used in methods" \
1601
+ rlse node, "local declaration can only be used in methods" \
1550
1602
  unless wnode.in_method_scope?
1551
1603
  hash_node = node.children.last
1552
1604
  local_types = parse_type_args(hash_node, :local)
1553
1605
  local_types.each do |name, wtype|
1554
1606
  lvar = wnode.find_or_create_lvar(name)
1555
- raise "couldn't find or create local variable #{name}" unless lvar
1607
+ rlse node, "couldn't find or create local variable #{name}" unless lvar
1556
1608
  lvar.wtype = WType.new(wtype)
1557
1609
  end
1558
1610
  return
@@ -1571,13 +1623,13 @@ module Rlang::Parser
1571
1623
  # s(:sym, :I64))
1572
1624
  # ))
1573
1625
  def parse_send_arg(node, wnode, keep_eval)
1574
- raise "arg declaration can only be used in methods" \
1626
+ rlse node, "arg declaration can only be used in methods" \
1575
1627
  unless wnode.in_method_scope?
1576
1628
  hash_node = node.children.last
1577
1629
  marg_types = parse_type_args(hash_node, :argument)
1578
1630
  marg_types.each do |name, wtype|
1579
1631
  marg = wnode.find_marg(name)
1580
- raise "couldn't find method argument #{name}" unless marg
1632
+ rlse node, "couldn't find method argument #{name}" unless marg
1581
1633
  marg.wtype = WType.new(wtype)
1582
1634
  end
1583
1635
  return
@@ -1621,7 +1673,7 @@ module Rlang::Parser
1621
1673
  def parse_send_result(node, wnode, keep_eval)
1622
1674
  if wnode.in_method_scope?
1623
1675
  result_type, = *node.children[2]
1624
- raise "result directive expects a symbol argument (got #{result_type})" \
1676
+ rlse node, "result directive expects a symbol argument (got #{result_type})" \
1625
1677
  unless result_type.is_a? Symbol
1626
1678
  wnode.method_wnode.wtype = WType.new(result_type)
1627
1679
  logger.debug "result_type #{result_type} updated for method #{wnode.method_wnode.method}"
@@ -1629,11 +1681,11 @@ module Rlang::Parser
1629
1681
  class_path_name, = *node.children[2]
1630
1682
  method_name, = *node.children[3]
1631
1683
  result_type, = *node.children[4]
1632
- 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}" \
1633
1685
  unless result_type.is_a? Symbol
1634
1686
  @wgenerator.declare_method(wnode, WType.new(class_path_name), method_name.to_sym, result_type)
1635
1687
  else
1636
- raise "result declaration not supported #{wn.scope} scope"
1688
+ rlse node, "result declaration not supported #{wn.scope} scope"
1637
1689
  end
1638
1690
  return
1639
1691
  end
@@ -1652,21 +1704,21 @@ module Rlang::Parser
1652
1704
  # s(:sym, :ptr),
1653
1705
  # s(:sym, :size))
1654
1706
  def parse_send_attr(node, wnode, keep_eval)
1655
- raise "attr directives can only happen in class scope" \
1707
+ rlse node, "attr directives can only happen in class scope" \
1656
1708
  unless wnode.in_class_scope?
1657
1709
 
1658
1710
  # check accessor directive is valid
1659
1711
  attr_access = node.children[1].to_s
1660
- raise "Unknown kind of attribute accessor: #{attr_access}" \
1712
+ rlse node, "Unknown kind of attribute accessor: #{attr_access}" \
1661
1713
  unless ['attr_reader', 'attr_writer', 'attr_accessor'].include? attr_access
1662
1714
  # scan through all attributes
1663
1715
  attr_nodes = node.children[2..-1]
1664
1716
  attr_nodes.each do |an|
1665
1717
  logger.debug "processing attr node #{an}"
1666
- 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
1667
1719
  attr_name = an.children.last
1668
1720
  if (attr = wnode.find_attr(attr_name))
1669
- raise "attribute #{attr_name} already declared" if attr
1721
+ rlse node, "attribute #{attr_name} already declared" if attr
1670
1722
  else
1671
1723
  attr = wnode.create_attr(attr_name)
1672
1724
  attr.export!
@@ -1692,7 +1744,7 @@ module Rlang::Parser
1692
1744
  # s(:sym, :I32)) ))
1693
1745
  #
1694
1746
  def parse_send_attr_type(node, wnode, keep_eval)
1695
- raise "attr directives can only happen in class scope" \
1747
+ rlse node, "attr directives can only happen in class scope" \
1696
1748
  unless wnode.in_class_scope?
1697
1749
  hash_node = node.children.last
1698
1750
  attr_types = parse_type_args(hash_node, :attribute)
@@ -1702,7 +1754,7 @@ module Rlang::Parser
1702
1754
  # TODO find a way to update both wtype at once
1703
1755
  attr.wtype = WType.new(wtype)
1704
1756
  else
1705
- raise "Unknown class attribute #{name} in #{wnode.head}"
1757
+ rlse node, "Unknown class attribute #{name} in #{wnode.head}"
1706
1758
  end
1707
1759
  end
1708
1760
  return
@@ -1740,17 +1792,17 @@ module Rlang::Parser
1740
1792
  # (str "call_indirect(state, cf, opcodes, opcode)"))
1741
1793
  #
1742
1794
  def parse_send_inline(node, wnode, keep_eval)
1743
- 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" \
1744
1796
  unless wnode.in_method_scope? || wnode.in_root_scope?
1745
1797
  hash_node = node.children.last
1746
- raise "inline expects a hash argument (got #{hash_node.type}" \
1798
+ rlse node, "inline expects a hash argument (got #{hash_node.type}" \
1747
1799
  unless hash_node.type == :hash
1748
1800
 
1749
1801
  # Find the :wat entry in hash
1750
1802
  logger.debug "Hash node: #{hash_node} "
1751
1803
  wat_node = hash_node.children.\
1752
1804
  find {|pair| sym_node, = *pair.children; sym_node.children.last == :wat}
1753
- raise "inline has no wat: hash entry" unless wat_node
1805
+ rlse node, "inline has no wat: hash entry" unless wat_node
1754
1806
  logger.debug "inline wat entry: #{wat_node}"
1755
1807
 
1756
1808
  # Find the :wtype entry in hash if any
@@ -1765,7 +1817,7 @@ module Rlang::Parser
1765
1817
  logger.debug "wtype: #{wtype} "
1766
1818
 
1767
1819
  # Now extract the WAT code itself
1768
- raise "inline has no wat: hash entry" unless wat_node
1820
+ rlse node, "inline has no wat: hash entry" unless wat_node
1769
1821
  wcode_node = wat_node.children.last
1770
1822
  if wcode_node.type == :dstr
1771
1823
  # iterate over str children
@@ -1773,7 +1825,7 @@ module Rlang::Parser
1773
1825
  elsif wcode_node.type == :str
1774
1826
  wat_code = wcode_node.children.last
1775
1827
  else
1776
- raise "inline WAT code must be a string (got #{wcode_node})"
1828
+ rlse node, "inline WAT code must be a string (got #{wcode_node})"
1777
1829
  end
1778
1830
  wn_inline = @wgenerator.inline(wnode, wat_code, wtype)
1779
1831
  # Drop last evaluated result if asked to
@@ -1798,7 +1850,7 @@ module Rlang::Parser
1798
1850
  const_path = _build_const_path(recv_node)
1799
1851
  # if this is a Constant, not a class
1800
1852
  # then it's actually an instance method call
1801
- raise "Unknown constant #{const_path}" unless (c = wnode.find_const(const_path))
1853
+ rlse node, "Unknown constant #{const_path}" unless (c = wnode.find_const(const_path))
1802
1854
  if (c.class? || c.module?)
1803
1855
  return parse_send_class_method_call(node, wnode, keep_eval)
1804
1856
  else
@@ -1853,7 +1905,7 @@ module Rlang::Parser
1853
1905
  elsif recv_node.type == :const
1854
1906
  class_path = _build_const_path(recv_node)
1855
1907
  else
1856
- 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})"
1857
1909
  end
1858
1910
  logger.debug "...#{class_path}::#{method_name}"
1859
1911
  if method_name == :new && (wnode.in_class_scope? || wnode.in_root_scope?)
@@ -1872,7 +1924,7 @@ module Rlang::Parser
1872
1924
  @wgenerator.drop(wnode) unless (keep_eval || wn_call.wtype.blank?)
1873
1925
  return wn_call
1874
1926
  end
1875
- 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})"
1876
1928
  end
1877
1929
 
1878
1930
  # Instance Method lookup and native operator
@@ -1925,28 +1977,28 @@ module Rlang::Parser
1925
1977
  logger.debug "Parsing instance method call #{method_name}, keep_eval: #{keep_eval}..."
1926
1978
  logger.debug "... on receiver #{recv_node}..."
1927
1979
 
1928
- # parse the receiver node just to know its wtype
1929
- # 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
1930
1982
  wn_phony = @wgenerator.phony(wnode)
1931
-
1932
1983
  wn_recv = recv_node.nil? ? parse_self(recv_node, wn_phony) : parse_node(recv_node, wn_phony)
1933
1984
  logger.debug "Parsed receiver : #{wn_recv} / wtype: #{wn_recv.wtype}"
1934
1985
 
1935
- # Invoke method call
1986
+ # Generate method call code
1936
1987
  wn_op = @wgenerator.send_method(wnode, wn_recv.wtype.class_path, method_name, :instance)
1937
1988
 
1938
1989
  # reparent the receiver wnode(s) to operator wnode
1939
1990
  wn_phony.reparent_children_to(wn_op)
1940
1991
  wnode.remove_child(wn_phony)
1941
1992
 
1942
- # 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
1943
1995
  arg_nodes = node.children[2..-1]
1944
1996
  wn_args = arg_nodes.collect do |n|
1945
1997
  logger.debug "...with arg #{n}"
1946
1998
  parse_node(n, wn_op, true)
1947
1999
  end
1948
2000
 
1949
- # now cast operands (will do nothing if it's a method call)
2001
+ # now process operands (e.g. cast them if needed)
1950
2002
  @wgenerator.operands(wn_op, wn_recv, wn_args)
1951
2003
  logger.debug "After operands, call wnode: #{wn_op} wtype: #{wn_op.wtype}, wn_op children types: #{wn_op.children.map(&:wtype)}"
1952
2004
 
@@ -1961,14 +2013,14 @@ module Rlang::Parser
1961
2013
  types = {}
1962
2014
  # Is this a hash Node ?
1963
2015
  unless hash_node.respond_to?(:type) && hash_node.type == :hash
1964
- raise "#{entity} expects a hash argument (got #{hash_node}" \
2016
+ rlse hash_node, "#{entity} expects a hash argument (got #{hash_node}" \
1965
2017
  end
1966
2018
  logger.debug "#{entity} hash node: #{hash_node}"
1967
2019
  hash_node.children.each do |pair_node|
1968
2020
  name_node, type_node = pair_node.children
1969
- 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})" \
1970
2022
  unless name_node.type == :sym
1971
- 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})" \
1972
2024
  unless type_node.type == :sym
1973
2025
  name = name_node.children.last
1974
2026
  type = type_node.children.last
@@ -1992,7 +2044,7 @@ module Rlang::Parser
1992
2044
  # TODO: not sure this is the right thing to do. Double check
1993
2045
  logger.debug "self in class definition scope. Nothing to do."
1994
2046
  else
1995
- raise "Don't know what self means in this context: #{wnode.head}"
2047
+ rlse node, "Don't know what self means in this context: #{wnode.head}"
1996
2048
  end
1997
2049
  wn
1998
2050
  end
@@ -2011,27 +2063,27 @@ module Rlang::Parser
2011
2063
  logger.debug "in send: recv_node #{recv_node}, method_name #{method_name}"
2012
2064
  case method_name
2013
2065
  when :to_I64
2014
- 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}" \
2015
2067
  unless recv_node.type == :int
2016
2068
  value = recv_node.children.last
2017
2069
  DAta.append(label, value, Type::I64)
2018
2070
  when :[]
2019
- raise "Initializer can only be a Data address (got #{node})" \
2071
+ rlse node, "Initializer can only be a Data address (got #{node})" \
2020
2072
  unless recv_node.children.last == :DAta
2021
- raise "Initializer expects a symbol (got #{arg_node})" \
2073
+ rlse node, "Initializer expects a symbol (got #{arg_node})" \
2022
2074
  unless arg_node.type == :sym
2023
2075
  DAta.append(label, DAta[arg_node.children.last])
2024
2076
  else
2025
- raise "Unknow data initializer #{node}"
2077
+ rlse node, "Unknow data initializer #{node}"
2026
2078
  end
2027
2079
  else
2028
- raise "Unknow data initializer #{node}"
2080
+ rlse node, "Unknow data initializer #{node}"
2029
2081
  end
2030
2082
  end
2031
2083
 
2032
2084
  def parse_return(node, wnode, keep_eval)
2033
2085
  ret_count = node.children.count
2034
- 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
2035
2087
  exp_node = node.children.first
2036
2088
  wn_ret = @wgenerator.return(wnode)
2037
2089
  if exp_node
@@ -2141,7 +2193,7 @@ module Rlang::Parser
2141
2193
  parse_node(else_node, wn_else, keep_eval)
2142
2194
  wn_else.wtype = wn_else.children.last.wtype
2143
2195
  if wn_then.wtype != wn_else.wtype
2144
- 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}"
2145
2197
  end
2146
2198
  else
2147
2199
  # if the else clause doesn't exist in Ruby we still
@@ -2243,7 +2295,7 @@ module Rlang::Parser
2243
2295
  logger.debug "Building constant path..."
2244
2296
  const_path = []; n = node
2245
2297
  while n
2246
- raise "expecting a const node (got #{n})" unless n.type == :const
2298
+ rlse node, "expecting a const node (got #{n})" unless n.type == :const
2247
2299
  logger.debug "adding #{n.children.last} to constant path"
2248
2300
  const_path.unshift(n.children.last)
2249
2301
  n = n.children.first