This commit is contained in:
2024-08-11 12:18:07 -07:00
parent 32536fc264
commit f27c03ef20
4 changed files with 75 additions and 77 deletions

View File

@@ -7,35 +7,75 @@ 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
- [ ] flag for debug?
### Data
- [x] typecheck `plus`
- [ ] 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)
- [ ] Learn stuff like `n = S k` in case trees.
- Need test case
- If this is all var = tm, I could mutate the local env (Would it need to be `let` to be used in unification?)
- I could subst into something (environment / goal?)
- I could carry around extra stuff for unification
- With names, I could dump a `let` into the env
- [ ] Handle default cases (non-constructor)
- [ ] When we do impossible, take agda approach
- [ ] test cases. Maybe from pi-forall
### Primitives
Maybe we can declare primitive ops and not hardwire a list in the codegen?
- [ ] Add primitive strings
- [ ] Add primitive numbers
- [ ] Wire through compilation
- [ ] Magic Nat in compilation
### Erasure
We need some erasure for runtime. The pi-forall notation isn't compatible with implicits. Maybe use Idris2 or Agda notation. Prop is another option.
- [ ] Erased values?
- pi-forall handles this, so it's probably not too crazy. She won't go near implicits and I think I understand why.
- I don't think I Want to go full QTT at the moment
- Is erased different from 0/many?
### Compilation
Code generation is partially done.
- [ ] Handle meta in compile - [ ] Handle meta in compile
- [ ] 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 lombda 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
- [ ] Don't do assign var to fresh var
### Parsing / Language
When we do impossible, take agda approach
- [x] typecheck plus
- [x] checkAlt
- [ ] process data decl should check some stuff
- [x] switch to FC - [x] switch to FC
- [ ] add operators to parser state (Are we going to run this on LHS too?)
- [ ] Modules and namespaces
- [ ] List sugar
### Editor
- [ ] Type at point for the editor
### Typecheck / Elaboration
- [ ] think about whether there needs to be a desugar step separate from check/infer - [ ] think about whether there needs to be a desugar step separate from check/infer
- [ ] look into Lennart.newt issues
- [ ] Type at point for the editor
- [ ] add operators to parser state (Are we going to run this on LHS too?)
- [ ] Data
- [x] Read data as real constructors
- [x] Typecheck / eval the same
- [x] Add data elimination / case #partial
- [ ] test cases. Maybe from pi-forall
- [x] Code Gen #partial - [x] Code Gen #partial
- [ ] Less expansion - [ ] Less expansion
- 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
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.
@@ -57,8 +97,6 @@ I've added a bunch of info logs for the editor support.
Zoo4 examples run now. Zoo4 examples run now.
Maybe do `data` next. There is a crude version in place, we'll want to fix that, typecheck the new stuff, and then add cases. (Maybe introduce eliminators.)
When I generate code, I'll eventually run up against the erased thing. (I'll want to erase some of the stuff that is compile time.) But we'll generate code and decide how far we need to take this. It's probably pointless to just reproduce Idris. When I generate code, I'll eventually run up against the erased thing. (I'll want to erase some of the stuff that is compile time.) But we'll generate code and decide how far we need to take this. It's probably pointless to just reproduce Idris.
When I self host, I'll have to drop or implement typeclasses. I do understand auto enough to make it happen. When I self host, I'll have to drop or implement typeclasses. I do understand auto enough to make it happen.
@@ -66,20 +104,16 @@ When I self host, I'll have to drop or implement typeclasses. I do understand au
Ok, for code gen, I think I'll need something like primitive values and definitely primitive functions. For v0, I could leave the holes as undefined and if there is a function with that name, it's magically FFI. Ok, for code gen, I think I'll need something like primitive values and definitely primitive functions. For v0, I could leave the holes as undefined and if there is a function with that name, it's magically FFI.
Questions: Questions:
- [ ] Code gen or data next?
- [ ] Should I write this up properly? - [ ] Should I write this up properly?
- [ ] Erased values?
- pi-forall handles this, so it's probably not too crazy. She won't go near implicits and I think I understand why.
- I don't think I Want to go full QTT at the moment
- Is erased different from 0/many?
Parser: Parser:
- [x] parser for block comments - [x] parser for block comments
- [x] import statement - [x] import statement
- [x] def - [x] def
- [x] simple decl - [x] simple decl
- [ ] check (either check at _ or infer and let it throw) - [ ] %check (either check at _ or infer and let it throw)
- [ ] nf (ditto, but print value. WHNF for now ) - Lean checks (λ x => x) to ?m.249 → ?m.249
- [ ] %nf (ditto, but print value. WHNF for now, eval in lean?)
- [ ] operators / mixfix - [ ] operators / mixfix
- Maybe put operators in parser state and update, ideally we'd have mixfix though - Maybe put operators in parser state and update, ideally we'd have mixfix though
- how does agda handle clashes between names and mixfix? - how does agda handle clashes between names and mixfix?
@@ -88,9 +122,9 @@ Parser:
Testing: Testing:
- [ ] black box testing - [ ] black box testing
- [ ] Proper exit code
- [ ] bug.newt should fail with a certain parse error, but there will be noise, so look for specific error? - [ ] bug.newt should fail with a certain parse error, but there will be noise, so look for specific error?
- [ ] zoo?.newt should complete successfully - [ ] zoo?.newt should complete successfully
- [ ]
Misc: Misc:
- [x] vscode support for .newt - [x] vscode support for .newt
@@ -110,9 +144,8 @@ Misc:
- [x] figure out context representation - Global context? - [x] figure out context representation - Global context?
- [x] type checking / elab - [x] type checking / elab
- What does this represent? The basics, implicits? pattern unification? - What does this represent? The basics, implicits? pattern unification?
- [ ] check for unsolved metas (after each def or at end?) - [x] check for unsolved metas (after each def or at end?)
- [ ] compilation - [ ] compilation
- I'm thinking I get data working first
- [ ] repl - [ ] repl
- [ ] write tests - [ ] write tests
- [ ] Split up code better - [ ] Split up code better

