Browse Source

Changed the way array types are represented, and cleaned up a lot of code in the process

Taddeus Kroes 12 years ago
parent
commit
f979c1faf4
18 changed files with 297 additions and 352 deletions
  1. 3 3
      Makefile
  2. 2 4
      main.ml
  3. 5 5
      parser.mly
  4. 0 2
      phases/assemble.ml
  5. 1 2
      phases/constant_propagation.ml
  6. 21 36
      phases/context_analysis.ml
  7. 158 160
      phases/desug.ml
  8. 48 12
      phases/dim_reduce.ml
  9. 0 40
      phases/expand_dims.ml
  10. 5 22
      phases/extern_vars.ml
  11. 1 1
      phases/index_analysis.ml
  12. 1 3
      phases/print.ml
  13. 12 6
      phases/typecheck.ml
  14. 9 14
      stringify.ml
  15. 6 1
      test/old/array_scope.cvc
  16. 17 15
      types.ml
  17. 8 20
      util.ml
  18. 0 6
      util.mli

+ 3 - 3
Makefile

@@ -1,7 +1,7 @@
 RESULT := civicc
-PHASES := load parse print desug context_analysis expand_dims typecheck \
-	dim_reduce bool_op extern_vars constant_propagation index_analysis assemble \
-	peephole output
+PHASES := load parse print desug context_analysis typecheck dim_reduce \
+	bool_op extern_vars constant_propagation index_analysis assemble peephole \
+	output
 SOURCES := types.ml stringify.mli stringify.ml util.mli util.ml lexer.mll \
 	parser.mly $(patsubst %,phases/%.ml,$(PHASES)) main.ml
 PRE_TARGETS := types.cmi types.o stringify.cmi stringify.o util.cmi util.o

+ 2 - 4
main.ml

@@ -17,12 +17,10 @@ let phases = [
      "Context analysis");
     ("typecheck", Typecheck.phase, always,
      "Type checking");
-    ("expand", Expand_dims.phase, always,
-     "Expand array dimensions");
-    ("boolop", Bool_op.phase, always,
-     "Convert bool operations");
     ("dimreduce", Dim_reduce.phase, always,
      "Array dimension reduction");
+    ("boolop", Bool_op.phase, always,
+     "Convert bool operations");
     ("extern", Extern_vars.phase, always,
      "Create getters and setters for extern variables");
     ("constant", Constant_propagation.phase, when_optimize,

+ 5 - 5
parser.mly

@@ -81,7 +81,7 @@ decl:
       name=ID; SEMICOL
     { let dimloc = loc $startpos(dims) $endpos(dims) in
       let loc = loc $startpos(name) $endpos(name) in
-      GlobalDec (Array (ctype, make_dims dimloc dims), name, loc) }
+      GlobalDec (ArrayDims (ctype, make_dims dimloc dims), name, loc) }
 
     | export=boption(EXPORT); ctype=basic_type; name=ID; SEMICOL
     { let loc = loc $startpos(name) $endpos(name) in
@@ -95,7 +95,7 @@ decl:
       LBRACK; dims=separated_list(COMMA, expr); RBRACK;
       name=ID; SEMICOL
     { let loc = loc $startpos(name) $endpos(name) in
-      GlobalDef (export, Array (ctype, dims), name, None, loc) }
+      GlobalDef (export, ArrayDims (ctype, dims), name, None, loc) }
 
 fun_header:
     (* function header: use location of function name *)
@@ -113,7 +113,7 @@ param:
     | ctype=basic_type; LBRACK; dims=separated_list(COMMA, ID); RBRACK; name=ID
     { let dimloc = loc $startpos(dims) $endpos(dims) in
       let loc = loc $startpos(name) $endpos(name) in
-      Param (Array (ctype, make_dims dimloc dims), name, loc) }
+      Param (ArrayDims (ctype, make_dims dimloc dims), name, loc) }
 
 fun_body:
     | var_dec* local_fun_dec* statement* loption(return_statement)
@@ -141,12 +141,12 @@ var_dec:
     | ctype=basic_type; LBRACK; dims=separated_list(COMMA, expr); RBRACK;
       name=ID; SEMICOL
     { let loc = loc $startpos(name) $endpos(name) in
-      VarDec (Array (ctype, dims), name, None, loc) }
+      VarDec (ArrayDims (ctype, dims), name, None, loc) }
 
     | ctype=basic_type; LBRACK; dims=separated_list(COMMA, expr); RBRACK;
       name=ID; ASSIGN; init=expr; SEMICOL
     { let loc = loc $startpos(name) $endpos(name) in
-      VarDec (Array (ctype, dims), name, Some init, loc) }
+      VarDec (ArrayDims (ctype, dims), name, Some init, loc) }
 
 statement:
     (* assignment: use location of assigned variable name *)

+ 0 - 2
phases/assemble.ml

@@ -55,8 +55,6 @@ let assemble program =
 
         | VarDec (_, name, _, _) ->
             [comline (sprintf "local var \"%s\" at index %d" name (indexof node))]
-        | DimDec (name, _, _) ->
-            [comline (sprintf "local dim \"%s\" at index %d" name (indexof node))]
 
         | LocalFuns _ -> []
 

+ 1 - 2
phases/constant_propagation.ml

@@ -160,11 +160,10 @@ let rec propagate consts node =
 
 let rec prune_vardecs consts = function
     | VarDec (_, name, _, _) when Hashtbl.mem consts name -> DummyNode
-    | DimDec (name, _, _) when Hashtbl.mem consts name -> DummyNode
     | node -> transform_children (prune_vardecs consts) node
 
 let phase = function
