summaryrefslogtreecommitdiff
path: root/Jennisys/Printer.fs
blob: da481176bca875942fccba0d4c141ff5c586d89c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
module Printer

open Ast

let rec PrintSep sep f list =
  match list with
  | [] -> ()
  | [a] -> f a
  | a :: more -> f a ; printf "%s" sep ; PrintSep sep f more
  
let rec PrintType ty =
  match ty with
  | NamedType(id) -> printf "%s" id
  | InstantiatedType(id,arg) -> printf "%s[" id ; PrintType arg ; printf "]"

let PrintVarDecl vd =
  match vd with
  | Var(id,None) -> printf "%s" id
  | Var(id,Some(ty)) -> printf "%s: " id ; PrintType ty

let rec PrintExpr ctx expr =
  match expr with
  | IntLiteral(n) -> printf "%O" n
  | IdLiteral(id) -> printf "%s" id
  | Star -> printf "*"
  | Dot(e,id) -> PrintExpr 100 e ; printf ".%s" id
  | UnaryExpr(op,e) -> printf "%s" op ; PrintExpr 90 e
  | BinaryExpr((strength,op),e0,e1) ->
      let needParens = strength <= ctx
      if needParens then printf "(" else ()
      PrintExpr strength e0 ; printf " %s " op ; PrintExpr strength e1
      if needParens then printf ")" else ()
  | SelectExpr(e,i) -> PrintExpr 100 e ; printf "[" ; PrintExpr 0 i ; printf "]"
  | UpdateExpr(e,i,v) -> PrintExpr 100 e ; printf "[" ; PrintExpr 0 i ; printf " := " ; PrintExpr 0 v ; printf "]"
  | SequenceExpr(ee) -> printf "[" ; ee |> PrintSep ", " (PrintExpr 0) ; printf "]"
  | SeqLength(e) -> printf "|" ; PrintExpr 0 e ; printf "|"
  | ForallExpr(vv,e) ->
      let needParens = ctx <> 0
      if needParens then printf "(" else ()
      printf "forall " ; vv |> PrintSep ", " PrintVarDecl ; printf " :: " ; PrintExpr 0 e
      if needParens then printf ")" else ()

let PrintSig signature =
  match signature with
  | Sig(ins, outs) ->
      printf "("
      ins |> PrintSep ", " PrintVarDecl
      printf ")"
      if outs <> [] then
        printf " returns ("
        outs |> PrintSep ", " PrintVarDecl
        printf ")"
      else ()

let rec ForeachConjunct f expr =
  match expr with
  | IdLiteral("true") -> ()
  | BinaryExpr((_,"&&"),e0,e1) -> ForeachConjunct f e0 ; ForeachConjunct f e1
  | _ -> f expr

let rec Indent i =
  if i = 0 then () else printf " " ; Indent (i-1)

let rec PrintStmt stmt indent =
  match stmt with
  | Block(stmts) ->
      Indent indent ; printfn "{"
      PrintStmtList stmts (indent + 2)
      Indent indent ; printfn "}"
  | Assign(lhs,rhs) -> Indent indent ; PrintExpr 0 lhs ; printf " := " ; PrintExpr 0 rhs ; printfn ""
and PrintStmtList stmts indent =
  stmts |> List.iter (fun s -> PrintStmt s indent)

let PrintRoutine signature pre body =
  PrintSig signature
  printfn ""
  pre |> ForeachConjunct (fun e -> printf "    requires " ; PrintExpr 0 e ; printfn "")
  PrintStmtList body 2

let PrintMember m =
  match m with
  | Field(vd) -> printf "  var " ; PrintVarDecl vd ; printfn ""
  | Constructor(id,signature,pre,body) -> printf "  constructor %s" id ; PrintRoutine signature pre body
  | Method(id,signature,pre,body) -> printf "  method %s" id ; PrintRoutine signature pre body
      
let PrintTopLevelDeclHeader kind id typeParams =
  printf "%s %s" kind id
  match typeParams with
    | [] -> ()
    | _ -> printf "[" ; typeParams |> PrintSep ", " (fun tp -> printf "%s" tp) ; printf "]"
  printfn " {"

let PrintDecl d =
  match d with
  | Class(id,typeParams,members) ->
      PrintTopLevelDeclHeader "class" id typeParams
      List.iter PrintMember members
      printfn "}"
  | Model(id,typeParams,vars,frame,inv) ->
      PrintTopLevelDeclHeader "model" id typeParams
      vars |> List.iter (fun vd -> printf "  var " ; PrintVarDecl vd ; printfn "")
      printfn "  frame"
      frame |> List.iter (fun fr -> printf "    " ; PrintExpr 0 fr ; printfn "")
      printfn "  invariant"
      inv |> ForeachConjunct (fun e -> printf "    " ; PrintExpr 0 e ; printfn "")
      printfn "}"
  | Code(id,typeParams) ->
      PrintTopLevelDeclHeader "code" id typeParams
      printfn "}"

let Print prog =
  match prog with
  | Program(decls) -> List.iter PrintDecl decls