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.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +10 -0
 - data/Gemfile.lock +3 -5
 - data/README +11 -0
 - data/bin/rlang +4 -0
 - data/docs/RlangCompiler.md +2 -0
 - data/docs/RlangManual.md +37 -8
 - data/lib/rlang/lib/array/array32.rb +13 -4
 - data/lib/rlang/lib/array/array64.rb +11 -3
 - data/lib/rlang/lib/base64.rb +223 -0
 - data/lib/rlang/lib/io.rb +7 -2
 - data/lib/rlang/lib/malloc.rb +5 -3
 - data/lib/rlang/lib/object.rb +23 -0
 - data/lib/rlang/lib/rlang_core.rb +2 -1
 - data/lib/rlang/lib/string.rb +95 -11
 - data/lib/rlang/lib/type/i32.rb +30 -12
 - data/lib/rlang/lib/type/i64.rb +0 -2
 - data/lib/rlang/lib/wasi.rb +57 -6
 - data/lib/rlang/parser/data.rb +5 -0
 - data/lib/rlang/parser/ext/integer.rb +3 -1
 - data/lib/rlang/parser/ext/type.rb +30 -1
 - data/lib/rlang/parser/global.rb +7 -0
 - data/lib/rlang/parser/wgenerator.rb +221 -83
 - data/lib/rlang/parser/wnode.rb +41 -14
 - data/lib/rlang/parser/wtype.rb +12 -6
 - data/lib/rlang/parser.rb +182 -130
 - data/lib/rlang/version.rb +1 -1
 - data/lib/ruby/mirror/rstring.rb +16 -0
 - data/lib/utils/exceptions.rb +12 -0
 - data/rlang.gemspec +4 -4
 - metadata +16 -12
 
| 
         @@ -22,26 +22,29 @@ module Rlang::Parser 
     | 
|
| 
       22 
22 
     | 
    
         
             
                :+  => :add,
         
     | 
| 
       23 
23 
     | 
    
         
             
                :-  => :sub,
         
     | 
| 
       24 
24 
     | 
    
         
             
                :*  => :mul,
         
     | 
| 
       25 
     | 
    
         
            -
                :/  => :div_u,
         
     | 
| 
       26 
     | 
    
         
            -
                :%  => :rem_u,
         
     | 
| 
       27 
25 
     | 
    
         
             
                :&  => :and,
         
     | 
| 
       28 
26 
     | 
    
         
             
                :|  => :or,
         
     | 
| 
       29 
27 
     | 
    
         
             
                :^  => :xor,
         
     | 
| 
       30 
     | 
    
         
            -
                :>> => :shr_u,
         
     | 
| 
       31 
28 
     | 
    
         
             
                :<< => :shl
         
     | 
| 
       32 
29 
     | 
    
         
             
              }
         
     | 
| 
       33 
30 
     | 
    
         | 
| 
      
 31 
     | 
    
         
            +
              ARITHMETIC_SIGNED_OPS_MAP = {
         
     | 
| 
      
 32 
     | 
    
         
            +
                :/  => :div_x,
         
     | 
| 
      
 33 
     | 
    
         
            +
                :%  => :rem_x,
         
     | 
| 
      
 34 
     | 
    
         
            +
                :>> => :shr_x
         
     | 
| 
      
 35 
     | 
    
         
            +
              }
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       34 
37 
     | 
    
         
             
              RELATIONAL_OPS_MAP = {
         
     | 
| 
       35 
38 
     | 
    
         
             
                :==    => :eq,
         
     | 
| 
       36 
39 
     | 
    
         
             
                :!=    => :ne,
         
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                 
     | 
| 
       42 
     | 
    
         
            -
                 
     | 
| 
       43 
     | 
    
         
            -
                 
     | 
| 
       44 
     | 
    
         
            -
                :>=    => : 
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              }
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              RELATIONAL_SIGNED_OPS_MAP = {
         
     | 
| 
      
 44 
     | 
    
         
            +
                :<     => :lt_x,
         
     | 
| 
      
 45 
     | 
    
         
            +
                :>     => :gt_x,
         
     | 
| 
      
 46 
     | 
    
         
            +
                :<=    => :le_x,
         
     | 
| 
      
 47 
     | 
    
         
            +
                :>=    => :ge_x
         
     | 
| 
       45 
48 
     | 
    
         
             
              }
         
     | 
| 
       46 
49 
     | 
    
         | 
| 
       47 
50 
     | 
    
         
             
              BOOLEAN_OPS_MAP = {
         
     | 
| 
         @@ -50,19 +53,40 @@ module Rlang::Parser 
     | 
|
| 
       50 
53 
     | 
    
         
             
              }
         
     | 
| 
       51 
54 
     | 
    
         | 
| 
       52 
55 
     | 
    
         
             
              UNARY_OPS_MAP = {
         
     | 
| 
       53 
     | 
    
         
            -
                :'!'   => :eqz
         
     | 
| 
      
 56 
     | 
    
         
            +
                :'!'   => :eqz,
         
     | 
| 
      
 57 
     | 
    
         
            +
                :'-@'  => :sub  # special case for unary - turned into (sub 0 x)
         
     | 
| 
       54 
58 
     | 
    
         
             
              }
         
     | 
| 
       55 
59 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
               
     | 
| 
      
 60 
     | 
    
         
            +
              SIGNED_OPS = {
         
     | 
| 
      
 61 
     | 
    
         
            +
                signed: {div_x: :div_s, rem_x: :rem_s, shr_x: :shr_s, lt_x: :lt_s, gt_x: :gt_s,
         
     | 
| 
      
 62 
     | 
    
         
            +
                  le_x: :le_s, ge_x: :ge_s},
         
     | 
| 
      
 63 
     | 
    
         
            +
                unsigned: {div_x: :div_u, rem_x: :rem_u, shr_x: :shr_u, lt_x: :lt_u, gt_x: :gt_u,
         
     | 
| 
      
 64 
     | 
    
         
            +
                    le_x: :le_u, ge_x: :ge_u},
         
     | 
| 
      
 65 
     | 
    
         
            +
              }
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              # Operators that can be legally used when doing
         
     | 
| 
      
 68 
     | 
    
         
            +
              # arithmetic on class instance (= object) pointers
         
     | 
| 
      
 69 
     | 
    
         
            +
              # Only unsigned relational operators make sense as pointers
         
     | 
| 
      
 70 
     | 
    
         
            +
              # are by nature unsigned integers
         
     | 
| 
      
 71 
     | 
    
         
            +
              LEGAL_CLASS_WASM_OPS = [:eq, :ne, :lt_u, :gt_u, :le_u, :ge_u, :add, :sub]
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
              # All operators with signed / unsigned variants
         
     | 
| 
      
 74 
     | 
    
         
            +
              ALL_SIGNED_OPS_MAP = [*ARITHMETIC_SIGNED_OPS_MAP, *RELATIONAL_SIGNED_OPS_MAP].to_h
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
              # All operators in on hash
         
     | 
| 
      
 77 
     | 
    
         
            +
              ALL_OPS_MAP = [*ARITHMETIC_OPS_MAP, *ARITHMETIC_SIGNED_OPS_MAP, *RELATIONAL_OPS_MAP, *RELATIONAL_SIGNED_OPS_MAP,
         
     | 
| 
      
 78 
     | 
    
         
            +
                             *BOOLEAN_OPS_MAP, *UNARY_OPS_MAP].to_h
         
     | 
| 
       57 
79 
     | 
    
         | 
| 
       58 
80 
     | 
    
         
             
              # Matrix of how to cast a WASM type to another
         
     | 
| 
       59 
