sbuilder-ethereum 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|