adam@1348: (* Copyright (c) 2008-2010, Adam Chlipala
adamc@29:  * All rights reserved.
adamc@29:  *
adamc@29:  * Redistribution and use in source and binary forms, with or without
adamc@29:  * modification, are permitted provided that the following conditions are met:
adamc@29:  *
adamc@29:  * - Redistributions of source code must retain the above copyright notice,
adamc@29:  *   this list of conditions and the following disclaimer.
adamc@29:  * - Redistributions in binary form must reproduce the above copyright notice,
adamc@29:  *   this list of conditions and the following disclaimer in the documentation
adamc@29:  *   and/or other materials provided with the distribution.
adamc@29:  * - The names of contributors may not be used to endorse or promote products
adamc@29:  *   derived from this software without specific prior written permission.
adamc@29:  *
adamc@29:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
adamc@29:  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
adamc@29:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
adamc@29:  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
adamc@29:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
adamc@29:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
adamc@29:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
adamc@29:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
adamc@29:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
adamc@29:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
adamc@29:  * POSSIBILITY OF SUCH DAMAGE.
adamc@29:  *)
adamc@29: 
adamc@29: structure Cjrize :> CJRIZE = struct
adamc@29: 
adamc@109: structure L = Mono
adamc@29: structure L' = Cjr
adamc@29: 
adamc@196: structure IM = IntBinaryMap
adamc@196: 
adamc@29: structure Sm :> sig
adamc@29:     type t
adamc@29: 
adamc@29:     val empty : t
adamc@29:     val find : t * (string * L.typ) list * (string * L'.typ) list -> t * int
adamc@757:     val findList : t * L.typ * L'.typ -> t * int
adamc@29: 
adamc@29:     val declares : t -> (int * (string * L'.typ) list) list
adamc@453:     val clearDeclares : t -> t
adamc@29: end = struct
adamc@29: 
adamc@29: structure FM = BinaryMapFn(struct
adamc@29:                            type ord_key = L.typ
adamc@109:                            val compare = MonoUtil.Typ.compare
adamc@29:                            end)
adamc@29: 
adamc@757: type t = {
adamc@757:      count : int,
adamc@757:      normal : int FM.map,
adamc@757:      lists : int FM.map,
adamc@757:      decls : (int * (string * L'.typ) list) list
adamc@757: }
adamc@29: 
adamc@757: val empty : t = {
adamc@757:     count = 1,
adamc@757:     normal = FM.insert (FM.empty, (L.TRecord [], ErrorMsg.dummySpan), 0),
adamc@757:     lists = FM.empty,
adamc@757:     decls = []
adamc@757: }
adamc@29: 
adamc@757: fun find (v as {count, normal, decls, lists}, xts, xts') =
adamc@29:     let
adamc@29:         val t = (L.TRecord xts, ErrorMsg.dummySpan)
adamc@29:     in
adamc@757:         case FM.find (normal, t) of
adamc@757:             SOME i => (v, i)
adamc@757:           | NONE => ({count = count+1,
adamc@757:                       normal = FM.insert (normal, t, count),
adamc@757:                       lists = lists,
adamc@757:                       decls = (count, xts') :: decls},
adamc@757:                      count)
adamc@29:     end
adamc@29: 
adamc@757: fun findList (v as {count, normal, decls, lists}, t, t') =
adamc@757:     case FM.find (lists, t) of
adamc@757:         SOME i => (v, i)
adamc@757:       | NONE =>
adamc@757:         let
adamc@757:             val xts = [("1", t), ("2", (L.TList t, #2 t))]
adamc@757:             val xts' = [("1", t'), ("2", (L'.TList (t', count), #2 t'))]
adamc@757:         in
adamc@757:             ({count = count+1,
adamc@757:               normal = FM.insert (normal, (L.TRecord xts, ErrorMsg.dummySpan), count),
adamc@757:               lists = FM.insert (lists, t, count),
adamc@757:               decls = (count, xts') :: decls},
adamc@757:              count)
adamc@757:     end
adamc@29: 
adamc@757: fun declares (v : t) = #decls v
adamc@757: 
adamc@757: fun clearDeclares (v : t) = {count = #count v,
adamc@757:                              normal = #normal v,
adamc@757:                              lists = #lists v,
adamc@757:                              decls = []}
adamc@453: 
adamc@29: end
adamc@29: 
adamc@196: fun cifyTyp x =
adamc@196:     let
adamc@196:         fun cify dtmap ((t, loc), sm) =
adamc@196:             case t of
adamc@196:                 L.TFun (t1, t2) =>
adamc@196:                 let
adamc@196:                     val (t1, sm) = cify dtmap (t1, sm)
adamc@196:                     val (t2, sm) = cify dtmap (t2, sm)
adamc@196:                 in
adamc@196:                     ((L'.TFun (t1, t2), loc), sm)
adamc@196:                 end
adamc@196:               | L.TRecord xts =>
adamc@196:                 let
adam@1314:                     val xts = MonoUtil.Typ.sortFields xts
adamc@196:                     val old_xts = xts
adamc@196:                     val (xts, sm) = ListUtil.foldlMap (fn ((x, t), sm) =>
adamc@196:                                                           let
adamc@196:                                                               val (t, sm) = cify dtmap (t, sm)
adamc@196:                                                           in
adamc@196:                                                               ((x, t), sm)
adamc@196:                                                           end)
adamc@196:                                                       sm xts
adamc@196:                     val (sm, si) = Sm.find (sm, old_xts, xts)
adamc@196:                 in
adamc@196:                     ((L'.TRecord si, loc), sm)
adamc@196:                 end
adamc@196:               | L.TDatatype (n, ref (dk, xncs)) =>
adamc@196:                 (case IM.find (dtmap, n) of
adamc@196:                      SOME r => ((L'.TDatatype (dk, n, r), loc), sm)
adamc@196:                    | NONE =>
adamc@196:                      let
adamc@196:                          val r = ref []
adamc@196:                          val dtmap = IM.insert (dtmap, n, r)
adamc@196: 
adamc@196:                          val (xncs, sm) = ListUtil.foldlMap (fn ((x, n, to), sm) =>
adamc@196:                                                                 case to of
adamc@196:                                                                     NONE => ((x, n, NONE), sm)
adamc@196:                                                                   | SOME t =>
adamc@196:                                                                     let
adamc@196:                                                                         val (t, sm) = cify dtmap (t, sm)
adamc@196:                                                                     in
adamc@196:                                                                         ((x, n, SOME t), sm)
adamc@196:                                                                     end)
adamc@196:                                                             sm xncs
adamc@196:                      in
adamc@196:                          r := xncs;
adamc@196:                          ((L'.TDatatype (dk, n, r), loc), sm)
adamc@196:                      end)
adamc@196:               | L.TFfi mx => ((L'.TFfi mx, loc), sm)
adamc@288:               | L.TOption t =>
adamc@288:                 let
adamc@288:                     val (t, sm) = cify dtmap (t, sm)
adamc@288:                 in
adamc@288:                     ((L'.TOption t, loc), sm)
adamc@288:                 end
adamc@757:               | L.TList t =>
adamc@757:                 let
adamc@757:                     val (t', sm) = cify dtmap (t, sm)
adamc@757:                     val (sm, si) = Sm.findList (sm, t, t')
adamc@757:                 in
adamc@757:                     ((L'.TList (t', si), loc), sm)
adamc@757:                 end
adam@1446:               | L.TSource => ((L'.TFfi ("Basis", "source"), loc), sm)
adamc@568:               | L.TSignal _ => raise Fail "Cjrize: TSignal remains"
adamc@196:     in
adamc@196:         cify IM.empty x
adamc@196:     end
adamc@29: 
adamc@109: val dummye = (L'.EPrim (Prim.Int 0), ErrorMsg.dummySpan)
adamc@109: 
adamc@186: fun cifyPatCon (pc, sm) =
adamc@181:     case pc of
adamc@186:         L.PConVar n => (L'.PConVar n, sm)
adamc@186:       | L.PConFfi {mod = m, datatyp, con, arg} =>
adamc@186:         let
adamc@186:             val (arg, sm) =
adamc@186:                 case arg of
adamc@186:                     NONE => (NONE, sm)
adamc@186:                   | SOME t =>
adamc@186:                     let
adamc@186:                         val (t, sm) = cifyTyp (t, sm)
adamc@186:                     in
adamc@186:                         (SOME t, sm)
adamc@186:                     end
adamc@186:         in
adamc@186:             (L'.PConFfi {mod = m, datatyp = datatyp, con = con, arg = arg}, sm)
adamc@186:         end
adamc@181: 
adamc@182: fun cifyPat ((p, loc), sm) =
adamc@181:     case p of
adamc@182:         L.PWild => ((L'.PWild, loc), sm)
adamc@182:       | L.PVar (x, t) =>
adamc@182:         let
adamc@182:             val (t, sm) = cifyTyp (t, sm)
adamc@182:         in
adamc@182:             ((L'.PVar (x, t), loc), sm)
adamc@182:         end
adamc@182:       | L.PPrim p => ((L'.PPrim p, loc), sm)
adamc@188:       | L.PCon (dk, pc, NONE) =>
adamc@186:         let
adamc@186:             val (pc, sm) = cifyPatCon (pc, sm)
adamc@186:         in
adamc@188:             ((L'.PCon (dk, pc, NONE), loc), sm)
adamc@186:         end
adamc@188:       | L.PCon (dk, pc, SOME p) =>
adamc@182:         let
adamc@186:             val (pc, sm) = cifyPatCon (pc, sm)
adamc@182:             val (p, sm) = cifyPat (p, sm)
adamc@182:         in
adamc@188:             ((L'.PCon (dk, pc, SOME p), loc), sm)
adamc@182:         end
adamc@182:       | L.PRecord xps =>
adamc@182:         let
adamc@182:             val (xps, sm) = ListUtil.foldlMap (fn ((x, p, t), sm) =>
adamc@182:                                                   let
adamc@182:                                                       val (p, sm) = cifyPat (p, sm)
adamc@182:                                                       val (t, sm) = cifyTyp (t, sm)
adamc@182:                                                   in
adamc@182:                                                       ((x, p, t), sm)
adamc@182:                                                   end) sm xps
adamc@182:         in
adamc@182:             ((L'.PRecord xps, loc), sm)
adamc@182:         end
adamc@288:       | L.PNone t =>
adamc@288:         let
adamc@288:             val (t, sm) = cifyTyp (t, sm)
adamc@288:         in
adamc@288:             ((L'.PNone t, loc), sm)
adamc@288:         end
adamc@288:       | L.PSome (t, p) =>
adamc@288:         let
adamc@288:             val (t, sm) = cifyTyp (t, sm)
adamc@288:             val (p, sm) = cifyPat (p, sm)
adamc@288:         in
adamc@288:             ((L'.PSome (t, p), loc), sm)
adamc@288:         end
adamc@288: 
adamc@280: fun cifyExp (eAll as (e, loc), sm) =
adam@1601:     let
adam@1601:         fun fail msg =
adam@1601:             (ErrorMsg.errorAt loc msg;
adam@1601:              ((L'.EPrim (Prim.String ""), loc), sm))
adam@1601:     in
adam@1601:         case e of
adam@1601:             L.EPrim p => ((L'.EPrim p, loc), sm)
adam@1601:           | L.ERel n => ((L'.ERel n, loc), sm)
adam@1601:           | L.ENamed n => ((L'.ENamed n, loc), sm)
adam@1601:           | L.ECon (dk, pc, eo) =>
adam@1601:             let
adam@1601:                 val (eo, sm) =
adam@1601:                     case eo of
adam@1601:                         NONE => (NONE, sm)
adam@1601:                       | SOME e =>
adam@1601:                         let
adam@1601:                             val (e, sm) = cifyExp (e, sm)
adam@1601:                         in
adam@1601:                             (SOME e, sm)
adam@1601:                         end
adam@1601:                 val (pc, sm) = cifyPatCon (pc, sm)
adam@1601:             in
adam@1601:                 ((L'.ECon (dk, pc, eo), loc), sm)
adam@1601:             end
adam@1601:           | L.ENone t =>
adam@1601:             let
adam@1601:                 val (t, sm) = cifyTyp (t, sm)
adam@1601:             in
adam@1601:                 ((L'.ENone t, loc), sm)
adam@1601:             end
adam@1601:           | L.ESome (t, e) =>
adam@1601:             let
adam@1601:                 val (t, sm) = cifyTyp (t, sm)
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:             in
adam@1601:                 ((L'.ESome (t, e), loc), sm)
adam@1601:             end
adam@1601:           | L.EFfi mx => ((L'.EFfi mx, loc), sm)
adam@1601:           | L.EFfiApp (m, x, es) =>
adam@1601:             let
adam@1601:                 val (es, sm) = ListUtil.foldlMap cifyExp sm es
adam@1601:             in
adam@1601:                 ((L'.EFfiApp (m, x, es), loc), sm)
adam@1601:             end
adam@1601:           | L.EApp (e1, e2) =>
adam@1601:             let
adam@1601:                 fun unravel (e, args) =
adam@1601:                     case e of
adam@1601:                         (L.EApp (e1, e2), _) => unravel (e1, e2 :: args)
adam@1601:                       | _ => (e, args)
adamc@316: 
adam@1601:                 val (f, es) = unravel (e1, [e2])
adamc@316: 
adam@1601:                 val (f, sm) = cifyExp (f, sm)
adam@1601:                 val (es, sm) = ListUtil.foldlMap cifyExp sm es
adam@1601:             in
adam@1601:                 ((L'.EApp (f, es), loc), sm)
adam@1601:             end
adam@1601:           | L.EAbs _ => (ErrorMsg.errorAt loc "Anonymous function remains at code generation";
adam@1601:                          Print.prefaces' [("Function", MonoPrint.p_exp MonoEnv.empty eAll)];
adam@1601:                          (dummye, sm))
adamc@29: 
adam@1601:           | L.EUnop (s, e1) =>
adam@1601:             let
adam@1601:                 val (e1, sm) = cifyExp (e1, sm)
adam@1601:             in
adam@1601:                 ((L'.EUnop (s, e1), loc), sm)
adam@1601:             end
adam@1601:           | L.EBinop (_, s, e1, e2) =>
adam@1601:             let
adam@1601:                 val (e1, sm) = cifyExp (e1, sm)
adam@1601:                 val (e2, sm) = cifyExp (e2, sm)
adam@1601:             in
adam@1601:                 ((L'.EBinop (s, e1, e2), loc), sm)
adam@1601:             end
adamc@387: 
adam@1601:           | L.ERecord xes =>
adam@1601:             let
adam@1601:                 val old_xts = map (fn (x, _, t) => (x, t)) xes
adamc@29: 
adam@1601:                 val (xets, sm) = ListUtil.foldlMap (fn ((x, e, t), sm) =>
adam@1601:                                                        let
adam@1601:                                                            val (e, sm) = cifyExp (e, sm)
adam@1601:                                                            val (t, sm) = cifyTyp (t, sm)
adam@1601:                                                        in
adam@1601:                                                            ((x, e, t), sm)
adam@1601:                                                        end)
adam@1601:                                                    sm xes
adamc@29: 
adam@1601:                 val (sm, si) = Sm.find (sm, old_xts, map (fn (x, _, t) => (x, t)) xets)
adamc@29: 
adam@1601:                 val xes = map (fn (x, e, _) => (x, e)) xets
adam@1601:                 val xes = ListMergeSort.sort (fn ((x1, _), (x2, _)) => String.compare (x1, x2) = GREATER) xes
adam@1601:             in
adam@1601:                 ((L'.ERecord (si, xes), loc), sm)
adam@1601:             end
adam@1601:           | L.EField (e, x) =>
adam@1601:             let
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:             in
adam@1601:                 ((L'.EField (e, x), loc), sm)
adam@1601:             end
adamc@29: 
adam@1601:           | L.ECase (e, pes, {disc, result}) =>
adam@1601:             let
adamc@181:                 val (e, sm) = cifyExp (e, sm)
adamc@181:                 val (pes, sm) = ListUtil.foldlMap
adamc@181:                                     (fn ((p, e), sm) =>
adamc@181:                                         let
adamc@181:                                             val (e, sm) = cifyExp (e, sm)
adamc@182:                                             val (p, sm) = cifyPat (p, sm)
adamc@181:                                         in
adamc@182:                                             ((p, e), sm)
adamc@181:                                         end) sm pes
adamc@182:                 val (disc, sm) = cifyTyp (disc, sm)
adamc@182:                 val (result, sm) = cifyTyp (result, sm)
adamc@181:             in
adamc@182:                 ((L'.ECase (e, pes, {disc = disc, result = result}), loc), sm)
adamc@181:             end
adamc@178: 
adam@1601:           | L.EError (e, t) =>
adam@1601:             let
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:                 val (t, sm) = cifyTyp (t, sm)
adam@1601:             in
adam@1601:                 ((L'.EError (e, t), loc), sm)
adam@1601:             end
adam@1601:           | L.EReturnBlob {blob, mimeType, t} =>
adam@1601:             let
adam@1601:                 val (blob, sm) = cifyExp (blob, sm)
adam@1601:                 val (mimeType, sm) = cifyExp (mimeType, sm)
adam@1601:                 val (t, sm) = cifyTyp (t, sm)
adam@1601:             in
adam@1601:                 ((L'.EReturnBlob {blob = blob, mimeType = mimeType, t = t}, loc), sm)
adam@1601:             end
adam@1601:           | L.ERedirect (e, t) =>
adam@1601:             let
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:                 val (t, sm) = cifyTyp (t, sm)
adam@1601:             in
adam@1601:                 ((L'.ERedirect (e, t), loc), sm)
adam@1601:             end
adamc@283: 
adam@1601:           | L.EStrcat (e1, e2) =>
adam@1601:             let
adam@1601:                 val (e1, sm) = cifyExp (e1, sm)
adam@1601:                 val (e2, sm) = cifyExp (e2, sm)
adam@1601:             in
adam@1601:                 ((L'.EFfiApp ("Basis", "strcat", [e1, e2]), loc), sm)
adam@1601:             end
adamc@102: 
adam@1601:           | L.EWrite e =>
adam@1601:             let
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:             in
adam@1601:                 ((L'.EWrite e, loc), sm)
adam@1601:             end
adamc@102: 
adam@1601:           | L.ESeq (e1, e2) =>
adam@1601:             let
adam@1601:                 val (e1, sm) = cifyExp (e1, sm)
adam@1601:                 val (e2, sm) = cifyExp (e2, sm)
adam@1601:             in
adam@1601:                 ((L'.ESeq (e1, e2), loc), sm)
adam@1601:             end
adamc@106: 
adam@1601:           | L.ELet (x, t, e1, e2) =>
adam@1601:             let
adam@1601:                 val (t, sm) = cifyTyp (t, sm)
adam@1601:                 val (e1, sm) = cifyExp (e1, sm)
adam@1601:                 val (e2, sm) = cifyExp (e2, sm)
adam@1601:             in
adam@1601:                 ((L'.ELet (x, t, e1, e2), loc), sm)
adam@1601:             end
adamc@251: 
adam@1601:           | L.EClosure _ => (ErrorMsg.errorAt loc "Nested closure remains in code generation";
adam@1601:                              (dummye, sm))
adamc@111: 
adam@1601:           | L.EQuery {exps, tables, state, query, body, initial} =>
adam@1601:             let
adam@1601:                 val (exps', sm) = ListUtil.foldlMap (fn ((x, t), sm) =>
adam@1601:                                                         let
adam@1601:                                                             val (t, sm) = cifyTyp (t, sm)
adam@1601:                                                         in
adam@1601:                                                             ((x, t), sm)
adam@1601:                                                         end) sm exps
adam@1601:                 val (tables', sm) = ListUtil.foldlMap (fn ((x, xts), sm) =>
adam@1601:                                                           let
adam@1601:                                                               val (xts, sm) = ListUtil.foldlMap
adam@1601:                                                                                   (fn ((x, t), sm) =>
adam@1601:                                                                                       let
adam@1601:                                                                                           val (t, sm) = cifyTyp (t, sm)
adam@1601:                                                                                       in
adam@1601:                                                                                           ((x, t), sm)
adam@1601:                                                                                       end) sm xts
adam@1601:                                                           in
adam@1601:                                                               ((x, xts), sm)
adam@1601:                                                           end) sm tables
adamc@269: 
adam@1601:                 val row = exps @ map (fn (x, xts) => (x, (L.TRecord xts, loc))) tables
adam@1601:                 val row = ListMergeSort.sort (fn ((x, _), (y, _)) => String.compare (x, y) = GREATER) row
adamc@269: 
adam@1601:                 val (tableRows, sm) = ListUtil.foldlMap (fn (((x, xts), (_, xts')), sm) =>
adam@1601:                                                             let
adam@1601:                                                                 val (sm, rnum) = Sm.find (sm, xts, xts')
adam@1601:                                                             in
adam@1601:                                                                 ((x, rnum), sm)
adam@1601:                                                             end)
adam@1601:                                                         sm (ListPair.zip (tables, tables'))
adam@1601:                 val row' = exps' @ map (fn (x, n) => (x, (L'.TRecord n, loc))) tableRows
adam@1601:                 val row' = ListMergeSort.sort (fn ((x, _), (y, _)) => String.compare (x, y) = GREATER) row'
adamc@269: 
adam@1601:                 val (sm, rnum) = Sm.find (sm, row, row')
adamc@269: 
adam@1601:                 val (state, sm) = cifyTyp (state, sm)
adam@1601:                 val (query, sm) = cifyExp (query, sm)
adam@1601:                 val (body, sm) = cifyExp (body, sm)
adam@1601:                 val (initial, sm) = cifyExp (initial, sm)
adam@1601:             in
adam@1601:                 ((L'.EQuery {exps = exps', tables = tables', rnum = rnum, state = state,
adam@1601:                              query = query, body = body, initial = initial, prepared = NONE}, loc), sm)
adam@1601:             end
adamc@269: 
adam@1601:           | L.EDml (e, mode) =>
adam@1601:             let
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:             in
adam@1601:                 ((L'.EDml {dml = e, prepared = NONE, mode = mode}, loc), sm)
adam@1601:             end
adamc@307: 
adam@1601:           | L.ENextval e =>
adam@1601:             let
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:             in
adam@1601:                 ((L'.ENextval {seq = e, prepared = NONE}, loc), sm)
adam@1601:             end
adam@1601:           | L.ESetval (e1, e2) =>
adam@1601:             let
adam@1601:                 val (e1, sm) = cifyExp (e1, sm)
adam@1601:                 val (e2, sm) = cifyExp (e2, sm)
adam@1601:             in
adam@1601:                 ((L'.ESetval {seq = e1, count = e2}, loc), sm)
adam@1601:             end
adamc@338: 
adam@1601:           | L.EUnurlify (e, t, b) =>
adam@1601:             let
adam@1601:                 val (e, sm) = cifyExp (e, sm)
adam@1601:                 val (t, sm) = cifyTyp (t, sm)
adam@1601:             in
adam@1601:                 ((L'.EUnurlify (e, t, b), loc), sm)
adam@1601:             end
adamc@252: 
adam@1601:           | L.EJavaScript _ => fail "Uncompilable JavaScript remains"
adamc@578: 
adam@1601:           | L.ESignalReturn _ => fail "Signal monad 'return' remains in server-side code"
adam@1601:           | L.ESignalBind _ => fail "Signal monad 'bind' remains in server-side code"
adam@1601:           | L.ESignalSource _ => fail "Signal monad 'source' remains in server-side code"
adamc@566: 
adam@1601:           | L.EServerCall _ => fail "RPC in server-side code"
adam@1601:           | L.ERecv _ => fail "Message receive in server-side code"
adam@1601:           | L.ESleep _ => fail "Sleep in server-side code"
adam@1601:           | L.ESpawn _ => fail "Thread spawn in server-side code"
adam@1601:     end
adamc@608: 
adamc@29: fun cifyDecl ((d, loc), sm) =
adamc@29:     case d of
adamc@809:         L.DDatatype dts =>
adamc@165:         let
adamc@809:             val (dts, sm) = ListUtil.foldlMap
adamc@809:                                 (fn ((x, n, xncs), sm) =>
adamc@809:                                     let
adamc@809:                                         val dk = ElabUtil.classifyDatatype xncs
adamc@809:                                         val (xncs, sm) = ListUtil.foldlMap (fn ((x, n, to), sm) =>
adamc@809:                                                                                case to of
adamc@809:                                                                                    NONE => ((x, n, NONE), sm)
adamc@809:                                                                                  | SOME t =>
adamc@809:                                                                                    let
adamc@809:                                                                                        val (t, sm) = cifyTyp (t, sm)
adamc@809:                                                                                    in
adamc@809:                                                                                        ((x, n, SOME t), sm)
adamc@809:                                                                                    end) sm xncs
adamc@809:                                     in
adamc@809:                                         ((dk, x, n, xncs), sm)
adamc@809:                                     end)
adamc@809:                                 sm dts
adamc@165:         in
adamc@809:             (SOME (L'.DDatatype dts, loc), NONE, sm)
adamc@809:         end
adamc@164: 
adamc@164:       | L.DVal (x, n, t, e, _) =>
adamc@29:         let
adamc@29:             val (t, sm) = cifyTyp (t, sm)
adamc@109: 
adamc@109:             val (d, sm) = case #1 t of
adamc@121:                               L'.TFun _ =>
adamc@121:                               let
adamc@121:                                   fun unravel (tAll as (t, _), eAll as (e, _)) =
adamc@121:                                       case (t, e) of
adamc@121:                                           (L'.TFun (dom, ran), L.EAbs (ax, _, _, e)) =>
adamc@121:                                           let
adamc@121:                                               val (args, t, e) = unravel (ran, e)
adamc@121:                                           in
adamc@121:                                               ((ax, dom) :: args, t, e)
adamc@121:                                           end
adamc@993:                                         | (L'.TFun (dom, ran), _) =>
adamc@993:                                           let
adamc@993:                                               val e = MonoEnv.liftExpInExp 0 eAll
adamc@993:                                               val e = (L.EApp (e, (L.ERel 0, loc)), loc)
adamc@993:                                               val (args, t, e) = unravel (ran, e)
adamc@993:                                           in
adamc@993:                                               (("x", dom) :: args, t, e)
adamc@993:                                           end
adamc@121:                                         | _ => ([], tAll, eAll)
adamc@121: 
adamc@121:                                   val (args, ran, e) = unravel (t, e)
adamc@121:                                   val (e, sm) = cifyExp (e, sm)
adamc@121:                               in
adamc@121:                                   (L'.DFun (x, n, args, ran, e), sm)
adamc@121:                               end
adamc@121: 
adamc@109:                             | _ =>
adamc@109:                               let
adamc@109:                                   val (e, sm) = cifyExp (e, sm)
adamc@109:                               in
adamc@109:                                   (L'.DVal (x, n, t, e), sm)
adamc@109:                               end
adamc@29:         in
adamc@109:             (SOME (d, loc), NONE, sm)
adamc@29:         end
adamc@129:       | L.DValRec vis =>
adamc@129:         let
adamc@129:             val (vis, sm) = ListUtil.foldlMap
adamc@129:                             (fn ((x, n, t, e, _), sm) =>
adamc@129:                                 let                                    
adamc@129:                                     val (t, sm) = cifyTyp (t, sm)
adamc@129: 
adamc@129:                                     fun unravel (tAll as (t, _), eAll as (e, _)) =
adamc@129:                                         case (t, e) of
adamc@129:                                             (L'.TFun (dom, ran), L.EAbs (ax, _, _, e)) =>
adamc@129:                                             let
adamc@129:                                                 val (args, t, e) = unravel (ran, e)
adamc@129:                                             in
adamc@129:                                                 ((ax, dom) :: args, t, e)
adamc@129:                                             end
adamc@129:                                           | (L'.TFun _, _) =>
adamc@129:                                             (ErrorMsg.errorAt loc "Function isn't explicit at code generation";
adamc@129:                                              ([], tAll, eAll))
adamc@129:                                           | _ => ([], tAll, eAll)
adamc@129:                                                  
adamc@129:                                     val (args, ran, e) = unravel (t, e)
adamc@129:                                     val (e, sm) = cifyExp (e, sm)
adamc@129:                               in
adamc@129:                                   ((x, n, args, ran, e), sm)
adamc@129:                               end)
adamc@129:                             sm vis
adamc@129:         in
adamc@129:             (SOME (L'.DFunRec vis, loc), NONE, sm)
adamc@129:         end        
adamc@129: 
adamc@1104:       | L.DExport (ek, s, n, ts, t, b) =>
adamc@120:         let
adamc@120:             val (ts, sm) = ListUtil.foldlMap cifyTyp sm ts
adamc@609:             val (t, sm) = cifyTyp (t, sm)
adamc@120:         in
adamc@1104:             (NONE, SOME (ek, "/" ^ s, n, ts, t, L'.ServerAndPullAndPush, b), sm)
adamc@120:         end
adamc@29: 
adamc@707:       | L.DTable (s, xts, pe, ce) =>
adamc@273:         let
adamc@273:             val (xts, sm) = ListUtil.foldlMap (fn ((x, t), sm) =>
adamc@273:                                                   let
adamc@273:                                                       val (t, sm) = cifyTyp (t, sm)
adamc@273:                                                   in
adamc@273:                                                       ((x, t), sm)
adamc@273:                                                   end) sm xts
adamc@704: 
adamc@704:             fun flatten e =
adamc@704:                 case #1 e of
adamc@704:                     L.ERecord [] => []
adamc@704:                   | L.ERecord [(x, (L.EPrim (Prim.String v), _), _)] => [(x, v)]
adamc@704:                   | L.EStrcat (e1, e2) => flatten e1 @ flatten e2
adamc@704:                   | _ => (ErrorMsg.errorAt loc "Constraint has not been fully determined";
adamc@704:                           Print.prefaces "Undetermined constraint"
adamc@707:                                          [("e", MonoPrint.p_exp MonoEnv.empty e)];
adamc@704:                           [])
adamc@707: 
adamc@707:             val pe = case #1 pe of
adamc@707:                          L.EPrim (Prim.String s) => s
adamc@707:                        | _ => (ErrorMsg.errorAt loc "Primary key has not been fully determined";
adamc@707:                                Print.prefaces "Undetermined constraint"
adamc@707:                                               [("e", MonoPrint.p_exp MonoEnv.empty pe)];
adamc@707:                                "")
adamc@273:         in
adamc@707:             (SOME (L'.DTable (s, xts, pe, flatten ce), loc), NONE, sm)
adamc@273:         end
adamc@338:       | L.DSequence s =>
adamc@338:         (SOME (L'.DSequence s, loc), NONE, sm)
adamc@754:       | L.DView (s, xts, e) =>
adamc@754:         let
adamc@754:             val (xts, sm) = ListUtil.foldlMap (fn ((x, t), sm) =>
adamc@754:                                                   let
adamc@754:                                                       val (t, sm) = cifyTyp (t, sm)
adamc@754:                                                   in
adamc@754:                                                       ((x, t), sm)
adamc@754:                                                   end) sm xts
adamc@754: 
adamc@754:             fun flatten e =
adamc@754:                 case #1 e of
adamc@754:                     L.ERecord [] => []
adamc@754:                   | L.ERecord [(x, (L.EPrim (Prim.String v), _), _)] => [(x, v)]
adamc@754:                   | L.EStrcat (e1, e2) => flatten e1 @ flatten e2
adamc@754:                   | _ => (ErrorMsg.errorAt loc "Constraint has not been fully determined";
adamc@754:                           Print.prefaces "Undetermined constraint"
adamc@754:                                          [("e", MonoPrint.p_exp MonoEnv.empty e)];
adamc@754:                           [])
adamc@754: 
adamc@754:             val e = case #1 e of
adamc@754:                         L.EPrim (Prim.String s) => s
adamc@754:                       | _ => (ErrorMsg.errorAt loc "VIEW query has not been fully determined";
adamc@754:                               Print.prefaces "Undetermined VIEW query"
adamc@754:                                              [("e", MonoPrint.p_exp MonoEnv.empty e)];
adamc@754:                               "")
adamc@754:         in
adamc@754:             (SOME (L'.DView (s, xts, e), loc), NONE, sm)
adamc@754:         end
adamc@271:       | L.DDatabase s => (SOME (L'.DDatabase s, loc), NONE, sm)
adamc@569:       | L.DJavaScript s => (SOME (L'.DJavaScript s, loc), NONE, sm)
adamc@725:       | L.DCookie args => (SOME (L'.DCookie args, loc), NONE, sm)
adamc@718:       | L.DStyle args => (SOME (L'.DStyle args, loc), NONE, sm)
adamc@1075:       | L.DTask (e1, e2) =>
adamc@1075:         (case #1 e2 of
adam@1348:              L.EAbs (x1, _, _, (L.EAbs (x2, _, _, e), _)) =>
adamc@1073:              let
adamc@1075:                  val tk = case #1 e1 of
adamc@1075:                               L.EFfi ("Basis", "initialize") => L'.Initialize
adam@1348:                             | L.EFfi ("Basis", "clientLeaves") => L'.ClientLeaves
adam@1349:                             | L.EFfiApp ("Basis", "periodic", [(L.EPrim (Prim.Int n), _)]) => L'.Periodic n
adamc@1075:                             | _ => (ErrorMsg.errorAt loc "Task kind not fully determined";
adamc@1075:                                     L'.Initialize)
adamc@1073:                  val (e, sm) = cifyExp (e, sm)
adamc@1073:              in
adam@1348:                  (SOME (L'.DTask (tk, x1, x2, e), loc), NONE, sm)
adamc@1073:              end
adamc@1073:            | _ => (ErrorMsg.errorAt loc "Initializer has not been fully determined";
adamc@1073:                    (NONE, NONE, sm)))
adamc@1199:       | L.DPolicy _ => (NONE, NONE, sm)
adam@1294:       | L.DOnError n => (SOME (L'.DOnError n, loc), NONE, sm)
adamc@271: 
adamc@29: fun cjrize ds =
adamc@29:     let
adamc@196:         val (dsF, ds, ps, sm) = foldl (fn (d, (dsF, ds, ps, sm)) =>
adamc@196:                                           let
adamc@196:                                               val (dop, pop, sm) = cifyDecl (d, sm)
adamc@453: 
adamc@640:                                               val dsF = case dop of
adamc@809:                                                             SOME (L'.DDatatype dts, loc) =>
adamc@809:                                                             map (fn (dk, x, n, _) =>
adamc@809:                                                                     (L'.DDatatypeForward (dk, x, n), loc)) dts @ dsF
adamc@640:                                                           | _ => dsF
adamc@640: 
adamc@640:                                               val dsF = map (fn v => (L'.DStruct v, ErrorMsg.dummySpan)) (Sm.declares sm)
adamc@640:                                                         @ dsF
adamc@640: 
adamc@196:                                               val (dsF, ds) = case dop of
adamc@196:                                                                   NONE => (dsF, ds)
adamc@453:                                                                 | SOME (d as (L'.DDatatype _, loc)) =>
adamc@453:                                                                   (d :: dsF, ds)
adamc@196:                                                                 | SOME d => (dsF, d :: ds)
adamc@453: 
adamc@196:                                               val ps = case pop of
adamc@196:                                                            NONE => ps
adamc@196:                                                          | SOME p => p :: ps
adamc@196:                                           in
adamc@453:                                               (dsF, ds, ps, Sm.clearDeclares sm)
adamc@196:                                           end)
adamc@196:                                       ([], [], [], Sm.empty) ds
adamc@29:     in
adamc@453:         (List.revAppend (dsF, rev ds),
adamc@101:          ps)
adamc@29:     end
adamc@29: 
adamc@29: end