dtr_to_rust 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b42b05c23f4f6cd523b03895ef4e41734d83d836f768143379b12d996415038d
4
- data.tar.gz: d23996a0656a9ee252065f4f36d68646d18c42a9b9a05fe9897574ca4453dfb8
3
+ metadata.gz: b758e2693dba6f08986542c9a49c6d15f285529cbb172d3a29bb171ec95536b1
4
+ data.tar.gz: 3d4ef34c8dfd29ff2124fe8c3b0c8ac194872729bbd9443b633a0e5e973aafb6
5
5
  SHA512:
6
- metadata.gz: f4238874b6d9be9f31090673903cf2d265b0aa5bcf4eb69056eb642b8750b73724a46bb005ad0e5fad7e22a98ca6e6ae95de9c401e8533bd6aa334622bc1002f
7
- data.tar.gz: baebd2c976094cc88714c008f93ce5fd048fb0b5eb8a3c174d2ec899b612606a837d7c9bc7da1b12319d79d141793768c17336d5c82126226f24af7e491d3652
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
@@ -32,7 +32,7 @@ module DTRToRust
32
32
  end
33
33
 
34
34
  def variable_return(_input)
35
- { value: @input, type: 'variable', needs_reference: true }
35
+ { value: @input, type: 'variable', needs_reference: !@input.start_with?('&') }
36
36
  end
37
37
 
38
38
  ## String ##
@@ -5,6 +5,9 @@ module DTRToRust
5
5
  # This module appends references to variables.
6
6
  module ReferenceAppender
7
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
+
8
11
  decorated_input = Common::InputInterpreter.interpret(input)
9
12
 
10
13
  # HACK: is likely chain of method calls
@@ -11,6 +11,8 @@ module DTRToRust
11
11
  .gsub('Dictionary<', 'HashMap<')
12
12
  .gsub('BigInteger', 'i128')
13
13
  .gsub('Integer', 'i64')
14
+ .gsub('ByteStringSmall', 'BytesN<32>')
15
+ .gsub('ByteStringLarge', 'BytesN<64>')
14
16
  .gsub('String', 'Symbol')
15
17
  .gsub('Boolean', 'bool')
16
18
  .gsub('Float', 'f64')
data/lib/dtr_to_rust.rb CHANGED
@@ -24,6 +24,8 @@ module DTRToRust
24
24
  autoload :And, 'instruction/and'
25
25
  autoload :Or, 'instruction/or'
26
26
  autoload :Label, 'instruction/label'
27
+ autoload :EndOfIterationCheck, 'instruction/end_of_iteration_check'
28
+ autoload :Increment, 'instruction/increment'
27
29
  end
28
30
 
29
31
  # This module contains all the classes that handle common logic.
@@ -36,10 +38,17 @@ module DTRToRust
36
38
  # This module contains all the classes that handle optimization.
37
39
  module Optimization
38
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'
39
43
  end
40
44
 
41
45
  # This module contains all the classes that handle user defined types.
42
46
  module UserDefinedTypes
43
47
  autoload :Handler, 'user_defined_types/handler'
44
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'
53
+ end
45
54
  end
data/lib/generator.rb CHANGED
@@ -37,15 +37,19 @@ module DTRToRust
37
37
 
38
38
  def generate_contract_header
39
39
  imports_super_set = %w[
40
+ Address
41
+ BytesN
40
42
  contract
41
43
  contractimpl
42
44
  contracttype
45
+ contracterror
43
46
  symbol_short
44
47
  vec
45
48
  Env
46
49
  Symbol
47
50
  Vec
48
51
  log
52
+ token
49
53
  ]
50
54
 
51
55
  used_imports = []
@@ -58,6 +62,10 @@ module DTRToRust
58
62
 
59
63
  used_imports.uniq!
60
64
 
65
+ # TODO: unsure how to check this one
66
+ used_imports << 'auth::Context'
67
+ used_imports << 'IntoVal'
68
+
61
69
  # TODO: don't hardcode imports
62
70
  @content = "#![no_std]\nuse soroban_sdk::{#{used_imports.join(', ')}};\n\n" + @content
63
71
  end
@@ -93,18 +101,19 @@ module DTRToRust
93
101
  function_names = functions&.map(&:name)
94
102
 
95
103
  functions&.map do |function|
