rlang 0.3.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 +7 -0
- data/.gitignore +10 -0
- data/.rake_tasks~ +0 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE +373 -0
- data/README.md +61 -0
- data/Rakefile +10 -0
- data/bin/rlang +164 -0
- data/docs/RlangCompiler.md +37 -0
- data/docs/RlangManual.md +391 -0
- data/lib/builder/ext/tempfile.rb +7 -0
- data/lib/builder/ext.rb +5 -0
- data/lib/builder/rlang/builder.rb +31 -0
- data/lib/builder/rlang.rb +2 -0
- data/lib/builder/wat/builder.rb +52 -0
- data/lib/builder/wat/renderer.rb +28 -0
- data/lib/builder/wat.rb +3 -0
- data/lib/builder.rb +7 -0
- data/lib/rlang/lib/malloc.c +97 -0
- data/lib/rlang/lib/malloc.rb +169 -0
- data/lib/rlang/lib/memory.rb +11 -0
- data/lib/rlang/lib/type/i32.rb +7 -0
- data/lib/rlang/lib/type/i64.rb +7 -0
- data/lib/rlang/lib/type.rb +6 -0
- data/lib/rlang/lib/unistd.rb +47 -0
- data/lib/rlang/lib.rb +10 -0
- data/lib/rlang/parser/const.rb +15 -0
- data/lib/rlang/parser/cvar.rb +44 -0
- data/lib/rlang/parser/data.rb +105 -0
- data/lib/rlang/parser/export.rb +22 -0
- data/lib/rlang/parser/ext/integer.rb +5 -0
- data/lib/rlang/parser/ext/string.rb +5 -0
- data/lib/rlang/parser/ext/type.rb +64 -0
- data/lib/rlang/parser/global.rb +65 -0
- data/lib/rlang/parser/lvar.rb +29 -0
- data/lib/rlang/parser/marg.rb +30 -0
- data/lib/rlang/parser/method.rb +76 -0
- data/lib/rlang/parser/wattr.rb +65 -0
- data/lib/rlang/parser/wgenerator.rb +509 -0
- data/lib/rlang/parser/winstruction.rb +148 -0
- data/lib/rlang/parser/wnode.rb +455 -0
- data/lib/rlang/parser/wtree.rb +19 -0
- data/lib/rlang/parser/wtype.rb +116 -0
- data/lib/rlang/parser.rb +1842 -0
- data/lib/rlang/version.rb +3 -0
- data/lib/rlang.rb +4 -0
- data/lib/simul/classes/data.rb +80 -0
- data/lib/simul/classes/global.rb +38 -0
- data/lib/simul/classes/memory.rb +131 -0
- data/lib/utils/log.rb +32 -0
- data/rlang.gemspec +38 -0
- metadata +158 -0
@@ -0,0 +1,455 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Nodes used to generate WASM code
|
6
|
+
|
7
|
+
require_relative '../../utils/log'
|
8
|
+
require_relative './wtype'
|
9
|
+
require_relative './const'
|
10
|
+
require_relative './cvar'
|
11
|
+
require_relative './lvar'
|
12
|
+
require_relative './wattr'
|
13
|
+
require_relative './method'
|
14
|
+
|
15
|
+
module Rlang::Parser
|
16
|
+
class WNode
|
17
|
+
include Log
|
18
|
+
|
19
|
+
# WASM code templates
|
20
|
+
T = {
|
21
|
+
func: 'func %{func_name}',
|
22
|
+
param: 'param %{name} %{wasm_type}',
|
23
|
+
result: 'result %{wasm_type}',
|
24
|
+
return: 'return',
|
25
|
+
local: 'local %{name} %{wasm_type}',
|
26
|
+
call: 'call %{func_name}',
|
27
|
+
store: '%{wasm_type}.store',
|
28
|
+
load: '%{wasm_type}.load',
|
29
|
+
local_get: 'local.get %{var_name}',
|
30
|
+
local_set: 'local.set %{var_name}',
|
31
|
+
global_get: 'global.get %{var_name}',
|
32
|
+
global_set: 'global.set %{var_name}',
|
33
|
+
addr: 'i32.const %{value}',
|
34
|
+
operator: '%{wasm_type}.%{operator}',
|
35
|
+
const: '%{wasm_type}.const %{value}',
|
36
|
+
drop: 'drop',
|
37
|
+
nop: 'nop',
|
38
|
+
extend_i32_u: '%{wasm_type}.extend_i32_u',
|
39
|
+
extend_i32_s: '%{wasm_type}.extend_i32_s',
|
40
|
+
wrap_i64: '%{wasm_type}.wrap_i64',
|
41
|
+
eqz: '%{wasm_type}.eqz',
|
42
|
+
if: 'if',
|
43
|
+
then: 'then',
|
44
|
+
else: 'else',
|
45
|
+
block: 'block %{label}',
|
46
|
+
loop: 'loop %{label}',
|
47
|
+
br_if: 'br_if %{label}',
|
48
|
+
br: 'br %{label}',
|
49
|
+
inline: '%{code}',
|
50
|
+
wattr_reader: %q{func %{func_name} (param $_self_ i32) (result %{wtype})
|
51
|
+
(%{wtype}.load offset=%{offset} (local.get $_self_))},
|
52
|
+
wattr_writer: %q{func %{func_name} (param $_self_ i32) (param %{wattr_name} %{wtype}) (result %{wtype})
|
53
|
+
(local.get %{wattr_name})
|
54
|
+
(%{wtype}.store offset=%{offset} (local.get $_self_) (local.get %{wattr_name}))},
|
55
|
+
class_size: %q{func %{func_name} (result %{wtype})
|
56
|
+
(%{wtype}.const %{size})}
|
57
|
+
}
|
58
|
+
|
59
|
+
attr_accessor :type, :wargs, :children, :parent, :comment, :lvars, :cvars, :margs,
|
60
|
+
:consts, :methods, :method, :template, :keep_on_stack,
|
61
|
+
:class_wnodes
|
62
|
+
attr_reader :wtype, :label, :klass_name, :klass_size, :wattrs
|
63
|
+
|
64
|
+
@@label_index = 0
|
65
|
+
|
66
|
+
def initialize(type, parent=nil, prepend=false)
|
67
|
+
@type = type # :root, :method, :class, :insn, :none
|
68
|
+
@parent = parent
|
69
|
+
@comment = nil
|
70
|
+
|
71
|
+
@wargs = {}
|
72
|
+
@template = nil
|
73
|
+
@children = []
|
74
|
+
@@root = self if type == :root
|
75
|
+
# make this wnode a child of its parent
|
76
|
+
@parent.add_child(self, prepend) if @parent
|
77
|
+
|
78
|
+
# WASM type of this node. If node is :method
|
79
|
+
# then it's the type of the return value (nil
|
80
|
+
# means no value returned)
|
81
|
+
@wtype = WType::DEFAULT
|
82
|
+
|
83
|
+
# For root wnode
|
84
|
+
@class_wnodes = [] # wnodes of classes
|
85
|
+
|
86
|
+
# For class wnode only
|
87
|
+
@klass_name = nil
|
88
|
+
@wattrs = [] # class attributes
|
89
|
+
@cvars = [] # class variables=
|
90
|
+
@consts = [] # class constants
|
91
|
+
@methods = [] # methods
|
92
|
+
|
93
|
+
# For method wnode only
|
94
|
+
@method = nil
|
95
|
+
@margs = [] # method args
|
96
|
+
@lvars = [] # local variables
|
97
|
+
|
98
|
+
# For insn wnode with
|
99
|
+
# label (.e.g block, loop)
|
100
|
+
@label = nil
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.root
|
104
|
+
@@root
|
105
|
+
end
|
106
|
+
|
107
|
+
def root?
|
108
|
+
self == @@root
|
109
|
+
end
|
110
|
+
|
111
|
+
# Says whether this wnode produces a straight
|
112
|
+
# WASM const node in the end
|
113
|
+
def const?
|
114
|
+
self.template == :const || self.template == :addr
|
115
|
+
end
|
116
|
+
|
117
|
+
# set instruction template and args
|
118
|
+
def c(template, wargs = {})
|
119
|
+
raise "Error: unknown WASM code template (#{template})" unless T.has_key? template
|
120
|
+
raise "Error: this WNode is already populated with instruction #{@template}" if @template
|
121
|
+
if [:loop, :block].include? template
|
122
|
+
wargs[:label] = self.set_label
|
123
|
+
end
|
124
|
+
@template = template
|
125
|
+
@wargs = wargs
|
126
|
+
end
|
127
|
+
|
128
|
+
def wasm_code
|
129
|
+
@wargs[:wasm_type] ||= self.wasm_type
|
130
|
+
wargs = {}
|
131
|
+
@wargs.each { |k, v| wargs[k] = (v.is_a?(Proc) ? v.call : v) }
|
132
|
+
T[@template] ? T[@template] % wargs : ''
|
133
|
+
end
|
134
|
+
|
135
|
+
def wasm_type
|
136
|
+
@wtype.wasm_type
|
137
|
+
end
|
138
|
+
|
139
|
+
def set_label
|
140
|
+
@label = "$lbl_#{'%02d' % (@@label_index += 1)}"
|
141
|
+
end
|
142
|
+
|
143
|
+
# Specify the WASM type of this node
|
144
|
+
def wtype=(wtype)
|
145
|
+
raise "Expecting a WType argument (got #{wtype.inspect}" unless wtype.is_a? WType
|
146
|
+
logger.debug "Setting wtype #{wtype} for wnode #{self}"
|
147
|
+
@wtype = wtype
|
148
|
+
@method.wtype = @wtype if self.method?
|
149
|
+
# update wasm_type template arg accordingly
|
150
|
+
@wargs[:wasm_type] = @wtype.wasm_type if @wtype
|
151
|
+
logger.debug "type #{self.type} wargs #{self.wargs} wtype #{@wtype}"
|
152
|
+
@wtype
|
153
|
+
end
|
154
|
+
|
155
|
+
# Add a new child to current node at the
|
156
|
+
# end or at the beginning of the child list
|
157
|
+
def add_child(wnode, prepend=false)
|
158
|
+
#logger.debug "Adding #{wnode.object_id} to #{self.object_id} (children: #{self.children.map(&:object_id)})"
|
159
|
+
if prepend
|
160
|
+
self.children.unshift(wnode)
|
161
|
+
else
|
162
|
+
self.children << wnode
|
163
|
+
end
|
164
|
+
wnode.parent = self
|
165
|
+
#logger.debug "Added #{wnode.object_id} to #{self.object_id} (children: #{self.children.map(&:object_id)})"
|
166
|
+
#logger.debug "Parent of #{wnode.object_id} is now #{wnode.parent.object_id}"
|
167
|
+
self
|
168
|
+
end
|
169
|
+
alias :<< :add_child
|
170
|
+
|
171
|
+
# Remove child to current node
|
172
|
+
def remove_child(wnode)
|
173
|
+
logger.debug "Removing #{wnode.object_id} from #{self.children.map(&:object_id)}"
|
174
|
+
wn = self.children.delete(wnode) do
|
175
|
+
logger.error "Couldn't find wnode ID #{wnode.object_id} (#{wnode})"
|
176
|
+
raise
|
177
|
+
end
|
178
|
+
wn.parent = nil
|
179
|
+
#logger.debug "Removed #{wnode.object_id} from #{self.object_id} (children: #{self.children.map(&:object_id)})"
|
180
|
+
wn
|
181
|
+
end
|
182
|
+
alias :>> :remove_child
|
183
|
+
|
184
|
+
# Reparent self node to another wnode
|
185
|
+
def reparent_to(wnode)
|
186
|
+
return if self.parent == wnode
|
187
|
+
old_parent, new_parent = self.parent, wnode
|
188
|
+
new_parent << self
|
189
|
+
old_parent >> self if old_parent
|
190
|
+
end
|
191
|
+
|
192
|
+
# insert a blank wnode above self, so between self wnode
|
193
|
+
# and its parent (self -> parent becomes self -> wn -> parent)
|
194
|
+
def insert(wtype=:none)
|
195
|
+
wn = WNode.new(wtype, self.parent)
|
196
|
+
self.reparent_to(wn)
|
197
|
+
wn
|
198
|
+
end
|
199
|
+
|
200
|
+
# Set this node class name
|
201
|
+
def class_name=(class_name)
|
202
|
+
@klass_name = class_name
|
203
|
+
end
|
204
|
+
|
205
|
+
# Find class name in this node and up the tree
|
206
|
+
def class_name
|
207
|
+
(cn = self.class_wnode) ? cn.klass_name : nil
|
208
|
+
end
|
209
|
+
|
210
|
+
# Find class name in this node and up the tree
|
211
|
+
def class_size
|
212
|
+
(cn = self.class_wnode) ? cn.wattrs.sum(&:size) : nil
|
213
|
+
end
|
214
|
+
|
215
|
+
# Find the class wnode matching with the given
|
216
|
+
# class name
|
217
|
+
def find_class(class_name=nil)
|
218
|
+
if class_name
|
219
|
+
WNode.root.class_wnodes.find { |wn| wn.class_name == class_name }
|
220
|
+
else
|
221
|
+
self.class_wnode
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# create a constant
|
226
|
+
def create_const(c_name, class_name, value, wtype)
|
227
|
+
class_name ||= self.class_name
|
228
|
+
if (cn = self.class_wnode)
|
229
|
+
cn.consts << (const = Const.new(class_name, c_name, value, wtype))
|
230
|
+
else
|
231
|
+
raise "No class found for class constant #{const}"
|
232
|
+
end
|
233
|
+
const
|
234
|
+
end
|
235
|
+
|
236
|
+
# Look for constant in the appropriate class wnode
|
237
|
+
# (it can be the current class or another class)
|
238
|
+
def find_const(c_name, class_name=nil)
|
239
|
+
wn_class = find_class(class_name)
|
240
|
+
raise "Can't find parent class for constant #{c_name}" unless wn_class
|
241
|
+
class_name = wn_class.class_name
|
242
|
+
logger.debug "looking for const #{c_name} in class #{class_name} at wnode #{self.class_wnode}..."
|
243
|
+
wn_class.consts.find { |c| c.class_name == class_name && c.name == c_name }
|
244
|
+
end
|
245
|
+
|
246
|
+
def find_or_create_const(c_name, class_name, value, wtype)
|
247
|
+
self.find_const(c_name, class_name) || self.create_const(c_name, class_name, value, wtype)
|
248
|
+
end
|
249
|
+
|
250
|
+
def find_wattr(wa_name, class_name=nil)
|
251
|
+
wn_class = find_class(class_name)
|
252
|
+
raise "Can't find parent class for wattr #{wa_name}" unless wn_class
|
253
|
+
class_name = wn_class.class_name
|
254
|
+
logger.debug "looking for wattr #{wa_name} in class #{class_name} at wnode #{self.class_wnode}..."
|
255
|
+
wn_class.wattrs.find { |wa| wa.class_name == class_name && wa.name == wa_name }
|
256
|
+
end
|
257
|
+
|
258
|
+
def create_wattr(wa_name, wtype=WType::DEFAULT)
|
259
|
+
if (cn = self.class_wnode)
|
260
|
+
logger.debug "creating wattr #{wa_name} in class #{self.class_name} at wnode #{self.class_wnode}..."
|
261
|
+
cn.wattrs << (wattr = WAttr.new(cn, wa_name, wtype))
|
262
|
+
else
|
263
|
+
raise "No class found for class attribute #{wa_name}"
|
264
|
+
end
|
265
|
+
wattr
|
266
|
+
end
|
267
|
+
|
268
|
+
def create_cvar(cv_name, value=0, wtype=WType::DEFAULT)
|
269
|
+
if (cn = self.class_wnode)
|
270
|
+
logger.debug "creating cvar #{cv_name} in class #{self.class_name} at wnode #{self.class_wnode}..."
|
271
|
+
cn.cvars << (cvar = CVar.new(cn.klass_name, cv_name, value, wtype))
|
272
|
+
else
|
273
|
+
raise "No class found for class variable #{cv_name}"
|
274
|
+
end
|
275
|
+
cvar
|
276
|
+
end
|
277
|
+
|
278
|
+
def find_cvar(cv_name)
|
279
|
+
logger.debug "looking for cvar #{cv_name} in class #{self.class_name} at wnode #{self.class_wnode}..."
|
280
|
+
self.class_wnode.cvars.find { |cv| cv.class_name == self.class_name && cv.name == cv_name }
|
281
|
+
end
|
282
|
+
|
283
|
+
def create_lvar(name)
|
284
|
+
if (mn = self.method_wnode)
|
285
|
+
mn.lvars << (lvar = LVar.new(name))
|
286
|
+
else
|
287
|
+
raise "No method found for local variable #{name}"
|
288
|
+
end
|
289
|
+
lvar
|
290
|
+
end
|
291
|
+
|
292
|
+
def find_lvar(name)
|
293
|
+
self.method_wnode.lvars.find { |lv| lv.name == name }
|
294
|
+
end
|
295
|
+
|
296
|
+
def find_or_create_lvar(name)
|
297
|
+
self.find_lvar(name) || self.create_lvar(name)
|
298
|
+
end
|
299
|
+
|
300
|
+
# add method argument
|
301
|
+
def create_marg(name)
|
302
|
+
if (mn = self.method_wnode)
|
303
|
+
mn.margs << (marg = MArg.new(name))
|
304
|
+
else
|
305
|
+
raise "No class found for class variable #{marg}"
|
306
|
+
end
|
307
|
+
marg
|
308
|
+
end
|
309
|
+
|
310
|
+
def find_marg(name)
|
311
|
+
self.method_wnode.margs.find { |ma| ma.name == name }
|
312
|
+
end
|
313
|
+
|
314
|
+
# method_type is either :instance or :class
|
315
|
+
def create_method(method_name, class_name, wtype, method_type)
|
316
|
+
raise "MEthod already exists: #{m}" \
|
317
|
+
if (m = find_method(method_name, class_name, method_type))
|
318
|
+
if (cn = self.class_wnode)
|
319
|
+
class_name ||= cn.klass_name
|
320
|
+
cn.methods << (method = MEthod.new(method_name, class_name, wtype))
|
321
|
+
else
|
322
|
+
raise "No class wnode found to create method #{method_name}"
|
323
|
+
end
|
324
|
+
method_type == :class ? method.class! : method.instance!
|
325
|
+
logger.debug "Created MEthod: #{method.inspect}"
|
326
|
+
method
|
327
|
+
end
|
328
|
+
|
329
|
+
# method_type is either :instance or :class
|
330
|
+
def find_method(method_name, class_name, method_type)
|
331
|
+
if class_name
|
332
|
+
class_wnode = find_class(class_name)
|
333
|
+
else
|
334
|
+
class_wnode = self.class_wnode
|
335
|
+
end
|
336
|
+
raise "Couldn't find class wnode for class_name #{class_name}" unless class_wnode
|
337
|
+
class_name = class_wnode.klass_name
|
338
|
+
if method_type == :class
|
339
|
+
method = class_wnode.methods.find { |m| m.name == method_name && m.class_name == class_name && m.class? }
|
340
|
+
elsif method_type == :instance
|
341
|
+
method = class_wnode.methods.find { |m| m.name == method_name && m.class_name == class_name && m.instance? }
|
342
|
+
else
|
343
|
+
raise "Unknown method type : #{method_type.inspect}"
|
344
|
+
end
|
345
|
+
if method
|
346
|
+
logger.debug "Found MEthod: #{method.inspect}"
|
347
|
+
else
|
348
|
+
logger.debug "Couldn't find MEthod: #{class_name.inspect},#{method_name.inspect}"
|
349
|
+
end
|
350
|
+
method
|
351
|
+
end
|
352
|
+
|
353
|
+
def find_or_create_method(method_name, class_name=nil, method_type=:class)
|
354
|
+
self.find_method(method_name, class_name, method_type) || \
|
355
|
+
self.create_method(method_name, class_name, WType::DEFAULT, method_type)
|
356
|
+
end
|
357
|
+
|
358
|
+
# Find block wnode up the tree
|
359
|
+
def block_wnode
|
360
|
+
if self.template == :block
|
361
|
+
self
|
362
|
+
else
|
363
|
+
@parent ? @parent.block_wnode : nil
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
# Find loop wnode up the tree
|
368
|
+
def loop_wnode
|
369
|
+
if self.template == :loop
|
370
|
+
self
|
371
|
+
else
|
372
|
+
@parent ? @parent.loop_wnode : nil
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# Find class wnode up the tree
|
377
|
+
def class_wnode
|
378
|
+
if self.class?
|
379
|
+
self
|
380
|
+
else
|
381
|
+
@parent ? @parent.class_wnode : nil
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
# Find method wnode up the tree
|
386
|
+
def method_wnode
|
387
|
+
if self.method?
|
388
|
+
self
|
389
|
+
else
|
390
|
+
@parent ? @parent.method_wnode : nil
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def scope
|
395
|
+
return :class_method if self.in_class_method_scope?
|
396
|
+
return :instance_method if self.in_instance_method_scope?
|
397
|
+
return :class if self.in_class_scope?
|
398
|
+
return :root if self.in_root_scope?
|
399
|
+
end
|
400
|
+
|
401
|
+
def in_method_scope?
|
402
|
+
!self.method_wnode.nil?
|
403
|
+
end
|
404
|
+
|
405
|
+
def in_class_method_scope?
|
406
|
+
!self.method_wnode.nil? && !self.method_wnode.method.instance?
|
407
|
+
end
|
408
|
+
|
409
|
+
def in_instance_method_scope?
|
410
|
+
!self.method_wnode.nil? && self.method_wnode.method.instance?
|
411
|
+
end
|
412
|
+
|
413
|
+
def in_class_scope?
|
414
|
+
!self.class_wnode.nil? && self.method_wnode.nil?
|
415
|
+
end
|
416
|
+
|
417
|
+
def in_root_scope?
|
418
|
+
self.root? || self.parent.root?
|
419
|
+
end
|
420
|
+
|
421
|
+
def method?
|
422
|
+
self.type == :method
|
423
|
+
end
|
424
|
+
|
425
|
+
def class?
|
426
|
+
self.type == :class
|
427
|
+
end
|
428
|
+
|
429
|
+
# format the wnode and tree below
|
430
|
+
# Note: this a just a tree dump. The output generated is
|
431
|
+
# not valid WAT code
|
432
|
+
def to_s(indent=0)
|
433
|
+
"\n%sw(%s:%s" % [' '*2*indent, self.type, self.wasm_code] + self.children.map { |wn| wn.to_s(indent+1) }.join('') + ')'
|
434
|
+
end
|
435
|
+
|
436
|
+
# Generate WAT code starting for this node and tree branches below
|
437
|
+
def transpile(indent=0)
|
438
|
+
case @type
|
439
|
+
when :insn, :method
|
440
|
+
if @template == :inline
|
441
|
+
"\n%s%s" % [' '*2*indent, self.wasm_code]
|
442
|
+
else
|
443
|
+
"\n%s(%s" % [' '*2*indent, self.wasm_code] + self.children.map { |wn| wn.transpile(indent+1) }.join('') + ')'
|
444
|
+
end
|
445
|
+
when :root, :class, :none
|
446
|
+
# no WAT code to generate for these nodes. Process children directly.
|
447
|
+
self.children.map { |wn| wn.transpile(indent) }.join('')
|
448
|
+
else
|
449
|
+
raise "Error: Unknown wnode type #{@type}. No WAT code generated"
|
450
|
+
end
|
451
|
+
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Node tree structure supporting the construction
|
6
|
+
# of the WASM Abstract Syntax Tree
|
7
|
+
|
8
|
+
require_relative './wnode'
|
9
|
+
|
10
|
+
module Rlang::Parser
|
11
|
+
class WTree
|
12
|
+
attr_reader :root
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@root = WNode.new(:root)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# Rubinius WebAssembly VM
|
2
|
+
# Copyright (c) 2019, Laurent Julliard and contributors
|
3
|
+
# All rights reserved.
|
4
|
+
|
5
|
+
# WType class. This class manages the wtype
|
6
|
+
# of Wnode objects. This is a higher level
|
7
|
+
# representation of WASM types
|
8
|
+
#
|
9
|
+
# A wtype can be initialized with values like
|
10
|
+
# - :none or :nil : no type defined
|
11
|
+
# - A legit WASM type :I32, : I64,....
|
12
|
+
# - or a Rlang class name
|
13
|
+
|
14
|
+
require_relative '../../utils/log'
|
15
|
+
require_relative './ext/type'
|
16
|
+
|
17
|
+
class WType
|
18
|
+
|
19
|
+
WASM_TYPE_MAP = {
|
20
|
+
I64: Type::I64,
|
21
|
+
I32: Type::I32,
|
22
|
+
F64: Type::F64,
|
23
|
+
F32: Type::F32
|
24
|
+
}
|
25
|
+
|
26
|
+
# Implicit Type cast order in decreasing order of precedence
|
27
|
+
# Class types have precedence over default integer type
|
28
|
+
# because of pointer arithmetics
|
29
|
+
# TODO: :Class should be inserted before WType::DEFAULT
|
30
|
+
CAST_PRECEDENCE = [:F64, :F32, :I64, :Class, :I32]
|
31
|
+
|
32
|
+
attr_reader :name
|
33
|
+
|
34
|
+
def self.legit?(name)
|
35
|
+
WASM_TYPE_MAP.has_key? name
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.leading(wtypes)
|
39
|
+
logger.debug "wtypes: #{wtypes}"
|
40
|
+
# The compact below is to remove the nil
|
41
|
+
# when wtype is blank or class
|
42
|
+
leading_idx = wtypes.map {|wt| wt.class? ? :Class : wt.name}. \
|
43
|
+
map {|wtn| CAST_PRECEDENCE.index(wtn) }.compact.each_with_index.min.last
|
44
|
+
wtypes[leading_idx]
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(name)
|
48
|
+
@name = name.to_sym
|
49
|
+
raise "Invalid WType #{name.inspect}" unless self.valid?
|
50
|
+
end
|
51
|
+
|
52
|
+
def default?
|
53
|
+
@name == WType::DEFAULT.name
|
54
|
+
end
|
55
|
+
|
56
|
+
def valid?
|
57
|
+
self.blank? || self.native? || self.class?
|
58
|
+
end
|
59
|
+
|
60
|
+
def native?
|
61
|
+
WASM_TYPE_MAP.has_key? @name
|
62
|
+
end
|
63
|
+
|
64
|
+
def blank?
|
65
|
+
@name == :none || @name == :nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def class?
|
69
|
+
# name starts with uppercase and is not a native type
|
70
|
+
!self.native? && ('A'..'Z').include?(@name.to_s[0])
|
71
|
+
end
|
72
|
+
|
73
|
+
def ==(other)
|
74
|
+
@name == other.name
|
75
|
+
end
|
76
|
+
|
77
|
+
def size
|
78
|
+
if self.blank?
|
79
|
+
0
|
80
|
+
elsif self.native?
|
81
|
+
WASM_TYPE_MAP[@name].size
|
82
|
+
else
|
83
|
+
Type::DEFAULT.size
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# returns a String with the proper WASM type
|
88
|
+
# that can be used for code generation
|
89
|
+
def wasm_type
|
90
|
+
if self.blank?
|
91
|
+
''
|
92
|
+
elsif self.native?
|
93
|
+
WASM_TYPE_MAP[@name].wasm_type
|
94
|
+
elsif self.class?
|
95
|
+
# it's a class name return DEFAULT WASM
|
96
|
+
# type because this is always the class of
|
97
|
+
# amemory address in VASM VM
|
98
|
+
Type::DEFAULT.wasm_type
|
99
|
+
else
|
100
|
+
raise "Unknown WType #{self.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_s
|
105
|
+
":#{@name}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def inspect
|
109
|
+
self.to_s
|
110
|
+
end
|
111
|
+
|
112
|
+
DEFAULT = self.new(WASM_TYPE_MAP.key(Type::DEFAULT))
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|