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,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
@@ -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
@@ -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,3 @@
1
+ require_relative "controller"
2
+ require_relative "plugin"
3
+
@@ -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