Module ErgoSpec.Ergo.Lang.ErgoExpand
Translates contract logic to calculus
Require
Import
String
.
Require
Import
List
.
Require
Import
ErgoSpec.Backend.ForeignErgo
.
Require
Import
ErgoSpec.Backend.ErgoBackend
.
Require
Import
ErgoSpec.Common.Utils.Names
.
Require
Import
ErgoSpec.Common.Utils.Provenance
.
Require
Import
ErgoSpec.Common.Utils.Result
.
Require
Import
ErgoSpec.Common.Utils.Ast
.
Require
Import
ErgoSpec.Common.Types.ErgoType
.
Require
Import
ErgoSpec.Ergo.Lang.Ergo
.
Section
ErgoExpand
.
Definition
create_call
(
prov
:
provenance
)
(
cname
:
string
)
(
v0
:
string
)
(
effparam0
:
laergo_expr
)
(
effparamrest
:
list
laergo_expr
)
(
callparams
:
list
(
string
*
laergo_type
)) :
eresult
laergo_stmt
:=
let
zipped
:=
zip
callparams
(
effparam0
::
effparamrest
)
in
match
zipped
with
|
None
=>
main_parameter_mismatch_error
prov
|
Some
_
=>
esuccess
(
SCallClause
prov
(
EThisContract
prov
)
cname
(
EVar
prov
v0
::
effparamrest
))
end
.
Definition
case_of_sig
(
prov
:
provenance
)
(
v0
:
string
)
(
effparam0
:
laergo_expr
)
(
effparamrest
:
list
laergo_expr
)
(
s
: (
string
*
laergo_type_signature
)) :
eresult
(
list
(
ergo_pattern
*
laergo_stmt
)) :=
let
cname
:= (
fst
s
)
in
let
callparams
:= (
snd
s
).(
type_signature_params
)
in
match
callparams
with
|
nil
=>
main_at_least_one_parameter_error
prov
| (
param0
,
et
)::
otherparams
=>
match
et
with
|
ErgoTypeClassRef
_
type0
=>
elift
(
fun
x
=>
((
CaseLet
prov
v0
(
Some
type0
),
x
)::
nil
))
(
create_call
prov
cname
v0
effparam0
effparamrest
callparams
)
|
_
=>
esuccess
nil
end
end
.
Definition
match_of_sigs
(
prov
:
provenance
)
(
v0
:
string
)
(
effparam0
:
laergo_expr
)
(
effparamrest
:
list
laergo_expr
)
(
ss
:
list
(
string
*
laergo_type_signature
)) :
eresult
laergo_stmt
:=
elift
(
fun
s
=>
SMatch
prov
effparam0
s
(
SThrow
prov
(
EConst
prov
(
default_match_error_content
prov
""))))
(
eflatmaplift
(
case_of_sig
prov
v0
effparam0
effparamrest
)
ss
).
Definition
match_of_sigs_top
(
prov
:
provenance
)
(
effparams
:
list
ergo_expr
)
(
ss
:
list
(
string
*
laergo_type_signature
)) :=
match
effparams
with
|
nil
=>
main_at_least_one_parameter_error
prov
|
effparam0
::
effparamrest
=>
let
v0
:= ("$"++
clause_main_name
)%
string
in
match_of_sigs
prov
v0
effparam0
effparamrest
ss
end
.
Definition
filter_init
(
sigs
:
list
(
string
*
laergo_type_signature
)) :=
filter
(
fun
s
=>
if
(
string_dec
(
fst
s
)
clause_init_name
)
then
false
else
true
)
sigs
.
Definition
create_main_clause_for_contract
(
prov
:
provenance
)
(
c
:
laergo_contract
) :
eresult
laergo_clause
:=
let
sigs
:=
lookup_contract_signatures
c
in
let
sigs
:=
filter_init
sigs
in
let
effparams
:=
EVar
prov
"
request
"%
string
::
nil
in
elift
(
fun
disp
=>
(
mkClause
prov
clause_main_name
(
mkErgoTypeSignature
prov
(("
request
"%
string
,
ErgoTypeClassRef
prov
default_request_absolute_name
)::
nil
)
None
None
)
(
Some
disp
)))
(
match_of_sigs_top
prov
effparams
sigs
).
Definition
default_state
(
prov
:
provenance
) :
laergo_expr
:=
EUnaryOp
prov
(
OpBrand
(
default_state_absolute_name
::
nil
))
(
EConst
prov
(
drec
(("
stateId
",
dstring
"1") ::
nil
)))%
string
.
Definition
create_init_clause_for_contract
(
prov
:
provenance
)
(
c
:
laergo_contract
) :
laergo_clause
:=
let
effparams
:
list
laergo_expr
:=
EVar
prov
"
request
"%
string
::
nil
in
let
init_body
:=
SSetState
prov
(
default_state
prov
)
(
SReturn
prov
(
EConst
prov
dunit
))
in
mkClause
prov
clause_init_name
(
mkErgoTypeSignature
prov
(("
request
"%
string
,
ErgoTypeClassRef
prov
default_request_absolute_name
)::
nil
)
(
Some
(
ErgoTypeUnit
prov
))
(
Some
(
ErgoTypeClassRef
prov
default_emits_absolute_name
)))
(
Some
init_body
).
Definition
add_init_clause_to_contract
(
c
:
laergo_contract
) :
laergo_contract
:=
let
prov
:=
c
.(
contract_annot
)
in
if
in_dec
string_dec
clause_init_name
(
map
(
fun
cl
=>
cl
.(
clause_name
))
c
.(
contract_clauses
))
then
c
else
let
init_clause
:=
create_init_clause_for_contract
prov
c
in
mkContract
prov
c
.(
contract_template
)
c
.(
contract_state
)
(
c
.(
contract_clauses
) ++ (
init_clause
::
nil
)).
Definition
add_main_clause_to_contract
(
c
:
laergo_contract
) :
eresult
laergo_contract
:=
let
prov
:=
c
.(
contract_annot
)
in
if
in_dec
string_dec
clause_main_name
(
map
(
fun
cl
=>
cl
.(
clause_name
))
c
.(
contract_clauses
))
then
esuccess
c
else
elift
(
fun
main_clause
=>
mkContract
prov
c
.(
contract_template
)
c
.(
contract_state
)
(
c
.(
contract_clauses
) ++ (
main_clause
::
nil
)))
(
create_main_clause_for_contract
prov
c
).
Definition
ergo_expand_declaration
(
d
:
laergo_declaration
) :
eresult
laergo_declaration
:=
match
d
with
|
DNamespace
_
_
=>
esuccess
d
|
DImport
_
_
=>
esuccess
d
|
DType
_
_
=>
esuccess
d
|
DStmt
_
_
=>
esuccess
d
|
DConstant
_
_
_
_
=>
esuccess
d
|
DFunc
_
_
_
=>
esuccess
d
|
DContract
_
cn
c
=>
let
cd
:=
add_init_clause_to_contract
c
in
elift
(
fun
dd
=>
(
DContract
(
decl_annot
d
)
cn
dd
))
(
add_main_clause_to_contract
cd
)
|
DSetContract
_
_
_
=>
esuccess
d
end
.
Definition
ergo_expand_declarations
(
dl
:
list
laergo_declaration
) :
eresult
(
list
laergo_declaration
) :=
emaplift
ergo_expand_declaration
dl
.
Pre-processing. At the moment only add main clauses when missing
Definition
ergo_expand_module
(
p
:
laergo_module
) :
eresult
laergo_module
:=
elift
(
fun
ds
=>
mkModule
p
.(
module_annot
)
p
.(
module_file
)
p
.(
module_namespace
)
ds
)
(
ergo_expand_declarations
p
.(
module_declarations
)).
Definition
ergo_expand_modules
(
pl
:
list
laergo_module
) :
eresult
(
list
laergo_module
) :=
emaplift
(
ergo_expand_module
)
pl
.
End
ErgoExpand
.