Make scanner work with exceptions

This commit is contained in:
Sam Vervaeck 2022-08-31 13:37:26 +02:00
parent 48f1b0f45c
commit eac4279a5e
3 changed files with 35 additions and 12 deletions

View file

@ -8,7 +8,7 @@ import fs from "fs"
import yargs from "yargs"
import { Diagnostics, UnexpectedCharDiagnostic, UnexpectedTokenDiagnostic } from "../diagnostics"
import { Punctuator, Scanner } from "../scanner"
import { Punctuator, ScanError, Scanner } from "../scanner"
import { ParseError, Parser } from "../parser"
import { Checker } from "../checker"
import { TextFile } from "../cst"
@ -44,11 +44,15 @@ yargs
try {
sourceFile = parser.parseSourceFile();
} catch (error) {
if (!(error instanceof ParseError)) {
throw error;
if (error instanceof ParseError) {
diagnostics.add(new UnexpectedTokenDiagnostic(error.file, error.actual, error.expected));
return;
}
diagnostics.add(new UnexpectedTokenDiagnostic(error.file, error.actual, error.expected));
return;
if (error instanceof ScanError) {
diagnostics.add(new UnexpectedCharDiagnostic(error.file, error.position, error.actual));
return;
}
throw error;
}
sourceFile.setParents();
//debug(sourceFile.toJSON());

View file

@ -40,7 +40,7 @@ export class UnexpectedCharDiagnostic {
const endPos = this.position.clone();
endPos.advance(this.actual);
return ANSI_FG_RED + ANSI_BOLD + 'error: ' + ANSI_RESET
+ `unexpeced character '${this.actual}'.\n\n`
+ `unexpeced character sequence '${this.actual}'.\n\n`
+ printExcerpt(this.file, new TextRange(this.position, endPos)) + '\n';
}

View file

@ -28,6 +28,8 @@ import {
Constructor,
Integer,
TextFile,
Dot,
DotDot,
} from "./cst"
import { Diagnostics, UnexpectedCharDiagnostic } from "./diagnostics"
import { Stream, BufferedStream, assert } from "./util";
@ -64,7 +66,17 @@ function isOperatorPart(ch: string): boolean {
return /\+-*\/%^&|$<>!?=/.test(ch);
}
class ScanError extends Error {}
export class ScanError extends Error {
public constructor(
public file: TextFile,
public position: TextPosition,
public actual: string,
) {
super(`Uncaught scanner error`);
}
}
export class Scanner extends BufferedStream<Token> {
@ -174,8 +186,7 @@ export class Scanner extends BufferedStream<Token> {
case '\'': contents += '\''; break;
case '\"': contents += '\"'; break;
default:
this.diagnostics.add(new UnexpectedCharDiagnostic(this.file, startPos, c1));
throw new ScanError();
throw new ScanError(this.file, startPos, c1);
}
escaping = false;
} else {
@ -203,7 +214,16 @@ export class Scanner extends BufferedStream<Token> {
case '}': return new RBrace(startPos);
case ',': return new Comma(startPos);
case ':': return new Colon(startPos);
case '.': return new Dot(startPos);
case '.': {
const dots = c0 + this.takeWhile(ch => ch === '.');
if (dots === '.') {
return new Dot(startPos);
} else if (dots === '..') {
return new DotDot(startPos);
} else {
throw new ScanError(this.file, startPos, dots);
}
}
case '+':
case '-':
@ -336,8 +356,7 @@ export class Scanner extends BufferedStream<Token> {
default:
// Nothing matched, so the current character is unrecognisable
this.diagnostics.add(new UnexpectedCharDiagnostic(this.file, startPos, c0));
throw new ScanError();
throw new ScanError(this.file, startPos, c0);
}
}