diff --git a/src/headers/SemanticAnalysis.hpp b/src/headers/SemanticAnalysis.hpp index 10fcf59..4d46953 100644 --- a/src/headers/SemanticAnalysis.hpp +++ b/src/headers/SemanticAnalysis.hpp @@ -4,7 +4,13 @@ #include "parsing/ParseComponents.hpp" #include "Tasking.hpp" +using namespace StandardComponents; + struct SemanticAnalyser final: public Tasking { + typedef Yerbacon::Exception SemanticException; + static void error(const string_view& text, unsigned long line = 0) { + throw SemanticException(text, line); + } const auto& analyseTree(const ParseTree& tree) { const auto& task_map = getTaskMapInstance(); for (unsigned int i = 0; i < tree.size(); ++i) { @@ -15,9 +21,25 @@ struct SemanticAnalyser final: public Tasking { return tree; } private: - unordered_task_map getTaskMapInstance() final { + unordered_task_map getTaskMapInstance() final { // TODO Include line in error messages + using namespace StandardComponents; return { - + make_nonlocal_task(Reference, + if (index > 0 and any_of(parsedTree.cbegin(), parsedTree.cbegin() + index + 1, [&parseComponent](const component_ptr& pointer){ + try { + return dynamic_cast&>(*pointer).name == parseComponent.name; + } catch (const bad_cast&) { + return false; + } + })) { error(parseComponent.name + " has already been defined previously"); } + ), + share_task(Reference, Function), + share_task(Reference, Class), + make_nonlocal_task(Define, + const optional previousDefinition = parsedTree.findReferenceByName(parseComponent.name).value(); + if (&previousDefinition.value().get() != &parseComponent && (previousDefinition.value().get().final || parseComponent.final)) + error(parseComponent.name + string(previousDefinition->get().final ? " cannot be redefined as it is final" : " cannot be made final after it has been declared")); + ) }; }; }; diff --git a/src/headers/Tasking.hpp b/src/headers/Tasking.hpp index acdabde..546e580 100644 --- a/src/headers/Tasking.hpp +++ b/src/headers/Tasking.hpp @@ -10,6 +10,7 @@ #define make_task(T, F) make_task_base_R(T, this, F) #define make_task_noR(T, F) make_task_base(,T, this, F) #define make_nonlocal_task(T, F) make_task_base_R(T, , F) +#define share_task(T, T2) make_task_noR(T2, this->getTaskMapInstance()[typeid(T)](parsedTree, index);) class Tasking { protected: diff --git a/src/headers/parsing/Parser.hpp b/src/headers/parsing/Parser.hpp index 0b231c0..49754f5 100644 --- a/src/headers/parsing/Parser.hpp +++ b/src/headers/parsing/Parser.hpp @@ -134,13 +134,9 @@ namespace Parser { i += 2; break; } else i -= parametersDistance; - - // TODO Move this to semantic analysis + bool isFinalDefine = nextAre({TAG, DEFINE}); if (isFinalDefine || next.toktype == DEFINE) { - const optional previousDefinition = parseTree.template findReferenceByName(current.toktext); - if (previousDefinition.has_value() && (previousDefinition.value().get().final || isFinalDefine)) - parsingError(current, previousDefinition->get().final ? " cannot be redefined as it is final" : " cannot be made final after it has been declared", true); const unsigned increment = 2 + isFinalDefine; const auto beginning = lexed.begin() + i + increment; const auto end = find_if(beginning, lexed.end(), [¤t](const tok& it){ @@ -184,23 +180,6 @@ namespace Parser { } catch (const NamedIdentifier::identifier_reserved_exception&) { parsingError(current, " is a reserved identifier", true); } - // TODO Move this to semantic analysis - if (not parseTree.empty()) { - const auto& last = parseTree.cend() - 1; - const type_info& lastId = last->get()->getId(); - const auto* last_identifier = dynamic_cast*>(last->get()); - if (last_identifier != nullptr) { - if (lastId != typeid(Define) and - any_of(parseTree.cbegin(), last, [&last_identifier](const component_ptr& pointer){ - try { - return dynamic_cast&>(*pointer).name == last_identifier->name; - } catch (const bad_cast&) { - return false; - } - })) - { parsingError(current, " has already been defined previously", true); } - } - } } return parseTree; }