Compare commits
3 Commits
d4df3aa4ea
...
dbb08a5299
Author | SHA1 | Date |
---|---|---|
Username404-59 | dbb08a5299 | |
Username404-59 | 2c0cec16d6 | |
Username404-59 | 7fb9ca37a7 |
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(), [¤t](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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
),
|
||||
|
|
|
@ -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);
|
||||
),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 << '(';
|
||||
|
|
Loading…
Reference in New Issue