rlang 0.4.1 → 0.5.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 +4 -1
- data/Gemfile.lock +1 -1
- data/README.md +15 -9
- data/docs/RlangManual.md +26 -4
- data/lib/rlang/lib/array/array32.rb +43 -0
- data/lib/rlang/lib/array/array64.rb +43 -0
- data/lib/rlang/lib/array.rb +6 -0
- data/lib/rlang/lib/kernel.rb +18 -0
- data/lib/rlang/lib/malloc.rb +5 -3
- data/lib/rlang/lib/memory.rb +102 -2
- data/lib/rlang/lib/object.rb +11 -4
- data/lib/rlang/lib/string.rb +1 -0
- data/lib/rlang/lib/unistd.rb +1 -2
- data/lib/rlang/lib.rb +4 -2
- data/lib/rlang/parser/attr.rb +9 -13
- data/lib/rlang/parser/const.rb +105 -1
- data/lib/rlang/parser/cvar.rb +10 -6
- data/lib/rlang/parser/data.rb +5 -2
- data/lib/rlang/parser/ivar.rb +3 -7
- data/lib/rlang/parser/klass.rb +8 -35
- data/lib/rlang/parser/method.rb +22 -11
- data/lib/rlang/parser/module.rb +143 -0
- data/lib/rlang/parser/wgenerator.rb +190 -90
- data/lib/rlang/parser/wnode.rb +296 -121
- data/lib/rlang/parser/wtype.rb +18 -1
- data/lib/rlang/parser.rb +224 -113
- data/lib/rlang/version.rb +1 -1
- metadata +7 -2
@@ -12,6 +12,9 @@
|
|
12
12
|
|
13
13
|
require_relative '../../utils/log'
|
14
14
|
require_relative './wnode'
|
15
|
+
require_relative './klass'
|
16
|
+
require_relative './module'
|
17
|
+
require_relative './module'
|
15
18
|
|
16
19
|
module Rlang::Parser
|
17
20
|
|
@@ -67,10 +70,10 @@ module Rlang::Parser
|
|
67
70
|
|
68
71
|
# new template when object size > 0
|
69
72
|
NEW_TMPL = %q{
|
70
|
-
result :Object, :
|
73
|
+
result :Object, :allocate, :%{default_wtype}
|
71
74
|
def self.new(%{margs})
|
72
|
-
result
|
73
|
-
object_ptr = Object.
|
75
|
+
result :"%{class_name}"
|
76
|
+
object_ptr = Object.allocate(%{class_name}._size_).cast_to(:"%{class_name}")
|
74
77
|
object_ptr.initialize(%{margs})
|
75
78
|
return object_ptr
|
76
79
|
end
|
@@ -80,14 +83,13 @@ module Rlang::Parser
|
|
80
83
|
# use 0 as the _self_ address in memory. It should never
|
81
84
|
# be used anyway
|
82
85
|
NEW_ZERO_TMPL = %q{
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
}
|
86
|
+
def self.new(%{margs})
|
87
|
+
result :"%{class_name}"
|
88
|
+
object_ptr = 0.cast_to(:"%{class_name}")
|
89
|
+
object_ptr.initialize(%{margs})
|
90
|
+
return object_ptr
|
91
|
+
end
|
92
|
+
}
|
91
93
|
|
92
94
|
# Do nothing initialize method
|
93
95
|
DUMB_INIT_TMPL = %q{
|
@@ -117,18 +119,122 @@ module Rlang::Parser
|
|
117
119
|
@root = WTree.new().root
|
118
120
|
@new_count = 0
|
119
121
|
@static_count = 0
|
120
|
-
end
|
121
122
|
|
122
|
-
|
123
|
+
# define Object class and Kernel modules
|
124
|
+
# and include Kernel in Object
|
125
|
+
wn_object_class = self.klass(@root, [:Object], [])
|
126
|
+
@object_class = wn_object_class.klass
|
127
|
+
@root.klass = @object_class
|
128
|
+
wn_kernel_module = self.module(@root, [:Kernel])
|
129
|
+
self.include(wn_object_class, [:Kernel])
|
130
|
+
|
131
|
+
# Create Class and Module classes
|
132
|
+
# And Class inherits from module
|
133
|
+
self.klass(@root, [:Module], [:Object])
|
134
|
+
self.klass(@root, [:Class], [:Module])
|
135
|
+
end
|
136
|
+
|
137
|
+
# Create class and its basic methods (new, initialize and _size_)
|
138
|
+
def klass(wnode, class_path, super_class_path)
|
139
|
+
logger.debug "Defining klass #{class_path} < #{super_class_path}"
|
140
|
+
# See if class already created
|
141
|
+
if (k = wnode.find_class_or_module(class_path))
|
142
|
+
return k.wnode
|
143
|
+
end
|
144
|
+
|
145
|
+
# Make sure super class is known like Ruby does
|
146
|
+
if super_class_path.empty?
|
147
|
+
# special case to bootstrap Object class
|
148
|
+
if (class_path == [:Object] && wnode.in_root_scope?)
|
149
|
+
sk = nil
|
150
|
+
else
|
151
|
+
sk = @object_class
|
152
|
+
super_class_path << sk.path_name
|
153
|
+
end
|
154
|
+
else
|
155
|
+
sk = wnode.find_class_or_module(super_class_path)
|
156
|
+
raise "Unknown super class #{super_class_path}" unless sk
|
157
|
+
end
|
123
158
|
# Create class object and class wnode if it doesn't exist yet
|
124
|
-
|
125
|
-
#
|
126
|
-
|
127
|
-
|
128
|
-
|
159
|
+
# only one level deep class for now so scope class is always
|
160
|
+
# Object class
|
161
|
+
if (class_path == [:Object] && wnode.in_root_scope?)
|
162
|
+
k = wnode.create_class(class_path, super_class_path)
|
163
|
+
else
|
164
|
+
k = wnode.find_or_create_class(class_path, super_class_path)
|
165
|
+
end
|
166
|
+
# make sure the super class is correct in case class
|
167
|
+
# was previously declared in a result directive where
|
168
|
+
# no super class can be specified
|
169
|
+
k.super_class = sk if sk
|
170
|
+
# Create methods Class::new, Class#initialize and Class::_size_
|
171
|
+
# (do not generate the code yet as the end user code may
|
172
|
+
# define its own implementation in the class body)
|
173
|
+
k.wnode.find_or_create_method(k, :new, :class, k.wtype, true)
|
174
|
+
k.wnode.find_or_create_method(k, :_size_, :class, WType::DEFAULT, true)
|
175
|
+
k.wnode.find_or_create_method(k, :initialize, :instance, WType.new(:none), true)
|
129
176
|
k.wnode
|
130
177
|
end
|
131
178
|
|
179
|
+
# Create module object and module wnode
|
180
|
+
# if it doesn't exist yet
|
181
|
+
def module(wnode, module_path)
|
182
|
+
m = wnode.find_or_create_module(module_path)
|
183
|
+
m.wnode
|
184
|
+
end
|
185
|
+
|
186
|
+
def include(wnode, module_path)
|
187
|
+
m = wnode.find_module(module_path)
|
188
|
+
raise "Unknown module #{module_path}. Please require module first." \
|
189
|
+
unless m
|
190
|
+
wnc = wnode.class_or_module_wnode
|
191
|
+
raise "Cannot find scope class/module for included module!!" unless wnc
|
192
|
+
wnc.klass.include(m)
|
193
|
+
m.included!
|
194
|
+
wnc
|
195
|
+
end
|
196
|
+
|
197
|
+
def prepend(wnode, module_path)
|
198
|
+
m = wnode.find_module(module_path)
|
199
|
+
raise "Unknown module #{module_path}. Please require module first." \
|
200
|
+
unless m
|
201
|
+
wnc = wnode.class_or_module_wnode
|
202
|
+
raise "Cannot find scope class/module for prepended module!!" unless wnc
|
203
|
+
wnc.klass.prepend(m)
|
204
|
+
m.prepended!
|
205
|
+
wnc
|
206
|
+
end
|
207
|
+
|
208
|
+
def extend(wnode, module_path)
|
209
|
+
m = wnode.find_module(module_path)
|
210
|
+
raise "Cannot find module #{module_path}. Please require module first." \
|
211
|
+
unless m
|
212
|
+
wnc = wnode.class_or_module_wnode
|
213
|
+
raise "Cannot find scope class/module for included module!!" unless wnc
|
214
|
+
wnc.klass.extend(m)
|
215
|
+
m.extended!
|
216
|
+
wnc
|
217
|
+
end
|
218
|
+
|
219
|
+
# Ahead of time method declaration and return type
|
220
|
+
# Create corresponding classes and method objects as we known we'll
|
221
|
+
# be calling them later on
|
222
|
+
def declare_method(wnode, wtype, method_name, result_type)
|
223
|
+
class_path = wtype.class_path
|
224
|
+
logger.debug "Declaring method #{method_name} in class #{class_path}"
|
225
|
+
klass = WNode.root.find_or_create_class(class_path, [])
|
226
|
+
if method_name[0] == '#'
|
227
|
+
method_type = :instance
|
228
|
+
mth_name = method_name[1..-1].to_sym
|
229
|
+
else
|
230
|
+
method_type = :class
|
231
|
+
mth_name = method_name.to_sym
|
232
|
+
end
|
233
|
+
(m = wnode.find_or_create_method(klass, mth_name, method_type, nil)).wtype = WType.new(result_type)
|
234
|
+
logger.debug "Declared #{method_type} method #{m.name} in class #{m.klass.name} with wtype #{m.wtype.name}"
|
235
|
+
m
|
236
|
+
end
|
237
|
+
|
132
238
|
# Postprocess ivars
|
133
239
|
# (called at end of class parsing)
|
134
240
|
def ivars_setup(wnode)
|
@@ -147,11 +253,12 @@ module Rlang::Parser
|
|
147
253
|
# generate code for class attributes
|
148
254
|
# (called at end of class parsing)
|
149
255
|
def def_attr(wnode)
|
150
|
-
|
256
|
+
klass = wnode.find_current_class_or_module()
|
257
|
+
wnc = klass.wnode
|
151
258
|
raise "Cannot find class for attributes definition!!" unless wnc
|
152
259
|
# Process each declared class attribute
|
153
|
-
|
154
|
-
logger.debug("Generating accessors for attribute #{
|
260
|
+
klass.attrs.each do |attr|
|
261
|
+
logger.debug("Generating accessors for attribute #{klass.name}\##{attr.name}")
|
155
262
|
# Generate getter and setter methods wnode
|
156
263
|
# unless method already implemented by user
|
157
264
|
if attr.setter
|
@@ -173,9 +280,9 @@ module Rlang::Parser
|
|
173
280
|
# Also generate the Class::_size_ method
|
174
281
|
# (needed for dynamic memory allocation
|
175
282
|
# by Object.allocate)
|
176
|
-
size_method = wnc.find_or_create_method(SIZE_METHOD,
|
283
|
+
size_method = wnc.find_or_create_method(klass, SIZE_METHOD, :class, WType::DEFAULT)
|
177
284
|
unless size_method.wnode
|
178
|
-
logger.debug("Generating #{size_method.
|
285
|
+
logger.debug("Generating #{size_method.klass.name}\##{size_method.name}")
|
179
286
|
wns = WNode.new(:insn, wnc, true)
|
180
287
|
wns.wtype = WType::DEFAULT
|
181
288
|
wns.c(:class_size, func_name: size_method.wasm_name,
|
@@ -204,28 +311,24 @@ module Rlang::Parser
|
|
204
311
|
wn_get
|
205
312
|
end
|
206
313
|
|
207
|
-
def
|
208
|
-
logger.debug("
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
#
|
215
|
-
|
216
|
-
wn.create_marg(:_self_)
|
217
|
-
logger.debug("Building instance method: wn.wtype #{wn.wtype}, wn.method #{wn.method}")
|
218
|
-
wn
|
219
|
-
end
|
220
|
-
|
221
|
-
def class_method(wnode, method)
|
222
|
-
logger.debug("Generating wnode for class method #{method}")
|
314
|
+
def def_method(wnode, method_name, method_type)
|
315
|
+
logger.debug("Defining #{method_type} method #{method_name}...")
|
316
|
+
if (method = wnode.find_method(nil, method_name, method_type, true))
|
317
|
+
logger.warn "Redefining #{method.klass.name},#{method_name}" if method.wnode
|
318
|
+
else
|
319
|
+
method = wnode.create_method(nil, method_name, method_type, nil, true)
|
320
|
+
end
|
321
|
+
# Generate method definition wnode
|
322
|
+
logger.debug("Generating wnode for #{method_type} method #{method_name}")
|
223
323
|
wn = WNode.new(:method, wnode)
|
224
324
|
method.wnode = wn
|
225
|
-
wn.method = method # must be set before calling func_name
|
226
325
|
wn.wtype = method.wtype
|
227
326
|
wn.c(:func, func_name: wn.method.wasm_name)
|
228
|
-
|
327
|
+
# On instance method also declare a first parameter
|
328
|
+
# called _self_ representing the pointer to the
|
329
|
+
# object instance
|
330
|
+
wn.create_marg(:_self_) if method.instance?
|
331
|
+
logger.debug("Building #{method_type} method: wn.wtype #{wn.wtype}, wn.method #{wn.method}")
|
229
332
|
wn
|
230
333
|
end
|
231
334
|
|
@@ -273,7 +376,7 @@ module Rlang::Parser
|
|
273
376
|
wn
|
274
377
|
end
|
275
378
|
|
276
|
-
# Get
|
379
|
+
# Get constant
|
277
380
|
def const(wnode, const)
|
278
381
|
(wn = WNode.new(:insn, wnode)).wtype = const.wtype
|
279
382
|
wn.c(:load, wtype: const.wtype, var_name: const.wasm_name)
|
@@ -298,7 +401,7 @@ module Rlang::Parser
|
|
298
401
|
# Call setter (on attr or instance variable)
|
299
402
|
# This is the same as calling the corresponding setter
|
300
403
|
def call_setter(wnode, wnode_recv, attr)
|
301
|
-
wn = self.
|
404
|
+
wn = self.send_method(wnode, wnode_recv.wtype, attr.setter_name, :instance)
|
302
405
|
# First argument of the setter must be the receiver
|
303
406
|
wnode_recv.reparent_to(wn)
|
304
407
|
wn
|
@@ -307,7 +410,7 @@ module Rlang::Parser
|
|
307
410
|
# Call getter (on attr or instance variable)
|
308
411
|
# This is the same as calling the corresponding getter
|
309
412
|
def call_getter(wnode, wnode_recv, attr)
|
310
|
-
wn = self.
|
413
|
+
wn = self.send_method(wnode, wnode_recv.wtype, attr.getter_name, :instance)
|
311
414
|
# First argument of the getter must always be the receiver
|
312
415
|
wnode_recv.reparent_to(wn)
|
313
416
|
wn
|
@@ -402,7 +505,7 @@ module Rlang::Parser
|
|
402
505
|
|
403
506
|
# Static new string object
|
404
507
|
def string_static_new(wnode, string)
|
405
|
-
klass = wnode.
|
508
|
+
klass = wnode.find_current_class_or_module()
|
406
509
|
data_label = "#{klass.name}_string_#{@static_count += 1}"
|
407
510
|
# Statically
|
408
511
|
data_stg = self.string_static(string, data_label)
|
@@ -418,16 +521,16 @@ module Rlang::Parser
|
|
418
521
|
|
419
522
|
# Dynamic new string object
|
420
523
|
def string_dynamic_new(wnode, string)
|
421
|
-
klass = wnode.
|
524
|
+
klass = wnode.find_current_class_or_module()
|
422
525
|
data_label = "#{klass.name}_string_#{@static_count += 1}"
|
423
526
|
data_stg = self.string_static(string, data_label)
|
424
527
|
string_new_source = STRING_NEW_TMPL % {
|
425
|
-
string: string,
|
426
528
|
ptr: data_stg.address,
|
427
529
|
length: string.length
|
428
530
|
}
|
429
531
|
#puts string_new_source;exit
|
430
532
|
wn_string = self.parser.parse(string_new_source, wnode)
|
533
|
+
#puts wn_string; exit
|
431
534
|
end
|
432
535
|
|
433
536
|
# All the cast_xxxx methods below returns
|
@@ -503,25 +606,6 @@ module Rlang::Parser
|
|
503
606
|
wn_cast_op
|
504
607
|
end
|
505
608
|
|
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
|
-
|
525
609
|
# just create a wnode for the WASM operator
|
526
610
|
# Do not set wtype or a code template yet,
|
527
611
|
# wait until operands type is known (see
|
@@ -592,10 +676,10 @@ module Rlang::Parser
|
|
592
676
|
|
593
677
|
# Statically allocate an object in data segment
|
594
678
|
# with the size of the class
|
595
|
-
def static_new(wnode,
|
596
|
-
klass = wnode.
|
679
|
+
def static_new(wnode, class_path)
|
680
|
+
klass = wnode.find_class_or_module(class_path)
|
597
681
|
if klass.size > 0
|
598
|
-
data_label = "#{
|
682
|
+
data_label = "#{klass.path_name}_new_#{@new_count += 1}"
|
599
683
|
data = DAta.new(data_label.to_sym, "\x00"*klass.wnode.class_size)
|
600
684
|
address = data.address
|
601
685
|
else
|
@@ -606,50 +690,66 @@ module Rlang::Parser
|
|
606
690
|
end
|
607
691
|
(wn_object_addr = WNode.new(:insn, wnode)).c(:addr, value: address)
|
608
692
|
# VERY IMPORTANT the wtype of this node is the Class name !!!
|
609
|
-
wn_object_addr.wtype = WType.new(
|
693
|
+
wn_object_addr.wtype = WType.new(klass.path_name)
|
610
694
|
wn_object_addr
|
611
695
|
end
|
612
696
|
|
613
697
|
# Create the dynamic new method. It allocates memory
|
614
698
|
# for the object created and calls initialize
|
615
699
|
def def_new(wnode_class)
|
616
|
-
|
700
|
+
k = wnode_class.find_current_class_or_module()
|
701
|
+
logger.debug "Defining new method for #{k.name}"
|
702
|
+
# no need to define new method for native types
|
617
703
|
return if wnode_class.klass.wtype.native?
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
logger.debug "Creating code for #{
|
704
|
+
if (new_mth = wnode_class.find_method(k, :new, :class, true))
|
705
|
+
return if new_mth.wnode # already implemented
|
706
|
+
end
|
707
|
+
|
708
|
+
logger.debug "Creating code for #{k.name}.new"
|
709
|
+
# Find initialize method and use the same method args for new
|
710
|
+
init_method = wnode_class.find_method(k, :initialize, :instance, true)
|
623
711
|
new_tmpl = wnode_class.class_size.zero? ? NEW_ZERO_TMPL : NEW_TMPL
|
624
712
|
new_source = new_tmpl % {
|
625
713
|
default_wtype: WType::DEFAULT.name,
|
626
|
-
class_name:
|
714
|
+
class_name: k.path_name,
|
627
715
|
# Do not pass _self_ argument to the new method of course !!
|
628
716
|
margs: init_method.margs.reject {|ma| ma._self_?}.map(&:name).join(', '),
|
629
717
|
class_size: wnode_class.class_size
|
630
718
|
}
|
631
|
-
|
719
|
+
new_mth.wnode = self.parser.parse(new_source, wnode_class)
|
632
720
|
end
|
633
721
|
|
634
722
|
# Define a dumb initialize method if not implemented
|
635
723
|
# already in user code
|
636
724
|
def def_initialize(wnode_class)
|
725
|
+
k = wnode_class.find_current_class_or_module()
|
637
726
|
# no new/initialize method for native types
|
638
|
-
return if WType.new(
|
727
|
+
return if WType.new(k.path_name).native?
|
639
728
|
# generate code for a dumb initialize method if not defined
|
640
729
|
# in user code
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
730
|
+
if (init_mth = wnode_class.find_method(k, :initialize, :instance, true))
|
731
|
+
return if init_mth.wnode # already implemented
|
732
|
+
end
|
733
|
+
logger.debug "Creating MEthod and code for #{k.name}#initialize"
|
734
|
+
init_source = DUMB_INIT_TMPL
|
735
|
+
init_mth.wnode = self.parser.parse(init_source, wnode_class)
|
736
|
+
end
|
737
|
+
|
738
|
+
# generate code for method call
|
739
|
+
def send_method(wnode, class_path, method_name, method_type)
|
740
|
+
logger.debug "In call generator for #{class_path}::#{method_name}"
|
741
|
+
k = wnode.find_class_or_module(class_path)
|
742
|
+
if k && (method = wnode.find_method(k, method_name, method_type))
|
743
|
+
logger.debug "Found method #{method.name} in class #{method.klass.name}"
|
744
|
+
(wn_call = WNode.new(:insn, wnode)).c(:call, func_name: method.wasm_name)
|
745
|
+
wn_call.wtype = method.wtype
|
746
|
+
wn_call
|
747
|
+
elsif ALL_OPS_MAP.has_key? method_name
|
748
|
+
# it's a native Wasm operator
|
749
|
+
wn_call = self.native_operator(wnode, method_name, WType.new(class_path))
|
750
|
+
else
|
751
|
+
raise "Unknown method '#{method_name}' in class #{class_path}"
|
645
752
|
end
|
646
|
-
end
|
647
|
-
|
648
|
-
def call(wnode, class_name, method_name, method_type)
|
649
|
-
method = wnode.find_or_create_method(method_name, class_name, nil, method_type)
|
650
|
-
logger.debug "found method #{method}"
|
651
|
-
(wn_call = WNode.new(:insn, wnode)).c(:call, func_name: method.wasm_name)
|
652
|
-
wn_call.wtype = method.wtype
|
653
753
|
wn_call
|
654
754
|
end
|
655
755
|
|