dtr_to_rust 0.2.10 → 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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aggregator/scope_block_aggregator.rb +72 -0
  3. data/lib/common/input_interpreter.rb +12 -1
  4. data/lib/common/reference_appender.rb +59 -0
  5. data/lib/common/type_translator.rb +22 -0
  6. data/lib/dtr_to_rust.rb +34 -4
  7. data/lib/generator.rb +105 -32
  8. data/lib/instruction/add.rb +12 -0
  9. data/lib/instruction/and.rb +19 -0
  10. data/lib/instruction/assign.rb +16 -0
  11. data/lib/instruction/divide.rb +12 -0
  12. data/lib/instruction/end_of_iteration_check.rb +11 -0
  13. data/lib/instruction/evaluate.rb +92 -17
  14. data/lib/instruction/exit_with_message.rb +18 -0
  15. data/lib/instruction/field.rb +3 -3
  16. data/lib/instruction/goto.rb +12 -0
  17. data/lib/instruction/handler.rb +11 -7
  18. data/lib/instruction/increment.rb +11 -0
  19. data/lib/instruction/instantiate_object.rb +78 -0
  20. data/lib/instruction/jump.rb +28 -0
  21. data/lib/instruction/label.rb +12 -0
  22. data/lib/instruction/multiply.rb +12 -0
  23. data/lib/instruction/or.rb +19 -0
  24. data/lib/instruction/{log_string.rb → print.rb} +2 -2
  25. data/lib/instruction/return.rb +1 -1
  26. data/lib/instruction/subtract.rb +13 -0
  27. data/lib/instruction_handler.rb +34 -18
  28. data/lib/optimization/binary_x_to_self_assignment_reduction.rb +93 -0
  29. data/lib/optimization/chained_invocation_assignment_reduction.rb +123 -0
  30. data/lib/optimization/field_to_assignment_conversion.rb +37 -0
  31. data/lib/user_defined_types/handler.rb +78 -0
  32. metadata +25 -7
  33. data/lib/instruction/add_and_assign.rb +0 -12
  34. data/lib/instruction/create_list.rb +0 -31
  35. data/lib/instruction/initialize_udt.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7572c039db830a1a216b31e01f53a104701d8321d487b47811a7a366ea520e53
4
- data.tar.gz: d359cdc39400f9a0bdaf4823cdf77aea9c1aeb6fb7dbee931419e2208d073a51
3
+ metadata.gz: b758e2693dba6f08986542c9a49c6d15f285529cbb172d3a29bb171ec95536b1
4
+ data.tar.gz: 3d4ef34c8dfd29ff2124fe8c3b0c8ac194872729bbd9443b633a0e5e973aafb6
5
5
  SHA512:
