Use numbers for constructor tags.

This commit is contained in:
2025-10-04 14:41:48 -07:00
parent f1e6f98c99
commit 8209d2d839
10 changed files with 86 additions and 70 deletions

21
TODO.md
View File

@@ -1,11 +1,20 @@
## TODO ## TODO
- [ ] Add info to Ref/VRef (is dcon, arity, etc)
- To save lookups during compilation and it might make eval faster
- [x] number tags for data constructors
- Numeric tags are about 9% faster
- Issues:
- They make debugging more difficult. I was able to sort out debruijn issues because the names were wrong.
- There are a couple of spots I have to fudge in the native code, because there is no constant for `Nil` and `_::_` tags
- the debugString pretty printer was leveraging the names
- [x] Increment row/col in printing, so vscode can click on compiler output - [x] Increment row/col in printing, so vscode can click on compiler output
- [ ] Raw is duplicated between Lib.Syntax and Lib.Compile, but not detected - [ ] Raw is duplicated between Lib.Syntax and Lib.Compile, but not detected
- Maybe add qualified names - [ ] Maybe add qualified names to surface syntax and allow / detect conflicts on reference
- [ ] Add `export` keywords
- [ ] vscode - run newt when switching editors - [ ] vscode - run newt when switching editors
- [ ] who calls X? We can only do this scoped to the current context for now. Someday whole source dir - [ ] who calls X? We can only do this scoped to the current context for now. Someday whole source dir.
- [ ] case split - [ ] case split
- We could fake this up: - We could fake this up:
- given a name and a point in the editor - given a name and a point in the editor
@@ -14,10 +23,12 @@
- enumerate valid constructors (and their arity) - enumerate valid constructors (and their arity)
- Repeat the line with each, applied to args - Repeat the line with each, applied to args
- For `<-` or `let` we'd want to fudge some `|` lines - For `<-` or `let` we'd want to fudge some `|` lines
- [ ] inline struct getters during code generation (We'd like `x.h1.h2`)
- [ ] Better FC for parse errors (both EOF and the ones that show up just after the error)
- [ ] Support "Add missing cases" - [ ] Support "Add missing cases"
- [ ] Code gen for PiType (rather than static JS) - We could possibly fake up missing cases, too. Since they're listed and have an FC pointing at the first one
- [ ] Might need proper, enumerated errors for that
- [x] inline struct getters during code generation (We'd like `x.h1.h2`)
- [ ] Better FC for parse errors (both EOF and the ones that show up just after the error)
- [x] Code gen for PiType (rather than static JS)
- [x] fix string highlighting - [x] fix string highlighting
- [x] implement tail call optimization - [x] implement tail call optimization
- [x] implement magic nat - [x] implement magic nat

View File

@@ -25,7 +25,7 @@ JSStmt : StKind -> U
JSExp : U JSExp : U
data JAlt : U where data JAlt : U where
JConAlt : e. String -> JSStmt e -> JAlt JConAlt : e. Nat -> JSStmt e -> JAlt
JDefAlt : e. JSStmt e -> JAlt JDefAlt : e. JSStmt e -> JAlt
JLitAlt : e. JSExp -> JSStmt e -> JAlt JLitAlt : e. JSExp -> JSStmt e -> JAlt
@@ -172,7 +172,7 @@ termToJS env (CLetRec nm t u) f =
in case termToJS env' t (JAssign nm') of in case termToJS env' t (JAssign nm') of
(JAssign _ exp) => JSnoc (JConst nm' exp) (termToJS env' u f) (JAssign _ exp) => JSnoc (JConst nm' exp) (termToJS env' u f)
t' => JSnoc (JLet nm' t') (termToJS env' u f) t' => JSnoc (JLet nm' t') (termToJS env' u f)
termToJS env (CConstr nm args) f = go args 0 (\ args => f $ LitObject (("tag", LitString nm) :: args)) termToJS env (CConstr ix _ args) f = go args 0 (\ args => f $ LitObject (("tag", LitInt (cast ix)) :: args))
where where
go : e. List CExp -> Int -> (List (String × JSExp) -> JSStmt e) -> JSStmt e go : e. List CExp -> Int -> (List (String × JSExp) -> JSStmt e) -> JSStmt e
go Nil ix k = k Nil go Nil ix k = k Nil
@@ -207,14 +207,14 @@ termToJS {e} env (CCase t alts) f =
else JSnoc (JConst nm t') (maybeCaseStmt env' (Var nm) alts) else JSnoc (JConst nm t') (maybeCaseStmt env' (Var nm) alts)
where where
termToJSAlt : JSEnv -> JSExp -> CAlt -> JAlt termToJSAlt : JSEnv -> JSExp -> CAlt -> JAlt
termToJSAlt env nm (CConAlt name info args u) = JConAlt name (termToJS (mkEnv nm 0 env args) u f) termToJSAlt env nm (CConAlt ix name info args u) = JConAlt ix (termToJS (mkEnv nm 0 env args) u f)
-- intentionally reusing scrutinee name here -- intentionally reusing scrutinee name here
termToJSAlt env nm (CDefAlt u) = JDefAlt (termToJS (env) u f) termToJSAlt env nm (CDefAlt u) = JDefAlt (termToJS (env) u f)
termToJSAlt env nm (CLitAlt lit u) = JLitAlt (litToJS lit) (termToJS env u f) termToJSAlt env nm (CLitAlt lit u) = JLitAlt (litToJS lit) (termToJS env u f)
maybeCaseStmt : JSEnv -> JSExp -> List CAlt -> JSStmt e maybeCaseStmt : JSEnv -> JSExp -> List CAlt -> JSStmt e
-- If there is a single alt, assume it matched -- If there is a single alt, assume it matched
maybeCaseStmt env nm ((CConAlt _ info args u) :: Nil) = (termToJS (mkEnv nm 0 env args) u f) maybeCaseStmt env nm ((CConAlt _ _ info args u) :: Nil) = (termToJS (mkEnv nm 0 env args) u f)
maybeCaseStmt env nm alts@(CLitAlt _ _ :: _) = maybeCaseStmt env nm alts@(CLitAlt _ _ :: _) =
(JCase nm (map (termToJSAlt env nm) alts)) (JCase nm (map (termToJSAlt env nm) alts))
maybeCaseStmt env nm alts = maybeCaseStmt env nm alts =
@@ -278,7 +278,7 @@ caseBody {e} stmt@(JCase _ _) = nest 2 (line ++ stmtToDoc stmt </> text "break;"
caseBody stmt = line ++ text "{" ++ nest 2 (line ++ stmtToDoc stmt </> text "break;") </> text "}" caseBody stmt = line ++ text "{" ++ nest 2 (line ++ stmtToDoc stmt </> text "break;") </> text "}"
altToDoc : JAlt -> Doc altToDoc : JAlt -> Doc
altToDoc (JConAlt nm stmt) = text "case" <+> text (quoteString nm) ++ text ":" ++ caseBody stmt altToDoc (JConAlt nm stmt) = text "case" <+> text (show nm) ++ text ":" ++ caseBody stmt
altToDoc (JDefAlt stmt) = text "default" ++ text ":" ++ caseBody stmt altToDoc (JDefAlt stmt) = text "default" ++ text ":" ++ caseBody stmt
altToDoc (JLitAlt a stmt) = text "case" <+> expToDoc a ++ text ":" ++ caseBody stmt altToDoc (JLitAlt a stmt) = text "case" <+> expToDoc a ++ text ":" ++ caseBody stmt
@@ -374,7 +374,7 @@ sortedNames : SortedMap QName CExp → QName → List QName
sortedNames defs qn = map snd $ filter (not fst) $ go Nil Nil (True, qn) sortedNames defs qn = map snd $ filter (not fst) $ go Nil Nil (True, qn)
where where
getBody : CAlt CExp getBody : CAlt CExp
getBody (CConAlt _ _ _ t) = t getBody (CConAlt _ _ _ _ t) = t
getBody (CLitAlt _ t) = t getBody (CLitAlt _ t) = t
getBody (CDefAlt t) = t getBody (CDefAlt t) = t
@@ -398,7 +398,7 @@ sortedNames defs qn = map snd $ filter (not ∘ fst) $ go Nil Nil (True, qn)
getNames deep acc (CRef qn) = (deep, qn) :: acc getNames deep acc (CRef qn) = (deep, qn) :: acc
getNames deep acc (CLet _ t u) = getNames deep (getNames deep acc t) u getNames deep acc (CLet _ t u) = getNames deep (getNames deep acc t) u
getNames deep acc (CLetRec _ t u) = getNames deep (getNames deep acc t) u getNames deep acc (CLetRec _ t u) = getNames deep (getNames deep acc t) u
getNames deep acc (CConstr _ ts) = foldl (getNames deep) acc ts getNames deep acc (CConstr _ _ ts) = foldl (getNames deep) acc ts
-- if the CRaw is called, then the deps are called -- if the CRaw is called, then the deps are called
getNames deep acc (CRaw _ deps) = map (_,_ deep) deps ++ acc getNames deep acc (CRaw _ deps) = map (_,_ deep) deps ++ acc
-- wrote these out so I get an error when I add a new constructor -- wrote these out so I get an error when I add a new constructor

View File

@@ -17,7 +17,7 @@ import Data.SortedMap
CExp : U CExp : U
data CAlt : U where data CAlt : U where
CConAlt : String ConInfo List String CExp CAlt CConAlt : Nat String ConInfo List String CExp CAlt
-- REVIEW keep var name? -- REVIEW keep var name?
CDefAlt : CExp -> CAlt CDefAlt : CExp -> CAlt
-- literal -- literal
@@ -38,7 +38,7 @@ data CExp : U where
CLetRec : Name -> CExp -> CExp -> CExp CLetRec : Name -> CExp -> CExp -> CExp
CErased : CExp CErased : CExp
-- Data / type constructor -- Data / type constructor
CConstr : Name -> List CExp -> CExp CConstr : Nat Name -> List CExp -> CExp
-- Raw javascript for `pfunc` -- Raw javascript for `pfunc`
CRaw : String -> List QName -> CExp CRaw : String -> List QName -> CExp
-- Need this for magic Nat -- Need this for magic Nat
@@ -70,7 +70,7 @@ arityForName fc nm = do
Nothing => error fc "Name \{show nm} not in scope" Nothing => error fc "Name \{show nm} not in scope"
(Just Axiom) => pure Z (Just Axiom) => pure Z
(Just (TCon arity strs)) => pure $ cast arity (Just (TCon arity strs)) => pure $ cast arity
(Just (DCon _ k str)) => pure $ cast k (Just (DCon _ _ k str)) => pure $ cast k
(Just (Fn t)) => pure $ lamArity t (Just (Fn t)) => pure $ lamArity t
(Just (PrimTCon arity)) => pure $ cast arity (Just (PrimTCon arity)) => pure $ cast arity
(Just (PrimFn t arity used)) => pure arity (Just (PrimFn t arity used)) => pure arity
@@ -115,9 +115,9 @@ compileTerm t@(Ref fc nm@(QN _ tag)) = do
(S Z) => pure $ CRef nm (S Z) => pure $ CRef nm
Z => Z =>
case the (Maybe Def) $ lookupMap' nm defs of case the (Maybe Def) $ lookupMap' nm defs of
Just (DCon EnumCon _ _) => pure $ CLit $ LString tag Just (DCon ix EnumCon _ _) => pure $ CLit $ LInt $ cast ix
Just (DCon ZeroCon _ _) => pure $ CLit $ LInt 0 Just (DCon _ ZeroCon _ _) => pure $ CLit $ LInt 0
Just (DCon SuccCon _ _) => Just (DCon _ SuccCon _ _) =>
pure $ CLam "x" $ CPrimOp "+" (CLit $ LInt 1) (CBnd 0) pure $ CLam "x" $ CPrimOp "+" (CLit $ LInt 1) (CBnd 0)
_ => pure $ CRef nm _ => pure $ CRef nm
_ => apply nm Nil Lin arity _ => apply nm Nil Lin arity
@@ -136,7 +136,7 @@ compileTerm tm@(App _ _ _) = case funArgs tm of
let (Nothing) = compilePrimOp (show nm) args' let (Nothing) = compilePrimOp (show nm) args'
| Just cexp => pure cexp | Just cexp => pure cexp
case the (Maybe Def) $ lookupMap' nm defs of case the (Maybe Def) $ lookupMap' nm defs of
Just (DCon SuccCon _ _) => applySucc args' Just (DCon _ SuccCon _ _) => applySucc args'
_ => apply nm args' Lin arity _ => apply nm args' Lin arity
-- REVIEW maybe we want a different constructor for non-Ref applications? -- REVIEW maybe we want a different constructor for non-Ref applications?
(t, args) => do (t, args) => do
@@ -163,23 +163,23 @@ compileTerm (Case fc t alts) = do
defs <- getRef Defs defs <- getRef Defs
def <- lookupDef emptyFC qn def <- lookupDef emptyFC qn
case def of case def of
DCon info _ _ => CConAlt nm info args <$> compileTerm tm DCon ix info _ _ => CConAlt ix nm info args <$> compileTerm tm
_ => error fc "\{show nm} is not constructor" _ => error fc "\{show nm} is not constructor"
CaseLit lit tm => CLitAlt lit <$> compileTerm tm CaseLit lit tm => CLitAlt lit <$> compileTerm tm
pure $ CCase t' $ fancyCons t' alts' pure $ CCase t' $ fancyCons t' alts'
where where
numAltP : CAlt Bool numAltP : CAlt Bool
numAltP (CConAlt _ SuccCon _ _) = True numAltP (CConAlt _ _ SuccCon _ _) = True
numAltP (CConAlt _ ZeroCon _ _) = True numAltP (CConAlt _ _ ZeroCon _ _) = True
numAltP _ = False numAltP _ = False
enumAlt : CAlt CAlt enumAlt : CAlt CAlt
enumAlt (CConAlt nm EnumCon args tm) = CLitAlt (LString nm) tm enumAlt (CConAlt ix nm EnumCon args tm) = CLitAlt (LInt $ cast ix) tm
enumAlt alt = alt enumAlt alt = alt
isInfo : ConInfo CAlt Bool isInfo : ConInfo CAlt Bool
isInfo needle (CConAlt _ info _ _) = needle == info isInfo needle (CConAlt _ _ info _ _) = needle == info
isInfo _ _ = False isInfo _ _ = False
isDef : CAlt Bool isDef : CAlt Bool
@@ -187,14 +187,14 @@ compileTerm (Case fc t alts) = do
isDef _ = False isDef _ = False
getBody : CAlt CExp getBody : CAlt CExp
getBody (CConAlt _ _ _ t) = t getBody (CConAlt _ _ _ _ t) = t
getBody (CLitAlt _ t) = t getBody (CLitAlt _ t) = t
getBody (CDefAlt t) = t getBody (CDefAlt t) = t
doNumCon : CExp List CAlt List CAlt doNumCon : CExp List CAlt List CAlt
doNumCon sc alts = doNumCon sc alts =
let zeroAlt = case find (isInfo ZeroCon) alts of let zeroAlt = case find (isInfo ZeroCon) alts of
Just (CConAlt _ _ _ tm) => CLitAlt (LInt 0) tm :: Nil Just (CConAlt _ _ _ _ tm) => CLitAlt (LInt 0) tm :: Nil
Just tm => fatalError "ERROR zeroAlt mismatch \{debugStr tm}" Just tm => fatalError "ERROR zeroAlt mismatch \{debugStr tm}"
_ => case find isDef alts of _ => case find isDef alts of
Just (CDefAlt tm) => CLitAlt (LInt 0) tm :: Nil Just (CDefAlt tm) => CLitAlt (LInt 0) tm :: Nil
@@ -202,7 +202,7 @@ compileTerm (Case fc t alts) = do
_ => Nil _ => Nil
in in
let succAlt = case find (isInfo SuccCon) alts of let succAlt = case find (isInfo SuccCon) alts of
Just (CConAlt _ _ _ tm) => CDefAlt (CLet "x" (CPrimOp "-" sc (CLit $ LInt 1)) tm) :: Nil Just (CConAlt _ _ _ _ tm) => CDefAlt (CLet "x" (CPrimOp "-" sc (CLit $ LInt 1)) tm) :: Nil
Just tm => fatalError "ERROR succAlt mismatch \{debugStr tm}" Just tm => fatalError "ERROR succAlt mismatch \{debugStr tm}"
_ => case find isDef alts of _ => case find isDef alts of
Just alt => alt :: Nil Just alt => alt :: Nil
@@ -235,18 +235,19 @@ compileFun tm = go tm Lin
go tm args = CFun (args <>> Nil) <$> compileTerm tm go tm args = CFun (args <>> Nil) <$> compileTerm tm
-- What are the Defs used for above? (Arity for name) -- What are the Defs used for above? (Arity for name)
compileDCon : QName ConInfo Int CExp compileDCon : Nat QName ConInfo Int CExp
compileDCon (QN _ nm) EnumCon 0 = CLit $ LString nm compileDCon ix (QN _ nm) EnumCon 0 = CLit $ LInt $ cast ix
compileDCon (QN _ nm) info 0 = CConstr nm Nil compileDCon ix (QN _ nm) info 0 = CConstr ix nm Nil
compileDCon (QN _ nm) info arity = compileDCon ix (QN _ nm) info arity =
let args = map (\k => "h\{show k}") (range 0 arity) in let args = map (\k => "h\{show k}") (range 0 arity) in
CFun args $ CConstr nm $ map (\k => CBnd $ arity - k - 1) (range 0 arity) CFun args $ CConstr ix nm $ map (\k => CBnd $ arity - k - 1) (range 0 arity)
-- probably want to drop the Ref2 when we can -- probably want to drop the Ref2 when we can
defToCExp : {{Ref2 Defs St}} → (QName × Def) -> M (QName × CExp) defToCExp : {{Ref2 Defs St}} → (QName × Def) -> M (QName × CExp)
defToCExp (qn, Axiom) = pure $ (qn, CErased) defToCExp (qn, Axiom) = pure $ (qn, CErased)
defToCExp (qn, DCon info arity _) = pure $ (qn, compileDCon qn info arity) defToCExp (qn, DCon ix info arity _) = pure $ (qn, compileDCon ix qn info arity)
defToCExp (qn, TCon arity _) = pure $ (qn, compileDCon qn NormalCon arity) -- FIXME need a number if we ever add typecase.
defToCExp (qn, PrimTCon arity) = pure $ (qn, compileDCon qn NormalCon arity) defToCExp (qn, TCon arity _) = pure $ (qn, compileDCon Z qn NormalCon arity)
defToCExp (qn, PrimTCon arity) = pure $ (qn, compileDCon Z qn NormalCon arity)
defToCExp (qn, PrimFn src _ deps) = pure $ (qn, CRaw src deps) defToCExp (qn, PrimFn src _ deps) = pure $ (qn, CRaw src deps)
defToCExp (qn, Fn tm) = (_,_ qn) <$> compileFun tm defToCExp (qn, Fn tm) = (_,_ qn) <$> compileFun tm

View File

@@ -727,7 +727,7 @@ getConstructors ctx scfc (VRef fc nm _) = do
lookupDCon nm = do lookupDCon nm = do
top <- getTop top <- getTop
case lookup nm top of case lookup nm top of
(Just (MkEntry _ name type (DCon _ k str) _)) => pure (name, k, type) (Just (MkEntry _ name type (DCon _ _ k str) _)) => pure (name, k, type)
Just _ => error fc "Internal Error: \{show nm} is not a DCon" Just _ => error fc "Internal Error: \{show nm} is not a DCon"
Nothing => error fc "Internal Error: DCon \{show nm} not found" Nothing => error fc "Internal Error: DCon \{show nm} not found"
getConstructors ctx scfc tm = do getConstructors ctx scfc tm = do
@@ -964,7 +964,7 @@ buildCase ctx prob scnm scty (dcName, arity, ty) = do
-- TODO can we check this when we make the PatCon? -- TODO can we check this when we make the PatCon?
top <- getTop top <- getTop
case lookup nm top of case lookup nm top of
(Just (MkEntry _ name type (DCon _ k tcname) _)) => (Just (MkEntry _ name type (DCon _ _ k tcname) _)) =>
if (tcname /= sctynm) if (tcname /= sctynm)
then error fc "Constructor is \{show tcname} expected \{show sctynm}" then error fc "Constructor is \{show tcname} expected \{show sctynm}"
else pure Nothing else pure Nothing
@@ -992,7 +992,7 @@ mkPat (tm, icit) = do
top <- getTop top <- getTop
case splitArgs tm Nil of case splitArgs tm Nil of
((RVar fc nm), b) => case lookupRaw nm top of ((RVar fc nm), b) => case lookupRaw nm top of
(Just (MkEntry _ name type (DCon _ k str) _)) => do (Just (MkEntry _ name type (DCon _ _ k str) _)) => do
-- TODO check arity, also figure out why we need reverse -- TODO check arity, also figure out why we need reverse
bpat <- traverse (mkPat) b bpat <- traverse (mkPat) b
pure $ PatCon fc icit name bpat Nothing pure $ PatCon fc icit name bpat Nothing
@@ -1365,7 +1365,7 @@ updateRec ctx fc clauses arg ty = do
let (Just (MkEntry _ _ _ (TCon _ (conname :: Nil)) _)) = lookup nm top let (Just (MkEntry _ _ _ (TCon _ (conname :: Nil)) _)) = lookup nm top
| Just _ => error fc "\{show nm} is not a record" | Just _ => error fc "\{show nm} is not a record"
| _ => error fc "\{show nm} not in scope" | _ => error fc "\{show nm} not in scope"
let (Just (MkEntry _ _ ty (DCon _ _ _) _)) = lookup conname top let (Just (MkEntry _ _ ty (DCon _ _ _ _) _)) = lookup conname top
| _ => error fc "\{show conname} not a dcon" | _ => error fc "\{show conname} not a dcon"
pure $ (conname, collect arg ty) pure $ (conname, collect arg ty)
-- --

View File

@@ -108,7 +108,7 @@ evalCase env sc@(VRef _ nm sp) (cc@(CaseCons name nms t) :: xs) = do
debug $ \ _ => "ECase \{show nm} \{show sp} \{show nms} \{showTm t}" debug $ \ _ => "ECase \{show nm} \{show sp} \{show nms} \{showTm t}"
pushArgs env (sp <>> Nil) nms pushArgs env (sp <>> Nil) nms
else case lookup nm top of else case lookup nm top of
(Just (MkEntry _ str type (DCon _ k str1) _)) => evalCase env sc xs (Just (MkEntry _ str type (DCon _ _ k str1) _)) => evalCase env sc xs
-- bail for a stuck function -- bail for a stuck function
_ => pure Nothing _ => pure Nothing
where where

View File

@@ -296,7 +296,7 @@ processInstance ns instfc ty decls = do
| _ => error tyFC "\{show tconName} is not a type constructor" | _ => error tyFC "\{show tconName} is not a type constructor"
let (con :: Nil) = cons let (con :: Nil) = cons
| _ => error tyFC "\{show tconName} has multiple constructors \{show cons}" | _ => error tyFC "\{show tconName} has multiple constructors \{show cons}"
let (Just (MkEntry _ _ dcty (DCon _ _ _) _)) = lookup con top let (Just (MkEntry _ _ dcty (DCon _ _ _ _) _)) = lookup con top
| _ => error tyFC "can't find constructor \{show con}" | _ => error tyFC "can't find constructor \{show con}"
vdcty@(VPi _ nm icit rig a b) <- eval Nil dcty vdcty@(VPi _ nm icit rig a b) <- eval Nil dcty
| x => error (getFC x) "dcty not Pi" | x => error (getFC x) "dcty not Pi"
@@ -411,20 +411,20 @@ populateConInfo entries =
setInfo zero ZeroCon :: setInfo succ SuccCon :: Nil setInfo zero ZeroCon :: setInfo succ SuccCon :: Nil
where where
setInfo : TopEntry ConInfo TopEntry setInfo : TopEntry ConInfo TopEntry
setInfo (MkEntry fc nm dty (DCon _ arity hn) flags) info = MkEntry fc nm dty (DCon info arity hn) flags setInfo (MkEntry fc nm dty (DCon ix _ arity hn) flags) info = MkEntry fc nm dty (DCon ix info arity hn) flags
setInfo x _ = x setInfo x _ = x
checkEnum : TopEntry Maybe TopEntry checkEnum : TopEntry Maybe TopEntry
checkEnum (MkEntry fc nm dty (DCon _ 0 hn) flags) = Just $ MkEntry fc nm dty (DCon EnumCon 0 hn) flags checkEnum (MkEntry fc nm dty (DCon ix _ 0 hn) flags) = Just $ MkEntry fc nm dty (DCon ix EnumCon 0 hn) flags
checkEnum _ = Nothing checkEnum _ = Nothing
isZero : TopEntry Bool isZero : TopEntry Bool
isZero (MkEntry fc nm dty (DCon _ 0 hn) flags) = True isZero (MkEntry fc nm dty (DCon _ _ 0 hn) flags) = True
isZero _ = False isZero _ = False
-- TODO - handle indexes, etc -- TODO - handle indexes, etc
isSucc : TopEntry Bool isSucc : TopEntry Bool
isSucc (MkEntry fc nm dty@(Pi _ _ _ _ (Ref _ a) (Ref _ b)) (DCon _ 1 hn) _) = a == b isSucc (MkEntry fc nm dty@(Pi _ _ _ _ (Ref _ a) (Ref _ b)) (DCon _ _ 1 hn) _) = a == b
isSucc _ = False isSucc _ = False
processData : List String FC String Raw List Decl M Unit processData : List String FC String Raw List Decl M Unit
@@ -441,8 +441,8 @@ processData ns fc nm ty cons = do
unifyCatch fc (mkCtx fc) tyty' type' unifyCatch fc (mkCtx fc) tyty' type'
Just _ => error fc "\{show nm} already declared" Just _ => error fc "\{show nm} already declared"
Nothing => setDef (QN ns nm) fc tyty Axiom Nil Nothing => setDef (QN ns nm) fc tyty Axiom Nil
entries <- join <$> (for cons $ \x => case x of entries <- join <$> (for (enumerate cons) $ \x => case x of
(TypeSig fc names tm) => do (ix, TypeSig fc names tm) => do
traverse (checkAlreadyDef fc) names traverse (checkAlreadyDef fc) names
debug $ \ _ => "check dcon \{show names} \{show tm}" debug $ \ _ => "check dcon \{show names} \{show tm}"
dty <- check (mkCtx fc) tm (VU fc) dty <- check (mkCtx fc) tm (VU fc)
@@ -457,8 +457,8 @@ processData ns fc nm ty cons = do
| (tm, _) => error (getFC tm) "expected \{nm} got \{render 90 $ pprint tnames tm}" | (tm, _) => error (getFC tm) "expected \{nm} got \{render 90 $ pprint tnames tm}"
when (hn /= QN ns nm) $ \ _ => when (hn /= QN ns nm) $ \ _ =>
error (getFC codomain) "Constructor codomain is \{render 90 $ pprint tnames codomain} rather than \{nm}" error (getFC codomain) "Constructor codomain is \{render 90 $ pprint tnames codomain} rather than \{nm}"
pure $ map (\ nm' => (MkEntry fc (QN ns nm') dty (DCon NormalCon (getArity dty) hn) Nil)) names pure $ map (\ nm' => (MkEntry fc (QN ns nm') dty (DCon ix NormalCon (getArity dty) hn) Nil)) names
decl => throwError $ E (getFC decl) "expected constructor declaration") (_,decl) => throwError $ E (getFC decl) "expected constructor declaration")
-- type level autos like _++_ -- type level autos like _++_
solveAutos solveAutos
let entries = populateConInfo entries let entries = populateConInfo entries