81 
     | 
    
         
             
              CAST_OPS = {
         
     | 
| 
       60 
     | 
    
         
            -
                 
     | 
| 
       61 
     | 
    
         
            -
                 
     | 
| 
       62 
     | 
    
         
            -
                 
     | 
| 
       63 
     | 
    
         
            -
                 
     | 
| 
       64 
     | 
    
         
            -
                 
     | 
| 
       65 
     | 
    
         
            -
                 
     | 
| 
      
 82 
     | 
    
         
            +
                UI32:  { UI32: :cast_nope,   I32: :cast_wtype,  UI64: :cast_extend, I64: :cast_extend, F32: :cast_notyet, F64: :cast_notyet, Class: :cast_wtype, none: :cast_error},
         
     | 
| 
      
 83 
     | 
    
         
            +
                I32:   { UI32: :cast_wtype,  I32: :cast_nope,   UI64: :cast_extend, I64: :cast_extend, F32: :cast_notyet, F64: :cast_notyet, Class: :cast_wtype, none: :cast_error},
         
     | 
| 
      
 84 
     | 
    
         
            +
                UI64:  { UI32: :cast_wrap,   I32: :cast_wrap,   UI64: :cast_nope,   I64: :cast_wtype,  F32: :cast_notyet, F64: :cast_notyet, Class: :cast_error, none: :cast_error},    
         
     | 
| 
      
 85 
     | 
    
         
            +
                I64:   { UI32: :cast_wrap,   I32: :cast_wrap,   UI64: :cast_wtype,   I64: :cast_nope,   F32: :cast_notyet, F64: :cast_notyet, Class: :cast_error, none: :cast_error},    
         
     | 
| 
      
 86 
     | 
    
         
            +
                F32:   { UI32: :cast_notyet, I32: :cast_notyet, UI64: :cast_notyet, I64: :cast_notyet, F32: :cast_nope,   F64: :cast_notyet, Class: :cast_error, none: :cast_error},    
         
     | 
| 
      
 87 
     | 
    
         
            +
                F64:   { UI32: :cast_notyet, I32: :cast_notyet, UI64: :cast_notyet, I64: :cast_notyet, F32: :cast_notyet, F64: :cast_nope,   Class: :cast_error, none: :cast_error},    
         
     | 
| 
      
 88 
     | 
    
         
            +
                Class: { UI32: :cast_wtype,  I32: :cast_wtype,  UI64: :cast_extend, I64: :cast_extend, F32: :cast_error,  F64: :cast_error,  Class: :cast_wtype, none: :cast_error},
         
     | 
| 
      
 89 
     | 
    
         
            +
                none:  { UI32: :cast_error,  I32: :cast_error,  UI64: :cast_error,  I64: :cast_error,  F32: :cast_error,  F64: :cast_error,  Class: :cast_error, none: :cast_error},
         
     | 
| 
       66 
90 
     | 
    
         
             
              }
         
     | 
| 
       67 
91 
     | 
    
         | 
| 
       68 
92 
     | 
    
         
             
              # Rlang class size method name
         
     | 
| 
         @@ -103,6 +127,11 @@ module Rlang::Parser 
     | 
|
| 
       103 
127 
     | 
    
         
             
                String.new(%{ptr}, %{length})
         
     | 
| 
       104 
128 
     | 
    
         
             
              }
         
     | 
| 
       105 
129 
     | 
    
         | 
| 
      
 130 
     | 
    
         
            +
              # Dynamically allocate a string object
         
     | 
| 
      
 131 
     | 
    
         
            +
              ARRAY_NEW_TMPL = %q{
         
     | 
| 
      
 132 
     | 
    
         
            +
                Array%{elt_size_in_bits}.new(%{ptr}, %{length})
         
     | 
| 
      
 133 
     | 
    
         
            +
              }
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
       106 
135 
     | 
    
         
             
              # Generate the wasm nodes and tree structure
         
     | 
| 
       107 
136 
     | 
    
         
             
              # ***IMPORTANT NOTE***
         
     | 
| 
       108 
137 
     | 
    
         
             
              # Unless otherwise stated all methods receive
         
     | 
| 
         @@ -190,6 +219,13 @@ module Rlang::Parser 
     | 
|
| 
       190 
219 
     | 
    
         
             
                  k.wnode
         
     | 
| 
       191 
220 
     | 
    
         
             
                end
         
     | 
| 
       192 
221 
     | 
    
         | 
| 
      
 222 
     | 
    
         
            +
                def comments(wnode, comments)
         
     | 
| 
      
 223 
     | 
    
         
            +
                  # The gsub below is to handle =begin...=end block comments
         
     | 
| 
      
 224 
     | 
    
         
            +
                  comments.each do |c|
         
     | 
