dtr_core 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6c7633c61c5ed0d1268fb63d2b9245037292c352e850c819e5017fab420c8044
4
+ data.tar.gz: 7a0dcefa916e3daecefa505c8556e75fe5047e39836a31fe893affa043745f02
5
+ SHA512:
6
+ metadata.gz: a2de4799a22ec515c6a23ee27e09735f6cd7043832dc3ab79b108ea68c802ddc0ae721ca78c72384712796302a2df55aee0b529c12439430b1ceaf948ee6ad79
7
+ data.tar.gz: 0b379f38905d1d28ea6d4dc8044622b7598383d1ee3bf627fa70f9c6d25d019506b8ab269bc99561c71bd6548afa969e3ec18621af19372bf4f441c2677b2fcd
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRCore
4
+ # Common methods used by the DTRCore module.
5
+ module Common
6
+ def strip_and_remove_quotes(str)
7
+ str.strip.gsub(/['"]/, '')
8
+ end
9
+
10
+ def split_strip_select(some_list)
11
+ some_list&.split("\n")&.map { |x| x&.strip }&.select { |x| x.length.positive? }
12
+ end
13
+
14
+ def first_match_for_content(patterm)
15
+ content.match(patterm)&.captures&.first
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRCore
4
+ # Represents a contract in a DTR file.
5
+ class Contract
6
+ attr_reader :functions, :name, :state
7
+
8
+ def initialize(name, state, functions)
9
+ @name = name
10
+ @state = state
11
+ @functions = functions
12
+ end
13
+
14
+ def ==(other)
15
+ name == other.name &&
16
+ state == other.state &&
17
+ functions == other.functions
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRCore
4
+ # Represents a state in a DTR file.
5
+ class Function
6
+ attr_reader :name, :inputs, :output, :instructions
7
+
8
+ def initialize(name, inputs, output, instructions)
9
+ @name = name
10
+ @inputs = inputs
11
+ @output = output
12
+ @instructions = instructions
13
+ end
14
+
15
+ def ==(other)
16
+ name == other.name &&
17
+ inputs == other.inputs &&
18
+ output == other.output &&
19
+ instructions == other.instructions
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRCore
4
+ module Number
5
+ MIN_U32 = 0
6
+ MAX_U32 = (2**32) - 1
7
+
8
+ MIN_U64 = 0
9
+ MAX_U64 = (2**64) - 1
10
+
11
+ MIN_U256 = 0
12
+ MAX_U256 = (2**256) - 1
13
+
14
+ MIN_I32 = -2**31
15
+ MAX_I32 = (2**31) - 1
16
+
17
+ MIN_I64 = -2**63
18
+ MAX_I64 = (2**63) - 1
19
+
20
+ MIN_I256 = -2**255
21
+ MAX_I256 = (2**255) - 1
22
+ end
23
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dtr_core/common'
4
+
5
+ module DTRCore
6
+ # Parses a DTR file and returns a Contract object.
7
+ class Parser
8
+ include ::DTRCore::Common
9
+
10
+ def initialize(file_path)
11
+ raise "Unable to find file: #{file_path}." unless File.exist?(file_path)
12
+
13
+ @content = File.read(file_path)
14
+ end
15
+
16
+ def self.parse(file_path)
17
+ new(file_path).parse
18
+ end
19
+
20
+ def parse
21
+ DTRCore::Contract.new(parse_contract_name_section, parse_state_section, parse_function_section)
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :content
27
+ attr_accessor :sections
28
+
29
+ def parse_contract_name_section
30
+ contract_name_section = first_match_for_content(/\[Contract\]:\s*(.+)/)
31
+
32
+ raise 'Missing contract name.' if contract_name_section.nil?
33
+
34
+ contract_name_section
35
+ end
36
+
37
+ def parse_state_section
38
+ state_section = first_match_for_content(/\[State\]:\s*((?:\s*\*\s*\[.+?\]\n(?:\s* \* .+\n?)*)*)/)
39
+
40
+ return nil if state_section.nil?
41
+
42
+ state_definitions = state_section
43
+ .split(/\n\s*\*\s*\[/).map { |x| "[#{x.strip}" }
44
+ .map { |definition| state_definition_to_state_object(definition) }
45
+
46
+ raise 'Empty state section.' if state_definitions.empty?
47
+
48
+ state_definitions
49
+ end
50
+
51
+ def clean_state_definition_name(definition)
52
+ definition.gsub(/[\*\n\[]/, '').strip
53
+ end
54
+
55
+ def state_definition_to_state_object(definition)
56
+ name = clean_state_definition_name definition[/^\[([^\]]+)\]/, 1]
57
+
58
+ type = definition[/Type:\s*(\w+)/, 1]
59
+
60
+ initial_value = DTRCore::TypeValidator.new(type, definition[/Initial Value:\s*(.+)/, 1])
61
+ .validate_then_coerce_initial_value!
62
+
63
+ DTRCore::State.new(name, type, initial_value)
64
+ end
65
+
66
+ def parse_function_section
67
+ function_section = first_match_for_content(/\[Functions\]:(?<all>.*):\[Functions\]/m)
68
+
69
+ return nil if function_section.nil?
70
+
71
+ function_definitions = parse_parse_function_section(function_section)
72
+
73
+ raise 'Empty function section.' if function_definitions.empty?
74
+
75
+ function_definitions
76
+ end
77
+
78
+ def parse_parse_function_section(function_section)
79
+ function_section.split('-()')
80
+ .map { |x| function_definition_to_function_object(x.strip.to_s) }
81
+ .reject { |x| x.name.nil? }
82
+ end
83
+
84
+ def function_definition_to_function_object(definition)
85
+ name = definition[/\s*\[(?<all>[^\]]+)]/, 1]
86
+ inputs = format_function_inputs(definition[/Inputs\s*:\s*{\s*(?<inputs>[^}]+)\s*}/, 1])
87
+ # TODO: check output type
88
+ output = definition[/Output:\s*(.+)/, 1]
89
+ instructions = format_function_instruction(definition[/Instructions:\s*\$(?<inputs>[^\$]+)\$/, 1])
90
+
91
+ DTRCore::Function.new(name, inputs, output, instructions)
92
+ end
93
+
94
+ def format_function_inputs(inputs)
95
+ return [] if inputs.nil?
96
+
97
+ split_strip_select(inputs).map { |x| { name: x.split(':')[0].strip, type_name: x.split(':')[1].strip } }
98
+ end
99
+
100
+ def format_function_instruction(instructions)
101
+ split_strip_select(instructions)&.map { |instruction| parse_function_instruction(instruction) }
102
+ end
103
+
104
+ def parse_function_instruction(instruction)
105
+ {
106
+ instruction: instruction[/instruction:\s*(?<all>[^\s,]+)/, 1],
107
+ inputs: parse_function_instruction_input(instruction),
108
+ assign: instruction[/\s*assign:\s*(?<all>[^\s\,]+)/, 1]
109
+ }
110
+ end
111
+
112
+ def parse_function_instruction_input(definition)
113
+ definition[/\s*input:\s*\((?<all>[^\)]+)\)/, 1]
114
+ &.split(',')&.map(&:strip)
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DTRCore
4
+ # Represents a state in a DTR file.
5
+ class State
6
+ attr_reader :name, :type, :initial_value
7
+
8
+ def initialize(name, type, initial_value)
9
+ @name = name
10
+ @type = type
11
+ @initial_value = initial_value
12
+ end
13
+
14
+ def ==(other)
15
+ name == other.name &&
16
+ type == other.type &&
17
+ initial_value == other.initial_value
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dtr_core/common'
4
+
5
+ module DTRCore
6
+ # Type validator for DTR types.
7
+ class TypeValidator
8
+ include ::DTRCore::Common
9
+
10
+ def initialize(type_name, initial_value)
11
+ @type_name = type_name
12
+ @initial_value = initial_value
13
+ end
14
+
15
+ def validate_then_coerce_initial_value!
16
+ raise 'Missing Type Name.' if @type_name.nil?
17
+ raise 'Missing Initial Value.' if @initial_value.nil?
18
+
19
+ case @type_name
20
+ when 'I32', 'I64', 'I256', 'U32', 'U64', 'U256'
21
+ validate_numeric!
22
+
23
+ # TODO: check type
24
+ when 'Symbol'
25
+ strip_and_remove_quotes(@initial_value)
26
+ else
27
+ raise 'Missing Invalid Type Name.'
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def validate_numeric!
34
+ raise 'Invalid initial value for type. Wrong type.' unless @initial_value =~ (/^[\-\.\d]\d*(\.?\d*)*/)
35
+
36
+ raise "Invalid initial value for type #{@type_name}. Out of range." unless @initial_value.to_i.between?(
37
+ DTRCore::Number.const_get(:"MIN_#{@type_name}"), DTRCore::Number.const_get(:"MAX_#{@type_name}")
38
+ )
39
+
40
+ @initial_value.to_i
41
+ end
42
+ end
43
+ end
data/lib/dtr_core.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Core logic for consuming Digicus Textual Representation (DTR) files.
4
+ module DTRCore
5
+ autoload :Contract, 'dtr_core/contract'
6
+ autoload :Function, 'dtr_core/function'
7
+ autoload :Number, 'dtr_core/number'
8
+ autoload :Parser, 'dtr_core/parser'
9
+ autoload :State, 'dtr_core/state'
10
+ autoload :TypeValidator, 'dtr_core/type_validator'
11
+
12
+ VERSION = '0.1.0'
13
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dtr_core
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Rob Durst
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-04-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A longer description of my_gem
14
+ email:
15
+ - me@robdurst.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/dtr_core.rb
21
+ - lib/dtr_core/common.rb
22
+ - lib/dtr_core/contract.rb
23
+ - lib/dtr_core/function.rb
24
+ - lib/dtr_core/number.rb
25
+ - lib/dtr_core/parser.rb
26
+ - lib/dtr_core/state.rb
27
+ - lib/dtr_core/type_validator.rb
28
+ homepage:
29
+ licenses:
30
+ - MIT
31
+ metadata:
32
+ rubygems_mfa_required: 'true'
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 3.2.0
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubygems_version: 3.4.10
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: A short summary of my_gem
52
+ test_files: []