diff --git a/src/parser2.ts b/src/parser2.ts index bb0a2ca..c9a65a8 100644 --- a/src/parser2.ts +++ b/src/parser2.ts @@ -35,6 +35,12 @@ export function parse( // Parser for evaluating Notcl scripts +export class ParseError extends Error { + constructor(message: string, public pos: number) { + super(message); + } +} + type TokenType = | "newline" | "whitespace" @@ -47,8 +53,7 @@ type TokenType = | "backslash" | "comment" | "text" - | "EOF" - | "ERROR"; + | "EOF"; type Token = [TokenType, string, number]; @@ -81,9 +86,9 @@ class WipScript { return this.wipWord.length == 0 && this.wipCommand.length == 0; } - addWordPiece(piece: InterpolatedPiece, pos?: number) { + addWordPiece(piece: InterpolatedPiece, pos: number) { if (this.endOfWordError) { - throw new Error(this.endOfWordError); + throw new ParseError(this.endOfWordError, pos); } if (this.startOfWord()) { this.wordPos = pos; @@ -137,13 +142,14 @@ class Parser { } } - return (this.next = ["ERROR", "Token not matched", startPos]); + throw new ParseError("Token not matched", startPos); } expect(type: TokenType) { if (this.next[0] != type) { - throw new Error( - `Expected ${type}, found ${this.next[0]} (${this.next[1]})` + throw new ParseError( + `Expected ${type}, found ${this.next[0]} (${this.next[1]})`, + this.next[2] ); } } @@ -175,7 +181,7 @@ class Parser { case "[": { this.advance(); const script = this.parseScript(); - wip.addWordPiece({ script }); + wip.addWordPiece({ script }, pos); this.expect("]"); break; } @@ -200,8 +206,6 @@ class Parser { case "backslash": this.advance(); continue; - case "ERROR": - throw new Error(chars); default: continue; } @@ -223,10 +227,11 @@ class Parser { case "quote": throw new Error(`Unhandled case: ${type} (${chars})`); - case "ERROR": - throw new Error(chars); default: - throw new Error(`Unhandled case: ${type satisfies never} (${chars})`); + throw new ParseError( + `Unhandled case: ${type satisfies never} (${chars})`, + pos + ); } this.advance(); @@ -261,17 +266,19 @@ class Parser { wip.addWordPiece({ text: "\n" }, pos); break; default: - throw new Error(`Unknown backslash escape: ${chars}`); + throw new ParseError(`Unknown backslash escape: ${chars}`, pos); } break; case "EOF": - throw new Error( - "Reached end of input while parsing a backslash escape" + throw new ParseError( + "Reached end of input while parsing a backslash escape", + pos ); - case "ERROR": - throw new Error(chars); default: - throw new Error(`Unhandled case: ${type satisfies never} (${chars})`); + throw new ParseError( + `Unhandled case: ${type satisfies never} (${chars})`, + pos + ); } } @@ -297,9 +304,10 @@ class Parser { case "}": return wip; case "EOF": - throw new Error("Reached end of input while parsing a brace word"); - case "ERROR": - throw new Error(chars); + throw new ParseError( + "Reached end of input while parsing a brace word", + pos + ); default: wip += chars; }