tealrb 0.10.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.
@@ -4,9 +4,11 @@ module TEALrb
4
4
  module Rewriters
5
5
  class Rewriter < Parser::TreeRewriter
6
6
  include RuboCop::AST::Traversal
7
+ attr_reader :contract
7
8
 
8
- def rewrite(processed_source)
9
+ def rewrite(processed_source, contract)
9
10
  @comments = processed_source.comments
11
+ @contract = contract
10
12
  super(processed_source.buffer, processed_source.ast)
11
13
  end
12
14
  end
@@ -36,22 +38,11 @@ module TEALrb
36
38
  def on_block(node)
37
39
  replace node.source_range, node.body.source
38
40
  end
39
-
40
- def on_send(node)
41
- remove node.loc.selector if node.loc.selector.source == 'subroutine' || node.loc.selector.source == 'teal'
42
-
43
- # @teal_methods[:name] = ->(*args) { ... } becomes ->(*args) { ... }
44
- if ['@teal_methods', '@subroutines'].include? node.children[0]&.source
45
- replace node.source_range, node.children[3].body.source
46
- end
47
-
48
- super
49
- end
50
41
  end
51
42
 
52
43
  class AssignRewriter < Rewriter
53
44
  def on_lvasgn(node)
54
- wrap(node.children[1].source_range, '-> { ', ' }')
45
+ wrap(node.children[1].source_range, '-> {', '}')
55
46
  super
56
47
  end
57
48
 
@@ -61,12 +52,12 @@ module TEALrb
61
52
  end
62
53
 
63
54
  def on_ivasgn(node)
64
- wrap(node.children[1].source_range, '-> { ', ' }')
55
+ wrap(node.children[1].source_range, '-> {', ' }')
65
56
  super
66
57
  end
67
58
 
68
59
  def on_ivar(node)
69
- insert_after(node.loc.name, '.call') unless ['@teal_methods', '@subroutines', '@scratch'].include? node.source
60
+ insert_after(node.loc.name, '.call')
70
61
  super
71
62
  end
72
63
 
@@ -125,32 +116,32 @@ module TEALrb
125
116
  super
126
117
  end
127
118
 
128
- OPCODE_METHODS = TEALrb::Opcodes::AllOpcodes.instance_methods.freeze
119
+ def on_return(node)
120
+ replace node.loc.keyword, 'abi_return'
121
+
122
+ super
123
+ end
124
+
125
+ OPCODE_METHODS = TEALrb::Opcodes::TEALOpcodes.instance_methods.freeze
126
+ OPCODE_INSTANCE_METHODS = TEALrb::Opcodes::BINARY_OPCODE_METHOD_MAPPING.merge(
127
+ TEALrb::Opcodes::UNARY_OPCODE_METHOD_MAPPING
128
+ )
129
129
 
130
130
  def on_send(node)
131
131
  meth_name = node.children[1]
132
132
 
133
133
  if OPCODE_METHODS.include? meth_name
134
- if meth_name[/(byte|int)cblock/]
134
+ if %w[bytecblock intcblock pushints pushbytess switch match].include? meth_name.to_s
135
135
  @skips += node.children[2..]
136
136
  else
137
- params = TEALrb::Opcodes::AllOpcodes.instance_method(meth_name).parameters
137
+ params = TEALrb::Opcodes::TEALOpcodes.instance_method(meth_name).parameters
138
138
  req_params = params.count { |param| param[0] == :req }
139
139
  @skips += node.children[2..(1 + req_params.size)] unless req_params.zero?
140
140
  end
141
- elsif %i[comment placeholder rb].include?(meth_name) ||
142
- (%i[[] []=].include?(meth_name) &&
143
- (
144
- %i[@scratch @teal_methods Gtxn
145
- AppArgs].include?(node.children[0].children.last) ||
146
- node.children[0].children.first&.children&.last == :Txna
147
- ))
148
-
141
+ elsif %i[comment placeholder rb].include?(meth_name)
149
142
  @skips << node.children[2]
