rlang 0.4.1 → 0.6.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 +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
|