sbuilder-eth 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+