dtr_to_rust 0.2.10 → 0.3.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: 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