From 2a977707ee6446b2437c20cb298031c388389902 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 1 Oct 2025 13:43:08 +1000 Subject: [PATCH] Fixes and functions --- src/defs/defs.h | 2 +- src/executor/executor.cpp | 17 ++++++++++++++- src/main.cpp | 5 ++--- src/modules/function/function.cpp | 25 ++++++++++++++++++++++ src/modules/function/function.h | 8 +++++++ src/parser/parser.cpp | 35 ++++++++++++++++++++++++++++++- tests/func.kyn | 5 +++++ tests/loop.kyn | 6 ++++++ 8 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/modules/function/function.cpp create mode 100644 src/modules/function/function.h create mode 100644 tests/func.kyn create mode 100644 tests/loop.kyn diff --git a/src/defs/defs.h b/src/defs/defs.h index 7d416d7..fa9cf29 100644 --- a/src/defs/defs.h +++ b/src/defs/defs.h @@ -6,7 +6,7 @@ enum class InstructionType { - None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare + None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare, Function }; enum class ValueType { diff --git a/src/executor/executor.cpp b/src/executor/executor.cpp index 32e28e0..984c0cb 100644 --- a/src/executor/executor.cpp +++ b/src/executor/executor.cpp @@ -12,6 +12,7 @@ #include "../modules/while/while.h" #include "../modules/compare/compare.h" #include "../modules/input/input.h" +#include "../modules/function/function.h" Value execute(Instruction inst) { // Special cases that need to manage their own argument evaluation @@ -24,6 +25,9 @@ Value execute(Instruction inst) { if (inst.instruction == InstructionType::While) { return modules::whiles(inst.args); } + if (inst.instruction == InstructionType::Function) { + return modules::fndef(inst.args); + } // For all other instructions, evaluate the arguments first size_t i = 0; @@ -64,7 +68,17 @@ Value execute(Instruction inst) { case InstructionType::Exit: return modules::exit(inst.args); break; - case InstructionType::Variable: + case InstructionType::Variable: { + if (!inst.args.empty()) { + const std::string& name = inst.args[0].real; + if (data::functions.count(name)) { + Value return_val; + for (const auto& body_inst : data::functions.at(name)) { + return_val = execute(body_inst); + } + return return_val; + } + } if (inst.args.size() > 2 && inst.args[1].valtype == ValueType::Real && inst.args[1].real == "=") { return varmod(inst.args); } else { @@ -72,6 +86,7 @@ Value execute(Instruction inst) { return Value(""); } break; + } default: // Note: 'If' and 'Let' are already handled. error("Unknown instruction"); diff --git a/src/main.cpp b/src/main.cpp index 530a9e7..036399b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,8 +7,8 @@ int main(int argc, char** argv) { if (argc < 2) { repl(); } else { - for (int i = 0; i < argc; i++) { - if (strcmp(argv[i], "-h") || strcmp(argv[i], "--help")) { + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { std::cout << "Kyn programming language" << std::endl; std::cout << "Usage: " << argv[0] << " (filename).kyn" << std::endl; std::cout << "Kyn is licensed to you under the Mozilla Public License v2.0" << std::endl; @@ -16,7 +16,6 @@ int main(int argc, char** argv) { exit(0); } } - execFile(argv[1]); } } diff --git a/src/modules/function/function.cpp b/src/modules/function/function.cpp new file mode 100644 index 0000000..cfa27ba --- /dev/null +++ b/src/modules/function/function.cpp @@ -0,0 +1,25 @@ +#include "function.h" +#include "../../defs/defs.h" +#include "../../data/data.h" +#include "../../error/error.h" +#include + +Value modules::fndef(std::vector args) { + if (args.size() < 2) { + 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) { + 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; + + return Value(""); +} diff --git a/src/modules/function/function.h b/src/modules/function/function.h new file mode 100644 index 0000000..539b8c9 --- /dev/null +++ b/src/modules/function/function.h @@ -0,0 +1,8 @@ +#pragma once + +#include "../../defs/defs.h" +#include + +namespace modules { + Value fndef(std::vector args); +} diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index 5517ae6..3ac4d99 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -137,9 +137,42 @@ std::vector parse(std::string program) { std::string then_content = line.substr(block_start + 1, block_end - block_start - 1); while_inst.args.push_back(Value(parse(then_content))); // Recursive call instructions.push_back(while_inst); + } else if (line.rfind("fun", 0) == 0) { + Instruction function_inst; + function_inst.instruction = InstructionType::Function; + + size_t block_start = line.find('{'); + if (block_start == std::string::npos) { + error("Expected '{' for function statement"); + continue; + } + + // 1. Function name + std::string name = line.substr(3, block_start - 3); + function_inst.args.push_back(Value(Instruction(split(trim(name))))); + + // 2. Find 'then' block + size_t block_end = 0; + int brace_level = 0; + for (size_t i = block_start; i < line.length(); ++i) { + if (line[i] == '{') brace_level++; + else if (line[i] == '}') brace_level--; + if (brace_level == 0) { + block_end = i; + break; + } + } + if (block_end == 0) { + error("Mismatched braces in function statement"); + continue; + } + + std::string then_content = line.substr(block_start + 1, block_end - block_start - 1); + function_inst.args.push_back(Value(parse(then_content))); // Recursive call + instructions.push_back(function_inst); } else { instructions.push_back(Instruction(split(line))); } } return instructions; -} \ No newline at end of file +} diff --git a/tests/func.kyn b/tests/func.kyn new file mode 100644 index 0000000..b72cc67 --- /dev/null +++ b/tests/func.kyn @@ -0,0 +1,5 @@ +fun dingus { + println "hello" +} + +dingus diff --git a/tests/loop.kyn b/tests/loop.kyn new file mode 100644 index 0000000..8ee52b9 --- /dev/null +++ b/tests/loop.kyn @@ -0,0 +1,6 @@ +let counter = 0 + +while compare $counter <= 1000 { + println $counter + counter = (math 1 + $counter) +}