150
- elsif node.children.first&.children&.last == :@scratch && meth_name[/=$/]
151
- nil
152
- elsif %i[@scratch Gtxn Accounts ApplicationArgs Assets Apps Logs].include? node.children.first&.children&.last
153
- @skips << node.children.last
143
+ elsif meth_name == :[]
144
+ @skips << node.children[2] if node.children[2].type == :int
154
145
  end
155
146
 
156
147
  super
@@ -191,9 +182,15 @@ module TEALrb
191
182
  def on_if(node)
192
183
  unless node.loc.respond_to? :else
193
184
  conditional = node.children[0].source
194
- if_blk = node.children[1].source
195
185
 
196
- replace(node.loc.expression, "if(#{conditional})\n#{if_blk}\nend")
186
+ if_blk = if node.keyword == 'unless'
187
+ node.children[2].source
188
+ conditional = "!(#{conditional})"
189
+ else
190
+ node.children[1].source
191
+ end
192
+
193
+ replace(node.loc.expression, "if(#{conditional});#{if_blk};end")
197
194
  end
198
195
 
199
196
  super
@@ -202,17 +199,53 @@ module TEALrb
202
199
 
203
200
  class IfRewriter < Rewriter
204
201
  def on_if(node)
202
+ condition = node.children.first
203
+ block = node.children[1]
204
+
205
205
  case node.loc.keyword.source
206
- when 'if'
207
- replace(node.loc.keyword, 'IfBlock.new(')
206
+ when 'if', 'unless'
207
+ @contract.if_count += 1
208
+ @elsif_count ||= 0
209
+
210
+ if node.loc.keyword.source == 'unless'
211
+ replace(node.loc.keyword, ":if#{@contract.if_count}_condition;!")
212
+ else
213
+ replace(node.loc.keyword, ":if#{@contract.if_count}_condition;")
214
+ end
215
+ insert_before(block.source_range, ":if#{@contract.if_count}_logic;")
216
+
217
+ case node.loc.else&.source
218
+ when 'else'
219
+ insert_after(condition.source_range, "; bz :if#{@contract.if_count}_else")
220
+ insert_after(block.source_range, "; b :if#{@contract.if_count}_end")
221
+ replace(node.loc.else, ":if#{@contract.if_count}_else;")
222
+ when 'elsif'
223
+ insert_after(condition.source_range, "; bz :if#{@contract.if_count}_elsif#{@elsif_count + 1}_condition")
224
+ insert_after(block.source_range, "; b :if#{@contract.if_count}_end")
225
+ replace(node.loc.else, ":if#{@contract.if_count}_elsif#{@elsif_count + 1}_condition;")
226
+ else
227
+ insert_after(condition.source_range, "; bz :if#{@contract.if_count}_end")
228
+ end
229
+ replace(node.loc.end, ":if#{@contract.if_count}_end")
208
230
  when 'elsif'
209
- replace(node.loc.keyword, 'end.elsif(')
210
- end
231
+ @elsif_count += 1
232
+
233
+ case node.loc.else&.source
234
+ when 'else'
235
+ insert_after(condition.source_range, "; bz :if#{@contract.if_count}_else")
236
+ insert_after(block.source_range, "; b :if#{@contract.if_count}_end")
237
+ replace(node.loc.else, ":if#{@contract.if_count}_else;")
238
+ when 'elsif'
239
+ insert_after(condition.source_range, "; bz :if#{@contract.if_count}_elsif#{@elsif_count + 1}_condition")
240
+ insert_after(block.source_range, "; b :if#{@contract.if_count}_end")
241
+ replace(node.loc.else, ":if#{@contract.if_count}_elsif#{@elsif_count + 1}_condition;")
242
+ else
243
+ insert_after(condition.source_range, "; bz :if#{@contract.if_count}_end")
244
+ end
211
245
 
212
- cond_expr = node.children.first.source_range
213
- replace(cond_expr, "#{cond_expr.source} ) do")
246
+ insert_before(block.source_range, ":if#{@contract.if_count}_elsif#{@elsif_count}_logic;")
247
+ end
214
248
 
