From 57728af0b630e2d17c77f7923c8a913523da3973 Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Wed, 3 Sep 2025 05:21:41 +0100 Subject: [PATCH] add multiplication, division, and && --- .vscode/launch.json | 2 +- anonymous-function-test.ar | 10 ++- app.py | 1 - src/runtime/call/call.c | 7 +- src/runtime/objects/number/number.c | 91 +++++++++++++++++--- src/runtime/runtime.c | 124 +++++++++++++++++++++++++-- src/shell.c | 4 +- src/translator/bytecode_spec.md | 27 +++++- src/translator/operation/operation.c | 47 +++++++++- src/translator/translator.h | 4 +- 10 files changed, 286 insertions(+), 31 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 4916ce1..4e22090 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/argon", - "args": ["testing.ar"], + "args": [], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/anonymous-function-test.ar b/anonymous-function-test.ar index 6a7a012..fcda09c 100644 --- a/anonymous-function-test.ar +++ b/anonymous-function-test.ar @@ -1,4 +1,8 @@ -let i = 1000000 +let factorial(x) = do + if (x-1) return x * factorial(x-1) + return 1 + +let i = 10000000 +term.log(factorial(10000)) while (i) do - i=i-1 -term.log(add) \ No newline at end of file + i=i-1 \ No newline at end of file diff --git a/app.py b/app.py index 827d8f8..0bacd2d 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,3 @@ i = 1_000_000 while i: - print(i) i=i-1 \ No newline at end of file diff --git a/src/runtime/call/call.c b/src/runtime/call/call.c index bdb9b5a..a3ce6b6 100644 --- a/src/runtime/call/call.c +++ b/src/runtime/call/call.c @@ -6,6 +6,7 @@ #include "call.h" #include "../../hash_data/hash_data.h" +#include "../objects/literals/literals.h" #include "../objects/string/string.h" #include #include @@ -143,7 +144,8 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, object->value.argon_fn.bytecode_length, false}, object->value.argon_fn.translated.constants, object->value.argon_fn.translated.path}, - {ar_alloc(object->value.argon_fn.translated.registerCount * sizeof(ArgonObject *)), + {ar_alloc(object->value.argon_fn.translated.registerCount * + sizeof(ArgonObject *)), 0, object->value.argon_fn.translated.path, NULL, @@ -153,6 +155,9 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, scope, *state->currentStackFramePointer, (*state->currentStackFramePointer)->depth + 1}; + for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) { + new_stackFrame.state.registers[i] = ARGON_NULL; + } if (CStackFrame) { runtime(new_stackFrame.translated, new_stackFrame.state, new_stackFrame.stack, err); diff --git a/src/runtime/objects/number/number.c b/src/runtime/objects/number/number.c index 906fc3c..69fe289 100644 --- a/src/runtime/objects/number/number.c +++ b/src/runtime/objects/number/number.c @@ -147,8 +147,6 @@ ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv, "__subtract__ 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_builtin_field_for_class( get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); @@ -158,6 +156,7 @@ ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv, type_name->value.as_str.length, type_name->value.as_str.data); return ARGON_NULL; } + if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) { int64_t a = argv[0]->value.as_number.n.i64; int64_t b = argv[1]->value.as_number.n.i64; @@ -213,8 +212,6 @@ ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv, "__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_builtin_field_for_class( get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); @@ -224,10 +221,52 @@ ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv, type_name->value.as_str.length, type_name->value.as_str.data); return ARGON_NULL; } - mpq_mul(r, *argv[0]->value.as_number.n.mpq, *argv[1]->value.as_number.n.mpq); - ArgonObject *result = new_number_object(r); - mpq_clear(r); - return result; + + if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) { + int64_t a = argv[0]->value.as_number.n.i64; + int64_t b = argv[1]->value.as_number.n.i64; + bool gonna_overflow = + a > 0 ? (b > 0 ? a > INT64_MAX / b : b < INT64_MIN / a) + : (b > 0 ? a < INT64_MIN / b : a != 0 && b < INT64_MAX / a); + if (!gonna_overflow) { + return new_number_object_from_int64(a * b); + } + mpq_t a_GMP, b_GMP; + mpq_init(a_GMP); + mpq_init(b_GMP); + mpq_set_si(a_GMP, a, 1); + mpq_set_si(b_GMP, b, 1); + mpq_mul(a_GMP, a_GMP, b_GMP); + ArgonObject *result = new_number_object(a_GMP); + mpq_clear(a_GMP); + mpq_clear(b_GMP); + return result; + } else if (!argv[0]->value.as_number.is_int64 && + !argv[1]->value.as_number.is_int64) { + mpq_t r; + mpq_init(r); + mpq_mul(r, *argv[0]->value.as_number.n.mpq, + *argv[1]->value.as_number.n.mpq); + ArgonObject *result = new_number_object(r); + mpq_clear(r); + return result; + } else { + mpq_t a_GMP, b_GMP; + mpq_init(a_GMP); + mpq_init(b_GMP); + if (argv[0]->value.as_number.is_int64) { + mpq_set_si(a_GMP, argv[0]->value.as_number.n.i64, 1); + mpq_set(b_GMP, *argv[1]->value.as_number.n.mpq); + } else { + mpq_set(a_GMP, *argv[0]->value.as_number.n.mpq); + mpq_set_si(b_GMP, argv[1]->value.as_number.n.i64, 1); + } + mpq_mul(a_GMP, a_GMP, b_GMP); + ArgonObject *result = new_number_object(a_GMP); + mpq_clear(a_GMP); + mpq_clear(b_GMP); + return result; + } } ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, @@ -238,8 +277,6 @@ ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, "__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_builtin_field_for_class( get_builtin_field(argv[1], __class__, false, false), __name__, argv[1]); @@ -249,10 +286,36 @@ ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, type_name->value.as_str.length, type_name->value.as_str.data); return ARGON_NULL; } - mpq_div(r, *argv[0]->value.as_number.n.mpq, *argv[1]->value.as_number.n.mpq); - ArgonObject *result = new_number_object(r); - mpq_clear(r); - return result; + if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) { + int64_t a = argv[0]->value.as_number.n.i64; + int64_t b = argv[1]->value.as_number.n.i64; + return new_number_object_from_num_and_den(a, b); + } else if (!argv[0]->value.as_number.is_int64 && + !argv[1]->value.as_number.is_int64) { + mpq_t r; + mpq_init(r); + mpq_div(r, *argv[0]->value.as_number.n.mpq, + *argv[1]->value.as_number.n.mpq); + ArgonObject *result = new_number_object(r); + mpq_clear(r); + return result; + } else { + mpq_t a_GMP, b_GMP; + mpq_init(a_GMP); + mpq_init(b_GMP); + if (argv[0]->value.as_number.is_int64) { + mpq_set_si(a_GMP, argv[0]->value.as_number.n.i64, 1); + mpq_set(b_GMP, *argv[1]->value.as_number.n.mpq); + } else { + mpq_set(a_GMP, *argv[0]->value.as_number.n.mpq); + mpq_set_si(b_GMP, argv[1]->value.as_number.n.i64, 1); + } + mpq_div(a_GMP, a_GMP, b_GMP); + ArgonObject *result = new_number_object(a_GMP); + mpq_clear(a_GMP); + mpq_clear(b_GMP); + return result; + } } ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv, diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index fc73f2a..a567b3f 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -681,6 +681,9 @@ RuntimeState init_runtime_state(Translated translated, char *path) { NULL, {0, 0, 0}, {}}; + for (size_t i = 0;iregisters[0]->type != TYPE_OBJECT)) { + if (likely(state->registers[to_register]->type != TYPE_OBJECT)) { state->registers[to_register] = - state->registers[0]->as_bool ? ARGON_TRUE : ARGON_FALSE; + state->registers[to_register]->as_bool ? ARGON_TRUE : ARGON_FALSE; continue; } ArgonObject *args[] = {ARGON_BOOL_TYPE, state->registers[0]}; @@ -937,13 +942,122 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, ArgonObject *args[] = {valueA, valueB}; state->registers[registerC] = - ARGON_ADDITION_FUNCTION(2, args, err, state); + ARGON_SUBTRACTION_FUNCTION(2, args, err, state); + continue; + } + DO_MULTIPLICATION: { + uint8_t registerA = pop_byte(translated, state); + uint8_t registerB = pop_byte(translated, state); + uint8_t registerC = pop_byte(translated, state); + + ArgonObject *valueA = state->registers[registerA]; + ArgonObject *valueB = state->registers[registerB]; + + if (likely(valueA->type == TYPE_NUMBER && valueB->type == TYPE_NUMBER)) { + if (likely(valueA->value.as_number.is_int64 && + valueB->value.as_number.is_int64)) { + int64_t a = valueA->value.as_number.n.i64; + int64_t b = valueB->value.as_number.n.i64; + bool gonna_overflow = + a > 0 ? (b > 0 ? a > INT64_MAX / b : b < INT64_MIN / a) + : (b > 0 ? a < INT64_MIN / b : a != 0 && b < INT64_MAX / a); + if (!gonna_overflow) { + state->registers[registerC] = new_number_object_from_int64(a * b); + continue; + } + mpq_t a_GMP, b_GMP; + mpq_init(a_GMP); + mpq_init(b_GMP); + mpq_set_si(a_GMP, a, 1); + mpq_set_si(b_GMP, b, 1); + mpq_mul(a_GMP, a_GMP, b_GMP); + state->registers[registerC] = new_number_object(a_GMP); + mpq_clear(a_GMP); + mpq_clear(b_GMP); + } else if (!valueA->value.as_number.is_int64 && + !valueB->value.as_number.is_int64) { + mpq_t r; + mpq_init(r); + mpq_mul(r, *valueA->value.as_number.n.mpq, + *valueB->value.as_number.n.mpq); + state->registers[registerC] = new_number_object(r); + mpq_clear(r); + } else { + mpq_t a_GMP, b_GMP; + mpq_init(a_GMP); + mpq_init(b_GMP); + if (valueA->value.as_number.is_int64) { + mpq_set_si(a_GMP, valueA->value.as_number.n.i64, 1); + mpq_set(b_GMP, *valueB->value.as_number.n.mpq); + } else { + mpq_set(a_GMP, *valueA->value.as_number.n.mpq); + mpq_set_si(b_GMP, valueB->value.as_number.n.i64, 1); + } + mpq_mul(a_GMP, a_GMP, b_GMP); + state->registers[registerC] = new_number_object(a_GMP); + mpq_clear(a_GMP); + mpq_clear(b_GMP); + } + continue; + } + + ArgonObject *args[] = {valueA, valueB}; + state->registers[registerC] = + ARGON_MULTIPLY_FUNCTION(2, args, err, state); + continue; + } + DO_DIVISION: { + uint8_t registerA = pop_byte(translated, state); + uint8_t registerB = pop_byte(translated, state); + uint8_t registerC = pop_byte(translated, state); + + ArgonObject *valueA = state->registers[registerA]; + ArgonObject *valueB = state->registers[registerB]; + + if (likely(valueA->type == TYPE_NUMBER && valueB->type == TYPE_NUMBER)) { + if (likely(valueA->value.as_number.is_int64 && + valueB->value.as_number.is_int64)) { + int64_t a = valueA->value.as_number.n.i64; + int64_t b = valueB->value.as_number.n.i64; + state->registers[registerC] = + new_number_object_from_num_and_den(a, b); + } else if (!valueA->value.as_number.is_int64 && + !valueB->value.as_number.is_int64) { + mpq_t r; + mpq_init(r); + mpq_div(r, *valueA->value.as_number.n.mpq, + *valueB->value.as_number.n.mpq); + state->registers[registerC] = new_number_object(r); + mpq_clear(r); + } else { + mpq_t a_GMP, b_GMP; + mpq_init(a_GMP); + mpq_init(b_GMP); + if (valueA->value.as_number.is_int64) { + mpq_set_si(a_GMP, valueA->value.as_number.n.i64, 1); + mpq_set(b_GMP, *valueB->value.as_number.n.mpq); + } else { + mpq_set(a_GMP, *valueA->value.as_number.n.mpq); + mpq_set_si(b_GMP, valueB->value.as_number.n.i64, 1); + } + mpq_div(a_GMP, a_GMP, b_GMP); + state->registers[registerC] = new_number_object(a_GMP); + mpq_clear(a_GMP); + mpq_clear(b_GMP); + } + continue; + } + + ArgonObject *args[] = {valueA, valueB}; + state->registers[registerC] = + ARGON_DIVISION_FUNCTION(2, args, err, state); continue; } } ArgonObject *result = currentStackFrame->state.registers[0]; currentStackFrame = currentStackFrame->previousStackFrame; - if(currentStackFrame) currentStackFrame->state.registers[0] = result; + if (currentStackFrame) + currentStackFrame->state.registers[0] = result; } } diff --git a/src/shell.c b/src/shell.c index 43e490e..a380368 100644 --- a/src/shell.c +++ b/src/shell.c @@ -55,7 +55,7 @@ int execute_code(FILE *stream, char *path, Stack *scope, return 1; } - ArErr err; + ArErr err = no_err; DArray tokens; darray_init(&tokens, sizeof(Token)); @@ -263,7 +263,7 @@ int shell() { if (resp) { continue; } - ArErr err; + ArErr err = no_err; argon_call(output_object, 1, (ArgonObject *[]){runtime_state.registers[0]}, &err, &runtime_state); totranslatelength = 0; diff --git a/src/translator/bytecode_spec.md b/src/translator/bytecode_spec.md index 1dc2ad2..1e45868 100644 --- a/src/translator/bytecode_spec.md +++ b/src/translator/bytecode_spec.md @@ -82,13 +82,12 @@ jumps when a the value in the given register is false. 1. the register to read. (*) 1. the index to jump to. -## OP_JUMP_IF_FALSE +## OP_JUMP jumps unconditionally to an index. 1. the index to jump to. - ## OP_NEW_SCOPE creates a new stack @@ -156,6 +155,30 @@ copies the value from one register to another performs an addition between register A and register B, storing the result in register C +1. the register A (*) +2. the register B (*) +2. the register C (*) + +## OP_SUBTRACTION + +performs an subtraction between register A and register B, storing the result in register C + +1. the register A (*) +2. the register B (*) +2. the register C (*) + +## OP_MULTIPLICATION + +performs an multiplication between register A and register B, storing the result in register C + +1. the register A (*) +2. the register B (*) +2. the register C (*) + +## OP_DIVISION + +performs an division between register A and register B, storing the result in register C + 1. the register A (*) 2. the register B (*) 2. the register C (*) \ No newline at end of file diff --git a/src/translator/operation/operation.c b/src/translator/operation/operation.c index 021069f..bd234e0 100644 --- a/src/translator/operation/operation.c +++ b/src/translator/operation/operation.c @@ -11,15 +11,54 @@ size_t translate_operation(Translated *translated, ParsedOperation *operation, ArErr *err) { + if (operation->operation == TOKEN_AND) { + size_t *jump_to_if_false = + checked_malloc(operation->to_operate_on.size * sizeof(size_t)); + uint8_t registerA = translated->registerAssignment++; + set_registers(translated, translated->registerAssignment); + uint64_t first = 0; + for (size_t i = 0; i < operation->to_operate_on.size; i++) { + uint64_t position = translate_parsed( + translated, darray_get(&operation->to_operate_on, i), err); + if (i == 0) + position = first; + if (err->exists) { + free(jump_to_if_false); + return first; + } + push_instruction_byte(translated, OP_COPY_TO_REGISTER); + push_instruction_byte(translated, 0); + push_instruction_byte(translated, registerA); + + push_instruction_byte(translated, OP_BOOL); + push_instruction_byte(translated, registerA); + + push_instruction_byte(translated, OP_JUMP_IF_FALSE); + push_instruction_byte(translated, registerA); + jump_to_if_false[i] = push_instruction_code(translated, 0); + } + for (size_t i = 0; i < operation->to_operate_on.size; i++) { + set_instruction_code(translated, jump_to_if_false[i], + translated->bytecode.size); + } + + free(jump_to_if_false); + return first; + } uint8_t registerA = translated->registerAssignment++; uint8_t registerB = translated->registerAssignment++; set_registers(translated, translated->registerAssignment); - uint64_t first = translate_parsed(translated, darray_get(&operation->to_operate_on, 0), err); + uint64_t first = translate_parsed( + translated, darray_get(&operation->to_operate_on, 0), err); + if (err->exists) + return first; push_instruction_byte(translated, OP_COPY_TO_REGISTER); push_instruction_byte(translated, 0); push_instruction_byte(translated, registerA); for (size_t i = 1; i < operation->to_operate_on.size; i++) { translate_parsed(translated, darray_get(&operation->to_operate_on, i), err); + if (err->exists) + return first; push_instruction_byte(translated, OP_COPY_TO_REGISTER); push_instruction_byte(translated, 0); push_instruction_byte(translated, registerB); @@ -30,6 +69,12 @@ size_t translate_operation(Translated *translated, ParsedOperation *operation, case TOKEN_MINUS:; push_instruction_byte(translated, OP_SUBTRACTION); break; + case TOKEN_STAR:; + push_instruction_byte(translated, OP_MULTIPLICATION); + break; + case TOKEN_SLASH:; + push_instruction_byte(translated, OP_DIVISION); + 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 774d49d..3a63935 100644 --- a/src/translator/translator.h +++ b/src/translator/translator.h @@ -36,7 +36,9 @@ typedef enum { OP_COPY_TO_REGISTER, OP_ADDITION, OP_SUBTRACTION, - OP_LOAD_ACCESS_FUNCTION + OP_LOAD_ACCESS_FUNCTION, + OP_MULTIPLICATION, + OP_DIVISION } OperationType; void arena_resize(ConstantArena *arena, size_t new_size);