add dictionaries

This commit is contained in:
William Bell
2025-10-22 19:53:19 +01:00
parent b6714b390a
commit dd3b3b936d
15 changed files with 380 additions and 94 deletions

View File

@@ -35,7 +35,8 @@ typedef enum {
__number__,
field_length,
__getattribute__,
__set_attr__,
__setattr__,
__setitem__,
__hash__,
__repr__,

View File

@@ -84,12 +84,22 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
return (ParsedValueReturn){err, NULL};
}
(*index)++;
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(assign_to);
free(assign_to);
return (ParsedValueReturn){err, NULL};
}
token = darray_get(tokens, *index);
ParsedValueReturn from = parse_token(file, tokens, index, true);
if (from.err.exists) {
free_parsed(assign_to);
free(assign_to);
return from;
}
if (!from.value) {
free_parsed(assign_to);
free(assign_to);
return (ParsedValueReturn){create_err(token->line, token->column,
token->length, file, "Syntax Error",
"expected body"),
@@ -110,12 +120,6 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_ASSIGN;
parsedValue->data = assign;
ArErr err = error_if_finished(file, tokens, index);
if (err.exists) {
free_parsed(parsedValue);
free(parsedValue);
return (ParsedValueReturn){err, NULL};
}
assign->from = from.value;
return (ParsedValueReturn){no_err, parsedValue};
}

View File

@@ -47,6 +47,7 @@ ParsedValueReturn parse_parentheses(char *file, DArray *tokens, size_t *index) {
"Syntax Error", "expected comma"),
NULL};
}
(*index)++;
skip_newlines_and_indents(tokens, index);
err = error_if_finished(file, tokens, index);
if (err.exists) {

View File

@@ -132,36 +132,58 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
new_string_object(key.data, key.length, 0, hash), value,
0);
}
StackFrame new_stackFrame = {
{object->value.argon_fn->translated.registerCount,
object->value.argon_fn->translated.registerAssignment,
NULL,
{object->value.argon_fn->bytecode, sizeof(uint8_t),
object->value.argon_fn->bytecode_length,
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 *)),
0,
object->value.argon_fn->translated.path,
NULL,
state->currentStackFramePointer,
{},
{}},
scope,
*state->currentStackFramePointer,
(*state->currentStackFramePointer)->depth + 1};
for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) {
new_stackFrame.state.registers[i] = NULL;
}
if (CStackFrame) {
StackFrame new_stackFrame = {
{object->value.argon_fn->translated.registerCount,
object->value.argon_fn->translated.registerAssignment,
NULL,
{object->value.argon_fn->bytecode, sizeof(uint8_t),
object->value.argon_fn->bytecode_length,
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 *)),
0,
object->value.argon_fn->translated.path,
NULL,
state->currentStackFramePointer,
{},
{}},
scope,
*state->currentStackFramePointer,
(*state->currentStackFramePointer)->depth + 1};
for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) {
new_stackFrame.state.registers[i] = NULL;
}
runtime(new_stackFrame.translated, new_stackFrame.state,
new_stackFrame.stack, err);
state->registers[0] = new_stackFrame.state.registers[0];
} else {
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame));
*currentStackFrame = new_stackFrame;
*currentStackFrame = (StackFrame){
{object->value.argon_fn->translated.registerCount,
object->value.argon_fn->translated.registerAssignment,
NULL,
{object->value.argon_fn->bytecode, sizeof(uint8_t),
object->value.argon_fn->bytecode_length,
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 *)),
0,
object->value.argon_fn->translated.path,
NULL,
state->currentStackFramePointer,
{},
{}},
scope,
*state->currentStackFramePointer,
(*state->currentStackFramePointer)->depth + 1};
for (size_t i = 0; i < (*currentStackFrame).translated.registerCount; i++) {
(*currentStackFrame).state.registers[i] = NULL;
}
*state->currentStackFramePointer = currentStackFrame;
if ((*state->currentStackFramePointer)->depth >= 10000) {
double logval =

View File

@@ -146,14 +146,36 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___get_attr__(size_t argc,
}
ArgonObject *create_ARGON_DICTIONARY_TYPE___set_attr__(size_t argc,
ArgonObject *create_ARGON_DICTIONARY_TYPE___setattr__(size_t argc,
ArgonObject **argv,
ArErr *err,
RuntimeState *state) {
(void)state;
if (argc != 3) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__set_attr__ expects 2 argument, got %" PRIu64, argc);
"__setattr__ expects 2 argument, got %" PRIu64, argc);
return ARGON_NULL;
}
ArgonObject *object = argv[0];
ArgonObject *key = argv[1];
ArgonObject *value = argv[2];
int64_t hash = hash_object(key, err, state);
if (err->exists) {
return ARGON_NULL;
}
hashmap_insert_GC(object->value.as_hashmap, hash, key, value, 0);
return value;
}
ArgonObject *create_ARGON_DICTIONARY_TYPE___setitem__(size_t argc,
ArgonObject **argv,
ArErr *err,
RuntimeState *state) {
(void)state;
if (argc != 3) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__setitem__ expects 2 argument, got %" PRIu64, argc);
return ARGON_NULL;
}
ArgonObject *object = argv[0];
@@ -179,9 +201,13 @@ void create_ARGON_DICTIONARY_TYPE() {
create_argon_native_function("__get_attr__",
create_ARGON_DICTIONARY_TYPE___get_attr__));
add_builtin_field(
ARGON_DICTIONARY_TYPE, __set_attr__,
create_argon_native_function("__set_attr__",
create_ARGON_DICTIONARY_TYPE___set_attr__));
ARGON_DICTIONARY_TYPE, __setattr__,
create_argon_native_function("__setattr__",
create_ARGON_DICTIONARY_TYPE___setattr__));
add_builtin_field(
ARGON_DICTIONARY_TYPE, __setitem__,
create_argon_native_function("__setitem__",
create_ARGON_DICTIONARY_TYPE___setitem__));
add_builtin_field(ARGON_DICTIONARY_TYPE, __string__,
create_argon_native_function(
"__string__", create_ARGON_DICTIONARY_TYPE___string__));

