Improve preprocessor error reporting
This commit is contained in:
parent
8888ac3fe9
commit
3edb680c19
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
@ -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).`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[] {
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue