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:
Tobias Bosch
2017-05-16 16:30:37 -07:00
committed by Chuck Jazdzewski
parent 3b28c75d1f
commit 6123b9c0c6
28 changed files with 589 additions and 774 deletions

View File

@ -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);
}

View File

@ -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[];
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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, `>`);
}
}

View File

@ -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);
}
}
}