96
- @last_scope = nil
97
- optimized_instructions =
98
- Optimization::ChainedInvocationAssignmentReduction.apply(function.instructions)
104
+ optimized_instructions = optimize_instructions(function.instructions)
105
+
106
+ instruction_blocks = Aggregator::ScopeBlockAggregator.aggregate(optimized_instructions)
99
107
 
100
108
  return_string = "\n#{is_helper ? '' : ' '}pub fn #{function.name}(#{generate_function_args(function)}) "
101
109
  return_string += generate_function_output(function)
102
- return_string += " {\n#{generate_instructions_each(optimized_instructions, function_names,
103
- is_helper)}"
104
- unless @last_scope.nil?
110
+ return_string += " {\n#{generate_instructions_for_blocks(instruction_blocks, function_names,
111
+ is_helper)}"
112
+
113
+ if @last_scope.positive?
105
114
  while @last_scope.positive?
106
- return_string += "\n#{form_rust_string('}', @last_scope,
107
- is_helper)}"
115
+ return_string += "\n" + form_rust_string('}', @last_scope,
116
+ is_helper)
108
117
  @last_scope -= 1
109
118
  end
110
119
  end
@@ -114,6 +123,12 @@ module DTRToRust
114
123
  end&.join("\n")
115
124
  end
116
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
+
117
132
  def generate_function_output(function)
118
133
  return '' if function.output.nil?
119
134
 
@@ -126,16 +141,27 @@ module DTRToRust
126
141
  all_inputs.map { |x| "#{x[:name]}: #{Common::TypeTranslator.translate_type(x[:type_name])}" }.join(', ')
127
142
  end
128
143
 
129
- def generate_instructions_each(instructions, function_names, is_helper)
130
- instructions.map do |instruction|
144
+ def generate_instructions_for_blocks(instruction_blocks, function_names, is_helper)
145
+ instruction_blocks.map do |block|
146
+ spacing_scope = block[:decorated_value]
131
147
  content = ''
132
- if @last_scope.nil?
133
- @last_scope = instruction.scope
134
- elsif @last_scope != instruction.scope
135
- content += form_rust_string("}\n", instruction.scope, is_helper) if @last_scope > instruction.scope
136
- @last_scope = instruction.scope
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
137
153
  end
138
- content += generate_instruction(instruction, function_names, is_helper)
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)
162
+ instructions.map do |instruction|
163
+ content = ''
164
+ content += generate_instruction(instruction, spacing_scope, function_names, is_helper)
139
165
 
140
166
  content
141
167
  end.join("\n")
@@ -149,8 +175,9 @@ module DTRToRust
149
175
  ' ' * (is_helper ? 0 : scope + 1)
150
176
  end
151
177
 
152
- def generate_instruction(instruction, function_names, is_helper)
153
- handler = InstructionHandler.new(instruction, function_names, dtr_contract.user_defined_types || [], is_helper)
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)
154
181
  handler.generate_rust
155
182
  end
156
183
 
@@ -5,8 +5,7 @@ module DTRToRust
5
5
  # This class handles the add instruction.
6
6
  class Add < Handler
7
7
  def handle
8
- form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} + #{@instruction.inputs[1]};",
9
- @instruction.scope)
8
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} + #{@instruction.inputs[1]};")
10
9
  end
11
10
  end
12
11
  end
@@ -12,7 +12,7 @@ module DTRToRust
12
12
  body_rust = "#{inputs[0]} && #{inputs[1]};"
13
13
  rust_string = "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
14
14
 
15
- form_rust_string(rust_string, @instruction.scope)
15
+ form_rust_string(rust_string)
16
16
  end
17
17
  end
18
18
  end
@@ -5,7 +5,11 @@ module DTRToRust
5
5
  # This class handles the assign instruction.
6
6
  class Assign < Handler
7
7
  def handle
8
- form_rust_string("let mut #{@instruction.assign} = #{@instruction.inputs[0]};", @instruction.scope)
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
9
13
  end
10
14
  end
11
15
  end
@@ -5,8 +5,7 @@ module DTRToRust
5
5
  # This class handles the add instruction.
6
6
  class Divide < Handler
7
7
  def handle
8
- form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} / #{@instruction.inputs[1]};",
9
- @instruction.scope)
8
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} / #{@instruction.inputs[1]};")
10
9
  end
11
10
  end
12
11
  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
@@ -6,7 +6,7 @@ module DTRToRust
6
6
  class Evaluate < Handler
7
7
  def handle
8
8
  rust_string = handle_keyword_method_invocation
