remove std::any
This commit is contained in:
parent
f2b4a53176
commit
186cab9ac9
@ -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);
|
||||
|
@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <any>
|
||||
|
||||
class Context;
|
||||
|
||||
@ -11,7 +12,7 @@ class Context;
|
||||
class Scope {
|
||||
public:
|
||||
std::shared_ptr<Scope> parentScope;
|
||||
std::unordered_map<std::string, std::any> vars;
|
||||
std::unordered_map<std::string, Value> vars;
|
||||
// std::function<bool(Context&,Args&)> returnHandler;
|
||||
// std::function<bool(Context&)> breakHandler;
|
||||
// std::function<bool(Context&)> 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);
|
||||
};
|
111
src/context.cpp
111
src/context.cpp
@ -1,39 +1,38 @@
|
||||
#include "context.h"
|
||||
|
||||
#include <cpp-peglib/peglib.h>
|
||||
#include <iostream>
|
||||
|
||||
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<Identifier>(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<ast.nodes.size(); i++) {
|
||||
eval(*nodes[i]);
|
||||
}
|
||||
return Nil();
|
||||
} else if (ast.name == "VarDecl") {
|
||||
auto identifier = any_cast<Identifier>(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<long>();
|
||||
} else if (ast.name == "BUILTINCALL" ) {
|
||||
auto identifier = any_cast<Identifier>(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<std::any> exprs;
|
||||
Args exprs;
|
||||
for (int i=0; i<ast.nodes.size(); i++) {
|
||||
exprs.push_back(getValue(eval(*nodes[i])));
|
||||
exprs.args.push_back(getValue(eval(*nodes[i])));
|
||||
}
|
||||
return exprs;
|
||||
return Value(exprs);
|
||||
} else if (ast.name == "AdditionExpr") {
|
||||
auto value = getValue(eval(*nodes[0]));
|
||||
Value value = getValue(eval(*nodes[0]));
|
||||
for (int i=1; i<nodes.size(); i+=2) {
|
||||
int op = (*nodes[i]).choice;
|
||||
auto v2 = getValue(eval(*nodes[i+1]));
|
||||
Value v2 = getValue(eval(*nodes[i+1]));
|
||||
// TODO: floats
|
||||
if (op == 0) {
|
||||
value = any_cast<long>(value) + any_cast<long>(v2);
|
||||
value = Value(value.getInt(cxt) + v2.getInt(cxt));
|
||||
} else {
|
||||
value = any_cast<long>(value) - any_cast<long>(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<nodes.size(); i+=2) {
|
||||
int op = (*nodes[i]).choice;
|
||||
auto v2 = getValue(eval(*nodes[i+1]));
|
||||
Value v2 = getValue(eval(*nodes[i+1]));
|
||||
// TODO: floats
|
||||
if (op == 0) {
|
||||
value = any_cast<long>(value) * any_cast<long>(v2);
|
||||
value = Value(value.getInt(cxt) * v2.getInt(cxt));
|
||||
} else {
|
||||
value = any_cast<long>(value) / any_cast<long>(v2);
|
||||
value = Value(value.getInt(cxt) / v2.getInt(cxt));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
} else if (ast.name == "AssignExpr") {
|
||||
std::string name = any_cast<Identifier>(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<long>(v1) * any_cast<long>(v2);
|
||||
result = Value(v1.getInt(cxt) * v2.getInt(cxt));
|
||||
} else if (op == 1) {
|
||||
result = any_cast<long>(v1) % any_cast<long>(v2);
|
||||
result = Value(v1.getInt(cxt) % v2.getInt(cxt));
|
||||
} else if (op == 2) {
|
||||
result = any_cast<long>(v1) + any_cast<long>(v2);
|
||||
result = Value(v1.getInt(cxt) + v2.getInt(cxt));
|
||||
} else if (op == 3) {
|
||||
result = any_cast<long>(v1) - any_cast<long>(v2);
|
||||
result = Value(v1.getInt(cxt) - v2.getInt(cxt));
|
||||
} else if (op == 4) {
|
||||
result = any_cast<long>(v1) & any_cast<long>(v2);
|
||||
result = Value(v1.getInt(cxt) & v2.getInt(cxt));
|
||||
} else if (op == 5) {
|
||||
result = any_cast<long>(v1) ^ any_cast<long>(v2);
|
||||
result = Value(v1.getInt(cxt) ^ v2.getInt(cxt));
|
||||
} else if (op == 6) {
|
||||
result = any_cast<long>(v1) | any_cast<long>(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<long>(v1) == any_cast<long>(v2));
|
||||
return (bool)(v1.getInt(cxt) == v2.getInt(cxt));
|
||||
} else if (op == 1) {
|
||||
return (bool)(any_cast<long>(v1) != any_cast<long>(v2));
|
||||
return (bool)(v1.getInt(cxt) != v2.getInt(cxt));
|
||||
} else if (op == 2) {
|
||||
return (bool)(any_cast<long>(v1) < any_cast<long>(v2));
|
||||
return (bool)(v1.getInt(cxt) < v2.getInt(cxt));
|
||||
} else if (op == 3) {
|
||||
return (bool)(any_cast<long>(v1) > any_cast<long>(v2));
|
||||
return (bool)(v1.getInt(cxt) > v2.getInt(cxt));
|
||||
} else if (op == 4) {
|
||||
return (bool)(any_cast<long>(v1) <= any_cast<long>(v2));
|
||||
return (bool)(v1.getInt(cxt) <= v2.getInt(cxt));
|
||||
} else if (op == 5) {
|
||||
return (bool)(any_cast<long>(v1) >= any_cast<long>(v2));
|
||||
return (bool)(v1.getInt(cxt) >= v2.getInt(cxt));
|
||||
}
|
||||
} else if (ast.name == "IfStatement") {
|
||||
auto val = getValue(eval(*nodes[0]));
|
||||
if (any_cast<bool>(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<ast.nodes.size(); i++) {
|
||||
result = eval(*nodes[i]);
|
||||
}
|
||||
return result;
|
||||
} else if (ast.name == "WhileStatement") {
|
||||
std::any result = Nil();
|
||||
while (any_cast<bool>(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<std::vector<Identifier>>(eval(*nodes[0]));
|
||||
Args args = eval(*nodes[0]).getArgs(cxt);
|
||||
std::vector<Identifier> identifiers;
|
||||
for (int i=0; i<args.args.size(); i++) {
|
||||
identifiers.push_back(args.args[i].getIdentifier(cxt));
|
||||
}
|
||||
return Func(nodes[1], identifiers);
|
||||
} else if (ast.name == "ParamDeclList") {
|
||||
std::vector<Identifier> identifiers;
|
||||
Args identifiers;
|
||||
for (int i=0; i<nodes.size(); i++) {
|
||||
identifiers.push_back(any_cast<Identifier>(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<Func>(val);
|
||||
Value val = getValue(eval(*nodes[0]));
|
||||
Func func = val.getFunction(cxt);
|
||||
for (int i=1; i<nodes.size(); i++) {
|
||||
auto args = Args::toArgs(*this, eval(*nodes[i]));
|
||||
Args args = eval(*nodes[i]).getArgs(cxt);
|
||||
return func.execute(*this, args);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <cpp-peglib/peglib.h>
|
||||
|
||||
#include "Scope.h"
|
||||
#include "util.h"
|
||||
@ -13,8 +14,8 @@ public:
|
||||
std::shared_ptr<Scope> 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);
|
||||
};
|
12
src/main.cpp
12
src/main.cpp
@ -5,7 +5,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#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);
|
||||
};
|
||||
|
221
src/types.cpp
Normal file
221
src/types.cpp
Normal file
@ -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<std::any>)) {
|
||||
// args.args = std::any_cast<std::vector<std::any>>(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; i<args.args.size(); i++) {
|
||||
cxt.currentScope->writeVar(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;
|
||||
}
|
127
src/types.h
Normal file
127
src/types.h
Normal file
@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cpp-peglib/peglib.h>
|
||||
|
||||
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<Value> 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<Scope> capturedScope;
|
||||
|
||||
std::shared_ptr<peg::Ast> ast = nullptr;
|
||||
std::vector<Identifier> argNames;
|
||||
|
||||
std::function<Value(Context&,Args&)> nativeFunction;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a native function
|
||||
*/
|
||||
Func(std::function<Value(Context&,Args&)> nativeFunction)
|
||||
: capturedScope(nullptr), nativeFunction(nativeFunction) {}
|
||||
|
||||
/**
|
||||
* Create an interpreted function
|
||||
*/
|
||||
Func(std::shared_ptr<peg::Ast> ast, std::vector<Identifier> 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);
|
||||
};
|
46
src/util.cpp
46
src/util.cpp
@ -1,48 +1,24 @@
|
||||
#include "util.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
Args Args::toArgs(Context& cxt, std::any input) {
|
||||
Args args;
|
||||
if (input.type() == typeid(std::vector<std::any>)) {
|
||||
args.args = std::any_cast<std::vector<std::any>>(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; i<args.args.size(); i++) {
|
||||
cxt.currentScope->writeVar(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<args.args.size(); i++) {
|
||||
std::any var = args.args[i];
|
||||
if (var.type() == typeid(long)) {
|
||||
std::cout << std::any_cast<long>(var) << '\t';
|
||||
} else if (var.type() == typeid(std::string)) {
|
||||
std::cout << std::any_cast<std::string>(var) << '\t';
|
||||
} else if (var.type() == typeid(bool)) {
|
||||
bool v = std::any_cast<bool>(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");
|
||||
|
59
src/util.h
59
src/util.h
@ -1,63 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <cpp-peglib/peglib.h>
|
||||
|
||||
#include <string>
|
||||
#include <any>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
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<std::any> args;
|
||||
static Args toArgs(Context& cxt, std::any input);
|
||||
};
|
||||
|
||||
// Function - captured scope, ast ptr OR native function
|
||||
class Func {
|
||||
public:
|
||||
std::shared_ptr<Scope> capturedScope;
|
||||
|
||||
std::shared_ptr<peg::Ast> ast = nullptr;
|
||||
std::vector<Identifier> argNames;
|
||||
|
||||
std::function<std::any(Context&,Args&)> nativeFunction;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a native function
|
||||
*/
|
||||
Func(std::function<std::any(Context&,Args&)> nativeFunction)
|
||||
: capturedScope(nullptr), nativeFunction(nativeFunction) {}
|
||||
|
||||
/**
|
||||
* Create an interpreted function
|
||||
*/
|
||||
Func(std::shared_ptr<peg::Ast> ast, std::vector<Identifier> 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);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user