(* This is the definition of the abstract syntax for Pseudo-Pascal
   (PP). This language is typed, with integers, Booleans, and arrays.
   All data is word-sized. *)

(* Expressions. *)

type expression =

    (* Constants. *)

  | EConst of constant                         

    (* Global or local variable access. *)

  | EGetVar of string                               

    (* Unary operator applications. *)

  | EUnOp of unop * expression                 

    (* Binary operator applications. *)

  | EBinOp of MIPSOps.binop * expression * expression  

    (* Function call. *)

  | EFunCall of Primitive.callee * expression list          

    (* Array read. Parameters are an array and an integer index. *)

  | EArrayGet of expression * expression       

    (* Array allocation. Parameters are the desired element type
       and the desired number of elements. *)

  | EArrayAlloc of typ * expression

(* Constants. *)

and constant = LPP.constant =

    (* Boolean constants. *)

  | ConstBool of bool                          

    (* Integer constants. *)

  | ConstInt of int32

(* Unary integer arithmetic operators. *)

and unop = LPP.unop =

  | UOpNeg

(* Conditions are expressions that produce a Boolean result. Their
   syntax allows the use of the Boolean connectives [not], [and], and
   [or], which are not available as part of the syntax of
   expressions. This somewhat nonstandard design is intended to
   eliminate some redundancy in the compiler. Conditions are used in
   the [if] and [while] instructions.

   The [and] or [or] connectives are special in that their right-hand
   side is not evaluated if the value of the left-hand side determines
   the value of the whole. *)

and condition =

    (* Boolean expression. *)

  | CExpression of expression

    (* Boolean connectives. *)

  | CNot of condition
  | CAnd of condition * condition
  | COr of condition * condition

(* Instructions. *)

and instruction = 

    (* Procedure call. *)

  | IProcCall of Primitive.callee * expression list          

    (* Local or global variable update. *)

  | ISetVar of string * expression

    (* Array write. Parameters are an array, an integer index, and a
       new element value. *)

  | IArraySet of expression * expression * expression

    (* Sequence. *)

  | ISeq of instruction list                   

    (* Conditional. *)

  | IIf of condition * instruction * instruction 

    (* Loop. *)

  | IWhile of condition * instruction

(* Types. *)

and typ = LPP.typ =
  | TypInt
  | TypBool
  | TypArray of typ

(* Function definitions. *)

and procedure = {

  (* A list of typed formal arguments. *)

  formals: (string * typ) list;

  (* A typed result, present for functions and absent for
     procedures. By convention, functions return a result by writing
     into a local variable whose name is that of the function. *)

  result: typ option;

  (* A set of typed local variables. *)

  locals: typ StringMap.t;

  (* The body of the function. *)

  body: instruction

}

(* Programs. *)

and program = {

  (* A set of typed global variables. *)

  globals: typ StringMap.t;

  (* A set of named function or procedure definitions. *)

  defs: procedure StringMap.t;

  (* The program body. *)

  main: instruction

}