add \case sugar and editor support. fix symlink

This commit is contained in:
2024-12-28 16:02:31 -08:00
parent a6e68ac2a2
commit 23a95f70f5
9 changed files with 40 additions and 55 deletions

13
TODO.md
View File

@@ -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

View File

@@ -1,8 +0,0 @@
aoc2024/day20/eg.txt
base 84
part1 1
part2 285
aoc2024/day20/input.txt
base 9440
part1 1332
part2 987695

View File

@@ -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
View File

@@ -0,0 +1 @@
../newt/SortedMap.newt

View File

@@ -33,7 +33,7 @@
], ],
"onEnterRules": [ "onEnterRules": [
{ {
"beforeText": "\\b(where|of)$", "beforeText": "\\b(where|of|case)$",
"action": { "indent": "indent" } "action": { "indent": "indent" }
}, },
{ {

View File

@@ -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);
} }

View File

@@ -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,
}, },

View File

@@ -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

View File

@@ -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