9
- form_rust_string(rust_string, @instruction.scope)
9
+ form_rust_string(rust_string)
10
10
  end
11
11
 
12
12
  private
@@ -17,6 +17,10 @@ module DTRToRust
17
17
  handle_equal_to
18
18
  when '!'
19
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
20
24
  else
21
25
  handle_non_keyword_method_invocation
22
26
  end
@@ -30,7 +34,7 @@ module DTRToRust
30
34
  assignment_rust = "let mut #{assignment} = "
31
35
  # TODO: make this less hacky evaluated_method_name.end_with?('set')
32
36
  body_rust = "#{invocation_name(evaluated_method_name)}(#{inputs_to_rust_string(inputs,
33
- don_t_append_ref)});"
37
+ append_ref_to_num?, try_append_ref_to_var?)});"
34
38
  "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
35
39
  end
36
40
 
@@ -47,6 +51,32 @@ module DTRToRust
47
51
  "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
48
52
  end
49
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};"
63
+
64
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
65
+ end
66
+
67
+ def handle_less_than_or_equal_to
68
+ inputs = @instruction.inputs[1..]
69
+ @instruction.inputs[0]
70
+ assignment = @instruction.assign
71
+
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
+
50
80
  def handle_unary_negation
51
81
  inputs = @instruction.inputs[1..]
52
82
  @instruction.inputs[0]
@@ -58,8 +88,13 @@ module DTRToRust
58
88
  "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
59
89
  end
60
90
 
61
- def don_t_append_ref
62
- @instruction.inputs[0].end_with?('set') || @instruction.inputs[0].end_with?('unwrap_or')
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'))
63
98
  end
64
99
 
65
100
  def invocation_name(evaluated_method_name)
@@ -70,8 +105,8 @@ module DTRToRust
70
105
  end
71
106
  end
72
107
 
73
- def inputs_to_rust_string(inputs, ref_nums)
74
- inputs.map { |input| Common::ReferenceAppender.call(input, ref_nums:) }.join(', ')
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(', ')
75
110
  end
76
111
  end
77
112
  end
@@ -5,7 +5,7 @@ module DTRToRust
5
5
  # This class handles the exit_with_message instruction.
6
6
  class ExitWithMessage < Handler
7
7
  def handle
8
- form_rust_string("panic! #{inputs_to_rust_string(@instruction.inputs)};", @instruction.scope)
8
+ form_rust_string("panic!(#{inputs_to_rust_string(@instruction.inputs)});")
9
9
  end
10
10
 
11
11
  private
@@ -5,7 +5,7 @@ module DTRToRust
5
5
  # This class is responsible for generating Rust code for the Field instruction.
6
6
  class Field < Handler
7
7
  def handle
8
- form_rust_string("#{handle_field_assign}#{handle_field_call}", @instruction.scope)
8
+ form_rust_string("#{handle_field_assign}#{handle_field_call}")
9
9
  end
10
10
 
11
11
  private
@@ -5,7 +5,7 @@ module DTRToRust
5
5
  # This class handles the goto instruction.
6
6
  class Goto < Handler
7
7
  def handle
8
- ''
8
+ form_rust_string("goto: #{@instruction.inputs[0]}")
9
9
  end
10
10
  end
11
11
  end
@@ -4,23 +4,24 @@ module DTRToRust
4
4
  module Instruction
5
5
  # This class is responsible for generating Rust code for the AddAndAssign instruction.
6
6
  class Handler
7
- def initialize(instruction, function_names, user_defined_types, is_helper)
7
+ def initialize(instruction, spacing_scope, function_names, user_defined_types, is_helper)
8
8
  @instruction = instruction
9
+ @spacing_scope = spacing_scope
9
10
  @function_names = function_names
10
11
  @user_defined_types = user_defined_types
11
12
  @is_helper = is_helper
12
13
  end
13
14
 
14
- def self.handle(instruction, function_names, user_defined_types, is_helper)
15
- new(instruction, function_names, user_defined_types, is_helper).handle
15
+ def self.handle(instruction, spacing_scope, function_names, user_defined_types, is_helper)
16
+ new(instruction, spacing_scope, function_names, user_defined_types, is_helper).handle
16
17
  end
17
18
 
18
- def spacing(scope)
19
- ' ' * (@is_helper ? 1 : scope + 2)
19
+ def spacing
20
+ ' ' * (@is_helper ? 1 : @spacing_scope + 2)
20
21
  end
