Function arguments

This commit is contained in:
2025-10-02 12:41:11 +10:00
parent 2a977707ee
commit 08d3c1545b
10 changed files with 148 additions and 38 deletions

View File

@@ -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 {
error("Could not find variable " + key + "to modify (try defining first with let?)");
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();
}
}
}

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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("");
}

View File

@@ -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)");

View File

@@ -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;

View File

@@ -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;
}
}
}

View File

@@ -1,5 +1,5 @@
fun dingus {
println "hello"
fun dingus in {
println $in
}
dingus
dingus "hi there"