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.
- checksums.yaml +7 -0
- data/README.org +19 -0
- data/VERSION +1 -0
- data/bin/state-explorer.sh +215 -0
- data/lib/eth/al_api.rb +12 -0
- data/lib/eth/ast_sexp.rb +519 -0
- data/lib/eth/constants.rb +354 -0
- data/lib/eth/ethereum.rb +2054 -0
- data/lib/eth/ethereum_expression.rb +476 -0
- data/lib/eth/exception.rb +9 -0
- data/lib/eth/global_scope.rb +100 -0
- data/lib/eth/module.rb +18 -0
- data/lib/eth/sexp_processor.rb +66 -0
- data/lib/eth/sexp_processor_call_separator.rb +163 -0
- data/lib/eth/sexp_processor_getter.rb +125 -0
- data/lib/eth/sexp_processor_resolve.rb +122 -0
- data/lib/eth/sexp_processor_scope.rb +355 -0
- data/lib/eth/sexp_utils.rb +214 -0
- data/lib/eth/solidity_compiler.rb +145 -0
- data/lib/eth/solidity_loader.rb +53 -0
- data/lib/eth/solidity_translator.rb +840 -0
- data/lib/mixer/reference.rb +30 -0
- data/lib/mixer/scope.rb +100 -0
- data/lib/mixer/scoped.rb +18 -0
- data/lib/plugin/controller.rb +267 -0
- data/lib/plugin/module.rb +3 -0
- data/lib/plugin/plugin.rb +33 -0
- data/lib/sbuilder-eth.rb +6 -0
- data/sbuilder-eth.gemspec +38 -0
- metadata +149 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
module Eth
|
3
|
+
|
4
|
+
##
|
5
|
+
# Mixer module to AST nodes, which need to be resolved for a
|
6
|
+
# {#reference} to a {#Sbuilder::Eth::Scoped} symbol
|
7
|
+
module Reference
|
8
|
+
|
9
|
+
# @!attribute enclosingScope [Scope] a pointer to scope which
|
10
|
+
# knows how to resolve {#reference}
|
11
|
+
attr_accessor :enclosingScope
|
12
|
+
|
13
|
+
# @!attribute reference [Scoped] a (resolved) pointer to
|
14
|
+
# {#Scoped} symbol declaration
|
15
|
+
attr_writer :reference
|
16
|
+
|
17
|
+
def reference
|
18
|
+
raise "Reference not resolved for #{self}" if @reference.nil?
|
19
|
+
@reference
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# @return [Boolean] true because mixes as reference
|
24
|
+
def isReference
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/mixer/scope.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
module Eth
|
3
|
+
##
|
4
|
+
# Mixer module to be included to AST nodes, which scope symbols
|
5
|
+
module Scope
|
6
|
+
|
7
|
+
# @!attribute [Hash<Symbol:AstSexp>] symbols
|
8
|
+
def symbols
|
9
|
+
@symbols || {}
|
10
|
+
end
|
11
|
+
|
12
|
+
# @attribute [Sccope] enclosingScope
|
13
|
+
attr_accessor :enclosingScope
|
14
|
+
|
15
|
+
# @param name [String,Symbol] identifier to assign to 'astSexp'
|
16
|
+
# @param astSexp [AstSexp] AST node to associate with name
|
17
|
+
def define(name, astSexp)
|
18
|
+
@symbols ||= {}
|
19
|
+
@symbols[name] = astSexp
|
20
|
+
|
21
|
+
# Add back reference
|
22
|
+
astSexp.scopeDefining = self
|
23
|
+
end
|
24
|
+
|
25
|
+
# def resolve( name )
|
26
|
+
# ret
|
27
|
+
# end
|
28
|
+
|
29
|
+
def scopeHiearachy
|
30
|
+
# assume to be included sto AstSexp implementing 'sexp_type'
|
31
|
+
hierarchy = [ sexp_type ]
|
32
|
+
if enclosingScope
|
33
|
+
hierarchy += enclosingScope.scopeHiearachy
|
34
|
+
end
|
35
|
+
hierarchy
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# @return [Scope] topmost scope
|
40
|
+
def globalScope
|
41
|
+
return self if enclosingScope.nil?
|
42
|
+
enclosingScope.globalScope
|
43
|
+
end
|
44
|
+
|
45
|
+
def allSymbols()
|
46
|
+
parentSymbols = {}
|
47
|
+
if enclosingScope
|
48
|
+
parentSymbols = enclosingScope.allSymbols
|
49
|
+
end
|
50
|
+
parentSymbols.merge( symbols )
|
51
|
+
end
|
52
|
+
|
53
|
+
def getSymbol( name )
|
54
|
+
symbols[name] if symbols && symbols[name]
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param [String] name to resolve
|
58
|
+
#
|
59
|
+
# @param errorReport [Boolean] true for raising error if not
|
60
|
+
# found
|
61
|
+
#
|
62
|
+
# @return [Symbol] symbol resolved for the 'name', nil if not
|
63
|
+
# found
|
64
|
+
def resolve( name, errorReport=true )
|
65
|
+
ret = getSymbol( name )
|
66
|
+
return ret unless ret.nil?
|
67
|
+
ret = enclosingScope.resolve( name, false ) if enclosingScope
|
68
|
+
return ret unless ret.nil?
|
69
|
+
|
70
|
+
raise ScopeException, <<-EOS if errorReport
|
71
|
+
Could not resolve '#{name}' on #{self}
|
72
|
+
|
73
|
+
Scope hierarchy: #{scopeHiearachy.join(',')}
|
74
|
+
Known symbols : #{allSymbols.keys().join(',')}
|
75
|
+
EOS
|
76
|
+
# it is nil
|
77
|
+
ret
|
78
|
+
end
|
79
|
+
|
80
|
+
# def resolveOrReportError( name )
|
81
|
+
# resolved = resolve( name )
|
82
|
+
# return resolved if resolved
|
83
|
+
|
84
|
+
# raise SbuilderEtherumScopeException, <<-EOS
|
85
|
+
# Could not resolve '#{name}' on #{self}
|
86
|
+
|
87
|
+
# Scope hierarchy: #{scopeHiearachy.join(',')}
|
88
|
+
# Known symbols : #{allSymbols.keys().join(',')}
|
89
|
+
# EOS
|
90
|
+
|
91
|
+
# end
|
92
|
+
|
93
|
+
|
94
|
+
# @return [Boolean] true because mixes module scope
|
95
|
+
def isScope
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/mixer/scoped.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
module Eth
|
3
|
+
##
|
4
|
+
# Mixer module to be included to AST nodes acting as symbols which
|
5
|
+
# can be refenced to.
|
6
|
+
module Scoped
|
7
|
+
|
8
|
+
# @!attribute [AstSexp:Scope] back pointer to scope defininign this symbol
|
9
|
+
attr_accessor :scopeDefining
|
10
|
+
|
11
|
+
# @return [Boolean] true because can be scoped
|
12
|
+
def isScoped
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
module Sbuilder
|
2
|
+
module Eth
|
3
|
+
module Plugin
|
4
|
+
|
5
|
+
# Controller for Loading Ethreum application to sbuilder.
|
6
|
+
#
|
7
|
+
# Plugin calls {#initApplication} method, which creates an array
|
8
|
+
# of AlObject and passes these objects controller parent using
|
9
|
+
# method {Sbuilder::Al::Plugin::Controller#addAlObjects}.
|
10
|
+
#
|
11
|
+
#
|
12
|
+
|
13
|
+
|
14
|
+
class Controller < Sbuilder::Al::Plugin::Controller
|
15
|
+
|
16
|
+
|
17
|
+
# ------------------------------------------------------------------
|
18
|
+
# @!group Attributes
|
19
|
+
|
20
|
+
|
21
|
+
# @!attribute [Hash] options command line configurations
|
22
|
+
attr_accessor :options
|
23
|
+
|
24
|
+
# @!attribute [Sbuilder::Eth::SolidityCompiler] compiler
|
25
|
+
attr_accessor :compiler
|
26
|
+
|
27
|
+
# @!attribute [Sbuilder::Eth::SolidityLoader] loader
|
28
|
+
attr_accessor :loader
|
29
|
+
|
30
|
+
# @!attribute [Sbuilder::Eth::SolidityT] eth_translator
|
31
|
+
attr_accessor :eth_translator
|
32
|
+
|
33
|
+
# @!attribute [SexpProcessorScope] scope
|
34
|
+
attr_accessor :scope
|
35
|
+
|
36
|
+
# @!attribute [SexpProcessorResolve] resolve
|
37
|
+
attr_accessor :resolve
|
38
|
+
|
39
|
+
# @!attribute ethRuntimeReturned allows 'ethRuntime' to execute only once
|
40
|
+
@@ethRuntimeReturned = false
|
41
|
+
|
42
|
+
# @!attribute contractClasses [Array<String>] names of classes
|
43
|
+
# parsed
|
44
|
+
@@contractClasses = []
|
45
|
+
|
46
|
+
|
47
|
+
# @!endgroup
|
48
|
+
|
49
|
+
# ------------------------------------------------------------------
|
50
|
+
# @!group Constructor & initialization
|
51
|
+
|
52
|
+
def initialize( options = {} )
|
53
|
+
super( options )
|
54
|
+
self.options = options
|
55
|
+
@logger = getLogger( "EthController", options )
|
56
|
+
@logger.info( "#{__method__}: init eth.controller")
|
57
|
+
# initApi
|
58
|
+
end
|
59
|
+
|
60
|
+
# Create tools in toolchain
|
61
|
+
#
|
62
|
+
# # @param configuration [Hash] configugration yaml from sbuilder.yaml
|
63
|
+
def initInputProcessingPipe( configuration )
|
64
|
+
@logger.info( "#{__method__}: configuration=#{configuration}")
|
65
|
+
|
66
|
+
self.loader = Sbuilder::Eth::SolidityLoader.new( options )
|
67
|
+
|
68
|
+
self.compiler = Sbuilder::Eth::SolidityCompiler.new( options )
|
69
|
+
compiler.solc_command =configuration['compiler']['solc_command'] if configuration && configuration['compiler'] && configuration['compiler']['solc_command']
|
70
|
+
compiler.solc_flags =configuration['compiler']['solc_flags'] if configuration && configuration['compiler'] && configuration['compiler']['solc_flags']
|
71
|
+
compiler.output_directory =configuration['compiler']['output_directory'] if configuration && configuration['compiler'] && configuration['compiler']['output_directory']
|
72
|
+
|
73
|
+
self.scope = Sbuilder::Eth::SexpProcessorScope.new( options )
|
74
|
+
|
75
|
+
self.resolve = Sbuilder::Eth::SexpProcessorResolve.new( options )
|
76
|
+
|
77
|
+
self.eth_translator = Sbuilder::Eth::SolidityTranslator.new( options )
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
# @!endgroup
|
82
|
+
|
83
|
+
# ------------------------------------------------------------------
|
84
|
+
# @!group Class services
|
85
|
+
|
86
|
+
|
87
|
+
# Load inputs as AlObjects to an application array (managed in
|
88
|
+
# super class)
|
89
|
+
#
|
90
|
+
# Method in Sbuilder::Al::Plugin::Controller overridden.
|
91
|
+
#
|
92
|
+
# @param configuration [Hash] hash with properites
|
93
|
+
#
|
94
|
+
# @option configuration [String|Array<String>] 'input' path to
|
95
|
+
# input files to load.
|
96
|
+
#
|
97
|
+
def initApplication( configuration )
|
98
|
+
@logger.info( "#{__method__}: configuration=#{configuration}")
|
99
|
+
|
100
|
+
|
101
|
+
warn "No 'input' property in #{configuration} - nothing loaded" if configuration['input'].nil?
|
102
|
+
|
103
|
+
# Create clean state for processing
|
104
|
+
initInputProcessingPipe( configuration )
|
105
|
+
|
106
|
+
# add metatype definitions (used by alObjects below) to
|
107
|
+
# parent controller state
|
108
|
+
metaDefs = processMetatypes
|
109
|
+
addMetatypes( metaDefs )
|
110
|
+
|
111
|
+
# add AL (application language) objects to parent controller
|
112
|
+
alObjects = processInputs( configuration['input'] )
|
113
|
+
addAlObjects( alObjects )
|
114
|
+
|
115
|
+
end # initApplication
|
116
|
+
|
117
|
+
# Add runtime AL-objects for translation.
|
118
|
+
#
|
119
|
+
# This method called when all sbuilder plugins have had their
|
120
|
+
# {#initApplication} called, and next phase in sbuilder
|
121
|
+
# loading starts. In out case we'll add runtime AL objects
|
122
|
+
# (only once)
|
123
|
+
#
|
124
|
+
|
125
|
+
def initApplicationFinalize
|
126
|
+
|
127
|
+
# run only once (also for many instances!)
|
128
|
+
return if @@ethRuntimeReturned
|
129
|
+
|
130
|
+
alObject = []
|
131
|
+
# Create alObjects - if any alObjects created
|
132
|
+
alObjects = eth_translator.solidityRuntime( @@contractClasses ) unless eth_translator.nil?
|
133
|
+
addAlObjects( alObjects )
|
134
|
+
|
135
|
+
@@ethRuntimeReturned = true
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# @!endgroup
|
141
|
+
|
142
|
+
# ------------------------------------------------------------------
|
143
|
+
# @!group Class implementation
|
144
|
+
|
145
|
+
# Implementation 1) compiles solidity source file pointed by
|
146
|
+
# configuration['input'], 2) loads AST files created in
|
147
|
+
# compilation step 3) translates AST structures to AlObjects,
|
148
|
+
# 4) passes AlObjects to application using method
|
149
|
+
# {Sbuilder::Al::Plugin::Controller#addAlObjects}.
|
150
|
+
#
|
151
|
+
# @param inputs [String, Array<String>] file names to load
|
152
|
+
def processInputs( inputs )
|
153
|
+
inputs = inputs || []
|
154
|
+
inputs = [inputs] unless inputs.is_a?(Array)
|
155
|
+
@logger.info "#{__method__}: inputs=#{inputs.join(',')}"
|
156
|
+
|
157
|
+
alObjects =
|
158
|
+
# # runtime objects
|
159
|
+
# eth_translator.solidityTranslate( nil ) +
|
160
|
+
|
161
|
+
# objects compiled for input files
|
162
|
+
inputs.map do |inputFile|
|
163
|
+
|
164
|
+
# compiles & returns name of AST fie
|
165
|
+
compiler.compile(inputFile)
|
166
|
+
|
167
|
+
end.reduce( []) do |memo, astFile|
|
168
|
+
|
169
|
+
# 1 AST file = N ASTs
|
170
|
+
@logger.info "#{__method__}: astFile=#{astFile}"
|
171
|
+
loader.load( astFile ) do |solSource, index, ast|
|
172
|
+
# loaded one 'ast' from 'astFile'
|
173
|
+
memo << {
|
174
|
+
:ast => ast,
|
175
|
+
:solSource => solSource
|
176
|
+
}
|
177
|
+
end
|
178
|
+
memo
|
179
|
+
end.
|
180
|
+
map do |astDef|
|
181
|
+
ast = astDef[:ast]
|
182
|
+
|
183
|
+
# ensure getters for public membar variables
|
184
|
+
SexpProcessorGetter.new(options).process( ast )
|
185
|
+
|
186
|
+
astDef
|
187
|
+
end.
|
188
|
+
map do |astDef|
|
189
|
+
ast = astDef[:ast]
|
190
|
+
|
191
|
+
# find scope of declations && resolve identifiers
|
192
|
+
scope.process( ast )
|
193
|
+
resolve.process( ast )
|
194
|
+
|
195
|
+
astDef
|
196
|
+
|
197
|
+
end.
|
198
|
+
map do |astDef|
|
199
|
+
ast = astDef[:ast]
|
200
|
+
|
201
|
+
# sepate function call from expressions
|
202
|
+
SexpProcessorCallSeparator.new(options).process( ast )
|
203
|
+
|
204
|
+
astDef
|
205
|
+
end.
|
206
|
+
reduce( [] ) do |memo, astDef|
|
207
|
+
ast = astDef[:ast]
|
208
|
+
# translate one AST at a time + memoize alObjects
|
209
|
+
outputMsg( astDef[:solSource] )
|
210
|
+
memo += eth_translator.solidityTranslate( ast, astDef[:solSource] ) do |contractClass|
|
211
|
+
outputMsg( " - #{astDef[:solSource]} : processing class #{contractClass}" )
|
212
|
+
# Collect class names into an array
|
213
|
+
addContractClass(contractClass)
|
214
|
+
end
|
215
|
+
memo
|
216
|
+
end
|
217
|
+
|
218
|
+
@logger.info( "#{__method__}: alObjects.length=#{alObjects.length}")
|
219
|
+
@logger.debug( "#{__method__}: alObjects=#{alObjects}") if @logger.debug?
|
220
|
+
# @logger.info( "#{__method__}: alObjects=#{alObjects.map { |alO| alO[:type] }.join(',')}")
|
221
|
+
|
222
|
+
# pass alObjects to application array
|
223
|
+
alObjects
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
# @return [Hash] metaDefs (metatype definition used in
|
228
|
+
# application)
|
229
|
+
def processMetatypes
|
230
|
+
eth_translator.metaDefs
|
231
|
+
end
|
232
|
+
|
233
|
+
# @!endgroup
|
234
|
+
|
235
|
+
# ------------------------------------------------------------------
|
236
|
+
# @!group Helpers
|
237
|
+
|
238
|
+
|
239
|
+
# @param soliditySource [String] name solidity file processed
|
240
|
+
def outputMsg(soliditySource)
|
241
|
+
msg =" - Solidity translation: #{soliditySource}"
|
242
|
+
@logger.info( msg )
|
243
|
+
puts msg
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
# @!endgroup
|
248
|
+
|
249
|
+
# ------------------------------------------------------------------
|
250
|
+
# @!group Helpers
|
251
|
+
|
252
|
+
def addContractClass(className)
|
253
|
+
@@contractClasses << className
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
# @!endgroup
|
258
|
+
|
259
|
+
|
260
|
+
|
261
|
+
end # class Controller < Sbuilder::Al::Plugin::Controller
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "sbuilder"
|
2
|
+
|
3
|
+
module Sbuilder
|
4
|
+
|
5
|
+
module Eth
|
6
|
+
|
7
|
+
module Plugin
|
8
|
+
|
9
|
+
|
10
|
+
# Extent Sbuilder::Al::Plugin::Plugin class. The only
|
11
|
+
# modification being to replace default plugin.controller
|
12
|
+
# Sbuilder::Al::Plugin::Controller with
|
13
|
+
# Sbuilder::Eth::Controller.
|
14
|
+
class Plugin < Sbuilder::Al::Plugin::Plugin
|
15
|
+
|
16
|
+
def initialize( options={} )
|
17
|
+
@logger = getLogger( "EthPlugin", options )
|
18
|
+
@logger.info( "#{__method__} sbuilder-eth plugin initialized" )
|
19
|
+
super( options )
|
20
|
+
# replace controller
|
21
|
+
self.controller = Sbuilder::Eth::Plugin::Controller.new( options )
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String] version from VERSION
|
25
|
+
def self.version
|
26
|
+
File.read( File.join( File.dirname( __FILE__), "../..", "VERSION"))
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|