215
- replace(node.loc.else, 'end.else do') if node.loc.else && node.loc.else.source == 'else'
216
249
  super
217
250
  end
218
251
  end
@@ -234,9 +267,12 @@ module TEALrb
234
267
 
235
268
  def on_while(node)
236
269
  cond_node = node.children.first
237
- replace(node.loc.keyword, ":while#{while_count}\n#{cond_node.source}\nbz :end_while#{while_count}")
270
+ replace(
271
+ node.loc.keyword,
272
+ ":while#{while_count}_condition;#{cond_node.source};bz :while#{while_count}_end; :while#{while_count}_logic;"
273
+ )
238
274
  replace(node.loc.begin, '') if node.loc.begin
239
- replace(node.loc.end, "b :while#{while_count}\n:end_while#{while_count}")
275
+ replace(node.loc.end, "b :while#{while_count}_condition;:while#{while_count}_end")
240
276
  replace(cond_node.loc.expression, '')
241
277
  super
242
278
  end
@@ -2,14 +2,15 @@
2
2
 
3
3
  module TEALrb
4
4
  class Scratch
5
- def initialize
5
+ def initialize(contract)
6
6
  @open_slots = (0..256).to_a
7
7
  @named_slots = {}
8
8
  @values = {}
9
+ @contract = contract
9
10
  end
10
11
 
11
12
  def [](key)
12
- TEAL.instance << "load #{@named_slots[key]} // #{key}"
13
+ @contract.teal << "load #{@named_slots[key]} // #{key}"
13
14
  @values[key]
14
15
  end
15
16
 
@@ -17,9 +18,9 @@ module TEALrb
17
18
  store(key, value)
18
19
  end
19
20
 
20
- def store(key, value = TEAL.instance)
21
+ def store(key, value = @contract.teal)
21
22
  @values[key] = value
22
- TEAL.instance << "store #{@named_slots[key] ||= @open_slots.shift} // #{key}"
23
+ @contract.teal << "store #{@named_slots[key] ||= @open_slots.shift} // #{key}"
23
24
  end
24
25
 
