Refactoring for OOP
This commit is contained in:
@@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
#include "../parser/parser.h"
|
#include "../parser/parser.h"
|
||||||
|
|
||||||
|
Object::Object(ASTValue value) : value(value) {}
|
||||||
|
Object::Object(ASTFunction function) : value(function) {}
|
||||||
|
Object::Object() = default;
|
||||||
|
|
||||||
|
|
||||||
std::optional<ASTNode> Executor::consume() {
|
std::optional<ASTNode> Executor::consume() {
|
||||||
if (iterator < code.nodes.size()) {
|
if (iterator < code.nodes.size()) {
|
||||||
return code.nodes[iterator++];
|
return code.nodes[iterator++];
|
||||||
@@ -30,10 +35,8 @@ std::optional<ASTNode> Executor::peek(int ahead) {
|
|||||||
* @param in The abstract syntax tree (AST) code block to execute.
|
* @param in The abstract syntax tree (AST) code block to execute.
|
||||||
* @param isInitCall A boolean flag to determine if this is the initial entry point to execution.
|
* @param isInitCall A boolean flag to determine if this is the initial entry point to execution.
|
||||||
* If true, it runs the "main" function after setting up the context.
|
* If true, it runs the "main" function after setting up the context.
|
||||||
* @param scopeVals A map of variable names (strings) to their corresponding `ASTValue` objects used as
|
* @param scopeVals A map of variable names (strings) to their corresponding `Object` objects used as
|
||||||
* the current scope of variables.
|
* the current scope of variables.
|
||||||
* @param scopeFns A map of function names (strings) to their corresponding `ASTFunction` objects used as
|
|
||||||
* the current set of functions within scope.
|
|
||||||
* @param args A vector of `ASTValue` objects passed as arguments for the context of this execution.
|
* @param args A vector of `ASTValue` objects passed as arguments for the context of this execution.
|
||||||
*
|
*
|
||||||
* @details
|
* @details
|
||||||
@@ -48,9 +51,19 @@ std::optional<ASTNode> Executor::peek(int ahead) {
|
|||||||
*
|
*
|
||||||
* @note Exits the process if critical execution errors occur (e.g., unexpected nodes or missing values).
|
* @note Exits the process if critical execution errors occur (e.g., unexpected nodes or missing values).
|
||||||
*/
|
*/
|
||||||
Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTValue> scopeVals, std::map<std::string, ASTFunction> scopeFns, std::vector<ASTValue> args) : code(std::move(in)), variables(std::move(scopeVals)), functions(std::move(scopeFns)) {
|
Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Object> scopeVals, std::vector<Object> args) : code(std::move(in)) {
|
||||||
for (size_t i = 0; i < args.size(); i++) {
|
for (size_t i = 0; i < args.size(); i++) {
|
||||||
variables["arg" + std::to_string(i)] = args[i];
|
variables.emplace("arg" + std::to_string(i), args[i]);
|
||||||
|
}
|
||||||
|
for (auto &pair : scopeVals) {
|
||||||
|
variables.emplace(pair.first, pair.second);
|
||||||
|
}
|
||||||
|
if (isInitCall) {
|
||||||
|
// add a main function if it doesn't exist
|
||||||
|
if (variables.find("main") == variables.end()) {
|
||||||
|
ASTFunction mainFunc;
|
||||||
|
mainFunc.body = ASTCodeBlock({"println(\"Hey there! Looks like your main function doesn't exist, so we made one for you :)\")"});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
std::optional<ASTNode> node = consume();
|
std::optional<ASTNode> node = consume();
|
||||||
@@ -63,7 +76,7 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
// eg: main func { ... }
|
// eg: main func { ... }
|
||||||
// eg: dingus func { ... }
|
// eg: dingus func { ... }
|
||||||
if (std::holds_alternative<std::shared_ptr<ASTFunction>>(next.value())) {
|
if (std::holds_alternative<std::shared_ptr<ASTFunction>>(next.value())) {
|
||||||
functions[std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name] = *std::get<std::shared_ptr<ASTFunction>>(next.value());
|
variables.emplace(std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name, *std::get<std::shared_ptr<ASTFunction>>(next.value()));
|
||||||
} else if (std::holds_alternative<std::shared_ptr<ASTIdentifier>>(next.value())) {
|
} else if (std::holds_alternative<std::shared_ptr<ASTIdentifier>>(next.value())) {
|
||||||
std::string id = std::get<std::shared_ptr<ASTIdentifier>>(next.value())->name;
|
std::string id = std::get<std::shared_ptr<ASTIdentifier>>(next.value())->name;
|
||||||
if (id == "=") {
|
if (id == "=") {
|
||||||
@@ -72,9 +85,9 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
if (valueNode.has_value()) {
|
if (valueNode.has_value()) {
|
||||||
ASTValue next;
|
ASTValue next;
|
||||||
if (std::holds_alternative<std::shared_ptr<ASTValue>>(valueNode.value())) {
|
if (std::holds_alternative<std::shared_ptr<ASTValue>>(valueNode.value())) {
|
||||||
variables[std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name] = *std::get<std::shared_ptr<ASTValue>>(valueNode.value());
|
variables.emplace(std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name, *std::get<std::shared_ptr<ASTValue>>(valueNode.value()));
|
||||||
} else if (std::holds_alternative<std::shared_ptr<ASTFunction>>(valueNode.value())) {
|
} else if (std::holds_alternative<std::shared_ptr<ASTFunction>>(valueNode.value())) {
|
||||||
functions[std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name] = *std::get<std::shared_ptr<ASTFunction>>(valueNode.value());
|
variables.emplace(std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name, *std::get<std::shared_ptr<ASTFunction>>(valueNode.value()));
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Expected value or function after = sign" << std::endl;
|
std::cout << "Expected value or function after = sign" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -96,10 +109,10 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
if (std::holds_alternative<std::shared_ptr<ASTFunctionCall>>(node.value())) {
|
if (std::holds_alternative<std::shared_ptr<ASTFunctionCall>>(node.value())) {
|
||||||
std::string fnName = std::get<std::shared_ptr<ASTFunctionCall>>(node.value())->func;
|
std::string fnName = std::get<std::shared_ptr<ASTFunctionCall>>(node.value())->func;
|
||||||
std::vector<ASTNode> callArgNodes = std::get<std::shared_ptr<ASTFunctionCall>>(node.value())->args;
|
std::vector<ASTNode> callArgNodes = std::get<std::shared_ptr<ASTFunctionCall>>(node.value())->args;
|
||||||
std::vector<ASTValue> callArgs;
|
std::vector<Object> callArgs;
|
||||||
for (auto &callArgNode : callArgNodes) {
|
for (auto &callArgNode : callArgNodes) {
|
||||||
if (std::holds_alternative<std::shared_ptr<ASTValue>>(callArgNode)) {
|
if (std::holds_alternative<std::shared_ptr<ASTValue>>(callArgNode)) {
|
||||||
callArgs.push_back(*std::get<std::shared_ptr<ASTValue>>(callArgNode));
|
callArgs.emplace_back(*std::get<std::shared_ptr<ASTValue>>(callArgNode));
|
||||||
} else if (std::holds_alternative<std::shared_ptr<ASTIdentifier>>(callArgNode)) {
|
} else if (std::holds_alternative<std::shared_ptr<ASTIdentifier>>(callArgNode)) {
|
||||||
if (variables.find(std::get<std::shared_ptr<ASTIdentifier>>(callArgNode)->name) != variables.end()) {
|
if (variables.find(std::get<std::shared_ptr<ASTIdentifier>>(callArgNode)->name) != variables.end()) {
|
||||||
callArgs.push_back(variables[std::get<std::shared_ptr<ASTIdentifier>>(callArgNode)->name]);
|
callArgs.push_back(variables[std::get<std::shared_ptr<ASTIdentifier>>(callArgNode)->name]);
|
||||||
@@ -116,7 +129,14 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (fnName == "print") {
|
if (fnName == "print") {
|
||||||
for (ASTValue &arg : callArgs) {
|
for (Object &object : callArgs) {
|
||||||
|
ASTValue arg;
|
||||||
|
if (object.isCustomObject == false && std::holds_alternative<ASTValue>(object.value)) {
|
||||||
|
arg = std::get<ASTValue>(object.value);
|
||||||
|
} else {
|
||||||
|
std::cout << "Type mismatch - expecting string, int, float, or bool but got something else" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (arg.type == ValueType::String) {
|
if (arg.type == ValueType::String) {
|
||||||
std::optional<std::string> argString = arg.getString();
|
std::optional<std::string> argString = arg.getString();
|
||||||
if (argString.has_value()) {
|
if (argString.has_value()) {
|
||||||
@@ -150,7 +170,14 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (fnName == "println") {
|
} else if (fnName == "println") {
|
||||||
for (ASTValue &arg : callArgs) {
|
for (Object &object : callArgs) {
|
||||||
|
ASTValue arg;
|
||||||
|
if (object.isCustomObject == false && std::holds_alternative<ASTValue>(object.value)) {
|
||||||
|
arg = std::get<ASTValue>(object.value);
|
||||||
|
} else {
|
||||||
|
std::cout << "Type mismatch - expecting string, int, float, or bool but got something else" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (arg.type == ValueType::String) {
|
if (arg.type == ValueType::String) {
|
||||||
std::optional<std::string> argString = arg.getString();
|
std::optional<std::string> argString = arg.getString();
|
||||||
if (argString.has_value()) {
|
if (argString.has_value()) {
|
||||||
@@ -175,7 +202,7 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
} else if (arg.type == ValueType::Bool) {
|
} else if (arg.type == ValueType::Bool) {
|
||||||
std::optional<bool> argBool = arg.getBool();
|
std::optional<bool> argBool = arg.getBool();
|
||||||
if (argBool.has_value()) {
|
if (argBool.has_value()) {
|
||||||
std::cout << argBool.value() << std::endl;
|
std::cout << (argBool.value() ? "true" : "false") << std::endl;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Type mismatch - expecting bool but got something else" << std::endl;
|
std::cout << "Type mismatch - expecting bool but got something else" << std::endl;
|
||||||
}
|
}
|
||||||
@@ -188,8 +215,15 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
std::cout << "Expected at least one argument to if statement" << std::endl;
|
std::cout << "Expected at least one argument to if statement" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (callArgs[0].type != ValueType::Bool) {
|
ASTValue arg;
|
||||||
std::cout << "Expected first argument to if statement to be a boolean" << std::endl;
|
if (callArgs[0].isCustomObject == false && std::holds_alternative<ASTValue>(callArgs[0].value)) {
|
||||||
|
arg = std::get<ASTValue>(callArgs[0].value);
|
||||||
|
} else {
|
||||||
|
std::cout << "Type mismatch - expecting boolean in if statement" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (arg.type != ValueType::Bool) {
|
||||||
|
std::cout << "Type mismatch - expecting boolean in if statement" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
std::optional<ASTNode> block = consume();
|
std::optional<ASTNode> block = consume();
|
||||||
@@ -197,35 +231,53 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
std::cout << "If statement expects a body" << std::endl;
|
std::cout << "If statement expects a body" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (callArgs[0].getBool().value()) {
|
if (arg.getBool().value()) {
|
||||||
if (std::holds_alternative<std::shared_ptr<ASTCodeBlock>>(block.value())) {
|
if (std::holds_alternative<std::shared_ptr<ASTCodeBlock>>(block.value())) {
|
||||||
Executor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables, functions);
|
Executor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (fnName == "while") {
|
} else if (fnName == "while") {
|
||||||
if (callArgs.empty()) {
|
ASTValue arg;
|
||||||
std::cout << "Expected at least one argument to if statement" << std::endl;
|
if (callArgs[0].isCustomObject == false && std::holds_alternative<ASTValue>(callArgs[0].value)) {
|
||||||
|
arg = std::get<ASTValue>(callArgs[0].value);
|
||||||
|
} else {
|
||||||
|
std::cout << "Type mismatch - expecting boolean in while statement" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (callArgs[0].type != ValueType::Bool) {
|
if (callArgs.empty()) {
|
||||||
std::cout << "Expected first argument to if statement to be a boolean" << std::endl;
|
std::cout << "Expected at least one argument to while statement" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (arg.type != ValueType::Bool) {
|
||||||
|
std::cout << "Expected first argument to while statement to be a boolean" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
std::optional<ASTNode> block = consume();
|
std::optional<ASTNode> block = consume();
|
||||||
if (!block.has_value()) {
|
if (!block.has_value()) {
|
||||||
std::cout << "If statement expects a body" << std::endl;
|
std::cout << "While statement expects a body" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (callArgs[0].getBool().value()) {
|
if (arg.getBool().value()) {
|
||||||
while (callArgs[0].getBool().value()) {
|
while (arg.getBool().value()) {
|
||||||
if (std::holds_alternative<std::shared_ptr<ASTCodeBlock>>(block.value())) {
|
if (std::holds_alternative<std::shared_ptr<ASTCodeBlock>>(block.value())) {
|
||||||
Executor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables, functions);
|
Executor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (functions.find(fnName) != functions.end()) {
|
if (variables.find(fnName) != variables.end()) {
|
||||||
Executor(functions[fnName].body, false, variables, functions, callArgs);
|
if (variables[fnName].isCustomObject) {
|
||||||
|
if (std::holds_alternative<ASTFunction>(variables[fnName].children["handler"])) {
|
||||||
|
Executor(std::get<ASTFunction>(variables[fnName].children["handler"]).body, false, {}, callArgs);
|
||||||
|
} else {
|
||||||
|
std::cout << "Object " << fnName << " does not have a handler function" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<ASTFunction>(variables[fnName].value)) {
|
||||||
|
Executor(std::get<ASTFunction>(variables[fnName].value).body, false, {}, callArgs);
|
||||||
|
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Function " << fnName << " not found" << std::endl;
|
std::cout << "Function " << fnName << " not found" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -237,6 +289,6 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isInitCall) {
|
if (isInitCall) {
|
||||||
Executor(functions["main"].body, false, variables, functions);
|
Executor(std::get<ASTFunction>(variables[std::string("main")].value).body, false, variables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <variant>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../parser/parser.h"
|
#include "../parser/parser.h"
|
||||||
|
|
||||||
|
class Object {
|
||||||
|
public:
|
||||||
|
bool isCustomObject = false;
|
||||||
|
std::variant<ASTValue, ASTFunction> value;
|
||||||
|
std::map<std::string, std::variant<Object, ASTFunction, ASTValue>> children;
|
||||||
|
Object(ASTValue value);
|
||||||
|
Object(ASTFunction function);
|
||||||
|
Object();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Executor
|
* @class Executor
|
||||||
* @brief Responsible for executing a sequence of operations defined in an abstract syntax tree (AST).
|
* @brief Responsible for executing a sequence of operations defined in an abstract syntax tree (AST).
|
||||||
@@ -14,20 +28,14 @@
|
|||||||
* and consuming or peeking at individual nodes.
|
* and consuming or peeking at individual nodes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Object {
|
|
||||||
public:
|
|
||||||
std::vector<Object> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Executor {
|
class Executor {
|
||||||
private:
|
private:
|
||||||
std::map<std::string, ASTFunction> functions;
|
std::map<std::string, Object> variables;
|
||||||
std::map<std::string, ASTValue> variables;
|
|
||||||
ASTCodeBlock code;
|
ASTCodeBlock code;
|
||||||
size_t iterator = 0;
|
size_t iterator = 0;
|
||||||
std::optional<ASTNode> consume();
|
std::optional<ASTNode> consume();
|
||||||
std::optional<ASTNode> peek(int ahead = 1);
|
std::optional<ASTNode> peek(int ahead = 1);
|
||||||
public:
|
public:
|
||||||
explicit Executor(ASTCodeBlock in, bool isInitCall = false, std::map<std::string, ASTValue> scopeVals = {}, std::map<std::string, ASTFunction> scopeFns = {}, std::vector<ASTValue> args = {});
|
explicit Executor(ASTCodeBlock in, bool isInitCall = false, std::map<std::string, Object> scopeVals = {}, std::vector<Object> args = {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,30 @@
|
|||||||
import("io")
|
|
||||||
|
|
||||||
dingus func {
|
dingus func {
|
||||||
|
// println is an inbuilt function, you can also use print
|
||||||
println("you got dingused")
|
println("you got dingused")
|
||||||
|
// for now, args for functions are accessed with arg0, arg1, etc
|
||||||
|
print("You said: ")
|
||||||
|
println(arg0)
|
||||||
|
// set a variable, similar to Python
|
||||||
|
x = 5
|
||||||
|
println(x)
|
||||||
|
// if statements are pretty standard
|
||||||
if (true) {
|
if (true) {
|
||||||
println("yay")
|
println("yay")
|
||||||
}
|
}
|
||||||
|
// types available are int, float, string, bool
|
||||||
println(321)
|
println(321)
|
||||||
|
println(3.14)
|
||||||
|
println("I am a string!")
|
||||||
|
println(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// main is the entry point of the program, like many other languages
|
||||||
main func {
|
main func {
|
||||||
dingus()
|
// call a function (with arguments!)
|
||||||
|
dingus("hehe")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run this if you dare! try adding it in the main function!
|
||||||
infinity func {
|
infinity func {
|
||||||
while (true) {
|
while (true) {
|
||||||
println("to infinity and beyond!")
|
println("to infinity and beyond!")
|
||||||
|
|||||||
Reference in New Issue
Block a user