dtr_to_rust 0.2.10 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7572c039db830a1a216b31e01f53a104701d8321d487b47811a7a366ea520e53
4
- data.tar.gz: d359cdc39400f9a0bdaf4823cdf77aea9c1aeb6fb7dbee931419e2208d073a51
3
+ metadata.gz: b42b05c23f4f6cd523b03895ef4e41734d83d836f768143379b12d996415038d
4
+ data.tar.gz: d23996a0656a9ee252065f4f36d68646d18c42a9b9a05fe9897574ca4453dfb8
5
5
  SHA512:
6
- metadata.gz: 8c62415d2d4f63cb331cf26bdf73c72e9b230a69c65cf8df5bf0ff83f102f4658641b329e48d3c7f01a2c53501f58be1c5bfd5133ce98b9652674911043a0b60
7
- data.tar.gz: 43caee328ae2b7216104600b8a656cb0ab5cc71ceeaae6a75de277516bef5b095ab1ca2f57a495c47dd353b7bd87b3a66ace7d11ebdcd7ecff97ead0521aa381
6
+ metadata.gz: f4238874b6d9be9f31090673903cf2d265b0aa5bcf4eb69056eb642b8750b73724a46bb005ad0e5fad7e22a98ca6e6ae95de9c401e8533bd6aa334622bc1002f
7
+ data.tar.gz: baebd2c976094cc88714c008f93ce5fd048fb0b5eb8a3c174d2ec899b612606a837d7c9bc7da1b12319d79d141793768c17336d5c82126226f24af7e491d3652
@@ -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
@@ -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,56 @@
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
+ decorated_input = Common::InputInterpreter.interpret(input)
9
+
10
+ # HACK: is likely chain of method calls
11
+ # ex: env.storage().instance().get(COUNTER).unwrap_or(0);
12
+ # --> env.storage().instance().get(&COUNTER).unwrap_or(0);
13
+ if decorated_input[:type] != 'number' &&
14
+ decorated_input[:value].include?('.') &&
15
+ decorated_input[:value].include?('(') && decorated_input[:value].include?(')')
16
+ more_complex_ref_appender(input, decorated_input)
17
+ elsif decorated_input[:needs_reference]
18
+ "&#{decorated_input[:value]}"
19
+ elsif decorated_input[:type] == 'number'
20
+ ref_nums ? "&#{decorated_input[:value]}" : decorated_input[:value]
21
+ else
22
+ decorated_input[:value]
23
+ end
24
+ end
25
+
26
+ def self.more_complex_ref_appender(_input, decorated_input)
27
+ decorated_input[:value].split('.').map do |x|
28
+ x = x.strip
29
+ if call_with_input?(x)
30
+ matches = x.scan(/\((.*?)\)/)
31
+ things = matches
32
+ .flatten
33
+ .filter(&method(:not_empty_string?))
34
+ .map(&method(:wild_stuff))
35
+ .join(', ')
36
+ "#{x.split('(')[0]}(#{things})"
37
+ else
38
+ x
39
+ end
40
+ end.join('.')
41
+ end
42
+
43
+ def self.not_empty_string?(input)
44
+ input != ''
45
+ end
46
+
47
+ def self.wild_stuff(input)
48
+ input.split(',').map { |x| ReferenceAppender.call(x.strip) }.join(', ')
49
+ end
50
+
51
+ def self.call_with_input?(input)
52
+ input.include?('(') && input.end_with?(')') && !input.end_with?('()')
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,20 @@
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('String', 'Symbol')
15
+ .gsub('Boolean', 'bool')
16
+ .gsub('Float', 'f64')
17
+ end
18
+ end
19
+ end
20
+ end
data/lib/dtr_to_rust.rb CHANGED
@@ -7,18 +7,39 @@ 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'
18
27
  end
19
28
 
20
29
  # This module contains all the classes that handle common logic.
21
30
  module Common
22
31
  autoload :InputInterpreter, 'common/input_interpreter'
32
+ autoload :ReferenceAppender, 'common/reference_appender'
33
+ autoload :TypeTranslator, 'common/type_translator'
34
+ end
35
+
36
+ # This module contains all the classes that handle optimization.
37
+ module Optimization
38
+ autoload :ChainedInvocationAssignmentReduction, 'optimization/chained_invocation_assignment_reduction'
39
+ end
40
+
41
+ # This module contains all the classes that handle user defined types.
42
+ module UserDefinedTypes
43
+ autoload :Handler, 'user_defined_types/handler'
23
44
  end
