mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-07-04 00:51:51 +00:00
Rename memory instructions; Rework constant handling
This commit is contained in:
155
src/program.ts
155
src/program.ts
@ -132,6 +132,12 @@ class TypeAlias {
|
||||
type: CommonTypeNode;
|
||||
}
|
||||
|
||||
/** Represents a module-level export. */
|
||||
class ModuleExport {
|
||||
element: Element;
|
||||
identifier: IdentifierExpression;
|
||||
}
|
||||
|
||||
/** Represents the kind of an operator overload. */
|
||||
export enum OperatorKind {
|
||||
INVALID,
|
||||
@ -319,7 +325,7 @@ export class Program extends DiagnosticEmitter {
|
||||
/** File-level exports by exported name. */
|
||||
fileLevelExports: Map<string,Element> = new Map();
|
||||
/** Module-level exports by exported name. */
|
||||
moduleLevelExports: Map<string,Element> = new Map();
|
||||
moduleLevelExports: Map<string,ModuleExport> = new Map();
|
||||
|
||||
/** Array prototype reference. */
|
||||
arrayPrototype: ClassPrototype | null = null;
|
||||
@ -329,6 +335,10 @@ export class Program extends DiagnosticEmitter {
|
||||
startFunction: FunctionPrototype;
|
||||
/** Main function reference, if present. */
|
||||
mainFunction: FunctionPrototype | null = null;
|
||||
/** Abort function reference, if present. */
|
||||
abortInstance: Function | null = null;
|
||||
/** Memory allocation function. */
|
||||
memoryAllocateInstance: Function | null = null;
|
||||
|
||||
/** Currently processing filespace. */
|
||||
currentFilespace: Filespace;
|
||||
@ -569,52 +579,54 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// set up global aliases
|
||||
var globalAliases = options.globalAliases;
|
||||
if (globalAliases) {
|
||||
for (let [alias, name] of globalAliases) {
|
||||
if (!name.length) continue; // explicitly disabled
|
||||
let element = this.elementsLookup.get(name);
|
||||
if (element) this.elementsLookup.set(alias, element);
|
||||
else throw new Error("element not found: " + name);
|
||||
{
|
||||
let globalAliases = options.globalAliases;
|
||||
if (globalAliases) {
|
||||
for (let [alias, name] of globalAliases) {
|
||||
if (!name.length) continue; // explicitly disabled
|
||||
let element = this.elementsLookup.get(name);
|
||||
if (element) this.elementsLookup.set(alias, element);
|
||||
else throw new Error("element not found: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register 'Array'
|
||||
var arrayPrototype = this.elementsLookup.get("Array");
|
||||
if (arrayPrototype) {
|
||||
assert(arrayPrototype.kind == ElementKind.CLASS_PROTOTYPE);
|
||||
this.arrayPrototype = <ClassPrototype>arrayPrototype;
|
||||
if (this.elementsLookup.has("Array")) {
|
||||
let element = assert(this.elementsLookup.get("Array"));
|
||||
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
||||
this.arrayPrototype = <ClassPrototype>element;
|
||||
}
|
||||
|
||||
// register 'String'
|
||||
var stringPrototype = this.elementsLookup.get("String");
|
||||
if (stringPrototype) {
|
||||
assert(stringPrototype.kind == ElementKind.CLASS_PROTOTYPE);
|
||||
let stringInstance = resolver.resolveClass(<ClassPrototype>stringPrototype, null);
|
||||
if (stringInstance) {
|
||||
if (this.elementsLookup.has("String")) {
|
||||
let element = assert(this.elementsLookup.get("String"));
|
||||
assert(element.kind == ElementKind.CLASS_PROTOTYPE);
|
||||
let instance = resolver.resolveClass(<ClassPrototype>element, null);
|
||||
if (instance) {
|
||||
if (this.typesLookup.has("string")) {
|
||||
let declaration = (<ClassPrototype>stringPrototype).declaration;
|
||||
let declaration = (<ClassPrototype>element).declaration;
|
||||
this.error(
|
||||
DiagnosticCode.Duplicate_identifier_0,
|
||||
declaration.name.range, declaration.programLevelInternalName
|
||||
);
|
||||
} else {
|
||||
this.stringInstance = stringInstance;
|
||||
this.typesLookup.set("string", stringInstance.type);
|
||||
this.stringInstance = instance;
|
||||
this.typesLookup.set("string", instance.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register 'start'
|
||||
{
|
||||
let element = <Element>assert(this.elementsLookup.get("start"));
|
||||
let element = assert(this.elementsLookup.get("start"));
|
||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||
this.startFunction = <FunctionPrototype>element;
|
||||
}
|
||||
|
||||
// register 'main' if present
|
||||
if (this.moduleLevelExports.has("main")) {
|
||||
let element = <Element>this.moduleLevelExports.get("main");
|
||||
if (this.elementsLookup.has("main")) {
|
||||
let element = <Element>this.elementsLookup.get("main");
|
||||
if (
|
||||
element.kind == ElementKind.FUNCTION_PROTOTYPE &&
|
||||
!(<FunctionPrototype>element).isAny(CommonFlags.GENERIC | CommonFlags.AMBIENT)
|
||||
@ -623,6 +635,28 @@ export class Program extends DiagnosticEmitter {
|
||||
this.mainFunction = <FunctionPrototype>element;
|
||||
}
|
||||
}
|
||||
|
||||
// register 'abort' if present
|
||||
if (this.elementsLookup.has("abort")) {
|
||||
let element = <Element>this.elementsLookup.get("abort");
|
||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||
let instance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||
if (instance) this.abortInstance = instance;
|
||||
}
|
||||
|
||||
// register 'memory.allocate' if present
|
||||
if (this.elementsLookup.has("memory")) {
|
||||
let element = <Element>this.elementsLookup.get("memory");
|
||||
let members = element.members;
|
||||
if (members) {
|
||||
if (members.has("allocate")) {
|
||||
element = assert(members.get("allocate"));
|
||||
assert(element.kind == ElementKind.FUNCTION_PROTOTYPE);
|
||||
let instance = this.resolver.resolveFunction(<FunctionPrototype>element, null);
|
||||
if (instance) this.memoryAllocateInstance = instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a constant integer value. */
|
||||
@ -824,14 +858,18 @@ export class Program extends DiagnosticEmitter {
|
||||
this.currentFilespace.members.set(simpleName, prototype);
|
||||
if (prototype.is(CommonFlags.EXPORT) && declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(simpleName)) {
|
||||
let existingExport = <ModuleExport>this.moduleLevelExports.get(simpleName);
|
||||
this.error(
|
||||
DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
declaration.name.range, existingExport.element.internalName
|
||||
);
|
||||
return;
|
||||
}
|
||||
prototype.set(CommonFlags.MODULE_EXPORT);
|
||||
this.moduleLevelExports.set(simpleName, prototype);
|
||||
this.moduleLevelExports.set(simpleName, <ModuleExport>{
|
||||
element: prototype,
|
||||
identifier: declaration.name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1269,14 +1307,18 @@ export class Program extends DiagnosticEmitter {
|
||||
this.currentFilespace.members.set(simpleName, element);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(simpleName)) {
|
||||
let existingExport = <ModuleExport>this.moduleLevelExports.get(simpleName);
|
||||
this.error(
|
||||
DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
declaration.name.range, existingExport.element.internalName
|
||||
);
|
||||
return;
|
||||
}
|
||||
element.set(CommonFlags.MODULE_EXPORT);
|
||||
this.moduleLevelExports.set(simpleName, element);
|
||||
this.moduleLevelExports.set(simpleName, <ModuleExport>{
|
||||
element,
|
||||
identifier: declaration.name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1332,31 +1374,39 @@ export class Program extends DiagnosticEmitter {
|
||||
private setExportAndCheckLibrary(
|
||||
internalName: string,
|
||||
element: Element,
|
||||
identifier: IdentifierExpression
|
||||
externalIdentifier: IdentifierExpression
|
||||
): void {
|
||||
// add to file-level exports
|
||||
this.fileLevelExports.set(internalName, element);
|
||||
|
||||
// add to filespace
|
||||
var internalPath = identifier.range.source.internalPath;
|
||||
var internalPath = externalIdentifier.range.source.internalPath;
|
||||
var prefix = FILESPACE_PREFIX + internalPath;
|
||||
var filespace = this.elementsLookup.get(prefix);
|
||||
if (!filespace) filespace = assert(this.elementsLookup.get(prefix + PATH_DELIMITER + "index"));
|
||||
assert(filespace.kind == ElementKind.FILESPACE);
|
||||
var simpleName = identifier.text;
|
||||
var simpleName = externalIdentifier.text;
|
||||
(<Filespace>filespace).members.set(simpleName, element);
|
||||
|
||||
// add global alias if from a library file
|
||||
if (identifier.range.source.isLibrary) {
|
||||
// add global alias if a top-level export of a library file
|
||||
var source = externalIdentifier.range.source;
|
||||
if (source.isLibrary) {
|
||||
if (this.elementsLookup.has(simpleName)) {
|
||||
this.error(
|
||||
DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0,
|
||||
identifier.range, simpleName
|
||||
externalIdentifier.range, simpleName
|
||||
);
|
||||
} else {
|
||||
element.internalName = simpleName;
|
||||
this.elementsLookup.set(simpleName, element);
|
||||
}
|
||||
|
||||
// add module level export if a top-level export of an entry file
|
||||
} else if (source.isEntry) {
|
||||
this.moduleLevelExports.set(externalIdentifier.text, <ModuleExport>{
|
||||
element,
|
||||
identifier: externalIdentifier
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1382,10 +1432,10 @@ export class Program extends DiagnosticEmitter {
|
||||
referencedName = member.range.source.internalPath + PATH_DELIMITER + member.name.text;
|
||||
|
||||
// resolve right away if the element exists
|
||||
if (referencedElement = this.elementsLookup.get(referencedName)) {
|
||||
if (this.elementsLookup.has(referencedName)) {
|
||||
this.setExportAndCheckLibrary(
|
||||
externalName,
|
||||
referencedElement,
|
||||
<Element>this.elementsLookup.get(referencedName),
|
||||
member.externalName
|
||||
);
|
||||
return;
|
||||
@ -1526,14 +1576,18 @@ export class Program extends DiagnosticEmitter {
|
||||
this.currentFilespace.members.set(simpleName, prototype);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(simpleName)) {
|
||||
let existingExport = <ModuleExport>this.moduleLevelExports.get(simpleName);
|
||||
this.error(
|
||||
DiagnosticCode.Duplicate_identifier_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
declaration.name.range, existingExport.element.internalName
|
||||
);
|
||||
return;
|
||||
}
|
||||
prototype.set(CommonFlags.MODULE_EXPORT);
|
||||
this.moduleLevelExports.set(simpleName, prototype);
|
||||
this.moduleLevelExports.set(simpleName, <ModuleExport>{
|
||||
element: prototype,
|
||||
identifier: declaration.name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1687,14 +1741,18 @@ export class Program extends DiagnosticEmitter {
|
||||
this.currentFilespace.members.set(simpleName, prototype);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(simpleName)) {
|
||||
let existingExport = <ModuleExport>this.moduleLevelExports.get(simpleName);
|
||||
this.error(
|
||||
DiagnosticCode.Duplicate_identifier_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
declaration.name.range, existingExport.element.internalName
|
||||
);
|
||||
return;
|
||||
}
|
||||
prototype.set(CommonFlags.MODULE_EXPORT);
|
||||
this.moduleLevelExports.set(simpleName, prototype);
|
||||
this.moduleLevelExports.set(simpleName, <ModuleExport>{
|
||||
element: prototype,
|
||||
identifier: declaration.name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1772,15 +1830,19 @@ export class Program extends DiagnosticEmitter {
|
||||
this.currentFilespace.members.set(simpleName, namespace);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(simpleName)) {
|
||||
if (this.moduleLevelExports.get(simpleName) !== namespace) { // not merged
|
||||
let existingExport = <ModuleExport>this.moduleLevelExports.get(simpleName);
|
||||
if (existingExport.element !== namespace) { // not merged
|
||||
this.error(
|
||||
DiagnosticCode.Duplicate_identifier_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
declaration.name.range, existingExport.element.internalName
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.moduleLevelExports.set(simpleName, namespace);
|
||||
this.moduleLevelExports.set(simpleName, <ModuleExport>{
|
||||
element: namespace,
|
||||
identifier: declaration.name
|
||||
});
|
||||
}
|
||||
namespace.set(CommonFlags.MODULE_EXPORT);
|
||||
}
|
||||
@ -1869,6 +1931,7 @@ export class Program extends DiagnosticEmitter {
|
||||
decorators
|
||||
? this.checkDecorators(decorators,
|
||||
DecoratorFlags.GLOBAL |
|
||||
DecoratorFlags.INLINE |
|
||||
DecoratorFlags.EXTERNAL
|
||||
)
|
||||
: DecoratorFlags.NONE
|
||||
@ -1904,14 +1967,18 @@ export class Program extends DiagnosticEmitter {
|
||||
this.currentFilespace.members.set(simpleName, global);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(simpleName)) {
|
||||
let existingExport = <ModuleExport>this.moduleLevelExports.get(simpleName);
|
||||
this.error(
|
||||
DiagnosticCode.Duplicate_identifier_0,
|
||||
declaration.name.range, (<Element>this.moduleLevelExports.get(simpleName)).internalName
|
||||
declaration.name.range, existingExport.element.internalName
|
||||
);
|
||||
continue;
|
||||
}
|
||||
global.set(CommonFlags.MODULE_EXPORT);
|
||||
this.moduleLevelExports.set(simpleName, global);
|
||||
this.moduleLevelExports.set(simpleName, <ModuleExport>{
|
||||
element: global,
|
||||
identifier: declaration.name
|
||||
});
|
||||
}
|
||||
}
|
||||
this.checkGlobal(global, declaration);
|
||||
|
Reference in New Issue
Block a user