6
- metadata.gz: 8c62415d2d4f63cb331cf26bdf73c72e9b230a69c65cf8df5bf0ff83f102f4658641b329e48d3c7f01a2c53501f58be1c5bfd5133ce98b9652674911043a0b60
7
- data.tar.gz: 43caee328ae2b7216104600b8a656cb0ab5cc71ceeaae6a75de277516bef5b095ab1ca2f57a495c47dd353b7bd87b3a66ace7d11ebdcd7ecff97ead0521aa381
6
+ metadata.gz: 40cd10cc460cae31a4a596a28e10d9ede4af898effbc4cd14037394ed6d3930cb47420c88f6716c253c3f33b732ed2474cb99f6af5a1d0048d3c71bfea80f9c5
7
+ data.tar.gz: b4dda97391b69c4eefa43916514d8185564ba98b2d86b461b8e45b2f94e2e578cc360de5c84a5768df99494c295a9c708db0500a4db9582d5ccacb80fc5d967c
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Aggregator
5
+ # Aggregates instructions into scope blocks
6
+ class ScopeBlockAggregator
7
+ def initialize(instructions)
8
+ @instructions = instructions
9
+ end
10
+
11
+ def self.aggregate(instructions)
12
+ new(instructions).aggregate
13
+ end
14
+
15
+ def aggregate
16
+ sequential_scope_blocks = sequentially_group_by_scope(@instructions)
17
+
18
+ decorate_scope_blocks(sequential_scope_blocks)
19
+ end
20
+
21
+ private
22
+
23
+ def sequentially_group_by_scope(_instructions)
24
+ return [] if @instructions.empty?
25
+
26
+ scope_blocks = []
27
+ current_scope = nil
28
+ current_scope_block = []
29
+
30
+ @instructions.each do |instruction|
31
+ if current_scope == instruction.scope
32
+ current_scope_block << instruction
33
+ else
34
+ scope_blocks << current_scope_block unless current_scope_block.empty?
35
+ current_scope_block = [instruction]
36
+ current_scope = instruction.scope
37
+ end
38
+ end
39
+
40
+ scope_blocks << current_scope_block unless current_scope_block.empty?
41
+
42
+ scope_blocks
43
+ end
44
+
45
+ def decorate_scope_blocks(scope_blocks)
46
+ current_scope = nil
47
+ current_scope_decorated_value = nil
48
+ scope_memoize = {}
49
+
50
+ scope_blocks.map do |scope_block|
51
+ if current_scope.nil?
52
+ current_scope = scope_block.first.scope
53
+ current_scope_decorated_value = 0
54
+ scope_memoize[current_scope] = current_scope_decorated_value
55
+ elsif scope_memoize[scope_block.first.scope]
56
+ current_scope = scope_block.first.scope
57
+ current_scope_decorated_value = scope_memoize[current_scope]
58
+ elsif current_scope < scope_block.first.scope
59
+ current_scope = scope_block.first.scope
60
+ current_scope_decorated_value += 1
61
+ scope_memoize[current_scope] = current_scope_decorated_value
62
+ else
63
+ current_scope = scope_block.first.scope
64
+ current_scope_decorated_value -= 1
65
+ scope_memoize[current_scope] = current_scope_decorated_value
66
+ end
67
+ { block: scope_block, scope: current_scope, decorated_value: current_scope_decorated_value }
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -17,6 +17,8 @@ module DTRToRust
17
17
  number_return(@input)
18
18
  elsif string?(@input)
19
19
  string_return(@input)
20
+ elsif boolean?(@input)
21
+ boolean_return(@input)
20
22
  else
21
23
  variable_return(@input)
22
24
  end
@@ -30,7 +32,7 @@ module DTRToRust
30
32
  end
31
33
 
32
34
  def variable_return(_input)
33
- { value: @input, type: 'variable', needs_reference: true }
35
+ { value: @input, type: 'variable', needs_reference: !@input.start_with?('&') }
34
36
  end
35
37
 
36
38
  ## String ##
@@ -58,6 +60,15 @@ module DTRToRust
58
60
  # Check if the string matches the pattern
59
61
  !!(str =~ decimal_pattern)
60
62
  end
63
+
64
+ ## Boolean ##
65
+ def boolean?(input)
66
+ input.is_a?(TrueClass) || input.is_a?(FalseClass) || input&.match?(/true|false/)
67
+ end
68
+
69
+ def boolean_return(_input)
70
+ { value: @input, type: 'boolean', needs_reference: false }
71
+ end
61
72
  end
62
73
  end