21
22
 
22
- def form_rust_string(instruction_string, scope)
23
- "#{spacing(scope)}#{instruction_string}"
23
+ def form_rust_string(instruction_string)
24
+ "#{spacing}#{instruction_string}"
24
25
  end
25
26
  end
26
27
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ class Increment < Handler
6
+ def handle
7
+ form_rust_string("increment: #{@instruction.inputs[0]}")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -10,6 +10,8 @@ module DTRToRust
10
10
  handle_list
11
11
  when 'UDT'
12
12
  handle_udt
13
+ when 'Tuple'
14
+ form_rust_string("let mut #{@instruction.assign} = (#{normalish_inputs});")
13
15
  else
14
16
  raise "Unknown object type: #{@instruction.inputs[0]}"
15
17
  end
@@ -18,8 +20,13 @@ module DTRToRust
18
20
  private
19
21
 
20
22
  def handle_list
21
- form_rust_string("let mut #{@instruction.assign} = vec![#{inputs_to_rust_string(@instruction.inputs[1..])}];",
22
- @instruction.scope)
23
+ form_rust_string("let mut #{@instruction.assign} = vec![#{normalish_inputs}];")
24
+ end
25
+
26
+ def normalish_inputs
27
+ @instruction.inputs[1..].map do |x|
28
+ foobar(x)
29
+ end.join(', ')
23
30
  end
24
31
 
25
32
  def udt_name_fix(udt)
@@ -37,7 +44,7 @@ module DTRToRust
37
44
  udt = "#{@instruction.inputs[1]}{"
38
45
  inputs = inputs_to_rust_string(@instruction.inputs[2..], udt_found[0].attributes.map { |x| x[:name] })
39
46
  end_ = '};'
40
- form_rust_string("#{assignment}#{udt}#{inputs}#{end_}", @instruction.scope)
47
+ form_rust_string("#{assignment}#{udt}#{inputs}#{end_}")
41
48
  end
42
49
 
43
50
  def inputs_to_rust_string(inputs, udt_type_names)
@@ -49,16 +56,20 @@ module DTRToRust
49
56
  inputs_to_return.join(', ')
50
57
  end
51
58
 
52
- def handle_input(input, udt_type_name)
59
+ def foobar(input)
53
60
  decorated_input = Common::InputInterpreter.interpret(input)
54
61
 
55
- value = if decorated_input[:type] == 'string'
56
- "symbol_short!(#{input})"
57
- elsif decorated_input[:needs_reference] && input == 'env'
58
- "&#{input}"
59
- else
60
- input
61
- end
62
+ if decorated_input[:type] == 'string'
63
+ "symbol_short!(#{input})"
64
+ elsif decorated_input[:needs_reference] && input == 'env'
65
+ "&#{input}"
66
+ else
67
+ input
68
+ end
69
+ end
70
+
71
+ def handle_input(input, udt_type_name)
72
+ value = foobar(input)
62
73
 
63
74
  "#{udt_type_name}: #{value}"
64
75
  end
@@ -5,21 +5,23 @@ module DTRToRust
5
5
  # This class handles the jump instruction.
6
6
  class Jump < Handler
7
7
  def handle
8
- if @instruction.inputs[0].nil?
8
+ if @instruction.inputs.size == 1
9
9
  handle_unconditional_jump
10
- else
10
+ elsif @instruction.inputs.size == 2
11
11
  handle_conditional_jump
12
+ else
13
+ raise 'Invalid jump instruction'
12
14
  end
13
15
  end
14
16
 
15
17
  private
16
18
 
17
19
  def handle_conditional_jump
18
- form_rust_string("if #{@instruction.inputs[0]} {", @instruction.scope)
20
+ form_rust_string("if #{@instruction.inputs[0]} {")
19
21
  end
20
22
 
21
23
  def handle_unconditional_jump
22
- form_rust_string('if true {', @instruction.scope)
24
+ form_rust_string('else {')
23
25
  end
24
26
  end
25
27
  end
@@ -5,7 +5,7 @@ module DTRToRust
5
5
  # This class handles the label instruction.
6
6
  class Label < Handler
7
7
  def handle
8
- ''
8
+ form_rust_string("label: #{@instruction.inputs[0]}")
9
9
  end
10
10
  end
11
11
  end
@@ -5,8 +5,7 @@ module DTRToRust
5
5
  # This class handles the add instruction.
6
6
  class Multiply < Handler
