diff --git a/src/arobject.h b/src/arobject.h index 59b4f67..07aab60 100644 --- a/src/arobject.h +++ b/src/arobject.h @@ -16,7 +16,11 @@ typedef enum { __base__, __class__, __name__, + __binding__, + __function__, + BUILT_IN_ARRAY_COUNT, + __add__, __string__, __subtract__, @@ -26,14 +30,13 @@ typedef enum { __init__, __boolean__, __get_attr__, - __binding__, - __function__, field__address, __call__, __number__, field_log, field_length, __getattribute__, + __setattr__, __hash__, __repr__, @@ -121,8 +124,8 @@ struct ArgonObject { struct built_in_slot built_in_slot[BUILT_IN_ARRAY_COUNT]; union { struct as_number *as_number; - struct hashmap_GC* as_hashmap; - struct string_struct* as_str; + struct hashmap_GC *as_hashmap; + struct string_struct *as_str; native_fn native_fn; struct argon_function_struct *argon_fn; } value; diff --git a/src/parser/assignable/access/access.c b/src/parser/assignable/access/access.c index 629bf9b..b6d2dbb 100644 --- a/src/parser/assignable/access/access.c +++ b/src/parser/assignable/access/access.c @@ -18,13 +18,11 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index, Token *first_token = darray_get(tokens, *index); (*index)++; ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); - ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); - parsedAccess->to_access = *to_access; - parsedValue->type = AST_ACCESS; - parsedValue->data = parsedAccess; - free(to_access); - darray_init(&parsedAccess->access, sizeof(ParsedValue)); if (first_token->type == TOKEN_DOT) { + ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); + parsedAccess->to_access = to_access; + parsedValue->type = AST_ACCESS; + parsedValue->data = parsedAccess; ArErr err = error_if_finished(file, tokens, index); if (err.exists) { free_parsed(parsedValue); @@ -41,59 +39,7 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index, free(parsedValue); return parsedString; } - darray_push(&parsedAccess->access, parsedString.value); - free(parsedString.value); - parsedAccess->access_fields = true; - } else { - parsedAccess->line = first_token->line; - parsedAccess->column = first_token->column; - parsedAccess->length = first_token->length; - parsedAccess->access_fields = false; - Token *token = first_token; - while (true) { - skip_newlines_and_indents(tokens, index); - ArErr err = error_if_finished(file, tokens, index); - if (err.exists) { - free_parsed(parsedValue); - free(parsedValue); - return (ParsedValueReturn){err, NULL}; - } - ParsedValueReturn parsedAccessValue = - parse_token(file, tokens, index, true); - if (parsedAccessValue.err.exists) { - free_parsed(parsedValue); - free(parsedValue); - return parsedAccessValue; - } else if (!parsedAccessValue.value) { - free_parsed(parsedValue); - free(parsedValue); - return (ParsedValueReturn){create_err(token->line, token->column, - token->length, file, - "Syntax Error", "expected value"), - NULL}; - } - darray_push(&parsedAccess->access, parsedAccessValue.value); - free(parsedAccessValue.value); - skip_newlines_and_indents(tokens, index); - err = error_if_finished(file, tokens, index); - if (err.exists) { - free_parsed(parsedValue); - free(parsedValue); - return (ParsedValueReturn){err, NULL}; - } - token = darray_get(tokens, *index); - if (token->type == TOKEN_RBRACKET) { - break; - } else if (token->type != TOKEN_COLON) { - free_parsed(parsedValue); - free(parsedValue); - return (ParsedValueReturn){create_err(token->line, token->column, - token->length, file, - "Syntax Error", "expected colon"), - NULL}; - } - (*index)++; - } + parsedAccess->access = parsedString.value; } (*index)++; return (ParsedValueReturn){no_err, parsedValue}; @@ -102,7 +48,9 @@ ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index, void free_parse_access(void *ptr) { ParsedValue *parsedValue = ptr; ParsedAccess *parsedAccess = parsedValue->data; - free_parsed(&parsedAccess->to_access); - darray_free(&parsedAccess->access, free_parsed); + free_parsed(parsedAccess->to_access); + free(parsedAccess->to_access); + free_parsed(parsedAccess->access); + free(parsedAccess->access); free(parsedAccess); } \ No newline at end of file diff --git a/src/parser/assignable/access/access.h b/src/parser/assignable/access/access.h index 5d2cef6..5dff201 100644 --- a/src/parser/assignable/access/access.h +++ b/src/parser/assignable/access/access.h @@ -10,9 +10,8 @@ #include "../../../lexer/token.h" // for Token typedef struct { - ParsedValue to_access; - bool access_fields; - DArray access; + ParsedValue *to_access; + ParsedValue *access; size_t line; size_t column; size_t length; diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index 341ec45..f58c871 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -52,6 +52,7 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = { "log", "length", "__getattribute__", + "__setattr__", "__hash__", "__repr__"}; diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 59fcc5a..8d39d4f 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -46,47 +46,44 @@ ArgonObject *FLOORDIVISION_FUNCTION; ArgonObject *BASE_CLASS___getattribute__(size_t argc, ArgonObject **argv, ArErr *err, RuntimeState *state) { (void)state; - if (argc != 3) { - *err = create_err(0, 0, 0, "", "Runtime Error", - "__getattribute__ expects 3 arguments, got %" PRIu64); + if (argc != 2) { + *err = + create_err(0, 0, 0, "", "Runtime Error", + "__getattribute__ expects 2 arguments, got %" PRIu64, argc); return ARGON_NULL; } ArgonObject *to_access = argv[0]; - bool check_field = argv[1] == ARGON_TRUE; - if (check_field) { - ArgonObject *access = argv[2]; - uint64_t hash; - if (access->value.as_str->hash_computed) { - hash = access->value.as_str->hash; - } else { - hash = - runtime_hash(access->value.as_str->data, access->value.as_str->length, - access->value.as_str->prehash); - access->value.as_str->hash = hash; - access->value.as_str->hash_computed = true; - } - ArgonObject *value = - get_field_l(to_access, access->value.as_str->data, hash, - access->value.as_str->length, true, false); - if (value) - return value; - ArgonObject *cls__get_attr__ = get_builtin_field_for_class( - get_builtin_field(to_access, __class__), __get_attr__, to_access); - if (cls__get_attr__) { - value = - argon_call(cls__get_attr__, 1, (ArgonObject *[]){access}, err, state); - if (err->exists) { - return ARGON_NULL; - } - return value; - } - ArgonObject *name = get_builtin_field_for_class( - get_builtin_field(to_access, __class__), __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 *access = argv[1]; + uint64_t hash; + if (access->value.as_str->hash_computed) { + hash = access->value.as_str->hash; + } else { + hash = + runtime_hash(access->value.as_str->data, access->value.as_str->length, + access->value.as_str->prehash); + access->value.as_str->hash = hash; + access->value.as_str->hash_computed = true; } + ArgonObject *value = get_field_l(to_access, access->value.as_str->data, hash, + access->value.as_str->length, true, false); + if (value) + return value; + ArgonObject *cls__get_attr__ = get_builtin_field_for_class( + get_builtin_field(to_access, __class__), __get_attr__, to_access); + if (cls__get_attr__) { + value = + argon_call(cls__get_attr__, 1, (ArgonObject *[]){access}, err, state); + if (err->exists) { + return ARGON_NULL; + } + return value; + } + ArgonObject *name = get_builtin_field_for_class( + get_builtin_field(to_access, __class__), __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; } @@ -310,9 +307,8 @@ ArgonObject *BASE_CLASS___string__(size_t argc, ArgonObject **argv, ArErr *err, return new_string_object_null_terminated(buffer); } - -ArgonObject *BASE_CLASS___repr__(size_t argc, ArgonObject **argv, - ArErr *err, RuntimeState *state) { +ArgonObject *BASE_CLASS___repr__(size_t argc, ArgonObject **argv, ArErr *err, + RuntimeState *state) { if (argc != 1) { *err = create_err(0, 0, 0, "", "Runtime Error", "__repr__ expects 1 arguments, got %" PRIu64, argc); @@ -447,14 +443,15 @@ ArgonObject *ARGON_STRING_TYPE___string__(size_t argc, ArgonObject **argv, return argv[0]; } ArgonObject *ARGON_STRING_TYPE___repr__(size_t argc, ArgonObject **argv, - ArErr *err, RuntimeState *state) { + ArErr *err, RuntimeState *state) { (void)state; if (argc != 1) { *err = create_err(0, 0, 0, "", "Runtime Error", "__repr__ expects 1 arguments, got %" PRIu64, argc); } - char* quoted = c_quote_string(argv[0]->value.as_str->data,argv[0]->value.as_str->length); - ArgonObject* result = new_string_object_null_terminated(quoted); + char *quoted = c_quote_string(argv[0]->value.as_str->data, + argv[0]->value.as_str->length); + ArgonObject *result = new_string_object_null_terminated(quoted); free(quoted); return result; } @@ -810,10 +807,11 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, [OP_COPY_TO_REGISTER] = &&DO_COPY_TO_REGISTER, [OP_ADDITION] = &&DO_ADDITION, [OP_SUBTRACTION] = &&DO_SUBTRACTION, - [OP_LOAD_GETATTRIBUTE_FUNCTION] = &&DO_LOAD_GETATTRIBUTE_FUNCTION, + [OP_LOAD_GETATTRIBUTE_METHOD] = &&DO_LOAD_GETATTRIBUTE_METHOD, [OP_MULTIPLICATION] = &&DO_MULTIPLICATION, [OP_DIVISION] = &&DO_DIVISION, - [OP_NOT] = &&DO_NOT}; + [OP_NOT] = &&DO_NOT, + [OP_LOAD_SETATTR_METHOD] = &&DO_LOAD_SETATTR_METHOD}; _state.head = 0; StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame)); @@ -917,7 +915,7 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, state->registers[0] = pop_byte(translated, state) ? ARGON_TRUE : ARGON_FALSE; continue; - DO_LOAD_GETATTRIBUTE_FUNCTION: + DO_LOAD_GETATTRIBUTE_METHOD: state->registers[0] = get_builtin_field_for_class( get_builtin_field(state->registers[0], __class__), __getattribute__, state->registers[0]); @@ -1177,6 +1175,18 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, ARGON_DIVISION_FUNCTION(2, args, err, state); continue; } + DO_LOAD_SETATTR_METHOD: { + state->registers[0] = get_builtin_field_for_class( + 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 __setattr__ from objects class"); + } + continue; + } } ArgonObject *result = currentStackFrame->state.registers[0]; diff --git a/src/translator/access/access.c b/src/translator/access/access.c index ddf7ed6..993f39d 100644 --- a/src/translator/access/access.c +++ b/src/translator/access/access.c @@ -8,25 +8,19 @@ size_t translate_access(Translated *translated, ParsedAccess *access, ArErr *err) { set_registers(translated, 1); - uint64_t first = translate_parsed(translated, &access->to_access, err); + uint64_t first = translate_parsed(translated, access->to_access, err); if (err->exists) return 0; - push_instruction_byte(translated, OP_LOAD_GETATTRIBUTE_FUNCTION); + push_instruction_byte(translated, OP_LOAD_GETATTRIBUTE_METHOD); push_instruction_byte(translated, OP_INIT_CALL); - push_instruction_code(translated, access->access.size+1); - push_instruction_byte(translated, OP_LOAD_BOOL); - push_instruction_byte(translated, access->access_fields); + push_instruction_code(translated, 1); + + translate_parsed(translated, access->access, err); + if (err->exists) + return 0; push_instruction_byte(translated, OP_INSERT_ARG); push_instruction_code(translated, 0); - for (size_t i = 0; i < access->access.size; i++) { - translate_parsed(translated, darray_get(&access->access, i), err); - if (err->exists) - return 0; - push_instruction_byte(translated, OP_INSERT_ARG); - push_instruction_code(translated, 1 + 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/assignment/assignment.c b/src/translator/assignment/assignment.c index 4a73dc0..1833893 100644 --- a/src/translator/assignment/assignment.c +++ b/src/translator/assignment/assignment.c @@ -7,6 +7,7 @@ #include "assignment.h" #include "../../hash_data/hash_data.h" #include "../../parser/assignable/identifier/identifier.h" +#include "../../parser/assignable/access/access.h" #include "../translator.h" #include #include @@ -41,6 +42,9 @@ size_t translate_parsed_assignment(Translated *translated, siphash_key_fixed_for_translator)); push_instruction_byte(translated, 0); break; + case AST_ACCESS:; + ParsedAccess *access = assignment->to->data; + break; default: fprintf(stderr, "panic: unsupported assignment\n"); exit(EXIT_FAILURE); diff --git a/src/translator/bytecode_spec.md b/src/translator/bytecode_spec.md index f0b9b91..9fda22d 100644 --- a/src/translator/bytecode_spec.md +++ b/src/translator/bytecode_spec.md @@ -120,9 +120,9 @@ sets the source location onto the runtime 1. the column 1. the length -## OP_LOAD_GETATTRIBUTE_FUNCTION +## OP_LOAD_GETATTRIBUTE_METHOD -loads the \_\_getattribute\_\_ function from the objects class in register 1 and put it into register 1 +loads the \_\_getattribute\_\_ method from the objects class in register 1 and put it into register 1 ## OP_LOAD_BOOL @@ -183,4 +183,8 @@ performs an division between register A and register B, storing the result in re ## OP_NOT -inverts the boolean value in register 0. \ No newline at end of file +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 \ No newline at end of file diff --git a/src/translator/translator.h b/src/translator/translator.h index 4062f90..cdf41fe 100644 --- a/src/translator/translator.h +++ b/src/translator/translator.h @@ -36,10 +36,11 @@ typedef enum { OP_COPY_TO_REGISTER, OP_ADDITION, OP_SUBTRACTION, - OP_LOAD_GETATTRIBUTE_FUNCTION, + OP_LOAD_GETATTRIBUTE_METHOD, OP_MULTIPLICATION, OP_DIVISION, - OP_NOT + OP_NOT, + OP_LOAD_SETATTR_METHOD } OperationType; void arena_resize(ConstantArena *arena, size_t new_size); diff --git a/tests/iteration-test.py b/tests/iteration-test.py index c9f7919..5399247 100644 --- a/tests/iteration-test.py +++ b/tests/iteration-test.py @@ -1,4 +1,3 @@ i = 1000000 while i: - print(i) i=i-1 \ No newline at end of file