25
26
  def delete(key)
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TEALrb
4
+ class ThisTxn < OpcodeType
5
+ include TxnFields
6
+
7
+ private
8
+
9
+ def txnfield_opcode(field, *_args)
10
+ @contract.txn field
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TEALrb
4
+ module TxnFields
5
+ def txnfield_opcode(*args)
6
+ raise NotImplementedError
7
+ end
8
+
9
+ # @return [[]byte] 32 byte address (v1)
10
+ def sender(*args)
11
+ @contract.account txnfield_opcode('Sender', *args)
12
+ end
13
+
14
+ # @return [uint64] microalgos (v1)
15
+ def fee(*args)
16
+ txnfield_opcode('Fee', *args)
17
+ end
18
+
19
+ # @return [uint64] round number (v1)
20
+ def first_valid(*args)
21
+ txnfield_opcode('FirstValid', *args)
22
+ end
23
+
24
+ # @return [uint64] Causes program to fail; reserved for future use (v1)
25
+ def first_valid_time(*args)
26
+ txnfield_opcode('FirstValidTime', *args)
27
+ end
28
+
29
+ # @return [uint64] round number (v1)
30
+ def last_valid(*args)
31
+ txnfield_opcode('LastValid', *args)
32
+ end
33
+
34
+ # @return [[]byte] Any data up to 1024 bytes (v1)
35
+ def note(*args)
36
+ txnfield_opcode('Note', *args)
37
+ end
38
+
39
+ # @return [[]byte] 32 byte lease value (v1)
40
+ def lease(*args)
41
+ txnfield_opcode('Lease', *args)
42
+ end
43
+
44
+ # @return [[]byte] 32 byte address (v1)
45
+ def receiver(*args)
46
+ @contract.account txnfield_opcode('Receiver', *args)
47
+ end
48
+
49
+ # @return [uint64] microalgos (v1)
50
+ def amount(*args)
51
+ txnfield_opcode('Amount', *args)
52
+ end
53
+
54
+ # @return [[]byte] 32 byte address (v1)
55
+ def close_remainder_to(*args)
56
+ @contract.account txnfield_opcode('CloseRemainderTo', *args)
57
+ end
58
+
59
+ # @return [[]byte] 32 byte address (v1)
60
+ def vote_pk(*args)
61
+ txnfield_opcode('VotePK', *args)
62
+ end
63
+
64
+ # @return [[]byte] 32 byte address (v1)
65
+ def selection_pk(*args)
66
+ txnfield_opcode('SelectionPK', *args)
67
+ end
68
+
69
+ # @return [uint64] The first round that the participation key is valid. (v1)
70
+ def vote_first(*args)
71
+ txnfield_opcode('VoteFirst', *args)
72
+ end
73
+
74
+ # @return [uint64] The last round that the participation key is valid. (v1)
75
+ def vote_last(*args)
76
+ txnfield_opcode('VoteLast', *args)
77
+ end
78
+
79
+ # @return [uint64] Dilution for the 2-level participation key (v1)
80
+ def vote_key_dilution(*args)
81
+ txnfield_opcode('VoteKeyDilution', *args)
82
+ end
83
+
84
+ # @return [[]byte] Transaction type as bytes (v1)
85
+ def type(*args)
86
+ txnfield_opcode('Type', *args)
87
+ end
88
+
89
+ # @return [uint64] See table below (v1)
90
+ def type_enum(*args)
91
+ txnfield_opcode('TypeEnum', *args)
92
+ end
93
+
94
+ # @return [uint64] Asset ID (v1)
95
+ def xfer_asset(*args)
96
+ @contract.asset txnfield_opcode('XferAsset', *args)
97
+ end
98
+
99
+ # @return [uint64] value in Asset's units (v1)
100
+ def asset_amount(*args)
101
+ txnfield_opcode('AssetAmount', *args)
102
+ end
103
+
104
+ # @return [[]byte] 32 byte address. Causes clawback of all value of asset from AssetSender if
105
+ # Sender is the Clawback address of the asset. (v1)
106
+ def asset_sender(*args)
107
+ @contract.account txnfield_opcode('AssetSender', *args)
108
+ end
109
+
110
+ # @return [[]byte] 32 byte address (v1)
111
+ def asset_receiver(*args)
112
+ @contract.account txnfield_opcode('AssetReceiver', *args)
113
+ end
114
+
115
+ # @return [[]byte] 32 byte address (v1)
116
+ def asset_close_to(*args)
117
+ @contract.account txnfield_opcode('AssetCloseTo', *args)
118
+ end
119
+
120
+ # @return [uint64] Position of this transaction within an atomic transaction group.
121
+ # A stand-alone transaction is implicitly element 0 in a group of 1 (v1)
122
+ def group_index(*args)
123
+ txnfield_opcode('GroupIndex', *args)
124
+ end
125
+
126
+ # @return [[]byte] The computed ID for this transaction. 32 bytes. (v1)
127
+ def tx_id(*args)
128
+ txnfield_opcode('TxID', *args)
129
+ end
130
+
131
+ # @return [uint64] ApplicationID from ApplicationCall transaction (v2)
132
+ def application_id(*args)
133
+ @contract.app txnfield_opcode('ApplicationID', *args)
134
+ end
135
+
136
+ # @return [uint64] ApplicationCall transaction on completion action (v2)
137
+ def on_completion(*args)
138
+ txnfield_opcode('OnCompletion', *args)
139
+ end
140
+
141
+ # @return [[]byte] Arguments passed to the application in the ApplicationCall transaction (v2)
142
+ def application_args(*args)
143
+ txnfield_opcode('ApplicationArgs', *args)
144
+ end
145
+
146
+ # @return [uint64] Number of ApplicationArgs (v2)
147
+ def num_app_args(*args)
148
+ txnfield_opcode('NumAppArgs', *args)
149
+ end
150
+
151
+ # @return [[]byte] Accounts listed in the ApplicationCall transaction (v2)
152
+ def accounts(*args)
153
+ txnfield_opcode('Accounts', *args)
154
+ end
155
+
156
+ # @return [uint64] Number of Accounts (v2)
157
+ def num_accounts(*args)
158
+ txnfield_opcode('NumAccounts', *args)
159
+ end
160
+
161
+ # @return [[]byte] Approval program (v2)
162
+ def approval_program(*args)
163
+ txnfield_opcode('ApprovalProgram', *args)
164
+ end
165
+
166
+ # @return [[]byte] Clear state program (v2)
167
+ def clear_state_program(*args)
168
+ txnfield_opcode('ClearStateProgram', *args)
169
+ end
170
+
171
+ # @return [[]byte] 32 byte Sender's new AuthAddr (v2)
172
+ def rekey_to(*args)
173
+ @contract.account txnfield_opcode('RekeyTo', *args)
174
+ end
175
+
176
+ # @return [uint64] Asset ID in asset config transaction (v2)
177
+ def config_asset(*args)
178
+ @contract.asset txnfield_opcode('ConfigAsset', *args)
179
+ end
180
+
181
+ # @return [uint64] Total number of units of this asset created (v2)
182
+ def config_asset_total(*args)
183
+ txnfield_opcode('ConfigAssetTotal', *args)
184
+ end
185
+
186
+ # @return [uint64] Number of digits to display after the decimal place when displaying the asset (v2)
187
+ def config_asset_decimals(*args)
188
+ txnfield_opcode('ConfigAssetDecimals', *args)
189
+ end
190
+
191
+ # @return [uint64] Whether the asset's slots are frozen by default or not, 0 or 1 (v2)
192
+ def config_asset_default_frozen(*args)
193
+ txnfield_opcode('ConfigAssetDefaultFrozen', *args)
194
+ end
195
+
196
+ # @return [[]byte] Unit name of the asset (v2)
197
+ def config_asset_unit_name(*args)
198
+ txnfield_opcode('ConfigAssetUnitName', *args)
199
+ end
200
+
201
+ # @return [[]byte] The asset name (v2)
202
+ def config_asset_name(*args)
203
+ txnfield_opcode('ConfigAssetName', *args)
204
+ end
205
+
206
+ # @return [[]byte] URL (v2)
207
+ def config_asset_url(*args)
208
+ txnfield_opcode('ConfigAssetURL', *args)
209
+ end
210
+
211
+ # @return [[]byte] 32 byte commitment to some unspecified asset metadata (v2)
212
+ def config_asset_metadata_hash(*args)
213
+ txnfield_opcode('ConfigAssetMetadataHash', *args)
214
+ end
215
+
216
+ # @return [[]byte] 32 byte address (v2)
217
+ def config_asset_manager(*args)
218
+ @contract.account txnfield_opcode('ConfigAssetManager', *args)
219
+ end
220
+
221
+ # @return [[]byte] 32 byte address (v2)
222
+ def config_asset_reserve(*args)
223
+ @contract.account txnfield_opcode('ConfigAssetReserve', *args)
224
+ end
225
+
226
+ # @return [[]byte] 32 byte address (v2)
227
+ def config_asset_freeze(*args)
228
+ @contract.account txnfield_opcode('ConfigAssetFreeze', *args)
229
+ end
230
+
231
+ # @return [[]byte] 32 byte address (v2)
232
+ def config_asset_clawback(*args)
233
+ @contract.account txnfield_opcode('ConfigAssetClawback', *args)
234
+ end
235
+
236
+ # @return [uint64] Asset ID being frozen or un-frozen (v2)
237
+ def freeze_asset(*args)
238
+ @contract.asset txnfield_opcode('FreezeAsset', *args)
239
+ end
240
+
241
+ # @return [[]byte] 32 byte address of the account whose asset slot is being frozen or un-frozen (v2)
242
+ def freeze_asset_account(*args)
243
+ @contract.account txnfield_opcode('FreezeAssetAccount', *args)
244
+ end
245
+
246
+ # @return [uint64] The new frozen value, 0 or 1 (v2)
247
+ def freeze_asset_frozen(*args)
248
+ txnfield_opcode('FreezeAssetFrozen', *args)
249
+ end
250
+
251
+ # @return [uint64] Foreign Assets listed in the ApplicationCall transaction (v3)
252
+ def assets(*args)
253
+ txnfield_opcode('Assets', *args)
254
+ end
255
+
256
+ # @return [uint64] Number of Assets (v3)
257
+ def num_assets(*args)
258
+ txnfield_opcode('NumAssets', *args)
259
+ end
260
+
261
+ # @return [uint64] Foreign Apps listed in the ApplicationCall transaction (v3)
262
+ def applications(*args)
263
+ txnfield_opcode('Applications', *args)
264
+ end
265
+
266
+ # @return [uint64] Number of Applications (v3)
267
+ def num_applications(*args)
268
+ txnfield_opcode('NumApplications', *args)
269
+ end
270
+
271
+ # @return [uint64] Number of global state integers in ApplicationCall (v3)
272
+ def global_num_uint(*args)
273
+ txnfield_opcode('GlobalNumUint', *args)
274
+ end
275
+
276
+ # @return [uint64] Number of global state byteslices in ApplicationCall (v3)
277
+ def global_num_byte_slice(*args)
278
+ txnfield_opcode('GlobalNumByteSlice', *args)
279
+ end
280
+
281
+ # @return [uint64] Number of local state integers in ApplicationCall (v3)
282
+ def local_num_uint(*args)
283
+ txnfield_opcode('LocalNumUint', *args)
284
+ end
285
+
286
+ # @return [uint64] Number of local state byteslices in ApplicationCall (v3)
287
+ def local_num_byte_slice(*args)
288
+ txnfield_opcode('LocalNumByteSlice', *args)
289
+ end
290
+
291
+ # @return [uint64] Number of additional pages for each of the application's approval and clear state programs.
292
+ # An ExtraProgramPages of 1 means 2048 more total bytes, or 1024 for each program. (v4)
293
+ def extra_program_pages(*args)
294
+ txnfield_opcode('ExtraProgramPages', *args)
295
+ end
296
+
297
+ # @return [uint64] Marks an account nonparticipating for rewards (v5)
298
+ def nonparticipation(*args)
299
+ txnfield_opcode('Nonparticipation', *args)
300
+ end
301
+
302
+ # @return [[]byte] Log messages emitted by an application call (only with itxn in v5). Application mode only (v5)
303
+ def logs(*args)
304
+ txnfield_opcode('Logs', *args)
305
+ end
306
+
307
+ # @return [uint64] Number of Logs (only with itxn in v5). Application mode only (v5)
308
+ def num_logs(*args)
309
+ txnfield_opcode('NumLogs', *args)
310
+ end
311
+
312
+ # @return [uint64] Asset ID allocated by the creation of an ASA (only with itxn in v5). Application mode only (v5)
313
+ def created_asset_id(*args)
314
+ @contract.asset txnfield_opcode('CreatedAssetID', *args)
315
+ end
316
+
317
+ # @return [uint64] ApplicationID allocated by the creation of an application (only with itxn in v5).
318
+ # Application mode only (v5)
319
+ def created_application_id(*args)
320
+ @contract.app txnfield_opcode('CreatedApplicationID', *args)
321
+ end
322
+
323
+ # @return [[]byte] The last message emitted. Empty bytes if none were emitted. Application mode only (v6)
324
+ def last_log(*args)
325
+ txnfield_opcode('LastLog', *args)
326
+ end
327
+
328
+ # @return [[]byte] 64 byte state proof public key commitment (v6)
329
+ def state_proof_pk(*args)
330
+ txnfield_opcode('StateProofPK', *args)
331
+ end
332
+ end
333
+ end
data/lib/tealrb.rb CHANGED
@@ -2,32 +2,40 @@
2
2
 