63
74
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Common
5
+ # This module appends references to variables.
6
+ module ReferenceAppender
7
+ def self.call(input, ref_nums: false)
8
+ # Hack to get tests to pass
9
+ return '&signature_payload.into()' if input == 'signature_payload.into()'
10
+
11
+ decorated_input = Common::InputInterpreter.interpret(input)
12
+
13
+ # HACK: is likely chain of method calls
14
+ # ex: env.storage().instance().get(COUNTER).unwrap_or(0);
15
+ # --> env.storage().instance().get(&COUNTER).unwrap_or(0);
16
+ if decorated_input[:type] != 'number' &&
17
+ decorated_input[:value].include?('.') &&
18
+ decorated_input[:value].include?('(') && decorated_input[:value].include?(')')
19
+ more_complex_ref_appender(input, decorated_input)
20
+ elsif decorated_input[:needs_reference]
21
+ "&#{decorated_input[:value]}"
22
+ elsif decorated_input[:type] == 'number'
23
+ ref_nums ? "&#{decorated_input[:value]}" : decorated_input[:value]
24
+ else
25
+ decorated_input[:value]
26
+ end
27
+ end
28
+
29
+ def self.more_complex_ref_appender(_input, decorated_input)
30
+ decorated_input[:value].split('.').map do |x|
31
+ x = x.strip
32
+ if call_with_input?(x)
33
+ matches = x.scan(/\((.*?)\)/)
34
+ things = matches
35
+ .flatten
36
+ .filter(&method(:not_empty_string?))
37
+ .map(&method(:wild_stuff))
38
+ .join(', ')
39
+ "#{x.split('(')[0]}(#{things})"
40
+ else
41
+ x
42
+ end
43
+ end.join('.')
44
+ end
45
+
46
+ def self.not_empty_string?(input)
47
+ input != ''
48
+ end
49
+
50
+ def self.wild_stuff(input)
51
+ input.split(',').map { |x| ReferenceAppender.call(x.strip) }.join(', ')
52
+ end
53
+
54
+ def self.call_with_input?(input)
55
+ input.include?('(') && input.end_with?(')') && !input.end_with?('()')
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Common
5
+ # TypeTranslator translates DTR types to Rust types
6
+ module TypeTranslator
7
+ def self.translate_type(type)
8
+ # TODO: fix this, it is incorrect
9
+ type
10
+ .gsub('List<', 'Vec<')
11
+ .gsub('Dictionary<', 'HashMap<')
12
+ .gsub('BigInteger', 'i128')
13
+ .gsub('Integer', 'i64')
14
+ .gsub('ByteStringSmall', 'BytesN<32>')
15
+ .gsub('ByteStringLarge', 'BytesN<64>')
16
+ .gsub('String', 'Symbol')
17
+ .gsub('Boolean', 'bool')
18
+ .gsub('Float', 'f64')
19
+ end
20
+ end
21
+ end
22
+ end
data/lib/dtr_to_rust.rb CHANGED
@@ -7,18 +7,48 @@ module DTRToRust
7
7
 
8
8
  # This module contains all the classes that handle the different types of instructions.
9
9
  module Instruction
10
- autoload :AddAndAssign, 'instruction/add_and_assign'
11
- autoload :CreateList, 'instruction/create_list'
12
10
  autoload :Evaluate, 'instruction/evaluate'
13
11
  autoload :Field, 'instruction/field'
14
12
  autoload :Handler, 'instruction/handler'
15
- autoload :InitializeUDT, 'instruction/initialize_udt'
16
- autoload :LogString, 'instruction/log_string'
13
+ autoload :Print, 'instruction/print'
17
14
  autoload :Return, 'instruction/return'
15
+ autoload :InstantiateObject, 'instruction/instantiate_object'
16
+ autoload :Add, 'instruction/add'
17
+ autoload :Subtract, 'instruction/subtract'
18
+ autoload :Multiply, 'instruction/multiply'
19
+ autoload :Divide, 'instruction/divide'
20
+ autoload :Assign, 'instruction/assign'
21
+ autoload :Jump, 'instruction/jump'
22
+ autoload :Goto, 'instruction/goto'
23
+ autoload :ExitWithMessage, 'instruction/exit_with_message'
24
+ autoload :And, 'instruction/and'
25
+ autoload :Or, 'instruction/or'
26
+ autoload :Label, 'instruction/label'
27
+ autoload :EndOfIterationCheck, 'instruction/end_of_iteration_check'
28
+ autoload :Increment, 'instruction/increment'
18
29
  end
