module Printer open Ast open Getters open AstUtils open PrintUtils let rec PrintType ty = match ty with | IntType -> "int" | BoolType -> "bool" | NamedType(id, args) -> if List.isEmpty args then id else (PrintSep ", " (fun s -> s) args) | SeqType(t) -> sprintf "seq[%s]" (PrintType t) | SetType(t) -> sprintf "set[%s]" (PrintType t) | InstantiatedType(id,args) -> sprintf "%s[%s]" id (PrintSep ", " (fun a -> PrintType a) args) let PrintVarDecl vd = let name = GetExtVarName vd match GetVarType vd with | None -> name | Some(ty) -> sprintf "%s: %s" name (PrintType ty) let rec PrintExpr ctx expr = match expr with | IntLiteral(d) -> sprintf "%d" d | BoolLiteral(b) -> sprintf "%b" b | BoxLiteral(id) -> sprintf "box_%s" id | ObjLiteral(id) | VarLiteral(id) | IdLiteral(id) -> id | VarDeclExpr(vlist, declare) -> let decl = if declare then "var " else "" let vars = PrintSep ", " PrintVarDecl vlist sprintf "%s%s" decl vars | Star -> "*" | Dot(e,id) -> sprintf "%s.%s" (PrintExpr 100 e) id | LCIntervalExpr(e) -> sprintf "%s.." (PrintExpr 90 e) | OldExpr(e) -> sprintf "old(%s)" (PrintExpr 90 e) | UnaryExpr(op,UnaryExpr(op2, e2)) -> sprintf "%s(%s)" op (PrintExpr 90 (UnaryExpr(op2, e2))) | UnaryExpr(op,e) -> sprintf "%s%s" op (PrintExpr 90 e) | BinaryExpr(strength,op,e0,e1) -> let needParens = strength <= ctx let openParen = if needParens then "(" else "" let closeParen = if needParens then ")" else "" sprintf "%s%s %s %s%s" openParen (PrintExpr strength e0) op (PrintExpr strength e1) closeParen | IteExpr(c,e1,e2) -> sprintf "%s ? %s : %s" (PrintExpr 25 c) (PrintExpr 25 e1) (PrintExpr 25 e2) | SelectExpr(e,i) -> sprintf "%s[%s]" (PrintExpr 100 e) (PrintExpr 0 i) | UpdateExpr(e,i,v) -> sprintf "%s[%s := %s]" (PrintExpr 100 e) (PrintExpr 0 i) (PrintExpr 0 v) | SequenceExpr(ee) -> sprintf "[%s]" (ee |> PrintSep " " (PrintExpr 0)) | SeqLength(e) -> sprintf "|%s|" (PrintExpr 0 e) | SetExpr(ee) -> sprintf "{%s}" (ee |> PrintSep " " (PrintExpr 0)) | AssertExpr(e) -> sprintf "assert %s" (PrintExpr 0 e) | AssumeExpr(e) -> sprintf "assume %s" (PrintExpr 0 e) | ForallExpr(vv,e) -> let needParens = ctx <> 0 let openParen = if needParens then "(" else "" let closeParen = if needParens then ")" else "" sprintf "%sforall %s :: %s%s" openParen (vv |> PrintSep ", " PrintVarDecl) (PrintExpr 0 e) closeParen | MethodCall(rcv,_,name,aparams) -> sprintf "%s.%s(%s)" (PrintExpr 0 rcv) name (aparams |> PrintSep ", " (PrintExpr 0)) | MethodOutSelect(mth,name) -> sprintf "%s[\"%s\"]" (PrintExpr 0 mth) name let rec PrintConst cst = match cst with | IntConst(v) -> sprintf "%d" v | BoolConst(b) -> sprintf "%b" b | BoxConst(id) -> sprintf "box_%s" id | VarConst(v) -> sprintf "%s" v | SetConst(cset) -> sprintf "{%s}" (PrintSep " " (fun c -> PrintConst c) (Set.toList cset)) | SeqConst(cseq) -> sprintf "[%s]" (PrintSep " " (fun c -> PrintConst c) cseq) | NullConst -> "null" | NoneConst -> "" | ThisConst(_,_) -> "this" | NewObj(name,_) -> PrintGenSym name | Unresolved(name) -> sprintf "Unresolved(%s)" name let PrintSig signature = match signature with | Sig(ins, outs) -> let returnClause = if outs <> [] then sprintf " returns (%s)" (outs |> PrintSep ", " PrintVarDecl) else "" sprintf "(%s)%s" (ins |> PrintSep ", " PrintVarDecl) returnClause let rec PrintStmt stmt indent printNewline = let idt = (Indent indent) let nl = if printNewline then newline else "" match stmt with | Block(stmts) -> idt + "{" + nl + (PrintStmtList stmts (indent + 2) true) + idt + "}" + nl | Assign(lhs,rhs) -> sprintf "%s%s := %s%s" idt (PrintExpr 0 lhs) (PrintExpr 0 rhs) nl | ExprStmt(expr) -> sprintf "%s%s%s" idt (PrintExpr 0 expr) nl and PrintStmtList stmts indent printNewline = stmts |> List.fold (fun acc s -> acc + (PrintStmt s indent printNewline)) "" let PrintRoutine signature pre body = let preStr = pre |> ForeachConjunct (fun e -> sprintf " requires %s%s" (PrintExpr 0 e) newline) sprintf "%s%s%s%s" (PrintSig signature) newline preStr (PrintExpr 0 body) let PrintMember m = match m with | Field(vd) -> sprintf " var %s%s" (PrintVarDecl vd) newline | Method(id,signature,pre,body,true) -> sprintf " constructor %s%s" id (PrintRoutine signature pre body) | Method(id,signature,pre,body,false) -> sprintf " method %s%s" id (PrintRoutine signature pre body) | Invariant(_) -> "" // invariants are handled separately let PrintTopLevelDeclHeader kind id typeParams = let typeParamStr = match typeParams with | [] -> "" | _ -> sprintf "[%s]" (typeParams |> PrintSep ", " (fun tp -> tp)) sprintf "%s %s%s {%s" kind id typeParamStr newline let PrintDecl d = match d with | Interface(id,typeParams,members) -> sprintf "%s%s}%s" (PrintTopLevelDeclHeader "interface" id typeParams) (List.fold (fun acc m -> acc + (PrintMember m)) "" members) newline | DataModel(id,typeParams,vars,frame,inv) -> (PrintTopLevelDeclHeader "model" id typeParams) + (vars |> List.fold (fun acc vd -> acc + " var " + (PrintVarDecl vd) + newline) "") + " frame" + newline + (frame |> List.fold (fun acc fr -> acc + " " + (PrintExpr 0 fr) + newline) "") + " invariant" + newline + (inv |> ForeachConjunct (fun e -> " " + (PrintExpr 0 e) + newline)) + "}" + newline | Code(id,typeParams) -> (PrintTopLevelDeclHeader "code" id typeParams) + "}" + newline let PrintMethodSignFull indent comp m = let idt = Indent indent let __PrintPrePost pfix expr = SplitIntoConjunts expr |> PrintSep newline (fun e -> pfix + (PrintExpr 0 e) + ";") let compName = GetComponentName comp match m with | Method(methodName, sgn, pre, post, isConstr) -> let mc = if isConstr then "constructor" else "method" let preStr = (__PrintPrePost (idt + " requires ") pre) let postStr = (__PrintPrePost (idt + " ensures ") post) idt + mc + " " + compName + "." + methodName + (PrintSig sgn) + newline + preStr + (if preStr = "" then "" else newline) + postStr | _ -> failwithf "not a method: %O" m let Print prog = match prog with | SProgram(decls) -> List.fold (fun acc d -> acc + (PrintDecl d)) "" decls let PrintObjRefName o = match o with | ThisConst(_,_) -> "this"; | NewObj(name, _) -> PrintGenSym name | _ -> failwith ("unresolved object ref: " + o.ToString())