From d2e742f992255189280e4cc6a6637a7f8dd5d5cd Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Mon, 11 Aug 2025 01:41:44 +0100 Subject: [PATCH] add number type and object --- Makefile | 2 +- src/parser/number/number.c | 277 +++++++++++++++------------- src/parser/number/number.h | 2 +- src/parser/parser.c | 18 +- src/runtime/objects/number/number.c | 43 +++++ src/runtime/objects/number/number.h | 17 ++ src/runtime/objects/object.c | 1 + src/runtime/runtime.c | 19 +- src/translator/number/number.c | 2 +- testing.ar | 3 - 10 files changed, 239 insertions(+), 145 deletions(-) create mode 100644 src/runtime/objects/number/number.c create mode 100644 src/runtime/objects/number/number.h diff --git a/Makefile b/Makefile index 438924a..151fc81 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ native: $(CFILES) $(LEXER_C) $(LEXER_H) debug: $(CFILES) $(LEXER_C) $(LEXER_H) mkdir -p bin - gcc -g -O0 -o $(BINARY) $(CFILES) $(CFLAGS) + gcc -g -O3 -o $(BINARY) $(CFILES) $(CFLAGS) full-debug: $(CFILES) $(LEXER_C) $(LEXER_H) mkdir -p bin diff --git a/src/parser/number/number.c b/src/parser/number/number.c index 3ab5974..8f834f5 100644 --- a/src/parser/number/number.c +++ b/src/parser/number/number.c @@ -5,160 +5,187 @@ */ #include "number.h" -#include "../../lexer/token.h" -#include "../parser.h" #include "../../memory.h" +#include #include +#include +#include #include -// #include -// #include -// #include -// #include +int parse_exponent(const char *exp_str, long *exp_val) { + char *endptr; + long val = strtol(exp_str, &endptr, 10); + if (*endptr != '\0') { + // exponent contains invalid chars or decimal point → reject + return -1; + } + *exp_val = val; + return 0; +} -// int parse_exponent(const char *exp_str, long *exp_val) { -// char *endptr; -// long val = strtol(exp_str, &endptr, 10); -// if (*endptr != '\0') { -// // exponent contains invalid chars or decimal point → reject -// return -1; -// } -// *exp_val = val; -// return 0; -// } +int mpq_set_decimal_str_exp(mpq_t r, const char *str) { + // Skip leading whitespace + while (isspace(*str)) + str++; -// int mpq_set_decimal_str_exp(mpq_t r, const char *str) { -// // Skip leading whitespace -// while (isspace(*str)) str++; + // Handle sign + int negative = 0; + if (*str == '-') { + negative = 1; + str++; + } else if (*str == '+') { + str++; + } -// // Handle sign -// int negative = 0; -// if (*str == '-') { -// negative = 1; -// str++; -// } else if (*str == '+') { -// str++; -// } + // Copy input to a buffer for manipulation + size_t len = strlen(str); + char *buf = malloc(len + 1); + if (!buf) + return -1; + strcpy(buf, str); -// // Copy input to a buffer for manipulation -// size_t len = strlen(str); -// char *buf = malloc(len + 1); -// if (!buf) return -1; -// strcpy(buf, str); + // Find 'e' or 'E' + char *e_ptr = strchr(buf, 'e'); + if (!e_ptr) + e_ptr = strchr(buf, 'E'); -// // Find 'e' or 'E' -// char *e_ptr = strchr(buf, 'e'); -// if (!e_ptr) e_ptr = strchr(buf, 'E'); + char *exp_str = NULL; + if (e_ptr) { + *e_ptr = '\0'; + exp_str = e_ptr + 1; + } -// char *exp_str = NULL; -// if (e_ptr) { -// *e_ptr = '\0'; -// exp_str = e_ptr + 1; -// } + // Validate decimal part (digits and one dot) + int dot_count = 0; + for (char *p = buf; *p; p++) { + if (*p == '.') { + if (++dot_count > 1) { + free(buf); + return -1; + } + continue; + } + if (!isdigit((unsigned char)*p)) { + free(buf); + return -1; + } + } -// // Validate decimal part (digits and one dot) -// int dot_count = 0; -// for (char *p = buf; *p; p++) { -// if (*p == '.') { -// if (++dot_count > 1) { free(buf); return -1; } -// continue; -// } -// if (!isdigit((unsigned char)*p)) { free(buf); return -1; } -// } + // Extract integer and fractional parts + char *dot = strchr(buf, '.'); + size_t int_len = dot ? (size_t)(dot - buf) : strlen(buf); + size_t frac_len = dot ? strlen(dot + 1) : 0; -// // Extract integer and fractional parts -// char *dot = strchr(buf, '.'); -// size_t int_len = dot ? (size_t)(dot - buf) : strlen(buf); -// size_t frac_len = dot ? strlen(dot + 1) : 0; + // Validate exponent if present + int exp_negative = 0; + long exp_val = 0; + if (exp_str) { + // Skip leading spaces in exponent (not in regex but safe) + while (isspace(*exp_str)) + exp_str++; -// // Validate exponent if present -// int exp_negative = 0; -// long exp_val = 0; -// if (exp_str) { -// // Skip leading spaces in exponent (not in regex but safe) -// while (isspace(*exp_str)) exp_str++; + if (*exp_str == '-') { + exp_negative = 1; + exp_str++; + } else if (*exp_str == '+') { + exp_str++; + } -// if (*exp_str == '-') { -// exp_negative = 1; -// exp_str++; -// } else if (*exp_str == '+') { -// exp_str++; -// } + if (!isdigit((unsigned char)*exp_str)) { + free(buf); + return -1; + } -// if (!isdigit((unsigned char)*exp_str)) { -// free(buf); -// return -1; -// } + char *endptr; + exp_val = strtol(exp_str, &endptr, 10); + if (*endptr != '\0') { + free(buf); + return -1; + } + if (exp_negative) + exp_val = -exp_val; + } -// char *endptr; -// exp_val = strtol(exp_str, &endptr, 10); -// if (*endptr != '\0') { -// free(buf); -// return -1; -// } -// if (exp_negative) exp_val = -exp_val; -// } + // Build numerator string (integer part + fractional part) + size_t num_len = int_len + frac_len; + if (num_len == 0) { + free(buf); + return -1; + } -// // Build numerator string (integer part + fractional part) -// size_t num_len = int_len + frac_len; -// if (num_len == 0) { free(buf); return -1; } + char *num_str = malloc(num_len + 1); + if (!num_str) { + free(buf); + return -1; + } -// char *num_str = malloc(num_len + 1); -// if (!num_str) { free(buf); return -1; } + if (int_len > 0) + memcpy(num_str, buf, int_len); + if (frac_len > 0) + memcpy(num_str + int_len, dot + 1, frac_len); + num_str[num_len] = '\0'; -// if (int_len > 0) memcpy(num_str, buf, int_len); -// if (frac_len > 0) memcpy(num_str + int_len, dot + 1, frac_len); -// num_str[num_len] = '\0'; + // Calculate denominator exponent considering exponent part + long denom_exp = frac_len - exp_val; -// // Calculate denominator exponent considering exponent part -// long denom_exp = frac_len - exp_val; + mpz_t numerator, denominator; + mpz_init(numerator); + mpz_init(denominator); -// mpz_t numerator, denominator; -// mpz_init(numerator); -// mpz_init(denominator); + if (mpz_set_str(numerator, num_str, 10) != 0) { + free(num_str); + free(buf); + mpz_clear(numerator); + mpz_clear(denominator); + return -1; + } + free(num_str); + free(buf); -// if (mpz_set_str(numerator, num_str, 10) != 0) { -// free(num_str); -// free(buf); -// mpz_clear(numerator); -// mpz_clear(denominator); -// return -1; -// } -// free(num_str); -// free(buf); + if (denom_exp >= 0) { + mpz_ui_pow_ui(denominator, 10, (unsigned long)denom_exp); + } else { + // denom_exp < 0 means multiply numerator by 10^(-denom_exp) + mpz_ui_pow_ui(denominator, 10, 0); + mpz_ui_pow_ui(numerator, 10, (unsigned long)(-denom_exp)); + } -// if (denom_exp >= 0) { -// mpz_ui_pow_ui(denominator, 10, (unsigned long)denom_exp); -// } else { -// // denom_exp < 0 means multiply numerator by 10^(-denom_exp) -// mpz_ui_pow_ui(denominator, 10, 0); -// mpz_ui_pow_ui(numerator, 10, (unsigned long)(-denom_exp)); -// } + if (denom_exp < 0) { + mpz_t temp; + mpz_init(temp); + mpz_ui_pow_ui(temp, 10, (unsigned long)(-denom_exp)); + mpz_mul(numerator, numerator, temp); + mpz_clear(temp); + mpz_set_ui(denominator, 1); + } -// if (denom_exp < 0) { -// mpz_t temp; -// mpz_init(temp); -// mpz_ui_pow_ui(temp, 10, (unsigned long)(-denom_exp)); -// mpz_mul(numerator, numerator, temp); -// mpz_clear(temp); -// mpz_set_ui(denominator, 1); -// } + mpq_set_num(r, numerator); + mpq_set_den(r, denominator); + mpq_canonicalize(r); -// mpq_set_num(r, numerator); -// mpq_set_den(r, denominator); -// mpq_canonicalize(r); + if (negative) + mpq_neg(r, r); -// if (negative) mpq_neg(r, r); + mpz_clear(numerator); + mpz_clear(denominator); -// mpz_clear(numerator); -// mpz_clear(denominator); + return 0; +} -// return 0; -// } - -ParsedValueReturn parse_number(Token *token) { +ParsedValueReturn parse_number(Token *token, char*path) { ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); parsedValue->type = AST_NUMBER; - parsedValue->data = strdup(token->value); + mpq_t r; + mpq_init(r); + int err = mpq_set_decimal_str_exp(r, token->value); + if (err) { + free(parsedValue); + return (ParsedValueReturn){ + create_err(token->length, token->column, token->length, path, "Parsing Error", "Unable to parse number"), + NULL + }; + } + char *s = mpq_get_str(NULL, 62, r); + parsedValue->data = strdup(s); return (ParsedValueReturn){no_err, parsedValue}; } \ No newline at end of file diff --git a/src/parser/number/number.h b/src/parser/number/number.h index f958729..49fe708 100644 --- a/src/parser/number/number.h +++ b/src/parser/number/number.h @@ -10,6 +10,6 @@ #include "../../lexer/token.h" // for Token // Function declaration for parsing an identifier -ParsedValueReturn parse_number(Token *token); +ParsedValueReturn parse_number(Token *token, char*path); #endif // NUMBER_H \ No newline at end of file diff --git a/src/parser/parser.c b/src/parser/parser.c index 542e11a..508a3a6 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -13,7 +13,6 @@ #include "assignable/identifier/identifier.h" #include "declaration/declaration.h" #include "dictionary/dictionary.h" -#include "return/return.h" #include "dowrap/dowrap.h" #include "function/function.h" #include "if/if.h" @@ -21,6 +20,7 @@ #include "literals/literals.h" #include "number/number.h" #include "operations/operations.h" +#include "return/return.h" #include "string/string.h" #include #include @@ -30,9 +30,10 @@ #include const char *ValueTypeNames[] = { - "string", "assign", "identifier", "number", "if statement", - "access", "call", "declaration", "null", "boolean", - "do wrap", "operations", "list", "dictionary", "function", "return"}; + "string", "assign", "identifier", "number", + "if statement", "access", "call", "declaration", + "null", "boolean", "do wrap", "operations", + "list", "dictionary", "function", "return"}; ArErr error_if_finished(char *file, DArray *tokens, size_t *index) { if ((*index) >= tokens->size) { @@ -117,7 +118,7 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index, break; case TOKEN_NUMBER: (*index)++; - output = parse_number(token); + output = parse_number(token, file); break; case TOKEN_LET: output = parse_declaration(file, tokens, index); @@ -132,10 +133,9 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index, output = parse_dictionary(file, tokens, index); break; default: - return (ParsedValueReturn){create_err(token->line, - token->column, - token->length, file, - "Syntax Error", "unexpected token"), + return (ParsedValueReturn){create_err(token->line, token->column, + token->length, file, "Syntax Error", + "unexpected token"), NULL}; } diff --git a/src/runtime/objects/number/number.c b/src/runtime/objects/number/number.c new file mode 100644 index 0000000..01495ca --- /dev/null +++ b/src/runtime/objects/number/number.c @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "number.h" +#include "../string/string.h" +#include +#include +#include "../functions/functions.h" + +ArgonObject *ARGON_NUMBER_TYPE; + +ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv, + ArErr *err, RuntimeState *state) { + (void)state; + if (argc != 1) { + *err = create_err(0, 0, 0, "", "Runtime Error", + "__string__ expects 1 arguments, got %" PRIu64, argc); + } + double val = mpq_get_d(argv[0]->value.as_number); + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%.15g", val); + return new_string_object_null_terminated(buffer); +} + +void create_ARGON_NUMBER_TYPE() { + ARGON_NUMBER_TYPE = new_object(); + add_field(ARGON_NUMBER_TYPE, "__name__", + new_string_object_null_terminated("number")); + add_field(ARGON_NUMBER_TYPE, "__string__", + create_argon_native_function("__string__", ARGON_NUMBER_TYPE___string__)); +} + +ArgonObject *new_number_object(char *data) { + ArgonObject *object = new_object(); + add_field(object, "__class__", ARGON_NUMBER_TYPE); + object->type = TYPE_NUMBER; + mpq_init(object->value.as_number); + mpq_set_str(object->value.as_number, data, 62); + return object; +} \ No newline at end of file diff --git a/src/runtime/objects/number/number.h b/src/runtime/objects/number/number.h new file mode 100644 index 0000000..926a8cf --- /dev/null +++ b/src/runtime/objects/number/number.h @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef RUNTIME_NUMBER_H +#define RUNTIME_NUMBER_H +#include "../object.h" + +extern ArgonObject *ARGON_NUMBER_TYPE; + +void create_ARGON_NUMBER_TYPE(); + +ArgonObject *new_number_object(char *data); + +#endif // RUNTIME_NUMBER_H \ No newline at end of file diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index a31230f..e3ca3c1 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -20,6 +20,7 @@ ArgonObject *new_object() { object->type = TYPE_OBJECT; object->dict = createHashmap_GC(); add_field(object, "__class__", ARGON_TYPE_TYPE); + add_field(object, "__base__", BASE_CLASS); return object; } diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 6df7bd7..166d430 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -18,6 +18,7 @@ #include "objects/string/string.h" #include "objects/term/term.h" #include "objects/type/type.h" +#include "objects/number/number.h" #include #include #include @@ -122,10 +123,14 @@ ArgonObject *BASE_CLASS___string__(size_t argc, ArgonObject **argv, ArErr *err, get_field(argv[0], "__class__", false, false), "__name__", NULL); char buffer[100]; - snprintf(buffer, sizeof(buffer), "<%.*s %.*s at %p>", - (int)class_name->value.as_str.length, class_name->value.as_str.data, - (int)object_name->value.as_str.length, - object_name->value.as_str.data, argv[0]); + if (class_name && object_name) + snprintf(buffer, sizeof(buffer), "<%.*s %.*s at %p>", + (int)class_name->value.as_str.length, + class_name->value.as_str.data, + (int)object_name->value.as_str.length, + object_name->value.as_str.data, argv[0]); + else + snprintf(buffer, sizeof(buffer), "", argv[0]); return new_string_object_null_terminated(buffer); } @@ -222,7 +227,8 @@ void bootstrap_types() { ARGON_NULL = new_object(); add_field(ARGON_NULL, "__class__", ARGON_NULL_TYPE); - add_field(BASE_CLASS, "__base__", ARGON_NULL); + add_field(BASE_CLASS, "__base__", NULL); + add_field(BASE_CLASS, "__class__", ARGON_TYPE_TYPE); ARGON_BOOL_TYPE = new_object(); add_field(ARGON_BOOL_TYPE, "__base__", BASE_CLASS); @@ -254,6 +260,7 @@ void bootstrap_types() { add_field(ARGON_METHOD_TYPE, "__base__", BASE_CLASS); add_field(ARGON_METHOD_TYPE, "__name__", new_string_object_null_terminated("method")); + create_ARGON_NUMBER_TYPE(); add_field(BASE_CLASS, "__new__", create_argon_native_function("__new__", BASE_CLASS___new__)); @@ -331,6 +338,8 @@ void load_const(Translated *translated, RuntimeState *state) { case TYPE_OP_STRING: object = new_string_object(data, length); break; + case TYPE_OP_NUMBER: + object = new_number_object(data); } state->registers[to_register] = object; } diff --git a/src/translator/number/number.c b/src/translator/number/number.c index 8d6818c..9a08008 100644 --- a/src/translator/number/number.c +++ b/src/translator/number/number.c @@ -12,7 +12,7 @@ #include size_t translate_parsed_number(Translated *translated, char *number_str, size_t to_register) { - size_t length = strlen(number_str); + size_t length = strlen(number_str)+1; size_t number_pos = arena_push(&translated->constants, number_str, length); set_registers(translated, to_register+1); diff --git a/testing.ar b/testing.ar index 9ab5a46..e69de29 100644 --- a/testing.ar +++ b/testing.ar @@ -1,3 +0,0 @@ -let x = "hello" -if (x) term.log('bruh') -else term.log('not bruh') \ No newline at end of file