|
|
1.1 ! root 1: (* Copyright 1989 by AT&T Bell Laboratories *) ! 2: (* moduleComp.sml *) ! 3: (* Modules compiler for New Jersey ML. Nick Rothwell, LFCS, January 1989. *) ! 4: (* New version, doing proper lambda nesting for declarations and imports, ! 5: rather than the old clatty concatenation stuff. *) ! 6: ! 7: functor ModuleComp(structure Absyn: BAREABSYN ! 8: sharing Absyn = BareAbsyn ! 9: structure Lambda: LAMBDA ! 10: structure Opt: OPT sharing Opt.L = Lambda ! 11: structure Machm: CODEGENERATOR ! 12: ): MODULE_COMPILER = ! 13: struct ! 14: structure Lambda = Lambda ! 15: structure Absyn = Absyn ! 16: ! 17: val bug = ErrorMsg.impossible ! 18: ! 19: (* Warning: if DEBUG is true, then exportFn tends to grab the whole ! 20: compiler. --Appel *) ! 21: val DEBUG = false ! 22: ! 23: type lvar = Access.lvar ! 24: type lexp = Lambda.lexp ! 25: type code = string ! 26: ! 27: fun assert(msg, cond) = ! 28: if cond then () else bug("assert: " ^ msg) ! 29: ! 30: fun pr s = (output std_out s; flush_out std_out) ! 31: ! 32: fun debug s = if DEBUG then pr s else () ! 33: ! 34: ! 35: abstype LambDynModule = ! 36: LAMBDYNMODULE of {entry: Entry, lvars: lvar list} list ! 37: (* These are in reverse order of declaration. *) ! 38: and CodeDynModule = ! 39: CODEDYNMODULE of {self: code, subModules: CodeDynModule list} ! 40: (* The code is for a function: ! 41: "(M1, ..., Mn) -> looker -> array*rubbish" ! 42: where each Mi is a "looker -> array*rubbish" *) ! 43: ! 44: and Entry = LAMBDAentry of lexp->lexp (* unclosed *) ! 45: | IMPORTentry of CodeDynModule ! 46: with ! 47: val emptyDynModule = LAMBDYNMODULE [] ! 48: ! 49: exception AddDeclaration ! 50: fun addDeclaration(dec, lvars, LAMBDYNMODULE entries) = ! 51: let ! 52: val newEntry = ! 53: {entry=LAMBDAentry(Translate.transDec dec), lvars=rev lvars} ! 54: in ! 55: if !ErrorMsg.anyErrors then ! 56: raise AddDeclaration ! 57: else ! 58: LAMBDYNMODULE(newEntry :: entries) ! 59: end ! 60: ! 61: fun importDynModule(LAMBDYNMODULE inner, LAMBDYNMODULE outer) = ! 62: LAMBDYNMODULE(inner @ outer) ! 63: ! 64: fun abstractDynModule(codeDynModule, lvars) = ! 65: LAMBDYNMODULE [{entry=IMPORTentry codeDynModule, lvars=lvars}] ! 66: ! 67: (* compiler: takes a LambDynModule to a CodeDynModule. We tie together ! 68: all the lambdas as a set of nested LET declarations. Where we import ! 69: already-compiled modules, these are abstracted to be arguments to the ! 70: final lambda expression. *) ! 71: ! 72: fun inventLvar name = ! 73: let ! 74: val saving = !System.Control.saveLvarNames ! 75: val _ = (System.Control.saveLvarNames := true) ! 76: val lvar = Access.namedLvar(Symbol.symbol(name ^ ":")) ! 77: val _ = (System.Control.saveLvarNames := saving) ! 78: in ! 79: lvar ! 80: end ! 81: ! 82: (* Some local lambda-building stuff. This should probably go in a wee ! 83: structure of its own. *) ! 84: ! 85: local ! 86: open Lambda ! 87: in ! 88: fun apply(lvar1, lvar2) = APP(VAR lvar1, VAR lvar2) ! 89: ! 90: fun let_1(lvar, exp1, exp2) = APP(FN(lvar, exp2), exp1) ! 91: ! 92: fun fn_N(name, lvars, exp) = ! 93: let ! 94: val vecLvar = inventLvar name ! 95: val vecExp = VAR vecLvar ! 96: fun doit(lv :: rest, n) = ! 97: let_1(lv, SELECT(n, vecExp), doit(rest, n+1)) ! 98: | doit(nil, _) = exp ! 99: in ! 100: FN(vecLvar, doit(lvars, 0)) ! 101: end ! 102: ! 103: fun let_N(name, lvars, exp1, exp2) = ! 104: APP(fn_N(name, lvars, exp2), exp1) ! 105: ! 106: fun record lvars = RECORD(map VAR lvars) ! 107: end ! 108: ! 109: (* foldLambda: takes a list of entries (assumed to be in same order ! 110: as the actual module declarations), and generates one big lambda. ! 111: We close it later. foldLambda returns ! 112: {lambda, imports, importLvars}. *) ! 113: ! 114: fun foldLambda({entry=LAMBDAentry thisFn, lvars} :: rest, ! 115: looker, allVars ! 116: ) = ! 117: let ! 118: val {lambda=next, imports, importLvars} = ! 119: foldLambda(rest, looker, lvars @ allVars) ! 120: in ! 121: {lambda=thisFn next, (* apply this fn->lambda to the ! 122: argument (that's how transDec ! 123: works...) *) ! 124: imports=imports, ! 125: importLvars=importLvars ! 126: } ! 127: end ! 128: ! 129: | foldLambda({entry=IMPORTentry subMod, lvars} :: rest, ! 130: looker, allVars ! 131: ) = ! 132: let ! 133: val modLvar = ! 134: inventLvar("importModule/" ^ makestring(length rest)) ! 135: val {lambda=next, imports, importLvars} = ! 136: foldLambda(rest, looker, lvars @ allVars) ! 137: in ! 138: {lambda=let_N("importEntry", lvars, apply(modLvar,looker), next), ! 139: imports=subMod :: imports, ! 140: importLvars = modLvar :: importLvars ! 141: } ! 142: end ! 143: ! 144: | foldLambda(nil, _, allVars) = ! 145: {lambda=record(rev allVars), imports=nil, importLvars=nil} ! 146: (* Make sure the lvars comprising ! 147: the eventual record are the ! 148: right way round!! *) ! 149: ! 150: (* codegen compiles a lambda to a machine-code string. *) ! 151: ! 152: exception Codegen ! 153: fun codegen lambda: string = ! 154: let ! 155: val _ = debug "codegen..."; ! 156: val executable = Machm.generate lambda ! 157: val _ = debug("done (" ^ makestring(size executable) ^ ").\n"); ! 158: in ! 159: if !ErrorMsg.anyErrors then raise Codegen else executable ! 160: end ! 161: ! 162: fun spaces n = ! 163: let ! 164: fun spaces'(0, sp) = debug sp ! 165: | spaces'(n, sp) = spaces'(n-1, " " ^ sp) ! 166: in ! 167: spaces'(n, "") ! 168: end ! 169: ! 170: fun printCodeDynModule indent (CODEDYNMODULE{self, subModules}) = ! 171: (spaces indent; ! 172: debug("CodeDynModule, self=[..." ^ makestring(size self) ^ "...]\n"); ! 173: spaces indent; ! 174: debug "sub-modules=(\n"; ! 175: app (printCodeDynModule(indent+3)) subModules; ! 176: spaces indent; ! 177: debug ")\n" ! 178: ) ! 179: ! 180: val printNums = app (fn i: int => debug(makestring i ^ " ")) ! 181: ! 182: fun printLambEntry{entry=LAMBDAentry lexpFn, lvars} = ! 183: (debug "*LAMBDA*\n"; ! 184: MCprint.printLexp(lexpFn(record nil)); ! 185: debug ";\n lvars=[ "; ! 186: printNums lvars; ! 187: debug "].\n" ! 188: ) ! 189: | printLambEntry{entry=IMPORTentry dyn, lvars} = ! 190: (debug "*IMPORT*\n"; ! 191: printCodeDynModule 6 dyn; ! 192: debug " lvars=[ "; ! 193: printNums lvars; ! 194: debug "].\n" ! 195: ) ! 196: ! 197: exception CompileDynModule ! 198: fun compileDynModule opt (LAMBDYNMODULE entries): CodeDynModule = ! 199: let ! 200: val _ = ! 201: if DEBUG then (debug "compileDynModule:\n"; ! 202: app printLambEntry entries ! 203: ) ! 204: else () ! 205: ! 206: val looker = inventLvar "looker" ! 207: ! 208: val {lambda=openLambda, imports, importLvars} = ! 209: foldLambda(rev entries, looker, nil) ! 210: (* reverse "entries" because a LambDynModule has the most ! 211: recent declaration at the front, and we want to nest the ! 212: lambda with the old stuff outermost - as well as get the ! 213: correct ordering of the lvars in the final result. *) ! 214: ! 215: val _ = if !ErrorMsg.anyErrors then raise CompileDynModule else () ! 216: (* Just check for any errors during last part of transDec. *) ! 217: ! 218: val closedLambda = ! 219: Opt.bareCloseTop{lambda=openLambda, ! 220: looker=looker, ! 221: extras=ProcessFile.getCore(), ! 222: keepFree=looker :: importLvars ! 223: } ! 224: (* Close the lambda, using the already-generated looker lvar - ! 225: this had to be generated in advance, since each imported ! 226: module is activated as M(looker). We DON'T want to close ! 227: with respect to the modLvars, since we're just about to ! 228: lambda-bind these. Keep the looker's lvar free as well, ! 229: otherwise it tries to find itself... Gnnnh! *) ! 230: ! 231: val finalLambda = ! 232: fn_N("imports", importLvars, closedLambda) ! 233: (* That's what we want: "fn (M1, ..., Mn) => fn looker => ..." ! 234: where the Mi's we apply to are each a "fn looker => ...". ! 235: In fact, I suspect that "imports" and "importLvars" are ! 236: both in reverse order, but as long as they're ! 237: coherent... *) ! 238: ! 239: val _ = ! 240: if DEBUG then (debug "Final (unopt) lambda:\n"; ! 241: MCprint.printLexp finalLambda; ! 242: debug ".\n" ! 243: ) ! 244: else () ! 245: ! 246: val optLambda = opt finalLambda ! 247: ! 248: val code = ! 249: codegen optLambda ! 250: handle Codegen => raise CompileDynModule ! 251: in ! 252: CODEDYNMODULE{self=code, subModules=imports} ! 253: end ! 254: ! 255: (* primeDynModule: returns a "fn lookup => ...result...". If the module ! 256: doesn't import anything, then we just apply the code to NIL. If the ! 257: module imports M1...Mn, then we prime these, and build an array of ! 258: them. *) ! 259: ! 260: type object = System.Unsafe.object ! 261: type looker = lvar -> object ! 262: type result = object array ! 263: type module = looker -> result ! 264: ! 265: fun primeDynModule(CODEDYNMODULE{self, subModules}): module = ! 266: let ! 267: val me: module array -> looker -> result = ! 268: System.Unsafe.boot self ! 269: ! 270: val subModules: module array = ! 271: arrayoflist(map primeDynModule subModules) ! 272: in ! 273: me subModules ! 274: end ! 275: ! 276: fun debugLooker looker = ! 277: fn lvar: int => (debug("[looker(" ^ makestring lvar ^ ")]\n"); ! 278: looker lvar ! 279: ) ! 280: ! 281: fun executeDynModule codeDynModule looker: object array = ! 282: let ! 283: val _ = debug "priming... " ! 284: val primed = primeDynModule codeDynModule ! 285: val _ = debug "executing... " ! 286: val result = primed(if DEBUG then debugLooker looker else looker) ! 287: in ! 288: debug "done\n"; ! 289: result ! 290: end ! 291: end ! 292: end;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.