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,119 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
|
4
|
+
module Sbuilder
|
5
|
+
module Ethereum
|
6
|
+
|
7
|
+
|
8
|
+
class Load
|
9
|
+
|
10
|
+
PROGNAME = nil # progname for logger default class name
|
11
|
+
include MyLogger # mix logger
|
12
|
+
|
13
|
+
|
14
|
+
def initialize( options = {} )
|
15
|
+
|
16
|
+
@options = options
|
17
|
+
@logger = getLogger( nil, options )
|
18
|
+
@logger.info "#{__method__}: initalized"
|
19
|
+
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# ------------------------------------------------------------------
|
25
|
+
# @!group Access solc AST for solidity source
|
26
|
+
|
27
|
+
# @param [String] solcAstPath path JSON file containing solc
|
28
|
+
# combined-AST
|
29
|
+
#
|
30
|
+
# @yield [SexpAst, compileUnit] ast process, string identifying
|
31
|
+
# ast (source+counter)
|
32
|
+
#
|
33
|
+
def processAllAsts( solcAstPath )
|
34
|
+
@logger.info "#{__method__}: solcAstPath=#{solcAstPath}"
|
35
|
+
solcHash = solc_input( solcAstPath )
|
36
|
+
|
37
|
+
solcHash['sourceList'].each do |solSource|
|
38
|
+
hashes = solcHash['sources'][solSource]['AST']
|
39
|
+
@logger.debug "#{__method__}: hash.keys=#{hashes.keys}" if @logger.debug?
|
40
|
+
hashes["children"].each_with_index do |ast,indx|
|
41
|
+
astName = "#{solSource}-#{indx}"
|
42
|
+
sourceUnit = SourceUnit.define( astName, SexpAst.build_sexp(ast) )
|
43
|
+
yield sourceUnit, astName
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Read solidyty source in +solcAstPath+, and
|
50
|
+
#
|
51
|
+
# @param [String] solcAstPath path JSON file containing solc
|
52
|
+
# combined-AST
|
53
|
+
#
|
54
|
+
# @param [Integer] index to contract to compile
|
55
|
+
#
|
56
|
+
# @return [SexpAst] sexp ast for solc json AST in {solc_hash},
|
57
|
+
# nil
|
58
|
+
def load_solc_ast_as_sexp( solcAstPath, index=0 )
|
59
|
+
|
60
|
+
@logger.info "#{__method__}: solcAstPath=#{solcAstPath}"
|
61
|
+
# read result of solc compiler
|
62
|
+
solcHash = solc_input( solcAstPath )
|
63
|
+
@logger.debug "#{__method__}: solcHash=#{solcHash.to_yaml}" if @logger.debug?
|
64
|
+
|
65
|
+
# extract AST from the result of solc compiler
|
66
|
+
solcSexpAst = solc_ast( solcHash, index )
|
67
|
+
|
68
|
+
solcSexpAst
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
#
|
74
|
+
# @param [String] solcAstPath path to solidity source file
|
75
|
+
#
|
76
|
+
# @return [hash] cached '@solcHash' parsed from JSON file in
|
77
|
+
# {solcAstPath} containing the AST from solc compilation
|
78
|
+
def solc_input( solcAstPath )
|
79
|
+
return @solcHash unless @solcHash.nil?
|
80
|
+
str = readSolc( solcAstPath )
|
81
|
+
@solcHash = JSON.parse( str )
|
82
|
+
end
|
83
|
+
|
84
|
+
# Read AST JSON string created by solc compiler for compiling
|
85
|
+
# solidity source in file {solcAstPath}.
|
86
|
+
#
|
87
|
+
# @param [String] solcAstPath path to solidity source
|
88
|
+
#
|
89
|
+
# @return [String] solc AST JSON in a string
|
90
|
+
def readSolc( solcAstPath )
|
91
|
+
File.read( solcAstPath )
|
92
|
+
end
|
93
|
+
|
94
|
+
# Create Sexp AST tree for +index+-th compile unit in solc AST
|
95
|
+
# in +solc_hash+
|
96
|
+
#
|
97
|
+
# @param [Hash] solcHash JSON hash created by solc compiler
|
98
|
+
#
|
99
|
+
# @option solcHash [sources.<file>.AST]
|
100
|
+
#
|
101
|
+
# @return [SexpAst] sexp ast for solc json AST in +solc_hash+,
|
102
|
+
# nil if +index+ exceeds number of sources in the +solcHash+.
|
103
|
+
def solc_ast( solcHash, index=0 )
|
104
|
+
return nil if solcHash['sourceList'].length <= index
|
105
|
+
solSource = solcHash['sourceList'][index]
|
106
|
+
@logger.info "#{__method__}: index:#{index}, solSource=#{solSource}"
|
107
|
+
# extract AST part from solcHash for {solSource}
|
108
|
+
hash = solcHash['sources'][solSource]['AST']
|
109
|
+
# converst hash to sexp AST tree
|
110
|
+
SexpAst.build_sexp( hash )
|
111
|
+
end
|
112
|
+
|
113
|
+
# @!endgroup
|
114
|
+
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
|
4
|
+
# ------------------------------------------------------------------
|
5
|
+
# Hack mustache to allow change default otag '{{' ctag '}}'
|
6
|
+
|
7
|
+
class Mustache
|
8
|
+
|
9
|
+
|
10
|
+
# Open mustache to define class accessors 'otag' and 'ctag'
|
11
|
+
def self.otag=( o )
|
12
|
+
@@otag = o
|
13
|
+
end
|
14
|
+
def self.ctag=( c )
|
15
|
+
@@ctag = c
|
16
|
+
end
|
17
|
+
def self.otag
|
18
|
+
@@otag ||= '{{'
|
19
|
+
end
|
20
|
+
def self.ctag
|
21
|
+
@@ctag ||= '}}'
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
class Template
|
26
|
+
|
27
|
+
# Open template to set otag/ctag on parser.
|
28
|
+
#
|
29
|
+
# Returns an array of tokens for a given template.
|
30
|
+
#
|
31
|
+
# @return [Array] Array of tokens.
|
32
|
+
#
|
33
|
+
def tokens(src = @source)
|
34
|
+
p = Parser.new
|
35
|
+
p.otag = Mustache.otag
|
36
|
+
p.ctag = Mustache.ctag
|
37
|
+
p.compile(src)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
module Sbuilder
|
44
|
+
module Ethereum
|
45
|
+
|
46
|
+
class Renderer < Mustache
|
47
|
+
|
48
|
+
# @attr [Logger] loger
|
49
|
+
attr_reader :logger
|
50
|
+
PROGNAME = nil # progname for logger default class name
|
51
|
+
include MyLogger # mix logger
|
52
|
+
|
53
|
+
|
54
|
+
# @attr [String:Array] partials must be set before +to_str+
|
55
|
+
attr_accessor :partials
|
56
|
+
|
57
|
+
# @attr [Hash] preferences modify mustache rendering (debug?)
|
58
|
+
attr_reader :preferences
|
59
|
+
|
60
|
+
def initialize( options={} )
|
61
|
+
# exception raise if accessing unknown property
|
62
|
+
self.raise_on_context_miss = true
|
63
|
+
|
64
|
+
@options = options
|
65
|
+
@logger = getLogger( nil, options )
|
66
|
+
@logger.info "#{__method__}: starting options=#{options}"
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def setPreferences( preferences )
|
71
|
+
@preferences = preferences
|
72
|
+
@logger.info "#{__method__}: preferences=#{preferences}"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Use 'to_str' instead of 'render' to use non-default otag/ctag's
|
76
|
+
def to_str( template, data=nil )
|
77
|
+
Mustache.otag = '{|'
|
78
|
+
Mustache.ctag = '|}'
|
79
|
+
|
80
|
+
begin
|
81
|
+
ret = render( template, data )
|
82
|
+
ensure
|
83
|
+
# restore default otag/ctag
|
84
|
+
Mustache.otag = '{{'
|
85
|
+
Mustache.ctag = '}}'
|
86
|
+
end
|
87
|
+
ret
|
88
|
+
end
|
89
|
+
|
90
|
+
# Render conxtext.current[key].
|
91
|
+
|
92
|
+
# @param [String, '.'] key to render, '.' means current context,
|
93
|
+
# string lookup key in current context
|
94
|
+
def EVAL( key )
|
95
|
+
|
96
|
+
logger.info "#{__method__}: key='#{key}', context.current=#{context.current}" if logger.debug?
|
97
|
+
|
98
|
+
# find generate sexp( :sym, data ) to render
|
99
|
+
if key == '.'
|
100
|
+
sexp = context.current
|
101
|
+
else
|
102
|
+
# to evaluate
|
103
|
+
hash = context.current.is_a?( Array ) ? context.current[1] : context.current
|
104
|
+
sexp = hash[key] || hash[key.to_sym]
|
105
|
+
raise SbuilderEtherumMustacheException, "No such key #{key}:#{key.class} found in #{hash}" if sexp.nil?
|
106
|
+
end
|
107
|
+
|
108
|
+
sexp_type = sexp[0]
|
109
|
+
data = sexp[1]
|
110
|
+
logger.debug "#{__method__}: key=#{key}, sexp_type=#{sexp_type}" if logger.debug?
|
111
|
+
|
112
|
+
|
113
|
+
# find correct template
|
114
|
+
template = partials[sexp_type]
|
115
|
+
raise SbuilderEtherumMustacheException, <<-EOS if template.nil?
|
116
|
+
Unknown partial for sexp_type '#{sexp_type}'
|
117
|
+
|
118
|
+
Known partials: #{partials.keys.join(',')}"
|
119
|
+
Conxt = #{context.current}
|
120
|
+
EOS
|
121
|
+
|
122
|
+
logger.debug "#{__method__}: template=#{template}, data=#{data}" if logger.debug?
|
123
|
+
return render( template, data )
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# # partials are constant strings, partial to use is defined in
|
129
|
+
# # SexpAst#sexp_type in context stack
|
130
|
+
# def partial( partial )
|
131
|
+
|
132
|
+
|
133
|
+
# logger.debug "#{__method__}: partial=#{partial}, sex_type=#{context.current.respond_to?(:sexp_type)}, context.current=#{context.current}, context.current.class=#{context.current.class}" if logger.debug?
|
134
|
+
|
135
|
+
# raise "TOOD remove"
|
136
|
+
|
137
|
+
# partial = context.current.sexp_type if context.current.respond_to?( :sexp_type )
|
138
|
+
# partial_str = partials[partial]
|
139
|
+
# logger.debug "#{__method__}: using partial =#{partial}"
|
140
|
+
|
141
|
+
|
142
|
+
# raise SbuilderEtherumMustacheException.new "Unknown partial '#{partial}'" if partial_str.nil?
|
143
|
+
|
144
|
+
# return partial_str
|
145
|
+
# end
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Sbuilder
|
5
|
+
module Ethereum
|
6
|
+
|
7
|
+
class Render
|
8
|
+
|
9
|
+
|
10
|
+
# SNIPPET_ROOT = <<-EOS
|
11
|
+
# {|>__partial_root__|}
|
12
|
+
# EOS
|
13
|
+
|
14
|
+
|
15
|
+
# @attr [Logger] logger
|
16
|
+
attr_reader :logger
|
17
|
+
PROGNAME = nil # progname for logger default class name
|
18
|
+
include MyLogger # mix logger
|
19
|
+
|
20
|
+
# @attr [Hash] options
|
21
|
+
attr_reader :options
|
22
|
+
|
23
|
+
# @attr [Hash] partials mapping used to find starting point for Snippets
|
24
|
+
attr_reader :partials
|
25
|
+
|
26
|
+
# # @attr [Renderer] renderer mustache template generator
|
27
|
+
# attr_reader :renderer
|
28
|
+
|
29
|
+
# @attr [Hash] preferences passesed as PREFERENCES property to rendering
|
30
|
+
attr_reader :preferences
|
31
|
+
|
32
|
+
# ------------------------------------------------------------------
|
33
|
+
# @!group Construct && configure
|
34
|
+
|
35
|
+
def initialize( options={} )
|
36
|
+
@options = options
|
37
|
+
@logger = getLogger( PROGNAME, options )
|
38
|
+
setPreferences( Constants::DEFAULT_PREFERENCES )
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Configure partials used to render snippets
|
43
|
+
def setPartials( partials )
|
44
|
+
# used later to find starting point for a snippet
|
45
|
+
@partials = partials
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Configure 'PREFERENCES' property passed to rendering
|
50
|
+
def setPreferences( preferences )
|
51
|
+
@preferences = Constants::DEFAULT_PREFERENCES.merge( preferences || {} )
|
52
|
+
end
|
53
|
+
|
54
|
+
def getRenderer
|
55
|
+
return @renderer unless @renderer.nil?
|
56
|
+
# create mustache renderer && configure it
|
57
|
+
@renderer = Renderer.new( options )
|
58
|
+
|
59
|
+
# Pass a hash mapping TLA generate element sexp_type to mustache
|
60
|
+
# templates used to generate TLA code for TLA generate element
|
61
|
+
# sexp to the object responsible the generation.
|
62
|
+
@renderer.partials = partials
|
63
|
+
@renderer.setPreferences( preferences )
|
64
|
+
@renderer
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# @!endgroup
|
69
|
+
|
70
|
+
# ------------------------------------------------------------------
|
71
|
+
# @!group Iterater, render yield result
|
72
|
+
|
73
|
+
##
|
74
|
+
# Uses +renderer+ to render +snippet+ to +body+ string in TLA language
|
75
|
+
#
|
76
|
+
# @param [Snippet] snippet ie. TLA generate (data) element
|
77
|
+
#
|
78
|
+
# @yield [metatype,appName,body]
|
79
|
+
# @yieldparam [String] metatype of the snippet
|
80
|
+
# @yieldparam [String] appName in application domain
|
81
|
+
# @yieldparam [String] body snippet content
|
82
|
+
#
|
83
|
+
|
84
|
+
def renderSnippet( snippet, &blk )
|
85
|
+
|
86
|
+
# logger.info "#{__method__}: snippet=#{snippet[0]}-#{snippet[0]}"
|
87
|
+
logger.debug "#{__method__}: snippet=#{snippet}" if logger.debug?
|
88
|
+
|
89
|
+
# use +snippet.sext_type+ to look up template in +partials+
|
90
|
+
partial = snippet.sexp_type
|
91
|
+
template = getRenderer.partials[partial]
|
92
|
+
logger.debug "#{__method__}, partial=#{partial}, template #{template}" if logger.debug?
|
93
|
+
|
94
|
+
raise SbuilderEtherumMustacheException.new, "Unknown partial '#{partial}', known partials: #{getRenderer.partials.keys.join(',')}" if template.nil?
|
95
|
+
|
96
|
+
# Typicall snippet renders a body, however it is also possible to
|
97
|
+
# create a mapping from appName to specName in some matatype
|
98
|
+
# without defining body. (Which may be laoded later for that
|
99
|
+
# specName)
|
100
|
+
#
|
101
|
+
snippet_str = getRenderer.to_str( template, snippet ) if snippet.snippet && snippet.snippet.any?
|
102
|
+
logger.debug "#{__method__}, metatype=#{snippet.metatype}, appName=#{snippet.appName}) snippet_str='#{snippet_str}'" if logger.debug?
|
103
|
+
|
104
|
+
# yield result to block
|
105
|
+
logger.debug "#{__method__}, yield metatype=#{snippet.metatype}, appName=#{snippet.appName}) body=#{snippet_str ? snippet_str[1..20] : 'no body'}" if logger.debug?
|
106
|
+
yield snippet.metatype, snippet.appName, snippet_str if block_given?
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# iterate, render, and yield result.
|
112
|
+
#
|
113
|
+
#
|
114
|
+
# @return [Integer] number of snippets rendered
|
115
|
+
|
116
|
+
def render( snippets, &blk )
|
117
|
+
|
118
|
+
logger.info "#{__method__}, start snippets=#{snippets}"
|
119
|
+
raise "Should have used #setPartials before #render" if partials.nil?
|
120
|
+
|
121
|
+
|
122
|
+
# init counter
|
123
|
+
rendered = 0
|
124
|
+
snippets.sexp_body.each do |snippet|
|
125
|
+
|
126
|
+
renderSnippet( snippet, &blk )
|
127
|
+
|
128
|
+
rendered += 1
|
129
|
+
end
|
130
|
+
rendered
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
# @!endgroup
|
135
|
+
|
136
|
+
# Render +snippet+ to string
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
data/lib/sbuilder/s.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
module Ethereum
|
3
|
+
|
4
|
+
# Helper method to build s-expressions
|
5
|
+
|
6
|
+
# def s(type, *children)
|
7
|
+
# Ast.new(type, children)
|
8
|
+
# end
|
9
|
+
|
10
|
+
def self.s(*args)
|
11
|
+
Sbuilder::Ethereum::SexpAst.new(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Override sexp_processos s
|
19
|
+
def s( *args )
|
20
|
+
Sbuilder::Ethereum::s( *args )
|
21
|
+
end
|
@@ -0,0 +1,1378 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'sexp_processor'
|
4
|
+
|
5
|
+
module Sbuilder
|
6
|
+
module Ethereum
|
7
|
+
|
8
|
+
|
9
|
+
# ------------------------------------------------------------------
|
10
|
+
# @!group Common root for Sbuilder
|
11
|
+
|
12
|
+
# Common root
|
13
|
+
|
14
|
+
class SexpSbuilder < Sexp
|
15
|
+
|
16
|
+
# Create a new Sexp containing +args+.
|
17
|
+
def initialize(*args)
|
18
|
+
super(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Ast:Array] sexpAst nodes with +type+
|
22
|
+
# def return_nodes_with_type( type )
|
23
|
+
# sexpAstArray = s() # []
|
24
|
+
# deep_each { |n|
|
25
|
+
# sexpAstArray << n if n.sexp_type == type
|
26
|
+
# }
|
27
|
+
# sexpAstArray
|
28
|
+
# end
|
29
|
+
def return_nodes_with_type( type )
|
30
|
+
return_nodes_with_match { |n|
|
31
|
+
n.sexp_type == type
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def return_nodes_with_match( &blk )
|
37
|
+
sexpAstArray = s() # []
|
38
|
+
deep_each { |n|
|
39
|
+
sexpAstArray << n if blk[n]
|
40
|
+
}
|
41
|
+
sexpAstArray
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# alias-method to return nodes with type
|
46
|
+
def t( type )
|
47
|
+
return_nodes_with_type( type ).first[1..-1]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Restore behaviour missing methods
|
51
|
+
def method_missing meth, delete = false
|
52
|
+
raise "Unknwon method '#{meth}' called on #{self}"
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
# @!endgroup
|
57
|
+
|
58
|
+
|
59
|
+
# ------------------------------------------------------------------
|
60
|
+
# @!group Node in AST
|
61
|
+
|
62
|
+
|
63
|
+
class SexpAst < SexpSbuilder
|
64
|
+
|
65
|
+
# @əttr [String] src source definition e.g. 0:106:1
|
66
|
+
attr_accessor :src
|
67
|
+
|
68
|
+
# @əttr [String] id as given by solc compiler
|
69
|
+
attr_accessor :id
|
70
|
+
|
71
|
+
# @attr [SexpAst] parent pointer to parent SexpAst
|
72
|
+
attr_accessor :parent
|
73
|
+
|
74
|
+
|
75
|
+
# Create a new Sexp containing +args+.
|
76
|
+
def initialize(*args)
|
77
|
+
super(*args)
|
78
|
+
end
|
79
|
+
|
80
|
+
def setParent( parent )
|
81
|
+
@parent = parent
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
# ------------------------------------------------------------------
|
86
|
+
# Build ast
|
87
|
+
|
88
|
+
# Create ast sexp tree from {json}.
|
89
|
+
#
|
90
|
+
# @param [Json] json to load as sexp
|
91
|
+
#
|
92
|
+
# @param [Interger] id generate unique identifier for each AST node
|
93
|
+
#
|
94
|
+
def self.build_sexp( json )
|
95
|
+
|
96
|
+
raise SexpException.new "Nil input" if json.nil?
|
97
|
+
raise SexpException.new "Missing name property in '#{json}'" if json['name'].nil?
|
98
|
+
|
99
|
+
# create sexp Node based on json['name']
|
100
|
+
result = new_node( json )
|
101
|
+
|
102
|
+
# add common content for all node types
|
103
|
+
result.src = json['src']
|
104
|
+
result.id = json['id']
|
105
|
+
|
106
|
+
# add children & create back pointer
|
107
|
+
json['children'] && json['children'].each do |x|
|
108
|
+
chld = self.build_sexp(x )
|
109
|
+
chld.setParent( result )
|
110
|
+
result << chld
|
111
|
+
end
|
112
|
+
|
113
|
+
result
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.new_node( json )
|
118
|
+
|
119
|
+
# map solc node type to SexpClass. This guarantees that we know
|
120
|
+
# each node type. Sexp classes know also attributes, which solc
|
121
|
+
# json defines.
|
122
|
+
node2class = {
|
123
|
+
:Identifier => Sbuilder::Ethereum::Identifier,
|
124
|
+
:PragmaDirective => Sbuilder::Ethereum::PragmaDirective,
|
125
|
+
:BinaryOperation => Sbuilder::Ethereum::BinaryOperation,
|
126
|
+
:Literal => Sbuilder::Ethereum::Literal,
|
127
|
+
:SourceUnit => Sbuilder::Ethereum::SourceUnit,
|
128
|
+
:ContractDefinition => Sbuilder::Ethereum::ContractDefinition,
|
129
|
+
:FunctionDefinition => Sbuilder::Ethereum::FunctionDefinition,
|
130
|
+
:ParameterList => Sbuilder::Ethereum::ParameterList,
|
131
|
+
:VariableDeclaration => Sbuilder::Ethereum::VariableDeclaration,
|
132
|
+
:ElementaryTypeName => Sbuilder::Ethereum::ElementaryTypeName,
|
133
|
+
:Mapping => Sbuilder::Ethereum::Mapping,
|
134
|
+
:IndexAccess => Sbuilder::Ethereum::IndexAccess,
|
135
|
+
:VariableDefinitionStatement =>Sbuilder::Ethereum::VariableDefinitionStatement,
|
136
|
+
:Block => Sbuilder::Ethereum::Block,
|
137
|
+
:Return => Sbuilder::Ethereum::Return,
|
138
|
+
:ExpressionStatement => Sbuilder::Ethereum::ExpressionStatement,
|
139
|
+
:Assignment => Sbuilder::Ethereum::Assignment,
|
140
|
+
:MemberAccess => Sbuilder::Ethereum::MemberAccess,
|
141
|
+
:FunctionCall => Sbuilder::Ethereum::FunctionCall,
|
142
|
+
:NewExpression => Sbuilder::Ethereum::NewExpression,
|
143
|
+
:UserDefinedTypeName => Sbuilder::Ethereum::UserDefinedTypeName,
|
144
|
+
:Throw => Sbuilder::Ethereum::Throw,
|
145
|
+
:Domain => Sbuilder::Ethereum::Domain,
|
146
|
+
:IfStatement => Sbuilder::Ethereum::IfStatement,
|
147
|
+
:UnaryOperation => Sbuilder::Ethereum::UnaryOperation,
|
148
|
+
}
|
149
|
+
|
150
|
+
nodeType = json['name'].is_a?( String ) ? json['name'].to_sym : json['name']
|
151
|
+
klass = node2class[nodeType]
|
152
|
+
raise SexpException.new "Unknown node type '#{json['name']}' in #{json.to_yaml}" if klass.nil?
|
153
|
+
|
154
|
+
result = klass.json( json )
|
155
|
+
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
class Identifier < SexpAst
|
164
|
+
|
165
|
+
# reference to declaration
|
166
|
+
include Sbuilder::Ethereum::DeclRef
|
167
|
+
|
168
|
+
# pointer to domain of the declaration
|
169
|
+
include Sbuilder::Ethereum::DomainRef
|
170
|
+
|
171
|
+
|
172
|
+
# Create a new Sexp containing +json+.
|
173
|
+
def self.json(json=nil)
|
174
|
+
ary = [
|
175
|
+
json['name'].to_sym,
|
176
|
+
json['attributes']['type'],
|
177
|
+
json['attributes']['value'],
|
178
|
+
] unless json.nil?
|
179
|
+
|
180
|
+
Identifier.new(*ary)
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.s( type, value )
|
184
|
+
Identifier.new( :Identifier, type, value )
|
185
|
+
end
|
186
|
+
|
187
|
+
def type
|
188
|
+
self[1]
|
189
|
+
end
|
190
|
+
|
191
|
+
# value for identifier as an expression
|
192
|
+
def value
|
193
|
+
self[2]
|
194
|
+
end
|
195
|
+
|
196
|
+
# semantic routine
|
197
|
+
|
198
|
+
# name of identifier
|
199
|
+
def name
|
200
|
+
value
|
201
|
+
end
|
202
|
+
def resolvedReference
|
203
|
+
raise 'Identifier reference #{self} not resolved' if declationRef.nil?
|
204
|
+
declationRef
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
class PragmaDirective < SexpAst
|
210
|
+
def self.json(json)
|
211
|
+
ary = [
|
212
|
+
json['name'].to_sym,
|
213
|
+
]
|
214
|
+
PragmaDirective.new(*ary)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class SourceUnit < SexpAst
|
219
|
+
def self.json(json)
|
220
|
+
ary = [
|
221
|
+
json['name'].to_sym,
|
222
|
+
]
|
223
|
+
SourceUnit.new(*ary)
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.define( sourceUnit, ast )
|
227
|
+
SourceUnit.new( :SourceUnit, sourceUnit, ast )
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
class ContractDefinition < SexpAst
|
233
|
+
|
234
|
+
# number of contracts is a domain
|
235
|
+
include Sbuilder::Ethereum::DomainRef
|
236
|
+
|
237
|
+
include Scope
|
238
|
+
|
239
|
+
# type hierarcy
|
240
|
+
include TypeSymbol
|
241
|
+
|
242
|
+
# TypeSymbol uses 'typeName' to create unique names in type
|
243
|
+
# hierarchy
|
244
|
+
def typeName
|
245
|
+
name
|
246
|
+
end
|
247
|
+
|
248
|
+
def self.json(json)
|
249
|
+
ary = [
|
250
|
+
json['name'].to_sym,
|
251
|
+
json['attributes']['name'],
|
252
|
+
]
|
253
|
+
ContractDefinition.new(*ary)
|
254
|
+
end
|
255
|
+
def name
|
256
|
+
self[1]
|
257
|
+
end
|
258
|
+
|
259
|
+
##
|
260
|
+
# Name of set to hold contract identifiers
|
261
|
+
def contractIdSet
|
262
|
+
"#{name}_ids"
|
263
|
+
end
|
264
|
+
|
265
|
+
##
|
266
|
+
# @return [VariableDeclaration:Array] symbols with 'sexp_type' ==
|
267
|
+
# :VariableDeclaration defined in contract scope
|
268
|
+
def contractVariables
|
269
|
+
return s() if symbols.nil?
|
270
|
+
symbols.values.select { |s| s.sexp_type == :VariableDeclaration }
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
class ParameterList < SexpAst
|
277
|
+
|
278
|
+
# back pointer to scope where declared
|
279
|
+
include Scoped
|
280
|
+
|
281
|
+
# it acts also as a scope
|
282
|
+
include Scope
|
283
|
+
|
284
|
+
def self.json(json)
|
285
|
+
ary = [
|
286
|
+
json['name'].to_sym,
|
287
|
+
]
|
288
|
+
ParameterList.new(*ary)
|
289
|
+
end
|
290
|
+
|
291
|
+
# parameters SexpAst nodes starting form pos 1
|
292
|
+
def parameters
|
293
|
+
# return self[1..-1] if self.length > 1
|
294
|
+
return self[1..-1]
|
295
|
+
end
|
296
|
+
|
297
|
+
##
|
298
|
+
# Name as function for function
|
299
|
+
def name
|
300
|
+
parent.name
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
class ExpressionStatement < SexpAst
|
306
|
+
def self.json(json)
|
307
|
+
ary = [
|
308
|
+
json['name'].to_sym,
|
309
|
+
]
|
310
|
+
ExpressionStatement.new(*ary)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
class MemberAccess < SexpAst
|
315
|
+
|
316
|
+
# reference to declaration
|
317
|
+
include DeclRef
|
318
|
+
|
319
|
+
# pointer to domain of the declaration
|
320
|
+
include DomainRef
|
321
|
+
|
322
|
+
|
323
|
+
def self.json(json)
|
324
|
+
ary = [
|
325
|
+
json['name'].to_sym,
|
326
|
+
json['attributes']['member_name'],
|
327
|
+
# json['attributes']['type'],
|
328
|
+
]
|
329
|
+
MemberAccess.new(*ary)
|
330
|
+
end
|
331
|
+
|
332
|
+
# @return [String] member_name e.g. 'sender' in 'msg.sender'
|
333
|
+
def member_name
|
334
|
+
self[1]
|
335
|
+
end
|
336
|
+
|
337
|
+
|
338
|
+
## Children
|
339
|
+
# @return [Identifier|MemberAccesss] msg in 'msg.sender', sender
|
340
|
+
# in 'msg.sender.send'
|
341
|
+
|
342
|
+
def memberStruct
|
343
|
+
self[2]
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
# "calling a function on the function" e.g. f.gas(2).value(20)()
|
348
|
+
# calls the modified function f and thereby sending 20 Wei and
|
349
|
+
# limiting the gas to 2 we catch this later in code generation
|
350
|
+
# phase, and have no need for declationRef
|
351
|
+
#
|
352
|
+
# @return [Boolean] true if 'mmbStct.decLRef.sexp_type == :FucnDef'
|
353
|
+
def isFunctionOnFunction
|
354
|
+
memberStruct && memberStruct.declationRef && memberStruct.declationRef.sexp_type == :FunctionDefinition
|
355
|
+
end
|
356
|
+
|
357
|
+
##
|
358
|
+
# @return [Sexp] recipientSexp in s(:MemberAccess, "send",
|
359
|
+
# s(:MemberAccess, "sender", s(:Identifier, "msg", "msg"))) it
|
360
|
+
# returns s(:MemberAccess, "sender", s(:Identifier, "msg", "msg"))
|
361
|
+
# def recipientSexp
|
362
|
+
# memberStruct
|
363
|
+
# end
|
364
|
+
|
365
|
+
|
366
|
+
end
|
367
|
+
|
368
|
+
class Assignment < SexpAst
|
369
|
+
def self.json(json)
|
370
|
+
ary = [
|
371
|
+
json['name'].to_sym,
|
372
|
+
json['attributes']['operator'],
|
373
|
+
json['attributes']['type'],
|
374
|
+
]
|
375
|
+
Assignment.new(*ary)
|
376
|
+
end
|
377
|
+
|
378
|
+
def operator
|
379
|
+
self[1]
|
380
|
+
end
|
381
|
+
|
382
|
+
def type
|
383
|
+
self[2]
|
384
|
+
end
|
385
|
+
|
386
|
+
# variable being assined to, 1.st child
|
387
|
+
def lval
|
388
|
+
self[3]
|
389
|
+
end
|
390
|
+
|
391
|
+
# expression being assined, 2nd child
|
392
|
+
def rval
|
393
|
+
self[4]
|
394
|
+
end
|
395
|
+
|
396
|
+
# Canonize
|
397
|
+
def setOperator( operator='=' )
|
398
|
+
self[1] = operator
|
399
|
+
end
|
400
|
+
|
401
|
+
def setRval( rval )
|
402
|
+
self[4] = rval
|
403
|
+
end
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
|
408
|
+
class Block < SexpAst
|
409
|
+
def self.json(json)
|
410
|
+
ary = [
|
411
|
+
json['name'].to_sym,
|
412
|
+
]
|
413
|
+
Block.new(*ary)
|
414
|
+
end
|
415
|
+
|
416
|
+
# ------------------------------------------------------------------
|
417
|
+
# semantic methods
|
418
|
+
def statements
|
419
|
+
self[1..-1]
|
420
|
+
end
|
421
|
+
|
422
|
+
end
|
423
|
+
|
424
|
+
class Return < SexpAst
|
425
|
+
|
426
|
+
# back pointer for the function scope where return variables are set
|
427
|
+
include Scoped
|
428
|
+
|
429
|
+
def self.json(json=nil)
|
430
|
+
ary = [
|
431
|
+
json['name'].to_sym,
|
432
|
+
] unless json.nil?
|
433
|
+
Return.new(*ary)
|
434
|
+
end
|
435
|
+
|
436
|
+
# list of expressions returned start from pos 1
|
437
|
+
def expressions
|
438
|
+
self[1..-1]
|
439
|
+
end
|
440
|
+
|
441
|
+
# semantic methods
|
442
|
+
|
443
|
+
# alias a name with more semantics
|
444
|
+
alias_method :function, :scopeDefining
|
445
|
+
|
446
|
+
# '(uint retVal, ...)' in 'function get() constant returns (uint retVal, ...)'
|
447
|
+
def functionReturnList
|
448
|
+
raise "function scope for #{self} not resolved" if function.nil?
|
449
|
+
function.returnList
|
450
|
+
end
|
451
|
+
|
452
|
+
def functionReturnParameter( i )
|
453
|
+
raise "function scope for #{self} not resolved" if function.nil?
|
454
|
+
function.returnParameter( i )
|
455
|
+
end
|
456
|
+
|
457
|
+
end
|
458
|
+
|
459
|
+
|
460
|
+
class IndexAccess < SexpAst
|
461
|
+
|
462
|
+
include DomainRef
|
463
|
+
|
464
|
+
def self.json(json)
|
465
|
+
ary = [
|
466
|
+
json['name'].to_sym,
|
467
|
+
]
|
468
|
+
IndexAccess.new(*ary)
|
469
|
+
end
|
470
|
+
|
471
|
+
# childs
|
472
|
+
def identifier
|
473
|
+
self[1]
|
474
|
+
end
|
475
|
+
|
476
|
+
def indexer
|
477
|
+
self[2]
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
class Mapping < SexpAst
|
482
|
+
|
483
|
+
|
484
|
+
def self.json(json)
|
485
|
+
ary = [
|
486
|
+
json['name'].to_sym,
|
487
|
+
]
|
488
|
+
Mapping.new(*ary)
|
489
|
+
end
|
490
|
+
|
491
|
+
# childs
|
492
|
+
def mapFrom
|
493
|
+
self[1]
|
494
|
+
end
|
495
|
+
def mapTo
|
496
|
+
self[2]
|
497
|
+
end
|
498
|
+
|
499
|
+
# @return [Array] mappings [from, to]
|
500
|
+
def maps
|
501
|
+
self[1..-1]
|
502
|
+
end
|
503
|
+
|
504
|
+
|
505
|
+
end
|
506
|
+
|
507
|
+
|
508
|
+
class VariableDeclaration < SexpAst
|
509
|
+
|
510
|
+
# back pointer to scope where declared
|
511
|
+
include Scoped
|
512
|
+
|
513
|
+
# pointer to domain of the declaration
|
514
|
+
include DomainRef
|
515
|
+
|
516
|
+
def self.json(json=nil)
|
517
|
+
ary = [
|
518
|
+
json['name'].to_sym,
|
519
|
+
json['attributes']['name'],
|
520
|
+
json['attributes']['type'],
|
521
|
+
|
522
|
+
] unless json.nil?
|
523
|
+
VariableDeclaration.new(*ary)
|
524
|
+
end
|
525
|
+
|
526
|
+
def self.s( name, typeSexp=ElementaryTypeName.s )
|
527
|
+
VariableDeclaration.new( :VariableDeclaration, name, "domain", typeSexp )
|
528
|
+
end
|
529
|
+
|
530
|
+
def name
|
531
|
+
self[1]
|
532
|
+
end
|
533
|
+
# function return parameters do not have a name,
|
534
|
+
# canonize process may update name
|
535
|
+
def setName( name )
|
536
|
+
self[1] = name
|
537
|
+
end
|
538
|
+
|
539
|
+
|
540
|
+
def type
|
541
|
+
self[2]
|
542
|
+
end
|
543
|
+
|
544
|
+
# childs
|
545
|
+
def typeSexp
|
546
|
+
self[3]
|
547
|
+
end
|
548
|
+
|
549
|
+
def isMapping
|
550
|
+
typeSexp.sexp_type == :Mapping
|
551
|
+
end
|
552
|
+
|
553
|
+
# @return true iff +typeSexp? == :ElementaryTypeName
|
554
|
+
# def isElementary
|
555
|
+
# typeSexp && typeSexp.sexp_type == :ElementaryTypeName
|
556
|
+
# end
|
557
|
+
|
558
|
+
|
559
|
+
end
|
560
|
+
|
561
|
+
|
562
|
+
# @see Assignment because 'VariableDefinitionStatement' is intepreted
|
563
|
+
# an assignment
|
564
|
+
class VariableDefinitionStatement < SexpAst
|
565
|
+
|
566
|
+
# back pointer to scope where declared
|
567
|
+
include Scoped
|
568
|
+
|
569
|
+
def self.json(json)
|
570
|
+
ary = [
|
571
|
+
json['name'].to_sym,
|
572
|
+
]
|
573
|
+
VariableDefinitionStatement.new(*ary)
|
574
|
+
end
|
575
|
+
|
576
|
+
# variable being assined to, 1.st child
|
577
|
+
def lval
|
578
|
+
self[1]
|
579
|
+
end
|
580
|
+
|
581
|
+
# expression being assined, 2nd child
|
582
|
+
def rval
|
583
|
+
self[2]
|
584
|
+
end
|
585
|
+
|
586
|
+
|
587
|
+
|
588
|
+
end
|
589
|
+
|
590
|
+
|
591
|
+
# @see UserDefinedTypeName implementing also typeName
|
592
|
+
class ElementaryTypeName < SexpAst
|
593
|
+
|
594
|
+
# back pointer to scope where declared
|
595
|
+
include Scoped
|
596
|
+
|
597
|
+
# pointer to symbol type (i.e User defined/elementary type)
|
598
|
+
include SymbolRef
|
599
|
+
|
600
|
+
# pointer to domain of the declaration
|
601
|
+
include DomainRef
|
602
|
+
|
603
|
+
def self.json(json)
|
604
|
+
ary = [
|
605
|
+
json['name'].to_sym,
|
606
|
+
json['attributes']['name'],
|
607
|
+
]
|
608
|
+
ElementaryTypeName.new(*ary)
|
609
|
+
end
|
610
|
+
|
611
|
+
def self.s()
|
612
|
+
ElementaryTypeName.new( :ElementaryTypeName )
|
613
|
+
end
|
614
|
+
|
615
|
+
def typeName
|
616
|
+
self[1]
|
617
|
+
end
|
618
|
+
|
619
|
+
|
620
|
+
end
|
621
|
+
|
622
|
+
class IfStatement < SexpAst
|
623
|
+
def self.json(json)
|
624
|
+
ary = [
|
625
|
+
json['name'].to_sym,
|
626
|
+
]
|
627
|
+
IfStatement.new(*ary)
|
628
|
+
end
|
629
|
+
|
630
|
+
def condition
|
631
|
+
self[1]
|
632
|
+
end
|
633
|
+
|
634
|
+
# childs
|
635
|
+
def then_branch
|
636
|
+
self[2]
|
637
|
+
end
|
638
|
+
|
639
|
+
def else_branch
|
640
|
+
self[3]
|
641
|
+
end
|
642
|
+
|
643
|
+
end
|
644
|
+
|
645
|
+
class Throw < SexpAst
|
646
|
+
def self.json(json)
|
647
|
+
ary = [
|
648
|
+
json['name'].to_sym,
|
649
|
+
]
|
650
|
+
Throw.new(*ary)
|
651
|
+
end
|
652
|
+
|
653
|
+
end
|
654
|
+
|
655
|
+
class UserDefinedTypeName < SexpAst
|
656
|
+
|
657
|
+
# back pointer to scope where declared
|
658
|
+
include Scoped
|
659
|
+
|
660
|
+
# pointer to symbol type (i.e User defined/elementary type)
|
661
|
+
include SymbolRef
|
662
|
+
|
663
|
+
def self.json(json)
|
664
|
+
ary = [
|
665
|
+
json['name'].to_sym,
|
666
|
+
json['attributes']['name'],
|
667
|
+
]
|
668
|
+
UserDefinedTypeName.new(*ary)
|
669
|
+
end
|
670
|
+
|
671
|
+
def name
|
672
|
+
self[1]
|
673
|
+
end
|
674
|
+
|
675
|
+
# common method for UserDefinedTypeName, ElementaryTypeName
|
676
|
+
def typeName
|
677
|
+
name
|
678
|
+
end
|
679
|
+
|
680
|
+
|
681
|
+
end
|
682
|
+
|
683
|
+
class NewExpression < SexpAst
|
684
|
+
|
685
|
+
# reference to constructor declaration
|
686
|
+
include DeclRef
|
687
|
+
|
688
|
+
def self.json(json)
|
689
|
+
ary = [
|
690
|
+
json['name'].to_sym,
|
691
|
+
json['attributes']['type'],
|
692
|
+
]
|
693
|
+
NewExpression.new(*ary)
|
694
|
+
end
|
695
|
+
|
696
|
+
def type
|
697
|
+
self[1]
|
698
|
+
end
|
699
|
+
|
700
|
+
##
|
701
|
+
# Semantic
|
702
|
+
def contractConstructed
|
703
|
+
self[2]
|
704
|
+
end
|
705
|
+
|
706
|
+
# def name
|
707
|
+
# functionCalled.name
|
708
|
+
# end
|
709
|
+
|
710
|
+
|
711
|
+
end
|
712
|
+
|
713
|
+
##
|
714
|
+
# Wrap function call to indicate that we should read result of
|
715
|
+
# function, which was called previously. This sexp is created when
|
716
|
+
# spllitting statement with function call e.g. in assignment or in
|
717
|
+
# condiational
|
718
|
+
class FunctionCallReadReturn < SexpAst
|
719
|
+
|
720
|
+
# function may assign to variable with domain of the declaration,
|
721
|
+
# this is handled in 'FunctionCallReadReturn'
|
722
|
+
include DomainRef
|
723
|
+
|
724
|
+
def initialize( functionCall )
|
725
|
+
ary = [
|
726
|
+
:FunctionCallReadReturn,
|
727
|
+
functionCall,
|
728
|
+
]
|
729
|
+
super(*ary)
|
730
|
+
end
|
731
|
+
def self.define( functionCall )
|
732
|
+
FunctionCallReadReturn.new( functionCall )
|
733
|
+
end
|
734
|
+
|
735
|
+
def functionCalled
|
736
|
+
self[1]
|
737
|
+
end
|
738
|
+
|
739
|
+
end
|
740
|
+
|
741
|
+
class FunctionCall < SexpAst
|
742
|
+
|
743
|
+
|
744
|
+
def self.json(json=nil)
|
745
|
+
ary = [
|
746
|
+
json['name'].to_sym,
|
747
|
+
json['attributes']['type'],
|
748
|
+
] unless json.nil?
|
749
|
+
FunctionCall.new(*ary)
|
750
|
+
end
|
751
|
+
|
752
|
+
def type
|
753
|
+
self[1]
|
754
|
+
end
|
755
|
+
|
756
|
+
##
|
757
|
+
# childs
|
758
|
+
def functionExpression
|
759
|
+
self[2]
|
760
|
+
end
|
761
|
+
|
762
|
+
def actualParameters
|
763
|
+
self[3..-1]
|
764
|
+
end
|
765
|
+
|
766
|
+
end
|
767
|
+
|
768
|
+
class FunctionDefinition < SexpAst
|
769
|
+
# Function definition is also a scope
|
770
|
+
include Scope
|
771
|
+
|
772
|
+
# @əttr [ContractDefinition] contractDefinition
|
773
|
+
attr_accessor :contractDefinition
|
774
|
+
|
775
|
+
# pointer to domain of the declaration
|
776
|
+
include DomainRef
|
777
|
+
|
778
|
+
def self.json(json=nil)
|
779
|
+
ary = [
|
780
|
+
json['name'].to_sym,
|
781
|
+
json['attributes']['name'],
|
782
|
+
json['attributes']['public'],
|
783
|
+
json['attributes']['constant'],
|
784
|
+
] unless json.nil?
|
785
|
+
FunctionDefinition.new(*ary)
|
786
|
+
end
|
787
|
+
|
788
|
+
def name
|
789
|
+
self[1]
|
790
|
+
end
|
791
|
+
|
792
|
+
def isPublic
|
793
|
+
self[2]
|
794
|
+
end
|
795
|
+
def isConstant
|
796
|
+
self[3]
|
797
|
+
end
|
798
|
+
# child nodes in AST
|
799
|
+
# @return [ParameterList] parameterList
|
800
|
+
def parameterList
|
801
|
+
self[4]
|
802
|
+
end
|
803
|
+
# child nodes in AST
|
804
|
+
# @return [ParameterList] returnList
|
805
|
+
def returnList
|
806
|
+
self[5]
|
807
|
+
end
|
808
|
+
def block
|
809
|
+
self[6]
|
810
|
+
end
|
811
|
+
|
812
|
+
# ------------------------------------------------------------------
|
813
|
+
# semantic
|
814
|
+
def statements
|
815
|
+
block.statements
|
816
|
+
end
|
817
|
+
|
818
|
+
def returnParameter( i )
|
819
|
+
returnList[i+1]
|
820
|
+
end
|
821
|
+
|
822
|
+
##
|
823
|
+
# Method added dyncamially
|
824
|
+
# def interfaceName
|
825
|
+
# return "Demo()" or "Demo(set)
|
826
|
+
# end
|
827
|
+
|
828
|
+
end
|
829
|
+
|
830
|
+
class UnaryOperation < SexpAst
|
831
|
+
# pointer to domain of the declaration
|
832
|
+
include DomainRef
|
833
|
+
|
834
|
+
# Create a new Sexp containing +args+.
|
835
|
+
def self.json(json)
|
836
|
+
ary = [
|
837
|
+
json['name'].to_sym,
|
838
|
+
json['attributes']['operator'],
|
839
|
+
]
|
840
|
+
|
841
|
+
UnaryOperation.new(*ary)
|
842
|
+
end
|
843
|
+
|
844
|
+
def operator
|
845
|
+
self[1]
|
846
|
+
end
|
847
|
+
|
848
|
+
# childs
|
849
|
+
def expr
|
850
|
+
self[2]
|
851
|
+
end
|
852
|
+
|
853
|
+
end
|
854
|
+
|
855
|
+
|
856
|
+
class BinaryOperation < SexpAst
|
857
|
+
|
858
|
+
# pointer to domain of the declaration
|
859
|
+
include DomainRef
|
860
|
+
|
861
|
+
|
862
|
+
# Create a new Sexp containing +args+.
|
863
|
+
def self.json(json)
|
864
|
+
ary = [
|
865
|
+
json['name'].to_sym,
|
866
|
+
json['attributes']['operator'],
|
867
|
+
]
|
868
|
+
|
869
|
+
BinaryOperation.new(*ary)
|
870
|
+
end
|
871
|
+
|
872
|
+
def operator
|
873
|
+
self[1]
|
874
|
+
end
|
875
|
+
|
876
|
+
# childs
|
877
|
+
def lhs
|
878
|
+
self[2]
|
879
|
+
end
|
880
|
+
def rhs
|
881
|
+
self[3]
|
882
|
+
end
|
883
|
+
|
884
|
+
|
885
|
+
# value of operator expression
|
886
|
+
def value
|
887
|
+
"op_#{operator}"
|
888
|
+
end
|
889
|
+
|
890
|
+
end
|
891
|
+
|
892
|
+
class Literal < SexpAst
|
893
|
+
|
894
|
+
# literals participate to data flows
|
895
|
+
include DomainRef
|
896
|
+
|
897
|
+
# Create a new Sexp containing +args+.
|
898
|
+
def self.json(json)
|
899
|
+
ary = [
|
900
|
+
json['name'].to_sym,
|
901
|
+
json['attributes']['type'],
|
902
|
+
json['attributes']['value'],
|
903
|
+
]
|
904
|
+
|
905
|
+
Literal.new(*ary)
|
906
|
+
end
|
907
|
+
|
908
|
+
def type
|
909
|
+
self[1]
|
910
|
+
end
|
911
|
+
|
912
|
+
# value of the expression
|
913
|
+
def value
|
914
|
+
self[2]
|
915
|
+
end
|
916
|
+
|
917
|
+
##
|
918
|
+
# canonize maps literal constant values in solc to TLA
|
919
|
+
def setValue( value )
|
920
|
+
self[2] = value
|
921
|
+
end
|
922
|
+
|
923
|
+
end
|
924
|
+
# @!endgroup
|
925
|
+
|
926
|
+
# ------------------------------------------------------------------
|
927
|
+
# @!group Symbols
|
928
|
+
|
929
|
+
class BuiltInSymbol < SexpSbuilder
|
930
|
+
|
931
|
+
# integer, boolean, etc
|
932
|
+
include TypeSymbol;
|
933
|
+
|
934
|
+
|
935
|
+
# TypeSymbol uses 'typeName' to create unique names in type
|
936
|
+
# hierarchy
|
937
|
+
def typeName
|
938
|
+
name
|
939
|
+
end
|
940
|
+
|
941
|
+
|
942
|
+
# it may define names e.g. address knowns of 'send'
|
943
|
+
include Scope;
|
944
|
+
|
945
|
+
def initialize(name)
|
946
|
+
ary = [
|
947
|
+
:BuiltInSymbol,
|
948
|
+
name
|
949
|
+
]
|
950
|
+
super(*ary)
|
951
|
+
end
|
952
|
+
|
953
|
+
def name
|
954
|
+
self[1]
|
955
|
+
end
|
956
|
+
|
957
|
+
# @return unique identifier like no other
|
958
|
+
def id
|
959
|
+
"#{self.class}-#{name}"
|
960
|
+
end
|
961
|
+
|
962
|
+
|
963
|
+
end
|
964
|
+
|
965
|
+
# @!endgroup
|
966
|
+
# ------------------------------------------------------------------
|
967
|
+
|
968
|
+
# ------------------------------------------------------------------
|
969
|
+
# @!group Sexp cretad outside AST
|
970
|
+
|
971
|
+
# Symbol table main entry (like Sexp), not found in AST
|
972
|
+
class GlobalScope < SexpSbuilder
|
973
|
+
include Scope
|
974
|
+
|
975
|
+
def initialize
|
976
|
+
ary = [
|
977
|
+
:GlobalScope,
|
978
|
+
]
|
979
|
+
|
980
|
+
super(*ary)
|
981
|
+
end
|
982
|
+
|
983
|
+
def name
|
984
|
+
self[0].to_s
|
985
|
+
end
|
986
|
+
|
987
|
+
##
|
988
|
+
# Use global scope like contract
|
989
|
+
def contractVariables
|
990
|
+
s()
|
991
|
+
end
|
992
|
+
|
993
|
+
end
|
994
|
+
|
995
|
+
# @see http://solidity.readthedocs.io/en/develop/units-and-global-variables.html
|
996
|
+
class Msg < SexpSbuilder
|
997
|
+
|
998
|
+
# e.g. to hold 'sender', 'value', 'gas', ...
|
999
|
+
include Scope
|
1000
|
+
|
1001
|
+
def initialize( id )
|
1002
|
+
ary = [
|
1003
|
+
:Msg,
|
1004
|
+
id,
|
1005
|
+
]
|
1006
|
+
super(*ary)
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
##
|
1010
|
+
# @return unique identifier like no other
|
1011
|
+
def id
|
1012
|
+
self[1]
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
|
1016
|
+
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
# @see http://solidity.readthedocs.io/en/develop/units-and-global-variables.html
|
1020
|
+
class Now < SexpSbuilder
|
1021
|
+
|
1022
|
+
def initialize( id )
|
1023
|
+
ary = [
|
1024
|
+
:Now,
|
1025
|
+
id,
|
1026
|
+
]
|
1027
|
+
super(*ary)
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
# @return unique identifier like no other
|
1031
|
+
def id
|
1032
|
+
self[1]
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
|
1037
|
+
# not <SexpSbuilder because we construct Domain nodes
|
1038
|
+
class Domain < SexpAst
|
1039
|
+
|
1040
|
+
# Using Domain to define types for common message properties
|
1041
|
+
include Scoped
|
1042
|
+
|
1043
|
+
# pointer to symbol type (i.e User defined/elementary type)
|
1044
|
+
include SymbolRef
|
1045
|
+
|
1046
|
+
def initialize(name, solidityType=nil)
|
1047
|
+
ary = [
|
1048
|
+
:Domain,
|
1049
|
+
name,
|
1050
|
+
solidityType,
|
1051
|
+
]
|
1052
|
+
|
1053
|
+
super(*ary)
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
def self.json(json)
|
1057
|
+
ary = [
|
1058
|
+
# json['name'].to_sym,
|
1059
|
+
json['attributes']['name'],
|
1060
|
+
json['attributes']['solidityType'],
|
1061
|
+
]
|
1062
|
+
Domain.new(*ary)
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
def self.s( name, solidityType=nil )
|
1066
|
+
Domain.new( name, solidityType )
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
def domainName
|
1070
|
+
self[1]
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def solidityType
|
1074
|
+
self[2]
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
|
1078
|
+
##
|
1079
|
+
# values idenfied for domain e.g. contract names in 'eth_code_hash'.
|
1080
|
+
# Possibly literals in ethereum contracts.
|
1081
|
+
#
|
1082
|
+
def domainValues
|
1083
|
+
self[3..-1]
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
def name
|
1087
|
+
domainName
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
class Domains < SexpSbuilder
|
1093
|
+
|
1094
|
+
# @param [Domain:array] domainArr array of Domain sexps
|
1095
|
+
def initialize( domainArr )
|
1096
|
+
ary = [
|
1097
|
+
:Domains,
|
1098
|
+
*domainArr
|
1099
|
+
]
|
1100
|
+
|
1101
|
+
super(*ary)
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
def domains
|
1105
|
+
self[1..-1]
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
|
1111
|
+
|
1112
|
+
# Snippets created
|
1113
|
+
class Snippets < SexpSbuilder
|
1114
|
+
|
1115
|
+
# @param [Domain:array] domainArr array of Domain sexps
|
1116
|
+
def initialize( snippets )
|
1117
|
+
ary = [
|
1118
|
+
:Snippets,
|
1119
|
+
*snippets
|
1120
|
+
]
|
1121
|
+
|
1122
|
+
super(*ary)
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
class Interfaces < SexpSbuilder
|
1128
|
+
|
1129
|
+
# @param [Interface:Array] interfaces array of Interface instances
|
1130
|
+
def initialize( interfaces )
|
1131
|
+
ary = [
|
1132
|
+
:Interfaces,
|
1133
|
+
*interfaces
|
1134
|
+
]
|
1135
|
+
super(*ary)
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
def interfaces
|
1139
|
+
self[1..-1]
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
|
1145
|
+
class Definitions < SexpSbuilder
|
1146
|
+
|
1147
|
+
# @param [Definition:Array] interfaces array of Definition instances
|
1148
|
+
def initialize( definitions )
|
1149
|
+
ary = [
|
1150
|
+
:Definitions,
|
1151
|
+
*definitions
|
1152
|
+
]
|
1153
|
+
super(*ary)
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
def definitions
|
1157
|
+
self[1..-1]
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
|
1163
|
+
class Definition < SexpSbuilder
|
1164
|
+
|
1165
|
+
#
|
1166
|
+
# @param [:Symbol] definitionType :normal or :function
|
1167
|
+
def initialize( definitionName, properties, definitionType )
|
1168
|
+
raise "Unknown type #{definitionType}" unless [:normal, :function ].include? definitionType
|
1169
|
+
ary = [
|
1170
|
+
:Definition,
|
1171
|
+
definitionName,
|
1172
|
+
properties,
|
1173
|
+
definitionType
|
1174
|
+
]
|
1175
|
+
super(*ary)
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
def self.define( definitionName, propertiesSexp, definitionType = :normal )
|
1179
|
+
Definition.new(
|
1180
|
+
definitionName,
|
1181
|
+
propertiesSexp.map do |prop|
|
1182
|
+
# prop = s(name domain_name)
|
1183
|
+
p = {
|
1184
|
+
:type => prop[0],
|
1185
|
+
:name => prop[1],
|
1186
|
+
}
|
1187
|
+
p[:domain_name] = prop[2] if prop[0] == :parameter
|
1188
|
+
p[:reference] = prop[2] if prop[0] == :reference
|
1189
|
+
p
|
1190
|
+
end,
|
1191
|
+
definitionType
|
1192
|
+
)
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def name
|
1196
|
+
self[1]
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
# @return [Hash:Array] prop
|
1200
|
+
# @option prop [:Symbol] :type values :parameter or :reference
|
1201
|
+
# @option prop [:Symbol] :name
|
1202
|
+
# @option prop [:Symbol] :domain_name if :type == :parameter
|
1203
|
+
# @option prop [:Symbol] :reference if :type == :reference
|
1204
|
+
def properties
|
1205
|
+
self[2]
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
# @return [:Symbol] definitionType one of [:normal, :function]
|
1209
|
+
def definitionType
|
1210
|
+
self[3]
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
|
1217
|
+
|
1218
|
+
class Interface < SexpSbuilder
|
1219
|
+
|
1220
|
+
def initialize( interfaceDefinition, input=nil, output=nil )
|
1221
|
+
ary = [
|
1222
|
+
:Interface,
|
1223
|
+
interfaceDefinition,
|
1224
|
+
input,
|
1225
|
+
output,
|
1226
|
+
]
|
1227
|
+
super(*ary)
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
def self.define( contractName, functionName, inputSexp, outputSexp )
|
1231
|
+
Interface.new(
|
1232
|
+
{
|
1233
|
+
:interface => contractName,
|
1234
|
+
:method => functionName,
|
1235
|
+
:input => inputSexp.map do |param|
|
1236
|
+
# param s(:type name domain_name)
|
1237
|
+
{
|
1238
|
+
:name => param[1],
|
1239
|
+
:domain_name => param[2]
|
1240
|
+
}
|
1241
|
+
end,
|
1242
|
+
:output => outputSexp.map do |param|
|
1243
|
+
# param s(:type name domain_name)
|
1244
|
+
{
|
1245
|
+
:name => param[1],
|
1246
|
+
:domain_name => param[2]
|
1247
|
+
}
|
1248
|
+
end
|
1249
|
+
})
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
# #
|
1253
|
+
# # @param [ParameterList] input request parameters
|
1254
|
+
# #
|
1255
|
+
# # @param [ParameterList] output response parameters
|
1256
|
+
|
1257
|
+
# def self.create( contractName, functionName, input, output )
|
1258
|
+
# Interface.new(
|
1259
|
+
# {
|
1260
|
+
# :interface => functionName,
|
1261
|
+
# :input => input.parameters.map do |param|
|
1262
|
+
# # param [VariableDeclation]
|
1263
|
+
# raise "Domain reference not resolved on #{param}" unless param.domainReference
|
1264
|
+
# {
|
1265
|
+
# :name => param.name,
|
1266
|
+
# # :type => param.type,
|
1267
|
+
# :domain_name => param.domainReference.name,
|
1268
|
+
# }
|
1269
|
+
# end,
|
1270
|
+
# :output => output.parameters.map do |param|
|
1271
|
+
# # param [VariableDeclation]
|
1272
|
+
# raise "Domain reference not resolved on #{param}" unless param.domainReference
|
1273
|
+
# {
|
1274
|
+
# :name => param.name,
|
1275
|
+
# # :type => param.type,
|
1276
|
+
# :domain_name => param.domainReference.name,
|
1277
|
+
# }
|
1278
|
+
# end,
|
1279
|
+
|
1280
|
+
# # :output => functionName.parameters.map { |param| a },
|
1281
|
+
# },
|
1282
|
+
# input, output,
|
1283
|
+
|
1284
|
+
# )
|
1285
|
+
# end
|
1286
|
+
|
1287
|
+
|
1288
|
+
|
1289
|
+
def interfaceDefinition
|
1290
|
+
self[1]
|
1291
|
+
end
|
1292
|
+
def inputParameters
|
1293
|
+
raise "Not used"
|
1294
|
+
self[2]
|
1295
|
+
end
|
1296
|
+
def outputParameters
|
1297
|
+
raise "Not used"
|
1298
|
+
self[3]
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
# return +path+ parameter for ApiLoaderFacade#newInterce
|
1302
|
+
def path
|
1303
|
+
interfaceDefinition[:interface]
|
1304
|
+
end
|
1305
|
+
|
1306
|
+
# return +op+ parameter for ApiLoaderFacade#newInterce
|
1307
|
+
def op
|
1308
|
+
interfaceDefinition[:method]
|
1309
|
+
end
|
1310
|
+
|
1311
|
+
def input
|
1312
|
+
raise "Not used"
|
1313
|
+
interfaceDefinition[:input]
|
1314
|
+
end
|
1315
|
+
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
class Snippet < SexpSbuilder
|
1319
|
+
|
1320
|
+
def initialize( metatype, name, sexp, specName=nil, comment=false )
|
1321
|
+
ary = [
|
1322
|
+
:Snippet,
|
1323
|
+
metatype,
|
1324
|
+
name,
|
1325
|
+
sexp,
|
1326
|
+
specName,
|
1327
|
+
comment,
|
1328
|
+
]
|
1329
|
+
super(*ary)
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
# ------
|
1333
|
+
# sematics
|
1334
|
+
|
1335
|
+
def metatype
|
1336
|
+
self[1]
|
1337
|
+
end
|
1338
|
+
def name
|
1339
|
+
self[2]
|
1340
|
+
end
|
1341
|
+
# Genarate body
|
1342
|
+
def sexp
|
1343
|
+
self[3]
|
1344
|
+
end
|
1345
|
+
# optional specName - if want override generation
|
1346
|
+
def specName
|
1347
|
+
self[4]
|
1348
|
+
end
|
1349
|
+
def comment
|
1350
|
+
self[5]
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
# this stuff gets rendered as snippetBody
|
1354
|
+
def snippet
|
1355
|
+
# self[2..-1]
|
1356
|
+
s(sexp)
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
|
1360
|
+
# metatype+appName combination is unique identifier in specification
|
1361
|
+
# code domain.
|
1362
|
+
|
1363
|
+
# appName is unique identifier in application domain
|
1364
|
+
def appName
|
1365
|
+
name
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
# Unique name as identified by 'metatype':'appName'
|
1369
|
+
def snippetId
|
1370
|
+
"#{metatype}:#{appName}"
|
1371
|
+
end
|
1372
|
+
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
# @!endgroup
|
1376
|
+
|
1377
|
+
end
|
1378
|
+
end
|