sbuilder-ethereum 0.0.6
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 +7 -0
- data/VERSION +1 -0
- data/lib/mixer/decl_ref.rb +19 -0
- data/lib/mixer/domain_ref.rb +18 -0
- data/lib/mixer/scope.rb +92 -0
- data/lib/mixer/scoped.rb +17 -0
- data/lib/mixer/symbol_ref.rb +16 -0
- data/lib/mixer/type_symbol.rb +75 -0
- data/lib/plugin/plugin.rb +332 -0
- data/lib/resources/correctness/accouns_type.tla +1 -0
- data/lib/resources/correctness/accounts_unique.tla +2 -0
- data/lib/resources/correctness/accounts_valid.tla +2 -0
- data/lib/resources/correctness/storage_root_unique.tla +2 -0
- data/lib/resources/correctness/total_value.tla +1 -0
- data/lib/resources/eth/accounts_state.tla +2 -0
- data/lib/resources/eth/accounts_temp.tla +2 -0
- data/lib/resources/eth/address_free.tla +2 -0
- data/lib/resources/eth/mined_state.tla +1 -0
- data/lib/resources/eth/storageRoot.tla +1 -0
- data/lib/resources/eth/storageRoot_temp.tla +1 -0
- data/lib/resources/mine/mine_entry.tla +4 -0
- data/lib/resources/mine/mine_service.tla +22 -0
- data/lib/resources/operators/elementExists.tla +4 -0
- data/lib/resources/operators/gasPrice.tla +2 -0
- data/lib/resources/operators/gasValue.tla +2 -0
- data/lib/resources/operators/getElement.tla +5 -0
- data/lib/resources/operators/intrinsicGas.tla +4 -0
- data/lib/resources/operators/transactionGas.tla +4 -0
- data/lib/resources/operators/upFrontCost.tla +6 -0
- data/lib/resources/personal_newAccount/personal_newAccount_done.tla +14 -0
- data/lib/resources/personal_newAccount/personal_newAccount_entry.tla +10 -0
- data/lib/resources/personal_newAccount/personal_newAccount_service.tla +29 -0
- data/lib/resources/removed/sendTransaction_entry.tla +5 -0
- data/lib/resources/removed/sendTransaction_service.tla +36 -0
- data/lib/resources/removed/tst.tla +1 -0
- data/lib/resources/transaction/ethereum_service_done.tla +24 -0
- data/lib/resources/transaction/ethereum_service_pop.tla +24 -0
- data/lib/resources/transaction/ethereum_service_push.tla +14 -0
- data/lib/resources/transaction/ethereum_service_start.tla +13 -0
- data/lib/resources/transaction/status_fail.tla +1 -0
- data/lib/resources/transaction/status_ok.tla +1 -0
- data/lib/sbuilder-ethereum.rb +52 -0
- data/lib/sbuilder/compile.rb +163 -0
- data/lib/sbuilder/constants.rb +93 -0
- data/lib/sbuilder/exception.rb +22 -0
- data/lib/sbuilder/generate/sexp_processor_tla.rb +2674 -0
- data/lib/sbuilder/generate/tla_element_generator.rb +1206 -0
- data/lib/sbuilder/generate/tla_element_text.rb +703 -0
- data/lib/sbuilder/load.rb +119 -0
- data/lib/sbuilder/mustache/renderer.rb +152 -0
- data/lib/sbuilder/render.rb +141 -0
- data/lib/sbuilder/s.rb +21 -0
- data/lib/sbuilder/sexp_ast.rb +1378 -0
- data/lib/sbuilder/sexp_processor_api.rb +184 -0
- data/lib/sbuilder/sexp_processor_canonize.rb +326 -0
- data/lib/sbuilder/sexp_processor_dataflow.rb +461 -0
- data/lib/sbuilder/sexp_processor_ethereum.rb +127 -0
- data/lib/sbuilder/sexp_processor_need_to_canonize.rb +572 -0
- data/lib/sbuilder/sexp_processor_snippet.rb +154 -0
- data/lib/sbuilder/sexp_processor_symboltable1.rb +296 -0
- data/lib/sbuilder/sexp_processor_symboltable2.rb +175 -0
- data/lib/sbuilder/sexp_utils.rb +417 -0
- data/lib/utils/logger.rb +82 -0
- data/lib/utils/string_inject.rb +11 -0
- data/sbuilder-ethereum.gemspec +39 -0
- metadata +190 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
module Ethereum
|
3
|
+
|
4
|
+
# A class allowing sbuilder ethereum to extend 'SexpProcessor'
|
5
|
+
# behaviour. (Possible candidate for extension env)
|
6
|
+
|
7
|
+
class SexpProcessorEthereum < SexpProcessor
|
8
|
+
|
9
|
+
PROGNAME = nil # progname for logger default class name
|
10
|
+
include MyLogger # mix logger
|
11
|
+
|
12
|
+
# @attr [Hash] options
|
13
|
+
# @option options [String] :log e.g. "WARN"
|
14
|
+
# @option options [String|STDOUT] :logfile e.g. STDOUT
|
15
|
+
attr_reader :options
|
16
|
+
|
17
|
+
# @attr [Logger] logger
|
18
|
+
attr_reader :logger
|
19
|
+
|
20
|
+
# ------------------------------------------------------------------
|
21
|
+
# @!group Contstruct and configure
|
22
|
+
|
23
|
+
def initialize( options={} )
|
24
|
+
super()
|
25
|
+
|
26
|
+
@options = options
|
27
|
+
@logger = getLogger( nil, options )
|
28
|
+
|
29
|
+
# Override defaults in parent class
|
30
|
+
self.strict = false
|
31
|
+
|
32
|
+
# Allow Sexp nodes to remain intact, see 'process_rest'
|
33
|
+
self.require_empty = false
|
34
|
+
|
35
|
+
# visitors just recurses - do not shift sexp (as sexp_processor default does)
|
36
|
+
self.default_method = :process_rest
|
37
|
+
|
38
|
+
# no warning needed when using default method
|
39
|
+
self.warn_on_default = false
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# @!endgroup
|
44
|
+
|
45
|
+
# ------------------------------------------------------------------
|
46
|
+
# @!group Node rules
|
47
|
+
|
48
|
+
# @!endgroup
|
49
|
+
|
50
|
+
# ------------------------------------------------------------------
|
51
|
+
# @!group Visitor helpers
|
52
|
+
|
53
|
+
##
|
54
|
+
# Process each element of #exp in turn.
|
55
|
+
|
56
|
+
# def process_until_empty exp
|
57
|
+
# until exp.empty?
|
58
|
+
# sexp = exp.shift
|
59
|
+
# process sexp if Sexp === sexp
|
60
|
+
# end
|
61
|
+
# s()
|
62
|
+
# end
|
63
|
+
|
64
|
+
|
65
|
+
##
|
66
|
+
# Process each element of +exp+ in turn
|
67
|
+
|
68
|
+
def process_rest exp
|
69
|
+
pos = 0
|
70
|
+
ret = s()
|
71
|
+
until pos >= exp.length
|
72
|
+
sexp = exp[pos]
|
73
|
+
pos += 1
|
74
|
+
psexps = process( sexp ) if Sexp === sexp
|
75
|
+
if !psexps.nil? && psexps.sexp_type == :dummy
|
76
|
+
# :dummy get flattened
|
77
|
+
psexps.rest.each do |psexp|
|
78
|
+
ret << psexp
|
79
|
+
end
|
80
|
+
else # non-dummy sexp || nil sexp
|
81
|
+
ret << psexps unless psexps.nil?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
ret
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
# Default operation: current node does not contribute to sexp,
|
89
|
+
# flatten it
|
90
|
+
def process_skip exp
|
91
|
+
ret = process_rest( exp )
|
92
|
+
return ret if ret.length == 0
|
93
|
+
return ret.first if ret.length == 1
|
94
|
+
raise <<-EOS
|
95
|
+
Expect child nodes to return s() or s( s(:any, ...)) -
|
96
|
+
|
97
|
+
When processing exp: #{exp}
|
98
|
+
|
99
|
+
process_rest returns: #{ret}
|
100
|
+
|
101
|
+
EOS
|
102
|
+
end
|
103
|
+
|
104
|
+
# Default operation: do nothing
|
105
|
+
def process_none exp
|
106
|
+
s()
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def process_abort exp
|
111
|
+
|
112
|
+
raise <<-EOS
|
113
|
+
Implementation missing for #{exp}
|
114
|
+
EOS
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
# @!endgroup
|
121
|
+
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,572 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
module Ethereum
|
3
|
+
|
4
|
+
##
|
5
|
+
#
|
6
|
+
# Add
|
7
|
+
# - constructor - if missing
|
8
|
+
# - balance - if missing
|
9
|
+
# - getter methods - if missing
|
10
|
+
|
11
|
+
class SexpProcessorNeedToCanonize < SexpProcessorEthereum
|
12
|
+
|
13
|
+
# ------------------------------------------------------------------
|
14
|
+
# @!group canonize operations
|
15
|
+
|
16
|
+
# @attr [Boolean] needConstructor
|
17
|
+
attr_reader :needConstructor
|
18
|
+
|
19
|
+
# @attr [String:Array] needVariableDeclarations, initialized
|
20
|
+
# with variable names, which will be added (unless they are defined)
|
21
|
+
attr_reader :needVariableDeclarations
|
22
|
+
|
23
|
+
# @attr [String:Array] neededGetters variable names missing
|
24
|
+
# getters, add entry each variable declation, and remove for
|
25
|
+
# each getter.
|
26
|
+
attr_reader :neededGetters
|
27
|
+
|
28
|
+
# @attr [Assignment:Array] assignmentOperatorSplits
|
29
|
+
attr_reader :assignmentOperatorSplits
|
30
|
+
|
31
|
+
|
32
|
+
# @attr [SexpAst:Array] functionCallsToSplit s(Block, Statement, FunctionCall)
|
33
|
+
attr_reader :functionCallsToSplit
|
34
|
+
|
35
|
+
|
36
|
+
# @attr [s(FunctionDef, s(s(:parameter, name,domain), s(:parameter, name, domain)]), ... )]
|
37
|
+
attr_reader :missing_request_parameters
|
38
|
+
|
39
|
+
# @attr [VariableDeclaration:Array] variable_declarations_without_name
|
40
|
+
attr_reader :variable_declarations_without_name
|
41
|
+
|
42
|
+
# @attr [s(Sexp(Literal), value ):Array]
|
43
|
+
attr_reader :map_literalValue
|
44
|
+
|
45
|
+
# @!endgroup
|
46
|
+
|
47
|
+
# @attr [Hash] optionss
|
48
|
+
attr_reader :options
|
49
|
+
|
50
|
+
# @!endgroup
|
51
|
+
|
52
|
+
# ------------------------------------------------------------------
|
53
|
+
# @!group Configs
|
54
|
+
|
55
|
+
# https://github.com/ethereum/wiki/wiki/Solidity-Features#contracts-inherit-all-members-from-address
|
56
|
+
#
|
57
|
+
# a contract type contains all members of the address type with
|
58
|
+
# the semantics applying to the contract's address, unless
|
59
|
+
# overwritten by the contract.
|
60
|
+
#
|
61
|
+
# Balance is hold in 'eth_accounts' not in eth_storageRoot
|
62
|
+
INHERITED_VARIABLE_DECLARATIONS = [
|
63
|
+
Constants::FIELD_NAME_ADDRESS,
|
64
|
+
# Constants::FIELD_NAME_BALANCE,
|
65
|
+
]
|
66
|
+
|
67
|
+
##
|
68
|
+
# Require 'expLiteral.type' to have TLA-value, if this is not the case
|
69
|
+
# check if 'expLiteral.value' is defined
|
70
|
+
LITERAL_MAPPINGS = {
|
71
|
+
|
72
|
+
# solc integer literals 'int_const 42', no rule to change
|
73
|
+
# value needed
|
74
|
+
/int_const/ => {
|
75
|
+
:rules => nil
|
76
|
+
},
|
77
|
+
|
78
|
+
# solc 'bool' is mapped to TLA-domain 'BOOLEAN' with values
|
79
|
+
# 'TRUE' and 'FALSE'
|
80
|
+
'bool' => {
|
81
|
+
:rules => {
|
82
|
+
# TLA-value => solc value
|
83
|
+
'TRUE' => 'true',
|
84
|
+
'FALSE' => 'false',
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
# @!endgroup
|
90
|
+
|
91
|
+
# ------------------------------------------------------------------
|
92
|
+
# @!group Construct & configure
|
93
|
+
|
94
|
+
def initialize( options={} )
|
95
|
+
super( options )
|
96
|
+
logger.debug "#{__method__}: created" if logger.debug?
|
97
|
+
|
98
|
+
@options = options
|
99
|
+
|
100
|
+
# reset state
|
101
|
+
initIt
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
def initIt()
|
106
|
+
##
|
107
|
+
logger.info "#{__method__} called"
|
108
|
+
|
109
|
+
# default - constructor should be added
|
110
|
+
@needConstructor = true
|
111
|
+
|
112
|
+
# default - no getters need
|
113
|
+
@neededGetters = []
|
114
|
+
|
115
|
+
# default - inherited variables should be added. NOTICE:
|
116
|
+
# clone here because later we are using
|
117
|
+
# needVariableDeclarations.delete opreation!!
|
118
|
+
@needVariableDeclarations = INHERITED_VARIABLE_DECLARATIONS.clone
|
119
|
+
|
120
|
+
# split assignment/conditional/.. with function calls
|
121
|
+
@functionCallsToSplit = []
|
122
|
+
|
123
|
+
# add: msg.value, msg.sender, etc. to FunctionDefinition
|
124
|
+
@missing_request_parameters = []
|
125
|
+
|
126
|
+
# invent a name: (function definition)
|
127
|
+
@variable_declarations_without_name = []
|
128
|
+
|
129
|
+
# map literal.value to tlavalue
|
130
|
+
@map_literalValue = []
|
131
|
+
|
132
|
+
# split assigment operator += etc.
|
133
|
+
@assignmentOperatorSplits = []
|
134
|
+
|
135
|
+
# currentCall initially nil
|
136
|
+
@currentCall = nil
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
# @!endgroup
|
141
|
+
|
142
|
+
# ------------------------------------------------------------------
|
143
|
+
# @!group scope support
|
144
|
+
|
145
|
+
# @attr [Contract] currentContract which currently processing
|
146
|
+
attr_accessor :currentContract
|
147
|
+
|
148
|
+
# @attr [FunctionDefinition] currentFunction
|
149
|
+
attr_accessor :currentFunction
|
150
|
+
|
151
|
+
# @attr [IfStatement] currentIf
|
152
|
+
attr_accessor :currentIf
|
153
|
+
|
154
|
+
# @attr [Block] currentBlock
|
155
|
+
attr_accessor :currentBlock
|
156
|
+
|
157
|
+
# @attr [IfStatement] currentAssign
|
158
|
+
attr_accessor :currentAssign
|
159
|
+
|
160
|
+
# @attr [FunctionCall] currentCall
|
161
|
+
attr_accessor :currentCall
|
162
|
+
|
163
|
+
# @attr [Sexp] s(s(:parameter, name domain), ...)
|
164
|
+
attr_accessor :request
|
165
|
+
|
166
|
+
# @attr [Sexp] s(s(:parameter, name domain), ...)
|
167
|
+
attr_accessor :response
|
168
|
+
|
169
|
+
def contracted( expContract )
|
170
|
+
|
171
|
+
self.currentContract = expContract
|
172
|
+
begin
|
173
|
+
yield
|
174
|
+
ensure
|
175
|
+
self.currentContract = nil
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def functed( expFunctionDef )
|
180
|
+
self.currentFunction = expFunctionDef
|
181
|
+
begin
|
182
|
+
yield
|
183
|
+
ensure
|
184
|
+
self.currentFunction = nil
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
def funcCalled( exp )
|
190
|
+
self.currentCall = exp
|
191
|
+
begin
|
192
|
+
yield
|
193
|
+
ensure
|
194
|
+
self.currentCall = nil
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def iffed( expIf )
|
201
|
+
prevIf = currentIf
|
202
|
+
self.currentIf = expIf
|
203
|
+
begin
|
204
|
+
yield
|
205
|
+
ensure
|
206
|
+
self.currentIf = prevIf
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
def blocked( expBlock )
|
212
|
+
prevBlock = currentBlock
|
213
|
+
self.currentBlock = expBlock
|
214
|
+
begin
|
215
|
+
yield
|
216
|
+
ensure
|
217
|
+
self.currentBlock = prevBlock
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
def assigned( expAssign )
|
223
|
+
prevAssign = currentAssign
|
224
|
+
self.currentAssign = expAssign
|
225
|
+
begin
|
226
|
+
yield
|
227
|
+
ensure
|
228
|
+
self.currentAssign = prevAssign
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
# @!endgroup
|
236
|
+
|
237
|
+
# ------------------------------------------------------------------
|
238
|
+
# @!group Rules triggering actions
|
239
|
+
|
240
|
+
# @return [Boolean] true if +expFunction+ is constructor for +currentContract+
|
241
|
+
def isConstructor( expFunction )
|
242
|
+
currentContract && expFunction.name == currentContract.name
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
# @!endgroup
|
247
|
+
|
248
|
+
|
249
|
+
# ------------------------------------------------------------------
|
250
|
+
# @!group Tree traversal
|
251
|
+
|
252
|
+
def process_GlobalScope( exp )
|
253
|
+
logger.debug "#{__method__}: exp=#{exp}" if logger.debug?
|
254
|
+
|
255
|
+
# wrap
|
256
|
+
contracted( exp ) do
|
257
|
+
process_rest( exp )
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
def process_ContractDefinition( exp )
|
264
|
+
logger.debug "#{__method__}: exp=#{exp}" if logger.debug?
|
265
|
+
|
266
|
+
# wrap
|
267
|
+
contracted( exp ) do
|
268
|
+
|
269
|
+
logger.debug "#{__method__}: start iterating FindVariableDeclarations for exp=#{exp}" if logger.debug?
|
270
|
+
FindVariableDeclarations.new( self, options ).process( exp )
|
271
|
+
FindMissingSetters.new( self, options ).process( exp )
|
272
|
+
|
273
|
+
process_rest( exp )
|
274
|
+
end
|
275
|
+
s()
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# see if it is a constructor - toggle if not
|
280
|
+
#
|
281
|
+
# - adds method #interfaceName
|
282
|
+
#
|
283
|
+
def process_FunctionDefinition( exp )
|
284
|
+
logger.debug "#{__method__}: exp=#{exp}" if logger.debug?
|
285
|
+
if isConstructor( exp )
|
286
|
+
logger.info "#{__method__}: consructor already defined #{exp}"
|
287
|
+
@needConstructor = false
|
288
|
+
interfaceName = "#{currentContract.name}()"
|
289
|
+
else
|
290
|
+
interfaceName = "#{currentContract.name}(#{exp.name})"
|
291
|
+
end
|
292
|
+
|
293
|
+
if !exp.respond_to?( :interfaceName ) then
|
294
|
+
logger.info "#{__method__}: addeded method :interfaceName to return #{interfaceName}"
|
295
|
+
SexpUtils.defineInterfaceName( exp, interfaceName )
|
296
|
+
# exp.define_singleton_method( :interfaceName ) do
|
297
|
+
# interfaceName
|
298
|
+
# end
|
299
|
+
end
|
300
|
+
|
301
|
+
# parameter lists
|
302
|
+
functed( exp ) do
|
303
|
+
|
304
|
+
logger.debug "#{__method__}: exp=#{exp}" if logger.debug?
|
305
|
+
formalParametersToFunction = exp.parameterList.parameters ? exp.parameterList.parameters.map { |varDecl| varDecl.name } : []
|
306
|
+
|
307
|
+
# should add parameters which are NOT found on current formal parameter list
|
308
|
+
parametersNeeds = TlaElementText.commonMsgProperties( 'request', isConstructor(exp)).
|
309
|
+
select { |par| !formalParametersToFunction.include?(par[1] ) }
|
310
|
+
|
311
|
+
if parametersNeeds.any?
|
312
|
+
logger.info "#{__method__}: parametersNeeds=#{parametersNeeds} in #{exp.name}"
|
313
|
+
@missing_request_parameters << s(exp, parametersNeeds )
|
314
|
+
end
|
315
|
+
|
316
|
+
# process function stmts
|
317
|
+
process_rest( exp )
|
318
|
+
end
|
319
|
+
s()
|
320
|
+
end
|
321
|
+
|
322
|
+
def process_Block( exp )
|
323
|
+
logger.debug "#{__method__}: #{exp}" if logger.debug?
|
324
|
+
|
325
|
+
#wrap
|
326
|
+
blocked( exp ) do
|
327
|
+
process_rest( exp )
|
328
|
+
end
|
329
|
+
s()
|
330
|
+
end
|
331
|
+
|
332
|
+
##
|
333
|
+
# Identify: 'if ( !msg.sender.send( msg.value ) )'
|
334
|
+
def process_IfStatement( exp )
|
335
|
+
logger.debug "#{__method__}: #{exp}" if logger.debug?
|
336
|
+
|
337
|
+
# if
|
338
|
+
iffed( exp ) do
|
339
|
+
process( exp.condition )
|
340
|
+
end
|
341
|
+
|
342
|
+
# then
|
343
|
+
blocked( exp.then_branch ) do
|
344
|
+
process( exp.then_branch )
|
345
|
+
end
|
346
|
+
|
347
|
+
# else
|
348
|
+
if exp.else_branch
|
349
|
+
blocked( exp.else_branch ) do
|
350
|
+
process( exp.else_branch )
|
351
|
+
end
|
352
|
+
end
|
353
|
+
s()
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
|
358
|
+
##
|
359
|
+
# Identify 'var = func()'
|
360
|
+
def process_ExpressionStatement( exp )
|
361
|
+
logger.debug "#{__method__}: #{exp}" if logger.debug?
|
362
|
+
assigned( exp ) do
|
363
|
+
process_rest( exp )
|
364
|
+
end
|
365
|
+
s()
|
366
|
+
end
|
367
|
+
|
368
|
+
def process_FunctionCallReadReturn( exp )
|
369
|
+
logger.debug "#{__method__}: #{exp}" if logger.debug?
|
370
|
+
# FunctionCallReadReturn indicates that canonzation has
|
371
|
+
# already taken place. no need to go down anymore
|
372
|
+
s()
|
373
|
+
end
|
374
|
+
|
375
|
+
def process_Assignment( exp )
|
376
|
+
logger.debug "#{__method__}: #{exp}" if logger.debug?
|
377
|
+
if exp.operator != '='
|
378
|
+
logger.info "#{__method__}: split assignment #{exp}"
|
379
|
+
assignmentOperatorSplits << exp
|
380
|
+
end
|
381
|
+
process_rest( exp )
|
382
|
+
end
|
383
|
+
|
384
|
+
def process_FunctionCall( exp )
|
385
|
+
logger.debug "#{__method__}: #{exp}" if logger.debug?
|
386
|
+
|
387
|
+
# split only fist level function in functionOnFunction -case
|
388
|
+
if currentAssign && currentCall.nil?
|
389
|
+
@functionCallsToSplit << s( currentBlock, currentAssign, exp )
|
390
|
+
logger.info "#{__method__}: function-call in assingment split #{currentAssign}"
|
391
|
+
elsif currentIf && currentCall.nil?
|
392
|
+
@functionCallsToSplit << s( currentBlock, currentIf, exp )
|
393
|
+
logger.info "#{__method__}: function-call in if split #{currentIf}"
|
394
|
+
end
|
395
|
+
|
396
|
+
funcCalled( exp ) do
|
397
|
+
process_rest( exp )
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def process_Literal( exp )
|
402
|
+
logger.debug "#{__method__}: #{exp}" if logger.debug?
|
403
|
+
# should literal be remapped (e.g. true -> TRUE),
|
404
|
+
# no need to remap integers
|
405
|
+
tlaValue = checkLiteralMapping( exp )
|
406
|
+
if tlaValue
|
407
|
+
# add to task list
|
408
|
+
logger.info "#{__method__}: map-literal tlaValue=#{tlaValue} on #{exp}"
|
409
|
+
|
410
|
+
@map_literalValue << s(exp, tlaValue)
|
411
|
+
end
|
412
|
+
process_rest( exp )
|
413
|
+
end
|
414
|
+
|
415
|
+
# def match( parameter )
|
416
|
+
# matchRule.is_a?( String ) ? parameter.name == matchRule : (parameter.name =~ matchRule) != nil
|
417
|
+
# end
|
418
|
+
|
419
|
+
|
420
|
+
##
|
421
|
+
# @return [Hash] mapper
|
422
|
+
# @option mapper [:Symbol] :rules defining mapping, nil if no mapping needed
|
423
|
+
private def findMapperHash( expLiteral )
|
424
|
+
mapperes = LITERAL_MAPPINGS
|
425
|
+
literalType = expLiteral.type.to_s
|
426
|
+
mapperes.each do |key,mapper|
|
427
|
+
# quit block && subroutine if found
|
428
|
+
return mapper if key.is_a?( String ) ? literalType == key : (literalType =~ key) != nil
|
429
|
+
end
|
430
|
+
|
431
|
+
nil
|
432
|
+
end
|
433
|
+
|
434
|
+
# @!endgroup
|
435
|
+
|
436
|
+
# ------------------------------------------------------------------
|
437
|
+
# @!group utils
|
438
|
+
|
439
|
+
##
|
440
|
+
# Check if literal should be remapped, and return mapper suggesion
|
441
|
+
# @return [Hash] tlaValue
|
442
|
+
# @option tlaValue [String] key as solcValue
|
443
|
+
# @option tlaValue [String] value in tla
|
444
|
+
private def checkLiteralMapping( expLiteral )
|
445
|
+
logger.debug "#{__method__}: check in solc type '#{expLiteral.type}' that value '#{expLiteral.value}' valid for tla " if logger.debug?
|
446
|
+
|
447
|
+
#
|
448
|
+
mapperHash = findMapperHash( expLiteral )
|
449
|
+
logger.debug "#{__method__}: mapperHash=#{mapperHash}" if logger.debug?
|
450
|
+
|
451
|
+
|
452
|
+
# Must be known literal type
|
453
|
+
raise SbuilderEtherumException, "Unkown literal type '#{expLiteral.type}', supported types #{mapperHash.keys}" if mapperHash.nil?
|
454
|
+
|
455
|
+
|
456
|
+
# No need to map if no rules defined
|
457
|
+
return nil unless mapperHash[:rules]
|
458
|
+
# Literal value valid TLA value in :rules
|
459
|
+
return nil if mapperHash[:rules][expLiteral.value]
|
460
|
+
|
461
|
+
# Invert mapper table for 'epx.type' i.e map solc=>tla
|
462
|
+
reverseMapper = mapperHash[:rules].inject( {}){ |solc2tla,(tla,solc)| solc2tla[solc] = tla; solc2tla }
|
463
|
+
|
464
|
+
# use inverted mapper to find TLA-name,
|
465
|
+
tlaValue = reverseMapper[expLiteral.value]
|
466
|
+
raise SbuilderEtherumException, "Could not map literal value '#{expLiteral.value}' for #{expLiteral} using #{reverseMapper}" unless tlaValue
|
467
|
+
logger.info "#{__method__}: map literal value '#{expLiteral.value}' to TLA value '#{tlaValue}' in #{expLiteral}"
|
468
|
+
tlaValue
|
469
|
+
|
470
|
+
end
|
471
|
+
|
472
|
+
|
473
|
+
# @!endgroup
|
474
|
+
|
475
|
+
# ------------------------------------------------------------------
|
476
|
+
# @!group Specialized processeros
|
477
|
+
|
478
|
+
##
|
479
|
+
# For each contract 'VariableDeclaration' remove in
|
480
|
+
# +needVariableDeclarations+, and add +neededGetters+.
|
481
|
+
#
|
482
|
+
|
483
|
+
class FindVariableDeclarations < SexpProcessorEthereum
|
484
|
+
|
485
|
+
# @attr [SexpProcessorNeedToCanonize] parent
|
486
|
+
attr_reader :parent
|
487
|
+
|
488
|
+
def initialize( parent, options={} )
|
489
|
+
super( options )
|
490
|
+
logger.debug "#{__method__}: created" if logger.debug?
|
491
|
+
@parent = parent
|
492
|
+
end
|
493
|
+
|
494
|
+
|
495
|
+
##
|
496
|
+
# Actions: 1 ) add contract variables to
|
497
|
+
# +parent.neededGetters+, remove from
|
498
|
+
# +parent.needVariableDeclarations+ 2) if variable declation
|
499
|
+
# does not have a name
|
500
|
+
def process_VariableDeclaration( exp )
|
501
|
+
logger.debug "#{__method__}: exp=#{exp}, exp.parent=#{exp.parent}" if logger.debug?
|
502
|
+
# parent.gettersNeeded << exp
|
503
|
+
|
504
|
+
if !exp.name or exp.name.length == 0
|
505
|
+
logger.info "#{__method__}: variable declared without name #{exp}"
|
506
|
+
parent.variable_declarations_without_name << exp
|
507
|
+
end
|
508
|
+
|
509
|
+
if exp.parent && exp.parent.sexp_type == :ContractDefinition
|
510
|
+
|
511
|
+
logger.debug "#{__method__}: variable declaration for contract, exp=#{exp}" if logger.debug?
|
512
|
+
|
513
|
+
# contract variable declared - remove it form the list
|
514
|
+
deleted = parent.needVariableDeclarations.delete( exp.name )
|
515
|
+
logger.debug "#{__method__}: variable already declared #{deleted}" if logger.debug?
|
516
|
+
|
517
|
+
# each contact varibale decl should have a getter
|
518
|
+
parent.neededGetters << exp.name
|
519
|
+
end
|
520
|
+
|
521
|
+
s()
|
522
|
+
end
|
523
|
+
|
524
|
+
end
|
525
|
+
|
526
|
+
class FindMissingSetters < SexpProcessorEthereum
|
527
|
+
|
528
|
+
# @attr [SexpProcessorNeedToCanonize] parent
|
529
|
+
attr_reader :parent
|
530
|
+
|
531
|
+
def initialize( parent, options={} )
|
532
|
+
super( options )
|
533
|
+
logger.debug "#{__method__}: created" if logger.debug?
|
534
|
+
@parent = parent
|
535
|
+
end
|
536
|
+
|
537
|
+
|
538
|
+
##
|
539
|
+
# remove from +parent.neededGetters+ if getter
|
540
|
+
def process_FunctionDefinition( exp )
|
541
|
+
logger.debug "#{__method__}: exp=#{exp}" if logger.debug?
|
542
|
+
|
543
|
+
# if getXaaB --> XaaB (or nil)
|
544
|
+
getterForVariable = exp.name[/get([A-Z]\w*)/, 1]
|
545
|
+
logger.debug "#{__method__}: exp.name=#{exp.name} --> extracted=#{getterForVariable}" if logger.debug?
|
546
|
+
|
547
|
+
# function name parses like getter
|
548
|
+
if ! getterForVariable.nil?
|
549
|
+
# xaaB --> xaaB
|
550
|
+
getterForVariable = getterForVariable[0,1].downcase + getterForVariable[1..-1]
|
551
|
+
logger.debug "#{__method__}: variable to get =#{getterForVariable}" if logger.debug?
|
552
|
+
|
553
|
+
# Getter implemented -> remove it from +parent.neededGetters+
|
554
|
+
parent.neededGetters.delete( getterForVariable )
|
555
|
+
end
|
556
|
+
|
557
|
+
s()
|
558
|
+
end
|
559
|
+
|
560
|
+
|
561
|
+
end
|
562
|
+
|
563
|
+
|
564
|
+
|
565
|
+
|
566
|
+
# @!endgroup
|
567
|
+
|
568
|
+
|
569
|
+
end
|
570
|
+
|
571
|
+
end
|
572
|
+
end
|