3
3
  require 'method_source'
4
4
  require 'rubocop'
5
+ require 'yard'
6
+ require 'faraday'
7
+ require 'source_map'
5
8
 
6
9
  require_relative 'tealrb/constants'
7
10
  require_relative 'tealrb/abi'
8
11
  require_relative 'tealrb/opcodes'
9
- require_relative 'tealrb/opcode_modules'
10
- require_relative 'tealrb/rewriters'
11
- require_relative 'tealrb/if_block'
12
+ require_relative 'tealrb/maybe_ops'
13
+ require_relative 'tealrb/byte_opcodes'
14
+ require_relative 'tealrb/txn_fields'
15
+ require_relative 'tealrb/opcode_type'
16
+ require_relative 'tealrb/account'
17
+ require_relative 'tealrb/this_txn'
18
+ require_relative 'tealrb/box'
19
+ require_relative 'tealrb/inner_txn'
20
+ require_relative 'tealrb/group_txn'
21
+ require_relative 'tealrb/global'
22
+ require_relative 'tealrb/app'
23
+ require_relative 'tealrb/asset'
24
+ require_relative 'tealrb/logs'
25
+ require_relative 'tealrb/app_args'
26
+ require_relative 'tealrb/local'
27
+ require_relative 'tealrb/enums'
12
28
  require_relative 'tealrb/scratch'
