rlang 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|