fresh names, move case stuff along a little

This commit is contained in:
2024-08-13 07:42:01 -07:00
parent 023e9e61ad
commit 1fef9dcfc6
6 changed files with 67 additions and 15 deletions

View File

@@ -7,25 +7,27 @@ Compiling to js including data.
v1 of cases requires a constructor and vars, var, or default. v1 of cases requires a constructor and vars, var, or default.
### Main ### Main
- [ ] flag for debug? - [x] flag for debug?
### Data ### Data
- [x] typecheck `plus` - [x] typecheck `plus`
- [ ] don't leave extra "Axiom" entries for incomplete `data` (switch to a map or drop the order) - [x] don't leave extra "Axiom" entries for incomplete `data` (switch to a map or drop the order)
- [ ] Check types when declaring data (collect telescope and check final type against type constructor) - [ ] Check types when declaring data (collect telescope and check final type against type constructor)
- [ ] Learn stuff like `n = S k` in case trees. - [ ] Learn stuff like `n = S k` in case trees.
- Need test case - Need test case, but existing plus case fails unification if we try.
- If this is all var = tm, I could mutate the local env (Would it need to be `let` to be used in unification?) - I guess I need to let these pattern vars unify/match and learn equalities
- If this is all var = tm, I could mutate the local env, so var is now a let. (Would it need to be `let` to be used in unification?)
- I could subst into something (environment / goal?) - I could subst into something (environment / goal?)
- I could carry around extra stuff for unification - I could carry around extra stuff for unification
- With names, I could dump a `let` into the env - With names, I could dump a `let` into the env
- [ ] Handle default cases (non-constructor) - [ ] Handle default cases (non-constructor)
- [ ] When we do impossible, take agda approach - [ ] When we do impossible, take agda approach
- [ ] test cases. Maybe from pi-forall - [ ] test cases. Maybe from pi-forall
- [ ] coverage checking
- [ ] case tree builder
### Primitives ### Primitives
@@ -49,13 +51,13 @@ We need some erasure for runtime. The pi-forall notation isn't compatible with i
Code generation is partially done. Code generation is partially done.
- [ ] Handle meta in compile - [ ] Handle meta in compile (inline solved metas?)
- [ ] Default case (need to process list to cases and maybe default) - [ ] Default case (need to process list to cases and maybe default)
- [ ] Arity for top level functions (and lambda for partial application) - [ ] Arity for top level functions (and lambda for partial application)
- I can do this here, but I'll have to wire in M, otherwise maybe a transform - I can do this here, but I'll have to wire in M, otherwise maybe a transform
before this (we could pull out default case too) before this (we could pull out default case too)
- [ ] Javascript operators / primitives - [ ] Javascript operators / primitives
- [ ] Don't do assign var to fresh var - [x] Don't do assign var to fresh var
### Parsing / Language ### Parsing / Language
@@ -76,6 +78,7 @@ Code generation is partially done.
- Look at smallTT rules - Look at smallTT rules
- Can we not expand top level - expand in unification and matching pi types? - Can we not expand top level - expand in unification and matching pi types?
- [ ] look into Lennart.newt issues - [ ] look into Lennart.newt issues
- [ ] figure out how to add laziness (might have to be via the monad)
So smalltt has TopVar with a Level. typechecking binders end up as top too. So smalltt has TopVar with a Level. typechecking binders end up as top too.

View File

@@ -52,6 +52,21 @@ not2 = \ v => case v of
True => False True => False
x => True x => True
and : Bool -> Bool -> Bool
and = \ x y => case x of
True => y
False => False
-- FIXME - a case is evaluated here, and I don't know why.
nand : Bool -> Bool -> Bool
nand = \ x y => not (case x of
True => y
False => False)
-- -- this should be an error.
-- foo : Bool -> Bool
data Void : U where data Void : U where

View File

