Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 119x 119x 103x 103x 103x 103x 3x 100x 100x 100x 100x 85x 10x 40x 10x 10x 10x 10x 7x | import type { ExpressionState } from '../../expression-state.js';
import { TypedValue } from '../../typed-value.js';
import { SpelNodeImpl } from '../spel-node.js';
import { NodeType } from '../../language/node-type.js';
import { SpelEvaluationException } from '../../error/spel-evaluation-exception.js';
import { SpelMessage } from '../../error/spel-message.js';
export class MethodReference extends SpelNodeImpl {
private readonly methodName: string;
constructor(startPos: number, endPos: number, methodName: string, ...args: SpelNodeImpl[]) {
super(NodeType.METHOD_REFERENCE, startPos, endPos, ...args);
this.methodName = methodName;
}
public getMethodName(): string {
return this.methodName;
}
public getValueInternal(state: ExpressionState): TypedValue {
const target = state.getThis().getValue();
// Arguments resolve at the expression's root scope, not at the receiver's.
const argumentScope = state.getArgumentScope();
const argValues = this.children.map((c) => c.getValue(argumentScope).getValue());
if (target === null || target === undefined) {
throw new SpelEvaluationException(
this.startPos,
SpelMessage.METHOD_NOT_FOUND,
this.methodName,
'null',
);
}
const context = state.getEvaluationContext();
for (const resolver of context.getMethodResolvers()) {
const result = resolver.resolve(context, target, this.methodName, argValues);
if (result !== null) {
return result;
}
}
// Fallback: try property accessor chain (e.g., TypeDescriptor.staticMethods)
for (const accessor of context.getPropertyAccessors()) {
Iif (accessor.canRead(context, target, this.methodName)) {
const propValue = accessor.read(context, target, this.methodName).getValue();
if (typeof propValue === 'function') {
try {
return new TypedValue((propValue as (...a: unknown[]) => unknown)(...argValues));
} catch (e) {
throw new SpelEvaluationException(
this.startPos,
SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION,
this.methodName,
(e as Error).message,
);
}
}
break;
}
}
// Also try function registry
try {
const fn = state.lookupFunction(this.methodName);
return new TypedValue(fn(...argValues));
} catch {
// not found in functions
}
throw new SpelEvaluationException(
this.startPos,
SpelMessage.METHOD_NOT_FOUND,
this.methodName,
typeof target,
);
}
public toStringAST(): string {
return `${this.methodName}(${this.children.map((c) => c.toStringAST()).join(', ')})`;
}
}
|