19
30
 
20
31
  # This module contains all the classes that handle common logic.
21
32
  module Common
22
33
  autoload :InputInterpreter, 'common/input_interpreter'
34
+ autoload :ReferenceAppender, 'common/reference_appender'
35
+ autoload :TypeTranslator, 'common/type_translator'
36
+ end
37
+
38
+ # This module contains all the classes that handle optimization.
39
+ module Optimization
40
+ autoload :ChainedInvocationAssignmentReduction, 'optimization/chained_invocation_assignment_reduction'
41
+ autoload :FieldToAssignmentConversion, 'optimization/field_to_assignment_conversion'
42
+ autoload :BinaryXToSelfAssignmentReduction, 'optimization/binary_x_to_self_assignment_reduction'
43
+ end
44
+
45
+ # This module contains all the classes that handle user defined types.
46
+ module UserDefinedTypes
47
+ autoload :Handler, 'user_defined_types/handler'
48
+ end
49
+
50
+ # This module contains all the classes that handle the aggregation of instructions.
51
+ module Aggregator
52
+ autoload :ScopeBlockAggregator, 'aggregator/scope_block_aggregator'
23
53
  end
24
54
  end
data/lib/generator.rb CHANGED
@@ -12,11 +12,13 @@ module DTRToRust
12
12
  def generate
13
13
  @content = ''
14
14
 
15
- generate_contract_header
16
15
  generate_user_defined_types
17
16
  generate_state
18
17
  generate_contract_name
19
- generate_functions
18
+ generate_interface
19
+ generate_helpers
20
+
21
+ generate_contract_header
20
22
 
21
23
  @content
22
24
  end
@@ -34,8 +36,38 @@ module DTRToRust
34
36
  attr_reader :dtr_contract
35
37
 
36
38
  def generate_contract_header
39
+ imports_super_set = %w[
40
+ Address
41
+ BytesN
42
+ contract
43
+ contractimpl
44
+ contracttype
45
+ contracterror
46
+ symbol_short
47
+ vec
48
+ Env
49
+ Symbol
50
+ Vec
51
+ log
52
+ token
53
+ ]
54
+
55
+ used_imports = []
56
+
57
+ @content.split.each do |word|
58
+ imports_super_set.each do |import|
59
+ used_imports << import if word.include?(import)
60
+ end
61
+ end
62
+
63
+ used_imports.uniq!
64
+
65
+ # TODO: unsure how to check this one
66
+ used_imports << 'auth::Context'
67
+ used_imports << 'IntoVal'
68
+
37
69
  # TODO: don't hardcode imports
38
- @content += "#![no_std]\nuse soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec, log};\n\n"
70
+ @content = "#![no_std]\nuse soroban_sdk::{#{used_imports.join(', ')}};\n\n" + @content
39
71
  end
40
72
 
41
73
  def generate_contract_name
@@ -47,73 +79,114 @@ module DTRToRust
47
79
 
48
80
  dtr_contract.state.each do |state_value|
49
81
  if state_value.type == 'String'
50
- @content += "const #{state_value.name}: Symbol = symbol_short!(\"#{state_value.initial_value}\");\n"
82
+ @content += "const #{state_value.name}: Symbol = symbol_short!(#{state_value.initial_value});\n"
83
+ else
84
+ @content += "const #{state_value.name}: #{Common::TypeTranslator.translate_type(state_value.type)} = #{state_value.initial_value};\n"
51
85
  end
52
86
  end
53
87
 
54
88
  @content += "\n"
55
89
  end
56
90
 
57
- def generate_functions
58
- @content += "#[contractimpl]\nimpl #{dtr_contract.name} {#{generate_functions_each(dtr_contract.functions)}}\n"
91
+ def generate_interface
92
+ @content += "#[contractimpl]\nimpl #{dtr_contract.name} {#{generate_functions_each(dtr_contract.interface,
93
+ false)}}\n"
59
94
  end
