ikra 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ast/builder.rb +225 -77
- data/lib/ast/host_section_builder.rb +38 -0
- data/lib/ast/interpreter.rb +67 -0
- data/lib/ast/lexical_variables_enumerator.rb +3 -2
- data/lib/ast/nodes.rb +521 -31
- data/lib/ast/printer.rb +116 -18
- data/lib/ast/ssa_generator.rb +192 -0
- data/lib/ast/visitor.rb +235 -21
- data/lib/config/configuration.rb +28 -3
- data/lib/config/os_configuration.rb +62 -9
- data/lib/cpu/cpu_implementation.rb +39 -0
- data/lib/ikra.rb +13 -3
- data/lib/resources/cuda/allocate_device_memory.cpp +5 -0
- data/lib/resources/cuda/allocate_host_memory.cpp +1 -0
- data/lib/resources/cuda/allocate_memcpy_environment_to_device.cpp +11 -0
- data/lib/resources/cuda/ast/assignment.cpp +1 -0
- data/lib/resources/cuda/block_function_head.cpp +7 -1
- data/lib/resources/cuda/entry_point.cpp +47 -0
- data/lib/resources/cuda/env_builder_copy_array.cpp +8 -2
- data/lib/resources/cuda/free_device_memory.cpp +3 -0
- data/lib/resources/cuda/free_memory_for_command.cpp +24 -0
- data/lib/resources/cuda/header.cpp +23 -9
- data/lib/resources/cuda/header_structs.cpp +92 -0
- data/lib/resources/cuda/host_section_block_function_head.cpp +12 -0
- data/lib/resources/cuda/host_section_entry_point.cpp +55 -0
- data/lib/resources/cuda/host_section_free_device_memory.cpp +18 -0
- data/lib/resources/cuda/host_section_launch_parallel_section.cpp +14 -0
- data/lib/resources/cuda/host_section_malloc_memcpy_device_to_host.cpp +10 -0
- data/lib/resources/cuda/kernel.cpp +9 -2
- data/lib/resources/cuda/launch_kernel.cpp +5 -0
- data/lib/resources/cuda/memcpy_device_to_host.cpp +3 -0
- data/lib/resources/cuda/memcpy_device_to_host_expr.cpp +10 -0
- data/lib/resources/cuda/reduce_body.cpp +88 -0
- data/lib/resources/cuda/stencil_array_reconstruction.cpp +2 -0
- data/lib/resources/cuda/stencil_body.cpp +16 -0
- data/lib/resources/cuda/struct_definition.cpp +4 -0
- data/lib/ruby_core/array.rb +34 -0
- data/lib/ruby_core/array_command.rb +313 -0
- data/lib/ruby_core/core.rb +103 -0
- data/lib/ruby_core/interpreter.rb +16 -0
- data/lib/ruby_core/math.rb +32 -0
- data/lib/ruby_core/ruby_integration.rb +256 -0
- data/lib/symbolic/host_section.rb +115 -0
- data/lib/symbolic/input.rb +87 -0
- data/lib/symbolic/input_visitor.rb +68 -0
- data/lib/symbolic/symbolic.rb +793 -117
- data/lib/symbolic/visitor.rb +70 -8
- data/lib/translator/array_command_struct_builder.rb +163 -0
- data/lib/translator/ast_translator.rb +572 -0
- data/lib/translator/block_translator.rb +104 -48
- data/lib/translator/commands/array_combine_command.rb +41 -0
- data/lib/translator/commands/array_identity_command.rb +28 -0
- data/lib/translator/commands/array_index_command.rb +52 -0
- data/lib/translator/commands/array_reduce_command.rb +135 -0
- data/lib/translator/commands/array_stencil_command.rb +129 -0
- data/lib/translator/commands/array_zip_command.rb +30 -0
- data/lib/translator/commands/command_translator.rb +264 -0
- data/lib/translator/cuda_errors.rb +32 -0
- data/lib/translator/environment_builder.rb +263 -0
- data/lib/translator/host_section/array_host_section_command.rb +150 -0
- data/lib/translator/host_section/array_in_host_section_command.rb +41 -0
- data/lib/translator/host_section/ast_translator.rb +14 -0
- data/lib/translator/host_section/parallel_section_invocation_visitor.rb +20 -0
- data/lib/translator/host_section/program_builder.rb +89 -0
- data/lib/translator/input_translator.rb +226 -0
- data/lib/translator/kernel_builder.rb +137 -0
- data/lib/translator/kernel_launcher/for_loop_kernel_launcher.rb +40 -0
- data/lib/translator/kernel_launcher/kernel_launcher.rb +259 -0
- data/lib/translator/kernel_launcher/while_loop_kernel_launcher.rb +38 -0
- data/lib/translator/last_returns_visitor.rb +19 -10
- data/lib/translator/program_builder.rb +197 -0
- data/lib/translator/program_launcher.rb +273 -0
- data/lib/translator/struct_type.rb +55 -0
- data/lib/translator/translator.rb +34 -11
- data/lib/translator/variable_classifier_visitor.rb +56 -0
- data/lib/types/inference/ast_inference.rb +586 -0
- data/lib/types/inference/clear_types_visitor.rb +11 -0
- data/lib/types/inference/command_inference.rb +101 -0
- data/lib/types/inference/input_inference.rb +62 -0
- data/lib/types/{object_tracer.rb → inference/object_tracer.rb} +5 -6
- data/lib/types/inference/ruby_extension.rb +35 -0
- data/lib/types/inference/symbol_table.rb +131 -0
- data/lib/types/types.rb +14 -0
- data/lib/types/types/array_command_type.rb +123 -0
- data/lib/types/types/array_type.rb +137 -0
- data/lib/types/{class_type.rb → types/class_type.rb} +42 -18
- data/lib/types/{primitive_type.rb → types/primitive_type.rb} +20 -7
- data/lib/types/types/ruby_type.rb +88 -0
- data/lib/types/types/struct_type.rb +179 -0
- data/lib/types/types/union_type.rb +239 -0
- metadata +160 -18
- data/lib/ast/method_definition.rb +0 -37
- data/lib/ast/translator.rb +0 -264
- data/lib/resources/cuda/kernel_launcher.cpp +0 -28
- data/lib/scope.rb +0 -166
- data/lib/translator/command_translator.rb +0 -421
- data/lib/translator/local_variables_enumerator.rb +0 -35
- data/lib/translator/method_translator.rb +0 -24
- data/lib/types/array_type.rb +0 -51
- data/lib/types/ruby_extension.rb +0 -67
- data/lib/types/ruby_type.rb +0 -45
- data/lib/types/type_inference.rb +0 -382
- data/lib/types/union_type.rb +0 -155
@@ -0,0 +1,101 @@
|
|
1
|
+
module Ikra
|
2
|
+
module TypeInference
|
3
|
+
class CommandInference < Symbolic::Visitor
|
4
|
+
def self.process_command(command)
|
5
|
+
return command.accept(CommandInference.new)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Processes a parallel section, i.e., a [BlockDefNode]. Performs the following steps:
|
9
|
+
# 1. Gather parameter types and names in a hash map.
|
10
|
+
# 2. Set lexical variables on [BlockDefNode].
|
11
|
+
# 3. Perform type inference, i.e., annotate [BlockDefNode] AST with types.
|
12
|
+
# 4. Return result type of the block.
|
13
|
+
def process_block(
|
14
|
+
block_def_node:,
|
15
|
+
lexical_variables: {},
|
16
|
+
block_parameters:)
|
17
|
+
|
18
|
+
# Build hash of parameter name -> type mappings
|
19
|
+
block_parameter_types = {}
|
20
|
+
for variable in block_parameters
|
21
|
+
block_parameter_types[variable.name] = variable.type
|
22
|
+
end
|
23
|
+
|
24
|
+
parameter_types_string = "[" + block_parameter_types.map do |id, type| "#{id}: #{type}" end.join(", ") + "]"
|
25
|
+
Log.info("Type inference for block with input types #{parameter_types_string}")
|
26
|
+
|
27
|
+
# Add information to block_def_node
|
28
|
+
block_def_node.parameters_names_and_types = block_parameter_types
|
29
|
+
|
30
|
+
# Lexical variables
|
31
|
+
lexical_variables.each do |name, value|
|
32
|
+
block_def_node.lexical_variables_names_and_types[name] = value.ikra_type.to_union_type
|
33
|
+
end
|
34
|
+
|
35
|
+
# Type inference
|
36
|
+
type_inference_visitor = TypeInference::Visitor.new
|
37
|
+
return_type = type_inference_visitor.process_block(block_def_node)
|
38
|
+
|
39
|
+
return return_type
|
40
|
+
end
|
41
|
+
|
42
|
+
# Processes all input commands. This is similar to `translate_entire_input`, but it
|
43
|
+
# performs only type inference and does not generate any source code.
|
44
|
+
def process_entire_input(command)
|
45
|
+
input_parameters = command.input.each_with_index.map do |input, index|
|
46
|
+
input.get_parameters(
|
47
|
+
parent_command: command,
|
48
|
+
# Assuming that every input consumes exactly one parameter
|
49
|
+
start_eat_params_offset: index)
|
50
|
+
end
|
51
|
+
|
52
|
+
return input_parameters.reduce(:+)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Process block and dependent computations. This method is used for all array
|
56
|
+
# commands that do not have a separate Visitor method.
|
57
|
+
def visit_array_command(command)
|
58
|
+
return process_block(
|
59
|
+
block_def_node: command.block_def_node,
|
60
|
+
lexical_variables: command.lexical_externals,
|
61
|
+
block_parameters: process_entire_input(command))
|
62
|
+
end
|
63
|
+
|
64
|
+
def visit_array_in_host_section_command(command)
|
65
|
+
return command.base_type
|
66
|
+
end
|
67
|
+
|
68
|
+
def visit_array_identity_command(command)
|
69
|
+
return command.base_type
|
70
|
+
end
|
71
|
+
|
72
|
+
def visit_array_index_command(command)
|
73
|
+
num_dims = command.dimensions.size
|
74
|
+
|
75
|
+
if num_dims > 1
|
76
|
+
# Build Ikra struct type
|
77
|
+
zipped_type_singleton = Types::ZipStructType.new(
|
78
|
+
*([Types::UnionType.create_int] * command.dimensions.size))
|
79
|
+
return zipped_type_singleton.to_union_type
|
80
|
+
else
|
81
|
+
return Types::UnionType.create_int
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def visit_array_zip_command(command)
|
86
|
+
input_types = command.input.each_with_index.map do |input, index|
|
87
|
+
input.get_parameters(
|
88
|
+
parent_command: command,
|
89
|
+
# Assuming that every input consumes exactly one parameter
|
90
|
+
start_eat_params_offset: index).map do |variable|
|
91
|
+
variable.type
|
92
|
+
end
|
93
|
+
end.reduce(:+)
|
94
|
+
|
95
|
+
# Build Ikra struct type
|
96
|
+
zipped_type_singleton = Types::ZipStructType.new(*input_types)
|
97
|
+
return zipped_type_singleton.to_union_type
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Ikra
|
2
|
+
module Symbolic
|
3
|
+
class Input
|
4
|
+
def get_parameters(**kwargs)
|
5
|
+
raise NotImplementedError.new
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class SingleInput < Input
|
10
|
+
def get_parameters(parent_command:, start_eat_params_offset: 0)
|
11
|
+
return [Translator::Variable.new(
|
12
|
+
name: parent_command.block_parameter_names[start_eat_params_offset],
|
13
|
+
type: command.result_type)]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ReduceInput < SingleInput
|
18
|
+
def get_parameters(parent_command:, start_eat_params_offset: 0)
|
19
|
+
# TODO: Fix type inference (sometimes type has to be expanded)
|
20
|
+
|
21
|
+
return [
|
22
|
+
Translator::Variable.new(
|
23
|
+
name: parent_command.block_parameter_names[start_eat_params_offset],
|
24
|
+
type: command.result_type),
|
25
|
+
Translator::Variable.new(
|
26
|
+
name: parent_command.block_parameter_names[start_eat_params_offset + 1],
|
27
|
+
type: command.result_type)]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class StencilArrayInput < Input
|
32
|
+
def get_parameters(parent_command:, start_eat_params_offset: 0)
|
33
|
+
# Parameters are allocated in a constant-sized array
|
34
|
+
|
35
|
+
return [Translator::Variable.new(
|
36
|
+
name: parent_command.block_parameter_names[start_eat_params_offset],
|
37
|
+
type: command.result_type.to_array_type)]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class StencilSingleInput < Input
|
42
|
+
def get_parameters(parent_command:, start_eat_params_offset: 0)
|
43
|
+
# Pass separate parameters
|
44
|
+
|
45
|
+
# Count number of parameters
|
46
|
+
num_parameters = parent_command.offsets.size
|
47
|
+
|
48
|
+
# Take return type from previous computation
|
49
|
+
parameters = []
|
50
|
+
for index in start_eat_params_offset...(start_eat_params_offset + num_parameters)
|
51
|
+
parameters.push(Translator::Variable.new(
|
52
|
+
name: parent_command.block_parameter_names[index],
|
53
|
+
type: command.result_type))
|
54
|
+
end
|
55
|
+
|
56
|
+
return parameters
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
require "set"
|
2
2
|
require "ffi"
|
3
|
-
require_relative "
|
4
|
-
require_relative "
|
5
|
-
require_relative "
|
6
|
-
require_relative "../translator/command_translator"
|
3
|
+
require_relative "../../entity"
|
4
|
+
require_relative "../../symbolic/symbolic"
|
5
|
+
require_relative "../../translator/commands/command_translator"
|
7
6
|
|
8
7
|
module Ikra
|
9
8
|
module TypeInference
|
@@ -48,10 +47,10 @@ module Ikra
|
|
48
47
|
|
49
48
|
object.instance_variables.each do |inst_var_name|
|
50
49
|
value = object.instance_variable_get(inst_var_name)
|
51
|
-
value_type = value.
|
50
|
+
value_type = value.ikra_type
|
52
51
|
|
53
52
|
# Gather type information
|
54
|
-
object.
|
53
|
+
object.ikra_type.inst_vars_types[inst_var_name].add(value_type)
|
55
54
|
|
56
55
|
if value.class.include?(Entity)
|
57
56
|
# Keep tracing this object
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# No explicit `require`s. This file should be includes via types.rb
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
class Fixnum
|
6
|
+
class << self
|
7
|
+
def to_ikra_type
|
8
|
+
Ikra::Types::PrimitiveType::Int
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Float
|
14
|
+
class << self
|
15
|
+
def to_ikra_type
|
16
|
+
Ikra::Types::PrimitiveType::Float
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TrueClass
|
22
|
+
class << self
|
23
|
+
def to_ikra_type
|
24
|
+
Ikra::Types::PrimitiveType::Bool
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class FalseClass
|
30
|
+
class << self
|
31
|
+
def to_ikra_type
|
32
|
+
Ikra::Types::PrimitiveType::Bool
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# No explicit `require`s. This file should be includes via types.rb
|
2
|
+
|
3
|
+
module Ikra
|
4
|
+
module TypeInference
|
5
|
+
# This is a symbol table that stores type information about variables. Ruby has a "flat"
|
6
|
+
# variable scope in method, i.e., variables defined in loop bodies, if statement bodies,
|
7
|
+
# or begin nodes are also visible outside of them.
|
8
|
+
#
|
9
|
+
# Every method/block has its own symbol table.
|
10
|
+
class SymbolTable
|
11
|
+
|
12
|
+
# Represents a lexical or local variable. Variables have a type and can read and/or
|
13
|
+
# written, all of which is stored in this class.
|
14
|
+
class Variable
|
15
|
+
attr_reader :type
|
16
|
+
|
17
|
+
# Determines the kind of the variables: lexial or local
|
18
|
+
attr_reader :kind
|
19
|
+
|
20
|
+
attr_accessor :read
|
21
|
+
attr_accessor :written
|
22
|
+
|
23
|
+
def initialize(type: Types::UnionType.new, kind: :local)
|
24
|
+
@type = type.dup
|
25
|
+
@kind = kind
|
26
|
+
@read = false
|
27
|
+
@written = false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :return_type
|
32
|
+
|
33
|
+
# For debug purposes
|
34
|
+
attr_reader :symbols
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
# This is a mapping from variable names to Variable instances.
|
38
|
+
@symbols = {}
|
39
|
+
@return_type = Types::UnionType.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def clear!
|
43
|
+
@symbols = {}
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](variable_name)
|
47
|
+
if !has_variable?(variable_name)
|
48
|
+
raise AssertionError.new("Variable #{variable_name} not defined")
|
49
|
+
end
|
50
|
+
|
51
|
+
return @symbols[variable_name].type
|
52
|
+
end
|
53
|
+
|
54
|
+
def read!(variable_name)
|
55
|
+
if !has_variable?(variable_name)
|
56
|
+
raise AssertionError.new(
|
57
|
+
"Variable #{variable_name} read but not found in symbol table")
|
58
|
+
end
|
59
|
+
|
60
|
+
@symbols[variable_name].read = true
|
61
|
+
end
|
62
|
+
|
63
|
+
def written!(variable_name)
|
64
|
+
if !has_variable?(variable_name)
|
65
|
+
raise AssertionError.new(
|
66
|
+
"Variable #{variable_name} written but not found in symbol table")
|
67
|
+
end
|
68
|
+
|
69
|
+
@symbols[variable_name].written = true
|
70
|
+
end
|
71
|
+
|
72
|
+
def read_variables
|
73
|
+
return @symbols.select do |k, v|
|
74
|
+
v.read
|
75
|
+
end.keys
|
76
|
+
end
|
77
|
+
|
78
|
+
def written_variables
|
79
|
+
return @symbols.select do |k, v|
|
80
|
+
v.written
|
81
|
+
end.keys
|
82
|
+
end
|
83
|
+
|
84
|
+
def read_and_written_variables
|
85
|
+
return read_variables + written_variables
|
86
|
+
end
|
87
|
+
|
88
|
+
def expand_type(variable_name, type)
|
89
|
+
if !has_variable?(variable_name)
|
90
|
+
raise AssertionError.new(
|
91
|
+
"Attempt to expand type of variable #{variable_name} but not found in " +
|
92
|
+
" symbol table")
|
93
|
+
end
|
94
|
+
|
95
|
+
@symbols[variable_name].type.expand(type)
|
96
|
+
end
|
97
|
+
|
98
|
+
def expand_return_type(type)
|
99
|
+
@return_type.expand(type)
|
100
|
+
end
|
101
|
+
|
102
|
+
def return_type
|
103
|
+
return @return_type
|
104
|
+
end
|
105
|
+
|
106
|
+
# Declares a local variable. This method should be used only for regular local
|
107
|
+
# variables (not parameters). Does not shadow lexical variables.
|
108
|
+
def ensure_variable_declared(variable_name, type: Types::UnionType.new, kind: :local)
|
109
|
+
if !has_variable?(variable_name)
|
110
|
+
declare_variable(variable_name, type: type, kind: kind)
|
111
|
+
else
|
112
|
+
# Extend type of variable
|
113
|
+
expand_type(variable_name, type)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Declares a local variable and overwrites (shadows) existing variables
|
118
|
+
# (lexical variables). Use this method for method/block parameters.
|
119
|
+
def declare_variable(variable_name, type: Types::UnionType.new, kind: :local)
|
120
|
+
@symbols[variable_name] = Variable.new(type: Types::UnionType.new, kind: kind)
|
121
|
+
expand_type(variable_name, type)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def has_variable?(variable_name)
|
127
|
+
return @symbols.include?(variable_name)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/lib/types/types.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative "types/ruby_type"
|
2
|
+
require_relative "types/array_type"
|
3
|
+
require_relative "types/class_type"
|
4
|
+
require_relative "types/primitive_type"
|
5
|
+
require_relative "types/union_type"
|
6
|
+
require_relative "types/struct_type"
|
7
|
+
require_relative "types/array_command_type"
|
8
|
+
|
9
|
+
require_relative "inference/object_tracer"
|
10
|
+
require_relative "inference/ruby_extension"
|
11
|
+
require_relative "inference/symbol_table"
|
12
|
+
require_relative "inference/ast_inference"
|
13
|
+
require_relative "inference/input_inference"
|
14
|
+
require_relative "inference/command_inference"
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require "weakref"
|
2
|
+
|
3
|
+
module Ikra
|
4
|
+
module Symbolic
|
5
|
+
module ArrayCommand
|
6
|
+
include Types::RubyType
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# TODO: Check what was wrong with the subclassed Hash...
|
14
|
+
class WeakCache
|
15
|
+
def initialize
|
16
|
+
@values = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_value(value)
|
20
|
+
@values.delete_if do |obj|
|
21
|
+
begin
|
22
|
+
if obj == value
|
23
|
+
return obj.__getobj__
|
24
|
+
end
|
25
|
+
rescue WeakRef::RefError
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
raise RuntimeError.new("Value not found")
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_value(value)
|
34
|
+
@values.push(WeakRef.new(value))
|
35
|
+
end
|
36
|
+
|
37
|
+
def include?(value)
|
38
|
+
@values.delete_if do |obj|
|
39
|
+
begin
|
40
|
+
if obj == value
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
rescue WeakRef::RefError
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class NormalCache
|
53
|
+
def initialize
|
54
|
+
@values = []
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_value(value)
|
58
|
+
for el in @values
|
59
|
+
if el == value
|
60
|
+
return el
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
raise RuntimeError.new("Value not found")
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_value(value)
|
68
|
+
@values.push(value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def include?(value)
|
72
|
+
return @values.include?(value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Ensure that ArrayCommands are singletons. Otherwise, we have a problem, because
|
77
|
+
# two equal commands can have different class IDs.
|
78
|
+
def new(*args, **kwargs, &block)
|
79
|
+
if @cache == nil
|
80
|
+
@cache = WeakCache.new
|
81
|
+
end
|
82
|
+
|
83
|
+
new_command = super
|
84
|
+
|
85
|
+
if @cache.include?(new_command)
|
86
|
+
return @cache.get_value(new_command)
|
87
|
+
else
|
88
|
+
@cache.add_value(new_command)
|
89
|
+
return new_command
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_c_type
|
95
|
+
return "#{Translator::ArrayCommandStructBuilder.struct_name(self)} *"
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_ffi_type
|
99
|
+
# TODO: This method is probably not required?
|
100
|
+
return :pointer
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_ruby_type
|
104
|
+
return ArrayCommand
|
105
|
+
end
|
106
|
+
|
107
|
+
# Every [ArrayCommand] has itself as an Ikra type. This integrates well with the
|
108
|
+
# current type inference approach and `ruby_core`.
|
109
|
+
def ikra_type
|
110
|
+
return self
|
111
|
+
end
|
112
|
+
|
113
|
+
def result_type
|
114
|
+
# Result cache should be cached, just like the result itself
|
115
|
+
if @result_type == nil
|
116
|
+
@result_type = TypeInference::CommandInference.process_command(self)
|
117
|
+
end
|
118
|
+
|
119
|
+
return @result_type
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|