tealrb 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/tealrb/abi.rb +4 -2
- data/lib/tealrb/contract.rb +123 -60
- data/lib/tealrb/opcode_modules.rb +22 -1
- data/lib/tealrb/rewriters.rb +32 -1
- data/lib/tealrb.rb +1 -0
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c937c416e2b2f337bdef2100c573862ed55a40e864d5a19f2cef3c737e823608
|
4
|
+
data.tar.gz: 0c09c2850d71f1392e0afc44943a62a0fed55153b6ef60b19700527639e43d84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 762827b72f11790427f51fd8021da4ef5ce2af3598b792b3b59b5ccf247fb1240cc9a0658482c09979167094a4337b9c93f27d025ae15ad603a32621c603123f
|
7
|
+
data.tar.gz: 135d42f56fdcd7520ca0677f4afb93e988b7151716fc534ba33682a0b51e1eee6ff5f0100b3ca14c2299948ab20fd9b338837e77289f2a62e6b1df8cd0c64f8d
|
data/lib/tealrb/abi.rb
CHANGED
data/lib/tealrb/contract.rb
CHANGED
@@ -11,8 +11,8 @@ module TEALrb
|
|
11
11
|
attr_reader :teal
|
12
12
|
|
13
13
|
class << self
|
14
|
-
attr_accessor :subroutines, :version, :teal_methods, :
|
15
|
-
:disable_abi_routing
|
14
|
+
attr_accessor :subroutines, :version, :teal_methods, :abi_interface, :debug,
|
15
|
+
:disable_abi_routing, :method_hashes
|
16
16
|
|
17
17
|
private
|
18
18
|
|
@@ -20,53 +20,47 @@ module TEALrb
|
|
20
20
|
klass.version = 6
|
21
21
|
klass.subroutines = {}
|
22
22
|
klass.teal_methods = {}
|
23
|
-
klass.
|
24
|
-
klass.
|
23
|
+
klass.abi_interface = ABI::ABIDescription.new
|
24
|
+
klass.abi_interface.name = klass.to_s
|
25
|
+
klass.method_hashes = []
|
25
26
|
klass.debug = false
|
26
27
|
klass.disable_abi_routing = false
|
28
|
+
parse(klass)
|
27
29
|
super
|
28
30
|
end
|
29
|
-
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
h[:type] = h[:type].to_s.split('::').last.downcase
|
36
|
-
h
|
37
|
-
end
|
32
|
+
def parse(klass)
|
33
|
+
YARD::Tags::Library.define_tag('ABI Method', :abi)
|
34
|
+
YARD::Tags::Library.define_tag('Subroutine', :subroutine)
|
35
|
+
YARD::Tags::Library.define_tag('TEAL Method', :teal)
|
38
36
|
|
39
|
-
|
40
|
-
end
|
37
|
+
YARD.parse Object.const_source_location(klass.to_s).first
|
41
38
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
# @param name [Symbol] name of the subroutine and the method to use as the subroutine definition
|
46
|
-
#
|
47
|
-
# @overload subroutine(name)
|
48
|
-
# @param name [Symbol] name of the subroutine
|
49
|
-
#
|
50
|
-
# @yield [*args] the definition of the subroutine
|
51
|
-
def self.subroutine(name, &blk)
|
52
|
-
@subroutines[name] = (blk || instance_method(name))
|
53
|
-
abi_description.add_method(**({ name: name.to_s }.merge abi_method_hash)) unless abi_method_hash.empty?
|
54
|
-
@abi_method_hash = {}
|
55
|
-
nil
|
56
|
-
end
|
39
|
+
YARD::Registry.all.each do |y|
|
40
|
+
next unless y.type == :method
|
41
|
+
next unless y.parent.to_s == klass.to_s
|
57
42
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
43
|
+
tags = y.tags.map(&:tag_name)
|
44
|
+
|
45
|
+
if tags.include?('abi') || tags.include?('subroutine')
|
46
|
+
method_hash = { name: y.name.to_s, desc: y.base_docstring, args: [], returns: { type: 'void' } }
|
47
|
+
|
48
|
+
y.tags.each do |t|
|
49
|
+
method_hash[:returns] = { type: t.types&.first } if t.tag_name == 'return'
|
50
|
+
|
51
|
+
next unless t.tag_name == 'param'
|
52
|
+
|
53
|
+
method_hash[:args] << { name: t.name, type: t.types&.first, desc: t.text }
|
54
|
+
end
|
55
|
+
|
56
|
+
klass.method_hashes << method_hash
|
57
|
+
|
58
|
+
klass.abi_interface.add_method(**method_hash) if tags.include? 'abi'
|
59
|
+
elsif tags.include? 'teal'
|
60
|
+
klass.teal_methods[y.name.to_s] = y
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
70
64
|
end
|
71
65
|
|
72
66
|
# sets the `#pragma version`, defines teal methods, and defines subroutines
|
@@ -75,18 +69,14 @@ module TEALrb
|
|
75
69
|
IfBlock.id = 0
|
76
70
|
@scratch = Scratch.new
|
77
71
|
|
78
|
-
self
|
79
|
-
define_singleton_method(name) do |*_args|
|
80
|
-
callsub(name)
|
81
|
-
end
|
82
|
-
end
|
72
|
+
@@active_contract = self # rubocop:disable Style/ClassVars
|
83
73
|
|
84
|
-
self.class.
|
85
|
-
define_subroutine
|
74
|
+
self.class.method_hashes.each do |mh|
|
75
|
+
define_subroutine(mh[:name], method(mh[:name]))
|
86
76
|
end
|
87
77
|
|
88
|
-
self.class.teal_methods.each do |name,
|
89
|
-
define_teal_method
|
78
|
+
self.class.teal_methods.each do |name, definition|
|
79
|
+
define_teal_method(name, definition)
|
90
80
|
end
|
91
81
|
end
|
92
82
|
|
@@ -155,7 +145,9 @@ module TEALrb
|
|
155
145
|
comment_content = "#{name}(#{comment_params})"
|
156
146
|
comment(comment_content, inline: true)
|
157
147
|
|
158
|
-
|
148
|
+
method_hash = self.class.method_hashes.find { _1[:name] == name.to_s }
|
149
|
+
new_source = generate_subroutine_source(definition, method_hash)
|
150
|
+
|
159
151
|
new_source = "#{new_source}retsub"
|
160
152
|
|
161
153
|
eval_tealrb(new_source, debug_context: "subroutine: #{name}")
|
@@ -185,7 +177,7 @@ module TEALrb
|
|
185
177
|
|
186
178
|
# the hash of the abi description
|
187
179
|
def abi_hash
|
188
|
-
self.class.
|
180
|
+
self.class.abi_interface.to_h
|
189
181
|
end
|
190
182
|
|
191
183
|
# transpiles the given string to TEAL
|
@@ -207,7 +199,7 @@ module TEALrb
|
|
207
199
|
private
|
208
200
|
|
209
201
|
def route_abi_methods
|
210
|
-
self.class.
|
202
|
+
self.class.abi_interface.methods.each do |meth|
|
211
203
|
signature = "#{meth[:name]}(#{meth[:args].map { _1[:type] }.join(',')})#{meth[:returns][:type]}"
|
212
204
|
selector = OpenSSL::Digest.new('SHA512-256').hexdigest(signature)[..7]
|
213
205
|
|
@@ -225,7 +217,7 @@ module TEALrb
|
|
225
217
|
|
226
218
|
scratch_names = []
|
227
219
|
definition.parameters.reverse.each_with_index do |param, _i|
|
228
|
-
param_name = param.
|
220
|
+
param_name = param.first
|
229
221
|
scratch_name = [name, param_name].map(&:to_s).join(': ')
|
230
222
|
scratch_names << scratch_name
|
231
223
|
|
@@ -233,12 +225,81 @@ module TEALrb
|
|
233
225
|
pre_string.puts "#{param_name} = -> { @scratch['#{scratch_name}'] }"
|
234
226
|
end
|
235
227
|
|
236
|
-
|
237
|
-
|
238
|
-
|
228
|
+
"#{pre_string.string}#{new_source}"
|
229
|
+
end
|
230
|
+
|
231
|
+
def generate_subroutine_source(definition, method_hash)
|
232
|
+
new_source = rewrite(definition.source, method_rewriter: true)
|
233
|
+
|
234
|
+
pre_string = StringIO.new
|
235
|
+
|
236
|
+
scratch_names = []
|
237
|
+
|
238
|
+
txn_types = %w[txn pay keyreg acfg axfer afrz appl]
|
239
|
+
|
240
|
+
args = method_hash[:args] || []
|
241
|
+
arg_types = args.map { _1[:type] } || []
|
242
|
+
txn_params = arg_types.select { txn_types.include? _1 }.count
|
243
|
+
app_param_index = -1
|
244
|
+
asset_param_index = -1
|
245
|
+
account_param_index = 0
|
246
|
+
args_index = 0
|
247
|
+
|
248
|
+
if abi_hash['methods'].find { _1[:name] == method_hash[:name].to_s }
|
249
|
+
definition.parameters.each_with_index do |param, i|
|
250
|
+
param_name = param.last
|
251
|
+
|
252
|
+
scratch_name = "#{definition.original_name}: #{param_name} [#{arg_types[i] || 'any'}] #{if args[i]
|
253
|
+
args[i][:desc]
|
254
|
+
end}"
|
255
|
+
scratch_names << scratch_name
|
256
|
+
|
257
|
+
if txn_types.include? arg_types[i]
|
258
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Gtxns[Txn.group_index - int(#{txn_params})]"
|
259
|
+
txn_params -= 1
|
260
|
+
elsif arg_types[i] == 'application'
|
261
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Apps[#{app_param_index += 1}]"
|
262
|
+
elsif arg_types[i] == 'asset'
|
263
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Assets[#{asset_param_index += 1}]"
|
264
|
+
elsif arg_types[i] == 'account'
|
265
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Accounts[#{account_param_index += 1}]"
|
266
|
+
else
|
267
|
+
pre_string.puts "@scratch['#{scratch_name}'] = AppArgs[#{args_index += 1}]"
|
268
|
+
end
|
269
|
+
|
270
|
+
pre_string.puts "#{param_name} = -> { @scratch['#{scratch_name}'] }"
|
271
|
+
end
|
272
|
+
|
273
|
+
else
|
274
|
+
args.reverse!
|
275
|
+
arg_types.reverse!
|
276
|
+
|
277
|
+
definition.parameters.reverse.each_with_index do |param, i|
|
278
|
+
param_name = param.last
|
279
|
+
|
280
|
+
scratch_name = "#{definition.original_name}: #{param_name} [#{arg_types[i] || 'any'}] #{if args[i]
|
281
|
+
args[i][:desc]
|
282
|
+
end}"
|
283
|
+
scratch_names << scratch_name
|
284
|
+
|
285
|
+
if txn_types.include? arg_types[i]
|
286
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Gtxns"
|
287
|
+
elsif arg_types[i] == 'application'
|
288
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Applications.new"
|
289
|
+
elsif arg_types[i] == 'asset'
|
290
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Assets.new"
|
291
|
+
elsif arg_types[i] == 'account'
|
292
|
+
pre_string.puts "@scratch['#{scratch_name}'] = Accounts.new"
|
293
|
+
else
|
294
|
+
pre_string.puts "@scratch.store('#{scratch_name}')"
|
295
|
+
end
|
296
|
+
|
297
|
+
pre_string.puts "#{param_name} = -> { @scratch['#{scratch_name}'] }"
|
298
|
+
end
|
299
|
+
|
239
300
|
end
|
240
301
|
|
241
|
-
"#{pre_string.string}#{new_source}
|
302
|
+
"#{pre_string.string}#{new_source}"
|
242
303
|
end
|
243
304
|
|
244
305
|
def rewrite_with_rewriter(string, rewriter)
|
@@ -254,7 +315,7 @@ module TEALrb
|
|
254
315
|
end
|
255
316
|
|
256
317
|
[CommentRewriter, ComparisonRewriter, WhileRewriter, InlineIfRewriter, IfRewriter, OpRewriter,
|
257
|
-
AssignRewriter].each do |rw|
|
318
|
+
AssignRewriter, InternalMethodRewriter].each do |rw|
|
258
319
|
string = rewrite_with_rewriter(string, rw)
|
259
320
|
end
|
260
321
|
|
@@ -289,7 +350,9 @@ module TEALrb
|
|
289
350
|
@eval_tealrb_rescue_count ||= 0
|
290
351
|
|
291
352
|
eval_locations = e.backtrace.select { _1[/\(eval\)/] }
|
292
|
-
|
353
|
+
if eval_locations[@eval_tealrb_rescue_count]
|
354
|
+
error_line = eval_locations[@eval_tealrb_rescue_count].split(':')[1].to_i
|
355
|
+
end
|
293
356
|
|
294
357
|
warn "'#{e}' when evaluating transpiled TEALrb source" if @eval_tealrb_rescue_count.zero?
|
295
358
|
|
@@ -474,6 +474,22 @@ module TEALrb
|
|
474
474
|
end
|
475
475
|
end
|
476
476
|
|
477
|
+
module ItxnField
|
478
|
+
extend TxnFields
|
479
|
+
|
480
|
+
def self.opcode(field, _value)
|
481
|
+
ExtendedOpcodes.itxn_field field
|
482
|
+
end
|
483
|
+
|
484
|
+
class << self
|
485
|
+
TxnFields.instance_methods.each do |m|
|
486
|
+
define_method("#{m}=") do |value|
|
487
|
+
send(m, value)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
477
493
|
module Gtxn
|
478
494
|
extend TxnFields
|
479
495
|
|
@@ -528,7 +544,12 @@ module TEALrb
|
|
528
544
|
end
|
529
545
|
|
530
546
|
def [](index)
|
531
|
-
|
547
|
+
if index.is_a? Integer
|
548
|
+
ExtendedOpcodes.txna @field, index
|
549
|
+
else
|
550
|
+
ExtendedOpcodes.txnas @field
|
551
|
+
end
|
552
|
+
|
532
553
|
self
|
533
554
|
end
|
534
555
|
end
|
data/lib/tealrb/rewriters.rb
CHANGED
@@ -27,6 +27,29 @@ module TEALrb
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
class InternalMethodRewriter < Rewriter
|
31
|
+
def on_send(node)
|
32
|
+
teal_methods = TEALrb::Contract.class_variable_get(:@@active_contract).class.teal_methods
|
33
|
+
|
34
|
+
method_name = node.loc.selector.source.to_sym
|
35
|
+
|
36
|
+
if teal_methods.keys.include? method_name
|
37
|
+
param_names = teal_methods[method_name].parameters.map(&:last)
|
38
|
+
|
39
|
+
pre_string = StringIO.new
|
40
|
+
param_names.each_with_index do |param, i|
|
41
|
+
scratch_name = [method_name, param].map(&:to_s).join(': ')
|
42
|
+
|
43
|
+
pre_string.puts "@scratch.store('#{scratch_name}', #{node.children[i + 2].loc.expression.source})"
|
44
|
+
end
|
45
|
+
|
46
|
+
replace node.source_range, "#{pre_string.string}\n#{method_name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
30
53
|
class MethodRewriter < Rewriter
|
31
54
|
def on_def(node)
|
32
55
|
replace node.source_range, node.body.source
|
@@ -125,6 +148,12 @@ module TEALrb
|
|
125
148
|
super
|
126
149
|
end
|
127
150
|
|
151
|
+
def on_return(node)
|
152
|
+
replace node.loc.keyword, 'abi_return'
|
153
|
+
|
154
|
+
super
|
155
|
+
end
|
156
|
+
|
128
157
|
OPCODE_METHODS = TEALrb::Opcodes::AllOpcodes.instance_methods.freeze
|
129
158
|
|
130
159
|
def on_send(node)
|
@@ -149,8 +178,10 @@ module TEALrb
|
|
149
178
|
@skips << node.children[2]
|
150
179
|
elsif node.children.first&.children&.last == :@scratch && meth_name[/=$/]
|
151
180
|
nil
|
152
|
-
elsif %i[@scratch Gtxn
|
181
|
+
elsif %i[@scratch Gtxn].include? node.children.first&.children&.last
|
153
182
|
@skips << node.children.last
|
183
|
+
elsif %i[Accounts ApplicationArgs Assets Apps Logs].include? node.children.first&.children&.last
|
184
|
+
@skips << node.children.last if node.children.last.int_type?
|
154
185
|
end
|
155
186
|
|
156
187
|
super
|
data/lib/tealrb.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tealrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Polny
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: method_source
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.36'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.27
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.27
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: minitest
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,19 +151,19 @@ dependencies:
|
|
137
151
|
- !ruby/object:Gem::Version
|
138
152
|
version: 0.21.2
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
154
|
+
name: terminal-table
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
142
156
|
requirements:
|
143
157
|
- - "~>"
|
144
158
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.
|
159
|
+
version: 3.0.2
|
146
160
|
type: :development
|
147
161
|
prerelease: false
|
148
162
|
version_requirements: !ruby/object:Gem::Requirement
|
149
163
|
requirements:
|
150
164
|
- - "~>"
|
151
165
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.
|
166
|
+
version: 3.0.2
|
153
167
|
description:
|
154
168
|
email: joepolny+dev@gmail.com
|
155
169
|
executables: []
|