diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc
index 72909abeaecf6c4d4c3fa7201a153d3a91ed52e5..7ff82308861b6e610e9ce938e8c3978d1e613419 100644
--- a/src/ParsingDriver.cc
+++ b/src/ParsingDriver.cc
@@ -3092,17 +3092,17 @@ ParsingDriver::add_external_function_arg(expr_t arg)
   stack_external_function_args.top().push_back(arg);
 }
 
-pair<bool, double>
+optional<int>
 ParsingDriver::is_there_one_integer_argument() const
 {
   if (stack_external_function_args.top().size() != 1)
-    return { false, 0 };
+    return nullopt;
 
   auto numNode = dynamic_cast<NumConstNode *>(stack_external_function_args.top().front());
   auto unaryNode = dynamic_cast<UnaryOpNode *>(stack_external_function_args.top().front());
 
   if (!numNode && !unaryNode)
-    return { false, 0 };
+    return nullopt;
 
   eval_context_t ectmp;
   double model_var_arg;
@@ -3114,12 +3114,12 @@ ParsingDriver::is_there_one_integer_argument() const
         }
       catch (ExprNode::EvalException &e)
         {
-          return { false, 0 };
+          return nullopt;
         }
     }
   else
     if (unaryNode->op_code != UnaryOpcode::uminus)
-      return { false, 0 };
+      return nullopt;
     else
       {
         try
@@ -3128,13 +3128,13 @@ ParsingDriver::is_there_one_integer_argument() const
           }
         catch (ExprNode::EvalException &e)
           {
-            return { false, 0 };
+            return nullopt;
           }
       }
 
   if (model_var_arg != floor(model_var_arg))
-    return { false, 0 };
-  return { true, model_var_arg };
+    return nullopt;
+  return static_cast<int>(model_var_arg);
 }
 
 expr_t
@@ -3155,12 +3155,12 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b
           if (undeclared_model_vars.contains(function_name))
             undeclared_model_variable_error("Unknown symbol: " + function_name, function_name);
 
-          pair<bool, double> rv = is_there_one_integer_argument();
-          if (!rv.first)
+          optional<int> rv{is_there_one_integer_argument()};
+          if (!rv)
             model_error("Symbol " + function_name
                         +" is being treated as if it were a function (i.e., takes an argument that is not an integer).", "");
 
-          nid = add_model_variable(mod_file->symbol_table.getID(function_name), static_cast<int>(rv.second));
+          nid = add_model_variable(mod_file->symbol_table.getID(function_name), *rv);
           stack_external_function_args.pop();
           return nid;
         }
@@ -3191,12 +3191,12 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b
           undeclared_model_vars.insert(function_name);
           undeclared_model_variable_error("Unknown symbol: " + function_name, function_name);
 
-          pair<bool, double> rv = is_there_one_integer_argument();
-          if (rv.first)
+          optional<int>rv{is_there_one_integer_argument()};
+          if (rv)
             {
               // assume it's a lead/lagged variable
               int symb_id = declare_exogenous(function_name);
-              return add_model_variable(symb_id, static_cast<int>(rv.second));
+              return add_model_variable(symb_id, *rv);
             }
           else
             error("To use an external function (" + function_name
diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh
index c17d7eed892cc27d94f077435a04414a36cc324d..6cafa8daf321bc46f81524b00e570fb606ee8238 100644
--- a/src/ParsingDriver.hh
+++ b/src/ParsingDriver.hh
@@ -28,6 +28,7 @@
 #include <vector>
 #include <istream>
 #include <stack>
+#include <optional>
 
 #include "ModFile.hh"
 #include "SymbolList.hh"
@@ -842,7 +843,7 @@ public:
   //! Adds an external function argument
   void add_external_function_arg(expr_t arg);
   //! Test to see if model/external function has exactly one integer argument
-  pair<bool, double> is_there_one_integer_argument() const;
+  optional<int> is_there_one_integer_argument() const;
   //! Adds an external function call node
   expr_t add_model_var_or_external_function(const string &function_name, bool in_model_block);
   //! Adds a native statement
diff --git a/src/macro/Environment.cc b/src/macro/Environment.cc
index 7e568fa3d31d5ed68216420ae1a13008351d8d00..7ceb75372a8a5cc53cbd576d92c7e86d8b7bc9b3 100644
--- a/src/macro/Environment.cc
+++ b/src/macro/Environment.cc
@@ -17,6 +17,8 @@
  * along with Dynare.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <cassert>
+
 #include "Environment.hh"
 #include "Expressions.hh"
 
@@ -99,7 +101,7 @@ Environment::isFunctionDefined(const string &name) const noexcept
 }
 
 void
