Parse Calls/ParseTrees
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
This commit is contained in:
parent
3f75c5cfc8
commit
f33aec687a
@ -43,7 +43,7 @@ vector<tok> lex(const string& in)
|
||||
} else goto insertToken;
|
||||
}
|
||||
[[unlikely]] case EOF_: --lineNumber;
|
||||
case DEFINE: case LPAR: case RPAR:
|
||||
case DEFINE: case LPAR: case RPAR: case COMMA:
|
||||
case LBRACE: case RBRACE: case LBRACKET: case RBRACKET:
|
||||
case PLUS: case HYPHEN: case LCOMP: case RCOMP:
|
||||
case DOT: case DOLLAR_SIGN: case SQUOTE:
|
||||
|
@ -10,7 +10,7 @@ struct tok {
|
||||
typedef Yerbacon::Exception LexerException;
|
||||
enum type: const unsigned short {
|
||||
UNEXPECTED = std::numeric_limits<unsigned char>::max() + 1, IDENTIFIER, NUMBER, ALPHACHAR,
|
||||
EOF_ = '\0', DEFINE = '=', TAG = '#', DOLLAR_SIGN = '$', DOT = '.',
|
||||
EOF_ = '\0', DEFINE = '=', TAG = '#', DOLLAR_SIGN = '$', DOT = '.', COMMA = ',',
|
||||
LPAR = '(', LBRACE = '{', LBRACKET = '[', RPAR = ')',
|
||||
RBRACE = '}', RBRACKET = ']',
|
||||
PLUS = '+', HYPHEN = '-', DIVIDE = '/',
|
||||
|
@ -20,41 +20,27 @@ struct ParseComponent {
|
||||
virtual ~ParseComponent() = default;
|
||||
};
|
||||
|
||||
namespace StandardComponents {
|
||||
struct NamedIdentifier: ParseComponent {
|
||||
const string name;
|
||||
explicit NamedIdentifier(string_view nameText): name(nameText) {}
|
||||
};
|
||||
struct Define: NamedIdentifier {
|
||||
const bool final;
|
||||
explicit Define(const bool& isFinal, string_view nameText): NamedIdentifier(nameText), final(isFinal) {}
|
||||
explicit Define(string_view nameText): Define(false, nameText) {}
|
||||
};
|
||||
struct Reference: NamedIdentifier {
|
||||
using NamedIdentifier::NamedIdentifier;
|
||||
};
|
||||
|
||||
struct Class: NamedIdentifier {
|
||||
using NamedIdentifier::NamedIdentifier;
|
||||
};
|
||||
namespace types {
|
||||
struct String: ParseComponent {
|
||||
const string content;
|
||||
explicit String(const char* string): content(string) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
struct NamedIdentifier: ParseComponent {
|
||||
const string name;
|
||||
explicit NamedIdentifier(string_view nameText): name(nameText) {}
|
||||
};
|
||||
|
||||
#define IS_PARSECOMPONENT IS(ParseComponent)
|
||||
class ParseTree {
|
||||
class ParseTree: public ParseComponent {
|
||||
mutable vector<unique_ptr<ParseComponent>> subComponents;
|
||||
using array_type = decltype(subComponents);
|
||||
using iterator = array_type::iterator;
|
||||
using constant_iterator = array_type::const_iterator;
|
||||
protected:
|
||||
IS_PARSECOMPONENT
|
||||
void addComponent(const T& component) const
|
||||
{ subComponents.emplace_back(new T(component)); };
|
||||
void addComponent(const T& component) const {
|
||||
if constexpr(is_copy_constructible_v<T>) {
|
||||
subComponents.emplace_back(new T(component));
|
||||
} else {
|
||||
static_assert(is_move_constructible_v<T>, "T is not copy-constructible or move-constructible");
|
||||
subComponents.emplace_back(new T(move(const_cast<T&>(component))));
|
||||
}
|
||||
};
|
||||
IS_PARSECOMPONENT
|
||||
void addAllComponents(
|
||||
const initializer_list<T>& components
|
||||
@ -63,6 +49,7 @@ protected:
|
||||
for (const T& current: components) addComponent<T>(current);
|
||||
}
|
||||
public:
|
||||
inline size_t size() const { return subComponents.size(); }
|
||||
inline iterator begin() const noexcept { return subComponents.begin(); }
|
||||
inline constant_iterator cbegin() const noexcept { return subComponents.cbegin(); }
|
||||
inline iterator end() const noexcept { return subComponents.end(); }
|
||||
@ -77,7 +64,7 @@ public:
|
||||
});
|
||||
return filteredComponents;
|
||||
}
|
||||
IS(StandardComponents::NamedIdentifier)
|
||||
IS(NamedIdentifier)
|
||||
optional<reference_wrapper<T>> findReferenceByName(const string& name) const {
|
||||
const vector<T*> identifiers = findById<T>();
|
||||
for (T* identifier: identifiers) {
|
||||
@ -88,16 +75,39 @@ public:
|
||||
return optional<reference_wrapper<T>>();
|
||||
};
|
||||
inline decltype(*subComponents.data()) operator[](const unsigned int& index) const { return subComponents[index]; }
|
||||
IS(StandardComponents::NamedIdentifier)
|
||||
IS(NamedIdentifier)
|
||||
inline auto operator[](const string& key) const { return findReferenceByName<T>(key); }
|
||||
inline size_t getCompCount() const { return subComponents.size(); }
|
||||
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; }
|
||||
ParseTree(): subComponents() {};
|
||||
IS_PARSECOMPONENT constexpr explicit ParseTree(const T& element): ParseTree() { addComponent(element); }
|
||||
IS_PARSECOMPONENT constexpr ParseTree(const initializer_list<T>& elements): ParseTree() { addAllComponents(elements); }
|
||||
ParseTree(ParseTree&& parseTree) noexcept: subComponents(move(parseTree.subComponents)) {}
|
||||
ParseTree(const ParseTree& parseTree) = delete;
|
||||
};
|
||||
#undef IS_PARSECOMPONENT
|
||||
|
||||
namespace StandardComponents {
|
||||
struct Define: NamedIdentifier {
|
||||
const bool final;
|
||||
explicit Define(const bool& isFinal, string_view nameText): NamedIdentifier(nameText), final(isFinal) {}
|
||||
explicit Define(string_view nameText): Define(false, nameText) {}
|
||||
};
|
||||
struct Reference: NamedIdentifier {
|
||||
using NamedIdentifier::NamedIdentifier;
|
||||
};
|
||||
namespace types {
|
||||
struct String: ParseComponent {
|
||||
const string content;
|
||||
explicit String(const char* string): content(string) {}
|
||||
};
|
||||
}
|
||||
struct Call: ParseTree { inline explicit Call(ParseTree&& tree) noexcept: ParseTree(move(tree)) {} };
|
||||
|
||||
struct Class: NamedIdentifier {
|
||||
using NamedIdentifier::NamedIdentifier;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //YERBACON_PARSECOMPONENTS_HPP
|
@ -58,7 +58,38 @@ namespace Parser {
|
||||
parseTree << Reference(current.toktext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LPAR: case LBRACE: case LBRACKET: {
|
||||
const auto inverseCharacter = static_cast<tok::type>((current.toktype + 2) - (current.toktype == LPAR));
|
||||
const auto closingCharacter = find_if(lexed.cbegin(), lexed.cend(), [&inverseCharacter](const tok& it){
|
||||
return it.toktype == inverseCharacter;
|
||||
});
|
||||
if (closingCharacter != lexed.cend()) {
|
||||
vector<tok> subTokens;
|
||||
subTokens.reserve(distance(lexed.cbegin() + i, closingCharacter));
|
||||
subTokens.assign(lexed.cbegin() + i + 1, closingCharacter);
|
||||
if (current.toktype == LPAR || current.toktype == LBRACKET) {
|
||||
if (subTokens.size() >= 2 && subTokens[1].toktype != RPAR) {
|
||||
for (auto iterator = subTokens.cbegin(); iterator < (subTokens.cend() - 1); ++iterator) {
|
||||
const auto nextIterator = iterator + 1;
|
||||
if (nextIterator->toktype == COMMA) {
|
||||
subTokens.erase(nextIterator);
|
||||
} else throw ParsingException("Missing comma after \"" + iterator->toktext + '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (current.toktype) {
|
||||
case LPAR: parseTree << Call(parseVector(subTokens)); break;
|
||||
case LBRACE: // TODO Add structures for class/function bodies
|
||||
case LBRACKET:
|
||||
default: parseTree << parseVector(subTokens); break;
|
||||
}
|
||||
i = distance(lexed.cbegin(), closingCharacter);
|
||||
} else parsingError(current, string(" is missing a closing \"").append(1, inverseCharacter) + '"', true);
|
||||
break;
|
||||
}
|
||||
case RPAR: case RBRACE: case RBRACKET: parsingError(current, " \u27F5 Unexpected character", true);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -67,15 +67,33 @@ protected:
|
||||
typedef function<void (const ParseTree& parsedTree, unsigned int& index)> task;
|
||||
#define make_task_base(type, captures, function_body) make_pair(type_index(typeid(type)), [captures](const ParseTree& parsedTree, unsigned int& index) { const type& parseComponent = pointerAs<type>(parsedTree[index]); function_body })
|
||||
#define make_task(T, F) make_task_base(T, this, F)
|
||||
#define make_nonlocal_task(T, F) make_task_base(T, , F)
|
||||
typedef unordered_map<type_index, task> unordered_task_map;
|
||||
typedef pair<const char*, const char*> print_functions_pair;
|
||||
virtual unordered_task_map getTaskMap() = 0;
|
||||
virtual print_functions_pair printFunctions() = 0;
|
||||
public:
|
||||
const unordered_task_map& getTaskMapInstance() {
|
||||
static unordered_task_map staticMap = getTaskMap();
|
||||
// Default / Shared tasks:
|
||||
staticMap.merge(unordered_task_map({
|
||||
make_task(StandardComponents::Reference,
|
||||
output << parseComponent.name;
|
||||
make_task(ParseTree,
|
||||
unsigned int subIndex = 0;
|
||||
for (auto pointer_iterator = parseComponent.cbegin(); pointer_iterator < parseComponent.cend(); ++pointer_iterator) {
|
||||
staticMap[pointer_iterator->get()->getId()](parseComponent, subIndex); ++subIndex;
|
||||
if ((pointer_iterator + 1) != parseComponent.cend() && parseComponent.getId() == typeid(StandardComponents::Call)) {
|
||||
output << ", ";
|
||||
}
|
||||
}
|
||||
),
|
||||
make_task_base(StandardComponents::Reference, &,
|
||||
const auto print_functions = printFunctions();
|
||||
output << ((parseComponent.name == "print") ? print_functions.first : (parseComponent.name == "print_line") ? print_functions.second : parseComponent.name);
|
||||
),
|
||||
make_task(StandardComponents::Call,
|
||||
output << '(';
|
||||
staticMap[typeid(ParseTree)](parsedTree, index);
|
||||
output << ')';
|
||||
)
|
||||
}));
|
||||
return staticMap;
|
||||
@ -88,12 +106,11 @@ public:
|
||||
throw Yerbacon::Exception("--newlines=off is not supported by the current target");
|
||||
}
|
||||
output.str(string());
|
||||
for (unsigned int i = 0; i < tree.getCompCount(); ++i) {
|
||||
for (unsigned int i = 0; i < tree.size(); ++i) {
|
||||
const unique_ptr<ParseComponent>& component = tree[i];
|
||||
const type_info& id = component->getId();
|
||||
try {
|
||||
const task& currentTask = taskMap.at(id);
|
||||
currentTask(tree, i);
|
||||
taskMap.at(id)(tree, i);
|
||||
} catch (const out_of_range&) {
|
||||
throw Yerbacon::Exception(string(
|
||||
#ifndef __GNUC__
|
||||
@ -141,7 +158,9 @@ shared_ptr<Target> Target::forName(string_view name, const bool newLines = true)
|
||||
default: Yerbacon::exit({"\"", string(1, (char) toupper(name.at(1))).data(), name.substr(2).data(), "\" is not a valid target."});
|
||||
}
|
||||
#undef ADDTARGET
|
||||
#undef make_nonlocal_task
|
||||
#undef make_task
|
||||
#undef make_task_base
|
||||
return target;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
using namespace StandardComponents;
|
||||
|
||||
struct JsTarget: Target {
|
||||
print_functions_pair printFunctions() final { return make_pair("util.write", "console.log"); }
|
||||
unordered_task_map getTaskMap() final {
|
||||
return {
|
||||
make_task(Define,
|
||||
|
@ -3,6 +3,7 @@
|
||||
using namespace StandardComponents;
|
||||
|
||||
struct LuaTarget: Target {
|
||||
print_functions_pair printFunctions() final { return make_pair("io.write", "print"); }
|
||||
unordered_task_map getTaskMap() final {
|
||||
return {
|
||||
make_task(Define,
|
||||
|
@ -4,6 +4,7 @@ using namespace StandardComponents;
|
||||
|
||||
struct PyTarget: Target {
|
||||
bool supportsOneLine() final { return false; }
|
||||
print_functions_pair printFunctions() final { return make_pair("sys.stdout.write", "print"); }
|
||||
unordered_task_map getTaskMap() final {
|
||||
return {
|
||||
make_task(Define, output << parseComponent.name << " = ";),
|
||||
|
Loading…
Reference in New Issue
Block a user