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" #include "../error/error.h"
namespace data { namespace data {
std::map<std::string, Value> vars; std::vector<std::map<std::string, Value>> scopes;
std::map<std::string, std::vector<Instruction>> functions; std::map<std::string, Function> functions;
void modifyValue(std::string key, Value value) {
if (vars.find(key) != vars.end()) { void initScopes() {
vars[key] = value; scopes.clear();
} else { scopes.push_back({}); // Global scope
error("Could not find variable " + key + "to modify (try defining first with let?)"); }
void pushScope() {
scopes.push_back({});
}
void popScope() {
if (!scopes.empty()) {
scopes.pop_back();
} }
} }
Value getValue(std::string key) {
if (vars.find(key) != vars.end()) { void modifyValue(std::string key, Value value) {
return vars[key]; for (auto it = scopes.rbegin(); it != scopes.rend(); ++it) {
} else { if (it->count(key)) {
error("Could not find variable " + key + " to access (try defining first with let?)"); (*it)[key] = value;
return Value(); return;
}
} }
error("Could not find variable " + key + " to modify (try defining first with let?)");
}
Value getValue(std::string key) {
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" #include "../defs/defs.h"
namespace data { namespace data {
extern std::map<std::string, Value> vars; extern std::vector<std::map<std::string, Value>> scopes;
extern std::map<std::string, std::vector<Instruction>> functions; extern std::map<std::string, Function> functions;
void modifyValue(std::string key, Value value); void modifyValue(std::string key, Value value);
Value getValue(std::string key); Value getValue(std::string key);
void pushScope();
void popScope();
void initScopes();
} }

View File

@@ -17,6 +17,11 @@ struct Instruction;
typedef std::vector<Instruction> InstructionGroup; typedef std::vector<Instruction> InstructionGroup;
struct Function {
std::vector<std::string> arg_names;
InstructionGroup body;
};
struct Varname { struct Varname {
std::string key; std::string key;
Varname(std::string in); Varname(std::string in);

View File

@@ -72,10 +72,27 @@ Value execute(Instruction inst) {
if (!inst.args.empty()) { if (!inst.args.empty()) {
const std::string& name = inst.args[0].real; const std::string& name = inst.args[0].real;
if (data::functions.count(name)) { 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; Value return_val;
for (const auto& body_inst : data::functions.at(name)) { for (const auto& body_inst : func.body) {
return_val = execute(body_inst); return_val = execute(body_inst);
} }
data::popScope();
return return_val; return return_val;
} }
} }

View File

@@ -2,8 +2,10 @@
#include "repl/repl.h" #include "repl/repl.h"
#include <iostream> #include <iostream>
#include <string.h> #include <string.h>
#include "data/data.h"
int main(int argc, char** argv) { int main(int argc, char** argv) {
data::initScopes();
if (argc < 2) { if (argc < 2) {
repl(); repl();
} else { } else {

View File

@@ -5,21 +5,42 @@
#include <vector> #include <vector>
Value modules::fndef(std::vector<Value> args) { 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"); error("Syntax error: function statement requires a name and a body");
return Value(); return Value();
} }
if (args[0].valtype != ValueType::Processed) {
error("Syntax error: function name must be a processed value"); // Last arg is the body
return Value(); Value body_val = args.back();
} if (body_val.valtype != ValueType::InstructionGroup) {
if (args[1].valtype != ValueType::InstructionGroup) {
error("Syntax error: function body must be an instruction group"); error("Syntax error: function body must be an instruction group");
return Value(); return Value();
} }
std::string func_name = args[0].processed->args[0].real; // First arg is the name
data::functions[func_name] = args[1].instructionGroup; 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(""); return Value("");
} }

View File

@@ -16,7 +16,7 @@ Value modules::let(std::vector<Value> values) {
if (values.size() > 1) { if (values.size() > 1) {
if (values[1].valtype == ValueType::Real && values[1].real == "=") { if (values[1].valtype == ValueType::Real && values[1].real == "=") {
if (values.size() > 2) { if (values.size() > 2) {
data::vars[varName] = values[2]; data::scopes.back()[varName] = values[2];
} else { } else {
error("Expecting value after token '=' (in let module)"); 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)"); error("Expecting token '=' (in let module)");
} }
} else { } else {
data::vars[varName] = Value(""); data::scopes.back()[varName] = Value("");
} }
} else { } else {
error("Expecting variable name (in let module)"); error("Expecting variable name (in let module)");

View File

@@ -147,9 +147,18 @@ std::vector<Instruction> parse(std::string program) {
continue; continue;
} }
// 1. Function name // 1. Function signature (name + args)
std::string name = line.substr(3, block_start - 3); std::string signature_str = line.substr(3, block_start - 3);
function_inst.args.push_back(Value(Instruction(split(trim(name))))); 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 // 2. Find 'then' block
size_t block_end = 0; size_t block_end = 0;

View File

@@ -4,18 +4,51 @@
#include "../defs/defs.h" #include "../defs/defs.h"
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "../data/data.h"
void repl() { void repl() {
data::initScopes();
inReplMode = true; inReplMode = true;
std::cout << "Kyn REPL v0.0.1" << std::endl; std::cout << "Kyn REPL v0.0.1" << std::endl;
std::cout << "Type 'exit' to exit" << 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) { while (true) {
std::cout << "kyn> "; if (brace_level == 0) {
getline(std::cin, buf); std::cout << "kyn> ";
std::vector<Instruction> parsed = parse(buf); } else {
for (Instruction inst : parsed) { std::cout << ".. > ";
execute(inst); }
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 { fun dingus in {
println "hello" println $in
} }
dingus dingus "hi there"