sbuilder-ial 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,404 @@
1
+ require_relative 'producer_ethereum_const.rb'
2
+
3
+ module Sbuilder
4
+ module Ial
5
+ module Action
6
+ module Render
7
+
8
+ class ProducerEthereum < Producer
9
+
10
+ PROGNAME = nil # progname for logger default class name
11
+ include Sbuilder::Ial::MyLogger # mix logger
12
+
13
+ # @attr [Boolean] fixed_snippet_produced guarantee that
14
+ # 'p_base_snippets' called only once
15
+ @@fixed_snippet_produced=false
16
+
17
+
18
+ # ------------------------------------------------------------------
19
+ # @!group Construct & configure
20
+
21
+ def initialize( options = {}, metatypes=nil )
22
+ super( options, metatypes )
23
+ @logger = getLogger( nil, options )
24
+ @logger.info "#{__method__}: starting options=#{options}"
25
+
26
+ end
27
+
28
+ def self.start( options = {}, metatypes=nil )
29
+ ProducerEthereum.new( options, metatypes )
30
+ end
31
+ # @!endgroup
32
+
33
+ # ------------------------------------------------------------------
34
+ # @!group Bridge to other modules
35
+
36
+ # @return [Hash] constanExpressions from
37
+ # 'Sbuilder::Ial::Model::Constants::CONSTANT_EXPRESSIONS'
38
+ #
39
+ # @option constanExpressions [:symbol] key constant
40
+ #
41
+ # @option constanExpressions [String] value constant in tla
42
+ # language
43
+
44
+ def constanExpressions
45
+ Sbuilder::Ial::Model::Constants::CONSTANT_EXPRESSIONS
46
+ end
47
+
48
+ # @return [Hash] IAL_OPERATORS to map ialOperator to
49
+ # corresponding tlaOperatr
50
+ def ialOperators
51
+ Sbuilder::Ial::Model::Constants::IAL_OPERATORS
52
+ end
53
+
54
+ # @!endgroup
55
+
56
+ # ------------------------------------------------------------------
57
+ # @!group Production rules
58
+
59
+ # produce fixed snippet only once
60
+ def p_base_snippets
61
+ return [] if @@fixed_snippet_produced
62
+ # toggle flag to produce only once
63
+ @@fixed_snippet_produced = true
64
+ ProducerEthereumConstants::BASE_SNIPPETS
65
+ end
66
+
67
+ def p_variable_definition( varName, initExpression )
68
+ @logger.info "#{__method__}: varName=#{varName}, initExpression=#{initExpression}"
69
+ {
70
+ :metatype => metatype4varName,
71
+ :appName => varName,
72
+ :specName => nil,
73
+ :comment => "Variable #{varName}",
74
+ :template => gen_state_variable( varName2Specname( varName ), initExpression )
75
+ }
76
+ end
77
+
78
+ # Produce macro snippet for 'macroName'
79
+ def p_macro( macroName, parameters, stmts )
80
+ @logger.info "#{__method__}: macroName=#{macroName}, parameters=#{parameters}"
81
+ @logger.debug "#{__method__}: macroName=#{macroName} stmts=#{stmts}" if @logger.debug?
82
+ {
83
+ :metatype => metatype4macro,
84
+ :appName => macroName,
85
+ :specName => nil,
86
+ :comment => "Macro #{macroName}",
87
+ :template => gen_macro( macroName2Specname( macroName ), parameters, stmts )
88
+ }
89
+ end
90
+
91
+ # Produce 'operator' snippet for 'operatorName' with
92
+ # 'parameters' and 'body' -expression
93
+ def p_operator( operatorName, parameters, body )
94
+ {
95
+ :metatype => metatype4operator,
96
+ :appName => operatorName,
97
+ :specName => nil,
98
+ :comment => "Operator #{operatorName}",
99
+ :template => gen_operator( operatorName2Specname( operatorName ), parameters, body )
100
+ }
101
+ end
102
+
103
+ # Entry-macro for transaction 'txName'
104
+ def p_tx_entry( txName, operationName, stmts=nil )
105
+ @logger.info "#{__method__}: txName=#{txName}, operationName=#{operationName}"
106
+ @logger.debug "#{__method__}: txName=#{txName} stmts=#{stmts}" if @logger.debug?
107
+
108
+ # appName = "#{ctx[:transaction_entry].name}(action)"
109
+ metatype = metaTxEntry
110
+ appName = txName2appName( txName, operationName )
111
+
112
+ #
113
+ formalParameter_for_tx_input = 'input'
114
+
115
+ # default calls 'service procedure' of txName
116
+ if stmts.nil? || !stmts.any?
117
+ stmts =
118
+ s(gen_procedure_call( txName2ServiceProcedure( txName, operationName ), formalParameter_for_tx_input))
119
+ end
120
+
121
+ stmts = gen_stmts( stmts )
122
+
123
+ {
124
+ :metatype => metatype,
125
+ :appName => appName,
126
+ :specName => nil,
127
+ :comment => "Enter transaction '#{txName}'",
128
+ :template => gen_macro( gen_specname( metatype, appName), formalParameter_for_tx_input, stmts )
129
+ }
130
+ end
131
+
132
+ # @param [String:Array] locals array names of local variables
133
+ def p_tx_function( txName, operationName, locals, stmts )
134
+ @logger.info "#{__method__}: txName=#{txName}, locals=#{locals}"
135
+ @logger.debug "#{__method__}: txName=#{txName} stmts=#{stmts}" if @logger.debug?
136
+ metatype = metaTxFunc
137
+ appName = txName2appName( txName, operationName )
138
+ interfaceName = txName2interfaceName( txName, operationName )
139
+ labelPrefix = gen_specname( metatype, appName )
140
+ labeledStmts = gen_stmts(gen_serviceProcedureLabelStatements( stmts, labelPrefix ))
141
+ # functionName = gen_specname( metatype, appName )
142
+ {
143
+ :metatype => metatype,
144
+ :appName => appName,
145
+ :specName => nil,
146
+ :comment => "Implementation of transaction '#{txName}'",
147
+ :template => gen_service_procedure( txName2ServiceProcedure( txName, operationName ), interfaceName, locals, labeledStmts )
148
+ }
149
+ end
150
+
151
+ # Produce exit (macro) for transaction 'txName'
152
+ def p_tx_exit( txName, operationName )
153
+ metatype = metaTxExit
154
+ appName = txName2appName( txName, operationName )
155
+ specName = "dummy"
156
+ {
157
+ :metatype => metatype,
158
+ :appName => appName,
159
+ :specName => specName,
160
+ :comment => "Exit from transaction #{appName}",
161
+ :template => nil, # no body - just map appName->specName
162
+ :body => nil, # no body - just map appName->specName
163
+ }
164
+ end
165
+
166
+ # @!endgroup
167
+
168
+ # ------------------------------------------------------------------
169
+ # @!group Production rules
170
+
171
+ private def varName2Specname( varName )
172
+ gen_specname( metatype4varName, varName )
173
+ end
174
+
175
+ private def domainName2Specname( domainName )
176
+ # gen_plainname( domainName )
177
+ gen_specname( metatype4Domain, domainName )
178
+ end
179
+
180
+ def macroName2Specname( macroName )
181
+ gen_specname( metatype4macro, macroName )
182
+ end
183
+
184
+ def operatorName2Specname( operatorName )
185
+ gen_specname( metatype4operator, operatorName )
186
+ end
187
+
188
+ private def metatype4varName
189
+ metaApp
190
+ end
191
+
192
+ # Domain are known to be defined under metatype
193
+ # 'META_MODEL_DOMAINS'
194
+ private def metatype4Domain
195
+ Sbuilder::FacadeConstants::META_MODEL_DOMAINS
196
+ end
197
+
198
+ private def metatype4macro
199
+ metaApp
200
+ end
201
+
202
+ private def metatype4operator
203
+ metaApp
204
+ end
205
+
206
+ private def metatype4txFunction
207
+ metaTxFunc
208
+ end
209
+
210
+ private def txName2InputVariable( txName, operationName )
211
+ gen_interface_input_variable_name( txName2interfaceName( txName, operationName ), metatype4txFunction )
212
+ end
213
+
214
+ private def txName2appName( txName, operationName )
215
+ "#{txName}(#{operationName})"
216
+ end
217
+
218
+ private def txName2interfaceName( txName, operationName )
219
+ "#{txName}(#{operationName})"
220
+ end
221
+
222
+ private def txName2EntryMacro( txName )
223
+ gen_specname( metaTxEntry, txName2appName( txName ) )
224
+ end
225
+
226
+ private def txName2ServiceProcedure( txName, operationName )
227
+ gen_specname( metatype4txFunction, txName2appName( txName, operationName ) )
228
+ end
229
+
230
+ # @!endgroup
231
+
232
+ # ------------------------------------------------------------------
233
+ # @!group Production rules for statements
234
+ def p_skipStatement
235
+ @logger.info "#{__method__}"
236
+ s(gen_skip )
237
+ end
238
+
239
+ def p_conditionalStatement( condition, ifBlock, elseBlock )
240
+ @logger.info "#{__method__}: condition=#{condition}"
241
+ @logger.debug "#{__method__}: ifBlock=#{ifBlock}" if @logger.debug?
242
+ @logger.debug "#{__method__}: elseBlock=#{elseBlock}" if @logger.debug?
243
+ s(gen_if( condition, ifBlock, elseBlock ))
244
+ end
245
+
246
+ def p_callServiceStatement( txName, operation, parameters )
247
+ @logger.info "#{__method__}: txName=#{txName}, operation=#{operation}, parameters=#{parameters}"
248
+ serviceSpecname = txName2ServiceProcedure( txName, operation )
249
+ s(gen_procedure_call( serviceSpecname, parameters))
250
+ end
251
+
252
+ def p_callMacroStatement( macroName, parameters )
253
+ @logger.info "#{__method__}: macroTarget=#{macroName}, parameters=#{parameters}"
254
+ s(gen_macro_call( macroName2Specname( macroName ), parameters ))
255
+ end
256
+
257
+ def p_printStatement( msg )
258
+ @logger.info "#{__method__}: msg=#{msg}"
259
+ s(gen_print( msg ))
260
+ end
261
+
262
+ def p_assignTo( assignTo, rval )
263
+ @logger.info "#{__method__}: assignTo=#{assignTo}, rval=#{rval}"
264
+ s(gen_assign( assignTo, rval ))
265
+ end
266
+
267
+
268
+ # @!endgroup
269
+
270
+ # ------------------------------------------------------------------
271
+ # @!group Production rules for expressions
272
+
273
+ # @param [String] varName (appName) of variable expression
274
+ # @return [sTla] specname of variable 'varName'
275
+ def p_variable_expression( varName )
276
+ @logger.info "#{__method__}: varName=#{varName}"
277
+ varName2Specname( varName )
278
+ end
279
+
280
+ # ----------
281
+ # expressions referencign parameters
282
+
283
+ # Expression accessing 'parameterName' of transaction 'txtName'
284
+ #
285
+ # @return [sTla]
286
+ def p_tx_parameter_expression( txName, operationName, parameterName )
287
+ @logger.info "#{__method__}: txName=#{txName}, parameterName=#{parameterName}"
288
+ gen_record_field( txName2InputVariable(txName, operationName), parameterName )
289
+ end
290
+
291
+ # Expression referencing 'paramaterName' in 'macro'
292
+ def p_macro_parameter_expression( macroName, parameterName )
293
+ @logger.info "#{__method__}: macroName=#{macroName}, parameterName=#{parameterName}"
294
+ p_parameter_expression( parameterName )
295
+ end
296
+
297
+ # Expression referencing 'paramaterName' in 'operatorName'
298
+ def p_operator_parameter_expression( operatorName, parameterName )
299
+ @logger.info "#{__method__}: operatorName=#{operatorName}, parameterName=#{parameterName}"
300
+ p_parameter_expression( parameterName )
301
+ end
302
+
303
+ # Local DRY method to access paramterName
304
+ private def p_parameter_expression( parameterName )
305
+ gen_plainname( parameterName )
306
+ end
307
+
308
+ # ----------
309
+ # Operator expressions
310
+
311
+ def p_operator_expression( operatorName, args )
312
+ @logger.info "#{__method__}: operatorName=#{operatorName}, args=#{args}"
313
+ p_operator_expression_exec( operatorName2Specname( operatorName ), args )
314
+ end
315
+
316
+ # Call operator 'operatorName' with arguments. NB:
317
+ # 'operatorName' not mapped using metatype (it is
318
+ # infrastructure operator).
319
+ def p_infra_operator_expression( operatorName, args )
320
+ @logger.info "#{__method__}: operatorName=#{operatorName}, args=#{args}"
321
+ p_operator_expression_exec( operatorName, args )
322
+ end
323
+
324
+ private def p_operator_expression_exec( opExpression, args )
325
+ gen_operator_call( opExpression, args )
326
+ end
327
+
328
+ # ----------
329
+
330
+ # Expression for calling 'operatorName' with arguments 'args'
331
+ # Expression for accessing domain (set) with name 'domainName'
332
+ def p_domain_expression( domainName )
333
+ @logger.info "#{__method__}: domainName=#{domainName}"
334
+ domainName2Specname( domainName )
335
+ end
336
+
337
+ # expression refering to local variable 'local'
338
+ def p_local_expression( local )
339
+ @logger.info "#{__method__}: local=#{local}"
340
+ gen_plainname( local )
341
+ end
342
+
343
+ def p_binary_expression( lval, op, rval )
344
+ @logger.info "#{__method__}: lval=#{lval}, op=#{op}, rval=#{rval}"
345
+ gen_bin_op( p_op(op), lval, rval )
346
+ end
347
+
348
+ # @param [Lambda] templateEval is lambda ->(gen, args)
349
+ # evaluate the template
350
+ def p_template_expression( templateEval, args )
351
+ @logger.info "#{__method__}: template=#{templateEval}, args=#{args}"
352
+ # Sbuilder::Ial::Model::Constants::TLA_TEMPLATES[template].call(self, args)
353
+ templateEval[self, *args]
354
+ end
355
+
356
+ # @param [String|Numeric|TrueClass|FalseClass] val
357
+ def p_constant_expression( val )
358
+ @logger.info "#{__method__}: val=#{val}"
359
+ case val
360
+ when String
361
+ gen_str( val )
362
+ when Numeric
363
+ gen_constant( val )
364
+ when TrueClass
365
+ gen_constant( "TRUE" )
366
+ when FalseClass
367
+ gen_constant( "FALSE" )
368
+ when Symbol
369
+ # map symbol 'val' to sTla for constant expression
370
+ p_constant_value( val )
371
+ else
372
+ raise "Unsupported type #{val.class} for val '#{val}'"
373
+ end
374
+ end
375
+
376
+ # Map 'constSymbol' to gen_constant( 'constValue') using
377
+ # hash table 'constanExpressions'
378
+ #
379
+ # @param [:Symbol] constSymbol any value :empty
380
+ #
381
+ # @return [sTla] expression value for 'constSymbol'
382
+ def p_constant_value( constSymbol )
383
+ constValue = constanExpressions[constSymbol]
384
+ raise "Unsupported symbol value #{constSymbol}" if constValue.nil?
385
+ gen_constant(constValue)
386
+ end
387
+
388
+ # Map 'ialOp' to 'tlaOperator' using hash table 'ialOperators'
389
+ def p_op( ialOp )
390
+ tlaOperator = ialOperators[ialOp]
391
+ raise "Unsupported operator value #{ialOp}" if tlaOperator.nil?
392
+ tlaOperator
393
+ end
394
+
395
+ # @!endgroup
396
+
397
+
398
+ end # class ProducerEthreum < Producer
399
+
400
+
401
+ end
402
+ end
403
+ end
404
+ end
@@ -0,0 +1,221 @@
1
+ module Sbuilder
2
+ module Ial
3
+ module Action
4
+ module Render
5
+ class ProducerEthereumConstants
6
+
7
+ # Metatypes used to produce ethreum code
8
+
9
+ # OP_INFRA_SET_RESPONSE="InfrastructureServiceResponse"
10
+ OP_INFRA_RETURN="InfrastructureServiceReturn"
11
+ OP_INFRA_GET_RESPONSE="InfrastructureServiceGetResponse"
12
+ OP_INFRA_GET_STATUS="InfrastructureServiceGetStatus"
13
+ OP_INFRA_STATUS_INIT="InfrastructureServiceInit"
14
+ OP_INFRA_THROW="schedule_throw"
15
+ OP_INFRA_UPDATE_TOP='UpdateTop'
16
+ OP_INFRA_RESPONSES='responses'
17
+ OP_INFRA_NEXT_ID='NextId'
18
+
19
+
20
+ # ------------------------------------------------------------------
21
+ # FRAMEWORK -services
22
+ FW_SVC_UNIQUE_ELEMENTS='uniqueElements'
23
+ FW_OP_ELEMENT_EXISTS = 'elementExists'
24
+ FW_OP_GET_ELEMENT = "getElement"
25
+
26
+ FW_STATE_ACCOUNTS = "accounts"
27
+ FW_STATE_ACCOUNTS_TEMP = "accounts_temp"
28
+ FW_STATE_STORAGE_ROOT = 'storageRoot'
29
+ FW_STATE_STORAGE_ROOT_TEMP = 'storageRoot_temp'
30
+ FW_STATE_MINED = 'mined'
31
+
32
+ ETH_OPEATOR_INTRINSIC_GAS = 'intrinsicGas'
33
+ ETH_OPEATOR_TRANSACTION_GAS = 'transactionGas'
34
+ ETH_OPEATOR_UP_FRONT_COST = 'upFrontCost'
35
+ ETH_OPEATOR_GAS_VALUE = 'gasValue'
36
+
37
+
38
+ # ethereum specific services
39
+ TLA_SERVICE_POP="ethereum_service_pop"
40
+
41
+
42
+ INITIAL_SNIPPETS=
43
+ [
44
+
45
+ # ------------------------------------------------------------------
46
+ # Base snippets - i.e. no connection to ethreums
47
+ # {
48
+ # :comment => "macro to update existing contract",
49
+ # :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
50
+ # :appName => 'update_existing_contract',
51
+ # :body =>
52
+ # <<-EOS.unindent,
53
+ # macro update_existing_contract() {
54
+ # print <<"update_existing_contract">>;
55
+ # }
56
+ # EOS
57
+ # },
58
+
59
+ {
60
+ :comment => "Add element to sequence head",
61
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
62
+ :appName => 'Push',
63
+ :body =>
64
+ <<-EOS.unindent,
65
+ Push( s, e ) == <<e>> \\o s
66
+ EOS
67
+ },
68
+
69
+ {
70
+ :comment => "Update element to sequence head",
71
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
72
+ :appName => OP_INFRA_UPDATE_TOP,
73
+ :body =>
74
+ <<-EOS.unindent,
75
+ UpdateTop( s, e ) == <<e>> \\o Tail(s)
76
+ EOS
77
+ },
78
+
79
+
80
+ {
81
+ :comment => "Propgate top element to stack & pop",
82
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
83
+ :appName => 'PropageOnStack',
84
+ :body =>
85
+ <<-EOS.unindent,
86
+ (* PropageOnStack( s, v ) == [i \\in 1..Len(s) |-> v ] *)
87
+ PropageOnStack( s, v ) == [i \\in 1..Len(s) |-> IF i = 1 THEN v ELSE s[i] ]
88
+ EOS
89
+ },
90
+
91
+ {
92
+ :comment => "Check if unique element exists",
93
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
94
+ :appName => 'elementExists',
95
+ :body =>
96
+ <<-EOS.unindent,
97
+ elementExists( set, key, id ) == Cardinality( { e \\in set : e[key] = id } ) = 1
98
+ EOS
99
+ },
100
+
101
+ {
102
+ :comment => "Check if unique element exists",
103
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
104
+ :appName => 'getElement',
105
+ :body =>
106
+ <<-EOS.unindent,
107
+ (*
108
+ * Return element from 'set' such that element['key'] == 'id'
109
+ * Assume 'id' unique, and element exists
110
+ *)
111
+ getElement( set, key, id ) == ( CHOOSE x \\in { e \\in set : e[key] = id } : TRUE )
112
+ EOS
113
+ },
114
+
115
+ {
116
+ :comment => "stable when process finished running",
117
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
118
+ :appName => 'Stable',
119
+ :body =>
120
+ <<-EOS.unindent,
121
+ Stable == tx_running = FALSE
122
+ EOS
123
+ },
124
+
125
+ {
126
+ :comment => "Sum record fields",
127
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
128
+ :appName => 'SumRecordField',
129
+ :body =>
130
+ <<-EOS.unindent,
131
+ RECURSIVE SumRecordField(_,_)
132
+ (*
133
+ * Sum of field 'f' of record elements in set 'S'
134
+ *
135
+ * @param [Set] S set of records
136
+ * @param [String] f name of field
137
+ *)
138
+ SumRecordField(S,f) ==
139
+ IF S = {} THEN 0
140
+ ELSE LET x == CHOOSE x \\in S : TRUE
141
+ IN x[f] + SumRecordField(S \\ {x}, f)
142
+ EOS
143
+ },
144
+
145
+ {
146
+ :comment => "Sum function",
147
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
148
+ :appName => 'SumOfFunction',
149
+ :body =>
150
+ <<-EOS.unindent,
151
+ RECURSIVE SumOfFunction(_)
152
+ (*
153
+ * Sum of function values
154
+ *
155
+ * @param [Sequnce|Function] F to sum over
156
+ *
157
+ *)
158
+ SumOfFunction( F ) ==
159
+ IF F = <<>> THEN 0
160
+ ELSE LET x == CHOOSE x \\in DOMAIN F : TRUE
161
+ IN F[x] + SumOfFunction( [ v \\in DOMAIN F \\ {x} |-> F[v] ] )
162
+ EOS
163
+ },
164
+
165
+ {
166
+ :comment => "Operator to check element uniques in a set",
167
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
168
+ :appName => FW_SVC_UNIQUE_ELEMENTS,
169
+ :body =>
170
+ <<-EOS.unindent,
171
+ #{FW_SVC_UNIQUE_ELEMENTS}( set, key ) == \\A e1 \\in set: \\A e2 \\in set: e1[key] = e2[key] => e1 = e2
172
+ EOS
173
+ },
174
+
175
+ {
176
+ :comment => "Take given 'address', or choose any address from pool of 'ids'. Notice (CHOOSE operation is deterministic)",
177
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
178
+ :appName => OP_INFRA_NEXT_ID,
179
+ :body =>
180
+ <<-EOS.unindent,
181
+ #{OP_INFRA_NEXT_ID}( ids, address ) == CHOOSE x \\in ids: (address = x /\\ address # Nil) \\/ address = Nil
182
+ EOS
183
+ },
184
+ ] # BASE_SNIPPETS
185
+
186
+ ETHEREUM_SNIPPETS =
187
+ [
188
+ {
189
+ :comment => 'Finish service procedure: propage stack top on succcess && pop',
190
+ :metatype => Sbuilder::Facade::META_MODEL_FRAMEWORK_SVC,
191
+ :appName => TLA_SERVICE_POP,
192
+ :body => <<-EOS.unindent
193
+ (*
194
+ * Service procedure for 'interface' has finished.
195
+ * Check status of service response.
196
+ * For success make changes in procedure permanent by propagating
197
+ * stack top to top-1..bottom.
198
+ *
199
+ * In any case pop one element from stack.
200
+ *
201
+ *)
202
+
203
+ macro ethereum_service_pop( interface ) {
204
+ \\* TODO - add implementation
205
+ skip;
206
+ }
207
+
208
+ EOS
209
+ },
210
+
211
+
212
+ ] # ETHEREUM_SNIPPETS
213
+
214
+ BASE_SNIPPETS = INITIAL_SNIPPETS + ETHEREUM_SNIPPETS
215
+
216
+
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end