Cleanup; Fix an issue with 'let' declarations reusing a local

This commit is contained in:
dcodeIO 2018-02-14 19:21:31 +01:00
parent b1c6ccab2a
commit d31e484b15
13 changed files with 684 additions and 484 deletions

View File

@ -173,7 +173,7 @@ exports.main = function main(argv, options, callback) {
stats.parseCount++; stats.parseCount++;
stats.parseTime += measure(() => { stats.parseTime += measure(() => {
parser = assemblyscript.parseFile(sourceText, sourcePath, parser, true); parser = assemblyscript.parseFile(sourceText, sourcePath, true, parser);
}); });
while ((sourcePath = parser.nextFile()) != null) { while ((sourcePath = parser.nextFile()) != null) {
@ -226,7 +226,7 @@ exports.main = function main(argv, options, callback) {
} }
stats.parseCount++; stats.parseCount++;
stats.parseTime += measure(() => { stats.parseTime += measure(() => {
assemblyscript.parseFile(sourceText, sourcePath, parser); assemblyscript.parseFile(sourceText, sourcePath, false, parser);
}); });
} }
if (checkDiagnostics(parser, stderr)) if (checkDiagnostics(parser, stderr))
@ -244,6 +244,7 @@ exports.main = function main(argv, options, callback) {
parser = assemblyscript.parseFile( parser = assemblyscript.parseFile(
exports.libraryFiles[libPath], exports.libraryFiles[libPath],
libPath + ".ts", libPath + ".ts",
false,
parser parser
); );
}); });
@ -263,6 +264,7 @@ exports.main = function main(argv, options, callback) {
parser = assemblyscript.parseFile( parser = assemblyscript.parseFile(
libText, libText,
exports.libraryPrefix + libPath, exports.libraryPrefix + libPath,
false,
parser parser
); );
}); });

