dtr_core 0.9.0 → 0.11.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: b6eb9933172ea48536b0efceffe9e9e222a54e37f214b8041dc5edd40c01f2d6
4
- data.tar.gz: 731d58a093c47bfd2b63f4ea884d4422d703b2c2ba47baacbda105bfb02e2264
3
+ metadata.gz: ec65bed75c4955e0c231146f532fd7d1c35ed2e7617966681dce5718076ba0be
4
+ data.tar.gz: a192a2cc58e2b4dbdd6bae900751675236d1532fc869676badc0b79a043a33e7
5
5
  SHA512:
6
- metadata.gz: '04824f70c5646161afb24637f614f1ba2431414cc5f98b8847b15f74299ba563957586ba40a88d36847d1cfce649462199a42508a0d276397dbe3f38d1ee7e59'
7
- data.tar.gz: 106a92f8de4ca9385d44f510dbb942b05d073bd2584d7dabbfe7d3003d348a121c21765da246e2c450a25df92cfb5151d1b541cf5b28029d96acd6ff1875c423
6
+ metadata.gz: 703ec3bd6c1ffd80d0f872bd13351467819daa7dfd42737c33f90402fd66f11026e1d902e4e186449cdd913d4ee2db8489ccdb4b7afcb691f43c7c4cb4c2156e
7
+ data.tar.gz: 5a7fc13e8418ea5917ffa8aa70855922f920750e8b9ee6bde1b0d910daecbb567cf058ce3b819f2cdae4fff8ecd41858a89936c207693456e46b17a7db404386
@@ -55,31 +55,31 @@ module DTRCore
55
55
  end
56
56
 
57
57
  def state_to_s
58
- return '' if @state.nil?
58
+ return '' if @state.nil? || @state.empty?
59
59
 
60
60
  "[State]:\n#{@state&.map(&:to_s)&.join("\n")}\n:[State]\n"
61
61
  end
62
62
 
63
63
  def interface_to_s
64
- return '' if @state.nil?
64
+ return '' if @interface.nil? || @interface.empty?
65
65
 
66
66
  "[Interface]:\n#{@interface&.map(&:to_s)&.join("\n")}\n:[Interface]\n"
67
67
  end
68
68
 
69
69
  def user_defined_types_to_s
70
- return '' if @user_defined_types.nil?
70
+ return '' if @user_defined_types.nil? || @user_defined_types.empty?
71
71
 
72
72
  "[User Defined Types]:\n#{@user_defined_types&.map(&:to_s)&.join("\n")}\n:[User Defined Types]\n"
73
73
  end
74
74
 
75
75
  def helpers_to_s
76
- return '' if @helpers.nil?
76
+ return '' if @helpers.nil? || @helpers.empty?
77
77
 
78
78
  "[Helpers]:\n#{@helpers&.map(&:to_s)&.join("\n")}\n:[Helpers]\n"
79
79
  end
80
80
 
81
81
  def non_translatables_to_s
82
- return '' if @non_translatables.nil?
82
+ return '' if @non_translatables.nil? || @non_translatables.empty?
83
83
 
84
84
  "[NonTranslatable]:\n#{@non_translatables}\n:[NonTranslatable]"
85
85
  end
@@ -98,7 +98,8 @@ module DTRCore
98
98
  instruction[/instruction:\s*(?<all>[^\s,]+)/, 1],
99
99
  parse_function_instruction_input(instruction),
100
100
  instruction[/\s*assign:\s*\[?(?<all>[^\s\,\]]+)\]?/, 1],
101
- instruction[/\s*scope:\s*(?<all>[^\s\,]+)/, 1].to_i || 0
101
+ instruction[/\s*scope:\s*(?<all>[^\s\,]+)/, 1].to_i || 0,
102
+ instruction[/\sid:\s*(?<all>[^\s,]+)/, 1].to_i || 0
102
103
  )
103
104
 