24
45
  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,30 @@ module DTRToRust
34
36
  attr_reader :dtr_contract
35
37
 
36
38
  def generate_contract_header
39
+ imports_super_set = %w[
40
+ contract
41
+ contractimpl
42
+ contracttype
43
+ symbol_short
44
+ vec
45
+ Env
46
+ Symbol
47
+ Vec
48
+ log
49
+ ]
50
+
51
+ used_imports = []
52
+
53
+ @content.split.each do |word|
54
+ imports_super_set.each do |import|
55
+ used_imports << import if word.include?(import)
56
+ end
57
+ end
58
+
59
+ used_imports.uniq!
60
+
37
61
  # TODO: don't hardcode imports
38
- @content += "#![no_std]\nuse soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec, log};\n\n"
62
+ @content = "#![no_std]\nuse soroban_sdk::{#{used_imports.join(', ')}};\n\n" + @content
39
63
  end
40
64
 
41
65
  def generate_contract_name
@@ -47,22 +71,44 @@ module DTRToRust
47
71
 
48
72
  dtr_contract.state.each do |state_value|
49
73
  if state_value.type == 'String'
50
- @content += "const #{state_value.name}: Symbol = symbol_short!(\"#{state_value.initial_value}\");\n"
74
+ @content += "const #{state_value.name}: Symbol = symbol_short!(#{state_value.initial_value});\n"
75
+ else
76
+ @content += "const #{state_value.name}: #{Common::TypeTranslator.translate_type(state_value.type)} = #{state_value.initial_value};\n"
51
77
  end
52
78
  end
53
79
 
54
80
  @content += "\n"
55
81
  end
56
82
 
57
- def generate_functions
58
- @content += "#[contractimpl]\nimpl #{dtr_contract.name} {#{generate_functions_each(dtr_contract.functions)}}\n"
83
+ def generate_interface
84
+ @content += "#[contractimpl]\nimpl #{dtr_contract.name} {#{generate_functions_each(dtr_contract.interface,
85
+ false)}}\n"
86
+ end
87
+
88
+ def generate_helpers
89
+ @content += "#{generate_functions_each(dtr_contract.helpers, true)}\n"
59
90
  end
60
91
 
61
- def generate_functions_each(functions)
92
+ def generate_functions_each(functions, is_helper)
93
+ function_names = functions&.map(&:name)
94
+
62
95
  functions&.map do |function|
63
- return_string = "\n pub fn #{function.name}(#{generate_function_args(function)}) "
96
+ @last_scope = nil
97
+ optimized_instructions =
98
+ Optimization::ChainedInvocationAssignmentReduction.apply(function.instructions)
99
+
100
+ return_string = "\n#{is_helper ? '' : ' '}pub fn #{function.name}(#{generate_function_args(function)}) "
64
101
  return_string += generate_function_output(function)
65
- return_string += " {\n#{generate_instructions_each(function.instructions)}\n }\n"
102
+ return_string += " {\n#{generate_instructions_each(optimized_instructions, function_names,
103
+ is_helper)}"
104
+ unless @last_scope.nil?
105
+ while @last_scope.positive?
106
+ return_string += "\n#{form_rust_string('}', @last_scope,
107
+ is_helper)}"
108
+ @last_scope -= 1
109
+ end
110
+ end
111
+ return_string += "\n#{is_helper ? '' : ' '}}\n"
66
112
 
67
113
  return_string
68
114
  end&.join("\n")
@@ -71,49 +117,49 @@ module DTRToRust
71
117
  def generate_function_output(function)
72
118
  return '' if function.output.nil?
73
119
 
74
- "-> #{translate_type(function.output)}"
120
+ "-> #{Common::TypeTranslator.translate_type(function.output)}"
75
121
  end
76
122
 
77
123
  def generate_function_args(function)
78
124
  all_inputs = [] + function.inputs
79
125
 
80
- all_inputs.map { |x| "#{x[:name]}: #{translate_type(x[:type_name])}" }.join(', ')
126
+ all_inputs.map { |x| "#{x[:name]}: #{Common::TypeTranslator.translate_type(x[:type_name])}" }.join(', ')
81
127
  end
