Module ErgoSpec.Ergo.Lang.Ergo


Ergo is a language for expressing contract logic.

Abstract Syntax


Require Import String.
Require Import List.
Require Import EquivDec.

Require Import ErgoSpec.Backend.QLib.
Require Import ErgoSpec.Utils.Misc.
Require Import ErgoSpec.Common.Provenance.
Require Import ErgoSpec.Common.Result.
Require Import ErgoSpec.Common.Names.
Require Import ErgoSpec.Common.NamespaceContext.
Require Import ErgoSpec.Common.Ast.
Require Import ErgoSpec.Types.CTO.
Require Import ErgoSpec.Types.ErgoType.

Section Ergo.
  Section Ast.
    Context {A:Set}.
    Context {A':Set}.
    Context {N:Set}.

Expression
    Inductive ergo_expr :=
    | EThis : A -> ergo_expr (* generic this *)
    | EThisContract : A -> ergo_expr (* this contract *)
    | EThisClause : A -> ergo_expr (* this clause *)
    | EThisState : A -> ergo_expr (* this state *)
    | EVar : A -> N -> ergo_expr (* variable *)
    | EConst : A -> data -> ergo_expr (* constant *)
    | EText : A -> list ergo_expr -> ergo_expr (* embedded text *)
    | ENone : A -> ergo_expr (* none *)
    | ESome : A -> ergo_expr -> ergo_expr (* some(e) *)
    | EArray : A -> list ergo_expr -> ergo_expr (* array constructor *)
    | EUnaryOperator : A -> ergo_unary_operator -> ergo_expr -> ergo_expr (* unary operator *)
    | EBinaryOperator : A -> ergo_binary_operator -> ergo_expr -> ergo_expr -> ergo_expr (* binary operator *)
    | EUnaryBuiltin : A -> QcertOps.Unary.op -> ergo_expr -> ergo_expr (* unary builtin *)
    | EBinaryBuiltin : A -> QcertOps.Binary.op -> ergo_expr -> ergo_expr -> ergo_expr (* binary builtin *)
    | EIf : A -> ergo_expr -> ergo_expr -> ergo_expr -> ergo_expr (* conditional *)
    | ELet : A -> string -> option (@ergo_type A' N) -> ergo_expr -> ergo_expr -> ergo_expr (* local variable binding *)
    | EPrint : A -> ergo_expr -> ergo_expr -> ergo_expr (* print *)
    | ERecord : A -> list (string * ergo_expr) -> ergo_expr (* create a new record *)
    | ENew : A -> N -> list (string * ergo_expr) -> ergo_expr (* create a new concept/object *)
    | ECallFun : A -> N -> list ergo_expr -> ergo_expr (* function call *)
    | ECallFunInGroup : A -> N -> string -> list ergo_expr -> ergo_expr (* call function in group *)
    | EMatch : A -> ergo_expr -> list (@ergo_pattern A N * ergo_expr) -> ergo_expr -> ergo_expr (* match-case *)
    | EForeach : A -> list (string * ergo_expr)
                 -> option ergo_expr -> ergo_expr -> ergo_expr (* foreach with optional where *)
    .

    Definition expr_annot (e:ergo_expr) : A :=
      match e with
      | EThis a => a
      | EThisContract a => a
      | EThisClause a => a
      | EThisState a => a
      | EVar a _ => a
      | EConst a _ => a
      | EText a _ => a
      | ENone a => a
      | ESome a _ => a
      | EArray a _ => a
      | EUnaryOperator a _ _ => a
      | EBinaryOperator a _ _ _ => a
      | EUnaryBuiltin a _ _ => a
      | EBinaryBuiltin a _ _ _ => a
      | EIf a _ _ _ => a
      | ELet a _ _ _ _ => a
      | EPrint a _ _ => a
      | ERecord a _ => a
      | ENew a _ _ => a
      | ECallFun a _ _ => a
      | ECallFunInGroup a _ _ _ => a
      | EMatch a _ _ _ => a
      | EForeach a _ _ _ => a
      end.
    
Statement
    Inductive ergo_stmt :=
    | SReturn : A -> ergo_expr -> ergo_stmt
    | SFunReturn : A -> ergo_expr -> ergo_stmt
    | SThrow : A -> ergo_expr -> ergo_stmt
    | SCallClause : A -> ergo_expr -> string -> list ergo_expr -> ergo_stmt (* clause call *)
    | SCallContract : A -> ergo_expr -> list ergo_expr -> ergo_stmt (* contract call *)
    | SSetState : A -> ergo_expr -> ergo_stmt -> ergo_stmt
    | SSetStateDot : A -> string -> ergo_expr -> ergo_stmt -> ergo_stmt
    | SEmit : A -> ergo_expr -> ergo_stmt -> ergo_stmt
    | SLet : A -> string -> option (@ergo_type A N) -> ergo_expr -> ergo_stmt -> ergo_stmt (* local variable *)
    | SPrint : A -> ergo_expr -> ergo_stmt -> ergo_stmt (* local variable *)
    | SIf : A -> ergo_expr -> ergo_stmt -> ergo_stmt -> ergo_stmt
    | SEnforce : A -> ergo_expr -> option ergo_stmt -> ergo_stmt -> ergo_stmt (* enforce *)
    | SMatch : A -> ergo_expr -> (list (@ergo_pattern A N * ergo_stmt)) -> ergo_stmt -> ergo_stmt
    .

    Definition stmt_annot (e:ergo_stmt) : A :=
      match e with
      | SReturn a _ => a
      | SFunReturn a _ => a
      | SThrow a _ => a
      | SCallClause a _ _ _ => a
      | SCallContract a _ _ => a
      | SSetState a _ _ => a
      | SSetStateDot a _ _ _ => a
      | SEmit a _ _ => a
      | SLet a _ _ _ _ => a
      | SPrint a _ _ => a
      | SIf a _ _ _ => a
      | SEnforce a _ _ _ => a
      | SMatch a _ _ _ => a
      end.
    
Function
    Record ergo_function :=
      mkFunc
        { function_annot : A;
          function_sig : @ergo_type_signature A N;
          function_body : option ergo_expr; }.

    Definition body_annot (f:ergo_function) : A :=
      match f.(function_body) with
      | None => f.(function_annot)
      | Some e => expr_annot e
      end.
    
Clause
    Record ergo_clause :=
      mkClause
        { clause_annot : A;
          clause_name : local_name;
          clause_sig : @ergo_type_signature A N;
          clause_body : option ergo_stmt; }.

Contract
    Record ergo_contract :=
      mkContract
        { contract_annot : A;
          contract_template : (@ergo_type A N);
          contract_state : option (@ergo_type A N);
          contract_clauses : list ergo_clause; }.

Declaration
    Inductive ergo_declaration :=
    | DNamespace : A -> namespace_name -> ergo_declaration
    | DImport : A -> @import_decl A -> ergo_declaration
    | DType : A -> @ergo_type_declaration A N -> ergo_declaration
    | DStmt : A -> ergo_stmt -> ergo_declaration
    | DConstant : A -> local_name -> option (@ergo_type A N) -> ergo_expr -> ergo_declaration
    | DFunc : A -> local_name -> ergo_function -> ergo_declaration
    | DContract : A -> local_name -> ergo_contract -> ergo_declaration
    | DSetContract : A -> N -> ergo_expr -> ergo_declaration
    .
    
    Definition decl_annot (d:ergo_declaration) : A :=
      match d with
      | DNamespace a _ => a
      | DImport a _ => a
      | DType a _ => a
      | DStmt a _ => a
      | DConstant a _ _ _ => a
      | DFunc a _ _ => a
      | DContract a _ _ => a
      | DSetContract a _ _ => a
      end.

Module.
    Record ergo_module :=
      mkModule
        { module_annot : A;
          module_file : string;
          module_prefix : string;
          module_namespace : namespace_name;
          module_declarations : list ergo_declaration; }.

    Inductive ergo_input :=
    | InputErgo : ergo_module -> ergo_input
    | InputCTO : @cto_package A N -> ergo_input.

  End Ast.

  Definition rergo_expr {A} {A'} := @ergo_expr A A' relative_name.
  Definition rergo_stmt {A} {A'} := @ergo_stmt A A' relative_name.
  Definition rergo_function {A} {A'} := @ergo_function A A' relative_name.
  Definition rergo_clause {A} {A'} := @ergo_clause A A' relative_name.
  Definition rergo_contract {A} {A'} := @ergo_contract A A' relative_name.
  Definition rergo_declaration {A} {A'} := @ergo_declaration A A' relative_name.
  Definition rergo_module {A} {A'} := @ergo_module A A' relative_name.
  Definition rergo_input {A} {A'} := @ergo_input A A' relative_name.

  Definition aergo_expr {A} {A'} := @ergo_expr A A' absolute_name.
  Definition aergo_stmt {A} {A'} := @ergo_stmt A A' absolute_name.
  Definition arergo_function {A} {A'} := @ergo_function A A' absolute_name.
  Definition arergo_clause {A} {A'} := @ergo_clause A A' absolute_name.
  Definition arergo_contract {A} {A'} := @ergo_contract A A' absolute_name.
  Definition arergo_declaration {A} {A'} := @ergo_declaration A A' absolute_name.
  Definition arergo_module {A} {A'} := @ergo_module A A' absolute_name.
  Definition arergo_input {A} {A'} := @ergo_input A A' absolute_name.

  Definition lrergo_expr := @ergo_expr provenance provenance relative_name.
  Definition lrergo_stmt := @ergo_stmt provenance provenance relative_name.
  Definition lrergo_function := @ergo_function provenance provenance relative_name.
  Definition lrergo_clause := @ergo_clause provenance provenance relative_name.
  Definition lrergo_contract := @ergo_contract provenance provenance relative_name.
  Definition lrergo_declaration := @ergo_declaration provenance provenance relative_name.
  Definition lrergo_module := @ergo_module provenance provenance relative_name.
  Definition lrergo_input := @ergo_input provenance provenance relative_name.

  Definition laergo_expr := @ergo_expr provenance provenance absolute_name.
  Definition laergo_stmt := @ergo_stmt provenance provenance absolute_name.
  Definition laergo_function := @ergo_function provenance provenance absolute_name.
  Definition laergo_clause := @ergo_clause provenance provenance absolute_name.
  Definition laergo_contract := @ergo_contract provenance provenance absolute_name.
  Definition laergo_declaration := @ergo_declaration provenance provenance absolute_name.
  Definition laergo_module := @ergo_module provenance provenance absolute_name.
  Definition laergo_input := @ergo_input provenance provenance absolute_name.

  Section Lookup.
    Fixpoint lookup_clause_signatures (dl:list laergo_clause) : list (local_name * ergo_type_signature) :=
      match dl with
      | nil => nil
      | cl :: dl' =>
        (cl.(clause_name),cl.(clause_sig)) :: lookup_clause_signatures dl'
      end.

    Definition lookup_contract_signatures (c:ergo_contract) : list (local_name * ergo_type_signature) :=
      lookup_clause_signatures c.(contract_clauses).

    Definition contract_of_declaration (d:laergo_declaration) : option (absolute_name * laergo_contract) :=
      match d with
      | DContract _ cn c => Some (cn, c)
      | _ => None
      end.

    Definition lookup_contracts_in_declarations (dl:list laergo_declaration)
      : list (absolute_name * laergo_contract) :=
      filter_some contract_of_declaration dl.

    Definition lookup_single_contract_in_declarations
               (prov:provenance) (dl:list laergo_declaration) : eresult (absolute_name * laergo_contract) :=
      match lookup_contracts_in_declarations dl with
      | nil => should_have_one_contract_error prov
      | c :: nil => esuccess c nil
      | _ :: _ => should_have_one_contract_error prov
      end.

    Definition lookup_single_contract (p:laergo_module) : eresult (absolute_name * laergo_contract) :=
      lookup_single_contract_in_declarations p.(module_annot) p.(module_declarations).

    Definition contract_name_of_decl (d:laergo_declaration) : option string :=
      match d with
      | DNamespace _ _
      | DImport _ _
      | DType _ _
      | DStmt _ _
      | DConstant _ _ _ _
      | DFunc _ _ _
      | DSetContract _ _ _ => None
      | DContract _ an _ => Some an
      end.

    Definition lift_contract_name_of_decl (d:laergo_declaration) (acc:option string) : option string :=
      match acc with
      | None => contract_name_of_decl d
      | Some _ => acc
      end.

    Definition default_contract_name_from_decls (dl:list ergo_declaration) : option string :=
      fold_right lift_contract_name_of_decl None dl.

    Definition default_contract_name (m:ergo_module) : option string :=
      default_contract_name_from_decls m.(module_declarations).
    
  End Lookup.

  Section TypeDeclarations.
    Fixpoint get_type_decls (decls:list laergo_declaration) : list laergo_type_declaration :=
      match decls with
      | nil => nil
      | DType _ td :: rest => td :: (get_type_decls rest)
      | _ :: rest => get_type_decls rest
      end.

    Definition module_get_type_decls (m:laergo_module) : list laergo_type_declaration :=
      get_type_decls m.(module_declarations).

    Definition modules_get_type_decls (m:list laergo_module) : list laergo_type_declaration :=
      List.concat (List.map module_get_type_decls m).
  End TypeDeclarations.


  Section Enums.
    Fixpoint either_from_enum_values (enum_values:list string) : list (string * data) :=
      match enum_values with
      | nil => nil
      | x :: enum_values' =>
        let new_values := either_from_enum_values enum_values' in
        (x, dleft (dstring x)) :: (map (fun xy => (fst xy, dright (snd xy))) new_values)
      end.

    Definition globals_from_enum prov (enum:string * list string) : list (string * laergo_expr * data) :=
      let (enum_name, enum_values) := enum in
      map (fun xy =>
             let d := dbrand (enum_name::nil) (snd xy) in
             (fst xy, (EConst prov d), d))
          (either_from_enum_values enum_values).

  End Enums.

End Ergo.