sbuilder-eth 0.0.4

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.
@@ -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
+