mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Support 'import * as' directives, see #27
This commit is contained in:
parent
f2eb64c0fd
commit
25b433dca9
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -602,7 +602,7 @@ export abstract class Node {
|
||||
}
|
||||
|
||||
static createExportStatement(
|
||||
members: ExportMember[],
|
||||
members: ExportMember[] | null,
|
||||
path: StringLiteralExpression | null,
|
||||
flags: CommonFlags,
|
||||
range: Range
|
||||
@ -610,7 +610,7 @@ export abstract class Node {
|
||||
var stmt = new ExportStatement();
|
||||
stmt.range = range;
|
||||
stmt.flags = flags;
|
||||
stmt.members = members; setParent(members, stmt);
|
||||
stmt.members = members; if (members) setParent(members, stmt);
|
||||
stmt.path = path;
|
||||
if (path) {
|
||||
let normalizedPath = normalizePath(path.value);
|
||||
@ -1627,8 +1627,8 @@ export class ExportMember extends Node {
|
||||
export class ExportStatement extends Statement {
|
||||
kind = NodeKind.EXPORT;
|
||||
|
||||
/** Array of members. */
|
||||
members: ExportMember[];
|
||||
/** Array of members if a set of named exports, or `null` if a filespace export. */
|
||||
members: ExportMember[] | null;
|
||||
/** Path being exported from, if applicable. */
|
||||
path: StringLiteralExpression | null;
|
||||
/** Normalized path, if `path` is set. */
|
||||
|
@ -1097,8 +1097,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
compileExportStatement(statement: ExportStatement): void {
|
||||
var module = this.module;
|
||||
var exports = this.program.fileLevelExports;
|
||||
var fileLevelExports = this.program.fileLevelExports;
|
||||
var members = statement.members;
|
||||
if (!members) return; // filespace
|
||||
for (let i = 0, k = members.length; i < k; ++i) {
|
||||
let member = members[i];
|
||||
let internalExportName = (
|
||||
@ -1106,7 +1107,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
PATH_DELIMITER +
|
||||
member.externalName.text
|
||||
);
|
||||
let element = exports.get(internalExportName);
|
||||
let element = fileLevelExports.get(internalExportName);
|
||||
if (!element) continue; // reported in Program#initialize
|
||||
switch (element.kind) {
|
||||
case ElementKind.CLASS_PROTOTYPE: {
|
||||
|
@ -1915,6 +1915,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
|
||||
// at 'export': '{' ExportMember (',' ExportMember)* }' ('from' StringLiteral)? ';'?
|
||||
|
||||
var path: StringLiteralExpression | null = null;
|
||||
if (tn.skip(Token.OPENBRACE)) {
|
||||
let members = new Array<ExportMember>();
|
||||
while (!tn.skip(Token.CLOSEBRACE)) {
|
||||
@ -1933,7 +1934,6 @@ export class Parser extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
let path: StringLiteralExpression | null = null;
|
||||
if (tn.skip(Token.FROM)) {
|
||||
if (tn.skip(Token.STRINGLITERAL)) {
|
||||
path = Node.createStringLiteralExpression(tn.readString(), tn.range());
|
||||
@ -1953,6 +1953,30 @@ export class Parser extends DiagnosticEmitter {
|
||||
}
|
||||
tn.skip(Token.SEMICOLON);
|
||||
return ret;
|
||||
} else if (tn.skip(Token.ASTERISK)) {
|
||||
if (tn.skip(Token.FROM)) {
|
||||
if (tn.skip(Token.STRINGLITERAL)) {
|
||||
path = Node.createStringLiteralExpression(tn.readString(), tn.range());
|
||||
let ret = Node.createExportStatement(null, path, flags, tn.range(startPos, tn.pos));
|
||||
let internalPath = ret.internalPath;
|
||||
if (internalPath !== null && !this.seenlog.has(internalPath)) {
|
||||
this.backlog.push(internalPath);
|
||||
this.seenlog.add(internalPath);
|
||||
}
|
||||
tn.skip(Token.SEMICOLON);
|
||||
return ret;
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.String_literal_expected,
|
||||
tn.range()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode._0_expected,
|
||||
tn.range(), "from"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode._0_expected,
|
||||
@ -2805,8 +2829,8 @@ export class Parser extends DiagnosticEmitter {
|
||||
return Node.createFalseExpression(tn.range());
|
||||
}
|
||||
|
||||
var p = determinePrecedenceStart(token);
|
||||
if (p != Precedence.INVALID) {
|
||||
var precedence = determinePrecedenceStart(token);
|
||||
if (precedence != Precedence.INVALID) {
|
||||
let operand: Expression | null;
|
||||
|
||||
// TODO: SpreadExpression, YieldExpression (currently become unsupported UnaryPrefixExpressions)
|
||||
@ -2830,7 +2854,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
operand = this.parseExpression(tn, p);
|
||||
operand = this.parseExpression(tn, precedence);
|
||||
if (!operand) return null;
|
||||
}
|
||||
|
||||
@ -3328,7 +3352,7 @@ export const enum Precedence {
|
||||
}
|
||||
|
||||
/** Determines the precedence of a starting token. */
|
||||
function determinePrecedenceStart(kind: Token): i32 {
|
||||
function determinePrecedenceStart(kind: Token): Precedence {
|
||||
switch (kind) {
|
||||
case Token.DOT_DOT_DOT: return Precedence.SPREAD;
|
||||
case Token.YIELD: return Precedence.YIELD;
|
||||
@ -3347,7 +3371,7 @@ function determinePrecedenceStart(kind: Token): i32 {
|
||||
}
|
||||
|
||||
/** Determines the precende of a non-starting token. */
|
||||
function determinePrecedence(kind: Token): i32 {
|
||||
function determinePrecedence(kind: Token): Precedence {
|
||||
switch (kind) {
|
||||
case Token.COMMA: return Precedence.COMMA;
|
||||
case Token.EQUALS:
|
||||
|
163
src/program.ts
163
src/program.ts
@ -120,6 +120,8 @@ export const INNER_DELIMITER = "~";
|
||||
export const LIBRARY_SUBST = "~lib";
|
||||
/** Library directory prefix. */
|
||||
export const LIBRARY_PREFIX = LIBRARY_SUBST + PATH_DELIMITER;
|
||||
/** Prefix used to indicate a filespace element. */
|
||||
export const FILESPACE_PREFIX = "file:";
|
||||
|
||||
/** Represents a yet unresolved export. */
|
||||
class QueuedExport {
|
||||
@ -133,7 +135,7 @@ class QueuedImport {
|
||||
internalName: string;
|
||||
referencedName: string;
|
||||
referencedNameAlt: string;
|
||||
declaration: ImportDeclaration;
|
||||
declaration: ImportDeclaration | null; // not set if a filespace
|
||||
}
|
||||
|
||||
/** Represents a type alias. */
|
||||
@ -338,6 +340,8 @@ export class Program extends DiagnosticEmitter {
|
||||
resolvedThisExpression: Expression | null = null;
|
||||
/** Element expression of the previously resolved element access. */
|
||||
resolvedElementExpression : Expression | null = null;
|
||||
/** Currently processing filespace. */
|
||||
currentFilespace: Filespace;
|
||||
|
||||
/** Constructs a new program, optionally inheriting parser diagnostics. */
|
||||
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
||||
@ -357,11 +361,12 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
/** Looks up the source for the specified possibly ambiguous path. */
|
||||
lookupSourceByPath(normalizedPathWithoutExtension: string): Source | null {
|
||||
var tmp: string;
|
||||
return (
|
||||
this.getSource(normalizedPathWithoutExtension + ".ts") ||
|
||||
this.getSource(normalizedPathWithoutExtension + "/index.ts") ||
|
||||
this.getSource(LIBRARY_PREFIX + normalizedPathWithoutExtension + ".ts") ||
|
||||
this.getSource(LIBRARY_PREFIX + normalizedPathWithoutExtension + "/index.ts")
|
||||
this.getSource((tmp = LIBRARY_PREFIX + normalizedPathWithoutExtension) + ".ts") ||
|
||||
this.getSource( tmp + "/index.ts")
|
||||
);
|
||||
}
|
||||
|
||||
@ -395,6 +400,13 @@ export class Program extends DiagnosticEmitter {
|
||||
// build initial lookup maps of internal names to declarations
|
||||
for (let i = 0, k = this.sources.length; i < k; ++i) {
|
||||
let source = this.sources[i];
|
||||
|
||||
// create one filespace per source
|
||||
let filespace = new Filespace(this, source);
|
||||
this.elementsLookup.set(filespace.internalName, filespace);
|
||||
this.currentFilespace = filespace;
|
||||
|
||||
// process this source's statements
|
||||
let statements = source.statements;
|
||||
for (let j = 0, l = statements.length; j < l; ++j) {
|
||||
let statement = statements[j];
|
||||
@ -442,22 +454,39 @@ export class Program extends DiagnosticEmitter {
|
||||
// queued imports should be resolvable now through traversing exports and queued exports
|
||||
for (let i = 0; i < queuedImports.length;) {
|
||||
let queuedImport = queuedImports[i];
|
||||
let element = this.tryResolveImport(queuedImport.referencedName, queuedExports);
|
||||
if (element) {
|
||||
this.elementsLookup.set(queuedImport.internalName, element);
|
||||
queuedImports.splice(i, 1);
|
||||
} else {
|
||||
if (element = this.tryResolveImport(queuedImport.referencedNameAlt, queuedExports)) {
|
||||
let declaration = queuedImport.declaration;
|
||||
if (declaration) { // named
|
||||
let element = this.tryResolveImport(queuedImport.referencedName, queuedExports);
|
||||
if (element) {
|
||||
this.elementsLookup.set(queuedImport.internalName, element);
|
||||
queuedImports.splice(i, 1);
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Module_0_has_no_exported_member_1,
|
||||
queuedImport.declaration.range,
|
||||
(<ImportStatement>queuedImport.declaration.parent).path.value,
|
||||
queuedImport.declaration.externalName.text
|
||||
);
|
||||
++i;
|
||||
if (element = this.tryResolveImport(queuedImport.referencedNameAlt, queuedExports)) {
|
||||
this.elementsLookup.set(queuedImport.internalName, element);
|
||||
queuedImports.splice(i, 1);
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Module_0_has_no_exported_member_1,
|
||||
declaration.range,
|
||||
(<ImportStatement>declaration.parent).path.value,
|
||||
declaration.externalName.text
|
||||
);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
} else { // filespace
|
||||
let element = this.elementsLookup.get(queuedImport.referencedName);
|
||||
if (element) {
|
||||
this.elementsLookup.set(queuedImport.internalName, element);
|
||||
queuedImports.splice(i, 1);
|
||||
} else {
|
||||
if (element = this.elementsLookup.get(queuedImport.referencedNameAlt)) {
|
||||
this.elementsLookup.set(queuedImport.internalName, element);
|
||||
queuedImports.splice(i, 1);
|
||||
} else {
|
||||
assert(false); // already reported by the parser not finding the file
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -732,6 +761,7 @@ export class Program extends DiagnosticEmitter {
|
||||
return;
|
||||
}
|
||||
this.fileLevelExports.set(internalName, prototype);
|
||||
this.currentFilespace.members.set(simpleName, prototype);
|
||||
if (prototype.is(CommonFlags.EXPORT) && declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(internalName)) {
|
||||
this.error(
|
||||
@ -1165,6 +1195,7 @@ export class Program extends DiagnosticEmitter {
|
||||
return;
|
||||
}
|
||||
this.fileLevelExports.set(internalName, element);
|
||||
this.currentFilespace.members.set(simpleName, element);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(internalName)) {
|
||||
this.error(
|
||||
@ -1215,26 +1246,45 @@ export class Program extends DiagnosticEmitter {
|
||||
queuedExports: Map<string,QueuedExport>
|
||||
): void {
|
||||
var members = statement.members;
|
||||
for (let i = 0, k = members.length; i < k; ++i) {
|
||||
this.initializeExport(members[i], statement.internalPath, queuedExports);
|
||||
if (members) { // named
|
||||
for (let i = 0, k = members.length; i < k; ++i) {
|
||||
this.initializeExport(members[i], statement.internalPath, queuedExports);
|
||||
}
|
||||
} else { // TODO: filespace
|
||||
this.error(
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
statement.range
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private setExportAndCheckLibrary(
|
||||
name: string,
|
||||
internalName: string,
|
||||
element: Element,
|
||||
identifier: IdentifierExpression
|
||||
): void {
|
||||
this.fileLevelExports.set(name, element);
|
||||
if (identifier.range.source.isLibrary) { // add global alias
|
||||
if (this.elementsLookup.has(identifier.text)) {
|
||||
// add to file-level exports
|
||||
this.fileLevelExports.set(internalName, element);
|
||||
|
||||
// add to filespace
|
||||
var internalPath = identifier.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;
|
||||
(<Filespace>filespace).members.set(simpleName, element);
|
||||
|
||||
// add global alias if from a library file
|
||||
if (identifier.range.source.isLibrary) {
|
||||
if (this.elementsLookup.has(simpleName)) {
|
||||
this.error(
|
||||
DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0,
|
||||
identifier.range, identifier.text
|
||||
identifier.range, simpleName
|
||||
);
|
||||
} else {
|
||||
element.internalName = identifier.text;
|
||||
this.elementsLookup.set(identifier.text, element);
|
||||
element.internalName = simpleName;
|
||||
this.elementsLookup.set(simpleName, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1401,6 +1451,7 @@ export class Program extends DiagnosticEmitter {
|
||||
return;
|
||||
}
|
||||
this.fileLevelExports.set(internalName, prototype);
|
||||
this.currentFilespace.members.set(simpleName, prototype);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(internalName)) {
|
||||
this.error(
|
||||
@ -1446,10 +1497,22 @@ export class Program extends DiagnosticEmitter {
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.error( // TODO
|
||||
DiagnosticCode.Operation_not_supported,
|
||||
statement.range
|
||||
);
|
||||
|
||||
// resolve right away if the exact filespace exists
|
||||
let filespace = this.elementsLookup.get(statement.internalPath);
|
||||
if (filespace) {
|
||||
this.elementsLookup.set(internalName, filespace);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise queue it
|
||||
let queuedImport = new QueuedImport();
|
||||
queuedImport.internalName = internalName;
|
||||
let prefix = FILESPACE_PREFIX + statement.internalPath;
|
||||
queuedImport.referencedName = prefix;
|
||||
queuedImport.referencedNameAlt = prefix + PATH_DELIMITER + "index";
|
||||
queuedImport.declaration = null;
|
||||
queuedImports.push(queuedImport);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1511,9 +1574,10 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
var decorators = declaration.decorators;
|
||||
var simpleName = declaration.name.text;
|
||||
var prototype = new InterfacePrototype(
|
||||
this,
|
||||
declaration.name.text,
|
||||
simpleName,
|
||||
internalName,
|
||||
declaration,
|
||||
decorators
|
||||
@ -1548,6 +1612,7 @@ export class Program extends DiagnosticEmitter {
|
||||
return;
|
||||
}
|
||||
this.fileLevelExports.set(internalName, prototype);
|
||||
this.currentFilespace.members.set(simpleName, prototype);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(internalName)) {
|
||||
this.error(
|
||||
@ -1632,6 +1697,7 @@ export class Program extends DiagnosticEmitter {
|
||||
} else {
|
||||
this.fileLevelExports.set(internalName, namespace);
|
||||
}
|
||||
this.currentFilespace.members.set(simpleName, namespace);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(internalName)) {
|
||||
this.error(
|
||||
@ -1759,6 +1825,7 @@ export class Program extends DiagnosticEmitter {
|
||||
} else {
|
||||
this.fileLevelExports.set(internalName, global);
|
||||
}
|
||||
this.currentFilespace.members.set(simpleName, global);
|
||||
if (declaration.range.source.isEntry) {
|
||||
if (this.moduleLevelExports.has(internalName)) {
|
||||
this.error(
|
||||
@ -2144,11 +2211,13 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
default: { // enums or other namespace-like elements
|
||||
let members = target.members;
|
||||
let member: Element | null;
|
||||
if (members && (member = members.get(propertyName))) {
|
||||
this.resolvedThisExpression = targetExpression;
|
||||
this.resolvedElementExpression = null;
|
||||
return member; // static ENUMVALUE, static GLOBAL, static FUNCTION_PROTOTYPE...
|
||||
if (members) {
|
||||
let member = members.get(propertyName);
|
||||
if (member) {
|
||||
this.resolvedThisExpression = targetExpression;
|
||||
this.resolvedElementExpression = null;
|
||||
return member; // static ENUMVALUE, static GLOBAL, static FUNCTION_PROTOTYPE...
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2373,7 +2442,9 @@ export enum ElementKind {
|
||||
/** A {@link Property}. */
|
||||
PROPERTY,
|
||||
/** A {@link Namespace}. */
|
||||
NAMESPACE
|
||||
NAMESPACE,
|
||||
/** A {@link Filespace}. */
|
||||
FILESPACE,
|
||||
}
|
||||
|
||||
/** Indicates traits of a {@link Node} or {@link Element}. */
|
||||
@ -2515,7 +2586,25 @@ export abstract class Element {
|
||||
hasDecorator(flag: DecoratorFlags): bool { return (this.decoratorFlags & flag) == flag; }
|
||||
}
|
||||
|
||||
/** A namespace. */
|
||||
/** A filespace representing the implicit top-level namespace of a source. */
|
||||
export class Filespace extends Element {
|
||||
|
||||
kind = ElementKind.FILESPACE;
|
||||
|
||||
/** File members (externally visible only). */
|
||||
members: Map<string,Element>; // more specific
|
||||
|
||||
/** Constructs a new filespace. */
|
||||
constructor(
|
||||
program: Program,
|
||||
source: Source
|
||||
) {
|
||||
super(program, source.internalPath, FILESPACE_PREFIX + source.internalPath);
|
||||
this.members = new Map();
|
||||
}
|
||||
}
|
||||
|
||||
/** A namespace that differs from a filespace in being user-declared with a name. */
|
||||
export class Namespace extends Element {
|
||||
|
||||
// All elements have namespace semantics. This is an explicitly declared one.
|
||||
|
@ -45,5 +45,24 @@
|
||||
)
|
||||
)
|
||||
(call $export/ns.two)
|
||||
(drop
|
||||
(i32.add
|
||||
(i32.add
|
||||
(call $export/add
|
||||
(i32.const 1)
|
||||
(i32.const 2)
|
||||
)
|
||||
(call $export/sub
|
||||
(i32.const 2)
|
||||
(i32.const 3)
|
||||
)
|
||||
)
|
||||
(call $export/mul
|
||||
(i32.const 3)
|
||||
(i32.const 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
(call $export/ns.two)
|
||||
)
|
||||
)
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* tslint:disable:no-duplicate-imports */
|
||||
|
||||
import {
|
||||
add,
|
||||
sub as sub,
|
||||
@ -11,3 +13,11 @@ import {
|
||||
add(a, b) + sub(b, c) + mul(c, a);
|
||||
|
||||
renamed_ns.two();
|
||||
|
||||
import * as other from "./export";
|
||||
|
||||
other.add(other.a, other.b) +
|
||||
other.sub(other.b, other.renamed_c) +
|
||||
other.renamed_mul(other.renamed_c, other.a);
|
||||
|
||||
other.ns.two();
|
||||
|
@ -55,5 +55,24 @@
|
||||
)
|
||||
)
|
||||
(call $export/ns.two)
|
||||
(drop
|
||||
(i32.add
|
||||
(i32.add
|
||||
(call $export/add
|
||||
(i32.const 1)
|
||||
(i32.const 2)
|
||||
)
|
||||
(call $export/sub
|
||||
(i32.const 2)
|
||||
(i32.const 3)
|
||||
)
|
||||
)
|
||||
(call $export/mul
|
||||
(i32.const 3)
|
||||
(i32.const 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
(call $export/ns.two)
|
||||
)
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user