2017-09-28 13:08:25 +02:00
|
|
|
import { Target } from "./compiler";
|
|
|
|
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
|
|
|
import { hasModifier } from "./parser";
|
2017-10-02 12:52:15 +02:00
|
|
|
import { Type } from "./types";
|
2017-09-28 13:08:25 +02:00
|
|
|
import {
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
ModifierKind,
|
2017-09-28 13:08:25 +02:00
|
|
|
Node,
|
|
|
|
NodeKind,
|
2017-10-02 12:52:15 +02:00
|
|
|
Source,
|
2017-09-28 13:08:25 +02:00
|
|
|
|
|
|
|
ClassDeclaration,
|
|
|
|
DeclarationStatement,
|
|
|
|
EnumDeclaration,
|
|
|
|
EnumValueDeclaration,
|
2017-09-29 17:25:02 +02:00
|
|
|
ExportMember,
|
|
|
|
ExportStatement,
|
2017-09-28 13:08:25 +02:00
|
|
|
FieldDeclaration,
|
|
|
|
FunctionDeclaration,
|
|
|
|
ImportDeclaration,
|
|
|
|
ImportStatement,
|
|
|
|
InterfaceDeclaration,
|
|
|
|
MethodDeclaration,
|
|
|
|
NamespaceDeclaration,
|
|
|
|
Statement,
|
|
|
|
VariableDeclaration,
|
|
|
|
VariableStatement
|
|
|
|
|
|
|
|
} from "./ast";
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
class QueuedExport {
|
|
|
|
importName: string;
|
|
|
|
member: ExportMember;
|
|
|
|
}
|
|
|
|
|
|
|
|
class QueuedImport {
|
2017-10-02 12:52:15 +02:00
|
|
|
internalName: string;
|
2017-09-29 17:25:02 +02:00
|
|
|
importName: string;
|
|
|
|
declaration: ImportDeclaration;
|
|
|
|
}
|
|
|
|
|
2017-09-28 13:08:25 +02:00
|
|
|
export class Program extends DiagnosticEmitter {
|
|
|
|
|
|
|
|
sources: Source[];
|
|
|
|
diagnosticsOffset: i32 = 0;
|
|
|
|
target: Target = Target.WASM32;
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
/** Internal map of names to declarations. */
|
2017-09-28 13:08:25 +02:00
|
|
|
names: Map<string,DeclarationStatement> = new Map();
|
2017-10-02 12:52:15 +02:00
|
|
|
/** Separate map of internal type names to declarations. */
|
2017-09-28 13:08:25 +02:00
|
|
|
types: Map<string,Type> = new Map();
|
2017-10-02 12:52:15 +02:00
|
|
|
/** Separate map of internal export names to declarations. */
|
2017-09-29 17:25:02 +02:00
|
|
|
exports: Map<string,DeclarationStatement> = new Map();
|
2017-09-28 13:08:25 +02:00
|
|
|
|
|
|
|
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
|
|
|
super(diagnostics);
|
|
|
|
this.sources = new Array();
|
|
|
|
}
|
|
|
|
|
|
|
|
initialize(target: Target): void {
|
|
|
|
this.target = target;
|
2017-10-02 12:52:15 +02:00
|
|
|
|
2017-09-28 13:08:25 +02:00
|
|
|
initializeBasicTypes(this.types, target);
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
const queuedExports: Map<string,QueuedExport> = new Map();
|
|
|
|
const queuedImports: QueuedImport[] = new Array();
|
2017-09-28 13:08:25 +02:00
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
// build initial lookup maps of internal and export names to declarations
|
2017-09-28 13:08:25 +02:00
|
|
|
for (let i: i32 = 0, k: i32 = this.sources.length; i < k; ++i) {
|
|
|
|
const source: Source = this.sources[i];
|
|
|
|
const statements: Statement[] = source.statements;
|
|
|
|
for (let j: i32 = 0, l: i32 = statements.length; j < l; ++j) {
|
|
|
|
const statement: Statement = statements[j];
|
|
|
|
switch (statement.kind) {
|
|
|
|
|
|
|
|
case NodeKind.CLASS:
|
|
|
|
this.initializeClass(<ClassDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.ENUM:
|
|
|
|
this.initializeEnum(<EnumDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
case NodeKind.EXPORT:
|
2017-10-02 12:52:15 +02:00
|
|
|
this.initializeExports(<ExportStatement>statement, queuedExports);
|
2017-09-29 17:25:02 +02:00
|
|
|
break;
|
|
|
|
|
2017-09-28 13:08:25 +02:00
|
|
|
case NodeKind.FUNCTION:
|
|
|
|
this.initializeFunction(<FunctionDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.IMPORT:
|
2017-10-02 12:52:15 +02:00
|
|
|
this.initializeImports(<ImportStatement>statement, queuedExports, queuedImports);
|
2017-09-28 13:08:25 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.INTERFACE:
|
|
|
|
this.initializeInterface(<InterfaceDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.NAMESPACE:
|
|
|
|
this.initializeNamespace(<NamespaceDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.VARIABLE:
|
|
|
|
this.initializeVariables(<VariableStatement>statement);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
// at this point queued exports should be resolvable
|
|
|
|
for (let [exportName, queuedExport] of queuedExports.entries()) {
|
2017-09-29 17:25:02 +02:00
|
|
|
const seen: Set<QueuedExport> = new Set();
|
2017-10-02 12:52:15 +02:00
|
|
|
while (queuedExports.has(queuedExport.importName)) {
|
|
|
|
queuedExport = <QueuedExport>queuedExports.get(queuedExport.importName);
|
|
|
|
if (seen.has(queuedExport))
|
2017-09-29 17:25:02 +02:00
|
|
|
break;
|
2017-10-02 12:52:15 +02:00
|
|
|
seen.add(queuedExport);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
2017-10-02 12:52:15 +02:00
|
|
|
if (this.exports.has(queuedExport.importName))
|
|
|
|
this.addExport(exportName, <DeclarationStatement>this.exports.get(queuedExport.importName));
|
2017-09-29 17:25:02 +02:00
|
|
|
else
|
2017-10-02 12:52:15 +02:00
|
|
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.externalIdentifier.range, queuedExport.importName);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
// at this point also queued imports should be resolvable
|
|
|
|
for (let i: i32 = 0, k: i32 = queuedImports.length; i < k; ++i) {
|
|
|
|
const queuedImport: QueuedImport = queuedImports[i];
|
|
|
|
const internalName: string = queuedImport.internalName;
|
|
|
|
let importName: string = queuedImport.importName;
|
2017-09-29 17:25:02 +02:00
|
|
|
const seen: Set<QueuedExport> = new Set();
|
2017-10-02 12:52:15 +02:00
|
|
|
while (queuedExports.has(importName)) {
|
|
|
|
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(importName);
|
|
|
|
importName = queuedExport.importName;
|
|
|
|
if (seen.has(queuedExport))
|
2017-09-29 17:25:02 +02:00
|
|
|
break;
|
2017-10-02 12:52:15 +02:00
|
|
|
seen.add(queuedExport);
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
2017-09-29 17:25:02 +02:00
|
|
|
if (this.exports.has(importName)) {
|
2017-10-02 12:52:15 +02:00
|
|
|
if (this.names.has(internalName))
|
|
|
|
this.error(DiagnosticCode.Duplicate_identifier_0, queuedImport.declaration.identifier.range, internalName);
|
2017-09-29 17:25:02 +02:00
|
|
|
else {
|
|
|
|
const declaration: DeclarationStatement = <DeclarationStatement>this.exports.get(importName);
|
2017-10-02 12:52:15 +02:00
|
|
|
this.names.set(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
// TODO: also mirror (non-private) member names?
|
2017-10-02 12:52:15 +02:00
|
|
|
// wouldn't it be better to look up members based on their parent?
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
|
|
|
} else
|
2017-10-02 12:52:15 +02:00
|
|
|
this.error(DiagnosticCode.Cannot_find_name_0, queuedImport.declaration.externalIdentifier.range, importName);
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeClass(declaration: ClassDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
2017-10-02 12:52:15 +02:00
|
|
|
this.addExport(/* same as */internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
const members: DeclarationStatement[] = declaration.members;
|
|
|
|
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
|
|
|
const statement: Statement = members[j];
|
|
|
|
switch (statement.kind) {
|
|
|
|
|
|
|
|
case NodeKind.FIELD:
|
|
|
|
this.initializeField(<FieldDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.METHOD:
|
|
|
|
this.initializeMethod(<MethodDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw new Error("unexpected class member");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeField(declaration: FieldDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeEnum(declaration: EnumDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
2017-10-02 12:52:15 +02:00
|
|
|
this.addExport(/* same as */internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
const members: EnumValueDeclaration[] = declaration.members;
|
|
|
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
|
|
|
this.initializeEnumValue(members[i]);
|
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeEnumValue(declaration: EnumValueDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
private initializeExports(statement: ExportStatement, queuedExports: Map<string,QueuedExport>): void {
|
2017-09-29 17:25:02 +02:00
|
|
|
const members: ExportMember[] = statement.members;
|
|
|
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
2017-10-02 12:52:15 +02:00
|
|
|
this.initializeExport(members[i], statement.normalizedPath, queuedExports);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
private initializeExport(member: ExportMember, normalizedPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
2017-09-29 17:25:02 +02:00
|
|
|
const exportName: string = member.range.source.normalizedPath + "/" + member.externalIdentifier.name;
|
2017-10-02 12:52:15 +02:00
|
|
|
if (queuedExports.has(exportName))
|
2017-09-29 17:25:02 +02:00
|
|
|
this.error(DiagnosticCode.Duplicate_identifier_0, member.externalIdentifier.range, exportName);
|
|
|
|
else {
|
2017-10-02 12:52:15 +02:00
|
|
|
const queuedExport: QueuedExport = new QueuedExport();
|
|
|
|
queuedExport.importName = normalizedPath == null
|
2017-09-29 17:25:02 +02:00
|
|
|
? member.range.source.normalizedPath + "/" + member.identifier.name // local
|
|
|
|
: (<string>normalizedPath) + "/" + member.identifier.name; // re-export
|
2017-10-02 12:52:15 +02:00
|
|
|
queuedExport.member = member;
|
|
|
|
queuedExports.set(exportName, queuedExport);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeFunction(declaration: FunctionDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
2017-10-02 12:52:15 +02:00
|
|
|
this.addExport(/* same as */internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
private initializeImports(statement: ImportStatement, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
2017-09-28 13:08:25 +02:00
|
|
|
const members: ImportDeclaration[] = statement.declarations;
|
2017-09-29 17:25:02 +02:00
|
|
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
|
|
|
const declaration: ImportDeclaration = members[i];
|
2017-10-02 12:52:15 +02:00
|
|
|
this.initializeImport(declaration, statement.normalizedPath, queuedExports, queuedImports);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
private initializeImport(declaration: ImportDeclaration, normalizedPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
2017-09-29 17:25:02 +02:00
|
|
|
const importName: string = normalizedPath + "/" + declaration.externalIdentifier.name;
|
|
|
|
let resolvedImportName: string = importName;
|
2017-10-02 12:52:15 +02:00
|
|
|
const seen: Set<QueuedExport> = new Set();
|
|
|
|
while (queuedExports.has(resolvedImportName)) {
|
|
|
|
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(resolvedImportName);
|
|
|
|
resolvedImportName = queuedExport.importName;
|
|
|
|
if (seen.has(queuedExport))
|
|
|
|
break;
|
|
|
|
seen.add(queuedExport);
|
|
|
|
}
|
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
if (this.exports.has(resolvedImportName)) { // resolvable right away
|
2017-10-02 12:52:15 +02:00
|
|
|
if (this.names.has(internalName))
|
|
|
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
2017-09-29 17:25:02 +02:00
|
|
|
else
|
2017-10-02 12:52:15 +02:00
|
|
|
this.names.set(internalName, <DeclarationStatement>this.exports.get(resolvedImportName));
|
2017-09-29 17:25:02 +02:00
|
|
|
} else { // points to yet unresolved export
|
2017-10-02 12:52:15 +02:00
|
|
|
const queuedImport: QueuedImport = new QueuedImport();
|
|
|
|
queuedImport.internalName = internalName;
|
|
|
|
queuedImport.importName = importName;
|
|
|
|
queuedImport.declaration = declaration;
|
|
|
|
queuedImports.push(queuedImport);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeInterface(declaration: InterfaceDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
2017-10-02 12:52:15 +02:00
|
|
|
this.addExport(/* same as */internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
const members: Statement[] = declaration.members;
|
|
|
|
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
|
|
|
const statement: Statement = members[j];
|
|
|
|
switch (statement.kind) {
|
|
|
|
|
|
|
|
case NodeKind.FIELD:
|
|
|
|
this.initializeField(<FieldDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.METHOD:
|
|
|
|
this.initializeMethod(<MethodDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw new Error("unexpected interface member");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeMethod(declaration: MethodDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 17:25:02 +02:00
|
|
|
private initializeNamespace(declaration: NamespaceDeclaration): void {
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
2017-10-02 12:52:15 +02:00
|
|
|
this.addExport(/* same as */internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
const members: Statement[] = declaration.members;
|
|
|
|
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
|
|
|
const statement: Statement = members[j];
|
|
|
|
switch (statement.kind) {
|
|
|
|
|
|
|
|
case NodeKind.CLASS:
|
|
|
|
this.initializeClass(<ClassDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.ENUM:
|
|
|
|
this.initializeEnum(<EnumDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.FUNCTION:
|
|
|
|
this.initializeFunction(<FunctionDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.INTERFACE:
|
|
|
|
this.initializeInterface(<InterfaceDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.NAMESPACE:
|
|
|
|
this.initializeNamespace(<NamespaceDeclaration>statement);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NodeKind.VARIABLE:
|
2017-09-29 17:25:02 +02:00
|
|
|
this.initializeVariables(<VariableStatement>statement, true);
|
2017-09-28 13:08:25 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw new Error("unexpected namespace member");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
private initializeVariables(statement: VariableStatement, isNamespaceMember: bool = false): void {
|
|
|
|
const declarations: VariableDeclaration[] = statement.declarations;
|
|
|
|
const isExport: bool = !isNamespaceMember && hasModifier(ModifierKind.EXPORT, statement.modifiers);
|
2017-09-28 13:08:25 +02:00
|
|
|
for (let i: i32 = 0, k = declarations.length; i < k; ++i) {
|
|
|
|
const declaration: VariableDeclaration = declarations[i];
|
2017-10-02 12:52:15 +02:00
|
|
|
const internalName: string = this.mangleInternalName(declaration);
|
|
|
|
this.addName(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
if (isExport)
|
2017-10-02 12:52:15 +02:00
|
|
|
this.addExport(/* same as */internalName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
private addName(internalName: string, declaration: DeclarationStatement): void {
|
|
|
|
if (this.names.has(internalName))
|
|
|
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName); // recoverable
|
2017-09-29 17:25:02 +02:00
|
|
|
else
|
2017-10-02 12:52:15 +02:00
|
|
|
this.names.set(internalName, declaration);
|
2017-09-29 17:25:02 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
private addExport(exportName: string, declaration: DeclarationStatement): void {
|
|
|
|
if (this.exports.has(exportName))
|
|
|
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, exportName); // recoverable
|
2017-09-28 13:08:25 +02:00
|
|
|
else
|
2017-10-02 12:52:15 +02:00
|
|
|
this.exports.set(exportName, declaration);
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
mangleInternalName(declaration: DeclarationStatement): string {
|
2017-09-28 13:08:25 +02:00
|
|
|
let name: string = declaration.identifier.name;
|
|
|
|
let parent: Node | null = declaration.parent;
|
|
|
|
if (parent) {
|
|
|
|
switch (parent.kind) {
|
|
|
|
|
|
|
|
case NodeKind.SOURCE:
|
2017-09-29 17:25:02 +02:00
|
|
|
return (<Source>parent).normalizedPath + "/" + name;
|
2017-09-28 13:08:25 +02:00
|
|
|
|
|
|
|
case NodeKind.CLASS: {
|
|
|
|
if (
|
|
|
|
(declaration.kind == NodeKind.FIELD && !hasModifier(ModifierKind.STATIC, (<FieldDeclaration>declaration).modifiers)) ||
|
|
|
|
(declaration.kind == NodeKind.METHOD && !hasModifier(ModifierKind.STATIC, (<MethodDeclaration>declaration).modifiers))
|
|
|
|
)
|
2017-10-02 12:52:15 +02:00
|
|
|
return this.mangleInternalName(<DeclarationStatement>parent) + "#" + name;
|
2017-09-28 13:08:25 +02:00
|
|
|
// otherwise fall through
|
|
|
|
}
|
|
|
|
case NodeKind.ENUM:
|
|
|
|
case NodeKind.ENUMVALUE:
|
|
|
|
case NodeKind.NAMESPACE:
|
2017-10-02 12:52:15 +02:00
|
|
|
return this.mangleInternalName(<DeclarationStatement>parent) + "." + name;
|
2017-09-28 13:08:25 +02:00
|
|
|
|
|
|
|
case NodeKind.IMPORT: {
|
2017-10-02 12:52:15 +02:00
|
|
|
const importParent: Node | null = (<ImportStatement>parent).parent;
|
|
|
|
if (importParent && importParent.kind == NodeKind.SOURCE)
|
|
|
|
return (<Source>importParent).path + "/" + name;
|
2017-09-28 13:08:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case NodeKind.VARIABLE: {
|
2017-10-02 12:52:15 +02:00
|
|
|
const variableParent: Node | null = (<VariableStatement>parent).parent;
|
|
|
|
if (variableParent) {
|
|
|
|
if (variableParent.kind == NodeKind.SOURCE)
|
|
|
|
return <Source>variableParent == this.sources[0] ? name : (<Source>variableParent).path + "/" + name;
|
|
|
|
if (variableParent.kind == NodeKind.NAMESPACE)
|
|
|
|
return this.mangleInternalName(<DeclarationStatement>variableParent) + "." + name;
|
2017-09-28 13:08:25 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new Error("unexpected parent");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-02 12:52:15 +02:00
|
|
|
function initializeBasicTypes(types: Map<string,Type>, target: Target): void {
|
2017-09-28 13:08:25 +02:00
|
|
|
types.set("i8", Type.i8);
|
|
|
|
types.set("i16", Type.i16);
|
|
|
|
types.set("i32", Type.i32);
|
|
|
|
types.set("i64", Type.i64);
|
2017-09-29 17:25:02 +02:00
|
|
|
types.set("isize", target == Target.WASM64 ? Type.isize64 : Type.isize32);
|
2017-09-28 13:08:25 +02:00
|
|
|
types.set("u8", Type.u8);
|
|
|
|
types.set("u16", Type.u16);
|
|
|
|
types.set("u32", Type.u32);
|
|
|
|
types.set("u64", Type.u64);
|
2017-09-29 17:25:02 +02:00
|
|
|
types.set("usize", target == Target.WASM64 ? Type.usize64 : Type.usize32);
|
2017-09-28 13:08:25 +02:00
|
|
|
types.set("bool", Type.bool);
|
2017-10-02 12:52:15 +02:00
|
|
|
types.set("f32", Type.f32);
|
|
|
|
types.set("f64", Type.f64);
|
2017-09-28 13:08:25 +02:00
|
|
|
types.set("void", Type.void);
|
|
|
|
}
|