mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 23:12:19 +00:00
Better testing infrastructure; Initial exports/imports/re-exports
This commit is contained in:
parent
00303fdf30
commit
ef859937a8
@ -257,8 +257,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.EXPORT:
|
case NodeKind.EXPORT:
|
||||||
if ((<ExportStatement>statement).path)
|
if ((<ExportStatement>statement).normalizedPath != null)
|
||||||
this.compileSourceByPath((<StringLiteralExpression>(<ExportStatement>statement).path).value, <StringLiteralExpression>(<ExportStatement>statement).path);
|
this.compileSourceByPath(<string>(<ExportStatement>statement).normalizedPath, <StringLiteralExpression>(<ExportStatement>statement).path);
|
||||||
if (noTreeShaking || isEntry)
|
if (noTreeShaking || isEntry)
|
||||||
this.compileExportStatement(<ExportStatement>statement);
|
this.compileExportStatement(<ExportStatement>statement);
|
||||||
break;
|
break;
|
||||||
@ -517,10 +517,10 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
const internalPath: string | null = statement.path ? statement.internalPath : statement.range.source.internalPath;
|
const internalPath: string | null = statement.path ? statement.internalPath : statement.range.source.internalPath;
|
||||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
||||||
const member: ExportMember = members[i];
|
const member: ExportMember = members[i];
|
||||||
const internalExportName: string = internalPath + PATH_DELIMITER + member.identifier.name;
|
const internalExportName: string = internalPath + PATH_DELIMITER + member.externalIdentifier.name;
|
||||||
const element: Element | null = <Element | null>this.program.exports.get(internalExportName);
|
const element: Element | null = <Element | null>this.program.exports.get(internalExportName);
|
||||||
if (!element)
|
if (!element) // reported in Program#initialize
|
||||||
throw new Error("unexpected missing element");
|
continue;
|
||||||
switch (element.kind) {
|
switch (element.kind) {
|
||||||
|
|
||||||
case ElementKind.CLASS_PROTOTYPE:
|
case ElementKind.CLASS_PROTOTYPE:
|
||||||
@ -1356,6 +1356,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
// TODO: sizeof, load, store, see program.ts/initializeBuiltins
|
// TODO: sizeof, load, store, see program.ts/initializeBuiltins
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: infer type arguments from parameter types if omitted
|
||||||
functionInstance = (<FunctionPrototype>element).resolveInclTypeArguments(expression.typeArguments, this.currentFunction.contextualTypeArguments, expression); // reports
|
functionInstance = (<FunctionPrototype>element).resolveInclTypeArguments(expression.typeArguments, this.currentFunction.contextualTypeArguments, expression); // reports
|
||||||
}
|
}
|
||||||
if (!functionInstance)
|
if (!functionInstance)
|
||||||
|
@ -48,6 +48,7 @@ export enum DiagnosticCode {
|
|||||||
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
|
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
|
||||||
Duplicate_identifier_0 = 2300,
|
Duplicate_identifier_0 = 2300,
|
||||||
Cannot_find_name_0 = 2304,
|
Cannot_find_name_0 = 2304,
|
||||||
|
Module_0_has_no_exported_member_1 = 2305,
|
||||||
Generic_type_0_requires_1_type_argument_s = 2314,
|
Generic_type_0_requires_1_type_argument_s = 2314,
|
||||||
Type_0_is_not_generic = 2315,
|
Type_0_is_not_generic = 2315,
|
||||||
Type_0_is_not_assignable_to_type_1 = 2322,
|
Type_0_is_not_assignable_to_type_1 = 2322,
|
||||||
@ -115,6 +116,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
|
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
|
||||||
case 2300: return "Duplicate identifier '{0}'.";
|
case 2300: return "Duplicate identifier '{0}'.";
|
||||||
case 2304: return "Cannot find name '{0}'.";
|
case 2304: return "Cannot find name '{0}'.";
|
||||||
|
case 2305: return "Module '{0}' has no exported member '{1}'.";
|
||||||
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
|
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
|
||||||
case 2315: return "Type '{0}' is not generic.";
|
case 2315: return "Type '{0}' is not generic.";
|
||||||
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
|
|
||||||
"Duplicate identifier '{0}'.": 2300,
|
"Duplicate identifier '{0}'.": 2300,
|
||||||
"Cannot find name '{0}'.": 2304,
|
"Cannot find name '{0}'.": 2304,
|
||||||
|
"Module '{0}' has no exported member '{1}'.": 2305,
|
||||||
"Generic type '{0}' requires {1} type argument(s).": 2314,
|
"Generic type '{0}' requires {1} type argument(s).": 2314,
|
||||||
"Type '{0}' is not generic.": 2315,
|
"Type '{0}' is not generic.": 2315,
|
||||||
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
||||||
|
@ -154,8 +154,8 @@ export abstract class DiagnosticEmitter {
|
|||||||
emitDiagnostic(code: DiagnosticCode, category: DiagnosticCategory, range: Range, arg0: string | null = null, arg1: string | null = null) {
|
emitDiagnostic(code: DiagnosticCode, category: DiagnosticCategory, range: Range, arg0: string | null = null, arg1: string | null = null) {
|
||||||
const message: DiagnosticMessage = DiagnosticMessage.create(code, category, arg0, arg1).withRange(range);
|
const message: DiagnosticMessage = DiagnosticMessage.create(code, category, arg0, arg1).withRange(range);
|
||||||
this.diagnostics.push(message);
|
this.diagnostics.push(message);
|
||||||
console.log(formatDiagnosticMessage(message, true, true)); // temporary
|
console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
|
||||||
console.log(new Error().stack);
|
// console.log(new Error().stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
error(code: DiagnosticCode, range: Range, arg0: string | null = null, arg1: string | null = null): void {
|
error(code: DiagnosticCode, range: Range, arg0: string | null = null, arg1: string | null = null): void {
|
||||||
|
@ -613,6 +613,14 @@ export class Module {
|
|||||||
return _BinaryenModuleValidate(this.ref) == 1;
|
return _BinaryenModuleValidate(this.ref) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toBinary(): Uint8Array {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
toText(): string {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
if (!this.ref) return; // sic
|
if (!this.ref) return; // sic
|
||||||
_BinaryenModuleDispose(this.ref);
|
_BinaryenModuleDispose(this.ref);
|
||||||
|
244
src/program.ts
244
src/program.ts
@ -1,6 +1,6 @@
|
|||||||
import { Target } from "./compiler";
|
import { Target } from "./compiler";
|
||||||
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants";
|
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants";
|
||||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, DiagnosticCategory } from "./diagnostics";
|
||||||
import { Type, typesToString } from "./types";
|
import { Type, typesToString } from "./types";
|
||||||
import { I64 } from "./util";
|
import { I64 } from "./util";
|
||||||
import {
|
import {
|
||||||
@ -40,19 +40,20 @@ import {
|
|||||||
VariableDeclaration,
|
VariableDeclaration,
|
||||||
VariableStatement,
|
VariableStatement,
|
||||||
|
|
||||||
hasModifier
|
hasModifier,
|
||||||
|
mangleInternalName
|
||||||
|
|
||||||
} from "./ast";
|
} from "./ast";
|
||||||
|
|
||||||
class QueuedExport {
|
class QueuedExport {
|
||||||
isForeign: bool;
|
isReExport: bool;
|
||||||
referencedName: string;
|
referencedName: string;
|
||||||
member: ExportMember;
|
member: ExportMember;
|
||||||
}
|
}
|
||||||
|
|
||||||
class QueuedImport {
|
class QueuedImport {
|
||||||
internalName: string;
|
internalName: string;
|
||||||
importName: string;
|
referencedName: string;
|
||||||
declaration: ImportDeclaration;
|
declaration: ImportDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,61 +131,63 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point queued exports should be resolvable
|
let element: Element | null;
|
||||||
for (let [exportName, queuedExport] of queuedExports) { // all file-level exports
|
|
||||||
if (queuedExport.isForeign) {
|
// queued imports should be resolvable now
|
||||||
const seen: Set<QueuedExport> = new Set();
|
for (let i: i32 = 0; i < queuedImports.length;) {
|
||||||
while (queuedExports.has(queuedExport.referencedName)) {
|
const queuedImport: QueuedImport = queuedImports[i];
|
||||||
queuedExport = <QueuedExport>queuedExports.get(queuedExport.referencedName);
|
element = this.tryResolveImport(queuedImport.referencedName, queuedExports);
|
||||||
if (seen.has(queuedExport))
|
if (element) {
|
||||||
break;
|
this.elements.set(queuedImport.internalName, element);
|
||||||
seen.add(queuedExport);
|
queuedImports.splice(i, 1);
|
||||||
}
|
} else {
|
||||||
if (this.exports.has(queuedExport.referencedName)) {
|
this.error(DiagnosticCode.Module_0_has_no_exported_member_1, queuedImport.declaration.range, (<ImportStatement>queuedImport.declaration.parent).path.value, queuedImport.declaration.externalIdentifier.name);
|
||||||
const element: Element = <Element>this.exports.get(queuedExport.referencedName);
|
++i;
|
||||||
if (!this.exports.has(exportName))
|
|
||||||
this.exports.set(exportName, element);
|
|
||||||
if (queuedExport.member.range.source.isEntry)
|
|
||||||
element.globalExportName = queuedExport.member.externalIdentifier.name;
|
|
||||||
} else
|
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.referencedName);
|
|
||||||
} else /* local */ {
|
|
||||||
if (this.elements.has(queuedExport.referencedName)) {
|
|
||||||
const element: Element = <Element>this.elements.get(queuedExport.referencedName);
|
|
||||||
if (!this.exports.has(exportName))
|
|
||||||
this.exports.set(exportName, element);
|
|
||||||
if (queuedExport.member.range.source.isEntry)
|
|
||||||
element.globalExportName = queuedExport.member.externalIdentifier.name;
|
|
||||||
} else
|
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.referencedName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point queued imports should be resolvable as well
|
// queued exports should be resolvable noww
|
||||||
for (let i: i32 = 0, k: i32 = queuedImports.length; i < k; ++i) {
|
for (let [exportName, queuedExport] of queuedExports) {
|
||||||
const queuedImport: QueuedImport = queuedImports[i];
|
let currentExport: QueuedExport | null = queuedExport;
|
||||||
const internalName: string = queuedImport.internalName;
|
do {
|
||||||
const seen: Set<QueuedExport> = new Set();
|
if (currentExport.isReExport) {
|
||||||
let importName: string = queuedImport.importName;
|
element = <Element | null>this.exports.get(currentExport.referencedName);
|
||||||
while (queuedExports.has(importName)) {
|
if (element) {
|
||||||
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(importName);
|
this.exports.set(exportName, element);
|
||||||
importName = queuedExport.referencedName;
|
break;
|
||||||
if (seen.has(queuedExport))
|
}
|
||||||
|
currentExport = <QueuedExport | null>queuedExports.get(currentExport.referencedName);
|
||||||
|
if (!currentExport)
|
||||||
|
this.error(DiagnosticCode.Module_0_has_no_exported_member_1, queuedExport.member.externalIdentifier.range, (<StringLiteralExpression>(<ExportStatement>queuedExport.member.parent).path).value, queuedExport.member.externalIdentifier.name);
|
||||||
|
} else {
|
||||||
|
element = <Element | null>this.elements.get(currentExport.referencedName);
|
||||||
|
if (element)
|
||||||
|
this.exports.set(exportName, element);
|
||||||
|
else
|
||||||
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.range, queuedExport.member.identifier.name);
|
||||||
break;
|
break;
|
||||||
seen.add(queuedExport);
|
|
||||||
}
|
|
||||||
if (this.exports.has(importName)) {
|
|
||||||
if (this.elements.has(internalName))
|
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, queuedImport.declaration.identifier.range, internalName);
|
|
||||||
else {
|
|
||||||
const element: Element = <Element>this.exports.get(importName);
|
|
||||||
this.elements.set(internalName, element);
|
|
||||||
}
|
}
|
||||||
} else
|
} while (currentExport);
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, queuedImport.declaration.externalIdentifier.range, importName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private tryResolveImport(referencedName: string, queuedExports: Map<string,QueuedExport>): Element | null {
|
||||||
|
let element: Element | null;
|
||||||
|
do {
|
||||||
|
element = <Element | null>this.exports.get(referencedName);
|
||||||
|
if (element)
|
||||||
|
return element;
|
||||||
|
const queuedExport: QueuedExport | null = <QueuedExport | null>queuedExports.get(referencedName);
|
||||||
|
if (!queuedExport)
|
||||||
|
return null;
|
||||||
|
if (queuedExport.isReExport) {
|
||||||
|
referencedName = queuedExport.referencedName;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return <Element | null>this.elements.get(queuedExport.referencedName);
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
private initializeClass(declaration: ClassDeclaration): void {
|
private initializeClass(declaration: ClassDeclaration): void {
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
if (this.elements.has(internalName)) {
|
if (this.elements.has(internalName)) {
|
||||||
@ -288,21 +291,79 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initializeExport(member: ExportMember, internalPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
private initializeExport(member: ExportMember, internalPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
||||||
const exportName: string = member.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name;
|
const externalName: string = member.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name;
|
||||||
if (queuedExports.has(exportName)) {
|
|
||||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, exportName);
|
if (this.exports.has(externalName)) {
|
||||||
|
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const queuedExport: QueuedExport = new QueuedExport();
|
|
||||||
|
let referencedName: string;
|
||||||
|
|
||||||
|
// export local element
|
||||||
if (internalPath == null) {
|
if (internalPath == null) {
|
||||||
queuedExport.isForeign = false;
|
referencedName = member.range.source.internalPath + PATH_DELIMITER + member.identifier.name;
|
||||||
queuedExport.referencedName = member.range.source.internalPath + PATH_DELIMITER + member.identifier.name;
|
|
||||||
|
// resolve right away if the element exists
|
||||||
|
if (this.elements.has(referencedName)) {
|
||||||
|
this.exports.set(externalName, <Element>this.elements.get(referencedName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise queue it
|
||||||
|
if (queuedExports.has(externalName)) {
|
||||||
|
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const queuedExport: QueuedExport = new QueuedExport();
|
||||||
|
queuedExport.isReExport = false;
|
||||||
|
queuedExport.referencedName = referencedName; // -> internal name
|
||||||
|
queuedExport.member = member;
|
||||||
|
queuedExports.set(externalName, queuedExport);
|
||||||
|
|
||||||
|
// export external element
|
||||||
} else {
|
} else {
|
||||||
queuedExport.isForeign = true;
|
referencedName = (<string>internalPath) + PATH_DELIMITER + member.externalIdentifier.name;
|
||||||
queuedExport.referencedName = (<string>internalPath) + PATH_DELIMITER + member.identifier.name;
|
|
||||||
|
// resolve right away if the export exists
|
||||||
|
if (this.exports.has(referencedName)) {
|
||||||
|
this.exports.set(externalName, <Element>this.exports.get(referencedName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk already known queued exports
|
||||||
|
const seen: Set<QueuedExport> = new Set();
|
||||||
|
while (queuedExports.has(referencedName)) {
|
||||||
|
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(referencedName);
|
||||||
|
if (queuedExport.isReExport) {
|
||||||
|
if (this.exports.has(queuedExport.referencedName)) {
|
||||||
|
this.exports.set(externalName, <Element>this.exports.get(referencedName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
referencedName = queuedExport.referencedName;
|
||||||
|
if (seen.has(queuedExport))
|
||||||
|
break;
|
||||||
|
seen.add(queuedExport);
|
||||||
|
} else {
|
||||||
|
if (this.elements.has(queuedExport.referencedName)) {
|
||||||
|
this.exports.set(externalName, <Element>this.elements.get(referencedName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise queue it
|
||||||
|
if (queuedExports.has(externalName)) {
|
||||||
|
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const queuedReExport: QueuedExport = new QueuedExport();
|
||||||
|
queuedReExport.isReExport = true;
|
||||||
|
queuedReExport.referencedName = referencedName; // -> export name
|
||||||
|
queuedReExport.member = member;
|
||||||
|
queuedExports.set(externalName, queuedReExport);
|
||||||
}
|
}
|
||||||
queuedExport.member = member;
|
|
||||||
queuedExports.set(exportName, queuedExport);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeFunction(declaration: FunctionDeclaration): void {
|
private initializeFunction(declaration: FunctionDeclaration): void {
|
||||||
@ -330,29 +391,48 @@ export class Program extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||||
const importName: string = internalPath + PATH_DELIMITER + declaration.externalIdentifier.name;
|
|
||||||
let resolvedImportName: string = importName;
|
|
||||||
const seen: Set<QueuedExport> = new Set();
|
|
||||||
while (queuedExports.has(resolvedImportName)) {
|
|
||||||
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(resolvedImportName);
|
|
||||||
resolvedImportName = queuedExport.referencedName;
|
|
||||||
if (seen.has(queuedExport))
|
|
||||||
break;
|
|
||||||
seen.add(queuedExport);
|
|
||||||
}
|
|
||||||
const internalName: string = declaration.internalName;
|
const internalName: string = declaration.internalName;
|
||||||
if (this.exports.has(resolvedImportName)) { // resolvable right away
|
if (this.elements.has(internalName)) {
|
||||||
if (this.elements.has(internalName))
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
return;
|
||||||
else
|
|
||||||
this.elements.set(internalName, <Element>this.exports.get(resolvedImportName));
|
|
||||||
} else { // points to yet unresolved export
|
|
||||||
const queuedImport: QueuedImport = new QueuedImport();
|
|
||||||
queuedImport.internalName = internalName;
|
|
||||||
queuedImport.importName = importName;
|
|
||||||
queuedImport.declaration = declaration;
|
|
||||||
queuedImports.push(queuedImport);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let referencedName: string = internalPath + PATH_DELIMITER + declaration.externalIdentifier.name;
|
||||||
|
|
||||||
|
// resolve right away if the export exists
|
||||||
|
if (this.exports.has(referencedName)) {
|
||||||
|
this.elements.set(internalName, <Element>this.exports.get(referencedName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk already known queued exports
|
||||||
|
const seen: Set<QueuedExport> = new Set();
|
||||||
|
while (queuedExports.has(referencedName)) {
|
||||||
|
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(referencedName);
|
||||||
|
if (queuedExport.isReExport) {
|
||||||
|
if (this.exports.has(queuedExport.referencedName)) {
|
||||||
|
this.elements.set(internalName, <Element>this.exports.get(referencedName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
referencedName = queuedExport.referencedName;
|
||||||
|
if (seen.has(queuedExport))
|
||||||
|
break;
|
||||||
|
seen.add(queuedExport);
|
||||||
|
} else {
|
||||||
|
if (this.elements.has(queuedExport.referencedName)) {
|
||||||
|
this.elements.set(internalName, <Element>this.elements.get(referencedName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise queue it
|
||||||
|
const queuedImport: QueuedImport = new QueuedImport();
|
||||||
|
queuedImport.internalName = internalName;
|
||||||
|
queuedImport.referencedName = referencedName;
|
||||||
|
queuedImport.declaration = declaration;
|
||||||
|
queuedImports.push(queuedImport);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeInterface(declaration: InterfaceDeclaration): void {
|
private initializeInterface(declaration: InterfaceDeclaration): void {
|
||||||
|
@ -724,10 +724,9 @@ export class Tokenizer extends DiagnosticEmitter {
|
|||||||
range(start: i32 = -1, end: i32 = -1): Range {
|
range(start: i32 = -1, end: i32 = -1): Range {
|
||||||
if (start < 0) {
|
if (start < 0) {
|
||||||
start = this.tokenPos;
|
start = this.tokenPos;
|
||||||
if (end < 0)
|
|
||||||
end = start;
|
|
||||||
} else if (end < 0)
|
|
||||||
end = this.pos;
|
end = this.pos;
|
||||||
|
} else if (end < 0)
|
||||||
|
end = start;
|
||||||
return new Range(this.source, start, end);
|
return new Range(this.source, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
tests/README.md
Normal file
29
tests/README.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Parser
|
||||||
|
------
|
||||||
|
|
||||||
|
Tests consist of a test case that is first parsed and then serialized again. The output is then compared to its respective fixture.
|
||||||
|
|
||||||
|
```
|
||||||
|
$> npm run test:parser [case name]
|
||||||
|
```
|
||||||
|
|
||||||
|
To recreate the fixtures:
|
||||||
|
|
||||||
|
```
|
||||||
|
$>npm run test:parser -- --create
|
||||||
|
```
|
||||||
|
|
||||||
|
Compiler
|
||||||
|
--------
|
||||||
|
|
||||||
|
Tests consist of a test case that is compiled to a module, converted to text format and then compared to its respective fixture.
|
||||||
|
|
||||||
|
```
|
||||||
|
$> npm run test:compiler [case name]
|
||||||
|
```
|
||||||
|
|
||||||
|
To recreate the fixtures:
|
||||||
|
|
||||||
|
```
|
||||||
|
$>npm run test:compiler -- --create
|
||||||
|
```
|
@ -1,6 +1,7 @@
|
|||||||
/// <reference path="../src/binaryen.d.ts" />
|
/// <reference path="../src/glue/binaryen.d.ts" />
|
||||||
|
|
||||||
import "../src/glue/js";
|
import "../src/glue/js";
|
||||||
import { Type, Module, MemorySegment, BinaryOp } from "../src/binaryen";
|
import { NativeType, Module, MemorySegment, BinaryOp } from "../src/module";
|
||||||
import { Target } from "../src/compiler";
|
import { Target } from "../src/compiler";
|
||||||
import { U64 } from "../src/util";
|
import { U64 } from "../src/util";
|
||||||
|
|
||||||
@ -11,33 +12,33 @@ mod.setMemory(1, Module.MAX_MEMORY_WASM32, [
|
|||||||
MemorySegment.create(new Uint8Array(4), U64.fromI32(12))
|
MemorySegment.create(new Uint8Array(4), U64.fromI32(12))
|
||||||
], Target.WASM32, "memory");
|
], Target.WASM32, "memory");
|
||||||
|
|
||||||
const add = mod.addFunctionType("iii", Type.I32, [ Type.I32, Type.I32 ]);
|
const add = mod.addFunctionType("iii", NativeType.I32, [ NativeType.I32, NativeType.I32 ]);
|
||||||
mod.addFunction("add", add, [], mod.createReturn(
|
mod.addFunction("add", add, [], mod.createReturn(
|
||||||
mod.createBinary(BinaryOp.AddI32,
|
mod.createBinary(BinaryOp.AddI32,
|
||||||
mod.createGetLocal(0, Type.I32),
|
mod.createGetLocal(0, NativeType.I32),
|
||||||
mod.createGetLocal(1, Type.I32)
|
mod.createGetLocal(1, NativeType.I32)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
mod.addExport("add", "add");
|
mod.addExport("add", "add");
|
||||||
|
|
||||||
const lit = mod.addFunctionType("I", Type.I64, []);
|
const lit = mod.addFunctionType("I", NativeType.I64, []);
|
||||||
mod.addFunction("lit", lit, [], mod.createReturn(
|
mod.addFunction("lit", lit, [], mod.createReturn(
|
||||||
mod.createI64(0, 0x80000000) // I64_MIN
|
mod.createI64(0, 0x80000000) // I64_MIN
|
||||||
));
|
));
|
||||||
mod.addExport("lit", "lit");
|
mod.addExport("lit", "lit");
|
||||||
|
|
||||||
mod.addGlobal("42", Type.I32, false, mod.createI32(42));
|
mod.addGlobal("42", NativeType.I32, false, mod.createI32(42));
|
||||||
|
|
||||||
const aSwitch = mod.addFunctionType("ii", Type.I32, [ Type.I32 ]);
|
const aSwitch = mod.addFunctionType("ii", NativeType.I32, [ NativeType.I32 ]);
|
||||||
const rl = mod.createRelooper();
|
const rl = mod.createRelooper();
|
||||||
const b0 = rl.addBlockWithSwitch(mod.createNop(), mod.createGetLocal(0, Type.I32));
|
const b0 = rl.addBlockWithSwitch(mod.createNop(), mod.createGetLocal(0, NativeType.I32));
|
||||||
let b1, b2, b3;
|
let b1, b2, b3;
|
||||||
rl.addBranchForSwitch(b0, b2 = rl.addBlock(mod.createReturn(mod.createI32(1))), [1]); // indexed branch
|
rl.addBranchForSwitch(b0, b2 = rl.addBlock(mod.createReturn(mod.createI32(1))), [1]); // indexed branch
|
||||||
rl.addBranchForSwitch(b0, b3 = rl.addBlock(mod.createReturn(mod.createI32(2))), [2]); // indexed branch
|
rl.addBranchForSwitch(b0, b3 = rl.addBlock(mod.createReturn(mod.createI32(2))), [2]); // indexed branch
|
||||||
rl.addBranch(b0, b1 = rl.addBlock(mod.createDrop(mod.createI32(0)))); // default branch
|
rl.addBranch(b0, b1 = rl.addBlock(mod.createDrop(mod.createI32(0)))); // default branch
|
||||||
rl.addBranch(b1, b2);
|
rl.addBranch(b1, b2);
|
||||||
|
|
||||||
mod.addFunction("aSwitch", aSwitch, [ Type.I32 ], mod.createBlock(null, [
|
mod.addFunction("aSwitch", aSwitch, [ NativeType.I32 ], mod.createBlock(null, [
|
||||||
rl.renderAndDispose(b0, 1),
|
rl.renderAndDispose(b0, 1),
|
||||||
mod.createUnreachable()
|
mod.createUnreachable()
|
||||||
]));
|
]));
|
||||||
|
@ -1,72 +1,74 @@
|
|||||||
|
/// <reference path="../src/glue/binaryen.d.ts" />
|
||||||
|
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
import * as chalk from "chalk";
|
||||||
|
import * as glob from "glob";
|
||||||
|
|
||||||
import "../src/glue/js";
|
import "../src/glue/js";
|
||||||
import { Compiler } from "../src/compiler";
|
import { Compiler } from "../src/compiler";
|
||||||
|
import { Module } from "../src/module";
|
||||||
import { Parser } from "../src/parser";
|
import { Parser } from "../src/parser";
|
||||||
|
import { diff } from "./util/diff";
|
||||||
|
|
||||||
/* const files: Map<string,string> = new Map([
|
// TODO: implement properly in module.ts
|
||||||
["main", `import { Test as TestAlias } from "./a"; export { TestAlias } from "./d"; if (1) {} export const a: i32 = 123;`],
|
import * as binaryen from "binaryen";
|
||||||
["a", `export { Test } from "./b";`],
|
Module.prototype.toText = function(): string {
|
||||||
["b", `export { Test } from "./c";`],
|
let old: any = (<any>binaryen)["print"];
|
||||||
["c", `export enum Test { ONE = 1, TWO = 1 + 1 }`],
|
let ret: string = "";
|
||||||
["d", `export { Test as TestAlias } from "./b";`]
|
(<any>binaryen)["print"] = function(x: string): void { ret += x + "\n" };
|
||||||
]); */
|
_BinaryenModulePrint(this.ref);
|
||||||
|
(<any>binaryen)["print"] = old;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const files: Map<string,string> = new Map([
|
const isCreate = process.argv[2] === "--create";
|
||||||
["main",
|
const filter = process.argv.length > 2 && !isCreate ? "*" + process.argv[2] + "*.ts" : "*.ts";
|
||||||
`
|
|
||||||
function add(a: i32, b: i32): i32 { return a + b; };
|
glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
|
||||||
export { add };
|
if (filename.charAt(0) == "_" || filename.endsWith(".fixture.ts"))
|
||||||
export { sub as notadd } from "../other";
|
return;
|
||||||
2+3;
|
|
||||||
export function switchMe(n: i32): i32 {
|
console.log("Testing compiler/" + filename);
|
||||||
switch (n) {
|
|
||||||
case 0:
|
const parser = new Parser();
|
||||||
return 0;
|
const sourceText = fs.readFileSync(__dirname + "/compiler/" + filename, { encoding: "utf8" });
|
||||||
default:
|
parser.parseFile(sourceText, filename, true);
|
||||||
return 2;
|
let nextFile;
|
||||||
case 1:
|
while ((nextFile = parser.nextFile()) !== null) {
|
||||||
return 1;
|
let nextSourceText: string;
|
||||||
case -1:
|
try {
|
||||||
break;
|
nextSourceText = fs.readFileSync(path.join(__dirname, "compiler", nextFile + ".ts"), { encoding: "utf8" });
|
||||||
|
} catch (e) {
|
||||||
|
nextSourceText = fs.readFileSync(path.join(__dirname, "compiler", nextFile, "index.ts"), { encoding: "utf8" });
|
||||||
}
|
}
|
||||||
return -1;
|
parser.parseFile(nextSourceText, nextFile, false);
|
||||||
}
|
}
|
||||||
import { sub } from "../other";
|
const program = parser.finish();
|
||||||
export function doCall(): void {
|
const module = Compiler.compile(program);
|
||||||
sub(1,2);
|
const actual = module.toText() + "(;\n[program.elements]\n " + iterate(program.elements.keys()).join("\n ") + "\n[program.exports]\n " + iterate(program.exports.keys()).join("\n ") + "\n;)\n";
|
||||||
|
const fixture = path.basename(filename, ".ts") + ".wast";
|
||||||
|
|
||||||
|
if (isCreate) {
|
||||||
|
fs.writeFileSync(__dirname + "/compiler/" + fixture, actual, { encoding: "utf8" });
|
||||||
|
console.log("Created\n");
|
||||||
|
} else {
|
||||||
|
const expected = fs.readFileSync(__dirname + "/compiler/" + fixture, { encoding: "utf8" });
|
||||||
|
const diffs = diff("compiler/" + fixture, expected, actual);
|
||||||
|
if (diffs !== null) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
console.log(diffs);
|
||||||
|
} else {
|
||||||
|
console.log("No changes\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export function doNaN(value: f32): bool {
|
});
|
||||||
return isNaN<f32>(0.3);
|
|
||||||
|
function iterate<T>(it: IterableIterator<T>): T[] {
|
||||||
|
let current: IteratorResult<T>;
|
||||||
|
var arr: T[] = [];
|
||||||
|
while ((current = it.next()) && !current.done) {
|
||||||
|
arr.push(current.value);
|
||||||
}
|
}
|
||||||
export function doRotl(value: u16): u8 {
|
return arr;
|
||||||
return rotl<i32>(value, 2);
|
}
|
||||||
}
|
|
||||||
`],
|
|
||||||
|
|
||||||
["../other",
|
|
||||||
`
|
|
||||||
export function sub(a: i32, b: i32): i32 { return a - b + c; };
|
|
||||||
let c: i32 = 42 >> 31;
|
|
||||||
1+2;
|
|
||||||
`]
|
|
||||||
]);
|
|
||||||
|
|
||||||
const parser = new Parser();
|
|
||||||
|
|
||||||
parser.parseFile(<string>files.get("main"), "main", true);
|
|
||||||
do {
|
|
||||||
let nextFile = parser.nextFile();
|
|
||||||
if (!nextFile)
|
|
||||||
break;
|
|
||||||
if (!files.has(nextFile))
|
|
||||||
throw new Error("file not found: " + nextFile);
|
|
||||||
parser.parseFile(<string>files.get(nextFile), nextFile, false);
|
|
||||||
} while(true);
|
|
||||||
const program = parser.finish();
|
|
||||||
const compiler = new Compiler(program);
|
|
||||||
const module = compiler.compile();
|
|
||||||
// console.log(program.elements.keys());
|
|
||||||
|
|
||||||
// module.optimize();
|
|
||||||
module.validate();
|
|
||||||
if (!module.noEmit)
|
|
||||||
_BinaryenModulePrint(module.ref);
|
|
15
tests/compiler/export.ts
Normal file
15
tests/compiler/export.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export function add(a: i32, b: i32): i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sub(a: i32, b: i32): i32 {
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { sub as renamed_sub };
|
||||||
|
|
||||||
|
export let a: i32 = 1;
|
||||||
|
|
||||||
|
let b: i32 = 2;
|
||||||
|
|
||||||
|
export { b as renamed_b };
|
52
tests/compiler/export.wast
Normal file
52
tests/compiler/export.wast
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
(module
|
||||||
|
(type $iii (func (param i32 i32) (result i32)))
|
||||||
|
(global $export/a i32 (i32.const 1))
|
||||||
|
(global $export/b i32 (i32.const 2))
|
||||||
|
(memory $0 1)
|
||||||
|
(data (i32.const 4) "\08\00\00\00")
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $export/sub (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.sub
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(;
|
||||||
|
[program.elements]
|
||||||
|
clz
|
||||||
|
ctz
|
||||||
|
popcnt
|
||||||
|
rotl
|
||||||
|
rotr
|
||||||
|
abs
|
||||||
|
ceil
|
||||||
|
copysign
|
||||||
|
floor
|
||||||
|
max
|
||||||
|
min
|
||||||
|
nearest
|
||||||
|
sqrt
|
||||||
|
trunc
|
||||||
|
isNaN
|
||||||
|
isFinite
|
||||||
|
export/add
|
||||||
|
export/sub
|
||||||
|
export/a
|
||||||
|
export/b
|
||||||
|
[program.exports]
|
||||||
|
export/add
|
||||||
|
export/renamed_sub
|
||||||
|
export/a
|
||||||
|
export/renamed_b
|
||||||
|
;)
|
3
tests/compiler/import.ts
Normal file
3
tests/compiler/import.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { add, renamed_sub as sub, a, renamed_b as b } from "./export";
|
||||||
|
|
||||||
|
add(a, b) + sub(b, a);
|
72
tests/compiler/import.wast
Normal file
72
tests/compiler/import.wast
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
(module
|
||||||
|
(type $iii (func (param i32 i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(global $export/a i32 (i32.const 1))
|
||||||
|
(global $export/b i32 (i32.const 2))
|
||||||
|
(memory $0 1)
|
||||||
|
(data (i32.const 4) "\08\00\00\00")
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $export/sub (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.sub
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 2 ;) (type $v)
|
||||||
|
(drop
|
||||||
|
(i32.add
|
||||||
|
(call $export/add
|
||||||
|
(get_global $export/a)
|
||||||
|
(get_global $export/b)
|
||||||
|
)
|
||||||
|
(call $export/sub
|
||||||
|
(get_global $export/b)
|
||||||
|
(get_global $export/a)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(;
|
||||||
|
[program.elements]
|
||||||
|
clz
|
||||||
|
ctz
|
||||||
|
popcnt
|
||||||
|
rotl
|
||||||
|
rotr
|
||||||
|
abs
|
||||||
|
ceil
|
||||||
|
copysign
|
||||||
|
floor
|
||||||
|
max
|
||||||
|
min
|
||||||
|
nearest
|
||||||
|
sqrt
|
||||||
|
trunc
|
||||||
|
isNaN
|
||||||
|
isFinite
|
||||||
|
export/add
|
||||||
|
export/sub
|
||||||
|
export/a
|
||||||
|
export/b
|
||||||
|
import/add
|
||||||
|
import/sub
|
||||||
|
import/a
|
||||||
|
import/b
|
||||||
|
[program.exports]
|
||||||
|
export/add
|
||||||
|
export/renamed_sub
|
||||||
|
export/a
|
||||||
|
export/renamed_b
|
||||||
|
;)
|
7
tests/compiler/reexport.ts
Normal file
7
tests/compiler/reexport.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export { add, renamed_sub } from "./export";
|
||||||
|
|
||||||
|
import { add as imported_add, renamed_sub as imported_sub } from "./export";
|
||||||
|
|
||||||
|
export { imported_add as renamed_add, imported_sub as rerenamed_sub };
|
||||||
|
|
||||||
|
imported_add(1, 2) + imported_sub(3, 4);
|
72
tests/compiler/reexport.wast
Normal file
72
tests/compiler/reexport.wast
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
(module
|
||||||
|
(type $iii (func (param i32 i32) (result i32)))
|
||||||
|
(type $v (func))
|
||||||
|
(memory $0 1)
|
||||||
|
(data (i32.const 4) "\08\00\00\00")
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(start $start)
|
||||||
|
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.add
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $export/sub (; 1 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||||
|
(return
|
||||||
|
(i32.sub
|
||||||
|
(get_local $0)
|
||||||
|
(get_local $1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func $start (; 2 ;) (type $v)
|
||||||
|
(drop
|
||||||
|
(i32.add
|
||||||
|
(call $export/add
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.const 2)
|
||||||
|
)
|
||||||
|
(call $export/sub
|
||||||
|
(i32.const 3)
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(;
|
||||||
|
[program.elements]
|
||||||
|
clz
|
||||||
|
ctz
|
||||||
|
popcnt
|
||||||
|
rotl
|
||||||
|
rotr
|
||||||
|
abs
|
||||||
|
ceil
|
||||||
|
copysign
|
||||||
|
floor
|
||||||
|
max
|
||||||
|
min
|
||||||
|
nearest
|
||||||
|
sqrt
|
||||||
|
trunc
|
||||||
|
isNaN
|
||||||
|
isFinite
|
||||||
|
export/add
|
||||||
|
export/sub
|
||||||
|
export/a
|
||||||
|
export/b
|
||||||
|
reexport/imported_add
|
||||||
|
reexport/imported_sub
|
||||||
|
[program.exports]
|
||||||
|
export/add
|
||||||
|
export/renamed_sub
|
||||||
|
export/a
|
||||||
|
export/renamed_b
|
||||||
|
reexport/add
|
||||||
|
reexport/renamed_sub
|
||||||
|
reexport/renamed_add
|
||||||
|
reexport/rerenamed_sub
|
||||||
|
;)
|
40
tests/parser.ts
Normal file
40
tests/parser.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import * as fs from "fs";
|
||||||
|
import * as chalk from "chalk";
|
||||||
|
import * as glob from "glob";
|
||||||
|
|
||||||
|
import "../src/glue/js";
|
||||||
|
import { Parser } from "../src/parser";
|
||||||
|
import { diff } from "./util/diff";
|
||||||
|
|
||||||
|
const isCreate = process.argv[2] === "--create";
|
||||||
|
const filter = process.argv.length > 2 && !isCreate ? "*" + process.argv[2] + "*.ts" : "**.ts";
|
||||||
|
|
||||||
|
glob.sync(filter, { cwd: __dirname + "/parser" }).forEach(filename => {
|
||||||
|
if (filename.charAt(0) == "_" || filename.endsWith(".fixture.ts"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
console.log("Testing parser/" + filename);
|
||||||
|
|
||||||
|
const parser = new Parser();
|
||||||
|
const sourceText = fs.readFileSync(__dirname + "/parser/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, "");
|
||||||
|
parser.parseFile(sourceText, filename, true);
|
||||||
|
|
||||||
|
var sb: string[] = [];
|
||||||
|
parser.program.sources[0].serialize(sb);
|
||||||
|
const actual = sb.join("");
|
||||||
|
const fixture = filename + ".fixture.ts";
|
||||||
|
|
||||||
|
if (isCreate) {
|
||||||
|
fs.writeFileSync(__dirname + "/parser/" + fixture, actual, { encoding: "utf8" });
|
||||||
|
console.log("Created\n");
|
||||||
|
} else {
|
||||||
|
const expected = fs.readFileSync(__dirname + "/parser/" + fixture, { encoding: "utf8" });
|
||||||
|
const diffs = diff("parser/" + fixture, expected, actual);
|
||||||
|
if (diffs !== null) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
console.log(diffs);
|
||||||
|
} else {
|
||||||
|
console.log("No changes\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
12
tests/parser/class.ts.fixture.ts
Normal file
12
tests/parser/class.ts.fixture.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export class Test<T> {
|
||||||
|
instanceFunction(): void {
|
||||||
|
}
|
||||||
|
static staticFunction(): void {
|
||||||
|
}
|
||||||
|
get instanceGetter(): i32 {
|
||||||
|
}
|
||||||
|
static set staticSetter(v: i32): i32 {
|
||||||
|
}
|
||||||
|
instanceField: i32;
|
||||||
|
static staticField: i32;
|
||||||
|
}
|
3
tests/parser/do.ts.fixture.ts
Normal file
3
tests/parser/do.ts.fixture.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
do {
|
||||||
|
;
|
||||||
|
} while (a != b);
|
10
tests/parser/enum.ts.fixture.ts
Normal file
10
tests/parser/enum.ts.fixture.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export const enum A {
|
||||||
|
B = 1,
|
||||||
|
C,
|
||||||
|
D = 3
|
||||||
|
}
|
||||||
|
enum E {
|
||||||
|
F,
|
||||||
|
G = 1 + 2,
|
||||||
|
H = 3 * 4
|
||||||
|
}
|
@ -1,42 +0,0 @@
|
|||||||
0;
|
|
||||||
1;
|
|
||||||
2;
|
|
||||||
3;
|
|
||||||
4;
|
|
||||||
5;
|
|
||||||
6;
|
|
||||||
7;
|
|
||||||
8;
|
|
||||||
9;
|
|
||||||
// 0x0;
|
|
||||||
// 0x1;
|
|
||||||
// 0x2;
|
|
||||||
// 0x3;
|
|
||||||
// 0x4;
|
|
||||||
// 0x5;
|
|
||||||
// 0x6;
|
|
||||||
// 0x7;
|
|
||||||
// 0x8;
|
|
||||||
// 0x9;
|
|
||||||
// 0xA;
|
|
||||||
// 0xB;
|
|
||||||
// 0xC;
|
|
||||||
// 0xD;
|
|
||||||
// 0xE;
|
|
||||||
// 0xF;
|
|
||||||
// 0xa;
|
|
||||||
// 0xb;
|
|
||||||
// 0xc;
|
|
||||||
// 0xd;
|
|
||||||
// 0xe;
|
|
||||||
// 0xf;
|
|
||||||
// 0o0;
|
|
||||||
// 0o1;
|
|
||||||
// 0o2;
|
|
||||||
// 0o3;
|
|
||||||
// 0o4;
|
|
||||||
// 0o5;
|
|
||||||
// 0o6;
|
|
||||||
// 0o7;
|
|
||||||
// 0b0;
|
|
||||||
// 0b1;
|
|
9
tests/parser/for.ts.fixture.ts
Normal file
9
tests/parser/for.ts.fixture.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
for (let i: i32 = 0; i < 10; ++i) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 10; ++i) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
;
|
||||||
|
}
|
7
tests/parser/function.ts.fixture.ts
Normal file
7
tests/parser/function.ts.fixture.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
function simple(): void {
|
||||||
|
}
|
||||||
|
function typeparams<T, V extends T>(a: V | null = null): void {
|
||||||
|
}
|
||||||
|
@decorator()
|
||||||
|
function withdecorator(): void {
|
||||||
|
}
|
@ -1,41 +0,0 @@
|
|||||||
import * as fs from "fs";
|
|
||||||
import * as diff from "diff";
|
|
||||||
import * as chalk from "chalk";
|
|
||||||
import * as glob from "glob";
|
|
||||||
|
|
||||||
import "../../src/glue/js";
|
|
||||||
import { NodeKind, ExpressionStatement } from "../../src/ast";
|
|
||||||
import { Parser } from "../../src/parser";
|
|
||||||
|
|
||||||
const filter = process.argv.length > 2 ? "*" + process.argv[2] + "*.ts" : "**.ts";
|
|
||||||
|
|
||||||
const files = glob.sync(filter, { cwd: __dirname + "/fixtures" });
|
|
||||||
files.forEach(filename => {
|
|
||||||
if (filename.charAt(0) == "_") return;
|
|
||||||
const isTree = filename.indexOf(".tree.") >= 0;
|
|
||||||
const parser = new Parser();
|
|
||||||
const text = fs.readFileSync(__dirname + "/fixtures/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, "");
|
|
||||||
parser.parseFile(text, filename, true);
|
|
||||||
var sb: string[] = [];
|
|
||||||
parser.program.sources[0].serialize(sb);
|
|
||||||
const actual = sb.join("");
|
|
||||||
const expected = isTree ? text : text.replace(/^\s+/mg, "");
|
|
||||||
const diffs = diff.diffLines(expected, actual);
|
|
||||||
let changed = false;
|
|
||||||
diffs.forEach(part => {
|
|
||||||
if (part.added || part.removed)
|
|
||||||
changed = true;
|
|
||||||
});
|
|
||||||
if (changed) { // print it
|
|
||||||
console.log("Differences in " + filename + ":");
|
|
||||||
diffs.forEach(part => {
|
|
||||||
if (part.added || part.removed)
|
|
||||||
changed = true;
|
|
||||||
process.stderr.write((part.added ? chalk.default.green : part.removed ? chalk.default.red : chalk.default.grey)(part.value));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log("No differences in " + filename + ".");
|
|
||||||
}
|
|
||||||
// parser.program.initialize();
|
|
||||||
// console.log(parser.program.names);
|
|
||||||
});
|
|
42
tests/parser/literals.ts
Normal file
42
tests/parser/literals.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
0;
|
||||||
|
1;
|
||||||
|
2;
|
||||||
|
3;
|
||||||
|
4;
|
||||||
|
5;
|
||||||
|
6;
|
||||||
|
7;
|
||||||
|
8;
|
||||||
|
9;
|
||||||
|
0x0;
|
||||||
|
0x1;
|
||||||
|
0x2;
|
||||||
|
0x3;
|
||||||
|
0x4;
|
||||||
|
0x5;
|
||||||
|
0x6;
|
||||||
|
0x7;
|
||||||
|
0x8;
|
||||||
|
0x9;
|
||||||
|
0xA;
|
||||||
|
0xB;
|
||||||
|
0xC;
|
||||||
|
0xD;
|
||||||
|
0xE;
|
||||||
|
0xF;
|
||||||
|
0xa;
|
||||||
|
0xb;
|
||||||
|
0xc;
|
||||||
|
0xd;
|
||||||
|
0xe;
|
||||||
|
0xf;
|
||||||
|
0o0;
|
||||||
|
0o1;
|
||||||
|
0o2;
|
||||||
|
0o3;
|
||||||
|
0o4;
|
||||||
|
0o5;
|
||||||
|
0o6;
|
||||||
|
0o7;
|
||||||
|
0b0;
|
||||||
|
0b1;
|
42
tests/parser/literals.ts.fixture.ts
Normal file
42
tests/parser/literals.ts.fixture.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
0;
|
||||||
|
1;
|
||||||
|
2;
|
||||||
|
3;
|
||||||
|
4;
|
||||||
|
5;
|
||||||
|
6;
|
||||||
|
7;
|
||||||
|
8;
|
||||||
|
9;
|
||||||
|
0;
|
||||||
|
1;
|
||||||
|
2;
|
||||||
|
3;
|
||||||
|
4;
|
||||||
|
5;
|
||||||
|
6;
|
||||||
|
7;
|
||||||
|
8;
|
||||||
|
9;
|
||||||
|
10;
|
||||||
|
11;
|
||||||
|
12;
|
||||||
|
13;
|
||||||
|
14;
|
||||||
|
15;
|
||||||
|
10;
|
||||||
|
11;
|
||||||
|
12;
|
||||||
|
13;
|
||||||
|
14;
|
||||||
|
15;
|
||||||
|
0;
|
||||||
|
1;
|
||||||
|
2;
|
||||||
|
3;
|
||||||
|
4;
|
||||||
|
5;
|
||||||
|
6;
|
||||||
|
7;
|
||||||
|
0;
|
||||||
|
1;
|
9
tests/parser/while.ts.fixture.ts
Normal file
9
tests/parser/while.ts.fixture.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
while (1) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
while ("str") {
|
||||||
|
;
|
||||||
|
}
|
30
tests/util/diff.ts
Normal file
30
tests/util/diff.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import * as JsDiff from "diff";
|
||||||
|
import * as chalk from "chalk";
|
||||||
|
|
||||||
|
export function diff(filename: string, expected: string, actual: string): string | null {
|
||||||
|
const diff = JsDiff.structuredPatch(filename, filename, expected, actual, "expected", "actual", { context: 2 });
|
||||||
|
if (!diff.hunks.length)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
const ret = [];
|
||||||
|
ret.push('--- ' + diff.oldHeader);
|
||||||
|
ret.push('+++ ' + diff.newHeader);
|
||||||
|
|
||||||
|
for (let i = 0; i < diff.hunks.length; i++) {
|
||||||
|
const hunk = diff.hunks[i];
|
||||||
|
ret.push(
|
||||||
|
'@@ -' + hunk.oldStart + ',' + hunk.oldLines
|
||||||
|
+ ' +' + hunk.newStart + ',' + hunk.newLines
|
||||||
|
+ ' @@'
|
||||||
|
);
|
||||||
|
ret.push.apply(ret, hunk.lines.map(line =>
|
||||||
|
line.charAt(0) === "+"
|
||||||
|
? chalk.default.green(line)
|
||||||
|
: line.charAt(0) === "-"
|
||||||
|
? line = chalk.default.red(line)
|
||||||
|
: line
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.join('\n') + '\n';
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user