Compare commits

...

3 Commits

Author SHA1 Message Date
Username404-59 dbb08a5299
Share the Reference analysis task with the Define one
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2024-12-31 20:22:38 +01:00
Username404-59 2c0cec16d6
Move redefinition checking to SemanticAnalysis.hpp
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2024-12-31 19:59:02 +01:00
Username404-59 7fb9ca37a7
Move task macros to Tasking.hpp
Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
2024-08-07 14:28:14 +02:00
9 changed files with 41 additions and 46 deletions

View File

@ -4,9 +4,13 @@
#include "parsing/ParseComponents.hpp"
#include "Tasking.hpp"
#define make_task(T, C, F) make_task_base_R(T, C, F)
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) {
@ -17,13 +21,23 @@ 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<NamedIdentifier<true>&>(*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),
share_task(Reference, Define<true>),
};
};
};
#undef make_task
#endif //YERBACON_SEMANTICANALYSIS_HPP

View File

@ -7,6 +7,10 @@
#define make_task_base(start, type, captures, function_body) make_pair(type_index(typeid(type)), [captures](const ParseTree& parsedTree, unsigned int& index) { start; function_body })
#define make_task_base_R(T, C, F) make_task_base(const T& parseComponent = reinterpret_cast<T&>(*parsedTree[index]), T, C, F)
#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:

View File

@ -105,12 +105,12 @@ public:
#undef IS_PARSECOMPONENT
namespace StandardComponents {
struct Define: NamedIdentifier<true> {
const bool final;
template<bool BOOL>
struct Define: NamedIdentifier<BOOL> {
const bool final = BOOL;
ParseTree content;
explicit Define(const bool& isFinal, string_view nameText, ParseTree&& content): NamedIdentifier(nameText), final(isFinal), content(move(content)) {}
explicit Define(string_view nameText, ParseTree&& content): Define(false, nameText, move(content)) {}
Define(Define&& define) noexcept: Define(define.final, define.name, move(define.content)) {}
explicit Define(string_view nameText, ParseTree&& content): NamedIdentifier<BOOL>(nameText), content(move(content)) {}
Define(Define&& define) noexcept: Define(define.name, move(define.content)) {}
};
struct Reference: NamedIdentifier<false> {
using NamedIdentifier::NamedIdentifier;

View File

@ -134,19 +134,20 @@ 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<Define>(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(), [&current](const tok& it){
return it.toktype == SEMICOLON || it.line != current.line;
});
parseTree << Define(isFinalDefine, current.toktext, parse(beginning, end));
if (isFinalDefine) {
parseTree << Define<true>(current.toktext, parse(beginning, end));
} else {
parseTree << Define<false>(current.toktext, parse(beginning, end));
}
i += 1 + isFinalDefine + distance(beginning, end);
} else {
const bool method = nextAre({DOT, IDENTIFIER, LPAR});
@ -184,23 +185,6 @@ namespace Parser {
} catch (const NamedIdentifier<true>::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<NamedIdentifier<true>*>(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<NamedIdentifier<true>&>(*pointer).name == last_identifier->name;
} catch (const bad_cast&) {
return false;
}
}))
{ parsingError(current, " has already been defined previously", true); }
}
}
}
return parseTree;
}

View File

@ -66,9 +66,6 @@ protected:
}
} else output << openCharacters << view << closeCharacters;
}
#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)
typedef pair<const char*, const char*> print_functions_pair;
virtual unordered_task_map getTaskMap() = 0;
virtual print_functions_pair printFunctions() = 0;
@ -135,7 +132,8 @@ public:
output << ')';
),
make_task(StandardComponents::types::Integer, output << setprecision(parseComponent.precision) << fixed << parseComponent.value;),
make_task(StandardComponents::Condition, output << '('; transpileTree(parseComponent); output << ')';)
make_task(StandardComponents::Condition, output << '('; transpileTree(parseComponent); output << ')';),
share_task(StandardComponents::Define<false>, StandardComponents::Define<true>)
}));
return fullMap;
};
@ -163,11 +161,6 @@ unique_ptr<Target> Target::forName(string_view name, const bool newLines = true)
ADDTARGET("py", PyTarget);
ADDTARGET("gd", GsTarget);
#undef ADDTARGET
#undef make_nonlocal_task
#undef make_task_noR
#undef make_task
#undef make_task_base_R
#undef make_task_base
Yerbacon::fail({"\"", name.data(), "\" is not a valid target."});
return nullptr;
}

View File

@ -6,7 +6,7 @@ struct GsTarget: Target {
print_functions_pair printFunctions() final { return make_pair("printraw", "print"); }
unordered_task_map getTaskMap() final {
return {
make_task(Define,
make_task(Define<false>,
output << (parseComponent.final ? "const " : "var ") << parseComponent.name << " = ";
transpileTree(parseComponent.content);
),

View File

@ -7,7 +7,7 @@ struct JsTarget: Target {
bool use_uniqueLineSeparator() final { return true; }
unordered_task_map getTaskMap() final {
return {
make_task(Define,
make_task(Define<false>,
output << (parseComponent.final ? "const " : "let ") << parseComponent.name << " = ";
transpileTree(parseComponent.content);
),

View File

@ -7,7 +7,7 @@ struct LuaTarget: Target {
optional_string uniqueLineSeparator() final { return " "; }
unordered_task_map getTaskMap() final {
return {
make_task(Define,
make_task(Define<false>,
if (parseComponent.final) output << "local ";
output << parseComponent.name;
if (parseComponent.final) output << " <const>"; // TODO Find an alternative to <const> for lua <5.4

View File

@ -7,7 +7,7 @@ struct PyTarget: Target {
optional_string uniqueLineSeparator() final { return {}; }
unordered_task_map getTaskMap() final {
return {
make_task(Define, output << parseComponent.name << " = "; transpileTree(parseComponent.content);),
make_task(Define<false>, output << parseComponent.name << " = "; transpileTree(parseComponent.content);),
make_task(types::String, stringInterpolation(R"(""")", parseComponent.content);),
make_task(Function,
output << "def " << parseComponent.name << '(';