Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions packages/compiler/src/expressions/compile-expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,7 @@ export function compileExpression(
ctx: CompilerContext,
options: CompileExpressionOptions = {}
): string {
let compiled = compileExprNode(expr, ctx, options);

// Post-process: Replace any remaining @variables references that weren't
// properly compiled (e.g., inside function calls like len(@variables.x))
// This matches agent-dsl's regex-based approach for comprehensive coverage.
compiled = compiled.replace(/@variables\.(\w+)/g, (_, varName) =>
resolveVariableRef(varName, ctx, expr.__cst?.range)
);

return compiled;
return compileExprNode(expr, ctx, options);
}

export interface CompileExpressionOptions {
Expand Down
40 changes: 40 additions & 0 deletions packages/compiler/test/expressions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,46 @@ describe('compileExpression', () => {
});

describe('@variables references', () => {
it.each([
['"@variables.missing"', '"@variables.missing"'],
['@variables.x == "@variables.x"', 'state.x == "@variables.x"'],
[
'concat("@variables.x", @variables.x, @variables.linked)',
'concat("@variables.x", state.x, variables.linked)',
],
[
'concat("say \\"@variables.missing\\"", @variables.x)',
'concat("say \\"@variables.missing\\"", state.x)',
],
])('preserves literal reference text in %s', (source, expected) => {
ctx.mutableVariableNames.add('x');
ctx.linkedVariableNames.add('linked');
const { rootNode } = parse(`value: ${source}\n`);
const mapping =
rootNode.namedChildren.find(node => node.type === 'mapping') ??
rootNode;
const result = new Dialect().parse(mapping, { value: ExpressionValue });

expect(result.diagnostics).toEqual([]);
expect(compileExpression(result.value.value, ctx)).toBe(expected);
expect(ctx.diagnostics).toEqual([]);
});

it('preserves template text while resolving interpolated references', () => {
ctx.mutableVariableNames.add('x');
const expr = new TemplateExpression([
new TemplateText('Use @variables.missing: '),
new TemplateInterpolation(
new MemberExpression(new AtIdentifier('variables'), 'x')
),
]);

expect(compileExpression(expr, ctx)).toBe(
'Use @variables.missing: {{state.x}}'
);
expect(ctx.diagnostics).toEqual([]);
});

it('should compile mutable @variables.x as state.x', () => {
ctx.mutableVariableNames.add('user_name');
const expr = new MemberExpression(
Expand Down
Loading