Improve preprocessor error reporting

This commit is contained in:
Tony Garnock-Jones 2021-12-11 16:49:12 +01:00
parent 8888ac3fe9
commit 3edb680c19
7 changed files with 54 additions and 22 deletions

View File

@ -6,7 +6,7 @@ import {
laxRead, itemText,
Items, Pattern, Templates, Substitution, TokenType,
SourceMap, CodeWriter, TemplateFunction, Token, SpanIndex,
SourceMap, CodeWriter, TemplateFunction, Token, SpanIndex, match, TokenBase, getRange, Pos,
} from '../syntax/index.js';
import {
SyndicateParser, SyndicateTypedParser,
@ -29,7 +29,7 @@ export function stripShebang(items: Items): Items {
export type ModuleType ='es6' | 'require' | 'global';
export type ErrorSink = (message: string) => void;
export type ErrorSink = (message: string, start: Pos | undefined, end: Pos | undefined) => void;
export interface CompileOptions {
source: string,
@ -52,17 +52,17 @@ export class ExpansionContext {
readonly parser: SyndicateParser;
readonly moduleType: ModuleType;
readonly typescript: boolean;
readonly emitError: (message: string) => void;
readonly errorEmitter: ErrorSink;
nextIdNumber = 0;
constructor(moduleType: ModuleType,
typescript: boolean,
emitError: ErrorSink)
errorEmitter: ErrorSink)
{
this.parser = typescript ? new SyndicateTypedParser : new SyndicateParser();
this.moduleType = moduleType;
this.typescript = typescript;
this.emitError = emitError;
this.errorEmitter = errorEmitter;
}
quasiRandomId(): string {
@ -72,6 +72,10 @@ export class ExpansionContext {
argDecl(t: TemplateFunction, name: Substitution, type: Substitution): Items {
return (this.typescript) ? t`${name}: ${type}` : t`${name}`;
}
emitError(m: string, loc: TokenBase) {
this.errorEmitter(m, loc.start, loc.end);
}
}
function stringifyId(i: Identifier): Items {
@ -99,7 +103,8 @@ function binderTypeGuard(ctx: ExpansionContext, t: TemplateFunction): (binder: B
case 'any':
return bind;
default:
ctx.emitError(`Cannot emit guard for binding of type: ${JSON.stringify(typeText)}`);
ctx.emitError(`Cannot emit guard for binding of type: ${JSON.stringify(typeText)}`,
getRange(binder.type));
return bind; /* act as if "any", for now */
}
}

View File

@ -2,13 +2,13 @@
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import {
Token, Item, Items,
Token, Items,
Pattern,
foldItems, match, anonymousTemplate as template, commaJoin,
scope, bind, seq, alt, upTo, atom, atomString, group,
repeat, option, withoutSpace, map, mapm, rest, discard,
value, succeed, fail, separatedOrTerminatedBy, anything, not
value, succeed, fail, separatedOrTerminatedBy, not, TokenBase
} from '../syntax/index.js';
import * as Matcher from '../syntax/matcher.js';

View File

@ -9,6 +9,10 @@ export interface Pos {
fixed?: boolean;
}
export function formatPos(p?: Pos): string {
return p ? `${p.name ?? '?'}:${p.line}:${p.column}` : '?';
}
export function startPos(name: string | null): Pos {
return { line: 1, column: 0, pos: 0, name };
}

View File

@ -34,6 +34,14 @@ export type Items = Array<Item>;
export type GroupInProgress = Omit<Group, 'end'>;
export function getRange(t: Item | Items): TokenBase {
if (Array.isArray(t)) {
return { start: t[0].start, end: t[t.length - 1].end, synthetic: true };
} else {
return t;
}
}
export function finishGroup(g: GroupInProgress, end: Pos): Group {
return { ... g, end };
}

View File

@ -7,7 +7,7 @@ import fs from 'fs';
import path from 'path';
import { glob } from 'glob';
import { compile } from '@syndicate-lang/compiler';
import { compile, Syntax } from '@syndicate-lang/compiler';
import { dataURL, sourceMappingComment} from './util.js';
export type ModuleChoice = 'es6' | 'require' | 'global';
@ -117,7 +117,7 @@ export function main(argv: string[]) {
argv => argv)
.argv);
const collectedErrors: Array<string> = [];
let errorCount = 0;
const rename = makeRenamer(options.outputDirectory ?? '',
options.rootDirectory ?? '.',
@ -146,9 +146,9 @@ export function main(argv: string[]) {
runtime: options.runtime,
module: options.module,
typescript: options.typed,
emitError: m => {
console.error(m);
collectedErrors.push(m);
emitError: (m, start, end) => {
console.error(`${Syntax.formatPos(start)}-${Syntax.formatPos(end)}: ${m}`);
errorCount++;
}
});
map.sourcesContent = [source];
@ -168,7 +168,7 @@ export function main(argv: string[]) {
}
}
if (collectedErrors.length > 0) {
throw new Error(`Compilation failed with ${collectedErrors.length} error(s).`);
if (errorCount > 0) {
throw new Error(`Compilation failed with ${errorCount} error(s).`);
}
}

View File

@ -11,6 +11,7 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
interface SyndicateInfo {
sourceFile: ts.SourceFile;
originalSource: string;
diagnostics: ts.DiagnosticWithLocation[];
targetToSourceMap: Syntax.SpanIndex<Syntax.Token>;
sourceToTargetMap: Syntax.SpanIndex<number>;
}
@ -159,20 +160,30 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
onError?.(`Could not read input file ${fileName}`);
return undefined;
}
const diagnostics:
Array<{ message: string, start?: Syntax.Pos, end?: Syntax.Pos }> = [];
console.log('Syndicate compiling', fileName);
const { text: expandedText, targetToSourceMap, sourceToTargetMap } = compile({
source: inputText,
name: fileName,
typescript: true,
emitError: m => {
console.error(m);
onError?.(m);
emitError: (message, start, end) => {
console.error(`${Syntax.formatPos(start)}-${Syntax.formatPos(end)}: ${message}`);
diagnostics.push({ message, start, end });
},
});
const sf = ts.createSourceFile(fileName, expandedText, languageVersion, true);
syndicateInfo.set(fileName, {
sourceFile: sf,
originalSource: inputText,
diagnostics: diagnostics.map(({ message, start, end }) => ({
category: ts.DiagnosticCategory.Error,
code: 99999,
file: sf,
start: start?.pos ?? 0,
length: Math.max(0, (end?.pos ?? 0) - (start?.pos ?? 0)),
messageText: message,
})),
targetToSourceMap,
sourceToTargetMap,
});
@ -243,7 +254,11 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
getSyntacticDiagnostics(fileName: string): ts.DiagnosticWithLocation[] {
const ds = this.inner.getSyntacticDiagnostics(fileName);
return withFileName(fileName, () => ds, (fixup) => fixup.diagnostics(ds));
return withFileName(fileName, () => ds, (fixup) => {
const fixedUp = fixup.diagnostics(ds);
fixedUp.push(... fixup.info.diagnostics);
return fixedUp;
});
}
getSemanticDiagnostics(fileName: string): ts.Diagnostic[] {

View File

@ -8,7 +8,7 @@ import crypto from 'crypto';
import fs from 'fs';
import path from 'path';
import { compile } from '@syndicate-lang/compiler';
import { compile, Syntax } from '@syndicate-lang/compiler';
import { SpanIndex, Token } from '@syndicate-lang/compiler/lib/syntax';
export type CommandLineArguments = {
@ -150,8 +150,8 @@ function runBuildOnce(options: CommandLineArguments, toWatch = new ToWatch()) {
source: inputText,
name: fileName,
typescript: true,
emitError: m => {
console.error(m);
emitError: (m, start, end) => {
console.error(`${Syntax.formatPos(start)}-${Syntax.formatPos(end)}: ${m}`);
onError?.(m);
},
});