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