View File

@@ -11,6 +11,7 @@
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
ArgonObject *ARGON_NUMBER_TYPE;
@@ -268,6 +269,64 @@ ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
}
}
static inline uint64_t mix64(uint64_t x) {
x ^= x >> 33;
x *= 0xff51afd7ed558ccdULL;
x ^= x >> 33;
x *= 0xc4ceb9fe1a85ec53ULL;
x ^= x >> 33;
return x;
}
uint64_t hash_mpz(const mpz_t z) {
// Export to raw bytes (big-endian for consistency)
size_t count;
unsigned char *data = mpz_export(NULL, &count, 1, 1, 1, 0, z);
// FNV-1a over bytes
uint64_t h = 1469598103934665603ULL;
for (size_t i = 0; i < count; i++) {
h ^= data[i];
h *= 1099511628211ULL;
}
// Include sign bit
if (mpz_sgn(z) < 0)
h = ~h;
// Free the temporary buffer allocated by mpz_export
free(data);
return mix64(h);
}
uint64_t hash_mpq(mpq_t q) {
uint64_t h_num = hash_mpz(mpq_numref(q));
uint64_t h_den = hash_mpz(mpq_denref(q));
// Combine using a standard 64-bit hash mix (boost-style)
uint64_t h = h_num ^ (h_den + 0x9e3779b97f4a7c15ULL + (h_num << 6) + (h_num >> 2));
return mix64(h);
}
ArgonObject *ARGON_NUMBER_TYPE___hash__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
if (argc != 1) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__hash__ expects 1 arguments, got %" PRIu64, argc);
}
uint64_t hash;
if (argv[0]->value.as_number->is_int64) {
hash = mix64(argv[0]->value.as_number->n.i64);
} else {
hash = hash_mpq(*argv[0]->value.as_number->n.mpq);
}
return new_number_object_from_int64(hash);
}
ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) {
(void)state;
@@ -497,7 +556,6 @@ void init_small_ints() {
for (int64_t i = 0; i <= small_ints_max - small_ints_min; i++) {
int64_t n = i + small_ints_min;
small_ints[i].type = TYPE_NUMBER;
small_ints[i].built_in_slot_length = 0;
small_ints[i].dict = NULL;
small_ints[i].value.as_number = &small_ints_as_number[i];
add_builtin_field(&small_ints[i], __class__, ARGON_NUMBER_TYPE);
@@ -520,6 +578,9 @@ void create_ARGON_NUMBER_TYPE() {
add_builtin_field(
ARGON_NUMBER_TYPE, __number__,
create_argon_native_function("__number__", ARGON_NUMBER_TYPE___number__));
add_builtin_field(
ARGON_NUMBER_TYPE, __hash__,
create_argon_native_function("__hash__", ARGON_NUMBER_TYPE___hash__));
add_builtin_field(ARGON_NUMBER_TYPE, __boolean__,
create_argon_native_function(
"__boolean__", ARGON_NUMBER_TYPE___boolean__));

View File

@@ -41,7 +41,7 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
"__string__",
"__subtract__",
"__multiply__",
"__divide__",
"__divide__",
"__new__",
"__init__",
"__boolean__",
@@ -51,7 +51,8 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
"__number__",
"length",
"__getattribute__",
"__set_attr__",
"__setattr__",
"__setitem__",
"__hash__",
"__repr__"};
@@ -77,9 +78,7 @@ int64_t hash_object(ArgonObject *object, ArErr *err, RuntimeState *state) {
ArgonObject *hash_function = get_builtin_field_for_class(
get_builtin_field(object, __class__), __hash__, object);
if (!hash_function) {
*err = create_err(err->line, err->column, err->length, err->path,
"Hash Error", "objects class has no __hash__ method");
return 0;
return (int64_t)object;
}
ArgonObject *hash_result = argon_call(hash_function, 0, NULL, err, state);
if (hash_result->type != TYPE_NUMBER ||

View File

@@ -285,12 +285,12 @@ ArgonObject *BASE_CLASS___init__(size_t argc, ArgonObject **argv, ArErr *err,
return ARGON_NULL;
}
ArgonObject *BASE_CLASS___set_attr__(size_t argc, ArgonObject **argv, ArErr *err,
ArgonObject *BASE_CLASS___setattr__(size_t argc, ArgonObject **argv, ArErr *err,
RuntimeState *state) {
(void)state;
if (argc != 3) {
*err = create_err(0, 0, 0, "", "Runtime Error",
"__set_attr__ expects 3 argument, got %" PRIu64, argc);
"__setattr__ expects 3 argument, got %" PRIu64, argc);
}
if (!argv[1]->value.as_str->hash)
argv[1]->value.as_str->hash =
@@ -691,13 +691,14 @@ void bootstrap_types() {
create_argon_native_function("__getattribute__",
BASE_CLASS___getattribute__));
add_builtin_field(
BASE_CLASS, __set_attr__,
create_argon_native_function("__set_attr__", BASE_CLASS___set_attr__));
BASE_CLASS, __setattr__,
create_argon_native_function("__setattr__", BASE_CLASS___setattr__));
create_ARGON_DICTIONARY_TYPE();
create_ARGON_NUMBER_TYPE();
}
void add_to_hashmap(struct hashmap_GC *hashmap, char *name, ArgonObject *value) {
void add_to_hashmap(struct hashmap_GC *hashmap, char *name,
ArgonObject *value) {
size_t length = strlen(name);
uint64_t hash = siphash64_bytes(name, length, siphash_key);
ArgonObject *key = new_string_object(name, length, 0, hash);
@@ -719,51 +720,53 @@ void bootstrap_globals() {
struct hashmap_GC *argon_term = createHashmap_GC();
add_to_hashmap(argon_term, "log",
create_argon_native_function("log", term_log));
create_argon_native_function("log", term_log));
add_to_scope(Global_Scope, "term", create_dictionary(argon_term));
struct hashmap_GC *environment_variables = createHashmap_GC();
#if defined(_WIN32)
// Windows: use WinAPI
LPCH env = GetEnvironmentStringsA();
if (!env) return;
#if defined(_WIN32)
// Windows: use WinAPI
LPCH env = GetEnvironmentStringsA();
if (!env)
return;
for (LPCH var = env; *var; var += strlen(var) + 1) {
// Each string is like "KEY=VALUE"
const char *equals = strchr(var, '=');
if (equals) {
size_t key_len = equals - var;
char key[256];
if (key_len >= sizeof(key))
key_len = sizeof(key) - 1;
strncpy(key, var, key_len);
key[key_len] = '\0';
for (LPCH var = env; *var; var += strlen(var) + 1) {
// Each string is like "KEY=VALUE"
const char *equals = strchr(var, '=');
if (equals) {
size_t key_len = equals - var;
char key[256];
if (key_len >= sizeof(key))
key_len = sizeof(key) - 1;
strncpy(key, var, key_len);
key[key_len] = '\0';
const char *value = getenv(key);
add_to_hashmap(environment_variables, key,
value?new_string_object_null_terminated((char *)value):ARGON_NULL);
}
const char *value = getenv(key);
add_to_hashmap(environment_variables, key,
value ? new_string_object_null_terminated((char *)value)
: ARGON_NULL);
}
}
FreeEnvironmentStringsA(env);
FreeEnvironmentStringsA(env);
#else
// POSIX systems: use environ
for (char **env = environ; *env != NULL; env++) {
const char *equals = strchr(*env, '=');
if (equals) {
size_t key_len = equals - *env;
char key[256];
if (key_len >= sizeof(key))
key_len = sizeof(key) - 1;
strncpy(key, *env, key_len);
key[key_len] = '\0';
// POSIX systems: use environ
for (char **env = environ; *env != NULL; env++) {
const char *equals = strchr(*env, '=');
if (equals) {
size_t key_len = equals - *env;
char key[256];
if (key_len >= sizeof(key))
key_len = sizeof(key) - 1;
strncpy(key, *env, key_len);
key[key_len] = '\0';
const char *value = getenv(key);
add_to_hashmap(environment_variables, key,
value?new_string_object_null_terminated((char *)value):ARGON_NULL);
}
const char *value = getenv(key);
add_to_hashmap(environment_variables, key,
value ? new_string_object_null_terminated((char *)value)
: ARGON_NULL);
}
}
#endif
add_to_scope(Global_Scope, "env", create_dictionary(environment_variables));
@@ -885,7 +888,9 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack,
[OP_MULTIPLICATION] = &&DO_MULTIPLICATION,
[OP_DIVISION] = &&DO_DIVISION,
[OP_NOT] = &&DO_NOT,
[OP_LOAD_SETATTR_METHOD] = &&DO_LOAD_SETATTR_METHOD};
[OP_LOAD_SETATTR_METHOD] = &&DO_LOAD_SETATTR_METHOD,
[OP_CREATE_DICTIONARY] = &&DO_CREATE_DICTIONARY,
[OP_LOAD_SETITEM_METHOD] = &&DO_LOAD_SETITEM_METHOD};
_state.head = 0;
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame));
@@ -1257,13 +1262,29 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack,
}
DO_LOAD_SETATTR_METHOD: {
state->registers[0] = get_builtin_field_for_class(
get_builtin_field(state->registers[0], __class__), __set_attr__,
get_builtin_field(state->registers[0], __class__), __setattr__,
state->registers[0]);
if (!state->registers[0]) {
*err = create_err(
state->source_location.line, state->source_location.column,
state->source_location.length, state->path, "Runtime Error",
"unable to get __set_attr__ from objects class");
"unable to get __setattr__ from objects class");
}
continue;
}
DO_CREATE_DICTIONARY: {
state->registers[0] = create_dictionary(createHashmap_GC());
continue;
}
DO_LOAD_SETITEM_METHOD: {
state->registers[0] = get_builtin_field_for_class(
get_builtin_field(state->registers[0], __class__), __setitem__,
state->registers[0]);
if (!state->registers[0]) {
*err = create_err(
state->source_location.line, state->source_location.column,
state->source_location.length, state->path, "Runtime Error",
"unable to get __setitem__ from objects class");
}
continue;
}

View File

@@ -122,11 +122,11 @@ sets the source location onto the runtime
## OP_LOAD_GETATTRIBUTE_METHOD
loads the \_\_getattribute\_\_ method from the objects class in register 1 and put it into register 1
loads the \_\_getattribute\_\_ method from the objects class in register 0 and put it into register 0
## OP_LOAD_BOOL
loads a boolean into register 1
loads a boolean into register 0
1. byte representing true or false (1 or 0) *
@@ -187,4 +187,12 @@ inverts the boolean value in register 0.
## OP_LOAD_SETATTR_METHOD
loads the \_\_setattr\_\_ method from the objects class in register 1 and put it into register 1
loads the \_\_setattr\_\_ method from the objects class in register 0 and put it into register 0
## OP_CREATE_DICTIONARY
create a dictionary object into register 0.
## OP_LOAD_SETITEM_METHOD
loads the \_\_setitem\_\_ method from the objects class in register 0 and put it into register 0

View File

@@ -6,6 +6,7 @@
#include "translator.h"
#include "../hash_data/hash_data.h"
#include "../parser/dictionary/dictionary.h"
#include "../parser/not/not.h"
#include "access/access.h"
#include "assignment/assignment.h"
@@ -176,6 +177,66 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue,
push_instruction_byte(translated, OP_NOT);
return first;
}
case AST_DICTIONARY: {
DArray *dictionaryDarray = parsedValue->data;
size_t first = push_instruction_byte(translated, OP_CREATE_DICTIONARY);
uint8_t dictionaryRegister = translated->registerAssignment++;
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
push_instruction_byte(translated, 0);
push_instruction_byte(translated, dictionaryRegister);
push_instruction_byte(translated, OP_LOAD_SETITEM_METHOD);
uint8_t setitemRegister = translated->registerAssignment++;
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
push_instruction_byte(translated, 0);
push_instruction_byte(translated, setitemRegister);
for (size_t i = 0; i < dictionaryDarray->size; i++) {
ParsedDictionaryEntry *entry = darray_get(dictionaryDarray, i);
if (i != 0) {
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
push_instruction_byte(translated, setitemRegister);
push_instruction_byte(translated, 0);
}
push_instruction_byte(translated, OP_INIT_CALL);
push_instruction_code(translated, 2);
translate_parsed(translated, entry->key, err);
if (err->exists)
return first;
push_instruction_byte(translated, OP_INSERT_ARG);
push_instruction_code(translated, 0);
translate_parsed(translated, entry->value, err);
if (err->exists)
return first;
push_instruction_byte(translated, OP_INSERT_ARG);
push_instruction_code(translated, 1);
push_instruction_byte(translated, OP_CALL);
}
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
push_instruction_byte(translated, dictionaryRegister);
push_instruction_byte(translated, 0);
push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_byte(translated, dictionaryRegister);
push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_byte(translated, setitemRegister);
translated->registerAssignment-=2;
return first;
}
default:
fprintf(stderr, "panic: undefined translation\n");
exit(EXIT_FAILURE);
}
return 0;
}

View File

@@ -40,7 +40,9 @@ typedef enum {
OP_MULTIPLICATION,
OP_DIVISION,
OP_NOT,
OP_LOAD_SETATTR_METHOD
OP_LOAD_SETATTR_METHOD,
OP_CREATE_DICTIONARY,
OP_LOAD_SETITEM_METHOD
} OperationType;
void arena_resize(ConstantArena *arena, size_t new_size);