rlang 0.4.1 → 0.5.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 +4 -1
- data/Gemfile.lock +1 -1
- data/README.md +15 -9
- data/docs/RlangManual.md +26 -4
- data/lib/rlang/lib/array/array32.rb +43 -0
- data/lib/rlang/lib/array/array64.rb +43 -0
- data/lib/rlang/lib/array.rb +6 -0
- data/lib/rlang/lib/kernel.rb +18 -0
- data/lib/rlang/lib/malloc.rb +5 -3
- data/lib/rlang/lib/memory.rb +102 -2
- data/lib/rlang/lib/object.rb +11 -4
- data/lib/rlang/lib/string.rb +1 -0
- data/lib/rlang/lib/unistd.rb +1 -2
- data/lib/rlang/lib.rb +4 -2
- data/lib/rlang/parser/attr.rb +9 -13
- data/lib/rlang/parser/const.rb +105 -1
- data/lib/rlang/parser/cvar.rb +10 -6
- data/lib/rlang/parser/data.rb +5 -2
- data/lib/rlang/parser/ivar.rb +3 -7
- data/lib/rlang/parser/klass.rb +8 -35
- data/lib/rlang/parser/method.rb +22 -11
- data/lib/rlang/parser/module.rb +143 -0
- data/lib/rlang/parser/wgenerator.rb +190 -90
- data/lib/rlang/parser/wnode.rb +296 -121
- data/lib/rlang/parser/wtype.rb +18 -1
- data/lib/rlang/parser.rb +224 -113
- data/lib/rlang/version.rb +1 -1
- metadata +7 -2
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
|
@@ -60,8 +61,9 @@ module Rlang::Parser
|
|
60
61
|
}
|
61
62
|
|
62
63
|
attr_accessor :type, :wargs, :children, :parent, :comment,
|
63
|
-
|
64
|
-
|
64
|
+
:method, :template, :keep_on_stack, :classes,
|
65
|
+
:modules
|
66
|
+
attr_reader :wtype, :label, :klass, :module
|
65
67
|
|
66
68
|
@@label_index = 0
|
67
69
|
|
@@ -82,16 +84,13 @@ module Rlang::Parser
|
|
82
84
|
# means no value returned)
|
83
85
|
@wtype = WType::DEFAULT
|
84
86
|
|
85
|
-
# For root wnode
|
86
|
-
@classes = [] # classes
|
87
87
|
# top level class needed only if const are
|
88
88
|
# defined at top level
|
89
89
|
# NOTE: can't use create_klass as it find_class
|
90
90
|
# which doesn't find root class ... endless loop!!
|
91
91
|
|
92
|
-
# For class wnode only
|
93
|
-
|
94
|
-
self.klass = Klass.new(:Top__) if self.root?
|
92
|
+
# For class or module wnode only
|
93
|
+
@klass = nil
|
95
94
|
|
96
95
|
# For method wnode only
|
97
96
|
@method = nil
|
@@ -192,16 +191,16 @@ module Rlang::Parser
|
|
192
191
|
self
|
193
192
|
end
|
194
193
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
194
|
+
# Reparent all children wnodes to another wnode
|
195
|
+
# (in the same order)
|
196
|
+
# WARNING!! Do not use self.children.each { } to
|
197
|
+
# reparent because we are modifying children list
|
198
|
+
# as we go
|
199
|
+
def reparent_children_to(wnode)
|
200
|
+
wnc = self.children
|
201
|
+
wnc.count.times { wnc.first.reparent_to(wnode) }
|
202
|
+
self
|
203
|
+
end
|
205
204
|
|
206
205
|
# insert a blank wnode above self, so between self wnode
|
207
206
|
# and its parent (self -> parent becomes self -> wn -> parent)
|
@@ -211,16 +210,22 @@ module Rlang::Parser
|
|
211
210
|
wn
|
212
211
|
end
|
213
212
|
|
213
|
+
# delete current wnode (which means
|
214
|
+
# basically remove it as a child)
|
215
|
+
def delete!
|
216
|
+
return if self.root? || self.parent.nil?
|
217
|
+
self.parent.remove_child(self)
|
218
|
+
end
|
219
|
+
|
214
220
|
def klass=(klass)
|
215
221
|
@klass = klass
|
216
222
|
@klass.wnode = self
|
217
|
-
|
218
|
-
klass
|
223
|
+
@klass
|
219
224
|
end
|
220
225
|
|
221
226
|
# Find class name in this node and up the tree
|
222
227
|
def class_name
|
223
|
-
(cn = self.class_wnode) ? cn.klass.
|
228
|
+
(cn = self.class_wnode) ? cn.klass.path_name : nil
|
224
229
|
end
|
225
230
|
|
226
231
|
# Find class size in this wnode or up the tree
|
@@ -228,108 +233,238 @@ module Rlang::Parser
|
|
228
233
|
(cn = self.class_wnode) ? cn.klass.size : nil
|
229
234
|
end
|
230
235
|
|
236
|
+
# Find the module object of the current wnode and up the tree
|
237
|
+
# if no name given
|
238
|
+
# or lookup the matching class from
|
239
|
+
# the root level if module name given
|
240
|
+
def find_module(module_path)
|
241
|
+
logger.debug "looking for #{module_path} module in scope #{self.scope}" # at wnode #{self}"
|
242
|
+
if modul = self.find_class_or_module_by_name(module_path)
|
243
|
+
logger.debug "Found module #{modul.name} / #{modul}"
|
244
|
+
else
|
245
|
+
logger.debug "Module #{module_path} not found"
|
246
|
+
end
|
247
|
+
modul
|
248
|
+
end
|
249
|
+
|
250
|
+
# Create a module object
|
251
|
+
def create_module(module_path)
|
252
|
+
# Create the constant associated to this module
|
253
|
+
klass = self.find_current_class_or_module()
|
254
|
+
logger.debug "Creating module #{module_path} in class #{klass} under wnode #{self.head}"
|
255
|
+
const = self.create_const(module_path, nil, WType.new(:Module))
|
256
|
+
modul = Module.new(const, klass)
|
257
|
+
# Add the constant to list of constants in current scope class
|
258
|
+
klass.consts << const
|
259
|
+
# Generate wnode
|
260
|
+
wnc = WNode.new(:module, self)
|
261
|
+
wnc.klass = modul
|
262
|
+
logger.debug "Created module #{modul.name}/ID:#{modul} under wnode #{wnc.parent} / ID: #{self.object_id}"
|
263
|
+
modul
|
264
|
+
end
|
265
|
+
|
266
|
+
def find_or_create_module(module_path)
|
267
|
+
self.find_module(module_path) || self.create_module(module_path)
|
268
|
+
end
|
269
|
+
|
270
|
+
# Return the first class/module up the tree
|
271
|
+
def find_current_class_or_module()
|
272
|
+
logger.debug "looking for current class in scope #{self.scope} at wnode #{self.head(3)}"
|
273
|
+
if wn = self.class_or_module_wnode
|
274
|
+
k = wn.klass
|
275
|
+
elsif self.in_root_scope?
|
276
|
+
# methods defined at root level goes to Object Class
|
277
|
+
k = self.find_class_or_module_by_name([:Object])
|
278
|
+
end
|
279
|
+
if k
|
280
|
+
logger.debug "Found class #{k.name} / #{k}"
|
281
|
+
else
|
282
|
+
logger.debug "No current class found!"
|
283
|
+
end
|
284
|
+
k
|
285
|
+
end
|
286
|
+
|
287
|
+
# Find the class by doing a lookup on the constant
|
288
|
+
def find_class_or_module_by_name(class_path)
|
289
|
+
raise "Class name argument expected" unless class_path && !class_path.empty?
|
290
|
+
logger.debug "looking for class/module constant #{class_path} in scope #{self.scope} at wnode #{self.head}"
|
291
|
+
const = self.find_const(class_path)
|
292
|
+
#raise "Class or Module #{class_path} not found!" unless const
|
293
|
+
if const
|
294
|
+
logger.debug "Found constant #{const.name} pointing to #{const.value}"
|
295
|
+
const.value
|
296
|
+
else
|
297
|
+
logger.debug "Constant #{class_path} not found"
|
298
|
+
nil
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
231
302
|
# Find the class object of the current and up the tree
|
232
303
|
# if no name given or lookup the matching class from
|
233
304
|
# the root level if class name given
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
305
|
+
# class_path can be passed either as in a Symbol (e.g. :"A::B")
|
306
|
+
# or as an array of symbols (e.g. [:A, :B])
|
307
|
+
def find_class_or_module(class_path)
|
308
|
+
logger.debug "looking for #{class_path} class in scope #{self.scope} at wnode #{self.head}"
|
309
|
+
# turn the symbol form of class_path into the array form
|
310
|
+
if class_path.is_a? Symbol
|
311
|
+
class_path = class_path.to_s.split('::').map(&:to_sym)
|
312
|
+
end
|
313
|
+
|
314
|
+
if class_path.empty?
|
315
|
+
k = self.find_current_class_or_module()
|
240
316
|
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}"
|
317
|
+
k = self.find_class_or_module_by_name(class_path)
|
318
|
+
end
|
319
|
+
if k
|
320
|
+
logger.debug "Found class #{k.name} / #{k}"
|
256
321
|
else
|
257
|
-
logger.debug "Class #{
|
322
|
+
logger.debug "Class #{class_path} not found!"
|
323
|
+
end
|
324
|
+
k
|
325
|
+
end
|
326
|
+
|
327
|
+
# Create a Class object. The code below assumes
|
328
|
+
# the class doesn't exist
|
329
|
+
def create_class(class_path, super_class_path)
|
330
|
+
# check that super class exists
|
331
|
+
super_class = nil
|
332
|
+
unless super_class_path.empty?
|
333
|
+
super_class_const = self.find_const(super_class_path)
|
334
|
+
raise NameError, "uninitialized constant #{super_class_path}" \
|
335
|
+
unless super_class_const
|
336
|
+
super_class = super_class_const.scope_class
|
258
337
|
end
|
259
|
-
c
|
260
|
-
end
|
261
338
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
end
|
339
|
+
# Find current class or module (lexical scope)
|
340
|
+
# special case for Object class
|
341
|
+
if class_path == [:Object] && self.in_root_scope?
|
342
|
+
scope_class = nil
|
343
|
+
else
|
344
|
+
scope_class = self.find_current_class_or_module()
|
345
|
+
end
|
270
346
|
|
271
|
-
|
272
|
-
|
347
|
+
# Create the constant associated to this class
|
348
|
+
# the class itself
|
349
|
+
const = self.create_const(class_path, nil, WType.new(:Class))
|
350
|
+
k = Klass.new(const, scope_class, super_class)
|
351
|
+
|
352
|
+
# special case to bootstrap Object class
|
353
|
+
if class_path == [:Object] && self.in_root_scope?
|
354
|
+
const.scope_class = k
|
355
|
+
end
|
356
|
+
|
357
|
+
# create class wnode
|
358
|
+
wnc = WNode.new(:class, self)
|
359
|
+
wnc.klass = k
|
360
|
+
k.wnode = wnc
|
361
|
+
logger.debug "Created class #{k.name}/ID: #{k} under wnode #{self}/ ID: #{self.object_id}"
|
362
|
+
k
|
273
363
|
end
|
274
364
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
if (cn = self.class_wnode)
|
280
|
-
cn.klass.consts << (const = Const.new(k.name, c_name, value, wtype))
|
365
|
+
def find_or_create_class(class_path, super_class_path)
|
366
|
+
logger.debug "Find/Create class: #{class_path}"
|
367
|
+
if (km = self.find_class_or_module(class_path))
|
368
|
+
raise TypeError, "#{class_path} is not a class" unless km.const.class?
|
281
369
|
else
|
282
|
-
|
370
|
+
km = self.create_class(class_path, super_class_path)
|
371
|
+
end
|
372
|
+
km
|
373
|
+
end
|
374
|
+
|
375
|
+
# create a constant, relative to the current wnode
|
376
|
+
# the constant is assumed to not exist already
|
377
|
+
def create_const(c_path, value, wtype)
|
378
|
+
logger.debug "Creating constant #{c_path} / wtype: #{wtype} at wnode #{self.class_wnode.head}..."
|
379
|
+
raise "Dynamic constant assignment. Constant #{name} cannot be created in scope #{cmn.scope}" \
|
380
|
+
if self.in_method_scope?
|
381
|
+
|
382
|
+
# if const_path has more than one element then check
|
383
|
+
# that all element but last already exist
|
384
|
+
!(c_prefix = c_path[0..-2]).empty? && self.find_const(c_prefix)
|
385
|
+
c_name = c_path.last
|
386
|
+
const = Const.new(c_name, value, wtype)
|
387
|
+
end
|
388
|
+
|
389
|
+
# Look for constant from where we are in wtree
|
390
|
+
# For a Ruby implementation of the constant lookup
|
391
|
+
# algo, see https://cirw.in/blog/constant-lookup
|
392
|
+
# - c_path is an array of constant name elements
|
393
|
+
# e.g. for constant A::B::C constant_path is [A, B, C]
|
394
|
+
def find_const(c_path)
|
395
|
+
logger.debug "looking for constant #{c_path}...from wnode #{self.head}..."
|
396
|
+
wn = self; idx = 0; count = c_path.size
|
397
|
+
while idx < count
|
398
|
+
const = wn._const_lookup(c_path[idx])
|
399
|
+
if const && (idx < count-1) && (const.class? || const.module?) && const.scope_class
|
400
|
+
wn = const.value.wnode
|
401
|
+
else
|
402
|
+
raise NameError, "uninitialized constant #{c_path.join('::')}" unless idx == count-1
|
403
|
+
end
|
404
|
+
idx += 1
|
283
405
|
end
|
284
406
|
const
|
285
407
|
end
|
286
408
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
409
|
+
def _const_lookup(name)
|
410
|
+
# build constant lookup path: lexical scope first
|
411
|
+
# excluding the
|
412
|
+
mn = self.find_current_class_or_module()&.nesting
|
413
|
+
return nil unless mn
|
414
|
+
# do not use find_class_... to find the Object class
|
415
|
+
# This is to avoid and endless loop
|
416
|
+
oc = WNode.root.klass
|
417
|
+
#oc = self.find_class_or_module_by_name([:Object])
|
418
|
+
logger.debug "Module/Class nesting: #{mn.map(&:name)}"
|
419
|
+
# and ancestors second
|
420
|
+
lookup_path = mn + (mn.first || oc).ancestors
|
421
|
+
lookup_path += oc.ancestors if (oc && mn.first.const.module?)
|
422
|
+
logger.debug "searching constant #{name} in path #{lookup_path.map(&:name)}..."
|
423
|
+
const = nil
|
424
|
+
lookup_path.find do |mod|
|
425
|
+
logger.debug "++ looking for const #{name} in #{mod.name}"
|
426
|
+
const = mod.const_get(name)
|
295
427
|
end
|
296
428
|
if const
|
297
|
-
logger.debug "
|
429
|
+
logger.debug "... found! in class #{const.scope_class&.name}"
|
298
430
|
else
|
299
|
-
logger.debug "Constant #{
|
431
|
+
logger.debug "Constant #{name} not found in lookup path #{lookup_path.map(&:name)}..." \
|
300
432
|
end
|
301
433
|
const
|
302
434
|
end
|
303
435
|
|
304
|
-
|
305
|
-
|
436
|
+
# find or create constant, relative to current wnode
|
437
|
+
def find_or_create_const(c_path, class_name, value, wtype)
|
438
|
+
self.find_const(c_path) || self.create_const(c_path, value, wtype)
|
306
439
|
end
|
307
440
|
|
308
|
-
|
309
|
-
|
441
|
+
# find attr in current class
|
442
|
+
def find_attr(name)
|
443
|
+
k = self.find_current_class_or_module()
|
310
444
|
raise "Can't find parent class for attr #{name}" unless k
|
311
445
|
logger.debug "looking for attr #{name} in class #{k.name} at wnode #{self.class_wnode}..."
|
312
|
-
k.attrs.find { |a| a.
|
446
|
+
k.attrs.find { |a| a.klass == k && a.name == name }
|
313
447
|
end
|
314
448
|
|
315
449
|
def create_attr(name, wtype=WType::DEFAULT)
|
316
|
-
if (
|
317
|
-
logger.debug "creating attr #{name} in class #{
|
318
|
-
|
450
|
+
if (k = self.find_current_class_or_module())
|
451
|
+
logger.debug "creating attr #{name} in class #{k.name} at wnode #{k.wnode}..."
|
452
|
+
k.attrs << (_attr = Attr.new(k, name, wtype))
|
319
453
|
else
|
320
454
|
raise "No class found for class attribute #{name}"
|
321
455
|
end
|
322
456
|
_attr
|
323
457
|
end
|
324
458
|
|
325
|
-
|
326
|
-
|
459
|
+
# find or create attr in current class
|
460
|
+
def find_or_create_attr(name, wtype=WType::DEFAULT)
|
461
|
+
find_attr(name) || create_attr(name, wtype)
|
327
462
|
end
|
328
463
|
|
329
464
|
def create_ivar(iv_name, wtype=WType::DEFAULT)
|
330
|
-
if (
|
465
|
+
if (k = self.find_current_class_or_module())
|
331
466
|
logger.debug "creating ivar #{iv_name} in class #{self.class_name} at wnode #{self.class_wnode}..."
|
332
|
-
|
467
|
+
k.ivars << (ivar = IVar.new(k, iv_name, wtype))
|
333
468
|
else
|
334
469
|
raise "No class found for instance variable #{iv_name}"
|
335
470
|
end
|
@@ -337,10 +472,10 @@ module Rlang::Parser
|
|
337
472
|
end
|
338
473
|
|
339
474
|
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.
|
475
|
+
k = self.find_current_class_or_module()
|
476
|
+
raise "Can't find parent class for ivar #{iv_name}" unless k
|
477
|
+
logger.debug "looking for ivar #{iv_name} in class #{k.name} at wnode #{self.class_wnode}..."
|
478
|
+
self.class_wnode.klass.ivars.find { |iv| iv.klass == k && iv.name == iv_name }
|
344
479
|
end
|
345
480
|
|
346
481
|
def find_or_create_ivar(iv_name)
|
@@ -350,7 +485,7 @@ module Rlang::Parser
|
|
350
485
|
def create_cvar(cv_name, value=0, wtype=WType::DEFAULT)
|
351
486
|
if (cn = self.class_wnode)
|
352
487
|
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
|
488
|
+
cn.klass.cvars << (cvar = CVar.new(cn.klass, cv_name, value, wtype))
|
354
489
|
else
|
355
490
|
raise "No class found for class variable #{cv_name}"
|
356
491
|
end
|
@@ -394,44 +529,51 @@ module Rlang::Parser
|
|
394
529
|
end
|
395
530
|
|
396
531
|
# 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
|
532
|
+
def create_method(klass, method_name, method_type, wtype, local=false)
|
533
|
+
logger.debug "Create #{method_type} method #{method_name} in class #{class_name || 'current'} / wtype: #{wtype}"
|
534
|
+
wtype ||= WType::DEFAULT
|
535
|
+
|
536
|
+
# see if method already created
|
537
|
+
m = find_method(klass, method_name, method_type, local)
|
538
|
+
raise "Method already exists: #{class_name},#{m.name} / ID: #{m}" if m
|
539
|
+
|
540
|
+
# Go create method
|
541
|
+
km = klass || self.find_current_class_or_module()
|
542
|
+
km.methods << (m = MEthod.new(method_name, km, wtype, method_type))
|
543
|
+
logger.debug "++++ adding #{method_type} method #{m.name}/ID:#{m} in class #{km.name}/ID:#{km}"
|
544
|
+
logger.debug "#{km.methods.count} methods in class #{km.name}/#{km}"
|
545
|
+
m
|
409
546
|
end
|
410
547
|
|
411
548
|
# method_type is either :instance or :class
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
549
|
+
# if local is true look for method in the current class only
|
550
|
+
def find_method(klass, method_name, method_type, local=false)
|
551
|
+
logger.debug "looking #{local ? 'locally' : 'globally'} for #{method_type} method #{method_name} in class #{klass}" #from wnode #{self.head(2)}"
|
552
|
+
km = klass || self.find_current_class_or_module()
|
553
|
+
raise "Couldn't find scope class/module where to search for method #{method_name}" unless km
|
554
|
+
|
555
|
+
class_hierarchy = (local ? [km] : km.ancestors)
|
556
|
+
logger.debug "searching #{method_type} method #{method_name} in ancestors #{class_hierarchy.map(&:name)}..."
|
557
|
+
method = nil
|
558
|
+
class_hierarchy.each do |k|
|
559
|
+
logger.debug "Currently #{k.methods.count} method(s) in class #{k.name}/#{k}"
|
560
|
+
method = k.methods.find do |m|
|
561
|
+
logger.debug "++ looking for #{method_type} method #{k.name}/#{method_name} in #{m.klass.name}/#{m.name}/#{m.method_type}"
|
562
|
+
m.name == method_name && m.klass == k && m.method_type == method_type
|
563
|
+
end
|
564
|
+
break if method
|
422
565
|
end
|
423
566
|
if method
|
424
|
-
logger.debug "Found #{method_type}
|
567
|
+
logger.debug "Found #{method_type} method: #{km.name},#{method.name} in #{method.klass.name}"
|
425
568
|
else
|
426
|
-
logger.debug "Couldn't find #{method_type}
|
569
|
+
logger.debug "Couldn't find #{method_type} method: #{km.name},#{method_name}"
|
427
570
|
end
|
428
571
|
method
|
429
572
|
end
|
430
573
|
|
431
|
-
def find_or_create_method(method_name,
|
432
|
-
|
433
|
-
self.
|
434
|
-
self.create_method(method_name, class_name, wtype, method_type)
|
574
|
+
def find_or_create_method(klass, method_name, method_type, wtype, local=false)
|
575
|
+
self.find_method(klass, method_name, method_type, local) ||
|
576
|
+
self.create_method(klass, method_name, method_type, wtype, local)
|
435
577
|
end
|
436
578
|
|
437
579
|
# Find block wnode up the tree
|
@@ -452,6 +594,15 @@ module Rlang::Parser
|
|
452
594
|
end
|
453
595
|
end
|
454
596
|
|
597
|
+
# Find module wnode up the tree
|
598
|
+
def module_wnode
|
599
|
+
if self.module?
|
600
|
+
self
|
601
|
+
else
|
602
|
+
@parent ? @parent.module_wnode : nil
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
455
606
|
# Find class wnode up the tree
|
456
607
|
def class_wnode
|
457
608
|
if self.class?
|
@@ -461,6 +612,16 @@ module Rlang::Parser
|
|
461
612
|
end
|
462
613
|
end
|
463
614
|
|
615
|
+
# Find class or module wnode up the tree
|
616
|
+
# which ever come first
|
617
|
+
def class_or_module_wnode
|
618
|
+
if self.class? || self.module?
|
619
|
+
self
|
620
|
+
else
|
621
|
+
@parent ? @parent.class_or_module_wnode : nil
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
464
625
|
# Find method wnode up the tree
|
465
626
|
def method_wnode
|
466
627
|
if self.method?
|
@@ -474,6 +635,7 @@ module Rlang::Parser
|
|
474
635
|
return :class_method if self.in_class_method_scope?
|
475
636
|
return :instance_method if self.in_instance_method_scope?
|
476
637
|
return :class if self.in_class_scope?
|
638
|
+
return :module if self.in_module_scope?
|
477
639
|
return :root if self.in_root_scope?
|
478
640
|
end
|
479
641
|
|
@@ -482,19 +644,23 @@ module Rlang::Parser
|
|
482
644
|
end
|
483
645
|
|
484
646
|
def in_class_method_scope?
|
485
|
-
|
647
|
+
self.in_method_scope? && self.method_wnode.method.class?
|
486
648
|
end
|
487
649
|
|
488
650
|
def in_instance_method_scope?
|
489
|
-
|
651
|
+
self.in_method_scope? && self.method_wnode.method.instance?
|
490
652
|
end
|
491
653
|
|
492
654
|
def in_class_scope?
|
493
|
-
!self.class_wnode.nil? && self.
|
655
|
+
!self.class_wnode.nil? && !self.in_method_scope?
|
656
|
+
end
|
657
|
+
|
658
|
+
def in_module_scope?
|
659
|
+
!self.module_wnode.nil? && !self.in_method_scope?
|
494
660
|
end
|
495
661
|
|
496
662
|
def in_root_scope?
|
497
|
-
self.root? || (self.parent.root? && !in_class_scope?)
|
663
|
+
self.root? || (self.parent.root? && !self.in_class_scope?)
|
498
664
|
end
|
499
665
|
|
500
666
|
def method?
|
@@ -502,9 +668,14 @@ module Rlang::Parser
|
|
502
668
|
end
|
503
669
|
|
504
670
|
def class?
|
671
|
+
# root always has the Object class associated
|
505
672
|
self.type == :class || self.type == :root
|
506
673
|
end
|
507
674
|
|
675
|
+
def module?
|
676
|
+
self.type == :module
|
677
|
+
end
|
678
|
+
|
508
679
|
# format the wnode and tree below
|
509
680
|
# Note: this a just a tree dump. The output generated is
|
510
681
|
# not valid WAT code
|
@@ -512,6 +683,10 @@ module Rlang::Parser
|
|
512
683
|
"\n%sw(%s:%s" % [' '*2*indent, self.type, self.wasm_code] + self.children.map { |wn| wn.to_s(indent+1) }.join('') + ')'
|
513
684
|
end
|
514
685
|
|
686
|
+
def head(n=5)
|
687
|
+
(self.to_s.lines[0,n] << "...\n").join('')
|
688
|
+
end
|
689
|
+
|
515
690
|
# Generate WAT code starting for this node and tree branches below
|
516
691
|
def transpile(indent=0)
|
517
692
|
case @type
|
@@ -521,7 +696,7 @@ module Rlang::Parser
|
|
521
696
|
else
|
522
697
|
"\n%s(%s" % [' '*2*indent, self.wasm_code] + self.children.map { |wn| wn.transpile(indent+1) }.join('') + ')'
|
523
698
|
end
|
524
|
-
when :root, :class, :none
|
699
|
+
when :root, :class, :module, :none
|
525
700
|
# no WAT code to generate for these nodes. Process children directly.
|
526
701
|
self.children.map { |wn| wn.transpile(indent) }.join('')
|
527
702
|
else
|
data/lib/rlang/parser/wtype.rb
CHANGED
@@ -45,11 +45,28 @@ class WType
|
|
45
45
|
wtypes[leading_idx]
|
46
46
|
end
|
47
47
|
|
48
|
+
# Name is a symbol of the form :A or :"A::B" or :"A::B::C"
|
49
|
+
# or a string "A" or "A::B" or "A::B::C"
|
50
|
+
# or it can also be an array of symbols [:A], [:A, :B] or [:A, :B, :C]
|
51
|
+
# (It is not a class object)
|
48
52
|
def initialize(name)
|
49
|
-
|
53
|
+
if name.is_a? Symbol
|
54
|
+
@name = name
|
55
|
+
elsif name.is_a? String
|
56
|
+
@name = name.to_sym
|
57
|
+
elsif name.is_a? Array
|
58
|
+
@name = name.map(&:to_s).join('::').to_sym
|
59
|
+
else
|
60
|
+
raise "Unknown type for WType name (got #{name}, class: #{name.class}"
|
61
|
+
end
|
50
62
|
raise "Invalid WType #{name.inspect}" unless self.valid?
|
51
63
|
end
|
52
64
|
|
65
|
+
def class_path
|
66
|
+
return [] if self.blank?
|
67
|
+
name.to_s.split('::').map(&:to_sym)
|
68
|
+
end
|
69
|
+
|
53
70
|
def default?
|
54
71
|
@name == WType::DEFAULT.name
|
55
72
|
end
|