82
128
 
83
- def generate_instructions_each(instructions)
129
+ def generate_instructions_each(instructions, function_names, is_helper)
84
130
  instructions.map do |instruction|
85
- generate_instruction(instruction)
131
+ 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
137
+ end
138
+ content += generate_instruction(instruction, function_names, is_helper)
139
+
140
+ content
86
141
  end.join("\n")
87
142
  end
88
143
 
89
- def generate_instruction(instruction)
90
- handler = InstructionHandler.new(instruction)
91
- handler.generate_rust
144
+ def form_rust_string(instruction_string, scope, is_helper)
145
+ "#{spacing(scope, is_helper)}#{instruction_string}"
92
146
  end
93
147
 
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
148
+ def spacing(scope, is_helper)
149
+ ' ' * (is_helper ? 0 : scope + 1)
150
+ end
151
+
152
+ def generate_instruction(instruction, function_names, is_helper)
153
+ handler = InstructionHandler.new(instruction, function_names, dtr_contract.user_defined_types || [], is_helper)
154
+ handler.generate_rust
105
155
  end
106
156
 
107
157
  def generate_user_defined_types
108
158
  return if dtr_contract.user_defined_types.nil?
109
159
 
110
160
  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"
161
+ @content += DTRToRust::UserDefinedTypes::Handler.generate(udt)
112
162
  end
113
163
  end
114
-
115
- def derives
116
- "#[contracttype]\n#[derive(Clone, Debug, Eq, PartialEq)]\n"
117
- end
118
164
  end
119
165
  end
@@ -0,0 +1,13 @@
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
+ @instruction.scope)
10
+ end
11
+ end
12
+ end
13
+ 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, @instruction.scope)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
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
+ form_rust_string("let mut #{@instruction.assign} = #{@instruction.inputs[0]};", @instruction.scope)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
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
+ @instruction.scope)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -5,34 +5,74 @@ 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, @instruction.scope)
10
+ end
11
+
12
+ private
13
+
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
+ else
21
+ handle_non_keyword_method_invocation
22
+ end
23
+ end
11
24
 
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
25
+ def handle_non_keyword_method_invocation
26
+ inputs = @instruction.inputs[1..]
27
+ evaluated_method_name = @instruction.inputs[0]
28
+ assignment = @instruction.assign
17
29
 
18
- form_rust_string(rust_string, @instruction[:scope])
30
+ assignment_rust = "let mut #{assignment} = "
31
+ # TODO: make this less hacky evaluated_method_name.end_with?('set')
32
+ body_rust = "#{invocation_name(evaluated_method_name)}(#{inputs_to_rust_string(inputs,
33
+ don_t_append_ref)});"
34
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
19
35
  end
20
36
 
21
- private
37
+ def handle_equal_to
38
+ inputs = @instruction.inputs[1..]
39
+ @instruction.inputs[0]
40
+ assignment = @instruction.assign
22
41
 
23
- def inputs_to_rust_string(inputs)
24
- inputs.map { |input| ref_appender(input) }.join(', ')
42
+ assignment_rust = "let #{assignment} = "
43
+ lhs = Common::ReferenceAppender.call(inputs[0])
44
+ rhs = Common::ReferenceAppender.call(inputs[1])
45
+ body_rust = "#{lhs} == #{rhs};"
46
+
47
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
48
+ end
49
+
50
+ def handle_unary_negation
51
+ inputs = @instruction.inputs[1..]
52
+ @instruction.inputs[0]
53
+ assignment = @instruction.assign
54
+
55
+ assignment_rust = "let #{assignment} = "
56
+ body_rust = "!(#{inputs[0]});"
57
+
58
+ "#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
25
59
  end
26
60
 
27
- def ref_appender(input)
28
- decorated_input = Common::InputInterpreter.interpret(input)
61
+ def don_t_append_ref
62
+ @instruction.inputs[0].end_with?('set') || @instruction.inputs[0].end_with?('unwrap_or')
63
+ end
29
64
 
30
- if decorated_input[:needs_reference]
31
- "&#{decorated_input[:value]}"
65
+ def invocation_name(evaluated_method_name)
66
+ if @function_names.include?(evaluated_method_name)
67
+ "Self::#{evaluated_method_name}"
32
68
  else