-    | Ast node as input ->
+    | Ast node ->
         let consts = Hashtbl.create 32 in
         let node = propagate consts node in
         Ast (prune_vardecs consts node)

+ 21 - 36
phases/context_analysis.ml

@@ -26,6 +26,7 @@ let check_in_scope name errnode scope =
         raise (NodeError (errnode, msg))
 
 let add_to_scope name dec depth (vars, funs) =
+    prerr_string "__add_to_scope: "; prt_node dec;
     let (name, tbl, name_type) = match name with
         | Varname name  -> (name, vars, "variable")
         | Funcname name -> (name, funs, "function")
@@ -45,34 +46,13 @@ let add_to_scope name dec depth (vars, funs) =
 
 let rec analyse scope depth node =
     let rec collect node = match node with
-        (* Add node reference for this varname to vars map *)
-        | VarDec (ctype, name, init, ann) ->
-            (* Traverse Dim nodes *)
-            let node = VarDec (ctype, name, init, Depth depth :: ann) in
-            add_to_scope (Varname name) node depth scope;
-            node
-
-        | DimDec (name, init, ann) ->
-            let node = DimDec (name, init, Depth depth :: ann) in
-            add_to_scope (Varname name) node depth scope;
-            node
-
-        (* For global vars, only the name and array dimensions *)
-        | GlobalDec (ctype, name, ann) ->
-            let ctype = match ctype with
-                | Array (ctype, dims) -> Array (ctype, List.map collect dims)
-                | _ -> ctype
-            in
-            let node = GlobalDec (ctype, name, Depth depth :: ann) in
-            add_to_scope (Varname name) node depth scope;
-            node
-
-        | GlobalDef (export, ctype, name, init, ann) ->
-            let ctype = match ctype with
-                | Array (ctype, dims) -> Array (ctype, List.map collect dims)
-                | _ -> ctype
-            in
-            let node = GlobalDef (export, ctype, name, init, Depth depth :: ann) in
+        (* For variables, add the name (array dimensions are added
+         * implicitly, since they have separate VarDec nodes which were added
+         * during the desugaring phase *)
+        | VarDec (_, name, _, _)
+        | GlobalDec (_, name, _)
+        | GlobalDef (_, _, name, _, _) ->
+            let node = annotate (Depth depth) node in
             add_to_scope (Varname name) node depth scope;
             node
 
@@ -93,8 +73,8 @@ let rec analyse scope depth node =
             let (dec, dec_depth) = check_in_scope (Funcname name) node scope in
             FunUse (dec, List.map collect args, Depth depth :: ann)
 
-        (* Assign statements are replaced with VarLet nodes, which stores the type
-         * and depth of the assigned variable are *)
+        (* Assign statements are replaced with VarLet nodes, which stores the
+         * declaration of the assigned variable *)
         | Assign (name, dims, value, ann) ->
             let (dec, dec_depth) = check_in_scope (Varname name) node scope in
             VarLet (dec, optmap collect dims, collect value, Depth depth :: ann)
@@ -116,16 +96,21 @@ let rec analyse scope depth node =
             let body = analyse local_scope (depth + 1) body in
             FunDef (export, ret_type, name, params, body, ann)
 
-        | Param (Array (ctype, dims), name, ann) ->
-            let dims = List.map (traverse scope depth) dims in
-            let node = Param (Array (ctype, dims), name, ann) in
+        | Param (ArrayDims (ctype, dims), name, ann) ->
+            let rec add_dims = function
+                | [] -> []
+                | Dim (name, ann) :: tl ->
+                    let dim = Dim (name, Depth depth :: ann) in
+                    add_to_scope (Varname name) dim depth scope;
+                    dim :: (add_dims tl)
+                | _ -> raise InvalidNode
+            in
+            let node = Param (ArrayDims (ctype, add_dims dims), name, ann) in
             add_to_scope (Varname name) node depth scope;
             node
 
-        (* Prevent Dim nodes from VarDec types from being added twice *)
-        | DimDec _ -> node
+        | VarDec _ -> node
 
-        | Dim (name, _)  (* Dim nodes as children of Param nodes *)
         | Param (_, name, _) ->
             let node = annotate (Depth depth) node in
             add_to_scope (Varname name) node depth scope;

+ 158 - 160
phases/desug.ml

@@ -2,121 +2,173 @@ open Printf
 open Types
 open Util
 
-let rec var_init = function
-    (* Move global initialisations to __init function *)
-    | Program (decls, ann) ->
-        let decls = flatten_blocks (List.map var_init decls) in
-        let rec trav assigns = function
-            | [] -> (assigns, [])
-            | (Assign _ as hd) :: tl
-            | (Allocate _ as hd) :: tl -> trav (assigns @ [hd]) tl
-            | hd :: tl ->
-                let (assigns, decls) = trav assigns tl in
-                (assigns, (hd :: decls))
-        in
-        let (assigns, decls) = trav [] decls in (
-            match assigns with
-            | [] -> Program (decls, ann)
-            | assigns ->
-                let init_func = FunDef (true, Void, "__init", [], Block assigns, []) in
-                Program (init_func :: decls, ann)
-        )
+(* Generate new variables for array dimensions in function bodies, to avoid
+ * re-evalutation after array dimension reduction. For example:
+ *
+ * int dims = 0;
+ *
+ * int dim() {
+ *     dims = dims 1;  // Side effect => dims() should be called once
+ *     return 10;
+ * }
+ *
+ * void foo() {
+ *    int[10, dim()] arr;
+ *    arr[0, 1] = 1;
+ * }
+ *
+ * After dimension reduction, this would become:
+ * void foo() {
+ *    int[] arr;
+ *    arr = allocate(10, dim());
+ *    arr[1 * dim() + 0] = 1;
+ * }
+ *
+ * This behaviour is of course incorrect. To avoid dim() from being evaluated
+ * twice, the snippet above is transformed into the following code: (note the $$
+ * which will help later during constant propagation)
+ * void foo() {
+ *    int[a$dim$$1, a$dim$$2] arr;
+ *    a$dim$$1 = 10;
+ *    a$dim$$2 = dim();
+ *    arr[1, 2] = 1;
+ * }
+ *
+ * ... which later becomes:
+ * void foo() {
+ *    int[a$dim$$1, a$dim$$2] arr;
+ *    a$dim$$1 = 10;
+ *    a$dim$$2 = dim();
+ *    arr = __allocate(a$dim$$1 * a$dim$$2);
+ *    arr[1 * a$dim$2 * 0] = 1;
+ * }
+ * *)
+let rec array_dims node =
+    let make_dims basename values make_dec =
+        let make_name i _ = basename ^ "$dim$$" ^ string_of_int (i + 1) in
+        let names = mapi make_name values in
 
-    (* Global variable initialisation:
-     * Add an assign statement and the Program node will remove it later on *)
-    | GlobalDef (export, ctype, name, Some init, ann) ->
-        Block [GlobalDef (export, ctype, name, None, ann);
-               Assign (name, None, init, ann)]
+        let decs = List.map2 make_dec values names in
 
-    (* Global array definition:
-     * - Create a new global variable for each dimension and initialise it to
-     *   the given expression
-     * - create __allocate statement in __init *)
-    | GlobalDef (export, Array (ctype, dims), name, None, ann) as dec ->
-        let rec create_dimvars i = function
+        let make_dim value name = Dim (name, annof value) in
+        let dims = List.map2 make_dim values names in
+
+        (decs, dims)
+    in
+    match node with
+    | VarDec (ArrayDims (ctype, values), name, init, ann) ->
+        let make_dec value name = VarDec (Int, name, Some value, []) in
+        let (decs, dims) = make_dims name values make_dec in
+        Block (decs @ [VarDec (ArrayDims (ctype, dims), name, init, ann)])
+
+    | GlobalDef (export, ArrayDims (ctype, values), name, None, ann) ->
+        let make_dec value name = GlobalDef (export, Int, name, Some value, []) in
+        let (decs, dims) = make_dims name values make_dec in
+        Block (decs @ [GlobalDef (export, ArrayDims (ctype, dims), name, None, ann)])
+
+    | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
+        let rec make_decs = function
             | [] -> []
-            | hd :: tl ->
-                let dimname = name ^ "$" ^ string_of_int i in
-                let var = Var (dimname, None, ann) in
-                var :: (create_dimvars (i + 1) tl)
-        in
-        let dimvars = create_dimvars 1 dims in
-        let create_globaldef dim = function
-            | Var (dimname, None, ann) ->
-                var_init (GlobalDef (export, Int, dimname, Some dim, ann))
+            | Dim (name, ann) :: tl -> GlobalDec (Int, name, ann) :: (make_decs tl)
             | _ -> raise InvalidNode
         in
-        let vardecs = List.map2 create_globaldef dims dimvars in
-        let alloc = [Allocate (dec, dimvars, ann)] in
-        Block (vardecs @
-               [GlobalDef (export, Array (ctype, dimvars), name, None, ann)] @
-               alloc)
+        let decs = make_decs dims in
+        Block (decs @ [GlobalDec (ArrayDims (ctype, dims), name, ann)])
 
-    (* Split local variable initialisations in declaration and assignment *)
-    | FunDef (export, ret_type, name, params, body, ann) ->
-        let inits = ref [] in
-        let rec extract_inits = function
-            (* Translate scalar array initialisation to ArrayScalar node,
-                * for easy replacement later on *)
-            | VarDec (Array _ as vtype, name, Some (Const _   as v), ann) ->
-                let init = Some (ArrayInit (ArrayScalar v, vtype)) in
-                extract_inits (VarDec (vtype, name, init, ann))
-
-            (* Wrap ArrayConst in ArrayInit to pass dimensions *)
-            | VarDec (Array _ as vtype, name, Some (ArrayConst _ as v), ann) ->
-                let init = Some (ArrayInit (v, vtype)) in
-                extract_inits (VarDec (vtype, name, init, ann))
+    | node -> transform_children array_dims node
 
-            | VarDec (ctype, name, init, ann) as dec ->
-                (* array definition: create __allocate statement *)
-                let alloc = match ctype with
-                    | Array (_, dims) ->
-                        let create_dimvar = function
-                            | Dim (name, _) -> Var (name, None, [])
-                            | _ -> raise InvalidNode
-                        in [Allocate (dec, List.map create_dimvar dims, ann)]
-                    | _ -> []
-                in
-                (* initialisation: create assign statement *)
-                let add = match init with
-                    | Some value -> alloc @ [Assign (name, None, value, ann)]
-                    | None -> alloc
-                in
-                inits := !inits @ add;
-                VarDec (ctype, name, None, ann)
+(* Split variable declaration and initialisation *)
+let rec split_inits = function
+    (* Translate scalar array initialisation to ArrayScalar node,
+        * for easy replacement later on *)
+    | VarDec (ArrayDims (_, dims) as ctype, name, Some (Const _   as v), ann) ->
+        let init = Some (ArrayInit (ArrayScalar v, dims)) in
+        split_inits (VarDec (ctype, name, init, ann))
 
-            | DimDec (name, Some init, ann) ->
-                (* dimension initialisation: create assign statement *)
-                inits := !inits @ [Assign (name, None, init, ann)];
-                DimDec (name, None, ann)
+    (* Wrap ArrayConst in ArrayInit to pass dimensions *)
+    | VarDec (ArrayDims (_, dims) as ctype, name, Some (ArrayConst _ as v), ann) ->
+        let init = Some (ArrayInit (v, dims)) in
+        split_inits (VarDec (ctype, name, init, ann))
 
-            | LocalFuns funs -> LocalFuns (List.map var_init funs)
+    (* Variable initialisations are split into dec;assign *)
+    | VarDec (ctype, name, Some init, ann) ->
+        Block [
+            VarDec (ctype, name, None, ann);
+            Assign (name, None, init, ann);
+        ]
 
-            | node -> transform_children extract_inits node
-        in
-        let rec place_inits = function
-            (* initialisations need to be placed after local functions *)
-            | (LocalFuns _ as hd) :: tl -> hd :: !inits @ tl
-            | hd :: tl -> hd :: (place_inits tl)
-            | [] -> []
-        in
-        let params = flatten_blocks (List.map var_init params) in
-        let body = flatten_blocks (place_inits (block_body (extract_inits body))) in
-        FunDef (export, ret_type, name, params, Block body, ann)
+    | GlobalDef (export, ctype, name, Some init, ann) ->
+        Block [
+            GlobalDef (export, ctype, name, None, ann);
+            Assign (name, None, init, ann);
+        ]
 
-    | node -> transform_children var_init node
+    | node -> transform_children split_inits node
 
-let rec replace_var var replacement node =
-    let trav = (replace_var var replacement) in
+(* Add <allocate> statements after array declarations *)
+let rec add_allocs node =
+    let create_dimvar = function
+        | Dim (name, _) -> Var (name, None, [])
+        | _ -> raise InvalidNode
+    in
     match node with
-    | Var (name, None, ann) when name = var ->
-        Var (replacement, None, ann)
-    | For (counter, start, stop, step, body, ann) when counter = var ->
-        For (replacement, trav start, trav stop, trav step, trav body, ann)
-    | node ->
-        transform_children trav node
+    | VarDec (ArrayDims (_, dims), _, _, ann) ->
+        Block [node; Allocate (node, List.map create_dimvar dims, ann)]
+
+    | GlobalDef (_, ArrayDims (_, dims), _, _, ann) ->
+        Block [node; Allocate (node, List.map create_dimvar dims, ann)]
+
+    | node -> transform_children add_allocs node
+
+let extract_inits lst =
+    let rec trav inits = function
+        | [] ->
+            (List.rev inits, [])
+        | (Assign _ as hd) :: tl
+        | (Allocate _ as hd) :: tl ->
+            trav (hd :: inits) tl
+        | hd :: tl ->
+            let (inits, tl) = trav inits tl in
+            (inits, (hd :: tl))
+    in trav [] lst
+
+let rec move_inits = function
+    (* Move global initialisations to __init function *)
+    | Program (decls, ann) ->
+        let decls = List.map move_inits decls in
+        (match extract_inits decls with
+        | ([], _) -> Program (decls, ann)
+        | (inits, decls) ->
+            let init_func = FunDef (true, Void, "__init", [], Block inits, []) in
+            Program (init_func :: decls, ann)
+        )
+
+    (* Split local variable initialisations in declaration and assignment *)
+    | FunDef (export, ret_type, name, params, Block body, ann) ->
+        let rec place_inits inits = function
+            | VarDecs lst :: tl ->
+                let (inits, decs) = extract_inits lst in
+                VarDecs decs :: (place_inits inits tl)
+            | LocalFuns _ as hd :: tl ->
+                hd :: inits @ tl
+            | _ -> raise InvalidNode
+        in
+        let body = Block (place_inits [] body) in
+        FunDef (export, ret_type, name, params, body, ann)
+
+    | node -> transform_children move_inits node
 
 let for_to_while node =
+    let rec replace_var var replacement node =
+        let trav = (replace_var var replacement) in
+        match node with
+        | Var (name, None, ann) when name = var ->
+            Var (replacement, None, ann)
+        | For (counter, start, stop, step, body, ann) when counter = var ->
+            For (replacement, trav start, trav stop, trav step, trav body, ann)
+        | node ->
+            transform_children trav node
+    in
     let rec traverse new_vars = function
         | FunDef (export, ret_type, name, params, body, ann) ->
             let new_vars = ref [] in
@@ -166,7 +218,7 @@ let for_to_while node =
 
 let rec array_init = function
     (* Transform scalar assignment into nested for-loops *)
-    | Assign (name, None, ArrayInit (ArrayScalar value, Array (_, dims)), ann) ->
+    | Assign (name, None, ArrayInit (ArrayScalar value, dims), ann) ->
         let rec add_loop indices = function
             | [] ->
                 Assign (name, Some indices, value, ann)
@@ -180,8 +232,8 @@ let rec array_init = function
     (* Transform array constant inisialisation into separate assign statements
      * for all entries in the constant array *)
     (* TODO: only allow when array dimensions are constant? *)
-    | Assign (name, None, ArrayInit (ArrayConst _ as value, Array (_, dims)), ann) ->
-        let ndims = list_size dims in
+    | Assign (name, None, ArrayInit (ArrayConst _ as value, dims), ann) ->
+        let ndims = List.length dims in
         let rec make_assigns depth i indices = function
             | [] -> []
             | hd :: tl ->
@@ -204,62 +256,8 @@ let rec array_init = function
 
     | node -> transform_children array_init node
 
-(* Generate new variables for array dimensions in function bodies, to avoid
- * re-evalutation after array dimension reduction. For example:
- *
- * int dims = 0;
- *
- * int dim() {
- *     dims = dims 1;  // Side effect => dims() should be called once
- *     return 10;
- * }
- *
- * void foo() {
- *    int[10, dim()] arr;
- *    arr[0, 1] = 1;
- * }
- *
- * After dimension reduction, this would become:
- * void foo() {
- *    int[] arr;
- *    arr = allocate(10, dim());
- *    arr[1 * dim() + 0] = 1;
- * }
- *
- * This behaviour is of course incorrect. To avoid dim() from being evaluated
- * twice, the snippet above is transformed into the following code: (note the $$
- * which will help later during constant propagation)
- * void foo() {
- *    int[a$dim$$1, a$dim$$2] arr;
- *    a$dim$$1 = 10;
- *    a$dim$$2 = dim();
- *    arr[1, 2] = 1;
- * }
- *
- * ... which later becomes:
- * void foo() {
- *    int[a$dim$$1, a$dim$$2] arr;
- *    a$dim$$1 = 10;
- *    a$dim$$2 = dim();
- *    arr = __allocate(a$dim$$1 * a$dim$$2);
- *    arr[1 * a$dim$2 * 0] = 1;
- * }
- * *)
-let rec array_dims = function
-    | VarDec (Array (ctype, values), name, init, ann) ->
-        let make_dimname i _ = name ^ "$dim$$" ^ string_of_int (i + 1) in
-        let dimnames = mapi make_dimname values in
-
-        let make_dimvar value name = Dim (name, annof value) in
-        let dims = List.map2 make_dimvar values dimnames in
-
-        let make_dimdec name value = DimDec (name, Some value, annof value) in
-        let dimdecs = List.map2 make_dimdec dimnames values in
-
-        Block (dimdecs @ [VarDec (Array (ctype, dims), name, init, ann)])
-
-    | node -> transform_children array_dims node
-
 let phase = function
-    | Ast node -> Ast (for_to_while (array_init (var_init (array_dims node))))
+    | Ast node ->
+        let node = move_inits (add_allocs (split_inits (array_dims node))) in
+        Ast (for_to_while (array_init (node)))
     | _ -> raise (InvalidInput "desugar")

+ 48 - 12
phases/dim_reduce.ml

@@ -1,6 +1,51 @@
 open Types
 open Util
 
+let rec expand_dims = function
+    (* Flatten Block nodes returned by transformations below *)
+    | FunDef (export, ret_type, name, params, body, ann) ->
+        let params = flatten_blocks (List.map expand_dims params) in
+        FunDef (export, ret_type, name, params, expand_dims body, ann)
+
+    | FunDec (ret_type, name, params, ann) ->
+        let params = flatten_blocks (List.map expand_dims params) in
+        FunDec (ret_type, name, params, ann)
+
+    | FunUse (dec, params, ann) ->
+        FunUse (dec, flatten_blocks (List.map expand_dims params), ann)
+
+    (* Add additional parameters for array dimensions *)
+    | Param (ArrayDims (ctype, dims), name, ann) ->
+        let rec do_expand = function
+            | [] -> [Param (Array ctype, name, ann)]
+            | Dim (name, ann) :: tail ->
+                Param (Int, name, ann) :: (do_expand tail)
+            | _ -> raise InvalidNode
+        in
+        Block (do_expand dims)
+
+    (* Add additional function arguments for array dimensions *)
+    | Arg (VarUse (VarDec (ArrayDims (ctype, dims), name, None, decann), None, ann)) as node ->
+        let rec do_expand = function
+            | [] ->
+                (* Remove the (now obsolete dimensions fromt the type) *)
+                let dec = VarDec (Array ctype, name, None, decann) in
+                [VarUse (dec, None, ann)]
+            | hd :: tl ->
+                (* A VarDec node has been added for each dimension during
+                 * desugaring, so we can safely reconstruct it here (we need no
+                 * refrence because the type is immutable, yay!) *)
+                let dimdec = VarDec (Int, nameof hd, None, annof hd) in
+                Arg (VarUse (dimdec, None, [])) :: (do_expand tl)
+        in
+        Block (do_expand dims)
+
+    (* Simplify array types in declarations *)
+    | VarDec (ArrayDims (ctype, _), name, None, ann) ->
+        VarDec (Array ctype, name, None, ann)
+
+    | node -> transform_children expand_dims node
+
 let rec multiply = function
     | []       -> raise InvalidNode
     | [node]   -> node
@@ -31,7 +76,7 @@ and dim_reduce depth = function
     (* Expand indices when dereferencing *)
     | VarUse (dec, Some values, ann) as node ->
         (match typeof dec with
-        | Array (_, dims) ->
+        | ArrayDims (_, dims) ->
             VarUse (dec, Some [expand depth (List.rev dims) values], ann)
         | _ -> node
         )
@@ -39,22 +84,13 @@ and dim_reduce depth = function
     (* Expand indices when assigning to array index *)
     | VarLet (dec, Some values, value, ann) as node ->
         (match typeof dec with
-        | Array (_, dims) ->
+        | ArrayDims (_, dims) ->
             VarLet (dec, Some [expand depth (List.rev dims) values], value, ann)
         | _ -> node
         )
 
     | node -> transform_children (dim_reduce depth) node
 
-let rec simplify_decs = function
-    | VarDec (Array (ctype, dims), name, init, ann) as node ->
-        VarDec (FlatArray ctype, name, init, ann)
-
-    | Param (Array (ctype, dims), name, ann) ->
-        Param (FlatArray ctype, name, ann)
-
-    | node -> transform_children simplify_decs node
-
 let phase = function
-    | Ast node -> Ast (simplify_decs (dim_reduce 0 node))
+    | Ast node -> Ast (dim_reduce 0 (expand_dims node))
     | _ -> raise (InvalidInput "dimension reduction")

+ 0 - 40
phases/expand_dims.ml

@@ -1,40 +0,0 @@
-open Types
-open Util
-
-let rec expand_dims = function
-    (* Flatten Block nodes returned by transformations below *)
-    | FunDef (export, ret_type, name, params, body, ann) ->
-        let params = flatten_blocks (List.map expand_dims params) in
-        FunDef (export, ret_type, name, params, expand_dims body, ann)
-
-    | FunDec (ret_type, name, params, ann) ->
-        let params = flatten_blocks (List.map expand_dims params) in
-        FunDec (ret_type, name, params, ann)
-
-    | FunUse (dec, params, ann) ->
-        FunUse (dec, flatten_blocks (List.map expand_dims params), ann)
-
-    (* Add additional parameters for array dimensions *)
-    | Param (Array (_,dims) as ctype, name, ann) ->
-        let rec do_expand = function
-            | [] ->
-                [Param (ctype, name, ann)]
-            | Dim (name, ann) :: tail ->
-                Param (Int, name, ann) :: (do_expand tail)
-            | _ -> raise InvalidNode
-        in
-        Block (do_expand dims)
-
-    (* Add additional function arguments for array dimensions *)
-    | Arg (VarUse (VarDec (Array (_, dims), _, _, _), None, _)) as node ->
-        let rec do_expand = function
-            | []       -> [node]
-            | hd :: tl -> Arg (VarUse (hd, None, [])) :: (do_expand tl)
-        in
-        Block (do_expand dims)
-
-    | node -> transform_children expand_dims node
-
-let phase = function
-    | Ast node -> Ast (expand_dims node)
-    | _ -> raise (InvalidInput "expand dimensions")

+ 5 - 22
phases/extern_vars.ml

@@ -12,7 +12,7 @@ let call node args depth = match node with
     | _ -> raise InvalidNode
 
 let process globals = function
-    | GlobalDef (true, Array (ctype, dims), name, None, ann) as dec ->
+    | GlobalDef (true, Array ctype, name, None, ann) as dec ->
         (* Getters for array variable: crate getter for given index Note that
          * getters and setters for dimensions are automatically generated,
          * because they have been put into new global variables during the
@@ -43,27 +43,10 @@ let process globals = function
 
         [getter; setter]
 
-    | GlobalDec (Array (ctype, dims), name, ann) ->
-        (* Getters for external array variable: create getter for a given index *)
-        (* Setters for external array variable:
-         * - define setter for a given index
-         * - define setter for each dimension*)
+    | GlobalDec (Array ctype, name, ann) ->
+        (* Getters for external array variable: create getter and setter for a
+         * given index *)
         let (param, _) = create_param Int "index" in
-        let rec process_dims i = function
-            | [] -> []
-            | Dim (oldname, _) :: tl ->
-                let dimname = name ^ "$" ^ string_of_int i in
-
-                let getter = FunDec (Void, dimname ^ "$get", [], []) in
-
-                let (param, _) = create_param ctype "value" in
-                let setter = FunDec (Void, dimname ^ "$set", [param], []) in
-
-                Hashtbl.add globals oldname (call getter, call setter);
-                getter :: setter :: (process_dims (i + 1) tl)
-            | _ -> raise InvalidNode
-        in
-
         let getter = FunDec (ctype, name ^ "$get", [param], []) in
 
         let (param1, index) = create_param Int "index" in
@@ -71,7 +54,7 @@ let process globals = function
         let setter = FunDec (Void, name ^ "$set", [param1; param2], []) in
 
         Hashtbl.add globals name (call getter, call setter);
-        getter :: setter :: (process_dims 1 dims)
+        [getter; setter]
 
     (* Getter for basic variable type: return the variable *)
     | GlobalDec (ctype, name, ann) ->

+ 1 - 1
phases/index_analysis.ml

@@ -37,7 +37,7 @@ let tag_index program =
 
         | LocalFuns _ -> node
 
-        | VarDec _ | DimDec _ | Param _ | Dim _ ->
+        | VarDec _ | Param _ | Dim _ ->
             let index = !stacklen in
             stacklen := !stacklen + 1;
             annotate (Index index) (transform_children trav node)

+ 1 - 3
phases/print.ml

@@ -9,7 +9,7 @@ let si = string_of_int
 
 let ctype2str = Stringify.type2str
 let type2str = function
-    | Array (t, dims) -> ctype2str t ^ repeat "," (List.length dims - 1)
+    | ArrayDims (t, dims) -> ctype2str t ^ repeat "," (List.length dims - 1)
     | t -> ctype2str t
 
 let op2str = function
@@ -129,7 +129,6 @@ let rec instr2str = function
 
     | EmptyLine -> ""
     | DummyInstr -> tab ^ "<dummy>"
-    | _ -> tab ^ "<unknown instruction>"
 
 let rec print_assembly oc instrs =
     let output_line line =
@@ -177,4 +176,3 @@ let phase = function
         input
 
     | Empty -> Empty
-    | _ -> raise (InvalidInput "print")

+ 12 - 6
phases/typecheck.ml

@@ -20,9 +20,13 @@ open Stringify
  * - Only values having a basic type can be type cast.
  *)
 
+let array_depth = function
+    | ArrayDims (_, dims) -> List.length dims
+    | _                   -> raise InvalidNode
+
 let spec = function
-    | Array (ctype, dims) -> ArrayDepth (ctype, list_size dims)
-    | ctype               -> ctype
+    | ArrayDims (ctype, dims) -> (ctype, List.length dims)
+    | ctype                   -> (ctype, 0)
 
 let check_type ?(msg="") expected node =
     let got = typeof node in
@@ -57,7 +61,7 @@ let check_type_op allowed_types desc node =
     ); ()
 
 let check_dims_match dims dec_type errnode =
