rlang 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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, :alloc, :%{default_wtype}
73
+ result :Object, :allocate, :%{default_wtype}
71
74
  def self.new(%{margs})
72
- result :%{class_name}
73
- object_ptr = Object.alloc(%{class_name}._size_).cast_to(:%{class_name})
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
- result :Object, :alloc, :%{default_wtype}
84
- def self.new(%{margs})
85
- result :%{class_name}
86
- object_ptr = 0.cast_to(:%{class_name})
87
- object_ptr.initialize(%{margs})
88
- return object_ptr
89
- end
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
- def klass(wnode, class_name)
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
- k = wnode.find_or_create_class(class_name)
125
- # Create the Class.new method object too (not
126
- # the code yet in case the end user code defines
127
- # its own implementation in the class body)
128
- k.wnode.find_or_create_method(:new, k.name, k.wtype, :class)
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
- wnc = wnode.class_wnode
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
- wnc.klass.attrs.each do |attr|
154
- logger.debug("Generating accessors for attribute #{wnc.klass.name}\##{attr.name}")
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, wnc.klass.name, WType::DEFAULT, :class)
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.class_name}\##{size_method.name}")
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 instance_method(wnode, method)
208
- logger.debug("Generating wnode for instance method #{method.inspect}")
209
- wn = WNode.new(:method, wnode)
210
- method.wnode = wn
211
- wn.method = method # must be set before calling func_name
212
- wn.wtype = method.wtype
213
- wn.c(:func, func_name: wn.method.wasm_name)
214
- # Also declare a "hidden" parameter representing the
215
- # pointer to the instance (always default wtype)
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
- logger.debug("Building class method: wn.wtype #{wn.wtype}, wn.method #{wn.method}")
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 class variable
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.call(wnode, wnode_recv.wtype.name, attr.setter_name, :instance)
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.call(wnode, wnode_recv.wtype.name, attr.getter_name, :instance)
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.find_class(nil)
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.find_class(nil)
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, class_name)
596
- klass = wnode.find_class(class_name)
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 = "#{class_name}_new_#{@new_count += 1}"
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(class_name.to_sym)
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
- # no new method for native types
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
- new_method = wnode_class.find_method(:new, wnode_class.class_name, :class)
619
- return if new_method.wnode # already implemented
620
-
621
- init_method = wnode_class.find_method(:initialize, wnode_class.class_name, :instance)
622
- logger.debug "Creating code for #{wnode_class.class_name}.new"
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: wnode_class.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
- new_method.wnode = self.parser.parse(new_source, wnode_class)
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(wnode_class.class_name).native?
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
- unless wnode_class.find_method(:initialize, wnode_class.class_name, :instance)
642
- logger.debug "Creating MEthod and code for #{wnode_class.class_name}#initialize"
643
- init_source = DUMB_INIT_TMPL
644
- self.parser.parse(init_source, wnode_class)
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