From bd64c91ca47bf840deb83bd51332467b7c97dd54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Mon, 2 Nov 2020 12:44:54 +0100 Subject: [PATCH] Fix the interpretation of @#elseif clauses within an @#ifdef or @#ifndef (cherry picked from commit 5d564eed071b009ae382440435ede70be163ca39) --- src/macro/Directives.cc | 62 +++++++++++++++++------------------------ src/macro/Directives.hh | 14 +++++----- 2 files changed, 32 insertions(+), 44 deletions(-) diff --git a/src/macro/Directives.cc b/src/macro/Directives.cc index 64fa4854..d12a0f29 100644 --- a/src/macro/Directives.cc +++ b/src/macro/Directives.cc @@ -245,19 +245,35 @@ For::interpret(ostream &output, vector<filesystem::path> &paths) void If::interpret(ostream &output, vector<filesystem::path> &paths) { + bool first_clause = true; for (const auto & [expr, body] : expr_and_body) try { - auto tmp = expr->eval(); - RealPtr dp = dynamic_pointer_cast<Real>(tmp); - BoolPtr bp = dynamic_pointer_cast<Bool>(tmp); - if (!bp && !dp) - error(StackTrace("@#if", - "The condition must evaluate to a boolean or a double", location)); - if ((bp && *bp) || (dp && *dp)) + if ((ifdef || ifndef) && first_clause) { - interpretBody(body, output, paths); - break; + first_clause = false; + VariablePtr vp = dynamic_pointer_cast<Variable>(expr); + assert(vp); + if ((ifdef && env.isVariableDefined(vp->getName())) + || (ifndef && !env.isVariableDefined(vp->getName()))) + { + interpretBody(body, output, paths); + break; + } + } + else + { + auto tmp = expr->eval(); + RealPtr dp = dynamic_pointer_cast<Real>(tmp); + BoolPtr bp = dynamic_pointer_cast<Bool>(tmp); + if (!bp && !dp) + error(StackTrace("@#if", + "The condition must evaluate to a boolean or a double", location)); + if ((bp && *bp) || (dp && *dp)) + { + interpretBody(body, output, paths); + break; + } } } catch (StackTrace &ex) @@ -286,31 +302,3 @@ If::interpretBody(const vector<DirectivePtr> &body, ostream &output, vector<file statement->interpret(output, paths); } } - -void -Ifdef::interpret(ostream &output, vector<filesystem::path> &paths) -{ - for (const auto & [expr, body] : expr_and_body) - if (VariablePtr vp = dynamic_pointer_cast<Variable>(expr); - dynamic_pointer_cast<BaseType>(expr) - || (vp && env.isVariableDefined(vp->getName()))) - { - interpretBody(body, output, paths); - break; - } - printEndLineInfo(output); -} - -void -Ifndef::interpret(ostream &output, vector<filesystem::path> &paths) -{ - for (const auto & [expr, body] : expr_and_body) - if (VariablePtr vp = dynamic_pointer_cast<Variable>(expr); - dynamic_pointer_cast<BaseType>(expr) - || (vp && !env.isVariableDefined(vp->getName()))) - { - interpretBody(body, output, paths); - break; - } - printEndLineInfo(output); -} diff --git a/src/macro/Directives.hh b/src/macro/Directives.hh index db71ae3f..cc7ec6e1 100644 --- a/src/macro/Directives.hh +++ b/src/macro/Directives.hh @@ -175,24 +175,25 @@ namespace macro * If there is an `else` statement it is the last element in the vector. Its condition is true. */ const vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body; + const bool ifdef, ifndef; public: If(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg, - Environment &env_arg, Tokenizer::location location_arg) : - Directive(env_arg, move(location_arg)), expr_and_body{move(expr_and_body_arg)} { } + Environment &env_arg, Tokenizer::location location_arg, + bool ifdef_arg = false, bool ifndef_arg = false) : + Directive(env_arg, move(location_arg)), expr_and_body{move(expr_and_body_arg)}, + ifdef{ifdef_arg}, ifndef{ifndef_arg} { } void interpret(ostream &output, vector<filesystem::path> &paths) override; protected: void interpretBody(const vector<DirectivePtr> &body, ostream &output, vector<filesystem::path> &paths); }; - class Ifdef : public If { public: Ifdef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg, Environment &env_arg, Tokenizer::location location_arg) : - If(move(expr_and_body_arg), env_arg, move(location_arg)) { } - void interpret(ostream &output, vector<filesystem::path> &paths) override; + If(move(expr_and_body_arg), env_arg, move(location_arg), true, false) { } }; @@ -201,8 +202,7 @@ namespace macro public: Ifndef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg, Environment &env_arg, Tokenizer::location location_arg) : - If(move(expr_and_body_arg), env_arg, move(location_arg)) { } - void interpret(ostream &output, vector<filesystem::path> &paths) override; + If(move(expr_and_body_arg), env_arg, move(location_arg), false, true) { } }; } #endif -- GitLab