1(* 2 Copyright (c) 2013-2015, 2020 David C.J. Matthews 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Lesser General Public 6 License version 2.1 as published by the Free Software Foundation. 7 8 This library is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public 14 License along with this library; if not, write to the Free Software 15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 16*) 17 18(* 19 Derived from the original parse-tree 20 21 Copyright (c) 2000 22 Cambridge University Technical Services Limited 23 24 Title: Parse Tree Structure and Operations. 25 Author: Dave Matthews, Cambridge University Computer Laboratory 26 Copyright Cambridge University 1985 27 28*) 29 30functor CODEGEN_PARSETREE ( 31 structure BASEPARSETREE : BaseParseTreeSig 32 structure PRINTTREE: PrintParsetreeSig 33 structure EXPORTTREE: ExportParsetreeSig 34 structure MATCHCOMPILER: MatchCompilerSig 35 structure LEX : LEXSIG 36 structure CODETREE : CODETREESIG 37 structure DEBUGGER : DEBUGGER 38 structure TYPETREE : TYPETREESIG 39 structure TYPEIDCODE: TYPEIDCODESIG 40 structure STRUCTVALS : STRUCTVALSIG 41 structure VALUEOPS : VALUEOPSSIG 42 structure DATATYPEREP: DATATYPEREPSIG 43 structure DEBUG: DEBUG 44 45 structure MISC : 46 sig 47 (* These are handled in the compiler *) 48 exception Conversion of string (* string to int conversion failure *) 49 50 (* This isn't handled at all (except generically) *) 51 exception InternalError of string (* compiler error *) 52 end 53 54 structure ADDRESS : AddressSig 55 56 sharing BASEPARSETREE.Sharing 57 = PRINTTREE.Sharing 58 = EXPORTTREE.Sharing 59 = MATCHCOMPILER.Sharing 60 = LEX.Sharing 61 = CODETREE.Sharing 62 = DEBUGGER.Sharing 63 = TYPETREE.Sharing 64 = TYPEIDCODE.Sharing 65 = STRUCTVALS.Sharing 66 = VALUEOPS.Sharing 67 = DATATYPEREP.Sharing 68 = ADDRESS 69): CodegenParsetreeSig = 70struct 71 open BASEPARSETREE 72 open PRINTTREE 73 open EXPORTTREE 74 open MATCHCOMPILER 75 open CODETREE 76 open TYPEIDCODE 77 open LEX 78 open TYPETREE 79 open DEBUG 80 open STRUCTVALS 81 open VALUEOPS 82 open MISC 83 open DATATYPEREP 84 open TypeVarMap 85 open DEBUGGER 86 87 datatype environEntry = datatype DEBUGGER.environEntry 88 89 (* To simplify passing the context it is wrapped up in this type. *) 90 type cgContext = 91 { 92 decName: string, debugEnv: debuggerStatus, mkAddr: int->int, 93 level: level, typeVarMap: typeVarMap, lex: lexan, lastDebugLine: int ref, 94 isOuterLevel: bool (* Used only to decide if we need to report non-exhaustive matches. *) 95 } 96 97 fun repDecName decName ({debugEnv, mkAddr, level, typeVarMap, lex, lastDebugLine, isOuterLevel, ...}: cgContext) = 98 { debugEnv=debugEnv, mkAddr=mkAddr, level=level, typeVarMap=typeVarMap, 99 decName=decName, lex=lex, lastDebugLine=lastDebugLine, isOuterLevel = isOuterLevel}: cgContext 100 and repDebugEnv debugEnv ({decName, mkAddr, level, typeVarMap, lex, lastDebugLine, isOuterLevel, ...}: cgContext) = 101 { debugEnv=debugEnv, mkAddr=mkAddr, level=level, typeVarMap=typeVarMap, 102 decName=decName, lex=lex, lastDebugLine=lastDebugLine, isOuterLevel = isOuterLevel}: cgContext 103 and repTypeVarMap typeVarMap ({decName, debugEnv, mkAddr, level, lex, lastDebugLine, isOuterLevel, ...}: cgContext) = 104 { debugEnv=debugEnv, mkAddr=mkAddr, level=level, typeVarMap=typeVarMap, 105 decName=decName, lex=lex, lastDebugLine=lastDebugLine, isOuterLevel = isOuterLevel}: cgContext 106 (* Create a new level. Sets isOuterLevel to false. *) 107 and repNewLevel(decName, mkAddr, level) ({debugEnv, lex, lastDebugLine, typeVarMap, ...}: cgContext) = 108 { debugEnv=debugEnv, mkAddr=mkAddr, level=level, typeVarMap=typeVarMap, 109 decName=decName, lex=lex, lastDebugLine=lastDebugLine, isOuterLevel = false}: cgContext 110 111 (* Try this pipeline function *) 112 infix |> 113 fun a |> f = f a 114 115 val singleArg = mkLoadArgument 0 116 117 (* Make a tuple out of a set of arguments or return the single 118 argument if there is just one. *) 119 fun mkArgTuple(from, nTuple) = 120 if nTuple = 1 (* "tuple" is a singleton *) 121 then mkLoadArgument from 122 else if nTuple <= 0 then raise InternalError "mkArgTuple" 123 else mkTuple(List.tabulate(nTuple, fn n => mkLoadArgument(n+from))) 124 125 (* Load args by selecting from a tuple. *) 126 fun loadArgsFromTuple([t], arg) = [(arg, t)](* "tuple" is a singleton *) 127 | loadArgsFromTuple(types, arg) = 128 ListPair.zip(List.tabulate(List.length types, fn num => mkInd (num, arg)), types) 129 130 (* Return the argument/result type which is currently just floating point or everything else. *) 131 fun getCodeArgType t = 132 case isFloatingPt t of 133 NONE => GeneralType 134 | SOME FloatDouble => DoubleFloatType 135 | SOME FloatSingle => SingleFloatType 136 137 (* tupleWidth returns the width of a tuple or record or 1 if it 138 isn't one. It is used to detect both argument tuples and results. 139 When used for arguments the idea is that frequently a tuple is 140 used as a way of passing multiple arguments and these can be 141 passed on the stack. When used for results the idea is to 142 create the result tuple on the stack and avoid garbage collector 143 and allocator time. If we could tell that the caller was simply going 144 to explode it we would gain but if the caller needed a 145 tuple on the heap we wouldn't. We wouldn't actually lose 146 if we were going to create a tuple and return it but we 147 would lose if we exploded a tuple here and then created 148 a new one in the caller. 149 This version of the code assumes that if we create a tuple 150 on one branch we're going to create one on others which may 151 not be correct. *) 152 (* This now returns the argument type for each entry so returns a list rather 153 than a number. *) 154 fun tupleWidth(TupleTree{expType=ref expType, ...}) = recordFieldMap getCodeArgType expType 155 156 | tupleWidth(Labelled{expType=ref expType, ...}) = 157 if recordNotFrozen expType (* An error, but reported elsewhere. *) 158 then [GeneralType] (* Safe enough *) 159 else recordFieldMap getCodeArgType expType 160 161 | tupleWidth(Cond{thenpt, elsept, ...}) = 162 ( 163 case tupleWidth thenpt of 164 [_] => tupleWidth elsept 165 | w => w 166 ) 167 168 | tupleWidth(Constraint{value, ...}) = tupleWidth value 169 170 | tupleWidth(HandleTree{exp, ...}) = 171 (* Look only at the expression and ignore 172 the handlers on the, possibly erroneous, 173 assumption that they won't normally be 174 executed. *) 175 tupleWidth exp 176 177 | tupleWidth(Localdec{body=[], ...}) = raise InternalError "tupleWidth: empty localdec" 178 179 | tupleWidth(Localdec{body, ...}) = 180 (* We are only interested in the last expression. *) 181 tupleWidth(#1 (List.last body)) 182 183 | tupleWidth(Case{match, ...}) = 184 let 185 fun getWidth(MatchTree{exp, ...}) = tupleWidth exp 186 in 187 List.foldl(fn(v, [_]) => getWidth v | (_, s) => s) 188 [GeneralType] match 189 end 190 191 | tupleWidth(Parenthesised(p, _)) = tupleWidth p 192 193 | tupleWidth(ExpSeq(p, _)) = tupleWidth(#1 (List.last p)) 194 195 | tupleWidth(Ident{ expType=ref expType, ...}) = [getCodeArgType expType] 196 197 | tupleWidth(Literal{ expType=ref expType, ...}) = [getCodeArgType expType] 198 199 | tupleWidth(Applic{ expType=ref expType, ...}) = [getCodeArgType expType] 200 201 | tupleWidth _ = [GeneralType] 202 203 (* Start of the code-generator itself. *) 204 205 (* Report unreferenced identifiers. *) 206 207 fun reportUnreferencedValue lex 208 (Value{name, references=SOME{exportedRef=ref false, localRef=ref nil, ...}, locations, ...}) = 209 let 210 fun getDeclLoc (DeclaredAt loc :: _) = loc 211 | getDeclLoc (_ :: locs) = getDeclLoc locs 212 | getDeclLoc [] = nullLocation (* Shouldn't happen. *) 213 in 214 warningMessage(lex, getDeclLoc locations, 215 "Value identifier ("^name^") has not been referenced.") 216 end 217 | reportUnreferencedValue _ _ = () 218 219 (* Process a list of possibly mutually recursive functions and identify those that 220 are really referenced. *) 221 fun reportUnreferencedValues(valList, lex) = 222 let 223 fun checkRefs valList = 224 let 225 fun unReferenced(Value{references=SOME{exportedRef=ref false, localRef=ref nil, ...}, ...}) = true 226 | unReferenced _ = false 227 val (unrefed, refed) = List.partition unReferenced valList 228 fun update(Value{references=SOME{localRef, recursiveRef, ...}, ...}, changed) = 229 let 230 (* If it is referred to by a referenced function it is referenced. *) 231 fun inReferenced(_, refName) = List.exists (fn Value{name, ...} => name=refName) refed 232 val (present, absent) = List.partition inReferenced (!recursiveRef) 233 in 234 if null present 235 then changed 236 else 237 ( 238 localRef := List.map #1 present @ ! localRef; 239 recursiveRef := absent; 240 true 241 ) 242 end 243 | update(_, changed) = changed 244 in 245 (* Repeat until there's no change. *) 246 if List.foldl update false unrefed then checkRefs unrefed else () 247 end 248 in 249 checkRefs valList; 250 List.app (reportUnreferencedValue lex) valList 251 end 252 253 fun makeDebugEntries (vars: values list, {debugEnv, level, typeVarMap, lex, mkAddr, ...}: cgContext) = 254 let 255 val (code, newDebug) = 256 DEBUGGER.makeValDebugEntries(vars, debugEnv, level, lex, mkAddr, typeVarMap) 257 in 258 (code, newDebug) 259 end 260 261 (* Add a breakpoint if debugging is enabled. The bpt argument is set in 262 the parsetree so that it can be found by the IDE. *) 263 fun addBreakPointCall(bpt, location, {mkAddr, level, lex, debugEnv, ...}) = 264 let 265 open DEBUGGER 266 val (lineCode, newStatus) = updateDebugLocation(debugEnv, location, lex) 267 val code = breakPointCode(bpt, location, level, lex, mkAddr) 268 in 269 (lineCode @ code, newStatus) 270 end 271 272 (* In order to build a call stack in the debugger we need to know about 273 function entry and exit. *) 274 fun wrapFunctionInDebug(codeBody, name, argCode, argType, restype, location, {debugEnv, mkAddr, level, lex, ...}) = 275 DEBUGGER.wrapFunctionInDebug(codeBody, name, argCode, argType, restype, location, debugEnv, level, lex, mkAddr) 276 277 (* Create an entry in the static environment for the function. *) 278(* fun debugFunctionEntryCode(name, argCode, argType, location, {debugEnv, mkAddr, level, lex, ...}) = 279 DEBUGGER.debugFunctionEntryCode(name, argCode, argType, location, debugEnv, level, lex, mkAddr)*) 280 281 (* Find all the variables declared by each pattern. *) 282 fun getVariablesInPatt (Ident {value = ref ident, ...}, varl) = 283 (* Ignore constructors *) 284 if isConstructor ident then varl else ident :: varl 285 | getVariablesInPatt(TupleTree{fields, ...}, varl) = List.foldl getVariablesInPatt varl fields 286 | getVariablesInPatt(Labelled {recList, ...}, varl) = 287 List.foldl (fn ({valOrPat, ...}, vl) => getVariablesInPatt(valOrPat, vl)) varl recList 288 (* Application of a constructor: only the argument 289 can contain vars. *) 290 | getVariablesInPatt(Applic {arg, ...}, varl) = getVariablesInPatt (arg, varl) 291 | getVariablesInPatt(List{elements, ...}, varl) = List.foldl getVariablesInPatt varl elements 292 | getVariablesInPatt(Constraint {value, ...}, varl) = getVariablesInPatt(value, varl) 293 | getVariablesInPatt(Layered {var, pattern, ...}, varl) = 294 (* There may be a constraint on the variable 295 so it is easiest to recurse. *) 296 getVariablesInPatt(pattern, getVariablesInPatt(var, varl)) 297 | getVariablesInPatt(Parenthesised(p, _), varl) = getVariablesInPatt(p, varl) 298 | getVariablesInPatt(_, varl) = varl (* constants and error cases. *); 299 300 (* If we are only passing equality types filter out the others. *) 301 val filterTypeVars = List.filter (fn tv => not justForEqualityTypes orelse tvEquality tv) 302 303 304 fun codeMatch(near, alt : matchtree list, arg, 305 isHandlerMatch, matchContext as { level, mkAddr, lex, typeVarMap, ...}): codetree = 306 let 307 val noOfPats = length alt 308 (* Check for unreferenced variables. *) 309 val () = 310 if getParameter reportUnreferencedIdsTag (debugParams lex) 311 then 312 let 313 fun getVars(MatchTree{vars, ...}, l) = getVariablesInPatt(vars, l) 314 val allVars = List.foldl getVars [] alt 315 in 316 List.app (reportUnreferencedValue lex) allVars 317 end 318 else () 319 320 val lineNo = 321 case alt of 322 MatchTree {location, ... } :: _ => location 323 | _ => raise Match 324 325 (* Save the argument in a variable. *) 326 val decCode = multipleUses (arg, fn () => mkAddr 1, level); 327 328 (* Generate code to load it. *) 329 val loadExpCode = #load decCode level; 330 331 (* Generate a range of addresses for any functions that have to 332 be generated for the expressions. *) 333 val baseAddr = mkAddr noOfPats 334 335 (* We want to avoid the code blowing up if we have a large expression which occurs 336 multiple times in the resulting code. 337 e.g. case x of [1,2,3,4] => exp1 | _ => exp2 338 Here exp2 will be called at several points in the code. Most patterns occur 339 only once, sometimes a few more times. The first three times the pattern 340 occurs the code is inserted directly. Further cases are dealt with as 341 function calls. *) 342 val insertDirectCount = 3 (* First three cases are inserted directly. *) 343 344 (* Make an array to count the number of references to a pattern. 345 This is used to decide whether to use a function for certain 346 expressions or to make it inline. *) 347 val uses = IntArray.array (noOfPats, 0); 348 349 (* Called when a selection has been made to code-generate the expression. *) 350 fun codePatternExpression pattChosenIndex = 351 let 352 val context = matchContext 353 (* Increment the count for this pattern. *) 354 val useCount = IntArray.sub(uses, pattChosenIndex) + 1 355 val () = IntArray.update (uses, pattChosenIndex, useCount) 356 val MatchTree {vars, exp, breakPoint, ... } = List.nth(alt, pattChosenIndex) 357 in 358 if useCount <= insertDirectCount 359 then (* Use the expression directly *) 360 let 361 (* If debugging add debug entries for the variables then put in a break-point. *) 362 val vl = getVariablesInPatt(vars, []) 363 val (envDec, varDebugEnv) = makeDebugEntries(vl, context) 364 val (bptCode, bptEnv) = 365 addBreakPointCall(breakPoint, getLocation exp, context |> repDebugEnv varDebugEnv) 366 in 367 mkEnv(envDec @ bptCode, codegen (exp, context |> repDebugEnv bptEnv)) 368 end 369 else 370 let (* Put in a call to the expression as a function. *) 371 val thisVars = getVariablesInPatt(vars, []) 372 (* Make an argument list from the variables bound in the pattern. *) 373 fun makeArg(Value{access=Local{addr=ref lvAddr, ...}, ...}) = 374 mkLoadLocal lvAddr 375 | makeArg _ = raise InternalError "makeArg" 376 val argsForCall = List.map makeArg thisVars 377 in 378 mkEval(mkLoadLocal (baseAddr + pattChosenIndex), argsForCall) 379 end 380 end 381 382 (* Generate the code and also check for redundancy 383 and exhaustiveness. *) 384 local 385 val cmContext = 386 { mkAddr = mkAddr, level = level, typeVarMap = typeVarMap, lex = lex } 387 in 388 val (matchCode, exhaustive) = 389 codeMatchPatterns(alt, loadExpCode, isHandlerMatch, lineNo, codePatternExpression, cmContext) 390 end 391 392 (* Report inexhaustiveness if necessary. TODO: It would be nice to have 393 some example of a pattern that isn't matched for. *) 394 (* If this is a handler we may have set the option to report exhaustiveness. 395 This helps in tracking down handlers that don't treat Interrupt specially. *) 396 val () = 397 if exhaustive 398 then if isHandlerMatch andalso getParameter reportExhaustiveHandlersTag (debugParams lex) 399 then errorNear (lex, false, near, lineNo, "Handler catches all exceptions.") 400 else () 401 else if isHandlerMatch 402 then () 403 else errorNear (lex, false, near, lineNo, "Matches are not exhaustive.") 404 (* Report redundant patterns. *) 405 local 406 fun reportRedundant(patNo, 0) = 407 let 408 val MatchTree {location, ... } = List.nth(alt, patNo) 409 in 410 errorNear (lex, false, near, location, 411 "Pattern " ^ Int.toString (patNo+1) ^ " is redundant.") 412 end 413 | reportRedundant _ = () 414 in 415 val () = IntArray.appi reportRedundant uses 416 end 417 418 (* Generate functions for expressions that have been used more than 3 times. *) 419 fun cgExps([], _, _, _, _, _, _) = [] 420 421 | cgExps (MatchTree {vars, exp, breakPoint, ...} ::al, 422 base, patNo, uses, lex, near, cgContext as { decName, level, ...}) = 423 if IntArray.sub(uses, patNo - 1) <= insertDirectCount 424 then (* Skip if it has been inserted directly and we don't need a fn. *) 425 cgExps(al, base, patNo + 1, uses, lex, near, cgContext) 426 else 427 let 428 val functionLevel = newLevel level (* For the function. *) 429 local 430 val addresses = ref 1 431 in 432 fun fnMkAddrs n = ! addresses before (addresses := !addresses + n) 433 end 434 435 val fnContext = cgContext |> repNewLevel(decName, fnMkAddrs, functionLevel) 436 437 (* We have to pass the variables as arguments. Bind a local variable to the argument 438 so we can set the variable address as a local address. *) 439 val pattVars = getVariablesInPatt(vars, []) 440 val noOfArgs = length pattVars 441 val argumentList = List.tabulate(noOfArgs, mkLoadArgument) 442 val localAddresses = List.map(fn _ => fnMkAddrs 1) pattVars (* One address for each argument. *) 443 val localDecs = ListPair.mapEq mkDec (localAddresses, argumentList) 444 445 local 446 (* Set the addresses to be suitable for arguments. At the 447 same time create a debugging environment if required. *) 448 fun setAddr (Value{access=Local{addr=lvAddr, level=lvLevel}, ...}, localAddr) = 449 (lvAddr := localAddr; lvLevel := functionLevel) 450 | setAddr _ = raise InternalError "setAddr" 451 in 452 val _ = ListPair.appEq setAddr (pattVars, localAddresses) 453 end 454 455 (* If debugging add the debug entries for the variables then a break-point. *) 456 val (envDec, varDebugEnv) = makeDebugEntries(pattVars, fnContext) 457 val (bptCode, bptEnv) = 458 addBreakPointCall(breakPoint, getLocation exp, fnContext |> repDebugEnv varDebugEnv) 459 460 val functionBody = 461 mkEnv(localDecs @ envDec @ bptCode, codegen (exp, fnContext |> repDebugEnv bptEnv)) 462 val patNoIndex = patNo - 1 463 in 464 mkDec(base + patNoIndex, 465 mkProc (functionBody, noOfArgs, decName ^ "/" ^ Int.toString patNo, getClosure functionLevel, fnMkAddrs 0)) :: 466 cgExps(al, base, patNo + 1, uses, lex, near, cgContext) 467 end 468 469 val expressionFuns = 470 cgExps(alt, baseAddr, 1, uses, lex, near, matchContext) 471 in 472 (* Return the code in a block. *) 473 mkEnv (#dec decCode @ expressionFuns, matchCode) 474 end (* codeMatch *) 475 476 (* Code-generates a piece of tree. Returns the code and also the, possibly updated, 477 debug context. This is needed to record the last location that was set in the 478 thread data. *) 479 and codeGenerate(Ident {value = ref (v as Value{class = Exception, ...}), location, ...}, 480 { level, typeVarMap, lex, debugEnv, ...}) = (* Exception identifier *) 481 (codeExFunction (v, level, typeVarMap, [], lex, location), debugEnv) 482 483 | codeGenerate(Ident {value = ref (v as Value{class = Constructor _, ...}), expType=ref expType, location, ...}, 484 { level, typeVarMap, lex, debugEnv, ...}) = (* Constructor identifier *) 485 let 486 (* The instance type is not necessarily the same as the type 487 of the value of the identifier. e.g. in the expression 488 1 :: nil, "::" has an instance type of 489 int * list int -> list int but the type of "::" is 490 'a * 'a list -> 'a list. *) 491 (* When using the constructor as a value we just want 492 the second word. Must pass [] as the polyVars otherwise 493 this will be applied BEFORE extracting the construction 494 function not afterwards. *) 495 fun getConstr level = 496 ValueConstructor.extractInjection(codeVal (v, level, typeVarMap, [], lex, location)) 497 val polyVars = getPolymorphism (v, expType, typeVarMap) 498 val code = 499 applyToInstance(if justForEqualityTypes then [] else polyVars, level, typeVarMap, getConstr) 500 in 501 (code, debugEnv) 502 end 503 504 | codeGenerate(Ident {value = ref v, expType=ref expType, location, ...}, 505 { level, typeVarMap, lex, debugEnv, ...}) = (* Value identifier *) 506 let 507 val polyVars = getPolymorphism (v, expType, typeVarMap) 508 val code = codeVal (v, level, typeVarMap, polyVars, lex, location) 509 in 510 (code, debugEnv) 511 end 512 513 | codeGenerate(c as Literal{converter, literal, expType=ref expType, location}, { lex, debugEnv, ...}) = 514 ( 515 case getLiteralValue(converter, literal, expType, fn s => errorNear(lex, true, c, location, s)) of 516 SOME w => (mkConst w, debugEnv) 517 | NONE => (CodeZero, debugEnv) 518 ) 519 520 | codeGenerate(Applic {f = Ident {value = ref function, expType=ref expType, ...}, arg, location, ...}, context as { level, typeVarMap, lex, ...}) = 521 (* Some functions are special e.g. overloaded and type-specific functions. 522 These need to picked out and processed by applyFunction. *) 523 let 524 val polyVars = getPolymorphism (function, expType, typeVarMap) 525 val (argCode, argEnv) = codeGenerate (arg, context) 526 val code = applyFunction (function, argCode, level, typeVarMap, polyVars, lex, location) 527 in 528 (code, argEnv) 529 end 530 531 | codeGenerate(Applic {f, arg, ...}, context) = 532 let 533 val (fnCode, fnEnv) = codeGenerate(f, context) 534 val (argCode, argEnv) = codeGenerate(arg, context |> repDebugEnv fnEnv) 535 in 536 (mkEval (fnCode, [argCode]), argEnv) 537 end 538 539 | codeGenerate(Cond {test, thenpt, elsept, thenBreak, elseBreak, ...}, context) = 540 let 541 val (testCode, testEnv) = codeGenerate(test, context) 542 val (thenBptCode, thenDebug) = 543 addBreakPointCall(thenBreak, getLocation thenpt, context |> repDebugEnv testEnv) 544 val (thenCode, _) = codeGenerate(thenpt, context |> repDebugEnv thenDebug) 545 val (elseBptCode, elseDebug) = 546 addBreakPointCall(elseBreak, getLocation elsept, context |> repDebugEnv testEnv) 547 val (elseCode, _) = codeGenerate(elsept, context |> repDebugEnv elseDebug) 548 in 549 (mkIf (testCode, mkEnv(thenBptCode, thenCode), mkEnv(elseBptCode, elseCode)), testEnv) 550 end 551 552 | codeGenerate(TupleTree{fields=[(*pt*)_], ...}, _) = 553 (* There was previously a special case to optimise unary tuples but I can't 554 understand how they can occur. Check this and remove the special case 555 if it really doesn't. *) 556 raise InternalError "codegen: Unary tuple" (*codegen (pt, context)*) 557 558 | codeGenerate(TupleTree{fields, ...}, context as { debugEnv, ...}) = (* Construct a vector of objects. *) 559 (mkTuple(map (fn x => codegen (x, context)) fields), debugEnv) 560 561 | codeGenerate(Labelled {recList = [{valOrPat, ...}], ...}, context) = 562 codeGenerate (valOrPat, context) (* optimise unary records *) 563 564 | codeGenerate(Labelled {recList, expType=ref expType, ...}, context as { level, mkAddr, debugEnv, ...}) = 565 let 566 (* We must evaluate the expressions in the order they are 567 written. This is not necessarily the order they appear 568 in the record. *) 569 val recordSize = length recList; (* The size of the record. *) 570 571 (* First declare the values as local variables. *) 572 (* We work down the list evaluating the expressions and putting 573 the results away in temporaries. When we reach the end we 574 construct the tuple by asking for each entry in turn. *) 575 fun declist [] look = ([], mkTuple (List.tabulate (recordSize, look))) 576 577 | declist ({name, valOrPat, ...} :: t) look = 578 let 579 val thisDec = 580 multipleUses (codegen (valOrPat, context), fn () => mkAddr 1, level); 581 582 val myPosition = entryNumber (name, expType); 583 584 fun lookFn i = 585 if i = myPosition then #load thisDec (level) else look i 586 val (otherDecs, tuple) = declist t lookFn 587 in 588 (#dec thisDec @ otherDecs, tuple) 589 end 590 in 591 (* Create the record and package it up as a block. *) 592 (mkEnv (declist recList (fn _ => raise InternalError "missing in record")), debugEnv) 593 end 594 595 | codeGenerate(c as Selector {name, labType, location, typeof, ...}, { decName, typeVarMap, lex, debugEnv, ...}) = 596 let 597 (* Check that the type is frozen. *) 598 val () = 599 if recordNotFrozen labType 600 then errorNear (lex, true, c, location, "Can't find a fixed record type.") 601 else (); 602 603 val selectorBody : codetree = 604 if recordWidth labType = 1 605 then singleArg (* optimise unary tuples - no indirection! *) 606 else 607 let 608 val offset : int = entryNumber (name, labType); 609 in 610 mkInd (offset, singleArg) 611 end 612 val code =(* Make an inline function. *) 613 case filterTypeVars (getPolyTypeVars(typeof, mapTypeVars typeVarMap)) of 614 [] => mkInlproc (selectorBody, 1, decName ^ "#" ^ name, [], 0) 615 | polyVars => (* This may be polymorphic. *) 616 mkInlproc( 617 mkInlproc (selectorBody, 1, decName ^ "#" ^ name, [], 0), 618 List.length polyVars, decName ^ "#" ^ name ^ "(P)", [], 0) 619 in 620 (code, debugEnv) 621 end 622 623 | codeGenerate(Unit _, { debugEnv, ...}) = (* Use zero. It is possible to have () = (). *) 624 (CodeZero, debugEnv) 625 626 | codeGenerate(List{elements, expType = ref listType, location, ...}, context as { level, typeVarMap, lex, debugEnv, ...}) = 627 let (* Construct a list. We need to apply the constructors appropriate to the type. *) 628 val baseType = 629 case listType of 630 TypeConstruction{args=[baseType], ...} => baseType 631 | _ => raise InternalError "List: bad element type" 632 val consType = mkFunctionType(mkProductType[baseType, listType], listType) 633 fun consList [] = 634 let (* "nil" *) 635 val polyVars = getPolymorphism (nilConstructor, listType, typeVarMap) 636 fun getConstr level = 637 ValueConstructor.extractInjection( 638 codeVal (nilConstructor, level, typeVarMap, [], lex, location)) 639 in 640 applyToInstance(polyVars, level, typeVarMap, getConstr) 641 end 642 | consList (h::t) = 643 let (* :: *) 644 val H = codegen (h, context) and T = consList t 645 val polyVars = getPolymorphism (consConstructor, consType, typeVarMap) 646 in 647 applyFunction (consConstructor, mkTuple [H,T], level, typeVarMap, polyVars, lex, location) 648 end 649 in 650 (consList elements, debugEnv) 651 end 652 653 | codeGenerate(Constraint {value, ...}, context) = codeGenerate (value, context) (* code gen. the value *) 654 655 | codeGenerate(c as Fn { location, expType=ref expType, ... }, context as { typeVarMap, debugEnv, ...}) = 656 (* Function *) 657 (codeLambda(c, location, filterTypeVars(getPolyTypeVars(expType, mapTypeVars typeVarMap)), context), debugEnv) 658 659 | codeGenerate(Localdec {decs, body, ...}, context) = 660 (* Local expressions only. Local declarations will be handled 661 by codeSequence.*) 662 let 663 (* This is the continuation called when the declarations have been 664 processed. We need to ensure that if there are local datatypes 665 we make new entries in the type value cache after them. *) 666 (* TODO: This is a bit of a mess. We want to return the result of the 667 last expression as an expression rather than a codeBinding. *) 668 fun processBody (previousDecs: codeBinding list, nextContext as {debugEnv, ...}) = 669 let 670 fun codeList ([], d) = ([], d) 671 | codeList ((p, bpt) :: tl, d) = 672 (* Generate any break point code first, then this entry, then the rest. *) 673 let 674 val (lineChange, newEnv) = 675 addBreakPointCall(bpt, getLocation p, nextContext |> repDebugEnv d) 676 (* addBreakPointCall also updates the location info in case of a break-point 677 or a function call. We want to pass that along. *) 678 val code = mkNullDec(codegen (p, nextContext |> repDebugEnv newEnv)) 679 val (codeRest, finalEnv) = codeList (tl, newEnv) 680 in 681 (lineChange @ [code] @ codeRest, finalEnv) 682 end 683 val (exps, finalDebugEnv) = codeList (body, debugEnv) 684 in 685 (previousDecs @ exps, finalDebugEnv) 686 end 687 688 val (decs, lastEnv) = codeSequence (decs, [], context, processBody) 689 in 690 (decSequenceWithFinalExp decs, lastEnv) 691 end 692 693 | codeGenerate(ExpSeq(ptl, _), context as { debugEnv, ...}) = 694 (* Sequence of expressions. Discard results of all except the last.*) 695 let 696 fun codeList ([], _) = raise InternalError "ExpSeq: empty sequence" 697 | codeList ((p, bpt)::tl, d) = 698 let 699 val (bptCode, newEnv) = 700 addBreakPointCall(bpt, getLocation p, context |> repDebugEnv d) 701 (* Because addBreakPointCall updates the location info in the debug env 702 we need to pass this along in the same way as when making bindings. *) 703 val (thisCode, postCodeEnv) = codeGenerate (p, context |> repDebugEnv newEnv) 704 in 705 case tl of 706 [] => (bptCode, thisCode, postCodeEnv) 707 | tl => 708 let 709 val (otherDecs, expCode, postListEnv) = codeList(tl, postCodeEnv) 710 in 711 (bptCode @ (mkNullDec thisCode :: otherDecs), expCode, postListEnv) 712 end 713 end 714 val (codeDecs, codeExp, finalEnv) = codeList(ptl, debugEnv) 715 in 716 (mkEnv (codeDecs, codeExp), finalEnv) 717 end 718 719 | codeGenerate(Raise (pt, location), context as { level, mkAddr, ...}) = 720 let 721 val (raiseCode, raiseEnv) = codeGenerate(pt, context) 722 val {dec, load} = multipleUses (raiseCode, fn () => mkAddr 1, level) 723 val load = load level 724 (* Copy the identifier, name and argument from the packet and add this location. *) 725 val excPacket = 726 mkEnv(dec, 727 mkTuple[mkInd(0, load), mkInd(1, load), mkInd(2, load), codeLocation location]) 728 in 729 (mkRaise excPacket, raiseEnv) 730 end 731 732 | codeGenerate(c as HandleTree {exp, hrules, ...}, context as { debugEnv, mkAddr, ...}) = 733 (* Execute an expression in the scope of a handler *) 734 let 735 val exPacketAddr = mkAddr 1 736 val handleExp = codegen (exp, context) 737 val handlerCode = codeMatch (c, hrules, mkLoadLocal exPacketAddr, true, context) 738 in 739 (mkHandle (handleExp, handlerCode, exPacketAddr), debugEnv) 740 end 741 742 | codeGenerate(While {test, body, breakPoint, ...}, context as { debugEnv, ...}) = 743 let 744 val (testCode, testEnv) = codeGenerate(test, context) 745 val (bptCode, testDebug) = 746 addBreakPointCall(breakPoint, getLocation body, context |> repDebugEnv testEnv) 747 val (bodyCode, _) = codeGenerate(body, context |> repDebugEnv testDebug) 748 in 749 (mkWhile (testCode, mkEnv(bptCode, bodyCode)), debugEnv) 750 end 751 752 | codeGenerate(c as Case {test, match, ...}, context as { debugEnv, ...}) = 753 (* The matches are made into a series of tests and 754 applied to the test expression. *) 755 let 756 val testCode = codegen (test, context) 757 in 758 (codeMatch (c, match, testCode, false, context), debugEnv) 759 end 760 761 | codeGenerate(Andalso {first, second, ...}, context) = 762 let 763 val (firstCode, firstEnv) = codeGenerate(first, context) 764 (* Any updates to the debug context in the first part will carry over 765 but we can't be sure whether any of the second part will be executed. *) 766 val (secondCode, _) = codeGenerate(second, context |> repDebugEnv firstEnv) 767 in 768 (* Equivalent to if first then second else false *) 769 (mkCand (firstCode, secondCode), firstEnv) 770 end 771 772 | codeGenerate(Orelse {first, second, ...}, context) = 773 let 774 val (firstCode, firstEnv) = codeGenerate(first, context) 775 (* Any updates to the debug context in the first part will carry over 776 but we can't be sure whether any of the second part will be executed. *) 777 val (secondCode, _) = codeGenerate(second, context |> repDebugEnv firstEnv) 778 in 779 (* Equivalent to if first then true else second *) 780 (mkCor (firstCode, secondCode), firstEnv) 781 end 782 783 | codeGenerate(Parenthesised(p, _), context) = codeGenerate (p, context) 784 785 | codeGenerate(_, {debugEnv, ...}) = (CodeZero, debugEnv) (* empty and any others *) 786 787 (* Old codegen function which discards the debug context. *) 788 and codegen (c: parsetree, context) = #1 (codeGenerate(c, context)) 789 790 (* Code-generate a lambda (fn expression). *) 791 and codeLambda(c, location, polyVars, 792 cpContext as 793 {mkAddr=originalmkAddr, level=originalLevel, decName, ...}) = 794 let 795 fun getFnBody (Constraint {value, ...}) = getFnBody value 796 | getFnBody (Fn{matches, ...}) = matches 797 | getFnBody (Parenthesised(p, _)) = getFnBody p 798 | getFnBody _ = raise InternalError "getFnBody: not a constrained fn-expression"; 799 800 val f = getFnBody c; 801 (* This function comprises a new declaration level *) 802 val nLevel = 803 if null polyVars then originalLevel else newLevel originalLevel 804 805 local 806 val addresses = ref 1 807 in 808 fun fnMkAddr n = (! addresses) before (addresses := ! addresses + n) 809 end 810 811 val (firstPat, resType, argType) = 812 case f of 813 MatchTree {vars, resType = ref rtype, argType = ref atype, ...} :: _ => (vars, rtype, atype) 814 | _ => raise InternalError "codeLambda: body of fn is not a clause list"; 815 816 val tupleSize = List.length(tupleWidth firstPat) 817 in 818 if tupleSize <> 1 andalso null polyVars 819 then 820 let 821 (* If the first pattern is a tuple we make a tuple from the 822 arguments and pass that in. Could possibly treat labelled 823 records in the same way but we have the problem of 824 finding the size of the record. 825 Currently, we don't apply this optimisation if the function is 826 polymorphic. *) 827 val newDecName : string = decName ^ "(" ^ Int.toString tupleSize ^ ")"; 828 829 val fnLevel = newLevel nLevel 830 val argumentCode = mkArgTuple(0, tupleSize) 831 val newContext = cpContext |> repNewLevel(newDecName, fnMkAddr, fnLevel) 832 833 fun codeAlts newDebugEnv = 834 let 835 val bodyContext = newContext |> repDebugEnv newDebugEnv 836 in 837 codeMatch (c, f, argumentCode, false, bodyContext) 838 end 839 840 val wrap = 841 wrapFunctionInDebug(codeAlts, newDecName, argumentCode, argType, resType, location, newContext) 842 val mainProc = mkProc(wrap, tupleSize, newDecName, getClosure fnLevel, fnMkAddr 0) 843 844 (* Now make a block containing the procedure which expects 845 multiple arguments and an inline procedure which expects 846 a single tuple argument and calls the main procedure after 847 taking the tuple apart. *) 848 val thisDec = multipleUses (mainProc, fn () => originalmkAddr 1, originalLevel); 849 850 val resProc = (* Result procedure. *) 851 let 852 val nLevel = newLevel originalLevel 853 in 854 mkInlproc 855 (mkEval(#load thisDec nLevel, 856 List.map #1 (loadArgsFromTuple(List.tabulate(tupleSize, fn _ => GeneralType), singleArg))), 857 1, decName ^ "(1)", getClosure nLevel, 0) 858 end 859 in 860 mkEnv(#dec thisDec, resProc) 861 end 862 863 else 864 let (* No tuple or polymorphic. *) 865 val newDecName : string = decName ^ "(1)"; 866 val fnLevel = newLevel nLevel 867 val newContext = cpContext |> repNewLevel(newDecName, fnMkAddr, fnLevel) 868 869 fun codeAlts newDebugEnv = 870 let 871 val bodyContext = newContext |> repDebugEnv newDebugEnv 872 in 873 codeMatch (c, f, mkLoadArgument 0, false, bodyContext) 874 end 875 876 (* If we're debugging add the debug info before resetting the level. *) 877 val wrapped = 878 wrapFunctionInDebug(codeAlts, newDecName, mkLoadArgument 0, argType, resType, location, newContext) 879 val pr = mkProc (wrapped, 1, newDecName, getClosure fnLevel, fnMkAddr 0) 880 in 881 if null polyVars then pr 882 else mkProc(pr, List.length polyVars, newDecName^"(P)", getClosure nLevel, 0) 883 end 884 end (* codeLambda *) 885 886 887 (* Code-generates a sequence of declarations. *) 888 and codeSequence ([], leading, codeSeqContext, processBody): codeBinding list * debuggerStatus = 889 processBody(leading, codeSeqContext) (* Do the continuation. *) 890 891 | codeSequence ((firstEntry as FunDeclaration {dec, ...}, _) :: pTail, leading, codeSeqContext, processBody) = 892 let 893 val (firstDec, firstEnv) = codeFunBindings(dec, firstEntry, codeSeqContext) 894 in 895 codeSequence (pTail, leading @ firstDec, codeSeqContext |> repDebugEnv firstEnv, processBody) 896 end 897 898 | codeSequence ((firstEntry as ValDeclaration {dec, location, ...}, bpt) :: pTail, leading, codeSeqContext as {lex, ...}, processBody) = 899 let 900 (* Check the types for escaped datatypes. *) 901 local 902 fun checkVars(ValBind{variables=ref vars, line, ...}) = 903 List.app(fn var => checkForEscapingDatatypes(valTypeOf var, 904 fn message => errorNear (lex, true, firstEntry, line, message))) vars 905 in 906 val () = List.app checkVars dec 907 end 908 909 (* Put in a break point *) 910 val (bptCode, bptDbEnv) = addBreakPointCall(bpt, location, codeSeqContext) 911 val postBptContext = codeSeqContext |> repDebugEnv bptDbEnv 912 (* Split the bindings into recursive and non-recursive. These have to 913 be processed differently. *) 914 val (recBindings, nonrecBindings) = 915 List.partition(fn ValBind{isRecursive, ...} => isRecursive) dec 916 917 val nonRecCode = codeNonRecValBindings(nonrecBindings, firstEntry, postBptContext) 918 val recCode = 919 case recBindings of 920 [] => [] 921 | _ => #1 (codeRecValBindings(recBindings, firstEntry, postBptContext)) 922 (* Construct the debugging environment by loading all variables. *) 923 val vars = List.foldl(fn (ValBind{variables=ref v, ...}, vars) => v @ vars) [] dec 924 val (decEnv, env) = makeDebugEntries (vars, postBptContext) 925 in 926 codeSequence (pTail, leading @ bptCode @ nonRecCode @ recCode @ decEnv, 927 codeSeqContext |> repDebugEnv env, processBody) 928 end 929 930 | codeSequence ((Localdec {decs, body, varsInBody=ref vars, ...}, _) :: pTail, leading, codeSeqContext, processBody) = 931 let (* Local declarations only *) 932 (* The debug environment needs to reflect the local...in...end structure but if 933 there are local datatypes we need to process all subsequent declarations in the 934 scope of the "stopper" we've put onto the typeVarMap. *) 935 fun processTail(previous, newContext) = 936 let 937 (* The debug env for the tail is the original environment together with the 938 variables in the body, excluding variables in the local...in part. *) 939 val (decEnv, resEnv) = makeDebugEntries (vars, codeSeqContext) (* Original context. *) 940 in 941 codeSequence (pTail, previous @ decEnv, newContext |> repDebugEnv resEnv, processBody) 942 end 943 in 944 (* Process the declarations then the tail. *) 945 codeSequence (decs @ body, leading, codeSeqContext, processTail) 946 end 947 948 | codeSequence ((ExDeclaration(tlist, _), _) :: pTail, leading, 949 codeSeqContext as {mkAddr, level, typeVarMap, lex, ...}, processBody) = 950 let 951 fun codeEx (ExBind{value=ref exval, previous, ... }) = 952 let 953 val ex = exval; 954 (* This exception is treated in the same way as a local 955 variable except that the value it contains is created 956 by generating a word on the heap. The address of this word 957 constitutes a unique identifier. Non-generative exception 958 bindings i.e. exception ex=ex' merely copy the word from 959 the previous exception. *) 960 val (lvAddr, lvLevel, exType) = 961 case ex of 962 Value{access=Local{addr, level}, typeOf, ...} => (addr, level, typeOf) 963 | _ => raise InternalError "lvAddr" 964 in 965 lvAddr := mkAddr 1; 966 lvLevel := level; 967 968 mkDec 969 (! lvAddr, 970 case previous of 971 EmptyTree => 972 (* Generate a new exception. This is a single 973 mutable word which acts as a token. It is a 974 mutable to ensure that there is precisely one 975 copy of it. It contains a function to print values 976 of the type so when we raise the exception we can print 977 the exception packet without knowing the type. *) 978 mkExIden (exType, level, typeVarMap) 979 | Ident{value=ref prevVal, location, ...} => 980 (* Copy the previous value. N.B. We want the exception 981 identifier here so we can't call codegen. *) 982 codeVal (prevVal, level, typeVarMap, [], lex, location) 983 | _ => raise InternalError "codeEx" 984 ) 985 end (* codeEx *); 986 987 val exdecs = map codeEx tlist 988 989 fun getValue(ExBind{value=ref exval, ...}) = exval 990 val (debugDecs, newDebugEnv) = makeDebugEntries(map getValue tlist, codeSeqContext) 991 992 in 993 codeSequence (pTail, leading @ exdecs @ debugDecs, codeSeqContext |> repDebugEnv newDebugEnv, processBody) 994 end (* ExDeclaration *) 995 996 | codeSequence ( 997 (AbsDatatypeDeclaration {typelist, declist, equalityStatus = ref absEq, isAbsType, withtypes, ...}, _) :: pTail, 998 leading, codeSeqContext as {mkAddr, level, typeVarMap, debugEnv, lex, ...}, processBody) = 999 let (* Code-generate the eq and print functions for the abstype first 1000 then the declarations, which may use these. *) 1001 (* The debugging environment for the declarations should include 1002 the constructors but the result shouldn't. For the moment 1003 ignore the constructors. *) 1004 val typeCons = List.map(fn (DatatypeBind {tcon = ref tc, ...}) => tc) typelist 1005 val eqStatus = if isAbsType then absEq else List.map (tcEquality o tsConstr) typeCons 1006 1007 local 1008 fun getConstrCode(DatatypeBind {tcon = ref (tc as TypeConstrSet(_, constrs)), typeVars, ...}, eqStatus) = 1009 let 1010 (* Get the argument types or EmptyType if this is nullary. *) 1011 fun getConstrType(Value{typeOf=FunctionType{arg, ...}, name, ...}) = (name, arg) 1012 | getConstrType(Value{name, ...}) = (name, EmptyType) 1013 val constrTypesAndNames = List.map getConstrType constrs 1014 val {constrs, boxed, size} = chooseConstrRepr(constrTypesAndNames, List.map TypeVar typeVars) 1015 in 1016 ({typeConstr=tc, eqStatus=eqStatus, boxedCode=boxed, sizeCode=size}, constrs) 1017 end 1018 in 1019 val constrAndBoxSizeCode = ListPair.mapEq getConstrCode (typelist, eqStatus) 1020 val (tcEqBoxSize, constrsCode) = ListPair.unzip constrAndBoxSizeCode 1021 end 1022 1023 local 1024 fun decConstrs(DatatypeBind {tcon = ref (TypeConstrSet(_, constrs)), ...}, reprs, (decs, debugEnv)) = 1025 let 1026 (* Declare the constructors as local variables. *) 1027 fun decCons(Value{access=Local{addr, level=lev}, ...}, repr) = 1028 let 1029 val newAddr = mkAddr 1 1030 in 1031 addr := newAddr; 1032 lev := level; 1033 mkDec(newAddr, repr) 1034 end 1035 | decCons _ = raise InternalError "decCons: Not local" 1036 val constrDecs = ListPair.map decCons (constrs, reprs) 1037 val (newDecs, newDebug) = 1038 makeDebugEntries(constrs, codeSeqContext |> repDebugEnv debugEnv) 1039 in 1040 (constrDecs @ decs @ newDecs, newDebug) 1041 end 1042 in 1043 val (valConstrDecs: codeBinding list, constrDebugenv: debuggerStatus) = 1044 ListPair.foldl decConstrs ([], debugEnv) (typelist, constrsCode) 1045 end 1046 1047 val typeFunctions = 1048 createDatatypeFunctions(tcEqBoxSize, mkAddr, level, typeVarMap, 1049 getParameter createPrintFunctionsTag (debugParams lex)) 1050 1051 local 1052 (* Create debug entries for the type constructors and the new type ids. *) 1053 val (dataTypeDebugDecs, dataTypeDebugEnv) = 1054 makeTypeConstrDebugEntries(typeCons, constrDebugenv, level, lex, mkAddr) 1055 val withTypeTypes = List.map(fn (TypeBind {tcon = ref tc, ...}) => tc) withtypes 1056 val (withTypeDebugDecs, withTypeDebugEnv) = 1057 makeTypeConstrDebugEntries(withTypeTypes, dataTypeDebugEnv, level, lex, mkAddr) 1058 in 1059 val typeDebugDecs = dataTypeDebugDecs @ withTypeDebugDecs 1060 val typeDebugEnv = withTypeDebugEnv 1061 end 1062 1063 (* Mark these in the type value cache. If they are used in subsequent polymorphic IDs 1064 we must create them after this. *) 1065 val newTypeVarMap = 1066 markTypeConstructors(List.map tsConstr typeCons, mkAddr, level, typeVarMap) 1067 1068 (* Process the with..end part. We have to restore the equality attribute for abstypes 1069 here in case getPolymorphism requires it. *) 1070 val () = 1071 if isAbsType 1072 then ListPair.appEq(fn(TypeConstrSet(tc, _), eqt) => tcSetEquality (tc, eqt)) (typeCons, absEq) 1073 else () 1074 val (localDecs, newDebug) = 1075 codeSequence (declist, [], 1076 codeSeqContext |> repDebugEnv typeDebugEnv |> repTypeVarMap newTypeVarMap, 1077 fn (code, {debugEnv, ...}) => (code, debugEnv)) 1078 val () = 1079 if isAbsType 1080 then List.app(fn TypeConstrSet(tc, _) => tcSetEquality (tc, false)) typeCons else () 1081 1082 (* Then the subsequent declarations. *) 1083 val (tailDecs, finalEnv) = 1084 codeSequence (pTail, [], codeSeqContext |> repDebugEnv newDebug |> repTypeVarMap newTypeVarMap, processBody) 1085 in 1086 (* The code consists of previous declarations, the value constructors, the type IDs, 1087 debug declarations for the types and value constructors, any type values created for 1088 subsequent polymorphic calls, declarations in with...end and finally code after 1089 this declaration within the same "let..in..end" block. *) 1090 (leading @ valConstrDecs @ typeFunctions @ typeDebugDecs @ 1091 getCachedTypeValues newTypeVarMap @ localDecs @ tailDecs, finalEnv) 1092 end 1093 1094 | codeSequence ((OpenDec {variables=ref vars, structures = ref structs, typeconstrs = ref types, ...}, _) :: pTail, 1095 leading, codeSeqContext as { level, lex, mkAddr, ...}, processBody) = 1096 let 1097 (* All we need to do here is make debugging entries. *) 1098 val (firstDec, firstEnv) = makeDebugEntries(vars, codeSeqContext) 1099 val (secondDec, secondEnv) = makeTypeConstrDebugEntries(types, firstEnv, level, lex, mkAddr) 1100 val (thirdDec, thirdEnv) = makeStructDebugEntries(structs, secondEnv, level, lex, mkAddr) 1101 in 1102 codeSequence (pTail, leading @ firstDec @ secondDec @ thirdDec, codeSeqContext |> repDebugEnv thirdEnv, processBody) 1103 end 1104 1105 | codeSequence ((TypeDeclaration (typebinds, _), _) :: pTail, leading, 1106 codeSeqContext as { debugEnv, level, lex, mkAddr, ...}, processBody) = 1107 let 1108 (* Just create debug entries for the type constructors. *) 1109 val typeCons = List.map(fn (TypeBind {tcon = ref tc, ...}) => tc) typebinds 1110 val (typeDebugDecs, typeDebugEnv) = 1111 makeTypeConstrDebugEntries(typeCons, debugEnv, level, lex, mkAddr) 1112 in 1113 codeSequence (pTail, leading @ typeDebugDecs, codeSeqContext |> repDebugEnv typeDebugEnv, processBody) 1114 end 1115 1116 | codeSequence (_ :: pTail, leading, (* Directive *) codeSeqContext, processBody) = 1117 codeSequence (pTail, leading, codeSeqContext, processBody) 1118 1119 (* Code generate a set of fun bindings. This is used for other function creation as 1120 well since it handles the most general case. *) 1121 and codeFunBindings(tlist: fvalbind list, near, 1122 context as {decName, mkAddr, level, typeVarMap, lex, ...}) = 1123 let 1124 (* Get the function variables. *) 1125 val functionVars = map (fn(FValBind{functVar = ref var, ...}) => var) tlist 1126 1127 (* Check the types for escaped datatypes. *) 1128 local 1129 fun checkVars(FValBind{functVar=ref var, location, ...}) = 1130 checkForEscapingDatatypes(valTypeOf var, 1131 fn message => errorNear (lex, true, near, location, message)) 1132 in 1133 val () = List.app checkVars tlist 1134 end 1135 (* Each function may result in either one or two functions 1136 actually being generated. If a function is not curried 1137 it will generate a single function of one argument, but 1138 if it is curried (e.g. fun f a b = ...) it will 1139 generate two mutually recursive functions. A function 1140 fun f a b = X will be translated into 1141 val rec f' = fn(a,b) => X and f = fn a => b => f'(a,b) 1142 with the second function (f) being inline. This allows 1143 the optimiser to replace references to f with all its 1144 arguments by f' which avoids building unneccessary 1145 closures. *) 1146 1147 fun setValueAddress( 1148 FValBind{functVar = ref(Value{access=Local{addr, level}, ...}), ...}, ad, lev) = 1149 (addr := ad; level := lev) 1150 | setValueAddress _ = raise InternalError "setValueAddress" 1151 1152 (* Create a list of addresses for the functions. This is the address 1153 used for the most general case. Also set the variable addresses. 1154 These may be changed for polymorphic functions but will eventually 1155 be reset. *) 1156 1157 val addressList = List.map (fn _ => mkAddr 2 (* We need two addresses. *)) tlist 1158 val () = ListPair.appEq (fn (t, a) => setValueAddress(t, a, level)) (tlist, addressList) 1159 1160 (* Get the polymorphic variables for each function. *) 1161 local 1162 fun getPoly(FValBind{functVar = ref (Value{typeOf, ...}), ...}) = 1163 filterTypeVars(getPolyTypeVars(typeOf, mapTypeVars typeVarMap)) 1164 in 1165 val polyVarList = List.map getPoly tlist 1166 end 1167 1168 (* Now we can process the function bindings. *) 1169 fun loadFunDecs ((fb as FValBind{numOfPatts = ref numOfPats, functVar = ref(Value{name, ...}), 1170 clauses, argType = ref aType, resultType = ref resType, location, ...})::otherDecs, 1171 polyVars :: otherPolyVars, 1172 addr :: otherAddresses) = 1173 let 1174 (* Make up the function, and if there are several mutually 1175 recursive functions, put it in the vector. *) 1176 val procName = decName ^ name; 1177 val nPolyVars = List.length polyVars 1178 (*val _ = 1179 print(concat[name, " is ", Int.toString nPolyVars, "-ary\n"])*) 1180 (* Check that all the type-vars are in the list. *) 1181 (*local 1182 fun checkVars tv = 1183 case List.find(fn t => sameTv(t, tv)) fdTypeVars of 1184 SOME _ => () 1185 | NONE => raise InternalError "Type var not found" 1186 in 1187 val _ = List.app checkVars polyVars 1188 end*) 1189 1190 (* Produce a list of the size of any tuples or labelled records 1191 in the first clause. Tuples in the first clause are passed as 1192 separate arguments. We could look at the other clauses and only 1193 pass them as separate arguments if each clause contains a tuple. 1194 1195 We can treat labelled records exactly like tuples here - we only 1196 need to worry about the mapping from labels to tuple offsets 1197 when we create the record (getting the order of evaluation right) 1198 and in the pattern-matching code (extracting the right fields). 1199 We don't have to worry about that here, because all we're doing 1200 is untupling and retupling, taking care always to put the values 1201 back at exactly the same offset we got them from. *) 1202 val tupleSeq : argumentType list list = 1203 case clauses of 1204 (FValClause{dec= { args, ...}, ...} :: _) => List.map tupleWidth args 1205 | _ => raise InternalError "badly formed parse tree"; 1206 1207 local 1208 fun getResultTuple(FValClause{exp, ...}) = tupleWidth exp 1209 1210 val resultTuples = 1211 List.foldl(fn(t, [_]) => getResultTuple t | (_, s) => s) [GeneralType] clauses 1212 1213 (* If we're debugging we want the result of the function so we don't do this optimisation. *) 1214 (* The optimiser also detects functions returning tuples and turns them into containers. 1215 That works for local functions but doesn't work if the function is exported e.g. 1216 IntInf.divMod. *) 1217 val resultTuple = 1218 if (getParameter debugTag (debugParams lex)) then [GeneralType] 1219 else resultTuples 1220 in 1221 val resTupleLength = List.length resultTuple 1222 (*val _ = resTupleLength = 1 orelse raise InternalError "resTupleLength <> 1"*) 1223 (* If there's a single argument return the type of that otherwise if we're tupling the 1224 result is general. *) 1225 val (resultType, extraArg) = case resultTuple of [one] => (one, 0) | _ => (GeneralType, 1) 1226 end 1227 1228 (* Count the total number of arguments needed. *) 1229 val totalArgs = List.foldl (op +) (extraArg+nPolyVars) (List.map List.length tupleSeq) 1230 1231 (* The old test was "totalArgs = 1", but that's not really 1232 right, because we could have one genuine arg plus a 1233 lot of "()" patterns. We now use the normal inlining 1234 mechanism to optimise this (unusual) case too. *) 1235 val noInlineFunction = 1236 numOfPats = 1 andalso totalArgs = 1 andalso tupleSeq = [[GeneralType]] andalso resultType = GeneralType 1237 1238 (* Turn the list of clauses into a match. *) 1239 fun clauseToTree(FValClause {dec={ args, ...}, exp, line, breakPoint, ...}) = 1240 MatchTree 1241 { 1242 vars = 1243 if numOfPats = 1 then hd args 1244 else TupleTree{fields=args, location=line, expType=ref EmptyType}, 1245 exp = exp, 1246 location = line, 1247 argType = ref badType, 1248 resType = ref badType, 1249 breakPoint = breakPoint 1250 } 1251 val matches = map clauseToTree clauses 1252 1253 (* We arrange for the inner function to be called with 1254 the curried arguments in reverse order, but the tupled 1255 arguments in the normal order. For example, the 1256 ML declaration: 1257 1258 fun g a b c = ... gives the order <c,b,a> 1259 fun g (a, b, c) = ... gives the order <a,b,c> 1260 fun g (a, b) c (d, e, f) = ... gives the order <d,e,f,c,a,b> 1261 1262 We want reverse the order of curried arguments to produce 1263 better code. (The last curried argument often gets put 1264 into the first argument register by the normal calling 1265 mechanism, so we try to ensure that it stays there.) 1266 We don't reverse the order of tupled arguments because 1267 I'm still a bit confused about when a tuple is an 1268 argument tuple (reversed?) and when it isn't (not reversed). 1269 1270 Just to add to this, if the function is polymorphic we 1271 have to add the polymorphic arguments on at the end. 1272 1273 *) 1274 local 1275 (* Create the argument type list. I'm sure this can be combined with the 1276 next version of makeArgs but it's all too complicated. *) 1277 fun makeArgs(parms, []) = 1278 let 1279 val polyParms = List.tabulate(nPolyVars, fn _ => GeneralType) 1280 val resTupleSize = resTupleLength 1281 in 1282 if resTupleSize = 1 1283 then parms @ polyParms 1284 else parms @ polyParms @ [GeneralType] 1285 end 1286 | makeArgs(parms, t::ts) = makeArgs (t @ parms, ts) 1287 in 1288 val argTypes = makeArgs ([], tupleSeq) 1289 end 1290 1291 local 1292 (* This function comprises a new declaration level *) 1293 val nArgTypes = List.length argTypes 1294 val fnLevel = newLevel level 1295 1296 val argList : codetree = 1297 if numOfPats = 1 1298 then mkArgTuple(nArgTypes-totalArgs, totalArgs-extraArg-nPolyVars) 1299 else 1300 let 1301 fun makeArgs([], _) = [] 1302 | makeArgs(h::t, n) = mkArgTuple(nArgTypes-n-List.length h, List.length h) :: makeArgs(t, n + List.length h) 1303 in 1304 mkTuple (makeArgs(tupleSeq, extraArg+nPolyVars)) 1305 end 1306 1307 local 1308 val addresses = ref 1 1309 in 1310 fun fnMkAddr n = (! addresses) before (addresses := ! addresses + n) 1311 end 1312 1313 val innerProcName : string = 1314 concat ([procName, "(" , Int.toString totalArgs, ")"]); 1315 1316 local 1317 (* The poly args come after any result tuple. *) 1318 val tupleOffset = if resTupleLength = 1 then 0 else 1 1319 val argAddrs = 1320 List.tabulate(nPolyVars, fn n => fn l => mkLoadParam(n+nArgTypes-nPolyVars-tupleOffset, l, fnLevel)) 1321 val mainTypeVars = ListPair.zipEq(polyVars, argAddrs) 1322 (* Also need to add any variables used by other polymorphic 1323 functions but not in the existing list. This is only for very unusual cases. *) 1324 fun addExtras (fPolyVars, pVarList) = 1325 let 1326 fun checkPolymorphism(fpVar, pVars) = 1327 if isSome(List.find (fn(t, _) => sameTv(t, fpVar)) mainTypeVars) 1328 orelse isSome(List.find (fn (t, _) => sameTv(t, fpVar)) pVars) 1329 then pVars else (fpVar, fn _ => defaultTypeCode) :: pVars 1330 in 1331 List.foldl checkPolymorphism pVarList fPolyVars 1332 end 1333 val extraEntries = List.foldl addExtras [] polyVarList 1334 in 1335 val typevarArgMap = mainTypeVars @ extraEntries 1336 val newTypeVarMap = 1337 extendTypeVarMap(typevarArgMap, fnMkAddr, fnLevel, typeVarMap) 1338 end 1339 1340 val fnContext = 1341 context |> 1342 repNewLevel(innerProcName, fnMkAddr, fnLevel) |> repTypeVarMap newTypeVarMap 1343 1344 (* If we have (mutually) recursive references to polymorphic functions 1345 we need to create local versions applied to the polymorphic variables. 1346 We only need to consider functions that use the polymorphic variables 1347 for this function. If another function uses different variables it 1348 can't be called from this one. If it had been called from this any 1349 type variables would have been fixed as monotypes or the type variables 1350 of this function. 1351 Except this is wrong in one case. If one of the recursive calls involves 1352 an exception (e.g. f (fn _ => raise Fail "") (or perhaps some other case 1353 involving "don't care" polymorphic variables) it is possible to call a 1354 function with more polymorphism. *) 1355 local 1356 fun createApplications(fVal::fVals, addr::addrList, [] :: polyVarList, otherDecs) = 1357 ( 1358 (* Monomorphic functions. *) 1359 setValueAddress(fVal, addr, level); 1360 createApplications(fVals, addrList, polyVarList, otherDecs) 1361 ) 1362 1363 | createApplications( 1364 fVal::fVals, addr::addrList, fPolyVars ::polyVarList, otherDecs) = 1365 let 1366 fun createMatches fpVar = 1367 case List.find (fn(t, _) => sameTv(t, fpVar)) typevarArgMap of 1368 SOME (_, codeFn) => codeFn fnLevel 1369 | NONE => raise InternalError "createMatches: Missing type var" 1370 val polyArgs = List.map createMatches fPolyVars 1371 val newAddr = fnMkAddr 1 1372 val polyFn = mkLoad(addr, fnLevel, level) 1373 (* Set the address to this so if we use this function we pick 1374 up this declaration. *) 1375 val () = setValueAddress(fVal, newAddr, fnLevel); 1376 val newDecs = mkDec(newAddr, mkEval(polyFn, polyArgs)) :: otherDecs 1377 in 1378 createApplications(fVals, addrList, polyVarList, newDecs) 1379 end 1380 1381 | createApplications(_, _, _, decs) = decs 1382 in 1383 val appDecs = 1384 if noInlineFunction then [] (* This may be directly recursive. *) 1385 else createApplications (tlist, addressList, polyVarList, []) 1386 end 1387 1388 local 1389 (* Function body. The debug state has a "start of function" entry that 1390 is used when tracing and points to the arguments. There are then 1391 entries for the recursive functions so they can be used if we 1392 break within the function. *) 1393 fun codeBody fnEntryEnv = 1394 let 1395 val startContext = fnContext |> repDebugEnv fnEntryEnv 1396 (* Create debug entries for recursive references. *) 1397 val (recDecs, recDebugEnv) = makeDebugEntries(functionVars, startContext) 1398 val bodyContext = fnContext |> repDebugEnv recDebugEnv 1399 1400 val codeMatches = 1401 mkEnv(recDecs, codeMatch (near, matches, argList, false, bodyContext)) 1402 in 1403 (* If the result is a tuple we try to avoid creating it by adding 1404 an extra argument to the inline function and setting this to 1405 the result. *) 1406 if resTupleLength = 1 1407 then codeMatches 1408 else 1409 (* The function sets the extra argument to the result 1410 of the body of the function. We use the last 1411 argument for the container so that 1412 other arguments will be passed in registers in 1413 preference. Since the container is used for the 1414 result this argument is more likely to have to be 1415 pushed onto the stack within the function than an 1416 argument which may have its last use early on. *) 1417 mkSetContainer(mkLoadParam(nArgTypes-1, fnLevel, fnLevel), codeMatches, resTupleLength) 1418 end 1419 in 1420 (* If we're debugging add the debug info before resetting the level. *) 1421 val codeForBody = 1422 wrapFunctionInDebug(codeBody, procName, argList, aType, resType, location, fnContext) 1423 end 1424 1425 val () = 1426 if List.length argTypes = totalArgs then () else raise InternalError "Argument length problem" 1427 in 1428 val innerFun = 1429 mkFunction{ 1430 body=mkEnv(getCachedTypeValues newTypeVarMap @ appDecs, codeForBody), 1431 argTypes=argTypes, resultType=resultType, name=innerProcName, 1432 closure=getClosure fnLevel, numLocals=fnMkAddr 0} 1433 end; 1434 1435 (* We now have a function which can be applied to the 1436 arguments once we have them. If the function is curried 1437 we must make a set of nested inline procedures which 1438 will take one of the parameters at a time. If all the 1439 parameters are provided at once they will be 1440 optimised away. *) 1441 1442 val polyLevel = 1443 if null polyVars then level else newLevel level 1444 1445 (* Make into curried functions *) 1446 fun makeFuns(innerLevel, _, mkParms, []) = 1447 let 1448 (* Load a reference to the inner function. *) 1449 val loadInnerFun = mkLoad (addr + 1, innerLevel, level) 1450 val polyParms = 1451 List.tabulate(nPolyVars, fn n => (mkLoadParam(n, innerLevel, polyLevel), GeneralType)) 1452 val resTupleSize = resTupleLength 1453 val parms = mkParms innerLevel 1454 in 1455 (* Got to the bottom. - put in a call to the procedure. *) 1456 if resTupleSize = 1 1457 then (mkCall (loadInnerFun, parms @ polyParms, resultType), 0) 1458 else (* Create a container for the result, side-effect 1459 it in the function, then create a tuple from it. 1460 Most of the time this will be optimised away. *) 1461 let 1462 val containerAddr = 0 (* In a new space *) 1463 val loadContainer = mkLoadLocal containerAddr 1464 in 1465 (mkEnv( 1466 [mkContainer(containerAddr, resTupleSize, 1467 mkCall(loadInnerFun, parms @ polyParms @ [(loadContainer, GeneralType)], GeneralType))], 1468 mkTupleFromContainer(containerAddr, resTupleSize)), 1469 containerAddr+1 (* One local *)) 1470 end 1471 end 1472 | makeFuns(innerLevel, decName, mkParms, t::ts) = 1473 let (* Make a function. *) 1474 val nLevel = newLevel innerLevel 1475 val newDecName : string = decName ^ "(1)" 1476 (* Arguments from this tuple precede older arguments, 1477 but order of arguments within the tuple is preserved. *) 1478 fun nextParms l = loadArgsFromTuple(t, mkLoadParam (0, l, nLevel)) @ mkParms l 1479 val (body, lCount) = makeFuns (nLevel, newDecName, nextParms, ts) 1480 in 1481 (mkInlproc (body, 1, newDecName, getClosure nLevel, lCount), 0) 1482 end (* end makeFuns *); 1483 1484 (* Reset the address of the variable. *) 1485 val () = setValueAddress(fb, addr, level) 1486 in 1487 if noInlineFunction 1488 then (addr, innerFun) :: loadFunDecs(otherDecs, otherPolyVars, otherAddresses) 1489 else 1490 let 1491 val (baseFun, _) = makeFuns (polyLevel, procName, fn _ => [], tupleSeq) 1492 val polyFun = 1493 if null polyVars then baseFun 1494 else mkInlproc(baseFun, List.length polyVars, procName ^ "(P)", getClosure polyLevel, 0) 1495 in 1496 (* Return the `inner' procedure and the inline 1497 functions as a mutually recursive pair. Try putting 1498 the inner function first to see if the optimiser 1499 does better this way. *) 1500 (addr + 1, innerFun) :: (addr, polyFun) :: 1501 loadFunDecs(otherDecs, otherPolyVars, otherAddresses) 1502 end 1503 end (* loadFunDecs *) 1504 | loadFunDecs _ = [] 1505 1506 val loaded = loadFunDecs(tlist, polyVarList, addressList) 1507 1508 (* Set the final addresses in case they have changed. N.B. Do this before 1509 loading any debug references. *) 1510 val () = ListPair.appEq (fn (t, a) => setValueAddress(t, a, level)) (tlist, addressList) 1511 1512 (* Construct the debugging environment for the rest of the scope. *) 1513 1514 val (decEnv, newDebugEnv) = makeDebugEntries(functionVars, context) 1515 (* Check whether any of the functions were unreferenced. *) 1516 val _ = 1517 if getParameter reportUnreferencedIdsTag (debugParams lex) 1518 then reportUnreferencedValues(functionVars, lex) 1519 else () 1520 1521 in 1522 (* Put the declarations into a package of mutual decs. *) 1523 (mkMutualDecs loaded :: decEnv, newDebugEnv) 1524 end (* codeFunBindings *) 1525 1526 (* Recursive val declarations. Turn them into fun-bindings. This avoids duplicating a lot 1527 of code and codeFunBindings does a lot of optimisation. *) 1528 and codeRecValBindings(valDecs, near, context) = 1529 let 1530 (* Turn this into a fun binding. *) 1531 fun valBindToFvalBind(ValBind{ exp, line, variables=ref vars, ...}, fVals) = 1532 let 1533 fun getMatches (Fn { matches: matchtree list, ... }) = matches 1534 | getMatches (Constraint {value, ...}) = getMatches value 1535 | getMatches (Parenthesised(p, _)) = getMatches p 1536 | getMatches _ = raise InternalError "getMatches" 1537 1538 fun matchTreeToClause(MatchTree{vars, exp, location, breakPoint, ...}) = 1539 let 1540 val dec = 1541 { ident = { name="", expType=ref EmptyType, location=location}, 1542 isInfix = false, args=[vars], constraint=NONE} 1543 in 1544 FValClause{dec = dec, exp=exp, line=location, breakPoint = breakPoint } 1545 end 1546 1547 val clauses = List.map matchTreeToClause (getMatches exp) 1548 1549 fun mkFValBind(var as Value{typeOf, ...}) = 1550 let 1551 val argType = mkTypeVar(generalisable, false, false, false) 1552 and resultType = mkTypeVar(generalisable, false, false, false) 1553 val () = 1554 if isSome(unifyTypes(typeOf, mkFunctionType(argType, resultType))) 1555 then raise InternalError "mkFValBind" 1556 else () 1557 in 1558 FValBind { clauses=clauses, numOfPatts=ref 1, functVar=ref var, 1559 argType=ref argType, resultType=ref resultType, location=line } 1560 end 1561 in 1562 fVals @ List.map mkFValBind vars 1563 end 1564 1565 val converted = List.foldl valBindToFvalBind [] valDecs 1566 in 1567 codeFunBindings(converted, near, context) 1568 end (* codeRecValBindings *) 1569 1570 (* Non-recursive val bindings. *) 1571 and codeNonRecValBindings(valBindings, near, originalContext: cgContext as { decName, typeVarMap, lex, isOuterLevel, ...}) = 1572 let 1573 (* Non-recursive val bindings. *) 1574 fun codeBinding (ValBind{dec=vbDec, exp=vbExp, line, variables=ref vars, ...}, otherDecs) = 1575 let (* A binding. *) 1576 (* Get a name for any functions. This is used for profiling and exception trace. *) 1577 val fName = 1578 case vars of [] => "_" | _ => String.concatWith "|" (List.map valName vars) 1579 1580 (* Does this contain polymorphism? *) 1581 val polyVarsForVals = 1582 List.map(fn Value{typeOf, ...} => 1583 filterTypeVars (getPolyTypeVars(typeOf, mapTypeVars typeVarMap))) vars 1584 val polyVars = List.foldl(op @) [] polyVarsForVals 1585 val nPolyVars = List.length polyVars 1586 1587 (* In almost all cases polymorphic declarations are of the form 1588 val a = b or val a = fn ... . They can, though, arise in 1589 pathological cases with arbitrary patterns and complex expressions. 1590 If any of the variables are polymorphic the expression must have been 1591 non-expansive. That means that we can safely evaluate it repeatedly. 1592 There's one exception: it may raise Bind. (e.g. val SOME x = NONE). 1593 For that reason we make sure it is evaluated at least once. 1594 We build the code as a function and then apply it one or more times. 1595 This is really to deal with pathological cases and pretty well all 1596 of this will be optimised away. *) 1597 val localContext as {level, mkAddr, typeVarMap, ...} = 1598 if nPolyVars = 0 1599 then originalContext 1600 else 1601 let 1602 val addresses = ref 1 1603 fun fnMkAddr n = (! addresses) before (addresses := ! addresses + n) 1604 val fnLevel = newLevel (#level originalContext) 1605 val argAddrs = List.tabulate(nPolyVars, fn n => fn l => mkLoadParam(n, l, fnLevel)) 1606 val argMap = ListPair.zipEq(polyVars, argAddrs) 1607 val newTypeVarMap = 1608 extendTypeVarMap(argMap, fnMkAddr, fnLevel, #typeVarMap originalContext) 1609 in 1610 originalContext |> repNewLevel(decName, fnMkAddr, fnLevel) |> repTypeVarMap newTypeVarMap 1611 end 1612 1613 val exp = codegen (vbExp, localContext |> repDecName (decName ^ fName ^ "-")) 1614 (* Save the argument in a variable. *) 1615 val decCode = multipleUses (exp, fn () => mkAddr 1, level) 1616 1617 (* Generate the code and also check for redundancy and exhaustiveness. *) 1618 local 1619 val cmContext = 1620 { mkAddr = mkAddr, level = level, typeVarMap = typeVarMap, lex = lex } 1621 in 1622 val (bindCode, exhaustive) = 1623 codeBindingPattern(vbDec, #load decCode level, line, cmContext) 1624 end 1625 1626 (* Report inexhaustiveness if necessary. *) 1627 val () = 1628 if not exhaustive andalso not isOuterLevel 1629 then errorNear (lex, false, near, line, "Pattern is not exhaustive.") 1630 else () 1631 1632 (* Check for unreferenced variables. *) 1633 val () = 1634 if getParameter reportUnreferencedIdsTag (debugParams lex) 1635 then List.app (reportUnreferencedValue lex) (getVariablesInPatt(vbDec, [])) 1636 else () 1637 1638 val resultCode = 1639 if nPolyVars = 0 then #dec decCode @ bindCode 1640 else 1641 let 1642 fun loadVal(Value{access=Local{addr=ref add, ...}, ...}) = mkLoadLocal add 1643 | loadVal _ = raise InternalError "loadVal" 1644 1645 val outerAddrs = #mkAddr originalContext 1646 and outerLevel = #level originalContext 1647 1648 (* Construct a function that, when applied, returns all the variables. *) 1649 val fnAddr = outerAddrs 1 1650 val resFunction = 1651 mkDec(fnAddr, 1652 mkInlproc( 1653 mkEnv(getCachedTypeValues typeVarMap @ #dec decCode 1654 @ bindCode, mkTuple(List.map loadVal vars)), 1655 nPolyVars, "(P)", getClosure level, mkAddr 0)) 1656 1657 (* Apply the general function to the set of type variables using either the 1658 actual type variables if they are in this particular variable or defaults 1659 if they're not. *) 1660 fun application(pVars, level) = 1661 let 1662 val nPVars = List.length pVars 1663 val varNos = ListPair.zipEq(pVars, List.tabulate(nPVars, fn x=>x)) 1664 fun getArg argV = 1665 case List.find (fn (v, _) => sameTv(v, argV)) varNos of 1666 SOME (_, n) => mkLoadParam(n, level, level) 1667 | NONE => defaultTypeCode 1668 in 1669 mkEval(mkLoad(fnAddr, level, outerLevel), List.map getArg polyVars) 1670 end 1671 1672 (* For each variable construct either a new function if it is polymorphic 1673 or a simple value if it is not (e.g. val (a, b) = (fn x=>x, 1)). 1674 Set the local addresses at the same time. *) 1675 fun loadFunctions(var::vars, polyV::polyVs, n) = 1676 let 1677 val vAddr = outerAddrs 1 1678 val () = 1679 case var of 1680 Value{access=Local{addr, level}, ...} => 1681 (addr := vAddr; level := outerLevel) 1682 | _ => raise InternalError "loadFunctions" 1683 in 1684 mkDec(vAddr, 1685 case polyV of 1686 [] => (* monomorphic *) mkInd(n, application([], outerLevel)) 1687 | _ => (* polymorphic *) 1688 let 1689 val nPolyVars = List.length polyV 1690 val nLevel = newLevel outerLevel 1691 in 1692 mkInlproc( 1693 mkInd(n, application(polyV, nLevel)), 1694 nPolyVars, "(P)", getClosure nLevel, 0) 1695 end 1696 ) :: loadFunctions(vars, polyVs, n+1) 1697 end 1698 | loadFunctions _ = [] 1699 1700 val loadCode = loadFunctions(vars, polyVarsForVals, 0) 1701 in 1702 (* Return the declaration of the function, a dummy application that will 1703 force any pattern checking and raise a Match if necessary and the 1704 declarations of the variables. *) 1705 resFunction :: mkNullDec(application([], outerLevel)) :: loadCode 1706 end 1707 in 1708 otherDecs @ resultCode 1709 end 1710 in 1711 List.foldl codeBinding [] valBindings 1712 end (* codeNonRecValBindings *) 1713 1714 (* Code generates the parse tree. *) 1715 fun gencode 1716 (pt : parsetree, lex: lexan, debugEnv: debuggerStatus, outerLevel, 1717 mkOuterAddresses, outerTypeVarMap, structName: string, continuation) : codeBinding list * debuggerStatus = 1718 codeSequence ([(pt, ref NONE)], [], 1719 {decName=structName, mkAddr=mkOuterAddresses, level=outerLevel, typeVarMap=outerTypeVarMap, 1720 debugEnv=debugEnv, lex=lex, lastDebugLine=ref 0, isOuterLevel = true}, 1721 fn (code: codeBinding list, {debugEnv, typeVarMap, ...}) => continuation(code, debugEnv, typeVarMap)) 1722 1723 (* Types that can be shared. *) 1724 structure Sharing = 1725 struct 1726 type parsetree = parsetree 1727 and lexan = lexan 1728 and codetree = codetree 1729 and environEntry = environEntry 1730 and level = level 1731 and typeVarMap = typeVarMap 1732 and codeBinding = codeBinding 1733 and debuggerStatus = debuggerStatus 1734 end 1735 1736end; 1737 1738