Class: Rlang::Parser::WNode
- Includes:
- Log
- Defined in:
- lib/rlang/parser/wnode.rb
Constant Summary collapse
- T =
WASM code templates
{ func: 'func %{func_name}', import: 'import "%{module_name}" "%{function_name}"', param: 'param %{name} %{wasm_type}', result: 'result %{wasm_type}', return: 'return', local: 'local %{name} %{wasm_type}', call: 'call %{func_name}', store: '%{wasm_type}.store', store_offset: '%{wasm_type}.store offset=%{offset}', load: '%{wasm_type}.load', load_offset: '%{wasm_type}.load offset=%{offset}', local_get: 'local.get %{var_name}', local_set: 'local.set %{var_name}', global_get: 'global.get %{var_name}', global_set: 'global.set %{var_name}', addr: 'i32.const %{value}', operator: '%{wasm_type}.%{operator}', const: '%{wasm_type}.const %{value}', drop: 'drop', nop: 'nop', extend_i32_u: '%{wasm_type}.extend_i32_u', extend_i32_s: '%{wasm_type}.extend_i32_s', wrap_i64: '%{wasm_type}.wrap_i64', eqz: '%{wasm_type}.eqz', if: 'if', then: 'then', else: 'else', block: 'block %{label}', loop: 'loop %{label}', br_if: 'br_if %{label}', br: 'br %{label}', inline: '%{code}', attr_getter: %q{func %{func_name} (param $_self_ i32) (result %{wasm_type}) (%{wasm_type}.load offset=%{offset} (local.get $_self_))}, attr_setter: %q{func %{func_name} (param $_self_ i32) (param %{attr_name} %{wasm_type}) (result %{wasm_type}) (local.get %{attr_name}) (%{wasm_type}.store offset=%{offset} (local.get $_self_) (local.get %{attr_name}))}, class_size: %q{func %{func_name} (result %{wasm_type}) (%{wasm_type}.const %{size})}, comment: ';; %{text}', memory: 'memory $0 %{min} %{max}', module: 'module %{module}' }
- @@label_index =
0
Instance Attribute Summary collapse
-
#children ⇒ Object
Returns the value of attribute children.
-
#classes ⇒ Object
Returns the value of attribute classes.
-
#comment ⇒ Object
Returns the value of attribute comment.
-
#keep_on_stack ⇒ Object
Returns the value of attribute keep_on_stack.
-
#klass ⇒ Object
Returns the value of attribute klass.
-
#label ⇒ Object
readonly
Returns the value of attribute label.
-
#link ⇒ Object
Returns the value of attribute link.
-
#method ⇒ Object
Returns the value of attribute method.
-
#module ⇒ Object
readonly
Returns the value of attribute module.
-
#modules ⇒ Object
Returns the value of attribute modules.
-
#parent ⇒ Object
Returns the value of attribute parent.
-
#template ⇒ Object
Returns the value of attribute template.
-
#type ⇒ Object
Returns the value of attribute type.
-
#wargs ⇒ Object
Returns the value of attribute wargs.
-
#wtype ⇒ Object
Returns the value of attribute wtype.
Class Method Summary collapse
Instance Method Summary collapse
- #_const_lookup(name) ⇒ Object
-
#add_child(wnode, prepend = false) ⇒ Object
(also: #<<)
Add a new child to current node at the end or at the beginning of the child list.
-
#block_wnode ⇒ Object
Find block wnode up the tree.
-
#c(template, wargs = {}) ⇒ Object
set instruction template and args.
- #class? ⇒ Boolean
-
#class_name ⇒ Object
Find class name in this node and up the tree.
-
#class_or_module_wnode ⇒ Object
Find class or module wnode up the tree which ever come first.
-
#class_size ⇒ Object
Find class size in this wnode or up the tree.
-
#class_wnode ⇒ Object
Find class wnode up the tree.
-
#const? ⇒ Boolean
Says whether this wnode produces a straight WASM const node in the end.
- #create_attr(name, wtype = WType::DEFAULT) ⇒ Object
-
#create_class(class_path, super_class_path) ⇒ Object
Create a Class object.
-
#create_const(c_path, value, wtype) ⇒ Object
create a constant, relative to the current wnode the constant is assumed to not exist already.
- #create_cvar(cv_name, value = 0, wtype = WType::DEFAULT) ⇒ Object
- #create_ivar(iv_name, wtype = WType::DEFAULT) ⇒ Object
- #create_lvar(name) ⇒ Object
-
#create_marg(name) ⇒ Object
add method argument.
-
#create_method(klass, method_name, method_type, wtype, local = false) ⇒ Object
method_type is either :instance or :class.
-
#create_module(module_path) ⇒ Object
Create a module object.
-
#delete! ⇒ Object
delete current wnode (which means basically remove it as a child).
-
#find_attr(name) ⇒ Object
find attr in current class.
-
#find_class_or_module(class_path) ⇒ Object
Find the class object of the current and up the tree if no name given or lookup the matching class from the root level if class name given class_path can be passed either as in a Symbol (e.g. :“A::B”) or as an array of symbols (e.g. [:A, :B]).
-
#find_class_or_module_by_name(class_path) ⇒ Object
Find the class by doing a lookup on the constant.
-
#find_const(c_path) ⇒ Object
Look for constant from where we are in wtree For a Ruby implementation of the constant lookup algo, see cirw.in/blog/constant-lookup - c_path is an array of constant name elements e.g.
-
#find_current_class_or_module ⇒ Object
Return the first class/module up the tree.
- #find_cvar(cv_name) ⇒ Object
- #find_ivar(iv_name, class_name = nil) ⇒ Object
- #find_lvar(name) ⇒ Object
- #find_marg(name) ⇒ Object
-
#find_method(klass, method_name, method_type, local = false) ⇒ Object
method_type is either :instance or :class if local is true look for method in the current class only.
-
#find_module(module_path) ⇒ Object
Find the module object of the current wnode and up the tree if no name given or lookup the matching class from the root level if module name given.
-
#find_or_create_attr(name, wtype = WType::DEFAULT) ⇒ Object
find or create attr in current class.
- #find_or_create_class(class_path, super_class_path) ⇒ Object
-
#find_or_create_const(c_path, class_name, value, wtype) ⇒ Object
find or create constant, relative to current wnode.
- #find_or_create_ivar(iv_name) ⇒ Object
- #find_or_create_lvar(name) ⇒ Object
- #find_or_create_method(klass, method_name, method_type, wtype, local = false) ⇒ Object
- #find_or_create_module(module_path) ⇒ Object
- #head(n = 5) ⇒ Object
- #in_class_method_scope? ⇒ Boolean
- #in_class_or_module_scope? ⇒ Boolean
- #in_class_scope? ⇒ Boolean
- #in_instance_method_scope? ⇒ Boolean
- #in_method_scope? ⇒ Boolean
- #in_module_scope? ⇒ Boolean
- #in_root_scope? ⇒ Boolean
-
#initialize(type, parent = nil, prepend = false) ⇒ WNode
constructor
A new instance of WNode.
-
#insert(type = :none) ⇒ Object
insert a blank wnode above self, so between self wnode and its parent (self -> parent becomes self -> wn -> parent).
-
#loop_wnode ⇒ Object
Find loop wnode up the tree.
- #method? ⇒ Boolean
-
#method_wnode ⇒ Object
Find method wnode up the tree.
- #module? ⇒ Boolean
-
#module_wnode ⇒ Object
Find module wnode up the tree.
-
#remove_child(wnode) ⇒ Object
(also: #>>)
Remove child from current node.
-
#reparent_children_to(wnode) ⇒ Object
Reparent all children wnodes to another wnode (in the same order) WARNING!! Do not use self.children.each { } to reparent because we are modifying children list as we go.
-
#reparent_to(wnode) ⇒ Object
Reparent self node to another wnode.
- #root? ⇒ Boolean
- #scope ⇒ Object
- #set_label ⇒ Object
-
#silence! ⇒ Object
Silence the current wnode (which means inserting a silent type wnode between this and its parent).
-
#to_s(indent = 0) ⇒ Object
format the wnode and tree below Note: this a just a tree dump.
-
#transpile(depth = 0) ⇒ Object
Generate WAT code starting for this node and tree branches below.
- #wasm_code ⇒ Object
- #wasm_type ⇒ Object
Methods included from Log
included, logger, #logger, logger=
Constructor Details
#initialize(type, parent = nil, prepend = false) ⇒ WNode
Returns a new instance of WNode.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rlang/parser/wnode.rb', line 74 def initialize(type, parent=nil, prepend=false) @type = type # :root, :method, :class, :insn, :none @parent = parent @comment = nil @wargs = {} @template = nil @children = [] @@root = self if type == :root # make this wnode a child of its parent @parent.add_child(self, prepend) if @parent # WASM type of this node. If node is :method # then it's the type of the return value (nil # means no value returned) @wtype = WType::DEFAULT # top level class needed only if const are # defined at top level # NOTE: can't use create_klass as it find_class # which doesn't find root class ... endless loop!! # For class or module wnode only @klass = nil # For method wnode only @method = nil # For insn wnode with # label (.e.g block, loop) @label = nil # link to a related node # Semantic of the link depend on the wnode type @link = nil end |
Instance Attribute Details
#children ⇒ Object
Returns the value of attribute children.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def children @children end |
#classes ⇒ Object
Returns the value of attribute classes.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def classes @classes end |
#comment ⇒ Object
Returns the value of attribute comment.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def comment @comment end |
#keep_on_stack ⇒ Object
Returns the value of attribute keep_on_stack.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def keep_on_stack @keep_on_stack end |
#klass ⇒ Object
Returns the value of attribute klass.
70 71 72 |
# File 'lib/rlang/parser/wnode.rb', line 70 def klass @klass end |
#label ⇒ Object (readonly)
Returns the value of attribute label.
70 71 72 |
# File 'lib/rlang/parser/wnode.rb', line 70 def label @label end |
#link ⇒ Object
Returns the value of attribute link.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def link @link end |
#method ⇒ Object
Returns the value of attribute method.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def method @method end |
#module ⇒ Object (readonly)
Returns the value of attribute module.
70 71 72 |
# File 'lib/rlang/parser/wnode.rb', line 70 def module @module end |
#modules ⇒ Object
Returns the value of attribute modules.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def modules @modules end |
#parent ⇒ Object
Returns the value of attribute parent.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def parent @parent end |
#template ⇒ Object
Returns the value of attribute template.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def template @template end |
#type ⇒ Object
Returns the value of attribute type.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def type @type end |
#wargs ⇒ Object
Returns the value of attribute wargs.
67 68 69 |
# File 'lib/rlang/parser/wnode.rb', line 67 def wargs @wargs end |
#wtype ⇒ Object
Returns the value of attribute wtype.
70 71 72 |
# File 'lib/rlang/parser/wnode.rb', line 70 def wtype @wtype end |
Class Method Details
Instance Method Details
#_const_lookup(name) ⇒ Object
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
# File 'lib/rlang/parser/wnode.rb', line 449 def _const_lookup(name) # build constant lookup path: lexical scope first # excluding the mn = self.find_current_class_or_module()&.nesting return nil unless mn # do not use find_class_... to find the Object class # This is to avoid and endless loop oc = WNode.root.klass #oc = self.find_class_or_module_by_name([:Object]) logger.debug "Module/Class nesting: #{mn.map(&:name)}" # and ancestors second lookup_path = mn + (mn.first || oc).ancestors lookup_path += oc.ancestors if (oc && mn.first.const.module?) logger.debug "searching constant #{name} in path #{lookup_path.map(&:name)}..." const = nil lookup_path.find do |mod| logger.debug "++ looking for const #{name} in #{mod.name}" const = mod.const_get(name) end if const logger.debug "... found! in class #{const.scope_class&.name}" else logger.debug "Constant #{name} not found in lookup path #{lookup_path.map(&:name)}..." \ end const end |
#add_child(wnode, prepend = false) ⇒ Object Also known as: <<
Add a new child to current node at the end or at the beginning of the child list
190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/rlang/parser/wnode.rb', line 190 def add_child(wnode, prepend=false) #logger.debug "Adding #{wnode.object_id} to #{self.object_id} (children: #{self.children.map(&:object_id)})" if prepend self.children.unshift(wnode) else self.children << wnode end wnode.parent = self #logger.debug "Added #{wnode.object_id} to #{self.object_id} (children: #{self.children.map(&:object_id)})" #logger.debug "Parent of #{wnode.object_id} is now #{wnode.parent.object_id}" self end |
#block_wnode ⇒ Object
Find block wnode up the tree
620 621 622 623 624 625 626 |
# File 'lib/rlang/parser/wnode.rb', line 620 def block_wnode if self.template == :block self else @parent ? @parent.block_wnode : nil end end |
#c(template, wargs = {}) ⇒ Object
set instruction template and args
126 127 128 129 130 131 132 133 134 |
# File 'lib/rlang/parser/wnode.rb', line 126 def c(template, wargs = {}) raise "Error: unknown WASM code template (#{template})" unless T.has_key? template raise "Error: this WNode is already populated with instruction #{@template}" if @template #if [:loop, :block].include? template # wargs[:label] = self.set_label #end @template = template @wargs = wargs end |
#class? ⇒ Boolean
714 715 716 717 |
# File 'lib/rlang/parser/wnode.rb', line 714 def class? # root always has the Object class associated self.type == :class || self.type == :root end |
#class_name ⇒ Object
Find class name in this node and up the tree
267 268 269 |
# File 'lib/rlang/parser/wnode.rb', line 267 def class_name (cn = self.class_wnode) ? cn.klass.path_name : nil end |
#class_or_module_wnode ⇒ Object
Find class or module wnode up the tree which ever come first
657 658 659 660 661 662 663 |
# File 'lib/rlang/parser/wnode.rb', line 657 def class_or_module_wnode if self.class? || self.module? self else @parent ? @parent.class_or_module_wnode : nil end end |
#class_size ⇒ Object
Find class size in this wnode or up the tree
272 273 274 |
# File 'lib/rlang/parser/wnode.rb', line 272 def class_size (cn = self.class_wnode) ? cn.klass.size : nil end |
#class_wnode ⇒ Object
Find class wnode up the tree
647 648 649 650 651 652 653 |
# File 'lib/rlang/parser/wnode.rb', line 647 def class_wnode if self.class? self else @parent ? @parent.class_wnode : nil end end |
#const? ⇒ Boolean
Says whether this wnode produces a straight WASM const node in the end
121 122 123 |
# File 'lib/rlang/parser/wnode.rb', line 121 def const? self.template == :const || self.template == :addr end |
#create_attr(name, wtype = WType::DEFAULT) ⇒ Object
489 490 491 492 493 494 495 496 497 |
# File 'lib/rlang/parser/wnode.rb', line 489 def create_attr(name, wtype=WType::DEFAULT) if (k = self.find_current_class_or_module()) logger.debug "creating attr #{name} in class #{k.name} at wnode #{k.wnode}..." k.attrs << (_attr = Attr.new(k, name, wtype)) else raise "No class found for class attribute #{name}" end _attr end |
#create_class(class_path, super_class_path) ⇒ Object
Create a Class object. The code below assumes the class doesn’t exist
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
# File 'lib/rlang/parser/wnode.rb', line 369 def create_class(class_path, super_class_path) # check that super class exists super_class = nil unless super_class_path.empty? super_class_const = self.find_const(super_class_path) raise NameError, "uninitialized constant #{super_class_path}" \ unless super_class_const super_class = super_class_const.scope_class end # Find current class or module (lexical scope) # special case for Object class if class_path == [:Object] && self.in_root_scope? scope_class = nil else scope_class = self.find_current_class_or_module() end # Create the constant associated to this class # the class itself const = self.create_const(class_path, nil, WType.new(:Class)) k = Klass.new(const, scope_class, super_class) # special case to bootstrap Object class if class_path == [:Object] && self.in_root_scope? const.scope_class = k end # create class wnode wnc = WNode.new(:class, self) wnc.klass = k k.wnode = wnc logger.debug "Created class #{k.name}/ID: #{k} under wnode #{self}/ ID: #{self.object_id}" k end |
#create_const(c_path, value, wtype) ⇒ Object
create a constant, relative to the current wnode the constant is assumed to not exist already
417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/rlang/parser/wnode.rb', line 417 def create_const(c_path, value, wtype) logger.debug "Creating constant #{c_path} / wtype: #{wtype} at wnode #{self.class_wnode.head}..." raise "Dynamic constant assignment. Constant #{name} cannot be created in scope #{cmn.scope}" \ if self.in_method_scope? # if const_path has more than one element then check # that all element but last already exist !(c_prefix = c_path[0..-2]).empty? && self.find_const(c_prefix) c_name = c_path.last const = Const.new(c_name, value, wtype) end |
#create_cvar(cv_name, value = 0, wtype = WType::DEFAULT) ⇒ Object
525 526 527 528 529 530 531 532 533 |
# File 'lib/rlang/parser/wnode.rb', line 525 def create_cvar(cv_name, value=0, wtype=WType::DEFAULT) if (cn = self.class_wnode) logger.debug "creating cvar #{cv_name} in class #{self.class_name} at wnode #{self.class_wnode}..." cn.klass.cvars << (cvar = CVar.new(cn.klass, cv_name, value, wtype)) else raise "No class found for class variable #{cv_name}" end cvar end |
#create_ivar(iv_name, wtype = WType::DEFAULT) ⇒ Object
504 505 506 507 508 509 510 511 512 |
# File 'lib/rlang/parser/wnode.rb', line 504 def create_ivar(iv_name, wtype=WType::DEFAULT) if (k = self.find_current_class_or_module()) logger.debug "creating ivar #{iv_name} in class #{self.class_name} at wnode #{self.class_wnode}..." k.ivars << (ivar = IVar.new(k, iv_name, wtype)) else raise "No class found for instance variable #{iv_name}" end ivar end |
#create_lvar(name) ⇒ Object
540 541 542 543 544 545 546 547 |
# File 'lib/rlang/parser/wnode.rb', line 540 def create_lvar(name) if (mn = self.method_wnode) mn.method.lvars << (lvar = LVar.new(name)) else raise "No method found for local variable #{name}" end lvar end |
#create_marg(name) ⇒ Object
add method argument
558 559 560 561 562 563 564 565 |
# File 'lib/rlang/parser/wnode.rb', line 558 def create_marg(name) if (mn = self.method_wnode) mn.method.margs << (marg = MArg.new(name)) else raise "No class found for method argument #{marg}" end marg end |
#create_method(klass, method_name, method_type, wtype, local = false) ⇒ Object
method_type is either :instance or :class
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
# File 'lib/rlang/parser/wnode.rb', line 572 def create_method(klass, method_name, method_type, wtype, local=false) logger.debug "Create #{method_type} method #{method_name} in class #{class_name || 'current'} / wtype: #{wtype}" wtype ||= WType::DEFAULT # see if method already created m = find_method(klass, method_name, method_type, local) raise "Method already exists: #{class_name},#{m.name} / ID: #{m}" if m # Go create method km = klass || self.find_current_class_or_module() km.methods << (m = MEthod.new(method_name, km, wtype, method_type)) logger.debug "++++ adding #{method_type} method #{m.name}/ID:#{m} in class #{km.name}/ID:#{km}" logger.debug "#{km.methods.count} methods in class #{km.name}/#{km}" m end |
#create_module(module_path) ⇒ Object
Create a module object
291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/rlang/parser/wnode.rb', line 291 def create_module(module_path) # Create the constant associated to this module klass = self.find_current_class_or_module() logger.debug "Creating module #{module_path} in class #{klass} under wnode #{self.head}" const = self.create_const(module_path, nil, WType.new(:Module)) modul = Module.new(const, klass) # Add the constant to list of constants in current scope class klass.consts << const # Generate wnode wnc = WNode.new(:module, self) wnc.klass = modul logger.debug "Created module #{modul.name}/ID:#{modul} under wnode #{wnc.parent} / ID: #{self.object_id}" modul end |
#delete! ⇒ Object
delete current wnode (which means basically remove it as a child)
248 249 250 251 |
# File 'lib/rlang/parser/wnode.rb', line 248 def delete! return if self.root? || self.parent.nil? self.parent.remove_child(self) end |
#find_attr(name) ⇒ Object
find attr in current class
482 483 484 485 486 487 |
# File 'lib/rlang/parser/wnode.rb', line 482 def find_attr(name) k = self.find_current_class_or_module() raise "Can't find parent class for attr #{name}" unless k logger.debug "looking for attr #{name} in class #{k.name} at wnode #{self.class_wnode}..." k.attrs.find { |a| a.klass == k && a.name == name } end |
#find_class_or_module(class_path) ⇒ Object
Find the class object of the current and up the tree if no name given or lookup the matching class from the root level if class name given class_path can be passed either as in a Symbol (e.g. :“A::B”) or as an array of symbols (e.g. [:A, :B])
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/rlang/parser/wnode.rb', line 347 def find_class_or_module(class_path) logger.debug "looking for #{class_path} class in scope #{self.scope} at wnode #{self.head}" # turn the symbol form of class_path into the array form if class_path.is_a? Symbol class_path = class_path.to_s.split('::').map(&:to_sym) end if class_path.empty? k = self.find_current_class_or_module() else k = self.find_class_or_module_by_name(class_path) end if k logger.debug "Found class #{k.name} / #{k}" else logger.debug "Class #{class_path} not found!" end k end |
#find_class_or_module_by_name(class_path) ⇒ Object
Find the class by doing a lookup on the constant
328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/rlang/parser/wnode.rb', line 328 def find_class_or_module_by_name(class_path) raise "Class name argument expected" unless class_path && !class_path.empty? logger.debug "looking for class/module constant #{class_path} in scope #{self.scope} at wnode #{self.head}" const = self.find_const(class_path) #raise "Class or Module #{class_path} not found!" unless const if const logger.debug "Found constant #{const.name} pointing to #{const.value}" const.value else logger.debug "Constant #{class_path} not found" nil end end |
#find_const(c_path) ⇒ Object
Look for constant from where we are in wtree For a Ruby implementation of the constant lookup algo, see cirw.in/blog/constant-lookup
- c_path is an array of constant name elements
e.g. for constant A::B::C constant_path is [A, B, C]
434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
# File 'lib/rlang/parser/wnode.rb', line 434 def find_const(c_path) logger.debug "looking for constant #{c_path}...from wnode #{self.head}..." wn = self; idx = 0; count = c_path.size while idx < count const = wn._const_lookup(c_path[idx]) if const && (idx < count-1) && (const.class? || const.module?) && const.scope_class wn = const.value.wnode else raise NameError, "uninitialized constant #{c_path.join('::')}" unless idx == count-1 end idx += 1 end const end |
#find_current_class_or_module ⇒ Object
Return the first class/module up the tree
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/rlang/parser/wnode.rb', line 311 def find_current_class_or_module() logger.debug "looking for current class in scope #{self.scope} at wnode #{self.head(3)}" if wn = self.class_or_module_wnode k = wn.klass elsif self.in_root_scope? # methods defined at root level goes to Object Class k = self.find_class_or_module_by_name([:Object]) end if k logger.debug "Found class #{k.name} / #{k}" else logger.debug "No current class found!" end k end |
#find_cvar(cv_name) ⇒ Object
535 536 537 538 |
# File 'lib/rlang/parser/wnode.rb', line 535 def find_cvar(cv_name) logger.debug "looking for cvar #{cv_name} in class #{self.class_name} at wnode #{self.class_wnode}..." self.class_wnode.klass.cvars.find { |cv| cv.class_name == self.class_name && cv.name == cv_name } end |
#find_ivar(iv_name, class_name = nil) ⇒ Object
514 515 516 517 518 519 |
# File 'lib/rlang/parser/wnode.rb', line 514 def find_ivar(iv_name, class_name=nil) k = self.find_current_class_or_module() raise "Can't find parent class for ivar #{iv_name}" unless k logger.debug "looking for ivar #{iv_name} in class #{k.name} at wnode #{self.class_wnode}..." self.class_wnode.klass.ivars.find { |iv| iv.klass == k && iv.name == iv_name } end |
#find_lvar(name) ⇒ Object
549 550 551 |
# File 'lib/rlang/parser/wnode.rb', line 549 def find_lvar(name) self.method_wnode.method.lvars.find { |lv| lv.name == name } end |
#find_marg(name) ⇒ Object
567 568 569 |
# File 'lib/rlang/parser/wnode.rb', line 567 def find_marg(name) self.method_wnode.method.margs.find { |ma| ma.name == name } end |
#find_method(klass, method_name, method_type, local = false) ⇒ Object
method_type is either :instance or :class if local is true look for method in the current class only
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 |
# File 'lib/rlang/parser/wnode.rb', line 590 def find_method(klass, method_name, method_type, local=false) logger.debug "looking #{local ? 'locally' : 'globally'} for #{method_type} method #{method_name} in class #{klass}" #from wnode #{self.head(2)}" km = klass || self.find_current_class_or_module() raise "Couldn't find scope class/module where to search for method #{method_name}" unless km class_hierarchy = (local ? [km] : km.ancestors) logger.debug "searching #{method_type} method #{method_name} in ancestors #{class_hierarchy.map(&:name)}..." method = nil class_hierarchy.each do |k| logger.debug "Currently #{k.methods.count} method(s) in class #{k.name}/#{k}" method = k.methods.find do |m| logger.debug "++ looking for #{method_type} method #{k.name}/#{method_name} in #{m.klass.name}/#{m.name}/#{m.method_type}" m.name == method_name && m.klass == k && m.method_type == method_type end break if method end if method logger.debug "Found #{method_type} method: #{km.name},#{method.name} in #{method.klass.name}" else logger.debug "Couldn't find #{method_type} method: #{km.name},#{method_name}" end method end |
#find_module(module_path) ⇒ Object
Find the module object of the current wnode and up the tree if no name given or lookup the matching class from the root level if module name given
280 281 282 283 284 285 286 287 288 |
# File 'lib/rlang/parser/wnode.rb', line 280 def find_module(module_path) logger.debug "looking for #{module_path} module in scope #{self.scope}" # at wnode #{self}" if modul = self.find_class_or_module_by_name(module_path) logger.debug "Found module #{modul.name} / #{modul}" else logger.debug "Module #{module_path} not found" end modul end |
#find_or_create_attr(name, wtype = WType::DEFAULT) ⇒ Object
find or create attr in current class
500 501 502 |
# File 'lib/rlang/parser/wnode.rb', line 500 def find_or_create_attr(name, wtype=WType::DEFAULT) find_attr(name) || create_attr(name, wtype) end |
#find_or_create_class(class_path, super_class_path) ⇒ Object
405 406 407 408 409 410 411 412 413 |
# File 'lib/rlang/parser/wnode.rb', line 405 def find_or_create_class(class_path, super_class_path) logger.debug "Find/Create class: #{class_path}" if (km = self.find_class_or_module(class_path)) raise TypeError, "#{class_path} is not a class" unless km.const.class? else km = self.create_class(class_path, super_class_path) end km end |
#find_or_create_const(c_path, class_name, value, wtype) ⇒ Object
find or create constant, relative to current wnode
477 478 479 |
# File 'lib/rlang/parser/wnode.rb', line 477 def find_or_create_const(c_path, class_name, value, wtype) self.find_const(c_path) || self.create_const(c_path, value, wtype) end |
#find_or_create_ivar(iv_name) ⇒ Object
521 522 523 |
# File 'lib/rlang/parser/wnode.rb', line 521 def find_or_create_ivar(iv_name) self.find_ivar(iv_name) || self.create_ivar(iv_name) end |
#find_or_create_lvar(name) ⇒ Object
553 554 555 |
# File 'lib/rlang/parser/wnode.rb', line 553 def find_or_create_lvar(name) self.find_lvar(name) || self.create_lvar(name) end |
#find_or_create_method(klass, method_name, method_type, wtype, local = false) ⇒ Object
614 615 616 617 |
# File 'lib/rlang/parser/wnode.rb', line 614 def find_or_create_method(klass, method_name, method_type, wtype, local=false) self.find_method(klass, method_name, method_type, local) || self.create_method(klass, method_name, method_type, wtype, local) end |
#find_or_create_module(module_path) ⇒ Object
306 307 308 |
# File 'lib/rlang/parser/wnode.rb', line 306 def find_or_create_module(module_path) self.find_module(module_path) || self.create_module(module_path) end |
#head(n = 5) ⇒ Object
730 731 732 |
# File 'lib/rlang/parser/wnode.rb', line 730 def head(n=5) (self.to_s.lines[0,n] << "...\n").join('') end |
#in_class_method_scope? ⇒ Boolean
686 687 688 |
# File 'lib/rlang/parser/wnode.rb', line 686 def in_class_method_scope? self.in_method_scope? && self.method_wnode.method.class? end |
#in_class_or_module_scope? ⇒ Boolean
702 703 704 |
# File 'lib/rlang/parser/wnode.rb', line 702 def in_class_or_module_scope? self.in_class_scope? || self.in_module_scope? end |
#in_class_scope? ⇒ Boolean
694 695 696 |
# File 'lib/rlang/parser/wnode.rb', line 694 def in_class_scope? !self.class_wnode.nil? && !self.in_method_scope? end |
#in_instance_method_scope? ⇒ Boolean
690 691 692 |
# File 'lib/rlang/parser/wnode.rb', line 690 def in_instance_method_scope? self.in_method_scope? && self.method_wnode.method.instance? end |
#in_method_scope? ⇒ Boolean
682 683 684 |
# File 'lib/rlang/parser/wnode.rb', line 682 def in_method_scope? !self.method_wnode.nil? end |
#in_module_scope? ⇒ Boolean
698 699 700 |
# File 'lib/rlang/parser/wnode.rb', line 698 def in_module_scope? !self.module_wnode.nil? && !self.in_method_scope? end |
#in_root_scope? ⇒ Boolean
706 707 708 |
# File 'lib/rlang/parser/wnode.rb', line 706 def in_root_scope? self.root? || (self.parent.root? && !self.in_class_scope?) end |
#insert(type = :none) ⇒ Object
insert a blank wnode above self, so between self wnode and its parent (self -> parent becomes self -> wn -> parent)
240 241 242 243 244 |
# File 'lib/rlang/parser/wnode.rb', line 240 def insert(type=:none) wn = WNode.new(type, self.parent) self.reparent_to(wn) wn end |
#loop_wnode ⇒ Object
Find loop wnode up the tree
629 630 631 632 633 634 635 |
# File 'lib/rlang/parser/wnode.rb', line 629 def loop_wnode if self.template == :loop self else @parent ? @parent.loop_wnode : nil end end |
#method? ⇒ Boolean
710 711 712 |
# File 'lib/rlang/parser/wnode.rb', line 710 def method? self.type == :method end |
#method_wnode ⇒ Object
Find method wnode up the tree
666 667 668 669 670 671 672 |
# File 'lib/rlang/parser/wnode.rb', line 666 def method_wnode if self.method? self else @parent ? @parent.method_wnode : nil end end |
#module? ⇒ Boolean
719 720 721 |
# File 'lib/rlang/parser/wnode.rb', line 719 def module? self.type == :module end |
#module_wnode ⇒ Object
Find module wnode up the tree
638 639 640 641 642 643 644 |
# File 'lib/rlang/parser/wnode.rb', line 638 def module_wnode if self.module? self else @parent ? @parent.module_wnode : nil end end |
#remove_child(wnode) ⇒ Object Also known as: >>
Remove child from current node
205 206 207 208 209 210 211 212 213 |
# File 'lib/rlang/parser/wnode.rb', line 205 def remove_child(wnode) logger.debug "Removing #{wnode.object_id} from wnodes list #{self.children.map(&:object_id)} under parent #{self.parent.object_id}" unless (wn = self.children.delete(wnode)) && wn == wnode raise "Couldn't find wnode ID #{wnode.object_id} (#{wnode})" end wn.parent = nil #logger.debug "Removed #{wnode.object_id} from #{self.object_id} (children: #{self.children.map(&:object_id)})" wnode end |
#reparent_children_to(wnode) ⇒ Object
Reparent all children wnodes to another wnode (in the same order) WARNING!! Do not use self.children.each { } to reparent because we are modifying children list as we go
232 233 234 235 236 |
# File 'lib/rlang/parser/wnode.rb', line 232 def reparent_children_to(wnode) wnc = self.children wnc.count.times { wnc.first.reparent_to(wnode) } self end |
#reparent_to(wnode) ⇒ Object
Reparent self node to another wnode
217 218 219 220 221 222 223 224 225 |
# File 'lib/rlang/parser/wnode.rb', line 217 def reparent_to(wnode) unless self.parent == wnode logger.debug "Reparenting #{self.object_id} from #{self.parent.object_id} to #{wnode.object_id}" old_parent, new_parent = self.parent, wnode old_parent >> self if old_parent new_parent << self end self end |
#root? ⇒ Boolean
115 116 117 |
# File 'lib/rlang/parser/wnode.rb', line 115 def root? self == @@root end |
#scope ⇒ Object
674 675 676 677 678 679 680 |
# File 'lib/rlang/parser/wnode.rb', line 674 def scope return :class_method if self.in_class_method_scope? return :instance_method if self.in_instance_method_scope? return :class if self.in_class_scope? return :module if self.in_module_scope? return :root if self.in_root_scope? end |
#set_label ⇒ Object
167 168 169 |
# File 'lib/rlang/parser/wnode.rb', line 167 def set_label @label = "$lbl_#{'%02d' % (@@label_index += 1)}" end |
#silence! ⇒ Object
Silence the current wnode (which means inserting a silent type wnode between this and its parent)
256 257 258 |
# File 'lib/rlang/parser/wnode.rb', line 256 def silence! self.insert(:silent) end |
#to_s(indent = 0) ⇒ Object
format the wnode and tree below Note: this a just a tree dump. The output generated is not valid WAT code
726 727 728 |
# File 'lib/rlang/parser/wnode.rb', line 726 def to_s(indent=0) "\n%sw(%s:%s" % [' '*2*indent, self.type, self.wasm_code] + self.children.map { |wn| wn.to_s(indent+1) }.join('') + ')' end |
#transpile(depth = 0) ⇒ Object
Generate WAT code starting for this node and tree branches below
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 |
# File 'lib/rlang/parser/wnode.rb', line 735 def transpile(depth=0) # follow children first and then go on with # the wnode link if it exits children = self.children + (self.link ? [self.link] : []) indent = ' ' * depth * 2 logger.debug "children: #{self} / #{children.map(&:head)}" if self.link case @type # Section nodes when :comment "\n%s%s" % [indent, self.wasm_code] when :imports "\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] + children.map { |wn| wn.transpile(depth) }.join('') when :data "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] + DAta.transpile(depth) when :globals "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] + Global.transpile(depth) when :exports "\n\n%s;;============= %s SECTION ===============\n" % [indent, @type.to_s.upcase] + "%s(export \"memory\" (memory $0))\n" % [indent] + Export.transpile(depth) when :insn, :method, :root if @template == :inline "\n%s%s" % [indent, self.wasm_code] else "\n%s(%s" % [indent, self.wasm_code] + children.map { |wn| wn.transpile(depth+1) }.join('') + ')' end when :class, :module, :none, :memory # no WAT code to generate for these nodes. Process children directly. children.map { |wn| wn.transpile(depth) }.join('') when :silent # Do not generate any WAT code for a silent node and # and its children '' else raise "Error: Unknown wnode type #{@type}. No WAT code generated" end end |
#wasm_code ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/rlang/parser/wnode.rb', line 136 def wasm_code return '' unless T[@template] wargs = {} @wargs.each { |k, v| wargs[k] = (v.is_a?(Proc) ? v.call : v) } # Because WNode#to_s generate wasm code from sometimes incomplete # information, we must add the wasm_type key if needed by the template if T[@template].index("%{wasm_type}") puts "*** adding wasm_type to #{T[@template]}" unless wargs.has_key? :wasm_type wargs[:wasm_type] ||= self.wasm_type end # debug code to activate if you get # a Ruby warning on too many or too few arguments # wargs.each do |k, v| # if T[@template].index("%{#{k.to_s}}").nil? # puts "**** Error wargs missing keys in wargs : template: #{@template} / wargs: #{wargs.inspect}" # end # end #T[@template].scan(/%{([^}]+)}/).flatten.each do |k| # unless wargs.has_key? k.to_sym # puts "**** Error wargs missing keys in template: template: #{@template} / wargs: #{wargs.inspect}" # end # end #logger.debug "code template : #{@template} / T : #{T[@template]} / wargs : #{wargs.inspect}" if @template T[@template] ? T[@template] % wargs : '' end |
#wasm_type ⇒ Object
163 164 165 |
# File 'lib/rlang/parser/wnode.rb', line 163 def wasm_type @wtype.wasm_type end |