Implement reserved identifiers
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
This commit is contained in:
parent
2ebb1d5239
commit
4e08c0cf05
CMakeLists.txt
src/headers
|
@ -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}")
|
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CMAKE_PROJECT_VERSION}-${TIME}")
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
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_compile_definitions(${EXENAME} PRIVATE YBCON_VERSION="${CODENAME} ${PROJECT_VERSION}")
|
||||||
target_precompile_headers(${EXENAME} PRIVATE src/headers/Yerbacon.hpp)
|
target_precompile_headers(${EXENAME} PRIVATE src/headers/Yerbacon.hpp)
|
||||||
if (Threads_FOUND)
|
if (Threads_FOUND)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "ReservedIdentifiers.hpp"
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include "../lex.hpp"
|
#include "../lex.hpp"
|
||||||
|
@ -19,16 +20,22 @@ struct ParseComponent {
|
||||||
[[nodiscard]] inline const type_info& getId() const { return typeid(*this); }
|
[[nodiscard]] inline const type_info& getId() const { return typeid(*this); }
|
||||||
virtual ~ParseComponent() = default;
|
virtual ~ParseComponent() = default;
|
||||||
};
|
};
|
||||||
|
template<bool disallow_reserved>
|
||||||
struct NamedIdentifier: virtual ParseComponent {
|
struct NamedIdentifier: virtual ParseComponent {
|
||||||
|
struct identifier_reserved_exception: exception {};
|
||||||
const string name;
|
const string name;
|
||||||
explicit NamedIdentifier(string_view nameText): name(nameText) {}
|
explicit NamedIdentifier(const string_view nameText): name(nameText) {
|
||||||
NamedIdentifier() = default;
|
if (disallow_reserved and reserved(name)) {
|
||||||
|
throw identifier_reserved_exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NamedIdentifier() = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef unique_ptr<ParseComponent> component_ptr;
|
typedef unique_ptr<ParseComponent> component_ptr;
|
||||||
|
|
||||||
#define IS_PARSECOMPONENT IS(ParseComponent)
|
#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 {
|
class ParseTree: public virtual ParseComponent {
|
||||||
mutable vector<component_ptr> subComponents;
|
mutable vector<component_ptr> subComponents;
|
||||||
using array_type = decltype(subComponents);
|
using array_type = decltype(subComponents);
|
||||||
|
@ -68,8 +75,8 @@ public:
|
||||||
});
|
});
|
||||||
return filteredComponents;
|
return filteredComponents;
|
||||||
}
|
}
|
||||||
IS(NamedIdentifier)
|
template<typename T>
|
||||||
optional<reference_wrapper<T>> findReferenceByName(const string& name) const {
|
optional<reference_wrapper<IS_IDENTIFIER>> findReferenceByName(const string& name) const {
|
||||||
const vector<T*> identifiers = findById<T>();
|
const vector<T*> identifiers = findById<T>();
|
||||||
for (T* identifier: identifiers) {
|
for (T* identifier: identifiers) {
|
||||||
if (identifier->getId() == typeid(T) && identifier->name == name) {
|
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& operator[](const unsigned int& index) const { return subComponents[index]; }
|
||||||
inline component_ptr& at(const unsigned int& index) const { return subComponents.at(index); }
|
inline component_ptr& at(const unsigned int& index) const { return subComponents.at(index); }
|
||||||
IS(NamedIdentifier)
|
template<typename T>
|
||||||
inline auto operator[](const string& key) const { return findReferenceByName<T>(key); }
|
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 add(const T& component) { addComponent<T>(component); }
|
||||||
IS_PARSECOMPONENT inline void addAll(const initializer_list<T>& components) { addAllComponents<T>(components); }
|
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; }
|
IS_PARSECOMPONENT inline ParseTree& operator<<(const T& component) { add(component); return *this; }
|
||||||
|
@ -96,14 +103,14 @@ public:
|
||||||
#undef IS_PARSECOMPONENT
|
#undef IS_PARSECOMPONENT
|
||||||
|
|
||||||
namespace StandardComponents {
|
namespace StandardComponents {
|
||||||
struct Define: NamedIdentifier {
|
struct Define: NamedIdentifier<true> {
|
||||||
const bool final;
|
const bool final;
|
||||||
ParseTree content;
|
ParseTree content;
|
||||||
explicit Define(const bool& isFinal, string_view nameText, ParseTree&& content): NamedIdentifier(nameText), final(isFinal), content(move(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)) {}
|
explicit Define(string_view nameText, ParseTree&& content): Define(false, nameText, move(content)) {}
|
||||||
Define(Define&& define) noexcept: Define(define.final, define.name, move(define.content)) {}
|
Define(Define&& define) noexcept: Define(define.final, define.name, move(define.content)) {}
|
||||||
};
|
};
|
||||||
struct Reference: NamedIdentifier {
|
struct Reference: NamedIdentifier<false> {
|
||||||
using NamedIdentifier::NamedIdentifier;
|
using NamedIdentifier::NamedIdentifier;
|
||||||
};
|
};
|
||||||
namespace types {
|
namespace types {
|
||||||
|
@ -122,11 +129,11 @@ namespace StandardComponents {
|
||||||
using Reference::Reference;
|
using Reference::Reference;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Function: NamedIdentifier, ParseTree {
|
struct Function: NamedIdentifier<true>, ParseTree {
|
||||||
ParseTree parameters;
|
ParseTree parameters;
|
||||||
using NamedIdentifier::NamedIdentifier;
|
using NamedIdentifier::NamedIdentifier;
|
||||||
};
|
};
|
||||||
struct Class: NamedIdentifier, ParseTree {
|
struct Class: NamedIdentifier<true>, ParseTree {
|
||||||
using NamedIdentifier::NamedIdentifier;
|
using NamedIdentifier::NamedIdentifier;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include "ReservedIdentifiers.hpp"
|
||||||
|
|
||||||
namespace Parser {
|
namespace Parser {
|
||||||
typedef Yerbacon::Exception ParsingException;
|
typedef Yerbacon::Exception ParsingException;
|
||||||
|
@ -58,92 +59,94 @@ namespace Parser {
|
||||||
const bool hasNext = (i + 1) < lexed.size();
|
const bool hasNext = (i + 1) < lexed.size();
|
||||||
const tok& current = lexed[i], next = hasNext ? lexed[i + 1] : tok(UNEXPECTED, current.line);
|
const tok& current = lexed[i], next = hasNext ? lexed[i + 1] : tok(UNEXPECTED, current.line);
|
||||||
|
|
||||||
switch (current.toktype) {
|
try {
|
||||||
case NUMBER: {
|
switch (current.toktype) {
|
||||||
long double v = stoul(current.toktext);
|
case NUMBER: {
|
||||||
if (i != 0 && lexed[i - 1].toktype == HYPHEN) v = -v;
|
long double v = stoul(current.toktext);
|
||||||
types::Integer::precision_type p = 0;
|
if (i != 0 && lexed[i - 1].toktype == HYPHEN) v = -v;
|
||||||
if (nextAre({DOT, NUMBER})) {
|
types::Integer::precision_type p = 0;
|
||||||
i += 2;
|
if (nextAre({DOT, NUMBER})) {
|
||||||
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;
|
|
||||||
i += 2;
|
i += 2;
|
||||||
break;
|
const string& right = lexed[i].toktext;
|
||||||
} else i -= parametersDistance;
|
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});
|
bool isFinalDefine = nextAre({TAG, DEFINE});
|
||||||
if (isFinalDefine || next.toktype == DEFINE) {
|
if (isFinalDefine || next.toktype == DEFINE) {
|
||||||
const optional previousDefinition = parseTree.template findReferenceByName<Define>(current.toktext);
|
const optional previousDefinition = parseTree.template findReferenceByName<Define>(current.toktext);
|
||||||
if (previousDefinition.has_value() && (previousDefinition.value().get().final || isFinalDefine))
|
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);
|
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 unsigned increment = 2 + isFinalDefine;
|
||||||
const auto beginning = lexed.begin() + i + increment;
|
const auto beginning = lexed.begin() + i + increment;
|
||||||
const auto end = find_if(beginning, lexed.end(), [¤t](const tok& it){
|
const auto end = find_if(beginning, lexed.end(), [¤t](const tok& it){
|
||||||
return it.toktype == SEMICOLON || it.line != current.line;
|
return it.toktype == SEMICOLON || it.line != current.line;
|
||||||
});
|
});
|
||||||
parseTree << Define(isFinalDefine, current.toktext, parse(beginning, end));
|
parseTree << Define(isFinalDefine, current.toktext, parse(beginning, end));
|
||||||
i += 1 + isFinalDefine + distance(beginning, end);
|
i += 1 + isFinalDefine + distance(beginning, end);
|
||||||
} else if (next.toktype == LPAR) {
|
} else if (next.toktype == LPAR) {
|
||||||
parseTree << Call(current.toktext);
|
parseTree << Call(current.toktext);
|
||||||
} else
|
} else parseTree << Reference(current.toktext);
|
||||||
parseTree << Reference(current.toktext);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case SEMICOLON: break;
|
case SEMICOLON: break;
|
||||||
case LPAR: case LBRACE: case LBRACKET: {
|
case LPAR: case LBRACE: case LBRACKET: {
|
||||||
const auto closingCharacter = find_corresponding(lexed.begin() + i + 1, lexed.end(), current.toktype, tok::inverseLCharacter(current.toktype));
|
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);
|
vector<tok> subTokens(lexed.begin() + i + 1, closingCharacter);
|
||||||
if (current.toktype == LPAR || current.toktype == LBRACKET) filter_comma_list(subTokens);
|
if (current.toktype == LPAR || current.toktype == LBRACKET) filter_comma_list(subTokens);
|
||||||
if (not parseTree.empty()) {
|
if (not parseTree.empty()) {
|
||||||
try {
|
try {
|
||||||
auto& previous = dynamic_cast<ParseTree&>(*parseTree.at(parseTree.size() - 1));
|
auto& previous = dynamic_cast<ParseTree&>(*parseTree.at(parseTree.size() - 1));
|
||||||
if (find_if(reverse_iterator(lexed.begin() + i), lexed.rend(), [](const tok& token){
|
if (find_if(reverse_iterator(lexed.begin() + i), lexed.rend(), [](const tok& token){
|
||||||
return token.toktype != SEMICOLON;
|
return token.toktype != SEMICOLON;
|
||||||
})->toktype != *closingCharacter) {
|
})->toktype != *closingCharacter) {
|
||||||
previous = parse(subTokens);
|
previous = parse(subTokens);
|
||||||
i = distance(lexed.begin(), closingCharacter);
|
i = distance(lexed.begin(), closingCharacter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (const out_of_range&) {} catch (const bad_cast&) {}
|
} 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 {
|
try {
|
||||||
const auto& last = parseTree.cend() - 1;
|
const auto& last = parseTree.cend() - 1;
|
||||||
const type_info& lastId = last->get()->getId();
|
const type_info& lastId = last->get()->getId();
|
||||||
const auto& last_identifier = dynamic_cast<NamedIdentifier&>(**last);
|
const auto& last_identifier = dynamic_cast<NamedIdentifier<true>&>(**last);
|
||||||
if (lastId != typeid(Reference) &&
|
if (lastId != typeid(Define) and
|
||||||
lastId != typeid(Call) &&
|
|
||||||
lastId != typeid(Define) and
|
|
||||||
any_of(parseTree.cbegin(), last, [&last_identifier](const component_ptr& pointer){
|
any_of(parseTree.cbegin(), last, [&last_identifier](const component_ptr& pointer){
|
||||||
try {
|
try {
|
||||||
return dynamic_cast<NamedIdentifier&>(*pointer).name == last_identifier.name;
|
return dynamic_cast<NamedIdentifier<true>&>(*pointer).name == last_identifier.name;
|
||||||
} catch (const bad_cast&) {
|
} catch (const bad_cast&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -132,7 +132,8 @@ public:
|
||||||
make_task(StandardComponents::Reference, output << parseComponent.name;),
|
make_task(StandardComponents::Reference, output << parseComponent.name;),
|
||||||
make_task(StandardComponents::Call,
|
make_task(StandardComponents::Call,
|
||||||
const auto print_functions = printFunctions();
|
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, ", ");
|
separate_transpileTree(parseComponent, ", ");
|
||||||
output << ')';
|
output << ')';
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in New Issue