From c856e7d654a1602cfb56ef6f23efe46e1d6475ae Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Tue, 19 Aug 2025 02:36:09 +0100 Subject: [PATCH] add multiplication and division --- src/runtime/access/access.c | 16 +++---- src/runtime/objects/number/number.c | 57 +++++++++++++++++++++++ src/runtime/runtime.c | 68 ++++++++++++++++++++++++++-- src/shell.c | 50 +++++++++----------- src/translator/access/access.c | 15 +++--- src/translator/bytecode_spec.md | 10 +++- src/translator/operation/operation.c | 6 +++ src/translator/translator.h | 4 +- 8 files changed, 178 insertions(+), 48 deletions(-) diff --git a/src/runtime/access/access.c b/src/runtime/access/access.c index df41b32..caeacf0 100644 --- a/src/runtime/access/access.c +++ b/src/runtime/access/access.c @@ -15,19 +15,19 @@ ArgonObject *ARGON_TYPE_TYPE___get_attr__(size_t argc, ArgonObject **argv, return ARGON_NULL; } ArgonObject *to_access = argv[0]; - ArgonObject *access = argv[1]; - bool check_field = argv[2] == ARGON_TRUE; + bool check_field = argv[1] == ARGON_TRUE; if (check_field) { + ArgonObject *access = argv[2]; ArgonObject *value = get_field_l(to_access, access->value.as_str.data, access->value.as_str.length, true, false); if (value) return value; + ArgonObject *name = get_field_for_class( + get_field(to_access, "__class__", false, false), "__name__", to_access); + *err = create_err( + 0, 0, 0, "", "Runtime Error", "'%.*s' object has no attribute '%.*s'", + (int)name->value.as_str.length, name->value.as_str.data, + (int)access->value.as_str.length, access->value.as_str.data); } - ArgonObject *name = get_field_for_class( - get_field(to_access, "__class__", false, false), "__name__", to_access); - *err = create_err(0, 0, 0, "", "Runtime Error", - "'%.*s' object has no attribute '%.*s'", - (int)name->value.as_str.length, name->value.as_str.data, - (int)access->value.as_str.length, access->value.as_str.data); return ARGON_NULL; } \ No newline at end of file diff --git a/src/runtime/objects/number/number.c b/src/runtime/objects/number/number.c index 6fbd1ac..56e5dd9 100644 --- a/src/runtime/objects/number/number.c +++ b/src/runtime/objects/number/number.c @@ -7,6 +7,7 @@ #include "number.h" #include "../functions/functions.h" #include "../string/string.h" +#include #include #include #include @@ -126,6 +127,56 @@ ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv, return result; } +ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv, + ArErr *err, RuntimeState *state) { + (void)state; + if (argc != 2) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__multiply__ expects 2 arguments, got %" PRIu64, argc); + return ARGON_NULL; + } + mpq_t r; + mpq_init(r); + if (argv[1]->type != TYPE_NUMBER) { + ArgonObject *type_name = get_field_for_class( + get_field(argv[1], "__class__", false, false), "__name__", argv[1]); + *err = create_err(0, 0, 0, "", "Runtime Error", + "__multiply__ cannot perform multiplication between number and %.*s", + type_name->value.as_str.length, + type_name->value.as_str.data); + return ARGON_NULL; + } + mpq_mul(r, *argv[0]->value.as_number, *argv[1]->value.as_number); + ArgonObject *result = new_number_object(r); + mpq_clear(r); + return result; +} + +ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, + ArErr *err, RuntimeState *state) { + (void)state; + if (argc != 2) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__division__ expects 2 arguments, got %" PRIu64, argc); + return ARGON_NULL; + } + mpq_t r; + mpq_init(r); + if (argv[1]->type != TYPE_NUMBER) { + ArgonObject *type_name = get_field_for_class( + get_field(argv[1], "__class__", false, false), "__name__", argv[1]); + *err = create_err(0, 0, 0, "", "Runtime Error", + "__division__ cannot perform division between number and %.*s", + type_name->value.as_str.length, + type_name->value.as_str.data); + return ARGON_NULL; + } + mpq_div(r, *argv[0]->value.as_number, *argv[1]->value.as_number); + ArgonObject *result = new_number_object(r); + mpq_clear(r); + return result; +} + ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { (void)state; @@ -298,6 +349,12 @@ void create_ARGON_NUMBER_TYPE() { add_field(ARGON_NUMBER_TYPE, "__subtract__", create_argon_native_function("__subtract__", ARGON_NUMBER_TYPE___subtract__)); + add_field(ARGON_NUMBER_TYPE, "__multiply__", + create_argon_native_function("__multiply__", + ARGON_NUMBER_TYPE___multiply__)); + add_field(ARGON_NUMBER_TYPE, "__division__", + create_argon_native_function("__division__", + ARGON_NUMBER_TYPE___division__)); } void mpz_init_gc_managed(mpz_t z, size_t limbs_count) { diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index d8110a8..5d938d6 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -37,10 +37,10 @@ ArgonObject *ACCESS_FUNCTION; ArgonObject *ADDITION_FUNCTION; ArgonObject *SUBTRACTION_FUNCTION; ArgonObject *MULTIPLY_FUNCTION; -ArgonObject *DIVIDE_FUNCTION; +ArgonObject *DIVISION_FUNCTION; ArgonObject *POWER_FUNCTION; ArgonObject *MODULO_FUNCTION; -ArgonObject *FLOORDIV_FUNCTION; +ArgonObject *FLOORDIVISION_FUNCTION; ArgonObject *ARGON_ADDITION_FUNCTION(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { @@ -70,7 +70,7 @@ ArgonObject *ARGON_SUBTRACTION_FUNCTION(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { if (argc < 1) { *err = create_err(0, 0, 0, "", "Runtime Error", - "add expects at least 1 argument, got %" PRIu64, argc); + "subtract expects at least 1 argument, got %" PRIu64, argc); return ARGON_NULL; } ArgonObject *output = argv[0]; @@ -91,6 +91,56 @@ ArgonObject *ARGON_SUBTRACTION_FUNCTION(size_t argc, ArgonObject **argv, return output; } +ArgonObject *ARGON_MULTIPLY_FUNCTION(size_t argc, ArgonObject **argv, + ArErr *err, RuntimeState *state) { + if (argc < 1) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "multiply expects at least 1 argument, got %" PRIu64, argc); + return ARGON_NULL; + } + ArgonObject *output = argv[0]; + for (size_t i = 1; i < argc; i++) { + ArgonObject *__multiply__ = get_field_for_class( + get_field(output, "__class__", false, false), "__multiply__", output); + if (!__multiply__) { + ArgonObject *cls___name__ = get_field(output, "__name__", true, false); + *err = create_err(0, 0, 0, "", "Runtime Error", + "Object '%.*s' is missing __multiply__ method", + (int)cls___name__->value.as_str.length, + cls___name__->value.as_str.data); + return ARGON_NULL; + } + output = + argon_call(__multiply__, 1, (ArgonObject *[]){argv[i]}, err, state); + } + return output; +} + +ArgonObject *ARGON_DIVISION_FUNCTION(size_t argc, ArgonObject **argv, + ArErr *err, RuntimeState *state) { + if (argc < 1) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "division expects at least 1 argument, got %" PRIu64, argc); + return ARGON_NULL; + } + ArgonObject *output = argv[0]; + for (size_t i = 1; i < argc; i++) { + ArgonObject *__multiply__ = get_field_for_class( + get_field(output, "__class__", false, false), "__division__", output); + if (!__multiply__) { + ArgonObject *cls___name__ = get_field(output, "__name__", true, false); + *err = create_err(0, 0, 0, "", "Runtime Error", + "Object '%.*s' is missing __division__ method", + (int)cls___name__->value.as_str.length, + cls___name__->value.as_str.data); + return ARGON_NULL; + } + output = + argon_call(__multiply__, 1, (ArgonObject *[]){argv[i]}, err, state); + } + return output; +} + ArgonObject *ARGON_TYPE_TYPE___call__(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { (void)state; @@ -509,6 +559,10 @@ void bootstrap_types() { create_argon_native_function("add", ARGON_ADDITION_FUNCTION); SUBTRACTION_FUNCTION = create_argon_native_function("subtract", ARGON_SUBTRACTION_FUNCTION); + MULTIPLY_FUNCTION = + create_argon_native_function("multiply", ARGON_MULTIPLY_FUNCTION); + DIVISION_FUNCTION = + create_argon_native_function("division", ARGON_DIVISION_FUNCTION); add_field(BASE_CLASS, "__get_attr__", ACCESS_FUNCTION); } @@ -527,6 +581,8 @@ void bootstrap_globals() { add_to_scope(Global_Scope, "number", ARGON_NUMBER_TYPE); add_to_scope(Global_Scope, "add", ADDITION_FUNCTION); add_to_scope(Global_Scope, "subtract", SUBTRACTION_FUNCTION); + add_to_scope(Global_Scope, "multiply", MULTIPLY_FUNCTION); + add_to_scope(Global_Scope, "division", DIVISION_FUNCTION); ArgonObject *argon_term = new_object(); add_field(argon_term, "__init__", ARGON_NULL); @@ -722,6 +778,12 @@ ArErr run_instruction(Translated *translated, RuntimeState *state, case OP_LOAD_SUBTRACTION_FUNCTION: state->registers[0] = SUBTRACTION_FUNCTION; break; + case OP_LOAD_MULTIPLY_FUNCTION: + state->registers[0] = MULTIPLY_FUNCTION; + break; + case OP_LOAD_DIVISION_FUNCTION: + state->registers[0] = DIVISION_FUNCTION; + break; default: return create_err(0, 0, 0, NULL, "Runtime Error", "Invalid Opcode %#x", opcode); diff --git a/src/shell.c b/src/shell.c index 93bdc86..41c8fa1 100644 --- a/src/shell.c +++ b/src/shell.c @@ -20,32 +20,32 @@ #endif #if defined(_WIN32) || defined(_WIN64) FILE *fmemopen(void *buf, size_t size, const char *mode) { - if (strchr(mode, 'r') == NULL) { - return NULL; - } + if (strchr(mode, 'r') == NULL) { + return NULL; + } - FILE *tmp = tmpfile(); - if (!tmp) return NULL; + FILE *tmp = tmpfile(); + if (!tmp) + return NULL; - if (fwrite(buf, 1, size, tmp) != size) { - fclose(tmp); - return NULL; - } + if (fwrite(buf, 1, size, tmp) != size) { + fclose(tmp); + return NULL; + } - rewind(tmp); + rewind(tmp); - return tmp; + return tmp; } #else #include "../external/linenoise/linenoise.h" #endif -volatile sig_atomic_t interrupted = 0; - // Ctrl+C handler void handle_sigint(int sig) { (void)sig; - interrupted = 1; + printf("\nBye :)\n"); + exit(0); } int execute_code(FILE *stream, char *path, Stack *scope, @@ -116,9 +116,9 @@ int execute_code(FILE *stream, char *path, Stack *scope, return 0; } -#if defined(_WIN32) || defined(_WIN64) // Simple input function char *input(const char *prompt) { +#if defined(_WIN32) || defined(_WIN64) printf("%s", prompt); fflush(stdout); @@ -131,14 +131,17 @@ char *input(const char *prompt) { return NULL; } - // Remove trailing newline if (len > 0 && buffer[len - 1] == '\n') { buffer[len - 1] = '\0'; } - +#else + char *buffer = linenoise(prompt); + if (buffer && buffer[0] != '\0') { + linenoiseHistoryAdd(buffer); + } +#endif return buffer; } -#endif char *read_all_stdin(size_t *out_len) { size_t size = 1024; @@ -216,11 +219,7 @@ int shell() { memcpy(prompt, textBefore, strlen(textBefore)); memcpy(prompt + strlen(textBefore), indentStr, isz + 1); -#if defined(_WIN32) || defined(_WIN64) char *inp = input(prompt); -#else - char *inp = linenoise(prompt); -#endif free(prompt); if (!inp) { @@ -231,13 +230,6 @@ int shell() { free(indentStr); return 0; } -#if defined(_WIN32) || defined(_WIN64) -#else - if (inp[0] != '\0') { - // Optionally add line to history - linenoiseHistoryAdd(inp); - } -#endif // Append line to totranslate size_t length = strlen(inp); diff --git a/src/translator/access/access.c b/src/translator/access/access.c index 5921db3..400b404 100644 --- a/src/translator/access/access.c +++ b/src/translator/access/access.c @@ -10,19 +10,22 @@ size_t translate_access(Translated *translated, ParsedAccess *access, set_registers(translated, 1); uint64_t first = push_instruction_byte(translated, OP_LOAD_ACCESS_FUNCTION); push_instruction_byte(translated, OP_INIT_CALL); - push_instruction_code(translated, 3); + push_instruction_code(translated, access->access.size + 2); translate_parsed(translated, &access->to_access, err); push_instruction_byte(translated, OP_INSERT_ARG); push_instruction_code(translated, 0); - translate_parsed(translated, darray_get(&access->access, 0), err); - push_instruction_byte(translated, OP_INSERT_ARG); - push_instruction_code(translated, 1); - push_instruction_byte(translated, OP_LOAD_BOOL); push_instruction_byte(translated, access->access_fields); push_instruction_byte(translated, OP_INSERT_ARG); - push_instruction_code(translated, 2); + push_instruction_code(translated, 1); + + for (size_t i = 0; i < access->access.size; i++) { + translate_parsed(translated, darray_get(&access->access, i), err); + push_instruction_byte(translated, OP_INSERT_ARG); + push_instruction_code(translated, 2+i); + } + push_instruction_byte(translated, OP_SOURCE_LOCATION); push_instruction_code(translated, access->line); push_instruction_code(translated, access->column); diff --git a/src/translator/bytecode_spec.md b/src/translator/bytecode_spec.md index ecebad2..e9bf711 100644 --- a/src/translator/bytecode_spec.md +++ b/src/translator/bytecode_spec.md @@ -135,4 +135,12 @@ loads the addition function into register 1 ## OP_LOAD_SUBTRACTION_FUNCTION -loads the subtraction function into register 1 \ No newline at end of file +loads the subtraction function into register 1 + +## OP_LOAD_MULTIPLY_FUNCTION + +loads the multiply function into register 1 + +## OP_LOAD_DIVISION_FUNCTION + +loads the division function into register 1 \ No newline at end of file diff --git a/src/translator/operation/operation.c b/src/translator/operation/operation.c index 0c4e3ad..357c9e6 100644 --- a/src/translator/operation/operation.c +++ b/src/translator/operation/operation.c @@ -18,6 +18,12 @@ size_t translate_operation(Translated *translated, ParsedOperation *operation, case TOKEN_MINUS: first = push_instruction_byte(translated, OP_LOAD_SUBTRACTION_FUNCTION); break; + case TOKEN_STAR: + first = push_instruction_byte(translated, OP_LOAD_MULTIPLY_FUNCTION); + break; + case TOKEN_SLASH: + first = push_instruction_byte(translated, OP_LOAD_DIVISION_FUNCTION); + break; default: *err = create_err(operation->line, operation->column, operation->length, translated->path, "Syntax Error", "unknown operation"); diff --git a/src/translator/translator.h b/src/translator/translator.h index d7134b8..3f5f05d 100644 --- a/src/translator/translator.h +++ b/src/translator/translator.h @@ -33,7 +33,9 @@ typedef enum { OP_LOAD_BOOL, OP_LOAD_NUMBER, OP_LOAD_ADDITION_FUNCTION, - OP_LOAD_SUBTRACTION_FUNCTION + OP_LOAD_SUBTRACTION_FUNCTION, + OP_LOAD_MULTIPLY_FUNCTION, + OP_LOAD_DIVISION_FUNCTION } OperationType; void arena_resize(ConstantArena *arena, size_t new_size);