-Environment::print(ostream &output, const vector<string> &vars, int line, bool save) const
+Environment::print(ostream &output, const vector<string> &vars, const optional<int> &line, bool save) const
 {
   if (!save && !variables.empty())
     output << "Macro Variables:" << endl;
@@ -128,9 +130,10 @@ Environment::print(ostream &output, const vector<string> &vars, int line, bool s
 }
 
 void
-Environment::printVariable(ostream &output, const string &name, int line, bool save) const
+Environment::printVariable(ostream &output, const string &name, const optional<int> &line, bool save) const
 {
-  output << (save ? "options_.macrovars_line_" + to_string(line) + "." : "  ")
+  assert(!save || line);
+  output << (save ? "options_.macrovars_line_" + to_string(*line) + "." : "  ")
          << name << " = ";
   getVariable(name)->eval(const_cast<Environment &>(*this))->print(output, save);
   if (save)
@@ -139,9 +142,10 @@ Environment::printVariable(ostream &output, const string &name, int line, bool s
 }
 
 void
-Environment::printFunction(ostream &output, const tuple<FunctionPtr, ExpressionPtr> &function, int line, bool save) const
+Environment::printFunction(ostream &output, const tuple<FunctionPtr, ExpressionPtr> &function, const optional<int> &line, bool save) const
 {
-  output << (save ? "options_.macrovars_line_" + to_string(line) + ".function." : "  ");
+  assert(!save || line);
+  output << (save ? "options_.macrovars_line_" + to_string(*line) + ".function." : "  ");
   if (save)
     {
       get<0>(function)->printName(output);
diff --git a/src/macro/Environment.hh b/src/macro/Environment.hh
index ee315cf979a4396d1a08beda89253888690af45f..9135711857a8cb583804ec6c0368c850c9df0a0b 100644
--- a/src/macro/Environment.hh
+++ b/src/macro/Environment.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019-2021 Dynare Team
+ * Copyright © 2019-2022 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -24,6 +24,7 @@
 
 #include <map>
 #include <vector>
+#include <optional>
 
 namespace macro
 {
@@ -44,9 +45,9 @@ namespace macro
     bool isVariableDefined(const string &name) const noexcept;
     bool isFunctionDefined(const string &name) const noexcept;
     inline bool isSymbolDefined(const string &name) const noexcept { return isVariableDefined(name) || isFunctionDefined(name); }
-    void print(ostream &output, const vector<string> &vars, int line = -1, bool save = false) const;
-    void printVariable(ostream &output, const string &name, int line, bool save) const;
-    void printFunction(ostream &output, const tuple<FunctionPtr, ExpressionPtr> &function, int line, bool save) const;
+    void print(ostream &output, const vector<string> &vars, const optional<int> &line = nullopt, bool save = false) const;
+    void printVariable(ostream &output, const string &name, const optional<int> &line, bool save) const;
+    void printFunction(ostream &output, const tuple<FunctionPtr, ExpressionPtr> &function, const optional<int> &line, bool save) const;
     inline size_t size() const noexcept { return variables.size() + functions.size(); }
     inline const Environment *getGlobalEnv() const noexcept { return parent == nullptr ? this : parent->getGlobalEnv(); }
   };