104
105
  raise "Invalid instruction: #{instruction}" unless instruction.valid?
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRCore
4
+ module Graph
5
+ class LCPBT_Forrest
6
+ attr_accessor :trees
7
+
8
+ def initialize
9
+ @trees = []
10
+ end
11
+
12
+ def add_tree(tree)
13
+ @trees << tree
14
+ end
15
+
16
+ def traverse
17
+ @trees.map(&:traverse)
18
+ end
19
+
20
+ def traverse_with_indentation
21
+ @trees.map(&:traverse_with_indentation)
22
+ end
23
+
24
+ # This represents a traversal through a unique path, covering all trees in the forest
25
+ # only once. This is useful for code generation.
26
+ def traverse_to_ids
27
+ id_map = {}
28
+ result = []
29
+
30
+ traverse
31
+ .map { |x| x.map(&:id) }
32
+ .each do |x|
33
+ sub_result = []
34
+ x.each do |y|
35
+ next if id_map[y]
36
+
37
+ sub_result << y
38
+ id_map[y] = true
39
+ end
40
+ result << sub_result
41
+ end
42
+
43
+ result
44
+ end
45
+
46
+ def code_generator_traverse(&block)
47
+ traverse_with_indentation
48
+ .map { |tree| tree.reverse.uniq.reverse.map(&block) }
49
+ end
50
+
51
+ def size
52
+ @trees.size
53
+ end
54
+
55
+ def all_paths_to(instruction_id)
56
+ @trees.map { |x| x.all_paths_to(instruction_id) }.flatten(1).compact
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module DTRCore
6
+ module Graph
7
+ class LeftChildPreferentialBinaryTree
8
+ attr_accessor :value, :left_child, :right_child, :tree_id
9
+
10
+ def initialize(value, indentation: 0)
11
+ @tree_id = SecureRandom.uuid
12
+ @indentation = indentation
13
+ @value = value
14
+ @left_child = nil
15
+ @right_child = nil
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]
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
67
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRCore
4
+ module Graph
5
+ class Silviculturist
6
+ attr_accessor :forrest
7
+
8
+ def initialize(instructions)
9
+ @instructions = instructions
10
+ @forrest = LCPBT_Forrest.new
11
+ @seen_instructions = {}
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)
20
+ @forrest.add_tree(tree)
21
+
22
+ seen = true
23
+ while seen && index < @instructions.size
24
+ index += 1
25
+ seen = @instructions[index].nil? || @seen_instructions[@instructions[index].id]
26
+ end
27
+ end
28
+ end
29
+
30
+ def plant_trees(scope, instructions, from_id: nil, indentation: 0)
31
+ cur_instruction = instructions[0]
32
+
33
+ return nil if cur_instruction.nil?
34
+
35
+ if cur_instruction.scope != scope
36
+ return plant_trees(scope, instructions[1..], from_id: cur_instruction.id,
37
+ indentation:)
38
+ end
39
+
40
+ return @seen_instructions[cur_instruction.id] if @seen_instructions[cur_instruction.id]
41
+
42
+ down_jump = cur_instruction.instruction == 'jump' && (
43
+ (cur_instruction.inputs.size == 1 && cur_instruction.inputs[0].to_i < scope) ||
44
+ (cur_instruction.inputs.size == 2 && cur_instruction.inputs[1].to_i < scope))
45
+
46
+ rest_of_instructions = instructions[1..]
47
+
48
+ tree = LeftChildPreferentialBinaryTree.new(cur_instruction,
49
+ indentation: if down_jump
50
+ indentation - 1
51
+ else
52
+ indentation
53
+ end)
54
+ @seen_instructions[cur_instruction.id] = tree
55
+
56
+ case cur_instruction.instruction
57
+ when 'jump'
58
+ case cur_instruction.inputs.size
59
+ # unconditional jump
60
+ when 1
61
+ new_scope = cur_instruction.inputs[0].to_i
62
+
63
+ # halt when going back to 0
64
+ return tree if new_scope.zero?
65
+
66
+ tree.set_left_child(plant_trees(new_scope, rest_of_instructions, from_id: cur_instruction.id,
67
+ indentation: down_jump ? indentation - 1 : indentation + 1))
68
+ # conditional jump
69
+ when 2
70
+ # detour
71
+ new_scope = cur_instruction.inputs[1].to_i
72
+
73
+ tree.set_left_child(plant_trees(new_scope, rest_of_instructions,
74
+ from_id: cur_instruction.id, indentation: down_jump ? indentation - 1 : indentation + 1))
75
+ # continue
76
+ tree.set_right_child(plant_trees(scope, rest_of_instructions, from_id: cur_instruction.id,
77
+ indentation:))
78
+ # if-let
79
+ when 3
80
+ raise 'We do not yet support if-let statements'
81
+ end
82
+ # the way a goto works is that you want to drop out of the loop back to the scope you were at
83
+ # when you started the loop
84
+ when 'goto'
85
+ goto_target_id = cur_instruction.inputs[0].to_i
86
+ return_scope = @instructions.find { |x| x.id == goto_target_id }.scope
87
+
88
+ return tree if return_scope.zero?
89
+
90
+ # TODO: fix indentation
91
+ tree.set_left_child(plant_trees(return_scope.to_i, rest_of_instructions, from_id: cur_instruction.id,
92
+ indentation:))
93
+ else
94
+ # left_child
95
+ tree.set_left_child(plant_trees(scope, rest_of_instructions, from_id: cur_instruction.id,
96
+ indentation:))
97
+ end
98
+
99
+ tree
100
+ end
101
+ end
102
+ end
103
+ end
@@ -3,26 +3,29 @@
3
3
  module DTRCore
