rlang 0.3.1 → 0.4.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.
@@ -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