7
7
  def handle
8
- form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} * #{@instruction.inputs[1]};",
9
- @instruction.scope)
8
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} * #{@instruction.inputs[1]};")
10
9
  end
11
10
  end
12
11
  end
@@ -12,7 +12,7 @@ module DTRToRust
12
12
  body_rust = "#{inputs[0]} || #{inputs[1]};"
13
13
  rust_string = "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
14
14
 
15
- form_rust_string(rust_string, @instruction.scope)
15
+ form_rust_string(rust_string)
16
16
  end
17
17
  end
18
18
  end
@@ -5,7 +5,7 @@ module DTRToRust
5
5
  # This class is responsible for generating Rust code for the LogString instruction.
6
6
  class Print < Handler
7
7
  def handle
8
- form_rust_string("log!(#{inputs_to_rust_string(@instruction.inputs)});", @instruction.scope)
8
+ form_rust_string("log!(#{inputs_to_rust_string(@instruction.inputs)});")
9
9
  end
10
10
 
11
11
  private
@@ -5,7 +5,7 @@ module DTRToRust
5
5
  # This class is responsible for generating Rust code for the Return instruction.
6
6
  class Return < Handler
7
7
  def handle
8
- form_rust_string(@instruction.inputs[0], @instruction.scope)
8
+ form_rust_string(@instruction.inputs[0])
9
9
  end
10
10
  end
11
11
  end
@@ -5,8 +5,8 @@ module DTRToRust
5
5
  # This class handles the add instruction.
6
6
  class Subtract < Handler
7
7
  def handle
8
- form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} - #{@instruction.inputs[1]};",
9
- @instruction.scope)
8
+ # TODO: fix this, depends if this is init or not
9
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} - #{@instruction.inputs[1]};")
10
10
  end
11
11
  end
12
12
  end
@@ -3,8 +3,9 @@
3
3
  module DTRToRust
4
4
  # This class is responsible for generating Rust code for a single instruction.
5
5
  class InstructionHandler
6
- def initialize(instruction, function_names, user_defined_types, is_helper)
6
+ def initialize(instruction, spacing_scope, function_names, user_defined_types, is_helper)
7
7
  @instruction = instruction
8
+ @spacing_scope = spacing_scope
8
9
  @function_names = function_names
9
10
  @user_defined_types = user_defined_types
10
11
  @is_helper = is_helper
@@ -15,7 +16,7 @@ module DTRToRust
15
16
  raise "Unknown instruction type: #{@instruction.instruction}"
16
17
  end
17
18
 
18
- EXPRESSION_FOOBAR[@instruction.instruction.strip].send(:handle, @instruction, @function_names,
19
+ EXPRESSION_FOOBAR[@instruction.instruction.strip].send(:handle, @instruction, @spacing_scope, @function_names,
19
20
  @user_defined_types, @is_helper)
20
21
  end
21
22
 
@@ -37,7 +38,9 @@ module DTRToRust
37
38
  'print' => Instruction::Print,
38
39
  'return' => Instruction::Return,
39
40
  'evaluate' => Instruction::Evaluate,
40
- 'field' => Instruction::Field
41
+ 'field' => Instruction::Field,
42
+ 'end_of_iteration_check' => Instruction::EndOfIterationCheck,
43
+ 'increment' => Instruction::Increment
41
44
  }.freeze
42
45
 
