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