diff --git a/src/Scope.cpp b/src/Scope.cpp index db9b6fe..4341a84 100644 --- a/src/Scope.cpp +++ b/src/Scope.cpp @@ -14,7 +14,7 @@ bool Scope::varExists(Context& ctx, std::string name) { } } -std::any& Scope::getVar(Context& cxt, std::string name) { +Value& Scope::getVar(Context& cxt, std::string name) { if (vars.find(name) == vars.end()) { if (varExists(cxt, name)) { return parentScope.get()->getVar(cxt, name); @@ -26,7 +26,7 @@ std::any& Scope::getVar(Context& cxt, std::string name) { return vars.at(name); } -void Scope::writeVar(Context& cxt, std::string name, std::any& var) { +void Scope::writeVar(Context& cxt, std::string name, const Value& var) { if (vars.find(name) == vars.end()) { if (varExists(cxt, name)) { parentScope.get()->writeVar(cxt, name, var); diff --git a/src/Scope.h b/src/Scope.h index 7d4dc9e..c1b9b6c 100644 --- a/src/Scope.h +++ b/src/Scope.h @@ -1,9 +1,10 @@ #pragma once +#include "types.h" + #include #include #include -#include class Context; @@ -11,7 +12,7 @@ class Context; class Scope { public: std::shared_ptr parentScope; - std::unordered_map vars; + std::unordered_map vars; // std::function returnHandler; // std::function breakHandler; // std::function continueHandler; @@ -25,7 +26,7 @@ public: /** * Looks up var and creates it in the current scope if it doesn't exist */ - std::any& getVar(Context& cxt, std::string name); + Value& getVar(Context& cxt, std::string name); - void writeVar(Context& cxt, std::string name, std::any& var); + void writeVar(Context& cxt, std::string name, const Value& var); }; \ No newline at end of file diff --git a/src/context.cpp b/src/context.cpp index 91d20a5..1ed70a8 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -1,39 +1,38 @@ #include "context.h" +#include #include void Context::error(std::string_view msg) { std::cout << "Error! " << msg << std::endl; } -using std::any_cast; - -std::any Context::readIdentifier(std::any val) { - assert(val.type() == typeid(Identifier)); - return currentScope->getVar(*this, any_cast(val).identifier); +Value Context::readIdentifier(Value val) { + return currentScope->getVar(*this, val.getIdentifier(*this).identifier); } /** * Returns the value of the input (reads the value if it is a refers to a variable) */ -std::any Context::getValue(std::any input) { - if (input.type() == typeid(Identifier)) +Value Context::getValue(Value input) { + if (input.isIdentifier()) return readIdentifier(input); else return input; } -std::any Context::eval(peg::Ast& ast) { +Value Context::eval(peg::Ast& ast) { const auto &nodes = ast.nodes; + Context &cxt = *this; if (ast.name == "Root") { for (int i=0; i(eval(*nodes[0])); - auto value = eval(*nodes[1]); - currentScope->writeVar(*this, identifier.identifier, value); + std::string identifier = eval(*nodes[0]).getIdentifier(cxt).identifier; + Value value = eval(*nodes[1]); + currentScope->writeVar(cxt, identifier, value); return Nil(); } else if (ast.name == "IDENTIFIER" || ast.name == "BUILTINIDENTIFIER") { return Identifier(std::string(ast.token_to_string())); @@ -41,68 +40,66 @@ std::any Context::eval(peg::Ast& ast) { // TODO parse hex, oct, and binary return ast.token_to_number(); } else if (ast.name == "BUILTINCALL" ) { - auto identifier = any_cast(eval(*nodes[0])); - auto args = Args::toArgs(*this, eval(*nodes[1])); - builtins.at(identifier.identifier).execute(*this, args); - // TODO: handle returns - return Nil(); + std::string identifier = eval(*nodes[0]).getIdentifier(cxt).identifier; + Args args = eval(*nodes[1]).getArgs(cxt); + return builtins.at(identifier).execute(cxt, args); } else if (ast.name == "STRINGLITERALSINGLE") { return ast.token_to_string(); } else if (ast.name == "ExprList") { - std::vector exprs; + Args exprs; for (int i=0; i(value) + any_cast(v2); + value = Value(value.getInt(cxt) + v2.getInt(cxt)); } else { - value = any_cast(value) - any_cast(v2); + value = Value(value.getInt(cxt) - v2.getInt(cxt)); } } return value; } else if (ast.name == "MultiplyExpr") { - auto value = getValue(eval(*nodes[0])); + Value value = getValue(eval(*nodes[0])); for (int i=1; i(value) * any_cast(v2); + value = Value(value.getInt(cxt) * v2.getInt(cxt)); } else { - value = any_cast(value) / any_cast(v2); + value = Value(value.getInt(cxt) / v2.getInt(cxt)); } } return value; } else if (ast.name == "AssignExpr") { - std::string name = any_cast(eval(*nodes[0])).identifier; + std::string name = eval(*nodes[0]).getIdentifier(cxt).identifier; // TODO arrays, dot operator, etc. auto v1 = currentScope->getVar(*this, name); int op = (*nodes[1]).choice; auto v2 = getValue(eval(*nodes[2])); - std::any result; + Value result = Value(Nil()); // TODO: floats if (op == 0) { - result = any_cast(v1) * any_cast(v2); + result = Value(v1.getInt(cxt) * v2.getInt(cxt)); } else if (op == 1) { - result = any_cast(v1) % any_cast(v2); + result = Value(v1.getInt(cxt) % v2.getInt(cxt)); } else if (op == 2) { - result = any_cast(v1) + any_cast(v2); + result = Value(v1.getInt(cxt) + v2.getInt(cxt)); } else if (op == 3) { - result = any_cast(v1) - any_cast(v2); + result = Value(v1.getInt(cxt) - v2.getInt(cxt)); } else if (op == 4) { - result = any_cast(v1) & any_cast(v2); + result = Value(v1.getInt(cxt) & v2.getInt(cxt)); } else if (op == 5) { - result = any_cast(v1) ^ any_cast(v2); + result = Value(v1.getInt(cxt) ^ v2.getInt(cxt)); } else if (op == 6) { - result = any_cast(v1) | any_cast(v2); + result = Value(v1.getInt(cxt) | v2.getInt(cxt)); } else if (op == 7) { result = v2; } @@ -118,58 +115,62 @@ std::any Context::eval(peg::Ast& ast) { return true; } } else if (ast.name == "CompareExpr") { - auto v1 = getValue(eval(*nodes[0])); + Value v1 = getValue(eval(*nodes[0])); int op = (*nodes[1]).choice; - auto v2 = getValue(eval(*nodes[2])); + Value v2 = getValue(eval(*nodes[2])); // TODO: floats, bool, etc. if (op == 0) { - return (bool)(any_cast(v1) == any_cast(v2)); + return (bool)(v1.getInt(cxt) == v2.getInt(cxt)); } else if (op == 1) { - return (bool)(any_cast(v1) != any_cast(v2)); + return (bool)(v1.getInt(cxt) != v2.getInt(cxt)); } else if (op == 2) { - return (bool)(any_cast(v1) < any_cast(v2)); + return (bool)(v1.getInt(cxt) < v2.getInt(cxt)); } else if (op == 3) { - return (bool)(any_cast(v1) > any_cast(v2)); + return (bool)(v1.getInt(cxt) > v2.getInt(cxt)); } else if (op == 4) { - return (bool)(any_cast(v1) <= any_cast(v2)); + return (bool)(v1.getInt(cxt) <= v2.getInt(cxt)); } else if (op == 5) { - return (bool)(any_cast(v1) >= any_cast(v2)); + return (bool)(v1.getInt(cxt) >= v2.getInt(cxt)); } } else if (ast.name == "IfStatement") { - auto val = getValue(eval(*nodes[0])); - if (any_cast(val)) { + Value val = getValue(eval(*nodes[0])); + if (val.getBoolean(cxt)) { return eval(*nodes[1]); } else { return eval(*nodes[2]); } } else if (ast.name == "Block") { // TODO create new scope - std::any result = Nil(); + Value result = Value(Nil()); for (int i=0; i(getValue(eval(*nodes[0])))) { + Value result = Nil(); + while (getValue(eval(*nodes[0])).getBoolean(cxt)) { result = eval(*nodes[1]); } return result; } else if (ast.name == "Fn") { - auto identifiers = any_cast>(eval(*nodes[0])); + Args args = eval(*nodes[0]).getArgs(cxt); + std::vector identifiers; + for (int i=0; i identifiers; + Args identifiers; for (int i=0; i(eval(*nodes[i]))); + identifiers.args.push_back(Value(eval(*nodes[i]).getIdentifier(cxt))); } return identifiers; } else if (ast.name == "SuffixExpr") { // TODO handle other PrimaryTypeExpr types - auto val = getValue(eval(*nodes[0])); - auto func = any_cast(val); + Value val = getValue(eval(*nodes[0])); + Func func = val.getFunction(cxt); for (int i=1; i #include #include +#include #include "Scope.h" #include "util.h" @@ -13,8 +14,8 @@ public: std::shared_ptr currentScope; public: void error(std::string_view msg); - std::any eval(peg::Ast& ast); + Value eval(peg::Ast& ast); protected: - std::any readIdentifier(std::any val); - std::any getValue(std::any input); + Value readIdentifier(Value val); + Value getValue(Value input); }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index fe1f1c8..5eaabb8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,7 @@ #include #include "context.h" -#include "util.h" +#include "types.h" int main(void) { peg::parser parser( @@ -26,11 +26,11 @@ int main(void) { } else { @print("neigh"); } - a = 10; - while(a > 0) { - a -= 1; - @print(a); - } + // a = 10000000; + // while(a > 0) { + // a -= 1; + // // @print(a); + // } var hello = fn(abc) { @print(abc); }; diff --git a/src/types.cpp b/src/types.cpp new file mode 100644 index 0000000..190b25c --- /dev/null +++ b/src/types.cpp @@ -0,0 +1,221 @@ +#include "types.h" + +#include "context.h" + +// Args Args::toArgs(Context& cxt, Value input) { +// Args args; +// if (input.type() == typeid(std::vector)) { +// args.args = std::any_cast>(input); +// } else { +// cxt.error("Unimplemented toArgs"); +// } +// return args; +// } + +Value Func::execute(Context& cxt, Args& args) { + if (ast == nullptr) { + return nativeFunction(cxt, args); + } else { + // TODO create scope + Value result = Value(Nil()); + for (int i=0; iwriteVar(cxt, argNames[i].identifier, args.args[i]); + } + result = cxt.eval(*ast); + // TODO tear down scope + return result; + } +} + +Value::Value(Nil nil) : type(TypeNil) { + value.nil = Nil(); +} +Value::Value(long int_) : type(TypeInt) { + value.int_ = int_; +} +Value::Value(double float_) : type(TypeFloat) { + value.float_ = float_; +} +Value::Value(bool bool_) : type(TypeBoolean) { + value.bool_ = bool_; +} +Value::Value(const std::string &string) : type(TypeString) { + value.string = new std::string(string); +} +Value::Value(const Func &function) : type(TypeFunction) { + value.function = new Func(function); +} +Value::Value(const Args &args) : type(TypeArgs) { + value.args = new Args(args); +} +Value::Value(const Identifier &identifier) : type(TypeIdentifier) { + value.identifier = new Identifier(identifier); +} + +Value::Value(const Value &val) { + type = val.type; + if (isNil()) { + value.nil = Nil(); + } else if (isInt()) { + value.int_ = val.value.int_; + } else if (isFloat()) { + value.float_ = val.value.float_; + } else if (isBoolean()) { + value.bool_ = val.value.bool_; + } else if (isString()) { + value.string = new std::string(*val.value.string); + } else if (isFunction()) { + value.function = new Func(*val.value.function); + } else if (isArgs()) { + value.args = new Args(*val.value.args); + } else if (isIdentifier()) { + value.identifier = new Identifier(*val.value.identifier); + } +} + +Value& Value::operator=(const Value &rhs) { + type = rhs.type; + if (isNil()) { + value.nil = Nil(); + } else if (isInt()) { + value.int_ = rhs.value.int_; + } else if (isFloat()) { + value.float_ = rhs.value.float_; + } else if (isBoolean()) { + value.bool_ = rhs.value.bool_; + } else if (isString()) { + value.string = new std::string(*rhs.value.string); + } else if (isFunction()) { + value.function = new Func(*rhs.value.function); + } else if (isArgs()) { + value.args = new Args(*rhs.value.args); + } else if (isIdentifier()) { + value.identifier = new Identifier(*rhs.value.identifier); + } + return *this; +} + +Value::~Value() { + if (isString()) { + delete value.string; + } else if (isFunction()) { + delete value.function; + } else if (isArgs()) { + delete value.args; + } else if (isIdentifier()) { + delete value.identifier; + } +} + +bool Value::isNil() { + return type == TypeNil; +} +bool Value::isInt() { + return type == TypeInt; +} +bool Value::isFloat() { + return type == TypeFloat; +} +bool Value::isNumber() { + return isInt() || isFloat(); +} +bool Value::isBoolean() { + return type == TypeBoolean; +} +bool Value::isString() { + return type == TypeString; +} +bool Value::isFunction() { + return type == TypeFunction; +} +bool Value::isArgs() { + return type == TypeArgs; +} +bool Value::isIdentifier() { + return type == TypeIdentifier; +} + +void Value::assertNil(Context &cxt) { + if (!isNil()) { + cxt.error("value is not nil"); + } +} +void Value::assertInt(Context &cxt) { + if (!isInt()) { + cxt.error("value is not an integer"); + } +} +void Value::assertFloat(Context &cxt) { + if (!isFloat()) { + cxt.error("value is not a float"); + } +} +void Value::assertNumber(Context &cxt) { + if (!isNumber()) { + cxt.error("value is not a number"); + } +} +void Value::assertBoolean(Context &cxt) { + if (!isBoolean()) { + cxt.error("value is not a boolean"); + } +} +void Value::assertString(Context &cxt) { + if (!isString()) { + cxt.error("value is not a string"); + } +} +void Value::assertFunction(Context &cxt) { + if (!isFunction()) { + cxt.error("value is not a function"); + } +} +void Value::assertArgs(Context &cxt) { + if (!isArgs()) { + cxt.error("value is not arguments"); + } +} +void Value::assertIdentifier(Context &cxt) { + if (!isIdentifier()) { + cxt.error("value is not identifier"); + } +} + +Nil Value::getNil(Context &cxt) { + assertNil(cxt); + return value.nil; +} +long Value::getInt(Context &cxt) { + assertNumber(cxt); + if (isFloat()) + return (long)value.float_; + else + return value.int_; +} +double Value::getFloat(Context &cxt) { + assertNumber(cxt); + if (isInt()) + return (double)value.int_; + else + return value.float_; +} +bool Value::getBoolean(Context &cxt) { + assertBoolean(cxt); + return value.bool_; +} +std::string Value::getString(Context &cxt) { + assertString(cxt); + return *value.string; +} +Func Value::getFunction(Context &cxt) { + assertFunction(cxt); + return *value.function; +} +Args Value::getArgs(Context &cxt) { + assertArgs(cxt); + return *value.args; +} +Identifier Value::getIdentifier(Context &cxt) { + assertIdentifier(cxt); + return *value.identifier; +} \ No newline at end of file diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..fbf6510 --- /dev/null +++ b/src/types.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include +#include + +class Context; +class Identifier; +class Value; +class Scope; + +/** + * Arguments passed to a function and also results returned from a function + */ +class Args { +public: + std::vector args; + // static Args toArgs(Context& cxt, Value input); +}; + +// represents the 'nil' type +class Nil { +}; + +class Identifier { +public: + std::string identifier; + Identifier(std::string id) : identifier(id) {} +}; + +// Function - captured scope, ast ptr OR native function +class Func { +public: + std::shared_ptr capturedScope; + + std::shared_ptr ast = nullptr; + std::vector argNames; + + std::function nativeFunction; + +public: + /** + * Create a native function + */ + Func(std::function nativeFunction) + : capturedScope(nullptr), nativeFunction(nativeFunction) {} + + /** + * Create an interpreted function + */ + Func(std::shared_ptr ast, std::vector argNames) + : ast(ast), argNames(argNames) {} + + Value execute(Context& cxt, Args& args); +}; + +class Value { +protected: + enum Type { + TypeNil, + TypeInt, + TypeFloat, + TypeBoolean, + TypeString, + TypeFunction, + + // Internal types + TypeArgs, + TypeIdentifier, + }; + union TypeValues { + Nil nil; + long int_; + double float_; + bool bool_; + std::string *string; + Func *function; + Args *args; + Identifier *identifier; + }; + + Type type; + TypeValues value; + +public: + Value(Nil nil); + Value(long int_); + Value(double float_); + Value(bool bool_); + Value(const std::string &string); + Value(const Func &function); + Value(const Args &args); + Value(const Identifier &identifier); + + Value(const Value &value); + Value& operator=(const Value &rhs); + ~Value(); + + bool isNil(); + bool isInt(); + bool isFloat(); + bool isNumber(); + bool isBoolean(); + bool isString(); + bool isFunction(); + bool isArgs(); + bool isIdentifier(); + + void assertNil(Context &cxt); + void assertInt(Context &cxt); + void assertFloat(Context &cxt); + void assertNumber(Context &cxt); + void assertBoolean(Context &cxt); + void assertString(Context &cxt); + void assertFunction(Context &cxt); + void assertArgs(Context &cxt); + void assertIdentifier(Context &cxt); + + Nil getNil(Context &cxt); + long getInt(Context &cxt); + double getFloat(Context &cxt); + bool getBoolean(Context &cxt); + std::string getString(Context &cxt); + Func getFunction(Context &cxt); + Args getArgs(Context &cxt); + Identifier getIdentifier(Context &cxt); +}; \ No newline at end of file diff --git a/src/util.cpp b/src/util.cpp index e26b036..b81e6dc 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,48 +1,24 @@ #include "util.h" #include "context.h" +#include "types.h" #include +#include -Args Args::toArgs(Context& cxt, std::any input) { - Args args; - if (input.type() == typeid(std::vector)) { - args.args = std::any_cast>(input); - } else { - cxt.error("Unimplemented toArgs"); - } - return args; -} - -std::any Func::execute(Context& cxt, Args& args) { - if (ast == nullptr) { - return nativeFunction(cxt, args); - } else { - // TODO create scope - std::any result; - for (int i=0; iwriteVar(cxt, argNames[i].identifier, args.args[i]); - } - result = cxt.eval(*ast); - // TODO tear down scope - return result; - } -} - -std::any BuiltinFunctions::print(Context& cxt, Args& args) { +Value BuiltinFunctions::print(Context& cxt, Args& args) { for (int i=0; i(var) << '\t'; - } else if (var.type() == typeid(std::string)) { - std::cout << std::any_cast(var) << '\t'; - } else if (var.type() == typeid(bool)) { - bool v = std::any_cast(var); - if (v) + Value var = args.args[i]; + if (var.isInt()) { + std::cout << var.getInt(cxt) << '\t'; + } else if (var.isString()) { + std::cout << var.getString(cxt) << '\t'; + } else if (var.isBoolean()) { + if (var.getBoolean(cxt)) std::cout << "true" << '\t'; else std::cout << "false" << '\t'; - } else if (var.type() == typeid(Nil)) { + } else if (var.isNil()) { std::cout << "nil" << '\t'; } else { cxt.error("Attempt to print unsupported type"); diff --git a/src/util.h b/src/util.h index 2caf4e4..3db1354 100644 --- a/src/util.h +++ b/src/util.h @@ -1,63 +1,10 @@ #pragma once -#include - -#include -#include -#include -#include -#include -#include - class Context; -class Scope; - -// represents the 'nil' type -class Nil { -}; - -class Identifier { -public: - std::string identifier; - Identifier(std::string id) : identifier(id) {} -}; - -/** - * Arguments passed to a function and also results returned from a function - */ -class Args { -public: - std::vector args; - static Args toArgs(Context& cxt, std::any input); -}; - -// Function - captured scope, ast ptr OR native function -class Func { -public: - std::shared_ptr capturedScope; - - std::shared_ptr ast = nullptr; - std::vector argNames; - - std::function nativeFunction; - -public: - /** - * Create a native function - */ - Func(std::function nativeFunction) - : capturedScope(nullptr), nativeFunction(nativeFunction) {} - - /** - * Create an interpreted function - */ - Func(std::shared_ptr ast, std::vector argNames) - : ast(ast), argNames(argNames) {} - - std::any execute(Context& cxt, Args& args); -}; +class Value; +class Args; class BuiltinFunctions { public: - static std::any print(Context& cxt, Args& args); + static Value print(Context& cxt, Args& args); }; \ No newline at end of file