43
46
  def handle_empty_instruction
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Optimization
5
+ # This class is responsible for reducing binary operations that assign the result to the same variable
6
+ class BinaryXToSelfAssignmentReduction
7
+ def initialize(instructions)
8
+ @instructions = instructions
9
+ @cur_instruction = nil
10
+ @optimized_instructions = []
11
+ @memoize_assigns = {}
12
+ @to_remove = {}
13
+ @last_was_eavluate = nil
14
+ end
15
+
16
+ def self.apply(instructions)
17
+ new(instructions).apply
18
+ end
19
+
20
+ def apply
21
+ @instructions.each_with_index do |instruction, index|
22
+ @cur_instruction = instruction
23
+
24
+ if skip_instruction?
25
+ @optimized_instructions << @cur_instruction
26
+ next unless @cur_instruction.assign && @cur_instruction.assign == @cur_instruction.assign.upcase
27
+
28
+ @memoize_assigns[@cur_instruction.assign] = {
29
+ inputs: @cur_instruction.inputs,
30
+ index:
31
+ }
32
+ next
33
+ end
34
+
35
+ apply_to_instruction(index)
36
+ end
37
+ actually_optimized_instructions = []
38
+ @optimized_instructions.each_with_index do |instruction, index|
39
+ actually_optimized_instructions << instruction unless @to_remove[index]
40
+ end
41
+
42
+ actually_optimized_instructions
43
+ end
44
+
45
+ private
46
+
47
+ def skip_instruction?
48
+ !%w[add subtract divide multiply].include?(@cur_instruction.instruction)
49
+ end
50
+
51
+ def apply_to_instruction(index)
52
+ match_on0 = @cur_instruction.inputs[0] == @cur_instruction.assign
53
+ match_on1 = @cur_instruction.inputs[1] == @cur_instruction.assign
54
+
55
+ unless @cur_instruction.inputs.length == 2 &&
56
+ (match_on1 || match_on0)
57
+
58
+ @optimized_instructions << @cur_instruction
59
+ return
60
+ end
61
+
62
+ optimized_inputs = []
63
+
64
+ if @memoize_assigns[@cur_instruction.inputs[0]]
65
+ optimized_inputs << @memoize_assigns[@cur_instruction.inputs[0]][:inputs]
66
+ @to_remove[@memoize_assigns[@cur_instruction.inputs[0]][:index]] = true
67
+ else
68
+ optimized_inputs << @cur_instruction.inputs[0]
69
+ end
70
+
71
+ if @memoize_assigns[@cur_instruction.inputs[1]]
72
+ optimized_inputs << @memoize_assigns[@cur_instruction.inputs[1]][:inputs]
73
+ @to_remove[@memoize_assigns[@cur_instruction.inputs[1]][:index]] = true
74
+ else
75
+ optimized_inputs << @cur_instruction.inputs[1]
76
+ end
77
+
78
+ optimized_inputs.flatten!
79
+ assignment = match_on0 ? optimized_inputs[0] : optimized_inputsinputs[1]
80
+
81
+ @optimized_instructions << DTRCore::Instruction.new(@cur_instruction.instruction, optimized_inputs, assignment,
82
+ @cur_instruction.scope)
83
+
84
+ return unless @cur_instruction.assign && @cur_instruction.assign == @cur_instruction.assign.upcase
85
+
86
+ @memoize_assigns[@cur_instruction.assign] = {
87
+ inputs: optimized_inputs,
88
+ index:
89
+ }
90
+ end
91
+ end
92
+ end
93
+ end
@@ -50,6 +50,10 @@ module DTRToRust
50
50
  @cur_instruction&.assign, @cur_instruction.scope)
51
51
 
52
52
  @memoize_assigns = {} unless clear_memoize?
