#pragma once #include #include #include #include #include // for clangd #include "utils.hpp" namespace info { template class ContextManager { public: ContextManager() { contexts_.emplace_back(); } template utils::IdType AddValue(const T& value, utils::ValueType value_type) { return value_manager_.AddValue(value, value_type); } utils::IdType AddAnyValue(Value&& value, utils::ValueType value_type) { return value_manager_.AddAnyValue(std::move(value), value_type); } template std::optional GetValue(utils::IdType value_id) { return value_manager_.template GetValue(value_id); } Value* GetAnyValue(utils::IdType value_id) { return value_manager_.GetAnyValue(value_id); } bool AddValueRequirement(utils::IdType type, utils::IdType requrement) { return value_manager_.AddValueRequirement(type, requrement); } bool EqualValues(utils::IdType first_type, utils::IdType second_type) { return value_manager_.EqualValues(first_type, second_type); } utils::ValueType GetValueType(utils::IdType value_id) { return value_manager_.GetValueType(value_id); } utils::IdType ToModifiedValue(utils::IdType value_id, utils::ValueType new_value_type) { Value value = *GetAnyValue(value_id); return AddAnyValue(std::move(value), new_value_type); } ValueManager* GetValueManager() { return &value_manager_; } void EnterContext() { contexts_.emplace_back(); } void ExitContext() { if (contexts_.empty()) { // error } contexts_.pop_back(); } void ExitFromAllContexts() { contexts_.clear(); contexts_.emplace_back(); } bool DefineVariable(const std::string& name, utils::IdType value_id) { // check in previous contexts ?? return contexts_.back().DefineVariable(name, value_id); } bool DefineLocalType(const std::string& name, utils::IdType type_id) { if (GetLocalType(name).has_value()) { return false; } return contexts_.back().DefineLocalType(name, type_id); } bool RemoveVariable(const std::string& name) { for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) { if (contexts_[i].RemoveVariable(name)) { return true; } } return false; } void EnterVariableContext(const std::string& name, utils::IdType value_id) { // for variable namespaces, for loops contexts_.emplace_back(); DefineVariable(name, value_id); } std::optional GetVariableInfo(const std::string& name) { for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) { auto maybe_type = contexts_[i].GetVariableInfo(name); if (maybe_type.has_value()) { return maybe_type.value(); } } return std::nullopt; } std::optional GetLocalType(const std::string& name) { for (ssize_t i = (ssize_t)contexts_.size() - 1; i >= 0; --i) { auto maybe_type = contexts_[i].GetLocalType(name); if (maybe_type.has_value()) { return maybe_type.value(); } } return std::nullopt; } private: class Context { public: Context() = default; bool DefineVariable(const std::string& name, utils::IdType value_id) { if (name == "_") { // placeholder // TODO: ?? return true; } if (variables_.count(name) > 0) { return false; } variables_[name] = value_id; return true; } bool DefineLocalType(const std::string& name, utils::IdType type_id) { if (local_types_.count(name) > 0) { return false; } local_types_[name] = type_id; return true; } bool RemoveVariable(const std::string& name) { return variables_.erase(name); } std::optional GetVariableInfo(const std::string& name) { auto variable_iter = variables_.find(name); if (variable_iter == variables_.end()) { return std::nullopt; } return variable_iter->second; } std::optional GetLocalType(const std::string& name) { auto local_abstract_type_iter = local_types_.find(name); if (local_abstract_type_iter == local_types_.end()) { return std::nullopt; } return local_abstract_type_iter->second; } private: std::unordered_map variables_; std::unordered_map local_types_; }; std::vector contexts_; ValueManager value_manager_; }; } // namespace info