Skip to content
Closed
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
31 changes: 31 additions & 0 deletions src/preprocessor/preprocessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,37 @@ true
`);
});

test('evaluates binary expression with simple macro', () => {
const program = `
#define A 1
#if A + 1 == 2
true
#endif
`;

const ast = parse(program);
preprocessAst(ast);
expect(generate(ast)).toBe(`
true
`);
});

test('evaluates binary expression with nested macro', () => {
const program = `
#define A 1
#define B A + 1
#if B == 2
true
#endif
`;

const ast = parse(program);
preprocessAst(ast);
expect(generate(ast)).toBe(`
true
`);
});

test('define inside if/else is properly expanded when the if branch is chosen', () => {
const program = `
#define MACRO
Expand Down
20 changes: 19 additions & 1 deletion src/preprocessor/preprocessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,25 @@ const evaluteExpression = (node: PreprocessorAstNode, macros: Macros) =>
// TODO: Handle non-base-10 numbers. Should these be parsed in the peg grammar?
int_constant: (node) => parseInt(node.token, 10),
unary_defined: (node) => node.identifier.identifier in macros,
identifier: (node) => node.identifier,
identifier: (node) => {
// If the identifier is a pure number (e.g. "123"), parse it as an integer.
if (/^\d+$/.test(node.identifier)) {
return parseInt(node.identifier, 10);
}

// If the identifier contains no letters (e.g. "1+2", "(1+2)*3"), try to evaluate it as a JS expression.
if (!/[a-zA-Z]/.test(node.identifier)) {
try {
return eval(node.identifier);
} catch (e) {
// If evaluation fails, fall through to error below.
}
}
// If it's not a number or evaluatable expression, throw an error (likely an unknown macro or invalid expression).
throw new Error(
`Preprocessing error: Unknown identifier or unsupported expression "${node.identifier}"`
);
},
group: (node, visit) => visit(node.expression),
binary: ({ left, right, operator: { literal } }, visit) => {
switch (literal) {
Expand Down