Function arguments
This commit is contained in:
@@ -7,21 +7,41 @@
|
||||
#include "../error/error.h"
|
||||
|
||||
namespace data {
|
||||
std::map<std::string, Value> vars;
|
||||
std::map<std::string, std::vector<Instruction>> functions;
|
||||
std::vector<std::map<std::string, Value>> scopes;
|
||||
std::map<std::string, Function> functions;
|
||||
|
||||
void initScopes() {
|
||||
scopes.clear();
|
||||
scopes.push_back({}); // Global scope
|
||||
}
|
||||
|
||||
void pushScope() {
|
||||
scopes.push_back({});
|
||||
}
|
||||
|
||||
void popScope() {
|
||||
if (!scopes.empty()) {
|
||||
scopes.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void modifyValue(std::string key, Value value) {
|
||||
if (vars.find(key) != vars.end()) {
|
||||
vars[key] = value;
|
||||
} else {
|
||||
for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) {
|
||||
if (it->count(key)) {
|
||||
(*it)[key] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("Could not find variable " + key + " to modify (try defining first with let?)");
|
||||
}
|
||||
}
|
||||
|
||||
Value getValue(std::string key) {
|
||||
if (vars.find(key) != vars.end()) {
|
||||
return vars[key];
|
||||
} else {
|
||||
for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) {
|
||||
if (it->count(key)) {
|
||||
return (*it)[key];
|
||||
}
|
||||
}
|
||||
error("Could not find variable " + key + " to access (try defining first with let?)");
|
||||
return Value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
#include "../defs/defs.h"
|
||||
|
||||
namespace data {
|
||||
extern std::map<std::string, Value> vars;
|
||||
extern std::map<std::string, std::vector<Instruction>> functions;
|
||||
extern std::vector<std::map<std::string, Value>> scopes;
|
||||
extern std::map<std::string, Function> functions;
|
||||
void modifyValue(std::string key, Value value);
|
||||
Value getValue(std::string key);
|
||||
void pushScope();
|
||||
void popScope();
|
||||
void initScopes();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ struct Instruction;
|
||||
|
||||
typedef std::vector<Instruction> InstructionGroup;
|
||||
|
||||
struct Function {
|
||||
std::vector<std::string> arg_names;
|
||||
InstructionGroup body;
|
||||
};
|
||||
|
||||
struct Varname {
|
||||
std::string key;
|
||||
Varname(std::string in);
|
||||
|
||||
@@ -72,10 +72,27 @@ Value execute(Instruction inst) {
|
||||
if (!inst.args.empty()) {
|
||||
const std::string& name = inst.args[0].real;
|
||||
if (data::functions.count(name)) {
|
||||
const auto& func = data::functions.at(name);
|
||||
|
||||
if (func.arg_names.size() != inst.args.size() - 1) {
|
||||
error("Function " + name + " expects " + std::to_string(func.arg_names.size()) + " arguments, but got " + std::to_string(inst.args.size() - 1));
|
||||
return Value();
|
||||
}
|
||||
|
||||
data::pushScope();
|
||||
|
||||
for (size_t i = 0; i < func.arg_names.size(); ++i) {
|
||||
Value arg_val = inst.args[i+1];
|
||||
data::scopes.back()[func.arg_names[i]] = arg_val;
|
||||
}
|
||||
|
||||
Value return_val;
|
||||
for (const auto& body_inst : data::functions.at(name)) {
|
||||
for (const auto& body_inst : func.body) {
|
||||
return_val = execute(body_inst);
|
||||
}
|
||||
|
||||
data::popScope();
|
||||
|
||||
return return_val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#include "repl/repl.h"
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include "data/data.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
data::initScopes();
|
||||
if (argc < 2) {
|
||||
repl();
|
||||
} else {
|
||||
|
||||
@@ -5,21 +5,42 @@
|
||||
#include <vector>
|
||||
|
||||
Value modules::fndef(std::vector<Value> args) {
|
||||
if (args.size() < 2) {
|
||||
if (args.size() < 2) { // At least a name and a body
|
||||
error("Syntax error: function statement requires a name and a body");
|
||||
return Value();
|
||||
}
|
||||
if (args[0].valtype != ValueType::Processed) {
|
||||
error("Syntax error: function name must be a processed value");
|
||||
return Value();
|
||||
}
|
||||
if (args[1].valtype != ValueType::InstructionGroup) {
|
||||
|
||||
// Last arg is the body
|
||||
Value body_val = args.back();
|
||||
if (body_val.valtype != ValueType::InstructionGroup) {
|
||||
error("Syntax error: function body must be an instruction group");
|
||||
return Value();
|
||||
}
|
||||
|
||||
std::string func_name = args[0].processed->args[0].real;
|
||||
data::functions[func_name] = args[1].instructionGroup;
|
||||
// First arg is the name
|
||||
Value name_val = args[0];
|
||||
if (name_val.valtype != ValueType::Real) {
|
||||
error("Syntax error: function name must be a real value");
|
||||
return Value();
|
||||
}
|
||||
std::string func_name = name_val.real;
|
||||
|
||||
// In-between args are the argument names
|
||||
std::vector<std::string> arg_names;
|
||||
for (size_t i = 1; i < args.size() - 1; ++i) {
|
||||
if (args[i].valtype != ValueType::Real) {
|
||||
error("Syntax error: function argument names must be real values");
|
||||
return Value();
|
||||
}
|
||||
arg_names.push_back(args[i].real);
|
||||
}
|
||||
|
||||
// Create and store the function
|
||||
Function new_func;
|
||||
new_func.arg_names = arg_names;
|
||||
new_func.body = body_val.instructionGroup;
|
||||
|
||||
data::functions[func_name] = new_func;
|
||||
|
||||
return Value("");
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ Value modules::let(std::vector<Value> values) {
|
||||
if (values.size() > 1) {
|
||||
if (values[1].valtype == ValueType::Real && values[1].real == "=") {
|
||||
if (values.size() > 2) {
|
||||
data::vars[varName] = values[2];
|
||||
data::scopes.back()[varName] = values[2];
|
||||
} else {
|
||||
error("Expecting value after token '=' (in let module)");
|
||||
}
|
||||
@@ -24,7 +24,7 @@ Value modules::let(std::vector<Value> values) {
|
||||
error("Expecting token '=' (in let module)");
|
||||
}
|
||||
} else {
|
||||
data::vars[varName] = Value("");
|
||||
data::scopes.back()[varName] = Value("");
|
||||
}
|
||||
} else {
|
||||
error("Expecting variable name (in let module)");
|
||||
|
||||
@@ -147,9 +147,18 @@ std::vector<Instruction> parse(std::string program) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1. Function name
|
||||
std::string name = line.substr(3, block_start - 3);
|
||||
function_inst.args.push_back(Value(Instruction(split(trim(name)))));
|
||||
// 1. Function signature (name + args)
|
||||
std::string signature_str = line.substr(3, block_start - 3);
|
||||
std::vector<Value> signature_parts = split(trim(signature_str));
|
||||
|
||||
if (signature_parts.empty()) {
|
||||
error("Function definition is missing a name.");
|
||||
continue;
|
||||
}
|
||||
|
||||
for(const auto& part : signature_parts) {
|
||||
function_inst.args.push_back(part);
|
||||
}
|
||||
|
||||
// 2. Find 'then' block
|
||||
size_t block_end = 0;
|
||||
|
||||
@@ -4,18 +4,51 @@
|
||||
#include "../defs/defs.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "../data/data.h"
|
||||
|
||||
void repl() {
|
||||
data::initScopes();
|
||||
inReplMode = true;
|
||||
std::cout << "Kyn REPL v0.0.1" << std::endl;
|
||||
std::cout << "Type 'exit' to exit" << std::endl;
|
||||
std::string buf;
|
||||
|
||||
std::string full_command;
|
||||
std::string line_buf;
|
||||
int brace_level = 0;
|
||||
|
||||
while (true) {
|
||||
if (brace_level == 0) {
|
||||
std::cout << "kyn> ";
|
||||
getline(std::cin, buf);
|
||||
std::vector<Instruction> parsed = parse(buf);
|
||||
} else {
|
||||
std::cout << ".. > ";
|
||||
}
|
||||
|
||||
if (!getline(std::cin, line_buf)) {
|
||||
break; // Handle EOF (Ctrl+D)
|
||||
}
|
||||
|
||||
for (char c : line_buf) {
|
||||
if (c == '{') {
|
||||
brace_level++;
|
||||
} else if (c == '}') {
|
||||
brace_level--;
|
||||
}
|
||||
}
|
||||
|
||||
if (!full_command.empty()) {
|
||||
full_command += "\n";
|
||||
}
|
||||
full_command += line_buf;
|
||||
|
||||
if (brace_level <= 0 && !full_command.empty()) {
|
||||
if (full_command.find_first_not_of(" \t\n\r") != std::string::npos) {
|
||||
std::vector<Instruction> parsed = parse(full_command);
|
||||
for (Instruction inst : parsed) {
|
||||
execute(inst);
|
||||
}
|
||||
}
|
||||
full_command.clear();
|
||||
brace_level = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fun dingus {
|
||||
println "hello"
|
||||
fun dingus in {
|
||||
println $in
|
||||
}
|
||||
|
||||
dingus
|
||||
dingus "hi there"
|
||||
|
||||
Reference in New Issue
Block a user