rlang 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+ # Rubinius WebAssembly VM
2
+ # Copyright (c) 2019, Laurent Julliard and contributors
3
+ # All rights reserved.
4
+ #
5
+ # Turns an RLang source file into a Wasm text
6
+ # code file (WAT)
7
+ require_relative '../../utils/log'
8
+ require_relative '../ext/tempfile'
9
+ require_relative '../../rlang/parser'
10
+
11
+ module Builder::Rlang
12
+ class Compiler
13
+ include Log
14
+
15
+ attr_reader :target
16
+
17
+ # WAT source frame
18
+ WAT_FRAME = %q{
19
+ ;; Generated by Rlang compiler version %{version} on %{time}\n"
20
+ (module %{module}
21
+ (memory $0 %{memory_min} %{memory_max})
22
+
23
+ ;; ======= EXPORTS =======
24
+ (export "memory" (memory $0))
25
+ %{exports}
26
+
27
+ ;; ======= GLOBAL VARIABLES =======
28
+ %{globals}
29
+
30
+ ;; ======= STATIC DATA =======
31
+ %{data}
32
+
33
+ ;; ======= CODE =======
34
+ %{code}
35
+ )
36
+ }
37
+
38
+ # source: Path to Rlang file (.rb)
39
+ # target: Path to Wat file (.wat)
40
+ # options: Rlang parser options (parser.config)
41
+ def initialize(source, target, options={})
42
+ @source = source # Path to Rlang file (.rb)
43
+ @target = target # Path to Wat file (.wat)
44
+ @options = options # Rlang parser options (parser.config)
45
+ @temp_target = target.nil?
46
+ # Initialize parser and WAT code generator
47
+ @parser = Rlang::Parser::Parser.new(nil, @options)
48
+ @wgenerator = Rlang::Parser::WGenerator.new(@parser)
49
+ @parser.wgenerator = @wgenerator
50
+ end
51
+
52
+ # return true if everything went well, false otherwise
53
+ def compile
54
+ @parser.parse_file(@source)
55
+ # Write generated WAT code in a temp file if
56
+ # target file not given
57
+ # Do not delete temp file when closing
58
+ if @target
59
+ @tf = File.open(@target, 'r')
60
+ else
61
+ @tf = Tempfile.new([File.basename(@source), '.wat'])
62
+ @tf.persist!
63
+ @target = @tf.path
64
+ end
65
+ @tf.write(WAT_FRAME % {version: Rlang::VERSION,
66
+ time: Time.now,
67
+ module: @options[:module],
68
+ memory_min: @options[:memory_min],
69
+ memory_max: @options[:memory_max],
70
+ exports: Rlang::Parser::Export.transpile,
71
+ globals: Rlang::Parser::Global.transpile,
72
+ data: Rlang::Parser::DAta.transpile,
73
+ code: @wgenerator.root.transpile
74
+ })
75
+ @tf.close
76
+ true
77
+ end
78
+
79
+ def cleanup
80
+ File.unlink(@tf.path) if @temp_target
81
+ end
82
+ end
83
+ end
@@ -2,25 +2,29 @@
2
2
  # Copyright (c) 2019, Laurent Julliard and contributors
3
3
  # All rights reserved.
4
4
 
5
+ require_relative '../../utils/log'
5
6
  require_relative '../ext/tempfile'
7
+ require_relative './renderer'
6
8
 
7
9
  module Builder::Wat
8
10
  class Builder
11
+ include Log
9
12
 
10
13
  @@wat_compiler = 'wat2wasm'
11
14
 
12
15
  attr_reader :target, :source
13
16
 
14
- def initialize(source, target, include_paths = nil)
17
+ def initialize(source, target)
15
18
  check_compiler
16
19
  @source = source
17
- @target = target
18
- @include_paths = include_paths || ['.', File.expand_path('../../machine', source)]
19
- if File.extname(source) == '.erb'
20
- @wat_path = self.assemble
20
+ if target
21
+ @target = target
21
22
  else
22
- @wat_path = source
23
+ @target = @source.gsub(/\.wat$/,'.wasm')
24
+ @temp_target = true
23
25
  end
