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