rlang 0.4.1 → 0.5.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 +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
|
|