refactor(compiler): make OutputAst
contain the moduleName, not the filePath (#16832).
The goal of this change is to simplify the emitters, as we will soon create a new one to emit TypeScript nodes directly.
This commit is contained in:

committed by
Chuck Jazdzewski

parent
3b28c75d1f
commit
6123b9c0c6
@ -19,7 +19,7 @@ export const CATCH_STACK_VAR = o.variable('stack', null, null);
|
||||
|
||||
export abstract class OutputEmitter {
|
||||
abstract emitStatements(
|
||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[],
|
||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
|
||||
preamble?: string|null): string;
|
||||
}
|
||||
|
||||
@ -31,21 +31,15 @@ class _EmittedLine {
|
||||
}
|
||||
|
||||
export class EmitterVisitorContext {
|
||||
static createRoot(exportedVars: string[]): EmitterVisitorContext {
|
||||
return new EmitterVisitorContext(exportedVars, 0);
|
||||
}
|
||||
static createRoot(): EmitterVisitorContext { return new EmitterVisitorContext(0); }
|
||||
|
||||
private _lines: _EmittedLine[];
|
||||
private _classes: o.ClassStmt[] = [];
|
||||
|
||||
constructor(private _exportedVars: string[], private _indent: number) {
|
||||
this._lines = [new _EmittedLine(_indent)];
|
||||
}
|
||||
constructor(private _indent: number) { this._lines = [new _EmittedLine(_indent)]; }
|
||||
|
||||
private get _currentLine(): _EmittedLine { return this._lines[this._lines.length - 1]; }
|
||||
|
||||
isExportedVar(varName: string): boolean { return this._exportedVars.indexOf(varName) !== -1; }
|
||||
|
||||
println(from?: {sourceSpan: ParseSourceSpan | null}|null, lastPart: string = ''): void {
|
||||
this.print(from || null, lastPart, true);
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ParseSourceSpan} from '../parse_util';
|
||||
|
||||
import * as o from './output_ast';
|
||||
|
||||
|
||||
/**
|
||||
* Create a new class stmts based on the given data.
|
||||
*/
|
||||
export function createClassStmt(config: {
|
||||
name: string,
|
||||
parent?: o.Expression,
|
||||
parentArgs?: o.Expression[],
|
||||
ctorParams?: o.FnParam[],
|
||||
builders: ClassBuilderPart | ClassBuilderPart[],
|
||||
modifiers?: o.StmtModifier[],
|
||||
sourceSpan?: ParseSourceSpan
|
||||
}): o.ClassStmt {
|
||||
const parentArgs = config.parentArgs || [];
|
||||
const superCtorStmts = config.parent ? [o.SUPER_EXPR.callFn(parentArgs).toStmt()] : [];
|
||||
const builder =
|
||||
concatClassBuilderParts(Array.isArray(config.builders) ? config.builders : [config.builders]);
|
||||
const ctor =
|
||||
new o.ClassMethod(null, config.ctorParams || [], superCtorStmts.concat(builder.ctorStmts));
|
||||
|
||||
return new o.ClassStmt(
|
||||
config.name, config.parent || null, builder.fields, builder.getters, ctor, builder.methods,
|
||||
config.modifiers || [], config.sourceSpan);
|
||||
}
|
||||
|
||||
function concatClassBuilderParts(builders: ClassBuilderPart[]) {
|
||||
return {
|
||||
fields: [].concat(...(builders.map((builder => builder.fields || [])) as any)),
|
||||
methods: [].concat(...(builders.map(builder => builder.methods || []) as any)),
|
||||
getters: [].concat(...(builders.map(builder => builder.getters || []) as any)),
|
||||
ctorStmts: [].concat(...(builders.map(builder => builder.ctorStmts || []) as any)),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects data for a generated class.
|
||||
*/
|
||||
export interface ClassBuilderPart {
|
||||
fields?: o.ClassField[];
|
||||
methods?: o.ClassMethod[];
|
||||
getters?: o.ClassGetter[];
|
||||
ctorStmts?: o.Statement[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects data for a generated class.
|
||||
*/
|
||||
export interface ClassBuilder {
|
||||
fields: o.ClassField[];
|
||||
methods: o.ClassMethod[];
|
||||
getters: o.ClassGetter[];
|
||||
ctorStmts: o.Statement[];
|
||||
}
|
@ -13,24 +13,21 @@ import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
||||
import * as o from './output_ast';
|
||||
import {ImportResolver} from './path_util';
|
||||
|
||||
export class JavaScriptEmitter implements OutputEmitter {
|
||||
constructor(private _importResolver: ImportResolver) {}
|
||||
|
||||
emitStatements(
|
||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[],
|
||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
|
||||
preamble: string = ''): string {
|
||||
const converter = new JsEmitterVisitor(genFilePath, this._importResolver);
|
||||
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||
const converter = new JsEmitterVisitor();
|
||||
const ctx = EmitterVisitorContext.createRoot();
|
||||
converter.visitAllStatements(stmts, ctx);
|
||||
|
||||
const preambleLines = preamble ? preamble.split('\n') : [];
|
||||
converter.importsWithPrefixes.forEach((prefix, importedFilePath) => {
|
||||
converter.importsWithPrefixes.forEach((prefix, importedModuleName) => {
|
||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||
preambleLines.push(
|
||||
`var ${prefix} = req` +
|
||||
`uire('${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}');`);
|
||||
`uire('${importedModuleName}');`);
|
||||
});
|
||||
|
||||
const sm =
|
||||
@ -47,46 +44,36 @@ export class JavaScriptEmitter implements OutputEmitter {
|
||||
class JsEmitterVisitor extends AbstractJsEmitterVisitor {
|
||||
importsWithPrefixes = new Map<string, string>();
|
||||
|
||||
constructor(private _genFilePath: string, private _importResolver: ImportResolver) { super(); }
|
||||
|
||||
private _resolveStaticSymbol(value: CompileIdentifierMetadata): StaticSymbol {
|
||||
const reference = value.reference;
|
||||
if (!(reference instanceof StaticSymbol)) {
|
||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
|
||||
}
|
||||
return this._importResolver.getImportAs(reference) || reference;
|
||||
}
|
||||
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
||||
const {name, filePath} = this._resolveStaticSymbol(ast.value);
|
||||
if (filePath != this._genFilePath) {
|
||||
let prefix = this.importsWithPrefixes.get(filePath);
|
||||
const {name, moduleName} = ast.value;
|
||||
if (moduleName) {
|
||||
let prefix = this.importsWithPrefixes.get(moduleName);
|
||||
if (prefix == null) {
|
||||
prefix = `i${this.importsWithPrefixes.size}`;
|
||||
this.importsWithPrefixes.set(filePath, prefix);
|
||||
this.importsWithPrefixes.set(moduleName, prefix);
|
||||
}
|
||||
ctx.print(ast, `${prefix}.`);
|
||||
}
|
||||
ctx.print(ast, name);
|
||||
ctx.print(ast, name !);
|
||||
return null;
|
||||
}
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||
super.visitDeclareVarStmt(stmt, ctx);
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.println(stmt, exportVar(stmt.name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
|
||||
super.visitDeclareFunctionStmt(stmt, ctx);
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.println(stmt, exportVar(stmt.name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||
super.visitDeclareClassStmt(stmt, ctx);
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.println(stmt, exportVar(stmt.name));
|
||||
}
|
||||
return null;
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
|
||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||
import {ParseSourceSpan} from '../parse_util';
|
||||
|
||||
//// Types
|
||||
@ -344,8 +343,8 @@ export class LiteralExpr extends Expression {
|
||||
|
||||
export class ExternalExpr extends Expression {
|
||||
constructor(
|
||||
public value: CompileIdentifierMetadata, type?: Type|null,
|
||||
public typeParams: Type[]|null = null, sourceSpan?: ParseSourceSpan|null) {
|
||||
public value: ExternalReference, type?: Type|null, public typeParams: Type[]|null = null,
|
||||
sourceSpan?: ParseSourceSpan|null) {
|
||||
super(type, sourceSpan);
|
||||
}
|
||||
visitExpression(visitor: ExpressionVisitor, context: any): any {
|
||||
@ -353,6 +352,9 @@ export class ExternalExpr extends Expression {
|
||||
}
|
||||
}
|
||||
|
||||
export class ExternalReference {
|
||||
constructor(public moduleName: string|null, public name: string|null, public runtime: any|null) {}
|
||||
}
|
||||
|
||||
export class ConditionalExpr extends Expression {
|
||||
public trueCase: Expression;
|
||||
@ -533,7 +535,8 @@ export const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null);
|
||||
//// Statements
|
||||
export enum StmtModifier {
|
||||
Final,
|
||||
Private
|
||||
Private,
|
||||
Exported
|
||||
}
|
||||
|
||||
export abstract class Statement {
|
||||
@ -1125,13 +1128,13 @@ export function variable(
|
||||
}
|
||||
|
||||
export function importExpr(
|
||||
id: CompileIdentifierMetadata, typeParams: Type[] | null = null,
|
||||
id: ExternalReference, typeParams: Type[] | null = null,
|
||||
sourceSpan?: ParseSourceSpan | null): ExternalExpr {
|
||||
return new ExternalExpr(id, null, typeParams, sourceSpan);
|
||||
}
|
||||
|
||||
export function importType(
|
||||
id: CompileIdentifierMetadata, typeParams: Type[] | null = null,
|
||||
id: ExternalReference, typeParams: Type[] | null = null,
|
||||
typeModifiers: TypeModifier[] | null = null): ExpressionType|null {
|
||||
return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
|
||||
}
|
||||
|
@ -11,13 +11,13 @@
|
||||
import * as o from './output_ast';
|
||||
import {debugOutputAstAsTypeScript} from './ts_emitter';
|
||||
|
||||
export function interpretStatements(statements: o.Statement[], resultVars: string[]): any[] {
|
||||
const stmtsWithReturn = statements.concat(
|
||||
[new o.ReturnStatement(o.literalArr(resultVars.map(resultVar => o.variable(resultVar))))]);
|
||||
export function interpretStatements(statements: o.Statement[]): {[key: string]: any} {
|
||||
const ctx = new _ExecutionContext(null, null, null, new Map<string, any>());
|
||||
const visitor = new StatementInterpreter();
|
||||
const result = visitor.visitAllStatements(stmtsWithReturn, ctx);
|
||||
return result != null ? result.value : null;
|
||||
visitor.visitAllStatements(statements, ctx);
|
||||
const result: {[key: string]: any} = {};
|
||||
ctx.exports.forEach((exportName) => { result[exportName] = ctx.vars.get(exportName); });
|
||||
return result;
|
||||
}
|
||||
|
||||
function _executeFunctionStatements(
|
||||
@ -32,6 +32,8 @@ function _executeFunctionStatements(
|
||||
}
|
||||
|
||||
class _ExecutionContext {
|
||||
exports: string[] = [];
|
||||
|
||||
constructor(
|
||||
public parent: _ExecutionContext|null, public instance: any, public className: string|null,
|
||||
public vars: Map<string, any>) {}
|
||||
@ -90,6 +92,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any {
|
||||
ctx.vars.set(stmt.name, stmt.value.visitExpression(this, ctx));
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.exports.push(stmt.name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitWriteVarExpr(expr: o.WriteVarExpr, ctx: _ExecutionContext): any {
|
||||
@ -185,6 +190,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: _ExecutionContext): any {
|
||||
const clazz = createDynamicClass(stmt, ctx, this);
|
||||
ctx.vars.set(stmt.name, clazz);
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.exports.push(stmt.name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitExpressionStmt(stmt: o.ExpressionStatement, ctx: _ExecutionContext): any {
|
||||
@ -219,9 +227,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
return new clazz(...args);
|
||||
}
|
||||
visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { return ast.value; }
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any {
|
||||
return ast.value.reference;
|
||||
}
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any { return ast.value.runtime; }
|
||||
visitConditionalExpr(ast: o.ConditionalExpr, ctx: _ExecutionContext): any {
|
||||
if (ast.condition.visitExpression(this, ctx)) {
|
||||
return ast.trueCase.visitExpression(this, ctx);
|
||||
@ -246,6 +252,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: _ExecutionContext): any {
|
||||
const paramNames = stmt.params.map((param) => param.name);
|
||||
ctx.vars.set(stmt.name, _declareFn(paramNames, stmt.statements, ctx, this));
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.exports.push(stmt.name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: _ExecutionContext): any {
|
||||
|
@ -35,19 +35,24 @@ function evalExpression(
|
||||
return new Function(...fnArgNames.concat(fnBody))(...fnArgValues);
|
||||
}
|
||||
|
||||
export function jitStatements(
|
||||
sourceUrl: string, statements: o.Statement[], resultVars: string[]): any[] {
|
||||
export function jitStatements(sourceUrl: string, statements: o.Statement[]): {[key: string]: any} {
|
||||
const converter = new JitEmitterVisitor();
|
||||
const ctx = EmitterVisitorContext.createRoot(resultVars);
|
||||
const returnStmt =
|
||||
new o.ReturnStatement(o.literalArr(resultVars.map(resultVar => o.variable(resultVar))));
|
||||
converter.visitAllStatements(statements.concat([returnStmt]), ctx);
|
||||
const ctx = EmitterVisitorContext.createRoot();
|
||||
converter.visitAllStatements(statements, ctx);
|
||||
converter.createReturnStmt(ctx);
|
||||
return evalExpression(sourceUrl, ctx, converter.getArgs());
|
||||
}
|
||||
|
||||
class JitEmitterVisitor extends AbstractJsEmitterVisitor {
|
||||
private _evalArgNames: string[] = [];
|
||||
private _evalArgValues: any[] = [];
|
||||
private _evalExportedVars: string[] = [];
|
||||
|
||||
createReturnStmt(ctx: EmitterVisitorContext) {
|
||||
const stmt = new o.ReturnStatement(new o.LiteralMapExpr(this._evalExportedVars.map(
|
||||
resultVar => new o.LiteralMapEntry(resultVar, o.variable(resultVar)))));
|
||||
stmt.visitStatement(this, ctx);
|
||||
}
|
||||
|
||||
getArgs(): {[key: string]: any} {
|
||||
const result: {[key: string]: any} = {};
|
||||
@ -58,15 +63,36 @@ class JitEmitterVisitor extends AbstractJsEmitterVisitor {
|
||||
}
|
||||
|
||||
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
||||
const value = ast.value.reference;
|
||||
const value = ast.value.runtime;
|
||||
let id = this._evalArgValues.indexOf(value);
|
||||
if (id === -1) {
|
||||
id = this._evalArgValues.length;
|
||||
this._evalArgValues.push(value);
|
||||
const name = identifierName(ast.value) || 'val';
|
||||
const name = identifierName({reference: ast.value.runtime}) || 'val';
|
||||
this._evalArgNames.push(`jit_${name}${id}`);
|
||||
}
|
||||
ctx.print(ast, this._evalArgNames[id]);
|
||||
return null;
|
||||
}
|
||||
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
this._evalExportedVars.push(stmt.name);
|
||||
}
|
||||
return super.visitDeclareVarStmt(stmt, ctx);
|
||||
}
|
||||
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
this._evalExportedVars.push(stmt.name);
|
||||
}
|
||||
return super.visitDeclareFunctionStmt(stmt, ctx);
|
||||
}
|
||||
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
this._evalExportedVars.push(stmt.name);
|
||||
}
|
||||
return super.visitDeclareClassStmt(stmt, ctx);
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StaticSymbol} from '../aot/static_symbol';
|
||||
|
||||
/**
|
||||
* Interface that defines how import statements should be generated.
|
||||
*/
|
||||
export abstract class ImportResolver {
|
||||
/**
|
||||
* Converts a file path to a module name that can be used as an `import.
|
||||
* I.e. `path/to/importedFile.ts` should be imported by `path/to/containingFile.ts`.
|
||||
*/
|
||||
abstract fileNameToModuleName(importedFilePath: string, containingFilePath: string): string|null;
|
||||
|
||||
/**
|
||||
* Converts the given StaticSymbol into another StaticSymbol that should be used
|
||||
* to generate the import from.
|
||||
*/
|
||||
abstract getImportAs(symbol: StaticSymbol): StaticSymbol|null;
|
||||
|
||||
/**
|
||||
* Determine the arity of a type.
|
||||
*/
|
||||
abstract getTypeArity(symbol: StaticSymbol): number|null;
|
||||
}
|
@ -12,18 +12,13 @@ import {CompileIdentifierMetadata} from '../compile_metadata';
|
||||
|
||||
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||
import * as o from './output_ast';
|
||||
import {ImportResolver} from './path_util';
|
||||
|
||||
const _debugFilePath = '/debug/lib';
|
||||
|
||||
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
||||
string {
|
||||
const converter = new _TsEmitterVisitor(_debugFilePath, {
|
||||
fileNameToModuleName(filePath: string, containingFilePath: string) { return filePath; },
|
||||
getImportAs(symbol: StaticSymbol | null) { return null; },
|
||||
getTypeArity: symbol => null
|
||||
});
|
||||
const ctx = EmitterVisitorContext.createRoot([]);
|
||||
const converter = new _TsEmitterVisitor();
|
||||
const ctx = EmitterVisitorContext.createRoot();
|
||||
const asts: any[] = Array.isArray(ast) ? ast : [ast];
|
||||
|
||||
asts.forEach((ast) => {
|
||||
@ -42,30 +37,27 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T
|
||||
|
||||
|
||||
export class TypeScriptEmitter implements OutputEmitter {
|
||||
constructor(private _importResolver: ImportResolver) {}
|
||||
|
||||
emitStatements(
|
||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[], exportedVars: string[],
|
||||
srcFilePath: string, genFilePath: string, stmts: o.Statement[],
|
||||
preamble: string = ''): string {
|
||||
const converter = new _TsEmitterVisitor(genFilePath, this._importResolver);
|
||||
const converter = new _TsEmitterVisitor();
|
||||
|
||||
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||
const ctx = EmitterVisitorContext.createRoot();
|
||||
|
||||
converter.visitAllStatements(stmts, ctx);
|
||||
|
||||
const preambleLines = preamble ? preamble.split('\n') : [];
|
||||
converter.reexports.forEach((reexports, exportedFilePath) => {
|
||||
converter.reexports.forEach((reexports, exportedModuleName) => {
|
||||
const reexportsCode =
|
||||
reexports.map(reexport => `${reexport.name} as ${reexport.as}`).join(',');
|
||||
preambleLines.push(
|
||||
`export {${reexportsCode}} from '${this._importResolver.fileNameToModuleName(exportedFilePath, genFilePath)}';`);
|
||||
preambleLines.push(`export {${reexportsCode}} from '${exportedModuleName}';`);
|
||||
});
|
||||
|
||||
converter.importsWithPrefixes.forEach((prefix, importedFilePath) => {
|
||||
converter.importsWithPrefixes.forEach((prefix, importedModuleName) => {
|
||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||
preambleLines.push(
|
||||
`imp` +
|
||||
`ort * as ${prefix} from '${this._importResolver.fileNameToModuleName(importedFilePath, genFilePath)}';`);
|
||||
`ort * as ${prefix} from '${importedModuleName}';`);
|
||||
});
|
||||
|
||||
const sm =
|
||||
@ -82,9 +74,7 @@ export class TypeScriptEmitter implements OutputEmitter {
|
||||
class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
||||
private typeExpression = 0;
|
||||
|
||||
constructor(private _genFilePath: string, private _importResolver: ImportResolver) {
|
||||
super(false);
|
||||
}
|
||||
constructor() { super(false); }
|
||||
|
||||
importsWithPrefixes = new Map<string, string>();
|
||||
reexports = new Map<string, {name: string, as: string}[]>();
|
||||
@ -136,20 +126,21 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
}
|
||||
|
||||
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
||||
if (ctx.isExportedVar(stmt.name) && stmt.value instanceof o.ExternalExpr && !stmt.type) {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported) && stmt.value instanceof o.ExternalExpr &&
|
||||
!stmt.type) {
|
||||
// check for a reexport
|
||||
const {name, filePath, members} = this._resolveStaticSymbol(stmt.value.value);
|
||||
if (members !.length === 0 && filePath !== this._genFilePath) {
|
||||
let reexports = this.reexports.get(filePath);
|
||||
const {name, moduleName} = stmt.value.value;
|
||||
if (moduleName) {
|
||||
let reexports = this.reexports.get(moduleName);
|
||||
if (!reexports) {
|
||||
reexports = [];
|
||||
this.reexports.set(filePath, reexports);
|
||||
this.reexports.set(moduleName, reexports);
|
||||
}
|
||||
reexports.push({name, as: stmt.name});
|
||||
reexports.push({name: name !, as: stmt.name});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.print(stmt, `export `);
|
||||
}
|
||||
if (stmt.hasModifier(o.StmtModifier.Final)) {
|
||||
@ -187,7 +178,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
|
||||
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
||||
ctx.pushClass(stmt);
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.print(stmt, `export `);
|
||||
}
|
||||
ctx.print(stmt, `class ${stmt.name}`);
|
||||
@ -273,7 +264,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
}
|
||||
|
||||
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
|
||||
if (ctx.isExportedVar(stmt.name)) {
|
||||
if (stmt.hasModifier(o.StmtModifier.Exported)) {
|
||||
ctx.print(stmt, `export `);
|
||||
}
|
||||
ctx.print(stmt, `function ${stmt.name}(`);
|
||||
@ -376,40 +367,18 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
}, params, ctx, ',');
|
||||
}
|
||||
|
||||
private _resolveStaticSymbol(value: CompileIdentifierMetadata):
|
||||
{name: string, filePath: string, members?: string[], arity?: number} {
|
||||
const reference = value.reference;
|
||||
if (!(reference instanceof StaticSymbol)) {
|
||||
throw new Error(`Internal error: unknown identifier ${JSON.stringify(value)}`);
|
||||
}
|
||||
const arity = this._importResolver.getTypeArity(reference) || undefined;
|
||||
const importReference = this._importResolver.getImportAs(reference) || reference;
|
||||
return {
|
||||
name: importReference.name,
|
||||
filePath: importReference.filePath,
|
||||
members: importReference.members, arity
|
||||
};
|
||||
}
|
||||
|
||||
private _visitIdentifier(
|
||||
value: CompileIdentifierMetadata, typeParams: o.Type[]|null,
|
||||
ctx: EmitterVisitorContext): void {
|
||||
const {name, filePath, members, arity} = this._resolveStaticSymbol(value);
|
||||
if (filePath != this._genFilePath) {
|
||||
let prefix = this.importsWithPrefixes.get(filePath);
|
||||
value: o.ExternalReference, typeParams: o.Type[]|null, ctx: EmitterVisitorContext): void {
|
||||
const {name, moduleName} = value;
|
||||
if (moduleName) {
|
||||
let prefix = this.importsWithPrefixes.get(moduleName);
|
||||
if (prefix == null) {
|
||||
prefix = `i${this.importsWithPrefixes.size}`;
|
||||
this.importsWithPrefixes.set(filePath, prefix);
|
||||
this.importsWithPrefixes.set(moduleName, prefix);
|
||||
}
|
||||
ctx.print(null, `${prefix}.`);
|
||||
}
|
||||
if (members !.length) {
|
||||
ctx.print(null, name);
|
||||
ctx.print(null, '.');
|
||||
ctx.print(null, members !.join('.'));
|
||||
} else {
|
||||
ctx.print(null, name);
|
||||
}
|
||||
ctx.print(null, name !);
|
||||
|
||||
if (this.typeExpression > 0) {
|
||||
// If we are in a type expression that refers to a generic type then supply
|
||||
@ -417,19 +386,10 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||
// supplied, supply any as the type. Outside a type expression the reference
|
||||
// should not supply type parameters and be treated as a simple value reference
|
||||
// to the constructor function itself.
|
||||
const suppliedParameters = (typeParams && typeParams.length) || 0;
|
||||
const additionalParameters = (arity || 0) - suppliedParameters;
|
||||
if (suppliedParameters > 0 || additionalParameters > 0) {
|
||||
const suppliedParameters = typeParams || [];
|
||||
if (suppliedParameters.length > 0) {
|
||||
ctx.print(null, `<`);
|
||||
if (suppliedParameters > 0) {
|
||||
this.visitAllObjects(type => type.visitType(this, ctx), typeParams !, ctx, ',');
|
||||
}
|
||||
if (additionalParameters > 0) {
|
||||
for (let i = 0; i < additionalParameters; i++) {
|
||||
if (i > 0 || suppliedParameters > 0) ctx.print(null, ',');
|
||||
ctx.print(null, 'any');
|
||||
}
|
||||
}
|
||||
this.visitAllObjects(type => type.visitType(this, ctx), typeParams !, ctx, ',');
|
||||
ctx.print(null, `>`);
|
||||
}
|
||||
}
|
||||
|
@ -7,17 +7,19 @@
|
||||
*/
|
||||
|
||||
|
||||
import {ValueTransformer, visitValue} from '../util';
|
||||
import {OutputContext, ValueTransformer, visitValue} from '../util';
|
||||
|
||||
import * as o from './output_ast';
|
||||
|
||||
export const QUOTED_KEYS = '$quoted$';
|
||||
|
||||
export function convertValueToOutputAst(value: any, type: o.Type | null = null): o.Expression {
|
||||
return visitValue(value, new _ValueOutputAstTransformer(), type);
|
||||
export function convertValueToOutputAst(
|
||||
ctx: OutputContext, value: any, type: o.Type | null = null): o.Expression {
|
||||
return visitValue(value, new _ValueOutputAstTransformer(ctx), type);
|
||||
}
|
||||
|
||||
class _ValueOutputAstTransformer implements ValueTransformer {
|
||||
constructor(private ctx: OutputContext) {}
|
||||
visitArray(arr: any[], type: o.Type): o.Expression {
|
||||
return o.literalArr(arr.map(value => visitValue(value, this, null)), type);
|
||||
}
|
||||
@ -38,7 +40,7 @@ class _ValueOutputAstTransformer implements ValueTransformer {
|
||||
if (value instanceof o.Expression) {
|
||||
return value;
|
||||
} else {
|
||||
return o.importExpr({reference: value});
|
||||
return this.ctx.importExpr(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user