@@ -238,8 +238,13 @@ checkAlt scty ctx ty (MkAlt ptm body) = do
-- nameless variable -- nameless variable
go ctype [] ctx = do go ctype [] ctx = do
debug "*** end \{show ctype}" debug "*** end \{show ctype}"
-- FIXME FIXME - I think I should be unifying ctype against scty and learning stuff from it
-- like n = S k.
-- debug "Unifying constructor"
-- unifyCatch emptyFC ctx ctype scty
-- my first example has issues with Vect Z 0 =?=
check ctx body ty check ctx body ty
-- pure ctx -- this should be our constructor.
-- This happens if we run out of runway (more args and no pi) -- This happens if we run out of runway (more args and no pi)
-- go ctype tm ctx = error (getF "unhandled in checkAlt.go type: \{show ctype} term: \{show tm}" -- go ctype tm ctx = error (getF "unhandled in checkAlt.go type: \{show ctype} term: \{show tm}"
go ctype args ctx = error (argsFC args) "Extra args" go ctype args ctx = error (argsFC args) "Extra args"

View File

@@ -1,5 +1,6 @@
-- TODO fresh names -- TODO I think I'm missing the bit where a case might need to be assigned to a variable.
-- TODO And then get primitives and a way to declare extern functions. That may get us
-- to utility
module Lib.Compile module Lib.Compile
import Lib.Types import Lib.Types
@@ -41,7 +42,9 @@ data JSStmt : Kind -> Type where
Cont e = JSExp -> JSStmt e Cont e = JSExp -> JSStmt e
-- FIXME - add names to env so we can guarantee fresh names in the generated javascript. ||| JSEnv contains `Var` for binders or `Dot` for destructured data. It
||| used to translate binders
JSEnv : Type
JSEnv = List JSExp JSEnv = List JSExp
-- Stuff nm.h1, nm.h2, ... into environment -- Stuff nm.h1, nm.h2, ... into environment
@@ -49,6 +52,21 @@ mkEnv : String -> Nat -> List JSExp -> List String -> List JSExp
mkEnv nm k env [] = env mkEnv nm k env [] = env
mkEnv nm k env (x :: xs) = mkEnv nm (S k) (Dot (Var nm) "h\{show k}" :: env) xs mkEnv nm k env (x :: xs) = mkEnv nm (S k) (Dot (Var nm) "h\{show k}" :: env) xs
envNames : Env -> List String
-- If I was golfing, I'd be tempted to stick with deBruijn
||| given a name, find a similar one that doesn't shadow in Env
fresh : String -> JSEnv -> String
fresh nm env = if free env nm then nm else go nm 1
where
free : JSEnv -> String -> Bool
free [] nm = True
free (Var n :: xs) nm = if n == nm then False else free xs nm
free (_ :: xs) nm = free xs nm
go : String -> Nat -> String
go nm k = let nm' = "\{nm}\{show k}" in if free env nm' then nm' else go nm (S k)
-- This is inspired by A-normalization, look into the continuation monad -- This is inspired by A-normalization, look into the continuation monad
-- There is an index on JSStmt, adopted from Stefan Hoeck's code. -- There is an index on JSStmt, adopted from Stefan Hoeck's code.
@@ -61,11 +79,11 @@ termToJS env (CBnd k) f = case getAt k env of
(Just e) => f e (Just e) => f e
Nothing => ?bad_bounds Nothing => ?bad_bounds
termToJS env (CLam nm t) f = termToJS env (CLam nm t) f =
let nm' = "\{nm}$\{show $ length env}" let nm' = fresh nm env -- "\{nm}$\{show $ length env}"
env' = (Var nm' :: env) env' = (Var nm' :: env)
in f $ JLam [nm'] (termToJS env' t JReturn) in f $ JLam [nm'] (termToJS env' t JReturn)
termToJS env (CFun nms t) f = termToJS env (CFun nms t) f =
let nms' = map (\nm => "\{nm}$\{show $ length env}") nms let nms' = map (\nm => fresh nm env) nms
env' = foldl (\ e, nm => Var nm :: e) env nms' env' = foldl (\ e, nm => Var nm :: e) env nms'
in f $ JLam nms' (termToJS env' t JReturn) in f $ JLam nms' (termToJS env' t JReturn)
termToJS env (CRef nm) f = f $ Var nm termToJS env (CRef nm) f = f $ Var nm
@@ -85,7 +103,7 @@ termToJS env (CCase t alts) f =
termToJS env t $ \case termToJS env t $ \case
(Var nm) => (JCase (Dot (Var nm) "tag") (map (termToJSAlt nm) alts)) (Var nm) => (JCase (Dot (Var nm) "tag") (map (termToJSAlt nm) alts))
t' => t' =>
let nm = "sc$\{show $ length env}" in let nm = fresh "sc" env in
JSnoc (JConst nm t') JSnoc (JConst nm t')
(JCase (Dot (Var nm) "tag") (map (termToJSAlt nm) alts)) (JCase (Dot (Var nm) "tag") (map (termToJSAlt nm) alts))
where where

View File

@@ -15,10 +15,14 @@ getArity (Pi x str icit t u) = S (getArity u)
getArity _ = Z getArity _ = Z
-- Can metas live in context for now?
export export
processDecl : Decl -> M () processDecl : Decl -> M ()
processDecl (TypeSig fc nm tm) = do processDecl (TypeSig fc nm tm) = do
top <- get top <- get
let Nothing := lookup nm top
| _ => error fc "\{show nm} is already defined"
putStrLn "-----" putStrLn "-----"
putStrLn "TypeSig \{nm} \{show tm}" putStrLn "TypeSig \{nm} \{show tm}"
ty <- check (mkCtx top.metas) tm (VU fc) ty <- check (mkCtx top.metas) tm (VU fc)

View File

@@ -106,6 +106,10 @@ lookup ctx nm = go ctx.types
export export
eval : Env -> Mode -> Tm -> M Val eval : Env -> Mode -> Tm -> M Val
-- REVIEW everything is evalutated whether it's needed or not
-- It would be nice if the environment were lazy.
-- e.g. case is getting evaluated when passed to a function because
-- of dependencies in pi-types, even if the dependency isn't used
public export public export
($$) : {auto mode : Mode} -> Closure -> Val -> M Val ($$) : {auto mode : Mode} -> Closure -> Val -> M Val
($$) {mode} (MkClosure env tm) u = eval (u :: env) mode tm ($$) {mode} (MkClosure env tm) u = eval (u :: env) mode tm
@@ -153,7 +157,9 @@ eval env mode (Pi fc x icit a b) = pure $ VPi fc x icit !(eval env mode a) (MkCl
eval env mode (Bnd fc i) = case getAt i env of eval env mode (Bnd fc i) = case getAt i env of
Just rval => pure rval Just rval => pure rval
Nothing => error' "Bad deBruin index \{show i}" Nothing => error' "Bad deBruin index \{show i}"
eval env mode (Case{}) = ?todo
-- We need a neutral and some code to run the case tree
eval env mode tm@(Case{}) = ?todo_eval_case
export export
quote : (lvl : Nat) -> Val -> M Tm quote : (lvl : Nat) -> Val -> M Tm
@@ -206,3 +212,4 @@ solveMeta ctx ix tm = do
go (meta@(Solved k _) :: xs) lhs = if k == ix go (meta@(Solved k _) :: xs) lhs = if k == ix
then error' "Meta \{show ix} already solved!" then error' "Meta \{show ix} already solved!"
else go xs (lhs :< meta) else go xs (lhs :< meta)