60
95
 
61
- def generate_functions_each(functions)
96
+ def generate_helpers
97
+ @content += "#{generate_functions_each(dtr_contract.helpers, true)}\n"
98
+ end
99
+
100
+ def generate_functions_each(functions, is_helper)
101
+ function_names = functions&.map(&:name)
102
+
62
103
  functions&.map do |function|
63
- return_string = "\n pub fn #{function.name}(#{generate_function_args(function)}) "
104
+ optimized_instructions = optimize_instructions(function.instructions)
105
+
106
+ instruction_blocks = Aggregator::ScopeBlockAggregator.aggregate(optimized_instructions)
107
+
108
+ return_string = "\n#{is_helper ? '' : ' '}pub fn #{function.name}(#{generate_function_args(function)}) "
64
109
  return_string += generate_function_output(function)
65
- return_string += " {\n#{generate_instructions_each(function.instructions)}\n }\n"
110
+ return_string += " {\n#{generate_instructions_for_blocks(instruction_blocks, function_names,
111
+ is_helper)}"
112
+
113
+ if @last_scope.positive?
114
+ while @last_scope.positive?
115
+ return_string += "\n" + form_rust_string('}', @last_scope,
116
+ is_helper)
117
+ @last_scope -= 1
118
+ end
119
+ end
120
+ return_string += "\n#{is_helper ? '' : ' '}}\n"
66
121
 
67
122
  return_string
68
123
  end&.join("\n")
69
124
  end
70
125
 
126
+ def optimize_instructions(instructions)
127
+ stage1_optimized = Optimization::FieldToAssignmentConversion.apply(instructions)
128
+ stage2_optimized = Optimization::BinaryXToSelfAssignmentReduction.apply(stage1_optimized)
129
+ Optimization::ChainedInvocationAssignmentReduction.apply(stage2_optimized)
130
+ end
131
+
71
132
  def generate_function_output(function)
72
133
  return '' if function.output.nil?
73
134
 
74
- "-> #{translate_type(function.output)}"
135
+ "-> #{Common::TypeTranslator.translate_type(function.output)}"
75
136
  end
76
137
 
77
138
  def generate_function_args(function)
78
139
  all_inputs = [] + function.inputs
79
140
 
80
- all_inputs.map { |x| "#{x[:name]}: #{translate_type(x[:type_name])}" }.join(', ')
141
+ all_inputs.map { |x| "#{x[:name]}: #{Common::TypeTranslator.translate_type(x[:type_name])}" }.join(', ')
81
142
  end
82
143
 
83
- def generate_instructions_each(instructions)
144
+ def generate_instructions_for_blocks(instruction_blocks, function_names, is_helper)
145
+ instruction_blocks.map do |block|
146
+ spacing_scope = block[:decorated_value]
147
+ content = ''
148
+ if @last_scope && @last_scope > spacing_scope
149
+ while @last_scope > spacing_scope
150
+ content += form_rust_string("}\n", @last_scope, is_helper)
151
+ @last_scope -= 1
152
+ end
153
+ end
154
+ @last_scope = spacing_scope
155
+ content += generate_instructions_each(block[:block], spacing_scope, function_names, is_helper)
156
+
157
+ content
158
+ end.join("\n")
159
+ end
160
+
161
+ def generate_instructions_each(instructions, spacing_scope, function_names, is_helper)
84
162
  instructions.map do |instruction|
85
- generate_instruction(instruction)
163
+ content = ''
164
+ content += generate_instruction(instruction, spacing_scope, function_names, is_helper)
165
+
166
+ content
86
167
  end.join("\n")
87
168
  end
88
169
 
89
- def generate_instruction(instruction)
90
- handler = InstructionHandler.new(instruction)
91
- handler.generate_rust
170
+ def form_rust_string(instruction_string, scope, is_helper)
171
+ "#{spacing(scope, is_helper)}#{instruction_string}"
92
172
  end