53
+ return unless @cur_instruction.assign && @cur_instruction.assign == @cur_instruction.assign.upcase && !%w[
54
+ add subtract multiply divide
55
+ ].include?(@cur_instruction.instruction)
56
+
53
57
  @memoize_assigns[@cur_instruction.assign] = {
54
58
  inputs: @optimized_inputs,
55
59
  index:
@@ -79,23 +83,29 @@ module DTRToRust
79
83
 
80
84
  def apply_to_instruction_input(_instruction, input)
81
85
  done_a_thing = false
86
+ memoize_assigns_to_clear = []
82
87
  @memoize_assigns.each do |key, value|
83
88
  next unless do_a_thing?(input, key, input.split('.')[0])
84
89
 
85
90
  # input = input.gsub(key, "#{value[:inputs][0]}(#{value[:inputs][1..].join(', ')})")
86
91
 
87
- input = input.gsub(key, "#{evaluate_input(key, value)}")
92
+ input = input.gsub(key, evaluate_input(key, value).to_s)
88
93
  @optimized_inputs << input # evaluate_input(key, value)
89
94
  done_a_thing = true
90
95
  @to_remove[value[:index]] = true
96
+ memoize_assigns_to_clear << key
91
97
  next
92
98
  end
93
99
 
94
100
  @optimized_inputs << input unless done_a_thing
101
+
102
+ memoize_assigns_to_clear.each do |key|
103
+ @memoize_assigns.delete(key)
104
+ end
95
105
  end
96
106
 
97
107
  def evaluate_input(_key, input)
98
- InstructionHandler.new(DTRCore::Instruction.new('evaluate', input[:inputs], nil, 0), [], [],
108
+ InstructionHandler.new(DTRCore::Instruction.new('evaluate', input[:inputs], nil, 0), 0, [], [],
99
109
  false).generate_rust.strip.gsub(';', '')
100
110
  end
101
111
 
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Optimization
5
+ # This class is responsible for converting field instructions to assignment instructions
6
+ class FieldToAssignmentConversion
7
+ def initialize(instructions)
8
+ @instructions = instructions
9
+ end
10
+
11
+ def self.apply(instructions)
12
+ new(instructions).apply
13
+ end
14
+
15
+ def apply
16
+ @instructions.map do |instruction|
17
+ next instruction if skip_instruction?(instruction)
18
+
19
+ apply_to_instruction(instruction)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def skip_instruction?(instruction)
26
+ instruction.instruction != 'field'
27
+ end
28
+
29
+ def apply_to_instruction(instruction)
30
+ return instruction unless instruction.inputs.length == 2
31
+
32
+ DTRCore::Instruction.new('assign', ["#{instruction.inputs[0]}.#{instruction.inputs[1]}"], instruction.assign,
33
+ instruction.scope)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -35,12 +35,31 @@ module DTRToRust
35
35
 
36
36
  def generate_enum_attributes
37
37
  @user_defined_type.attributes.map do |x|
38
- " #{x[:name]},"
38
+ if x[:value]
39
+ " #{x[:name]} = #{x[:value]},"
40
+ elsif x[:type] && x[:type] != '()'
41
+ " #{x[:name]}(#{Common::TypeTranslator.translate_type(x[:type])}),"
42
+ else
43
+ " #{x[:name]},"
44
+ end
39
45
  end.join("\n")
40
46
  end
41
47
 
42
48
  def derives
43
- "#[contracttype]\n#[derive(Clone, Debug, Eq, PartialEq)]\n"
49
+ base = if error? && enum?
50
+ "#[contracterror]\n#[derive(Clone, Debug, Eq, PartialEq)]\n"
51
+ else
52
+ "#[contracttype]\n#[derive(Clone, Debug, Eq, PartialEq)]\n"
53
+ end
54
+
55
+ base += "#[repr(u32)]\n" if numbered_enum?
56
+
57
+ base
58
+ end
59
+
60
+ # TODO: fix this terrible hack
61
+ def error?
62
+ @user_defined_type.name.start_with? 'Error'
44
63
  end
45
64
 
46
65
  def struct?
@@ -50,6 +69,10 @@ module DTRToRust
50
69
  def enum?
51
70
  @user_defined_type.name.end_with? '_ENUM'
52
71
  end
72
+
73
+ def numbered_enum?
74
+ enum? && @user_defined_type.attributes.all? { |x| x[:value] }
75
+ end
53
76
  end
54
77
  end
55
78
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dtr_to_rust
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Durst
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-20 00:00:00.000000000 Z
11
+ date: 2024-06-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Rust to DTR translator (Digicus Textual Representation).
14
14
  email:
@@ -17,6 +17,7 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - lib/aggregator/scope_block_aggregator.rb
20
21
  - lib/common/input_interpreter.rb
21
22
  - lib/common/reference_appender.rb
22
23
  - lib/common/type_translator.rb
@@ -26,11 +27,13 @@ files:
26
27
  - lib/instruction/and.rb
27
28
  - lib/instruction/assign.rb
28
29
  - lib/instruction/divide.rb
30
+ - lib/instruction/end_of_iteration_check.rb
29
31
  - lib/instruction/evaluate.rb
30
32
  - lib/instruction/exit_with_message.rb
31
33
  - lib/instruction/field.rb
32
34
  - lib/instruction/goto.rb
33
35
  - lib/instruction/handler.rb
36
+ - lib/instruction/increment.rb
34
37
  - lib/instruction/instantiate_object.rb
35
38
  - lib/instruction/jump.rb
36
39
  - lib/instruction/label.rb
@@ -40,7 +43,9 @@ files:
40
43
  - lib/instruction/return.rb
41
44
  - lib/instruction/subtract.rb
42
45
  - lib/instruction_handler.rb
46
+ - lib/optimization/binary_x_to_self_assignment_reduction.rb
43
47
  - lib/optimization/chained_invocation_assignment_reduction.rb
48
+ - lib/optimization/field_to_assignment_conversion.rb
44
49
  - lib/user_defined_types/handler.rb
45
50
  homepage: https://spaced-out-thoughts-dev-foundation.github.io/digicus/
46
51
  licenses: