Function arguments
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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("");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)");
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fun dingus {
|
fun dingus in {
|
||||||
println "hello"
|
println $in
|
||||||
}
|
}
|
||||||
|
|
||||||
dingus
|
dingus "hi there"
|
||||||
|
|||||||
Reference in New Issue
Block a user