View File

@@ -24,7 +24,7 @@ processDecl (TypeSig fc nm tm) = do
ty <- check (mkCtx top.metas) tm (VU fc) ty <- check (mkCtx top.metas) tm (VU fc)
ty' <- nf [] ty ty' <- nf [] ty
putStrLn "got \{pprint [] ty'}" putStrLn "got \{pprint [] ty'}"
modify $ claim nm ty' modify $ setDef nm ty' Axiom
processDecl (Def fc nm raw) = do processDecl (Def fc nm raw) = do
putStrLn "-----" putStrLn "-----"
@@ -48,7 +48,7 @@ processDecl (Def fc nm raw) = do
-- putStrLn "ERROR at (\{show l}, \{show c}): Unsolved meta \{show k}" -- putStrLn "ERROR at (\{show l}, \{show c}): Unsolved meta \{show k}"
throwError $ E (l,c) "Unsolved meta \{show k}" throwError $ E (l,c) "Unsolved meta \{show k}"
debug "Add def \{nm} \{pprint [] tm} : \{pprint [] ty}" debug "Add def \{nm} \{pprint [] tm} : \{pprint [] ty}"
put (addDef ctx nm tm ty) modify $ setDef nm ty (Fn tm)
processDecl (DCheck fc tm ty) = do processDecl (DCheck fc tm ty) = do
@@ -74,7 +74,7 @@ processDecl (Data fc nm ty cons) = do
ctx <- get ctx <- get
tyty <- check (mkCtx ctx.metas) ty (VU fc) tyty <- check (mkCtx ctx.metas) ty (VU fc)
-- FIXME we need this in scope, but need to update -- FIXME we need this in scope, but need to update
modify $ claim nm tyty modify $ setDef nm tyty Axiom
ctx <- get ctx <- get
cnames <- for cons $ \x => case x of cnames <- for cons $ \x => case x of
-- expecting tm to be a Pi type -- expecting tm to be a Pi type
@@ -84,14 +84,14 @@ processDecl (Data fc nm ty cons) = do
-- TODO count arity -- TODO count arity
dty <- check (mkCtx ctx.metas) tm (VU fc) dty <- check (mkCtx ctx.metas) tm (VU fc)
debug "dty \{nm'} is \{pprint [] dty}" debug "dty \{nm'} is \{pprint [] dty}"
modify $ defcon nm' (getArity dty) nm dty modify $ setDef nm' dty (DCon (getArity dty) nm)
pure nm' pure nm'
_ => throwError $ E (0,0) "expected constructor declaration" _ => throwError $ E (0,0) "expected constructor declaration"
-- TODO check tm is VU or Pi ending in VU -- TODO check tm is VU or Pi ending in VU
-- Maybe a pi -> binders function -- Maybe a pi -> binders function
-- TODO we're putting in axioms, we need constructors -- TODO we're putting in axioms, we need constructors
-- for each constructor, check and add -- for each constructor, check and add
modify $ deftype nm tyty cnames modify $ setDef nm tyty (TCon cnames)
pure () pure ()
where where
checkDeclType : Tm -> M () checkDeclType : Tm -> M ()

