sbuilder-eth 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b62782275cc9f06d62897fda5dd8066bbd13f30a
4
+ data.tar.gz: ba81ab05d6ff401f4502c7fc6083f534030c45ec
5
+ SHA512:
6
+ metadata.gz: e440647e8d019f30fcea31dab54eb23ae4fc7db7fe02ded360eac0a5bbf2d09ab28f870a2e41ca82b3a97ea58427e8191b0e9463df4daecccc47e96a0c0d3aea
7
+ data.tar.gz: 1dafec9250e8e950cc1053a8745829cc43f311ed45a09adf56cd03454bb26a40bde9022a4170c595bad9e8783f9ae21606224cd5e7c9536dfe6aa23f79137cf2
@@ -0,0 +1,19 @@
1
+ # -*- mode: flyspell; mode: org- *-
2
+
3
+ * sbuilder-eth - Ethereum Plugin for =tla-sbuilder=
4
+
5
+ [[https://github.com/jarjuk/tla-sbuilder][tla-sbuilder]] is tool to generate runnable formal models in [[http://research.microsoft.com/en-us/um/people/lamport/tla/book.html][TLA+
6
+ language]] for [[https://github.com/jarjuk/tla-sbuilder#TARGET-SYSTEM][business IT systems]]. A formal model can be [[https://en.wikipedia.org/wiki/Model_checking][model
7
+ checked]] using [[http://research.microsoft.com/en-us/um/people/lamport/tla/tools.html][TLA+ Tools]].
8
+
9
+ [[https://github.com/jarjuk/sbuilder-eth][sbuillder-eth]] loads Ethreum Solidity implementations into
10
+ =tla-sbuilder= context using API Language (AL) provided by
11
+ [[https://github.com/jarjuk/sbuilder-al][sbuillder-al]] GEM.
12
+
13
+ *Notice* replaces a previous plugin [[https://github.com/jarjuk/sbuilder-ethereum][sbuilder-ethereum]].
14
+
15
+
16
+ * Solidity language support
17
+
18
+
19
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
@@ -0,0 +1,215 @@
1
+ #!/bin/bash
2
+
3
+
4
+ usage() {
5
+
6
+
7
+ cat <<EOF
8
+ Usage $0:
9
+
10
+ $0 file ([STATE][-STATE]|last) VARIBALE[:VARIABLE]* [VARIABLE=[!]value,[VARIABLE=[-]value]*]"
11
+
12
+ where
13
+ - STATE is number 1 or string 'last'
14
+ - VARIABLE is shown for commnad $0 file 1
15
+ - query is comma ',' separated list of variable queries
16
+ 'variable=value' or 'variable=!value"
17
+
18
+ Exmpale
19
+ $0 DUMP 1-99999 x1_addressPool now=1
20
+ EOF
21
+
22
+ }
23
+
24
+ if [ $# -lt 2 ]; then
25
+ usage
26
+ exit
27
+ fi
28
+
29
+ DUMP=$1; shift
30
+
31
+ STATE=$1; shift
32
+ KEY=$1; shift
33
+ QUERY=$1;shift
34
+
35
+ # echo gawk -vrange="$STATE" -vkey=$KEY -vquerystr=$QUERY
36
+
37
+ gawk -vrange="$STATE" -vkey=$KEY -vquerystr=$QUERY '
38
+ BEGIN {
39
+ empty_lines = 0
40
+ max_state = 0
41
+
42
+ # printf( "Starting state=%s, variable=%s\n", state, variable )
43
+
44
+ # manage state
45
+ # in_state - processing state
46
+ # in_variable - processing variable
47
+ # collect hash[in_state][variable]= ...state
48
+ delete states
49
+ }
50
+
51
+ # qs: var1=val1,var2=!val2
52
+ # @return 1 true if match all
53
+ function checkquery( qs, states, state ) {
54
+
55
+ # no state to explore
56
+ if ( length( states[state]) == 0 ) {
57
+ return( 0 )
58
+ }
59
+
60
+ # printf( "DBG: qs=%s\n", qs )
61
+ split( qs, queries, "," )
62
+ for ( query in queries ) {
63
+ # printf( "DBG: query=%s--> %s\n", query, queries[query] )
64
+ split( queries[query], q, "=" )
65
+ query_variable=q[1]
66
+ if ( substr(q[2],1,1) == "~" ) {
67
+ # regexp matach
68
+ query_value= substr(q[2],2)
69
+ match_equal = 0
70
+ negate = 0
71
+ }
72
+ # else if ( substr(q[2],1,1) == "-" ) {
73
+ # # negated match
74
+ # query_value= substr(q[2],2)
75
+ # match_equal = 0
76
+ # negate = 1
77
+ # }
78
+ else if ( substr(q[2],1,1) == "-" ) {
79
+ # negated match
80
+ query_value= substr(q[2],2)
81
+ match_equal = 1
82
+ negate = 1
83
+ }
84
+ else {
85
+ # match equal
86
+ query_value=q[2]
87
+ match_equal = 1
88
+ negate = 0
89
+ }
90
+
91
+ # printf( "DBG: match-equal=%d, var=%s, qv=%s, state=%s match=%s\n", match_equal, query_variable, query_value, state, match( states[state][query_variable], query_value) )
92
+ check = (match_equal && states[state][query_variable] == query_value) || (!match_equal && match( states[state][query_variable], query_value))
93
+ if ( !check && !negate ) {
94
+ # query failed: because no match made
95
+ return( 0 )
96
+ }
97
+ if ( check && negate ) {
98
+ # query failed: becaue match made - but should not have
99
+ return( 0 )
100
+ }
101
+
102
+ } # for q in queries
103
+
104
+ # all match
105
+ return( 1 )
106
+
107
+ }
108
+
109
+
110
+
111
+ END {
112
+
113
+
114
+
115
+ if ( key ) {
116
+
117
+ if ( range == "last" ) {
118
+ # last
119
+ start=0+max_state
120
+ end=0+max_state
121
+ }
122
+ else {
123
+
124
+ # 1-2
125
+ # 1-
126
+ # -2
127
+ # -
128
+
129
+ split( range, s, "-" )
130
+ start = 0+s[1]
131
+ # end = (0+s[2]<0+start)?0+start:0+s[2]
132
+ end = 0+s[2]
133
+ if (start == "" ){
134
+ start=1
135
+ }
136
+ }
137
+
138
+ split( key, variables, ":" )
139
+
140
+ # printf ("range=%s %d-%d querystr=%s\n", range, start, end, querystr )
141
+
142
+
143
+ for ( state=start; (end!= 0 && state <= end) || state<=max_state; state +=1 ) {
144
+ if ( !querystr || checkquery( querystr, states, state )) {
145
+ # no querystr or query match
146
+ for ( i in variables ) {
147
+ variable = variables[i]
148
+ # show timetick - instead of state number
149
+ now = states[state]["now"]
150
+ # printf( "%s@%s=%s\n", variable, state, states[state][variable] )
151
+ printf( "%s@%s=%s\n§\n", variable, now, states[state][variable] )
152
+ }
153
+ print ""
154
+ } # query
155
+ }
156
+ }
157
+ else if ( !key ) {
158
+
159
+ min=1
160
+ max=0
161
+
162
+ for ( key in states ) {
163
+ max=(0+max>0+key)?max:key
164
+ min=(0+min<0+key)?min:key
165
+ }
166
+ print "States: " min " - " max
167
+
168
+
169
+ print "variables:"
170
+ for ( key in states[1] ) {
171
+ printf( " %s\n", key )
172
+ }
173
+
174
+ print "Usage:"
175
+ print
176
+ print "'$0' file ([STATE][-STATE]|last) VARIBALE[:VARIABLE]* [VARIABLE=[!]value,[VARIABLE=[-]value]*]"
177
+ }
178
+
179
+ }
180
+
181
+ # State 9999:
182
+ match( $0, /State\s([0-9]+)/, ary) {
183
+ in_state = ary[1]
184
+ in_variable = 0
185
+ if ( in_state > max_state ) {
186
+ max_state = in_state
187
+ }
188
+ }
189
+
190
+ # collect variable. Notice before setting in_variable
191
+ in_variable && !/^\/\\/ {
192
+ # print "invariable " in_variable $0
193
+ states[in_state][in_variable]=states[in_state][in_variable] $0
194
+ # print "invariable " states[in_state][in_variable]
195
+ }
196
+
197
+ # /\ variabale = state info
198
+ match( $0, /^\/\\ ([^ ]*) = (.*)/, ary) {
199
+ # printf( "and *%s*\n", ary[1] )
200
+ # printf( "AND *%s*\n", ary[2] )
201
+ in_variable = ary[1]
202
+ # first variable content
203
+ states[in_state][in_variable] = ary[2]
204
+ }
205
+
206
+ # Emtpy line - discard && reset
207
+ /^\s*$/ {
208
+ in_variable = 0
209
+ empty_lines = empty_lines + 1
210
+ }
211
+
212
+
213
+ ' $DUMP
214
+
215
+ # | fold -w 80 -s
@@ -0,0 +1,12 @@
1
+ require "sbuilder-al"
2
+
3
+ module Sbuilder
4
+
5
+ module Eth
6
+
7
+ # Mix {Sbuilder::Al::Model::Api} to enable Sbuilder API Language (AL).
8
+ class AlApi
9
+ include Sbuilder::Al::Model::Api
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,519 @@
1
+ require 'sexp_processor'
2
+
3
+ module Sbuilder
4
+ module Eth
5
+
6
+ ##
7
+ # AstSexp subclasses Sexps, which furher subclasses Array.
8
+ #
9
+ # First element is a symbol defining sexp type. AstSexp uses hash
10
+ # as the second array element for storing attributes. Elements
11
+ # starting with position are AST tree children.
12
+ #
13
+ # Method {.from_hash} creates AstSexp object for AST structure
14
+ # from solc Solidity compiler. It recurses AST nodes along
15
+ # 'children' property, and constructs AstSexp -object using 'name'
16
+ # (for sexp type), and 'attribute' properties.
17
+ #
18
+
19
+ class AstSexp < Sexp
20
+
21
+
22
+ # ------------------------------------------------------------------
23
+ # @!group Constructor
24
+
25
+ # Create a new Sexp containing +args+.
26
+ def initialize(*args)
27
+ super(*args)
28
+ end
29
+
30
+ # Create AstSexp tree from 'hash' with 'name' property,
31
+ # 'attributes' -property and 'children' -property
32
+ #
33
+ # @param hash [Hash ] Hash to convert to sexp
34
+ #
35
+
36
+ def self.from_hash( hash )
37
+
38
+ # create sexp Node based on json['name']
39
+ result = new_node( hash )
40
+
41
+ # add children from hash['children']
42
+ hash['children'] && hash['children'].each do |c|
43
+ chld = self.from_hash(c)
44
+ # chld.setParent( result )
45
+ # result << chld
46
+ result.addChild( chld )
47
+ end
48
+
49
+ # rename childs if needed
50
+ result.finalizeChilds
51
+
52
+ result
53
+
54
+ end
55
+
56
+ # Add 'chld' to Sexp
57
+ def addChild( chld )
58
+ self << chld
59
+ end
60
+
61
+ # Insert 'child' in 'pos'
62
+ def insertChild( pos, child )
63
+ # children start counting from 2,...
64
+ self.insert(2+pos, child)
65
+ end
66
+
67
+
68
+ # After all childs processed
69
+ def finalizeChilds
70
+ # no-operation
71
+ end
72
+
73
+ # Find class to build for 'hash#name' and use constructor
74
+ # '.start' to construct an instance for dispatched class.
75
+ def self.new_node( hash )
76
+
77
+
78
+ # map solc node type to Sexp-class. This allows us to create
79
+ # AST nodes with better semantic information.
80
+ node2class = {
81
+ :ContractDefinition => ContractDefinition,
82
+ :FunctionDefinition => FunctionDefinition,
83
+ :ModifierDefinition => ModifierDefinition,
84
+ :ModifierInvocation => ModifierInvocation,
85
+ :ParameterList => ParameterList,
86
+ :VariableDeclaration => VariableDeclaration,
87
+ :Identifier => Identifier,
88
+ :UserDefinedTypeName => UserDefinedTypeName,
89
+ :NewExpression => NewExpression,
90
+ :IndexAccess => IndexAccess,
91
+ :Assignment => Assignment,
92
+ :MemberAccess => MemberAccess,
93
+ :IfStatement => IfStatement,
94
+ :FunctionCall => FunctionCall,
95
+ }
96
+
97
+ #
98
+ raise "Missing property 'name' on hash #{hash}" if hash['name'].nil?
99
+ sexp_type = hash['name'].to_sym
100
+ klass = node2class[sexp_type]
101
+
102
+ # default klass
103
+ klass = AstSexp if klass.nil?
104
+
105
+ ret = klass.start( klass, hash )
106
+ ret
107
+ end
108
+
109
+ def self.start( klass, hash )
110
+
111
+ attributes = hash['attributes'] && hash['attributes'].keys.reduce( {} ) do |memo,key|
112
+ # memo << [key,hash['attributes'][key]]
113
+ memo[key] = hash['attributes'][key]
114
+ memo
115
+ end || {}
116
+ # link to sourceLine from a string 'line:col:lenggth' e.g. 102:6:1
117
+ attributes['sourceLine'] = hash['src'] ? hash['src'].split(':')[0].to_i : nil
118
+ ary = [ hash['name'].to_sym ] + [ attributes ]
119
+ klass.new( *ary )
120
+
121
+ end
122
+
123
+
124
+ # @!endgroup
125
+
126
+ # ------------------------------------------------------------------
127
+ # @!group traverse support
128
+
129
+ # @return [s(AstSexp) nodes matching 'sym' or 'blk' returning
130
+ # true anywhere in sexp-tree
131
+ def nodes_with_match( sym=nil, &blk )
132
+ blk = ->( chldSexp ) { chldSexp.sexp_type == sym } unless sym.nil?
133
+ sexpAstArray = s() # []
134
+ deep_each { |n|
135
+ sexpAstArray << n if blk[n]
136
+ }
137
+ sexpAstArray
138
+ end
139
+
140
+ # Restore behaviour missing methods
141
+ def method_missing meth, *args
142
+ raise "Unknwon method '#{meth}' called on #{self}"
143
+ end
144
+
145
+ def respond_to? msg, private = false # :nodoc:
146
+ # why do I need this? Because ruby 2.0 is broken. That's why.
147
+ super
148
+ end
149
+
150
+
151
+ # @!endgroup
152
+
153
+ # ------------------------------------------------------------------
154
+ # @!group Access sexp instance properties
155
+
156
+ # @return [Hash] hash in position 1 for attribute mapping
157
+ def attributes
158
+ self[1] || {}
159
+ end
160
+
161
+ # @return [value] value of first attribute with key == 'attrName'
162
+ def attribute( attrName )
163
+ # attributes.select{ |a| a[0] == attrName }.map{ |a| a[1] }.first
164
+ attributes[attrName]
165
+ end
166
+
167
+
168
+ # String/symbols index access attributes, all other are
169
+ # delegated to parent (array class)
170
+ def [](index)
171
+ if index.is_a?(String) || index.is_a?(Symbol)
172
+ ret = attribute(index)
173
+ raise "Accessing non existing attribute '#{index}' in #{self}" if ret.nil?
174
+ return ret
175
+ end
176
+ super(index)
177
+ end
178
+
179
+ # Override square bracket assignment to work on strings/symbols
180
+ # on 'attributes' hash in pos 1 of the sexp
181
+ def []=(index, val)
182
+ if index.is_a?(String) || index.is_a?(Symbol)
183
+ self[1] = attributes.merge( { index => val })
184
+ return self
185
+ end
186
+ super(index,val)
187
+ end
188
+
189
+
190
+ # @return [Boolean] true if 'key' is present in '#attributes'
191
+ def key?( key )
192
+ attributes.key?( key )
193
+ end
194
+
195
+
196
+ # @param sym [Symbol] create 'blk' c.sexpt_type == 'sym' if
197
+ # 'sym' given
198
+ #
199
+ # @param blk [Block] to filter children element to return
200
+ #
201
+ # @return [Array] array of childs (starting from position 2)
202
+ # where &blk evaluates true, return all childs if no block given
203
+ def children( sym=nil, &blk )
204
+ blk = ->( chldSexp ) { chldSexp.sexp_type == sym } unless sym.nil?
205
+ blk.nil? ? self[2..-1] : self[2..-1].select{ |e| blk[e] }
206
+ end
207
+
208
+ def hasChild( sym=nil )
209
+ children( sym ).any?
210
+ end
211
+
212
+ # @!endgroup
213
+ end # class AstSexp < Sexp
214
+
215
+
216
+ # Class defining context Solidity expression 'expressionAst'
217
+ class ExpressionContext < AstSexp;
218
+ # Create ExpressionContext for 'expressionAst' in context 'ctx'
219
+ def self.createExpressionContext( expressionAst, ctx={} )
220
+ expressionContext = ExpressionContext.new( :ExpressionContext )
221
+ expressionContext["expressionAst"] = expressionAst
222
+ expressionContext["context"] = ctx
223
+ expressionContext
224
+ end
225
+ # @return [SexpAst] expressionAst wrapped within ExpressionContext
226
+ def expressionAst
227
+ self["expressionAst"]
228
+ end
229
+ def setContextContract( contract )
230
+ self["context"][:ContractDefinition] = contract
231
+ end
232
+ def context
233
+ self["context"]
234
+ end
235
+
236
+ # supports :ContractDefinition
237
+ def getContext( contextType )
238
+ # supportContextTypes = [:ContractDefinition]
239
+ # raise "Unsupportted contextType:#{contextType}, supported #{supportContextTypes.join(',')} " unless supportContextTypes.include?( contextType )
240
+ context[contextType]
241
+ end
242
+ end
243
+
244
+ class ContractDefinition < AstSexp;
245
+ include Scope;
246
+ include Scoped;
247
+ # @return [Array<AstSexp>] member :VariableDeclaration of contract
248
+ def memberVariables
249
+ children(:VariableDeclaration )
250
+ end
251
+ end
252
+
253
+ class FunctionOrModifierDefinition < AstSexp
254
+ include Scope
255
+ include Scoped
256
+ # @return [:ParameterList] input to Function/Modifier
257
+ def requestParameters
258
+ children[0]
259
+ end
260
+ def block
261
+ children(:Block).first
262
+ end
263
+ # statements are children of :Block sexp entry
264
+ def statements
265
+ block.children
266
+ end
267
+ end
268
+ class FunctionDefinition < FunctionOrModifierDefinition
269
+ # Make a difference between (Request)ParameterList and
270
+ # ResponseParameterList
271
+ def finalizeChilds
272
+ # change sexp-type
273
+ responseParameters[0] = :ResponseParameterList
274
+ end
275
+ def responseParameters
276
+ children[1]
277
+ end
278
+ def modifierInvocations
279
+ children(:ModifierInvocation)
280
+ end
281
+ end
282
+ class ModifierDefinition < FunctionOrModifierDefinition
283
+ # Statements until 'PlaceholderStatement'
284
+ def preambleStatements
285
+ statements.take_while{ |stmt| stmt.sexp_type != :PlaceholderStatement }
286
+ end
287
+
288
+ # Enable access to translated actual parameters
289
+ # for :ModifierInvocation during :FunctionDefintion
290
+ # translation.
291
+ # @# @!attribute [Hash] map formal parameter name to TlaSexp
292
+ attr_accessor :invocationCtx
293
+
294
+ def define(name, astSexp)
295
+ super( name, astSexp )
296
+ end
297
+
298
+
299
+ # @return [Scoped,ScopedWrapper] wraper if 'name' is symbol in
300
+ # :ModifierDefinition, else propagate resolve to scope
301
+ # hierarchy (to return Scoped)
302
+ def resolve( name )
303
+ return ScopedWrapper.wrap( self, name, getSymbol( name ) ) if getSymbol( name )
304
+ super( name )
305
+ end
306
+
307
+ end
308
+
309
+ # Wrap 'Scoped' (e.g. VariabeDeclation) 'astSexp' to allow access
310
+ # to evaluated arguments of a :ModifierInvcation in
311
+ # 'invocationCtx' -attribute of 'scopeDefining'.
312
+ class ScopedWrapper < AstSexp
313
+
314
+ def resolve( name )
315
+ scoped.resolve(name)
316
+ end
317
+
318
+ # @return [ScopedWrapper] constructor wrapping 'astSexp' with 'name' in 'scope'
319
+ def self.wrap( scope, name, astSexp )
320
+ wrapper = ScopedWrapper.new( :ScopedWrapper, astSexp.attributes, *astSexp.children )
321
+ wrapper.scopeDefining = scope
322
+ wrapper.scoped = astSexp
323
+ wrapper.name = name
324
+ wrapper
325
+ end
326
+
327
+
328
+
329
+ # @# @!attribute [Scoped] scoped being wrapped
330
+ attr_accessor :scoped
331
+
332
+ # @# @!attribute [String] name of scoped used in define
333
+ attr_accessor :name
334
+
335
+ # @# @!attribute [Scope] scopeDefining i.e. scope defining {#scoped}
336
+ attr_writer :scopeDefining
337
+
338
+ # @return [TlaExpression,Scope] invocationCtx return expression
339
+ # evaluated in @scopeDefining.invocationCtx, else return
340
+ # scope {#scopeDefining} for {#scoped} (=wrapped) object
341
+ def scopeDefining
342
+ # return evaluated value from context
343
+ if @scopeDefining.invocationCtx
344
+ ctxElement = @scopeDefining.invocationCtx[name]
345
+ raise "Missing evaluation for key '#{name}' of class #{scoped.class}, known keys in invocationCtx=#{@scopeDefining.invocationCtx.keys.join(',')}" if ctxElement.nil?
346
+ return ctxElement
347
+ end
348
+
349
+ @scopeDefining
350
+ end
351
+
352
+ end
353
+
354
+ class ModifierInvocation < AstSexp
355
+ # @return [:ModifierDefinition] :ModifierDefinition resolved for
356
+ # :ModifierInvocation :Identifier
357
+ def modifierDefinition
358
+ children(:Identifier).first.reference
359
+ end
360
+ # Actual parametes used in :ModifierInvocation
361
+ def arguments
362
+ children[1..-1]
363
+ end
364
+ end
365
+
366
+
367
+
368
+ class Assignment < AstSexp
369
+ def lval
370
+ children[0]
371
+ end
372
+ def rval
373
+ children[1]
374
+ end
375
+ end
376
+ class ParameterList < AstSexp;
377
+ include Scope
378
+ include Scoped
379
+
380
+ def parameters
381
+ children
382
+ end
383
+
384
+ # @return [VariableDeclaration] index-th parameter declaration
385
+ def parameterByIndex( index )
386
+ children[index]
387
+ end
388
+
389
+ end
390
+ class VariableDeclarationWithDomain < AstSexp
391
+ include Scoped
392
+ # @param name_domain [Array] array of length with name and
393
+ # domain
394
+ def self.create( name_domain)
395
+ VariableDeclarationWithDomain.new(:VariableDeclarationWithDomain,
396
+ {"name" => name_domain[0],
397
+ "domain" => name_domain[1]})
398
+ end
399
+ end
400
+ class VariableDeclaration < AstSexp
401
+ include Scoped
402
+ def variableType
403
+ children[0]
404
+ end
405
+ end
406
+ class Identifier < AstSexp; include Reference; end
407
+ class MemberAccess < AstSexp;
408
+ include Reference;
409
+ def memberName
410
+ self['member_name']
411
+ end
412
+ def struct
413
+ children[0]
414
+ end
415
+ # Identifier for the MemberAccess
416
+ def identifierAst
417
+ return struct if struct.sexp_type == :Identifier
418
+ struct.identifierAst
419
+ end
420
+ end
421
+ class UserDefinedTypeName < AstSexp; include Reference; end
422
+ class NewExpression < AstSexp
423
+ include Reference
424
+ def classConstructed
425
+ children(:UserDefinedTypeName).first
426
+ end
427
+ end
428
+ class IndexAccess < AstSexp;
429
+ # @return [Identifier] identifier indexed
430
+ def identifier
431
+ children[0]
432
+ end
433
+ def indexer
434
+ children[1]
435
+ end
436
+ end
437
+ class FunctionCall < AstSexp
438
+ # AST nodes
439
+ def functionCalled
440
+ children[0]
441
+ end
442
+ def arguments
443
+ children[1..-1]
444
+ end
445
+
446
+ # @return [true] for selfdestruct, revert, require etc
447
+ def isCallToReservedFunctionType
448
+ # case this.f.value(1).gas(2)(3,4,5)
449
+ return false if functionCalled.sexp_type == :FunctionCall
450
+ # case f(3,4,5) is selfdestruct, require etc.
451
+ return functionCalled.reference.respond_to?(:functionType) &&
452
+ functionCalled.reference.functionType == :reservedFunctionType
453
+ end
454
+ # @return [Boolean] true if functionCalled.sexp_type == :NewExpression
455
+ def isConstructorCall
456
+ functionCalled.sexp_type == :NewExpression
457
+ end
458
+
459
+ # @return [nil,FunctionCall] if functionCalled contains :MemberAccess to value
460
+ def valueModified
461
+ (nodes_with_match { |n| n.sexp_type == :FunctionCall && n.functionCalled.sexp_type == :MemberAccess && n.functionCalled["member_name"] == "value" } || []).first
462
+ end
463
+
464
+ # @return [Identifier,:MemberAccess] Solidity expression AST in
465
+ # :FunctionCall to dispatch the calle = functionCalled
466
+ # minus gas/value modifiers
467
+ def callExpression
468
+ functionCalled.nodes_with_match(:Identifier).first
469
+
470
+ # nodes_with_match do |n|
471
+ # n.sexp_type != :FunctionCall &&
472
+ # ( n.sexp_type == :Identifier ||
473
+ # ( [:MemberAccess].include?( n.sexp_type ) &&
474
+ # ! [Constants::FIELD_NAME_GAS, Constants::FIELD_NAME_VALUE ].include?( n["member_name"] ))
475
+ # )
476
+ # end.first
477
+ end
478
+
479
+ def callTarget
480
+ case functionCalled.sexp_type
481
+ when :MemberAccess
482
+ if functionCalled.struct.respond_to?( :callTarget )
483
+ # recurse FunctionCall (while value/gas modifier)
484
+ functionCalled.struct.callTarget
485
+ else
486
+ # if value/gas then ptr to modify fun else resolved-func
487
+ [Constants::FIELD_NAME_GAS, Constants::FIELD_NAME_VALUE].include?( functionCalled["member_name"] ) ?
488
+ functionCalled.struct.reference :
489
+ functionCalled.reference
490
+ end
491
+ when :Identifier
492
+ functionCalled.reference
493
+ when :NewExpression
494
+ functionCalled.reference
495
+ when :FunctionCall
496
+ # recursion :FunctionCall modifiers
497
+ functionCalled.callTarget
498
+ else
499
+ raise "Do know how to process '#{functionCalled.sexp_type}' to get 'callTarget' in #{self}"
500
+ end
501
+ end
502
+
503
+ end
504
+
505
+ class IfStatement < AstSexp
506
+ def condition
507
+ children[0]
508
+ end
509
+ def ifThen
510
+ children[1]
511
+ end
512
+ def elseThen
513
+ children[2]
514
+ end
515
+ end
516
+
517
+ end
518
+ end
519
+