View File

@@ -23,12 +23,12 @@ tailNames (CAppRef nm args n) = nm :: Nil
tailNames (CCase _ alts) = join $ map altTailNames alts tailNames (CCase _ alts) = join $ map altTailNames alts
where where
altTailNames : CAlt List QName altTailNames : CAlt List QName
altTailNames (CConAlt _ _ _ exp) = tailNames exp altTailNames (CConAlt _ _ _ _ exp) = tailNames exp
altTailNames (CDefAlt exp) = tailNames exp altTailNames (CDefAlt exp) = tailNames exp
altTailNames (CLitAlt _ exp) = tailNames exp altTailNames (CLitAlt _ exp) = tailNames exp
tailNames (CLet _ _ t) = tailNames t tailNames (CLet _ _ t) = tailNames t
tailNames (CLetRec _ _ t) = tailNames t tailNames (CLetRec _ _ t) = tailNames t
tailNames (CConstr _ args) = Nil tailNames (CConstr _ _ args) = Nil
tailNames (CBnd _) = Nil tailNames (CBnd _) = Nil
tailNames (CFun _ tm) = tailNames tm tailNames (CFun _ tm) = tailNames tm
tailNames (CLam _ _) = Nil tailNames (CLam _ _) = Nil
@@ -46,16 +46,20 @@ tailNames (CPrimOp _ _ _) = Nil
rewriteTailCalls : List QName CExp CExp rewriteTailCalls : List QName CExp CExp
rewriteTailCalls nms tm = case tm of rewriteTailCalls nms tm = case tm of
CAppRef nm args 0 => CAppRef nm args 0 =>
if elem nm nms case getTag (S Z) nm nms of
then CConstr (show nm) args Just ix => CConstr ix (show nm) args
else CConstr "return" (tm :: Nil) Nothing => CConstr Z "return" (tm :: Nil)
CLetRec nm t u => CLetRec nm t $ rewriteTailCalls nms u CLetRec nm t u => CLetRec nm t $ rewriteTailCalls nms u
CLet nm t u => CLet nm t $ rewriteTailCalls nms u CLet nm t u => CLet nm t $ rewriteTailCalls nms u
CCase sc alts => CCase sc $ map rewriteAlt alts CCase sc alts => CCase sc $ map rewriteAlt alts
tm => CConstr "return" (tm :: Nil) tm => CConstr Z "return" (tm :: Nil)
where where
getTag : Nat QName List QName Maybe Nat
getTag t nm Nil = Nothing
getTag t nm (n :: ns) = if n == nm then Just t else getTag (S t) nm ns
rewriteAlt : CAlt -> CAlt rewriteAlt : CAlt -> CAlt
rewriteAlt (CConAlt nm info args t) = CConAlt nm info args $ rewriteTailCalls nms t rewriteAlt (CConAlt ix nm info args t) = CConAlt ix nm info args $ rewriteTailCalls nms t
rewriteAlt (CDefAlt t) = CDefAlt $ rewriteTailCalls nms t rewriteAlt (CDefAlt t) = CDefAlt $ rewriteTailCalls nms t
rewriteAlt (CLitAlt lit t) = CLitAlt lit $ rewriteTailCalls nms t rewriteAlt (CLitAlt lit t) = CLitAlt lit $ rewriteTailCalls nms t
@@ -67,16 +71,16 @@ doOptimize : List (QName × CExp) → M (List (QName × CExp))
doOptimize fns = do doOptimize fns = do
splitFuns <- traverse splitFun fns splitFuns <- traverse splitFun fns
let nms = map fst fns let nms = map fst fns
let alts = map (mkAlt nms) splitFuns let alts = map (mkAlt nms) $ enumerate splitFuns
recName <- mkRecName nms recName <- mkRecName nms
let recfun = CFun ("arg" :: Nil) $ CCase (CBnd 0) alts let recfun = CFun ("arg" :: Nil) $ CCase (CBnd 0) alts
wrapped <- traverse (mkWrap recName) fns wrapped <- traverse (mkWrap recName) (enumerate fns)
pure $ (recName, recfun) :: wrapped pure $ (recName, recfun) :: wrapped
where where
mkWrap : QName QName × CExp M (QName × CExp) mkWrap : QName Nat × QName × CExp M (QName × CExp)
mkWrap recName (qn, CFun args _) = do mkWrap recName (ix, qn, CFun args _) = do
let arglen = length' args let arglen = length' args
let arg = CConstr (show qn) $ map (\k => CBnd (arglen - k - 1)) (range 0 arglen) let arg = CConstr (S ix) (show qn) $ map (\k => CBnd (arglen - k - 1)) (range 0 arglen)
let body = CAppRef bouncer (CRef recName :: arg :: Nil) 0 let body = CAppRef bouncer (CRef recName :: arg :: Nil) 0
pure $ (qn, CFun args body) pure $ (qn, CFun args body)
mkWrap _ (qn, _) = error emptyFC "error in mkWrap: \{show qn} not a CFun" mkWrap _ (qn, _) = error emptyFC "error in mkWrap: \{show qn} not a CFun"
@@ -85,8 +89,8 @@ doOptimize fns = do
mkRecName Nil = error emptyFC "INTERNAL ERROR: Empty List in doOptimize" mkRecName Nil = error emptyFC "INTERNAL ERROR: Empty List in doOptimize"
mkRecName (QN ns nm :: _) = pure $ QN ns "REC_\{nm}" mkRecName (QN ns nm :: _) = pure $ QN ns "REC_\{nm}"
mkAlt : List QName (QName × List Name × CExp) -> CAlt mkAlt : List QName (Nat × QName × List Name × CExp) -> CAlt
mkAlt nms (qn, args, tm) = CConAlt (show qn) NormalCon args (rewriteTailCalls nms tm) mkAlt nms (ix, qn, args, tm) = CConAlt (S ix) (show qn) NormalCon args (rewriteTailCalls nms tm)
splitFun : (QName × CExp) M (QName × List Name × CExp) splitFun : (QName × CExp) M (QName × List Name × CExp)
splitFun (qn, CFun args body) = pure (qn, args, body) splitFun (qn, CFun args body) = pure (qn, args, body)

