adam@1848: (* Copyright (c) 2008-2010, 2013, Adam Chlipala adamc@23: * All rights reserved. adamc@23: * adamc@23: * Redistribution and use in source and binary forms, with or without adamc@23: * modification, are permitted provided that the following conditions are met: adamc@23: * adamc@23: * - Redistributions of source code must retain the above copyright notice, adamc@23: * this list of conditions and the following disclaimer. adamc@23: * - Redistributions in binary form must reproduce the above copyright notice, adamc@23: * this list of conditions and the following disclaimer in the documentation adamc@23: * and/or other materials provided with the distribution. adamc@23: * - The names of contributors may not be used to endorse or promote products adamc@23: * derived from this software without specific prior written permission. adamc@23: * adamc@23: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" adamc@23: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE adamc@23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE adamc@23: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE adamc@23: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR adamc@23: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF adamc@23: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS adamc@23: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN adamc@23: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) adamc@23: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE adamc@23: * POSSIBILITY OF SUCH DAMAGE. adamc@23: *) adamc@23: adamc@23: (* Remove unused definitions from a file *) adamc@23: adamc@23: structure Shake :> SHAKE = struct adamc@23: adamc@1112: val sliceDb = ref false adamc@1112: adamc@23: open Core adamc@23: adamc@23: structure U = CoreUtil adamc@23: adamc@23: structure IS = IntBinarySet adamc@23: structure IM = IntBinaryMap adamc@23: adamc@23: type free = { adamc@23: con : IS.set, adamc@23: exp : IS.set adamc@23: } adamc@23: adamc@338: val dummyt = (TRecord (CRecord ((KType, ErrorMsg.dummySpan), []), ErrorMsg.dummySpan), ErrorMsg.dummySpan) adam@2048: val dummye = (EPrim (Prim.String (Prim.Normal, "")), ErrorMsg.dummySpan) adamc@247: adamc@1060: fun tupleC cs = (CTuple cs, ErrorMsg.dummySpan) adamc@1060: fun tupleE es = (ERecord (map (fn e => (dummyt, e, dummyt)) es), ErrorMsg.dummySpan) adamc@1060: adamc@23: fun shake file = adamc@100: let adamc@1060: val usedVarsC = U.Con.fold {kind = fn (_, st) => st, adamc@1060: con = fn (c, cs) => adamc@1060: case c of adamc@1060: CNamed n => IS.add (cs, n) adamc@1060: | _ => cs} adamc@1060: adamc@704: val usedVars = U.Exp.fold {kind = fn (_, st) => st, adamc@704: con = fn (c, st as (es, cs)) => adamc@704: case c of adamc@704: CNamed n => (es, IS.add (cs, n)) adamc@704: | _ => st, adamc@704: exp = fn (e, st as (es, cs)) => adamc@704: case e of adamc@704: ENamed n => (IS.add (es, n), cs) adamc@704: | _ => st} adamc@704: adamc@1060: val (usedE, usedC) = adamc@248: List.foldl adamc@1112: (fn ((DExport (_, n, _), _), st as (usedE, usedC)) => adamc@1112: if !sliceDb then adamc@1112: st adamc@1112: else adamc@1112: (IS.add (usedE, n), usedC) adamc@1060: | ((DTable (_, _, c, _, pe, pc, ce, cc), _), (usedE, usedC)) => adamc@704: let adamc@1060: val usedC = usedVarsC usedC c adamc@1060: val usedC = usedVarsC usedC pc adamc@1060: val usedC = usedVarsC usedC cc adamc@1060: adamc@707: val (usedE, usedC) = usedVars (usedE, usedC) pe adamc@707: val (usedE, usedC) = usedVars (usedE, usedC) ce adamc@704: in adamc@1060: (usedE, usedC) adamc@704: end adamc@1265: | ((DView (_, _, _, e, c), _), (usedE, usedC)) => adamc@1265: let adamc@1265: val usedC = usedVarsC usedC c adamc@1265: in adamc@1265: usedVars (usedE, usedC) e adamc@1265: end adamc@1112: | ((DTask (e1, e2), _), st) => adamc@1112: if !sliceDb then adamc@1112: st adamc@1112: else adamc@1112: usedVars (usedVars st e1) e2 adamc@1199: | ((DPolicy e1, _), st) => adamc@1199: if !sliceDb then adamc@1199: st adamc@1199: else adamc@1199: usedVars st e1 adam@1294: | ((DOnError n, _), st as (usedE, usedC)) => adam@1294: if !sliceDb then adam@1294: st adam@1294: else adam@1294: (IS.add (usedE, n), usedC) adamc@1060: | (_, acc) => acc) (IS.empty, IS.empty) file adamc@23: adamc@163: val (cdef, edef) = foldl (fn ((DCon (_, n, _, c), _), (cdef, edef)) => (IM.insert (cdef, n, [c]), edef) adamc@807: | ((DDatatype dts, _), (cdef, edef)) => adamc@807: (foldl (fn ((_, n, _, xncs), cdef) => adamc@807: IM.insert (cdef, n, List.mapPartial #3 xncs)) cdef dts, edef) adamc@453: | ((DVal (_, n, t, e, _), _), (cdef, edef)) => (cdef, IM.insert (edef, n, ([], t, e))) adamc@125: | ((DValRec vis, _), (cdef, edef)) => adamc@453: let adamc@453: val all_ns = map (fn (_, n, _, _, _) => n) vis adamc@453: in adamc@453: (cdef, foldl (fn ((_, n, t, e, _), edef) => adamc@453: IM.insert (edef, n, (all_ns, t, e))) edef vis) adamc@453: end adamc@247: | ((DExport _, _), acc) => acc adamc@1060: | ((DTable (_, n, c, _, e1, c1, e2, c2), _), (cdef, edef)) => adamc@1060: (cdef, IM.insert (edef, n, ([], tupleC [c, c1, c2], tupleE [e1, e2]))) adamc@338: | ((DSequence (_, n, _), _), (cdef, edef)) => adamc@453: (cdef, IM.insert (edef, n, ([], dummyt, dummye))) adamc@754: | ((DView (_, n, _, _, c), _), (cdef, edef)) => adamc@754: (cdef, IM.insert (edef, n, ([], c, dummye))) adamc@461: | ((DDatabase _, _), acc) => acc adamc@461: | ((DCookie (_, n, c, _), _), (cdef, edef)) => adamc@718: (cdef, IM.insert (edef, n, ([], c, dummye))) adamc@720: | ((DStyle (_, n, _), _), (cdef, edef)) => adamc@1073: (cdef, IM.insert (edef, n, ([], dummyt, dummye))) adamc@1199: | ((DTask _, _), acc) => acc adam@1294: | ((DPolicy _, _), acc) => acc adam@1294: | ((DOnError _, _), acc) => acc) adamc@100: (IM.empty, IM.empty) file adamc@23: adamc@100: fun kind (_, s) = s adamc@23: adamc@100: fun con (c, s) = adamc@100: case c of adamc@100: CNamed n => adamc@100: if IS.member (#con s, n) then adamc@100: s adamc@100: else adamc@100: let adamc@100: val s' = {con = IS.add (#con s, n), adamc@100: exp = #exp s} adamc@100: in adamc@100: case IM.find (cdef, n) of adamc@100: NONE => s' adamc@163: | SOME cs => foldl (fn (c, s') => shakeCon s' c) s' cs adamc@100: end adamc@100: | _ => s adamc@23: adamc@100: and shakeCon s = U.Con.fold {kind = kind, con = con} s adamc@23: adamc@1080: (*val () = print "=====\nSHAKE\n=====\n" adamc@1080: val current = ref 0*) adamc@1080: adamc@100: fun exp (e, s) = adamc@607: let adamc@607: fun check n = adamc@607: if IS.member (#exp s, n) then adamc@607: s adamc@607: else adamc@607: let adamc@607: val s' = {exp = IS.add (#exp s, n), adamc@607: con = #con s} adamc@607: in adamc@1080: (*print ("Need " ^ Int.toString n ^ " <-- " ^ Int.toString (!current) ^ "\n");*) adamc@607: case IM.find (edef, n) of adamc@607: NONE => s' adamc@607: | SOME (ns, t, e) => adamc@607: let adamc@1080: (*val old = !current adamc@1080: val () = current := n*) adamc@607: val s' = shakeExp (shakeCon s' t) e adamc@607: in adamc@1080: (*current := old;*) adamc@607: foldl (fn (n, s') => exp (ENamed n, s')) s' ns adamc@607: end adamc@607: end adamc@607: in adamc@607: case e of adamc@607: ENamed n => check n adam@1848: | EServerCall (n, _, _, _) => check n adamc@607: | _ => s adamc@607: end adamc@23: adamc@100: and shakeExp s = U.Exp.fold {kind = kind, con = con, exp = exp} s adamc@100: adamc@704: val s = {con = usedC, exp = usedE} adamc@109: adamc@704: val s = IS.foldl (fn (n, s) => adamc@704: case IM.find (edef, n) of adamc@704: NONE => raise Fail "Shake: Couldn't find 'val'" adamc@704: | SOME (ns, t, e) => adamc@704: let adamc@1080: (*val () = current := n*) adamc@704: val s = shakeExp (shakeCon s t) e adamc@704: in adamc@704: foldl (fn (n, s) => exp (ENamed n, s)) s ns adamc@704: end) s usedE adamc@248: adamc@1060: val s = IS.foldl (fn (n, s) => adamc@1060: case IM.find (cdef, n) of adamc@1062: NONE => raise Fail ("Shake: Couldn't find 'con' " ^ Int.toString n) adamc@1060: | SOME cs => foldl (fn (c, s) => shakeCon s c) s cs) s usedC adamc@100: in adamc@100: List.filter (fn (DCon (_, n, _, _), _) => IS.member (#con s, n) adamc@807: | (DDatatype dts, _) => List.exists (fn (_, n, _, _) => IS.member (#con s, n)) dts adamc@109: | (DVal (_, n, _, _, _), _) => IS.member (#exp s, n) adamc@125: | (DValRec vis, _) => List.exists (fn (_, n, _, _, _) => IS.member (#exp s, n)) vis adamc@1112: | (DExport _, _) => not (!sliceDb) adamc@754: | (DView _, _) => true adamc@754: | (DSequence _, _) => true adamc@271: | (DTable _, _) => true adamc@1112: | (DDatabase _, _) => not (!sliceDb) adamc@1112: | (DCookie _, _) => not (!sliceDb) adamc@1112: | (DStyle _, _) => not (!sliceDb) adamc@1199: | (DTask _, _) => not (!sliceDb) adam@1294: | (DPolicy _, _) => not (!sliceDb) adam@1294: | (DOnError _, _) => not (!sliceDb)) file adamc@100: end adamc@23: adamc@23: end