···3535 -- TODO processing on hover is expensive, but info is not always there
3636 -- I suspect this picks up the case where a file has been invalidated by a change to
3737 -- another file and we switch editors. Handle that (enqueue a check) and switch this back.
3838+ -- this is also broken, because diagnostics don't get updated..
3839 top <- getTop
3939- mod <- processModule emptyFC repo Nil modns
4040- -- let (Just mod) = lookupMap' modns top.modules | Nothing => pure Nothing
4040+ -- mod <- processModule emptyFC repo Nil modns
4141+ let (Just mod) = lookupMap' modns top.modules | Nothing => pure Nothing
4142 modifyTop [ currentMod := mod; ops := mod.modOps ]
4243 pure $ Just mod
43444545+data HoverInfo = NoHoverInfo | NeedCheck | HasHover FC String
4646+4447-- The cheap version of type at point, find the token, lookup in global context
4548-- Later we will either get good FC for entries or scan them all and build a cache.
4646-getHoverInfo : FileSource → String → Int → Int → M (Maybe (String × FC))
4949+getHoverInfo : FileSource → String → Int → Int → M HoverInfo
4750getHoverInfo repo modns row col = do
4848- Just mod <- switchModule repo modns | _ => pure Nothing
5151+ Just mod <- switchModule repo modns | _ => pure NeedCheck
4952 top <- getTop
50535154 -- Find the token at the point
5255 let lines = split mod.modSource "\n"
5356 let line = fromMaybe "" (getAt' row lines)
5454- let (Right toks) = tokenise "" line | Left _ => pure Nothing
5555- let (Just name) = getTok toks | _ => pure Nothing
5757+ let (Right toks) = tokenise "" line | Left _ => pure NoHoverInfo
5858+ let (Just name) = getTok toks | _ => pure NoHoverInfo
56595760 let (Left _) = partialParse "" parseImport emptyMap toks
5861 | Right ((MkImport _ (fc, nm)), _, _) => do
5962 let (baseDir, _) = splitFileName fc.file
6060- let fc = MkFC (repo.baseDir ++ "/" ++ joinBy "/" (split nm ".")) (MkBounds 0 0 0 0)
6161- pure $ Just ("module \{nm}", fc)
6262-6363+ let fc = MkFC ("\{repo.baseDir}/\{joinBy "/" (split nm ".")}.newt") (MkBounds 0 0 0 0)
6464+ pure $ HasHover fc "module \{nm}"
6565+ putStrLn "Hover name is \{show name}"
6366 -- Lookup the name
6464- let (Just e) = lookupRaw name top | _ => pure Nothing
6767+ let (Just e) = lookupRaw name top | _ => pure NoHoverInfo
6568 ty <- nf Nil e.type
6666- pure $ Just ("\{show e.name} : \{rpprint Nil ty}", e.fc)
6969+ pure $ HasHover e.fc ("\{show e.name} : \{rpprint Nil ty}")
67706871 where
6972 getTok : List BTok → Maybe String
···140143 let phead = pack head
141144 let indent = getIndent 0 head
142145 let nextrow = scan indent lines (sr + 1)
143143-146146+ -- FIXME - doesn't handle `let`, but that's a little messy
147147+ -- need to remove let and add `|`, but also indent.
148148+ -- Existing `|` would have their own indent, indent of let matters. etc.
144149 -- No init or first :: rest for add missing case
145150 let (edits, rest) = doFirst inPlace cons
146151···193198 pure $ Just $ CaseSplitAction edits
194199195200posInFC : Int → Int → FC → Bool
196196--- FIXME ec + 1 again...
197197-posInFC row col (MkFC _ (MkBounds sr sc er ec)) = (sr <= row && row <= er) && (sc <= col && col <= ec + 1)
201201+posInFC row col (MkFC _ (MkBounds 0 0 0 0)) = False
202202+posInFC row col (MkFC _ (MkBounds sr sc er ec)) = (sr <= row && row <= er) && (sc <= col && col <= ec)
198203199204getHole : ModContext → Int → Int → Maybe MetaEntry
200205getHole mod row col =
···243248244249errorActions : Int → Int → Error → M (List CodeAction)
245250errorActions row col err = do
246246- let (ENotFound fc nm) = err | _ => pure Nil
251251+ let (ENotInScope fc nm) = err | _ => pure Nil
247252 let (True) = posInFC row col fc | _ => pure Nil
248253 top <- getTop
249254 let mods = map (\e => e.name.qns) $ lookupAll nm top
+7-3
src/LSP.newt
···9494 st <- readIORef state
9595 repo <- lspFileSource
9696 -- We're proactively running check if there is no module information, make sure we save it
9797- Right (top, Just (msg, fc)) <- (getHoverInfo repo modns line col).runM st.topContext
9898- | Right (top, _) => do
9797+ Right (top, HasHover fc msg) <- (getHoverInfo repo modns line col).runM st.topContext
9898+ | Right (top, NeedCheck) => do
9999+ modifyIORef state $ [ topContext := top ]
100100+ putStrLn $ "NeedsCheck"
101101+ pure $ js_castBool True
102102+ | Right (top, NoHoverInfo) => do
99103 modifyIORef state $ [ topContext := top ]
100104 putStrLn $ "Nothing to see here"
101101- pure $ jsonToJObject JsonNull
105105+ pure $ js_castBool True
102106 | Left err => do
103107 putStrLn $ showError "" err
104108 pure $ jsonToJObject JsonNull
+151
src/Lib/Derive.newt
···11+module Lib.Derive
22+33+import Prelude
44+import Lib.Common
55+import Lib.Types
66+import Lib.Syntax
77+import Lib.TopContext
88+import Lib.Error
99+import Lib.Elab -- (lookupDCon)
1010+import Lib.Prettier
1111+1212+-- describe type
1313+1414+data Desc : U
1515+1616+data DConst : U where
1717+ MkConst : (name : String) → List (String × Desc) → DConst
1818+1919+2020+data Desc : U where
2121+ DInd : List DConst → Desc
2222+2323+-- So I guess we do a few of these and then figure out how to make it easier
2424+2525+deriveEq : FC → String → M (List Decl)
2626+deriveEq fc name = do
2727+ top <- getTop
2828+ let (Just (MkEntry fc qname type (TCon _ names) eflags)) = lookupRaw name top
2929+ | Just _ => throwError $ E fc "\{name} is not a type constructor"
3030+ | _ => throwError $ ENotInScope fc name
3131+ dcons <- traverse lookupDCon names
3232+ clauses <- traverse makeClause dcons
3333+ let fallback = (buildApp "_==_" (rvar "_" :: rvar "_" :: Nil), Just (rvar "False"))
3434+ let eqDecl = FunDef fc "_==_" (snoc clauses fallback)
3535+ let inst = Instance fc (buildApp "Eq" (rvar name :: Nil)) (Just $ eqDecl :: Nil)
3636+ pure $ inst :: Nil
3737+3838+ where
3939+ arr : Raw → Raw → Raw
4040+ arr a b = RPi emptyFC (BI fc "_" Explicit Many) a b
4141+4242+ rvar : String → Raw
4343+ rvar nm = RVar emptyFC nm
4444+4545+ getExplictNames : SnocList String → Tm → List String
4646+ getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
4747+ getExplictNames acc (Pi fc nm Implicit quant a b) = getExplictNames acc b
4848+ getExplictNames acc (Pi fc nm Auto quant a b) = getExplictNames acc b
4949+ getExplictNames acc _ = acc <>> Nil
5050+5151+ buildApp : String → List Raw → Raw
5252+ buildApp nm nms = foldl (\ t u => RApp emptyFC t u Explicit) (rvar nm) $ nms
5353+5454+ equate : (Raw × Raw) → Raw
5555+ equate (a,b) = buildApp "_==_" (a :: b :: Nil)
5656+5757+ makeClause : (QName × Int × Tm) → M (Raw × Maybe Raw)
5858+ makeClause ((QN ns nm), _, ty) = do
5959+ -- We're only looking at explicit args for now.
6060+ -- TODO check quantity
6161+ let names = getExplictNames Lin ty
6262+ anames <- map rvar <$> traverse freshName names
6363+ bnames <- map rvar <$> traverse freshName names
6464+ let a = buildApp nm anames
6565+ let b = buildApp nm bnames
6666+6767+ let left = equate (a,b)
6868+ let right = case map equate $ zip anames bnames of
6969+ Nil => rvar "True"
7070+ (hd :: tl) => foldr (\a b => buildApp "_&&_" (a :: b :: Nil)) hd tl
7171+7272+ pure (left, Just right)
7373+7474+7575+-- This is a little more of a pain, we'll generate a number for each constructor
7676+-- and use that as the fallback. Eventually we'll want something like quasi-quote
7777+deriveShow : FC → String → M (List Decl)
7878+deriveShow fc name = do
7979+ top <- getTop
8080+ let (Just (MkEntry fc qname type (TCon _ names) eflags)) = lookupRaw name top
8181+ | Just _ => throwError $ E fc "\{name} is not a type constructor"
8282+ | _ => throwError $ ENotInScope fc name
8383+ dcons <- traverse lookupDCon names
8484+ clauses <- traverse makeClause dcons
8585+8686+ let eqDecl = FunDef fc "show" clauses
8787+ let inst = Instance fc (buildApp "Show" (rvar name :: Nil)) (Just $ eqDecl :: Nil)
8888+ pure $ inst :: Nil
8989+9090+ where
9191+ arr : Raw → Raw → Raw
9292+ arr a b = RPi emptyFC (BI fc "_" Explicit Many) a b
9393+9494+ rvar : String → Raw
9595+ rvar nm = RVar emptyFC nm
9696+9797+ lstring : String → Raw
9898+ lstring s = RLit emptyFC (LString s)
9999+100100+ getExplictNames : SnocList String → Tm → List String
101101+ getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
102102+ getExplictNames acc (Pi fc nm Implicit quant a b) = getExplictNames acc b
103103+ getExplictNames acc (Pi fc nm Auto quant a b) = getExplictNames acc b
104104+ getExplictNames acc _ = acc <>> Nil
105105+106106+ buildApp : String → List Raw → Raw
107107+ buildApp nm nms = foldl (\ t u => RApp emptyFC t u Explicit) (rvar nm) $ nms
108108+109109+ equate : (Raw × Raw) → Raw
110110+ equate (a,b) = buildApp "_==_" (a :: b :: Nil)
111111+112112+ makeList : List Raw → Raw
113113+ makeList Nil = rvar "Nil"
114114+ makeList (x :: xs) = buildApp "_::_" (x :: makeList xs :: Nil)
115115+116116+ makeClause : (QName × Int × Tm) → M (Raw × Maybe Raw)
117117+ makeClause ((QN ns nm), _, ty) = do
118118+ let names = getExplictNames Lin ty
119119+ anames <- map rvar <$> traverse freshName names
120120+ let left = buildApp "show" $ buildApp nm anames :: Nil
121121+ let shows = map (\ nm => RApp emptyFC (rvar "show") nm Explicit) anames
122122+ let right = case anames of
123123+ Nil => lstring nm
124124+ _ =>
125125+ let parts = makeList $ lstring ("(" ++ nm) :: shows in
126126+ buildApp "_++_" $ buildApp "joinBy" (lstring " " :: parts :: Nil) :: lstring ")" :: Nil
127127+128128+ pure (left, Just right)
129129+130130+131131+132132+-- -- A description would be nice.
133133+-- deriveShow : FC → QName → M Raw
134134+-- deriveShow fc qn = do
135135+-- top <- getTop
136136+-- case lookup qn top : Maybe TopEntry of
137137+-- Nothing => error {Raw} fc "Can't find \{show qn} in derive Show"
138138+-- -- I want case split too... I need to tie the editor into the repl.
139139+-- (Just (MkEntry fc name type (TCon _ conNames) eflags) ) => ?
140140+-- (Just (MkEntry fc name type (Axiom) eflags) ) => ?
141141+-- (Just (MkEntry fc name type (DCon _ _ _ _) eflags) ) => ?
142142+-- (Just (MkEntry fc name type (Fn _) eflags) ) => ?
143143+-- (Just (MkEntry fc name type (PrimTCon _) eflags) ) => ?
144144+-- (Just (MkEntry fc name type (PrimFn _ _ _) eflags) ) => ?
145145+-- (Just (MkEntry fc name type (PrimOp _) eflags) ) => ?
146146+147147+-- error fc "TODO"
148148+149149+150150+-- HasFC as example of user-defined derivation (when we get to that)
151151+-- SetFC would be nice, too.
+4-2
src/Lib/Elab.newt
···15441544 debug $ \ _ => "lookup \{show name} as \{show def}"
15451545 vty <- eval Nil ty
15461546 pure (Ref fc name, vty)
15471547- -- Can we soften this without introducing a meta?
15481548- Nothing => throwError $ ENotFound fc nm
15471547+ -- Can we soften this without introducing a meta for the type
15481548+ -- it might be additional errors, but also could lead to narrowing of possible names...
15491549+ -- especially when we hit this for .foo
15501550+ Nothing => throwError $ ENotInScope fc nm
15491551 go i ((x, ty) :: xs) = if x == nm then pure (Bnd fc i, ty)
15501552 else go (i + 1) xs
15511553
+3-3
src/Lib/Error.newt
···77-- and a pretty printer in the monad
88data Error
99 = E FC String
1010- | ENotFound FC String
1010+ | ENotInScope FC String
1111 | Postpone FC QName String
121213131414instance HasFC Error where
1515 getFC (E x str) = x
1616- getFC (ENotFound x _) = x
1616+ getFC (ENotInScope x _) = x
1717 getFC (Postpone x k str) = x
18181919errorMsg : Error -> String
2020errorMsg (E x str) = str
2121-errorMsg (ENotFound x nm) = "\{nm} not in scope"
2121+errorMsg (ENotInScope x nm) = "\{nm} not in scope"
2222errorMsg (Postpone x k str) = str
23232424showError : (src : String) -> Error -> String
+13-2
src/Lib/Parser.newt
···538538 -- TODO revisit when we have parser for qualified names in source
539539 (nameFC, ident) <- withFC uident
540540 (restFC,rest) <- withFC $ many $ token Projection
541541+ let nameFC = case rest of
542542+ Nil => nameFC
543543+ (_ :: _) => nameFC + restFC
541544 let name = joinBy "" (ident :: rest)
542542- pure $ MkImport fc (nameFC + restFC, name)
545545+ pure $ MkImport fc (nameFC, name)
543546544547-- Do we do pattern stuff now? or just name = lambda?
545548-- TODO multiple names
···679682 names <- many $ withFC ident
680683 pure $ Exports loc names
681684685685+parseDerive : Parser Decl
686686+parseDerive = do
687687+ loc <- getPos
688688+ keyword "derive"
689689+ className <- withFC uident
690690+ name <- withFC uident
691691+ pure $ DDerive loc className name
692692+682693parseDecl : Parser Decl
683694parseDecl = parseMixfix <|> parsePType <|> parsePFunc
684695 <|> parseNorm <|> parseData <|> parseShortData
685696 <|> parseClass <|> parseInstance <|> parseRecord
686686- <|> parseExport
697697+ <|> parseExport <|> parseDerive
687698 -- We'll put the backtracing stuff last, but there is a commit issue in parseDef
688699 <|> parseSig <|> parseDef
689700
+13
src/Lib/ProcessDecl.newt
···1616import Lib.Types
1717import Lib.Util
1818import Lib.Erasure
1919+import Lib.Derive
19202021dumpEnv : Context -> M String
2122dumpEnv ctx =
···529530 let deps = ((name, RApp fc (RVar fc pname) (RVar fc "$self") Explicit) :: deps)
530531 processFields autoPat tail deps rest
531532533533+processDerive : String → FC → FC × String → (FC × String) → M Unit
534534+processDerive ns fc (clFC, clName) (fc, name) = do
535535+ case clName of
536536+ "Eq" => do
537537+ decls <- deriveEq fc name
538538+ for_ decls $ processDecl ns
539539+ "Show" => do
540540+ decls <- deriveShow fc name
541541+ for_ decls $ processDecl ns
542542+ _ => error fc "derive \{clName} is not supported"
543543+532544processExports : String → FC → List (FC × String) → M Unit
533545processExports ns fc names = do
534546 top <- getTop
···542554-- currently mixfix registration is handled in the parser
543555-- since we now run a decl at a time we could do it here.
544556processDecl ns (PMixFix _ _ _ _) = pure MkUnit
557557+processDecl ns (DDerive fc tclass name) = processDerive ns fc tclass name
545558processDecl ns (TypeSig fc names tm) = processTypeSig ns fc names tm
546559processDecl ns (PType fc nm ty) = processPrimType ns fc nm ty
547560processDecl ns (PFunc fc nm used ty src) = processPrimFn ns fc nm used ty src
+6-2
src/Lib/Syntax.newt
···8888 = TypeSig FC (List Name) Raw
8989 | FunDef FC Name (List (Raw × Maybe Raw))
9090 | DCheck FC Raw Raw
9191+ | DDerive FC (FC × String) (FC × String)
9192 -- TODO maybe add Telescope (before `:`) and auto-add to constructors...
9293 | Data FC (FC × Name) Raw (Maybe $ List Decl)
9394 | ShortData FC Raw (List Raw)
···113114 getFC (Class x str xs ys) = x
114115 getFC (Instance x tm xs) = x
115116 getFC (Record x str tm str1 xs) = x
117117+ getFC (DDerive x _ _) = x
116118117119118120record Module where
···126128127129instance Show Raw
128130129129-130131instance Show Clause where
131132 show (MkClause fc cons pats expr) = show (fc, cons, pats, expr)
132133···140141141142instance Show Decl where
142143 show (TypeSig _ str x) = foo ("TypeSig" :: show str :: show x :: Nil)
144144+ show (DDerive _ x y) = foo ("DDerive" :: show x :: show y :: Nil)
143145 show (FunDef _ str clauses) = foo ("FunDef" :: show str :: show clauses :: Nil)
144146 show (Data _ str xs ys) = foo ("Data" :: show str :: show xs :: show ys :: Nil)
145147 show (DCheck _ x y) = foo ("DCheck" :: show x :: show y :: Nil)
···248250249251instance Pretty Decl where
250252 pretty (TypeSig _ nm ty) = spread (map text nm) <+> text ":" <+> nest 2 (pretty ty)
253253+ pretty (DDerive _ x y) = text "derive" <+> text (snd x) <+> text (snd y)
251254 pretty (FunDef _ nm clauses) = stack $ map prettyPair clauses
252255 where
253256 prettyPair : Raw × Maybe Raw → Doc
···264267 <+> (nest 2 $ text "where" </> stack (maybe empty (\ nm' => text "constructor" <+> text (snd nm')) cname :: map pretty decls))
265268 pretty (Class _ (_,nm) tele decls) = text "class" <+> text nm <+> text ":" <+> spread (map prettyBind tele)
266269 <+> (nest 2 $ text "where" </> stack (map pretty decls))
267267- pretty (Instance _ _ _) = text "TODO pretty Instance"
270270+ pretty (Instance fc top Nothing) = text "instance" <+> pretty top
271271+ pretty (Instance fc top (Just decls)) = text "instance" <+> pretty top <+> nest 2 (text "where" </> stack (map pretty decls))
268272 pretty (ShortData _ lhs sigs) = text "data" <+> pretty lhs <+> text "=" <+> pipeSep (map pretty sigs)
269273 pretty (Exports _ nms) = text "#export" <+> spread (map (text ∘ show ∘ snd) nms)
270274
+1-1
src/Lib/Tokenizer.newt
···2020keywords : List String
2121keywords = ("let" :: "in" :: "where" :: "case" :: "of" :: "data" :: "U" :: "do" ::
2222 "ptype" :: "pfunc" :: "module" :: "infixl" :: "infixr" :: "infix" ::
2323- "∀" :: "forall" :: "import" :: "uses" ::
2323+ "∀" :: "forall" :: "import" :: "uses" :: "derive" ::
2424 "class" :: "instance" :: "record" :: "constructor" ::
2525 "if" :: "then" :: "else" ::
2626 -- it would be nice to find a way to unkeyword "." so it could be
+8-1
src/Lib/TopContext.newt
···4646 show top = "\nContext:\n [\{ joinBy "\n" $ map (show ∘ snd) $ toList top.currentMod.modDefs}]"
47474848emptyTop : TopContext
4949-emptyTop = MkTop emptyMap emptyMap (emptyModCtx "" "") 0 emptyMap
4949+emptyTop = MkTop emptyMap emptyMap (emptyModCtx "" "") 0 emptyMap 0
50505151setFlag : QName → FC → EFlag → M Unit
5252setFlag name fc flag = do
···94949595addInfo : EditorInfo → M Unit
9696addInfo info = modifyTop [ currentMod $= [modInfos $= (info ::) ] ]
9797+9898+-- temporary? used in derive for now
9999+freshName : String → M String
100100+freshName nm = do
101101+ top <- getTop
102102+ modifyTop [ freshIx $= 1 + ]
103103+ pure $ "f$" ++ nm ++ show top.freshIx
+6-3
src/Lib/Types.newt
···8181 Lam : FC -> Name -> Icit -> Quant -> Tm -> Tm
8282 App : FC -> Tm -> Tm -> Tm
8383 UU : FC -> Tm
8484- Pi : FC -> Name -> Icit -> Quant -> Tm -> Tm -> Tm
8484+ Pi : (fc : FC) -> (nm : Name) -> Icit -> Quant -> (a : Tm) -> (b : Tm) -> Tm
8585 Case : FC -> Tm -> List CaseAlt -> Tm
8686 -- need type?
8787 Let : FC -> Name -> Tm -> Tm -> Tm
···442442 currentMod : ModContext
443443 verbose : Int -- command line flag increments this
444444 ops : Operators
445445+ freshIx : Int
445446446447-- we'll use this for typechecking, but need to keep a TopContext around too.
447448···594595mkCtx : FC -> Context
595596mkCtx fc = MkCtx 0 Nil Nil Nil fc
596597598598+-- Used by Syntax and Elab
599599+597600data Pattern
598601 = PatVar FC Icit Name
599602 | PatCon FC Icit QName (List Pattern) (Maybe Name)
···627630 show (PC nm pat ty) = show (nm,pat,ty)
628631629632-- Lazy because `let` would do work at the top of a `M a`
630630-prof : ∀ a. String → Lazy (M a) → M a
631631-prof desc work = do
633633+profile : ∀ a. String → Lazy (M a) → M a
634634+profile desc work = do
632635 start <- getTime
633636 res <- force work
634637 end <- getTime
+14
tests/Derive.newt
···11+module Derive
22+33+import Prelude
44+55+data Blah = Foo Int | Bar | Baz String
66+77+derive Eq Blah
88+derive Show Blah
99+1010+main : IO Unit
1111+main = do
1212+ printLn $ Foo 42
1313+ printLn $ Bar
1414+ printLn $ Baz "woo"
···11+module ImportError
22+33+-- test the FC are right and don't include next line
44+-- TODO continue on and hit the next one.
55+import Blah
66+import Foo.Bar
77+import Prelude
+2
tests/ImportError.newt.fail
···11+*** Process tests/ImportError.newt
22+ERROR at tests/ImportError.newt:5:8--5:12: error reading tests/Blah.newt: Error: ENOENT: no such file or directory, open 'tests/Blah.newt'
+8
tests/UnsafeIO.newt
···11+module UnsafeIO
22+33+import Prelude
44+55+main : IO Unit
66+main = do
77+ let x = unsafePerformIO $ putStrLn "Hello, World!"
88+ pure MkUnit