26
+ logger.debug "Wat Builder Source: #{@source}"
27
+ logger.debug "Wat Builder Target: #{@target}"
24
28
  end
25
29
 
26
30
  def check_compiler
@@ -29,24 +33,11 @@ module Builder::Wat
29
33
  end
30
34
 
31
35
  def compile
32
- @target ||= @wat_path.gsub(/\.wat$/,'.wasm')
33
- %x{ #{@@wat_compiler} #{@wat_path} -o #{@target} }
34
- @target
36
+ system("#{@@wat_compiler} #{@source} -o #{@target}")
35
37
  end
36
38
 
37
39
  def cleanup
38
- File.unlink(@wat_path) unless @wat_path == @source
39
- end
40
-
41
- # Create a tempfile with .wat extension from
42
- # an erb template
43
- def assemble
44
- renderer = Renderer.new(@include_paths)
45
- tf = Tempfile.new([File.basename(@source), '.wat'])
46
- tf.persist! # do not delete tempfile if inspection needed
47
- tf.write(renderer.render(@source))
48
- tf.close
49
- tf.path
40
+ File.unlink(@target) if @temp_target
50
41
  end
51
42
  end
52
43
  end
@@ -3,7 +3,7 @@
3
3
  # All rights reserved.
4
4
 
5
5
  # Rlang standard library
6
-
6
+ require_relative './lib/object'
7
7
  require_relative './lib/type'
8
8
  require_relative './lib/memory'
9
9
  require_relative './lib/unistd'
@@ -11,23 +11,6 @@
11
11
  require 'rlang/lib/memory'
12
12
  require 'rlang/lib/unistd'
13
13
 
14
- # These 3 global variables below are used by the
15
- # dynamic memory allocator. They must however be
16
- # defined in the end applications.
17
-
18
- # Heap base address (make sure it's aligned on
19
- # an address compatible with the most restrictive data type
20
- # used in WASM (I64). So make this address a multiple of 8
21
- # $HEAP = 10024
22
-
23
- # Maximum amount of memory the heap can grow
24
- # NOTE: must be less than the upper WASM memory limit (4GB)
25
- # $HEAP_MAX_SIZE = 1073741824 # 1GB
26
-
27
- # Current heap size (starts at 0, the first malloc will
28
- # set it up)
29
- # $HEAP_SIZE = 0
30
-
31
14
  # minimum number of units to request
32
15
  $NALLOC = 1024
33
16
 
@@ -75,7 +58,7 @@ class Malloc
75
58
  # allocate memory by chunk of units (the unit is
76
59
  # the size of a Header object here)
77
60
  # units = (nbytes+sizeof(Header)-1)/sizeof(Header) + 1;
78
- nunits = (nbytes + Header.size - 1) / Header.size + 1
61
+ nunits = (nbytes + Header._size_ - 1) / Header._size_ + 1
79
62
 
80
63
  # No free list yet. Initialize it.
81
64
  if (prevp = @@freep) == 0
@@ -126,7 +109,7 @@ class Malloc
126
109
  local up: :Header
127
110
 
128
111
  nu = $NALLOC if nu < $NALLOC
129
- cp = Unistd::sbrk(nu * Header.size)
112
+ cp = Unistd::sbrk(nu * Header._size_)
130
113
  return 0 if cp == -1 # no space at all
131
114
 
132
115
  up = cp.cast_to(:Header)
@@ -137,9 +120,16 @@ class Malloc
137
120
 
138
121
  # Free memory block
139
122
  def self.free(ap)
123
+ arg ap: :I32
140
124
  result :none
141
125
  local bp: :Header, p: :Header
142
126
 
127
+ # NULL is a special value used for
128
+ # all Rlag object instances that doesn't
129
+ # have any instance variables and therefore
130
+ # doesn't use any memory
131
+ return if ap == 0
132
+
143
133
  bp = ap.cast_to(:Header) - 1 # point to block header
144
134
  p = @@freep
145
135
  while !(bp > p && bp < p.ptr)
@@ -0,0 +1,16 @@
1
+ require_relative './malloc'
2
+
3
+ class Object
4
+ # don't use allocate as a name to avoid
5
+ # colliding with Ruby native method in
6
+ # Rlang simulator
7
+ def self.alloc(nbytes)
8
+ result :I32
9
+ Malloc.malloc(nbytes)
10
+ end
11
+
12
+ def self.free(object_ptr)
13
+ result :none
14
+ Malloc.free(object_ptr)
15
+ end
16
+ end
@@ -7,7 +7,29 @@
7
7
  # sbrk(n) returns the address of the allocated block or -1 if it failed
8
8
  # srbk(0) returns the current value of the break
9
9
  # Note: in WASM we can only grow linear memory by pages (64 KB block)
10
+
11
+
12
+ # These 3 global variables below are used by the
13
+ # dynamic memory allocator. You can redefine them
14
+ # in your own module
15
+
16
+ # Heap base address (make sure it's aligned on
17
+ # an address compatible with the most restrictive data type
18
+ # used in WASM (I64). So make this address a multiple of 8
19
+ $HEAP = 1024
20
+
21
+ # Maximum amount of memory the heap can grow
22
+ # NOTE: must be less than the upper WASM memory limit (4GB)
23
+ $HEAP_MAX_SIZE = 1073741824 # 1GB
24
+
25
+ # Current heap size (starts at 0, the first malloc will
26
+ # set it up)
27
+ $HEAP_SIZE = 0
28
+
10
29
  class Unistd
30
+ result :Memory, :grow, :I32
31
+ result :Memory, :size, :I32
32
+
11
33
  def self.sbrk(n)
12
34
  # local variables used. All default type
13
35
  # wasm_mem_size: current wasm memory size (in bytes)
@@ -16,6 +16,7 @@ require_relative '../utils/log'
16
16
  require_relative './parser/wtype'
17
17
  require_relative './parser/wtree'
18
18
  require_relative './parser/wnode'
19
+ require_relative './parser/ivar'
19
20
  require_relative './parser/cvar'
20
21
  require_relative './parser/lvar'
21
22
  require_relative './parser/marg'
@@ -49,18 +50,32 @@ module Rlang::Parser
49
50
 
50
51
  attr_accessor :wgenerator, :source, :config
51
52
 
52
- def initialize(wgenerator)
53
+ def initialize(wgenerator, options={})
53
54
  @wgenerator = wgenerator
54
55
  # LIFO of parsed files (stacked by require)
55
56
  @requires = []
56
- config_init
57
+ config_init(options)
58
+ logger.level = Kernel.const_get("Logger::#{@config[:log_level].upcase}")
59
+ logger.formatter = proc do |severity, datetime, progname, msg|
60
+ loc = caller_locations[3] # skip over the logger call itself
61
+ "#{severity[0]}: #{File.basename(loc.path)}:#{loc.lineno}##{loc.label} > #{msg}\n"
62
+ end
63
+ # reset all persistent objects
64
+ # TODO: change the design so those objects are
65
+ # stored with the parser instance and not in a
66
+ # class variable
67
+ Global.reset!
68
+ Export.reset!
69
+ DAta.reset!
57
70
  end
58
71
 
59
- def config_init
72
+ def config_init(options)
60
73
  @config = {}
61
74
  @config[:LOADED_FEATURES] = []
62
- @config[:LOAD_PATH] = ''
75
+ @config[:LOAD_PATH] = []
63
76
  @config[:__FILE__] = ''
77
+ @config[:log_level] = 'FATAL'
78
+ @config.merge!(options)
64
79
  end
65
80
 
66
81
  # Note : this method can be called recursively
@@ -91,9 +106,9 @@ module Rlang::Parser
91
106
  end
92
107
  end
93
108
 
94
- def parse(source)
109
+ def parse(source, wnode=nil)
95
110
  ast = ::Parser::CurrentRuby.parse(source)
96
- parse_node(ast, @wgenerator.root) if ast
111
+ parse_node(ast, wnode || @wgenerator.root) if ast
97
112
  end
98
113
 
99
114
  # Parse Ruby AST node and generate WAT
@@ -125,6 +140,9 @@ module Rlang::Parser
125
140
  when :casgn
126
141
  wn = parse_casgn(node, wnode, keep_eval)
127
142
 
143
+ when :ivasgn
144
+ wn = parse_ivasgn(node, wnode, keep_eval)
145
+
128
146
  when :cvasgn
129
147
  wn = parse_cvasgn(node, wnode, keep_eval)
130
148
 
@@ -140,8 +158,8 @@ module Rlang::Parser
140
158
  when :lvar
141
159
  wn = parse_lvar(node, wnode, keep_eval)
142
160
 
143
- when :ivar, :ivasgn
144
- raise "Instance variable not supported"
161
+ when :ivar
162
+ wn = parse_ivar(node, wnode, keep_eval)
145
163
 
146
164
  when :cvar
147
165
  wn = parse_cvar(node, wnode, keep_eval)
@@ -237,12 +255,19 @@ module Rlang::Parser
237
255
  raise "expecting a constant for class name (got #{const_node})" \
238
256
  unless const_node.type == :const
239
257
 
258
+ # create the class wnode
240
259
  wn_class = @wgenerator.klass(wnode, const_node.children.last)
260
+
261
+ # Parse the body of the class
241
262
  parse_node(body_node, wn_class) if body_node
242
263
 
243
- # now that we finished parsing the class node
244
- # process the class attributes if any
245
- @wgenerator.attributes(wn_class)
264
+ # We finished parsing the class body so
265
+ # 1) generate the wnodes for the new/initialize function
266
+ # 2) generate the wnodes for accessing attributes
267
+ @wgenerator.def_initialize(wn_class) # generate **BEFORE** new
268
+ @wgenerator.def_new(wn_class)
269
+ @wgenerator.def_wattr(wn_class)
270
+
246
271
  return wn_class
247
272
  end
248
273
 
@@ -270,6 +295,11 @@ module Rlang::Parser
270
295
  # s(:op_asgn,
271
296
  # s(:gvasgn, :$MYGLOBAL), :-, s(:lvar, :nbytes))
272
297
  #
298
+ # Example (instance var)
299
+ # @stack_ptr -= nbytes
300
+ # ---
301
+ # s(:op_asgn,
302
+ # s(:ivasgn, :@stack_ptr), :-, s(:lvar, :nbytes))
273
303
  #
274
304
  # Example (setter/getter)
275
305
  # p.size -= nunits
@@ -344,6 +374,44 @@ module Rlang::Parser
344
374
  # Create the var getter node as a child of operator node
345
375
  wn_var_get = @wgenerator.lvar(wn_op, lvar)
346
376
 
377
+ # Instance variable case
378
+ # Example (instance var)
379
+ # @stack_ptr -= nbytes
380
+ # ---
381
+ # s(:op_asgn,
382
+ # s(:ivasgn, :@stack_ptr), :-, s(:lvar, :nbytes))
383
+ when :ivasgn
384
+ var_asgn_node, op, exp_node = *node.children
385
+ var_name = var_asgn_node.children.last
386
+
387
+ # To op_asgn to work, ivar must already be declared
388
+ wattr = wnode.find_ivar(var_name)
389
+ raise "Unknown instance variable #{var_name}" unless wattr
390
+
391
+ # Instance variable op_asgn case is actually like
392
+ # the getter/setter case below where the receiver
393
+ # wnode is self
394
+ wn_recv = parse_self(node, wnode)
395
+
396
+ # Create the top level variable setter node
397
+ wn_var_set = @wgenerator.ivasgn(wnode, wn_recv, wattr)
398
+
399
+ # Second argument of the setter is the operator wnode
400
+ # Create it with wtype :none for now. We'll fix that
401
+ # with the operands call later on
402
+ wn_op = @wgenerator.operator(wn_var_set, op)
403
+
404
+ # now create the getter node as the first child of the
405
+ # operator
406
+ wn_var_get = @wgenerator.ivar(wnode, wn_recv, wattr)
407
+
408
+ # If the setter returns something and last evaluated value
409
+ # must be ignored then drop it
410
+ unless keep_eval && !wn_var_set.wtype.blank?
411
+ @wgenerator.drop(wnode)
412
+ #@wgenerator.call(wnode, wn_recv.wtype.name, "#{method_name}", :instance)
413
+ end
414
+
347
415
  # setter/getter case
348
416
  # Example (setter/getter)
349
417
  # p.size -= nunits
@@ -360,13 +428,13 @@ module Rlang::Parser
360
428
  # above to get its wtype
361
429
  # Force keep_eval to true whatever upper level
362
430
  # keep_eval says
363
- wn_recv_node = parse_node(recv_node, wnode, true)
431
+ wn_recv = parse_node(recv_node, wnode, true)
364
432
 
365
433
  # Create the top level setter call
366
- wn_var_set = @wgenerator.call(wnode, wn_recv_node.wtype.name, "#{method_name}=", :instance)
434
+ wn_var_set = @wgenerator.call(wnode, wn_recv.wtype.name, "#{method_name}=", :instance)
367
435
 
368
436
  # First argument of the setter must be the recv_node
369
- wn_recv_node.reparent_to(wn_var_set)
437
+ wn_recv.reparent_to(wn_var_set)
370
438
 
371
439
  # Second argument of the setter is the operator wnode
372
440
  # Create it with wtype :none for now. We'll fix that
@@ -384,7 +452,7 @@ module Rlang::Parser
384
452
  # must be ignored then drop it
385
453
  unless keep_eval && !wn_var_set.wtype.blank?
386
454
  @wgenerator.drop(wnode)
387
- #@wgenerator.call(wnode, wn_recv_node.wtype.name, "#{method_name}", :instance)
455
+ #@wgenerator.call(wnode, wn_recv.wtype.name, "#{method_name}", :instance)
388
456
  end
389
457
  else
390
458
  raise "op_asgn not supported for #{node.children.first}"
@@ -472,7 +540,6 @@ module Rlang::Parser
472
540
  else
473
541
  # If we are at root or in class scope
474
542
  # then it is a global variable initialization
475
- raise "Global #{gv_name} already declared" if gvar
476
543
  raise "Global op_asgn can only happen in method scope" unless exp_node
477
544
  # In the class or root scope
478
545
  # it can only be a Global var **declaration**
@@ -486,12 +553,61 @@ module Rlang::Parser
486
553
  raise "Global initializer can only be a straight number" \
487
554
  unless wn_exp.const?
488
555
  wnode.remove_child(wn_exp)
489
- gvar = Global.new(gv_name, wn_exp.wtype, wn_exp.wargs[:value])
556
+ if gvar
557
+ gvar.value = wn_exp.wargs[:value]
558
+ else
559
+ gvar = Global.new(gv_name, wn_exp.wtype, wn_exp.wargs[:value])
560
+ end
490
561
  # Do not export global for now
491
562
  #gvar.export! if self.config[:export_all]
492
563
  end
493
564
  end
494
565
 
566
+
567
+ # Example
568
+ # @stack_ptr = 10 + nbytes
569
+ # ---
570
+ # s(:ivasgn, :@stack_ptr, s(:send, s(:int, 10), :+, s(:lvar, :nbytes)))
571
+ def parse_ivasgn(node, wnode, keep_eval)
572
+ iv_name, exp_node = *node.children
573
+
574
+ raise "Instance variable #{iv_name} can only be used in method scope" \
575
+ unless wnode.in_method_scope?
576
+
577
+ unless (wattr = wnode.find_ivar(iv_name))
578
+ # first ivar occurence, create it
579
+ wattr = wnode.create_ivar(iv_name)
580
+ new_ivar = true
581
+ end
582
+
583
+ # ivar assignment is like calling the corresponding
584
+ # setter on self. So create self wnode first
585
+ wn_recv = parse_self(node, wnode)
586
+ wn_ivasgn = @wgenerator.ivasgn(wnode, wn_recv, wattr)
587
+
588
+ # Second argument is the expression
589
+ wn_exp = parse_node(exp_node, wn_ivasgn)
590
+
591
+ if new_ivar
592
+ # type cast the wattr and its ivar to the wtype
593
+ # of the expression as this its first occurence
594
+ logger.debug "Setting new ivar #{wattr.name} wtype to #{wn_exp.wtype.name}"
595
+ wattr.wtype = wn_exp.wtype
596
+ else
597
+ # if ivar already exists then type cast the
598
+ # expression to the wtype of the existing ivar
599
+ logger.debug "Casting exp. wtype #{wn_exp.wtype} to existing ivar #{wattr.name} wtype #{wattr.wtype}"
600
+ @wgenerator.cast(wn_exp, wattr.wtype, false)
601
+ end
602
+
603
+ # If the setter returns something and last evaluated value
604
+ # must be ignored then drop it
605
+ unless keep_eval && !wn_ivasgn.wtype.blank?
606
+ @wgenerator.drop(wnode)
607
+ end
608
+ return wn_ivasgn
609
+ end
610
+
495
611
  # Example
496
612
  # @@stack_ptr = 10 + nbytes
497
613
  # ---
@@ -602,6 +718,25 @@ module Rlang::Parser
602
718
  return wn_gvar
603
719
  end
604
720
 
721
+ # Example
722
+ # ... @stack_ptr
723
+ # ---
724
+ # ... s(:ivar, :@stack_ptr)
725
+ def parse_ivar(node, wnode, keep_eval)
726
+ raise "Instance variable can only be accessed in method scope" \
727
+ unless wnode.in_method_scope?
728
+ iv_name, = *node.children
729
+ if (wattr = wnode.find_ivar(iv_name))
730
+ wn_recv = parse_self(node, wnode)
731
+ wn_ivar = @wgenerator.ivar(wnode, wn_recv, wattr)
732
+ else
733
+ raise "unknown instance variable #{cv_name}"
734
+ end
735
+ # Drop last evaluated result if asked to
736
+ @wgenerator.drop(wnode) unless keep_eval
737
+ return wn_ivar
738
+ end
739
+
605
740
  # Example
606
741
  # ... @@stack_ptr
607
742
  # ---
@@ -730,9 +865,9 @@ module Rlang::Parser
730
865
  logger.debug "recv_node: #{recv_node}\nmethod_name: #{method_name}"
731
866
 
732
867
  # create corresponding func node
733
- method = wnode.find_or_create_method(method_name, nil, :class)
868
+ method = wnode.find_or_create_method(method_name, nil, nil, :class)
734
869
  method.export! if (@@export || self.config[:export_all])
735
- logger.debug "Method object : #{method.inspect}"
870
+ logger.debug "Method object : #{method}"
736
871
  wn_method = @wgenerator.class_method(wnode, method)
737
872
  # collect method arguments
738
873
  parse_args(arg_nodes, wn_method)
@@ -778,11 +913,10 @@ module Rlang::Parser
778
913
  logger.debug "method_name: #{method_name}"
779
914
 
780
915
  # create corresponding func node
781
- method = wnode.find_or_create_method(method_name, nil, :instance)
916
+ method = wnode.find_or_create_method(method_name, nil, nil, :instance)
782
917
  method.export! if (@@export || self.config[:export_all])
783
- logger.debug "Method object : #{method.inspect}"
918
+ logger.debug "Method object : #{method}"
784
919
  wn_method = @wgenerator.instance_method(wnode, method)
785
- # add a receiver argument
786
920
 
787
921
  # collect method arguments
788
922
  parse_args(arg_nodes, wn_method)
@@ -821,7 +955,10 @@ module Rlang::Parser
821
955
  logger.debug "Absolute path detected"
822
956
  extensions.each do |ext|
823
957
  full_path_file = file+ext
824
- break if File.file?(full_path_file)
958
+ if File.file?(full_path_file)
959
+ logger.debug "Found required file: #{full_path_file}"
960
+ break
961
+ end
825
962
  end
826
963
  else
827
964
  case file
@@ -1219,13 +1356,18 @@ module Rlang::Parser
1219
1356
  raise "result directive expects a symbol argument (got #{result_type})" \
1220
1357
  unless result_type.is_a? Symbol
1221
1358
  wnode.method_wnode.wtype = WType.new(result_type)
1222
- logger.debug "result_type #{result_type} updated for method #{wnode.method_wnode.method.inspect}"
1359
+ logger.debug "result_type #{result_type} updated for method #{wnode.method_wnode.method}"
1223
1360
  elsif wnode.in_class_scope?
1224
1361
  cn_name, = *node.children[2]
1225
1362
  mn_name, = *node.children[3]
1226
1363
  result_type, = *node.children[4]
1364
+ raise "result directive expects a symbol argument (got #{result_type}) in node #{node}" \
1365
+ unless result_type.is_a? Symbol
1366
+ # Create class and method objects as we known we'll
1367
+ # be calling them later on
1368
+ WNode.root.find_or_create_class(cn_name)
1227
1369
  method_type = (mn_name[0] == '#' ? :instance : :class)
1228
- (mwn = wnode.find_or_create_method(mn_name, cn_name, method_type)).wtype = WType.new(result_type)
1370
+ (mwn = wnode.find_or_create_method(mn_name, cn_name, nil, method_type)).wtype = WType.new(result_type)
1229
1371
  logger.debug "result_type #{mwn.wtype} for method #{mwn.name}"
1230
1372
  else
1231
1373
  raise "result declaration not supported #{wn.scope} scope"
@@ -1286,7 +1428,8 @@ module Rlang::Parser
1286
1428
  wattr_types.each do |name, wtype|
1287
1429
  if (wattr = wnode.find_wattr(name))
1288
1430
  logger.debug "Setting wattr #{name} type to #{wtype}"
1289
- wattr.wtype = WType.new(wtype)
1431
+ # TODO find a way to update both wtype at once
1432
+ wattr.wtype = wattr.ivar.wtype = WType.new(wtype)
1290
1433
  else
1291
1434
  raise "Unknown class attribute #{name} in #{wnode}"
1292
1435
  end
@@ -1504,14 +1647,12 @@ module Rlang::Parser
1504
1647
  raise "Can only call method class on self or class objects (got #{recv_node} in node #{node})"
1505
1648
  end
1506
1649
  logger.debug "...#{class_name}::#{method_name}"
1507
- if method_name == :new
1508
- raise "Cannot instantiate object in scope #{wnode.scope} on #{node}" \
1509
- unless wnode.in_class_scope?
1650
+ if method_name == :new && wnode.in_class_scope?
1510
1651
  # This is class object instantiation. Statically
1511
1652
  # allocated though. So it can only happen in the
1512
1653
  # class scope for a class variable or a constant
1513
1654
  # Returns a wnode with a i32.const containing the address
1514
- wn_addr = @wgenerator.new(wnode, class_name)
1655
+ wn_addr = @wgenerator.static_new(wnode, class_name)
1515
1656
  return wn_addr
1516
1657
  else
1517
1658
  wn_call = @wgenerator.call(wnode, class_name, method_name, :class)
@@ -1578,14 +1719,16 @@ module Rlang::Parser
1578
1719
  # when sis an object instance (not a class instance)
1579
1720
  def parse_self(node, wnode)
1580
1721
  if wnode.in_instance_method_scope?
1581
- wn = @wgenerator._self(wnode)
1722
+ wn = @wgenerator._self_(wnode)
1582
1723
  logger.debug "self in instance method scope"
1583
1724
  elsif wnode.in_class_method_scope?
1584
1725
  # Nothing to do just return nil
1585
- logger.debug "self in class method scope"
1726
+ # TODO: not sure this is the right thing to do. Double check
1727
+ logger.debug "self in class method scope. Nothing to do."
1586
1728
  elsif wnode.in_class_scope?
1587
1729
  # Nothing to do just return nil
1588
- logger.debug "self in class definition scope"
1730
+ # TODO: not sure this is the right thing to do. Double check
1731
+ logger.debug "self in class definition scope. Nothing to do."
1589
1732
  else
1590
1733
  raise "Don't know what self means in this context: #{wnode}"
1591
1734
  end