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
|