Select Git revision
Environment.cc
-
Sébastien Villemot authored
Closes: #128
Sébastien Villemot authoredCloses: #128
Environment.cc 4.68 KiB
/*
* Copyright © 2019-2024 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <cassert>
#include <ranges>
#include "Environment.hh"
#include "Expressions.hh"
using namespace macro;
void
Environment::define(const VariablePtr& var, const ExpressionPtr& value)
{
string name = var->getName();
if (functions.contains(name))
throw StackTrace("Variable " + name + " was previously defined as a function");
variables[move(name)] = value->eval(*this);
}
void
Environment::define(FunctionPtr func, ExpressionPtr value)
{
string name = func->getName();
if (variables.contains(name))
throw StackTrace("Variable " + name + " was previously defined as a variable");
functions[name] = {move(func), move(value)};
}
ExpressionPtr
Environment::getVariable(const string& name) const
{
if (auto it = variables.find(name); it != variables.end())
return it->second;
if (!parent)
throw StackTrace("Unknown variable " + name);
return getGlobalEnv()->getVariable(name);
}
pair<FunctionPtr, ExpressionPtr>
Environment::getFunction(const string& name) const
{
if (auto it = functions.find(name); it != functions.end())
return it->second;
if (!parent)
throw StackTrace("Unknown function " + name);
return parent->getFunction(name);
}
codes::BaseType
Environment::getType(const string& name) const
{
return getVariable(name)->eval(const_cast<Environment&>(*this))->getType();
}
bool
Environment::isVariableDefined(const string& name) const noexcept
{
try
{
getVariable(name);
return true;
}
catch (StackTrace& ex)
{
return false;
}
}
bool
Environment::isFunctionDefined(const string& name) const noexcept
{
try
{
getFunction(name);
return true;
}
catch (StackTrace& ex)
{
return false;
}
}
void
Environment::print(ostream& output, const vector<string>& vars, int line, bool save) const
{
if (!save && !variables.empty())
output << "Macro Variables (at line " << line << "):" << endl;
// For sorting the symbols in a case-insensitive way, see #128
auto case_insensitive_string_less = [](const string& a, const string& b) {
return lexicographical_compare(
begin(a), end(a), begin(b), end(b),
[](const char& c1, const char& c2) { return tolower(c1) < tolower(c2); });
};
if (vars.empty())
{
vector<string> variables_sorted;
ranges::copy(views::keys(variables), back_inserter(variables_sorted));
ranges::sort(variables_sorted, case_insensitive_string_less);
for (const auto& it : variables_sorted)
printVariable(output, it, line, save);
}
else
for (const auto& it : vars)
if (isVariableDefined(it))
printVariable(output, it, line, save);
if (!save && !functions.empty())
output << "Macro Functions (at line " << line << "):" << endl;
if (vars.empty())
{
vector<string> functions_sorted;
ranges::copy(views::keys(functions), back_inserter(functions_sorted));
ranges::sort(functions_sorted, case_insensitive_string_less);
for (const auto& it : functions_sorted)
printFunction(output, it, line, save);
}
else
for (const auto& it : vars)
if (isFunctionDefined(it))
printFunction(output, it, line, save);
if (parent)
parent->print(output, vars, line, save);
}
void
Environment::printVariable(ostream& output, const string& name, int line, bool save) const
{
output << (save ? "options_.macrovars_line_" + to_string(line) + "." : " ") << name << " = ";
getVariable(name)->eval(const_cast<Environment&>(*this))->print(output, save);
if (save)
output << ";";
output << endl;
}
void
Environment::printFunction(ostream& output, const string& name, int line, bool save) const
{
auto [func_signature, func_body] = getFunction(name);
output << (save ? "options_.macrovars_line_" + to_string(line) + ".function." : " ");
if (save)
{
func_signature->printName(output);
output << " = '";
}
func_signature->print(output);
output << " = ";
func_body->print(output);
if (save)
output << "';";
output << endl;
}