Add a POC test runner for the parser and scanner

This commit is contained in:
Sam Vervaeck 2020-06-03 09:19:30 +02:00
parent 99f2944e1c
commit 2a0e24213d
6 changed files with 113 additions and 12 deletions

View file

@ -163,7 +163,7 @@ export interface BoltBracketed extends BoltPunctuated {}
export interface BoltSourceFile extends BoltSyntax, SourceFile {
elements: BoltSourceElement[],
pkg: Package,
pkg: Package | null,
}
export interface BoltQualName extends BoltSyntax {

View file

@ -575,7 +575,7 @@ type BoltBracketedChild = never;
export class BoltSourceFile extends SyntaxBase {
parentNode: null | BoltSourceFileParent = null;
kind: SyntaxKind.BoltSourceFile = SyntaxKind.BoltSourceFile;
constructor(public elements: BoltSourceElement[], public pkg: Package, span: TextSpan | null = null) { super(span); }
constructor(public elements: BoltSourceElement[], public pkg: Package | null, span: TextSpan | null = null) { super(span); }
*getChildNodes(): IterableIterator<BoltSourceFileChild> { for (let element of this.elements)
yield element; }
}
@ -1991,7 +1991,7 @@ export function createBoltBraced(text: string, span: TextSpan | null = null): Bo
export function createBoltBracketed(text: string, span: TextSpan | null = null): BoltBracketed { return new BoltBracketed(text, span); }
export function createBoltSourceFile(elements: BoltSourceElement[], pkg: Package, span: TextSpan | null = null): BoltSourceFile { return new BoltSourceFile(elements, pkg, span); }
export function createBoltSourceFile(elements: BoltSourceElement[], pkg: Package | null, span: TextSpan | null = null): BoltSourceFile { return new BoltSourceFile(elements, pkg, span); }
export function createBoltQualName(isAbsolute: boolean, modulePath: BoltIdentifier[], name: BoltSymbol, span: TextSpan | null = null): BoltQualName { return new BoltQualName(isAbsolute, modulePath, name, span); }

View file

@ -62,14 +62,16 @@ function firstIndexOfNonEmpty(str: string) {
return j
}
export class DiagnosticWriter {
export class DiagnosticIndex {
constructor(private fd: number) {
}
private diagnostics = new Array<Diagnostic>();
public add(diagnostic: Diagnostic) {
fs.writeSync(this.fd, JSON.stringify(diagnostic) + '\n');
this.diagnostics.push(diagnostic);
}
public getAllDiagnostics(): IterableIterator<Diagnostic> {
return this.diagnostics[Symbol.iterator]();
}
}

51
src/marktest.ts Normal file
View file

@ -0,0 +1,51 @@
import { SyntaxKind, Syntax } from "./ast";
import { serialize, Json } from "./util";
import { DiagnosticIndex } from "./diagnostics";
import { Test } from "@marktest/core"
export async function scanner(test: Test): Promise<Json> {
const { DiagnosticIndex } = await import("./diagnostics")
const diagnostics = new DiagnosticIndex;
const { Scanner } = await import("./scanner");
const scanner = new Scanner(test.file, test.text, test.startPos);
const tokens = []
while (true) {
const token = scanner.scan();
if (token.kind === SyntaxKind.EndOfFile) {
break;
}
tokens.push(token);
}
return serialize({
diagnostics,
tokens,
});
}
export async function parser(test: Test): Promise<Json> {
const kind = test.args.kind ?? 'SourceFile';
const { Scanner } = await import("./scanner")
const { Parser } = await import("./parser");
const diagnostics = new DiagnosticIndex;
const parser = new Parser();
const tokens = new Scanner(test.file, test.text);
let results: Syntax[];
switch (kind) {
case 'SourceFile':
results = [ parser.parseSourceFile(tokens) ];
break;
case 'SourceElements':
results = parser.parseSourceElements(tokens);
break;
default:
throw new Error(`I did not know how to parse ${kind}`)
}
return serialize({
diagnostics,
results,
})
}
export function check(test: Test): Json {
// TODO
}

View file

@ -1534,7 +1534,7 @@ export class Parser {
// return lhs
//}
public parseSourceFile(tokens: BoltTokenStream, pkg: Package): BoltSourceFile {
public parseSourceFile(tokens: BoltTokenStream, pkg: Package | null = null): BoltSourceFile {
const elements = this.parseSourceElements(tokens);
const t1 = tokens.peek();
assertToken(t1, SyntaxKind.EndOfFile);

View file

@ -7,6 +7,7 @@ import moment from "moment"
import chalk from "chalk"
import { LOG_DATETIME_FORMAT } from "./constants"
import { E_CANDIDATE_FUNCTION_REQUIRES_THIS_PARAMETER } from "./diagnostics"
import { isPrimitive } from "util"
export function isPowerOf(x: number, n: number):boolean {
const a = Math.log(x) / Math.log(n);
return Math.pow(a, n) == x;
@ -152,7 +153,7 @@ function isObjectLike(value: any) {
return typeof value === 'object' && value !== null;
}
export function isPlainObject(value: any): value is object {
export function isPlainObject(value: any): value is MapLike<any> {
if (!isObjectLike(value) || getTag(value) != '[object Object]') {
return false
}
@ -166,10 +167,16 @@ export function isPlainObject(value: any): value is object {
return Object.getPrototypeOf(value) === proto
}
export function mapValues<T extends object, R extends PropertyKey>(obj: T, func: (value: keyof T) => R): { [K in keyof T]: R } {
export function* values<T extends object>(obj: T): IterableIterator<T[keyof T]> {
for (const key of Object.keys(obj)) {
yield obj[key as keyof T];
}
}
export function mapValues<T extends object, R>(obj: T, func: (value: T[keyof T]) => R): { [K in keyof T]: R } {
const newObj: any = {}
for (const key of Object.keys(obj)) {
newObj[key] = func((obj as any)[key]);
newObj[key as keyof T] = func(obj[key as keyof T]);
}
return newObj;
}
@ -183,6 +190,47 @@ export function prettyPrint(value: any): string {
return value.toString();
}
export type Newable<T> = {
new(...args: any): T;
}
export const serializeTag = Symbol('serializer tag');
const serializableClasses = new Map<string, Newable<{ [serializeTag](): Json }>>();
export function serialize(value: any): Json {
if (isPrimitive(value)) {
return {
type: 'primitive',
value,
}
} else if (isObjectLike(value)) {
if (isPlainObject(value)) {
return {
type: 'object',
elements: [...map(values(value), element => serialize(element))]
};
} else if (value[serializeTag] !== undefined
&& typeof(value[serializeTag]) === 'function'
&& typeof(value.constructor.name) === 'string') {
return {
type: 'class',
name: value.constructor.name,
data: value[serializeTag](),
}
} else {
throw new Error(`Could not serialize ${value}: it was a non-primitive object and has no serializer tag.`)
}
} else if (Array.isArray(value)) {
return {
type: 'array',
elements: value.map(serialize)
}
} else {
throw new Error(`Could not serialize ${value}: is was not recognised as a primitive type, an object, a class instance, or an array.`)
}
}
export type TransparentProxy<T> = T & { updateHandle(value: T): void }
export function createTransparentProxy<T extends object>(value: T): TransparentProxy<T> {