-    match (list_size dims, array_depth dec_type) with
+    match (List.length dims, array_depth dec_type) with
     | (got, expected) when got != expected ->
         let msg = sprintf
             "dimension mismatch: expected %d indices, got %d" expected got
@@ -74,7 +78,7 @@ let rec typecheck node =
     match node with
     | FunUse ((FunDec (ret_type, name, params, _) as dec), args, ann)
     | FunUse ((FunDef (_, ret_type, name, params, _, _) as dec), args, ann) ->
-        (match (list_size args, list_size params) with
+        (match (List.length args, List.length params) with
         | (nargs, nparams) when nargs != nparams ->
             let msg = sprintf
                 "function \"%s\" expects %d arguments, got %d"
@@ -127,11 +131,13 @@ let rec typecheck node =
         Dim (name, Type Int :: ann)
 
     (* Functions and parameters must be traversed to give types to Dim nodes *)
+    (*
     | FunDec (ret_type, name, params, ann) ->
         FunDec (ret_type, name, List.map typecheck params, ann)
 
-    | Param (Array (ctype, dims), name, ann) ->
-        Param (Array (ctype, List.map typecheck dims), name, ann)
+    | Param (ArrayDims (ctype, dims), name, ann) ->
+        Param (ArrayDims (ctype, List.map typecheck dims), name, ann)
+        *)
 
     (* Void functions may have no return statement, other functions must have a
      * return statement of valid type *)

+ 9 - 14
stringify.ml

@@ -24,8 +24,7 @@ let nameof = function
     | FunDef (_, _, name, _, _, _)
     | VarDec (_, name, _, _)
     | Param (_, name, _)
-    | Dim (name, _)
-    | DimDec (name, _, _) -> name
+    | Dim (name, _) -> name
     | _ -> raise InvalidNode
 
 (* operator -> string *)
@@ -52,9 +51,8 @@ let rec type2str = function
     | Bool  -> "bool"
     | Int   -> "int"
     | Float -> "float"
-    | Array (t, dims)       -> (type2str t) ^ "[" ^ (concat ", " dims) ^ "]"
-    | ArrayDepth (t, ndims) -> (type2str t) ^ "[" ^ string_of_int ndims ^ "]"
-    | FlatArray t           -> (type2str t) ^ "[]"
+    | ArrayDims (t, dims) -> (type2str t) ^ "[" ^ (concat ", " dims) ^ "]"
+    | Array t             -> (type2str t) ^ "[]"
 
 and concat sep nodes = String.concat sep (List.map node2str nodes)
 
@@ -150,15 +148,12 @@ and node2str node =
         "<scalar:" ^ str value ^ ">"
     | Arg node                     when args.verbose >= 3 ->
         "<arg:" ^ str node ^ ">"
-    | DimDec (name, None, _)       when args.verbose >= 3 ->
-        type2str Int ^ " <dim:" ^ name ^ ">;"
-    | DimDec (name, Some init, _)  when args.verbose >= 3 ->
-        type2str Int ^ " <dim:" ^ name ^ "> = " ^ str init ^ ";"
-
-    | DimDec (name, None, _) ->
-        type2str Int ^ " " ^ name ^ ";"
-    | DimDec (name, Some init, _) ->
-        type2str Int ^ " " ^ name ^ " = " ^ str init ^ ";"
+    (*
+    | VarDecs nodes                when args.verbose >= 3 ->
+        String.concat "\n" ("// vardecs" :: List.map str nodes)
+    | LocalFuns nodes              when args.verbose >= 3 ->
+        String.concat "\n" ("// localfuns" :: List.map str nodes)
+    *)
 
     | VarLet (dec, dims, value, _) ->
         node2str (Assign (nameof dec, dims, value, []))

+ 6 - 1
test/old/array_scope.cvc

@@ -1,6 +1,11 @@
 extern void printInt(int val);
 
 void foo(int[n] arr) {
+    int[n] q;
     printInt(n);
-    foo(arr);
+    printLast(arr);
+}
+
+void printLast(int[m] p) {
+    printInt(p[m - 1]);
 }

+ 17 - 15
types.ml

@@ -1,15 +1,18 @@
 type location = string * int * int * int * int
 let noloc = ("", 0, 0, 0, 0)
 
-type operator = Neg | Not
-              | Add | Sub | Mul | Div | Mod
-              | Eq | Ne | Lt | Le | Gt | Ge
-              | And | Or
-type const = BoolVal of bool | IntVal of int | FloatVal of float
-type ctype = Void | Bool | Int | Float
-           | Array of ctype * node list
-           | ArrayDepth of ctype * int  (* TODO: remove? *)
-           | FlatArray of ctype
+type operator =
+    | Neg | Not
+    | Add | Sub | Mul | Div | Mod
+    | Eq | Ne | Lt | Le | Gt | Ge
+    | And | Or
+type const =
+    | BoolVal of bool
+    | IntVal of int
+    | FloatVal of float
+type ctype =
+    | Void | Bool | Int | Float | Array of ctype
+    | ArrayDims of ctype * node list
 and annotation =
     | Loc of location
     | Depth of int
@@ -32,7 +35,7 @@ and node =
     | Param of ctype * string * ann
       (* type, name *)
     | Dim of string * ann
-      (* dimension name in array Param *)
+      (* name *)
 
     | VarDecs of node list
     | LocalFuns of node list
@@ -70,9 +73,8 @@ and node =
     | FunUse of node * node list * ann         (* Same as FunCall, but with decl. *)
     | VarLet of node * node list option * node * ann (* replacement for Assign *)
     | ArrayScalar of node                      (* (Bool|Int|Float)Const *)
-    | ArrayInit of node * ctype                (* Array(Scalar|Const) * dimensions *)
+    | ArrayInit of node * node list            (* Array(Scalar|Const), dimensions *)
     | Cond of node * node * node * ann         (* cond, true_expr, false_expr *)
-    | DimDec of string * node option * ann
     | DummyNode                                (* null node, pruned by traversals *)
 
 type stack_scope = Glob | Local | Rel of int | Current
@@ -146,7 +148,7 @@ type args_record = {
 }
 
 (* Commandline args are stored in a global record
- * (yes, it is a bit dirty, but I don't know how to do this without passin
+ * (yes, it is a bit dirty, but I don't know how to do this without passing
  * [args] to every function) *)
 let args = {
     infile   = None;
@@ -157,14 +159,14 @@ let args = {
     endphase = "";
 }
 
-(* intermediate representations between phases *)
+(* Intermediate representations between phases *)
 type intermediate =
     | Empty
     | FileContent of string * string
     | Ast of node
     | Assembly of instr list
 
-(* exceptions *)
+(* Exceptions *)
 exception LocError of location * string
 exception NodeError of node * string
 exception CompileError of string

+ 8 - 20
util.ml

@@ -147,8 +147,6 @@ let transform_children trav node =
         VarUse (dec, Some (trav_all dims), ann)
     | FunUse (dec, params, ann) ->
         FunUse (dec, trav_all params, ann)
-    | DimDec (name, Some init, ann) ->
-        DimDec (name, Some (trav init), ann)
 
     | _ -> node
 
@@ -213,8 +211,6 @@ let annotate a = function
         Param (ctype, name, a :: ann)
     | Dim (name, ann) ->
         Dim (name, a :: ann)
-    | DimDec (name, init, ann) ->
-        DimDec (name, init, a :: ann)
 
     | _ -> raise InvalidNode
 
@@ -247,8 +243,7 @@ let rec annof = function
     | TypeCast (_, _, ann)
     | VarUse (_, _, ann)
     | FunUse (_, _, ann)
-    | FunCall (_, _, ann)
-    | DimDec (_, _, ann) -> ann
+    | FunCall (_, _, ann) -> ann
 
     | ArrayInit (value, _)
     | ArrayScalar value
@@ -297,7 +292,7 @@ let typeof = function
 
     (* Dim nodes are always type Int, and are copied by context analysis before
      * they are annotated with Type Int, so this match is necessary *)
-    | DimDec _ | Dim _ -> Int
+    | Dim _ -> Int
 
     (* Other nodes must be annotated during typechecking *)
     | node ->
@@ -388,19 +383,11 @@ let block_body = function
     | Block nodes -> nodes
     | _ -> raise InvalidNode
 
-let rec list_size = function
-    | [] -> 0
-    | hd :: tl -> 1 + (list_size tl)
-
 let basetypeof node = match typeof node with
-    | Array (ctype, _)
-    | FlatArray ctype
+    | ArrayDims (ctype, _)
+    | Array ctype
     | ctype -> ctype
 
-let array_depth = function
-    | Array (_, dims) -> list_size dims
-    | _               -> raise InvalidNode
-
 let nameof = function
     | GlobalDec (_, name, _)
     | GlobalDef (_, _, name, _, _)
@@ -408,8 +395,7 @@ let nameof = function
     | FunDef (_, _, name, _, _, _)
     | VarDec (_, name, _, _)
     | Param (_, name, _)
-    | Dim (name, _)
-    | DimDec (name, _, _) -> name
+    | Dim (name, _) -> name
     | _ -> raise InvalidNode
 
 let optmap f = function
@@ -429,4 +415,6 @@ let mapi f lst =
 let is_immediate_const const =
     if args.optimize then List.mem const immediate_consts else false
 
-let is_array node = match typeof node with Array _ -> true | _ -> false
+let is_array node = match typeof node with
+    | ArrayDims _ | Array _ -> true
+    | _ -> false

+ 0 - 6
util.mli

@@ -48,15 +48,9 @@ val flatten_blocks : Types.node list -> Types.node list
 (* Extract the node list from a Block node *)
 val block_body : Types.node -> Types.node list
 
-(* Get the size of a list by traversing it recurcively *)
-val list_size : 'a list -> int
-
 (* Get the basic type of a declaration, removing array dimensions *)
 val basetypeof : Types.node -> Types.ctype
 
-(* Get the number of dimensions from an Array type *)
-val array_depth : Types.ctype -> int
-
 (* Get name from variable or function declaration *)
 val nameof : Types.node -> string