View File

@@ -23,34 +23,15 @@ Show TopContext where
public export public export
empty : HasIO m => m TopContext empty : HasIO m => m TopContext
empty = pure $ MkTop [] !(newIORef (MC [] 0)) True empty = pure $ MkTop [] !(newIORef (MC [] 0)) False
||| set or replace def. probably need to check types and Axiom on replace
public export public export
claim : String -> Tm -> TopContext -> TopContext setDef : String -> Tm -> Def -> TopContext -> TopContext
claim name ty = { defs $= (MkEntry name ty Axiom ::) } setDef name ty def = { defs $= go }
public export
deftype : String -> Tm -> List String -> TopContext -> TopContext
deftype name ty cons = { defs $= (MkEntry name ty (TCon cons) :: )}
public export
defcon : String -> Nat -> String -> Tm -> TopContext -> TopContext
defcon cname arity tyname ty = { defs $= (MkEntry cname ty (DCon arity tyname) ::) }
-- TODO update existing, throw, etc.
public export
addDef : TopContext -> String -> Tm -> Tm -> TopContext
addDef tc name tm ty = { defs $= go } tc
where where
-- What did I do here?
go : List TopEntry -> List TopEntry go : List TopEntry -> List TopEntry
-- FIXME throw if we hit [] or is not an axiom go [] = [MkEntry name ty def]
-- FIXME use a map, I want updates go (x@(MkEntry nm ty' def') :: defs) = if nm == name
go [] = ?addDEF_fail then MkEntry name ty def :: defs
go (x@(MkEntry nm _ _) :: xs) = if nm == name else x :: go defs
then MkEntry nm ty (Fn tm) :: xs
else x :: go xs

View File

@@ -18,28 +18,12 @@ import Lib.Token
import Lib.Tokenizer import Lib.Tokenizer
import Lib.TopContext import Lib.TopContext
import Lib.Types import Lib.Types
-- import Lib.TT
import Lib.Syntax import Lib.Syntax
import Lib.Syntax import Lib.Syntax
import System import System
import System.Directory import System.Directory
import System.File import System.File
{-
Main2.idr has an older App attempt without the code below.
It has a repl, so we might want to re-integrate that code. And it uses
App, but we have a way to make that work on javascript.
I still want to stay in MonadError outside this file though.
-}
dumpContext : TopContext -> M () dumpContext : TopContext -> M ()
dumpContext top = do dumpContext top = do
putStrLn "Context:" putStrLn "Context:"
@@ -79,7 +63,7 @@ main' = do
| _ => putStrLn "Usage: newt foo.newt" | _ => putStrLn "Usage: newt foo.newt"
-- Right files <- listDir "eg" -- Right files <- listDir "eg"
-- | Left err => printLn err -- | Left err => printLn err
when ("-v" `elem` files) $ modify { verbose := True }
traverse_ processFile (filter (".newt" `isSuffixOf`) files) traverse_ processFile (filter (".newt" `isSuffixOf`) files)
main : IO () main : IO ()