derive Show and Eq, improvements to LSP
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
InitializeResult,
|
InitializeResult,
|
||||||
TextDocumentSyncKind,
|
TextDocumentSyncKind,
|
||||||
Location,
|
Location,
|
||||||
|
TextDocumentIdentifier,
|
||||||
} from "vscode-languageserver/node";
|
} from "vscode-languageserver/node";
|
||||||
import { TextDocument } from "vscode-languageserver-textdocument";
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
||||||
|
|
||||||
@@ -24,10 +25,10 @@ const documents = new TextDocuments(TextDocument);
|
|||||||
|
|
||||||
// the last is the most important to the user, but we run FIFO
|
// the last is the most important to the user, but we run FIFO
|
||||||
// to ensure dependencies are seen in causal order
|
// to ensure dependencies are seen in causal order
|
||||||
let changes: TextDocument[] = []
|
let changes: (TextDocument|TextDocumentIdentifier)[] = []
|
||||||
let running = false
|
let running = false
|
||||||
let lastChange = 0
|
let lastChange = 0
|
||||||
function addChange(doc: TextDocument) {
|
function addChange(doc: TextDocument | TextDocumentIdentifier) {
|
||||||
console.log('enqueue', doc.uri)
|
console.log('enqueue', doc.uri)
|
||||||
// drop stale pending changes
|
// drop stale pending changes
|
||||||
let before = changes.length
|
let before = changes.length
|
||||||
@@ -94,15 +95,20 @@ connection.onHover((params): Hover | null => {
|
|||||||
console.log('HOVER', uri, pos)
|
console.log('HOVER', uri, pos)
|
||||||
let res = LSP_hoverInfo(uri, pos.line, pos.character)
|
let res = LSP_hoverInfo(uri, pos.line, pos.character)
|
||||||
if (!res) return null
|
if (!res) return null
|
||||||
|
if (res == true) {
|
||||||
|
addChange(params.textDocument)
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
console.log('HOVER is ', res)
|
console.log('HOVER is ', res)
|
||||||
return { contents: { kind: "plaintext", value: res.info } };
|
return { contents: { kind: "plaintext", value: res.info } };
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.onDefinition((params): Location | null => {
|
connection.onDefinition((params): Location | null => {
|
||||||
const uri = params.textDocument.uri;
|
const uri = params.textDocument.uri;
|
||||||
const pos = params.position;
|
const pos = params.position;
|
||||||
let value = LSP_hoverInfo(uri, pos.line, pos.character)
|
let value = LSP_hoverInfo(uri, pos.line, pos.character)
|
||||||
if (!value) return null;
|
if (!value || value == true) return null;
|
||||||
return value.location
|
return value.location
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
2
newt-vscode-lsp/src/newt.d.ts
vendored
2
newt-vscode-lsp/src/newt.d.ts
vendored
@@ -6,5 +6,5 @@ interface HoverResult {
|
|||||||
info: string
|
info: string
|
||||||
location: Location
|
location: Location
|
||||||
}
|
}
|
||||||
export function LSP_hoverInfo(name: string, row: number, col: number): HoverResult|null;
|
export function LSP_hoverInfo(name: string, row: number, col: number): HoverResult|boolean|null;
|
||||||
export function LSP_codeActionInfo(name: string, row: number, col: number): CodeAction[]|null;
|
export function LSP_codeActionInfo(name: string, row: number, col: number): CodeAction[]|null;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "keyword.newt",
|
"name": "keyword.newt",
|
||||||
"match": "\\b(λ|=>|<-|->|→|:=|\\$|data|record|constructor|where|do|class|uses|instance|case|of|let|if|then|else|forall|∀|in|U|module|import|ptype|pfunc|infix|infixl|infixr)\\b"
|
"match": "\\b(λ|=>|<-|->|→|:=|\\$|data|record|constructor|where|do|derive|class|uses|instance|case|of|let|if|then|else|forall|∀|in|U|module|import|ptype|pfunc|infix|infixl|infixr)\\b"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "string.js",
|
"name": "string.js",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const keywords = [
|
|||||||
"case",
|
"case",
|
||||||
"of",
|
"of",
|
||||||
"data",
|
"data",
|
||||||
|
"derive",
|
||||||
"U",
|
"U",
|
||||||
"do",
|
"do",
|
||||||
"ptype",
|
"ptype",
|
||||||
|
|||||||
@@ -35,35 +35,38 @@ switchModule repo modns = do
|
|||||||
-- TODO processing on hover is expensive, but info is not always there
|
-- TODO processing on hover is expensive, but info is not always there
|
||||||
-- I suspect this picks up the case where a file has been invalidated by a change to
|
-- I suspect this picks up the case where a file has been invalidated by a change to
|
||||||
-- another file and we switch editors. Handle that (enqueue a check) and switch this back.
|
-- another file and we switch editors. Handle that (enqueue a check) and switch this back.
|
||||||
|
-- this is also broken, because diagnostics don't get updated..
|
||||||
top <- getTop
|
top <- getTop
|
||||||
mod <- processModule emptyFC repo Nil modns
|
-- mod <- processModule emptyFC repo Nil modns
|
||||||
-- let (Just mod) = lookupMap' modns top.modules | Nothing => pure Nothing
|
let (Just mod) = lookupMap' modns top.modules | Nothing => pure Nothing
|
||||||
modifyTop [ currentMod := mod; ops := mod.modOps ]
|
modifyTop [ currentMod := mod; ops := mod.modOps ]
|
||||||
pure $ Just mod
|
pure $ Just mod
|
||||||
|
|
||||||
|
data HoverInfo = NoHoverInfo | NeedCheck | HasHover FC String
|
||||||
|
|
||||||
-- The cheap version of type at point, find the token, lookup in global context
|
-- The cheap version of type at point, find the token, lookup in global context
|
||||||
-- Later we will either get good FC for entries or scan them all and build a cache.
|
-- Later we will either get good FC for entries or scan them all and build a cache.
|
||||||
getHoverInfo : FileSource → String → Int → Int → M (Maybe (String × FC))
|
getHoverInfo : FileSource → String → Int → Int → M HoverInfo
|
||||||
getHoverInfo repo modns row col = do
|
getHoverInfo repo modns row col = do
|
||||||
Just mod <- switchModule repo modns | _ => pure Nothing
|
Just mod <- switchModule repo modns | _ => pure NeedCheck
|
||||||
top <- getTop
|
top <- getTop
|
||||||
|
|
||||||
-- Find the token at the point
|
-- Find the token at the point
|
||||||
let lines = split mod.modSource "\n"
|
let lines = split mod.modSource "\n"
|
||||||
let line = fromMaybe "" (getAt' row lines)
|
let line = fromMaybe "" (getAt' row lines)
|
||||||
let (Right toks) = tokenise "" line | Left _ => pure Nothing
|
let (Right toks) = tokenise "" line | Left _ => pure NoHoverInfo
|
||||||
let (Just name) = getTok toks | _ => pure Nothing
|
let (Just name) = getTok toks | _ => pure NoHoverInfo
|
||||||
|
|
||||||
let (Left _) = partialParse "" parseImport emptyMap toks
|
let (Left _) = partialParse "" parseImport emptyMap toks
|
||||||
| Right ((MkImport _ (fc, nm)), _, _) => do
|
| Right ((MkImport _ (fc, nm)), _, _) => do
|
||||||
let (baseDir, _) = splitFileName fc.file
|
let (baseDir, _) = splitFileName fc.file
|
||||||
let fc = MkFC (repo.baseDir ++ "/" ++ joinBy "/" (split nm ".")) (MkBounds 0 0 0 0)
|
let fc = MkFC ("\{repo.baseDir}/\{joinBy "/" (split nm ".")}.newt") (MkBounds 0 0 0 0)
|
||||||
pure $ Just ("module \{nm}", fc)
|
pure $ HasHover fc "module \{nm}"
|
||||||
|
putStrLn "Hover name is \{show name}"
|
||||||
-- Lookup the name
|
-- Lookup the name
|
||||||
let (Just e) = lookupRaw name top | _ => pure Nothing
|
let (Just e) = lookupRaw name top | _ => pure NoHoverInfo
|
||||||
ty <- nf Nil e.type
|
ty <- nf Nil e.type
|
||||||
pure $ Just ("\{show e.name} : \{rpprint Nil ty}", e.fc)
|
pure $ HasHover e.fc ("\{show e.name} : \{rpprint Nil ty}")
|
||||||
|
|
||||||
where
|
where
|
||||||
getTok : List BTok → Maybe String
|
getTok : List BTok → Maybe String
|
||||||
@@ -140,7 +143,9 @@ makeEdits fc@(MkFC uri (MkBounds sr sc er ec)) names inPlace = do
|
|||||||
let phead = pack head
|
let phead = pack head
|
||||||
let indent = getIndent 0 head
|
let indent = getIndent 0 head
|
||||||
let nextrow = scan indent lines (sr + 1)
|
let nextrow = scan indent lines (sr + 1)
|
||||||
|
-- FIXME - doesn't handle `let`, but that's a little messy
|
||||||
|
-- need to remove let and add `|`, but also indent.
|
||||||
|
-- Existing `|` would have their own indent, indent of let matters. etc.
|
||||||
-- No init or first :: rest for add missing case
|
-- No init or first :: rest for add missing case
|
||||||
let (edits, rest) = doFirst inPlace cons
|
let (edits, rest) = doFirst inPlace cons
|
||||||
|
|
||||||
@@ -193,8 +198,8 @@ getCaseSplit row col fc@(MkFC uri (MkBounds sr sc er ec)) ctx nm scty = do
|
|||||||
pure $ Just $ CaseSplitAction edits
|
pure $ Just $ CaseSplitAction edits
|
||||||
|
|
||||||
posInFC : Int → Int → FC → Bool
|
posInFC : Int → Int → FC → Bool
|
||||||
-- FIXME ec + 1 again...
|
posInFC row col (MkFC _ (MkBounds 0 0 0 0)) = False
|
||||||
posInFC row col (MkFC _ (MkBounds sr sc er ec)) = (sr <= row && row <= er) && (sc <= col && col <= ec + 1)
|
posInFC row col (MkFC _ (MkBounds sr sc er ec)) = (sr <= row && row <= er) && (sc <= col && col <= ec)
|
||||||
|
|
||||||
getHole : ModContext → Int → Int → Maybe MetaEntry
|
getHole : ModContext → Int → Int → Maybe MetaEntry
|
||||||
getHole mod row col =
|
getHole mod row col =
|
||||||
@@ -243,7 +248,7 @@ introActions _ = pure Nil
|
|||||||
|
|
||||||
errorActions : Int → Int → Error → M (List CodeAction)
|
errorActions : Int → Int → Error → M (List CodeAction)
|
||||||
errorActions row col err = do
|
errorActions row col err = do
|
||||||
let (ENotFound fc nm) = err | _ => pure Nil
|
let (ENotInScope fc nm) = err | _ => pure Nil
|
||||||
let (True) = posInFC row col fc | _ => pure Nil
|
let (True) = posInFC row col fc | _ => pure Nil
|
||||||
top <- getTop
|
top <- getTop
|
||||||
let mods = map (\e => e.name.qns) $ lookupAll nm top
|
let mods = map (\e => e.name.qns) $ lookupAll nm top
|
||||||
|
|||||||
10
src/LSP.newt
10
src/LSP.newt
@@ -94,11 +94,15 @@ hoverInfo uri line col = unsafePerformIO $ do
|
|||||||
st <- readIORef state
|
st <- readIORef state
|
||||||
repo <- lspFileSource
|
repo <- lspFileSource
|
||||||
-- We're proactively running check if there is no module information, make sure we save it
|
-- We're proactively running check if there is no module information, make sure we save it
|
||||||
Right (top, Just (msg, fc)) <- (getHoverInfo repo modns line col).runM st.topContext
|
Right (top, HasHover fc msg) <- (getHoverInfo repo modns line col).runM st.topContext
|
||||||
| Right (top, _) => do
|
| Right (top, NeedCheck) => do
|
||||||
|
modifyIORef state $ [ topContext := top ]
|
||||||
|
putStrLn $ "NeedsCheck"
|
||||||
|
pure $ js_castBool True
|
||||||
|
| Right (top, NoHoverInfo) => do
|
||||||
modifyIORef state $ [ topContext := top ]
|
modifyIORef state $ [ topContext := top ]
|
||||||
putStrLn $ "Nothing to see here"
|
putStrLn $ "Nothing to see here"
|
||||||
pure $ jsonToJObject JsonNull
|
pure $ js_castBool True
|
||||||
| Left err => do
|
| Left err => do
|
||||||
putStrLn $ showError "" err
|
putStrLn $ showError "" err
|
||||||
pure $ jsonToJObject JsonNull
|
pure $ jsonToJObject JsonNull
|
||||||
|
|||||||
151
src/Lib/Derive.newt
Normal file
151
src/Lib/Derive.newt
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
module Lib.Derive
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
import Lib.Common
|
||||||
|
import Lib.Types
|
||||||
|
import Lib.Syntax
|
||||||
|
import Lib.TopContext
|
||||||
|
import Lib.Error
|
||||||
|
import Lib.Elab -- (lookupDCon)
|
||||||
|
import Lib.Prettier
|
||||||
|
|
||||||
|
-- describe type
|
||||||
|
|
||||||
|
data Desc : U
|
||||||
|
|
||||||
|
data DConst : U where
|
||||||
|
MkConst : (name : String) → List (String × Desc) → DConst
|
||||||
|
|
||||||
|
|
||||||
|
data Desc : U where
|
||||||
|
DInd : List DConst → Desc
|
||||||
|
|
||||||
|
-- So I guess we do a few of these and then figure out how to make it easier
|
||||||
|
|
||||||
|
deriveEq : FC → String → M (List Decl)
|
||||||
|
deriveEq fc name = do
|
||||||
|
top <- getTop
|
||||||
|
let (Just (MkEntry fc qname type (TCon _ names) eflags)) = lookupRaw name top
|
||||||
|
| Just _ => throwError $ E fc "\{name} is not a type constructor"
|
||||||
|
| _ => throwError $ ENotInScope fc name
|
||||||
|
dcons <- traverse lookupDCon names
|
||||||
|
clauses <- traverse makeClause dcons
|
||||||
|
let fallback = (buildApp "_==_" (rvar "_" :: rvar "_" :: Nil), Just (rvar "False"))
|
||||||
|
let eqDecl = FunDef fc "_==_" (snoc clauses fallback)
|
||||||
|
let inst = Instance fc (buildApp "Eq" (rvar name :: Nil)) (Just $ eqDecl :: Nil)
|
||||||
|
pure $ inst :: Nil
|
||||||
|
|
||||||
|
where
|
||||||
|
arr : Raw → Raw → Raw
|
||||||
|
arr a b = RPi emptyFC (BI fc "_" Explicit Many) a b
|
||||||
|
|
||||||
|
rvar : String → Raw
|
||||||
|
rvar nm = RVar emptyFC nm
|
||||||
|
|
||||||
|
getExplictNames : SnocList String → Tm → List String
|
||||||
|
getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
|
||||||
|
getExplictNames acc (Pi fc nm Implicit quant a b) = getExplictNames acc b
|
||||||
|
getExplictNames acc (Pi fc nm Auto quant a b) = getExplictNames acc b
|
||||||
|
getExplictNames acc _ = acc <>> Nil
|
||||||
|
|
||||||
|
buildApp : String → List Raw → Raw
|
||||||
|
buildApp nm nms = foldl (\ t u => RApp emptyFC t u Explicit) (rvar nm) $ nms
|
||||||
|
|
||||||
|
equate : (Raw × Raw) → Raw
|
||||||
|
equate (a,b) = buildApp "_==_" (a :: b :: Nil)
|
||||||
|
|
||||||
|
makeClause : (QName × Int × Tm) → M (Raw × Maybe Raw)
|
||||||
|
makeClause ((QN ns nm), _, ty) = do
|
||||||
|
-- We're only looking at explicit args for now.
|
||||||
|
-- TODO check quantity
|
||||||
|
let names = getExplictNames Lin ty
|
||||||
|
anames <- map rvar <$> traverse freshName names
|
||||||
|
bnames <- map rvar <$> traverse freshName names
|
||||||
|
let a = buildApp nm anames
|
||||||
|
let b = buildApp nm bnames
|
||||||
|
|
||||||
|
let left = equate (a,b)
|
||||||
|
let right = case map equate $ zip anames bnames of
|
||||||
|
Nil => rvar "True"
|
||||||
|
(hd :: tl) => foldr (\a b => buildApp "_&&_" (a :: b :: Nil)) hd tl
|
||||||
|
|
||||||
|
pure (left, Just right)
|
||||||
|
|
||||||
|
|
||||||
|
-- This is a little more of a pain, we'll generate a number for each constructor
|
||||||
|
-- and use that as the fallback. Eventually we'll want something like quasi-quote
|
||||||
|
deriveShow : FC → String → M (List Decl)
|
||||||
|
deriveShow fc name = do
|
||||||
|
top <- getTop
|
||||||
|
let (Just (MkEntry fc qname type (TCon _ names) eflags)) = lookupRaw name top
|
||||||
|
| Just _ => throwError $ E fc "\{name} is not a type constructor"
|
||||||
|
| _ => throwError $ ENotInScope fc name
|
||||||
|
dcons <- traverse lookupDCon names
|
||||||
|
clauses <- traverse makeClause dcons
|
||||||
|
|
||||||
|
let eqDecl = FunDef fc "show" clauses
|
||||||
|
let inst = Instance fc (buildApp "Show" (rvar name :: Nil)) (Just $ eqDecl :: Nil)
|
||||||
|
pure $ inst :: Nil
|
||||||
|
|
||||||
|
where
|
||||||
|
arr : Raw → Raw → Raw
|
||||||
|
arr a b = RPi emptyFC (BI fc "_" Explicit Many) a b
|
||||||
|
|
||||||
|
rvar : String → Raw
|
||||||
|
rvar nm = RVar emptyFC nm
|
||||||
|
|
||||||
|
lstring : String → Raw
|
||||||
|
lstring s = RLit emptyFC (LString s)
|
||||||
|
|
||||||
|
getExplictNames : SnocList String → Tm → List String
|
||||||
|
getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
|
||||||
|
getExplictNames acc (Pi fc nm Implicit quant a b) = getExplictNames acc b
|
||||||
|
getExplictNames acc (Pi fc nm Auto quant a b) = getExplictNames acc b
|
||||||
|
getExplictNames acc _ = acc <>> Nil
|
||||||
|
|
||||||
|
buildApp : String → List Raw → Raw
|
||||||
|
buildApp nm nms = foldl (\ t u => RApp emptyFC t u Explicit) (rvar nm) $ nms
|
||||||
|
|
||||||
|
equate : (Raw × Raw) → Raw
|
||||||
|
equate (a,b) = buildApp "_==_" (a :: b :: Nil)
|
||||||
|
|
||||||
|
makeList : List Raw → Raw
|
||||||
|
makeList Nil = rvar "Nil"
|
||||||
|
makeList (x :: xs) = buildApp "_::_" (x :: makeList xs :: Nil)
|
||||||
|
|
||||||
|
makeClause : (QName × Int × Tm) → M (Raw × Maybe Raw)
|
||||||
|
makeClause ((QN ns nm), _, ty) = do
|
||||||
|
let names = getExplictNames Lin ty
|
||||||
|
anames <- map rvar <$> traverse freshName names
|
||||||
|
let left = buildApp "show" $ buildApp nm anames :: Nil
|
||||||
|
let shows = map (\ nm => RApp emptyFC (rvar "show") nm Explicit) anames
|
||||||
|
let right = case anames of
|
||||||
|
Nil => lstring nm
|
||||||
|
_ =>
|
||||||
|
let parts = makeList $ lstring ("(" ++ nm) :: shows in
|
||||||
|
buildApp "_++_" $ buildApp "joinBy" (lstring " " :: parts :: Nil) :: lstring ")" :: Nil
|
||||||
|
|
||||||
|
pure (left, Just right)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- -- A description would be nice.
|
||||||
|
-- deriveShow : FC → QName → M Raw
|
||||||
|
-- deriveShow fc qn = do
|
||||||
|
-- top <- getTop
|
||||||
|
-- case lookup qn top : Maybe TopEntry of
|
||||||
|
-- Nothing => error {Raw} fc "Can't find \{show qn} in derive Show"
|
||||||
|
-- -- I want case split too... I need to tie the editor into the repl.
|
||||||
|
-- (Just (MkEntry fc name type (TCon _ conNames) eflags) ) => ?
|
||||||
|
-- (Just (MkEntry fc name type (Axiom) eflags) ) => ?
|
||||||
|
-- (Just (MkEntry fc name type (DCon _ _ _ _) eflags) ) => ?
|
||||||
|
-- (Just (MkEntry fc name type (Fn _) eflags) ) => ?
|
||||||
|
-- (Just (MkEntry fc name type (PrimTCon _) eflags) ) => ?
|
||||||
|
-- (Just (MkEntry fc name type (PrimFn _ _ _) eflags) ) => ?
|
||||||
|
-- (Just (MkEntry fc name type (PrimOp _) eflags) ) => ?
|
||||||
|
|
||||||
|
-- error fc "TODO"
|
||||||
|
|
||||||
|
|
||||||
|
-- HasFC as example of user-defined derivation (when we get to that)
|
||||||
|
-- SetFC would be nice, too.
|
||||||
@@ -1544,8 +1544,10 @@ infer ctx (RVar fc nm) = go 0 ctx.types
|
|||||||
debug $ \ _ => "lookup \{show name} as \{show def}"
|
debug $ \ _ => "lookup \{show name} as \{show def}"
|
||||||
vty <- eval Nil ty
|
vty <- eval Nil ty
|
||||||
pure (Ref fc name, vty)
|
pure (Ref fc name, vty)
|
||||||
-- Can we soften this without introducing a meta?
|
-- Can we soften this without introducing a meta for the type
|
||||||
Nothing => throwError $ ENotFound fc nm
|
-- it might be additional errors, but also could lead to narrowing of possible names...
|
||||||
|
-- especially when we hit this for .foo
|
||||||
|
Nothing => throwError $ ENotInScope fc nm
|
||||||
go i ((x, ty) :: xs) = if x == nm then pure (Bnd fc i, ty)
|
go i ((x, ty) :: xs) = if x == nm then pure (Bnd fc i, ty)
|
||||||
else go (i + 1) xs
|
else go (i + 1) xs
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,18 @@ import Lib.Common
|
|||||||
-- and a pretty printer in the monad
|
-- and a pretty printer in the monad
|
||||||
data Error
|
data Error
|
||||||
= E FC String
|
= E FC String
|
||||||
| ENotFound FC String
|
| ENotInScope FC String
|
||||||
| Postpone FC QName String
|
| Postpone FC QName String
|
||||||
|
|
||||||
|
|
||||||
instance HasFC Error where
|
instance HasFC Error where
|
||||||
getFC (E x str) = x
|
getFC (E x str) = x
|
||||||
getFC (ENotFound x _) = x
|
getFC (ENotInScope x _) = x
|
||||||
getFC (Postpone x k str) = x
|
getFC (Postpone x k str) = x
|
||||||
|
|
||||||
errorMsg : Error -> String
|
errorMsg : Error -> String
|
||||||
errorMsg (E x str) = str
|
errorMsg (E x str) = str
|
||||||
errorMsg (ENotFound x nm) = "\{nm} not in scope"
|
errorMsg (ENotInScope x nm) = "\{nm} not in scope"
|
||||||
errorMsg (Postpone x k str) = str
|
errorMsg (Postpone x k str) = str
|
||||||
|
|
||||||
showError : (src : String) -> Error -> String
|
showError : (src : String) -> Error -> String
|
||||||
|
|||||||
@@ -538,8 +538,11 @@ parseImport = do
|
|||||||
-- TODO revisit when we have parser for qualified names in source
|
-- TODO revisit when we have parser for qualified names in source
|
||||||
(nameFC, ident) <- withFC uident
|
(nameFC, ident) <- withFC uident
|
||||||
(restFC,rest) <- withFC $ many $ token Projection
|
(restFC,rest) <- withFC $ many $ token Projection
|
||||||
|
let nameFC = case rest of
|
||||||
|
Nil => nameFC
|
||||||
|
(_ :: _) => nameFC + restFC
|
||||||
let name = joinBy "" (ident :: rest)
|
let name = joinBy "" (ident :: rest)
|
||||||
pure $ MkImport fc (nameFC + restFC, name)
|
pure $ MkImport fc (nameFC, name)
|
||||||
|
|
||||||
-- Do we do pattern stuff now? or just name = lambda?
|
-- Do we do pattern stuff now? or just name = lambda?
|
||||||
-- TODO multiple names
|
-- TODO multiple names
|
||||||
@@ -679,11 +682,19 @@ parseExport = do
|
|||||||
names <- many $ withFC ident
|
names <- many $ withFC ident
|
||||||
pure $ Exports loc names
|
pure $ Exports loc names
|
||||||
|
|
||||||
|
parseDerive : Parser Decl
|
||||||
|
parseDerive = do
|
||||||
|
loc <- getPos
|
||||||
|
keyword "derive"
|
||||||
|
className <- withFC uident
|
||||||
|
name <- withFC uident
|
||||||
|
pure $ DDerive loc className name
|
||||||
|
|
||||||
parseDecl : Parser Decl
|
parseDecl : Parser Decl
|
||||||
parseDecl = parseMixfix <|> parsePType <|> parsePFunc
|
parseDecl = parseMixfix <|> parsePType <|> parsePFunc
|
||||||
<|> parseNorm <|> parseData <|> parseShortData
|
<|> parseNorm <|> parseData <|> parseShortData
|
||||||
<|> parseClass <|> parseInstance <|> parseRecord
|
<|> parseClass <|> parseInstance <|> parseRecord
|
||||||
<|> parseExport
|
<|> parseExport <|> parseDerive
|
||||||
-- We'll put the backtracing stuff last, but there is a commit issue in parseDef
|
-- We'll put the backtracing stuff last, but there is a commit issue in parseDef
|
||||||
<|> parseSig <|> parseDef
|
<|> parseSig <|> parseDef
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import Lib.Prettier
|
|||||||
import Lib.Types
|
import Lib.Types
|
||||||
import Lib.Util
|
import Lib.Util
|
||||||
import Lib.Erasure
|
import Lib.Erasure
|
||||||
|
import Lib.Derive
|
||||||
|
|
||||||
dumpEnv : Context -> M String
|
dumpEnv : Context -> M String
|
||||||
dumpEnv ctx =
|
dumpEnv ctx =
|
||||||
@@ -529,6 +530,17 @@ processRecord ns recordFC (nameFC, nm) tele cname decls = do
|
|||||||
let deps = ((name, RApp fc (RVar fc pname) (RVar fc "$self") Explicit) :: deps)
|
let deps = ((name, RApp fc (RVar fc pname) (RVar fc "$self") Explicit) :: deps)
|
||||||
processFields autoPat tail deps rest
|
processFields autoPat tail deps rest
|
||||||
|
|
||||||
|
processDerive : String → FC → FC × String → (FC × String) → M Unit
|
||||||
|
processDerive ns fc (clFC, clName) (fc, name) = do
|
||||||
|
case clName of
|
||||||
|
"Eq" => do
|
||||||
|
decls <- deriveEq fc name
|
||||||
|
for_ decls $ processDecl ns
|
||||||
|
"Show" => do
|
||||||
|
decls <- deriveShow fc name
|
||||||
|
for_ decls $ processDecl ns
|
||||||
|
_ => error fc "derive \{clName} is not supported"
|
||||||
|
|
||||||
processExports : String → FC → List (FC × String) → M Unit
|
processExports : String → FC → List (FC × String) → M Unit
|
||||||
processExports ns fc names = do
|
processExports ns fc names = do
|
||||||
top <- getTop
|
top <- getTop
|
||||||
@@ -542,6 +554,7 @@ processExports ns fc names = do
|
|||||||
-- currently mixfix registration is handled in the parser
|
-- currently mixfix registration is handled in the parser
|
||||||
-- since we now run a decl at a time we could do it here.
|
-- since we now run a decl at a time we could do it here.
|
||||||
processDecl ns (PMixFix _ _ _ _) = pure MkUnit
|
processDecl ns (PMixFix _ _ _ _) = pure MkUnit
|
||||||
|
processDecl ns (DDerive fc tclass name) = processDerive ns fc tclass name
|
||||||
processDecl ns (TypeSig fc names tm) = processTypeSig ns fc names tm
|
processDecl ns (TypeSig fc names tm) = processTypeSig ns fc names tm
|
||||||
processDecl ns (PType fc nm ty) = processPrimType ns fc nm ty
|
processDecl ns (PType fc nm ty) = processPrimType ns fc nm ty
|
||||||
processDecl ns (PFunc fc nm used ty src) = processPrimFn ns fc nm used ty src
|
processDecl ns (PFunc fc nm used ty src) = processPrimFn ns fc nm used ty src
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ data Decl
|
|||||||
= TypeSig FC (List Name) Raw
|
= TypeSig FC (List Name) Raw
|
||||||
| FunDef FC Name (List (Raw × Maybe Raw))
|
| FunDef FC Name (List (Raw × Maybe Raw))
|
||||||
| DCheck FC Raw Raw
|
| DCheck FC Raw Raw
|
||||||
|
| DDerive FC (FC × String) (FC × String)
|
||||||
-- TODO maybe add Telescope (before `:`) and auto-add to constructors...
|
-- TODO maybe add Telescope (before `:`) and auto-add to constructors...
|
||||||
| Data FC (FC × Name) Raw (Maybe $ List Decl)
|
| Data FC (FC × Name) Raw (Maybe $ List Decl)
|
||||||
| ShortData FC Raw (List Raw)
|
| ShortData FC Raw (List Raw)
|
||||||
@@ -113,6 +114,7 @@ instance HasFC Decl where
|
|||||||
getFC (Class x str xs ys) = x
|
getFC (Class x str xs ys) = x
|
||||||
getFC (Instance x tm xs) = x
|
getFC (Instance x tm xs) = x
|
||||||
getFC (Record x str tm str1 xs) = x
|
getFC (Record x str tm str1 xs) = x
|
||||||
|
getFC (DDerive x _ _) = x
|
||||||
|
|
||||||
|
|
||||||
record Module where
|
record Module where
|
||||||
@@ -126,7 +128,6 @@ foo ts = "(" ++ unwords ts ++ ")"
|
|||||||
|
|
||||||
instance Show Raw
|
instance Show Raw
|
||||||
|
|
||||||
|
|
||||||
instance Show Clause where
|
instance Show Clause where
|
||||||
show (MkClause fc cons pats expr) = show (fc, cons, pats, expr)
|
show (MkClause fc cons pats expr) = show (fc, cons, pats, expr)
|
||||||
|
|
||||||
@@ -140,6 +141,7 @@ instance Show BindInfo where
|
|||||||
|
|
||||||
instance Show Decl where
|
instance Show Decl where
|
||||||
show (TypeSig _ str x) = foo ("TypeSig" :: show str :: show x :: Nil)
|
show (TypeSig _ str x) = foo ("TypeSig" :: show str :: show x :: Nil)
|
||||||
|
show (DDerive _ x y) = foo ("DDerive" :: show x :: show y :: Nil)
|
||||||
show (FunDef _ str clauses) = foo ("FunDef" :: show str :: show clauses :: Nil)
|
show (FunDef _ str clauses) = foo ("FunDef" :: show str :: show clauses :: Nil)
|
||||||
show (Data _ str xs ys) = foo ("Data" :: show str :: show xs :: show ys :: Nil)
|
show (Data _ str xs ys) = foo ("Data" :: show str :: show xs :: show ys :: Nil)
|
||||||
show (DCheck _ x y) = foo ("DCheck" :: show x :: show y :: Nil)
|
show (DCheck _ x y) = foo ("DCheck" :: show x :: show y :: Nil)
|
||||||
@@ -248,6 +250,7 @@ pipeSep = folddoc (\a b => a <+/> text "|" <+> b)
|
|||||||
|
|
||||||
instance Pretty Decl where
|
instance Pretty Decl where
|
||||||
pretty (TypeSig _ nm ty) = spread (map text nm) <+> text ":" <+> nest 2 (pretty ty)
|
pretty (TypeSig _ nm ty) = spread (map text nm) <+> text ":" <+> nest 2 (pretty ty)
|
||||||
|
pretty (DDerive _ x y) = text "derive" <+> text (snd x) <+> text (snd y)
|
||||||
pretty (FunDef _ nm clauses) = stack $ map prettyPair clauses
|
pretty (FunDef _ nm clauses) = stack $ map prettyPair clauses
|
||||||
where
|
where
|
||||||
prettyPair : Raw × Maybe Raw → Doc
|
prettyPair : Raw × Maybe Raw → Doc
|
||||||
@@ -264,7 +267,8 @@ instance Pretty Decl where
|
|||||||
<+> (nest 2 $ text "where" </> stack (maybe empty (\ nm' => text "constructor" <+> text (snd nm')) cname :: map pretty decls))
|
<+> (nest 2 $ text "where" </> stack (maybe empty (\ nm' => text "constructor" <+> text (snd nm')) cname :: map pretty decls))
|
||||||
pretty (Class _ (_,nm) tele decls) = text "class" <+> text nm <+> text ":" <+> spread (map prettyBind tele)
|
pretty (Class _ (_,nm) tele decls) = text "class" <+> text nm <+> text ":" <+> spread (map prettyBind tele)
|
||||||
<+> (nest 2 $ text "where" </> stack (map pretty decls))
|
<+> (nest 2 $ text "where" </> stack (map pretty decls))
|
||||||
pretty (Instance _ _ _) = text "TODO pretty Instance"
|
pretty (Instance fc top Nothing) = text "instance" <+> pretty top
|
||||||
|
pretty (Instance fc top (Just decls)) = text "instance" <+> pretty top <+> nest 2 (text "where" </> stack (map pretty decls))
|
||||||
pretty (ShortData _ lhs sigs) = text "data" <+> pretty lhs <+> text "=" <+> pipeSep (map pretty sigs)
|
pretty (ShortData _ lhs sigs) = text "data" <+> pretty lhs <+> text "=" <+> pipeSep (map pretty sigs)
|
||||||
pretty (Exports _ nms) = text "#export" <+> spread (map (text ∘ show ∘ snd) nms)
|
pretty (Exports _ nms) = text "#export" <+> spread (map (text ∘ show ∘ snd) nms)
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ standalone = unpack "()\\{}[],.@;"
|
|||||||
keywords : List String
|
keywords : List String
|
||||||
keywords = ("let" :: "in" :: "where" :: "case" :: "of" :: "data" :: "U" :: "do" ::
|
keywords = ("let" :: "in" :: "where" :: "case" :: "of" :: "data" :: "U" :: "do" ::
|
||||||
"ptype" :: "pfunc" :: "module" :: "infixl" :: "infixr" :: "infix" ::
|
"ptype" :: "pfunc" :: "module" :: "infixl" :: "infixr" :: "infix" ::
|
||||||
"∀" :: "forall" :: "import" :: "uses" ::
|
"∀" :: "forall" :: "import" :: "uses" :: "derive" ::
|
||||||
"class" :: "instance" :: "record" :: "constructor" ::
|
"class" :: "instance" :: "record" :: "constructor" ::
|
||||||
"if" :: "then" :: "else" ::
|
"if" :: "then" :: "else" ::
|
||||||
-- it would be nice to find a way to unkeyword "." so it could be
|
-- it would be nice to find a way to unkeyword "." so it could be
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ instance Show TopContext where
|
|||||||
show top = "\nContext:\n [\{ joinBy "\n" $ map (show ∘ snd) $ toList top.currentMod.modDefs}]"
|
show top = "\nContext:\n [\{ joinBy "\n" $ map (show ∘ snd) $ toList top.currentMod.modDefs}]"
|
||||||
|
|
||||||
emptyTop : TopContext
|
emptyTop : TopContext
|
||||||
emptyTop = MkTop emptyMap emptyMap (emptyModCtx "" "") 0 emptyMap
|
emptyTop = MkTop emptyMap emptyMap (emptyModCtx "" "") 0 emptyMap 0
|
||||||
|
|
||||||
setFlag : QName → FC → EFlag → M Unit
|
setFlag : QName → FC → EFlag → M Unit
|
||||||
setFlag name fc flag = do
|
setFlag name fc flag = do
|
||||||
@@ -94,3 +94,10 @@ addError err = modifyTop [ currentMod $= [ modErrors $= (err ::) ] ]
|
|||||||
|
|
||||||
addInfo : EditorInfo → M Unit
|
addInfo : EditorInfo → M Unit
|
||||||
addInfo info = modifyTop [ currentMod $= [modInfos $= (info ::) ] ]
|
addInfo info = modifyTop [ currentMod $= [modInfos $= (info ::) ] ]
|
||||||
|
|
||||||
|
-- temporary? used in derive for now
|
||||||
|
freshName : String → M String
|
||||||
|
freshName nm = do
|
||||||
|
top <- getTop
|
||||||
|
modifyTop [ freshIx $= 1 + ]
|
||||||
|
pure $ "f$" ++ nm ++ show top.freshIx
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ data Tm : U where
|
|||||||
Lam : FC -> Name -> Icit -> Quant -> Tm -> Tm
|
Lam : FC -> Name -> Icit -> Quant -> Tm -> Tm
|
||||||
App : FC -> Tm -> Tm -> Tm
|
App : FC -> Tm -> Tm -> Tm
|
||||||
UU : FC -> Tm
|
UU : FC -> Tm
|
||||||
Pi : FC -> Name -> Icit -> Quant -> Tm -> Tm -> Tm
|
Pi : (fc : FC) -> (nm : Name) -> Icit -> Quant -> (a : Tm) -> (b : Tm) -> Tm
|
||||||
Case : FC -> Tm -> List CaseAlt -> Tm
|
Case : FC -> Tm -> List CaseAlt -> Tm
|
||||||
-- need type?
|
-- need type?
|
||||||
Let : FC -> Name -> Tm -> Tm -> Tm
|
Let : FC -> Name -> Tm -> Tm -> Tm
|
||||||
@@ -442,6 +442,7 @@ record TopContext where
|
|||||||
currentMod : ModContext
|
currentMod : ModContext
|
||||||
verbose : Int -- command line flag increments this
|
verbose : Int -- command line flag increments this
|
||||||
ops : Operators
|
ops : Operators
|
||||||
|
freshIx : Int
|
||||||
|
|
||||||
-- we'll use this for typechecking, but need to keep a TopContext around too.
|
-- we'll use this for typechecking, but need to keep a TopContext around too.
|
||||||
|
|
||||||
@@ -594,6 +595,8 @@ lookupMeta ix@(QN ns nm) = do
|
|||||||
mkCtx : FC -> Context
|
mkCtx : FC -> Context
|
||||||
mkCtx fc = MkCtx 0 Nil Nil Nil fc
|
mkCtx fc = MkCtx 0 Nil Nil Nil fc
|
||||||
|
|
||||||
|
-- Used by Syntax and Elab
|
||||||
|
|
||||||
data Pattern
|
data Pattern
|
||||||
= PatVar FC Icit Name
|
= PatVar FC Icit Name
|
||||||
| PatCon FC Icit QName (List Pattern) (Maybe Name)
|
| PatCon FC Icit QName (List Pattern) (Maybe Name)
|
||||||
@@ -627,8 +630,8 @@ instance Show Constraint where
|
|||||||
show (PC nm pat ty) = show (nm,pat,ty)
|
show (PC nm pat ty) = show (nm,pat,ty)
|
||||||
|
|
||||||
-- Lazy because `let` would do work at the top of a `M a`
|
-- Lazy because `let` would do work at the top of a `M a`
|
||||||
prof : ∀ a. String → Lazy (M a) → M a
|
profile : ∀ a. String → Lazy (M a) → M a
|
||||||
prof desc work = do
|
profile desc work = do
|
||||||
start <- getTime
|
start <- getTime
|
||||||
res <- force work
|
res <- force work
|
||||||
end <- getTime
|
end <- getTime
|
||||||
|
|||||||
14
tests/Derive.newt
Normal file
14
tests/Derive.newt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
module Derive
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
|
||||||
|
data Blah = Foo Int | Bar | Baz String
|
||||||
|
|
||||||
|
derive Eq Blah
|
||||||
|
derive Show Blah
|
||||||
|
|
||||||
|
main : IO Unit
|
||||||
|
main = do
|
||||||
|
printLn $ Foo 42
|
||||||
|
printLn $ Bar
|
||||||
|
printLn $ Baz "woo"
|
||||||
3
tests/Derive.newt.golden
Normal file
3
tests/Derive.newt.golden
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
(Foo 42)
|
||||||
|
Bar
|
||||||
|
(Baz woo)
|
||||||
7
tests/ImportError.newt
Normal file
7
tests/ImportError.newt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module ImportError
|
||||||
|
|
||||||
|
-- test the FC are right and don't include next line
|
||||||
|
-- TODO continue on and hit the next one.
|
||||||
|
import Blah
|
||||||
|
import Foo.Bar
|
||||||
|
import Prelude
|
||||||
2
tests/ImportError.newt.fail
Normal file
2
tests/ImportError.newt.fail
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*** Process tests/ImportError.newt
|
||||||
|
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
Normal file
8
tests/UnsafeIO.newt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module UnsafeIO
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
|
||||||
|
main : IO Unit
|
||||||
|
main = do
|
||||||
|
let x = unsafePerformIO $ putStrLn "Hello, World!"
|
||||||
|
pure MkUnit
|
||||||
1
tests/UnsafeIO.newt.golden
Normal file
1
tests/UnsafeIO.newt.golden
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello, World!
|
||||||
Reference in New Issue
Block a user