2
dist/asc.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -12,9 +12,7 @@ import {
import { import {
Node, Node,
Expression, Expression
BinaryExpression,
SourceKind
} from "./ast"; } from "./ast";
import { import {
@ -24,7 +22,6 @@ import {
} from "./types"; } from "./types";
import { import {
Module,
UnaryOp, UnaryOp,
BinaryOp, BinaryOp,
HostOp, HostOp,
@ -35,11 +32,8 @@ import {
} from "./module"; } from "./module";
import { import {
Program,
Global, Global,
Function,
FunctionPrototype, FunctionPrototype,
Parameter,
Local, Local,
ElementFlags, ElementFlags,
Class, Class,
@ -48,21 +42,21 @@ import {
/** Compiles a get of a built-in global. */ /** Compiles a get of a built-in global. */
export function compileGetConstant(compiler: Compiler, global: Global, reportNode: Node): ExpressionRef { export function compileGetConstant(compiler: Compiler, global: Global, reportNode: Node): ExpressionRef {
switch (global.internalName) { // switching on strings should become a compiler optimization eventually switch (global.internalName) {
case "NaN": case "NaN": // context-sensitive
if (compiler.currentType == Type.f32) if (compiler.currentType == Type.f32)
return compiler.module.createF32(NaN); return compiler.module.createF32(NaN);
compiler.currentType = Type.f64; compiler.currentType = Type.f64;
return compiler.module.createF64(NaN); return compiler.module.createF64(NaN);
case "Infinity": case "Infinity": // context-sensitive
if (compiler.currentType == Type.f32) if (compiler.currentType == Type.f32)
return compiler.module.createF32(Infinity); return compiler.module.createF32(Infinity);
compiler.currentType = Type.f64; compiler.currentType = Type.f64;
return compiler.module.createF64(Infinity); return compiler.module.createF64(Infinity);
case "HEAP_BASE": // constant, but never inlined case "HEAP_BASE": // never inlined for linking purposes
compiler.currentType = compiler.options.usizeType; compiler.currentType = compiler.options.usizeType;
return compiler.module.createGetGlobal("HEAP_BASE", compiler.options.nativeSizeType); return compiler.module.createGetGlobal("HEAP_BASE", compiler.options.nativeSizeType);
} }
@ -83,9 +77,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
tempLocal1: Local; tempLocal1: Local;
var type: Type, var type: Type,
ftype: FunctionTypeRef; offset: i32;
var offset: i32;
// NOTE that some implementations below make use of the select expression where straight-forward. // NOTE that some implementations below make use of the select expression where straight-forward.
// whether worth or not should probably be tested once it's known if/how embedders handle it. // whether worth or not should probably be tested once it's known if/how embedders handle it.

View File

@ -648,7 +648,7 @@ export class Compiler extends DiagnosticEmitter {
// check module export // check module export
if (declaration.range.source.isEntry && declaration.isTopLevelExport) if (declaration.range.source.isEntry && declaration.isTopLevelExport)
this.module.addFunctionExport(instance.internalName, declaration.name.name); this.module.addFunctionExport(instance.internalName, declaration.name.text);
instance.finalize(this.module, ref); instance.finalize(this.module, ref);
return true; return true;
@ -741,7 +741,7 @@ export class Compiler extends DiagnosticEmitter {
var members = statement.members; var members = statement.members;
for (var i = 0, k = members.length; i < k; ++i) { for (var i = 0, k = members.length; i < k; ++i) {
var member = members[i]; var member = members[i];
var internalExportName = statement.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name; var internalExportName = statement.range.source.internalPath + PATH_DELIMITER + member.externalName.text;
var element = this.program.exports.get(internalExportName); var element = this.program.exports.get(internalExportName);
if (!element) // reported in Program#initialize if (!element) // reported in Program#initialize
continue; continue;
@ -762,7 +762,7 @@ export class Compiler extends DiagnosticEmitter {
if (functionInstance) { if (functionInstance) {
var functionDeclaration = functionInstance.prototype.declaration; var functionDeclaration = functionInstance.prototype.declaration;
if (functionDeclaration && functionDeclaration.needsExplicitExport(member)) if (functionDeclaration && functionDeclaration.needsExplicitExport(member))
this.module.addFunctionExport(functionInstance.internalName, member.externalIdentifier.name); this.module.addFunctionExport(functionInstance.internalName, member.externalName.text);
} }
} }
break; break;
@ -772,7 +772,7 @@ export class Compiler extends DiagnosticEmitter {
var globalDeclaration = (<Global>element).declaration; var globalDeclaration = (<Global>element).declaration;
if (globalDeclaration && globalDeclaration.needsExplicitExport(member)) { if (globalDeclaration && globalDeclaration.needsExplicitExport(member)) {
if ((<Global>element).is(ElementFlags.INLINED)) if ((<Global>element).is(ElementFlags.INLINED))
this.module.addGlobalExport(element.internalName, member.externalIdentifier.name); this.module.addGlobalExport(element.internalName, member.externalName.text);
else else
this.warning(DiagnosticCode.Cannot_export_a_mutable_global, member.range); this.warning(DiagnosticCode.Cannot_export_a_mutable_global, member.range);
} }
@ -1195,7 +1195,7 @@ export class Compiler extends DiagnosticEmitter {
var initializers = new Array<ExpressionRef>(); var initializers = new Array<ExpressionRef>();
for (i = 0, k = declarations.length; i < k; ++i) { for (i = 0, k = declarations.length; i < k; ++i) {
var declaration = declarations[i]; var declaration = declarations[i];
var name = declaration.name.name; var name = declaration.name.text;
var type: Type | null = null; var type: Type | null = null;
var init: ExpressionRef = 0; var init: ExpressionRef = 0;
if (declaration.type) { if (declaration.type) {

View File

@ -309,7 +309,7 @@ export function serializeSource(source: Source, sb: string[]): void {
// types // types
export function serializeTypeNode(node: TypeNode, sb: string[]): void { export function serializeTypeNode(node: TypeNode, sb: string[]): void {
serializeIdentifierExpression(<IdentifierExpression>node.identifier, sb); serializeIdentifierExpression(<IdentifierExpression>node.name, sb);
if (node.typeArguments.length) { if (node.typeArguments.length) {
sb.push("<"); sb.push("<");
for (var i = 0, k = node.typeArguments.length; i < k; ++i) { for (var i = 0, k = node.typeArguments.length; i < k; ++i) {
@ -324,7 +324,7 @@ export function serializeTypeNode(node: TypeNode, sb: string[]): void {
} }
export function serializeTypeParameter(node: TypeParameter, sb: string[]): void { export function serializeTypeParameter(node: TypeParameter, sb: string[]): void {
serializeIdentifierExpression(node.identifier, sb); serializeIdentifierExpression(node.name, sb);
if (node.extendsType) { if (node.extendsType) {
sb.push(" extends "); sb.push(" extends ");
serializeTypeNode(node.extendsType, sb); serializeTypeNode(node.extendsType, sb);
@ -338,7 +338,7 @@ export function serializeExpression(node: Expression, sb: string[]): void {
} }
export function serializeIdentifierExpression(node: IdentifierExpression, sb: string[]): void { export function serializeIdentifierExpression(node: IdentifierExpression, sb: string[]): void {
sb.push(node.name); sb.push(node.text);
} }
export function serializeArrayLiteralExpression(node: ArrayLiteralExpression, sb: string[]): void { export function serializeArrayLiteralExpression(node: ArrayLiteralExpression, sb: string[]): void {
@ -705,7 +705,7 @@ export function serializeClassDeclaration(node: ClassDeclaration, sb: string[]):
sb.push(" "); sb.push(" ");
} }
sb.push("class "); sb.push("class ");
sb.push(node.name.name); sb.push(node.name.text);
if (node.typeParameters.length) { if (node.typeParameters.length) {
sb.push("<"); sb.push("<");
for (i = 0, k = node.typeParameters.length; i < k; ++i) { for (i = 0, k = node.typeParameters.length; i < k; ++i) {
@ -779,16 +779,16 @@ export function serializeEnumValueDeclaration(node: EnumValueDeclaration, sb: st
export function serializeExportImportStatement(node: ExportImportStatement, sb: string[]): void { export function serializeExportImportStatement(node: ExportImportStatement, sb: string[]): void {
sb.push("export import "); sb.push("export import ");
serializeIdentifierExpression(node.externalIdentifier, sb); serializeIdentifierExpression(node.externalName, sb);
sb.push(" = "); sb.push(" = ");
serializeIdentifierExpression(node.identifier, sb); serializeIdentifierExpression(node.name, sb);
} }
export function serializeExportMember(node: ExportMember, sb: string[]): void { export function serializeExportMember(node: ExportMember, sb: string[]): void {
serializeIdentifierExpression(node.identifier, sb); serializeIdentifierExpression(node.name, sb);
if (node.externalIdentifier.name != node.identifier.name) { if (node.externalName.text != node.name.text) {
sb.push(" as "); sb.push(" as ");
serializeIdentifierExpression(node.externalIdentifier, sb); serializeIdentifierExpression(node.externalName, sb);
} }
} }
@ -922,8 +922,8 @@ export function serializeIfStatement(node: IfStatement, sb: string[]): void {
} }
export function serializeImportDeclaration(node: ImportDeclaration, sb: string[]): void { export function serializeImportDeclaration(node: ImportDeclaration, sb: string[]): void {
serializeIdentifierExpression(node.externalIdentifier, sb); serializeIdentifierExpression(node.externalName, sb);
if (node.externalIdentifier != node.name) { if (node.externalName.text != node.name.text) {
sb.push(" as "); sb.push(" as ");
serializeIdentifierExpression(node.name, sb); serializeIdentifierExpression(node.name, sb);
} }

View File

@ -1,30 +1,4 @@
/* //////////////////////// Low-level C-Like Compiler API /////////////////////////
Exports a C-like API to the embedder.
[obtain entrySource, entryPath]
parseFile(entrySource, entryPath) -> parser
while nextPath = nextFile(parser)
[obtain nextSource]
parseFile(nextSource, nextPath)
Checking for errors:
while diagnostic = nextDiagnostic(parser)
[print] formatDiagnostic(diagnostic, useColors?, showContext?)
if (isError(diagnostic))
[abort parsing afterwards]
compile(parser) -> module
[check diagnostics again]
[output module]
*/
import {
Module
} from "./module";
import { import {
Compiler, Compiler,
@ -32,28 +6,28 @@ import {
Target Target
} from "./compiler"; } from "./compiler";
import {
Decompiler
} from "./decompiler";
import { import {
DiagnosticMessage, DiagnosticMessage,
DiagnosticCategory, DiagnosticCategory,
formatDiagnosticMessage formatDiagnosticMessage
} from "./diagnostics"; } from "./diagnostics";
import {
Module
} from "./module";
import { import {
Parser Parser
} from "./parser"; } from "./parser";
import { /** Parses a source file. If `parser` has been omitted a new one is created. */
Program export function parseFile(text: string, path: string, isEntry: bool = false,
} from "./program"; parser: Parser | null = null
): Parser {
import {
Decompiler
} from "./decompiler";
export { LIBRARY_PREFIX } from "./program";
/** Parses a single source file. If `parser` has been omitted a new one is created. */
export function parseFile(text: string, path: string, parser: Parser | null = null, isEntry: bool = false): Parser {
if (!parser) { if (!parser) {
parser = new Parser(); parser = new Parser();
isEntry = true; isEntry = true;
@ -62,12 +36,12 @@ export function parseFile(text: string, path: string, parser: Parser | null = nu
return parser; return parser;
} }
/** Obtains the path to the next file required by the parser. Returns `null` once complete. */ /** Obtains the next required file's path. Returns `null` once complete. */
export function nextFile(parser: Parser): string | null { export function nextFile(parser: Parser): string | null {
return parser.nextFile(); return parser.nextFile();
} }
/** Obtains the next diagnostic message. Returns `null` once there are no more messages. */ /** Obtains the next diagnostic message. Returns `null` once complete. */
export function nextDiagnostic(parser: Parser): DiagnosticMessage | null { export function nextDiagnostic(parser: Parser): DiagnosticMessage | null {
var program = parser.program; var program = parser.program;
return program.diagnosticsOffset < program.diagnostics.length return program.diagnosticsOffset < program.diagnostics.length
@ -76,9 +50,7 @@ export function nextDiagnostic(parser: Parser): DiagnosticMessage | null {
} }
/** Formats a diagnostic message to a string. */ /** Formats a diagnostic message to a string. */
export function formatDiagnostic(message: DiagnosticMessage, useColors: bool, showContext: bool): string { export { formatDiagnosticMessage as formatDiagnostic };
return formatDiagnosticMessage(message, useColors, showContext);
}
/** Tests whether a diagnostic is informatory. */ /** Tests whether a diagnostic is informatory. */
export function isInfo(message: DiagnosticMessage): bool { export function isInfo(message: DiagnosticMessage): bool {
@ -138,3 +110,6 @@ export function decompile(module: Module): string {
decompiler.decompile(module); decompiler.decompile(module);
return decompiler.finish(); return decompiler.finish();
} }
/** Prefix indicating a library file. */
export { LIBRARY_PREFIX } from "./program";

View File

@ -60,7 +60,6 @@ import {
hasDecorator, hasDecorator,
hasModifier, hasModifier,
mangleInternalName, mangleInternalName,
getFirstDecorator,
BinaryExpression BinaryExpression
} from "./ast"; } from "./ast";
@ -210,7 +209,7 @@ export class Program extends DiagnosticEmitter {
this.elements.set(queuedImport.internalName, element); this.elements.set(queuedImport.internalName, element);
queuedImports.splice(i, 1); queuedImports.splice(i, 1);
} else { } else {
this.error(DiagnosticCode.Module_0_has_no_exported_member_1, queuedImport.declaration.range, (<ImportStatement>queuedImport.declaration.parent).path.value, queuedImport.declaration.externalIdentifier.name); this.error(DiagnosticCode.Module_0_has_no_exported_member_1, queuedImport.declaration.range, (<ImportStatement>queuedImport.declaration.parent).path.value, queuedImport.declaration.externalName.text);
++i; ++i;
} }
} }
@ -221,20 +220,20 @@ export class Program extends DiagnosticEmitter {
do { do {
if (currentExport.isReExport) { if (currentExport.isReExport) {
if (element = this.exports.get(currentExport.referencedName)) { if (element = this.exports.get(currentExport.referencedName)) {
this.setExportAndCheckLibrary(exportName, element, currentExport.member.externalIdentifier); this.setExportAndCheckLibrary(exportName, element, currentExport.member.externalName);
break; break;
} }
currentExport = queuedExports.get(currentExport.referencedName); currentExport = queuedExports.get(currentExport.referencedName);
if (!currentExport) 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); this.error(DiagnosticCode.Module_0_has_no_exported_member_1, queuedExport.member.externalName.range, (<StringLiteralExpression>(<ExportStatement>queuedExport.member.parent).path).value, queuedExport.member.externalName.text);
} else { } else {
if ( if (
(element = this.elements.get(currentExport.referencedName)) || // normal export (element = this.elements.get(currentExport.referencedName)) || // normal export
(element = this.elements.get(currentExport.member.identifier.name)) // library re-export (element = this.elements.get(currentExport.member.name.text)) // library re-export
) )
this.setExportAndCheckLibrary(exportName, element, currentExport.member.externalIdentifier); this.setExportAndCheckLibrary(exportName, element, currentExport.member.externalName);
else else
this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.range, queuedExport.member.identifier.name); this.error(DiagnosticCode.Cannot_find_name_0, queuedExport.member.range, queuedExport.member.name.text);
break; break;
} }
} while (currentExport); } while (currentExport);
@ -246,7 +245,7 @@ export class Program extends DiagnosticEmitter {
assert(derivedDeclaration != null); assert(derivedDeclaration != null);
var derivedType = (<ClassDeclaration>derivedDeclaration).extendsType; var derivedType = (<ClassDeclaration>derivedDeclaration).extendsType;
assert(derivedType != null); assert(derivedType != null);
var resolved = this.resolveIdentifier((<TypeNode>derivedType).identifier, null); // reports var resolved = this.resolveIdentifier((<TypeNode>derivedType).name, null); // reports
if (resolved) { if (resolved) {
if (resolved.element.kind != ElementKind.CLASS_PROTOTYPE) { if (resolved.element.kind != ElementKind.CLASS_PROTOTYPE) {
this.error(DiagnosticCode.A_class_may_only_extend_another_class, (<TypeNode>derivedType).range); this.error(DiagnosticCode.A_class_may_only_extend_another_class, (<TypeNode>derivedType).range);
@ -292,13 +291,13 @@ export class Program extends DiagnosticEmitter {
) )
) { ) {
element.set(ElementFlags.GLOBAL); element.set(ElementFlags.GLOBAL);
if (this.elements.has(declaration.name.name)) if (this.elements.has(declaration.name.text))
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, element.internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, element.internalName);
else { else {
this.elements.set(declaration.name.name, element); this.elements.set(declaration.name.text, element);
this.exports.set(declaration.name.name, element); this.exports.set(declaration.name.text, element);
if (isBuiltin) if (isBuiltin)
element.internalName = declaration.name.name; element.internalName = declaration.name.text;
} }
} }
} }
@ -309,7 +308,7 @@ export class Program extends DiagnosticEmitter {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
var prototype = new ClassPrototype(this, declaration.name.name, internalName, declaration); var prototype = new ClassPrototype(this, declaration.name.text, internalName, declaration);
prototype.namespace = namespace; prototype.namespace = namespace;
this.elements.set(internalName, prototype); this.elements.set(internalName, prototype);
@ -329,13 +328,13 @@ export class Program extends DiagnosticEmitter {
// add as namespace member if applicable // add as namespace member if applicable
if (namespace) { if (namespace) {
if (namespace.members) { if (namespace.members) {
if (namespace.members.has(declaration.name.name)) { if (namespace.members.has(declaration.name.text)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(declaration.name.name, prototype); namespace.members.set(declaration.name.text, prototype);
// otherwise add to file-level exports if exported // otherwise add to file-level exports if exported
} else if (prototype.is(ElementFlags.EXPORTED)) { } else if (prototype.is(ElementFlags.EXPORTED)) {
@ -370,7 +369,7 @@ export class Program extends DiagnosticEmitter {
} }
// check and possibly register string type // check and possibly register string type
if (prototype.is(ElementFlags.GLOBAL) && declaration.name.name === "String" && !this.types.has("string")) { if (prototype.is(ElementFlags.GLOBAL) && declaration.name.text === "String" && !this.types.has("string")) {
var instance = prototype.resolve(null); var instance = prototype.resolve(null);
if (instance) if (instance)
this.types.set("string", instance.type); this.types.set("string", instance.type);
@ -378,7 +377,7 @@ export class Program extends DiagnosticEmitter {
} }
private initializeField(declaration: FieldDeclaration, classPrototype: ClassPrototype): void { private initializeField(declaration: FieldDeclaration, classPrototype: ClassPrototype): void {
var name = declaration.name.name; var name = declaration.name.text;
var internalName = declaration.fileLevelInternalName; var internalName = declaration.fileLevelInternalName;
// static fields become global variables // static fields become global variables
@ -413,7 +412,7 @@ export class Program extends DiagnosticEmitter {
} }
private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void { private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void {
var name = declaration.name.name; var name = declaration.name.text;
var internalName = declaration.fileLevelInternalName; var internalName = declaration.fileLevelInternalName;
var prototype: FunctionPrototype | null = null; var prototype: FunctionPrototype | null = null;
@ -511,7 +510,7 @@ export class Program extends DiagnosticEmitter {
} }
private initializeAccessor(declaration: MethodDeclaration, classPrototype: ClassPrototype, isGetter: bool): void { private initializeAccessor(declaration: MethodDeclaration, classPrototype: ClassPrototype, isGetter: bool): void {
var propertyName = declaration.name.name; var propertyName = declaration.name.text;
var internalPropertyName = declaration.fileLevelInternalName; var internalPropertyName = declaration.fileLevelInternalName;
var propertyElement = this.elements.get(internalPropertyName); var propertyElement = this.elements.get(internalPropertyName);
@ -568,7 +567,7 @@ export class Program extends DiagnosticEmitter {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
var enm = new Enum(this, declaration.name.name, internalName, declaration); var enm = new Enum(this, declaration.name.text, internalName, declaration);
enm.namespace = namespace; enm.namespace = namespace;
this.elements.set(internalName, enm); this.elements.set(internalName, enm);
@ -576,13 +575,13 @@ export class Program extends DiagnosticEmitter {
if (namespace) { if (namespace) {
if (namespace.members) { if (namespace.members) {
if (namespace.members.has(declaration.name.name)) { if (namespace.members.has(declaration.name.text)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(declaration.name.name, enm); namespace.members.set(declaration.name.text, enm);
} else if (enm.is(ElementFlags.EXPORTED)) { } else if (enm.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
@ -597,7 +596,7 @@ export class Program extends DiagnosticEmitter {
} }
private initializeEnumValue(declaration: EnumValueDeclaration, enm: Enum): void { private initializeEnumValue(declaration: EnumValueDeclaration, enm: Enum): void {
var name = declaration.name.name; var name = declaration.name.text;
var internalName = declaration.fileLevelInternalName; var internalName = declaration.fileLevelInternalName;
if (enm.members) { if (enm.members) {
if (enm.members.has(name)) { if (enm.members.has(name)) {
@ -619,19 +618,19 @@ export class Program extends DiagnosticEmitter {
private setExportAndCheckLibrary(name: string, element: Element, identifier: IdentifierExpression): void { private setExportAndCheckLibrary(name: string, element: Element, identifier: IdentifierExpression): void {
this.exports.set(name, element); this.exports.set(name, element);
if (identifier.range.source.isLibrary) { // add global alias if (identifier.range.source.isLibrary) { // add global alias
if (this.elements.has(identifier.name)) if (this.elements.has(identifier.text))
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, identifier.range, identifier.name); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, identifier.range, identifier.text);
else { else {
element.internalName = identifier.name; element.internalName = identifier.text;
this.elements.set(identifier.name, element); this.elements.set(identifier.text, element);
} }
} }
} }
private initializeExport(member: ExportMember, internalPath: string | null, queuedExports: Map<string,QueuedExport>): void { private initializeExport(member: ExportMember, internalPath: string | null, queuedExports: Map<string,QueuedExport>): void {
var externalName = member.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name; var externalName = member.range.source.internalPath + PATH_DELIMITER + member.externalName.text;
if (this.exports.has(externalName)) { if (this.exports.has(externalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalName.range, externalName);
return; return;
} }
var referencedName: string; var referencedName: string;
@ -640,17 +639,17 @@ export class Program extends DiagnosticEmitter {
// export local element // export local element
if (internalPath == null) { if (internalPath == null) {
referencedName = member.range.source.internalPath + PATH_DELIMITER + member.identifier.name; referencedName = member.range.source.internalPath + PATH_DELIMITER + member.name.text;
// resolve right away if the element exists // resolve right away if the element exists
if (referencedElement = this.elements.get(referencedName)) { if (referencedElement = this.elements.get(referencedName)) {
this.setExportAndCheckLibrary(externalName, referencedElement, member.externalIdentifier); this.setExportAndCheckLibrary(externalName, referencedElement, member.externalName);
return; return;
} }
// otherwise queue it // otherwise queue it
if (queuedExports.has(externalName)) { if (queuedExports.has(externalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalName.range, externalName);
return; return;
} }
queuedExport = new QueuedExport(); queuedExport = new QueuedExport();
@ -661,11 +660,11 @@ export class Program extends DiagnosticEmitter {
// export external element // export external element
} else { } else {
referencedName = (<string>internalPath) + PATH_DELIMITER + member.identifier.name; referencedName = (<string>internalPath) + PATH_DELIMITER + member.name.text;
// resolve right away if the export exists // resolve right away if the export exists
if (referencedElement = this.elements.get(referencedName)) { if (referencedElement = this.elements.get(referencedName)) {
this.setExportAndCheckLibrary(externalName, referencedElement, member.externalIdentifier); this.setExportAndCheckLibrary(externalName, referencedElement, member.externalName);
return; return;
} }
@ -674,7 +673,7 @@ export class Program extends DiagnosticEmitter {
while (queuedExport = queuedExports.get(referencedName)) { while (queuedExport = queuedExports.get(referencedName)) {
if (queuedExport.isReExport) { if (queuedExport.isReExport) {
if (referencedElement = this.exports.get(queuedExport.referencedName)) { if (referencedElement = this.exports.get(queuedExport.referencedName)) {
this.setExportAndCheckLibrary(externalName, referencedElement, member.externalIdentifier); this.setExportAndCheckLibrary(externalName, referencedElement, member.externalName);
return; return;
} }
referencedName = queuedExport.referencedName; referencedName = queuedExport.referencedName;
@ -683,7 +682,7 @@ export class Program extends DiagnosticEmitter {
seen.add(queuedExport); seen.add(queuedExport);
} else { } else {
if (referencedElement = this.elements.get(queuedExport.referencedName)) { if (referencedElement = this.elements.get(queuedExport.referencedName)) {
this.setExportAndCheckLibrary(externalName, referencedElement, member.externalIdentifier); this.setExportAndCheckLibrary(externalName, referencedElement, member.externalName);
return; return;
} }
break; break;
@ -692,7 +691,7 @@ export class Program extends DiagnosticEmitter {
// otherwise queue it // otherwise queue it
if (queuedExports.has(externalName)) { if (queuedExports.has(externalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalName.range, externalName);
return; return;
} }
queuedExport = new QueuedExport(); queuedExport = new QueuedExport();
@ -709,7 +708,7 @@ export class Program extends DiagnosticEmitter {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
var prototype = new FunctionPrototype(this, declaration.name.name, internalName, declaration, null); var prototype = new FunctionPrototype(this, declaration.name.text, internalName, declaration, null);
prototype.namespace = namespace; prototype.namespace = namespace;
this.elements.set(internalName, prototype); this.elements.set(internalName, prototype);
@ -717,13 +716,13 @@ export class Program extends DiagnosticEmitter {
if (namespace) { if (namespace) {
if (namespace.members) { if (namespace.members) {
if (namespace.members.has(declaration.name.name)) { if (namespace.members.has(declaration.name.text)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(declaration.name.name, prototype); namespace.members.set(declaration.name.text, prototype);
} else if (prototype.is(ElementFlags.EXPORTED)) { } else if (prototype.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
@ -739,7 +738,7 @@ export class Program extends DiagnosticEmitter {
for (var i = 0, k = declarations.length; i < k; ++i) for (var i = 0, k = declarations.length; i < k; ++i)
this.initializeImport(declarations[i], statement.internalPath, queuedExports, queuedImports); this.initializeImport(declarations[i], statement.internalPath, queuedExports, queuedImports);
} else if (statement.namespaceName) { } else if (statement.namespaceName) {
var internalName = statement.range.source.internalPath + "/" + statement.namespaceName.name; var internalName = statement.range.source.internalPath + "/" + statement.namespaceName.text;
if (this.elements.has(internalName)) { if (this.elements.has(internalName)) {
this.error(DiagnosticCode.Duplicate_identifier_0, statement.namespaceName.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, statement.namespaceName.range, internalName);
return; return;
@ -755,7 +754,7 @@ export class Program extends DiagnosticEmitter {
return; return;
} }
var referencedName = internalPath + PATH_DELIMITER + declaration.externalIdentifier.name; var referencedName = internalPath + PATH_DELIMITER + declaration.externalName.text;
// resolve right away if the export exists // resolve right away if the export exists
if (this.exports.has(referencedName)) { if (this.exports.has(referencedName)) {
@ -799,7 +798,7 @@ export class Program extends DiagnosticEmitter {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
var prototype = new InterfacePrototype(this, declaration.name.name, internalName, declaration); var prototype = new InterfacePrototype(this, declaration.name.text, internalName, declaration);
prototype.namespace = namespace; prototype.namespace = namespace;
this.elements.set(internalName, prototype); this.elements.set(internalName, prototype);
@ -850,7 +849,7 @@ export class Program extends DiagnosticEmitter {
var namespace = this.elements.get(internalName); var namespace = this.elements.get(internalName);
if (!namespace) { if (!namespace) {
namespace = new Namespace(this, declaration.name.name, internalName, declaration); namespace = new Namespace(this, declaration.name.text, internalName, declaration);
namespace.namespace = parentNamespace; namespace.namespace = parentNamespace;
this.elements.set(internalName, namespace); this.elements.set(internalName, namespace);
this.checkInternalDecorators(namespace, declaration); this.checkInternalDecorators(namespace, declaration);
@ -858,13 +857,13 @@ export class Program extends DiagnosticEmitter {
if (parentNamespace) { if (parentNamespace) {
if (parentNamespace.members) { if (parentNamespace.members) {
if (parentNamespace.members.has(declaration.name.name)) { if (parentNamespace.members.has(declaration.name.text)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
return; return;
} }
} else } else
parentNamespace.members = new Map(); parentNamespace.members = new Map();
parentNamespace.members.set(declaration.name.name, namespace); parentNamespace.members.set(declaration.name.text, namespace);
} else if (namespace.is(ElementFlags.EXPORTED)) { } else if (namespace.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) { if (this.exports.has(internalName)) {
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName); this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
@ -916,7 +915,7 @@ export class Program extends DiagnosticEmitter {
private initializeTypeAlias(declaration: TypeDeclaration, namespace: Element | null = null): void { private initializeTypeAlias(declaration: TypeDeclaration, namespace: Element | null = null): void {
// type aliases are program globals // type aliases are program globals
// TODO: what about namespaced types? // TODO: what about namespaced types?
var name = declaration.name.name; var name = declaration.name.text;
if (this.types.has(name) || this.typeAliases.has(name)) { if (this.types.has(name) || this.typeAliases.has(name)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name);
return; return;
@ -934,7 +933,7 @@ export class Program extends DiagnosticEmitter {
continue; continue;
} }
var global = new Global(this, declaration.name.name, internalName, declaration, /* resolved later */ Type.void); var global = new Global(this, declaration.name.text, internalName, declaration, /* resolved later */ Type.void);
global.namespace = namespace; global.namespace = namespace;
this.elements.set(internalName, global); this.elements.set(internalName, global);
@ -942,13 +941,13 @@ export class Program extends DiagnosticEmitter {
if (namespace) { if (namespace) {
if (namespace.members) { if (namespace.members) {
if (namespace.members.has(declaration.name.name)) { if (namespace.members.has(declaration.name.text)) {
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
continue; continue;
} }
} else } else
namespace.members = new Map(); namespace.members = new Map();
namespace.members.set(declaration.name.name, global); namespace.members.set(declaration.name.text, global);
} else if (global.is(ElementFlags.EXPORTED)) { } else if (global.is(ElementFlags.EXPORTED)) {
if (this.exports.has(internalName)) if (this.exports.has(internalName))
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName); this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
@ -960,8 +959,8 @@ export class Program extends DiagnosticEmitter {
/** Resolves a {@link TypeNode} to a concrete {@link Type}. */ /** Resolves a {@link TypeNode} to a concrete {@link Type}. */
resolveType(node: TypeNode, contextualTypeArguments: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null { resolveType(node: TypeNode, contextualTypeArguments: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null {
var globalName = node.identifier.name; var globalName = node.name.text;
var localName = node.range.source.internalPath + PATH_DELIMITER + node.identifier.name; var localName = node.range.source.internalPath + PATH_DELIMITER + node.name.text;
var element: Element | null; var element: Element | null;
@ -1008,7 +1007,7 @@ export class Program extends DiagnosticEmitter {
return type; return type;
if (reportNotFound) if (reportNotFound)
this.error(DiagnosticCode.Cannot_find_name_0, node.identifier.range, globalName); this.error(DiagnosticCode.Cannot_find_name_0, node.name.range, globalName);
return null; return null;
} }
@ -1037,7 +1036,7 @@ export class Program extends DiagnosticEmitter {
/** Resolves an identifier to the element it refers to. */ /** Resolves an identifier to the element it refers to. */
resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function | null, contextualEnum: Enum | null = null): ResolvedElement | null { resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function | null, contextualEnum: Enum | null = null): ResolvedElement | null {
var name = identifier.name; var name = identifier.text;
var element: Element | null; var element: Element | null;
var namespace: Element | null; var namespace: Element | null;
@ -1086,7 +1085,7 @@ export class Program extends DiagnosticEmitter {
var target = resolvedElement.element; var target = resolvedElement.element;
// at this point we know exactly what the target is, so look up the element within // at this point we know exactly what the target is, so look up the element within
var propertyName = propertyAccess.property.name; var propertyName = propertyAccess.property.text;
var targetType: Type; var targetType: Type;
var member: Element | null; var member: Element | null;
@ -1608,7 +1607,7 @@ export class FunctionPrototype extends Element {
if ((k = this.classTypeArguments.length) != classTypeParameters.length) if ((k = this.classTypeArguments.length) != classTypeParameters.length)
throw new Error("type argument count mismatch"); throw new Error("type argument count mismatch");
for (i = 0; i < k; ++i) for (i = 0; i < k; ++i)
contextualTypeArguments.set(classTypeParameters[i].identifier.name, this.classTypeArguments[i]); contextualTypeArguments.set(classTypeParameters[i].name.text, this.classTypeArguments[i]);
} }
// override call specific contextual type arguments // override call specific contextual type arguments
@ -1617,7 +1616,7 @@ export class FunctionPrototype extends Element {
if (k != functionTypeParameters.length) if (k != functionTypeParameters.length)
throw new Error("type argument count mismatch"); throw new Error("type argument count mismatch");
for (i = 0; i < k; ++i) for (i = 0; i < k; ++i)
contextualTypeArguments.set(functionTypeParameters[i].identifier.name, functionTypeArguments[i]); contextualTypeArguments.set(functionTypeParameters[i].name.text, functionTypeArguments[i]);
} }
// resolve parameters // resolve parameters
@ -1631,7 +1630,7 @@ export class FunctionPrototype extends Element {
typeNode = assert(parameterDeclaration.type); typeNode = assert(parameterDeclaration.type);
var parameterType = this.program.resolveType(typeNode, contextualTypeArguments, true); // reports var parameterType = this.program.resolveType(typeNode, contextualTypeArguments, true); // reports
if (parameterType) { if (parameterType) {
parameters[i] = new Parameter(parameterDeclaration.name.name, parameterType, parameterDeclaration.initializer); parameters[i] = new Parameter(parameterDeclaration.name.text, parameterType, parameterDeclaration.initializer);
parameterTypes[i] = parameterType; parameterTypes[i] = parameterType;
} else } else
return null; return null;
@ -1785,9 +1784,12 @@ export class Function extends Element {
case NativeType.F64: temps = this.tempF64s; break; case NativeType.F64: temps = this.tempF64s; break;
default: throw new Error("concrete type expected"); default: throw new Error("concrete type expected");
} }
return temps && temps.length > 0 if (temps && temps.length) {
? temps.pop() var ret = temps.pop();
: this.addLocal(type); ret.type = type;
return ret;
}
return this.addLocal(type);
} }
/** Frees the temporary local for reuse. */ /** Frees the temporary local for reuse. */
@ -2023,7 +2025,7 @@ export class ClassPrototype extends Element {
if ((k = typeArguments.length) != declaration.typeParameters.length) if ((k = typeArguments.length) != declaration.typeParameters.length)
throw new Error("type argument count mismatch"); throw new Error("type argument count mismatch");
for (var i = 0; i < k; ++i) for (var i = 0; i < k; ++i)
contextualTypeArguments.set(declaration.typeParameters[i].identifier.name, typeArguments[i]); contextualTypeArguments.set(declaration.typeParameters[i].name.text, typeArguments[i]);
} else if (declaration.typeParameters.length) } else if (declaration.typeParameters.length)
throw new Error("type argument count mismatch"); throw new Error("type argument count mismatch");
@ -2172,7 +2174,7 @@ export class Class extends Element {
if (!this.contextualTypeArguments) if (!this.contextualTypeArguments)
this.contextualTypeArguments = new Map(); this.contextualTypeArguments = new Map();
for (i = 0; i < k; ++i) for (i = 0; i < k; ++i)
this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]); this.contextualTypeArguments.set(typeParameters[i].name.text, typeArguments[i]);
} }
} else if (typeParameters.length) } else if (typeParameters.length)
throw new Error("type argument count mismatch"); throw new Error("type argument count mismatch");

View File

@ -1,9 +1,13 @@
(module (module
(type $iv (func (param i32)))
(type $v (func)) (type $v (func))
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $start (; 0 ;) (type $v) (func $scoped/fn (; 0 ;) (type $iv) (param $0 i32)
(nop)
)
(func $start (; 1 ;) (type $v)
(local $0 i32) (local $0 i32)
(loop $continue|0 (loop $continue|0
(if (if
@ -42,5 +46,8 @@
) )
) )
) )
(call $scoped/fn
(i32.const 42)
)
) )
) )

View File

@ -12,3 +12,15 @@ for (let aGlobal /* that shadows */: i32 = 0; aGlobal < 1; ++aGlobal)
let /* still not */ aConstant: f32 = 10; let /* still not */ aConstant: f32 = 10;
} }
} }
// regression test: reused local should be updated with new requested type
function fn(c: i32): void {
{
let a: bool = 0;
}
{
let b: i32;
b = c; // should not issue a conversion warning mentioning 'bool'
}
}
fn(42);

View File

@ -1,4 +1,5 @@
(module (module
(type $iv (func (param i32)))
(type $v (func)) (type $v (func))
(global $scoped/aGlobal (mut i32) (i32.const 1)) (global $scoped/aGlobal (mut i32) (i32.const 1))
(global $scoped/aConstant i32 (i32.const 3)) (global $scoped/aConstant i32 (i32.const 3))
@ -7,7 +8,28 @@
(memory $0 1) (memory $0 1)
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $start (; 0 ;) (type $v) (func $scoped/fn (; 0 ;) (type $iv) (param $0 i32)
(local $1 i32)
;;@ scoped.ts:18:2
(block
;;@ scoped.ts:19:4
(set_local $1
;;@ scoped.ts:19:18
(i32.const 0)
)
)
;;@ scoped.ts:21:2
(block
;;@ scoped.ts:22:4
(nop)
;;@ scoped.ts:23:4
(set_local $1
;;@ scoped.ts:23:8
(get_local $0)
)
)
)
(func $start (; 1 ;) (type $v)
(local $0 i32) (local $0 i32)
(local $1 i32) (local $1 i32)
(local $2 i64) (local $2 i64)
@ -92,5 +114,10 @@
) )
) )
) )
;;@ scoped.ts:26:0
(call $scoped/fn
;;@ scoped.ts:26:3
(i32.const 42)
)
) )
) )