View File

@@ -352,13 +352,13 @@ instance Show ConInfo where
show ZeroCon = "[Z]" show ZeroCon = "[Z]"
show EnumCon = "[E]" show EnumCon = "[E]"
data Def = Axiom | TCon Int (List QName) | DCon ConInfo Int QName | Fn Tm | PrimTCon Int data Def = Axiom | TCon Int (List QName) | DCon Nat ConInfo Int QName | Fn Tm | PrimTCon Int
| PrimFn String Nat (List QName) | PrimFn String Nat (List QName)
instance Show Def where instance Show Def where
show Axiom = "axiom" show Axiom = "axiom"
show (TCon _ strs) = "TCon \{show strs}" show (TCon _ strs) = "TCon \{show strs}"
show (DCon ci k tyname) = "DCon \{show k} \{show tyname} \{show ci}" show (DCon ix ci k tyname) = "DCon \{show ix} \{show k} \{show tyname} \{show ci}"
show (Fn t) = "Fn \{show t}" show (Fn t) = "Fn \{show t}"
show (PrimTCon _) = "PrimTCon" show (PrimTCon _) = "PrimTCon"
show (PrimFn src arity used) = "PrimFn \{show src} \{show arity} \{show used}" show (PrimFn src arity used) = "PrimFn \{show src} \{show arity} \{show used}"