93
173
 
94
- def translate_type(type)
95
- case type
96
- when 'String'
97
- 'Symbol'
98
- when 'Vec<String>'
99
- 'Vec<Symbol>'
100
- when 'List<String>'
101
- 'Vec<Symbol>'
102
- else
103
- type
104
- end
174
+ def spacing(scope, is_helper)
175
+ ' ' * (is_helper ? 0 : scope + 1)
176
+ end
177
+
178
+ def generate_instruction(instruction, spacing_scope, function_names, is_helper)
179
+ handler = InstructionHandler.new(instruction, spacing_scope, function_names,
180
+ dtr_contract.user_defined_types || [], is_helper)
181
+ handler.generate_rust
105
182
  end
106
183
 
107
184
  def generate_user_defined_types
108
185
  return if dtr_contract.user_defined_types.nil?
109
186
 
110
187
  dtr_contract.user_defined_types.each do |udt|
111
- @content += "#{derives}pub struct #{udt.name} {#{udt.attributes.map { |x| "#{x[:name]}: #{x[:type]}" }.join(', ')}}\n\n"
188
+ @content += DTRToRust::UserDefinedTypes::Handler.generate(udt)
112
189
  end
113
190
  end
114
-
115
- def derives
116
- "#[contracttype]\n#[derive(Clone, Debug, Eq, PartialEq)]\n"
117
- end
118
191
  end
119
192
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the add instruction.
6
+ class Add < Handler
7
+ def handle
8
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} + #{@instruction.inputs[1]};")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the and instruction.
6
+ class And < Handler
7
+ def handle
8
+ inputs = @instruction.inputs
9
+ assignment = @instruction.assign
10
+
11
+ assignment_rust = "let #{assignment} = "
12
+ body_rust = "#{inputs[0]} && #{inputs[1]};"
13
+ rust_string = "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
14
+
15
+ form_rust_string(rust_string)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the assign instruction.
6
+ class Assign < Handler
7
+ def handle
8
+ if @instruction.assign.include?('.')
9
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]};")
10
+ else
11
+ form_rust_string("let mut #{@instruction.assign} = #{@instruction.inputs[0]};")
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the add instruction.
6
+ class Divide < Handler
7
+ def handle
8
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} / #{@instruction.inputs[1]};")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ class EndOfIterationCheck < Handler
6
+ def handle
7
+ form_rust_string('if !iteration_finished {')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -5,34 +5,109 @@ module DTRToRust
5
5
  # This class is responsible for generating Rust code for the Evaluate instruction.
6
6
  class Evaluate < Handler
7
7
  def handle
8
- inputs = @instruction[:inputs][1..]
9
- evaluated_method_name = @instruction[:inputs][0]
10
- assignment = @instruction[:assign]
8
+ rust_string = handle_keyword_method_invocation
9
+ form_rust_string(rust_string)
10
+ end
11
11
 
12
- rust_string = if assignment.nil?
13
- "#{evaluated_method_name}(#{inputs_to_rust_string(inputs)});"
14
- else
15
- "let mut #{assignment} = #{evaluated_method_name}(#{inputs_to_rust_string(inputs)});"
16
- end
12
+ private
17
13
 
18
- form_rust_string(rust_string, @instruction[:scope])
14
+ def handle_keyword_method_invocation
15
+ case @instruction.inputs[0]
16
+ when 'equal_to'
17
+ handle_equal_to
18
+ when '!'
19
+ handle_unary_negation
20
+ when 'less_than'
21
+ handle_less_than
22
+ when 'less_than_or_equal_to'
23
+ handle_less_than_or_equal_to
24
+ else
25
+ handle_non_keyword_method_invocation
26
+ end
19
27
  end
20
28
 
