ikra 0.0.1 → 0.0.2
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/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
|