sbuilder-eth 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.org +19 -0
- data/VERSION +1 -0
- data/bin/state-explorer.sh +215 -0
- data/lib/eth/al_api.rb +12 -0
- data/lib/eth/ast_sexp.rb +519 -0
- data/lib/eth/constants.rb +354 -0
- data/lib/eth/ethereum.rb +2054 -0
- data/lib/eth/ethereum_expression.rb +476 -0
- data/lib/eth/exception.rb +9 -0
- data/lib/eth/global_scope.rb +100 -0
- data/lib/eth/module.rb +18 -0
- data/lib/eth/sexp_processor.rb +66 -0
- data/lib/eth/sexp_processor_call_separator.rb +163 -0
- data/lib/eth/sexp_processor_getter.rb +125 -0
- data/lib/eth/sexp_processor_resolve.rb +122 -0
- data/lib/eth/sexp_processor_scope.rb +355 -0
- data/lib/eth/sexp_utils.rb +214 -0
- data/lib/eth/solidity_compiler.rb +145 -0
- data/lib/eth/solidity_loader.rb +53 -0
- data/lib/eth/solidity_translator.rb +840 -0
- data/lib/mixer/reference.rb +30 -0
- data/lib/mixer/scope.rb +100 -0
- data/lib/mixer/scoped.rb +18 -0
- data/lib/plugin/controller.rb +267 -0
- data/lib/plugin/module.rb +3 -0
- data/lib/plugin/plugin.rb +33 -0
- data/lib/sbuilder-eth.rb +6 -0
- data/sbuilder-eth.gemspec +38 -0
- metadata +149 -0
@@ -0,0 +1,476 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Sbuilder
|
3
|
+
|
4
|
+
module Eth
|
5
|
+
|
6
|
+
# Module to include to Ethreum class containing methods to
|
7
|
+
# translate Solidity expression to Al language expressions.
|
8
|
+
module EthereumExpression
|
9
|
+
|
10
|
+
# ------------------------------------------------------------------
|
11
|
+
# @!group Distpath reference to lvalue
|
12
|
+
|
13
|
+
# @!endgroup
|
14
|
+
|
15
|
+
|
16
|
+
# Dispatch lval reference based lval AST node sexp_type.
|
17
|
+
#
|
18
|
+
# @return [TlaSexp] :Identifier -> name (='value' attribute),
|
19
|
+
# :IndexAccess => [ raise TODO ]
|
20
|
+
def lvalAccessDistpatcher
|
21
|
+
@lvalAccessDistpatched || {
|
22
|
+
:Identifier => ->(identifierAst) { identifierAst['value'] },
|
23
|
+
:IndexAccess => ->(indexAccessAst) do
|
24
|
+
#intetifierAst = indexAccessAst.identifier
|
25
|
+
indexerAst = indexAccessAst.indexer
|
26
|
+
indexer = Ethereum.dispatcher( expressionDispatcher, indexerAst.sexp_type, indexerAst)
|
27
|
+
alApi.tlaRecordIndex(indexAccessAst.identifier['value'], indexer )
|
28
|
+
end,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# ------------------------------------------------------------------
|
33
|
+
# @!group Expression translation
|
34
|
+
|
35
|
+
# Translate 'expressionAst' using {#expressionDispatcher}.
|
36
|
+
#
|
37
|
+
# @return [Al::Expression] trasnalation of 'expressionAst'
|
38
|
+
#
|
39
|
+
def dispatchExpression( expressionAst ) #
|
40
|
+
@logger.debug( "#{__method__}: expressionAst=#{expressionAst}" ) if @logger.debug?
|
41
|
+
Ethereum.dispatcher( expressionDispatcher, expressionAst.sexp_type, expressionAst)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Dispatch tranlation for Solidity AST expression based
|
45
|
+
# sexp_type of expression sexp_type.
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# @return [Hash] :sexp_type => lambda(AstSexp) to tranlate
|
49
|
+
# Solidity AST node to AL language expression
|
50
|
+
def expressionDispatcher
|
51
|
+
@expressionDispatcher ||= {
|
52
|
+
:ExpressionContext => ->(contextAst) do
|
53
|
+
# dispatch again using sexp_type of the wrapped expressionAst
|
54
|
+
Ethereum.dispatcher( expressionDispatcher, contextAst.expressionAst.sexp_type, contextAst)
|
55
|
+
end,
|
56
|
+
:BinaryOperation => method(:binaryExpr),
|
57
|
+
:Literal => method(:constantExpr),
|
58
|
+
:FunctionCall => method(:functionResponseExpr),
|
59
|
+
:Identifier => method(:identifierExpr),
|
60
|
+
:MemberAccess => method( :memberAccessExpr),
|
61
|
+
:IndexAccess => method( :indexAccessExpr ),
|
62
|
+
:TupleExpression => method( :tupleExpression ),
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
# Translate expression for 'functionCall' to read operator call
|
67
|
+
# reading function response, and accessing return value.
|
68
|
+
#
|
69
|
+
# Assume: pre-processor has added function call just prior to
|
70
|
+
# the statement accessing function response value)
|
71
|
+
#
|
72
|
+
# TODO: should add support to manage tuple return values from
|
73
|
+
# function call
|
74
|
+
#
|
75
|
+
# @param ast [ExpressionContext,:FunctionCall] function call (or
|
76
|
+
# function wrapped into context) to create expression to
|
77
|
+
# access response from function call
|
78
|
+
|
79
|
+
def functionResponseExpr( ast )
|
80
|
+
@logger.info "#{__method__}: ast=#{ast}" if @logger.debug?
|
81
|
+
|
82
|
+
if ast.sexp_type == :ExpressionContext
|
83
|
+
functionCallStmt = ast.expressionAst
|
84
|
+
else
|
85
|
+
functionCallStmt = ast
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# call target
|
90
|
+
functionCalled = functionCallStmt.callTarget # functionCallStmt.functionCalled.reference
|
91
|
+
contractCalled = functionCalled.enclosingScope
|
92
|
+
@logger.info "#{__method__} called= #{contractCalled['name']}(#{functionCalled['name']})"
|
93
|
+
|
94
|
+
# TODO: add suppport for tuples
|
95
|
+
if ( functionCallStmt.isConstructorCall )
|
96
|
+
# contrcutors return addres
|
97
|
+
returnParameter = Constants::FIELD_NAME_ADDRESS
|
98
|
+
else
|
99
|
+
# normal function
|
100
|
+
raise MissingImplementation, "Support only 1 return value, called f with #{functionCalled.responseParameters.parameters.length} params" if functionCalled.responseParameters.parameters.length != 1
|
101
|
+
returnParameter = functionCalled.responseParameters.parameters[0]['name']
|
102
|
+
end
|
103
|
+
|
104
|
+
# access return variable in function response
|
105
|
+
alApi.tlaRecordField(
|
106
|
+
alApi.tlaOperatorCall(alApi.tlaPlainname(Constants::SBUILDER_GET_RESPONSE), [exprInterfaceOperation(contractCalled['name'], functionCalled['name'])]),
|
107
|
+
returnParameter
|
108
|
+
)
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# Translate tupleExpression by translating each tuple element
|
114
|
+
# indididually with {#dispatchExpression}.
|
115
|
+
#
|
116
|
+
# @return [Array<AlExpression>] array of translated expressions
|
117
|
+
#
|
118
|
+
def tupleExpression( tupleAst )
|
119
|
+
|
120
|
+
@logger.info "#{__method__}: proces tuple with #{tupleAst.children.length} elements"
|
121
|
+
tupleAst.children.map do |tupleElement|
|
122
|
+
dispatchExpression( tupleElement )
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# Translate Solidity AST node of type :BinaryOperation to
|
129
|
+
# al-binary expression. Left hand side and right hand side
|
130
|
+
# expresions are dispatched using {#expressionDispatcher}, and
|
131
|
+
# operator translated using {#binaryOperator}. Evaluate in
|
132
|
+
# {ExpressionContext}, if 'ast' is defined within
|
133
|
+
# {ExpressionContext}.
|
134
|
+
#
|
135
|
+
# @param ast [ExpressionContext,Identifier] identifier (or
|
136
|
+
# identifier wrapped in context) to create expression for.
|
137
|
+
#
|
138
|
+
def binaryExpr( ast )
|
139
|
+
|
140
|
+
if ast.sexp_type == :ExpressionContext
|
141
|
+
|
142
|
+
# Evaluate lval and rval in ExpressionContext
|
143
|
+
lExpr = Ethereum.dispatcher( expressionDispatcher,
|
144
|
+
ast.expressionAst.children[0].sexp_type,
|
145
|
+
ExpressionContext.createExpressionContext( ast.expressionAst.children[0], ast.context )
|
146
|
+
)
|
147
|
+
rExpr = Ethereum.dispatcher( expressionDispatcher,
|
148
|
+
ast.expressionAst.children[1].sexp_type,
|
149
|
+
ExpressionContext.createExpressionContext( ast.expressionAst.children[1], ast.context )
|
150
|
+
)
|
151
|
+
operator = ast.expressionAst['operator']
|
152
|
+
|
153
|
+
else
|
154
|
+
# No context given - extract element of bin expression
|
155
|
+
lExpr = Ethereum.dispatcher( expressionDispatcher,
|
156
|
+
ast.children[0].sexp_type,
|
157
|
+
ast.children[0]
|
158
|
+
)
|
159
|
+
operator = ast['operator']
|
160
|
+
rExpr = Ethereum.dispatcher( expressionDispatcher,
|
161
|
+
ast.children[1].sexp_type,
|
162
|
+
ast.children[1]
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
alApi.binaryExpression do
|
167
|
+
lval lExpr
|
168
|
+
op binaryOperator(operator)
|
169
|
+
rval rExpr
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
# Translate 'solidityOperator' to 'alOperator. Raise
|
176
|
+
# {#MissingImplementation} if no translation found.
|
177
|
+
def binaryOperator( solidityOperator )
|
178
|
+
# TODO : map to AL-constants
|
179
|
+
solidityOperators = {
|
180
|
+
"*" => :mult,
|
181
|
+
"+" => :plus,
|
182
|
+
"-" => :minus,
|
183
|
+
"&&" => :and,
|
184
|
+
"||" => :or,
|
185
|
+
"==" => :equal,
|
186
|
+
"!=" => :unequal,
|
187
|
+
">=" => :ge,
|
188
|
+
">" => :gt,
|
189
|
+
"<" => :lt,
|
190
|
+
"<=" => :le,
|
191
|
+
}
|
192
|
+
alOperator = solidityOperators[solidityOperator]
|
193
|
+
raise MissingImplementation, "Unknown solidity operator #{solidityOperator} - known Solidity operators #{solidityOperators.keys.join(',')}" if alOperator.nil?
|
194
|
+
alOperator
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
# Translate Solidity :Literal to AL Constant
|
199
|
+
# expression. Translation inspects AST 'type' attribute to
|
200
|
+
# choose correct intepration for AST 'value' attribute.
|
201
|
+
#
|
202
|
+
# @param ast [ExpressionContext,Constant] constant (or constant
|
203
|
+
# wrapped in context) to create expression for.
|
204
|
+
#
|
205
|
+
#
|
206
|
+
def constantExpr( ast )
|
207
|
+
|
208
|
+
# Context does no impact constant trasnlation
|
209
|
+
if ast.sexp_type == :ExpressionContext
|
210
|
+
constantAst = ast.expressionAst
|
211
|
+
else
|
212
|
+
constantAst = ast
|
213
|
+
end
|
214
|
+
|
215
|
+
case constantAst.attribute("type")
|
216
|
+
when /^literal_string/
|
217
|
+
alApi.constantExpression do
|
218
|
+
value constantAst.attribute('value')
|
219
|
+
end
|
220
|
+
when /^int_const */
|
221
|
+
alApi.constantExpression do
|
222
|
+
value constantAst.attribute('value').to_i
|
223
|
+
end
|
224
|
+
when /^bool/
|
225
|
+
alApi.constantExpression do
|
226
|
+
value constantAst.attribute('value') == "true"
|
227
|
+
end
|
228
|
+
else
|
229
|
+
raise TranslatorException, "Missing implementation for constant expression type '#{constantAst.attribute('type')}' in #{constantAst}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Create expression to access member in an identifier.
|
234
|
+
#
|
235
|
+
# Implementation find path for member variables, and creates an
|
236
|
+
# {#identifierExpression}. expression to access member of the
|
237
|
+
# identifier of 'memberAccessAst'
|
238
|
+
#
|
239
|
+
# @param ast [ExpressionContext,MemberAccess] MemberAccess (or
|
240
|
+
# MemberAccess wrapped in context) to create expression
|
241
|
+
# for.
|
242
|
+
#
|
243
|
+
def memberAccessExpr( ast )
|
244
|
+
@logger.debug "#{__method__}: ast=#{ast}" if @logger.debug?
|
245
|
+
|
246
|
+
if ast.sexp_type == :ExpressionContext
|
247
|
+
memberAccessAst = ast.expressionAst
|
248
|
+
# Evaluate idExpression within context
|
249
|
+
idExpression = Ethereum.dispatcher( expressionDispatcher,
|
250
|
+
ast.expressionAst.identifierAst.sexp_type,
|
251
|
+
ExpressionContext.createExpressionContext( ast.expressionAst.identifierAst, ast.context )
|
252
|
+
)
|
253
|
+
|
254
|
+
else
|
255
|
+
memberAccessAst = ast
|
256
|
+
# Create id expression
|
257
|
+
idExpression = Ethereum.dispatcher( expressionDispatcher,
|
258
|
+
ast.identifierAst.sexp_type,
|
259
|
+
ast.identifierAst )
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
@logger.debug "#{__method__}: memberAccessAst.member=#{memberAccessAst.memberName}, idExpression=#{idExpression}" if @logger.debug?
|
264
|
+
# Translation to 'idExpression.member'
|
265
|
+
alApi.tlaRecordField( idExpression, memberAccessAst.memberName )
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
# Create expression for Solidity identifier. Evaluate identifier
|
271
|
+
# in 3 cases 1) in existing contract context (e.g. assign
|
272
|
+
# statement) 2) in context (but not for contract) 3) without
|
273
|
+
# context.
|
274
|
+
#
|
275
|
+
# Expression identifier may be available in execution context,
|
276
|
+
# for example in TLA action updating contract variable uses set
|
277
|
+
# operation and an iteration variable for contracts. In this
|
278
|
+
# case, reference to a contract should be resolved to set
|
279
|
+
# iteration variable.
|
280
|
+
#
|
281
|
+
#
|
282
|
+
#
|
283
|
+
# @param ast [ExpressionContext,Identifier] identifier (or
|
284
|
+
# identifier wrapped in context) to create expression for.
|
285
|
+
#
|
286
|
+
# @return [Al::Expression] 1) Al expression such as 'a.idName'
|
287
|
+
# if ast.sexp_type == :ExpressionContext && context for
|
288
|
+
# scope of variable declation found in context. 2)
|
289
|
+
# create expression using {#identifierReference} - else
|
290
|
+
def identifierExpr( ast )
|
291
|
+
@logger.debug "#{__method__}: ast=#{ast}" if @logger.debug?
|
292
|
+
|
293
|
+
if ast.sexp_type == :ExpressionContext && ast.getContext( ast.expressionAst.reference.scopeDefining.sexp_type ) && ast.expressionAst['value'] != Constants::SOL_THIS
|
294
|
+
|
295
|
+
# if context found for variable scope
|
296
|
+
translation = alApi.tlaRecordField(
|
297
|
+
ast.getContext( ast.expressionAst.reference.scopeDefining.sexp_type ),
|
298
|
+
ast.expressionAst['value']
|
299
|
+
)
|
300
|
+
|
301
|
+
elsif ast.sexp_type == :ExpressionContext
|
302
|
+
|
303
|
+
# in context but no match -> continue evaluation in context
|
304
|
+
translation = alApi.expression(identifierReference( ast.expressionAst ))
|
305
|
+
|
306
|
+
else
|
307
|
+
|
308
|
+
# Resolve direct reference to identifier
|
309
|
+
translation = alApi.expression(identifierReference( ast ))
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
@logger.debug( "#{__method__}: translation=#{translation.strOutput}") if @logger.debug?
|
314
|
+
translation
|
315
|
+
end
|
316
|
+
|
317
|
+
|
318
|
+
# Create expression to access indexed element of identifer. Use
|
319
|
+
# {#expressionDispatcher} to dispatch 'identifier' and 'indexer'
|
320
|
+
# expresion of IndexAccess AST node (possible wrapped within
|
321
|
+
# ExpressionContext).
|
322
|
+
#
|
323
|
+
# @param ast [ExpressionContext,IndexAccess] IndexAccess (or
|
324
|
+
# IndexAccess wrapped in context) to create expression
|
325
|
+
# for.
|
326
|
+
#
|
327
|
+
#
|
328
|
+
# @return [Al::Expression] expression to access indexed member
|
329
|
+
def indexAccessExpr( ast )
|
330
|
+
@logger.debug "#{__method__}: ast=#{ast}" if @logger.debug?
|
331
|
+
|
332
|
+
if ast.sexp_type == :ExpressionContext
|
333
|
+
indexerAst = ast.expressionAst
|
334
|
+
# eval identifier with context
|
335
|
+
indexExpr = Ethereum.dispatcher(
|
336
|
+
expressionDispatcher,
|
337
|
+
indexerAst.identifier.sexp_type,
|
338
|
+
ExpressionContext.createExpressionContext(indexerAst.identifier, ast.context )
|
339
|
+
)
|
340
|
+
indexer = Ethereum.dispatcher(
|
341
|
+
expressionDispatcher, indexerAst.indexer.sexp_type,
|
342
|
+
ExpressionContext.createExpressionContext(indexerAst.indexer, ast.context )
|
343
|
+
)
|
344
|
+
else
|
345
|
+
indexAccessAst = ast
|
346
|
+
indexExpr = Ethereum.dispatcher(
|
347
|
+
expressionDispatcher,
|
348
|
+
indexerAst.identifier.sexp_type,
|
349
|
+
indexerAst.identifier
|
350
|
+
)
|
351
|
+
indexer = Ethereum.dispatcher(
|
352
|
+
expressionDispatcher, indexerAst.indexer.sexp_type,
|
353
|
+
indexerAst.indexer
|
354
|
+
)
|
355
|
+
end
|
356
|
+
|
357
|
+
alApi.tlaRecordIndex( indexExpr, indexer )
|
358
|
+
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
|
363
|
+
# @!endgroup
|
364
|
+
|
365
|
+
|
366
|
+
# ------------------------------------------------------------------
|
367
|
+
# @!group Resolve identifier reference
|
368
|
+
|
369
|
+
# Use dispatcher {#referenceContextDispatcher} to create a
|
370
|
+
# reference to 'identifierAst'.
|
371
|
+
#
|
372
|
+
# Impelementation user pointer chain
|
373
|
+
# identifierAst.reference.scopeDefining to find 1) variable
|
374
|
+
# declaration and 2) scope of declaration to dispatch correct
|
375
|
+
# translation method in {#referenceContextDispatcher}.
|
376
|
+
#
|
377
|
+
# @param identifierAst [Identifier] AST node to resolve.
|
378
|
+
def identifierReference( identifierAst )
|
379
|
+
# identifierAst = context[:identifierAst]
|
380
|
+
@logger.debug "#{__method__}: identifierAst=#{identifierAst}" if @logger.debug?
|
381
|
+
@logger.info "#{__method__}: ident:'#{identifierAst['value']}'" +
|
382
|
+
" decl.ref='#{identifierAst.reference.key?( "name") ? identifierAst.reference['name'] : '??' }:#{identifierAst&.reference.sexp_type}'" +
|
383
|
+
", scope='#{identifierAst.reference.scopeDefining.respond_to?( :sexp_type) ? identifierAst.reference.scopeDefining.sexp_type : identifierAst.reference.scopeDefining.class }'"
|
384
|
+
|
385
|
+
ref = identifierAst.reference.scopeDefining
|
386
|
+
|
387
|
+
# Reference has already been resolde (e.g. :ModifierIncation)
|
388
|
+
return( ref ) if ref.is_a? Sbuilder::Al::Model::Expression
|
389
|
+
#
|
390
|
+
Ethereum.dispatcher( referenceContextDispatcher, ref.sexp_type, identifierAst )
|
391
|
+
end
|
392
|
+
|
393
|
+
|
394
|
+
# Reference to identifier depends on the type of the scope,
|
395
|
+
# where the variable, referenced by 'identifierAst', is declared
|
396
|
+
# in.
|
397
|
+
#
|
398
|
+
# Scope may be ::GlobalScope -> e.g. this, :ContractDefinition
|
399
|
+
# --> contract member variable #{contractContextReference},
|
400
|
+
# :FunctionDefinition --> function local varibale
|
401
|
+
# {#functionContextReference}, :ParameterList --> to access
|
402
|
+
# Solidity 'msg' {#parameterContextReference},
|
403
|
+
#
|
404
|
+
def referenceContextDispatcher
|
405
|
+
@referenceContextDispatcher ||= {
|
406
|
+
:GlobalScope => method(:globalContextReference),
|
407
|
+
:ContractDefinition =>method(:contractContextReference),
|
408
|
+
:FunctionDefinition =>method(:functionContextReference),
|
409
|
+
:ParameterList=>method(:parameterContextReference),
|
410
|
+
}
|
411
|
+
end
|
412
|
+
|
413
|
+
# Currently runnign contract found in local variable 'refRunningContractAddress'
|
414
|
+
#
|
415
|
+
# @return [Al::Reference] reference to currenly running contract
|
416
|
+
def globalContextReference(identifierAst)
|
417
|
+
@logger.debug "#{__method__}: identifierAst=#{identifierAst}" if @logger.debug?
|
418
|
+
raise "Supports only '#{Constants::SOL_THIS}' - unkwon #{identifierAst['value']}" unless identifierAst['value'] == Constants::SOL_THIS
|
419
|
+
|
420
|
+
refRunningContractAddress
|
421
|
+
end
|
422
|
+
|
423
|
+
# # Create a reference for an identifier in :ModifierDefinition
|
424
|
+
# # context, which has been invoked :ModifierInvocation for a
|
425
|
+
# # function (sexp_type :FunctionDefinition).
|
426
|
+
# def modifierContextReference( identifierAst )
|
427
|
+
# @logger.debug "#{__method__}: identifierAst=#{identifierAst}" if @logger.debug?
|
428
|
+
# functionAst = identifierAst.reference.scopeDefining
|
429
|
+
# raise "identifierAst=#{identifierAst}\n\nidentifierAst.reference=#{identifierAst.reference}\n\nfunctionAst=#{functionAst}"
|
430
|
+
# end
|
431
|
+
|
432
|
+
# Create a reference to member variable of currently running
|
433
|
+
# contract.
|
434
|
+
#
|
435
|
+
# Contract members variables are fields in records in
|
436
|
+
# 'storageRoot' variable. Current contract is pointed by
|
437
|
+
# {#refRunningContractAddress} (, which is local variable with
|
438
|
+
# the 'address' of currently running contract ).
|
439
|
+
#
|
440
|
+
def contractContextReference( identifierAst )
|
441
|
+
@logger.debug "#{__method__}: identifierAst=#{identifierAst}" if @logger.debug?
|
442
|
+
contract = identifierAst.reference.scopeDefining
|
443
|
+
if identifierAst['value'] == Constants::SOL_THIS
|
444
|
+
# this found in local varible thisCid
|
445
|
+
refRunningContractAddress
|
446
|
+
else
|
447
|
+
ethContractVariableReference( refStorageRoot, refRunningContractAddress, identifierAst['value'] )
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
# Translate reference to function local variable.
|
452
|
+
def functionContextReference( identifierAst )
|
453
|
+
@logger.debug "#{__method__}: identifierAst=#{identifierAst}" if @logger.debug?
|
454
|
+
function = identifierAst.reference.scopeDefining
|
455
|
+
contract = function.enclosingScope
|
456
|
+
|
457
|
+
ethFunctionParameterReference( contract['name'], function['name'] )
|
458
|
+
end
|
459
|
+
|
460
|
+
# Translate reference to an identifier in function paramers (=Solidity 'msg')
|
461
|
+
#
|
462
|
+
# Msg variable is accessed in a parameter passed to the
|
463
|
+
# procedure created to model 'contract' 'function'.
|
464
|
+
def parameterContextReference( identifierAst )
|
465
|
+
@logger.debug "#{__method__}: identifierAst=#{identifierAst}" if @logger.debug?
|
466
|
+
function = identifierAst.reference.scopeDefining.enclosingScope
|
467
|
+
contract = function.enclosingScope
|
468
|
+
ethFunctionParameterReference( contract['name'], function['name'], identifierAst['value'] )
|
469
|
+
end
|
470
|
+
|
471
|
+
|
472
|
+
# @!endgroup
|
473
|
+
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|