Refactoring for OOP
This commit is contained in:
@@ -6,6 +6,11 @@
|
||||
|
||||
#include "../parser/parser.h"
|
||||
|
||||
Object::Object(ASTValue value) : value(value) {}
|
||||
Object::Object(ASTFunction function) : value(function) {}
|
||||
Object::Object() = default;
|
||||
|
||||
|
||||
std::optional<ASTNode> Executor::consume() {
|
||||
if (iterator < code.nodes.size()) {
|
||||
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 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.
|
||||
* @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.
|
||||
* @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.
|
||||
*
|
||||
* @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).
|
||||
*/
|
||||
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++) {
|
||||
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) {
|
||||
std::optional<ASTNode> node = consume();
|
||||
@@ -63,7 +76,7 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
||||
// eg: main func { ... }
|
||||
// eg: dingus func { ... }
|
||||
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())) {
|
||||
std::string id = std::get<std::shared_ptr<ASTIdentifier>>(next.value())->name;
|
||||
if (id == "=") {
|
||||
@@ -72,9 +85,9 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
||||
if (valueNode.has_value()) {
|
||||
ASTValue next;
|
||||
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())) {
|
||||
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 {
|
||||
std::cout << "Expected value or function after = sign" << std::endl;
|
||||
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())) {
|
||||
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<ASTValue> callArgs;
|
||||
std::vector<Object> callArgs;
|
||||
for (auto &callArgNode : callArgNodes) {
|
||||
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)) {
|
||||
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]);
|
||||
@@ -116,7 +129,14 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
||||
exit(1);
|
||||
}
|
||||
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) {
|
||||
std::optional<std::string> argString = arg.getString();
|
||||
if (argString.has_value()) {
|
||||
@@ -150,7 +170,14 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
||||
}
|
||||
}
|
||||
} 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) {
|
||||
std::optional<std::string> argString = arg.getString();
|
||||
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) {
|
||||
std::optional<bool> argBool = arg.getBool();
|
||||
if (argBool.has_value()) {
|
||||
std::cout << argBool.value() << std::endl;
|
||||
std::cout << (argBool.value() ? "true" : "false") << std::endl;
|
||||
} else {
|
||||
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;
|
||||
exit(1);
|
||||
}
|
||||
if (callArgs[0].type != ValueType::Bool) {
|
||||
std::cout << "Expected first argument to if statement to be a boolean" << std::endl;
|
||||
ASTValue arg;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
exit(1);
|
||||
}
|
||||
if (callArgs[0].getBool().value()) {
|
||||
if (arg.getBool().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") {
|
||||
if (callArgs.empty()) {
|
||||
std::cout << "Expected at least one argument to if statement" << std::endl;
|
||||
ASTValue arg;
|
||||
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);
|
||||
}
|
||||
if (callArgs[0].type != ValueType::Bool) {
|
||||
std::cout << "Expected first argument to if statement to be a boolean" << std::endl;
|
||||
if (callArgs.empty()) {
|
||||
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);
|
||||
}
|
||||
std::optional<ASTNode> block = consume();
|
||||
if (!block.has_value()) {
|
||||
std::cout << "If statement expects a body" << std::endl;
|
||||
std::cout << "While statement expects a body" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if (callArgs[0].getBool().value()) {
|
||||
while (callArgs[0].getBool().value()) {
|
||||
if (arg.getBool().value()) {
|
||||
while (arg.getBool().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 (functions.find(fnName) != functions.end()) {
|
||||
Executor(functions[fnName].body, false, variables, functions, callArgs);
|
||||
if (variables.find(fnName) != variables.end()) {
|
||||
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 {
|
||||
std::cout << "Function " << fnName << " not found" << std::endl;
|
||||
exit(1);
|
||||
@@ -237,6 +289,6 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, ASTVa
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
* @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.
|
||||
*/
|
||||
|
||||
class Object {
|
||||
public:
|
||||
std::vector<Object> children;
|
||||
};
|
||||
|
||||
class Executor {
|
||||
private:
|
||||
std::map<std::string, ASTFunction> functions;
|
||||
std::map<std::string, ASTValue> variables;
|
||||
std::map<std::string, Object> variables;
|
||||
ASTCodeBlock code;
|
||||
size_t iterator = 0;
|
||||
std::optional<ASTNode> consume();
|
||||
std::optional<ASTNode> peek(int ahead = 1);
|
||||
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 {
|
||||
// println is an inbuilt function, you can also use print
|
||||
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) {
|
||||
println("yay")
|
||||
}
|
||||
// types available are int, float, string, bool
|
||||
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 {
|
||||
dingus()
|
||||
// call a function (with arguments!)
|
||||
dingus("hehe")
|
||||
}
|
||||
|
||||
// run this if you dare! try adding it in the main function!
|
||||
infinity func {
|
||||
while (true) {
|
||||
println("to infinity and beyond!")
|
||||
|
||||
Reference in New Issue
Block a user