33
- decorated_input[:value]
69
+ evaluated_method_name
34
70
  end
35
71
  end
72
+
73
+ def inputs_to_rust_string(inputs, ref_nums)
74
+ inputs.map { |input| Common::ReferenceAppender.call(input, ref_nums:) }.join(', ')
75
+ end
36
76
  end
37
77
  end
38
78
  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)};", @instruction.scope)
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
@@ -5,17 +5,17 @@ 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}", @instruction.scope)
9
9
  end
10
10
 
11
11
  private
12
12
 
13
13
  def handle_field_call
14
- "#{@instruction[:inputs][0]}.#{@instruction[:inputs][1]};"
14
+ "#{@instruction.inputs[0]}.#{@instruction.inputs[1]};"
15
15
  end
16
16
 
17
17
  def handle_field_assign
18
- "let mut #{@instruction[:assign]} = " if @instruction[:assign]
18
+ "let mut #{@instruction.assign} = " if @instruction.assign
19
19
  end
20
20
  end
21
21
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the goto instruction.
6
+ class Goto < Handler
7
+ def handle
8
+ ''
9
+ end
10
+ end
11
+ end
12
+ end
@@ -4,16 +4,19 @@ 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)
7
+ def initialize(instruction, function_names, user_defined_types, is_helper)
8
8
  @instruction = instruction
9
+ @function_names = function_names
10
+ @user_defined_types = user_defined_types
11
+ @is_helper = is_helper
9
12
  end
10
13
 
11
- def self.handle(instruction)
12
- new(instruction).handle
14
+ def self.handle(instruction, function_names, user_defined_types, is_helper)
15
+ new(instruction, function_names, user_defined_types, is_helper).handle
13
16
  end
14
17
 
15
18
  def spacing(scope)
16
- ' ' * (scope + 1)
19
+ ' ' * (@is_helper ? 1 : scope + 2)
17
20
  end
18
21
 
19
22
  def form_rust_string(instruction_string, scope)
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class is responsible for generating Rust code for the LogString instruction.
6
+ class InstantiateObject < Handler
7
+ def handle
8
+ case @instruction.inputs[0]
9
+ when 'List'
10
+ handle_list
11
+ when 'UDT'
12
+ handle_udt
13
+ else
14
+ raise "Unknown object type: #{@instruction.inputs[0]}"
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def handle_list
21
+ form_rust_string("let mut #{@instruction.assign} = vec![#{inputs_to_rust_string(@instruction.inputs[1..])}];",
22
+ @instruction.scope)
23
+ end
24
+
25
+ def udt_name_fix(udt)
26
+ if udt.name.end_with?('_STRUCT') || udt.name.end_with?('_ENUM')
27
+ udt.name.split('_')[0..-2].join('_')
28
+ else
29
+ udt.name
30
+ end
31
+ end
32
+
33
+ def handle_udt
34
+ udt_found = @user_defined_types.filter { |udt| udt_name_fix(udt) == @instruction.inputs[1] }
35
+
36
+ assignment = "let mut #{@instruction.assign} = "
37
+ udt = "#{@instruction.inputs[1]}{"
38
+ inputs = inputs_to_rust_string(@instruction.inputs[2..], udt_found[0].attributes.map { |x| x[:name] })
39
+ end_ = '};'
40
+ form_rust_string("#{assignment}#{udt}#{inputs}#{end_}", @instruction.scope)
41
+ end
42
+
43
+ def inputs_to_rust_string(inputs, udt_type_names)
44
+ inputs_to_return = []
45
+ inputs.each_with_index do |input, index|
46
+ inputs_to_return << handle_input(input, udt_type_names[index])
47
+ end
48
+
49
+ inputs_to_return.join(', ')
50
+ end
51
+
52
+ def handle_input(input, udt_type_name)
53
+ decorated_input = Common::InputInterpreter.interpret(input)
54
+
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
+
63
+ "#{udt_type_name}: #{value}"
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the jump instruction.
6
+ class Jump < Handler
7
+ def handle
8
+ if @instruction.inputs[0].nil?
9
+ handle_unconditional_jump
10
+ else
11
+ handle_conditional_jump
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def handle_conditional_jump
18
+ form_rust_string("if #{@instruction.inputs[0]} {", @instruction.scope)
19
+ end
20
+
21
+ def handle_unconditional_jump
22
+ form_rust_string('if true {', @instruction.scope)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the label instruction.
6
+ class Label < Handler
7
+ def handle
8
+ ''
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the add instruction.
6
+ class Multiply < Handler
7
+ def handle
8
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} * #{@instruction.inputs[1]};",
9
+ @instruction.scope)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the or instruction.
6
+ class Or < 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, @instruction.scope)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -3,9 +3,9 @@
3
3
  module DTRToRust
