summaryrefslogtreecommitdiffstats
path: root/elab.sml
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2025-05-16 16:54:17 -0700
committerRose Hogenson <rosehogenson@posteo.net>2025-05-16 16:54:17 -0700
commit5582235bd300f8de997192f9109d596d12df4bbe (patch)
treed219a6c0a3d96052eec422527cd05775354abf76 /elab.sml
parentFix spelling in GenSym (diff)
downloadsml-5582235bd300f8de997192f9109d596d12df4bbe.tar.zst
Fix spelling of file names
Diffstat (limited to 'elab.sml')
-rw-r--r--elab.sml419
1 files changed, 0 insertions, 419 deletions
diff --git a/elab.sml b/elab.sml
deleted file mode 100644
index 60760cd..0000000
--- a/elab.sml
+++ /dev/null
@@ -1,419 +0,0 @@
-structure Elab =
-struct
- structure StringMap = Map(type k = string val cmp = String.compare)
- structure IntMap = Map(type k = int val cmp = Int.compare)
-
- fun primop (s : string) : Syntax.primop =
- case s of
- "exit" => Syntax.PExit
- | "add" => Syntax.PAdd
- | "sub" => Syntax.PSub
- | "mul" => Syntax.PMul
- | "div" => Syntax.PDiv
- | "read" => Syntax.PRead
- | "write" => Syntax.PWrite
- | "writeErr" => Syntax.PWriteErr
- | _ => raise Fail ("invalid op: " ^ s)
-
- fun enumerate (l : 'a list) : (int * 'a) list =
- let
- fun go _ [] = []
- | go i (x :: xs) = (i, x) :: go (i + 1) xs
- in go 0 l
- end
-
- fun hdstls ([] : 'a list list) : ('a list * 'a list list) option = SOME ([], [])
- | hdstls ([] :: _) = NONE
- | hdstls ((x :: xs) :: ls) =
- case hdstls ls of
- NONE => NONE
- | SOME (heads, tails) => SOME (x :: heads, xs :: tails)
-
- fun transpose ([] : 'a list list) : 'a list list = []
- | transpose l =
- case hdstls l of
- NONE => []
- | SOME (heads, tails) => heads :: transpose tails
-
- datatype env = Env of { vars: int StringMap.map, types: (int * int) StringMap.map, structTypes: env StringMap.map }
-
- val emptyEnv = Env { vars = StringMap.empty, types = StringMap.empty, structTypes = StringMap.empty }
-
- fun bindVar (name : string) (sym : int) (Env env) : env = Env { vars = StringMap.insert name sym (#vars env), types = #types env, structTypes = #structTypes env }
-
- fun lookupVar (name : string) (Env env) : int =
- case StringMap.lookup name (#vars env) of
- SOME x => x
- | NONE => raise Fail ("unbound identifier " ^ name)
-
- fun bindDataCons (cons : (string * Syntax.etype option) list) (Env env) : env =
- let
- val nCons = length cons
- val (_, vars, types) =
- foldl
- (fn ((name, _), (i, vars, types)) =>
- (i + 1, StringMap.insert name (GenSym.new ()) vars, StringMap.insert name (i, nCons) types))
- (0, #vars env, #types env)
- cons
- in Env { vars = vars, types = types, structTypes = #structTypes env }
- end
-
- fun lookupStructType (name : string) (Env env) : env =
- case StringMap.lookup name (#structTypes env) of
- SOME x => x
- | NONE => raise Fail ("unbound structure " ^ name)
-
- fun lookupCon ([name] : string list) (Env env) : int option =
- Option.map (fn (i, _) => i) (StringMap.lookup name (#types env))
- | lookupCon (structName :: names) env =
- lookupCon names (lookupStructType structName env)
- | lookupCon [] _ = raise Fail "lookupCon empty"
-
- fun nConstructors ([name] : string list) (Env env) : int =
- let val (_, n) = valOf (StringMap.lookup name (#types env))
- in n
- end
- | nConstructors (structName :: names) env =
- nConstructors names (lookupStructType structName env)
- | nConstructors [] _ = raise Fail "nConstructors empty"
-
- fun patternMatrix (arms : Syntax.pat list) : Syntax.pat list list =
- let val ts =
- foldl
- (fn (Syntax.PWild, tupleSize) => tupleSize
- | (Syntax.PVar _, tupleSize) => tupleSize
- | (Syntax.PCon _, _) => ~2
- | (Syntax.PInt _, _) => ~2
- | (Syntax.PTuple t, ~1) => length t
- | (Syntax.PTuple t, tupleSize) =>
- if tupleSize = length t
- then tupleSize
- else raise Fail "a type checker would have caught this")
- ~1
- arms
- in if ts < 0
- then [arms]
- else let
- val expandedArms =
- map
- (fn Syntax.PTuple t => t
- | _ => List.tabulate (ts, fn _ => Syntax.PWild))
- arms
- val cols = transpose expandedArms
- in List.concat (map patternMatrix cols)
- end
- end
-
- fun occurrenceVector (expr : Syntax.lexp) (arms : Syntax.pat list) : Syntax.lexp list =
- let
- val expandedArms =
- List.mapPartial
- (fn Syntax.PTuple t => SOME t
- | _ => NONE)
- arms
- val cols = transpose expandedArms
- in
- case cols of
- [] => [expr]
- | _ => List.concat (map (fn (i, col) => occurrenceVector (Syntax.LSelect (i, expr)) col) (enumerate cols))
- end
-
- fun patternBindings (expr : Syntax.lexp) (Syntax.PVar v) : (string * Syntax.lexp) list = [(v, expr)]
- | patternBindings expr (Syntax.PTuple t) =
- List.concat (map (fn (i, p) => patternBindings (Syntax.LSelect (i, expr)) p) (enumerate t))
- | patternBindings expr (Syntax.PCon (_, arg)) = patternBindings (Syntax.LSelect (1, expr)) arg
- | patternBindings _ _ = []
-
- fun swap1 0 (l : 'a list) : 'a list = l
- | swap1 n (first :: rest) =
- (case swap1 (n - 1) rest of
- x :: rest => x :: first :: rest
- | _ => raise Fail "swap1: index out of bounds")
- | swap1 _ _ = raise Fail "swap1: index out of bounds"
-
- fun swap (n : int) (patterns : Syntax.pat list list) (occurrences : Syntax.lexp list) : Syntax.pat list list * Syntax.lexp list =
- (map (swap1 n) patterns, swap1 n occurrences)
-
- fun specialize (env : env) (n : int) (patterns : Syntax.pat list list, occurrences : Syntax.lexp list, actions : Syntax.lexp list) : Syntax.pat list list * Syntax.lexp list * Syntax.lexp list =
- let
- val con1 =
- List.find
- (fn Syntax.PCon (name, _) => valOf (lookupCon name env) = n
- | _ => false)
- (map hd patterns)
- val newTupleSize =
- case con1 of
- SOME (Syntax.PCon (_, Syntax.PTuple t)) => length t
- | _ => 0
- val occHead = hd occurrences
- val occRest = tl occurrences
- val occurrences =
- if newTupleSize = 0
- then Syntax.LSelect (1, occHead) :: occRest
- else
- List.tabulate (newTupleSize, fn i => Syntax.LSelect (i, Syntax.LSelect (1, occHead))) @ occRest
- fun specializeRow (Syntax.PInt i :: rest) =
- if i = n then SOME (Syntax.PWild :: rest) else NONE
- | specializeRow (Syntax.PWild :: rest) = SOME (Syntax.PWild :: rest)
- | specializeRow (Syntax.PVar _ :: rest) = SOME (Syntax.PWild :: rest)
- | specializeRow (Syntax.PCon (con, Syntax.PTuple []) :: rest) =
- specializeRow (Syntax.PCon (con, Syntax.PTuple [Syntax.PWild]) :: rest)
- | specializeRow (Syntax.PCon (con, Syntax.PTuple args) :: rest) =
- if valOf (lookupCon con env) = n
- then SOME (args @ rest)
- else NONE
- | specializeRow (Syntax.PCon (con, obj) :: rest) =
- specializeRow (Syntax.PCon (con, Syntax.PTuple [obj]) :: rest)
- | specializeRow _ = raise Fail "unexpected pattern in the matrix"
- val (patterns, actions) =
- ListPair.unzip
- (List.mapPartial
- (fn (p, a) =>
- Option.map (fn p => (p, a)) (specializeRow p))
- (ListPair.zipEq (patterns, actions)))
- in (patterns, occurrences, actions)
- end
-
- fun default (patterns : Syntax.pat list list, occurrences : Syntax.lexp list, actions : Syntax.lexp list) : Syntax.pat list list * Syntax.lexp list * Syntax.lexp list =
- let
- val (patterns, actions) =
- ListPair.unzip
- (List.filter
- (fn (Syntax.PWild :: _, _) => true
- | (Syntax.PVar _ :: _, _) => true
- | _ => false)
- (ListPair.zipEq (patterns, actions)))
- in (patterns, occurrences, actions)
- end
-
- fun compilePatternMatching (env : env) ([] : Syntax.pat list list, _ : Syntax.lexp list, _ : Syntax.lexp list) : Syntax.lexp =
- raise Fail "nonexhaustive match"
- | compilePatternMatching env (patterns as firstRow :: rows, occurrences, actions) =
- let val refutablePattern =
- List.find
- (fn (_, Syntax.PInt _) => true
- | (_, Syntax.PCon _) => true
- | _ => false)
- (enumerate firstRow)
- in
- case refutablePattern of
- NONE => hd actions
- | SOME (i, _) =>
- let
- val (patterns, occurrences) =
- if i = 0
- then (patterns, occurrences)
- else swap i patterns occurrences
- val firstCol = map hd patterns
- val signatures =
- map (fn (x, _) => x)
- (IntMap.toList
- (foldl
- (fn (Syntax.PInt i, acc) => IntMap.insert i true acc
- | (Syntax.PCon (c, _), acc) => IntMap.insert (valOf (lookupCon c env)) true acc
- | (_, acc) => acc)
- IntMap.empty
- firstCol))
- val nCons =
- case List.find (fn (Syntax.PCon _) => true | _ => false) firstCol of
- SOME (Syntax.PCon (name, _)) => nConstructors name env
- | _ => ~1
- val defaultCase =
- if length signatures = nCons
- then NONE
- else SOME (compilePatternMatching env (default (patterns, occurrences, actions)))
- val switchOperand =
- if nCons < 0
- then hd occurrences
- else Syntax.LSelect (0, hd occurrences)
- in
- Syntax.LSwitch
- ( switchOperand
- , map
- (fn i => (i, compilePatternMatching env (specialize env i (patterns, occurrences, actions))))
- signatures
- , defaultCase
- )
- end
- end
-
- fun declBoundVars (Syntax.DVal (p, _)) : string list = map (fn (x, _) => x) (patternBindings (Syntax.LInt 0) p)
- | declBoundVars (Syntax.DValRec (p, _)) = map (fn (x, _) => x) (patternBindings (Syntax.LInt 0) p)
- | declBoundVars (Syntax.DFun (name, _)) = [name]
- | declBoundVars (Syntax.DDatatype (_, cons)) = map (fn (x, _) => x) cons
- | declBoundVars (Syntax.DStruct (name, _)) = [name]
-
- fun structBoundVars (decls : Syntax.dec list) : string list = List.concatMap declBoundVars decls
-
- fun bindStructType (name : string) (decls : Syntax.dec list) (Env env) : env =
- let
- val structEnv =
- foldl
- (fn (Syntax.DDatatype (_, cons), env) => bindDataCons cons env
- | (Syntax.DStruct (name, decls), env) => bindStructType name decls env
- | (_, env) => env)
- emptyEnv
- decls
- val structEnv =
- foldl
- (fn ((i, n), env) => bindVar n i env)
- structEnv
- (enumerate (structBoundVars decls))
- in
- Env { vars = #vars env, types = #types env, structTypes = StringMap.insert name structEnv (#structTypes env) }
- end
-
- fun actionVector (env : env) (expr : Syntax.lexp) (arms : (Syntax.pat * Syntax.expr) list) : Syntax.lexp list =
- map
- (fn (p, body) =>
- let
- val bindings = patternBindings expr p
- val env =
- foldl
- (fn ((name, _), env) =>
- bindVar name (GenSym.new ()) env)
- env
- bindings
- in
- foldl
- (fn ((name, binding), acc) =>
- Syntax.LApp (Syntax.LFn (lookupVar name env, acc), binding))
- (elab env body)
- bindings
- end)
- arms
-
- and elabCase (env : env) (expr : Syntax.lexp) (arms : (Syntax.pat * Syntax.expr) list) =
- let
- val patterns = transpose (patternMatrix (map (fn (x, _) => x) arms))
- val occurrences = occurrenceVector expr (map (fn (x, _) => x) arms)
- val actions = actionVector env expr arms
- val actionFns =
- map
- (fn a => (GenSym.new (), GenSym.new (), a))
- actions
- val smallActions =
- map
- (fn (f, _, _) => Syntax.LApp (Syntax.LVar f, Syntax.LInt 0))
- actionFns
- in
- Syntax.LFix
- ( actionFns
- , compilePatternMatching env (patterns, occurrences, smallActions)
- )
- end
-
- and elab (env : env) (p : Syntax.expr) : Syntax.lexp =
- case p of
- Syntax.EIdent [i] => Syntax.LVar (lookupVar i env)
- | Syntax.EIdent (structName :: accessors) =>
- let
- val s = Syntax.LVar (lookupVar structName env)
- val env = lookupStructType structName env
- fun go env [i] acc = Syntax.LSelect (lookupVar i env, acc)
- | go env (accessor :: accessors) acc =
- let val env = lookupStructType accessor env
- in go env accessors (Syntax.LSelect (lookupVar accessor env, acc))
- end
- | go _ [] _ = raise Fail "go empty"
- in go env accessors s
- end
- | Syntax.EIdent [] => raise Fail "invalid syntax"
- | Syntax.EBuiltin builtin => Syntax.LPrim (primop builtin)
- | Syntax.EInt i => Syntax.LInt i
- | Syntax.EStr s => Syntax.LString s
- | Syntax.ETuple exprs => Syntax.LRecord (map (elab env) exprs)
- | Syntax.EList exprs =>
- foldr
- (fn (x, acc) =>
- Syntax.LRecord [elab env x, acc])
- (Syntax.LInt 0)
- exprs
- | Syntax.EApp (f, x) => Syntax.LApp (elab env f, elab env x)
- | Syntax.ETyped (e, _) => elab env e
- | Syntax.EAndAlso (_, _) => raise Fail "unimplemented"
- | Syntax.EOrElse (_, _) => raise Fail "unimplemented"
- | Syntax.ELet ([], body) => elab env body
- | Syntax.ELet (Syntax.DDatatype (name, cons) :: decls, body) =>
- let
- val env = bindDataCons cons env
- val funs =
- List.mapPartial
- (fn (_, (_, NONE)) => NONE
- | (i, (name, _)) =>
- let val v = GenSym.new ()
- in SOME (lookupVar name env, v, Syntax.LRecord [Syntax.LInt i, Syntax.LVar v])
- end)
- (enumerate cons)
- val vals =
- List.mapPartial
- (fn (i, (name, NONE)) => SOME (lookupVar name env, Syntax.LRecord [Syntax.LInt i])
- | _ => NONE)
- (enumerate cons)
- in
- foldl
- (fn ((v, x), acc) =>
- Syntax.LApp (Syntax.LFn (v, acc), x))
- (Syntax.LFix (funs, elab env (Syntax.ELet (decls, body))))
- vals
- end
- | Syntax.ELet (Syntax.DVal (pat, v) :: decls, body) =>
- elab env (Syntax.ECase (v, [(pat, Syntax.ELet (decls, body))]))
- | Syntax.ELet (Syntax.DValRec (Syntax.PVar name, f as Syntax.ELambda _) :: decls, body) =>
- let
- val n = GenSym.new ()
- val env = bindVar name n env
- val (arg, fnBody) =
- case elab env f of
- Syntax.LFn x => x
- | _ => raise Fail "Syntax.ELambda should expand to Syntax.LFn"
- in
- Syntax.LFix ([(n, arg, fnBody)], elab env (Syntax.ELet (decls, body)))
- end
- | Syntax.ELet (Syntax.DValRec _ :: _, _) => raise Fail "invalid val rec"
- | Syntax.ELet (Syntax.DFun (name, cases) :: decls, body) =>
- let
- val (ps1, _) = hd cases
- val nPats = length ps1
- in if not (List.all (fn (ps, _) => length ps = nPats) cases)
- then raise Fail "clauses do not all have same number of patterns"
- else let
- val n = GenSym.new ()
- val temps = List.tabulate (nPats, fn _ => GenSym.new ())
- val env = bindVar name n env
- val t = GenSym.new ()
- val innerCase = elabCase env (Syntax.LVar t) (map (fn (ps, b) => (Syntax.PTuple ps, b)) cases)
- in
- Syntax.LFix
- ( [ ( n
- , hd temps
- , foldr
- Syntax.LFn
- (Syntax.LApp (Syntax.LFn (t, innerCase), Syntax.LRecord (map Syntax.LVar temps)))
- (tl temps)
- )
- ]
- , elab env (Syntax.ELet (decls, body))
- )
- end
- end
- | Syntax.ELet (Syntax.DStruct (name, structDecls) :: decls, body) =>
- let
- val names = structBoundVars structDecls
- val tuple = elab env (Syntax.ELet (structDecls, Syntax.ETuple (map (fn n => Syntax.EIdent [n]) names)))
- val v = GenSym.new ()
- val env = bindStructType name structDecls env
- val env = bindVar name v env
- in Syntax.LApp (Syntax.LFn (v, elab env (Syntax.ELet (decls, body))), tuple)
- end
- | Syntax.ELambda body =>
- let val v = GenSym.new ()
- in Syntax.LFn (v, elabCase env (Syntax.LVar v) [body])
- end
- | Syntax.ECase (expr, arms) =>
- let val v = GenSym.new ()
- in Syntax.LApp (Syntax.LFn (v, elabCase env (Syntax.LVar v) arms), elab env expr)
- end
-
- fun elaborate (p : Syntax.expr) : Syntax.lexp = elab emptyEnv p
-end