rlang 0.4.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 +19 -3
 - data/Gemfile.lock +4 -6
 - data/README +11 -0
 - data/README.md +18 -10
 - data/bin/rlang +17 -5
 - data/docs/RlangCompiler.md +5 -1
 - data/docs/RlangManual.md +98 -20
 - data/examples/fib/fib.rb +5 -1
 - data/lib/builder/rlang/compiler.rb +2 -21
 - data/lib/rlang/lib/array/array32.rb +59 -0
 - data/lib/rlang/lib/array/array64.rb +56 -0
 - data/lib/rlang/lib/array.rb +6 -0
 - data/lib/rlang/lib/base64.rb +223 -0
 - data/lib/rlang/lib/io.rb +75 -0
 - data/lib/rlang/lib/kernel.rb +23 -0
 - data/lib/rlang/lib/malloc.rb +12 -8
 - data/lib/rlang/lib/memory.rb +102 -2
 - data/lib/rlang/lib/object.rb +40 -4
 - data/lib/rlang/lib/rlang.rb +29 -0
 - data/lib/rlang/lib/rlang_core.rb +15 -0
 - data/lib/rlang/lib/string.rb +106 -8
 - data/lib/rlang/lib/type/i32.rb +43 -0
 - data/lib/rlang/lib/type/i64.rb +2 -0
 - data/lib/rlang/lib/unistd.rb +1 -2
 - data/lib/rlang/lib/wasi.rb +184 -0
 - data/lib/rlang/parser/attr.rb +9 -13
 - data/lib/rlang/parser/const.rb +105 -1
 - data/lib/rlang/parser/cvar.rb +11 -7
 - data/lib/rlang/parser/data.rb +17 -6
 - data/lib/rlang/parser/export.rb +4 -3
 - data/lib/rlang/parser/ext/integer.rb +3 -1
 - data/lib/rlang/parser/ext/type.rb +30 -1
 - data/lib/rlang/parser/global.rb +10 -2
 - data/lib/rlang/parser/ivar.rb +3 -7
 - data/lib/rlang/parser/klass.rb +8 -35
 - data/lib/rlang/parser/method.rb +36 -12
 - data/lib/rlang/parser/module.rb +143 -0
 - data/lib/rlang/parser/wgenerator.rb +462 -168
 - data/lib/rlang/parser/wnode.rb +387 -142
 - data/lib/rlang/parser/wtype.rb +30 -7
 - data/lib/rlang/parser.rb +506 -231
 - data/lib/rlang/version.rb +1 -1
 - data/lib/rlang.rb +3 -0
 - data/lib/ruby/mirror/rstring.rb +16 -0
 - data/lib/utils/exceptions.rb +12 -0
 - data/rlang.gemspec +4 -4
 - metadata +25 -13
 - data/lib/rlang/lib.rb +0 -11
 
    
        data/lib/rlang/parser/wnode.rb
    CHANGED
    
    | 
         @@ -12,6 +12,7 @@ require_relative './lvar' 
     | 
|
| 
       12 
12 
     | 
    
         
             
            require_relative './attr'
         
     | 
| 
       13 
13 
     | 
    
         
             
            require_relative './method'
         
     | 
| 
       14 
14 
     | 
    
         
             
            require_relative './klass'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require_relative './module'
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
17 
     | 
    
         
             
            module Rlang::Parser
         
     | 
| 
       17 
18 
     | 
    
         
             
              class WNode
         
     | 
| 
         @@ -20,6 +21,7 @@ module Rlang::Parser 
     | 
|
| 
       20 
21 
     | 
    
         
             
                # WASM code templates
         
     | 
| 
       21 
