rlang 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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
|
|