4
4
  module Instruction
5
5
  # This class is responsible for generating Rust code for the LogString instruction.
6
- class LogString < Handler
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)});", @instruction.scope)
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], @instruction.scope)
9
9
  end
10
10
  end
11
11
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Instruction
5
+ # This class handles the add instruction.
6
+ class Subtract < Handler
7
+ def handle
8
+ form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} - #{@instruction.inputs[1]};",
9
+ @instruction.scope)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -3,33 +3,46 @@
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)
6
+ def initialize(instruction, function_names, user_defined_types, is_helper)
7
7
  @instruction = instruction
8
+ @function_names = function_names
9
+ @user_defined_types = user_defined_types
10
+ @is_helper = is_helper
8
11
  end
9
12
 
10
13
  def generate_rust
11
- case @instruction[:instruction]
12
- when 'Return'
13
- Instruction::Return.handle(@instruction)
14
- when 'log_string'
15
- Instruction::LogString.handle(@instruction)
16
- when 'add_and_assign'
17
- Instruction::AddAndAssign.handle(@instruction)
18
- when 'evaluate'
19
- Instruction::Evaluate.handle(@instruction)
20
- when 'create_list'
21
- Instruction::CreateList.handle(@instruction)
22
- when 'field'
23
- Instruction::Field.handle(@instruction)
24
- when 'initialize_udt'
25
- Instruction::InitializeUDT.handle(@instruction)
26
- else
27
- raise "Unknown instruction type: #{@instruction[:instruction]}"
14
+ unless EXPRESSION_FOOBAR.key?(@instruction.instruction.strip)
15
+ raise "Unknown instruction type: #{@instruction.instruction}"
28
16
  end
17
+
18
+ EXPRESSION_FOOBAR[@instruction.instruction.strip].send(:handle, @instruction, @function_names,
19
+ @user_defined_types, @is_helper)
29
20
  end
30
21
 
31
22
  private
32
23
 
24
+ EXPRESSION_FOOBAR = {
25
+ 'assign' => Instruction::Assign,
26
+ 'jump' => Instruction::Jump,
27
+ 'goto' => Instruction::Goto,
28
+ 'exit_with_message' => Instruction::ExitWithMessage,
29
+ 'and' => Instruction::And,
30
+ 'or' => Instruction::Or,
31
+ 'label' => Instruction::Label,
32
+ 'add' => Instruction::Add,
33
+ 'subtract' => Instruction::Subtract,
34
+ 'multiply' => Instruction::Multiply,
35
+ 'divide' => Instruction::Divide,
36
+ 'instantiate_object' => Instruction::InstantiateObject,
37
+ 'print' => Instruction::Print,
38
+ 'return' => Instruction::Return,
39
+ 'evaluate' => Instruction::Evaluate,
40
+ 'field' => Instruction::Field
41
+ }.freeze
42
+
43
+ def handle_empty_instruction
44
+ ''
45
+ end
33
46
  attr_reader :instruction
34
47
  end
