From 8b3a9b8f0d80e7dd789f363deb6bb36189a31f01 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Sun, 18 May 2025 08:17:20 -0700 Subject: Add a typechecker --- .gitignore | 1 + Compiler.sml | 4 +- Elab.sml | 306 +++++++++++++------------------ Parser.sml | 34 +++- ShowSyntax.sml | 92 +++++++++- Syntax.sml | 56 +++++- Types.sml | 464 +++++++++++++++++++++++++++++++++++++++++++++++ generate-show-syntax.sml | 41 +++-- main.sml | 5 +- program.cm | 4 +- run-tests.fish | 12 +- 11 files changed, 793 insertions(+), 226 deletions(-) create mode 100644 Types.sml diff --git a/.gitignore b/.gitignore index cba7efc..1c60091 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ a.out +.cm diff --git a/Compiler.sml b/Compiler.sml index 0ca0ee5..539d334 100644 --- a/Compiler.sml +++ b/Compiler.sml @@ -3,7 +3,9 @@ struct fun compile (prog : Syntax.expr) : Word8Vector.vector = let val _ = print ("ast:\n" ^ ShowSyntax.exprToString prog ^ "\n") - val elab = Elab.elaborate prog + val typed as (typedAST, _) = Types.tag prog + val _ = print ("typed AST:\n" ^ ShowSyntax.typedExprToString typedAST ^ "\n") + val elab = Elab.elaborate typed val _ = print ("lambda lang:\n" ^ ShowSyntax.lexpToString elab ^ "\n") val cps = CPS.toCPS elab diff --git a/Elab.sml b/Elab.sml index 74e331b..cd7a5d4 100644 --- a/Elab.sml +++ b/Elab.sml @@ -35,80 +35,42 @@ struct NONE => [] | SOME (heads, tails) => heads :: transpose tails - datatype env = Env of { vars: int StringMap.map, types: (int * int) StringMap.map, structTypes: env StringMap.map } + datatype env = Env of int StringMap.map - val emptyEnv = Env { vars = StringMap.empty, types = StringMap.empty, structTypes = StringMap.empty } + val emptyEnv = Env 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 bindVar (name : string) (sym : int) (Env env) : env = Env (StringMap.insert name sym env) fun lookupVar (name : string) (Env env) : int = - case StringMap.lookup name (#vars env) of + case StringMap.lookup name 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 bindDataCons (cons : (string * Syntax.ty option) list) (Env env) : env = + Env + (foldl + (fn ((name, _), acc) => + StringMap.insert name (GenSym.new ()) acc) + env + cons) - 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 patternMatrix (arms : (Syntax.typedPat * Syntax.ty) list) : (Syntax.typedPat * Syntax.ty) list list = + if not (isSome (List.find (fn (Syntax.TPTuple t, _) => true | _ => false) arms)) then [arms] else + let + val expandedArms = + map + (fn (Syntax.TPTuple t, _) => t + | (_, Syntax.TTuple tys) => map (fn ty => (Syntax.TPWild, ty)) tys + | _ => raise Fail "unreachable") + arms + val cols = transpose expandedArms + in List.concat (map patternMatrix cols) end - fun occurrenceVector (expr : Syntax.lexp) (arms : Syntax.pat list) : Syntax.lexp list = + fun occurrenceVector (expr : Syntax.lexp) (arms : (Syntax.typedPat * Syntax.ty) list) : Syntax.lexp list = let val expandedArms = List.mapPartial - (fn Syntax.PTuple t => SOME t + (fn (Syntax.TPTuple t, _) => SOME t | _ => NONE) arms val cols = transpose expandedArms @@ -118,10 +80,10 @@ struct | _ => 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) = + fun patternBindings (expr : Syntax.lexp) (Syntax.TPVar v, _ : Syntax.ty) : (string * Syntax.lexp) list = [(v, expr)] + | patternBindings expr (Syntax.TPTuple 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 expr (Syntax.TPCon (_, arg), _) = patternBindings (Syntax.LSelect (1, expr)) arg | patternBindings _ _ = [] fun swap1 0 (l : 'a list) : 'a list = l @@ -131,19 +93,24 @@ struct | _ => 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 = + fun swap (n : int) (patterns : (Syntax.typedPat * Syntax.ty) list list) (occurrences : Syntax.lexp list) : (Syntax.typedPat * Syntax.ty) 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 = + fun lookupCon (name : string) (ty : string list) : int = + case List.find (fn (_, x) => x = name) (enumerate ty) of + SOME (i, _) => i + | NONE => raise Fail ("Unknown field " ^ name) + + fun specialize (n : int) (patterns : (Syntax.typedPat * Syntax.ty) list list, occurrences : Syntax.lexp list, actions : Syntax.lexp list) : (Syntax.typedPat * Syntax.ty) list list * Syntax.lexp list * Syntax.lexp list = let val con1 = List.find - (fn Syntax.PCon (name, _) => valOf (lookupCon name env) = n + (fn (Syntax.TPCon (name, _), Syntax.TDatatype cons) => lookupCon (List.last name) cons = n | _ => false) (map hd patterns) val newTupleSize = case con1 of - SOME (Syntax.PCon (_, Syntax.PTuple t)) => length t + SOME (Syntax.TPCon (_, (Syntax.TPTuple t, _)), _) => length t | _ => 0 val occHead = hd occurrences val occRest = tl occurrences @@ -152,19 +119,19 @@ struct 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 + fun specializeRow ((Syntax.TPInt i, ty):: rest) = + if i = n then SOME ((Syntax.TPWild, ty) :: rest) else NONE + | specializeRow ((Syntax.TPWild, ty) :: rest) = SOME ((Syntax.TPWild, ty) :: rest) + | specializeRow ((Syntax.TPVar _, ty) :: rest) = SOME ((Syntax.TPWild, ty) :: rest) + | specializeRow ((Syntax.TPCon (con, (Syntax.TPTuple [], tupleTy)), conTy) :: rest) = + specializeRow ((Syntax.TPCon (con, (Syntax.TPTuple [(Syntax.TPWild, Syntax.TTuple [])], tupleTy)), conTy) :: rest) + | specializeRow ((Syntax.TPCon (con, (Syntax.TPTuple args, _)), Syntax.TDatatype cons) :: rest) = + if lookupCon (List.last con) cons = 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" + | specializeRow ((Syntax.TPCon (con, (obj, objTy)), ty) :: rest) = + specializeRow ((Syntax.TPCon (con, (Syntax.TPTuple [(obj, objTy)], Syntax.TTuple [objTy])), ty) :: rest) + | specializeRow _ = raise Fail "you think that's air you're breathing now?" val (patterns, actions) = ListPair.unzip (List.mapPartial @@ -174,26 +141,26 @@ struct 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 = + fun default (patterns : (Syntax.typedPat * Syntax.ty) list list, occurrences : Syntax.lexp list, actions : Syntax.lexp list) : (Syntax.typedPat * Syntax.ty) list list * Syntax.lexp list * Syntax.lexp list = let val (patterns, actions) = ListPair.unzip (List.filter - (fn (Syntax.PWild :: _, _) => true - | (Syntax.PVar _ :: _, _) => true + (fn ((Syntax.TPWild, _) :: _, _) => true + | ((Syntax.TPVar _, _) :: _, _) => true | _ => false) (ListPair.zipEq (patterns, actions))) in (patterns, occurrences, actions) end (* https://compiler.club/compiling-pattern-matching/ *) - fun compilePatternMatching (env : env) ([] : Syntax.pat list list, _ : Syntax.lexp list, _ : Syntax.lexp list) : Syntax.lexp = + fun compilePatternMatching ([] : (Syntax.typedPat * Syntax.ty) list list, _ : Syntax.lexp list, _ : Syntax.lexp list) : Syntax.lexp = raise Fail "nonexhaustive match" - | compilePatternMatching env (patterns as firstRow :: rows, occurrences, actions) = + | compilePatternMatching (patterns as firstRow :: rows, occurrences, actions) = let val refutablePattern = List.find - (fn (_, Syntax.PInt _) => true - | (_, Syntax.PCon _) => true + (fn (_, (Syntax.TPInt _, _)) => true + | (_, (Syntax.TPCon _, _)) => true | _ => false) (enumerate firstRow) in @@ -210,19 +177,19 @@ struct 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 + (fn ((Syntax.TPInt i, _), acc) => IntMap.insert i true acc + | ((Syntax.TPCon (c, _), Syntax.TDatatype cons), acc) => IntMap.insert (lookupCon (List.last c) cons) 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 + case List.find (fn (Syntax.TPCon _, _) => true | _ => false) firstCol of + SOME (Syntax.TPCon _, Syntax.TDatatype cons) => length cons | _ => ~1 val defaultCase = if length signatures = nCons then NONE - else SOME (compilePatternMatching env (default (patterns, occurrences, actions))) + else SOME (compilePatternMatching (default (patterns, occurrences, actions))) val switchOperand = if nCons < 0 then hd occurrences @@ -231,49 +198,22 @@ struct Syntax.LSwitch ( switchOperand , map - (fn i => (i, compilePatternMatching env (specialize env i (patterns, occurrences, actions)))) + (fn i => (i, compilePatternMatching (specialize 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 declBoundVars (Syntax.TDVal (p, _)) : string list = map (fn (x, _) => x) (patternBindings (Syntax.LInt 0) p) + | declBoundVars (Syntax.TDValRec (p, _)) = map (fn (x, _) => x) (patternBindings (Syntax.LInt 0) p) + | declBoundVars (Syntax.TDFun (name, _)) = [name] + | declBoundVars (Syntax.TDDatatype (_, cons)) = map (fn (x, _) => x) cons + | declBoundVars (Syntax.TDStruct (name, _)) = [name] - fun bindStruct (name : string) (structEnv : env) (Env { vars, types, structTypes }) : env = - Env { vars = vars, types = types, structTypes = StringMap.insert name structEnv structTypes } - - 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, Syntax.SStruct decls), env) => bindStructType name decls env - | (Syntax.DStruct (name, Syntax.SIdent ident), env) => - let - fun lookup [name] env = lookupStructType name env - | lookup (name :: names) env = lookup names (lookupStructType name env) - | lookup _ _ = raise Fail "invalid struct identifier" - in lookup ident env end - | (_, env) => env) - emptyEnv - decls - val structEnv = - foldl - (fn ((i, n), env) => bindVar n i env) - structEnv - (enumerate (structBoundVars decls)) - in - bindStruct name structEnv env - end + fun structBoundVars (decls : Syntax.typedDec list) : string list = List.concatMap declBoundVars decls - fun actionVector (env : env) (expr : Syntax.lexp) (arms : (Syntax.pat * Syntax.expr) list) : Syntax.lexp list = + fun actionVector (env : env) (expr : Syntax.lexp) (arms : ((Syntax.typedPat * Syntax.ty) * (Syntax.typedExpr * Syntax.ty)) list) : Syntax.lexp list = map (fn (p, body) => let @@ -293,7 +233,7 @@ struct end) arms - and elabCase (env : env) (expr : Syntax.lexp) (arms : (Syntax.pat * Syntax.expr) list) = + and elabCase (env : env) (expr : Syntax.lexp) (arms : ((Syntax.typedPat * Syntax.ty) * (Syntax.typedExpr * Syntax.ty)) list) = let val patterns = transpose (patternMatrix (map (fn (x, _) => x) arms)) val occurrences = occurrenceVector expr (map (fn (x, _) => x) arms) @@ -309,41 +249,35 @@ struct in Syntax.LFix ( actionFns - , compilePatternMatching env (patterns, occurrences, smallActions) + , compilePatternMatching (patterns, occurrences, smallActions) ) end - and elab (env : env) (p : Syntax.expr) : Syntax.lexp = + and elab (env : env) (p : Syntax.typedExpr, ty : Syntax.ty) : Syntax.lexp = case p of - Syntax.EIdent [i] => Syntax.LVar (lookupVar i env) - | Syntax.EIdent (structName :: accessors) => + Syntax.TEIdent i => Syntax.LVar (lookupVar i env) + | Syntax.TEDot (structExpr as (_, Syntax.TStruct (_, fields)), field) => 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 => + val i = + case List.find (fn (_, (x, _)) => x = field) (enumerate fields) of + NONE => raise Fail ("Unknown field " ^ field) + | SOME (i, _) => i + in Syntax.LSelect (i, elabStructExpr env structExpr) end + | Syntax.TEBuiltin builtin => Syntax.LPrim (primop builtin) + | Syntax.TEInt i => Syntax.LInt i + | Syntax.TEStr s => Syntax.LString s + | Syntax.TETuple exprs => Syntax.LRecord (map (elab env) exprs) + | Syntax.TEList 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) => + | Syntax.TEApp (f, x) => Syntax.LApp (elab env f, elab env x) + | Syntax.TEAndAlso (_, _) => raise Fail "unimplemented" + | Syntax.TEOrElse (_, _) => raise Fail "unimplemented" + | Syntax.TELet ([], body) => elab env body + | Syntax.TELet (Syntax.TDDatatype (name, cons) :: decls, body) => let val env = bindDataCons cons env val funs = @@ -363,12 +297,12 @@ struct foldl (fn ((v, x), acc) => Syntax.LApp (Syntax.LFn (v, acc), x)) - (Syntax.LFix (funs, elab env (Syntax.ELet (decls, body)))) + (Syntax.LFix (funs, elab env (Syntax.TELet (decls, body), ty))) 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) => + | Syntax.TELet (Syntax.TDVal (pat, v) :: decls, body) => + elab env (Syntax.TECase (v, [(pat, (Syntax.TELet (decls, body), ty))]), ty) + | Syntax.TELet (Syntax.TDValRec ((Syntax.TPVar name, _), f as (Syntax.TELambda _, _)) :: decls, body) => let val n = GenSym.new () val env = bindVar name n env @@ -377,10 +311,10 @@ struct 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))) + Syntax.LFix ([(n, arg, fnBody)], elab env (Syntax.TELet (decls, body), ty)) end - | Syntax.ELet (Syntax.DValRec _ :: _, _) => raise Fail "invalid val rec" - | Syntax.ELet (Syntax.DFun (name, cases) :: decls, body) => + | Syntax.TELet (Syntax.TDValRec _ :: _, _) => raise Fail "invalid val rec" + | Syntax.TELet (Syntax.TDFun (name, cases) :: decls, body) => let val (ps1, _) = hd cases val nPats = length ps1 @@ -391,7 +325,12 @@ struct 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) + val innerCase = + elabCase env (Syntax.LVar t) + (map + (fn (ps, b) => + ((Syntax.TPTuple ps, Syntax.TTuple (map (fn (_, t) => t) ps)), b)) + cases) in Syntax.LFix ( [ ( n @@ -402,37 +341,44 @@ struct (tl temps) ) ] - , elab env (Syntax.ELet (decls, body)) + , elab env (Syntax.TELet (decls, body), ty) ) end end - | Syntax.ELet (Syntax.DStruct (name, Syntax.SStruct structDecls) :: decls, body) => + | Syntax.TELet (Syntax.TDStruct (name, (Syntax.TSStruct 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 tuple = elab env (Syntax.TELet (structDecls, (Syntax.TETuple (map (fn n => (Syntax.TEIdent n, Syntax.TTuple [])) names), Syntax.TTuple [] (* TODO *))), Syntax.TTuple [] (* TODO *)) + val v = GenSym.new () + val env = bindVar name v env + in Syntax.LApp (Syntax.LFn (v, elab env (Syntax.TELet (decls, body), ty)), tuple) end + | Syntax.TELet (Syntax.TDStruct (name, (Syntax.TSIdent structName, _)) :: decls, body) => + let 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.ELet (Syntax.DStruct (name, Syntax.SIdent (structName :: accessors)) :: decls, body) => + in Syntax.LApp (Syntax.LFn (v, elab env (Syntax.TELet (decls, body), ty)), Syntax.LVar (lookupVar structName env)) end + | Syntax.TELet (Syntax.TDStruct (name, (Syntax.TSDot (parent as (_, Syntax.TStruct (fields, _)), field), _)) :: decls, body) => let - val s = Syntax.LVar (lookupVar structName env) - fun go env [] acc = (env, acc) - | go env (accessor :: accessors) acc = - go - (lookupStructType accessor env) - accessors - (Syntax.LSelect (lookupVar accessor env, acc)) - val (structEnv, structExpr) = go (lookupStructType structName env) accessors s val v = GenSym.new () - val env = bindStruct name structEnv env val env = bindVar name v env - in Syntax.LApp (Syntax.LFn (v, elab env (Syntax.ELet (decls, body))), structExpr) end - | Syntax.ELambda body => + val i = + case List.find (fn (_, (x, _)) => x = field) (enumerate fields) of + NONE => raise Fail ("Unknown field " ^ field) + | SOME (i, _) => i + in Syntax.LApp (Syntax.LFn (v, elab env (Syntax.TELet (decls, body), ty)), Syntax.LSelect (i, elabStructExpr env parent)) end + | Syntax.TELambda body => let val v = GenSym.new () in Syntax.LFn (v, elabCase env (Syntax.LVar v) [body]) end - | Syntax.ECase (expr, arms) => + | Syntax.TECase (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 + and elabStructExpr (env : env) (Syntax.TSIdent structName, _ : Syntax.structType) : Syntax.lexp = Syntax.LVar (lookupVar structName env) + | elabStructExpr env (Syntax.TSDot (expr as (_, Syntax.TStruct (_, fields)), field), _) = + let val i = + case List.find (fn (_, (x, _)) => x = field) (enumerate fields) of + SOME (i, _) => i + | NONE => raise Fail "unbound field" + in Syntax.LSelect (i, elabStructExpr env expr) end + + fun elaborate (p : Syntax.typedExpr * Syntax.ty) : Syntax.lexp = elab emptyEnv p end diff --git a/Parser.sml b/Parser.sml index 4e20c13..8a1e1f3 100644 --- a/Parser.sml +++ b/Parser.sml @@ -451,12 +451,25 @@ struct typedPat (List.tabulate (10, fn i => 9 - i)) st + fun makeConvolutedEDotSyntax ([i] : string list) : Syntax.expr = Syntax.EIdent i + | makeConvolutedEDotSyntax (i :: is) = + let + val structSelectors = List.take (is, length is - 1) + val exprSelector = List.last is + in + Syntax.EDot + ( foldl (fn (x, acc) => Syntax.SDot (acc, x)) (Syntax.SIdent i) structSelectors + , exprSelector + ) + end + | makeConvolutedEDotSyntax _ = raise Fail "bad identifier" + val rec atom : Syntax.expr parser = fn st => (Syntax.EInt <$> integer <|> Syntax.EStr <$> stringConstant - <|> Syntax.EIdent <$> longIdentifier - <|> (reserved "op" >> Syntax.EIdent <$> longInfixIdentifier) + <|> makeConvolutedEDotSyntax <$> longIdentifier + <|> (reserved "op" >> makeConvolutedEDotSyntax <$> longInfixIdentifier) <|> builtin <|> (reserved "let" >> bind (many dec) (fn decs => @@ -483,14 +496,14 @@ struct fun exprLeft expr1 = bind (leftOp i) (fn opEx => bind exprLower (fn expr2 => - let val app = Syntax.EApp (Syntax.EIdent [opEx], Syntax.ETuple [expr1, expr2]) + let val app = Syntax.EApp (Syntax.EIdent opEx, Syntax.ETuple [expr1, expr2]) in exprLeft app <|> const app end)) fun exprRight expr1 = bind (rightOp i) (fn opEx => bind exprLower (fn expr2 => bind (exprRight expr2 <|> const expr2) (fn rest => - const (Syntax.EApp (Syntax.EIdent [opEx], Syntax.ETuple [expr1, rest]))))) + const (Syntax.EApp (Syntax.EIdent opEx, Syntax.ETuple [expr1, rest]))))) in bind exprLower (fn expr1 => exprLeft expr1 <|> exprRight expr1 <|> const expr1) @@ -550,9 +563,10 @@ struct end) >> const NONE))) <|> ((reserved "datatype" <|> reserved "and") >> - (between (symbol "(") (symbol ")") (sepBy1 tyvar (symbol ",")) - <|> (fn x => [x]) <$> tyvar - <|> const []) >> + bind + (between (symbol "(") (symbol ")") (sepBy1 tyvar (symbol ",")) + <|> (fn x => [x]) <$> tyvar + <|> const []) (fn vars => bind identifier (fn name => reserved "=" >> bind @@ -563,7 +577,7 @@ struct const (con, SOME ty))) <|> const (con, NONE))) (reserved "|")) (fn cons => - const (SOME (Syntax.DDatatype (name, cons)))))) + const (SOME (Syntax.DDatatype (vars, name, cons))))))) <|> (reserved "type" >> bind identifier (fn name => reserved "=" >> @@ -614,7 +628,7 @@ struct bind (many strdec) (fn bindings => reserved "end" >> const (Syntax.SStruct (List.mapPartial (fn x => x) bindings)))) - <|> Syntax.SIdent <$> longIdentifier) st + <|> (fn is => foldl (fn (x, acc) => Syntax.SDot (acc, x)) (Syntax.SIdent (hd is)) (tl is)) <$> longIdentifier) st (* There's ambiguity between pattern variables and constructors that can only * be resolved by checking for constructors in scope *) @@ -626,7 +640,7 @@ struct | fixPatConstructors constructors (Syntax.PCon (con, arg)) = Syntax.PCon (con, fixPatConstructors constructors arg) | fixPatConstructors _ pat = pat - fun findConstructors (Syntax.DDatatype (_, cases)) : string list = + fun findConstructors (Syntax.DDatatype (_, _, cases)) : string list = List.mapPartial (fn (constructor, NONE) => SOME constructor | _ => NONE) diff --git a/ShowSyntax.sml b/ShowSyntax.sml index 651ddda..f28895d 100644 --- a/ShowSyntax.sml +++ b/ShowSyntax.sml @@ -47,7 +47,9 @@ and patToStringI (indent : string) (Syntax.PWild : Syntax.pat) : string = and patToString (x : Syntax.pat) : string = patToStringI "" x and exprToStringI (indent : string) (Syntax.EIdent x : Syntax.expr) : string = - "EIdent " ^ listToString (stringToStringI) indent x + "EIdent " ^ stringToStringI indent x + | exprToStringI (indent : string) (Syntax.EDot x : Syntax.expr) : string = + "EDot " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ structExprToStringI indent' x0 ^ ",\n" ^ indent' ^ stringToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent x | exprToStringI (indent : string) (Syntax.EBuiltin x : Syntax.expr) : string = "EBuiltin " ^ stringToStringI indent x | exprToStringI (indent : string) (Syntax.EInt x : Syntax.expr) : string = @@ -81,7 +83,7 @@ and decToStringI (indent : string) (Syntax.DVal x : Syntax.dec) : string = | decToStringI (indent : string) (Syntax.DFun x : Syntax.dec) : string = "DFun " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ listToString (patToStringI) indent' x0 ^ ",\n" ^ indent' ^ exprToStringI indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x | decToStringI (indent : string) (Syntax.DDatatype x : Syntax.dec) : string = - "DDatatype " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ optionToString (etypeToStringI) indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + "DDatatype " ^ (fn indent => fn (x0, x1, x2) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ listToString (stringToStringI) indent' x0 ^ ",\n" ^ indent' ^ stringToStringI indent' x1 ^ ",\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ optionToString (etypeToStringI) indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x2 ^ "\n" ^ indent ^ ")" end) indent x | decToStringI (indent : string) (Syntax.DType x : Syntax.dec) : string = "DType " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ etypeToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent x | decToStringI (indent : string) (Syntax.DStruct x : Syntax.dec) : string = @@ -89,11 +91,95 @@ and decToStringI (indent : string) (Syntax.DVal x : Syntax.dec) : string = and decToString (x : Syntax.dec) : string = decToStringI "" x and structExprToStringI (indent : string) (Syntax.SIdent x : Syntax.structExpr) : string = - "SIdent " ^ listToString (stringToStringI) indent x + "SIdent " ^ stringToStringI indent x + | structExprToStringI (indent : string) (Syntax.SDot x : Syntax.structExpr) : string = + "SDot " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ structExprToStringI indent' x0 ^ ",\n" ^ indent' ^ stringToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent x | structExprToStringI (indent : string) (Syntax.SStruct x : Syntax.structExpr) : string = "SStruct " ^ listToString (decToStringI) indent x and structExprToString (x : Syntax.structExpr) : string = structExprToStringI "" x +and tyToStringI (indent : string) (Syntax.TInt : Syntax.ty) : string = + "TInt" + | tyToStringI (indent : string) (Syntax.TBool : Syntax.ty) : string = + "TBool" + | tyToStringI (indent : string) (Syntax.TString : Syntax.ty) : string = + "TString" + | tyToStringI (indent : string) (Syntax.TVar x : Syntax.ty) : string = + "TVar " ^ intToStringI indent x + | tyToStringI (indent : string) (Syntax.TTuple x : Syntax.ty) : string = + "TTuple " ^ listToString (tyToStringI) indent x + | tyToStringI (indent : string) (Syntax.TFun x : Syntax.ty) : string = + "TFun " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ tyToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | tyToStringI (indent : string) (Syntax.TList x : Syntax.ty) : string = + "TList " ^ tyToStringI indent x + | tyToStringI (indent : string) (Syntax.TDatatype x : Syntax.ty) : string = + "TDatatype " ^ listToString (stringToStringI) indent x +and tyToString (x : Syntax.ty) : string = tyToStringI "" x + +and structTypeToStringI (indent : string) (Syntax.TStruct x : Syntax.structType) : string = + "TStruct " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ structTypeToStringI indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x0 ^ ",\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x +and structTypeToString (x : Syntax.structType) : string = structTypeToStringI "" x + +and typedPatToStringI (indent : string) (Syntax.TPWild : Syntax.typedPat) : string = + "TPWild" + | typedPatToStringI (indent : string) (Syntax.TPVar x : Syntax.typedPat) : string = + "TPVar " ^ stringToStringI indent x + | typedPatToStringI (indent : string) (Syntax.TPInt x : Syntax.typedPat) : string = + "TPInt " ^ intToStringI indent x + | typedPatToStringI (indent : string) (Syntax.TPTuple x : Syntax.typedPat) : string = + "TPTuple " ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedPatToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end)) indent x + | typedPatToStringI (indent : string) (Syntax.TPCon x : Syntax.typedPat) : string = + "TPCon " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ listToString (stringToStringI) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedPatToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x +and typedPatToString (x : Syntax.typedPat) : string = typedPatToStringI "" x + +and typedExprToStringI (indent : string) (Syntax.TEIdent x : Syntax.typedExpr) : string = + "TEIdent " ^ stringToStringI indent x + | typedExprToStringI (indent : string) (Syntax.TEDot x : Syntax.typedExpr) : string = + "TEDot " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedStructExprToStringI indent' x0 ^ ",\n" ^ indent' ^ structTypeToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ stringToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedExprToStringI (indent : string) (Syntax.TEBuiltin x : Syntax.typedExpr) : string = + "TEBuiltin " ^ stringToStringI indent x + | typedExprToStringI (indent : string) (Syntax.TEInt x : Syntax.typedExpr) : string = + "TEInt " ^ intToStringI indent x + | typedExprToStringI (indent : string) (Syntax.TEStr x : Syntax.typedExpr) : string = + "TEStr " ^ stringToStringI indent x + | typedExprToStringI (indent : string) (Syntax.TETuple x : Syntax.typedExpr) : string = + "TETuple " ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end)) indent x + | typedExprToStringI (indent : string) (Syntax.TEList x : Syntax.typedExpr) : string = + "TEList " ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end)) indent x + | typedExprToStringI (indent : string) (Syntax.TEApp x : Syntax.typedExpr) : string = + "TEApp " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedExprToStringI (indent : string) (Syntax.TEAndAlso x : Syntax.typedExpr) : string = + "TEAndAlso " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedExprToStringI (indent : string) (Syntax.TEOrElse x : Syntax.typedExpr) : string = + "TEOrElse " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedExprToStringI (indent : string) (Syntax.TELet x : Syntax.typedExpr) : string = + "TELet " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ listToString (typedDecToStringI) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedExprToStringI (indent : string) (Syntax.TELambda x : Syntax.typedExpr) : string = + "TELambda " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedPatToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedExprToStringI (indent : string) (Syntax.TECase x : Syntax.typedExpr) : string = + "TECase " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedPatToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x +and typedExprToString (x : Syntax.typedExpr) : string = typedExprToStringI "" x + +and typedDecToStringI (indent : string) (Syntax.TDVal x : Syntax.typedDec) : string = + "TDVal " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedPatToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedDecToStringI (indent : string) (Syntax.TDValRec x : Syntax.typedDec) : string = + "TDValRec " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedPatToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedDecToStringI (indent : string) (Syntax.TDFun x : Syntax.typedDec) : string = + "TDFun " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedPatToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedExprToStringI indent' x0 ^ ",\n" ^ indent' ^ tyToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedDecToStringI (indent : string) (Syntax.TDDatatype x : Syntax.typedDec) : string = + "TDDatatype " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ listToString ((fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ optionToString (tyToStringI) indent' x1 ^ "\n" ^ indent ^ ")" end)) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedDecToStringI (indent : string) (Syntax.TDStruct x : Syntax.typedDec) : string = + "TDStruct " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ stringToStringI indent' x0 ^ ",\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedStructExprToStringI indent' x0 ^ ",\n" ^ indent' ^ structTypeToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x1 ^ "\n" ^ indent ^ ")" end) indent x +and typedDecToString (x : Syntax.typedDec) : string = typedDecToStringI "" x + +and typedStructExprToStringI (indent : string) (Syntax.TSIdent x : Syntax.typedStructExpr) : string = + "TSIdent " ^ stringToStringI indent x + | typedStructExprToStringI (indent : string) (Syntax.TSDot x : Syntax.typedStructExpr) : string = + "TSDot " ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ (fn indent => fn (x0, x1) => let val indent' = indent ^ " " in "(\n" ^ indent' ^ typedStructExprToStringI indent' x0 ^ ",\n" ^ indent' ^ structTypeToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent' x0 ^ ",\n" ^ indent' ^ stringToStringI indent' x1 ^ "\n" ^ indent ^ ")" end) indent x + | typedStructExprToStringI (indent : string) (Syntax.TSStruct x : Syntax.typedStructExpr) : string = + "TSStruct " ^ listToString (typedDecToStringI) indent x +and typedStructExprToString (x : Syntax.typedStructExpr) : string = typedStructExprToStringI "" x + and primopToStringI (indent : string) (Syntax.PExit : Syntax.primop) : string = "PExit" | primopToStringI (indent : string) (Syntax.PAdd : Syntax.primop) : string = diff --git a/Syntax.sml b/Syntax.sml index 5d45133..0d10dd2 100644 --- a/Syntax.sml +++ b/Syntax.sml @@ -15,7 +15,8 @@ struct | PCon of string list * pat datatype expr = - EIdent of string list + EIdent of string + | EDot of structExpr * string | EBuiltin of string | EInt of int | EStr of string @@ -33,14 +34,63 @@ struct DVal of pat * expr | DValRec of pat * expr | DFun of string * (pat list * expr) list - | DDatatype of string * (string * etype option) list + | DDatatype of string list * string * (string * etype option) list | DType of string * etype | DStruct of string * structExpr and structExpr = - SIdent of string list + SIdent of string + | SDot of structExpr * string | SStruct of dec list + datatype ty = + TInt + | TBool + | TString + | TVar of int + | TTuple of ty list + | TFun of ty * ty + | TList of ty + | TDatatype of string list + + datatype structType = + TStruct of (string * structType) list * (string * ty) list +(*| TFunctor of structType * structType *) + + datatype typedPat = + TPWild + | TPVar of string + | TPInt of int + | TPTuple of (typedPat * ty) list + | TPCon of string list * (typedPat * ty) + + datatype typedExpr = + TEIdent of string + | TEDot of (typedStructExpr * structType) * string + | TEBuiltin of string + | TEInt of int + | TEStr of string + | TETuple of (typedExpr * ty) list + | TEList of (typedExpr * ty) list + | TEApp of (typedExpr * ty) * (typedExpr * ty) + | TEAndAlso of (typedExpr * ty) * (typedExpr * ty) + | TEOrElse of (typedExpr * ty) * (typedExpr * ty) + | TELet of typedDec list * (typedExpr * ty) + | TELambda of (typedPat * ty) * (typedExpr * ty) + | TECase of (typedExpr * ty) * ((typedPat * ty) * (typedExpr * ty)) list + + and typedDec = + TDVal of (typedPat * ty) * (typedExpr * ty) + | TDValRec of (typedPat * ty) * (typedExpr * ty) + | TDFun of string * ((typedPat * ty) list * (typedExpr * ty)) list + | TDDatatype of string * (string * ty option) list + | TDStruct of string * (typedStructExpr * structType) + + and typedStructExpr = + TSIdent of string + | TSDot of (typedStructExpr * structType) * string + | TSStruct of typedDec list + (* Lambda language *) type var = int diff --git a/Types.sml b/Types.sml new file mode 100644 index 0000000..2722063 --- /dev/null +++ b/Types.sml @@ -0,0 +1,464 @@ +structure Types = struct + structure StringMap = Map(type k = string val cmp = String.compare) + structure IntMap = Map(type k = int val cmp = Int.compare) + + type tyvar = int + datatype tycon = Bool | Int | Str | Fun | Tuple | List | Datatype of int + and ty = + TyVar of tyvar + | TyCon of tycon * ty list + | TyStruct of structTy + and structTy = Struct of { + structs : structTy StringMap.map, + vals : ty StringMap.map + } + + structure TyVarMap = IntMap + + fun listToString (show : 'a -> string) (l : 'a list) : string = + "[" ^ String.concatWith ", " (map show l) ^ "]" + + fun printTyCon Int : string = "Int" + | printTyCon Fun = "Fun" + | printTyCon Tuple = "Tuple" + | printTyCon (Datatype tag) = "Datatype " ^ Int.toString tag + + and printTy (TyVar a) : string = "TyVar " ^ Int.toString a + | printTy (TyCon (n, tys)) = "TyCon (" ^ printTyCon n ^ ", " ^ listToString printTy tys ^ ")" + + (* map of type variables to types *) + val substitution : ty TyVarMap.map ref = ref TyVarMap.empty + + (* map of datatype tags to type description *) + val datatypes : string list IntMap.map ref = ref IntMap.empty + + fun find (TyVar a) : ty = + let val representative = + case getOpt (TyVarMap.lookup a (!substitution), TyVar a) of + TyVar b => if a = b then TyVar a else find (TyVar b) + | t => find t + in + substitution := TyVarMap.insert a representative (!substitution) ; + representative + end + | find (TyCon (n, ts)) = TyCon (n, map find ts) + | find (TyStruct structType) = TyStruct structType + + fun unify (t1 : ty) (t2 : ty) : unit = + case (find t1, find t2) of + (TyVar a, t2) => substitution := TyVarMap.insert a t2 (!substitution) + | (t1, TyVar a) => substitution := TyVarMap.insert a t1 (!substitution) + | (TyCon (n1, tys1), TyCon (n2, tys2)) => + if n1 <> n2 orelse length tys1 <> length tys2 then raise Fail ("attempt to unify distinct types " ^ printTy (TyCon (n1, tys1)) ^ " and " ^ printTy (TyCon (n2, tys2))) else + ListPair.appEq (fn (t1, t2) => unify t1 t2) (tys1, tys2) + | _ => raise Fail "unify invalid types" + + datatype binding = Let of tyvar | Arg of tyvar + + type env = { + bindings : binding StringMap.map, + boundVars : unit TyVarMap.map, + typesByName : tycon StringMap.map, + structs : structTy StringMap.map + } + + fun bind (makeBinding : tyvar -> binding) (s : string) (v : tyvar) ({bindings, boundVars, typesByName, structs} : env) : env = { + bindings = StringMap.insert s (makeBinding v) bindings, + boundVars = TyVarMap.insert v () boundVars, + typesByName = typesByName, + structs = structs + } + + val userTypeVariables : tyvar StringMap.map ref = ref StringMap.empty + + fun etypeToTy (_ : env) (Syntax.Tyvar "int") = TyCon (Int, []) + | etypeToTy _ (Syntax.Tyvar "bool") = TyCon (Bool, []) + | etypeToTy _ (Syntax.Tyvar "string") = TyCon (Str, []) + | etypeToTy env (Syntax.Tyvar v) = + if String.isPrefix "'" v then + case StringMap.lookup v (!userTypeVariables) of + SOME v => TyVar v + | NONE => + let val t = GenSym.new () in + userTypeVariables := StringMap.insert v t (!userTypeVariables); + TyVar t + end + else + (case StringMap.lookup v (#typesByName env) of + SOME t => TyCon (t, []) + | NONE => raise Fail "unknown type") + | etypeToTy env (Syntax.Tycon (tys, ty)) = + (case StringMap.lookup ty (#typesByName env) of + SOME t => TyCon (t, map (etypeToTy env) tys) + | NONE => raise Fail ("unknown type " ^ ty)) + | etypeToTy env (Syntax.TyTuple tys) = TyCon (Tuple, map (etypeToTy env) tys) + | etypeToTy env (Syntax.Tyfun (arg, result)) = TyCon (Fun, [etypeToTy env arg, etypeToTy env result]) + + fun bindType ((vars, name, constructors) : string list * string * (string * Syntax.etype option) list) (env as {bindings, boundVars, typesByName, structs} : env) : env = + let + val tag = GenSym.new () + val env = { + bindings = bindings, + boundVars = boundVars, + typesByName = StringMap.insert name (Datatype tag) typesByName, + structs = structs + } + in + datatypes := IntMap.insert tag (map (fn (x, _) => x) constructors) (!datatypes) ; + foldl + (fn ((x, t), env) => + let + val g = GenSym.new () + val resType = TyCon (Datatype tag, map (etypeToTy env o Syntax.Tyvar) vars) + val conType = + case t of + NONE => resType + | SOME t => TyCon (Fun, [etypeToTy env t, resType]) + in + unify (TyVar g) conType; + bind Let x g env + end) + env + constructors + end + + fun bindStruct (name : string) (str : structTy) ({bindings, boundVars, typesByName, structs} : env) : env = { + bindings = bindings, + boundVars = boundVars, + typesByName = typesByName, + structs = StringMap.insert name str structs + } + + fun bindPat (makeBinding : tyvar -> binding) (Syntax.PVar v) (env : env) : env = + bind makeBinding v (GenSym.new ()) env + | bindPat makeBinding (Syntax.PTuple pats) env = + foldl (fn (pat, env) => bindPat makeBinding pat env) env pats + | bindPat makeBinding (Syntax.PCon (_, pat)) env = bindPat makeBinding pat env + | bindPat _ _ env = env + + fun genericVars (env : env) (TyVar a) : unit TyVarMap.map = + if isSome (TyVarMap.lookup a (#boundVars env)) + then TyVarMap.empty + else TyVarMap.fromList [(a, ())] + | genericVars env (TyCon (_, tys)) = + foldl (fn (x, acc) => TyVarMap.union acc (genericVars env x)) TyVarMap.empty tys + | genericVars _ (TyStruct _) = TyVarMap.empty + + fun instantiate (env : env) (t : ty) : ty = + let + val genericVars = genericVars env t + val newVars = TyVarMap.fromList (map (fn (a, _) => (a, GenSym.new ())) (TyVarMap.toList genericVars)) + fun replace (TyVar a) = + TyVar (getOpt (TyVarMap.lookup a newVars, a)) + | replace (TyCon (n, tys)) = TyCon (n, map replace tys) + | replace (TyStruct structType) = TyStruct structType + in replace t end + + fun lookupBinding (name : string) (env : env) : ty = + case StringMap.lookup name (#bindings env) of + SOME (Let t) => instantiate env (find (TyVar t)) + | SOME (Arg t) => TyVar t + | NONE => raise Fail ("unbound var " ^ name) + + fun patBindings (Syntax.PVar v) : string list = [v] + | patBindings (Syntax.PTuple pats) = List.concat (map patBindings pats) + | patBindings (Syntax.PCon (_, pat)) = patBindings pat + | patBindings _ = [] + + fun tyToSyntaxTy (TyVar v) = Syntax.TVar v + | tyToSyntaxTy (TyCon (Bool, [])) = Syntax.TBool + | tyToSyntaxTy (TyCon (Int, [])) = Syntax.TInt + | tyToSyntaxTy (TyCon (Str, [])) = Syntax.TString + | tyToSyntaxTy (TyCon (Fun, [f, x])) = Syntax.TFun (tyToSyntaxTy f, tyToSyntaxTy x) + | tyToSyntaxTy (TyCon (Tuple, ts)) = Syntax.TTuple (map tyToSyntaxTy ts) + | tyToSyntaxTy (TyCon (List, [t])) = Syntax.TList (tyToSyntaxTy t) + | tyToSyntaxTy (TyCon (Datatype tag, _)) = + (case (IntMap.lookup tag (!datatypes)) of + SOME cases => Syntax.TDatatype cases + | NONE => raise Fail ("unknown datatype tag " ^ Int.toString tag)) + | tyToSyntaxTy t = raise Fail ("invalid ty " ^ printTy t) + + fun structTypeToSyntaxStructType (Struct s) = + Syntax.TStruct + ( map (fn (name, ty) => (name, structTypeToSyntaxStructType ty)) (StringMap.toList (#structs s)) + , map (fn (name, ty) => (name, tyToSyntaxTy ty)) (StringMap.toList (#vals s)) + ) + (* | structTypeToSyntaxStructType _ = raise Fail "we really need to combine structs and expressions" *) + + fun tagPat (_ : env) Syntax.PWild : Syntax.typedPat * ty = (Syntax.TPWild, TyVar (GenSym.new ())) + | tagPat env (Syntax.PVar v) = (Syntax.TPVar v, TyVar (case (StringMap.lookup v (#bindings env)) of SOME (Let t) => t | SOME (Arg t) => t | NONE => raise Fail "unknown pattern variable")) + | tagPat _ (Syntax.PInt i) = (Syntax.TPInt i, TyCon (Int, [])) + | tagPat env (Syntax.PTuple pats) = + let + val taggedPats = map (tagPat env) pats + val types = map (fn (_, ty) => ty) taggedPats + val taggedPats = map (fn (p, ty) => (p, tyToSyntaxTy ty)) taggedPats + in (Syntax.TPTuple taggedPats, TyCon (Tuple, types)) end + | tagPat env (Syntax.PCon (con, pat)) = + let + val conBinding = + case con of + [ident] => lookupBinding ident env + | str :: fields => + case StringMap.lookup str (#structs env) of + SOME (Struct structTy) => + let + fun go structTy [field] = + (case StringMap.lookup field (#vals structTy) of + SOME t => instantiate env (find t) + | NONE => raise Fail "unbound something or other") + | go structTy (str :: fields) = + case StringMap.lookup str (#structs structTy) of + SOME (Struct structTy) => go structTy fields + | NONE => raise Fail ("unbound field " ^ str) + in go structTy fields end + | NONE => raise Fail ("unbound struct " ^ str) + in + case conBinding of + TyCon (Fun, [argType, resType]) => + let val (pat, patType) = tagPat env pat + in + unify patType argType ; + (Syntax.TPCon (con, (pat, tyToSyntaxTy patType)), resType) + end + | conType => + case pat of + Syntax.PTuple [] => (Syntax.TPCon (con, (Syntax.TPTuple [], Syntax.TTuple [])), conType) + | _ => raise Fail ("non-function " ^ (String.concatWith "." con) ^ " applied to argument in pattern") + end + + fun F (env : env) (Syntax.EIdent i : Syntax.expr) : Syntax.typedExpr * ty = + (Syntax.TEIdent i, lookupBinding i env) + | F env (Syntax.EDot (expr, field)) = + let + val (str, Struct structType) = tagStructExpr env expr + val fieldType = instantiate env (find (valOf (StringMap.lookup field (#vals structType)))) + in (Syntax.TEDot ((str, structTypeToSyntaxStructType (Struct structType)), field), fieldType) end + | F _ (Syntax.EBuiltin "exit") = (Syntax.TEBuiltin "exit", TyCon (Fun, [TyCon (Int, []), TyVar (GenSym.new ())])) + | F _ (Syntax.EBuiltin "add") = (Syntax.TEBuiltin "add", TyCon (Fun, [TyCon (Tuple, [TyCon (Int, []), TyCon (Int, [])]), TyCon (Int, [])])) + | F _ (Syntax.EBuiltin "sub") = (Syntax.TEBuiltin "sub", TyCon (Fun, [TyCon (Tuple, [TyCon (Int, []), TyCon (Int, [])]), TyCon (Int, [])])) + | F _ (Syntax.EBuiltin "mul") = (Syntax.TEBuiltin "mul", TyCon (Fun, [TyCon (Tuple, [TyCon (Int, []), TyCon (Int, [])]), TyCon (Int, [])])) + | F _ (Syntax.EBuiltin "div") = (Syntax.TEBuiltin "div", TyCon (Fun, [TyCon (Tuple, [TyCon (Int, []), TyCon (Int, [])]), TyCon (Int, [])])) + | F _ (Syntax.EBuiltin b) = raise Fail ("unknown builtin " ^ b) + | F _ (Syntax.EInt i) = (Syntax.TEInt i, TyCon (Int, [])) + | F _ (Syntax.EStr s) = (Syntax.TEStr s, TyCon (Str, [])) + | F env (Syntax.ETuple exprs) = + let + val taggedExprs = map (F env) exprs + val types = map (fn (_, x) => x) taggedExprs + in (Syntax.TETuple (map (fn (e, t) => (e, tyToSyntaxTy t)) taggedExprs), TyCon (Tuple, types)) end + | F env (Syntax.EList exprs) = + let + val taggedExprs = map (fn expr => F env expr) exprs + val alpha = TyVar (GenSym.new ()) + val _ = app (fn (_, t) => unify alpha t) taggedExprs + in (Syntax.TEList (map (fn (e, t) => (e, tyToSyntaxTy t)) taggedExprs), TyCon (List, [alpha])) end + | F env (Syntax.EApp (func, arg)) = + let + val (func, funcType) = F env func + val (arg, argType) = F env arg + val beta = TyVar (GenSym.new ()) + val _ = unify funcType (TyCon (Fun, [argType, beta])) + in (Syntax.TEApp ((func, tyToSyntaxTy funcType), (arg, tyToSyntaxTy argType)), beta) end + | F env (Syntax.ETyped (expr, _)) = F env expr + | F env (Syntax.EAndAlso (e1, e2)) = + let + val (e1, e1Type) = F env e1 + val (e2, e2Type) = F env e2 + in + unify e1Type (TyCon (Bool, [])) ; + unify e2Type (TyCon (Bool, [])) ; + (Syntax.TEAndAlso ((e1, tyToSyntaxTy e1Type), (e2, tyToSyntaxTy e2Type)), TyCon (Bool, [])) + end + | F env (Syntax.EOrElse (e1, e2)) = + let + val (e1, e1Type) = F env e1 + val (e2, e2Type) = F env e2 + in + unify e1Type (TyCon (Bool, [])) ; + unify e2Type (TyCon (Bool, [])) ; + (Syntax.TEOrElse ((e1, tyToSyntaxTy e1Type), (e2, tyToSyntaxTy e2Type)), TyCon (Bool, [])) + end + | F env (Syntax.ELet (decs, body)) = + let + val (env, decs) = tagDecs env decs + val (body, bodyType) = F env body + in (Syntax.TELet (decs, (body, tyToSyntaxTy bodyType)), bodyType) + end + | F env (Syntax.ELambda (pat, body)) = + let + val env = bindPat Arg pat env + val (pat, patType) = tagPat env pat + val (body, bodyType) = F env body + in (Syntax.TELambda ((pat, tyToSyntaxTy patType), (body, tyToSyntaxTy bodyType)), TyCon (Fun, [patType, bodyType])) end + | F env (Syntax.ECase (arg, arms)) = + let + val (arg, argType) = F env arg + val resultType = TyVar (GenSym.new ()) + val arms = + map + (fn (pat, body) => + let + val env = bindPat Arg pat env + val (pat, patType) = tagPat env pat + val (body, bodyType) = F env body + in + unify patType argType; + unify bodyType resultType; + ((pat, tyToSyntaxTy patType), (body, tyToSyntaxTy bodyType)) + end) + arms + in (Syntax.TECase ((arg, tyToSyntaxTy argType), arms), resultType) end + + and tagDec (env : env) (Syntax.DVal (pat, expr)) : env * Syntax.typedDec option = + let + val (expr, exprType) = F env expr + val env = bindPat Let pat env + val (pat, patType) = tagPat env pat + in + unify patType exprType ; + (env, SOME (Syntax.TDVal ((pat, tyToSyntaxTy patType), (expr, tyToSyntaxTy exprType)))) + end + | tagDec env (Syntax.DValRec (pat, expr)) = + let + val recEnv = bindPat Arg pat env + val (expr, exprType) = F recEnv expr + val (taggedPat, patType) = tagPat recEnv pat + in + unify patType exprType ; + (bindPat Let pat env, SOME (Syntax.TDValRec ((taggedPat, tyToSyntaxTy patType), (expr, tyToSyntaxTy exprType)))) + end + | tagDec env (Syntax.DFun (name, (args, body) :: cases)) = + let + val fnType = GenSym.new () + val args1Env = + foldl + (fn (arg, env) => bindPat Arg arg env) + (bind Arg name fnType env) + args + val args = map (tagPat args1Env) args + val argTypes = map (fn (_, ty) => ty) args + val (body, bodyType) = F args1Env body + val cases = + (map (fn (arg, ty) => (arg, tyToSyntaxTy ty)) args, (body, tyToSyntaxTy bodyType)) + :: map + (fn (args, body) => + let + val env = + foldl + (fn (arg, env) => bindPat Arg arg env) + (bind Arg name fnType env) + args + val args = map (tagPat env) args + val (body, bt) = F env body + in + ListPair.appEq + (fn ((_, myArgType), argType) => unify myArgType argType) + (args, argTypes) ; + unify bodyType bt ; + (map (fn (arg, ty) => (arg, tyToSyntaxTy ty)) args, (body, tyToSyntaxTy bt)) + end) + cases + in (bind Let name fnType env, SOME (Syntax.TDFun (name, cases))) + end + | tagDec env (Syntax.DDatatype (vars, name, data)) = + let val env = bindType (vars, name, data) env + in (env, SOME (Syntax.TDDatatype (name, map (fn (name, ty) => (name, Option.map (tyToSyntaxTy o (etypeToTy env)) ty)) data))) end + | tagDec _ (Syntax.DType _) = raise Fail "TODO" + | tagDec env (Syntax.DStruct (name, str)) = + let val (str, strType) = tagStructExpr env str + in (bindStruct name strType env, SOME (Syntax.TDStruct (name, (str, structTypeToSyntaxStructType strType)))) end + | tagDec _ _ = raise Fail "invalid expr" + + and tagDecs env [] = (env, []) + | tagDecs env (dec :: decs) = + let + val (env, dec) = tagDec env dec + val (env, decs) = tagDecs env decs + val decs = + case dec of + NONE => decs + | SOME dec => dec :: decs + in (env, decs) + end + + and tagStructExpr (env : env) (Syntax.SIdent s) : Syntax.typedStructExpr * structTy = + (case StringMap.lookup s (#structs env) of + SOME t => (Syntax.TSIdent s, t) + | NONE => raise Fail ("unknown struct type " ^ s)) + | tagStructExpr env (Syntax.SDot (sExpr, field)) = + let + val (parent, Struct parentType) = tagStructExpr env sExpr + val fieldType = + case StringMap.lookup field (#structs parentType) of + SOME x => x + | NONE => raise Fail ("unknown struct field " ^ field) + in (Syntax.TSDot ((parent, structTypeToSyntaxStructType (Struct parentType)), field), fieldType) end + | tagStructExpr env (Syntax.SStruct decls) = + let val (env, decls) = tagDecs env decls + in + (Syntax.TSStruct decls, Struct { + structs = #structs env, + vals = + StringMap.fromList + (map + (fn (name, Let v) => (name, TyVar v) + | (name, Arg v) => (name, TyVar v)) + (StringMap.toList (#bindings env))) + }) + end + + fun reexpandType (Syntax.TVar i) : Syntax.ty = tyToSyntaxTy (find (TyVar i)) + | reexpandType ty = ty + + fun reexpandPat (pat : Syntax.typedPat, ty : Syntax.ty) : Syntax.typedPat * Syntax.ty = + let + val pat = + case pat of + Syntax.TPTuple pats => Syntax.TPTuple (map reexpandPat pats) + | Syntax.TPCon (con, arg) => Syntax.TPCon (con, reexpandPat arg) + | _ => pat + in (pat, reexpandType ty) end + + fun reexpand (expr : Syntax.typedExpr, ty : Syntax.ty) : Syntax.typedExpr * Syntax.ty = + let + val expr = + case expr of + Syntax.TEDot (str, field) => Syntax.TEDot (reexpandStructExpr str, field) + | Syntax.TETuple exprs => Syntax.TETuple (map reexpand exprs) + | Syntax.TEList exprs => Syntax.TEList (map reexpand exprs) + | Syntax.TEApp (f, arg) => Syntax.TEApp (reexpand f, reexpand arg) + | Syntax.TEAndAlso (expr1, expr2) => Syntax.TEAndAlso (reexpand expr1, reexpand expr2) + | Syntax.TEOrElse (expr1, expr2) => Syntax.TEOrElse (reexpand expr1, reexpand expr2) + | Syntax.TELet (decls, body) => Syntax.TELet (map reexpandDecl decls, reexpand body) + | Syntax.TELambda (arg, body) => Syntax.TELambda (reexpandPat arg, reexpand body) + | Syntax.TECase (arg, arms) => Syntax.TECase (reexpand arg, map (fn (pat, body) => (reexpandPat pat, reexpand body)) arms) + | _ => expr + in (expr, reexpandType ty) end + + and reexpandDecl (Syntax.TDVal (pat, expr)) : Syntax.typedDec = Syntax.TDVal (reexpandPat pat, reexpand expr) + | reexpandDecl (Syntax.TDValRec (pat, expr)) = Syntax.TDValRec (reexpandPat pat, reexpand expr) + | reexpandDecl (Syntax.TDFun (name, arms)) = Syntax.TDFun (name, map (fn (pats, body) => (map reexpandPat pats, reexpand body)) arms) + | reexpandDecl (decl as Syntax.TDDatatype _) = decl + | reexpandDecl (Syntax.TDStruct (name, str)) = Syntax.TDStruct (name, reexpandStructExpr str) + + and reexpandStructExpr (str : Syntax.typedStructExpr, structType : Syntax.structType) : Syntax.typedStructExpr * Syntax.structType = + let + val str = + case str of + Syntax.TSIdent _ => str + | Syntax.TSDot (str, field) => Syntax.TSDot (reexpandStructExpr str, field) + | Syntax.TSStruct decls => Syntax.TSStruct (map reexpandDecl decls) + in (str, structType) end + + fun tag (expr : Syntax.expr) : Syntax.typedExpr * Syntax.ty = + let + val env = { + bindings = StringMap.empty, + boundVars = TyVarMap.empty, + typesByName = StringMap.empty, + structs = StringMap.empty + } + val (expr, ty) = F env expr + in reexpand (expr, tyToSyntaxTy ty) end +end diff --git a/generate-show-syntax.sml b/generate-show-syntax.sml index d58d73d..c1e104f 100644 --- a/generate-show-syntax.sml +++ b/generate-show-syntax.sml @@ -4,30 +4,31 @@ use "Syntax.sml"; use "Parser.sml"; use "Opts.sml"; -val header = - "fun intToStringI (_ : string) (i : int) : string = Int.toString i\n" - ^ "\n" - ^ "fun varToStringI (_ : string) (v : Syntax.var) : string = \"Var \" ^ Int.toString v\n" - ^ "\n" - ^ "fun stringToStringI (_ : string) (s : string) : string = \"\\\"\" ^ String.toString s ^ \"\\\"\"\n" - ^ "\n" - ^ "fun optionToString (_ : string -> 'a -> string) (_ : string) NONE : string = \"NONE\"\n" - ^ " | optionToString show indent (SOME x) = \"SOME (\" ^ show indent x ^ \")\"\n" - ^ "\n" - ^ "fun listToString (_ : string -> 'a -> string) (_ : string) ([] : 'a list) : string = \"[]\"\n" - ^ " | listToString show indent [x] = \"[\" ^ show indent x ^ \"]\"\n" - ^ " | listToString show indent xs =\n" - ^ " let val indent' = indent ^ \" \" in\n" - ^ " \"[\\n\"\n" - ^ " ^ indent' ^ String.concatWith (\",\\n\" ^ indent') (map (show indent') xs) ^ \"\\n\"\n" - ^ " ^ indent ^ \"]\"\n" - ^ " end\n" +val header = "\ + \fun intToStringI (_ : string) (i : int) : string = Int.toString i\n\ + \\n\ + \fun varToStringI (_ : string) (v : Syntax.var) : string = \"Var \" ^ Int.toString v\n\ + \\n\ + \fun stringToStringI (_ : string) (s : string) : string = \"\\\"\" ^ String.toString s ^ \"\\\"\"\n\ + \\n\ + \fun optionToString (_ : string -> 'a -> string) (_ : string) NONE : string = \"NONE\"\n\ + \ | optionToString show indent (SOME x) = \"SOME (\" ^ show indent x ^ \")\"\n\ + \\n\ + \fun listToString (_ : string -> 'a -> string) (_ : string) ([] : 'a list) : string = \"[]\"\n\ + \ | listToString show indent [x] = \"[\" ^ show indent x ^ \"]\"\n\ + \ | listToString show indent xs =\n\ + \ let val indent' = indent ^ \" \" in\n\ + \ \"[\\n\"\n\ + \ ^ indent' ^ String.concatWith (\",\\n\" ^ indent') (map (show indent') xs) ^ \"\\n\"\n\ + \ ^ indent ^ \"]\"\n\ + \ end\n\ +\" fun showTy (Syntax.Tyvar var) : string = var ^ "ToStringI" | showTy (Syntax.Tycon ([ty], con)) = con ^ "ToString (" ^ showTy ty ^ ")" | showTy (Syntax.TyTuple tys) = let val vars = List.tabulate (length tys, fn i => "x" ^ Int.toString i) in - "(fn indent => fn (" ^ String.concatWith ", " vars ^ ") => let val indent' = indent ^ \" \" in \"(\\n\" ^ indent' ^ " ^ String.concatWith " ^ \",\\n\" ^ indent' ^ " (map (fn (var, ty) => showTy ty ^ " indent' " ^ var) (ListPair.zip (vars, tys))) ^ " ^ \"\\n\" ^ indent ^ \")\" end)" + "(fn indent => fn (" ^ String.concatWith ", " vars ^ ") => let val indent' = indent ^ \" \" in \"(\\n\" ^ indent' ^ " ^ String.concatWith " ^ \",\\n\" ^ indent' ^ " (map (fn (var, ty) => showTy ty ^ " indent' " ^ var) (ListPair.zipEq (vars, tys))) ^ " ^ \"\\n\" ^ indent ^ \")\" end)" end | showTy _ = "(fn _ => fn _ => \"UNHANDLED\")" @@ -51,7 +52,7 @@ val _ = TextIO.output (out, "(*\n This file was generated by generate-show-synt val _ = TextIO.output (out, "structure Show" ^ structName ^ " = struct\n") val _ = TextIO.output (out, header) val _ = map - (fn (i, Syntax.DDatatype (typeName, cases)) => + (fn (i, Syntax.DDatatype (_, typeName, cases)) => (TextIO.output (out, "\n" ^ (if i = 0 then "fun" else "and") ^ " " ^ String.concatWith "\n | " (map diff --git a/main.sml b/main.sml index 99d72bb..3b74705 100644 --- a/main.sml +++ b/main.sml @@ -7,9 +7,10 @@ use "Syntax.sml"; use "Opts.sml"; use "Parser.sml"; use "ShowSyntax.sml"; -use "CodeGen.sml"; -use "CPS.sml"; +use "Types.sml"; use "Elab.sml"; +use "CPS.sml"; +use "CodeGen.sml"; use "Linker.sml"; use "Compiler.sml"; diff --git a/program.cm b/program.cm index c99286a..8fbdf7a 100644 --- a/program.cm +++ b/program.cm @@ -2,7 +2,7 @@ Group is Buffer.sml CPS.sml -Codegen.sml +CodeGen.sml Compiler.sml Elab.sml GenSym.sml @@ -12,6 +12,8 @@ Opts.sml Parser.sml Result.sml ShowSyntax.sml +Sort.sml Syntax.sml +Types.sml $/basis.cm diff --git a/run-tests.fish b/run-tests.fish index 22c86d5..92200d2 100644 --- a/run-tests.fish +++ b/run-tests.fish @@ -13,12 +13,12 @@ else set files $d/tests/* end -for f in $files - $d/bytecode/target/debug/bytecode (sml $d/main.sml -o /dev/stderr $f >/dev/null 2>| psub) - set -l got $status +printf %s\n $files | parallel --keep-order --quote fish -c ' + bytecode/target/debug/bytecode (sml main.sml -o /dev/stderr $argv[1] >/dev/null 2>| psub) + set got $status if test $got -eq 42 - echo (basename -s.sml $f): PASS + echo (basename -s.sml $argv[1]): PASS else - echo (basename -s.sml $f): FAIL "(status $got)" + echo (basename -s.sml $argv[1]): FAIL "(status $got)" end -end +' -- cgit v1.3.1