Translates contract logic to calculus
Require Import String.
Require Import List.
Require Import Qcert.NNRC.NNRCRuntime.
Require Import ErgoSpec.Backend.ForeignErgo.
Require Import ErgoSpec.Common.Utils.Provenance.
Require Import ErgoSpec.Common.Utils.Names.
Require Import ErgoSpec.Common.Utils.Result.
Require Import ErgoSpec.Common.Utils.Ast.
Require Import ErgoSpec.Ergo.Lang.Ergo.
Require Import ErgoSpec.ErgoC.Lang.ErgoC.
Require Import ErgoSpec.ErgoNNRC.Lang.ErgoNNRC.
Require Import ErgoSpec.ErgoNNRC.Lang.ErgoNNRCSugar.
Require Import ErgoSpec.Backend.ErgoBackend.
Section ErgoCtoErgoNNRC.
Definition ergo_pattern_to_nnrc (
input_expr:
nnrc_expr) (
p:
laergo_pattern) : (
list string *
nnrc_expr) :=
match p with
|
CaseData prov d =>
(
nil,
NNRCIf (
NNRCBinop OpEqual input_expr (
NNRCConst d))
(
NNRCUnop OpLeft (
NNRCConst (
drec nil)))
(
NNRCUnop OpRight (
NNRCConst dunit)))
|
CaseWildcard prov None =>
(
nil,
NNRCUnop OpLeft (
NNRCConst (
drec nil)))
|
CaseWildcard prov (
Some type_name) =>
let (
v1,
v2) :=
fresh_var2 "$
case" "$
case"
nil in
(
nil,
NNRCEither
(
NNRCUnop (
OpCast (
type_name::
nil))
input_expr)
v1 (
NNRCUnop OpLeft (
NNRCConst (
drec nil)))
v2 (
NNRCUnop OpRight (
NNRCConst dunit)))
|
CaseLet prov v None =>
(
v::
nil,
NNRCUnop OpLeft (
NNRCUnop (
OpRec v)
input_expr))
|
CaseLet prov v (
Some type_name) =>
let (
v1,
v2) :=
fresh_var2 "$
case" "$
case"
nil in
(
v::
nil,
NNRCEither
(
NNRCUnop (
OpCast (
type_name::
nil))
input_expr)
v1 (
NNRCUnop OpLeft (
NNRCUnop (
OpRec v) (
NNRCVar v1)))
v2 (
NNRCUnop OpRight (
NNRCConst dunit)))
|
CaseLetOption prov v None =>
let v1 :=
fresh_var "$
case"
nil in
(
v::
nil, (
NNRCLet v1 input_expr
(
NNRCIf
(
NNRCBinop OpEqual (
NNRCVar v1) (
NNRCConst dunit))
(
NNRCUnop OpRight (
NNRCConst dunit))
(
NNRCUnop OpLeft (
NNRCUnop (
OpRec v) (
NNRCVar v1))))))
|
CaseLetOption prov v (
Some type_name) =>
let (
v1,
v2) :=
fresh_var2 "$
case" "$
case"
nil in
(
v::
nil, (
NNRCLet v1 input_expr
(
NNRCIf
(
NNRCBinop OpEqual (
NNRCVar v1) (
NNRCConst dunit))
(
NNRCUnop OpRight (
NNRCConst dunit))
(
NNRCEither
(
NNRCUnop (
OpCast (
type_name::
nil)) (
NNRCVar v1))
v1 (
NNRCUnop OpLeft (
NNRCUnop (
OpRec v) (
NNRCVar v1)))
v2 (
NNRCUnop OpRight (
NNRCConst dunit))))))
end.
Definition pack_pattern
(
vars:
list string)
(
pattern_expr:
nnrc_expr)
(
else_expr:
nnrc_expr)
(
cont_expr:
nnrc_expr)
:
nnrc_expr :=
let v_rec :=
fresh_in_case pattern_expr else_expr in
let init_expr :=
else_expr in
let proc_one (
acc:
nnrc_expr) (
v:
string) :=
NNRCLet v (
NNRCUnop (
OpDot v) (
NNRCVar v_rec))
acc
in
let inner_expr :=
fold_left proc_one vars init_expr
in
let (
v1,
v2) :=
fresh_var2 "$
case" "$
case"
nil in
NNRCEither
pattern_expr
v1 (
NNRCLet v_rec
(
NNRCVar v1)
inner_expr)
v2 cont_expr
.
Translate calculus expressions to NNRC
Fixpoint ergoc_expr_to_nnrc
(
env:
list string) (
e:
ergoc_expr) :
eresult nnrc_expr :=
match e with
|
EThisContract prov =>
contract_in_calculus_error prov
|
EThisClause prov =>
clause_in_calculus_error prov
|
EThisState prov =>
state_in_calculus_error prov
|
EVar prov v =>
if in_dec string_dec v env
then esuccess (
NNRCGetConstant v)
else esuccess (
NNRCVar v)
|
EConst prov d =>
esuccess (
NNRCConst d)
|
ENone prov =>
esuccess (
NNRCConst dunit)
|
ESome prov e =>
ergoc_expr_to_nnrc env e
|
EArray prov el =>
let init_el :=
esuccess nil in
let proc_one (
e:
ergo_expr) (
acc:
eresult (
list nnrc_expr)) :
eresult (
list nnrc_expr) :=
elift2
cons
(
ergoc_expr_to_nnrc env e)
acc
in
elift new_array (
fold_right proc_one init_el el)
|
EUnaryOp prov u e =>
elift (
NNRCUnop u)
(
ergoc_expr_to_nnrc env e)
|
EBinaryOp prov b e1 e2 =>
elift2 (
NNRCBinop b)
(
ergoc_expr_to_nnrc env e1)
(
ergoc_expr_to_nnrc env e2)
|
EIf prov e1 e2 e3 =>
elift3 NNRCIf
(
ergoc_expr_to_nnrc env e1)
(
ergoc_expr_to_nnrc env e2)
(
ergoc_expr_to_nnrc env e3)
|
ELet prov v None e1 e2 =>
elift2 (
NNRCLet v)
(
ergoc_expr_to_nnrc env e1)
(
ergoc_expr_to_nnrc env e2)
|
ELet prov v (
Some t1)
e1 e2 =>
elift2 (
NNRCLet v)
(
ergoc_expr_to_nnrc env e1)
(
ergoc_expr_to_nnrc env e2)
|
ENew prov cr nil =>
esuccess (
new_expr cr (
NNRCConst (
drec nil)))
|
ENew prov cr ((
s0,
init)::
rest) =>
let init_rec :
eresult nnrc :=
elift (
NNRCUnop (
OpRec s0)) (
ergoc_expr_to_nnrc env init)
in
let proc_one (
acc:
eresult nnrc) (
att:
string *
ergo_expr) :
eresult nnrc :=
let attname :=
fst att in
let e :=
ergoc_expr_to_nnrc env (
snd att)
in
elift2 (
NNRCBinop OpRecConcat)
acc (
elift (
NNRCUnop (
OpRec attname))
e)
in
elift (
new_expr cr) (
fold_left proc_one rest init_rec)
|
ERecord prov nil =>
esuccess (
NNRCConst (
drec nil))
|
ERecord prov ((
s0,
init)::
rest) =>
let init_rec :
eresult nnrc :=
elift (
NNRCUnop (
OpRec s0)) (
ergoc_expr_to_nnrc env init)
in
let proc_one (
acc:
eresult nnrc) (
att:
string *
ergo_expr) :
eresult nnrc :=
let attname :=
fst att in
let e :=
ergoc_expr_to_nnrc env (
snd att)
in
elift2 (
NNRCBinop OpRecConcat)
acc (
elift (
NNRCUnop (
OpRec attname))
e)
in
fold_left proc_one rest init_rec
|
ECallFun prov fname _ =>
function_not_inlined_error prov fname
|
ECallFunInGroup prov gname fname _ =>
function_in_group_not_inlined_error prov gname fname
|
EMatch prov e0 ecases edefault =>
let ec0 :=
ergoc_expr_to_nnrc env e0 in
let eccases :=
let proc_one acc ecase :=
eolift
(
fun acc =>
elift (
fun x => (
fst ecase,
x)::
acc)
(
ergoc_expr_to_nnrc env (
snd ecase)))
acc
in
fold_left proc_one ecases (
esuccess nil)
in
let ecdefault :=
ergoc_expr_to_nnrc env edefault in
eolift
(
fun ec0 :
nnrc_expr =>
eolift
(
fun eccases =>
eolift
(
fun ecdefault =>
let v0 :
string :=
fresh_in_match eccases ecdefault in
let proc_one_case
(
acc:
eresult nnrc_expr)
(
ecase:
ergo_pattern *
nnrc_expr)
:
eresult nnrc_expr :=
let (
vars,
pattern_expr) :=
ergo_pattern_to_nnrc (
NNRCVar v0) (
fst ecase)
in
elift
(
fun cont_expr :
nnrc_expr =>
pack_pattern
vars
pattern_expr
(
snd ecase)
cont_expr)
acc
in
let eccases_folded :
eresult nnrc_expr :=
fold_left proc_one_case eccases (
esuccess ecdefault)
in
elift (
NNRCLet v0 ec0)
eccases_folded)
ecdefault)
eccases)
ec0
|
EForeach loc ((
v,
e1)::
nil)
None e2 =>
elift2
(
NNRCFor v)
(
ergoc_expr_to_nnrc env e1)
(
ergoc_expr_to_nnrc env e2)
|
EForeach prov _ _ _ =>
complex_foreach_in_calculus_error prov
end.
Translate a function to function+calculus
Definition functionc_to_nnrc
(
fn:
absolute_name)
(
f:
ergoc_function) :
eresult nnrc_function :=
let env :=
List.map fst f.(
functionc_sig).(
sigc_params)
in
match f.(
functionc_body)
with
|
Some body =>
elift
(
mkFuncN fn)
(
elift
(
mkLambdaN
f.(
functionc_sig).(
sigc_params)
f.(
functionc_sig).(
sigc_output))
(
ergoc_expr_to_nnrc env body))
|
None =>
function_not_inlined_error dummy_provenance fn
end.
Translate a declaration to a declaration+calculus
Definition clausec_declaration_to_nnrc
(
fn:
absolute_name)
(
f:
ergoc_function) :
eresult nnrc_function :=
functionc_to_nnrc fn f.
Translate a contract to a contract+calculus
For a contract, add 'contract' and 'now' to the translation_context
Definition contractc_to_nnrc
(
cn:
local_name)
(
c:
ergoc_contract) :
eresult nnrc_function_table :=
let init :=
esuccess nil in
let proc_one
(
acc:
eresult (
list nnrc_function))
(
s:
absolute_name *
ergoc_function)
:
eresult (
list nnrc_function) :=
eolift
(
fun acc :
list nnrc_function =>
elift (
fun news :
nnrc_function =>
news::
acc)
(
clausec_declaration_to_nnrc (
fst s) (
snd s)))
acc
in
elift
(
mkFuncTableN cn)
(
List.fold_left proc_one c.(
contractc_clauses)
init).
Translate a statement to a statement+calculus
Definition declaration_to_nnrc (
s:
ergoc_declaration) :
eresult nnrc_declaration :=
match s with
|
DCExpr prov e =>
elift
DNExpr
(
ergoc_expr_to_nnrc nil e)
|
DCConstant prov v _ e =>
elift
(
DNConstant v)
(
ergoc_expr_to_nnrc nil e)
|
DCFunc prov fn f =>
elift
DNFunc
(
functionc_to_nnrc fn f)
|
DCContract prov cn c =>
elift DNFuncTable
(
contractc_to_nnrc cn c)
end.
Translate a module to a module+calculus
Definition declarations_calculus_with_table (
dl:
list ergoc_declaration)
:
eresult (
list nnrc_declaration) :=
let init :=
esuccess nil in
let proc_one
(
acc:
eresult (
list nnrc_declaration))
(
s:
ergoc_declaration)
:
eresult (
list nnrc_declaration) :=
eolift
(
fun acc :
list nnrc_declaration =>
let edecl :=
declaration_to_nnrc s in
elift (
fun news :
nnrc_declaration =>
news::
acc)
edecl)
acc
in
List.fold_left proc_one dl init.
Translate a module to a module+calculus
Definition module_to_nnrc_with_table (
p:
ergoc_module) :
eresult nnrc_module :=
elift
(
mkModuleN p.(
modulec_namespace))
(
declarations_calculus_with_table p.(
modulec_declarations)).
Definition ergoc_module_to_nnrc (
m:
ergoc_module) :
eresult nnrc_module :=
module_to_nnrc_with_table m.
Section Examples.
Open Scope string.
Definition env0 :
list string :=
nil.
Definition input1 :=
dnat 2.
Example j1 :
ergoc_expr :=
EMatch dummy_provenance
(
EConst dummy_provenance input1)
((
CaseData dummy_provenance (
dnat 1),
EConst dummy_provenance (
dstring "1"))
:: (
CaseData dummy_provenance (
dnat 2),
EConst dummy_provenance (
dstring "2"))
::
nil)
(
EConst dummy_provenance (
dstring "
lots")).
Definition jc1 :=
ergoc_expr_to_nnrc env0 j1.
Example j1' :
laergo_expr :=
EMatch dummy_provenance
(
EConst dummy_provenance input1)
((
CaseData dummy_provenance (
dnat 1),
EConst dummy_provenance (
dstring "1"))
:: (
CaseLet dummy_provenance "
v2"
None,
EVar dummy_provenance "
v2")
::
nil)
(
EConst dummy_provenance (
dstring "
lots")).
Definition jc1' :=
ergoc_expr_to_nnrc env0 j1'.
Definition input2 :=
dbrand ("
C2"::
nil) (
dnat 1).
Example j2 :
laergo_expr :=
EMatch dummy_provenance
(
EConst dummy_provenance input2)
((
CaseLet dummy_provenance "
v1" (
Some "
C1"),
EConst dummy_provenance (
dstring "1"))
:: (
CaseLet dummy_provenance "
v2" (
Some "
C2"),
EConst dummy_provenance (
dstring "2"))
::
nil)
(
EConst dummy_provenance (
dstring "
lots")).
Definition jc2 :=
ergoc_expr_to_nnrc env0 j2.
Definition input3 :=
dsome (
dnat 1).
Definition input3none :=
dnone.
Example j3 input :
laergo_expr :=
EMatch dummy_provenance
(
EConst dummy_provenance input)
((
CaseLetOption dummy_provenance "
v1"
None,
EConst dummy_provenance (
dstring "1"))
::
nil)
(
EConst dummy_provenance (
dstring "
nothing")).
Definition jc3 :=
ergoc_expr_to_nnrc env0 (
j3 input3).
Definition jc3none :=
ergoc_expr_to_nnrc env0 (
j3 input3none).
Example j4 :
laergo_expr :=
EForeach dummy_provenance
(("
x",
EConst dummy_provenance (
dcoll (
dnat 1::
dnat 2::
dnat 3::
nil)))
:: ("
y",
EConst dummy_provenance (
dcoll (
dnat 4::
dnat 5::
dnat 6::
nil)))
::
nil)
None
(
ERecord dummy_provenance
(("
a",
EVar dummy_provenance "
x")
::("
b",
EVar dummy_provenance "
y")
::
nil)).
Definition jc4 :=
ergoc_expr_to_nnrc env0 j4.
Example j5 :
laergo_expr :=
EForeach dummy_provenance
(("
x",
EConst dummy_provenance (
dcoll (
dnat 1::
dnat 2::
dnat 3::
nil)))
:: ("
y",
EConst dummy_provenance (
dcoll (
dnat 4::
dnat 5::
dnat 6::
nil)))
::
nil)
None
(
ENew dummy_provenance
"
person"
(("
a",
EVar dummy_provenance "
x")
::("
b",
EVar dummy_provenance "
y")
::
nil)).
Definition jc5 :=
ergoc_expr_to_nnrc env0 j5.
End Examples.
End ErgoCtoErgoNNRC.