35
48
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module Optimization
5
+ # Optimizes the instructions by reducing chained invocation assignments
6
+ class ChainedInvocationAssignmentReduction
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 apply
17
+ @instructions.each_with_index do |instruction, index|
18
+ @cur_instruction = instruction
19
+
20
+ if skip_instruction?
21
+ @optimized_instructions << @cur_instruction
22
+ next
23
+ end
24
+
25
+ apply_to_instruction(index)
26
+ end
27
+ actually_optimized_instructions = []
28
+ @optimized_instructions.each_with_index do |instruction, index|
29
+ actually_optimized_instructions << instruction unless @to_remove[index]
30
+ end
31
+
32
+ actually_optimized_instructions
33
+ end
34
+
35
+ def skip_instruction?
36
+ @cur_instruction.instruction == 'instantiate_object'
37
+ end
38
+
39
+ def self.apply(instructions)
40
+ new(instructions).apply
41
+ end
42
+
43
+ def apply_to_instruction(index)
44
+ @optimized_inputs = []
45
+
46
+ @cur_instruction&.inputs&.each do |input|
47
+ apply_to_instruction_input(@cur_instruction, input)
48
+ end
49
+ @optimized_instructions << DTRCore::Instruction.new(@cur_instruction.instruction, @optimized_inputs,
50
+ @cur_instruction&.assign, @cur_instruction.scope)
51
+
52
+ @memoize_assigns = {} unless clear_memoize?
53
+ @memoize_assigns[@cur_instruction.assign] = {
54
+ inputs: @optimized_inputs,
55
+ index:
56
+ }
57
+ end
58
+
59
+ def clear_memoize?
60
+ if @last_was_eavluate.nil?
61
+ @last_was_eavluate = @cur_instruction.instruction == 'evaluate'
62
+ return false
63
+ end
64
+
65
+ if @cur_instruction.instruction == 'evaluate'
66
+ if @last_was_eavluate
67
+ false
68
+ else
69
+ @last_was_eavluate = true
70
+ true
71
+ end
72
+ elsif @last_was_eavluate
73
+ @last_was_eavluate = false
74
+ true
75
+ else
76
+ false
77
+ end
78
+ end
79
+
80
+ def apply_to_instruction_input(_instruction, input)
81
+ done_a_thing = false
82
+ @memoize_assigns.each do |key, value|
83
+ next unless do_a_thing?(input, key, input.split('.')[0])
84
+
85
+ # input = input.gsub(key, "#{value[:inputs][0]}(#{value[:inputs][1..].join(', ')})")
86
+
87
+ input = input.gsub(key, "#{evaluate_input(key, value)}")
88
+ @optimized_inputs << input # evaluate_input(key, value)
89
+ done_a_thing = true
90
+ @to_remove[value[:index]] = true
91
+ next
92
+ end
93
+
94
+ @optimized_inputs << input unless done_a_thing
95
+ end
96
+
97
+ def evaluate_input(_key, input)
98
+ InstructionHandler.new(DTRCore::Instruction.new('evaluate', input[:inputs], nil, 0), [], [],
99
+ false).generate_rust.strip.gsub(';', '')
100
+ end
101
+
102
+ def do_a_thing?(input, key, input_beginning)
103
+ input &&
104
+ key &&
105
+ input_beginning == key &&
106
+ !(input.start_with?('"') &&
107
+ input.end_with?('"')) &&
108
+ @cur_instruction.instruction == 'evaluate' &&
109
+ !['equal_to', '!'].include?(@cur_instruction)
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRToRust
4
+ module UserDefinedTypes
5
+ class Handler
6
+ def initialize(user_defined_type)
7
+ @user_defined_type = user_defined_type
8
+ end
9
+
10
+ def self.generate(user_defined_type)
11
+ new(user_defined_type).generate
12
+ end
13
+
14
+ def generate
15
+ if struct?
16
+ generate_struct
17
+ elsif enum?
18
+ generate_enum
19
+ end
20
+ end
21
+
22
+ def generate_struct
23
+ "#{derives}pub struct #{@user_defined_type.name.gsub('_STRUCT', '')} {\n#{generate_struct_attributes}\n}\n\n"
24
+ end
25
+
26
+ def generate_struct_attributes
27
+ @user_defined_type.attributes.map do |x|
28
+ " pub #{x[:name]}: #{Common::TypeTranslator.translate_type(x[:type])},"
29
+ end.join("\n")
30
+ end
31
+
32
+ def generate_enum
33
+ "#{derives}pub enum #{@user_defined_type.name.gsub('_ENUM', '')} {\n#{generate_enum_attributes}\n}\n\n"
34
+ end
35
+
36
+ def generate_enum_attributes
37
+ @user_defined_type.attributes.map do |x|
38
+ " #{x[:name]},"
39
+ end.join("\n")
40
+ end
41
+
42
+ def derives
43
+ "#[contracttype]\n#[derive(Clone, Debug, Eq, PartialEq)]\n"
44
+ end
45
+
46
+ def struct?
47
+ @user_defined_type.name.end_with? '_STRUCT'
48
+ end
49
+
50
+ def enum?
51
+ @user_defined_type.name.end_with? '_ENUM'
52
+ end
53
+ end
54
+ end
55
+ 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.2.10
4
+ version: 0.3.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-16 00:00:00.000000000 Z
11
+ date: 2024-06-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Rust to DTR translator (Digicus Textual Representation).
14
14
  email:
