Implement reserved identifiers

Signed-off-by: Username404 <w.iron.zombie@gmail.com>
This commit is contained in:
Username404 2022-07-06 15:35:16 +02:00
parent 2ebb1d5239
commit 4e08c0cf05
Signed by: Username404-59
GPG Key ID: 7AB361FBB257A5D1
5 changed files with 123 additions and 87 deletions

View File

@ -145,7 +145,7 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} ${CMAKE_PROJECT_VERSION_MAJ
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CMAKE_PROJECT_VERSION}-${TIME}")
include_directories(${CMAKE_CURRENT_LIST_DIR})
add_executable(${EXENAME} src/main.cpp ${CMAKE_CURRENT_BINARY_DIR}/processed/${PROJECT_NAME}.rc src/etc/filefuncs.cpp src/etc/lexer.cpp src/headers/lex.hpp src/headers/misc.hpp src/headers/parsing/ParseComponents.hpp src/headers/transpiler/Target.hpp src/headers/transpiler/implementations/Lua.hpp src/headers/transpiler/implementations/Js.hpp src/headers/transpiler/implementations/Py.hpp src/headers/parsing/Parser.hpp src/headers/arguments.hpp)
add_executable(${EXENAME} src/main.cpp ${CMAKE_CURRENT_BINARY_DIR}/processed/${PROJECT_NAME}.rc src/etc/filefuncs.cpp src/etc/lexer.cpp src/headers/lex.hpp src/headers/misc.hpp src/headers/parsing/ParseComponents.hpp src/headers/transpiler/Target.hpp src/headers/transpiler/implementations/Lua.hpp src/headers/transpiler/implementations/Js.hpp src/headers/transpiler/implementations/Py.hpp src/headers/parsing/Parser.hpp src/headers/arguments.hpp src/headers/parsing/ReservedIdentifiers.hpp)
target_compile_definitions(${EXENAME} PRIVATE YBCON_VERSION="${CODENAME} ${PROJECT_VERSION}")
target_precompile_headers(${EXENAME} PRIVATE src/headers/Yerbacon.hpp)
if (Threads_FOUND)

View File