22 
     | 
    
         
             
                T = {
         
     | 
| 
       22 
23 
     | 
    
         
             
                  func: 'func %{func_name}',
         
     | 
| 
      
 24 
     | 
    
         
            +
                  import: 'import "%{module_name}" "%{function_name}"',
         
     | 
| 
       23 
25 
     | 
    
         
             
                  param: 'param %{name} %{wasm_type}',
         
     | 
| 
       24 
26 
     | 
    
         
             
                  result: 'result %{wasm_type}',
         
     | 
| 
       25 
27 
     | 
    
         
             
                  return: 'return',
         
     | 
| 
         @@ -50,18 +52,22 @@ module Rlang::Parser 
     | 
|
| 
       50 
52 
     | 
    
         
             
                  br_if: 'br_if %{label}',
         
     | 
| 
       51 
53 
     | 
    
         
             
                  br: 'br %{label}',
         
     | 
| 
       52 
54 
     | 
    
         
             
                  inline: '%{code}',
         
     | 
| 
       53 
     | 
    
         
            -
                  attr_getter: %q{func %{func_name} (param $_self_ i32) (result %{ 
     | 
| 
       54 
     | 
    
         
            -
              (%{ 
     | 
| 
       55 
     | 
    
         
            -
                  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})
         
     | 
| 
       56 
58 
     | 
    
         
             
              (local.get %{attr_name})
         
     | 
| 
       57 
     | 
    
         
            -
              (%{ 
     | 
| 
       58 
     | 
    
         
            -
                  class_size: %q{func %{func_name} (result %{ 
     | 
| 
       59 
     | 
    
         
            -
              (%{ 
     | 
| 
      
 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 
     | 
    
         
            +
                  memory: 'memory $0 %{min} %{max}',
         
     | 
| 
      
 64 
     | 
    
         
            +
                  module: 'module %{module}'
         
     | 
| 
       60 
65 
     | 
    
         
             
                }
         
     | 
| 
       61 
66 
     | 
    
         | 
| 
       62 
67 
     | 
    
         
             
                attr_accessor :type, :wargs, :children, :parent, :comment, 
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
      
 68 
     | 
    
         
            +
                              :method, :template, :keep_on_stack, :classes,
         
     | 
| 
      
 69 
     | 
    
         
            +
                              :modules, :link
         
     | 
| 
      
 70 
     | 
    
         
            +
                attr_reader :wtype, :label, :klass, :module
         
     | 
| 
       65 
71 
     | 
    
         | 
| 
       66 
72 
     | 
    
         
             
                @@label_index = 0
         
     | 
| 
       67 
73 
     | 
    
         | 
| 
         @@ -82,16 +88,13 @@ module Rlang::Parser 
     | 
|
| 
       82 
88 
     | 
    
         
             
                  # means no value returned)
         
     | 
| 
       83 
89 
     | 
    
         
             
                  @wtype = WType::DEFAULT
         
     | 
| 
       84 
90 
     | 
    
         | 
| 
       85 
     | 
    
         
            -
                  # For root wnode
         
     | 
| 
       86 
     | 
    
         
            -
                  @classes = [] # classes
         
     | 
| 
       87 
91 
     | 
    
         
             
                  # top level class needed only if const are
         
     | 
| 
       88 
92 
     | 
    
         
             
                  # defined at top level
         
     | 
| 
       89 
93 
     | 
    
         
             
                  # NOTE: can't use create_klass as it find_class
         
     | 
| 
       90 
94 
     | 
    
         
             
                  # which doesn't find root class ... endless loop!!
         
     | 
| 
       91 
95 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
                  # For class wnode only
         
     | 
| 
       93 
     | 
    
         
            -
                   
     | 
| 
       94 
     | 
    
         
            -
                  self.klass = Klass.new(:Top__) if self.root?
         
     | 
| 
      
 96 
     | 
    
         
            +
                  # For class or module wnode only
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @klass = nil
         
     | 
| 
       95 
98 
     | 
    
         | 
| 
       96 
99 
     | 
    
         
             
                  # For method wnode only
         
     | 
| 
       97 
100 
     | 
    
         
             
                  @method = nil
         
     | 
| 
         @@ -99,6 +102,10 @@ module Rlang::Parser 
     | 
|
| 
       99 
102 
     | 
    
         
             
                  # For insn wnode with 
         
     | 
| 
       100 
103 
     | 
    
         
             
                  # label (.e.g block, loop)
         
     | 
| 
       101 
104 
     | 
    
         
             
                  @label = nil
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                  # link to a related node
         
     | 
| 
      
 107 
     | 
    
         
            +
                  # Semantic of the link depend on the wnode type
         
     | 
| 
      
 108 
     | 
    
         
            +
                  @link = nil
         
     | 
| 
       102 
109 
     | 
    
         
             
                end
         
     | 
| 
       103 
110 
     | 
    
         | 
| 
       104 
111 
     | 
    
         
             
                def self.root
         
     | 
| 
         @@ -119,17 +126,37 @@ module Rlang::Parser 
     | 
|
| 
       119 
126 
     | 
    
         
             
                def c(template, wargs = {})
         
     | 
| 
       120 
127 
     | 
    
         
             
                  raise "Error: unknown WASM code template (#{template})" unless T.has_key? template
         
     | 
| 
       121 
128 
     | 
    
         
             
                  raise "Error: this WNode is already populated with instruction #{@template}" if @template
         
     | 
| 
       122 
     | 
    
         
            -
                  if [:loop, :block].include? template
         
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #if [:loop, :block].include? template
         
     | 
| 
      
 130 
     | 
    
         
            +
                  #  wargs[:label] = self.set_label
         
     | 
| 
      
 131 
     | 
    
         
            +
                  #end
         
     | 
| 
       125 
132 
     | 
    
         
             
                  @template = template
         
     | 
| 
       126 
133 
     | 
    
         
             
                  @wargs = wargs
         
     | 
| 
       127 
134 
     | 
    
         
             
                end
         
     | 
| 
       128 
135 
     | 
    
         | 
| 
       129 
136 
     | 
    
         
             
                def wasm_code
         
     | 
| 
       130 
     | 
    
         
            -
                  @ 
     | 
| 
      
 137 
     | 
    
         
            +
                  return '' unless T[@template]
         
     | 
| 
       131 
138 
     | 
    
         
             
                  wargs = {}
         
     | 
| 
       132 
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
         
     | 
| 
       133 
160 
     | 
    
         
             
                  T[@template] ? T[@template] % wargs : ''
         
     | 
| 
       134 
161 
     | 
    
         
             
                end
         
     | 
| 
       135 
162 
     | 
    
         | 
| 
         @@ -147,8 +174,13 @@ module Rlang::Parser 
     | 
|
| 
       147 
174 
     | 
    
         
             
                  logger.debug "Setting wtype #{wtype} for wnode #{self}"
         
     | 
| 
       148 
175 
     | 
    
         
             
                  @wtype = wtype
         
     | 
| 
       149 
176 
     | 
    
         
             
                  @method.wtype = @wtype if self.method?
         
     | 
| 
       150 
     | 
    
         
            -
                  # update wasm_type template arg accordingly
         
     | 
| 
       151 
     | 
    
         
            -
                   
     | 
| 
      
 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
         
     | 
| 
       152 
184 
     | 
    
         
             
                  logger.debug "type #{self.type} wargs #{self.wargs} wtype #{@wtype}"
         
     | 
| 
       153 
185 
     | 
    
         
             
                  @wtype
         
     | 
| 
       154 
186 
     | 
    
         
             
                end
         
     | 
| 
         @@ -169,7 +201,7 @@ module Rlang::Parser 
     | 
|
| 
       169 
201 
     | 
    
         
             
                end
         
     | 
| 
       170 
202 
     | 
    
         
             
                alias :<< :add_child
         
     | 
| 
       171 
203 
     | 
    
         | 
| 
       172 
     | 
    
         
            -
                # Remove child  
     | 
| 
      
 204 
     | 
    
         
            +
                # Remove child from current node
         
     | 
| 
       173 
205 
     | 
    
         
             
                def remove_child(wnode)
         
     | 
| 
       174 
206 
     | 
    
         
             
                  logger.debug "Removing #{wnode.object_id} from wnodes list #{self.children.map(&:object_id)} under parent #{self.parent.object_id}"
         
     | 
| 
       175 
207 
     | 
    
         
             
                  unless (wn = self.children.delete(wnode)) && wn == wnode
         
     | 
| 
         @@ -192,35 +224,48 @@ module Rlang::Parser 
     | 
|
| 
       192 
224 
     | 
    
         
             
                  self
         
     | 
| 
       193 
225 
     | 
    
         
             
                end
         
     | 
| 
       194 
226 
     | 
    
         | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
      
 227 
     | 
    
         
            +
                # Reparent all children wnodes to another wnode
         
     | 
| 
      
 228 
     | 
    
         
            +
                # (in the same order)
         
     | 
| 
      
 229 
     | 
    
         
            +
                # WARNING!! Do not use self.children.each { } to
         
     | 
| 
      
 230 
     | 
    
         
            +
                # reparent because we are modifying children list
         
     | 
| 
      
 231 
     | 
    
         
            +
                # as we go
         
     | 
| 
      
 232 
     | 
    
         
            +
                def reparent_children_to(wnode)
         
     | 
| 
      
 233 
     | 
    
         
            +
                  wnc = self.children
         
     | 
| 
      
 234 
     | 
    
         
            +
                  wnc.count.times { wnc.first.reparent_to(wnode) }
         
     | 
| 
      
 235 
     | 
    
         
            +
                  self
         
     | 
| 
      
 236 
     | 
    
         
            +
                end
         
     | 
| 
       205 
237 
     | 
    
         | 
| 
       206 
238 
     | 
    
         
             
                # insert a blank wnode above self, so between self wnode 
         
     | 
| 
       207 
239 
     | 
    
         
             
                # and its parent (self -> parent becomes self -> wn -> parent)
         
     | 
| 
       208 
     | 
    
         
            -
                def insert( 
     | 
| 
       209 
     | 
    
         
            -
                  wn = WNode.new( 
     | 
| 
      
 240 
     | 
    
         
            +
                def insert(type=:none)
         
     | 
| 
      
 241 
     | 
    
         
            +
                  wn = WNode.new(type, self.parent)
         
     | 
| 
       210 
242 
     | 
    
         
             
                  self.reparent_to(wn)
         
     | 
| 
       211 
243 
     | 
    
         
             
                  wn
         
     | 
| 
       212 
244 
     | 
    
         
             
                end
         
     | 
| 
       213 
245 
     | 
    
         | 
| 
      
 246 
     | 
    
         
            +
                # delete current wnode (which means
         
     | 
| 
      
 247 
     | 
    
         
            +
                # basically remove it as a child)
         
     | 
| 
      
 248 
     | 
    
         
            +
                def delete!
         
     | 
| 
      
 249 
     | 
    
         
            +
                  return if self.root? || self.parent.nil?
         
     | 
| 
      
 250 
     | 
    
         
            +
                  self.parent.remove_child(self)
         
     | 
| 
      
 251 
     | 
    
         
            +
                end
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
                # Silence the current wnode (which means
         
     | 
| 
      
 254 
     | 
    
         
            +
                # inserting a silent type wnode between this
         
     | 
| 
      
 255 
     | 
    
         
            +
                # and its parent)
         
     | 
| 
      
 256 
     | 
    
         
            +
                def silence!
         
     | 
| 
      
 257 
     | 
    
         
            +
                  self.insert(:silent)
         
     | 
| 
      
 258 
     | 
    
         
            +
                end
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
       214 
260 
     | 
    
         
             
                def klass=(klass)
         
     | 
| 
       215 
261 
     | 
    
         
             
                  @klass = klass
         
     | 
| 
       216 
262 
     | 
    
         
             
                  @klass.wnode = self
         
     | 
| 
       217 
     | 
    
         
            -
                   
     | 
| 
       218 
     | 
    
         
            -
                  klass
         
     | 
| 
      
 263 
     | 
    
         
            +
                  @klass
         
     | 
| 
       219 
264 
     | 
    
         
             
                end
         
     | 
| 
       220 
265 
     | 
    
         | 
| 
       221 
266 
     | 
    
         
             
                # Find class name in this node and up the tree
         
     | 
| 
       222 
267 
     | 
    
         
             
                def class_name
         
     | 
| 
       223 
     | 
    
         
            -
                  (cn = self.class_wnode) ? cn.klass. 
     | 
| 
      
 268 
     | 
    
         
            +
                  (cn = self.class_wnode) ? cn.klass.path_name : nil
         
     | 
| 
       224 
269 
     | 
    
         
             
                end
         
     | 
| 
       225 
270 
     | 
    
         | 
| 
       226 
271 
     | 
    
         
             
                # Find class size in this wnode or up the tree
         
     | 
| 
         @@ -228,108 +273,238 @@ module Rlang::Parser 
     | 
|
| 
       228 
273 
     | 
    
         
             
                  (cn = self.class_wnode) ? cn.klass.size : nil
         
     | 
| 
       229 
274 
     | 
    
         
             
                end
         
     | 
| 
       230 
275 
     | 
    
         | 
| 
      
 276 
     | 
    
         
            +
                # Find the module object of the current wnode and up the tree
         
     | 
| 
      
 277 
     | 
    
         
            +
                # if no name given
         
     | 
| 
      
 278 
     | 
    
         
            +
                # or lookup the matching class from
         
     | 
| 
      
 279 
     | 
    
         
            +
                # the root level if module name given
         
     | 
| 
      
 280 
     | 
    
         
            +
                def find_module(module_path)
         
     | 
| 
      
 281 
     | 
    
         
            +
                  logger.debug "looking for #{module_path} module in scope #{self.scope}" # at wnode #{self}"
         
     | 
| 
      
 282 
     | 
    
         
            +
                  if modul = self.find_class_or_module_by_name(module_path)
         
     | 
| 
      
 283 
     | 
    
         
            +
                    logger.debug "Found module #{modul.name} / #{modul}"
         
     | 
| 
      
 284 
     | 
    
         
            +
                  else
         
     | 
| 
      
 285 
     | 
    
         
            +
                    logger.debug "Module #{module_path} not found"
         
     | 
| 
      
 286 
     | 
    
         
            +
                  end
         
     | 
| 
      
 287 
     | 
    
         
            +
                  modul
         
     | 
| 
      
 288 
     | 
    
         
            +
                end
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
                # Create a module object
         
     | 
| 
      
 291 
     | 
    
         
            +
                def create_module(module_path)
         
     | 
| 
      
 292 
     | 
    
         
            +
                  # Create the constant associated to this module
         
     | 
| 
      
 293 
     | 
    
         
            +
                  klass = self.find_current_class_or_module()
         
     | 
| 
      
 294 
     | 
    
         
            +
                  logger.debug "Creating module #{module_path} in class #{klass} under wnode #{self.head}"
         
     | 
| 
      
 295 
     | 
    
         
            +
                  const = self.create_const(module_path, nil, WType.new(:Module))
         
     | 
| 
      
 296 
     | 
    
         
            +
                  modul = Module.new(const, klass)
         
     | 
| 
      
 297 
     | 
    
         
            +
                  # Add the constant to list of constants in current scope class
         
     | 
| 
      
 298 
     | 
    
         
            +
                  klass.consts << const
         
     | 
| 
      
 299 
     | 
    
         
            +
                  # Generate wnode
         
     | 
| 
      
 300 
     | 
    
         
            +
                  wnc = WNode.new(:module, self)
         
     | 
| 
      
 301 
     | 
    
         
            +
                  wnc.klass = modul
         
     | 
| 
      
 302 
     | 
    
         
            +
                  logger.debug "Created module #{modul.name}/ID:#{modul} under wnode #{wnc.parent} / ID: #{self.object_id}"
         
     | 
| 
      
 303 
     | 
    
         
            +
                  modul
         
     | 
| 
      
 304 
     | 
    
         
            +
                end
         
     | 
| 
      
 305 
     | 
    
         
            +
             
     | 
| 
      
 306 
     | 
    
         
            +
                def find_or_create_module(module_path)
         
     | 
| 
      
 307 
     | 
    
         
            +
                  self.find_module(module_path) || self.create_module(module_path)
         
     | 
| 
      
 308 
     | 
    
         
            +
                end
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
                # Return the first class/module up the tree
         
     | 
| 
      
 311 
     | 
    
         
            +
                def find_current_class_or_module()
         
     | 
| 
      
 312 
     | 
    
         
            +
                  logger.debug "looking for current class in scope #{self.scope}  at wnode #{self.head(3)}"
         
     | 
| 
      
 313 
     | 
    
         
            +
                  if wn = self.class_or_module_wnode
         
     | 
| 
      
 314 
     | 
    
         
            +
                    k = wn.klass
         
     | 
| 
      
 315 
     | 
    
         
            +
                  elsif self.in_root_scope?
         
     | 
| 
      
 316 
     | 
    
         
            +
                    # methods defined at root level goes to Object Class
         
     | 
| 
      
 317 
     | 
    
         
            +
                    k = self.find_class_or_module_by_name([:Object])
         
     | 
| 
      
 318 
     | 
    
         
            +
                  end
         
     | 
| 
      
 319 
     | 
    
         
            +
                  if k
         
     | 
| 
      
 320 
     | 
    
         
            +
                    logger.debug "Found class #{k.name} / #{k}"
         
     | 
| 
      
 321 
     | 
    
         
            +
                  else
         
     | 
| 
      
 322 
     | 
    
         
            +
                    logger.debug "No current class found!"
         
     | 
| 
      
 323 
     | 
    
         
            +
                  end
         
     | 
| 
      
 324 
     | 
    
         
            +
                  k
         
     | 
| 
      
 325 
     | 
    
         
            +
                end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
                # Find the class by doing a lookup on the constant
         
     | 
| 
      
 328 
     | 
    
         
            +
                def find_class_or_module_by_name(class_path)
         
     | 
| 
      
 329 
     | 
    
         
            +
                  raise "Class name argument expected" unless class_path && !class_path.empty?
         
     | 
| 
      
 330 
     | 
    
         
            +
                  logger.debug "looking for class/module constant #{class_path} in scope #{self.scope} at wnode #{self.head}"
         
     | 
| 
      
 331 
     | 
    
         
            +
                  const = self.find_const(class_path)
         
     | 
| 
      
 332 
     | 
    
         
            +
                  #raise "Class or Module #{class_path} not found!" unless const
         
     | 
| 
      
 333 
     | 
    
         
            +
                  if const
         
     | 
| 
      
 334 
     | 
    
         
            +
                    logger.debug "Found constant #{const.name} pointing to #{const.value}"
         
     | 
| 
      
 335 
     | 
    
         
            +
                    const.value
         
     | 
| 
      
 336 
     | 
    
         
            +
                  else
         
     | 
| 
      
 337 
     | 
    
         
            +
                    logger.debug "Constant #{class_path} not found"
         
     | 
| 
      
 338 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 339 
     | 
    
         
            +
                  end
         
     | 
| 
      
 340 
     | 
    
         
            +
                end
         
     | 
| 
      
 341 
     | 
    
         
            +
                  
         
     | 
| 
       231 
342 
     | 
    
         
             
                # Find the class object of the current and up the tree
         
     | 
| 
       232 
343 
     | 
    
         
             
                # if no name given or lookup the matching class from
         
     | 
| 
       233 
344 
     | 
    
         
             
                # the root level if class name given
         
     | 
| 
       234 
     | 
    
         
            -
                 
     | 
| 
       235 
     | 
    
         
            -
             
     | 
| 
       236 
     | 
    
         
            -
             
     | 
| 
       237 
     | 
    
         
            -
                   
     | 
| 
       238 
     | 
    
         
            -
             
     | 
| 
       239 
     | 
    
         
            -
             
     | 
| 
      
 345 
     | 
    
         
            +
                # class_path can be passed either as in a Symbol (e.g. :"A::B")
         
     | 
| 
      
 346 
     | 
    
         
            +
                # or as an array of symbols (e.g. [:A, :B])
         
     | 
| 
      
 347 
     | 
    
         
            +
                def find_class_or_module(class_path)
         
     | 
| 
      
 348 
     | 
    
         
            +
                  logger.debug "looking for #{class_path} class in scope #{self.scope} at wnode #{self.head}"
         
     | 
| 
      
 349 
     | 
    
         
            +
                  # turn the symbol form of class_path into the array form
         
     | 
| 
      
 350 
     | 
    
         
            +
                  if class_path.is_a? Symbol
         
     | 
| 
      
 351 
     | 
    
         
            +
                    class_path = class_path.to_s.split('::').map(&:to_sym)
         
     | 
| 
      
 352 
     | 
    
         
            +
                  end
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                  if class_path.empty?
         
     | 
| 
      
 355 
     | 
    
         
            +
                    k = self.find_current_class_or_module()
         
     | 
| 
       240 
356 
     | 
    
         
             
                  else
         
     | 
| 
       241 
     | 
    
         
            -
                     
     | 
| 
       242 
     | 
    
         
            -
             
     | 
| 
       243 
     | 
    
         
            -
             
     | 
| 
       244 
     | 
    
         
            -
             
     | 
| 
       245 
     | 
    
         
            -
                    else
         
     | 
| 
       246 
     | 
    
         
            -
                      logger.debug "Looking for class wnode from wnode #{self} / ID: #{self.object_id} / 
         
     | 
| 
       247 
     | 
    
         
            -
                      type: #{self.type} / class_wnode ID #{self.class_wnode.object_id} / 
         
     | 
| 
       248 
     | 
    
         
            -
                      class_wnode #{self.class_wnode} /
         
     | 
| 
       249 
     | 
    
         
            -
                      self klass : #{self.klass} / 
         
     | 
| 
       250 
     | 
    
         
            -
                      self klass wtype : #{self.klass&.wtype} / "
         
     | 
| 
       251 
     | 
    
         
            -
                      c = self.class_wnode.klass
         
     | 
| 
       252 
     | 
    
         
            -
                    end
         
     | 
| 
       253 
     | 
    
         
            -
                  end    
         
     | 
| 
       254 
     | 
    
         
            -
                  if c
         
     | 
| 
       255 
     | 
    
         
            -
                    logger.debug "Found class #{c.name} / #{c}"
         
     | 
| 
      
 357 
     | 
    
         
            +
                    k = self.find_class_or_module_by_name(class_path)
         
     | 
| 
      
 358 
     | 
    
         
            +
                  end
         
     | 
| 
      
 359 
     | 
    
         
            +
                  if k
         
     | 
| 
      
 360 
     | 
    
         
            +
                    logger.debug "Found class #{k.name} / #{k}"
         
     | 
| 
       256 
361 
     | 
    
         
             
                  else
         
     | 
| 
       257 
     | 
    
         
            -
                    logger.debug "Class #{ 
     | 
| 
      
 362 
     | 
    
         
            +
                    logger.debug "Class #{class_path} not found!"
         
     | 
| 
      
 363 
     | 
    
         
            +
                  end
         
     | 
| 
      
 364 
     | 
    
         
            +
                  k
         
     | 
| 
      
 365 
     | 
    
         
            +
                end
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
                # Create a Class object. The code below assumes
         
     | 
| 
      
 368 
     | 
    
         
            +
                # the class doesn't exist
         
     | 
| 
      
 369 
     | 
    
         
            +
                def create_class(class_path, super_class_path)
         
     | 
| 
      
 370 
     | 
    
         
            +
                  # check that super class exists
         
     | 
| 
      
 371 
     | 
    
         
            +
                  super_class = nil
         
     | 
| 
      
 372 
     | 
    
         
            +
                  unless super_class_path.empty?
         
     | 
| 
      
 373 
     | 
    
         
            +
                    super_class_const = self.find_const(super_class_path)
         
     | 
| 
      
 374 
     | 
    
         
            +
                    raise NameError, "uninitialized constant #{super_class_path}" \
         
     | 
| 
      
 375 
     | 
    
         
            +
                      unless super_class_const
         
     | 
| 
      
 376 
     | 
    
         
            +
                    super_class = super_class_const.scope_class
         
     | 
| 
       258 
377 
     | 
    
         
             
                  end
         
     | 
| 
       259 
     | 
    
         
            -
                  c
         
     | 
| 
       260 
     | 
    
         
            -
                end
         
     | 
| 
       261 
378 
     | 
    
         | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
       264 
     | 
    
         
            -
             
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
       266 
     | 
    
         
            -
                   
     | 
| 
       267 
     | 
    
         
            -
             
     | 
| 
       268 
     | 
    
         
            -
                   
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
      
 379 
     | 
    
         
            +
                  # Find current class or module (lexical scope)
         
     | 
| 
      
 380 
     | 
    
         
            +
                  # special case for Object class
         
     | 
| 
      
 381 
     | 
    
         
            +
                  if class_path == [:Object] && self.in_root_scope?
         
     | 
| 
      
 382 
     | 
    
         
            +
                    scope_class = nil
         
     | 
| 
      
 383 
     | 
    
         
            +
                  else
         
     | 
| 
      
 384 
     | 
    
         
            +
                    scope_class = self.find_current_class_or_module()
         
     | 
| 
      
 385 
     | 
    
         
            +
                  end
         
     | 
| 
      
 386 
     | 
    
         
            +
             
     | 
| 
      
 387 
     | 
    
         
            +
                  # Create the constant associated to this class
         
     | 
| 
      
 388 
     | 
    
         
            +
                  # the class itself
         
     | 
| 
      
 389 
     | 
    
         
            +
                  const = self.create_const(class_path, nil, WType.new(:Class))
         
     | 
| 
      
 390 
     | 
    
         
            +
                  k = Klass.new(const, scope_class, super_class)
         
     | 
| 
      
 391 
     | 
    
         
            +
             
     | 
| 
      
 392 
     | 
    
         
            +
                  # special case to bootstrap Object class
         
     | 
| 
      
 393 
     | 
    
         
            +
                  if class_path == [:Object] && self.in_root_scope?
         
     | 
| 
      
 394 
     | 
    
         
            +
                    const.scope_class = k
         
     | 
| 
      
 395 
     | 
    
         
            +
                  end
         
     | 
| 
       270 
396 
     | 
    
         | 
| 
       271 
     | 
    
         
            -
             
     | 
| 
       272 
     | 
    
         
            -
                   
     | 
| 
      
 397 
     | 
    
         
            +
                  # create class wnode
         
     | 
| 
      
 398 
     | 
    
         
            +
                  wnc = WNode.new(:class, self)
         
     | 
| 
      
 399 
     | 
    
         
            +
                  wnc.klass = k
         
     | 
| 
      
 400 
     | 
    
         
            +
                  k.wnode = wnc
         
     | 
| 
      
 401 
     | 
    
         
            +
                  logger.debug "Created class #{k.name}/ID: #{k} under wnode #{self}/ ID: #{self.object_id}"
         
     | 
| 
      
 402 
     | 
    
         
            +
                  k
         
     | 
| 
       273 
403 
     | 
    
         
             
                end
         
     | 
| 
       274 
404 
     | 
    
         | 
| 
       275 
     | 
    
         
            -
                 
     | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
       277 
     | 
    
         
            -
                   
     | 
| 
       278 
     | 
    
         
            -
             
     | 
| 
       279 
     | 
    
         
            -
                  if (cn = self.class_wnode)
         
     | 
| 
       280 
     | 
    
         
            -
                    cn.klass.consts << (const = Const.new(k.name, c_name, value, wtype))
         
     | 
| 
      
 405 
     | 
    
         
            +
                def find_or_create_class(class_path, super_class_path)
         
     | 
| 
      
 406 
     | 
    
         
            +
                  logger.debug "Find/Create class: #{class_path}"
         
     | 
| 
      
 407 
     | 
    
         
            +
                  if (km = self.find_class_or_module(class_path))
         
     | 
| 
      
 408 
     | 
    
         
            +
                    raise TypeError, "#{class_path} is not a class" unless km.const.class?
         
     | 
| 
       281 
409 
     | 
    
         
             
                  else
         
     | 
| 
       282 
     | 
    
         
            -
                     
     | 
| 
      
 410 
     | 
    
         
            +
                    km = self.create_class(class_path, super_class_path)
         
     | 
| 
      
 411 
     | 
    
         
            +
                  end
         
     | 
| 
      
 412 
     | 
    
         
            +
                  km
         
     | 
| 
      
 413 
     | 
    
         
            +
                end
         
     | 
| 
      
 414 
     | 
    
         
            +
             
     | 
| 
      
 415 
     | 
    
         
            +
                # create a constant, relative to the current wnode
         
     | 
| 
      
 416 
     | 
    
         
            +
                # the constant is assumed to not exist already
         
     | 
| 
      
 417 
     | 
    
         
            +
                def create_const(c_path, value, wtype)
         
     | 
| 
      
 418 
     | 
    
         
            +
                  logger.debug "Creating constant #{c_path} / wtype: #{wtype} at wnode #{self.class_wnode.head}..."
         
     | 
| 
      
 419 
     | 
    
         
            +
                  raise "Dynamic constant assignment. Constant #{name} cannot be created in scope #{cmn.scope}" \
         
     | 
| 
      
 420 
     | 
    
         
            +
                    if self.in_method_scope?
         
     | 
| 
      
 421 
     | 
    
         
            +
             
     | 
| 
      
 422 
     | 
    
         
            +
                  # if const_path has more than one element then check 
         
     | 
| 
      
 423 
     | 
    
         
            +
                  # that all element but last already exist
         
     | 
| 
      
 424 
     | 
    
         
            +
                  !(c_prefix = c_path[0..-2]).empty? && self.find_const(c_prefix)
         
     | 
| 
      
 425 
     | 
    
         
            +
                  c_name = c_path.last
         
     | 
| 
      
 426 
     | 
    
         
            +
                  const = Const.new(c_name, value, wtype)
         
     | 
| 
      
 427 
     | 
    
         
            +
                end
         
     | 
| 
      
 428 
     | 
    
         
            +
             
     | 
| 
      
 429 
     | 
    
         
            +
                # Look for constant from where we are in wtree
         
     | 
| 
      
 430 
     | 
    
         
            +
                # For a Ruby implementation of the constant lookup
         
     | 
| 
      
 431 
     | 
    
         
            +
                # algo, see https://cirw.in/blog/constant-lookup
         
     | 
| 
      
 432 
     | 
    
         
            +
                #  - c_path is an array of constant name elements
         
     | 
| 
      
 433 
     | 
    
         
            +
                #    e.g. for constant A::B::C constant_path is [A, B, C]
         
     | 
| 
      
 434 
     | 
    
         
            +
                def find_const(c_path)
         
     | 
| 
      
 435 
     | 
    
         
            +
                  logger.debug "looking for constant #{c_path}...from wnode #{self.head}..."
         
     | 
| 
      
 436 
     | 
    
         
            +
                  wn = self; idx = 0; count = c_path.size
         
     | 
| 
      
 437 
     | 
    
         
            +
                  while idx < count
         
     | 
| 
      
 438 
     | 
    
         
            +
                    const = wn._const_lookup(c_path[idx])
         
     | 
| 
      
 439 
     | 
    
         
            +
                    if const && (idx < count-1) && (const.class? || const.module?) && const.scope_class
         
     | 
| 
      
 440 
     | 
    
         
            +
                        wn = const.value.wnode
         
     | 
| 
      
 441 
     | 
    
         
            +
                    else
         
     | 
| 
      
 442 
     | 
    
         
            +
                      raise NameError, "uninitialized constant #{c_path.join('::')}" unless idx == count-1
         
     | 
| 
      
 443 
     | 
    
         
            +
                    end
         
     | 
| 
      
 444 
     | 
    
         
            +
                    idx += 1
         
     | 
| 
       283 
445 
     | 
    
         
             
                  end
         
     | 
| 
       284 
446 
     | 
    
         
             
                  const
         
     | 
| 
       285 
447 
     | 
    
         
             
                end
         
     | 
| 
       286 
448 
     | 
    
         | 
| 
       287 
     | 
    
         
            -
                 
     | 
| 
       288 
     | 
    
         
            -
             
     | 
| 
       289 
     | 
    
         
            -
                   
     | 
| 
       290 
     | 
    
         
            -
                   
     | 
| 
       291 
     | 
    
         
            -
                   
     | 
| 
       292 
     | 
    
         
            -
                   
     | 
| 
       293 
     | 
    
         
            -
             
     | 
| 
       294 
     | 
    
         
            -
             
     | 
| 
      
 449 
     | 
    
         
            +
                def _const_lookup(name)
         
     | 
| 
      
 450 
     | 
    
         
            +
                  # build constant lookup path: lexical scope first
         
     | 
| 
      
 451 
     | 
    
         
            +
                  # excluding the 
         
     | 
| 
      
 452 
     | 
    
         
            +
                  mn = self.find_current_class_or_module()&.nesting
         
     | 
| 
      
 453 
     | 
    
         
            +
                  return nil unless mn
         
     | 
| 
      
 454 
     | 
    
         
            +
                  # do not use find_class_... to find the Object class
         
     | 
| 
      
 455 
     | 
    
         
            +
                  # This is to avoid and endless loop
         
     | 
| 
      
 456 
     | 
    
         
            +
                  oc = WNode.root.klass 
         
     | 
| 
      
 457 
     | 
    
         
            +
                  #oc = self.find_class_or_module_by_name([:Object])
         
     | 
| 
      
 458 
     | 
    
         
            +
                  logger.debug "Module/Class nesting: #{mn.map(&:name)}"
         
     | 
| 
      
 459 
     | 
    
         
            +
                  # and ancestors second
         
     | 
| 
      
 460 
     | 
    
         
            +
                  lookup_path = mn + (mn.first || oc).ancestors
         
     | 
| 
      
 461 
     | 
    
         
            +
                  lookup_path += oc.ancestors if (oc && mn.first.const.module?)
         
     | 
| 
      
 462 
     | 
    
         
            +
                  logger.debug "searching constant #{name} in path #{lookup_path.map(&:name)}..."
         
     | 
| 
      
 463 
     | 
    
         
            +
                  const = nil
         
     | 
| 
      
 464 
     | 
    
         
            +
                  lookup_path.find do |mod|
         
     | 
| 
      
 465 
     | 
    
         
            +
                    logger.debug "++ looking for const #{name} in #{mod.name}"
         
     | 
| 
      
 466 
     | 
    
         
            +
                    const = mod.const_get(name)
         
     | 
| 
       295 
467 
     | 
    
         
             
                  end
         
     | 
| 
       296 
468 
     | 
    
         
             
                  if const
         
     | 
| 
       297 
     | 
    
         
            -
                    logger.debug " 
     | 
| 
      
 469 
     | 
    
         
            +
                    logger.debug "... found! in class #{const.scope_class&.name}"
         
     | 
| 
       298 
470 
     | 
    
         
             
                  else
         
     | 
| 
       299 
     | 
    
         
            -
                    logger.debug "Constant #{ 
     | 
| 
      
 471 
     | 
    
         
            +
                    logger.debug "Constant #{name} not found in lookup path #{lookup_path.map(&:name)}..." \
         
     | 
| 
       300 
472 
     | 
    
         
             
                  end
         
     | 
| 
       301 
473 
     | 
    
         
             
                  const
         
     | 
| 
       302 
474 
     | 
    
         
             
                end
         
     | 
| 
       303 
475 
     | 
    
         | 
| 
       304 
     | 
    
         
            -
                 
     | 
| 
       305 
     | 
    
         
            -
             
     | 
| 
      
 476 
     | 
    
         
            +
                # find or create constant, relative to current wnode
         
     | 
| 
      
 477 
     | 
    
         
            +
                def find_or_create_const(c_path, class_name, value, wtype)
         
     | 
| 
      
 478 
     | 
    
         
            +
                  self.find_const(c_path) || self.create_const(c_path, value, wtype)
         
     | 
| 
       306 
479 
     | 
    
         
             
                end
         
     | 
| 
       307 
480 
     | 
    
         | 
| 
       308 
     | 
    
         
            -
                 
     | 
| 
       309 
     | 
    
         
            -
             
     | 
| 
      
 481 
     | 
    
         
            +
                # find attr in current class
         
     | 
| 
      
 482 
     | 
    
         
            +
                def find_attr(name)
         
     | 
| 
      
 483 
     | 
    
         
            +
                  k = self.find_current_class_or_module()
         
     | 
| 
       310 
484 
     | 
    
         
             
                  raise "Can't find parent class for attr #{name}" unless k
         
     | 
| 
       311 
485 
     | 
    
         
             
                  logger.debug "looking for attr #{name} in class #{k.name} at wnode #{self.class_wnode}..."
         
     | 
| 
       312 
     | 
    
         
            -
                  k.attrs.find { |a| a. 
     | 
| 
      
 486 
     | 
    
         
            +
                  k.attrs.find { |a| a.klass == k && a.name == name }
         
     | 
| 
       313 
487 
     | 
    
         
             
                end
         
     | 
| 
       314 
488 
     | 
    
         | 
| 
       315 
489 
     | 
    
         
             
                def create_attr(name, wtype=WType::DEFAULT)
         
     | 
| 
       316 
     | 
    
         
            -
                  if ( 
     | 
| 
       317 
     | 
    
         
            -
                    logger.debug "creating attr #{name} in class #{ 
     | 
| 
       318 
     | 
    
         
            -
                     
     | 
| 
      
 490 
     | 
    
         
            +
                  if (k = self.find_current_class_or_module())
         
     | 
| 
      
 491 
     | 
    
         
            +
                    logger.debug "creating attr #{name} in class #{k.name} at wnode #{k.wnode}..."
         
     | 
| 
      
 492 
     | 
    
         
            +
                    k.attrs << (_attr = Attr.new(k, name, wtype))
         
     | 
| 
       319 
493 
     | 
    
         
             
                  else
         
     | 
| 
       320 
494 
     | 
    
         
             
                    raise "No class found for class attribute #{name}"
         
     | 
| 
       321 
495 
     | 
    
         
             
                  end
         
     | 
| 
       322 
496 
     | 
    
         
             
                  _attr
         
     | 
| 
       323 
497 
     | 
    
         
             
                end
         
     | 
| 
       324 
498 
     | 
    
         | 
| 
       325 
     | 
    
         
            -
                 
     | 
| 
       326 
     | 
    
         
            -
             
     | 
| 
      
 499 
     | 
    
         
            +
                # find or create attr in current class
         
     | 
| 
      
 500 
     | 
    
         
            +
                def find_or_create_attr(name, wtype=WType::DEFAULT)
         
     | 
| 
      
 501 
     | 
    
         
            +
                  find_attr(name) || create_attr(name, wtype)
         
     | 
| 
       327 
502 
     | 
    
         
             
                end
         
     | 
| 
       328 
503 
     | 
    
         | 
| 
       329 
504 
     | 
    
         
             
                def create_ivar(iv_name, wtype=WType::DEFAULT)
         
     | 
| 
       330 
     | 
    
         
            -
                  if ( 
     | 
| 
      
 505 
     | 
    
         
            +
                  if (k = self.find_current_class_or_module())
         
     | 
| 
       331 
506 
     | 
    
         
             
                    logger.debug "creating ivar #{iv_name} in class #{self.class_name} at wnode #{self.class_wnode}..."
         
     | 
| 
       332 
     | 
    
         
            -
                     
     | 
| 
      
 507 
     | 
    
         
            +
                    k.ivars << (ivar = IVar.new(k, iv_name, wtype))
         
     | 
| 
       333 
508 
     | 
    
         
             
                  else
         
     | 
| 
       334 
509 
     | 
    
         
             
                    raise "No class found for instance variable #{iv_name}"
         
     | 
| 
       335 
510 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -337,10 +512,10 @@ module Rlang::Parser 
     | 
|
| 
       337 
512 
     | 
    
         
             
                end
         
     | 
| 
       338 
513 
     | 
    
         | 
| 
       339 
514 
     | 
    
         
             
                def find_ivar(iv_name, class_name=nil)
         
     | 
| 
       340 
     | 
    
         
            -
                   
     | 
| 
       341 
     | 
    
         
            -
                  raise "Can't find parent class for ivar #{iv_name}" unless  
     | 
| 
       342 
     | 
    
         
            -
                  logger.debug "looking for ivar #{iv_name} in class #{ 
     | 
| 
       343 
     | 
    
         
            -
                  self.class_wnode.klass.ivars.find { |iv| iv. 
     | 
| 
      
 515 
     | 
    
         
            +
                  k = self.find_current_class_or_module()
         
     | 
| 
      
 516 
     | 
    
         
            +
                  raise "Can't find parent class for ivar #{iv_name}" unless k
         
     | 
| 
      
 517 
     | 
    
         
            +
                  logger.debug "looking for ivar #{iv_name} in class #{k.name} at wnode #{self.class_wnode}..."
         
     | 
| 
      
 518 
     | 
    
         
            +
                  self.class_wnode.klass.ivars.find { |iv| iv.klass == k && iv.name == iv_name }
         
     | 
| 
       344 
519 
     | 
    
         
             
                end
         
     | 
| 
       345 
520 
     | 
    
         | 
| 
       346 
521 
     | 
    
         
             
                def find_or_create_ivar(iv_name)
         
     | 
| 
         @@ -350,7 +525,7 @@ module Rlang::Parser 
     | 
|
| 
       350 
525 
     | 
    
         
             
                def create_cvar(cv_name, value=0, wtype=WType::DEFAULT)
         
     | 
| 
       351 
526 
     | 
    
         
             
                  if (cn = self.class_wnode)
         
     | 
| 
       352 
527 
     | 
    
         
             
                    logger.debug "creating cvar #{cv_name} in class #{self.class_name} at wnode #{self.class_wnode}..."
         
     | 
| 
       353 
     | 
    
         
            -
                    cn.klass.cvars << (cvar = CVar.new(cn.klass 
     | 
| 
      
 528 
     | 
    
         
            +
                    cn.klass.cvars << (cvar = CVar.new(cn.klass, cv_name, value, wtype))
         
     | 
| 
       354 
529 
     | 
    
         
             
                  else
         
     | 
| 
       355 
530 
     | 
    
         
             
                    raise "No class found for class variable #{cv_name}"
         
     | 
| 
       356 
531 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -384,7 +559,7 @@ module Rlang::Parser 
     | 
|
| 
       384 
559 
     | 
    
         
             
                  if (mn = self.method_wnode)
         
     | 
| 
       385 
560 
     | 
    
         
             
                    mn.method.margs << (marg = MArg.new(name))
         
     | 
| 
       386 
561 
     | 
    
         
             
                  else
         
     | 
| 
       387 
     | 
    
         
            -
                    raise "No class found for  
     | 
| 
      
 562 
     | 
    
         
            +
                    raise "No class found for method argument #{marg}"
         
     | 
| 
       388 
563 
     | 
    
         
             
                  end
         
     | 
| 
       389 
564 
     | 
    
         
             
                  marg
         
     | 
| 
       390 
565 
     | 
    
         
             
                end
         
     | 
| 
         @@ -394,44 +569,51 @@ module Rlang::Parser 
     | 
|
| 
       394 
569 
     | 
    
         
             
                end
         
     | 
| 
       395 
570 
     | 
    
         | 
| 
       396 
571 
     | 
    
         
             
                # method_type is either :instance or :class
         
     | 
| 
       397 
     | 
    
         
            -
                def create_method(method_name,  
     | 
| 
       398 
     | 
    
         
            -
                   
     | 
| 
       399 
     | 
    
         
            -
             
     | 
| 
       400 
     | 
    
         
            -
             
     | 
| 
       401 
     | 
    
         
            -
                  if  
     | 
| 
       402 
     | 
    
         
            -
             
     | 
| 
       403 
     | 
    
         
            -
             
     | 
| 
       404 
     | 
    
         
            -
             
     | 
| 
       405 
     | 
    
         
            -
             
     | 
| 
       406 
     | 
    
         
            -
                   
     | 
| 
       407 
     | 
    
         
            -
                   
     | 
| 
       408 
     | 
    
         
            -
                  method
         
     | 
| 
      
 572 
     | 
    
         
            +
                def create_method(klass, method_name, method_type, wtype, local=false)
         
     | 
| 
      
 573 
     | 
    
         
            +
                  logger.debug "Create #{method_type} method #{method_name} in class #{class_name || 'current'} / wtype: #{wtype}"
         
     | 
| 
      
 574 
     | 
    
         
            +
                  wtype ||= WType::DEFAULT
         
     | 
| 
      
 575 
     | 
    
         
            +
             
     | 
| 
      
 576 
     | 
    
         
            +
                  # see if method already created
         
     | 
| 
      
 577 
     | 
    
         
            +
                  m = find_method(klass, method_name, method_type, local)
         
     | 
| 
      
 578 
     | 
    
         
            +
                  raise "Method already exists: #{class_name},#{m.name} / ID: #{m}" if m
         
     | 
| 
      
 579 
     | 
    
         
            +
             
     | 
| 
      
 580 
     | 
    
         
            +
                  # Go create method
         
     | 
| 
      
 581 
     | 
    
         
            +
                  km = klass || self.find_current_class_or_module()
         
     | 
| 
      
 582 
     | 
    
         
            +
                  km.methods << (m = MEthod.new(method_name, km, wtype, method_type))
         
     | 
| 
      
 583 
     | 
    
         
            +
                  logger.debug "++++ adding #{method_type} method #{m.name}/ID:#{m} in class #{km.name}/ID:#{km}"
         
     | 
| 
      
 584 
     | 
    
         
            +
                  logger.debug "#{km.methods.count} methods in class #{km.name}/#{km}"
         
     | 
| 
      
 585 
     | 
    
         
            +
                  m
         
     | 
| 
       409 
586 
     | 
    
         
             
                end
         
     | 
| 
       410 
587 
     | 
    
         | 
| 
       411 
588 
     | 
    
         
             
                # method_type is either :instance or :class
         
     | 
| 
       412 
     | 
    
         
            -
                 
     | 
| 
       413 
     | 
    
         
            -
             
     | 
| 
       414 
     | 
    
         
            -
                   
     | 
| 
       415 
     | 
    
         
            -
                   
     | 
| 
       416 
     | 
    
         
            -
                   
     | 
| 
       417 
     | 
    
         
            -
             
     | 
| 
       418 
     | 
    
         
            -
                   
     | 
| 
       419 
     | 
    
         
            -
             
     | 
| 
       420 
     | 
    
         
            -
                   
     | 
| 
       421 
     | 
    
         
            -
             
     | 
| 
      
 589 
     | 
    
         
            +
                # if local is true look for method in the current class only
         
     | 
| 
      
 590 
     | 
    
         
            +
                def find_method(klass, method_name, method_type, local=false)
         
     | 
| 
      
 591 
     | 
    
         
            +
                  logger.debug "looking #{local ? 'locally' : 'globally'} for #{method_type} method #{method_name} in class #{klass}" #from wnode #{self.head(2)}"
         
     | 
| 
      
 592 
     | 
    
         
            +
                  km = klass || self.find_current_class_or_module()
         
     | 
| 
      
 593 
     | 
    
         
            +
                  raise "Couldn't find scope class/module where to search for method #{method_name}" unless km
         
     | 
| 
      
 594 
     | 
    
         
            +
             
     | 
| 
      
 595 
     | 
    
         
            +
                  class_hierarchy = (local ? [km] : km.ancestors)
         
     | 
| 
      
 596 
     | 
    
         
            +
                  logger.debug "searching #{method_type} method #{method_name} in ancestors #{class_hierarchy.map(&:name)}..."
         
     | 
| 
      
 597 
     | 
    
         
            +
                  method = nil
         
     | 
| 
      
 598 
     | 
    
         
            +
                  class_hierarchy.each do |k|
         
     | 
| 
      
 599 
     | 
    
         
            +
                    logger.debug "Currently #{k.methods.count} method(s) in class #{k.name}/#{k}"
         
     | 
| 
      
 600 
     | 
    
         
            +
                    method = k.methods.find do |m| 
         
     | 
| 
      
 601 
     | 
    
         
            +
                      logger.debug "++ looking for #{method_type} method #{k.name}/#{method_name} in #{m.klass.name}/#{m.name}/#{m.method_type}"
         
     | 
| 
      
 602 
     | 
    
         
            +
                      m.name == method_name && m.klass == k && m.method_type == method_type
         
     | 
| 
      
 603 
     | 
    
         
            +
                    end
         
     | 
| 
      
 604 
     | 
    
         
            +
                    break if method
         
     | 
| 
       422 
605 
     | 
    
         
             
                  end
         
     | 
| 
       423 
606 
     | 
    
         
             
                  if method
         
     | 
| 
       424 
     | 
    
         
            -
                    logger.debug "Found #{method_type}  
     | 
| 
      
 607 
     | 
    
         
            +
                    logger.debug "Found #{method_type} method: #{km.name},#{method.name} in #{method.klass.name}"
         
     | 
| 
       425 
608 
     | 
    
         
             
                  else
         
     | 
| 
       426 
     | 
    
         
            -
                    logger.debug "Couldn't find #{method_type}  
     | 
| 
      
 609 
     | 
    
         
            +
                    logger.debug "Couldn't find #{method_type} method: #{km.name},#{method_name}"
         
     | 
| 
       427 
610 
     | 
    
         
             
                  end
         
     | 
| 
       428 
611 
     | 
    
         
             
                  method
         
     | 
| 
       429 
612 
     | 
    
         
             
                end
         
     | 
| 
       430 
613 
     | 
    
         | 
| 
       431 
     | 
    
         
            -
                def find_or_create_method(method_name,  
     | 
| 
       432 
     | 
    
         
            -
                   
     | 
| 
       433 
     | 
    
         
            -
                  self. 
     | 
| 
       434 
     | 
    
         
            -
                  self.create_method(method_name, class_name, wtype, method_type)
         
     | 
| 
      
 614 
     | 
    
         
            +
                def find_or_create_method(klass, method_name, method_type, wtype, local=false)
         
     | 
| 
      
 615 
     | 
    
         
            +
                  self.find_method(klass, method_name, method_type, local) || 
         
     | 
| 
      
 616 
     | 
    
         
            +
                  self.create_method(klass, method_name, method_type, wtype, local)
         
     | 
| 
       435 
617 
     | 
    
         
             
                end
         
     | 
| 
       436 
618 
     | 
    
         | 
| 
       437 
619 
     | 
    
         
             
                # Find block wnode up the tree
         
     | 
| 
         @@ -452,6 +634,15 @@ module Rlang::Parser 
     | 
|
| 
       452 
634 
     | 
    
         
             
                  end
         
     | 
| 
       453 
635 
     | 
    
         
             
                end
         
     | 
| 
       454 
636 
     | 
    
         | 
| 
      
 637 
     | 
    
         
            +
                # Find module wnode up the tree
         
     | 
| 
      
 638 
     | 
    
         
            +
                def module_wnode
         
     | 
| 
      
 639 
     | 
    
         
            +
                  if self.module?
         
     | 
| 
      
 640 
     | 
    
         
            +
                    self
         
     | 
| 
      
 641 
     | 
    
         
            +
                  else
         
     | 
| 
      
 642 
     | 
    
         
            +
                    @parent ? @parent.module_wnode : nil
         
     | 
| 
      
 643 
     | 
    
         
            +
                  end
         
     | 
| 
      
 644 
     | 
    
         
            +
                end
         
     | 
| 
      
 645 
     | 
    
         
            +
             
     | 
| 
       455 
646 
     | 
    
         
             
                # Find class wnode up the tree
         
     | 
| 
       456 
647 
     | 
    
         
             
                def class_wnode
         
     | 
| 
       457 
648 
     | 
    
         
             
                  if self.class?
         
     | 
| 
         @@ -461,6 +652,16 @@ module Rlang::Parser 
     | 
|
| 
       461 
652 
     | 
    
         
             
                  end
         
     | 
| 
       462 
653 
     | 
    
         
             
                end
         
     | 
| 
       463 
654 
     | 
    
         | 
| 
      
 655 
     | 
    
         
            +
                # Find class or module wnode up the tree
         
     | 
| 
      
 656 
     | 
    
         
            +
                # which ever come first
         
     | 
| 
      
 657 
     | 
    
         
            +
                def class_or_module_wnode
         
     | 
| 
      
 658 
     | 
    
         
            +
                  if self.class? || self.module?
         
     | 
| 
      
 659 
     | 
    
         
            +
                    self
         
     | 
| 
      
 660 
     | 
    
         
            +
                  else
         
     | 
| 
      
 661 
     | 
    
         
            +
                    @parent ? @parent.class_or_module_wnode : nil
         
     | 
| 
      
 662 
     | 
    
         
            +
                  end
         
     | 
| 
      
 663 
     | 
    
         
            +
                end
         
     | 
| 
      
 664 
     | 
    
         
            +
             
     | 
| 
       464 
665 
     | 
    
         
             
                # Find method wnode up the tree
         
     | 
| 
       465 
666 
     | 
    
         
             
                def method_wnode
         
     | 
| 
       466 
667 
     | 
    
         
             
                  if self.method?
         
     | 
| 
         @@ -474,6 +675,7 @@ module Rlang::Parser 
     | 
|
| 
       474 
675 
     | 
    
         
             
                  return :class_method if self.in_class_method_scope?
         
     | 
| 
       475 
676 
     | 
    
         
             
                  return :instance_method if self.in_instance_method_scope?
         
     | 
| 
       476 
677 
     | 
    
         
             
                  return :class if self.in_class_scope?
         
     | 
| 
      
 678 
     | 
    
         
            +
                  return :module if self.in_module_scope?
         
     | 
| 
       477 
679 
     | 
    
         
             
                  return :root if self.in_root_scope?
         
     | 
| 
       478 
680 
     | 
    
         
             
                end
         
     | 
| 
       479 
681 
     | 
    
         | 
| 
         @@ -482,19 +684,27 @@ module Rlang::Parser 
     | 
|
| 
       482 
684 
     | 
    
         
             
                end
         
     | 
| 
       483 
685 
     | 
    
         | 
| 
       484 
686 
     | 
    
         
             
                def in_class_method_scope?
         
     | 
| 
       485 
     | 
    
         
            -
                   
     | 
| 
      
 687 
     | 
    
         
            +
                  self.in_method_scope? && self.method_wnode.method.class?
         
     | 
| 
       486 
688 
     | 
    
         
             
                end
         
     | 
| 
       487 
689 
     | 
    
         | 
| 
       488 
690 
     | 
    
         
             
                def in_instance_method_scope?
         
     | 
| 
       489 
     | 
    
         
            -
                   
     | 
| 
      
 691 
     | 
    
         
            +
                  self.in_method_scope? && self.method_wnode.method.instance?
         
     | 
| 
       490 
692 
     | 
    
         
             
                end
         
     | 
| 
       491 
693 
     | 
    
         | 
| 
       492 
694 
     | 
    
         
             
                def in_class_scope?
         
     | 
| 
       493 
     | 
    
         
            -
                  !self.class_wnode.nil? && self. 
     | 
| 
      
 695 
     | 
    
         
            +
                  !self.class_wnode.nil? && !self.in_method_scope?
         
     | 
| 
      
 696 
     | 
    
         
            +
                end
         
     | 
| 
      
 697 
     | 
    
         
            +
             
     | 
| 
      
 698 
     | 
    
         
            +
                def in_module_scope?
         
     | 
| 
      
 699 
     | 
    
         
            +
                  !self.module_wnode.nil? && !self.in_method_scope?
         
     | 
| 
      
 700 
     | 
    
         
            +
                end
         
     | 
| 
      
 701 
     | 
    
         
            +
             
     | 
| 
      
 702 
     | 
    
         
            +
                def in_class_or_module_scope?
         
     | 
| 
      
 703 
     | 
    
         
            +
                  self.in_class_scope? || self.in_module_scope?
         
     | 
| 
       494 
704 
     | 
    
         
             
                end
         
     | 
| 
       495 
705 
     | 
    
         | 
| 
       496 
706 
     | 
    
         
             
                def in_root_scope?
         
     | 
| 
       497 
     | 
    
         
            -
                  self.root? || (self.parent.root? && !in_class_scope?)
         
     | 
| 
      
 707 
     | 
    
         
            +
                  self.root? || (self.parent.root? && !self.in_class_scope?)
         
     | 
| 
       498 
708 
     | 
    
         
             
                end
         
     | 
| 
       499 
709 
     | 
    
         | 
| 
       500 
710 
     | 
    
         
             
                def method?
         
     | 
| 
         @@ -502,9 +712,14 @@ module Rlang::Parser 
     | 
|
| 
       502 
712 
     | 
    
         
             
                end
         
     | 
| 
       503 
713 
     | 
    
         | 
| 
       504 
714 
     | 
    
         
             
                def class?
         
     | 
| 
      
 715 
     | 
    
         
            +
                  # root always has the Object class associated
         
     | 
| 
       505 
716 
     | 
    
         
             
                  self.type == :class || self.type == :root 
         
     | 
| 
       506 
717 
     | 
    
         
             
                end
         
     | 
| 
       507 
718 
     | 
    
         | 
| 
      
 719 
     | 
    
         
            +
                def module?
         
     | 
| 
      
 720 
     | 
    
         
            +
                  self.type == :module
         
     | 
| 
      
 721 
     | 
    
         
            +
                end
         
     | 
| 
      
 722 
     | 
    
         
            +
             
     | 
| 
       508 
723 
     | 
    
         
             
                # format the wnode and tree below
         
     | 
| 
       509 
724 
     | 
    
         
             
                # Note: this a just a tree dump. The output generated is
         
     | 
| 
       510 
725 
     | 
    
         
             
                # not valid WAT code 
         
     | 
| 
         @@ -512,18 +727,48 @@ module Rlang::Parser 
     | 
|
| 
       512 
727 
     | 
    
         
             
                  "\n%sw(%s:%s" % [' '*2*indent, self.type, self.wasm_code] + self.children.map { |wn| wn.to_s(indent+1) }.join('') + ')'
         
     | 
| 
       513 
728 
     | 
    
         
             
                end
         
     | 
| 
       514 
729 
     | 
    
         | 
| 
      
 730 
     | 
    
         
            +
                def head(n=5)
         
     | 
| 
      
 731 
     | 
    
         
            +
                  (self.to_s.lines[0,n] << "...\n").join('')
         
     | 
| 
      
 732 
     | 
    
         
            +
                end
         
     | 
| 
      
 733 
     | 
    
         
            +
             
     | 
| 
       515 
734 
     | 
    
         
             
                # Generate WAT code starting for this node and tree branches below
         
     | 
| 
       516 
     | 
    
         
            -
                def transpile( 
     | 
| 
      
 735 
     | 
    
         
            +
                def transpile(depth=0)
         
     | 
| 
      
 736 
     | 
    
         
            +
                  # follow children first and then go on with
         
     | 
| 
      
 737 
     | 
    
         
            +
                  # the wnode link if it exits
         
     | 
| 
      
 738 
     | 
    
         
            +
                  children = self.children + (self.link ? [self.link] : [])
         
     | 
| 
      
 739 
     | 
    
         
            +
                  indent = ' ' * depth * 2
         
     | 
| 
      
 740 
     | 
    
         
            +
                  logger.debug "children: #{self} / #{children.map(&:head)}" if self.link
         
     | 
| 
      
 741 
     | 
    
         
            +
             
     | 
| 
       517 
742 
     | 
    
         
             
                  case @type
         
     | 
| 
       518 
     | 
    
         
            -
                   
     | 
| 
      
 743 
     | 
    
         
            +
                  # Section nodes
         
     | 
| 
      
 744 
     | 
    
         
            +
                  when :comment
         
     | 
| 
      
 745 
     | 
    
         
            +
                    "\n%s%s" % [indent, self.wasm_code]
         
     | 
| 
      
 746 
     | 
    
         
            +
                  when :imports
         
     | 
| 
      
 747 
     | 
    
         
            +
                    "\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
         
     | 
| 
      
 748 
     | 
    
         
            +
                    children.map { |wn| wn.transpile(depth) }.join('')
         
     | 
| 
      
 749 
     | 
    
         
            +
                  when :data
         
     | 
| 
      
 750 
     | 
    
         
            +
                    "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
         
     | 
| 
      
 751 
     | 
    
         
            +
                    DAta.transpile(depth)
         
     | 
| 
      
 752 
     | 
    
         
            +
                  when :globals
         
     | 
| 
      
 753 
     | 
    
         
            +
                    "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
         
     | 
| 
      
 754 
     | 
    
         
            +
                    Global.transpile(depth)
         
     | 
| 
      
 755 
     | 
    
         
            +
                  when :exports
         
     | 
| 
      
 756 
     | 
    
         
            +
                    "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] +
         
     | 
| 
      
 757 
     | 
    
         
            +
                    "%s(export \"memory\" (memory $0))\n" % [indent] +
         
     | 
| 
      
 758 
     | 
    
         
            +
                    Export.transpile(depth)        
         
     | 
| 
      
 759 
     | 
    
         
            +
                  when :insn, :method, :root
         
     | 
| 
       519 
760 
     | 
    
         
             
                    if @template == :inline
         
     | 
| 
       520 
     | 
    
         
            -
                      "\n%s%s" % [ 
     | 
| 
      
 761 
     | 
    
         
            +
                      "\n%s%s" % [indent, self.wasm_code]
         
     | 
| 
       521 
762 
     | 
    
         
             
                    else
         
     | 
| 
       522 
     | 
    
         
            -
                      "\n%s(%s" % [ 
     | 
| 
      
 763 
     | 
    
         
            +
                      "\n%s(%s" % [indent, self.wasm_code] + children.map { |wn| wn.transpile(depth+1) }.join('') + ')'
         
     | 
| 
       523 
764 
     | 
    
         
             
                    end
         
     | 
| 
       524 
     | 
    
         
            -
                  when : 
     | 
| 
      
 765 
     | 
    
         
            +
                  when :class, :module, :none, :memory
         
     | 
| 
       525 
766 
     | 
    
         
             
                    # no WAT code to generate for these nodes. Process children directly.
         
     | 
| 
       526 
     | 
    
         
            -
                     
     | 
| 
      
 767 
     | 
    
         
            +
                    children.map { |wn| wn.transpile(depth) }.join('')
         
     | 
| 
      
 768 
     | 
    
         
            +
                  when :silent
         
     | 
| 
      
 769 
     | 
    
         
            +
                    # Do not generate any WAT code for a silent node and
         
     | 
| 
      
 770 
     | 
    
         
            +
                    # and its children
         
     | 
| 
      
 771 
     | 
    
         
            +
                    ''
         
     | 
| 
       527 
772 
     | 
    
         
             
                  else
         
     | 
| 
       528 
773 
     | 
    
         
             
                    raise "Error: Unknown wnode type #{@type}. No WAT code generated"
         
     | 
| 
       529 
774 
     | 
    
         
             
                  end
         
     |