rlang 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +12 -2
- data/docs/RlangManual.md +43 -30
- data/lib/rlang/lib.rb +2 -1
- data/lib/rlang/lib/malloc.rb +2 -2
- data/lib/rlang/lib/memory.rb +18 -0
- data/lib/rlang/lib/string.rb +30 -0
- data/lib/rlang/parser.rb +263 -206
- data/lib/rlang/parser/{wattr.rb → attr.rb} +41 -33
- data/lib/rlang/parser/data.rb +3 -0
- data/lib/rlang/parser/ivar.rb +16 -7
- data/lib/rlang/parser/klass.rb +6 -3
- data/lib/rlang/parser/method.rb +17 -9
- data/lib/rlang/parser/wgenerator.rb +168 -47
- data/lib/rlang/parser/wnode.rb +96 -65
- data/lib/rlang/version.rb +1 -1
- metadata +4 -3
@@ -9,61 +9,64 @@ require_relative './ivar'
|
|
9
9
|
require_relative './wtype'
|
10
10
|
|
11
11
|
module Rlang::Parser
|
12
|
-
class
|
12
|
+
class Attr
|
13
13
|
include Log
|
14
|
-
attr_reader :name, :
|
14
|
+
attr_reader :name, :getter, :setter, :ivar
|
15
15
|
|
16
16
|
# The name argument can either be the attribute name
|
17
17
|
# (e.g. :size) or an ivar name (e.g. :@size)
|
18
18
|
def initialize(class_wnode, name, wtype=WType::DEFAULT)
|
19
19
|
@class_wnode = class_wnode
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# method objects (with default WType - wattr_type
|
30
|
-
# directives might later change this wtype)
|
31
|
-
# Don't generate WAT code yet
|
20
|
+
@name = name
|
21
|
+
@ivar = class_wnode.create_ivar(:"@#{name}", wtype)
|
22
|
+
@getter = nil
|
23
|
+
@setter = nil
|
24
|
+
@export = false
|
25
|
+
logger.debug "Class attribute #{name} created"
|
26
|
+
end
|
27
|
+
|
28
|
+
def attr_reader
|
32
29
|
@getter = @class_wnode.find_or_create_method(self.getter_name, nil, wtype, :instance)
|
33
|
-
@getter.
|
30
|
+
@getter.export! if @export
|
34
31
|
logger.debug "Getter created: #{@getter.inspect}"
|
32
|
+
@getter
|
33
|
+
end
|
35
34
|
|
35
|
+
def attr_writer
|
36
36
|
@setter = @class_wnode.find_or_create_method(self.setter_name, nil, wtype, :instance)
|
37
|
-
@setter.
|
37
|
+
@setter.export! if @export
|
38
38
|
logger.debug "Setter created: #{@setter.inspect}"
|
39
|
-
|
39
|
+
@setter
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
42
|
+
def attr_accessor
|
43
|
+
[self.attr_reader, self.attr_writer]
|
44
44
|
end
|
45
45
|
|
46
|
-
def
|
47
|
-
@
|
48
|
-
# Adjust corresponding method objects wtype accordingly
|
49
|
-
@getter.wtype = wtype
|
50
|
-
@setter.wtype = wtype
|
51
|
-
@ivar.wtype = wtype
|
52
|
-
logger.debug "WAttr/Getter/Setter/ivar wtype updated : #{@getter.inspect}"
|
46
|
+
def export!
|
47
|
+
@export = true
|
53
48
|
end
|
54
49
|
|
55
|
-
def
|
56
|
-
@
|
50
|
+
def class_name
|
51
|
+
@class_wnode.class_name
|
57
52
|
end
|
58
53
|
|
59
|
-
def
|
60
|
-
@ivar
|
54
|
+
def wtype
|
55
|
+
@ivar.wtype
|
61
56
|
end
|
62
57
|
|
63
|
-
def
|
64
|
-
|
58
|
+
def offset
|
59
|
+
@ivar.offset
|
65
60
|
end
|
66
61
|
|
62
|
+
def wtype=(wtype)
|
63
|
+
# Adjust getter/setter and ivar wtype accordingly
|
64
|
+
@getter.wtype = wtype if @getter
|
65
|
+
@setter.wtype = wtype if @setter
|
66
|
+
@ivar.wtype = wtype
|
67
|
+
logger.debug "Attr/Getter/Setter/ivar wtype updated : #{@getter.inspect}"
|
68
|
+
end
|
69
|
+
|
67
70
|
def getter_name
|
68
71
|
@name
|
69
72
|
end
|
@@ -71,8 +74,13 @@ module Rlang::Parser
|
|
71
74
|
def setter_name
|
72
75
|
"#{@name}=".to_sym
|
73
76
|
end
|
77
|
+
|
78
|
+
def wasm_name
|
79
|
+
"$#{@name}"
|
80
|
+
end
|
81
|
+
|
74
82
|
def wasm_type
|
75
|
-
|
83
|
+
self.wtype.wasm_type
|
76
84
|
end
|
77
85
|
end
|
78
86
|
end
|
data/lib/rlang/parser/data.rb
CHANGED
@@ -17,6 +17,9 @@ module Rlang::Parser
|
|
17
17
|
|
18
18
|
attr_reader :label, :wtype, :address, :value
|
19
19
|
|
20
|
+
# NOTE: new and append only takes individual DAta values
|
21
|
+
# not an array of values
|
22
|
+
# TODO: fix DAta.new and DAta.append not accepting an array of values
|
20
23
|
def initialize(label, value, wtype=WType::DEFAULT)
|
21
24
|
raise "Data label '#{label}' already initialized" \
|
22
25
|
if self.class.exist? label
|
data/lib/rlang/parser/ivar.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# Copyright (c) 2019, Laurent Julliard and contributors
|
3
3
|
# All rights reserved.
|
4
4
|
#
|
5
|
-
# Instance variables
|
5
|
+
# Instance variables class
|
6
6
|
#
|
7
7
|
require_relative '../../utils/log'
|
8
8
|
require_relative './wtype'
|
@@ -11,22 +11,31 @@ require_relative './data'
|
|
11
11
|
module Rlang::Parser
|
12
12
|
class IVar
|
13
13
|
include Log
|
14
|
-
attr_reader :name
|
15
|
-
attr_accessor :wtype
|
14
|
+
attr_reader :name
|
15
|
+
attr_accessor :wtype, :offset
|
16
16
|
|
17
17
|
def initialize(class_wnode, name, wtype=WType::DEFAULT)
|
18
|
-
@name = name
|
19
18
|
@class_wnode = class_wnode
|
19
|
+
@name = name
|
20
20
|
@wtype = wtype
|
21
|
-
|
21
|
+
# this is the offset of the instance variable
|
22
|
+
# in memory in the order they are declared
|
23
|
+
# It is computed at the end of a class
|
24
|
+
# definition
|
25
|
+
@offset = nil
|
26
|
+
logger.debug "Instance variable #{name} created"
|
22
27
|
end
|
23
28
|
|
24
29
|
def class_name
|
25
30
|
@class_wnode.class_name
|
26
31
|
end
|
27
32
|
|
28
|
-
def
|
29
|
-
@
|
33
|
+
def size
|
34
|
+
@wtype.size
|
35
|
+
end
|
36
|
+
|
37
|
+
def wasm_name
|
38
|
+
"$#{@name}"
|
30
39
|
end
|
31
40
|
|
32
41
|
def wasm_type
|
data/lib/rlang/parser/klass.rb
CHANGED
@@ -13,7 +13,8 @@ module Rlang::Parser
|
|
13
13
|
include Log
|
14
14
|
|
15
15
|
attr_reader :wtype
|
16
|
-
attr_accessor :name, :wnode, :
|
16
|
+
attr_accessor :name, :wnode, :attrs, :ivars, :cvars,
|
17
|
+
:consts, :methods, :offset
|
17
18
|
|
18
19
|
def initialize(name)
|
19
20
|
@name = name
|
@@ -23,14 +24,16 @@ module Rlang::Parser
|
|
23
24
|
# the wnode implementing the code of the class
|
24
25
|
@wnode = nil
|
25
26
|
logger.debug "Klass created #{self.inspect}"
|
26
|
-
@
|
27
|
+
@attrs = [] # class attributes
|
28
|
+
@ivars = [] # instance variables
|
27
29
|
@cvars = [] # class variables
|
28
30
|
@consts = [] # class constants
|
29
31
|
@methods = [] # methods
|
32
|
+
@offset = 0 # offset of the next class attribute in memory
|
30
33
|
end
|
31
34
|
|
32
35
|
def size
|
33
|
-
|
36
|
+
@offset
|
34
37
|
end
|
35
38
|
|
36
39
|
def wtype=(wtype)
|
data/lib/rlang/parser/method.rb
CHANGED
@@ -16,32 +16,40 @@ module Rlang::Parser
|
|
16
16
|
attr_reader :name, :wtype
|
17
17
|
attr_accessor :class_name, :margs, :lvars, :wnode
|
18
18
|
|
19
|
-
|
19
|
+
METHOD_TYPES = [:class, :instance]
|
20
|
+
|
21
|
+
def initialize(name, class_name, wtype, method_type)
|
20
22
|
raise "Wrong method wtype argument: #{wtype.inspect}" unless wtype.is_a? WType
|
21
23
|
@name = name
|
22
24
|
@class_name = class_name
|
23
|
-
@wtype = wtype
|
24
|
-
@
|
25
|
+
@wtype = wtype || WType::DEFAULT
|
26
|
+
@method_type = method_type
|
27
|
+
raise "Unknown method type: #{method_type}" unless METHOD_TYPES.include? @method_type
|
25
28
|
@wnode = nil # wnode where method is implemented
|
26
29
|
logger.debug "Method created #{self.inspect}"
|
27
30
|
@margs = [] # method args
|
28
31
|
@lvars = [] # local variables
|
29
32
|
end
|
30
33
|
|
34
|
+
def implemented?
|
35
|
+
!@wnode.nil?
|
36
|
+
end
|
37
|
+
|
31
38
|
def instance!
|
32
|
-
@
|
39
|
+
@method_type = :instance
|
33
40
|
end
|
34
41
|
|
35
42
|
def instance?
|
36
|
-
@instance
|
43
|
+
@method_type == :instance
|
44
|
+
|
37
45
|
end
|
38
46
|
|
39
47
|
def class!
|
40
|
-
@
|
48
|
+
@method_type = :class
|
41
49
|
end
|
42
50
|
|
43
51
|
def class?
|
44
|
-
|
52
|
+
@method_type == :class
|
45
53
|
end
|
46
54
|
|
47
55
|
def wtype=(wtype)
|
@@ -50,7 +58,7 @@ module Rlang::Parser
|
|
50
58
|
end
|
51
59
|
|
52
60
|
def wasm_name
|
53
|
-
if
|
61
|
+
if self.instance?
|
54
62
|
"$#{@class_name}##{@name}"
|
55
63
|
else
|
56
64
|
"$#{@class_name}::#{@name}"
|
@@ -62,7 +70,7 @@ module Rlang::Parser
|
|
62
70
|
end
|
63
71
|
|
64
72
|
def export_name
|
65
|
-
if
|
73
|
+
if self.instance?
|
66
74
|
"#{@class_name.downcase}_i_#{@name}"
|
67
75
|
else
|
68
76
|
"#{@class_name.downcase}_c_#{@name}"
|
@@ -50,6 +50,8 @@ module Rlang::Parser
|
|
50
50
|
:'!' => :eqz
|
51
51
|
}
|
52
52
|
|
53
|
+
ALL_OPS_MAP = [*ARITHMETIC_OPS_MAP, *RELATIONAL_OPS_MAP, *BOOLEAN_OPS_MAP, *UNARY_OPS_MAP].to_h
|
54
|
+
|
53
55
|
# Matrix of how to cast a WASM type to another
|
54
56
|
CAST_OPS = {
|
55
57
|
I32: { I32: :cast_nope, I64: :cast_extend, F32: :cast_notyet, F64: :cast_notyet, Class: :cast_wtype, none: :cast_error},
|
@@ -60,6 +62,9 @@ module Rlang::Parser
|
|
60
62
|
none: { I32: :cast_error, I64: :cast_error, F32: :cast_error, F64: :cast_error, Class: :cast_error, none: :cast_error},
|
61
63
|
}
|
62
64
|
|
65
|
+
# Rlang class size method name
|
66
|
+
SIZE_METHOD = :_size_
|
67
|
+
|
63
68
|
# new template when object size > 0
|
64
69
|
NEW_TMPL = %q{
|
65
70
|
result :Object, :alloc, :%{default_wtype}
|
@@ -71,7 +76,7 @@ module Rlang::Parser
|
|
71
76
|
end
|
72
77
|
}
|
73
78
|
|
74
|
-
# new template when object size
|
79
|
+
# new template when object size is 0 (no instance var)
|
75
80
|
# use 0 as the _self_ address in memory. It should never
|
76
81
|
# be used anyway
|
77
82
|
NEW_ZERO_TMPL = %q{
|
@@ -91,6 +96,11 @@ module Rlang::Parser
|
|
91
96
|
end
|
92
97
|
}
|
93
98
|
|
99
|
+
# Dynamically allocate a string object
|
100
|
+
STRING_NEW_TMPL = %q{
|
101
|
+
String.new(%{ptr}, %{length})
|
102
|
+
}
|
103
|
+
|
94
104
|
# Generate the wasm nodes and tree structure
|
95
105
|
# ***IMPORTANT NOTE***
|
96
106
|
# Unless otherwise stated all methods receive
|
@@ -106,6 +116,7 @@ module Rlang::Parser
|
|
106
116
|
@parser = parser
|
107
117
|
@root = WTree.new().root
|
108
118
|
@new_count = 0
|
119
|
+
@static_count = 0
|
109
120
|
end
|
110
121
|
|
111
122
|
def klass(wnode, class_name)
|
@@ -118,22 +129,51 @@ module Rlang::Parser
|
|
118
129
|
k.wnode
|
119
130
|
end
|
120
131
|
|
121
|
-
|
132
|
+
# Postprocess ivars
|
133
|
+
# (called at end of class parsing)
|
134
|
+
def ivars_setup(wnode)
|
122
135
|
wnc = wnode.class_wnode
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
136
|
+
raise "Cannot find class for attributes definition!!" unless wnc
|
137
|
+
klass = wnc.klass
|
138
|
+
logger.debug "Postprocessing ivars for class #{klass.name}..."
|
139
|
+
klass.ivars.each do |iv|
|
140
|
+
iv.offset = klass.offset
|
141
|
+
logger.debug "... ivar #{iv.name} has offset #{iv.offset}"
|
142
|
+
# Update offset for next ivar
|
143
|
+
klass.offset += iv.size
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# generate code for class attributes
|
148
|
+
# (called at end of class parsing)
|
149
|
+
def def_attr(wnode)
|
150
|
+
wnc = wnode.class_wnode
|
151
|
+
raise "Cannot find class for attributes definition!!" unless wnc
|
152
|
+
# Process each declared class attribute
|
153
|
+
wnc.klass.attrs.each do |attr|
|
154
|
+
logger.debug("Generating accessors for attribute #{wnc.klass.name}\##{attr.name}")
|
127
155
|
# Generate getter and setter methods wnode
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
156
|
+
# unless method already implemented by user
|
157
|
+
if attr.setter
|
158
|
+
unless attr.setter.implemented?
|
159
|
+
attr.setter.wnode = self.attr_setter(wnc, attr)
|
160
|
+
else
|
161
|
+
logger.debug "Attribute setter #{attr.setter.name} already defined. Skipping"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
if attr.getter
|
165
|
+
unless attr.getter.implemented?
|
166
|
+
attr.getter.wnode = self.attr_getter(wnc, attr)
|
167
|
+
else
|
168
|
+
logger.debug "Attribute getter #{attr.getter.name} already defined. Skipping"
|
169
|
+
end
|
170
|
+
end
|
132
171
|
end
|
133
172
|
|
134
173
|
# Also generate the Class::_size_ method
|
135
|
-
#
|
136
|
-
|
174
|
+
# (needed for dynamic memory allocation
|
175
|
+
# by Object.allocate)
|
176
|
+
size_method = wnc.find_or_create_method(SIZE_METHOD, wnc.klass.name, WType::DEFAULT, :class)
|
137
177
|
unless size_method.wnode
|
138
178
|
logger.debug("Generating #{size_method.class_name}\##{size_method.name}")
|
139
179
|
wns = WNode.new(:insn, wnc, true)
|
@@ -145,22 +185,22 @@ module Rlang::Parser
|
|
145
185
|
end
|
146
186
|
|
147
187
|
# Generate attribute setter method wnode
|
148
|
-
def
|
188
|
+
def attr_setter(wnode, attr)
|
149
189
|
wnc = wnode.class_wnode
|
150
190
|
wn_set = WNode.new(:insn, wnc, true)
|
151
|
-
wn_set.c(:
|
152
|
-
|
153
|
-
offset: offset)
|
191
|
+
wn_set.c(:attr_setter, func_name: attr.setter.wasm_name,
|
192
|
+
attr_name: attr.wasm_name, wtype: attr.wasm_type,
|
193
|
+
offset: attr.offset)
|
154
194
|
wn_set
|
155
195
|
end
|
156
196
|
|
157
197
|
# Generate attribute getter method wnode
|
158
|
-
def
|
198
|
+
def attr_getter(wnode, attr)
|
159
199
|
wnc = wnode.class_wnode
|
160
200
|
wn_get = WNode.new(:insn, wnc, true)
|
161
|
-
wn_get.c(:
|
162
|
-
|
163
|
-
offset: offset)
|
201
|
+
wn_get.c(:attr_getter, func_name: attr.getter.wasm_name,
|
202
|
+
attr_name: attr.wasm_name, wtype: attr.wasm_type,
|
203
|
+
offset: attr.offset)
|
164
204
|
wn_get
|
165
205
|
end
|
166
206
|
|
@@ -225,11 +265,12 @@ module Rlang::Parser
|
|
225
265
|
wn
|
226
266
|
end
|
227
267
|
|
228
|
-
# Set
|
229
|
-
# Constant assignment doesn't generate any code
|
230
|
-
# A Data object is instantiated and initialized
|
231
|
-
# when the Const object is created in parser
|
268
|
+
# Set constant
|
232
269
|
def casgn(wnode, const)
|
270
|
+
(wn = WNode.new(:insn, wnode)).wtype = const.wtype
|
271
|
+
wn.c(:store, wtype: const.wtype)
|
272
|
+
WNode.new(:insn, wn).c(:addr, value: const.address)
|
273
|
+
wn
|
233
274
|
end
|
234
275
|
|
235
276
|
# Get class variable
|
@@ -254,34 +295,38 @@ module Rlang::Parser
|
|
254
295
|
wn
|
255
296
|
end
|
256
297
|
|
257
|
-
# Call setter (on
|
298
|
+
# Call setter (on attr or instance variable)
|
258
299
|
# This is the same as calling the corresponding setter
|
259
|
-
def call_setter(wnode, wnode_recv,
|
260
|
-
wn = self.call(wnode, wnode_recv.wtype.name,
|
300
|
+
def call_setter(wnode, wnode_recv, attr)
|
301
|
+
wn = self.call(wnode, wnode_recv.wtype.name, attr.setter_name, :instance)
|
261
302
|
# First argument of the setter must be the receiver
|
262
303
|
wnode_recv.reparent_to(wn)
|
263
304
|
wn
|
264
305
|
end
|
265
306
|
|
266
|
-
# Call getter (on
|
307
|
+
# Call getter (on attr or instance variable)
|
267
308
|
# This is the same as calling the corresponding getter
|
268
|
-
def call_getter(wnode, wnode_recv,
|
269
|
-
wn = self.call(wnode, wnode_recv.wtype.name,
|
309
|
+
def call_getter(wnode, wnode_recv, attr)
|
310
|
+
wn = self.call(wnode, wnode_recv.wtype.name, attr.getter_name, :instance)
|
270
311
|
# First argument of the getter must always be the receiver
|
271
312
|
wnode_recv.reparent_to(wn)
|
272
313
|
wn
|
273
314
|
end
|
274
315
|
|
275
316
|
# Set instance variable
|
276
|
-
|
277
|
-
|
278
|
-
|
317
|
+
def ivasgn(wnode, ivar)
|
318
|
+
(wn = WNode.new(:insn, wnode)).wtype = ivar.wtype
|
319
|
+
wn.c(:store_offset, wtype: ivar.wasm_type, offset: lambda { ivar.offset })
|
320
|
+
self._self_(wn)
|
321
|
+
wn
|
279
322
|
end
|
280
323
|
|
281
324
|
# Get instance variable.
|
282
|
-
|
283
|
-
|
284
|
-
|
325
|
+
def ivar(wnode, ivar)
|
326
|
+
(wn = WNode.new(:insn, wnode)).wtype = ivar.wtype
|
327
|
+
wn.c(:load_offset, wtype: ivar.wasm_type, offset: lambda { ivar.offset })
|
328
|
+
self._self_(wn)
|
329
|
+
wn
|
285
330
|
end
|
286
331
|
|
287
332
|
# Set class variable
|
@@ -339,6 +384,52 @@ module Rlang::Parser
|
|
339
384
|
wn
|
340
385
|
end
|
341
386
|
|
387
|
+
# Generate a phony node (generally used to create
|
388
|
+
# a wnode subtree under the phony node and later
|
389
|
+
# reparent it to the proper place in the wtree)
|
390
|
+
def phony(wnode)
|
391
|
+
phony = WNode.new(:none, wnode)
|
392
|
+
phony
|
393
|
+
end
|
394
|
+
|
395
|
+
# Static string allocation
|
396
|
+
def string_static(string, data_label)
|
397
|
+
# Allocate string itself and the attributes
|
398
|
+
# of String object pointing to that string
|
399
|
+
data_stg = DAta.append(data_label.to_sym, string)
|
400
|
+
data_stg
|
401
|
+
end
|
402
|
+
|
403
|
+
# Static new string object
|
404
|
+
def string_static_new(wnode, string)
|
405
|
+
klass = wnode.find_class(nil)
|
406
|
+
data_label = "#{klass.name}_string_#{@static_count += 1}"
|
407
|
+
# Statically
|
408
|
+
data_stg = self.string_static(string, data_label)
|
409
|
+
# align on :I32 boundary
|
410
|
+
DAta.align(4)
|
411
|
+
data_len = DAta.append("#{data_label}_len".to_sym, string.length, WType::DEFAULT)
|
412
|
+
data_ptr = DAta.append("#{data_label}_ptr".to_sym, data_stg.address, WType::DEFAULT)
|
413
|
+
# Generate address wnode
|
414
|
+
(wn_object_addr = WNode.new(:insn, wnode)).c(:addr, value: data_len.address)
|
415
|
+
wn_object_addr.wtype = WType.new(:String)
|
416
|
+
wn_object_addr
|
417
|
+
end
|
418
|
+
|
419
|
+
# Dynamic new string object
|
420
|
+
def string_dynamic_new(wnode, string)
|
421
|
+
klass = wnode.find_class(nil)
|
422
|
+
data_label = "#{klass.name}_string_#{@static_count += 1}"
|
423
|
+
data_stg = self.string_static(string, data_label)
|
424
|
+
string_new_source = STRING_NEW_TMPL % {
|
425
|
+
string: string,
|
426
|
+
ptr: data_stg.address,
|
427
|
+
length: string.length
|
428
|
+
}
|
429
|
+
#puts string_new_source;exit
|
430
|
+
wn_string = self.parser.parse(string_new_source, wnode)
|
431
|
+
end
|
432
|
+
|
342
433
|
# All the cast_xxxx methods below returns
|
343
434
|
# the new wnode doing the cast operation
|
344
435
|
# or the same wnode if there is no additional code
|
@@ -402,27 +493,44 @@ module Rlang::Parser
|
|
402
493
|
# TODO: simplify this complex method (possibly by using
|
403
494
|
# a conversion table source type -> destination type)
|
404
495
|
def cast(wnode, wtype, signed=false)
|
405
|
-
logger.debug "wnode: #{wnode}, wtype: #{wtype}"
|
496
|
+
logger.debug "Casting wnode: #{wnode}, wtype: #{wtype}, wnode ID: #{wnode.object_id}"
|
406
497
|
src_type = (wnode.wtype.native? ? wnode.wtype.name : :Class)
|
407
498
|
dest_type = (wtype.native? ? wtype.name : :Class)
|
408
499
|
cast_method = CAST_OPS[src_type] && CAST_OPS[src_type][dest_type] || :cast_error
|
409
|
-
|
500
|
+
logger.debug "Calling cast method: #{cast_method}"
|
410
501
|
wn_cast_op = self.send(cast_method, wnode, wtype, signed)
|
411
|
-
logger.debug "After type cast: wnode: #{wn_cast_op}, wtype: #{wtype}"
|
502
|
+
logger.debug "After type cast: wnode: #{wn_cast_op}, wtype: #{wtype}, wnode ID: #{wn_cast_op.object_id}"
|
412
503
|
wn_cast_op
|
413
504
|
end
|
414
505
|
|
506
|
+
# before generating native operator Wasm code check
|
507
|
+
# if the operator was overloaded
|
508
|
+
def send_method(wnode, method_name, wtype=WType.new(:none))
|
509
|
+
class_name = wtype.name
|
510
|
+
if wnode.find_method(method_name, class_name, :instance)
|
511
|
+
# it's an instance method call
|
512
|
+
logger.debug "Overloaded operator #{method_name} found in class #{class_name}"
|
513
|
+
wn_op = self.call(wnode, class_name, method_name, :instance)
|
514
|
+
else
|
515
|
+
# it's a native Wasm operator
|
516
|
+
if ALL_OPS_MAP.has_key? method_name
|
517
|
+
wn_op = self.native_operator(wnode, method_name, wtype)
|
518
|
+
else
|
519
|
+
raise "Unknown method '#{method_name}' in class #{class_name}"
|
520
|
+
end
|
521
|
+
end
|
522
|
+
wn_op
|
523
|
+
end
|
524
|
+
|
415
525
|
# just create a wnode for the WASM operator
|
416
526
|
# Do not set wtype or a code template yet,
|
417
527
|
# wait until operands type is known (see
|
418
528
|
# operands below)
|
419
|
-
def
|
420
|
-
if (op =
|
421
|
-
RELATIONAL_OPS_MAP[operator] ||
|
422
|
-
BOOLEAN_OPS_MAP[operator] ||
|
423
|
-
UNARY_OPS_MAP[operator] ))
|
529
|
+
def native_operator(wnode, operator, wtype=WType.new(:none))
|
530
|
+
if (op = ALL_OPS_MAP[operator])
|
424
531
|
(wn_op = WNode.new(:insn, wnode)).c(:operator, operator: op)
|
425
532
|
wn_op.wtype = wtype
|
533
|
+
logger.debug "Creating operator #{operator} wnode: #{wn_op}"
|
426
534
|
wn_op
|
427
535
|
else
|
428
536
|
raise "operator '#{operator}' not supported"
|
@@ -432,8 +540,21 @@ module Rlang::Parser
|
|
432
540
|
# finish the setting of the operator node and
|
433
541
|
# attach operands
|
434
542
|
def operands(wnode_op, wnode_recv, wnode_args)
|
543
|
+
logger.debug "Processing operands in operator wnode: #{wnode_op}..."
|
544
|
+
# Do not post process operands if the operator
|
545
|
+
# wnode is a call (= overloaded operator)
|
546
|
+
# and not a native operand
|
547
|
+
if wnode_op.template == :call
|
548
|
+
logger.debug "Doing nothing because it's a func call..."
|
549
|
+
return wnode_op
|
550
|
+
end
|
551
|
+
|
552
|
+
# A native operator only expects 0 (unary) or 1 (binary)
|
553
|
+
# argument in addition to the receiver
|
435
554
|
raise "only 0 or 1 operand expected (got #{wnode_args.count})" if wnode_args.count > 1
|
436
555
|
op = wnode_op.wargs[:operator]
|
556
|
+
#wnode_recv = wnode_op.children[0]
|
557
|
+
#wnode_args = wnode_op.children[1..-1]
|
437
558
|
# First find out the wtype that has precedence
|
438
559
|
wtype = self.class.leading_wtype(wnode_recv, *wnode_args)
|
439
560
|
|
@@ -441,7 +562,7 @@ module Rlang::Parser
|
|
441
562
|
logger.debug "leading type cast: #{wtype}"
|
442
563
|
|
443
564
|
# Attach receiver and argument to the operator wnode
|
444
|
-
# type casting them if necessary
|
565
|
+
# type casting them if necessary
|
445
566
|
self.cast(wnode_recv, wtype).reparent_to(wnode_op)
|
446
567
|
self.cast(wnode_args.first, wtype).reparent_to(wnode_op) unless wnode_args.empty?
|
447
568
|
|
@@ -455,8 +576,7 @@ module Rlang::Parser
|
|
455
576
|
# if + or - operator then multiply arg by size of object
|
456
577
|
if [:add, :sub].include? wnode_op.wargs[:operator]
|
457
578
|
(wn_mulop = WNode.new(:insn, wnode_op)).c(:operator, operator: :mul)
|
458
|
-
WNode.new(:insn, wn_mulop).c(:
|
459
|
-
value: lambda { wnode_recv.find_class(wnode_recv.wtype.name).size })
|
579
|
+
WNode.new(:insn, wn_mulop).c(:call, func_name: "$#{wnode_recv.wtype.name}::#{SIZE_METHOD}")
|
460
580
|
wnode_args.first.reparent_to(wn_mulop)
|
461
581
|
else
|
462
582
|
# It's a relational operator. In this case
|
@@ -466,6 +586,7 @@ module Rlang::Parser
|
|
466
586
|
wnode_op.wtype = WType::DEFAULT
|
467
587
|
end
|
468
588
|
end
|
589
|
+
logger.debug "Operands in operator wnode after postprocessing: #{wnode_op}..."
|
469
590
|
wnode_op
|
470
591
|
end
|
471
592
|
|