4
4
  # Instruction class
5
5
  class Instruction
6
- attr_reader :instruction, :inputs, :assign, :scope
6
+ attr_reader :instruction, :inputs, :assign, :scope, :id
7
7
 
8
- def initialize(instruction, inputs, assign, scope)
8
+ def initialize(instruction, inputs, assign, scope, id)
9
9
  @instruction = instruction
10
10
  @inputs = inputs
11
11
  @assign = assign
12
12
  @scope = scope
13
+ @id = id
13
14
  end
14
15
 
15
16
  def ==(other)
16
17
  instruction == other.instruction &&
17
18
  inputs == other.inputs &&
18
19
  assign == other.assign &&
19
- scope == other.scope
20
+ scope == other.scope &&
21
+ id == other.id
20
22
  end
21
23
 
22
24
  def to_s
23
- "{ instruction: #{instruction}, " \
25
+ assignment = @assign.nil? ? '' : "assign: #{@assign}, "
26
+ "{ id: #{id}, instruction: #{instruction}, " \
24
27
  "input: (#{inputs&.join(', ')}), " \
25
- "assign: #{assign}, scope: #{scope} }"
28
+ "#{assignment}scope: #{scope} }"
26
29
  end
27
30
 
28
31
  def to_json(*_args)
@@ -30,7 +33,8 @@ module DTRCore
30
33
  instruction:,
31
34
  inputs:,
32
35
  assign:,
33
- scope:
36
+ scope:,
37
+ id:
34
38
  }.to_json
35
39
  end
36
40
 
data/lib/dtr_core.rb CHANGED
@@ -12,4 +12,11 @@ module DTRCore
12
12
  autoload :InstructionValidator, 'dtr_core/instruction_validator'
13
13
  autoload :Instruction, 'dtr_core/instruction'
14
14
  autoload :UserDefinedType, 'dtr_core/user_defined_type'
15
+
16
+ # A graph is a collection of nodes and edges representing the structure of a DTR file.
17
+ module Graph
18
+ autoload :LCPBT_Forrest, 'dtr_core/graph/lcpbt_forrest'
19
+ autoload :LeftChildPreferentialBinaryTree, 'dtr_core/graph/left_child_preferential_binary_tree'
20
+ autoload :Silviculturist, 'dtr_core/graph/silviculturist'
21
+ end
15
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dtr_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.11.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-07-07 00:00:00.000000000 Z
11
+ date: 2024-07-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Core smart contract intermediate language (Digicus Textual Representation)
14
14
  parser.
@@ -22,6 +22,9 @@ files:
22
22
  - lib/dtr_core/common.rb
23
23
  - lib/dtr_core/contract.rb
24
24
  - lib/dtr_core/function.rb
25
+ - lib/dtr_core/graph/lcpbt_forrest.rb
26
+ - lib/dtr_core/graph/left_child_preferential_binary_tree.rb
27
+ - lib/dtr_core/graph/silviculturist.rb
25
28
  - lib/dtr_core/instruction.rb
26
29
  - lib/dtr_core/instruction_validator.rb
27
30
  - lib/dtr_core/number.rb