| 
      
 225 
     | 
    
         
            +
                    WNode.new(:comment, wnode).c(:comment, text: c.text.sub(/^\s*#/,'').gsub("\n", "\n;;"))
         
     | 
| 
      
 226 
     | 
    
         
            +
                  end
         
     | 
| 
      
 227 
     | 
    
         
            +
                end
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
       193 
229 
     | 
    
         
             
                # Create module object and module wnode 
         
     | 
| 
       194 
230 
     | 
    
         
             
                # if it doesn't exist yet
         
     | 
| 
       195 
231 
     | 
    
         
             
                def module(wnode, module_path)
         
     | 
| 
         @@ -305,9 +341,9 @@ module Rlang::Parser 
     | 
|
| 
       305 
341 
     | 
    
         
             
                  unless size_method.wnode
         
     | 
| 
       306 
342 
     | 
    
         
             
                    logger.debug("Generating #{size_method.klass.name}\##{size_method.name}")
         
     | 
| 
       307 
343 
     | 
    
         
             
                    wns = WNode.new(:insn, wnc)
         
     | 
| 
       308 
     | 
    
         
            -
                    wns.wtype = WType::DEFAULT 
     | 
| 
      
 344 
     | 
    
         
            +
                    wns.wtype = WType::DEFAULT
         
     | 
| 
       309 
345 
     | 
    
         
             
                    wns.c(:class_size, func_name: size_method.wasm_name, 
         
     | 
| 
       310 
     | 
    
         
            -
                           
     | 
| 
      
 346 
     | 
    
         
            +
                          wasm_type: wns.wasm_type, size: wnc.class_size)
         
     | 
| 
       311 
347 
     | 
    
         
             
                    size_method.wnode = wns
         
     | 
| 
       312 
348 
     | 
    
         
             
                  end
         
     | 
| 
       313 
349 
     | 
    
         
             
                end
         
     | 
| 
         @@ -317,7 +353,7 @@ module Rlang::Parser 
     | 
|
| 
       317 
353 
     | 
    
         
             
                  wnc = wnode.class_wnode
         
     | 
| 
       318 
354 
     | 
    
         
             
                  wn_set = WNode.new(:insn, wnc, true)
         
     | 
| 
       319 
355 
     | 
    
         
             
                  wn_set.c(:attr_setter, func_name: attr.setter.wasm_name, 
         
     | 
| 
       320 
     | 
    
         
            -
                        attr_name: attr.wasm_name,  
     | 
| 
      
 356 
     | 
    
         
            +
                        attr_name: attr.wasm_name, wasm_type: attr.wasm_type,
         
     | 
| 
       321 
357 
     | 
    
         
             
                        offset: attr.offset)
         
     | 
| 
       322 
358 
     | 
    
         
             
                  wn_set
         
     | 
| 
       323 
359 
     | 
    
         
             
                end
         
     | 
| 
         @@ -327,8 +363,7 @@ module Rlang::Parser 
     | 
|
| 
       327 
363 
     | 
    
         
             
                  wnc = wnode.class_wnode
         
     | 
| 
       328 
364 
     | 
    
         
             
                  wn_get = WNode.new(:insn, wnc, true)
         
     | 
| 
       329 
365 
     | 
    
         
             
                  wn_get.c(:attr_getter, func_name: attr.getter.wasm_name, 
         
     | 
| 
       330 
     | 
    
         
            -
                         
     | 
| 
       331 
     | 
    
         
            -
                        offset: attr.offset)
         
     | 
| 
      
 366 
     | 
    
         
            +
                        wasm_type: attr.wasm_type, offset: attr.offset)
         
     | 
| 
       332 
367 
     | 
    
         
             
                  wn_get
         
     | 
| 
       333 
368 
     | 
    
         
             
                end
         
     | 
| 
       334 
369 
     | 
    
         | 
| 
         @@ -381,7 +416,7 @@ module Rlang::Parser 
     | 
|
| 
       381 
416 
     | 
    
         
             
                    logger.debug("Prepending param #{marg}")
         
     | 
| 
       382 
417 
     | 
    
         
             
                    wn = WNode.new(:insn, wnm, true)
         
     | 
| 
       383 
418 
     | 
    
         
             
                    wn.wtype = marg.wtype
         
     | 
| 
       384 
     | 
    
         
            -
                    wn.c(:param, name: marg.wasm_name)
         
     | 
| 
      
 419 
     | 
    
         
            +
                    wn.c(:param, name: marg.wasm_name, wasm_type: wn.wasm_type)
         
     | 
| 
       385 
420 
     | 
    
         
             
                  end
         
     | 
| 
       386 
421 
     | 
    
         
             
                end
         
     | 
| 
       387 
422 
     | 
    
         | 
| 
         @@ -389,7 +424,7 @@ module Rlang::Parser 
     | 
|
| 
       389 
424 
     | 
    
         
             
                  unless wnode.wtype.blank?
         
     | 
| 
       390 
425 
     | 
    
         
             
                    wn = WNode.new(:insn, wnode, true)
         
     | 
| 
       391 
426 
     | 
    
         
             
                    wn.wtype = wnode.wtype
         
     | 
| 
       392 
     | 
    
         
            -
                    wn.c(:result)      
         
     | 
| 
      
 427 
     | 
    
         
            +
                    wn.c(:result, wasm_type: wn.wasm_type)      
         
     | 
| 
       393 
428 
     | 
    
         
             
                  end
         
     | 
| 
       394 
429 
     | 
    
         
             
                end
         
     | 
| 
       395 
430 
     | 
    
         | 
| 
         @@ -399,7 +434,7 @@ module Rlang::Parser 
     | 
|
| 
       399 
434 
     | 
    
         
             
                    logger.debug("Prepending local #{lvar.inspect}")
         
     | 
| 
       400 
435 
     | 
    
         
             
                    wn = WNode.new(:insn, wnm, true)
         
     | 
| 
       401 
436 
     | 
    
         
             
                    wn.wtype = lvar.wtype
         
     | 
| 
       402 
     | 
    
         
            -
                    wn.c(:local, name: lvar.wasm_name)
         
     | 
| 
      
 437 
     | 
    
         
            +
                    wn.c(:local, name: lvar.wasm_name, wasm_type: wn.wasm_type)
         
     | 
| 
       403 
438 
     | 
    
         
             
                  end
         
     | 
| 
       404 
439 
     | 
    
         
             
                end
         
     | 
| 
       405 
440 
     | 
    
         | 
| 
         @@ -413,7 +448,7 @@ module Rlang::Parser 
     | 
|
| 
       413 
448 
     | 
    
         
             
                # Set constant
         
     | 
| 
       414 
449 
     | 
    
         
             
                def casgn(wnode, const)
         
     | 
| 
       415 
450 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = const.wtype
         
     | 
| 
       416 
     | 
    
         
            -
                  wn.c(:store,  
     | 
| 
      
 451 
     | 
    
         
            +
                  wn.c(:store, wasm_type: const.wtype)
         
     | 
| 
       417 
452 
     | 
    
         
             
                  WNode.new(:insn, wn).c(:addr, value: const.address)
         
     | 
| 
       418 
453 
     | 
    
         
             
                  wn
         
     | 
| 
       419 
454 
     | 
    
         
             
                end
         
     | 
| 
         @@ -421,7 +456,7 @@ module Rlang::Parser 
     | 
|
| 
       421 
456 
     | 
    
         
             
                # Get constant
         
     | 
| 
       422 
457 
     | 
    
         
             
                def const(wnode, const)
         
     | 
| 
       423 
458 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = const.wtype
         
     | 
| 
       424 
     | 
    
         
            -
                  wn.c(:load,  
     | 
| 
      
 459 
     | 
    
         
            +
                  wn.c(:load, wasm_type: const.wasm_type)
         
     | 
| 
       425 
460 
     | 
    
         
             
                  WNode.new(:insn, wn).c(:addr, value: const.address)
         
     | 
| 
       426 
461 
     | 
    
         
             
                  wn
         
     | 
| 
       427 
462 
     | 
    
         
             
                end
         
     | 
| 
         @@ -468,7 +503,7 @@ module Rlang::Parser 
     | 
|
| 
       468 
503 
     | 
    
         
             
                # Set instance variable
         
     | 
| 
       469 
504 
     | 
    
         
             
                def ivasgn(wnode, ivar)
         
     | 
| 
       470 
505 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = ivar.wtype
         
     | 
| 
       471 
     | 
    
         
            -
                  wn.c(:store_offset,  
     | 
| 
      
 506 
     | 
    
         
            +
                  wn.c(:store_offset, wasm_type: ivar.wasm_type, offset: lambda { ivar.offset })
         
     | 
| 
       472 
507 
     | 
    
         
             
                  self._self_(wn)
         
     | 
| 
       473 
508 
     | 
    
         
             
                  wn
         
     | 
| 
       474 
509 
     | 
    
         
             
                end
         
     | 
| 
         @@ -476,7 +511,7 @@ module Rlang::Parser 
     | 
|
| 
       476 
511 
     | 
    
         
             
                # Get instance variable. 
         
     | 
| 
       477 
512 
     | 
    
         
             
                def ivar(wnode, ivar)
         
     | 
| 
       478 
513 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = ivar.wtype
         
     | 
| 
       479 
     | 
    
         
            -
                  wn.c(:load_offset,  
     | 
| 
      
 514 
     | 
    
         
            +
                  wn.c(:load_offset, wasm_type: ivar.wasm_type, offset: lambda { ivar.offset })
         
     | 
| 
       480 
515 
     | 
    
         
             
                  self._self_(wn)
         
     | 
| 
       481 
516 
     | 
    
         
             
                  wn
         
     | 
| 
       482 
517 
     | 
    
         
             
                end
         
     | 
| 
         @@ -486,7 +521,7 @@ module Rlang::Parser 
     | 
|
| 
       486 
521 
     | 
    
         
             
                # an empty expression node to populate later
         
     | 
| 
       487 
522 
     | 
    
         
             
                def cvasgn(wnode, cvar)
         
     | 
| 
       488 
523 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = cvar.wtype
         
     | 
| 
       489 
     | 
    
         
            -
                  wn.c(:store,  
     | 
| 
      
 524 
     | 
    
         
            +
                  wn.c(:store, wasm_type: cvar.wasm_type)
         
     | 
| 
       490 
525 
     | 
    
         
             
                  WNode.new(:insn, wn).c(:addr, value: cvar.address)
         
     | 
| 
       491 
526 
     | 
    
         
             
                  wn
         
     | 
| 
       492 
527 
     | 
    
         
             
                end
         
     | 
| 
         @@ -494,7 +529,7 @@ module Rlang::Parser 
     | 
|
| 
       494 
529 
     | 
    
         
             
                # Get class variable
         
     | 
| 
       495 
530 
     | 
    
         
             
                def cvar(wnode, cvar)
         
     | 
| 
       496 
531 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = cvar.wtype
         
     | 
| 
       497 
     | 
    
         
            -
                  wn.c(:load,  
     | 
| 
      
 532 
     | 
    
         
            +
                  wn.c(:load, wasm_type: cvar.wasm_type)
         
     | 
| 
       498 
533 
     | 
    
         
             
                  WNode.new(:insn, wn).c(:addr, value: cvar.address)
         
     | 
| 
       499 
534 
     | 
    
         
             
                  wn
         
     | 
| 
       500 
535 
     | 
    
         
             
                end
         
     | 
| 
         @@ -510,14 +545,14 @@ module Rlang::Parser 
     | 
|
| 
       510 
545 
     | 
    
         
             
                # Create the local variable storage node 
         
     | 
| 
       511 
546 
     | 
    
         
             
                def lvasgn(wnode, lvar)
         
     | 
| 
       512 
547 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = lvar.wtype
         
     | 
| 
       513 
     | 
    
         
            -
                  wn.c(:local_set,  
     | 
| 
      
 548 
     | 
    
         
            +
                  wn.c(:local_set, var_name: lvar.wasm_name)
         
     | 
| 
       514 
549 
     | 
    
         
             
                  wn
         
     | 
| 
       515 
550 
     | 
    
         
             
                end
         
     | 
| 
       516 
551 
     | 
    
         | 
| 
       517 
552 
     | 
    
         
             
                # Read local variable
         
     | 
| 
       518 
553 
     | 
    
         
             
                def lvar(wnode, lvar)
         
     | 
| 
       519 
554 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = lvar.wtype
         
     | 
| 
       520 
     | 
    
         
            -
                  wn.c(:local_get,  
     | 
| 
      
 555 
     | 
    
         
            +
                  wn.c(:local_get, var_name: lvar.wasm_name)
         
     | 
| 
       521 
556 
     | 
    
         
             
                  wn
         
     | 
| 
       522 
557 
     | 
    
         
             
                end
         
     | 
| 
       523 
558 
     | 
    
         | 
| 
         @@ -534,13 +569,13 @@ module Rlang::Parser 
     | 
|
| 
       534 
569 
     | 
    
         | 
| 
       535 
570 
     | 
    
         
             
                def int(wnode, wtype, value)
         
     | 
| 
       536 
571 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = wtype
         
     | 
| 
       537 
     | 
    
         
            -
                  wn.c(:const,  
     | 
| 
      
 572 
     | 
    
         
            +
                  wn.c(:const, wasm_type: wn.wasm_type, value: value)
         
     | 
| 
       538 
573 
     | 
    
         
             
                  wn
         
     | 
| 
       539 
574 
     | 
    
         
             
                end
         
     | 
| 
       540 
575 
     | 
    
         | 
| 
       541 
576 
     | 
    
         
             
                def float(wnode, wtype, value)
         
     | 
| 
       542 
577 
     | 
    
         
             
                  (wn = WNode.new(:insn, wnode)).wtype = wtype
         
     | 
| 
       543 
     | 
    
         
            -
                  wn.c(:const,  
     | 
| 
      
 578 
     | 
    
         
            +
                  wn.c(:const, wasm_type: wn.wasm_type, value: value)
         
     | 
| 
       544 
579 
     | 
    
         
             
                  wn
         
     | 
| 
       545 
580 
     | 
    
         
             
                end
         
     | 
| 
       546 
581 
     | 
    
         | 
| 
         @@ -551,24 +586,25 @@ module Rlang::Parser 
     | 
|
| 
       551 
586 
     | 
    
         
             
                  WNode.new(type, wnode)
         
     | 
| 
       552 
587 
     | 
    
         
             
                end
         
     | 
| 
       553 
588 
     | 
    
         | 
| 
       554 
     | 
    
         
            -
                # Static string allocation
         
     | 
| 
       555 
     | 
    
         
            -
                def  
     | 
| 
       556 
     | 
    
         
            -
                  #  
     | 
| 
       557 
     | 
    
         
            -
                   
     | 
| 
       558 
     | 
    
         
            -
                  data_stg = DAta.append(data_label.to_sym, string)
         
     | 
| 
       559 
     | 
    
         
            -
                  data_stg
         
     | 
| 
      
 589 
     | 
    
         
            +
                # Static string data allocation
         
     | 
| 
      
 590 
     | 
    
         
            +
                def allocate_string_static_data(string, data_label)
         
     | 
| 
      
 591 
     | 
    
         
            +
                  # if string is empty do not allocate any memory space
         
     | 
| 
      
 592 
     | 
    
         
            +
                  DAta.append(data_label.to_sym, string) unless string.empty?
         
     | 
| 
       560 
593 
     | 
    
         
             
                end
         
     | 
| 
       561 
594 
     | 
    
         | 
| 
       562 
595 
     | 
    
         
             
                # Static new string object
         
     | 
| 
       563 
596 
     | 
    
         
             
                def string_static_new(wnode, string)
         
     | 
| 
       564 
597 
     | 
    
         
             
                  klass = wnode.find_current_class_or_module()
         
     | 
| 
       565 
598 
     | 
    
         
             
                  data_label = "#{klass.name}_string_#{@static_count += 1}"
         
     | 
| 
       566 
     | 
    
         
            -
                  #  
     | 
| 
       567 
     | 
    
         
            -
                  data_stg  
     | 
| 
      
 599 
     | 
    
         
            +
                  # Allocate string data statically
         
     | 
| 
      
 600 
     | 
    
         
            +
                  # Note : data_stg is nil if string is empty
         
     | 
| 
      
 601 
     | 
    
         
            +
                  data_stg = self.allocate_string_static_data(string, data_label)
         
     | 
| 
       568 
602 
     | 
    
         
             
                  # align on :I32 boundary
         
     | 
| 
      
 603 
     | 
    
         
            +
                  # then allocate the String object attributes
         
     | 
| 
      
 604 
     | 
    
         
            +
                  # and set them up
         
     | 
| 
       569 
605 
     | 
    
         
             
                  DAta.align(4)
         
     | 
| 
       570 
606 
     | 
    
         
             
                  data_len = DAta.append("#{data_label}_len".to_sym, string.length, WType::DEFAULT)
         
     | 
| 
       571 
     | 
    
         
            -
                  data_ptr = DAta.append("#{data_label}_ptr".to_sym, data_stg.address, WType::DEFAULT)
         
     | 
| 
      
 607 
     | 
    
         
            +
                  data_ptr = DAta.append("#{data_label}_ptr".to_sym, data_stg ? data_stg.address : 0, WType::DEFAULT)
         
     | 
| 
       572 
608 
     | 
    
         
             
                  # Generate address wnode
         
     | 
| 
       573 
609 
     | 
    
         
             
                  (wn_object_addr = WNode.new(:insn, wnode)).c(:addr, value: data_len.address)
         
     | 
| 
       574 
610 
     | 
    
         
             
                  wn_object_addr.wtype = WType.new(:String)
         
     | 
| 
         @@ -579,25 +615,73 @@ module Rlang::Parser 
     | 
|
| 
       579 
615 
     | 
    
         
             
                def string_dynamic_new(wnode, string)
         
     | 
| 
       580 
616 
     | 
    
         
             
                  klass = wnode.find_current_class_or_module()
         
     | 
| 
       581 
617 
     | 
    
         
             
                  data_label = "#{klass.name}_string_#{@static_count += 1}"
         
     | 
| 
       582 
     | 
    
         
            -
                  data_stg  
     | 
| 
      
 618 
     | 
    
         
            +
                  # Note : data_stg is nil if string is empty
         
     | 
| 
      
 619 
     | 
    
         
            +
                  data_stg = self.allocate_string_static_data(string, data_label)
         
     | 
| 
       583 
620 
     | 
    
         
             
                  string_new_source = STRING_NEW_TMPL % {
         
     | 
| 
       584 
     | 
    
         
            -
                    ptr: data_stg.address,
         
     | 
| 
      
 621 
     | 
    
         
            +
                    ptr: data_stg ? data_stg.address : 0,
         
     | 
| 
       585 
622 
     | 
    
         
             
                    length: string.length
         
     | 
| 
       586 
623 
     | 
    
         
             
                  }
         
     | 
| 
       587 
624 
     | 
    
         
             
                  #puts string_new_source;exit
         
     | 
| 
       588 
     | 
    
         
            -
                   
     | 
| 
       589 
     | 
    
         
            -
             
     | 
| 
      
 625 
     | 
    
         
            +
                  self.parser.parse(string_new_source, wnode)
         
     | 
| 
      
 626 
     | 
    
         
            +
                end
         
     | 
| 
      
 627 
     | 
    
         
            +
             
     | 
| 
      
 628 
     | 
    
         
            +
                # Static array data allocation
         
     | 
| 
      
 629 
     | 
    
         
            +
                def allocate_array_static_data(array, data_label)
         
     | 
| 
      
 630 
     | 
    
         
            +
                  # Append each array element to the same data section
         
     | 
| 
      
 631 
     | 
    
         
            +
                  label = data_label.to_sym
         
     | 
| 
      
 632 
     | 
    
         
            +
                  data_arr = nil
         
     | 
| 
      
 633 
     | 
    
         
            +
                  # Do not allocate memory space if array is empty
         
     | 
| 
      
 634 
     | 
    
         
            +
                  array.each { |elt| data_arr = DAta.append(label, elt) }
         
     | 
| 
      
 635 
     | 
    
         
            +
                  data_arr
         
     | 
| 
      
 636 
     | 
    
         
            +
                end
         
     | 
| 
      
 637 
     | 
    
         
            +
             
     | 
| 
      
 638 
     | 
    
         
            +
                # Static new array object
         
     | 
| 
      
 639 
     | 
    
         
            +
                def array_static_new(wnode, array)
         
     | 
| 
      
 640 
     | 
    
         
            +
                  klass = wnode.find_current_class_or_module()
         
     | 
| 
      
 641 
     | 
    
         
            +
                  data_label = "#{klass.name}_array_#{@static_count += 1}"
         
     | 
| 
      
 642 
     | 
    
         
            +
                  # Allocate array data statically
         
     | 
| 
      
 643 
     | 
    
         
            +
                  # Note : data_arr is nil if string is empty
         
     | 
| 
      
 644 
     | 
    
         
            +
                  data_arr = self.allocate_array_static_data(array, data_label)
         
     | 
| 
      
 645 
     | 
    
         
            +
                  # align on :I32 boundary
         
     | 
| 
      
 646 
     | 
    
         
            +
                  # then allocate the Array object attributes
         
     | 
| 
      
 647 
     | 
    
         
            +
                  # and set them up
         
     | 
| 
      
 648 
     | 
    
         
            +
                  DAta.align(4)
         
     | 
| 
      
 649 
     | 
    
         
            +
                  data_count = DAta.append("#{data_label}_count".to_sym, array.length, WType::DEFAULT)
         
     | 
| 
      
 650 
     | 
    
         
            +
                  data_ptr   = DAta.append("#{data_label}_ptr".to_sym, data_arr ? data_arr.address : 0, WType::DEFAULT)
         
     | 
| 
      
 651 
     | 
    
         
            +
                  # Generate address wnode
         
     | 
| 
      
 652 
     | 
    
         
            +
                  (wn_object_addr = WNode.new(:insn, wnode)).c(:addr, value: data_count.address)
         
     | 
| 
      
 653 
     | 
    
         
            +
                  wn_object_addr.wtype = WType.new(:Array32)
         
     | 
| 
      
 654 
     | 
    
         
            +
                  wn_object_addr
         
     | 
| 
      
 655 
     | 
    
         
            +
                end
         
     | 
| 
      
 656 
     | 
    
         
            +
             
     | 
| 
      
 657 
     | 
    
         
            +
                # Dynamic new array object
         
     | 
| 
      
 658 
     | 
    
         
            +
                def array_dynamic_new(wnode, array)
         
     | 
| 
      
 659 
     | 
    
         
            +
                  klass = wnode.find_current_class_or_module()
         
     | 
| 
      
 660 
     | 
    
         
            +
                  data_label = "#{klass.name}_array_#{@static_count += 1}"
         
     | 
| 
      
 661 
     | 
    
         
            +
                  # Note : data_arr is nil if string is empty
         
     | 
| 
      
 662 
     | 
    
         
            +
                  data_arr = self.allocate_array_static_data(array, data_label)
         
     | 
| 
      
 663 
     | 
    
         
            +
                  array_new_source = ARRAY_NEW_TMPL % {
         
     | 
| 
      
 664 
     | 
    
         
            +
                    elt_size_in_bits: WTYPE::DEFAULT.size * 8,
         
     | 
| 
      
 665 
     | 
    
         
            +
                    ptr: data_arr ? data_arr.address : 0,
         
     | 
| 
      
 666 
     | 
    
         
            +
                    count: array.length
         
     | 
| 
      
 667 
     | 
    
         
            +
                  }
         
     | 
| 
      
 668 
     | 
    
         
            +
                  #puts array_new_source;exit
         
     | 
| 
      
 669 
     | 
    
         
            +
                  self.parser.parse(array_new_source, wnode)
         
     | 
| 
       590 
670 
     | 
    
         
             
                end
         
     | 
| 
       591 
671 
     | 
    
         | 
| 
      
 672 
     | 
    
         
            +
                # TYPE CASTING methods
         
     | 
| 
       592 
673 
     | 
    
         
             
                # All the cast_xxxx methods below returns
         
     | 
| 
       593 
674 
     | 
    
         
             
                # the new wnode doing the cast operation
         
     | 
| 
       594 
675 
     | 
    
         
             
                # or the same wnode if there is no additional code
         
     | 
| 
       595 
676 
     | 
    
         
             
                # for the cast operation
         
     | 
| 
      
 677 
     | 
    
         
            +
             
     | 
| 
      
 678 
     | 
    
         
            +
                # No casting. Return node as is.
         
     | 
| 
       596 
679 
     | 
    
         
             
                def cast_nope(wnode, wtype, signed)
         
     | 
| 
       597 
     | 
    
         
            -
                  # Do nothing
         
     | 
| 
       598 
680 
     | 
    
         
             
                  wnode
         
     | 
| 
       599 
681 
     | 
    
         
             
                end
         
     | 
| 
       600 
682 
     | 
    
         | 
| 
      
 683 
     | 
    
         
            +
                # Cast by extending to a wtype of larger bit size
         
     | 
| 
      
 684 
     | 
    
         
            +
                # (e.g. I32 to I64)
         
     | 
| 
       601 
685 
     | 
    
         
             
                def cast_extend(wnode, wtype, signed)
         
     | 
| 
       602 
686 
     | 
    
         
             
                  if (wnode.template == :const)
         
     | 
| 
       603 
687 
     | 
    
         
             
                    # it's a WASM const, simply change the wtype
         
     | 
| 
         @@ -606,15 +690,19 @@ module Rlang::Parser 
     | 
|
| 
       606 
690 
     | 
    
         
             
                  else
         
     | 
| 
       607 
691 
     | 
    
         
             
                    wn_cast_op = wnode.insert(:insn)
         
     | 
| 
       608 
692 
     | 
    
         
             
                    wn_cast_op.wtype = wtype
         
     | 
| 
       609 
     | 
    
         
            -
                    wn_cast_op.c(signed ? :extend_i32_s : :extend_i32_u ,  
     | 
| 
      
 693 
     | 
    
         
            +
                    wn_cast_op.c(signed ? :extend_i32_s : :extend_i32_u , wasm_type: wn_cast_op.wasm_type)
         
     | 
| 
       610 
694 
     | 
    
         
             
                  end
         
     | 
| 
       611 
695 
     | 
    
         
             
                  wn_cast_op
         
     | 
| 
       612 
696 
     | 
    
         
             
                end
         
     | 
| 
       613 
697 
     | 
    
         | 
| 
      
 698 
     | 
    
         
            +
                # Cast by simply changing the node wtype
         
     | 
| 
      
 699 
     | 
    
         
            +
                # No change in native WASM type
         
     | 
| 
      
 700 
     | 
    
         
            +
                # (e.g. casting an object pointer to I32)
         
     | 
| 
       614 
701 
     | 
    
         
             
                def cast_wtype(wnode, wtype, signed)
         
     | 
| 
       615 
     | 
    
         
            -
                   
     | 
| 
       616 
     | 
    
         
            -
             
     | 
| 
       617 
     | 
    
         
            -
             
     | 
| 
      
 702 
     | 
    
         
            +
                  # Don't cast blindly. Check that source and target
         
     | 
| 
      
 703 
     | 
    
         
            +
                  # have the same bit size (e.g. Object pointers, I32, UI32
         
     | 
| 
      
 704 
     | 
    
         
            +
                  # are the same size, )
         
     | 
| 
      
 705 
     | 
    
         
            +
                  if wnode.wtype.size == wtype.size
         
     | 
| 
       618 
706 
     | 
    
         
             
                    wnode.wtype = wtype
         
     | 
| 
       619 
707 
     | 
    
         
             
                  else
         
     | 
| 
       620 
708 
     | 
    
         
             
                    cast_error(wnode, wtype, signed)
         
     | 
| 
         @@ -622,6 +710,8 @@ module Rlang::Parser 
     | 
|
| 
       622 
710 
     | 
    
         
             
                  wnode
         
     | 
| 
       623 
711 
     | 
    
         
             
                end
         
     | 
| 
       624 
712 
     | 
    
         | 
| 
      
 713 
     | 
    
         
            +
                # Cast by wraping a wtype to a smaller size
         
     | 
| 
      
 714 
     | 
    
         
            +
                # (e.g. I64 to I32)
         
     | 
| 
       625 
715 
     | 
    
         
             
                def cast_wrap(wnode, wtype, signed)
         
     | 
| 
       626 
716 
     | 
    
         
             
                  if (wnode.template == :const)
         
     | 
| 
       627 
717 
     | 
    
         
             
                    # it's a WASM const, simply change the wtype
         
     | 
| 
         @@ -630,17 +720,19 @@ module Rlang::Parser 
     | 
|
| 
       630 
720 
     | 
    
         
             
                  else
         
     | 
| 
       631 
721 
     | 
    
         
             
                    wn_cast_op = wnode.insert(:insn)
         
     | 
| 
       632 
722 
     | 
    
         
             
                    wn_cast_op.wtype = wtype
         
     | 
| 
       633 
     | 
    
         
            -
                    wn_cast_op.c(:wrap_i64,  
     | 
| 
      
 723 
     | 
    
         
            +
                    wn_cast_op.c(:wrap_i64, wasm_type: wn_cast_op.wasm_type)
         
     | 
| 
       634 
724 
     | 
    
         
             
                  end
         
     | 
| 
       635 
725 
     | 
    
         
             
                  wn_cast_op
         
     | 
| 
       636 
726 
     | 
    
         
             
                end
         
     | 
| 
       637 
727 
     | 
    
         | 
| 
      
 728 
     | 
    
         
            +
                # Cast operation not yet supported
         
     | 
| 
       638 
729 
     | 
    
         
             
                def cast_notyet(wnode, wtype, signed)
         
     | 
| 
       639 
730 
     | 
    
         
             
                  raise "Type cast from #{wnode.wtype} to #{wtype} not supported yet"
         
     | 
| 
       640 
731 
     | 
    
         
             
                end
         
     | 
| 
       641 
732 
     | 
    
         | 
| 
      
 733 
     | 
    
         
            +
                # Cast operation is invalid
         
     | 
| 
       642 
734 
     | 
    
         
             
                def cast_error(wnode, wtype, signed)
         
     | 
| 
       643 
     | 
    
         
            -
                  raise "Cannot cast type #{ 
     | 
| 
      
 735 
     | 
    
         
            +
                  raise "Cannot cast type #{wnode.wtype} to #{wtype}. Time to fix your code :-)"
         
     | 
| 
       644 
736 
     | 
    
         
             
                end
         
     | 
| 
       645 
737 
     | 
    
         | 
| 
       646 
738 
     | 
    
         
             
                # cast an expression to a different type
         
     | 
| 
         @@ -668,17 +760,20 @@ module Rlang::Parser 
     | 
|
| 
       668 
760 
     | 
    
         
             
                # operands below)
         
     | 
| 
       669 
761 
     | 
    
         
             
                def native_operator(wnode, operator, wtype=WType.new(:none))
         
     | 
| 
       670 
762 
     | 
    
         
             
                  if (op = ALL_OPS_MAP[operator])
         
     | 
| 
       671 
     | 
    
         
            -
                    (wn_op = WNode.new(:insn, wnode)). 
     | 
| 
       672 
     | 
    
         
            -
                    wn_op. 
     | 
| 
      
 763 
     | 
    
         
            +
                    (wn_op = WNode.new(:insn, wnode)).wtype = wtype
         
     | 
| 
      
 764 
     | 
    
         
            +
                    wn_op.c(:operator, wasm_type: wn_op.wasm_type, operator: op)
         
     | 
| 
       673 
765 
     | 
    
         
             
                    logger.debug "Creating operator #{operator} wnode: #{wn_op}"
         
     | 
| 
      
 766 
     | 
    
         
            +
                    # special case for - unary operator transformed into (0 - x)
         
     | 
| 
      
 767 
     | 
    
         
            +
                    WNode.new(:insn, wn_op).c(:const, wasm_type: wn_op.wasm_type, value: 0) if operator == :-@
         
     | 
| 
       674 
768 
     | 
    
         
             
                    wn_op
         
     | 
| 
       675 
769 
     | 
    
         
             
                  else
         
     | 
| 
       676 
770 
     | 
    
         
             
                    raise "operator '#{operator}' not supported"
         
     | 
| 
       677 
771 
     | 
    
         
             
                  end
         
     | 
| 
       678 
772 
     | 
    
         
             
                end
         
     | 
| 
       679 
773 
     | 
    
         | 
| 
       680 
     | 
    
         
            -
                #  
     | 
| 
       681 
     | 
    
         
            -
                # attach operands
         
     | 
| 
      
 774 
     | 
    
         
            +
                # Finish the setting of the operator node, 
         
     | 
| 
      
 775 
     | 
    
         
            +
                # attach operands and see if they need implicit
         
     | 
| 
      
 776 
     | 
    
         
            +
                # type casting
         
     | 
| 
       682 
777 
     | 
    
         
             
                def operands(wnode_op, wnode_recv, wnode_args)
         
     | 
| 
       683 
778 
     | 
    
         
             
                  logger.debug "Processing operands in operator wnode: #{wnode_op}..."
         
     | 
| 
       684 
779 
     | 
    
         
             
                  # Do not post process operands if the operator
         
     | 
| 
         @@ -696,26 +791,48 @@ module Rlang::Parser 
     | 
|
| 
       696 
791 
     | 
    
         
             
                  #wnode_recv = wnode_op.children[0]
         
     | 
| 
       697 
792 
     | 
    
         
             
                  #wnode_args = wnode_op.children[1..-1]
         
     | 
| 
       698 
793 
     | 
    
         
             
                  # First find out the wtype that has precedence
         
     | 
| 
       699 
     | 
    
         
            -
                   
     | 
| 
      
 794 
     | 
    
         
            +
                  leading_wtype = self.class.leading_wtype(wnode_recv, *wnode_args)
         
     | 
| 
       700 
795 
     | 
    
         | 
| 
       701 
     | 
    
         
            -
                  wnode_op.wtype =  
     | 
| 
       702 
     | 
    
         
            -
                  logger.debug "leading type cast: #{ 
     | 
| 
      
 796 
     | 
    
         
            +
                  wnode_op.wtype = leading_wtype
         
     | 
| 
      
 797 
     | 
    
         
            +
                  logger.debug "leading type cast: #{leading_wtype}"
         
     | 
| 
       703 
798 
     | 
    
         | 
| 
       704 
799 
     | 
    
         
             
                  # Attach receiver and argument to the operator wnode
         
     | 
| 
       705 
     | 
    
         
            -
                  # type casting them if necessary 
     | 
| 
       706 
     | 
    
         
            -
                   
     | 
| 
       707 
     | 
    
         
            -
                   
     | 
| 
      
 800 
     | 
    
         
            +
                  # type casting them if necessary
         
     | 
| 
      
 801 
     | 
    
         
            +
                  # Note : normally for an operator there is only one argument
         
     | 
| 
      
 802 
     | 
    
         
            +
                  # but process args as if they were many one day.
         
     | 
| 
      
 803 
     | 
    
         
            +
                  logger.debug "Perform implicit type casting of receviver and operator arg(s)"
         
     | 
| 
      
 804 
     | 
    
         
            +
                  self.cast(wnode_recv, leading_wtype).reparent_to(wnode_op)
         
     | 
| 
      
 805 
     | 
    
         
            +
                  wnode_args.each do |wna|
         
     | 
| 
      
 806 
     | 
    
         
            +
                    self.cast(wna, leading_wtype).reparent_to(wnode_op)
         
     | 
| 
      
 807 
     | 
    
         
            +
                  end
         
     | 
| 
      
 808 
     | 
    
         
            +
             
     | 
| 
      
 809 
     | 
    
         
            +
                  # Once operands casting is done, see if we need the signed or unsigned
         
     | 
| 
      
 810 
     | 
    
         
            +
                  # version of the native operator
         
     | 
| 
      
 811 
     | 
    
         
            +
                  # NOTE : At this stage, after the operands casting both of them
         
     | 
| 
      
 812 
     | 
    
         
            +
                  # should either be signed or unsigned, hence the XNOR sanity check
         
     | 
| 
      
 813 
     | 
    
         
            +
                  # below
         
     | 
| 
      
 814 
     | 
    
         
            +
                  if ALL_SIGNED_OPS_MAP.values.include? op
         
     | 
| 
      
 815 
     | 
    
         
            +
                    if !((signed = wnode_recv.wtype.signed?) ^ (wnode_args.empty? ? true : wnode_args.first.wtype.signed?))
         
     | 
| 
      
 816 
     | 
    
         
            +
                      wnode_op.wargs[:operator] = SIGNED_OPS[signed ? :signed : :unsigned][op]
         
     | 
| 
      
 817 
     | 
    
         
            +
                      logger.debug "Receiver has wtype #{wnode_recv.wtype} / Argument has wtype #{wnode_args.first.wtype}"
         
     | 
| 
      
 818 
     | 
    
         
            +
                      logger.debug "Replacing #{op} operator with #{wnode_op.wargs[:operator]}"
         
     | 
| 
      
 819 
     | 
    
         
            +
                      op = wnode_op.wargs[:operator]
         
     | 
| 
      
 820 
     | 
    
         
            +
                    else
         
     | 
| 
      
 821 
     | 
    
         
            +
                      raise "Type mismatch between operands. Receiver is #{wnode_recv.wtype} and argument is #{wnode_args.first.wtype}"
         
     | 
| 
      
 822 
     | 
    
         
            +
                    end
         
     | 
| 
      
 823 
     | 
    
         
            +
                  end
         
     | 
| 
       708 
824 
     | 
    
         | 
| 
       709 
825 
     | 
    
         
             
                  # if the receiver is a class object and not
         
     | 
| 
       710 
826 
     | 
    
         
             
                  # a native integer then pointer arithmetic
         
     | 
| 
       711 
827 
     | 
    
         
             
                  # applies (like in C)
         
     | 
| 
       712 
828 
     | 
    
         
             
                  if wnode_recv.wtype.class?
         
     | 
| 
       713 
     | 
    
         
            -
                     
     | 
| 
       714 
     | 
    
         
            -
             
     | 
| 
       715 
     | 
    
         
            -
             
     | 
| 
       716 
     | 
    
         
            -
                    #  
     | 
| 
       717 
     | 
    
         
            -
                    if [:add, :sub].include?  
     | 
| 
       718 
     | 
    
         
            -
                      (wn_mulop = WNode.new(:insn, wnode_op)). 
     | 
| 
      
 829 
     | 
    
         
            +
                    raise "Only #{LEGAL_CLASS_WASM_OPS.join(', ')} operators are supported on objects (got #{op} in #{wnode_op})" \
         
     | 
| 
      
 830 
     | 
    
         
            +
                      unless LEGAL_CLASS_WASM_OPS.include?(op)
         
     | 
| 
      
 831 
     | 
    
         
            +
                    # if :add or :sub operator then multiply arg by size of object
         
     | 
| 
      
 832 
     | 
    
         
            +
                    # like in C
         
     | 
| 
      
 833 
     | 
    
         
            +
                    if [:add, :sub].include? op
         
     | 
| 
      
 834 
     | 
    
         
            +
                      (wn_mulop = WNode.new(:insn, wnode_op)).wtype = WType::DEFAULT
         
     | 
| 
      
 835 
     | 
    
         
            +
                      wn_mulop.c(:operator, wasm_type: wn_mulop.wasm_type, operator: :mul)
         
     | 
| 
       719 
836 
     | 
    
         
             
                      WNode.new(:insn, wn_mulop).c(:call, func_name: "$#{wnode_recv.wtype.name}::#{SIZE_METHOD}")
         
     | 
| 
       720 
837 
     | 
    
         
             
                      wnode_args.first.reparent_to(wn_mulop)
         
     | 
| 
       721 
838 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -794,14 +911,35 @@ module Rlang::Parser 
     | 
|
| 
       794 
911 
     | 
    
         
             
                # generate code for method call
         
     | 
| 
       795 
912 
     | 
    
         
             
                def send_method(wnode, class_path, method_name, method_type)
         
     | 
| 
       796 
913 
     | 
    
         
             
                  logger.debug "In call generator for #{class_path}::#{method_name}"
         
     | 
| 
       797 
     | 
    
         
            -
                  k = wnode.find_class_or_module(class_path)
         
     | 
| 
       798 
     | 
    
         
            -
             
     | 
| 
       799 
     | 
    
         
            -
                     
     | 
| 
       800 
     | 
    
         
            -
             
     | 
| 
       801 
     | 
    
         
            -
             
     | 
| 
       802 
     | 
    
         
            -
             
     | 
| 
      
 914 
     | 
    
         
            +
                  if k = wnode.find_class_or_module(class_path)
         
     | 
| 
      
 915 
     | 
    
         
            +
                    method = wnode.find_method(k, method_name, method_type)
         
     | 
| 
      
 916 
     | 
    
         
            +
                    if k.wtype.native? && ALL_OPS_MAP.has_key?(method_name)
         
     | 
| 
      
 917 
     | 
    
         
            +
                      # An Rlang method exist for this class but methods corresponding to 
         
     | 
| 
      
 918 
     | 
    
         
            +
                      # Webassembly native operators applied to native Webassembly types
         
     | 
| 
      
 919 
     | 
    
         
            +
                      # (I32, I64, F32, F64) **cannot** be overriden by instance methods
         
     | 
| 
      
 920 
     | 
    
         
            +
                      # in Rlang code
         
     | 
| 
      
 921 
     | 
    
         
            +
                      if method
         
     | 
| 
      
 922 
     | 
    
         
            +
                        logger.warn "Rlang #{class_path}::#{method_name} method ignored. Native operator has precedence"
         
     | 
| 
      
 923 
     | 
    
         
            +
                      end
         
     | 
| 
      
 924 
     | 
    
         
            +
                      logger.debug "Apply native operator #{method_name} to native wtype  #{class_path}"
         
     | 
| 
      
 925 
     | 
    
         
            +
                      wn_call = self.native_operator(wnode, method_name, WType.new(class_path))
         
     | 
| 
      
 926 
     | 
    
         
            +
                    elsif !k.wtype.native? && ALL_OPS_MAP.has_key?(method_name) && method.nil?
         
     | 
| 
      
 927 
     | 
    
         
            +
                      # Similarly if the Class is not a native type (a regular class)
         
     | 
| 
      
 928 
     | 
    
         
            +
                      # and the Class doesn't provide its own method implementation of the native
         
     | 
| 
      
 929 
     | 
    
         
            +
                      # operator then apply the native operands
         
     | 
| 
      
 930 
     | 
    
         
            +
                      logger.debug "Apply native operator #{method_name} to class found : #{class_path}"
         
     | 
| 
      
 931 
     | 
    
         
            +
                      wn_call = self.native_operator(wnode, method_name, WType.new(class_path))
         
     | 
| 
      
 932 
     | 
    
         
            +
                    elsif method
         
     | 
| 
      
 933 
     | 
    
         
            +
                      logger.debug "Found method #{method.name} in class #{method.klass.name}"
         
     | 
| 
      
 934 
     | 
    
         
            +
                      (wn_call = WNode.new(:insn, wnode)).c(:call, func_name: method.wasm_name)
         
     | 
| 
      
 935 
     | 
    
         
            +
                      wn_call.wtype = method.wtype
         
     | 
| 
      
 936 
     | 
    
         
            +
                      wn_call
         
     | 
| 
      
 937 
     | 
    
         
            +
                    else
         
     | 
| 
      
 938 
     | 
    
         
            +
                      raise "Unknown method '#{method_name}' in class #{class_path}"
         
     | 
| 
      
 939 
     | 
    
         
            +
                    end
         
     | 
| 
       803 
940 
     | 
    
         
             
                  elsif ALL_OPS_MAP.has_key? method_name
         
     | 
| 
       804 
     | 
    
         
            -
                    #  
     | 
| 
      
 941 
     | 
    
         
            +
                    # It is a native Wasm operator
         
     | 
| 
      
 942 
     | 
    
         
            +
                    logger.debug "Native operator found : #{class_path}::#{method_name}"
         
     | 
| 
       805 
943 
     | 
    
         
             
                    wn_call = self.native_operator(wnode, method_name, WType.new(class_path))
         
     | 
| 
       806 
944 
     | 
    
         
             
                  else
         
     | 
| 
       807 
945 
     | 
    
         
             
                    raise "Unknown method '#{method_name}' in class #{class_path}"
         
     | 
| 
         @@ -838,8 +976,8 @@ module Rlang::Parser 
     | 
|
| 
       838 
976 
     | 
    
         
             
                end
         
     | 
| 
       839 
977 
     | 
    
         | 
| 
       840 
978 
     | 
    
         
             
                def while(wnode)
         
     | 
| 
       841 
     | 
    
         
            -
                  (wnb = WNode.new(:insn, wnode)).c(:block) 
         
     | 
| 
       842 
     | 
    
         
            -
                  (wnl = WNode.new(:insn, wnb)).c(:loop) 
         
     | 
| 
      
 979 
     | 
    
         
            +
                  (wnb = WNode.new(:insn, wnode)).c(:block, label: wnb.set_label) 
         
     | 
| 
      
 980 
     | 
    
         
            +
                  (wnl = WNode.new(:insn, wnb)).c(:loop, label: wnl.set_label) 
         
     | 
| 
       843 
981 
     | 
    
         
             
                  (wnbi = WNode.new(:insn, wnl)).c(:br_if, label: wnb.label)
         
     | 
| 
       844 
982 
     | 
    
         
             
                  return wnb,wnbi,wnl
         
     | 
| 
       845 
983 
     | 
    
         
             
                end
         
     | 
| 
         @@ -849,7 +987,7 @@ module Rlang::Parser 
     | 
|
| 
       849 
987 
     | 
    
         
             
                # negate the original while condition
         
     | 
| 
       850 
988 
     | 
    
         
             
                def while_cond(wnode, wnode_cond_exp)
         
     | 
| 
       851 
989 
     | 
    
         
             
                  wn_eqz = WNode.new(:insn, wnode)
         
     | 
| 
       852 
     | 
    
         
            -
                  wn_eqz.c(:eqz,  
     | 
| 
      
 990 
     | 
    
         
            +
                  wn_eqz.c(:eqz, wasm_type: wnode_cond_exp.wasm_type)
         
     | 
| 
       853 
991 
     | 
    
         
             
                  wnode_cond_exp.reparent_to(wn_eqz)
         
     | 
| 
       854 
992 
     | 
    
         
             
                  wn_eqz
         
     | 
| 
       855 
993 
     | 
    
         
             
                end
         
     | 
    
        data/lib/rlang/parser/wnode.rb
    CHANGED
    
    | 
         @@ -52,14 +52,14 @@ module Rlang::Parser 
     | 
|
| 
       52 
52 
     | 
    
         
             
                  br_if: 'br_if %{label}',
         
     | 
| 
       53 
53 
     | 
    
         
             
                  br: 'br %{label}',
         
     | 
| 
       54 
54 
     | 
    
         
             
                  inline: '%{code}',
         
     | 
| 
       55 
     | 
    
         
            -
                  attr_getter: %q{func %{func_name} (param $_self_ i32) (result %{ 
     | 
| 
       56 
     | 
    
         
            -
              (%{ 
     | 
| 
       57 
     | 
    
         
            -
                  attr_setter: %q{func %{func_name} (param $_self_ i32) (param %{attr_name} %{ 
     | 
| 
      
 55 
     | 
    
         
            +
                  attr_getter: %q{func %{func_name} (param $_self_ i32) (result %{wasm_type})
         
     | 
| 
      
 56 
     | 
    
         
            +
              (%{wasm_type}.load offset=%{offset} (local.get $_self_))},
         
     | 
| 
      
 57 
     | 
    
         
            +
                  attr_setter: %q{func %{func_name} (param $_self_ i32) (param %{attr_name} %{wasm_type}) (result %{wasm_type})
         
     | 
| 
       58 
58 
     | 
    
         
             
              (local.get %{attr_name})
         
     | 
| 
       59 
     | 
    
         
            -
              (%{ 
     | 
| 
       60 
     | 
    
         
            -
                  class_size: %q{func %{func_name} (result %{ 
     | 
| 
       61 
     | 
    
         
            -
              (%{ 
     | 
| 
       62 
     | 
    
         
            -
                  comment: ';; %{ 
     | 
| 
      
 59 
     | 
    
         
            +
              (%{wasm_type}.store offset=%{offset} (local.get $_self_) (local.get %{attr_name}))},
         
     | 
| 
      
 60 
     | 
    
         
            +
                  class_size: %q{func %{func_name} (result %{wasm_type})
         
     | 
| 
      
 61 
     | 
    
         
            +
              (%{wasm_type}.const %{size})},
         
     | 
| 
      
 62 
     | 
    
         
            +
                  comment: ';; %{text}',
         
     | 
| 
       63 
63 
     | 
    
         
             
                  memory: 'memory $0 %{min} %{max}',
         
     | 
| 
       64 
64 
     | 
    
         
             
                  module: 'module %{module}'
         
     | 
| 
       65 
65 
     | 
    
         
             
                }
         
     | 
| 
         @@ -126,17 +126,37 @@ module Rlang::Parser 
     | 
|
| 
       126 
126 
     | 
    
         
             
                def c(template, wargs = {})
         
     | 
| 
       127 
127 
     | 
    
         
             
                  raise "Error: unknown WASM code template (#{template})" unless T.has_key? template
         
     | 
| 
       128 
128 
     | 
    
         
             
                  raise "Error: this WNode is already populated with instruction #{@template}" if @template
         
     | 
| 
       129 
     | 
    
         
            -
                  if [:loop, :block].include? template
         
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #if [:loop, :block].include? template
         
     | 
| 
      
 130 
     | 
    
         
            +
                  #  wargs[:label] = self.set_label
         
     | 
| 
      
 131 
     | 
    
         
            +
                  #end
         
     | 
| 
       132 
132 
     | 
    
         
             
                  @template = template
         
     | 
| 
       133 
133 
     | 
    
         
             
                  @wargs = wargs
         
     | 
| 
       134 
134 
     | 
    
         
             
                end
         
     | 
| 
       135 
135 
     | 
    
         | 
| 
       136 
136 
     | 
    
         
             
                def wasm_code
         
     | 
| 
       137 
     | 
    
         
            -
                  @ 
     | 
| 
      
 137 
     | 
    
         
            +
                  return '' unless T[@template]
         
     | 
| 
       138 
138 
     | 
    
         
             
                  wargs = {}
         
     | 
| 
       139 
139 
     | 
    
         
             
                  @wargs.each { |k, v| wargs[k] = (v.is_a?(Proc) ? v.call : v) }
         
     | 
| 
      
 140 
     | 
    
         
            +
                  # Because WNode#to_s generate wasm code from sometimes incomplete
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # information, we must add the wasm_type key if needed by the template
         
     | 
| 
      
 142 
     | 
    
         
            +
                  if T[@template].index("%{wasm_type}")
         
     | 
| 
      
 143 
     | 
    
         
            +
                    puts "*** adding wasm_type to #{T[@template]}" unless wargs.has_key? :wasm_type
         
     | 
| 
      
 144 
     | 
    
         
            +
                    wargs[:wasm_type] ||= self.wasm_type
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  # debug code to activate if you get 
         
     | 
| 
      
 148 
     | 
    
         
            +
                  # a Ruby warning on too many or too few arguments
         
     | 
| 
      
 149 
     | 
    
         
            +
                  # wargs.each do |k, v|
         
     | 
| 
      
 150 
     | 
    
         
            +
                  #  if T[@template].index("%{#{k.to_s}}").nil? 
         
     | 
| 
      
 151 
     | 
    
         
            +
                  #    puts "**** Error wargs missing keys in wargs : template: #{@template} / wargs: #{wargs.inspect}"
         
     | 
| 
      
 152 
     | 
    
         
            +
                  #  end
         
     | 
| 
      
 153 
     | 
    
         
            +
                  # end
         
     | 
| 
      
 154 
     | 
    
         
            +
                  #T[@template].scan(/%{([^}]+)}/).flatten.each do |k|
         
     | 
| 
      
 155 
     | 
    
         
            +
                  #  unless wargs.has_key? k.to_sym
         
     | 
| 
      
 156 
     | 
    
         
            +
                  #    puts "**** Error wargs missing keys in template: template: #{@template} / wargs: #{wargs.inspect}"
         
     | 
| 
      
 157 
     | 
    
         
            +
                  #  end
         
     | 
| 
      
 158 
     | 
    
         
            +
                  # end
         
     | 
| 
      
 159 
     | 
    
         
            +
                  #logger.debug "code template : #{@template} / T : #{T[@template]} / wargs : #{wargs.inspect}" if @template
         
     | 
| 
       140 
160 
     | 
    
         
             
                  T[@template] ? T[@template] % wargs : ''
         
     | 
| 
       141 
161 
     | 
    
         
             
                end
         
     | 
| 
       142 
162 
     | 
    
         | 
| 
         @@ -154,8 +174,13 @@ module Rlang::Parser 
     | 
|
| 
       154 
174 
     | 
    
         
             
                  logger.debug "Setting wtype #{wtype} for wnode #{self}"
         
     | 
| 
       155 
175 
     | 
    
         
             
                  @wtype = wtype
         
     | 
| 
       156 
176 
     | 
    
         
             
                  @method.wtype = @wtype if self.method?
         
     | 
| 
       157 
     | 
    
         
            -
                  # update wasm_type template arg accordingly
         
     | 
| 
       158 
     | 
    
         
            -
                   
     | 
| 
      
 177 
     | 
    
         
            +
                  # update wasm_type template arg accordingly if ti is already set
         
     | 
| 
      
 178 
     | 
    
         
            +
                  # (this is needed in some cases - e.g. operands - where node wtype
         
     | 
| 
      
 179 
     | 
    
         
            +
                  # is known once the wtypes of the children nodes are known )
         
     | 
| 
      
 180 
     | 
    
         
            +
                  if @wtype && @wargs.has_key?(:wasm_type)
         
     | 
| 
      
 181 
     | 
    
         
            +
                    logger.debug "Updating @wargs[:wasm_type] from '#{@wargs[:wasm_type]}' to '#{@wtype.wasm_type}'"
         
     | 
| 
      
 182 
     | 
    
         
            +
                    @wargs[:wasm_type] = @wtype.wasm_type
         
     | 
| 
      
 183 
     | 
    
         
            +
                  end
         
     | 
| 
       159 
184 
     | 
    
         
             
                  logger.debug "type #{self.type} wargs #{self.wargs} wtype #{@wtype}"
         
     | 
| 
       160 
185 
     | 
    
         
             
                  @wtype
         
     | 
| 
       161 
186 
     | 
    
         
             
                end
         
     | 
| 
         @@ -715,7 +740,9 @@ module Rlang::Parser 
     | 
|
| 
       715 
740 
     | 
    
         
             
                  logger.debug "children: #{self} / #{children.map(&:head)}" if self.link
         
     | 
| 
       716 
741 
     | 
    
         | 
| 
       717 
742 
     | 
    
         
             
                  case @type
         
     | 
| 
       718 
     | 
    
         
            -
                  # Section nodes 
     | 
| 
      
 743 
     | 
    
         
            +
                  # Section nodes
         
     | 
| 
      
 744 
     | 
    
         
            +
                  when :comment
         
     | 
| 
      
 745 
     | 
    
         
            +
                    "\n%s%s" % [indent, self.wasm_code]
         
     | 
| 
       719 
746 
     | 
    
         
             
                  when :imports
         
     | 
| 
       720 
747 
     | 
    
         
             
                    "\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
         
     | 
| 
       721 
748 
     | 
    
         
             
                    children.map { |wn| wn.transpile(depth) }.join('')
         
     |