View File

@@ -51,7 +51,7 @@ writeSource fn = do
docs <- compile docs <- compile
let src = unlines $ let src = unlines $
( "\"use strict\";" ( "\"use strict\";"
:: "const bouncer = (f,ini) => { let obj = ini; while (obj.tag !== 'return') obj = f(obj); return obj.h0 };" :: "const bouncer = (f,ini) => { let obj = ini; while (obj.tag) obj = f(obj); return obj.h0 };"
:: Nil) :: Nil)
++ map (render 90 noAlt) docs ++ map (render 90 noAlt) docs
(Right _) <- liftIO {M} $ writeFile fn src (Right _) <- liftIO {M} $ writeFile fn src

View File

@@ -283,7 +283,7 @@ ptype Array : U → U
pfunc listToArray : a. List a Array a := ` pfunc listToArray : a. List a Array a := `
(a, l) => { (a, l) => {
let rval = [] let rval = []
while (l.tag !== 'Nil') { while (l.tag !== 'Nil' && l.tag) {
rval.push(l.h1) rval.push(l.h1)
l = l.h2 l = l.h2
} }
@@ -409,7 +409,7 @@ pfunc unpack uses (Nil _::_) : String → List Char
pfunc pack : List Char String := `(cs) => { pfunc pack : List Char String := `(cs) => {
let rval = '' let rval = ''
while (cs.tag === '_::_') { while (cs.tag === '_::_' || cs.tag === 1) {
rval += cs.h1 rval += cs.h1
cs = cs.h2 cs = cs.h2
} }
@@ -642,7 +642,7 @@ pfunc ioArrayToList uses (Nil _::_ MkIORes) : ∀ a. IOArray a → IO (List a) :
pfunc listToIOArray uses (MkIORes) : a. List a IO (Array a) := `(a,list) => w => { pfunc listToIOArray uses (MkIORes) : a. List a IO (Array a) := `(a,list) => w => {
let rval = [] let rval = []
while (list.tag === '_::_') { while (list.tag === '_::_' || list.tag === 1) {
rval.push(list.h1) rval.push(list.h1)
list = list.h2 list = list.h2
} }
@@ -704,7 +704,7 @@ instance Eq Ordering where
GT == GT = True GT == GT = True
_ == _ = False _ == _ = False
pfunc jsCompare : a. a a Ordering := `(_, a, b) => a == b ? "EQ" : a < b ? "LT" : "GT"` pfunc jsCompare uses (EQ LT GT) : a. a a Ordering := `(_, a, b) => a == b ? Prelude_EQ : a < b ? Prelude_LT : Prelude_GT`
infixl 6 _<_ _<=_ _>_ infixl 6 _<_ _<=_ _>_
class Ord a where class Ord a where