dtr_to_rust 0.8.1 → 0.12.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 +4 -4
- data/lib/code_generator.rb +90 -0
- data/lib/common/type_translator.rb +3 -3
- data/lib/contract_handler.rb +98 -0
- data/lib/contract_state/handler.rb +35 -0
- data/lib/function_handler.rb +47 -0
- data/lib/instruction/add.rb +4 -4
- data/lib/instruction/and.rb +2 -4
- data/lib/instruction/assign.rb +3 -3
- data/lib/instruction/binary_instruction.rb +22 -0
- data/lib/instruction/break.rb +12 -0
- data/lib/instruction/divide.rb +3 -3
- data/lib/instruction/end_of_iteration_check.rb +2 -2
- data/lib/instruction/evaluate.rb +26 -12
- data/lib/instruction/exit_with_message.rb +4 -3
- data/lib/instruction/field.rb +2 -2
- data/lib/instruction/handler.rb +18 -13
- data/lib/instruction/increment.rb +3 -2
- data/lib/instruction/instantiate_object.rb +31 -17
- data/lib/instruction/jump.rb +24 -5
- data/lib/instruction/multiply.rb +3 -3
- data/lib/instruction/or.rb +2 -4
- data/lib/instruction/print.rb +9 -8
- data/lib/instruction/return.rb +2 -2
- data/lib/instruction/subtract.rb +3 -4
- data/lib/instruction/{goto.rb → try_assign.rb} +3 -3
- data/lib/instruction_handler.rb +7 -11
- data/lib/lcpbt_forrest.rb +83 -0
- data/lib/left_child_preferential_binary_tree.rb +66 -0
- data/lib/non_translatables/handler.rb +23 -0
- data/lib/silviculturist.rb +149 -0
- data/lib/soroban_rust_backend.rb +51 -0
- data/lib/user_defined_types_handler.rb +87 -0
- metadata +19 -17
- data/lib/aggregator/scope_block_aggregator.rb +0 -72
- data/lib/common/input_interpreter.rb +0 -74
- data/lib/common/reference_appender.rb +0 -59
- data/lib/dtr_to_rust.rb +0 -54
- data/lib/generator.rb +0 -196
- data/lib/instruction/label.rb +0 -12
- data/lib/optimization/binary_x_to_self_assignment_reduction.rb +0 -93
- data/lib/optimization/chained_invocation_assignment_reduction.rb +0 -123
- data/lib/optimization/field_to_assignment_conversion.rb +0 -37
- data/lib/user_defined_types/handler.rb +0 -89
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class is responsible for generating Rust code for the LogString instruction.
|
6
6
|
class InstantiateObject < Handler
|
@@ -11,7 +11,9 @@ module DTRToRust
|
|
11
11
|
when 'UDT'
|
12
12
|
handle_udt
|
13
13
|
when 'Tuple'
|
14
|
-
|
14
|
+
"let mut #{@instruction.assign} = (#{normalish_inputs});"
|
15
|
+
when 'Range'
|
16
|
+
"let mut #{@instruction.assign} = #{range_inputs};"
|
15
17
|
else
|
16
18
|
raise "Unknown object type: #{@instruction.inputs[0]}"
|
17
19
|
end
|
@@ -20,7 +22,13 @@ module DTRToRust
|
|
20
22
|
private
|
21
23
|
|
22
24
|
def handle_list
|
23
|
-
|
25
|
+
"let mut #{@instruction.assign} = vec![#{normalish_inputs}];"
|
26
|
+
end
|
27
|
+
|
28
|
+
def range_inputs
|
29
|
+
@instruction.inputs[1..].map do |x|
|
30
|
+
foobar(x)
|
31
|
+
end.join('..')
|
24
32
|
end
|
25
33
|
|
26
34
|
def normalish_inputs
|
@@ -38,13 +46,18 @@ module DTRToRust
|
|
38
46
|
end
|
39
47
|
|
40
48
|
def handle_udt
|
41
|
-
udt_found = @user_defined_types.filter { |udt| udt_name_fix(udt) == @instruction.inputs[1] }
|
49
|
+
# udt_found = @user_defined_types.filter { |udt| udt_name_fix(udt) == @instruction.inputs[1] }
|
42
50
|
|
43
|
-
assignment = "let mut #{@instruction.assign} = "
|
44
|
-
udt = "#{@instruction.inputs[1]}{"
|
45
|
-
inputs = inputs_to_rust_string(@instruction.inputs[2..], udt_found[0].attributes.map { |x| x[:name] })
|
46
|
-
end_ = '};'
|
47
|
-
form_rust_string("#{assignment}#{udt}#{inputs}#{end_}")
|
51
|
+
# assignment = "let mut #{@instruction.assign} = "
|
52
|
+
# udt = "#{@instruction.inputs[1]}{"
|
53
|
+
# inputs = inputs_to_rust_string(@instruction.inputs[2..], udt_found[0].attributes.map { |x| x[:name] })
|
54
|
+
# end_ = '};'
|
55
|
+
# form_rust_string("#{assignment}#{udt}#{inputs}#{end_}")
|
56
|
+
|
57
|
+
"let mut #{@instruction.assign} = #{@instruction.inputs[1]}{#{inputs_to_rust_string(@instruction.inputs[2..],
|
58
|
+
@instruction.inputs[1])}}"
|
59
|
+
|
60
|
+
# raise 'Not implemented'
|
48
61
|
end
|
49
62
|
|
50
63
|
def inputs_to_rust_string(inputs, udt_type_names)
|
@@ -57,15 +70,16 @@ module DTRToRust
|
|
57
70
|
end
|
58
71
|
|
59
72
|
def foobar(input)
|
60
|
-
|
73
|
+
input
|
74
|
+
# decorated_input = Common::InputInterpreter.interpret(input)
|
61
75
|
|
62
|
-
if decorated_input[:type] == 'string'
|
63
|
-
|
64
|
-
elsif decorated_input[:needs_reference] && input == 'env'
|
65
|
-
|
66
|
-
else
|
67
|
-
|
68
|
-
end
|
76
|
+
# if decorated_input[:type] == 'string'
|
77
|
+
# "symbol_short!(#{input})"
|
78
|
+
# elsif decorated_input[:needs_reference] && input == 'env'
|
79
|
+
# "&#{input}"
|
80
|
+
# else
|
81
|
+
# input
|
82
|
+
# end
|
69
83
|
end
|
70
84
|
|
71
85
|
def handle_input(input, udt_type_name)
|
data/lib/instruction/jump.rb
CHANGED
@@ -1,27 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class handles the jump instruction.
|
6
6
|
class Jump < Handler
|
7
7
|
def handle
|
8
|
+
last_instruction_is_else_if = @instruction.inputs[@instruction.inputs.size - 1] == 'ELSE_IF_BRANCH'
|
9
|
+
last_instruction_is_while_loop = @instruction.inputs[@instruction.inputs.size - 1] == 'WHILE_LOOP'
|
10
|
+
|
8
11
|
if @instruction.inputs.size == 1
|
9
12
|
handle_unconditional_jump
|
10
13
|
elsif @instruction.inputs.size == 2
|
11
|
-
handle_conditional_jump
|
14
|
+
last_instruction_is_else_if ? handle_unconditional_jump : handle_conditional_jump
|
15
|
+
elsif @instruction.inputs.size == 3 && last_instruction_is_else_if
|
16
|
+
handle_conditional_else_if_jump
|
17
|
+
elsif @instruction.inputs.size == 4 && last_instruction_is_while_loop
|
18
|
+
handle_while_loop
|
12
19
|
else
|
13
|
-
raise 'Invalid jump instruction'
|
20
|
+
raise 'Invalid jump instruction. Received too many inputs: ' + @instruction.inputs.size.to_s
|
14
21
|
end
|
15
22
|
end
|
16
23
|
|
17
24
|
private
|
18
25
|
|
19
26
|
def handle_conditional_jump
|
20
|
-
|
27
|
+
"if #{@instruction.inputs[0]} {"
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_while_loop
|
31
|
+
"while let Some(#{@instruction.inputs[0]}) = OPTION_#{@instruction.inputs[0]} {"
|
32
|
+
end
|
33
|
+
|
34
|
+
def handle_conditional_else_if_jump
|
35
|
+
"else if #{@instruction.inputs[0]} {"
|
21
36
|
end
|
22
37
|
|
23
38
|
def handle_unconditional_jump
|
24
|
-
|
39
|
+
if @instruction.scope.to_i < @instruction.inputs[0].to_i
|
40
|
+
'else {'
|
41
|
+
else
|
42
|
+
'}'
|
43
|
+
end
|
25
44
|
end
|
26
45
|
end
|
27
46
|
end
|
data/lib/instruction/multiply.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class handles the add instruction.
|
6
6
|
class Multiply < Handler
|
7
|
-
def
|
8
|
-
|
7
|
+
def initialize(instruction, metadata)
|
8
|
+
super('&', instruction, metadata)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
data/lib/instruction/or.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class handles the or instruction.
|
6
6
|
class Or < Handler
|
@@ -10,9 +10,7 @@ module DTRToRust
|
|
10
10
|
|
11
11
|
assignment_rust = "let #{assignment} = "
|
12
12
|
body_rust = "#{inputs[0]} || #{inputs[1]};"
|
13
|
-
|
14
|
-
|
15
|
-
form_rust_string(rust_string)
|
13
|
+
"#{assignment.nil? ? '' : assignment_rust}#{body_rust}"
|
16
14
|
end
|
17
15
|
end
|
18
16
|
end
|
data/lib/instruction/print.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class is responsible for generating Rust code for the LogString instruction.
|
6
6
|
class Print < Handler
|
7
7
|
def handle
|
8
|
-
|
8
|
+
"log!(#{inputs_to_rust_string(@instruction.inputs)});"
|
9
9
|
end
|
10
10
|
|
11
11
|
private
|
@@ -15,13 +15,14 @@ module DTRToRust
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def ref_appender(input)
|
18
|
-
|
18
|
+
input
|
19
|
+
# decorated_input = Common::InputInterpreter.interpret(input)
|
19
20
|
|
20
|
-
if decorated_input[:needs_reference] && decorated_input[:value] == 'env'
|
21
|
-
|
22
|
-
else
|
23
|
-
|
24
|
-
end
|
21
|
+
# if decorated_input[:needs_reference] && decorated_input[:value] == 'env'
|
22
|
+
# "&#{decorated_input[:value]}"
|
23
|
+
# else
|
24
|
+
# decorated_input[:value]
|
25
|
+
# end
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
data/lib/instruction/return.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class is responsible for generating Rust code for the Return instruction.
|
6
6
|
class Return < Handler
|
7
7
|
def handle
|
8
|
-
|
8
|
+
"return #{@instruction.inputs[0]};"
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
data/lib/instruction/subtract.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class handles the add instruction.
|
6
6
|
class Subtract < Handler
|
7
|
-
def
|
8
|
-
|
9
|
-
form_rust_string("#{@instruction.assign} = #{@instruction.inputs[0]} - #{@instruction.inputs[1]};")
|
7
|
+
def initialize(instruction, metadata)
|
8
|
+
super('-', instruction, metadata)
|
10
9
|
end
|
11
10
|
end
|
12
11
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
4
4
|
module Instruction
|
5
5
|
# This class handles the goto instruction.
|
6
|
-
class
|
6
|
+
class TryAssign < Handler
|
7
7
|
def handle
|
8
|
-
|
8
|
+
"let #{@instruction.inputs[0]} = #{@instruction.inputs[1]}.try_into();"
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
data/lib/instruction_handler.rb
CHANGED
@@ -1,14 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module SorobanRustBackend
|
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, metadata)
|
7
7
|
@instruction = instruction
|
8
|
-
@
|
9
|
-
@function_names = function_names
|
10
|
-
@user_defined_types = user_defined_types
|
11
|
-
@is_helper = is_helper
|
8
|
+
@metadata = metadata
|
12
9
|
end
|
13
10
|
|
14
11
|
def generate_rust
|
@@ -16,20 +13,18 @@ module DTRToRust
|
|
16
13
|
raise "Unknown instruction type: #{@instruction.instruction}"
|
17
14
|
end
|
18
15
|
|
19
|
-
EXPRESSION_FOOBAR[@instruction.instruction.strip].send(:handle, @instruction, @
|
20
|
-
@user_defined_types, @is_helper)
|
16
|
+
EXPRESSION_FOOBAR[@instruction.instruction.strip].send(:handle, @instruction, @metadata)
|
21
17
|
end
|
22
18
|
|
23
19
|
private
|
24
20
|
|
25
21
|
EXPRESSION_FOOBAR = {
|
26
22
|
'assign' => Instruction::Assign,
|
23
|
+
'break' => Instruction::Break,
|
27
24
|
'jump' => Instruction::Jump,
|
28
|
-
'goto' => Instruction::Goto,
|
29
25
|
'exit_with_message' => Instruction::ExitWithMessage,
|
30
26
|
'and' => Instruction::And,
|
31
27
|
'or' => Instruction::Or,
|
32
|
-
'label' => Instruction::Label,
|
33
28
|
'add' => Instruction::Add,
|
34
29
|
'subtract' => Instruction::Subtract,
|
35
30
|
'multiply' => Instruction::Multiply,
|
@@ -40,7 +35,8 @@ module DTRToRust
|
|
40
35
|
'evaluate' => Instruction::Evaluate,
|
41
36
|
'field' => Instruction::Field,
|
42
37
|
'end_of_iteration_check' => Instruction::EndOfIterationCheck,
|
43
|
-
'increment' => Instruction::Increment
|
38
|
+
'increment' => Instruction::Increment,
|
39
|
+
'try_assign' => Instruction::TryAssign
|
44
40
|
}.freeze
|
45
41
|
|
46
42
|
def handle_empty_instruction
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SorobanRustBackend
|
4
|
+
class LCPBT_Forrest
|
5
|
+
attr_accessor :trees
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@trees = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_tree(tree)
|
12
|
+
@trees << tree
|
13
|
+
end
|
14
|
+
|
15
|
+
def traverse
|
16
|
+
@trees.map(&:traverse)
|
17
|
+
end
|
18
|
+
|
19
|
+
def traverse_with_indentation
|
20
|
+
@trees.compact.map(&:traverse_with_indentation)
|
21
|
+
end
|
22
|
+
|
23
|
+
# This represents a traversal through a unique path, covering all trees in the forest
|
24
|
+
# only once. This is useful for code generation.
|
25
|
+
def traverse_to_ids
|
26
|
+
id_map = {}
|
27
|
+
result = []
|
28
|
+
|
29
|
+
traverse
|
30
|
+
.map { |x| x.map(&:id) }
|
31
|
+
.each do |x|
|
32
|
+
sub_result = []
|
33
|
+
x.each do |y|
|
34
|
+
next if id_map[y]
|
35
|
+
|
36
|
+
sub_result << y
|
37
|
+
id_map[y] = true
|
38
|
+
end
|
39
|
+
result << sub_result
|
40
|
+
end
|
41
|
+
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
def code_generator_traverse(&block)
|
46
|
+
traverse_with_indentation
|
47
|
+
.map { |tree| tree.reverse.uniq.reverse.map(&block) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def size
|
51
|
+
@trees.size
|
52
|
+
end
|
53
|
+
|
54
|
+
def all_paths_to(instruction_id)
|
55
|
+
@trees.map { |x| x.all_paths_to(instruction_id) }.flatten(1).compact
|
56
|
+
end
|
57
|
+
|
58
|
+
def walk_it
|
59
|
+
@trees.each do |x|
|
60
|
+
puts "Walking tree #{x.tree_id}"
|
61
|
+
|
62
|
+
stack = []
|
63
|
+
symbol_table = {}
|
64
|
+
|
65
|
+
stack << x
|
66
|
+
|
67
|
+
while stack.any?
|
68
|
+
current = stack.pop
|
69
|
+
|
70
|
+
if current.value.assign
|
71
|
+
symbol_table[current.value.assign] = {
|
72
|
+
value: current.value.id
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
stack << current.left_child if current.left_child
|
77
|
+
|
78
|
+
stack << current.right_child if current.right_child
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module SorobanRustBackend
|
6
|
+
class LeftChildPreferentialBinaryTree
|
7
|
+
attr_accessor :value, :left_child, :right_child, :tree_id, :metadata
|
8
|
+
|
9
|
+
def initialize(value, metadata:, indentation: 0)
|
10
|
+
@tree_id = SecureRandom.uuid
|
11
|
+
@indentation = indentation
|
12
|
+
@value = value
|
13
|
+
@left_child = nil
|
14
|
+
@right_child = nil
|
15
|
+
@metadata = metadata
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_left_child(node)
|
19
|
+
raise 'Left child already exists' if @left_child
|
20
|
+
|
21
|
+
@left_child = node
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_right_child(node)
|
25
|
+
raise 'Right child already exists' if @right_child
|
26
|
+
|
27
|
+
@right_child = node
|
28
|
+
end
|
29
|
+
|
30
|
+
def traverse
|
31
|
+
result = []
|
32
|
+
result << @value
|
33
|
+
result += @left_child.traverse if @left_child
|
34
|
+
result += @right_child.traverse if @right_child
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
def traverse_with_indentation
|
39
|
+
result = []
|
40
|
+
result << [@value, @indentation, @metadata]
|
41
|
+
result += @left_child.traverse_with_indentation if @left_child
|
42
|
+
result += @right_child.traverse_with_indentation if @right_child
|
43
|
+
result
|
44
|
+
end
|
45
|
+
|
46
|
+
def all_paths_to(instruction_id, cur_result: [])
|
47
|
+
if value.id == instruction_id
|
48
|
+
return cur_result.empty? ? [[instruction_id]] : cur_result + [instruction_id]
|
49
|
+
end
|
50
|
+
|
51
|
+
result = nil
|
52
|
+
|
53
|
+
if @left_child
|
54
|
+
left_child_traverse = @left_child.all_paths_to(instruction_id, cur_result: cur_result + [value.id])
|
55
|
+
result = left_child_traverse unless left_child_traverse.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
if @right_child
|
59
|
+
right_child_traverse = @right_child.all_paths_to(instruction_id, cur_result: cur_result + [value.id])
|
60
|
+
result = result.nil? ? right_child_traverse : [result, right_child_traverse]
|
61
|
+
end
|
62
|
+
|
63
|
+
result
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SorobanRustBackend
|
2
|
+
module NonTranslatables
|
3
|
+
class Handler
|
4
|
+
def initialize(non_translatables)
|
5
|
+
@non_translatables = non_translatables
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.generate(non_translatables)
|
9
|
+
new(non_translatables).generate
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate
|
13
|
+
generate_non_translatables
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def generate_non_translatables
|
19
|
+
@non_translatables
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SorobanRustBackend
|
4
|
+
class Silviculturist
|
5
|
+
attr_accessor :forrest
|
6
|
+
|
7
|
+
def initialize(instructions, base_indentation: 0)
|
8
|
+
@instructions = instructions
|
9
|
+
@forrest = LCPBT_Forrest.new
|
10
|
+
@seen_instructions = {}
|
11
|
+
@base_indentation = base_indentation
|
12
|
+
end
|
13
|
+
|
14
|
+
def make_forrest
|
15
|
+
index = 0
|
16
|
+
while index < @instructions.size
|
17
|
+
instructions = @instructions[index..]
|
18
|
+
scope = 0
|
19
|
+
tree = plant_trees(scope, instructions, metadata: { last_node_was_conditional_jump: false, parent_scope: nil, symbol_table: {} },
|
20
|
+
indentation: @base_indentation)
|
21
|
+
@forrest.add_tree(tree)
|
22
|
+
|
23
|
+
seen = true
|
24
|
+
while seen && index < @instructions.size
|
25
|
+
index += 1
|
26
|
+
seen = @instructions[index].nil? || @seen_instructions[@instructions[index].id]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def plant_trees(scope, instructions, metadata:, from_id: nil, indentation: 0)
|
32
|
+
cur_instruction = instructions[0]
|
33
|
+
|
34
|
+
return nil if cur_instruction.nil?
|
35
|
+
|
36
|
+
if cur_instruction.scope != scope
|
37
|
+
return plant_trees(scope, instructions[1..], from_id: cur_instruction.id,
|
38
|
+
indentation:, metadata:)
|
39
|
+
end
|
40
|
+
|
41
|
+
return @seen_instructions[cur_instruction.id] if @seen_instructions[cur_instruction.id]
|
42
|
+
|
43
|
+
down_jump = cur_instruction.instruction == 'jump' && (
|
44
|
+
(cur_instruction.inputs.size == 1 && cur_instruction.inputs[0].to_i < scope) ||
|
45
|
+
(cur_instruction.inputs.size == 2 && cur_instruction.inputs[1].to_i < scope))
|
46
|
+
|
47
|
+
rest_of_instructions = instructions[1..]
|
48
|
+
|
49
|
+
tree = LeftChildPreferentialBinaryTree.new(cur_instruction,
|
50
|
+
indentation: if down_jump
|
51
|
+
indentation - 1
|
52
|
+
else
|
53
|
+
indentation
|
54
|
+
end, metadata:)
|
55
|
+
@seen_instructions[cur_instruction.id] = tree
|
56
|
+
|
57
|
+
case cur_instruction.instruction
|
58
|
+
when 'jump'
|
59
|
+
case cur_instruction.inputs.filter { |x| x.to_s.strip != 'ELSE_IF_BRANCH' }.size
|
60
|
+
# unconditional jump
|
61
|
+
when 1
|
62
|
+
new_scope = cur_instruction.inputs[0].to_i
|
63
|
+
|
64
|
+
# halt when going back to 0
|
65
|
+
return tree if new_scope.zero?
|
66
|
+
|
67
|
+
tree.set_left_child(plant_trees(new_scope, rest_of_instructions, from_id: cur_instruction.id,
|
68
|
+
indentation: down_jump ? indentation - 1 : indentation + 1, metadata: { last_node_was_conditional_jump: true, parent_scope: scope, symbol_table: metadata[:symbol_table] }))
|
69
|
+
# conditional jump
|
70
|
+
when 2
|
71
|
+
# detour
|
72
|
+
new_scope = cur_instruction.inputs[1].to_i
|
73
|
+
|
74
|
+
tree.set_left_child(plant_trees(new_scope, rest_of_instructions,
|
75
|
+
from_id: cur_instruction.id, indentation: down_jump ? indentation - 1 : indentation + 1, metadata: { last_node_was_conditional_jump: true, parent_scope: scope, symbol_table: metadata[:symbol_table] }))
|
76
|
+
# continue
|
77
|
+
tree.set_right_child(plant_trees(scope, rest_of_instructions, from_id: cur_instruction.id,
|
78
|
+
indentation:, metadata: { last_node_was_conditional_jump: true, parent_scope: scope, symbol_table: metadata[:symbol_table] }))
|
79
|
+
# if-let
|
80
|
+
when 3
|
81
|
+
raise 'We do not yet support if-let statements'
|
82
|
+
end
|
83
|
+
# the way a goto works is that you want to drop out of the loop back to the scope you were at
|
84
|
+
# when you started the loop
|
85
|
+
when 'goto'
|
86
|
+
goto_target_id = cur_instruction.inputs[0].to_i
|
87
|
+
return_scope = @instructions.find { |x| x.id == goto_target_id }.scope
|
88
|
+
|
89
|
+
tree.metadata[:return_scope] = return_scope
|
90
|
+
|
91
|
+
return tree if return_scope.zero?
|
92
|
+
|
93
|
+
# TODO: fix indentation
|
94
|
+
tree.set_left_child(plant_trees(return_scope.to_i, rest_of_instructions, from_id: cur_instruction.id,
|
95
|
+
indentation:, metadata: {
|
96
|
+
last_node_was_conditional_jump: false,
|
97
|
+
parent_scope: scope,
|
98
|
+
symbol_table: metadata[:symbol_table]
|
99
|
+
}))
|
100
|
+
|
101
|
+
when 'try_assign'
|
102
|
+
metadata = {
|
103
|
+
last_node_was_conditional_jump: false,
|
104
|
+
parent_scope: scope,
|
105
|
+
try_assign: {
|
106
|
+
lhs: cur_instruction.inputs[1],
|
107
|
+
rhs: cur_instruction.inputs[0],
|
108
|
+
assign: cur_instruction.assign
|
109
|
+
},
|
110
|
+
symbol_table: metadata[:symbol_table]
|
111
|
+
}
|
112
|
+
|
113
|
+
return plant_trees(scope, rest_of_instructions, from_id: cur_instruction.id,
|
114
|
+
indentation:, metadata:)
|
115
|
+
when 'end_of_iteration_check'
|
116
|
+
metadata = {
|
117
|
+
last_node_was_conditional_jump: false,
|
118
|
+
parent_scope: scope,
|
119
|
+
try_assign: nil,
|
120
|
+
end_of_iteration_check: {
|
121
|
+
lhs: cur_instruction.inputs[0],
|
122
|
+
rhs: cur_instruction.inputs[1],
|
123
|
+
assign: cur_instruction.assign
|
124
|
+
},
|
125
|
+
symbol_table: metadata[:symbol_table]
|
126
|
+
}
|
127
|
+
|
128
|
+
return plant_trees(scope, rest_of_instructions, from_id: cur_instruction.id, indentation:, metadata:)
|
129
|
+
else
|
130
|
+
last_symbol_table = metadata[:symbol_table]
|
131
|
+
last_symbol_table[cur_instruction.assign] = {} unless last_symbol_table.include?(cur_instruction.assign)
|
132
|
+
last_symbol_table[cur_instruction.assign][cur_instruction.scope] = cur_instruction
|
133
|
+
|
134
|
+
metadata = {
|
135
|
+
last_node_was_conditional_jump: false,
|
136
|
+
parent_scope: scope,
|
137
|
+
try_assign: nil,
|
138
|
+
symbol_table: last_symbol_table
|
139
|
+
}
|
140
|
+
|
141
|
+
# left_child
|
142
|
+
tree.set_left_child(plant_trees(scope, rest_of_instructions, from_id: cur_instruction.id,
|
143
|
+
indentation:, metadata:))
|
144
|
+
end
|
145
|
+
|
146
|
+
tree
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This is the main module for the DTR to Rust gem.
|
4
|
+
module SorobanRustBackend
|
5
|
+
autoload :LCPBT_Forrest, 'lcpbt_forrest'
|
6
|
+
autoload :LeftChildPreferentialBinaryTree, 'left_child_preferential_binary_tree'
|
7
|
+
autoload :Silviculturist, 'silviculturist'
|
8
|
+
autoload :CodeGenerator, 'code_generator'
|
9
|
+
autoload :Condenser, 'condenser'
|
10
|
+
autoload :InstructionHandler, 'instruction_handler'
|
11
|
+
autoload :UserDefinedTypesHandler, 'user_defined_types_handler'
|
12
|
+
autoload :FunctionHandler, 'function_handler'
|
13
|
+
autoload :ContractHandler, 'contract_handler'
|
14
|
+
|
15
|
+
# This module contains all the classes that handle the different types of instructions.
|
16
|
+
module Instruction
|
17
|
+
autoload :Evaluate, './lib/instruction/evaluate'
|
18
|
+
autoload :Field, './lib/instruction/field'
|
19
|
+
autoload :Handler, './lib/instruction/handler'
|
20
|
+
autoload :Print, './lib/instruction/print'
|
21
|
+
autoload :Return, './lib/instruction/return'
|
22
|
+
autoload :InstantiateObject, './lib/instruction/instantiate_object'
|
23
|
+
autoload :Add, './lib/instruction/add'
|
24
|
+
autoload :Subtract, './lib/instruction/subtract'
|
25
|
+
autoload :Multiply, './lib/instruction/multiply'
|
26
|
+
autoload :Divide, './lib/instruction/divide'
|
27
|
+
autoload :Assign, './lib/instruction/assign'
|
28
|
+
autoload :Jump, './lib/instruction/jump'
|
29
|
+
autoload :Goto, './lib/instruction/goto'
|
30
|
+
autoload :ExitWithMessage, './lib/instruction/exit_with_message'
|
31
|
+
autoload :And, './lib/instruction/and'
|
32
|
+
autoload :Or, './lib/instruction/or'
|
33
|
+
autoload :EndOfIterationCheck, './lib/instruction/end_of_iteration_check'
|
34
|
+
autoload :Increment, './lib/instruction/increment'
|
35
|
+
autoload :TryAssign, './lib/instruction/try_assign'
|
36
|
+
autoload :Break, './lib/instruction/break'
|
37
|
+
autoload :BinaryInstruction, './lib/instruction/binary_instruction'
|
38
|
+
end
|
39
|
+
|
40
|
+
module Common
|
41
|
+
autoload :TypeTranslator, './lib/common/type_translator'
|
42
|
+
end
|
43
|
+
|
44
|
+
module NonTranslatables
|
45
|
+
autoload :Handler, './lib/non_translatables/handler'
|
46
|
+
end
|
47
|
+
|
48
|
+
module ContractState
|
49
|
+
autoload :Handler, './lib/contract_state/handler'
|
50
|
+
end
|
51
|
+
end
|