Make scanner work with exceptions
This commit is contained in:
parent
48f1b0f45c
commit
eac4279a5e
3 changed files with 35 additions and 12 deletions
|
@ -8,7 +8,7 @@ import fs from "fs"
|
||||||
import yargs from "yargs"
|
import yargs from "yargs"
|
||||||
|
|
||||||
import { Diagnostics, UnexpectedCharDiagnostic, UnexpectedTokenDiagnostic } from "../diagnostics"
|
import { Diagnostics, UnexpectedCharDiagnostic, UnexpectedTokenDiagnostic } from "../diagnostics"
|
||||||
import { Punctuator, Scanner } from "../scanner"
|
import { Punctuator, ScanError, Scanner } from "../scanner"
|
||||||
import { ParseError, Parser } from "../parser"
|
import { ParseError, Parser } from "../parser"
|
||||||
import { Checker } from "../checker"
|
import { Checker } from "../checker"
|
||||||
import { TextFile } from "../cst"
|
import { TextFile } from "../cst"
|
||||||
|
@ -44,11 +44,15 @@ yargs
|
||||||
try {
|
try {
|
||||||
sourceFile = parser.parseSourceFile();
|
sourceFile = parser.parseSourceFile();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!(error instanceof ParseError)) {
|
if (error instanceof ParseError) {
|
||||||
throw error;
|
diagnostics.add(new UnexpectedTokenDiagnostic(error.file, error.actual, error.expected));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
diagnostics.add(new UnexpectedTokenDiagnostic(error.file, error.actual, error.expected));
|
if (error instanceof ScanError) {
|
||||||
return;
|
diagnostics.add(new UnexpectedCharDiagnostic(error.file, error.position, error.actual));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
sourceFile.setParents();
|
sourceFile.setParents();
|
||||||
//debug(sourceFile.toJSON());
|
//debug(sourceFile.toJSON());
|
||||||
|
|
|
@ -40,7 +40,7 @@ export class UnexpectedCharDiagnostic {
|
||||||
const endPos = this.position.clone();
|
const endPos = this.position.clone();
|
||||||
endPos.advance(this.actual);
|
endPos.advance(this.actual);
|
||||||
return ANSI_FG_RED + ANSI_BOLD + 'error: ' + ANSI_RESET
|
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';
|
+ printExcerpt(this.file, new TextRange(this.position, endPos)) + '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@ import {
|
||||||
Constructor,
|
Constructor,
|
||||||
Integer,
|
Integer,
|
||||||
TextFile,
|
TextFile,
|
||||||
|
Dot,
|
||||||
|
DotDot,
|
||||||
} from "./cst"
|
} from "./cst"
|
||||||
import { Diagnostics, UnexpectedCharDiagnostic } from "./diagnostics"
|
import { Diagnostics, UnexpectedCharDiagnostic } from "./diagnostics"
|
||||||
import { Stream, BufferedStream, assert } from "./util";
|
import { Stream, BufferedStream, assert } from "./util";
|
||||||
|
@ -64,7 +66,17 @@ function isOperatorPart(ch: string): boolean {
|
||||||
return /\+-*\/%^&|$<>!?=/.test(ch);
|
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> {
|
export class Scanner extends BufferedStream<Token> {
|
||||||
|
|
||||||
|
@ -174,8 +186,7 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
case '\'': contents += '\''; break;
|
case '\'': contents += '\''; break;
|
||||||
case '\"': contents += '\"'; break;
|
case '\"': contents += '\"'; break;
|
||||||
default:
|
default:
|
||||||
this.diagnostics.add(new UnexpectedCharDiagnostic(this.file, startPos, c1));
|
throw new ScanError(this.file, startPos, c1);
|
||||||
throw new ScanError();
|
|
||||||
}
|
}
|
||||||
escaping = false;
|
escaping = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,7 +214,16 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
case '}': return new RBrace(startPos);
|
case '}': return new RBrace(startPos);
|
||||||
case ',': return new Comma(startPos);
|
case ',': return new Comma(startPos);
|
||||||
case ':': return new Colon(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 '+':
|
||||||
case '-':
|
case '-':
|
||||||
|
@ -336,8 +356,7 @@ export class Scanner extends BufferedStream<Token> {
|
||||||
default:
|
default:
|
||||||
|
|
||||||
// Nothing matched, so the current character is unrecognisable
|
// Nothing matched, so the current character is unrecognisable
|
||||||
this.diagnostics.add(new UnexpectedCharDiagnostic(this.file, startPos, c0));
|
throw new ScanError(this.file, startPos, c0);
|
||||||
throw new ScanError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue