rltk 3.0.0 → 3.0.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/Rakefile +21 -22
- data/lib/rltk/ast.rb +185 -118
- data/lib/rltk/cfg.rb +157 -103
- data/lib/rltk/cg/basic_block.rb +19 -19
- data/lib/rltk/cg/bindings.rb +16 -16
- data/lib/rltk/cg/builder.rb +129 -129
- data/lib/rltk/cg/context.rb +7 -7
- data/lib/rltk/cg/contractor.rb +7 -7
- data/lib/rltk/cg/execution_engine.rb +30 -30
- data/lib/rltk/cg/function.rb +37 -37
- data/lib/rltk/cg/generated_bindings.rb +3932 -3932
- data/lib/rltk/cg/generic_value.rb +17 -17
- data/lib/rltk/cg/instruction.rb +116 -116
- data/lib/rltk/cg/llvm.rb +22 -22
- data/lib/rltk/cg/memory_buffer.rb +7 -7
- data/lib/rltk/cg/module.rb +73 -73
- data/lib/rltk/cg/pass_manager.rb +35 -35
- data/lib/rltk/cg/target.rb +41 -41
- data/lib/rltk/cg/triple.rb +7 -7
- data/lib/rltk/cg/type.rb +75 -75
- data/lib/rltk/cg/value.rb +161 -161
- data/lib/rltk/lexer.rb +57 -57
- data/lib/rltk/lexers/calculator.rb +7 -7
- data/lib/rltk/lexers/ebnf.rb +5 -5
- data/lib/rltk/parser.rb +338 -295
- data/lib/rltk/parsers/infix_calc.rb +7 -7
- data/lib/rltk/parsers/postfix_calc.rb +3 -3
- data/lib/rltk/parsers/prefix_calc.rb +3 -3
- data/lib/rltk/token.rb +13 -13
- data/lib/rltk/version.rb +6 -6
- data/test/cg/tc_basic_block.rb +17 -17
- data/test/cg/tc_control_flow.rb +41 -41
- data/test/cg/tc_function.rb +4 -4
- data/test/cg/tc_generic_value.rb +3 -3
- data/test/cg/tc_instruction.rb +53 -53
- data/test/cg/tc_math.rb +12 -12
- data/test/cg/tc_module.rb +14 -14
- data/test/cg/tc_transforms.rb +11 -11
- data/test/cg/tc_type.rb +12 -12
- data/test/cg/tc_value.rb +35 -35
- data/test/cg/ts_cg.rb +5 -5
- data/test/tc_ast.rb +137 -60
- data/test/tc_cfg.rb +34 -34
- data/test/tc_lexer.rb +42 -42
- data/test/tc_parser.rb +250 -173
- data/test/tc_token.rb +2 -2
- data/test/ts_rltk.rb +8 -8
- metadata +84 -85
- data/lib/rltk/cg/old_generated_bindings.rb +0 -6152
data/lib/rltk/cg/type.rb
CHANGED
@@ -16,13 +16,13 @@ require 'filigree/abstract_class'
|
|
16
16
|
# Ruby Language Toolkit
|
17
17
|
require 'rltk/cg/bindings'
|
18
18
|
require 'rltk/cg/context'
|
19
|
-
|
19
|
+
|
20
20
|
#######################
|
21
21
|
# Classes and Modules #
|
22
22
|
#######################
|
23
23
|
|
24
24
|
module RLTK::CG
|
25
|
-
|
25
|
+
|
26
26
|
# The Type class and its sub-classes are used to describe the size and
|
27
27
|
# structure of various data objects inside LLVM and how different
|
28
28
|
# operations interact with them. When instantiating objects of the
|
@@ -32,7 +32,7 @@ module RLTK::CG
|
|
32
32
|
class Type
|
33
33
|
include BindingClass
|
34
34
|
include Filigree::AbstractClass
|
35
|
-
|
35
|
+
|
36
36
|
# Instantiate a Type object from a pointer. This function is used
|
37
37
|
# internally, and as a library user you should never have to call it.
|
38
38
|
#
|
@@ -59,13 +59,13 @@ module RLTK::CG
|
|
59
59
|
when :x86_mmx then X86MMXType.new
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
# The default constructor for Type objects.
|
64
64
|
#
|
65
65
|
# @param [Context, nil] context An optional context in which to create the type.
|
66
66
|
def initialize(context = nil)
|
67
67
|
bname = Bindings.get_bname(self.class.short_name)
|
68
|
-
|
68
|
+
|
69
69
|
@ptr =
|
70
70
|
if context
|
71
71
|
Bindings.send((bname.to_s + '_in_context').to_sym, check_type(context, Context, 'context'))
|
@@ -73,82 +73,82 @@ module RLTK::CG
|
|
73
73
|
Bindings.send(bname)
|
74
74
|
end
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
# @return [NativeInt] Alignment of the type.
|
78
78
|
def allignment
|
79
79
|
NativeInt.new(Bindings.align_of(@ptr))
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
# @return [Context] Context in which this type was created.
|
83
83
|
def context
|
84
84
|
Context.new(Bindings.get_type_context(@ptr))
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
# Dump a string representation of the type to stdout.
|
88
88
|
#
|
89
89
|
# @return [void]
|
90
90
|
def dump
|
91
91
|
Bindings.dump_type(@ptr)
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# @return [Fixnum] Hashed value of the pointer representing this type.
|
95
95
|
def hash
|
96
96
|
@ptr.address.hash
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
# @see Bindings._enum_type_kind_
|
100
100
|
#
|
101
101
|
# @return [Symbol] The *kind* of this type.
|
102
102
|
def kind
|
103
103
|
Bindings.get_type_kind(@ptr)
|
104
104
|
end
|
105
|
-
|
105
|
+
|
106
106
|
# @return [NativeInt] Size of objects of this type.
|
107
107
|
def size
|
108
108
|
Int64.new(Bindings.size_of(@ptr))
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
# @return [String] LLVM IR representation of the type
|
112
112
|
def to_s
|
113
113
|
Bindings.print_type_to_string(@ptr)
|
114
114
|
end
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
# All types that are used to represent numbers inherit from this class.
|
118
118
|
#
|
119
119
|
# @abstract
|
120
120
|
class NumberType < Type
|
121
121
|
include Filigree::AbstractClass
|
122
|
-
|
122
|
+
|
123
123
|
# @return [Value] The corresponding Value sub-class that is used to represent values of this type.
|
124
124
|
def self.value_class
|
125
125
|
begin
|
126
126
|
@value_class ||=
|
127
127
|
RLTK::CG.const_get(self.name.match(/::(.+)Type$/).captures.last.to_sym)
|
128
|
-
|
128
|
+
|
129
129
|
rescue
|
130
130
|
raise "#{self.name} has no value class."
|
131
131
|
end
|
132
132
|
end
|
133
|
-
|
133
|
+
|
134
134
|
# @return [Value] The corresponding Value sub-class that is used to represent values of this type.
|
135
135
|
def value_class
|
136
136
|
self.class.value_class
|
137
137
|
end
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
# All types that represent integers of a given width inherit from this class.
|
141
141
|
#
|
142
142
|
# @abstract
|
143
143
|
class BasicIntType < NumberType
|
144
144
|
include Filigree::AbstractClass
|
145
|
-
|
145
|
+
|
146
146
|
# @return [Integer] Number of bits used to represent an integer type.
|
147
147
|
def width
|
148
148
|
@width ||= Bindings.get_int_type_width(@ptr)
|
149
149
|
end
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
# An integer of an arbitrary width.
|
153
153
|
class IntType < BasicIntType
|
154
154
|
# @param [Integer] width Width of new integer type.
|
@@ -167,7 +167,7 @@ module RLTK::CG
|
|
167
167
|
raise 'The width parameter must be greater then 0.'
|
168
168
|
end
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
# Overrides {NumberType#value_class}.
|
172
172
|
#
|
173
173
|
# @raise [RuntimeError] This function has no meaning in this class.
|
@@ -175,7 +175,7 @@ module RLTK::CG
|
|
175
175
|
raise 'The RLKT::CG::IntType class has no value class.'
|
176
176
|
end
|
177
177
|
end
|
178
|
-
|
178
|
+
|
179
179
|
# A class inherited by singleton integer type classes.
|
180
180
|
#
|
181
181
|
# @abstract
|
@@ -183,7 +183,7 @@ module RLTK::CG
|
|
183
183
|
include Filigree::AbstractClass
|
184
184
|
include Singleton
|
185
185
|
end
|
186
|
-
|
186
|
+
|
187
187
|
# A class inherited by all types representing floats.
|
188
188
|
#
|
189
189
|
# @abstract
|
@@ -191,7 +191,7 @@ module RLTK::CG
|
|
191
191
|
include Filigree::AbstractClass
|
192
192
|
include Singleton
|
193
193
|
end
|
194
|
-
|
194
|
+
|
195
195
|
# A class inherited by non-number singleton type classes.
|
196
196
|
#
|
197
197
|
# @abstract
|
@@ -199,7 +199,7 @@ module RLTK::CG
|
|
199
199
|
include Filigree::AbstractClass
|
200
200
|
include Singleton
|
201
201
|
end
|
202
|
-
|
202
|
+
|
203
203
|
# 1 bit integer type. Often used to represent Boolean values.
|
204
204
|
class Int1Type < SimpleIntType; end
|
205
205
|
# 8 bit (1 byte) integer type.
|
@@ -210,7 +210,7 @@ module RLTK::CG
|
|
210
210
|
class Int32Type < SimpleIntType; end
|
211
211
|
# 64 bit (8 byte) integer type.
|
212
212
|
class Int64Type < SimpleIntType; end
|
213
|
-
|
213
|
+
|
214
214
|
# Integer the same size as a native pointer.
|
215
215
|
class IntPtr < SimpleIntType
|
216
216
|
# Create an integer that is the same size as a pointer on the target
|
@@ -223,26 +223,26 @@ module RLTK::CG
|
|
223
223
|
def initialize(target_data, addr_space = nil, context = nil)
|
224
224
|
call = 'int_type'
|
225
225
|
args = [target_data]
|
226
|
-
|
226
|
+
|
227
227
|
if addr_space
|
228
228
|
call += '_for_as'
|
229
229
|
args << addr_space
|
230
230
|
end
|
231
|
-
|
231
|
+
|
232
232
|
if context
|
233
233
|
call += '_in_context'
|
234
234
|
args << context
|
235
235
|
end
|
236
|
-
|
236
|
+
|
237
237
|
Bindings.send(call.to_s, *args)
|
238
238
|
end
|
239
239
|
end
|
240
|
-
|
240
|
+
|
241
241
|
# The native integer type on the current (not the target) platform.
|
242
242
|
NativeIntType = RLTK::CG.const_get("Int#{FFI.type_size(:int) * 8}Type")
|
243
|
-
|
243
|
+
|
244
244
|
# A 16-bit floating point number type.
|
245
|
-
class HalfType < RealType; end
|
245
|
+
class HalfType < RealType; end
|
246
246
|
# A double precision floating point number type.
|
247
247
|
class DoubleType < RealType; end
|
248
248
|
# A single precision floating point number type.
|
@@ -253,29 +253,29 @@ module RLTK::CG
|
|
253
253
|
class PPCFP128Type < RealType; end
|
254
254
|
# A 80 bit (10 byte) floating point number type for the x86 architecture.
|
255
255
|
class X86FP80Type < RealType; end
|
256
|
-
|
256
|
+
|
257
257
|
# A type for x86 MMX instructions.
|
258
258
|
class X86MMXType < SimpleType; end
|
259
|
-
|
259
|
+
|
260
260
|
# A type used in representing void pointers and functions that return no values.
|
261
261
|
class VoidType < SimpleType; end
|
262
262
|
# A type used to represent labels in LLVM IR.
|
263
263
|
class LabelType < SimpleType; end
|
264
|
-
|
264
|
+
|
265
265
|
# The common ancestor for array, pointer, and struct types.
|
266
266
|
#
|
267
267
|
# @abstract
|
268
268
|
class AggregateType < Type
|
269
269
|
include Filigree::AbstractClass
|
270
270
|
end
|
271
|
-
|
271
|
+
|
272
272
|
# {ArrayType} and {PointerType} inherit from this class so they can share
|
273
273
|
# a constructor.
|
274
274
|
#
|
275
275
|
# @abstract
|
276
276
|
class SimpleAggregateType < AggregateType
|
277
277
|
include Filigree::AbstractClass
|
278
|
-
|
278
|
+
|
279
279
|
# Used to initialize {ArrayType ArrayTypes} and {PointerType PointerTypes}.
|
280
280
|
#
|
281
281
|
# @param [FFI::Pointer, Type] overloaded Pointer to an existing aggregate type or a Type object that
|
@@ -288,17 +288,17 @@ module RLTK::CG
|
|
288
288
|
else
|
289
289
|
@element_type = check_cg_type(overloaded, Type, 'overloaded')
|
290
290
|
bname = Bindings.get_bname(self.class.short_name)
|
291
|
-
|
291
|
+
|
292
292
|
Bindings.send(bname, @element_type, size_or_address_space)
|
293
293
|
end
|
294
294
|
end
|
295
|
-
|
295
|
+
|
296
296
|
# @return [Type] Type of objects stored inside this aggregate.
|
297
297
|
def element_type
|
298
298
|
@element_type ||= Type.from_ptr(Bindings.get_element_type(@ptr))
|
299
299
|
end
|
300
300
|
end
|
301
|
-
|
301
|
+
|
302
302
|
# A Type describing an array that holds objects of a single given type.
|
303
303
|
class ArrayType < SimpleAggregateType
|
304
304
|
# @return [Integer] Number of elements in this array type.
|
@@ -307,7 +307,7 @@ module RLTK::CG
|
|
307
307
|
end
|
308
308
|
alias :length :size
|
309
309
|
end
|
310
|
-
|
310
|
+
|
311
311
|
# A Type describing a pointer to another type.
|
312
312
|
class PointerType < SimpleAggregateType
|
313
313
|
# @return [Integer] Address space of this pointer.
|
@@ -315,7 +315,7 @@ module RLTK::CG
|
|
315
315
|
@address_space ||= Bindings.get_pointer_address_space(@ptr)
|
316
316
|
end
|
317
317
|
end
|
318
|
-
|
318
|
+
|
319
319
|
# A type used to represent vector operations (SIMD). This is NOT an
|
320
320
|
# aggregate type.
|
321
321
|
class VectorType < Type
|
@@ -331,28 +331,28 @@ module RLTK::CG
|
|
331
331
|
else
|
332
332
|
@element_type = check_cg_type(overloaded, Type, 'overloaded')
|
333
333
|
bname = Bindings.get_bname(self.class.short_name)
|
334
|
-
|
334
|
+
|
335
335
|
Bindings.send(bname, @element_type, size)
|
336
336
|
end
|
337
337
|
end
|
338
|
-
|
338
|
+
|
339
339
|
# @return [Type] Type of object stored inside this vector.
|
340
340
|
def element_type
|
341
341
|
@element_type ||= Type.from_ptr(Bindings.get_element_type(@ptr))
|
342
342
|
end
|
343
|
-
|
343
|
+
|
344
344
|
# @return [Integer] Number of objects in this vector type.
|
345
345
|
def size
|
346
346
|
Bindings.get_vector_size(@ptr)
|
347
347
|
end
|
348
348
|
alias :length :size
|
349
349
|
end
|
350
|
-
|
350
|
+
|
351
351
|
# A type representing the return an argument types for a function.
|
352
352
|
class FunctionType < Type
|
353
353
|
# @return [Array<Type>] Types of this function type's arguments.
|
354
354
|
attr_reader :arg_types
|
355
|
-
|
355
|
+
|
356
356
|
# Create a new function type from a pointer or description of the
|
357
357
|
# return type and argument types.
|
358
358
|
#
|
@@ -367,36 +367,36 @@ module RLTK::CG
|
|
367
367
|
else
|
368
368
|
@return_type = check_cg_type(overloaded, Type, 'return_type')
|
369
369
|
@arg_types = check_cg_array_type(arg_types, Type, 'arg_types').freeze
|
370
|
-
|
370
|
+
|
371
371
|
arg_types_ptr = FFI::MemoryPointer.new(:pointer, @arg_types.length)
|
372
372
|
arg_types_ptr.write_array_of_pointer(@arg_types)
|
373
|
-
|
373
|
+
|
374
374
|
Bindings.function_type(@return_type, arg_types_ptr, @arg_types.length, varargs.to_i)
|
375
375
|
end
|
376
376
|
end
|
377
|
-
|
377
|
+
|
378
378
|
# @return [Array<Type>] Types of this function type's arguments.
|
379
379
|
def argument_types
|
380
380
|
@arg_types ||=
|
381
381
|
begin
|
382
382
|
num_elements = Bindings.count_param_types(@ptr)
|
383
|
-
|
383
|
+
|
384
384
|
ret_ptr = FFI::MemoryPointer.new(:pointer)
|
385
385
|
Bindings.get_param_types(@ptr, ret_ptr)
|
386
|
-
|
386
|
+
|
387
387
|
types_ptr = ret_ptr.get_pointer(0)
|
388
|
-
|
388
|
+
|
389
389
|
types_ptr.get_array_of_pointer(0, num_elements).map { |ptr| Type.from_ptr(ptr) }
|
390
390
|
end
|
391
391
|
end
|
392
392
|
alias :arg_types :argument_types
|
393
|
-
|
393
|
+
|
394
394
|
# @return [Type] The return type of this function type.
|
395
395
|
def return_type
|
396
396
|
@return_type ||= Type.from_ptr(Bindings.get_return_type(@ptr))
|
397
397
|
end
|
398
398
|
end
|
399
|
-
|
399
|
+
|
400
400
|
# A type for representing an arbitrary collection of types.
|
401
401
|
class StructType < AggregateType
|
402
402
|
# Create a new struct type.
|
@@ -413,43 +413,43 @@ module RLTK::CG
|
|
413
413
|
else
|
414
414
|
# Check the types of the elements of the overloaded parameter.
|
415
415
|
@element_types = check_cg_array_type(overloaded, Type, 'overloaded')
|
416
|
-
|
416
|
+
|
417
417
|
el_types_ptr = FFI::MemoryPointer.new(:pointer, @element_types.length)
|
418
418
|
el_types_ptr.write_array_of_pointer(@element_types)
|
419
|
-
|
419
|
+
|
420
420
|
if name
|
421
421
|
@name = check_type(name, String, 'name')
|
422
|
-
|
422
|
+
|
423
423
|
Bindings.struct_create_named(Context.global, @name).tap do |ptr|
|
424
424
|
Bindings.struct_set_body(ptr, el_types_ptr, @element_types.length, packed.to_i) unless @element_types.empty?
|
425
425
|
end
|
426
|
-
|
426
|
+
|
427
427
|
elsif context
|
428
428
|
check_type(context, Context, 'context')
|
429
|
-
|
429
|
+
|
430
430
|
Bindings.struct_type_in_context(context, el_types_ptr, @element_types.length, is_packed.to_i)
|
431
|
-
|
431
|
+
|
432
432
|
else
|
433
433
|
Bindings.struct_type(el_types_ptr, @element_types.length, packed.to_i)
|
434
434
|
end
|
435
435
|
end
|
436
436
|
end
|
437
|
-
|
437
|
+
|
438
438
|
# @return [Array<Type>] Array of the types in this struct type.
|
439
439
|
def element_types
|
440
440
|
@element_types ||=
|
441
441
|
begin
|
442
442
|
num_elements = Bindings.count_struct_element_types(@ptr)
|
443
|
-
|
443
|
+
|
444
444
|
ret_ptr = FFI::MemoryPointer.new(:pointer)
|
445
445
|
Bindings.get_struct_element_types(@ptr, ret_ptr)
|
446
|
-
|
446
|
+
|
447
447
|
types_ptr = ret_ptr.get_pointer(0)
|
448
|
-
|
448
|
+
|
449
449
|
types_ptr.get_array_of_pointer(0, num_elements).map { |ptr| Type.from_ptr(ptr) }
|
450
450
|
end
|
451
451
|
end
|
452
|
-
|
452
|
+
|
453
453
|
# Set the types in the body of this struct type.
|
454
454
|
#
|
455
455
|
# @param [Array<Type>] el_types Array of types in the struct.
|
@@ -458,13 +458,13 @@ module RLTK::CG
|
|
458
458
|
# @return [void]
|
459
459
|
def element_types=(el_types, packed = false)
|
460
460
|
@element_types = check_cg_array_type(el_types, Type, 'el_types')
|
461
|
-
|
461
|
+
|
462
462
|
el_types_ptr = FFI::MemoryPointer.new(:pointer, @element_types.length)
|
463
463
|
el_types_ptr.write_array_of_pointer(@element_types)
|
464
|
-
|
464
|
+
|
465
465
|
Bindings.struct_set_body(@ptr, el_types_ptr, @element_types.length, packed.to_i)
|
466
466
|
end
|
467
|
-
|
467
|
+
|
468
468
|
# @return [String] Name of the struct type in LLVM IR.
|
469
469
|
def name
|
470
470
|
@name ||= Bindings.get_struct_name(@ptr)
|
@@ -494,8 +494,8 @@ end
|
|
494
494
|
# @return [Type] The object *o* or an instance of the class passed in parameter *o*.
|
495
495
|
def check_cg_type(o, type = RLTK::CG::Type, blame = 'type', strict = false)
|
496
496
|
if o.is_a?(Class)
|
497
|
-
type_ok = if strict then o == type else o.subclass_of?(type) end
|
498
|
-
|
497
|
+
type_ok = if strict then o == type else o.subclass_of?(type) end
|
498
|
+
|
499
499
|
if type_ok
|
500
500
|
if o.includes_module?(Singleton)
|
501
501
|
o.instance
|
@@ -503,7 +503,7 @@ def check_cg_type(o, type = RLTK::CG::Type, blame = 'type', strict = false)
|
|
503
503
|
raise ArgumentError, "The #{o.name} class (passed as parameter #{blame}) must be instantiated directly."
|
504
504
|
end
|
505
505
|
else
|
506
|
-
raise ArgumentError, "The #{o.name} class (passed as parameter #{blame} does not inherit from the #{type.name} class."
|
506
|
+
raise ArgumentError, "The #{o.name} class (passed as parameter #{blame} does not inherit from the #{type.name} class."
|
507
507
|
end
|
508
508
|
else
|
509
509
|
check_type(o, type, blame, strict)
|
@@ -512,7 +512,7 @@ end
|
|
512
512
|
|
513
513
|
# This helper function checks to make sure that an array of objects are all
|
514
514
|
# sub-classses of {RLTK::CG::Type Type} or instances of a sub-class of Type.
|
515
|
-
# If a class is present in the *array* parameter it is expected to be a
|
515
|
+
# If a class is present in the *array* parameter it is expected to be a
|
516
516
|
# singleton class and will be instantiated via the *instance* method.
|
517
517
|
#
|
518
518
|
# @param [Array<Type, Class>] array Array of objects to type check for code generation type.
|
@@ -530,7 +530,7 @@ def check_cg_array_type(array, type = RLTK::CG::Type, blame = 'el_types', strict
|
|
530
530
|
array.map do |o|
|
531
531
|
if o.is_a?(Class)
|
532
532
|
type_ok = if strict then o == type else o.subclass_of?(type) end
|
533
|
-
|
533
|
+
|
534
534
|
if type_ok
|
535
535
|
if o.includes_module?(Singleton)
|
536
536
|
o.instance
|
@@ -540,10 +540,10 @@ def check_cg_array_type(array, type = RLTK::CG::Type, blame = 'el_types', strict
|
|
540
540
|
else
|
541
541
|
raise ArgumentError, "The #{o.name} class (passed in parameter #{blame}) does not inherit from the #{type.name} class."
|
542
542
|
end
|
543
|
-
|
543
|
+
|
544
544
|
else
|
545
545
|
type_ok = if strict then o.instance_of(type) else o.is_a?(type) end
|
546
|
-
|
546
|
+
|
547
547
|
if type_ok
|
548
548
|
o
|
549
549
|
else
|