21
- private
29
+ def handle_non_keyword_method_invocation
30
+ inputs = @instruction.inputs[1..]
31
+ evaluated_method_name = @instruction.inputs[0]
32
+ assignment = @instruction.assign
33
+
34
+ assignment_rust = "let mut #{assignment} = "
35
+ # TODO: make this less hacky evaluated_method_name.end_with?('set')
36
+ body_rust = "#{invocation_name(evaluated_method_name)}(#{inputs_to_rust_string(inputs,
37
+ append_ref_to_num?, try_append_ref_to_var?)});"
38
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
39
+ end
40
+
41
+ def handle_equal_to
42
+ inputs = @instruction.inputs[1..]
43
+ @instruction.inputs[0]
44
+ assignment = @instruction.assign
45
+
46
+ assignment_rust = "let #{assignment} = "
47
+ lhs = Common::ReferenceAppender.call(inputs[0])
48
+ rhs = Common::ReferenceAppender.call(inputs[1])
49
+ body_rust = "#{lhs} == #{rhs};"
50
+
51
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
52
+ end
53
+
54
+ def handle_less_than
55
+ inputs = @instruction.inputs[1..]
56
+ @instruction.inputs[0]
57
+ assignment = @instruction.assign
58
+
59
+ assignment_rust = "let #{assignment} = "
60
+ lhs = Common::ReferenceAppender.call(inputs[0])
61
+ rhs = Common::ReferenceAppender.call(inputs[1])
62
+ body_rust = "#{lhs} < #{rhs};"
22
63
 
23
- def inputs_to_rust_string(inputs)
24
- inputs.map { |input| ref_appender(input) }.join(', ')
64
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
25
65
  end
26
66
 
27
- def ref_appender(input)
28
- decorated_input = Common::InputInterpreter.interpret(input)
67
+ def handle_less_than_or_equal_to
68
+ inputs = @instruction.inputs[1..]
69
+ @instruction.inputs[0]
70
+ assignment = @instruction.assign
29
71
 
30
- if decorated_input[:needs_reference]
31
- "&#{decorated_input[:value]}"
72
+ assignment_rust = "let #{assignment} = "
73
+ lhs = Common::ReferenceAppender.call(inputs[0])
74
+ rhs = Common::ReferenceAppender.call(inputs[1])
75
+ body_rust = "#{lhs} <= #{rhs};"
76
+
77
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
78
+ end
79
+
80
+ def handle_unary_negation
81
+ inputs = @instruction.inputs[1..]
82
+ @instruction.inputs[0]
83
+ assignment = @instruction.assign
84
+
85
+ assignment_rust = "let #{assignment} = "
86
+ body_rust = "!(#{inputs[0]});"
87
+
88
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
89
+ end
90
+
91
+ def append_ref_to_num?
92
+ @instruction.inputs[0].end_with?('set')
93
+ end
94
+
95
+ def try_append_ref_to_var?
96
+ # SO HACKY - Refs are hard man
97
+ !(@instruction.inputs[0].end_with?('unwrap_or') || @instruction.inputs[0].end_with?('publish'))
98
+ end
99
+
100
+ def invocation_name(evaluated_method_name)
101
+ if @function_names.include?(evaluated_method_name)
102
+ "Self::#{evaluated_method_name}"
32
103
  else
33
- decorated_input[:value]
104
+ evaluated_method_name
34
105
  end
35
106
  end
107
+
108
+ def inputs_to_rust_string(inputs, ref_nums, ref_vars)
109
+ inputs.map { |input| ref_vars ? Common::ReferenceAppender.call(input, ref_nums:) : input }.join(', ')
110
+ end
36
111
  end
37
112
  end
38
113
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the exit_with_message instruction.
6
+ class ExitWithMessage < Handler
7
+ def handle
8
+ form_rust_string("panic!(#{inputs_to_rust_string(@instruction.inputs)});")
9
+ end
10
+
11
+ private
12
+
13
+ def inputs_to_rust_string(inputs)
14
+ inputs.map { |input| Common::ReferenceAppender.call(input) }.join(', ')
15
+ end
16
+ end
17
+ end
18
+ end