mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-15 07:51:32 +00:00
New ArrayBuffer/TypedArray; Stdlib restructure; Fix importing stdlib in stdlib; Traverse constructors; Allow initialization of readonly instance fields in constructors
This commit is contained in:
@ -46,10 +46,10 @@ import {
|
||||
FlowFlags,
|
||||
CommonFlags,
|
||||
ConstantValueKind,
|
||||
Flow,
|
||||
|
||||
PATH_DELIMITER,
|
||||
LIBRARY_PREFIX,
|
||||
Flow
|
||||
INNER_DELIMITER
|
||||
} from "./program";
|
||||
|
||||
import {
|
||||
@ -220,8 +220,6 @@ export class Compiler extends DiagnosticEmitter {
|
||||
functionTable: Function[] = new Array();
|
||||
/** Argument count helper global. */
|
||||
argumentCountRef: GlobalRef = 0;
|
||||
/** Already processed file names. */
|
||||
files: Set<string> = new Set();
|
||||
|
||||
/** Compiles a {@link Program} to a {@link Module} using the specified options. */
|
||||
static compile(program: Program, options: Options | null = null): Module {
|
||||
@ -272,16 +270,14 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var startFunctionBody = this.startFunctionBody;
|
||||
if (startFunctionBody.length) {
|
||||
let typeRef = this.ensureFunctionType(startFunctionInstance.signature);
|
||||
let funcRef: FunctionRef;
|
||||
module.setStart(
|
||||
funcRef = module.addFunction(
|
||||
startFunctionInstance.internalName,
|
||||
typeRef,
|
||||
typesToNativeTypes(startFunctionInstance.additionalLocals),
|
||||
module.createBlock(null, startFunctionBody)
|
||||
)
|
||||
let funcRef = module.addFunction(
|
||||
startFunctionInstance.internalName,
|
||||
typeRef,
|
||||
typesToNativeTypes(startFunctionInstance.additionalLocals),
|
||||
module.createBlock(null, startFunctionBody)
|
||||
);
|
||||
startFunctionInstance.finalize(module, funcRef);
|
||||
module.setStart(funcRef);
|
||||
}
|
||||
|
||||
// set up static memory segments and the heap base pointer
|
||||
@ -319,13 +315,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// import memory if requested
|
||||
if (options.importMemory) {
|
||||
module.addMemoryImport("0", "env", "memory");
|
||||
}
|
||||
if (options.importMemory) module.addMemoryImport("0", "env", "memory");
|
||||
|
||||
// set up function table
|
||||
var functionTable = this.functionTable;
|
||||
var functionTableSize = functionTable.length;
|
||||
var functionTableExported = false;
|
||||
if (functionTableSize) {
|
||||
let entries = new Array<FunctionRef>(functionTableSize);
|
||||
for (let i = 0; i < functionTableSize; ++i) {
|
||||
@ -333,12 +328,13 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
module.setFunctionTable(entries);
|
||||
module.addTableExport("0", "table");
|
||||
functionTableExported = true;
|
||||
}
|
||||
|
||||
// import table if requested
|
||||
if (options.importTable) {
|
||||
module.addTableImport("0", "env", "table");
|
||||
if (!functionTableSize) module.addTableExport("0", "table");
|
||||
if (!functionTableExported) module.addTableExport("0", "table");
|
||||
}
|
||||
|
||||
return module;
|
||||
@ -347,49 +343,20 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// sources
|
||||
|
||||
compileSourceByPath(normalizedPathWithoutExtension: string, reportNode: Node): void {
|
||||
var sources = this.program.sources;
|
||||
|
||||
// try file.ts
|
||||
var expected = normalizedPathWithoutExtension + ".ts";
|
||||
for (let i = 0, k = sources.length; i < k; ++i) {
|
||||
let source = sources[i];
|
||||
if (source.normalizedPath == expected) {
|
||||
this.compileSource(source);
|
||||
return;
|
||||
}
|
||||
var source = this.program.lookupSourceByPath(normalizedPathWithoutExtension);
|
||||
if (!source) {
|
||||
this.error(
|
||||
DiagnosticCode.File_0_not_found,
|
||||
reportNode.range, normalizedPathWithoutExtension
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// try file/index.ts
|
||||
expected = normalizedPathWithoutExtension + "/index.ts";
|
||||
for (let i = 0, k = sources.length; i < k; ++i) {
|
||||
let source = sources[i];
|
||||
if (source.normalizedPath == expected) {
|
||||
this.compileSource(source);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// try ~lib/file.ts
|
||||
expected = LIBRARY_PREFIX + normalizedPathWithoutExtension + ".ts";
|
||||
for (let i = 0, k = sources.length; i < k; ++i) {
|
||||
let source = sources[i];
|
||||
if (source.normalizedPath == expected) {
|
||||
this.compileSource(source);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.error(
|
||||
DiagnosticCode.File_0_not_found,
|
||||
reportNode.range, normalizedPathWithoutExtension
|
||||
);
|
||||
this.compileSource(source);
|
||||
}
|
||||
|
||||
compileSource(source: Source): void {
|
||||
var files = this.files;
|
||||
var normalizedPath = source.normalizedPath;
|
||||
if (files.has(normalizedPath)) return;
|
||||
files.add(normalizedPath);
|
||||
if (source.is(CommonFlags.COMPILED)) return;
|
||||
source.set(CommonFlags.COMPILED);
|
||||
|
||||
// compile top-level statements
|
||||
var noTreeShaking = this.options.noTreeShaking;
|
||||
@ -1294,11 +1261,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// otherwise fall-through
|
||||
}
|
||||
default: {
|
||||
assert(false);
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
statement.range
|
||||
);
|
||||
assert(false);
|
||||
expr = module.createUnreachable();
|
||||
break;
|
||||
}
|
||||
@ -4161,7 +4128,15 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
case ElementKind.FIELD: {
|
||||
if ((<Field>target).is(CommonFlags.READONLY)) {
|
||||
const declaration = (<Field>target).declaration;
|
||||
if (
|
||||
(<Field>target).is(CommonFlags.READONLY) &&
|
||||
!(
|
||||
this.currentFunction.is(CommonFlags.CONSTRUCTOR) ||
|
||||
declaration == null ||
|
||||
declaration.initializer != null
|
||||
)
|
||||
) {
|
||||
this.error(
|
||||
DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property,
|
||||
expression.range, (<Field>target).internalName
|
||||
@ -4863,7 +4838,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
var prototype = new FunctionPrototype(
|
||||
this.program,
|
||||
simpleName,
|
||||
currentFunction.internalName + "~" + simpleName,
|
||||
currentFunction.internalName + INNER_DELIMITER + simpleName,
|
||||
declaration
|
||||
);
|
||||
var instance = this.compileFunctionUsingTypeArguments(
|
||||
@ -5385,7 +5360,13 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (!classInstance) return module.createUnreachable();
|
||||
|
||||
var expr: ExpressionRef;
|
||||
|
||||
// traverse to the first matching constructor
|
||||
var currentClassInstance: Class | null = classInstance;
|
||||
var constructorInstance = classInstance.constructorInstance;
|
||||
while (!constructorInstance && (currentClassInstance = classInstance.base)) {
|
||||
constructorInstance = currentClassInstance.constructorInstance;
|
||||
}
|
||||
|
||||
// if a constructor is present, call it with a zero `this`
|
||||
if (constructorInstance) {
|
||||
|
@ -41,10 +41,7 @@ import {
|
||||
export function parseFile(text: string, path: string, isEntry: bool = false,
|
||||
parser: Parser | null = null
|
||||
): Parser {
|
||||
if (!parser) {
|
||||
parser = new Parser();
|
||||
isEntry = true;
|
||||
}
|
||||
if (!parser) parser = new Parser();
|
||||
parser.parseFile(text, path, isEntry);
|
||||
return parser;
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ export const SETTER_PREFIX = "set:";
|
||||
export const INSTANCE_DELIMITER = "#";
|
||||
/** Delimiter used between class and namespace names and static members. */
|
||||
export const STATIC_DELIMITER = ".";
|
||||
/** Delimiter used between a function and its inner elements. */
|
||||
export const INNER_DELIMITER = "~";
|
||||
/** Substitution used to indicate a library directory. */
|
||||
export const LIBRARY_SUBST = "~lib";
|
||||
/** Library directory prefix. */
|
||||
@ -148,6 +150,26 @@ export class Program extends DiagnosticEmitter {
|
||||
this.sources = [];
|
||||
}
|
||||
|
||||
/** Gets a source by its exact path. */
|
||||
getSource(normalizedPath: string): Source | null {
|
||||
var sources = this.sources;
|
||||
for (let i = 0, k = sources.length; i < k; ++i) {
|
||||
let source = sources[i];
|
||||
if (source.normalizedPath == normalizedPath) return source;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Looks up the source for the specified possibly ambiguous path. */
|
||||
lookupSourceByPath(normalizedPathWithoutExtension: string): Source | null {
|
||||
return (
|
||||
this.getSource(normalizedPathWithoutExtension + ".ts") ||
|
||||
this.getSource(normalizedPathWithoutExtension + "/index.ts") ||
|
||||
this.getSource(LIBRARY_PREFIX + normalizedPathWithoutExtension + ".ts") ||
|
||||
this.getSource(LIBRARY_PREFIX + normalizedPathWithoutExtension + "/index.ts")
|
||||
);
|
||||
}
|
||||
|
||||
/** Initializes the program and its elements prior to compilation. */
|
||||
initialize(options: Options): void {
|
||||
this.options = options;
|
||||
@ -2524,20 +2546,22 @@ export class FunctionPrototype extends Element {
|
||||
/** Resolves this prototype partially by applying the specified inherited class type arguments. */
|
||||
resolvePartial(classTypeArguments: Type[] | null): FunctionPrototype | null {
|
||||
assert(this.is(CommonFlags.INSTANCE));
|
||||
assert(this.classPrototype);
|
||||
if (classTypeArguments && classTypeArguments.length) {
|
||||
let partialPrototype = new FunctionPrototype(
|
||||
this.program,
|
||||
this.simpleName,
|
||||
this.internalName,
|
||||
this.declaration,
|
||||
this.classPrototype
|
||||
);
|
||||
partialPrototype.flags = this.flags;
|
||||
partialPrototype.classTypeArguments = classTypeArguments;
|
||||
return partialPrototype;
|
||||
}
|
||||
return this; // no need to clone
|
||||
var classPrototype = assert(this.classPrototype);
|
||||
|
||||
if (!(classTypeArguments && classTypeArguments.length)) return this; // no need to clone
|
||||
|
||||
var simpleName = this.simpleName;
|
||||
var partialKey = typesToString(classTypeArguments);
|
||||
var partialPrototype = new FunctionPrototype(
|
||||
this.program,
|
||||
simpleName,
|
||||
classPrototype.internalName + "<" + partialKey + ">" + INSTANCE_DELIMITER + simpleName,
|
||||
this.declaration,
|
||||
classPrototype
|
||||
);
|
||||
partialPrototype.flags = this.flags;
|
||||
partialPrototype.classTypeArguments = classTypeArguments;
|
||||
return partialPrototype;
|
||||
}
|
||||
|
||||
/** Resolves the specified type arguments prior to resolving this prototype to an instance. */
|
||||
@ -3079,10 +3103,7 @@ export class ClassPrototype extends Element {
|
||||
|
||||
if (this.constructorPrototype) {
|
||||
let partialConstructor = this.constructorPrototype.resolvePartial(typeArguments); // reports
|
||||
if (partialConstructor) {
|
||||
instance.constructorInstance = partialConstructor.resolve(); // reports
|
||||
}
|
||||
// TODO: ^ doesn't know the return type, hence returns null
|
||||
if (partialConstructor) instance.constructorInstance = partialConstructor.resolve(); // reports
|
||||
}
|
||||
|
||||
if (this.instanceMembers) {
|
||||
@ -3487,7 +3508,7 @@ export class Flow {
|
||||
// scopedGlobal = new Global(
|
||||
// scopedLocal.program,
|
||||
// scopedLocal.simpleName,
|
||||
// this.currentFunction.internalName + "~" + scopedLocal.internalName,
|
||||
// this.currentFunction.internalName + INNER_DELIMITER + scopedLocal.internalName,
|
||||
// scopedLocal.type,
|
||||
// assert(scopedLocal.declaration)
|
||||
// );
|
||||
|
Reference in New Issue
Block a user