@@ -18,17 +18,30 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - lib/common/input_interpreter.rb
21
+ - lib/common/reference_appender.rb
22
+ - lib/common/type_translator.rb
21
23
  - lib/dtr_to_rust.rb
22
24
  - lib/generator.rb
23
- - lib/instruction/add_and_assign.rb
24
- - lib/instruction/create_list.rb
25
+ - lib/instruction/add.rb
26
+ - lib/instruction/and.rb
27
+ - lib/instruction/assign.rb
28
+ - lib/instruction/divide.rb
25
29
  - lib/instruction/evaluate.rb
30
+ - lib/instruction/exit_with_message.rb
26
31
  - lib/instruction/field.rb
32
+ - lib/instruction/goto.rb
27
33
  - lib/instruction/handler.rb
28
- - lib/instruction/initialize_udt.rb
29
- - lib/instruction/log_string.rb
34
+ - lib/instruction/instantiate_object.rb
35
+ - lib/instruction/jump.rb
36
+ - lib/instruction/label.rb
37
+ - lib/instruction/multiply.rb
38
+ - lib/instruction/or.rb
39
+ - lib/instruction/print.rb
30
40
  - lib/instruction/return.rb
41
+ - lib/instruction/subtract.rb
31
42
  - lib/instruction_handler.rb
43
+ - lib/optimization/chained_invocation_assignment_reduction.rb
44
+ - lib/user_defined_types/handler.rb
32
45
  homepage: https://spaced-out-thoughts-dev-foundation.github.io/digicus/
33
46
  licenses:
34
47
  - MIT
@@ -49,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
49
62
  - !ruby/object:Gem::Version
50
63
  version: '0'
51
64
  requirements: []
52
- rubygems_version: 3.4.10
65
+ rubygems_version: 3.5.13
53
66
  signing_key:
54
67
  specification_version: 4
55
68
  summary: Rust to DTR translator (Digicus Textual Representation).
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DTRToRust
4
- module Instruction
5
- # This class is responsible for generating Rust code for the AddAndAssign instruction.
6
- class AddAndAssign < Handler
7
- def handle
8
- form_rust_string("#{@instruction[:inputs][0]} += #{@instruction[:inputs][1]};", @instruction[:scope])
9
- end
10
- end
11
- end
12
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DTRToRust
4
- module Instruction
5
- # This class is responsible for generating Rust code for the AddAndAssign instruction.
6
- class CreateList < Handler
7
- def handle
8
- form_rust_string("let #{@instruction[:assign]} = vec![#{handle_inputs}];",
9
- @instruction[:scope])
10
- end
11
-
12
- private
13
-
14
- def handle_inputs
15
- @instruction[:inputs].map { |input| handle_input(input) }.join(', ')
16
- end
17
-
18
- def handle_input(input)
19
- decorated_input = Common::InputInterpreter.interpret(input)
20
-
21
- if decorated_input[:type] == 'string'
22
- "symbol_short!(#{input})"
23
- elsif decorated_input[:needs_reference] && input == 'env'
24
- "&#{input}"
25
- else
26
- input
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DTRToRust
4
- module Instruction
5
- # This class is responsible for generating Rust code for the Field instruction.
6
- class InitializeUDT < Handler
7
- def handle
8
- form_rust_string("#{handle_assign}#{handle_udt_part}", @instruction[:scope])
9
- end
10
-
11
- private
12
-
13
- def handle_udt_part
14
- "#{@instruction[:inputs][0]} { #{@instruction[:inputs][1..].join(' ')} };"
15
- end
16
-
17
- def handle_assign
18
- "let mut #{@instruction[:assign]} = " if @instruction[:assign]
19
- end
20
- end
21
- end
22
- end