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,9 @@
1
+ module Sbuilder
2
+ module Eth
3
+ class CompilerException < Exception; end
4
+ class TranslatorException < Exception; end
5
+ class MissingImplementation < Exception; end
6
+ class EthereumException < Exception; end
7
+ class ScopeException < Exception; end
8
+ end
9
+ end
@@ -0,0 +1,100 @@
1
+
2
+ module Sbuilder
3
+ module Eth
4
+
5
+ module Test
6
+ def hei
7
+ end
8
+ end
9
+
10
+ class GlobalScopeEntry < AstSexp
11
+
12
+ include Sbuilder::Eth::Scoped
13
+ def initialize
14
+ super( self.class.name.split('::').last.to_sym )
15
+ end
16
+ # @return [Symbol] class basename (as a symbol)
17
+ # def sexp_type
18
+ # self.class.name.split('::').last.to_sym
19
+ # end
20
+ end
21
+
22
+ class SolidityFunction < GlobalScopeEntry
23
+ # @return [Symbol] :reservedFunctionType to indicate that
24
+ # specaial Solidity function
25
+ def functionType
26
+ :reservedFunctionType
27
+ end
28
+ end
29
+
30
+ # Solidity function pushed in global scope
31
+ class SelfDestruct < SolidityFunction; end
32
+ class Revert < SolidityFunction; end
33
+ class Require < SolidityFunction; end
34
+
35
+
36
+ # # SexpExtry for keyword 'this'
37
+ # class This < GlobalScopeEntry; end
38
+
39
+ class GlobalScope < AstSexp
40
+
41
+
42
+ include Sbuilder::Eth::Scope
43
+
44
+ GLOBAL_SCOPE_DEFS =
45
+ [
46
+ {
47
+ :name => Constants::SOL_SELF_DESTRUCT,
48
+ :astSexp => SelfDestruct.new,
49
+ },
50
+ {
51
+ :name => Constants::SOL_REVERT,
52
+ :astSexp => Revert.new,
53
+ },
54
+ {
55
+ :name => Constants::SOL_REQUIRE,
56
+ :astSexp => Require.new,
57
+ },
58
+ # {
59
+ # :name => Constants::SOL_THIS,
60
+ # :astSexp => This.new,
61
+ # }
62
+ ]
63
+
64
+ # ------------------------------------------------------------------
65
+ # @!group Constructor
66
+
67
+ # @return [GlobalScope] initialized (defined scope) GlobalScope
68
+ # instance
69
+ def initialize( options={})
70
+ super( self.class.name.split('::').last.to_sym )
71
+ end
72
+
73
+
74
+ def self.start( options={} )
75
+ globalScope = GlobalScope.new( options )
76
+
77
+ globalScopeInit.each do |scopeDef|
78
+ globalScope.define( scopeDef[:name], scopeDef[:astSexp])
79
+ end
80
+
81
+ globalScope
82
+ end
83
+
84
+ # @return [Array<Hash>] initHash array of hashes defining
85
+ # initial gloabl scope, hash defines properties ':name' and
86
+ # ':astSexp'
87
+ # @option initHash [:Symbol] :name
88
+ # @option initHash [:Symbol] :astSexp
89
+ def self.globalScopeInit
90
+ GLOBAL_SCOPE_DEFS
91
+ end
92
+
93
+ # @!endgroup
94
+
95
+ extend Test
96
+
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'constants'
2
+ require_relative 'exception'
3
+ require_relative 'al_api'
4
+ require_relative 'ethereum_expression'
5
+ require_relative 'ethereum'
6
+ require_relative 'ast_sexp'
7
+ require_relative 'global_scope'
8
+ require_relative "solidity_compiler"
9
+ require_relative "solidity_loader"
10
+ require_relative "solidity_translator"
11
+
12
+ require_relative "sexp_utils"
13
+ require_relative "sexp_processor"
14
+ # require_relative "sexp_processor_constructors"
15
+ require_relative "sexp_processor_getter"
16
+ require_relative "sexp_processor_call_separator"
17
+ require_relative "sexp_processor_scope"
18
+ require_relative "sexp_processor_resolve"
@@ -0,0 +1,66 @@
1
+ require 'sexp_processor'
2
+
3
+ module Sbuilder
4
+ module Eth
5
+ class SexpProcessorEth < SexpProcessor
6
+
7
+ # include logger
8
+ include Sbuilder::Al::Util::MyLogger # mix logger
9
+
10
+ # @# @!attribute [Hash] options
11
+ attr_accessor :options
12
+
13
+ # @# @!attribute [Logger] logger
14
+ attr_reader :logger
15
+
16
+ def initialize( options={})
17
+ super()
18
+
19
+ self.options = options
20
+ @logger = getLogger( nil, options )
21
+
22
+ # Override defaults in parent class
23
+ self.strict = false
24
+
25
+ # Allow Sexp nodes to remain intact, see 'process_rest'
26
+ self.require_empty = false
27
+
28
+ # visitors just recurses - do not shift sexp (as sexp_processor default does)
29
+ self.default_method = :process_rest
30
+
31
+ # no warning needed when using default method
32
+ self.warn_on_default = false
33
+
34
+ end
35
+
36
+ # Use for default processor when we need to control what gets
37
+ # processed.
38
+ def process_skip exp
39
+ s()
40
+ end
41
+
42
+
43
+ def process_rest exp
44
+ pos = 0
45
+ ret = s()
46
+ until pos >= exp.length
47
+ sexp = exp[pos]
48
+ pos += 1
49
+ psexps = process( sexp ) if Sexp === sexp
50
+ if !psexps.nil? && psexps.sexp_type == :dummy
51
+ # :dummy get flattened
52
+ psexps.rest.each do |psexp|
53
+ ret << psexp
54
+ end
55
+ else # non-dummy sexp || nil sexp
56
+ ret << psexps unless psexps.nil?
57
+ end
58
+ end
59
+ ret
60
+ end
61
+
62
+
63
+ end
64
+ end
65
+ end
66
+
@@ -0,0 +1,163 @@
1
+ require 'sexp_processor'
2
+
3
+ module Sbuilder
4
+ module Eth
5
+
6
+ # Sexp preprocessor find call statements in expression and add a
7
+ # separate call immediately before statement containing the
8
+ # expression
9
+ #
10
+ class SexpProcessorCallSeparator < SexpProcessorEth
11
+
12
+ # ------------------------------------------------------------------
13
+ # @!group Object state
14
+
15
+
16
+ # @!attribute [Ast::Statement] current statement
17
+ attr_accessor :currentStatement
18
+
19
+
20
+ # @!endgroup
21
+
22
+
23
+ # ------------------------------------------------------------------
24
+ # @!group Constructor
25
+
26
+ def initialize( options={} )
27
+ super( options )
28
+ end
29
+
30
+ # @!endgroup
31
+
32
+ # ------------------------------------------------------------------
33
+ # @!group Scope hierarch utils
34
+
35
+ def wrapStatement( stmtSexp )
36
+
37
+ # remember 'prevScope', update enclosing scope, switch '@currentScope',
38
+ prevStatement = currentStatement
39
+ self.currentStatement = stmtSexp
40
+
41
+ begin
42
+ yield
43
+ ensure
44
+ self.currentStatement = prevStatement
45
+ end
46
+
47
+ end
48
+
49
+ # @!endgroup
50
+
51
+
52
+ # ------------------------------------------------------------------
53
+ # @!group AST-node processors
54
+
55
+
56
+ # Add :FunctionCalls immediately before a statement, which has
57
+ # expressions with requiring :FunctionCall
58
+ #
59
+ # Implementation visits block statements AST nodes, and finds
60
+ # FunctionCalls expect for "calls without assignment"
61
+ # i.e. :ExpressionStatement with direct child[0] as
62
+ # :FunctionCall.
63
+
64
+ def process_Block( sexp )
65
+
66
+ logger.debug "#{__method__}: sexp=#{sexp}" if logger.debug?
67
+
68
+ # Array of [Int, Array<:FunctionCall>]
69
+ callsToAdd = []
70
+
71
+ sexp.children.each_with_index do |stmt,i|
72
+
73
+ calls = process( stmt )
74
+ @logger.debug "\n\nstmt=#{stmt}\ncalls=#{calls}" if @logger.debug?
75
+
76
+ # collect index && :FunctionCalls lValueRequested
77
+ calls = unwrap(calls).select{ |s| s.sexp_type == :FunctionCall } || []
78
+ @logger.debug "#{__method__}: calls=#{calls}" if @logger.debug?
79
+
80
+ # build [ 0, [f1,f2] ], [ 1, [f3,f4, ..] ], ...
81
+ if calls.length
82
+ # normal function/constructor!!
83
+ logger.info "#{__method__}: add #{calls.length} function calls #{calls.map { |call| call.callTarget["name"] } }"
84
+ callsToAdd << [ i, calls ]
85
+ end
86
+
87
+ end # each with index
88
+
89
+ # Process in reverse order to keep index valid
90
+ callsToAdd.reverse.each do |posToAdd|
91
+ pos = posToAdd[0]
92
+ calls = posToAdd[1]
93
+ calls.reverse.each do |call|
94
+ logger.info "#{__method__}: insert pos #{pos}, call #{call}"
95
+ sexp.insertChild( pos, call )
96
+ logger.debug "#{__method__}: sexp.children #{sexp.children}" if logger.debug?
97
+ end
98
+ end
99
+
100
+ s()
101
+
102
+ end
103
+
104
+
105
+ # @!endgroup
106
+
107
+
108
+
109
+ # ------------------------------------------------------------------
110
+ # @!group Function found
111
+
112
+
113
+ def process_ExpressionStatement( sexp )
114
+ return s() if sexp.children[0].sexp_type == :FunctionCall
115
+ process_rest( sexp )
116
+ end
117
+
118
+ def process_FunctionCall( sexp )
119
+ sexp
120
+ end
121
+
122
+
123
+ # @!endgroup
124
+
125
+ # ------------------------------------------------------------------
126
+ # @!group Helpers
127
+
128
+ # Recursively flatten 1 level until sArray is Array<Sexp> (with
129
+ # non-empty Sexps)
130
+ #
131
+ # @param sArray [Array<Array*<Sexp>>] Array
132
+ #
133
+ # @return [Array<Sexp>]
134
+ def unwrap( sArray )
135
+
136
+ # not an array - no change
137
+ return sArray unless sArray.is_a?(Array)
138
+
139
+ sArray = sArray.
140
+ # unwrap non sexps
141
+ map { |e| e.is_a?( Sexp) && e.sexp_type.is_a?( Symbol ) ? e : unwrap(e) }.
142
+ # reject empty elements
143
+ select { |e| e != [] }
144
+
145
+ # peel off proper outer arrays
146
+ sArray = sArray[0] while sArray.is_a?(Array) &&
147
+ sArray.length == 1 &&
148
+ sArray[0].is_a?(Array) && sArray[0].length == 1 && sArray[0][0].is_a?( Array)
149
+
150
+
151
+ sArray
152
+
153
+ end
154
+
155
+ # @!endgroup
156
+
157
+
158
+
159
+ end # class
160
+
161
+ end
162
+ end
163
+
@@ -0,0 +1,125 @@
1
+ require 'sexp_processor'
2
+
3
+ module Sbuilder
4
+ module Eth
5
+
6
+ # Sexp preprocessor, which adds getters for public variable
7
+ # declarations
8
+ #
9
+ class SexpProcessorGetter < SexpProcessorEth
10
+
11
+ def initialize( options={} )
12
+ super( options )
13
+ end
14
+
15
+ # Find public variable declarations without getter method
16
+ # {Sbuilder::Eth::SexpUtils.getterName}, add default getter to
17
+ # the contract using {Sbuilder::Eth::SexpUtils.sexpGetter}.
18
+ #
19
+ # Uses {#SexpProcessorGetterFinder} to get an array
20
+ # ':VariableDeclaration' and ':FunctionDefinition' sexps. Array
21
+ # contains also sexp_types :NONE for variable declaration which
22
+ # are not public.
23
+
24
+ def process_ContractDefinition( sexp )
25
+ logger.debug "#{__method__}: sexp=#{sexp}" if logger.debug?
26
+
27
+ # find public variable declarations without getter
28
+ gettersToImplemt =
29
+ SexpProcessorGetterFinder.new(options).
30
+ process( sexp ).
31
+ # s() generated by sexp-processor default-method e.g modifiers
32
+ select { |sexp| sexp.length > 0 }.
33
+ # sieve :VariableDeclaration before :FunctionDefinition
34
+ sort { |s1,s2| -1 * (s1.sexp_type.to_s <=> s2.sexp_type.to_s) }.
35
+ # sieve builds a hash getter name -> VariableDeclaration
36
+ reduce( {} ) do |getters,sexp|
37
+ case sexp.sexp_type
38
+ when :VariableDeclaration
39
+ # should implement getter with 'getterName'
40
+ getters[ SexpUtils.getterName( sexp['name']) ] = sexp
41
+ when :FunctionDefinition
42
+ # getter already implemented - remove
43
+ getters[ sexp["name"] ] = nil
44
+ when :NONE
45
+ # getter not needed for a variable declation
46
+ else
47
+ raise "Unexppected sexp-type #{sexp.sexp_type} for #{sexp}"
48
+ end
49
+ getters
50
+ end.
51
+ # create getter only for var-decls without getter
52
+ select do |k,sexp|
53
+ !sexp.nil?
54
+ end
55
+
56
+ logger.info "#{__method__}:gettersToImplemt=#{gettersToImplemt.keys.join(',')}"
57
+
58
+ # add getter method to contract 'sexp'
59
+ gettersToImplemt.each do |name, variableDeclarationSexp|
60
+ # create getter for contract 'sexp'
61
+ sexp.addChild( SexpUtils.sexpGetter( variableDeclarationSexp["name"]) )
62
+ end
63
+ sexp
64
+ end # process_ContractDefinition( sexp )
65
+
66
+ end
67
+
68
+ # Get an array ':VariableDeclaration' and ':FunctionDefinition'
69
+ # sexps. Array contains also sexp_types :NONE for variable
70
+ # declaration which are not public.
71
+
72
+ class SexpProcessorGetterFinder < SexpProcessorEth
73
+ # ------------------------------------------------------------------
74
+ # @!group Constructor
75
+
76
+ def initialize( options={} )
77
+ super( options )
78
+
79
+ # Process known sexp
80
+ self.default_method = :process_skip
81
+
82
+ end
83
+
84
+
85
+ # @!endgroup
86
+
87
+ # ------------------------------------------------------------------
88
+ # @!group Resolvers for reference node types
89
+
90
+ def process_ContractDefinition( sexp )
91
+ process_rest( sexp )
92
+ end
93
+
94
+ # We know that we are processing 'VariableDeclaration' for a
95
+ # contrcact (because we have intercepted FunctionDefinition in
96
+ # {#process_FunctionDefinition}). Create getter for public
97
+ # variable declaration.
98
+ #
99
+ # @return [AstSexp(:VariableDeclaration), AstSexp(:NONE)] :NONE
100
+ # if no getter needed
101
+ def process_VariableDeclaration( sexp )
102
+ logger.debug "#{__method__}: sexp=#{sexp}" if @logger.debug?
103
+ logger.info "#{__method__}: variable name =#{sexp['name']}, visibility #{sexp['visibility']}"
104
+ if sexp["visibility"] == Constants::SOL_VISIBILITY_PUBLIC
105
+ return sexp
106
+ end
107
+ # not public --> no getter needed
108
+ s(:NONE)
109
+ end
110
+
111
+ # Intercept 'FunctionDefinition' to prevent recursion into
112
+ # variable declaration for function parameters and locals. just
113
+ # return so that we can check, whether some getter already
114
+ # defined
115
+ #
116
+ def process_FunctionDefinition( sexp )
117
+ sexp
118
+ end
119
+
120
+ # @!endgroup
121
+
122
+ end
123
+ end
124
+ end
125
+