refactor(compiler): capture sourceSpan
when converting action bindings to output AST (#28055)
The `convertActionBinding()` now accepts an optional `baseSourceSpan`, which is the start point of the action expression being converted in the original source code. This is used to compute the original position of the output AST nodes. PR Close #28055
This commit is contained in:
parent
c0dac184cd
commit
497619f25d
@ -9,6 +9,7 @@
|
|||||||
import * as cdAst from '../expression_parser/ast';
|
import * as cdAst from '../expression_parser/ast';
|
||||||
import {Identifiers} from '../identifiers';
|
import {Identifiers} from '../identifiers';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
|
import {ParseSourceSpan} from '../parse_util';
|
||||||
|
|
||||||
export class EventHandlerVars { static event = o.variable('$event'); }
|
export class EventHandlerVars { static event = o.variable('$event'); }
|
||||||
|
|
||||||
@ -65,7 +66,8 @@ export type InterpolationFunction = (args: o.Expression[]) => o.Expression;
|
|||||||
*/
|
*/
|
||||||
export function convertActionBinding(
|
export function convertActionBinding(
|
||||||
localResolver: LocalResolver | null, implicitReceiver: o.Expression, action: cdAst.AST,
|
localResolver: LocalResolver | null, implicitReceiver: o.Expression, action: cdAst.AST,
|
||||||
bindingId: string, interpolationFunction?: InterpolationFunction): ConvertActionBindingResult {
|
bindingId: string, interpolationFunction?: InterpolationFunction,
|
||||||
|
baseSourceSpan?: ParseSourceSpan): ConvertActionBindingResult {
|
||||||
if (!localResolver) {
|
if (!localResolver) {
|
||||||
localResolver = new DefaultLocalResolver();
|
localResolver = new DefaultLocalResolver();
|
||||||
}
|
}
|
||||||
@ -92,8 +94,8 @@ export function convertActionBinding(
|
|||||||
},
|
},
|
||||||
action);
|
action);
|
||||||
|
|
||||||
const visitor =
|
const visitor = new _AstToIrVisitor(
|
||||||
new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction);
|
localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan);
|
||||||
const actionStmts: o.Statement[] = [];
|
const actionStmts: o.Statement[] = [];
|
||||||
flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
|
flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts);
|
||||||
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
||||||
@ -243,7 +245,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _localResolver: LocalResolver, private _implicitReceiver: o.Expression,
|
private _localResolver: LocalResolver, private _implicitReceiver: o.Expression,
|
||||||
private bindingId: string, private interpolationFunction: InterpolationFunction|undefined) {}
|
private bindingId: string, private interpolationFunction: InterpolationFunction|undefined,
|
||||||
|
private baseSourceSpan?: ParseSourceSpan) {}
|
||||||
|
|
||||||
visitBinary(ast: cdAst.Binary, mode: _Mode): any {
|
visitBinary(ast: cdAst.Binary, mode: _Mode): any {
|
||||||
let op: o.BinaryOperator;
|
let op: o.BinaryOperator;
|
||||||
@ -300,7 +303,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
return convertToStatementIfNeeded(
|
return convertToStatementIfNeeded(
|
||||||
mode,
|
mode,
|
||||||
new o.BinaryOperatorExpr(
|
new o.BinaryOperatorExpr(
|
||||||
op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression)));
|
op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression),
|
||||||
|
undefined, this.convertSourceSpan(ast.span)));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitChain(ast: cdAst.Chain, mode: _Mode): any {
|
visitChain(ast: cdAst.Chain, mode: _Mode): any {
|
||||||
@ -313,7 +317,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
return convertToStatementIfNeeded(
|
return convertToStatementIfNeeded(
|
||||||
mode, value.conditional(
|
mode, value.conditional(
|
||||||
this._visit(ast.trueExp, _Mode.Expression),
|
this._visit(ast.trueExp, _Mode.Expression),
|
||||||
this._visit(ast.falseExp, _Mode.Expression)));
|
this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span)));
|
||||||
}
|
}
|
||||||
|
|
||||||
visitPipe(ast: cdAst.BindingPipe, mode: _Mode): any {
|
visitPipe(ast: cdAst.BindingPipe, mode: _Mode): any {
|
||||||
@ -327,7 +331,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
if (ast instanceof BuiltinFunctionCall) {
|
if (ast instanceof BuiltinFunctionCall) {
|
||||||
fnResult = ast.converter(convertedArgs);
|
fnResult = ast.converter(convertedArgs);
|
||||||
} else {
|
} else {
|
||||||
fnResult = this._visit(ast.target !, _Mode.Expression).callFn(convertedArgs);
|
fnResult = this._visit(ast.target !, _Mode.Expression)
|
||||||
|
.callFn(convertedArgs, this.convertSourceSpan(ast.span));
|
||||||
}
|
}
|
||||||
return convertToStatementIfNeeded(mode, fnResult);
|
return convertToStatementIfNeeded(mode, fnResult);
|
||||||
}
|
}
|
||||||
@ -351,7 +356,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
}
|
}
|
||||||
return ast.expressions.length <= 9 ?
|
return ast.expressions.length <= 9 ?
|
||||||
o.importExpr(Identifiers.inlineInterpolate).callFn(args) :
|
o.importExpr(Identifiers.inlineInterpolate).callFn(args) :
|
||||||
o.importExpr(Identifiers.interpolate).callFn([args[0], o.literalArr(args.slice(1))]);
|
o.importExpr(Identifiers.interpolate).callFn([
|
||||||
|
args[0], o.literalArr(args.slice(1), undefined, this.convertSourceSpan(ast.span))
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any {
|
visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any {
|
||||||
@ -386,7 +393,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
|
ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ?
|
||||||
o.INFERRED_TYPE :
|
o.INFERRED_TYPE :
|
||||||
undefined;
|
undefined;
|
||||||
return convertToStatementIfNeeded(mode, o.literal(ast.value, type));
|
return convertToStatementIfNeeded(
|
||||||
|
mode, o.literal(ast.value, type, this.convertSourceSpan(ast.span)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
|
private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); }
|
||||||
@ -398,7 +406,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
|
`Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`);
|
||||||
}
|
}
|
||||||
return (args[0] as o.Expression).cast(o.DYNAMIC_TYPE);
|
return (args[0] as o.Expression).cast(o.DYNAMIC_TYPE, this.convertSourceSpan(ast.span));
|
||||||
}
|
}
|
||||||
|
|
||||||
const leftMostSafe = this.leftMostSafeNode(ast);
|
const leftMostSafe = this.leftMostSafeNode(ast);
|
||||||
@ -415,7 +423,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = receiver.callMethod(ast.name, args);
|
result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span));
|
||||||
}
|
}
|
||||||
return convertToStatementIfNeeded(mode, result);
|
return convertToStatementIfNeeded(mode, result);
|
||||||
}
|
}
|
||||||
@ -665,6 +673,27 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
throw new Error(`Temporary ${temporary.name} released out of order`);
|
throw new Error(`Temporary ${temporary.name} released out of order`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`.
|
||||||
|
*
|
||||||
|
* `ParseSpan` objects are relative to the start of the expression.
|
||||||
|
* This method converts these to full `ParseSourceSpan` objects that
|
||||||
|
* show where the span is within the overall source file.
|
||||||
|
*
|
||||||
|
* @param span the relative span to convert.
|
||||||
|
* @returns a `ParseSourceSpan` for the the given span or null if no
|
||||||
|
* `baseSourceSpan` was provided to this class.
|
||||||
|
*/
|
||||||
|
private convertSourceSpan(span: cdAst.ParseSpan) {
|
||||||
|
if (this.baseSourceSpan) {
|
||||||
|
const start = this.baseSourceSpan.start.moveBy(span.start);
|
||||||
|
const end = this.baseSourceSpan.start.moveBy(span.end);
|
||||||
|
return new ParseSourceSpan(start, end);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function flattenStatements(arg: any, output: o.Statement[]) {
|
function flattenStatements(arg: any, output: o.Statement[]) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user