add \case sugar and editor support. fix symlink
This commit is contained in:
13
TODO.md
13
TODO.md
@@ -5,14 +5,14 @@ More comments in code! This is getting big enough that I need to re-find my bear
|
|||||||
|
|
||||||
- [ ] tokenizer
|
- [ ] tokenizer
|
||||||
- [ ] string interpolation
|
- [ ] string interpolation
|
||||||
- [ ] pattern matching lambda
|
|
||||||
- I kept wanting this in AoC and use it a lot in the newt code
|
|
||||||
- [ ] editor - indent newline on let with no in
|
- [ ] editor - indent newline on let with no in
|
||||||
- I've seen this done in vi for Idris, but it seems non-trivial in vscode.
|
- I've seen this done in vi for Idris, but it seems non-trivial in vscode.
|
||||||
- [x] Move on to next decl in case of error
|
- [x] Move on to next decl in case of error
|
||||||
- [x] for parse error, seek to col 0 token and process next decl
|
- [x] for parse error, seek to col 0 token and process next decl
|
||||||
- [ ] record initialization sugar, e.g. `{ x := 1, y := 2 }`
|
- [ ] record initialization sugar, e.g. `{ x := 1, y := 2 }`
|
||||||
- [ ] record update sugar, syntax TBD
|
- [ ] record update sugar, syntax TBD
|
||||||
|
- I think I'm going to hold off on this for now as it requires the type to elaborate. This ends up at the head of an app, which typically is inferred. We'd need a special case somewhere that infers its argument instead.
|
||||||
- [ ] Change `Ord` to be more like Idris - LT / EQ / GT (and entail equality)
|
- [ ] Change `Ord` to be more like Idris - LT / EQ / GT (and entail equality)
|
||||||
- [ ] Keep a `compare` function on `SortedMap` (like lean)
|
- [ ] Keep a `compare` function on `SortedMap` (like lean)
|
||||||
- [x] keymap for monaco
|
- [x] keymap for monaco
|
||||||
@@ -128,7 +128,7 @@ More comments in code! This is getting big enough that I need to re-find my bear
|
|||||||
- [x] there is some zero argument application in generated code
|
- [x] there is some zero argument application in generated code
|
||||||
- [x] get equality.newt to work
|
- [x] get equality.newt to work
|
||||||
- [x] broken again because I added J, probably need to constrain scrutinee to value
|
- [x] broken again because I added J, probably need to constrain scrutinee to value
|
||||||
- [ ] Bad FC for missing case in where clause (probably from ctx)
|
- [x] Bad FC for missing case in where clause (probably from ctx)
|
||||||
- [x] inline metas. Maybe zonk after TC/elab
|
- [x] inline metas. Maybe zonk after TC/elab
|
||||||
- [x] implicit patterns
|
- [x] implicit patterns
|
||||||
- [x] operators
|
- [x] operators
|
||||||
@@ -137,7 +137,7 @@ More comments in code! This is getting big enough that I need to re-find my bear
|
|||||||
- [x] matching on operators
|
- [x] matching on operators
|
||||||
- [x] top level
|
- [x] top level
|
||||||
- [x] case statements
|
- [x] case statements
|
||||||
- [ ] Lean / Agda ⟨ ⟩ (does agda do this or just lean?)
|
- [ ] Lean ⟨ ⟩ anonymous constructors
|
||||||
- [ ] Lean-like .map, etc? (resolve name in namespace of target type, etc)
|
- [ ] Lean-like .map, etc? (resolve name in namespace of target type, etc)
|
||||||
- [x] autos / typeclass resolution
|
- [x] autos / typeclass resolution
|
||||||
- [x] very primitive version in place, not higher order, search at end
|
- [x] very primitive version in place, not higher order, search at end
|
||||||
@@ -167,6 +167,11 @@ More comments in code! This is getting big enough that I need to re-find my bear
|
|||||||
- [ ] magic newtype? (drop them in codegen)
|
- [ ] magic newtype? (drop them in codegen)
|
||||||
- [x] vscode: syntax highlighting for String
|
- [x] vscode: syntax highlighting for String
|
||||||
- [ ] add `pop` or variant of `pfunc` that maps to an operator, giving the js operator and precedence on RHS
|
- [ ] add `pop` or variant of `pfunc` that maps to an operator, giving the js operator and precedence on RHS
|
||||||
|
- [ ] consider moving caselet, etc. desugaring out of the parser
|
||||||
|
- [ ] pattern matching lambda
|
||||||
|
- I kept wanting this in AoC and use it a lot in the newt code
|
||||||
|
- This conflicts with current code (unused?) that allows telescope information in lambdas
|
||||||
|
- For now, I'll implement `\case`
|
||||||
|
|
||||||
### Parsing
|
### Parsing
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
aoc2024/day20/eg.txt
|
|
||||||
base 84
|
|
||||||
part1 1
|
|
||||||
part2 285
|
|
||||||
aoc2024/day20/input.txt
|
|
||||||
base 9440
|
|
||||||
part1 1332
|
|
||||||
part2 987695
|
|
||||||
@@ -30,12 +30,12 @@ fail msg = \ cs => Left msg
|
|||||||
|
|
||||||
-- TODO, case builder isn't expanding Parser Unit to count lambdas
|
-- TODO, case builder isn't expanding Parser Unit to count lambdas
|
||||||
eof : Parser Unit
|
eof : Parser Unit
|
||||||
eof = \ cs => case cs of
|
eof = \case
|
||||||
Nil => Right (MkUnit, Nil)
|
Nil => Right (MkUnit, Nil)
|
||||||
_ => Left "expected eof"
|
_ => Left "expected eof"
|
||||||
|
|
||||||
satisfy : (Char → Bool) → Parser Char
|
satisfy : (Char → Bool) → Parser Char
|
||||||
satisfy pred = λ cs => case cs of
|
satisfy pred = \case
|
||||||
Nil => Left "unexpected EOF"
|
Nil => Left "unexpected EOF"
|
||||||
(c :: cs) => if pred c then Right (c, cs) else Left ("did not expect " ++ show c)
|
(c :: cs) => if pred c then Right (c, cs) else Left ("did not expect " ++ show c)
|
||||||
|
|
||||||
|
|||||||
1
aoc2024/SortedMap.newt
Symbolic link
1
aoc2024/SortedMap.newt
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../newt/SortedMap.newt
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
],
|
],
|
||||||
"onEnterRules": [
|
"onEnterRules": [
|
||||||
{
|
{
|
||||||
"beforeText": "\\b(where|of)$",
|
"beforeText": "\\b(where|of|case)$",
|
||||||
"action": { "indent": "indent" }
|
"action": { "indent": "indent" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
if (err && err.code !== 1)
|
if (err && err.code !== 1)
|
||||||
vscode.window.showErrorMessage(`newt error: ${err}`);
|
vscode.window.showErrorMessage(`newt error: ${err}`);
|
||||||
|
|
||||||
|
|
||||||
// extract errors and messages from stdout
|
// extract errors and messages from stdout
|
||||||
const lines = stdout.split("\n");
|
const lines = stdout.split("\n");
|
||||||
const diagnostics: vscode.Diagnostic[] = [];
|
const diagnostics: vscode.Diagnostic[] = [];
|
||||||
@@ -70,17 +69,13 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
console.log("top data", topData);
|
console.log("top data", topData);
|
||||||
}
|
}
|
||||||
const match = line.match(
|
const match = line.match(
|
||||||
/(INFO|ERROR) at (.*):\((\d+), (\d+)\):\s*(.*)/
|
/(INFO|WARN|ERROR) at (.*):\((\d+), (\d+)\):\s*(.*)/
|
||||||
);
|
);
|
||||||
if (match) {
|
if (match) {
|
||||||
let [_full, kind, file, line, column, message] = match;
|
let [_full, kind, file, line, column, message] = match;
|
||||||
// FIXME - check filename against current
|
|
||||||
console.log("********", file, fileName);
|
|
||||||
|
|
||||||
let lnum = Number(line);
|
let lnum = Number(line);
|
||||||
let cnum = Number(column);
|
let cnum = Number(column);
|
||||||
if (file !== fileName)
|
if (file !== fileName) lnum = cnum = 0;
|
||||||
lnum = cnum = 0;
|
|
||||||
|
|
||||||
let start = new vscode.Position(lnum, cnum);
|
let start = new vscode.Position(lnum, cnum);
|
||||||
// we don't have the full range, so grab the surrounding word
|
// we don't have the full range, so grab the surrounding word
|
||||||
@@ -88,21 +83,17 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
let range =
|
let range =
|
||||||
document.getWordRangeAtPosition(start) ??
|
document.getWordRangeAtPosition(start) ??
|
||||||
new vscode.Range(start, end);
|
new vscode.Range(start, end);
|
||||||
// heuristics to grab the entire message:
|
// anything indented after the ERROR/INFO line are part of
|
||||||
// anything indented
|
// the message
|
||||||
// Context:, or Goal: are part of PRINTME
|
while (lines[i + 1]?.match(/^( )/)) message += "\n" + lines[++i];
|
||||||
// unexpected / expecting appear in parse errors
|
|
||||||
while (lines[i + 1]?.match(/^( )/))
|
|
||||||
message += "\n" + lines[++i];
|
|
||||||
|
|
||||||
const severity =
|
let severity;
|
||||||
kind === "ERROR"
|
|
||||||
? vscode.DiagnosticSeverity.Error
|
if (kind === "ERROR") severity = vscode.DiagnosticSeverity.Error;
|
||||||
: vscode.DiagnosticSeverity.Information;
|
else if (kind === "WARN") severity = vscode.DiagnosticSeverity.Warning;
|
||||||
|
else severity = vscode.DiagnosticSeverity.Information;
|
||||||
const diag = new vscode.Diagnostic(range, message, severity);
|
const diag = new vscode.Diagnostic(range, message, severity);
|
||||||
if (kind === "ERROR" || lnum > 0)
|
if (kind === "ERROR" || lnum > 0) diagnostics.push(diag);
|
||||||
diagnostics.push(diag);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
diagnosticCollection.set(vscode.Uri.file(fileName), diagnostics);
|
diagnosticCollection.set(vscode.Uri.file(fileName), diagnostics);
|
||||||
@@ -116,9 +107,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
const editor = vscode.window.activeTextEditor;
|
const editor = vscode.window.activeTextEditor;
|
||||||
if (editor) {
|
if (editor) {
|
||||||
const document = editor.document;
|
const document = editor.document;
|
||||||
if (document.fileName.endsWith(".newt"))
|
if (document.fileName.endsWith(".newt")) checkDocument(document);
|
||||||
checkDocument(document);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -148,7 +137,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
vscode.languages.registerHoverProvider(
|
vscode.languages.registerHoverProvider(
|
||||||
{language: 'newt'},
|
{ language: "newt" },
|
||||||
{
|
{
|
||||||
provideHover(document, position, token) {
|
provideHover(document, position, token) {
|
||||||
if (!topData) return null;
|
if (!topData) return null;
|
||||||
@@ -161,7 +150,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new vscode.Hover(`${entry.name} : ${entry.type}`);
|
return new vscode.Hover(`${entry.name} : ${entry.type}`);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -171,17 +160,13 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
vscode.workspace.onDidSaveTextDocument((document) => {
|
vscode.workspace.onDidSaveTextDocument((document) => {
|
||||||
if (document.fileName.endsWith(".newt"))
|
if (document.fileName.endsWith(".newt"))
|
||||||
vscode.commands.executeCommand("newt-vscode.check");
|
vscode.commands.executeCommand("newt-vscode.check");
|
||||||
|
|
||||||
});
|
});
|
||||||
vscode.workspace.onDidOpenTextDocument((document) => {
|
vscode.workspace.onDidOpenTextDocument((document) => {
|
||||||
if (document.fileName.endsWith(".newt"))
|
if (document.fileName.endsWith(".newt"))
|
||||||
vscode.commands.executeCommand("newt-vscode.check");
|
vscode.commands.executeCommand("newt-vscode.check");
|
||||||
|
|
||||||
});
|
});
|
||||||
for (let document of vscode.workspace.textDocuments)
|
for (let document of vscode.workspace.textDocuments)
|
||||||
if (document.fileName.endsWith(".newt"))
|
if (document.fileName.endsWith(".newt")) checkDocument(document);
|
||||||
checkDocument(document);
|
|
||||||
|
|
||||||
|
|
||||||
context.subscriptions.push(diagnosticCollection);
|
context.subscriptions.push(diagnosticCollection);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,13 +40,7 @@ export let newtConfig: monaco.languages.LanguageConfiguration = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
beforeText: /\bwhere$/,
|
beforeText: /\b(where|of|case)$/,
|
||||||
action: {
|
|
||||||
indentAction: monaco.languages.IndentAction.Indent,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
beforeText: /\bof$/,
|
|
||||||
action: {
|
action: {
|
||||||
indentAction: monaco.languages.IndentAction.Indent,
|
indentAction: monaco.languages.IndentAction.Indent,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -789,7 +789,7 @@ checkWhere ctx decls body ty = do
|
|||||||
-- context could hold a Name -> Val (not Tm because levels) to help with that
|
-- context could hold a Name -> Val (not Tm because levels) to help with that
|
||||||
-- e.g. "go" -> (VApp ... (VApp (VRef "ns.go") ...)
|
-- e.g. "go" -> (VApp ... (VApp (VRef "ns.go") ...)
|
||||||
-- But I'll attempt letrec first
|
-- But I'll attempt letrec first
|
||||||
tm <- buildTree ctx' (MkProb clauses' vty)
|
tm <- buildTree ({ fc := defFC} ctx') (MkProb clauses' vty)
|
||||||
vtm <- eval ctx'.env CBN tm
|
vtm <- eval ctx'.env CBN tm
|
||||||
-- Should we run the rest with the definition in place?
|
-- Should we run the rest with the definition in place?
|
||||||
-- I'm wondering if switching from bind to define will mess with metas
|
-- I'm wondering if switching from bind to define will mess with metas
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ parseOp = do
|
|||||||
pure res
|
pure res
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO case let? We see to only have it for `do`
|
||||||
|
-- try (keyword "let" >> sym "(")
|
||||||
|
|
||||||
export
|
export
|
||||||
letExpr : Parser Raw
|
letExpr : Parser Raw
|
||||||
@@ -221,6 +222,13 @@ caseExpr = do
|
|||||||
alts <- startBlock $ someSame $ caseAlt
|
alts <- startBlock $ someSame $ caseAlt
|
||||||
pure $ RCase fc sc alts
|
pure $ RCase fc sc alts
|
||||||
|
|
||||||
|
caseLamExpr : Parser Raw
|
||||||
|
caseLamExpr = do
|
||||||
|
fc <- getPos
|
||||||
|
try ((keyword "\\" <|> keyword "λ") *> keyword "case")
|
||||||
|
alts <- startBlock $ someSame $ caseAlt
|
||||||
|
pure $ RLam fc (BI fc "$case" Explicit Many) $ RCase fc (RVar fc "$case") alts
|
||||||
|
|
||||||
doExpr : Parser Raw
|
doExpr : Parser Raw
|
||||||
doStmt : Parser DoStmt
|
doStmt : Parser DoStmt
|
||||||
|
|
||||||
@@ -247,7 +255,6 @@ doCaseLet = do
|
|||||||
pat <- typeExpr
|
pat <- typeExpr
|
||||||
sym ")"
|
sym ")"
|
||||||
keyword "="
|
keyword "="
|
||||||
-- arrow <- (False <$ keyword "=" <|> True <$ keyword "<-")
|
|
||||||
sc <- typeExpr
|
sc <- typeExpr
|
||||||
alts <- startBlock $ manySame $ sym "|" *> caseAlt
|
alts <- startBlock $ manySame $ sym "|" *> caseAlt
|
||||||
bodyFC <- getPos
|
bodyFC <- getPos
|
||||||
@@ -287,6 +294,7 @@ term' : Parser Raw
|
|||||||
term' = caseExpr
|
term' = caseExpr
|
||||||
<|> caseLet
|
<|> caseLet
|
||||||
<|> letExpr
|
<|> letExpr
|
||||||
|
<|> caseLamExpr
|
||||||
<|> lamExpr
|
<|> lamExpr
|
||||||
<|> doExpr
|
<|> doExpr
|
||||||
<|> ifThenElse
|
<|> ifThenElse
|
||||||
|
|||||||
Reference in New Issue
Block a user