29
+ require_relative 'tealrb/algod'
30
+ require_relative 'tealrb/rewriters'
13
31
  require_relative 'tealrb/contract'
14
32
  require_relative 'tealrb/cmd_line/teal2tealrb'
15
33
 
16
34
  module TEALrb
17
35
  class TEAL < Array
18
- class << self
19
- attr_writer :instance
20
-
21
- def instance
22
- raise 'TEALrb does not support multi-threading' if Thread.current != Thread.main
23
-
24
- @instance
25
- end
26
- end
27
-
28
- def initialize(teal_array)
29
- self.class.instance = self
30
- super
36
+ def initialize(teal_array, contract)
37
+ @contract = contract
38
+ super(teal_array)
31
39
  end
32
40
 
33
41
  def teal
@@ -38,19 +46,41 @@ module TEALrb
38
46
  self << '&&'
39
47
  end
40
48
 
49
+ def <<(value)
50
+ return super unless @contract.class.src_map
51
+ return super if caller.join['src_map']
52
+ return super unless @contract.eval_location
53
+
54
+ eval_location = caller.reverse.find { _1[/^\(eval/] }&.split(':')
55
+ return super unless eval_location
56
+
57
+ eval_line = eval_location[1].to_i
58
+ src_map(@contract.eval_location.first, @contract.eval_location.last + eval_line)
59
+ super
60
+ end
61
+
62
+ def src_map(file, line_number)
63
+ ln = "// src_map:#{File.basename(file)}:#{line_number}"
64
+ return if ln == @last_src_map
65
+
66
+ @last_src_map = ln
67
+
68
+ self << ln
69
+ end
70
+
41
71
  def boolean_or(_other)
42
72
  self << '||'
43
73
  end
44
74
 
45
75
  TEALrb::Opcodes::BINARY_OPCODE_METHOD_MAPPING.each do |meth, opcode|
46
76
  define_method(meth) do |other|
47
- TEALrb::Opcodes::ExtendedOpcodes.send(opcode, self, other)
77
+ @contract.send(opcode, self, other)
48
78
  end
49
79
  end
50
80
 
51
81
  TEALrb::Opcodes::UNARY_OPCODE_METHOD_MAPPING.each do |meth, opcode|
52
82
  define_method(meth) do
53
- TEALrb::Opcodes::ExtendedOpcodes.send(opcode, self)
83
+ @contract.send(opcode, self)
54
84
  end
55
85
  end
56
86
  end