@ -9,6 +9,7 @@
#include <memory>
#include <optional>
#include <algorithm>
#include "ReservedIdentifiers.hpp"
using namespace std;
#include "../lex.hpp"
@ -19,16 +20,22 @@ struct ParseComponent {
[[nodiscard]] inline const type_info& getId() const { return typeid(*this); }
virtual ~ParseComponent() = default;
};
template<bool disallow_reserved>
struct NamedIdentifier: virtual ParseComponent {
struct identifier_reserved_exception: exception {};
const string name;
explicit NamedIdentifier(string_view nameText): name(nameText) {}
NamedIdentifier() = default;
explicit NamedIdentifier(const string_view nameText): name(nameText) {
if (disallow_reserved and reserved(name)) {
throw identifier_reserved_exception();
}
}
NamedIdentifier() = delete;
};
typedef unique_ptr<ParseComponent> component_ptr;
#define IS_PARSECOMPONENT IS(ParseComponent)
#define IS_IDENTIFIER enable_if_t<is_base_of_v<NamedIdentifier<false>, T> or is_base_of_v<NamedIdentifier<true>, T>, T>
class ParseTree: public virtual ParseComponent {
mutable vector<component_ptr> subComponents;
using array_type = decltype(subComponents);
@ -68,8 +75,8 @@ public:
});
return filteredComponents;
}
IS(NamedIdentifier)
optional<reference_wrapper<T>> findReferenceByName(const string& name) const {
template<typename T>
optional<reference_wrapper<IS_IDENTIFIER>> findReferenceByName(const string& name) const {
const vector<T*> identifiers = findById<T>();
for (T* identifier: identifiers) {
if (identifier->getId() == typeid(T) && identifier->name == name) {
@ -80,8 +87,8 @@ public:
};
inline component_ptr& operator[](const unsigned int& index) const { return subComponents[index]; }
inline component_ptr& at(const unsigned int& index) const { return subComponents.at(index); }
IS(NamedIdentifier)
inline auto operator[](const string& key) const { return findReferenceByName<T>(key); }
template<typename T>
inline auto operator[](const string& key) const { return findReferenceByName<IS_IDENTIFIER>(key); }
IS_PARSECOMPONENT inline void add(const T& component) { addComponent<T>(component); }
IS_PARSECOMPONENT inline void addAll(const initializer_list<T>& components) { addAllComponents<T>(components); }
IS_PARSECOMPONENT inline ParseTree& operator<<(const T& component) { add(component); return *this; }
@ -96,14 +103,14 @@ public:
#undef IS_PARSECOMPONENT
namespace StandardComponents {
struct Define: NamedIdentifier {
struct Define: NamedIdentifier<true> {
const bool final;
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)) {}
};
struct Reference: NamedIdentifier {
struct Reference: NamedIdentifier<false> {
using NamedIdentifier::NamedIdentifier;
};
namespace types {
@ -122,11 +129,11 @@ namespace StandardComponents {
using Reference::Reference;
};
struct Function: NamedIdentifier, ParseTree {
struct Function: NamedIdentifier<true>, ParseTree {
ParseTree parameters;
using NamedIdentifier::NamedIdentifier;
};
struct Class: NamedIdentifier, ParseTree {
struct Class: NamedIdentifier<true>, ParseTree {
using NamedIdentifier::NamedIdentifier;
};
}

View File

@ -8,6 +8,7 @@
#include <span>
#include <memory>
#include <cmath>
#include "ReservedIdentifiers.hpp"
namespace Parser {
typedef Yerbacon::Exception ParsingException;
@ -58,92 +59,94 @@ namespace Parser {
const bool hasNext = (i + 1) < lexed.size();
const tok& current = lexed[i], next = hasNext ? lexed[i + 1] : tok(UNEXPECTED, current.line);
switch (current.toktype) {
case NUMBER: {
long double v = stoul(current.toktext);
if (i != 0 && lexed[i - 1].toktype == HYPHEN) v = -v;
types::Integer::precision_type p = 0;
if (nextAre({DOT, NUMBER})) {
i += 2;
const string& right = lexed[i].toktext;
p = min(static_cast<int>(right.size()), numeric_limits<long double>::digits10);
v += copysign(stold(right.substr(0, p)) / powl(deca::num, p), v);
}
parseTree << types::Integer(v, p);
break;
}
case STRING: parseTree << current.toktext; break;
case IDENTIFIER: {
if (current.toktext == "class" || current.toktext == "structure") {
if (next.toktype == IDENTIFIER) {
parseTree << Class(next.toktext); ++i;
} else {
parsingError(next, hasNext ? " is not a valid class identifier" : "A class identifier is required", hasNext);
}
} else {
unsigned int parametersDistance = 0;
if (next.toktype == LPAR) {
const auto closing = find_if(lexed.begin() + i, lexed.end(), [](const tok& token){ return token.toktype == RPAR; });
parametersDistance = distance(lexed.begin() + i, closing);
i += parametersDistance;
}
if (nextAre({LCOMP, LCOMP, LBRACE})) {
Function function(current.toktext);
if (parametersDistance > 2)
function.parameters = parse(filter_comma_list(lexed.begin() + ((i + 2) - parametersDistance), lexed.begin() + i));
parseTree << function;
try {
switch (current.toktype) {
case NUMBER: {
long double v = stoul(current.toktext);
if (i != 0 && lexed[i - 1].toktype == HYPHEN) v = -v;
types::Integer::precision_type p = 0;
if (nextAre({DOT, NUMBER})) {
i += 2;
break;
} else i -= parametersDistance;
const string& right = lexed[i].toktext;
p = min(static_cast<int>(right.size()), numeric_limits<long double>::digits10);
v += copysign(stold(right.substr(0, p)) / powl(deca::num, p), v);
}
parseTree << types::Integer(v, p);
break;
}
case STRING: parseTree << current.toktext; break;
case IDENTIFIER: {
using enum ReservedIdentifier;
if (current.toktext == ID(CLASS) || current.toktext == ID(STRUCT)) {
if (next.toktype == IDENTIFIER) {
parseTree << Class(next.toktext); ++i;
} else {
parsingError(next, hasNext ? " is not a valid class identifier" : "A class identifier is required", hasNext);
}
} else {
unsigned int parametersDistance = 0;
if (next.toktype == LPAR) {
const auto closing = find_if(lexed.begin() + i, lexed.end(), [](const tok& token){ return token.toktype == RPAR; });
parametersDistance = distance(lexed.begin() + i, closing);
i += parametersDistance;
}
if (nextAre({LCOMP, LCOMP, LBRACE})) {
Function function(current.toktext);
if (parametersDistance > 2)
function.parameters = parse(filter_comma_list(lexed.begin() + ((i + 2) - parametersDistance), lexed.begin() + i));
parseTree << function;
i += 2;
break;
} else i -= parametersDistance;
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));
i += 1 + isFinalDefine + distance(beginning, end);
} else if (next.toktype == LPAR) {
parseTree << Call(current.toktext);
} else
parseTree << Reference(current.toktext);
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));
i += 1 + isFinalDefine + distance(beginning, end);
} else if (next.toktype == LPAR) {
parseTree << Call(current.toktext);
} else parseTree << Reference(current.toktext);
}
}
case SEMICOLON: break;
case LPAR: case LBRACE: case LBRACKET: {
const auto closingCharacter = find_corresponding(lexed.begin() + i + 1, lexed.end(), current.toktype, tok::inverseLCharacter(current.toktype));
vector<tok> subTokens(lexed.begin() + i + 1, closingCharacter);
if (current.toktype == LPAR || current.toktype == LBRACKET) filter_comma_list(subTokens);
if (not parseTree.empty()) {
try {
auto& previous = dynamic_cast<ParseTree&>(*parseTree.at(parseTree.size() - 1));
if (find_if(reverse_iterator(lexed.begin() + i), lexed.rend(), [](const tok& token){
return token.toktype != SEMICOLON;
})->toktype != *closingCharacter) {
previous = parse(subTokens);
i = distance(lexed.begin(), closingCharacter);
break;
}
} catch (const out_of_range&) {} catch (const bad_cast&) {}
case SEMICOLON: break;
case LPAR: case LBRACE: case LBRACKET: {
const auto closingCharacter = find_corresponding(lexed.begin() + i + 1, lexed.end(), current.toktype, tok::inverseLCharacter(current.toktype));
vector<tok> subTokens(lexed.begin() + i + 1, closingCharacter);
if (current.toktype == LPAR || current.toktype == LBRACKET) filter_comma_list(subTokens);
if (not parseTree.empty()) {
try {
auto& previous = dynamic_cast<ParseTree&>(*parseTree.at(parseTree.size() - 1));
if (find_if(reverse_iterator(lexed.begin() + i), lexed.rend(), [](const tok& token){
return token.toktype != SEMICOLON;
})->toktype != *closingCharacter) {
previous = parse(subTokens);
i = distance(lexed.begin(), closingCharacter);
break;
}
} catch (const out_of_range&) {} catch (const bad_cast&) {}
}
}
default: parsingError(current, " \u27F5 Unexpected character", true);
}
default: parsingError(current, " \u27F5 Unexpected character", true);
} catch (const NamedIdentifier<true>::identifier_reserved_exception&) {
parsingError(current, " is a reserved identifier", true);
}
try {
const auto& last = parseTree.cend() - 1;
const type_info& lastId = last->get()->getId();
const auto& last_identifier = dynamic_cast<NamedIdentifier&>(**last);
if (lastId != typeid(Reference) &&
lastId != typeid(Call) &&
lastId != typeid(Define) and
const auto& last_identifier = dynamic_cast<NamedIdentifier<true>&>(**last);
if (lastId != typeid(Define) and
any_of(parseTree.cbegin(), last, [&last_identifier](const component_ptr& pointer){
try {
return dynamic_cast<NamedIdentifier&>(*pointer).name == last_identifier.name;
return dynamic_cast<NamedIdentifier<true>&>(*pointer).name == last_identifier.name;
} catch (const bad_cast&) {
return false;
}

View File

@ -0,0 +1,25 @@
#ifndef YERBACON_RESERVEDIDENTIFIERS_HPP
#define YERBACON_RESERVEDIDENTIFIERS_HPP
#include <string>
#include <array>
#include "../Yerbacon.hpp"
#include <string_view>
static const array identifiers {
"class", "structure", "print", "print_line"
};
enum class ReservedIdentifier: size_t {
CLASS, STRUCT, PRINT_FUNCTION, PRINT_LINE_FUNCTION
};
inline const char* ID(const ReservedIdentifier& identifier) {
return identifiers.at(reinterpret_cast<const size_t&>(identifier));
}
bool reserved(const string_view words) {
return find(identifiers.cbegin(), identifiers.cend(), words) != identifiers.cend();
}
#endif //YERBACON_RESERVEDIDENTIFIERS_HPP

View File

@ -132,7 +132,8 @@ public:
make_task(StandardComponents::Reference, output << parseComponent.name;),
make_task(StandardComponents::Call,
const auto print_functions = printFunctions();
output << ((parseComponent.name == "print") ? print_functions.first : (parseComponent.name == "print_line") ? print_functions.second : parseComponent.name) << '(';
using enum ReservedIdentifier;
output << ((parseComponent.name == ID(PRINT_FUNCTION)) ? print_functions.first : (parseComponent.name == ID(PRINT_LINE_FUNCTION)) ? print_functions.second : parseComponent.name) << '(';
separate_transpileTree(parseComponent, ", ");
output << ')';
),