## To makePeState (e: Map of Text to CVal) and (f: Map of Text to CFunc) and (d: Int) -> PEState:
Return a new PEStateR with env e and funcs f and depth d and staticEnv (a new Map of Text to CExpr) and specResults (a new Map of Text to CExpr) and onStack (a new Seq of Text).
## To peEnv (st: PEState) -> Map of Text to CVal:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
Return e.
## To peFuncs (st: PEState) -> Map of Text to CFunc:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
Return f.
## To peDepth (st: PEState) -> Int:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
Return d.
## To peStateWithDepth (st: PEState) and (d: Int) -> PEState:
Inspect st:
When PEStateR (e, f, oldD, se, sr, os):
Return a new PEStateR with env e and funcs f and depth d and staticEnv se and specResults sr and onStack os.
## To peSpecResults (st: PEState) -> Map of Text to CExpr:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
Return sr.
## To peOnStack (st: PEState) -> Seq of Text:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
Return os.
## To peStateWithEnvDepth (st: PEState) and (newEnv: Map of Text to CVal) and (d: Int) -> PEState:
Inspect st:
When PEStateR (e, f, oldD, se, sr, os):
Return a new PEStateR with env newEnv and funcs f and depth d and staticEnv (a new Map of Text to CExpr) and specResults sr and onStack (copy of os).
## To peStaticEnv (st: PEState) -> Map of Text to CExpr:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
Return se.
## To peEnvBind (m: mutable Map of Text to CVal) and (k: Text) and (v: CVal):
Set item k of m to v.
## To peEnvDrop (m: mutable Map of Text to CVal) and (k: Text):
Remove k from m.
## To peSeBind (m: mutable Map of Text to CExpr) and (k: Text) and (v: CExpr):
Set item k of m to v.
## To peSeDrop (m: mutable Map of Text to CExpr) and (k: Text):
Remove k from m.
## To peOsPush (s: mutable Seq of Text) and (v: Text):
Push v to s.
## To peFuncBind (m: mutable Map of Text to CFunc) and (k: Text) and (v: CFunc):
Set item k of m to v.
## To peStateWithStaticBinding (st: PEState) and (name: Text) and (val: CExpr) -> PEState:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
peSeBind(se, name, val).
Return a new PEStateR with env e and funcs f and depth d and staticEnv se and specResults sr and onStack os.
## To peStateRemoveStatic (st: PEState) and (name: Text) -> PEState:
Inspect st:
When PEStateR (e, f, d, se, sr, os):
peSeDrop(se, name).
Return a new PEStateR with env e and funcs f and depth d and staticEnv se and specResults sr and onStack os.
## To peStateWithEnvDepthStatic (st: PEState) and (newEnv: Map of Text to CVal) and (d: Int) and (newSe: Map of Text to CExpr) -> PEState:
Inspect st:
When PEStateR (e, f, oldD, se, sr, os):
Return a new PEStateR with env newEnv and funcs f and depth d and staticEnv newSe and specResults sr and onStack (copy of os).
## To isVNothing (v: CVal) -> Bool:
Inspect v:
When VNothing:
Return true.
Otherwise:
Return false.
## To isLiteral (e: CExpr) -> Bool:
Inspect e:
When CInt (v):
Return true.
When CBool (v):
Return true.
When CText (v):
Return true.
When CFloat (v):
Return true.
Otherwise:
Return false.
## To exprToVal (e: CExpr) -> CVal:
Inspect e:
When CInt (v):
Return a new VInt with value v.
When CBool (v):
Return a new VBool with value v.
When CText (v):
Return a new VText with value v.
When CFloat (v):
Return a new VFloat with value v.
When CList (items):
Let vals be a new Seq of CVal.
Repeat for elem in items:
Push exprToVal(elem) to vals.
Return a new VSeq with items vals.
When CNewVariant (tag, names, vals):
Let vvals be a new Seq of CVal.
Repeat for v in vals:
Push exprToVal(v) to vvals.
Return a new VVariant with typeName tag and variantName tag and fields vvals.
When CNew (typeName, fieldNames, fieldExprs):
If typeName equals "Map":
Return a new VMap with entries a new Map of Text to CVal.
Let vvals be a new Seq of CVal.
Repeat for fe in fieldExprs:
Push exprToVal(fe) to vvals.
Return a new VVariant with typeName typeName and variantName typeName and fields vvals.
When CTuple (items):
Let vals be a new Seq of CVal.
Repeat for elem in items:
Push exprToVal(elem) to vals.
Return a new VTuple with items vals.
When CCopy (target):
Return exprToVal(target).
Otherwise:
Return a new VNothing.
## To valToExpr (v: CVal) -> CExpr:
Inspect v:
When VInt (n):
Return a new CInt with value n.
When VBool (b):
Return a new CBool with value b.
When VText (s):
Return a new CText with value s.
When VFloat (f):
Return a new CFloat with value f.
When VSeq (items):
Let exprs be a new Seq of CExpr.
Repeat for elem in items:
Push valToExpr(elem) to exprs.
Return a new CList with items exprs.
When VVariant (vTypeName, vVarName, vFields):
Let exprs be a new Seq of CExpr.
Repeat for v in vFields:
Push valToExpr(v) to exprs.
Return a new CNewVariant with tag vVarName and fnames (a new Seq of Text) and fvals exprs.
When VTuple (items):
Let exprs be a new Seq of CExpr.
Repeat for elem in items:
Push valToExpr(elem) to exprs.
Return a new CTuple with items exprs.
When VOption (inner, present):
If present:
Return a new COptionSome with inner (valToExpr(inner)).
Return a new COptionNone.
When VMap (entries):
Return a new CNew with typeName "Map" and fieldNames (a new Seq of Text) and fields (a new Seq of CExpr).
Otherwise:
Return a new CVar with name "__unresolvable".
## To evalBinOp (binOp: Text) and (lv: CVal) and (rv: CVal) -> CVal:
Inspect lv:
When VInt (a):
Inspect rv:
When VInt (b):
If binOp equals "+":
Return a new VInt with value (a + b).
If binOp equals "-":
Return a new VInt with value (a - b).
If binOp equals "*":
Return a new VInt with value (a * b).
If binOp equals "/":
If b equals 0:
Return a new VNothing.
Return a new VInt with value (a / b).
If binOp equals "%":
If b equals 0:
Return a new VNothing.
Return a new VInt with value (a % b).
If binOp equals "<":
Return a new VBool with value (a is less than b).
If binOp equals ">":
Return a new VBool with value (a is greater than b).
If binOp equals "<=":
Return a new VBool with value (a is at most b).
If binOp equals ">=":
Return a new VBool with value (a is at least b).
If binOp equals "==":
Return a new VBool with value (a equals b).
If binOp equals "!=":
Return a new VBool with value (a is not b).
If binOp equals "^":
Return a new VInt with value (a xor b).
If binOp equals "<<":
Return a new VInt with value (a shifted left by b).
If binOp equals ">>":
Return a new VInt with value (a shifted right by b).
Return a new VNothing.
When VFloat (b):
If binOp equals "+":
Return a new VFloat with value (a + b).
If binOp equals "-":
Return a new VFloat with value (a - b).
If binOp equals "*":
Return a new VFloat with value (a * b).
If binOp equals "/":
If b equals 0.0:
Return a new VNothing.
Return a new VFloat with value (a / b).
If binOp equals "<":
Return a new VBool with value (a is less than b).
If binOp equals ">":
Return a new VBool with value (a is greater than b).
If binOp equals "<=":
Return a new VBool with value (a is at most b).
If binOp equals ">=":
Return a new VBool with value (a is at least b).
If binOp equals "==":
Return a new VBool with value (a equals b).
If binOp equals "!=":
Return a new VBool with value (a is not b).
Return a new VNothing.
Otherwise:
Return a new VNothing.
When VFloat (a):
Inspect rv:
When VFloat (b):
If binOp equals "+":
Return a new VFloat with value (a + b).
If binOp equals "-":
Return a new VFloat with value (a - b).
If binOp equals "*":
Return a new VFloat with value (a * b).
If binOp equals "/":
If b equals 0.0:
Return a new VNothing.
Return a new VFloat with value (a / b).
If binOp equals "<":
Return a new VBool with value (a is less than b).
If binOp equals ">":
Return a new VBool with value (a is greater than b).
If binOp equals "<=":
Return a new VBool with value (a is at most b).
If binOp equals ">=":
Return a new VBool with value (a is at least b).
If binOp equals "==":
Return a new VBool with value (a equals b).
If binOp equals "!=":
Return a new VBool with value (a is not b).
Return a new VNothing.
When VInt (b):
If binOp equals "+":
Return a new VFloat with value (a + b).
If binOp equals "-":
Return a new VFloat with value (a - b).
If binOp equals "*":
Return a new VFloat with value (a * b).
If binOp equals "/":
If b equals 0:
Return a new VNothing.
Return a new VFloat with value (a / b).
If binOp equals "<":
Return a new VBool with value (a is less than b).
If binOp equals ">":
Return a new VBool with value (a is greater than b).
If binOp equals "<=":
Return a new VBool with value (a is at most b).
If binOp equals ">=":
Return a new VBool with value (a is at least b).
If binOp equals "==":
Return a new VBool with value (a equals b).
If binOp equals "!=":
Return a new VBool with value (a is not b).
Return a new VNothing.
Otherwise:
Return a new VNothing.
When VBool (a):
Inspect rv:
When VBool (b):
If binOp equals "&&":
Return a new VBool with value (a and b).
If binOp equals "||":
Return a new VBool with value (a or b).
If binOp equals "==":
Return a new VBool with value (a equals b).
If binOp equals "!=":
Return a new VBool with value (a is not b).
Return a new VNothing.
Otherwise:
Return a new VNothing.
When VText (a):
Inspect rv:
When VText (b):
If binOp equals "+":
Let joined be "{a}{b}".
Return a new VText with value joined.
If binOp equals "==":
Return a new VBool with value (a equals b).
If binOp equals "!=":
Return a new VBool with value (a is not b).
Return a new VNothing.
When VInt (b):
If binOp equals "+":
Let joined be "{a}{b}".
Return a new VText with value joined.
Return a new VNothing.
When VBool (b):
If binOp equals "+":
If b:
Let joinedT be "{a}true".
Return a new VText with value joinedT.
Otherwise:
Let joinedF be "{a}false".
Return a new VText with value joinedF.
Return a new VNothing.
Otherwise:
Return a new VNothing.
Otherwise:
Return a new VNothing.
## To isStatic (e: CExpr) -> Bool:
Inspect e:
When CInt (v):
Return true.
When CBool (v):
Return true.
When CText (v):
Return true.
When CFloat (v):
Return true.
When CList (items):
Repeat for elem in items:
Let s be isStatic(elem).
If not s:
Return false.
Return true.
When CNewVariant (tag, names, vals):
Repeat for v in vals:
Let s be isStatic(v).
If not s:
Return false.
Return true.
When CTuple (items):
Repeat for elem in items:
Let s be isStatic(elem).
If not s:
Return false.
Return true.
When COptionSome (inner):
Return isStatic(inner).
When COptionNone:
Return true.
When CNewSeq:
Return true.
When CNewSet:
Return true.
When CNew (typeName, fieldNames, fieldExprs):
Repeat for fe in fieldExprs:
Let s be isStatic(fe).
If not s:
Return false.
Return true.
When CRange (start, end):
Let s1 be isStatic(start).
Let s2 be isStatic(end).
Return (s1 and s2).
When CCopy (target):
Return isStatic(target).
When CClosure (clp, clb, clc):
Return true.
Otherwise:
Return false.
## To isStaticValue (e: CExpr) -> Bool:
Inspect e:
When CNewSeq:
Return false.
When CNewSet:
Return false.
When CList (litems):
Return false.
When CNew (isvTy, isvNames, isvFields):
If isvTy equals "Map":
Return false.
Return isStatic(e).
Otherwise:
Return isStatic(e).
## To isCopyPropSafe (e: CExpr) -> Bool:
Inspect e:
When CNewSeq:
Return false.
When CNewSet:
Return false.
Otherwise:
Return true.
## To isPeValueForCopyProp (e: CExpr) -> Bool:
Let sv be isStaticValue(e).
If sv:
Return true.
Inspect e:
When CList (cpvItems):
Return true.
When CTuple (cpvTup):
Return true.
When CNew (cpvTy, cpvNames, cpvVals):
Return true.
When CNewVariant (cpvTag, cpvNms, cpvVls):
Return true.
When COptionSome (cpvInner):
Return true.
When CRange (cpvS, cpvE):
Return true.
Otherwise:
Return false.
## To exprRefsAnyMutated (e: CExpr) and (muts: Seq of Text) -> Bool:
Inspect e:
When CVar (ravVn):
Repeat for ravM in muts:
If ravVn is equal to ravM:
Return true.
Return false.
When CBinOp (ravOp, ravL, ravR):
Let ravA be exprRefsAnyMutated(ravL, muts).
If ravA:
Return true.
Return exprRefsAnyMutated(ravR, muts).
When CNot (ravNi):
Return exprRefsAnyMutated(ravNi, muts).
When CIndex (ravIc, ravIi):
Let ravB be exprRefsAnyMutated(ravIc, muts).
If ravB:
Return true.
Return exprRefsAnyMutated(ravIi, muts).
When CLen (ravLt):
Return exprRefsAnyMutated(ravLt, muts).
When CFieldAccess (ravFt, ravFf):
Return exprRefsAnyMutated(ravFt, muts).
When CMapGet (ravMt, ravMk):
Let ravC be exprRefsAnyMutated(ravMt, muts).
If ravC:
Return true.
Return exprRefsAnyMutated(ravMk, muts).
When CContains (ravCc, ravCe):
Let ravD be exprRefsAnyMutated(ravCc, muts).
If ravD:
Return true.
Return exprRefsAnyMutated(ravCe, muts).
When CSlice (ravSc, ravSs, ravSe):
Let ravE be exprRefsAnyMutated(ravSc, muts).
If ravE:
Return true.
Let ravF be exprRefsAnyMutated(ravSs, muts).
If ravF:
Return true.
Return exprRefsAnyMutated(ravSe, muts).
When CUnion (ravUl, ravUr):
Let ravG be exprRefsAnyMutated(ravUl, muts).
If ravG:
Return true.
Return exprRefsAnyMutated(ravUr, muts).
When CIntersection (ravIl, ravIr):
Let ravH be exprRefsAnyMutated(ravIl, muts).
If ravH:
Return true.
Return exprRefsAnyMutated(ravIr, muts).
When CCopy (ravCt):
Return exprRefsAnyMutated(ravCt, muts).
When CInt (ravVi):
Return false.
When CBool (ravVb):
Return false.
When CText (ravVt):
Return false.
When CFloat (ravVf):
Return false.
Otherwise:
Return true.
## To shouldCopyProp (e: CExpr) and (muts: Seq of Text) -> Bool:
Let scpSv be isPeValueForCopyProp(e).
If scpSv:
Return true.
Let scpRm be exprRefsAnyMutated(e, muts).
If scpRm:
Return false.
Return true.
## To isRefAggregate (e: CExpr) -> Bool:
Inspect e:
When CList (items):
Return true.
When CNewSeq:
Return true.
When CNewSet:
Return true.
Otherwise:
Return false.
## To hasKnownTag (e: CExpr) -> Bool:
Inspect e:
When CNewVariant (tag, names, vals):
Return true.
When CNew (typeName, fieldNames, fieldExprs):
Return true.
Otherwise:
Return false.
## To allStatic (args: Seq of CExpr) -> Bool:
Repeat for a in args:
Let s be isStatic(a).
If not s:
Return false.
Return true.
## To allLiteral (args: Seq of CExpr) -> Bool:
Repeat for a in args:
Let lit be isLiteral(a).
If not lit:
Return false.
Return true.
## To dynamicOnly (args: Seq of CExpr) -> Bool:
Repeat for a in args:
Let lit be isLiteral(a).
If lit:
Return false.
Return true.
## To dynamicArgs (args: Seq of CExpr) -> Seq of CExpr:
Let filtered be a new Seq of CExpr.
Repeat for a in args:
Let lit be isLiteral(a).
If not lit:
Push a to filtered.
Return filtered.
## To hasReturn (stmts: Seq of CStmt) -> Bool:
Repeat for s in stmts:
Inspect s:
When CReturn (retExpr):
Return true.
Otherwise:
Let skip be true.
Return false.
## To hasBreak (stmts: Seq of CStmt) -> Bool:
Repeat for s in stmts:
Inspect s:
When CBreak:
Return true.
Otherwise:
Let skip be true.
Return false.
## To seqDropLast (items: Seq of CExpr) -> Seq of CExpr:
Let result be a new Seq of CExpr.
Let n be length of items.
Let mutable idx be 1.
Repeat for it in items:
If idx is less than n:
Push it to result.
Set idx to idx + 1.
Return result.
## To keyJoin (acc: Text) and (part: Text) -> Text:
Let n be length of part.
Return "{acc}_{n}_{part}".
## To exprToKeyPart (e: CExpr) -> Text:
Inspect e:
When CInt (v):
Return "i{v}".
When CBool (v):
If v:
Return "btrue".
Return "bfalse".
When CText (v):
Return "t{v}".
When CFloat (v):
Return "f{v}".
When CList (items):
Let mutable parts be "l".
Repeat for elem in items:
Let ep be exprToKeyPart(elem).
Set parts to keyJoin(parts, ep).
Return parts.
When CNewVariant (tag, names, vals):
Let mutable parts be keyJoin("v", tag).
Repeat for fv in vals:
Let vp be exprToKeyPart(fv).
Set parts to keyJoin(parts, vp).
Return parts.
When CTuple (items):
Let mutable parts be "tp".
Repeat for elem in items:
Let ep be exprToKeyPart(elem).
Set parts to keyJoin(parts, ep).
Return parts.
When COptionSome (inner):
Let ip be exprToKeyPart(inner).
Return keyJoin("s", ip).
When COptionNone:
Return "none".
When CNewSeq:
Return "seq".
When CNewSet:
Return "set".
When CVar (varName):
Return "var{varName}".
When CBinOp (op, left, right):
Let lp be exprToKeyPart(left).
Let rp be exprToKeyPart(right).
Let opTag be "op{op}".
Let s1 be keyJoin(opTag, lp).
Return keyJoin(s1, rp).
When CNot (inner):
Let ip be exprToKeyPart(inner).
Return keyJoin("nt", ip).
When CCall (fnName, args):
Let mutable parts be "call{fnName}".
Repeat for a in args:
Let ap be exprToKeyPart(a).
Set parts to keyJoin(parts, ap).
Return parts.
When CIndex (coll, idx):
Let cp be exprToKeyPart(coll).
Let ip be exprToKeyPart(idx).
Let s1 be keyJoin("idx", cp).
Return keyJoin(s1, ip).
When CLen (target):
Let tp be exprToKeyPart(target).
Return keyJoin("len", tp).
When CMapGet (mapExpr, key):
Let mp be exprToKeyPart(mapExpr).
Let kp be exprToKeyPart(key).
Let s1 be keyJoin("mg", mp).
Return keyJoin(s1, kp).
When CFieldAccess (target, field):
Let tp be exprToKeyPart(target).
Let s1 be keyJoin("fa", field).
Return keyJoin(s1, tp).
When CNew (typeName, fieldNames, fieldExprs):
Let mutable parts be keyJoin("nw", typeName).
Repeat for fv in fieldExprs:
Let vp be exprToKeyPart(fv).
Set parts to keyJoin(parts, vp).
Return parts.
When CRange (start, end):
Let sp be exprToKeyPart(start).
Let ep be exprToKeyPart(end).
Let s1 be keyJoin("r", sp).
Return keyJoin(s1, ep).
When CSlice (coll, startIdx, endIdx):
Let cp be exprToKeyPart(coll).
Let sp be exprToKeyPart(startIdx).
Let ep be exprToKeyPart(endIdx).
Let s1 be keyJoin("sl", cp).
Let s2 be keyJoin(s1, sp).
Return keyJoin(s2, ep).
When CCopy (target):
Let tp be exprToKeyPart(target).
Return keyJoin("cp", tp).
When CContains (coll, elem):
Let cp be exprToKeyPart(coll).
Let ep be exprToKeyPart(elem).
Let s1 be keyJoin("ct", cp).
Return keyJoin(s1, ep).
When CUnion (left, right):
Let lp be exprToKeyPart(left).
Let rp be exprToKeyPart(right).
Let s1 be keyJoin("un", lp).
Return keyJoin(s1, rp).
When CIntersection (left, right):
Let lp be exprToKeyPart(left).
Let rp be exprToKeyPart(right).
Let s1 be keyJoin("ix", lp).
Return keyJoin(s1, rp).
When CClosure (params, body, captured):
Return "cl".
When CCallExpr (target, args):
Let tp be exprToKeyPart(target).
Return keyJoin("ce", tp).
When CInterpolatedString (parts):
Let mutable ps be "is".
Repeat for p in parts:
Inspect p:
When CLiteralPart (litVal):
Let litTag be "lt{litVal}".
Set ps to keyJoin(ps, litTag).
When CExprPart (epExpr):
Let pp be exprToKeyPart(epExpr).
Set ps to keyJoin(ps, pp).
Return ps.
When CDuration (amount, unit):
Let ap be exprToKeyPart(amount).
Let s1 be keyJoin("dur", ap).
Return keyJoin(s1, unit).
When CTimeNow:
Return "tnow".
When CDateToday:
Return "today".
When CEscExpr (code):
Return "esc".
Otherwise:
Return "unk".
## To makeKey (fnName: Text) and (args: Seq of CExpr) -> Text:
Let key be fnName.
Repeat for a in args:
Let part be exprToKeyPart(a).
Set key to keyJoin(key, part).
Return key.
## To exprEmbeds (prevExpr: CExpr) and (nextExpr: CExpr) -> Bool:
Inspect prevExpr:
When CInt (a):
Inspect nextExpr:
When CInt (b):
Let mutable absA be a.
If a is less than 0:
Set absA to 0 - a.
Let mutable absB be b.
If b is less than 0:
Set absB to 0 - b.
Return (absA is at most absB).
Otherwise:
Return false.
When CBool (a):
Inspect nextExpr:
When CBool (b):
Return true.
Otherwise:
Return false.
When CText (a):
Inspect nextExpr:
When CText (b):
Return (length of a is at most length of b).
Otherwise:
Return false.
When CFloat (a):
Inspect nextExpr:
When CFloat (b):
Return true.
Otherwise:
Return false.
When CVar (a):
Inspect nextExpr:
When CVar (b):
Return true.
Otherwise:
Return false.
When CBinOp (op1, l1, r1):
Inspect nextExpr:
When CBinOp (op2, l2, r2):
If op1 equals op2:
Return (exprEmbeds(l1, l2) and exprEmbeds(r1, r2)).
Return false.
Otherwise:
Return false.
When CCall (fn1, args1):
Inspect nextExpr:
When CCall (fn2, args2):
If fn1 equals fn2:
Let len1 be length of args1.
Let len2 be length of args2.
If len1 equals len2:
Let mutable allEmbed be true.
Let mutable eidx be 1.
Repeat for a1 in args1:
If eidx is at most len2:
Let a2 be item eidx of args2.
If not exprEmbeds(a1, a2):
Set allEmbed to false.
Set eidx to eidx + 1.
Return allEmbed.
Return false.
Otherwise:
Return false.
When CList (items1):
Inspect nextExpr:
When CList (items2):
Let li1 be length of items1.
Let li2 be length of items2.
If li1 is at most li2:
Return true.
Return false.
Otherwise:
Return false.
Otherwise:
Return false.
## To argsStrictlyEmbed (prevExpr: Seq of CExpr) and (nextExpr: Seq of CExpr) -> Bool:
Let lenE be length of prevExpr.
Let lenL be length of nextExpr.
If not (lenE equals lenL):
Return false.
Let mutable allEmbed be true.
Let mutable someStrict be false.
Let mutable aidx be 1.
Repeat for ea in prevExpr:
If aidx is at most lenL:
Let la be item aidx of nextExpr.
If not exprEmbeds(ea, la):
Set allEmbed to false.
If not exprEmbeds(la, ea):
Set someStrict to true.
Set aidx to aidx + 1.
Return (allEmbed and someStrict).
## To makeCycleKey (fnName: Text) and (args: Seq of CExpr) -> Text:
Let key be fnName.
Repeat for a in args:
If isStatic(a):
Let part be exprToKeyPart(a).
Set key to keyJoin(key, part).
Otherwise:
Set key to keyJoin(key, "d").
Return key.
## To substExpr (e: CExpr) and (name: Text) and (repl: CExpr) -> CExpr:
Inspect e:
When CVar (vn):
If vn equals name:
Return copy of repl.
Return e.
When CBinOp (op, l, r):
Let nl be substExpr(l, name, repl).
Let nr be substExpr(r, name, repl).
Return a new CBinOp with op op and left nl and right nr.
When CNot (inner):
Let ni be substExpr(inner, name, repl).
Return a new CNot with inner ni.
When CCall (cfn, args):
Let nargs be a new Seq of CExpr.
Repeat for a in args:
Push substExpr(a, name, repl) to nargs.
Return a new CCall with name cfn and args nargs.
When CCallExpr (tgt, ceargs):
Let nt be substExpr(tgt, name, repl).
Let nca be a new Seq of CExpr.
Repeat for a in ceargs:
Push substExpr(a, name, repl) to nca.
Return a new CCallExpr with target nt and args nca.
When CIndex (coll, idx):
Let nc be substExpr(coll, name, repl).
Let nidx be substExpr(idx, name, repl).
Return a new CIndex with coll nc and idx nidx.
When CMapGet (t, k):
Let nt2 be substExpr(t, name, repl).
Let nk be substExpr(k, name, repl).
Return a new CMapGet with target nt2 and key nk.
When CLen (t):
Let nt3 be substExpr(t, name, repl).
Return a new CLen with target nt3.
When CContains (coll, elem):
Let nco be substExpr(coll, name, repl).
Let nel be substExpr(elem, name, repl).
Return a new CContains with coll nco and elem nel.
When CList (items):
Let nitems be a new Seq of CExpr.
Repeat for it in items:
Push substExpr(it, name, repl) to nitems.
Return a new CList with items nitems.
When CTuple (titems):
Let ntitems be a new Seq of CExpr.
Repeat for it in titems:
Push substExpr(it, name, repl) to ntitems.
Return a new CTuple with items ntitems.
When CNewVariant (nvTag, nvNames, nvVals):
Let nnv be a new Seq of CExpr.
Repeat for v in nvVals:
Push substExpr(v, name, repl) to nnv.
Return a new CNewVariant with tag nvTag and fnames nvNames and fvals nnv.
When CNew (cnTy, cnNames, cnFields):
Let ncn be a new Seq of CExpr.
Repeat for v in cnFields:
Push substExpr(v, name, repl) to ncn.
Return a new CNew with typeName cnTy and fieldNames cnNames and fields ncn.
When CRange (rs, re):
Let nrs be substExpr(rs, name, repl).
Let nre be substExpr(re, name, repl).
Return a new CRange with start nrs and end nre.
When CSlice (sc, ss, se2):
Let nsc be substExpr(sc, name, repl).
Let nss be substExpr(ss, name, repl).
Let nse be substExpr(se2, name, repl).
Return a new CSlice with coll nsc and startIdx nss and endIdx nse.
When CCopy (ct):
Let nct be substExpr(ct, name, repl).
Return a new CCopy with target nct.
When CUnion (ul, ur):
Let nul be substExpr(ul, name, repl).
Let nur be substExpr(ur, name, repl).
Return a new CUnion with left nul and right nur.
When CIntersection (il, ir):
Let nil be substExpr(il, name, repl).
Let nir be substExpr(ir, name, repl).
Return a new CIntersection with left nil and right nir.
When COptionSome (osinner):
Let nos be substExpr(osinner, name, repl).
Return a new COptionSome with inner nos.
When CFieldAccess (fatarget, fafield):
Let nfa be substExpr(fatarget, name, repl).
Return a new CFieldAccess with target nfa and field fafield.
Otherwise:
Return e.
## To applyPosFacts (cond: CExpr) and (se: mutable Map of Text to CExpr) -> Bool:
Inspect cond:
When CBinOp (cop, cleft, cright):
If cop equals "&&":
Let posL be applyPosFacts(cleft, se).
Let posR be applyPosFacts(cright, se).
Return true.
If cop equals "==":
Inspect cleft:
When CVar (vn):
If isLiteral(cright):
Let vk be "{vn}".
Let crCopy be copy of cright.
Set item vk of se to crCopy.
Otherwise:
Let skpP1 be true.
Inspect cright:
When CVar (vn2):
If isLiteral(cleft):
Let vk2 be "{vn2}".
Let clCopy be copy of cleft.
Set item vk2 of se to clCopy.
Otherwise:
Let skpP2 be true.
Return true.
Return true.
Otherwise:
Return true.
## To applyNegFacts (cond: CExpr) and (se: mutable Map of Text to CExpr) -> Bool:
Inspect cond:
When CBinOp (cop, cleft, cright):
If cop equals "==":
Inspect cleft:
When CVar (vn):
If isLiteral(cright):
Let vk be "__neg_{vn}".
Let crCopy be copy of cright.
Set item vk of se to crCopy.
Otherwise:
Let skpN1 be true.
Inspect cright:
When CVar (vn2):
If isLiteral(cleft):
Let vk2 be "__neg_{vn2}".
Let clCopy be copy of cleft.
Set item vk2 of se to clCopy.
Otherwise:
Let skpN2 be true.
Return true.
Return true.
Otherwise:
Return true.
## To clearGuardFacts (cond: CExpr) and (se: mutable Map of Text to CExpr) -> Bool:
Inspect cond:
When CBinOp (cop, cleft, cright):
If cop equals "&&":
Let cgL be clearGuardFacts(cleft, se).
Let cgR be clearGuardFacts(cright, se).
Return true.
If cop equals "==":
Inspect cleft:
When CVar (vn):
Let vk be "{vn}".
If se contains vk:
Remove vk from se.
Let nk be "__neg_{vn}".
If se contains nk:
Remove nk from se.
Otherwise:
Let skpC1 be true.
Inspect cright:
When CVar (vn2):
Let vk2 be "{vn2}".
If se contains vk2:
Remove vk2 from se.
Let nk2 be "__neg_{vn2}".
If se contains nk2:
Remove nk2 from se.
Otherwise:
Let skpC2 be true.
Return true.
Return true.
Otherwise:
Return true.
## To checkNegEq (varExpr: CExpr) and (litExpr: CExpr) and (state: PEState) -> Bool:
Inspect varExpr:
When CVar (vn):
If isLiteral(litExpr):
Let se be peStaticEnv(state).
Let nk be "__neg_{vn}".
If se contains nk:
Let excluded be item nk of se.
Let ek1 be exprToKeyPart(excluded).
Let ek2 be exprToKeyPart(litExpr).
Let ek1s be "{ek1}".
Let ek2s be "{ek2}".
If ek1s equals ek2s:
Return true.
Return false.
Otherwise:
Return false.
## To peExpr (e: CExpr) and (state: PEState) -> CExpr:
Let env be peEnv(state).
Let funcs be peFuncs(state).
Let depth be peDepth(state).
Inspect e:
When CInt (v):
Return a new CInt with value v.
When CBool (v):
Return a new CBool with value v.
When CText (v):
Return a new CText with value v.
When CVar (varName):
Let sEnv be peStaticEnv(state).
Let svn be "{varName}".
If sEnv contains svn:
Let staticVal be item svn of sEnv.
Return staticVal.
Let vn be "{varName}".
If env contains vn:
Let val be item vn of env.
Let dyn be isVNothing(val).
If dyn:
Return a new CVar with name varName.
Return valToExpr(val).
Return a new CVar with name varName.
When CBinOp (binOp, left, right):
Let peLeft be peExpr(left, state).
Let peRight be peExpr(right, state).
Let leftLit be isLiteral(peLeft).
Let rightLit be isLiteral(peRight).
If leftLit and rightLit:
Let lv be exprToVal(peLeft).
Let rv be exprToVal(peRight).
Let computed be evalBinOp(binOp, lv, rv).
Let unfoldable be isVNothing(computed).
If unfoldable:
Return a new CBinOp with op binOp and left peLeft and right peRight.
Return valToExpr(computed).
If binOp equals "==":
Let negFalse be checkNegEq(peLeft, peRight, state).
If negFalse:
Return a new CBool with value false.
Let negFalse2 be checkNegEq(peRight, peLeft, state).
If negFalse2:
Return a new CBool with value false.
Return a new CBinOp with op binOp and left peLeft and right peRight.
When CNot (inner):
Let peInner be peExpr(inner, state).
Let innerLit be isLiteral(peInner).
If innerLit:
Inspect peInner:
When CBool (b):
Return a new CBool with value (not b).
Otherwise:
Return a new CNot with inner peInner.
Return a new CNot with inner peInner.
When CCall (fnName, argExprs):
If depth is at most 0:
Let residArgs be a new Seq of CExpr.
Repeat for a in argExprs:
Push peExpr(a, peStateWithDepth(state, 0)) to residArgs.
Return a new CCall with name fnName and args residArgs.
Let fn1 be "{fnName}".
Let peArgs be a new Seq of CExpr.
Repeat for a in argExprs:
Push peExpr(a, state) to peArgs.
Let fnClKey be "{fnName}".
Let sEnvFC be peStaticEnv(state).
If sEnvFC contains fnClKey:
Let fcVal be item fnClKey of sEnvFC.
Inspect fcVal:
When CClosure (clParams, clBody, clCaptured):
Let clCallEnv be copy of env.
Let clChildSe be copy of sEnvFC.
Let mutable cpi be 1.
Repeat for clp in clParams:
Let clArg be item cpi of peArgs.
Let clpk be "{clp}".
Let clArgC be copy of clArg.
Set item clpk of clChildSe to clArgC.
Let clpk2 be "{clp}".
If isStatic(clArg):
Set item clpk2 of clCallEnv to exprToVal(clArg).
Otherwise:
Set item clpk2 of clCallEnv to a new VNothing.
Set cpi to cpi + 1.
Let clFuncs be peFuncs(state).
Let clSr be peSpecResults(state).
Let clOs be peOnStack(state).
Let clState be a new PEStateR with env clCallEnv and funcs clFuncs and depth (depth - 1) and staticEnv clChildSe and specResults clSr and onStack clOs.
Let clBodyRes be peBlock(clBody, clState).
Let clRaw be extractReturn(clBodyRes).
Let clResult be validateExtractReturn(clRaw, clBodyRes).
Inspect clResult:
When CVar (clrn):
If clrn equals "__no_return__":
Let clResidArgs be copy of peArgs.
Let clTargetExpr be a new CVar with name fnName.
Return a new CCallExpr with target clTargetExpr and args clResidArgs.
Otherwise:
Let skipClR be true.
Return clResult.
Otherwise:
Let skipFCv be true.
Let allStat be allStatic(peArgs).
If allStat:
Let memoKey be makeKey(fn1, peArgs).
Let memoKeyStr be "{memoKey}".
Let specRes be peSpecResults(state).
Let mk0 be "{memoKeyStr}".
If specRes contains mk0:
Let cached be item mk0 of specRes.
Return cached.
Let memoCache be peOnStack(state).
Let mk1 be "{memoKeyStr}".
If memoCache contains mk1:
Return a new CCall with name fn1 and args peArgs.
Let embedKey be "__embed_{fn1}".
Let embedKeyStr be "{embedKey}".
If specRes contains embedKeyStr:
Let prevArgsList be item embedKeyStr of specRes.
Inspect prevArgsList:
When CList (prevSnapshots):
Repeat for prevSnapshot in prevSnapshots:
Inspect prevSnapshot:
When CList (prevArgs):
If argsStrictlyEmbed(prevArgs, peArgs):
Return a new CCall with name fn1 and args peArgs.
Otherwise:
Let skipSnap be true.
Otherwise:
Let skipPrev be true.
Let embedKeyStr2 be "{embedKey}".
Let mutable newSnapshots be a new Seq of CExpr.
If specRes contains embedKeyStr2:
Let existingList be item embedKeyStr2 of specRes.
Inspect existingList:
When CList (existingSnaps):
Repeat for es in existingSnaps:
Push es to newSnapshots.
Otherwise:
Let skipExist be true.
Let peArgsCopy be copy of peArgs.
Push (a new CList with items peArgsCopy) to newSnapshots.
Let embedKeyStr3 be "{embedKey}".
Let newSnapWrap be a new CList with items newSnapshots.
peSeBind(specRes, embedKeyStr3, newSnapWrap).
Let fn2 be "{fn1}".
Let func be item fn2 of funcs.
Inspect func:
When CFuncDef (fname, params, fnParamTypes, fnReturnType, body):
Let callEnv be a new Map of Text to CVal.
Let childSEnv be a new Map of Text to CExpr.
Let mutable pidx be 1.
Repeat for p in params:
Let argExpr be item pidx of peArgs.
Let argVal be exprToVal(argExpr).
Let pk1 be "{p}".
Set item pk1 of callEnv to argVal.
Let cpSafeArg be isCopyPropSafe(argExpr).
If cpSafeArg:
Let pk2 be "{p}".
Set item pk2 of childSEnv to (copy of argExpr).
Set pidx to pidx + 1.
Let childState be peStateWithEnvDepthStatic(state, callEnv, depth - 1, childSEnv).
Let mk2 be "{memoKeyStr}".
Let childStack be peOnStack(childState).
peOsPush(childStack, mk2).
Let peBody be peBlock(body, childState).
Let embedKeyPop be "__embed_{fn1}".
If specRes contains embedKeyPop:
Let curSnaps be item embedKeyPop of specRes.
Inspect curSnaps:
When CList (curSnapList):
Let prunedSnaps be seqDropLast(curSnapList).
Let prunedWrap be a new CList with items prunedSnaps.
peSeBind(specRes, embedKeyPop, prunedWrap).
Otherwise:
Let skipPop be true.
Let rawResult be extractReturn(peBody).
Let bodyResult be validateExtractReturn(rawResult, peBody).
Inspect bodyResult:
When CVar (brName2):
If brName2 equals "__no_return__":
Return a new CCall with name fn1 and args peArgs.
Otherwise:
Let skip be true.
Let mk3 be "{memoKeyStr}".
Let bodyResultCopy be copy of bodyResult.
peSeBind(specRes, mk3, bodyResultCopy).
Return bodyResult.
Otherwise:
Let fn3 be "{fn1}".
Return a new CCall with name fn3 and args peArgs.
Let mutable hasSomeStatic be false.
Let mutable hasSomeDynamic be false.
Repeat for pa in peArgs:
If isStatic(pa):
Set hasSomeStatic to true.
Otherwise:
Set hasSomeDynamic to true.
If hasSomeStatic and hasSomeDynamic:
Let normArgs be a new Seq of CExpr.
Repeat for pna in peArgs:
If isStatic(pna):
Let pnaCopy be copy of pna.
Push pnaCopy to normArgs.
Otherwise:
Push (a new CVar with name "__dyn__") to normArgs.
Let pembKey be "__pemb_{fn1}".
Let pembSpec be peSpecResults(state).
Let mutable whistleBlew be false.
Let pembK0 be "{pembKey}".
If pembSpec contains pembK0:
Let pembList be item pembK0 of pembSpec.
Inspect pembList:
When CList (pembSnaps):
Repeat for pembSnap in pembSnaps:
Inspect pembSnap:
When CList (ancNorm):
If argsStrictlyEmbed(ancNorm, normArgs):
Set whistleBlew to true.
Otherwise:
Let skipAncW be true.
Otherwise:
Let skipAncW2 be true.
Otherwise:
Let skipPembW be true.
If whistleBlew:
Return a new CCall with name fn1 and args peArgs.
Let pembK1 be "{pembKey}".
Let mutable pembNewSnaps be a new Seq of CExpr.
If pembSpec contains pembK1:
Let pembExisting be item pembK1 of pembSpec.
Inspect pembExisting:
When CList (pembExSnaps):
Repeat for pes in pembExSnaps:
Push pes to pembNewSnaps.
Otherwise:
Let skipPEW be true.
Let normArgsCopy be copy of normArgs.
Push (a new CList with items normArgsCopy) to pembNewSnaps.
Let pembK2 be "{pembKey}".
Let pembNewWrap be a new CList with items pembNewSnaps.
peSeBind(pembSpec, pembK2, pembNewWrap).
Let specKey be makeCycleKey(fn1, peArgs).
Let specKeyStr be "{specKey}".
Let specCache be peOnStack(state).
Let sk1 be "{specKeyStr}".
If specCache contains sk1:
Let dynArgs be a new Seq of CExpr.
Repeat for pa in peArgs:
If not isStatic(pa):
Push pa to dynArgs.
Let sk2 be "{specKeyStr}".
Return a new CCall with name sk2 and args dynArgs.
Let fn4 be "{fn1}".
Let func2 be item fn4 of funcs.
Inspect func2:
When CFuncDef (fname, params, fnParamTypes, fnReturnType, body):
Let callEnv be a new Map of Text to CVal.
Let childSEnv be a new Map of Text to CExpr.
Let dynParams be a new Seq of Text.
Let mutable pidx be 1.
Repeat for p in params:
Let argExpr be item pidx of peArgs.
If isStatic(argExpr):
Let argVal be exprToVal(argExpr).
Let pk1 be "{p}".
Set item pk1 of callEnv to argVal.
Let pk2 be "{p}".
Let argExprCopy be copy of argExpr.
Set item pk2 of childSEnv to argExprCopy.
Otherwise:
Let pk3 be "{p}".
Push pk3 to dynParams.
Let pk4 be "{p}".
Set item pk4 of callEnv to a new VNothing.
Set pidx to pidx + 1.
Let sk3 be "{specKeyStr}".
peOsPush(specCache, sk3).
Let placeholderBody be a new Seq of CStmt.
Let sk4 be "{specKeyStr}".
Let phDynParams be a new Seq of Text.
Repeat for dp in dynParams:
Let dpCopy be "{dp}".
Push dpCopy to phDynParams.
Let phPT be a new Seq of Text.
Let placeholderFunc be a new CFuncDef with name sk4 and params phDynParams and paramTypes phPT and returnType "Any" and body placeholderBody.
Let sk5 be "{specKeyStr}".
peFuncBind(funcs, sk5, placeholderFunc).
Let childState be peStateWithEnvDepthStatic(state, callEnv, depth - 1, childSEnv).
Let peBody be peBlock(body, childState).
Let pembKeyPop be "__pemb_{fn1}".
If pembSpec contains pembKeyPop:
Let pembCur be item pembKeyPop of pembSpec.
Inspect pembCur:
When CList (pembCurList):
Let pembPruned be seqDropLast(pembCurList).
Let pembPrunedWrap be a new CList with items pembPruned.
peSeBind(pembSpec, pembKeyPop, pembPrunedWrap).
Otherwise:
Let skipPopW be true.
Let rawResult2 be extractReturn(peBody).
Let bodyResult be validateExtractReturn(rawResult2, peBody).
Let sk6 be "{specKeyStr}".
Let spDynParams be a new Seq of Text.
Repeat for dp in dynParams:
Let dpCopy be "{dp}".
Push dpCopy to spDynParams.
Let spPT be a new Seq of Text.
Let specFunc be a new CFuncDef with name sk6 and params spDynParams and paramTypes spPT and returnType "Any" and body peBody.
Let sk7 be "{specKeyStr}".
peFuncBind(funcs, sk7, specFunc).
Let mutable emitSpecCall be false.
Inspect bodyResult:
When CCall (brFn, brArgs):
Set emitSpecCall to true.
When CVar (brName):
If brName equals "__no_return__":
Set emitSpecCall to true.
Otherwise:
Let skipBRD be true.
If emitSpecCall:
Let fallbackDynArgs be a new Seq of CExpr.
Repeat for pa in peArgs:
If not isStatic(pa):
Push pa to fallbackDynArgs.
Let sk8 be "{specKeyStr}".
Return a new CCall with name sk8 and args fallbackDynArgs.
Let mutable hasClosureArg be false.
Repeat for pa in peArgs:
Inspect pa:
When CClosure (clcp, clcb, clcc):
Set hasClosureArg to true.
Otherwise:
Let skipCAchk be true.
If hasClosureArg:
Let mutable substResult be bodyResult.
Let dynArgsForSubst be a new Seq of CExpr.
Repeat for pa in peArgs:
If not isStatic(pa):
Push pa to dynArgsForSubst.
Let mutable dsi be 1.
Repeat for dpn in dynParams:
If dsi is at most length of dynArgsForSubst:
Let dArg be item dsi of dynArgsForSubst.
Set substResult to substExpr(substResult, dpn, dArg).
Set dsi to dsi + 1.
Return substResult.
Return bodyResult.
Otherwise:
Let fn5 be "{fn1}".
Return a new CCall with name fn5 and args peArgs.
Let mutable hasStructArg be false.
Repeat for pa in peArgs:
If hasKnownTag(pa):
Set hasStructArg to true.
If hasStructArg:
Let structKey be "struct_{fn1}".
Let osCheck be peOnStack(state).
Let mutable structSeen be false.
Repeat for osK in osCheck:
If osK equals structKey:
Set structSeen to true.
If not structSeen:
Let fn6 be "{fn1}".
If funcs contains fn6:
Let func3 be item fn6 of funcs.
Inspect func3:
When CFuncDef (fname3, params3, fnPT3, fnRT3, body3):
Let callEnv3 be a new Map of Text to CVal.
Let childSEnv3 be a new Map of Text to CExpr.
Let mutable pidx3 be 1.
Repeat for p3 in params3:
Let argExpr3 be item pidx3 of peArgs.
Let pk31 be "{p3}".
Set item pk31 of callEnv3 to a new VNothing.
Let cpSafe3 be isCopyPropSafe(argExpr3).
If cpSafe3:
Let pk32 be "{p3}".
Set item pk32 of childSEnv3 to (copy of argExpr3).
Set pidx3 to pidx3 + 1.
Let childOs3 be copy of osCheck.
Let structKeyCopy be "{structKey}".
Push structKeyCopy to childOs3.
Let childState3 be peStateWithEnvDepthStatic(state, callEnv3, depth - 1, childSEnv3).
Inspect childState3:
When PEStateR (ce, cf, cd, cse, csr, cos):
Set childState3 to a new PEStateR with env ce and funcs cf and depth cd and staticEnv cse and specResults csr and onStack childOs3.
Let peBody3 be peBlock(body3, childState3).
Let rawResult3 be extractReturn(peBody3).
Let bodyResult3 be validateExtractReturn(rawResult3, peBody3).
Inspect bodyResult3:
When CVar (brName3):
If brName3 equals "__no_return__":
Return a new CCall with name fnName and args peArgs.
Otherwise:
Let skip3 be true.
Return bodyResult3.
Otherwise:
Let fn7 be "{fn1}".
Return a new CCall with name fn7 and args peArgs.
Return a new CCall with name fn1 and args peArgs.
When CIndex (collExpr, idxExpr):
Let peColl be peExpr(collExpr, state).
Let peIdx be peExpr(idxExpr, state).
Inspect peColl:
When CList (listItems):
Inspect peIdx:
When CInt (idxVal):
If idxVal is greater than 0:
If idxVal is at most length of listItems:
Return item idxVal of listItems.
Otherwise:
Let skip be true.
When CTuple (tupleItems):
Inspect peIdx:
When CInt (tidxVal):
If tidxVal is greater than 0:
If tidxVal is at most length of tupleItems:
Return item tidxVal of tupleItems.
Otherwise:
Let skipT be true.
When CNew (ciTy, ciNames, ciVals):
If ciTy equals "Map":
Inspect peIdx:
When CText (ciKey):
Let mutable ciFi be 1.
Repeat for cinm in ciNames:
If cinm equals ciKey:
Return item ciFi of ciVals.
Set ciFi to ciFi + 1.
Otherwise:
Let skipCi be true.
Otherwise:
Let skip be true.
Return a new CIndex with coll peColl and idx peIdx.
When CLen (lenTarget):
Let peTarget be peExpr(lenTarget, state).
Inspect peTarget:
When CList (listItems):
Return a new CInt with value (length of listItems).
When CTuple (tupleItems):
Return a new CInt with value (length of tupleItems).
When CText (textVal):
Return a new CInt with value (length of textVal).
When CNewVariant (lnvTag, lnvNames, lnvVals):
If lnvTag equals "Map":
Return a new CInt with value (length of lnvNames).
When CNew (lcnTag, lcnNames, lcnVals):
If lcnTag equals "Map":
Return a new CInt with value (length of lcnNames).
If lcnTag equals "Set":
Return a new CInt with value (length of lcnVals).
Otherwise:
Let skip be true.
Return a new CLen with target peTarget.
When CMapGet (mapTarget, mapKey):
Let peTarget be peExpr(mapTarget, state).
Let peKey be peExpr(mapKey, state).
Inspect peTarget:
When CNewVariant (nvTag, nvNames, nvVals):
Inspect peKey:
When CText (keyStr):
If keyStr equals "__tag":
Return a new CText with value nvTag.
Let mutable fidx be 1.
Repeat for fname in nvNames:
If fname equals keyStr:
Return item fidx of nvVals.
Set fidx to fidx + 1.
Otherwise:
Let skip be true.
When CNew (cnTypeName, cnFieldNames, cnFieldVals):
Inspect peKey:
When CText (keyStr):
If keyStr equals "__tag":
Return a new CText with value cnTypeName.
Let mutable fidx2 be 1.
Repeat for fname2 in cnFieldNames:
If fname2 equals keyStr:
Return item fidx2 of cnFieldVals.
Set fidx2 to fidx2 + 1.
Otherwise:
Let skip be true.
Otherwise:
Let skip be true.
Return a new CMapGet with target peTarget and key peKey.
When CNewSeq:
Return a new CNewSeq.
When CNewVariant (nvTag, nvNames, nvVals):
Let peVals be a new Seq of CExpr.
Repeat for v in nvVals:
Push peExpr(v, state) to peVals.
Return a new CNewVariant with tag nvTag and fnames nvNames and fvals peVals.
When CFloat (fv):
Return a new CFloat with value fv.
When CList (listItems):
Let peItems be a new Seq of CExpr.
Repeat for li in listItems:
Push peExpr(li, state) to peItems.
Return a new CList with items peItems.
When CRange (rangeStart, rangeEnd):
Let peStart be peExpr(rangeStart, state).
Let peEnd be peExpr(rangeEnd, state).
Return a new CRange with start peStart and end peEnd.
When CSlice (sliceColl, sliceStart, sliceEnd):
Let peColl be peExpr(sliceColl, state).
Let peStart be peExpr(sliceStart, state).
Let peEnd be peExpr(sliceEnd, state).
Return a new CSlice with coll peColl and startIdx peStart and endIdx peEnd.
When CCopy (copyTarget):
Let peTarget be peExpr(copyTarget, state).
Return a new CCopy with target peTarget.
When CNewSet:
Return a new CNewSet.
When CContains (containsColl, containsElem):
Let peColl be peExpr(containsColl, state).
Let peElem be peExpr(containsElem, state).
Inspect peColl:
When CNew (cnTypeName, cnFieldNames, cnFields):
If cnTypeName equals "Set":
If isStatic(peElem):
Let ckey be exprToKeyPart(peElem).
Let ckeyS be "{ckey}".
Let mutable foundC be false.
Repeat for cnm in cnFieldNames:
If cnm equals ckeyS:
Set foundC to true.
If foundC:
Return a new CBool with value true.
Return a new CBool with value false.
If length of cnFields equals 0:
Return a new CBool with value false.
When CNewSeq:
Return a new CBool with value false.
When CNewSet:
Return a new CBool with value false.
When CList (litems):
If length of litems equals 0:
Return a new CBool with value false.
Otherwise:
Let skipContains be true.
Return a new CContains with coll peColl and elem peElem.
When CUnion (unionLeft, unionRight):
Let peLeft be peExpr(unionLeft, state).
Let peRight be peExpr(unionRight, state).
Return a new CUnion with left peLeft and right peRight.
When CIntersection (interLeft, interRight):
Let peLeft be peExpr(interLeft, state).
Let peRight be peExpr(interRight, state).
Return a new CIntersection with left peLeft and right peRight.
When COptionSome (optInner):
Let peInner be peExpr(optInner, state).
Return a new COptionSome with inner peInner.
When COptionNone:
Return a new COptionNone.
When CTuple (tupleItems):
Let peItems be a new Seq of CExpr.
Repeat for ti in tupleItems:
Push peExpr(ti, state) to peItems.
Return a new CTuple with items peItems.
When CNew (newTypeName, newFieldNames, newFieldExprs):
Let peNewFields be a new Seq of CExpr.
Repeat for nfe in newFieldExprs:
Push peExpr(nfe, state) to peNewFields.
Return a new CNew with typeName newTypeName and fieldNames newFieldNames and fields peNewFields.
When CFieldAccess (faTarget, faField):
Let peFaTarget be peExpr(faTarget, state).
Inspect peFaTarget:
When CNewVariant (nvTag, nvNames, nvVals):
Let mutable fidx be 1.
Repeat for fname in nvNames:
If fname equals faField:
Return item fidx of nvVals.
Set fidx to fidx + 1.
When CNew (nType, nNames, nVals):
Let mutable fidx be 1.
Repeat for fname in nNames:
If fname equals faField:
Return item fidx of nVals.
Set fidx to fidx + 1.
Otherwise:
Let skip be true.
Return a new CFieldAccess with target peFaTarget and field faField.
When CClosure (clParams, clBody, clCaptured):
Let peClBody be peBlock(clBody, state).
Return a new CClosure with params clParams and body peClBody and captured clCaptured.
When CCallExpr (ceTarget, ceArgs):
Let peCeTarget be peExpr(ceTarget, state).
Let peCeArgs be a new Seq of CExpr.
Repeat for ceArg in ceArgs:
Push peExpr(ceArg, state) to peCeArgs.
Return a new CCallExpr with target peCeTarget and args peCeArgs.
When CInterpolatedString (isParts):
Let peIsParts be a new Seq of CStringPart.
Repeat for isPart in isParts:
Inspect isPart:
When CLiteralPart (litVal):
Push a new CLiteralPart with value litVal to peIsParts.
When CExprPart (epExpr):
Let peEpExpr be peExpr(epExpr, state).
Push a new CExprPart with expr peEpExpr to peIsParts.
Return a new CInterpolatedString with parts peIsParts.
When CDuration (durAmount, durUnit):
Let peDurAmount be peExpr(durAmount, state).
Return a new CDuration with amount peDurAmount and unit durUnit.
When CTimeNow:
Return a new CTimeNow.
When CDateToday:
Return a new CDateToday.
When CEscExpr (escCode):
Return a new CEscExpr with code escCode.
When CManifestOf (zn):
Let peZone be peExpr(zn, state).
Return a new CManifestOf with zn peZone.
When CChunkAt (idx, zn):
Let peIdx be peExpr(idx, state).
Let peZone be peExpr(zn, state).
Return a new CChunkAt with idx peIdx and zn peZone.
## To collectSetVars (stmts: Seq of CStmt) -> Seq of Text:
Let result be a new Seq of Text.
Repeat for s in stmts:
Inspect s:
When CSet (setName, setExpr):
Push setName to result.
When CIf (ifCond, ifThen, ifElse):
Let thenVars be collectSetVars(ifThen).
Repeat for tv in thenVars:
Push tv to result.
Let elseVars be collectSetVars(ifElse).
Repeat for ev in elseVars:
Push ev to result.
When CWhile (wCond, wBody):
Let wVars be collectSetVars(wBody).
Repeat for wv in wVars:
Push wv to result.
When CRepeat (rVar, rColl, rBody):
Let rVars be collectSetVars(rBody).
Repeat for rv in rVars:
Push rv to result.
When CRepeatRange (rrVar, rrStart, rrEnd, rrBody):
Let rrVars be collectSetVars(rrBody).
Repeat for rrv in rrVars:
Push rrv to result.
When CInspect (inspTarget, inspArms):
Repeat for cinsArm in inspArms:
Inspect cinsArm:
When CWhen (cwName, cwBindings, cwBody):
Let cwVars be collectSetVars(cwBody).
Repeat for cwv in cwVars:
Push cwv to result.
Otherwise:
Let skipCinsArm be true.
When CSelect (selBranches):
Repeat for cselBr in selBranches:
Inspect cselBr:
When CSelectRecv (csrChan, csrVar, csrBody):
Let csrVars be collectSetVars(csrBody).
Repeat for csrv in csrVars:
Push csrv to result.
When CSelectTimeout (cstDur, cstBody):
Let cstVars be collectSetVars(cstBody).
Repeat for cstv in cstVars:
Push cstv to result.
Otherwise:
Let skipCselBr be true.
When CZone (zoneName, zoneKind, zoneBody):
Let zVars be collectSetVars(zoneBody).
Repeat for zv in zVars:
Push zv to result.
When CConcurrent (concBranches):
Repeat for concBranch in concBranches:
Let concVars be collectSetVars(concBranch).
Repeat for ccv in concVars:
Push ccv to result.
When CParallel (parBranches):
Repeat for parBranch in parBranches:
Let parVars be collectSetVars(parBranch).
Repeat for pcv in parVars:
Push pcv to result.
When CLaunchTask (ltBody, ltHandle):
Let ltVars be collectSetVars(ltBody).
Repeat for ltv in ltVars:
Push ltv to result.
Otherwise:
Let skip be true.
Return result.
## To isDeadTarget (targetName: Text) and (env: Map of Text to CVal) -> Bool:
Let tk be "{targetName}".
If env contains tk:
Let tv be item tk of env.
Let tvn be isVNothing(tv).
If tvn:
Return false.
Return true.
Return false.
## To peBlock (stmts: Seq of CStmt) and (state: PEState) -> Seq of CStmt:
Let env be peEnv(state).
Let funcs be peFuncs(state).
Let depth be peDepth(state).
Let mutable blockMutatedDone be false.
Let mutable blockMutated be a new Seq of Text.
Let blockResult be a new Seq of CStmt.
Repeat for s in stmts:
Let alreadyReturned be hasReturn(blockResult).
If alreadyReturned:
Return blockResult.
Let alreadyBroke be hasBreak(blockResult).
If alreadyBroke:
Return blockResult.
Inspect s:
When CLet (letName, letExpr):
Let peVal be peExpr(letExpr, state).
Let mutable aliasedRef be false.
Inspect letExpr:
When CVar (aliasSrc):
Let refAgg be isRefAggregate(peVal).
If refAgg:
Set aliasedRef to true.
Let sEnvAl be peStaticEnv(state).
Let aliasSrcK be "{aliasSrc}".
If sEnvAl contains aliasSrcK:
peSeDrop(sEnvAl, aliasSrcK).
Let aliasSrcK2 be "{aliasSrc}".
peEnvBind(env, aliasSrcK2, (a new VNothing)).
Let ltAlK be "{letName}".
If sEnvAl contains ltAlK:
peSeDrop(sEnvAl, ltAlK).
Let ltAlK2 be "{letName}".
peEnvBind(env, ltAlK2, (a new VNothing)).
Let ltAlName be "{letName}".
Let ltAlExpr be copy of letExpr.
Push (a new CLet with name ltAlName and expr ltAlExpr) to blockResult.
Otherwise:
Let skipAliasA be true.
Otherwise:
Let skipAliasB be true.
Let mutable letHandled be false.
If not aliasedRef:
Inspect peVal:
When CNewSet:
Let setEmptyNames be a new Seq of Text.
Let setEmptyVals be a new Seq of CExpr.
Let trackedSet be a new CNew with typeName "Set" and fieldNames setEmptyNames and fields setEmptyVals.
Let lsk be "{letName}".
Let sEnvLs be peStaticEnv(state).
peSeBind(sEnvLs, lsk, trackedSet).
Let lsk2 be "{letName}".
peEnvBind(env, lsk2, (a new VNothing)).
Let lsName be "{letName}".
Let lsVal be copy of peVal.
Push (a new CLet with name lsName and expr lsVal) to blockResult.
Set letHandled to true.
Otherwise:
Let skipLs be true.
If not aliasedRef:
If not letHandled:
Let valSV be isStaticValue(peVal).
Let cpvL be isPeValueForCopyProp(peVal).
Let mutable cpOk be cpvL.
If not cpvL:
If not blockMutatedDone:
Set blockMutated to collectSetVars(stmts).
Set blockMutatedDone to true.
Let rmmL be exprRefsAnyMutated(peVal, blockMutated).
If not rmmL:
Set cpOk to true.
If cpOk:
Let letNameS be "{letName}".
Let peValS be copy of peVal.
Let sEnvL be peStaticEnv(state).
peSeBind(sEnvL, letNameS, peValS).
Otherwise:
Let sEnvL2 be peStaticEnv(state).
Let letNameR be "{letName}".
If sEnvL2 contains letNameR:
peSeDrop(sEnvL2, letNameR).
If valSV:
peEnvBind(env, letName, exprToVal(peVal)).
Otherwise:
Let letKey be "{letName}".
peEnvBind(env, letKey, (a new VNothing)).
Push (a new CLet with name letName and expr peVal) to blockResult.
When CSet (setName, setExpr):
Let peVal be peExpr(setExpr, state).
Let valSV2 be isStaticValue(peVal).
Let cpvSL be isPeValueForCopyProp(peVal).
Let mutable cpOkS be cpvSL.
If not cpvSL:
If not blockMutatedDone:
Set blockMutated to collectSetVars(stmts).
Set blockMutatedDone to true.
Let rmmSL be exprRefsAnyMutated(peVal, blockMutated).
If not rmmSL:
Set cpOkS to true.
Let sEnvCS be peStaticEnv(state).
Let setNameChk be "{setName}".
Let mutable priorWasStatic be false.
Let mutable priorStaticVal be (a new CInt with value 0).
If sEnvCS contains setNameChk:
Let setNameItm be "{setName}".
Let priorCV be item setNameItm of sEnvCS.
Let pcvStatic be isStaticValue(priorCV).
If pcvStatic:
Set priorWasStatic to true.
Set priorStaticVal to copy of priorCV.
If cpOkS:
Let setNameS be "{setName}".
Let peValS be copy of peVal.
peSeBind(sEnvCS, setNameS, peValS).
Otherwise:
Let setNameR be "{setName}".
If sEnvCS contains setNameR:
Let setNameD be "{setName}".
peSeDrop(sEnvCS, setNameD).
If valSV2:
peEnvBind(env, setName, exprToVal(peVal)).
Otherwise:
If priorWasStatic:
Let setNameL be "{setName}".
Push (a new CLet with name setNameL and expr priorStaticVal) to blockResult.
Let setKey be "{setName}".
peEnvBind(env, setKey, (a new VNothing)).
Push (a new CSet with name setName and expr peVal) to blockResult.
When CIf (ifCond, thenBlock, elseBlock):
Let peCond be peExpr(ifCond, state).
Let condLit be isLiteral(peCond).
If condLit:
Inspect peCond:
When CBool (b):
If b:
Let thenRes be peBlock(thenBlock, state).
Repeat for ts in thenRes:
Push ts to blockResult.
Otherwise:
Let elseRes be peBlock(elseBlock, state).
Repeat for es in elseRes:
Push es to blockResult.
Otherwise:
Let thenRes2 be peBlock(thenBlock, state).
Let elseRes2 be peBlock(elseBlock, state).
Push (a new CIf with cond peCond and thenBlock thenRes2 and elseBlock elseRes2) to blockResult.
Otherwise:
Let thenModsIf be collectSetVars(thenBlock).
Let elseModsIf be collectSetVars(elseBlock).
Let allModsIf be a new Seq of Text.
Repeat for tmI in thenModsIf:
Push tmI to allModsIf.
Repeat for emI in elseModsIf:
Push emI to allModsIf.
Let ifSeShared be peStaticEnv(state).
Repeat for pmI in allModsIf:
Let pmK1 be "{pmI}".
If ifSeShared contains pmK1:
Let pmK2 be "{pmI}".
Let pmV be item pmK2 of ifSeShared.
Let pmK3 be "{pmI}".
Push (a new CLet with name pmK3 and expr pmV) to blockResult.
Let pmK4 be "{pmI}".
peSeDrop(ifSeShared, pmK4).
Let pmK5 be "{pmI}".
peEnvBind(env, pmK5, (a new VNothing)).
Let posR be applyPosFacts(peCond, ifSeShared).
Let thenRes3 be peBlock(thenBlock, state).
Let thenFinal be a new Seq of CStmt.
Repeat for tstmt in thenRes3:
Push tstmt to thenFinal.
Let sEnvThenIf be peStaticEnv(state).
Repeat for tmv in thenModsIf:
Let tmvK1 be "{tmv}".
If sEnvThenIf contains tmvK1:
Let tmvK2 be "{tmv}".
Let tmvV be item tmvK2 of sEnvThenIf.
Let tmvK3 be "{tmv}".
Push (a new CSet with name tmvK3 and expr tmvV) to thenFinal.
Let clr1 be clearGuardFacts(peCond, ifSeShared).
Repeat for rmv in allModsIf:
Let rmvK1 be "{rmv}".
If sEnvThenIf contains rmvK1:
Let rmvK2 be "{rmv}".
peSeDrop(sEnvThenIf, rmvK2).
Let rmvK3 be "{rmv}".
peEnvBind(env, rmvK3, (a new VNothing)).
Let negR be applyNegFacts(peCond, ifSeShared).
Let elseRes3 be peBlock(elseBlock, state).
Let elseFinal be a new Seq of CStmt.
Repeat for estmt in elseRes3:
Push estmt to elseFinal.
Let sEnvElseIf be peStaticEnv(state).
Repeat for emv in elseModsIf:
Let emvK1 be "{emv}".
If sEnvElseIf contains emvK1:
Let emvK2 be "{emv}".
Let emvV be item emvK2 of sEnvElseIf.
Let emvK3 be "{emv}".
Push (a new CSet with name emvK3 and expr emvV) to elseFinal.
Let clr2 be clearGuardFacts(peCond, ifSeShared).
Repeat for dmv in allModsIf:
Let dmvK1 be "{dmv}".
If sEnvElseIf contains dmvK1:
Let dmvK2 be "{dmv}".
peSeDrop(sEnvElseIf, dmvK2).
Let dmvK3 be "{dmv}".
peEnvBind(env, dmvK3, (a new VNothing)).
Push (a new CIf with cond peCond and thenBlock thenFinal and elseBlock elseFinal) to blockResult.
When CWhile (whileCond, whileBody):
Let modVars be collectSetVars(whileBody).
Let wEnv0 be peEnv(state).
Let wSe0 be peStaticEnv(state).
Let dryEnv be copy of wEnv0.
Let drySe be copy of wSe0.
Let dryFuncs be peFuncs(state).
Let dryDepth be peDepth(state).
Let drySr be peSpecResults(state).
Let dryOs be peOnStack(state).
Let dryState be a new PEStateR with env dryEnv and funcs dryFuncs and depth dryDepth and staticEnv drySe and specResults drySr and onStack dryOs.
Let mutable willUnrollW be false.
Let peCondDry be peExpr(whileCond, dryState).
Inspect peCondDry:
When CBool (dcb0):
Let mutable dCond be dcb0.
Let mutable dStop be false.
Let mutable dOk be true.
Let mutable dIter be 0.
While dOk and not dStop:
If not dCond:
Set dStop to true.
Set willUnrollW to true.
Otherwise:
Let dBody be peBlock(whileBody, dryState).
Let mutable dHalt be false.
Repeat for dus in dBody:
Inspect dus:
When CBreak:
Set dHalt to true.
When CReturn (drx):
Set dHalt to true.
Otherwise:
Let dsk be true.
If dHalt:
Set dStop to true.
Set willUnrollW to true.
Otherwise:
Set dIter to dIter + 1.
If dIter is at least 1024:
Set dOk to false.
Otherwise:
Let peCondDN be peExpr(whileCond, dryState).
Inspect peCondDN:
When CBool (dcbn):
Set dCond to dcbn.
Otherwise:
Set dOk to false.
Otherwise:
Let wskTop be true.
If willUnrollW:
Let mutable rCond be true.
Let mutable rStop be false.
Let peCondR0 be peExpr(whileCond, state).
Inspect peCondR0:
When CBool (rcb0):
Set rCond to rcb0.
Otherwise:
Set rStop to true.
While rCond and not rStop:
Let rBody be peBlock(whileBody, state).
Let mutable rHalt be false.
Repeat for rus in rBody:
If not rHalt:
Inspect rus:
When CBreak:
Set rHalt to true.
When CReturn (rrx):
Push rus to blockResult.
Set rHalt to true.
Otherwise:
Push rus to blockResult.
If rHalt:
Set rStop to true.
Otherwise:
Let peCondRN be peExpr(whileCond, state).
Inspect peCondRN:
When CBool (rcbn):
Set rCond to rcbn.
Otherwise:
Set rStop to true.
Otherwise:
Let sEnvW be peStaticEnv(state).
Repeat for mv in modVars:
Let mvK1 be "{mv}".
If sEnvW contains mvK1:
Let mvK2 be "{mv}".
Let prevVal be item mvK2 of sEnvW.
Let mvK3 be "{mv}".
Push (a new CLet with name mvK3 and expr prevVal) to blockResult.
Let mvK4 be "{mv}".
peSeDrop(sEnvW, mvK4).
Let mvK5 be "{mv}".
peEnvBind(env, mvK5, (a new VNothing)).
Let peCondF be peExpr(whileCond, state).
Let peBodyF be peBlock(whileBody, state).
Let sEnvPostF be peStaticEnv(state).
Repeat for mvF in modVars:
Let mvFK be "{mvF}".
If sEnvPostF contains mvFK:
Let mvFK2 be "{mvF}".
peSeDrop(sEnvPostF, mvFK2).
Let mvFK3 be "{mvF}".
peEnvBind(env, mvFK3, (a new VNothing)).
Push (a new CWhile with cond peCondF and body peBodyF) to blockResult.
When CReturn (retExpr):
Let peVal be peExpr(retExpr, state).
Push (a new CReturn with expr peVal) to blockResult.
When CShow (showExpr):
Let peVal be peExpr(showExpr, state).
Push (a new CShow with expr peVal) to blockResult.
When CCallS (callName, callArgs):
Let peArgs be a new Seq of CExpr.
Repeat for a in callArgs:
Push peExpr(a, state) to peArgs.
Push (a new CCallS with name callName and args peArgs) to blockResult.
When CPush (pushExpr, pushTarget):
Let sEnvPush be peStaticEnv(state).
Let ptk1 be "{pushTarget}".
If sEnvPush contains ptk1:
Let ptk2 be "{pushTarget}".
Let ptPrev be item ptk2 of sEnvPush.
Let ptk3 be "{pushTarget}".
Push (a new CLet with name ptk3 and expr ptPrev) to blockResult.
Let ptk4 be "{pushTarget}".
peSeDrop(sEnvPush, ptk4).
Let ptk5 be "{pushTarget}".
peEnvBind(env, ptk5, (a new VNothing)).
Let peVal be peExpr(pushExpr, state).
Push (a new CPush with expr peVal and target pushTarget) to blockResult.
When CSetIdx (siTarget, siIdx, siVal):
Let peIdx be peExpr(siIdx, state).
Let peVal be peExpr(siVal, state).
Let sEnvSI be peStaticEnv(state).
Let sik1 be "{siTarget}".
Let mutable siHandled be false.
If sEnvSI contains sik1:
Let sik2 be "{siTarget}".
Let siPrev be item sik2 of sEnvSI.
Let siValSafe be isCopyPropSafe(peVal).
Inspect siPrev:
When CNew (siTag, siNames, siVals):
If siTag equals "Map":
Inspect peIdx:
When CText (siKey):
If siValSafe:
Let newSiVals be a new Seq of CExpr.
Let mutable foundSi be false.
Let mutable siFi be 1.
Repeat for snm in siNames:
If snm equals siKey:
Push (copy of peVal) to newSiVals.
Set foundSi to true.
Otherwise:
Push (item siFi of siVals) to newSiVals.
Set siFi to siFi + 1.
Let newSiNames be copy of siNames.
If not foundSi:
Push siKey to newSiNames.
Push (copy of peVal) to newSiVals.
Let siUpdatedMap be a new CNew with typeName "Map" and fieldNames newSiNames and fields newSiVals.
Let sik6 be "{siTarget}".
peSeBind(sEnvSI, sik6, siUpdatedMap).
Set siHandled to true.
Otherwise:
Let skipSi2 be true.
Otherwise:
Let skipSi be true.
If not siHandled:
Let sik3 be "{siTarget}".
Push (a new CLet with name sik3 and expr siPrev) to blockResult.
Let sik4 be "{siTarget}".
peSeDrop(sEnvSI, sik4).
Let sik5 be "{siTarget}".
peEnvBind(env, sik5, (a new VNothing)).
Push (a new CSetIdx with target siTarget and idx peIdx and val peVal) to blockResult.
When CMapSet (msTarget, msKey, msVal):
Let peKey be peExpr(msKey, state).
Let peVal be peExpr(msVal, state).
Let sEnvMS be peStaticEnv(state).
Let msk1 be "{msTarget}".
If sEnvMS contains msk1:
Let msk2 be "{msTarget}".
Let msPrev be item msk2 of sEnvMS.
Let valSafeMS be isCopyPropSafe(peVal).
Let mutable updatedMS be false.
Inspect msPrev:
When CNewVariant (msTag, msNames, msVals):
Inspect peKey:
When CText (msFieldName):
If valSafeMS:
Let newMsVals be a new Seq of CExpr.
Let mutable foundField be false.
Let mutable msFi be 1.
Repeat for fnm in msNames:
If fnm equals msFieldName:
Push (copy of peVal) to newMsVals.
Set foundField to true.
Otherwise:
Push (item msFi of msVals) to newMsVals.
Set msFi to msFi + 1.
Let newMsNames be copy of msNames.
If not foundField:
If msTag equals "Map":
Push msFieldName to newMsNames.
Push (copy of peVal) to newMsVals.
Set foundField to true.
If foundField:
Let msUpdated be a new CNewVariant with tag msTag and fnames newMsNames and fvals newMsVals.
Let msk6 be "{msTarget}".
peSeBind(sEnvMS, msk6, msUpdated).
Set updatedMS to true.
Otherwise:
Let skipMsSafe be true.
Otherwise:
Let skipMs2 be true.
When CNew (cnMapTag, cnMapNames, cnMapVals):
If cnMapTag equals "Map":
Inspect peKey:
When CText (mpFieldName):
If valSafeMS:
Let newMpVals be a new Seq of CExpr.
Let mutable foundMp be false.
Let mutable mpFi be 1.
Repeat for mnm in cnMapNames:
If mnm equals mpFieldName:
Push (copy of peVal) to newMpVals.
Set foundMp to true.
Otherwise:
Push (item mpFi of cnMapVals) to newMpVals.
Set mpFi to mpFi + 1.
Let newMpNames be copy of cnMapNames.
If not foundMp:
Push mpFieldName to newMpNames.
Push (copy of peVal) to newMpVals.
Set foundMp to true.
If foundMp:
Let mpUpdated be a new CNew with typeName "Map" and fieldNames newMpNames and fields newMpVals.
Let mpk be "{msTarget}".
peSeBind(sEnvMS, mpk, mpUpdated).
Set updatedMS to true.
Otherwise:
Let skipMp2 be true.
Otherwise:
Let skipMs be true.
Let msk3 be "{msTarget}".
Push (a new CLet with name msk3 and expr msPrev) to blockResult.
If not updatedMS:
Let msk4 be "{msTarget}".
peSeDrop(sEnvMS, msk4).
Let msk5 be "{msTarget}".
peEnvBind(env, msk5, (a new VNothing)).
Push (a new CMapSet with target msTarget and key peKey and val peVal) to blockResult.
When CPop (popTarget):
Let sEnvPop be peStaticEnv(state).
Let ppk1 be "{popTarget}".
If sEnvPop contains ppk1:
Let ppk2 be "{popTarget}".
Let ppPrev be item ppk2 of sEnvPop.
Let ppk3 be "{popTarget}".
Push (a new CLet with name ppk3 and expr ppPrev) to blockResult.
Let ppk4 be "{popTarget}".
peSeDrop(sEnvPop, ppk4).
Let ppk5 be "{popTarget}".
peEnvBind(env, ppk5, (a new VNothing)).
Push (a new CPop with target popTarget) to blockResult.
When CRepeat (repVar, repColl, repBody):
Let peColl be peExpr(repColl, state).
Let collStatic be isStatic(peColl).
Let mutable didUnroll be false.
If collStatic:
Inspect peColl:
When CList (listItems):
Set didUnroll to true.
Repeat for listItem in listItems:
Let rv be "{repVar}".
peEnvBind(env, rv, exprToVal(listItem)).
Let rv2 be "{repVar}".
Let sEnvR be peStaticEnv(state).
peSeBind(sEnvR, rv2, listItem).
Let unrolledBody be peBlock(repBody, state).
Let mutable hasBreakOrReturn be false.
Repeat for us in unrolledBody:
Inspect us:
When CBreak:
Set hasBreakOrReturn to true.
When CReturn (retExpr):
Set hasBreakOrReturn to true.
Otherwise:
Let skip be true.
Repeat for us in unrolledBody:
Push us to blockResult.
If hasBreakOrReturn:
Return blockResult.
Otherwise:
Let skip be true.
If not didUnroll:
Let repModVars be collectSetVars(repBody).
Let sEnvF be peStaticEnv(state).
Repeat for rmv in repModVars:
Let rmvK1 be "{rmv}".
If sEnvF contains rmvK1:
Let rmvK2 be "{rmv}".
Let rmvPrev be item rmvK2 of sEnvF.
Let rmvK3 be "{rmv}".
Push (a new CLet with name rmvK3 and expr rmvPrev) to blockResult.
Let rmvK4 be "{rmv}".
peSeDrop(sEnvF, rmvK4).
Let rmvK5 be "{rmv}".
peEnvBind(env, rmvK5, (a new VNothing)).
If sEnvF contains repVar:
peSeDrop(sEnvF, repVar).
Let repVarEnvKey be "{repVar}".
peEnvBind(env, repVarEnvKey, (a new VNothing)).
Let peBody be peBlock(repBody, state).
Let sEnvF2 be peStaticEnv(state).
Repeat for rmv2 in repModVars:
Let rmv2K be "{rmv2}".
If sEnvF2 contains rmv2K:
peSeDrop(sEnvF2, rmv2K).
If sEnvF2 contains repVar:
peSeDrop(sEnvF2, repVar).
Push (a new CRepeat with var repVar and coll peColl and body peBody) to blockResult.
When CRepeatRange (rrVar, rrStart, rrEnd, rrBody):
Let peStart be peExpr(rrStart, state).
Let peEnd be peExpr(rrEnd, state).
Let startStatic be isStatic(peStart).
Let endStatic be isStatic(peEnd).
Let mutable didUnrollRR be false.
If startStatic and endStatic:
Inspect peStart:
When CInt (startVal):
Inspect peEnd:
When CInt (endVal):
Let rangeSize be endVal - startVal.
If rangeSize is less than 64:
Set didUnrollRR to true.
Let mutable ri be startVal.
Let mutable stopUnrollRR be false.
While ri is at most endVal:
If not stopUnrollRR:
Let rrKey be "{rrVar}".
peEnvBind(env, rrKey, (a new VInt with value ri)).
Let rrValExpr be a new CInt with value ri.
Let rrKey2 be "{rrVar}".
Let sEnvRR be peStaticEnv(state).
peSeBind(sEnvRR, rrKey2, rrValExpr).
Let unrolledBody be peBlock(rrBody, state).
Repeat for us in unrolledBody:
If not stopUnrollRR:
Inspect us:
When CBreak:
Set stopUnrollRR to true.
When CReturn (rrRetX):
Push us to blockResult.
Set stopUnrollRR to true.
Otherwise:
Push us to blockResult.
Set ri to ri + 1.
Otherwise:
Let skip be true.
Otherwise:
Let skip be true.
If not didUnrollRR:
Let rrModVars be collectSetVars(rrBody).
Let sEnvRR2 be peStaticEnv(state).
Repeat for rrmv in rrModVars:
Let rrmvK1 be "{rrmv}".
If sEnvRR2 contains rrmvK1:
Let rrmvK2 be "{rrmv}".
Let rrmvPrev be item rrmvK2 of sEnvRR2.
Let rrmvK3 be "{rrmv}".
Push (a new CLet with name rrmvK3 and expr rrmvPrev) to blockResult.
Let rrmvK4 be "{rrmv}".
peSeDrop(sEnvRR2, rrmvK4).
Let rrmvK5 be "{rrmv}".
peEnvBind(env, rrmvK5, (a new VNothing)).
Let peBody be peBlock(rrBody, state).
Let sEnvRR3 be peStaticEnv(state).
Repeat for rrmv2 in rrModVars:
Let rrmv2K be "{rrmv2}".
If sEnvRR3 contains rrmv2K:
peSeDrop(sEnvRR3, rrmv2K).
If sEnvRR3 contains rrVar:
peSeDrop(sEnvRR3, rrVar).
Push (a new CRepeatRange with var rrVar and start peStart and end peEnd and body peBody) to blockResult.
When CBreak:
Push a new CBreak to blockResult.
When CForceDynamic (fdName):
Let sEnvFd be peStaticEnv(state).
Let fdk be "{fdName}".
If sEnvFd contains fdk:
Let fdk2 be "{fdName}".
Let fdPrev be item fdk of sEnvFd.
Push (a new CLet with name fdName and expr fdPrev) to blockResult.
peSeDrop(sEnvFd, fdk).
peEnvBind(env, fdk2, (a new VNothing)).
When CAdd (addElem, addTarget):
Let peVal be peExpr(addElem, state).
Let sEnvAdd be peStaticEnv(state).
Let adk1 be "{addTarget}".
Let mutable addHandled be false.
If sEnvAdd contains adk1:
Let adPrev be item adk1 of sEnvAdd.
Let addSafe be isCopyPropSafe(peVal).
Inspect adPrev:
When CNew (adTag, adNames, adVals):
If adTag equals "Set":
If addSafe:
Let elemKey be exprToKeyPart(peVal).
Let elemKeyS be "{elemKey}".
Let mutable existsAd be false.
Repeat for anm in adNames:
If anm equals elemKeyS:
Set existsAd to true.
Let newAdNames be copy of adNames.
Let newAdVals be copy of adVals.
If not existsAd:
Push elemKeyS to newAdNames.
Push (copy of peVal) to newAdVals.
Let adUpdated be a new CNew with typeName "Set" and fieldNames newAdNames and fields newAdVals.
Let adk6 be "{addTarget}".
peSeBind(sEnvAdd, adk6, adUpdated).
Set addHandled to true.
Otherwise:
Let skipAd be true.
If not addHandled:
Let adk3 be "{addTarget}".
Push (a new CLet with name adk3 and expr adPrev) to blockResult.
Let adk4 be "{addTarget}".
peSeDrop(sEnvAdd, adk4).
Let adk5 be "{addTarget}".
peEnvBind(env, adk5, (a new VNothing)).
Push (a new CAdd with elem peVal and target addTarget) to blockResult.
When CRemove (remElem, remTarget):
Let sEnvRem be peStaticEnv(state).
Let rmk1 be "{remTarget}".
If sEnvRem contains rmk1:
Let rmk2 be "{remTarget}".
Let rmPrev be item rmk2 of sEnvRem.
Let rmk3 be "{remTarget}".
Push (a new CLet with name rmk3 and expr rmPrev) to blockResult.
Let rmk4 be "{remTarget}".
peSeDrop(sEnvRem, rmk4).
Let rmk5 be "{remTarget}".
peEnvBind(env, rmk5, (a new VNothing)).
Let peVal be peExpr(remElem, state).
Push (a new CRemove with elem peVal and target remTarget) to blockResult.
When CSetField (sfTarget, sfField, sfValExpr):
Let sEnvSF be peStaticEnv(state).
Let sfk1 be "{sfTarget}".
If sEnvSF contains sfk1:
Let sfk2 be "{sfTarget}".
Let sfPrev be item sfk2 of sEnvSF.
Let sfk3 be "{sfTarget}".
Push (a new CLet with name sfk3 and expr sfPrev) to blockResult.
Let sfk4 be "{sfTarget}".
peSeDrop(sEnvSF, sfk4).
Let sfk5 be "{sfTarget}".
peEnvBind(env, sfk5, (a new VNothing)).
Let peVal be peExpr(sfValExpr, state).
Push (a new CSetField with target sfTarget and field sfField and val peVal) to blockResult.
When CStructDef (sdName, sdFieldNames):
Push (a new CStructDef with name sdName and fieldNames sdFieldNames) to blockResult.
When CEnumDef (edName, edVariants):
Push (a new CEnumDef with name edName and variants edVariants) to blockResult.
When CInspect (inspTarget, inspArms):
Let peTarget be peExpr(inspTarget, state).
Let mutable inspDispatched be false.
Inspect peTarget:
When CNewVariant (nvTag, nvNames, nvVals):
Repeat for arm in inspArms:
Inspect arm:
When CWhen (wName, wBindings, wBody):
If wName equals nvTag:
Let mutable bidx be 1.
Repeat for b in wBindings:
Let bval be item bidx of nvVals.
Let bvalStatic be isStatic(bval).
If bvalStatic:
Let b2 be "{b}".
Let bvalCopy be copy of bval.
Let sEnvI be peStaticEnv(state).
peSeBind(sEnvI, b2, bvalCopy).
peEnvBind(env, b, exprToVal(bval)).
Otherwise:
Let b3 be "{b}".
peEnvBind(env, b3, (a new VNothing)).
Let b4 be "{b}".
Let bvalCopy2 be copy of bval.
Let sEnvI2 be peStaticEnv(state).
peSeBind(sEnvI2, b4, bvalCopy2).
Push (a new CLet with name b and expr bval) to blockResult.
Set bidx to bidx + 1.
Let matchedBody be peBlock(wBody, state).
Repeat for ms in matchedBody:
Push ms to blockResult.
Set inspDispatched to true.
Return blockResult.
Otherwise:
Let skip be true.
If not inspDispatched:
Repeat for arm in inspArms:
Inspect arm:
When COtherwise (oBody):
Let otherwiseBody be peBlock(oBody, state).
Repeat for os in otherwiseBody:
Push os to blockResult.
Set inspDispatched to true.
Return blockResult.
Otherwise:
Let skip be true.
When CNew (cnTypeName, cnFieldNames, cnFieldVals):
Repeat for arm in inspArms:
Inspect arm:
When CWhen (wName, wBindings, wBody):
If wName equals cnTypeName:
Let mutable bidx be 1.
Repeat for b in wBindings:
Let bval be item bidx of cnFieldVals.
Let bvalStatic be isStatic(bval).
If bvalStatic:
Let b2 be "{b}".
Let bvalCopy be copy of bval.
Let sEnvI be peStaticEnv(state).
peSeBind(sEnvI, b2, bvalCopy).
peEnvBind(env, b, exprToVal(bval)).
Otherwise:
Let b3 be "{b}".
peEnvBind(env, b3, (a new VNothing)).
Let b4 be "{b}".
Let bvalCopy2 be copy of bval.
Let sEnvI2 be peStaticEnv(state).
peSeBind(sEnvI2, b4, bvalCopy2).
Push (a new CLet with name b and expr bval) to blockResult.
Set bidx to bidx + 1.
Let matchedBody be peBlock(wBody, state).
Repeat for ms in matchedBody:
Push ms to blockResult.
Set inspDispatched to true.
Return blockResult.
Otherwise:
Let skip be true.
If not inspDispatched:
Repeat for arm in inspArms:
Inspect arm:
When COtherwise (oBody):
Let otherwiseBody be peBlock(oBody, state).
Repeat for os in otherwiseBody:
Push os to blockResult.
Set inspDispatched to true.
Return blockResult.
Otherwise:
Let skip be true.
Otherwise:
Let skip be true.
If not inspDispatched:
Let peArms be a new Seq of CMatchArm.
Repeat for arm in inspArms:
Inspect arm:
When CWhen (wName, wBindings, wBody):
Let peBody be peBlock(wBody, state).
Push (a new CWhen with variantName wName and bindings wBindings and body peBody) to peArms.
When COtherwise (oBody):
Let peBody be peBlock(oBody, state).
Push (a new COtherwise with body peBody) to peArms.
Push (a new CInspect with target peTarget and arms peArms) to blockResult.
When CRuntimeAssert (raCond, raMsg):
Let peRaCond be peExpr(raCond, state).
Let peRaMsg be peExpr(raMsg, state).
Push (a new CRuntimeAssert with cond peRaCond and msg peRaMsg) to blockResult.
When CHardAssert (raCond, raMsg):
Let peRaCond be peExpr(raCond, state).
Let peRaMsg be peExpr(raMsg, state).
Push (a new CHardAssert with cond peRaCond and msg peRaMsg) to blockResult.
When CGive (giveExpr, giveTarget):
Let peGiveExpr be peExpr(giveExpr, state).
Push (a new CGive with expr peGiveExpr and target giveTarget) to blockResult.
When CEscStmt (escCode):
Push (a new CEscStmt with code escCode) to blockResult.
When CSleep (sleepDur):
Let peSleepDur be peExpr(sleepDur, state).
Push (a new CSleep with duration peSleepDur) to blockResult.
When CReadConsole (rcTarget):
Push (a new CReadConsole with target rcTarget) to blockResult.
When CReadFile (rfPath, rfTarget):
Let peRfPath be peExpr(rfPath, state).
Push (a new CReadFile with path peRfPath and target rfTarget) to blockResult.
When CWriteFile (wfPath, wfContent):
Let peWfPath be peExpr(wfPath, state).
Let peWfContent be peExpr(wfContent, state).
Push (a new CWriteFile with path peWfPath and content peWfContent) to blockResult.
When CCheck (chkPred, chkMsg):
Let peChkPred be peExpr(chkPred, state).
Let peChkMsg be peExpr(chkMsg, state).
Push (a new CCheck with predicate peChkPred and msg peChkMsg) to blockResult.
When CAssert (assertProp):
Let peAssertProp be peExpr(assertProp, state).
Push (a new CAssert with proposition peAssertProp) to blockResult.
When CTrust (trustProp, trustJust):
Let peTrustProp be peExpr(trustProp, state).
Push (a new CTrust with proposition peTrustProp and justification trustJust) to blockResult.
When CRequire (reqDep):
Push (a new CRequire with dependency reqDep) to blockResult.
When CMerge (mergeTarget, mergeOther):
Let peMergeOther be peExpr(mergeOther, state).
Push (a new CMerge with target mergeTarget and other peMergeOther) to blockResult.
When CIncrease (incTarget, incAmount):
Let peIncAmount be peExpr(incAmount, state).
Push (a new CIncrease with target incTarget and amount peIncAmount) to blockResult.
When CDecrease (decTarget, decAmount):
Let peDecAmount be peExpr(decAmount, state).
Push (a new CDecrease with target decTarget and amount peDecAmount) to blockResult.
When CAppendToSeq (asTarget, asValue):
Let peAsValue be peExpr(asValue, state).
Push (a new CAppendToSeq with target asTarget and value peAsValue) to blockResult.
When CResolve (resTarget):
Push (a new CResolve with target resTarget) to blockResult.
When CSync (syncTarget, syncChannel):
Let peSyncChannel be peExpr(syncChannel, state).
Push (a new CSync with target syncTarget and channel peSyncChannel) to blockResult.
When CMount (mountTarget, mountPath):
Let peMountPath be peExpr(mountPath, state).
Push (a new CMount with target mountTarget and path peMountPath) to blockResult.
When CConcurrent (concBranches):
Let peConcBranches be a new Seq of Seq of CStmt.
Repeat for concBranch in concBranches:
Push peBlock(concBranch, state) to peConcBranches.
Push (a new CConcurrent with branches peConcBranches) to blockResult.
When CParallel (parBranches):
Let peParBranches be a new Seq of Seq of CStmt.
Repeat for parBranch in parBranches:
Push peBlock(parBranch, state) to peParBranches.
Push (a new CParallel with branches peParBranches) to blockResult.
When CLaunchTask (ltBody, ltHandle):
Let peLtBody be peBlock(ltBody, state).
Push (a new CLaunchTask with body peLtBody and handle ltHandle) to blockResult.
When CStopTask (stHandle):
Let peStHandle be peExpr(stHandle, state).
Push (a new CStopTask with handle peStHandle) to blockResult.
When CSelect (selBranches):
Let peSelBranches be a new Seq of CSelectBranch.
Repeat for selBr in selBranches:
Inspect selBr:
When CSelectRecv (selChan, selVar, selBody):
Let peSelBody be peBlock(selBody, state).
Push (a new CSelectRecv with chan selChan and var selVar and body peSelBody) to peSelBranches.
When CSelectTimeout (selDur, selBody):
Let peSelDur be peExpr(selDur, state).
Let peSelBody be peBlock(selBody, state).
Push (a new CSelectTimeout with duration peSelDur and body peSelBody) to peSelBranches.
Push (a new CSelect with branches peSelBranches) to blockResult.
When CCreatePipe (cpName, cpCapacity):
Let peCpCapacity be peExpr(cpCapacity, state).
Push (a new CCreatePipe with name cpName and capacity peCpCapacity) to blockResult.
When CSendPipe (spPipe, spValue):
Let peSpValue be peExpr(spValue, state).
Push (a new CSendPipe with chan spPipe and value peSpValue) to blockResult.
When CReceivePipe (rpPipe, rpTarget):
Push (a new CReceivePipe with chan rpPipe and target rpTarget) to blockResult.
When CTrySendPipe (tspPipe, tspValue):
Let peTspValue be peExpr(tspValue, state).
Push (a new CTrySendPipe with chan tspPipe and value peTspValue) to blockResult.
When CTryReceivePipe (trpPipe, trpTarget):
Push (a new CTryReceivePipe with chan trpPipe and target trpTarget) to blockResult.
When CSpawn (spawnType, spawnTarget):
Push (a new CSpawn with agentType spawnType and target spawnTarget) to blockResult.
When CSendMessage (smTarget, smMsg):
Let peSmTarget be peExpr(smTarget, state).
Let peSmMsg be peExpr(smMsg, state).
Push (a new CSendMessage with target peSmTarget and msg peSmMsg) to blockResult.
When CStreamMessage (stTarget, stVals):
Let peStTarget be peExpr(stTarget, state).
Let peStVals be peExpr(stVals, state).
Push (a new CStreamMessage with target peStTarget and values peStVals) to blockResult.
When CAwaitMessage (amTarget):
Push (a new CAwaitMessage with target amTarget) to blockResult.
When CListen (listenAddr, listenHandler):
Let peListenAddr be peExpr(listenAddr, state).
Push (a new CListen with addr peListenAddr and handler listenHandler) to blockResult.
When CConnectTo (connAddr, connTarget):
Let peConnAddr be peExpr(connAddr, state).
Push (a new CConnectTo with addr peConnAddr and target connTarget) to blockResult.
When CZone (zoneName, zoneKind, zoneBody):
Let peZoneBody be peBlock(zoneBody, state).
Push (a new CZone with name zoneName and kind zoneKind and body peZoneBody) to blockResult.
Otherwise:
Let skip be true.
Return blockResult.
## To validateExtractReturn (result: CExpr) and (bodyStmts: Seq of CStmt) -> CExpr:
Inspect result:
When CVar (retName):
If retName equals "__no_return__":
Return result.
If retName equals "__unresolvable":
Return result.
Repeat for s in bodyStmts:
Inspect s:
When CLet (letName, letExpr):
If letName equals retName:
Return a new CVar with name "__no_return__".
Otherwise:
Let skip be true.
Return result.
Otherwise:
Return result.
## To extractReturn (stmts: Seq of CStmt) -> CExpr:
Let mutable idx be length of stmts.
While idx is at least 1:
Let s be item idx of stmts.
Inspect s:
When CReturn (retExpr):
Return retExpr.
Otherwise:
Set idx to idx - 1.
Return a new CVar with name "__no_return__".