rlang 0.5.1 → 0.6.0

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