add item access
This commit is contained in:
@@ -29,13 +29,14 @@ typedef enum {
|
||||
__new__,
|
||||
__init__,
|
||||
__boolean__,
|
||||
__get_attr__,
|
||||
__getattr__,
|
||||
field__address,
|
||||
__call__,
|
||||
__number__,
|
||||
field_length,
|
||||
__getattribute__,
|
||||
__setattr__,
|
||||
__getitem__,
|
||||
__setitem__,
|
||||
__hash__,
|
||||
__repr__,
|
||||
|
||||
45
src/import.c
45
src/import.c
@@ -43,6 +43,15 @@ static inline uint64_t htole64(uint64_t x) { return x; }
|
||||
#elif defined(__linux__)
|
||||
#include <endian.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int is_regular_file(const char *path) {
|
||||
struct stat path_stat;
|
||||
stat(path, &path_stat);
|
||||
return S_ISREG(path_stat.st_mode);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define htole32(x) OSSwapHostToLittleInt32(x)
|
||||
@@ -93,11 +102,11 @@ const uint32_t version_number = 0;
|
||||
const char version_string[] = "4.0.0";
|
||||
|
||||
bool file_exists(const char *path) {
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0) {
|
||||
return S_ISREG(st.st_mode); // true only if it's a regular file
|
||||
}
|
||||
return false; // doesn't exist, or stat failed
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0) {
|
||||
return S_ISREG(st.st_mode); // true only if it's a regular file
|
||||
}
|
||||
return false; // doesn't exist, or stat failed
|
||||
}
|
||||
|
||||
static inline void write_and_hash(FILE *file, XXH64_state_t *state,
|
||||
@@ -285,7 +294,6 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
sizeof(cache_file_path));
|
||||
cwk_path_change_extension(cache_file_path, BYTECODE_EXTENTION,
|
||||
cache_file_path, sizeof(cache_file_path));
|
||||
|
||||
FILE *file = fopen(path, "r");
|
||||
if (!file) {
|
||||
*err = create_err(0, 0, 0, NULL, "File Error", "Unable to open file '%s'",
|
||||
@@ -400,7 +408,8 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
Translated gc_translated = {
|
||||
translated.registerCount, translated.registerAssignment, NULL, {}, {},
|
||||
translated.path};
|
||||
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity+translated.constants.capacity);
|
||||
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity +
|
||||
translated.constants.capacity);
|
||||
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
|
||||
translated.bytecode.capacity);
|
||||
gc_translated.bytecode.element_size = translated.bytecode.element_size;
|
||||
@@ -408,7 +417,8 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
gc_translated.bytecode.resizable = false;
|
||||
gc_translated.bytecode.capacity =
|
||||
translated.bytecode.size * translated.bytecode.element_size;
|
||||
gc_translated.constants.data = gc_translated.bytecode.data+translated.bytecode.capacity;
|
||||
gc_translated.constants.data =
|
||||
gc_translated.bytecode.data + translated.bytecode.capacity;
|
||||
memcpy(gc_translated.constants.data, translated.constants.data,
|
||||
translated.constants.capacity);
|
||||
gc_translated.constants.size = translated.constants.size;
|
||||
@@ -422,8 +432,8 @@ Translated load_argon_file(char *path, ArErr *err) {
|
||||
}
|
||||
|
||||
const char *PRE_PATHS_TO_TEST[] = {"", "", "argon_modules", "argon_modules"};
|
||||
const char *POST_PATHS_TO_TEST[sizeof(PRE_PATHS_TO_TEST)/sizeof(char *)] = {"", "init.ar", "",
|
||||
"init.ar"};
|
||||
const char *POST_PATHS_TO_TEST[sizeof(PRE_PATHS_TO_TEST) / sizeof(char *)] = {
|
||||
"", "init.ar", "", "init.ar"};
|
||||
|
||||
struct hashmap *importing_hash_table = NULL;
|
||||
struct hashmap_GC *imported_hash_table = NULL;
|
||||
@@ -431,8 +441,9 @@ struct hashmap_GC *imported_hash_table = NULL;
|
||||
Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
|
||||
char path[FILENAME_MAX];
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < sizeof(PRE_PATHS_TO_TEST)/sizeof(char *); i++) {
|
||||
cwk_path_get_absolute(current_directory, PRE_PATHS_TO_TEST[i], path, sizeof(path));
|
||||
for (size_t i = 0; i < sizeof(PRE_PATHS_TO_TEST) / sizeof(char *); i++) {
|
||||
cwk_path_get_absolute(current_directory, PRE_PATHS_TO_TEST[i], path,
|
||||
sizeof(path));
|
||||
cwk_path_get_absolute(path, path_relative, path, sizeof(path));
|
||||
cwk_path_get_absolute(path, POST_PATHS_TO_TEST[i], path, sizeof(path));
|
||||
if (file_exists(path)) {
|
||||
@@ -445,9 +456,10 @@ Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
|
||||
path_relative);
|
||||
return NULL;
|
||||
}
|
||||
if (!importing_hash_table) importing_hash_table = createHashmap();
|
||||
if (!importing_hash_table)
|
||||
importing_hash_table = createHashmap();
|
||||
uint64_t hash = siphash64_bytes(path, strlen(path), siphash_key);
|
||||
hashmap_insert(importing_hash_table, hash, path, (void*)true, 0);
|
||||
hashmap_insert(importing_hash_table, hash, path, (void *)true, 0);
|
||||
Translated translated = load_argon_file(path, err);
|
||||
if (err->exists) {
|
||||
return NULL;
|
||||
@@ -462,8 +474,9 @@ Stack *ar_import(char *current_directory, char *path_relative, ArErr *err) {
|
||||
end = clock();
|
||||
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;
|
||||
fprintf(stderr, "Execution time taken: %f seconds\n", time_spent);
|
||||
hashmap_insert(importing_hash_table, hash, path, (void*)false, 0);
|
||||
if (!imported_hash_table) imported_hash_table = createHashmap_GC();
|
||||
hashmap_insert(importing_hash_table, hash, path, (void *)false, 0);
|
||||
if (!imported_hash_table)
|
||||
imported_hash_table = createHashmap_GC();
|
||||
hashmap_insert_GC(imported_hash_table, hash, path, main_scope, 0);
|
||||
return main_scope;
|
||||
}
|
||||
10
src/memory.c
10
src/memory.c
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "memory.h"
|
||||
#include <gc.h>
|
||||
#include <gc/gc.h>
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -22,6 +21,15 @@ void *checked_malloc(size_t size) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *checked_realloc(void *ptr, size_t size) {
|
||||
void *new_ptr = realloc(ptr, size);
|
||||
if (!new_ptr) {
|
||||
fprintf(stderr, "fatal error: failed to allocate %zu bytes\n", size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
struct allocation *memory_allocations = NULL;
|
||||
size_t memory_allocations_size = 0;
|
||||
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdbool.h>
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
|
||||
// GC-managed allocations
|
||||
|
||||
@@ -37,5 +37,6 @@ void ar_memory_init();
|
||||
void ar_memory_shutdown();
|
||||
|
||||
void *checked_malloc(size_t size);
|
||||
void *checked_realloc(void *ptr, size_t size);
|
||||
|
||||
#endif // ARGON_MEMORY_H
|
||||
@@ -15,41 +15,38 @@
|
||||
|
||||
ParsedValueReturn parse_access(char *file, DArray *tokens, size_t *index,
|
||||
ParsedValue *to_access) {
|
||||
Token *first_token = darray_get(tokens, *index);
|
||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||
if (first_token->type == TOKEN_DOT) {
|
||||
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
|
||||
parsedAccess->to_access = to_access;
|
||||
parsedAccess->access = NULL;
|
||||
parsedValue->type = AST_ACCESS;
|
||||
parsedValue->data = parsedAccess;
|
||||
(*index)++;
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
Token *token = darray_get(tokens, *index);
|
||||
if (token->type != TOKEN_IDENTIFIER) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||
token->length, file, "Syntax Error",
|
||||
"expected identifier after dot"),
|
||||
NULL};
|
||||
}
|
||||
parsedAccess->line = token->line;
|
||||
parsedAccess->column = token->column;
|
||||
parsedAccess->length = token->length;
|
||||
ParsedValueReturn parsedString = parse_string(token, false);
|
||||
if (parsedString.err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return parsedString;
|
||||
}
|
||||
parsedAccess->access = parsedString.value;
|
||||
ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess));
|
||||
parsedAccess->to_access = to_access;
|
||||
parsedAccess->access = NULL;
|
||||
parsedValue->type = AST_ACCESS;
|
||||
parsedValue->data = parsedAccess;
|
||||
(*index)++;
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
Token *token = darray_get(tokens, *index);
|
||||
if (token->type != TOKEN_IDENTIFIER) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||
token->length, file, "Syntax Error",
|
||||
"expected identifier after dot"),
|
||||
NULL};
|
||||
}
|
||||
parsedAccess->line = token->line;
|
||||
parsedAccess->column = token->column;
|
||||
parsedAccess->length = token->length;
|
||||
ParsedValueReturn parsedString = parse_string(token, false);
|
||||
if (parsedString.err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return parsedString;
|
||||
}
|
||||
parsedAccess->access = parsedString.value;
|
||||
(*index)++;
|
||||
return (ParsedValueReturn){no_err, parsedValue};
|
||||
}
|
||||
|
||||
80
src/parser/assignable/item/item.c
Normal file
80
src/parser/assignable/item/item.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "item.h"
|
||||
#include "../../../lexer/token.h"
|
||||
#include "../../../memory.h"
|
||||
#include "../../parser.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index,
|
||||
ParsedValue *to_access) {
|
||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||
ParsedItemAccess *parsedItemAccess = checked_malloc(sizeof(ParsedItemAccess));
|
||||
parsedItemAccess->to_access = to_access;
|
||||
size_t capacity = 4;
|
||||
parsedItemAccess->items = checked_malloc(capacity * sizeof(ParsedValue *));
|
||||
parsedItemAccess->itemc = 0;
|
||||
parsedValue->type = AST_ITEM_ACCESS;
|
||||
parsedValue->data = parsedItemAccess;
|
||||
Token *token = darray_get(tokens, *index);
|
||||
parsedItemAccess->line = token->line;
|
||||
parsedItemAccess->column = token->column;
|
||||
parsedItemAccess->length = token->length;
|
||||
(*index)++;
|
||||
while (true) {
|
||||
ArErr err = error_if_finished(file, tokens, index);
|
||||
if (err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){err, NULL};
|
||||
}
|
||||
ParsedValueReturn parsedKey = parse_token(file, tokens, index, true);
|
||||
if (parsedKey.err.exists) {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return parsedKey;
|
||||
}
|
||||
parsedItemAccess->items[parsedItemAccess->itemc++] = parsedKey.value;
|
||||
if (parsedItemAccess->itemc > capacity) {
|
||||
capacity *= 2;
|
||||
parsedItemAccess->items = checked_realloc(
|
||||
parsedItemAccess->items, capacity * sizeof(ParsedValue *));
|
||||
}
|
||||
Token *token = darray_get(tokens, *index);
|
||||
(*index)++;
|
||||
if (token->type == TOKEN_COMMA) {
|
||||
continue;
|
||||
} else if (token->type == TOKEN_RBRACKET) {
|
||||
break;
|
||||
} else {
|
||||
free_parsed(parsedValue);
|
||||
free(parsedValue);
|
||||
return (ParsedValueReturn){
|
||||
create_err(token->line, token->column, token->length, file,
|
||||
"Syntax Error",
|
||||
"expected either a comma or a closing bracket"),
|
||||
NULL};
|
||||
}
|
||||
}
|
||||
return (ParsedValueReturn){no_err, parsedValue};
|
||||
}
|
||||
|
||||
void free_parse_item_access(void *ptr) {
|
||||
ParsedValue *parsedValue = ptr;
|
||||
ParsedItemAccess *parsedItemAccess = parsedValue->data;
|
||||
free_parsed(parsedItemAccess->to_access);
|
||||
free(parsedItemAccess->to_access);
|
||||
for (size_t i = 0; i < parsedItemAccess->itemc; i++) {
|
||||
free_parsed(parsedItemAccess->items[i]);
|
||||
free(parsedItemAccess->items[i]);
|
||||
}
|
||||
free(parsedItemAccess->items);
|
||||
free(parsedItemAccess);
|
||||
}
|
||||
25
src/parser/assignable/item/item.h
Normal file
25
src/parser/assignable/item/item.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ITEM_ACCESS_H
|
||||
#define ITEM_ACCESS_H
|
||||
#include "../../parser.h"
|
||||
#include "../../../lexer/token.h" // for Token
|
||||
typedef struct {
|
||||
ParsedValue *to_access;
|
||||
ParsedValue **items;
|
||||
size_t itemc;
|
||||
size_t line;
|
||||
size_t column;
|
||||
size_t length;
|
||||
} ParsedItemAccess;
|
||||
|
||||
ParsedValueReturn parse_item_access(char *file, DArray *tokens, size_t *index,
|
||||
ParsedValue *to_access);
|
||||
|
||||
void free_parse_item_access(void *ptr);
|
||||
|
||||
#endif // ACCESS_H
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "assignable/assign/assign.h"
|
||||
#include "assignable/call/call.h"
|
||||
#include "assignable/identifier/identifier.h"
|
||||
#include "assignable/item/item.h"
|
||||
#include "declaration/declaration.h"
|
||||
#include "dictionary/dictionary.h"
|
||||
#include "dowrap/dowrap.h"
|
||||
@@ -164,9 +165,11 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
|
||||
output = parse_call(file, tokens, index, output.value);
|
||||
break;
|
||||
case TOKEN_DOT:
|
||||
case TOKEN_LBRACKET:
|
||||
output = parse_access(file, tokens, index, output.value);
|
||||
break;
|
||||
case TOKEN_LBRACKET:
|
||||
output = parse_item_access(file, tokens, index, output.value);
|
||||
break;
|
||||
SWITCH_OPERATIONS
|
||||
if (process_operations) {
|
||||
output = parse_operations(file, tokens, index, output.value);
|
||||
@@ -241,6 +244,9 @@ void free_parsed(void *ptr) {
|
||||
case AST_ACCESS:
|
||||
free_parse_access(parsed);
|
||||
break;
|
||||
case AST_ITEM_ACCESS:
|
||||
free_parse_item_access(parsed);
|
||||
break;
|
||||
case AST_NULL:
|
||||
case AST_BOOLEAN:
|
||||
break;
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef enum {
|
||||
AST_NUMBER,
|
||||
AST_IF,
|
||||
AST_ACCESS,
|
||||
AST_ITEM_ACCESS,
|
||||
AST_CALL,
|
||||
AST_DECLARATION,
|
||||
AST_NULL,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "darray_armem.h"
|
||||
#include "../../../memory.h"
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "hashmap.h"
|
||||
|
||||
#include "../../../memory.h"
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -122,14 +122,14 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc,
|
||||
return result;
|
||||
}
|
||||
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___get_attr__(size_t argc,
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___getattr__(size_t argc,
|
||||
ArgonObject **argv,
|
||||
ArErr *err,
|
||||
RuntimeState *state) {
|
||||
(void)state;
|
||||
if (argc != 2) {
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"__get_attr__ expects 2 argument, got %" PRIu64, argc);
|
||||
"__getattr__ expects 2 argument, got %" PRIu64, argc);
|
||||
return ARGON_NULL;
|
||||
}
|
||||
ArgonObject *object = argv[0];
|
||||
@@ -169,6 +169,32 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___setattr__(size_t argc,
|
||||
return value;
|
||||
}
|
||||
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___getitem__(size_t argc,
|
||||
ArgonObject **argv,
|
||||
ArErr *err,
|
||||
RuntimeState *state) {
|
||||
(void)state;
|
||||
if (argc != 2) {
|
||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||
"__getitem__ expects 2 argument, got %" PRIu64, argc);
|
||||
return ARGON_NULL;
|
||||
}
|
||||
ArgonObject *object = argv[0];
|
||||
ArgonObject *key = argv[1];
|
||||
int64_t hash = hash_object(key, err, state);
|
||||
if (err->exists) {
|
||||
return ARGON_NULL;
|
||||
}
|
||||
ArgonObject *result = hashmap_lookup_GC(object->value.as_hashmap, hash);
|
||||
if (!result) {
|
||||
char *object_str = argon_object_to_null_terminated_string(key, err, state);
|
||||
|
||||
*err = create_err(0, 0, 0, NULL, "Attribute Error",
|
||||
"Dictionary has no item '%s'", object_str);
|
||||
return ARGON_NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ArgonObject *create_ARGON_DICTIONARY_TYPE___setitem__(size_t argc,
|
||||
ArgonObject **argv,
|
||||
@@ -199,9 +225,9 @@ void create_ARGON_DICTIONARY_TYPE() {
|
||||
create_argon_native_function(
|
||||
"__init__", create_ARGON_DICTIONARY_TYPE___init__));
|
||||
add_builtin_field(
|
||||
ARGON_DICTIONARY_TYPE, __get_attr__,
|
||||
create_argon_native_function("__get_attr__",
|
||||
create_ARGON_DICTIONARY_TYPE___get_attr__));
|
||||
ARGON_DICTIONARY_TYPE, __getattr__,
|
||||
create_argon_native_function("__getattr__",
|
||||
create_ARGON_DICTIONARY_TYPE___getattr__));
|
||||
add_builtin_field(
|
||||
ARGON_DICTIONARY_TYPE, __setattr__,
|
||||
create_argon_native_function("__setattr__",
|
||||
@@ -210,6 +236,10 @@ void create_ARGON_DICTIONARY_TYPE() {
|
||||
ARGON_DICTIONARY_TYPE, __setitem__,
|
||||
create_argon_native_function("__setitem__",
|
||||
create_ARGON_DICTIONARY_TYPE___setitem__));
|
||||
add_builtin_field(
|
||||
ARGON_DICTIONARY_TYPE, __getitem__,
|
||||
create_argon_native_function("__getitem__",
|
||||
create_ARGON_DICTIONARY_TYPE___getitem__));
|
||||
add_builtin_field(ARGON_DICTIONARY_TYPE, __string__,
|
||||
create_argon_native_function(
|
||||
"__string__", create_ARGON_DICTIONARY_TYPE___string__));
|
||||
|
||||
@@ -45,7 +45,8 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
|
||||
"__new__",
|
||||
"__init__",
|
||||
"__boolean__",
|
||||
"__get_attr__",
|
||||
"__getattr__",
|
||||
"__getitem__",
|
||||
"address",
|
||||
"__call__",
|
||||
"__number__",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "string.h"
|
||||
#include "../../call/call.h"
|
||||
#include "../number/number.h"
|
||||
#include "../object.h"
|
||||
#include <ctype.h>
|
||||
@@ -14,51 +15,58 @@
|
||||
|
||||
ArgonObject *ARGON_STRING_TYPE = NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
char *c_quote_string(const char *input, size_t len) {
|
||||
// Worst case: every byte becomes "\uXXXX" (6 chars) + quotes + NUL
|
||||
size_t max_out = 2 + (len * 6) + 1;
|
||||
char *out = malloc(max_out);
|
||||
if (!out) return NULL;
|
||||
// Worst case: every byte becomes "\uXXXX" (6 chars) + quotes + NUL
|
||||
size_t max_out = 2 + (len * 6) + 1;
|
||||
char *out = malloc(max_out);
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
size_t j = 0;
|
||||
out[j++] = '"';
|
||||
size_t j = 0;
|
||||
out[j++] = '"';
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
unsigned char c = (unsigned char)input[i];
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
unsigned char c = (unsigned char)input[i];
|
||||
|
||||
switch (c) {
|
||||
case '\n':
|
||||
out[j++] = '\\'; out[j++] = 'n'; break;
|
||||
case '\t':
|
||||
out[j++] = '\\'; out[j++] = 't'; break;
|
||||
case '\r':
|
||||
out[j++] = '\\'; out[j++] = 'r'; break;
|
||||
case '\\':
|
||||
out[j++] = '\\'; out[j++] = '\\'; break;
|
||||
case '\"':
|
||||
out[j++] = '\\'; out[j++] = '\"'; break;
|
||||
default:
|
||||
if (isprint(c)) {
|
||||
out[j++] = c;
|
||||
} else {
|
||||
// write \uXXXX
|
||||
j += sprintf(&out[j], "\\u%04X", c);
|
||||
}
|
||||
}
|
||||
switch (c) {
|
||||
case '\n':
|
||||
out[j++] = '\\';
|
||||
out[j++] = 'n';
|
||||
break;
|
||||
case '\t':
|
||||
out[j++] = '\\';
|
||||
out[j++] = 't';
|
||||
break;
|
||||
case '\r':
|
||||
out[j++] = '\\';
|
||||
out[j++] = 'r';
|
||||
break;
|
||||
case '\\':
|
||||
out[j++] = '\\';
|
||||
out[j++] = '\\';
|
||||
break;
|
||||
case '\"':
|
||||
out[j++] = '\\';
|
||||
out[j++] = '\"';
|
||||
break;
|
||||
default:
|
||||
if (isprint(c)) {
|
||||
out[j++] = c;
|
||||
} else {
|
||||
// write \uXXXX
|
||||
j += sprintf(&out[j], "\\u%04X", c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out[j++] = '"';
|
||||
out[j] = '\0';
|
||||
return out;
|
||||
out[j++] = '"';
|
||||
out[j] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash,
|
||||
uint64_t hash) {
|
||||
add_builtin_field(object, field_length,
|
||||
new_number_object_from_int64(length));
|
||||
void init_string(ArgonObject *object, char *data, size_t length,
|
||||
uint64_t prehash, uint64_t hash) {
|
||||
add_builtin_field(object, field_length, new_number_object_from_int64(length));
|
||||
object->type = TYPE_STRING;
|
||||
object->value.as_str = ar_alloc(sizeof(struct string_struct));
|
||||
object->value.as_str->data = data;
|
||||
@@ -69,18 +77,40 @@ void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash,
|
||||
object->as_bool = length;
|
||||
}
|
||||
|
||||
ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash,
|
||||
uint64_t hash) {
|
||||
ArgonObject *new_string_object_without_memcpy(char *data, size_t length,
|
||||
uint64_t prehash, uint64_t hash) {
|
||||
ArgonObject *object = new_instance(ARGON_STRING_TYPE);
|
||||
init_string(object,data,length,prehash,hash);
|
||||
init_string(object, data, length, prehash, hash);
|
||||
return object;
|
||||
}
|
||||
|
||||
ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash,
|
||||
uint64_t hash) {
|
||||
char*data_copy = ar_alloc_atomic(length);
|
||||
char *data_copy = ar_alloc_atomic(length);
|
||||
memcpy(data_copy, data, length);
|
||||
return new_string_object_without_memcpy(data_copy,length, prehash, hash);
|
||||
return new_string_object_without_memcpy(data_copy, length, prehash, hash);
|
||||
}
|
||||
|
||||
char *argon_object_to_null_terminated_string(ArgonObject *object, ArErr *err,
|
||||
RuntimeState *state) {
|
||||
ArgonObject *string_convert_method = get_builtin_field_for_class(
|
||||
get_builtin_field(object, __class__), __repr__, object);
|
||||
|
||||
if (!string_convert_method)
|
||||
return "<object>";
|
||||
|
||||
ArgonObject *string_object =
|
||||
argon_call(string_convert_method, 0, NULL, err, state);
|
||||
if (err->exists)
|
||||
return NULL;
|
||||
|
||||
|
||||
if (string_object->type != TYPE_STRING) return "<object>";
|
||||
|
||||
char *string = ar_alloc(string_object->value.as_str->length+1);
|
||||
string[string_object->value.as_str->length] = '\0';
|
||||
memcpy(string, string_object->value.as_str->data, string_object->value.as_str->length);
|
||||
return string;
|
||||
}
|
||||
|
||||
ArgonObject *new_string_object_null_terminated(char *data) {
|
||||
|
||||
@@ -12,13 +12,17 @@ extern ArgonObject *ARGON_STRING_TYPE;
|
||||
|
||||
char *c_quote_string(const char *input, size_t len);
|
||||
|
||||
void init_string(ArgonObject*object,char *data, size_t length, uint64_t prehash,
|
||||
void init_string(ArgonObject *object, char *data, size_t length,
|
||||
uint64_t prehash, uint64_t hash);
|
||||
|
||||
char *argon_object_to_null_terminated_string(ArgonObject *object, ArErr *err,
|
||||
RuntimeState *state);
|
||||
|
||||
ArgonObject *new_string_object_without_memcpy(char *data, size_t length,
|
||||
uint64_t prehash, uint64_t hash);
|
||||
|
||||
ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash,
|
||||
uint64_t hash);
|
||||
|
||||
ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash,
|
||||
uint64_t hash);
|
||||
|
||||
ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, uint64_t hash);
|
||||
|
||||
ArgonObject *new_string_object_null_terminated(char*data);
|
||||
ArgonObject *new_string_object_null_terminated(char *data);
|
||||
#endif // STRING_OBJ_H
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "objects/term/term.h"
|
||||
#include "objects/type/type.h"
|
||||
#include <fcntl.h>
|
||||
#include <gc/gc.h>
|
||||
#include <gc.h>
|
||||
#include <gmp.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
@@ -72,11 +72,11 @@ ArgonObject *BASE_CLASS___getattribute__(size_t argc, ArgonObject **argv,
|
||||
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__) {
|
||||
ArgonObject *cls__getattr__ = get_builtin_field_for_class(
|
||||
get_builtin_field(to_access, __class__), __getattr__, to_access);
|
||||
if (cls__getattr__) {
|
||||
value =
|
||||
argon_call(cls__get_attr__, 1, (ArgonObject *[]){access}, err, state);
|
||||
argon_call(cls__getattr__, 1, (ArgonObject *[]){access}, err, state);
|
||||
if (err->exists) {
|
||||
return ARGON_NULL;
|
||||
}
|
||||
@@ -890,7 +890,8 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack,
|
||||
[OP_NOT] = &&DO_NOT,
|
||||
[OP_LOAD_SETATTR_METHOD] = &&DO_LOAD_SETATTR_METHOD,
|
||||
[OP_CREATE_DICTIONARY] = &&DO_CREATE_DICTIONARY,
|
||||
[OP_LOAD_SETITEM_METHOD] = &&DO_LOAD_SETITEM_METHOD};
|
||||
[OP_LOAD_SETITEM_METHOD] = &&DO_LOAD_SETITEM_METHOD,
|
||||
[OP_LOAD_GETITEM_METHOD] = &&DO_LOAD_GETITEM_METHOD};
|
||||
_state.head = 0;
|
||||
|
||||
StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame));
|
||||
@@ -1288,6 +1289,18 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
DO_LOAD_GETITEM_METHOD: {
|
||||
state->registers[0] = get_builtin_field_for_class(
|
||||
get_builtin_field(state->registers[0], __class__), __getitem__,
|
||||
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 __getitem__ from objects class");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ArgonObject *result = currentStackFrame->state.registers[0];
|
||||
|
||||
@@ -193,6 +193,10 @@ loads the \_\_setattr\_\_ method from the objects class in register 0 and put it
|
||||
|
||||
create a dictionary object into register 0.
|
||||
|
||||
## OP_LOAD_GETITEM_METHOD
|
||||
|
||||
loads the \_\_getitem\_\_ method from the objects class in register 0 and put it into register 0
|
||||
|
||||
## OP_LOAD_SETITEM_METHOD
|
||||
|
||||
loads the \_\_setitem\_\_ method from the objects class in register 0 and put it into register 0
|
||||
33
src/translator/item_access/item_access.c
Normal file
33
src/translator/item_access/item_access.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
#include "item_access.h"
|
||||
#include <stddef.h>
|
||||
|
||||
size_t translate_item_access(Translated *translated, ParsedItemAccess *access,
|
||||
ArErr *err) {
|
||||
set_registers(translated, 1);
|
||||
uint64_t first = translate_parsed(translated, access->to_access, err);
|
||||
if (err->exists)
|
||||
return 0;
|
||||
push_instruction_byte(translated, OP_LOAD_GETITEM_METHOD);
|
||||
push_instruction_byte(translated, OP_INIT_CALL);
|
||||
push_instruction_code(translated, access->itemc);
|
||||
|
||||
for (size_t i = 0; i < access->itemc; i++) {
|
||||
translate_parsed(translated, access->items[i], err);
|
||||
if (err->exists)
|
||||
return 0;
|
||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
||||
push_instruction_code(translated, i);
|
||||
}
|
||||
|
||||
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
||||
push_instruction_code(translated, access->line);
|
||||
push_instruction_code(translated, access->column);
|
||||
push_instruction_code(translated, access->length);
|
||||
push_instruction_byte(translated, OP_CALL);
|
||||
return first;
|
||||
}
|
||||
15
src/translator/item_access/item_access.h
Normal file
15
src/translator/item_access/item_access.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 William Bell
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef translator_item_access_H
|
||||
#define translator_item_access_H
|
||||
#include "../../parser/assignable/item/item.h"
|
||||
#include "../translator.h"
|
||||
|
||||
size_t translate_item_access(Translated *translated, ParsedItemAccess *access,
|
||||
ArErr *err);
|
||||
|
||||
#endif // translator_item_access_H
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "../parser/dictionary/dictionary.h"
|
||||
#include "../parser/not/not.h"
|
||||
#include "access/access.h"
|
||||
#include "../parser/assignable/item/item.h"
|
||||
#include "item_access/item_access.h"
|
||||
#include "assignment/assignment.h"
|
||||
#include "call/call.h"
|
||||
#include "declaration/declaration.h"
|
||||
@@ -163,6 +165,8 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue,
|
||||
err);
|
||||
case AST_ACCESS:
|
||||
return translate_access(translated, (ParsedAccess *)parsedValue->data, err);
|
||||
case AST_ITEM_ACCESS:
|
||||
return translate_item_access(translated, (ParsedItemAccess *)parsedValue->data, err);
|
||||
case AST_OPERATION:
|
||||
return translate_operation(translated, (ParsedOperation *)parsedValue->data,
|
||||
err);
|
||||
|
||||
@@ -42,6 +42,7 @@ typedef enum {
|
||||
OP_NOT,
|
||||
OP_LOAD_SETATTR_METHOD,
|
||||
OP_CREATE_DICTIONARY,
|
||||
OP_LOAD_GETITEM_METHOD,
|
||||
OP_LOAD_SETITEM_METHOD
|
||||
} OperationType;
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
let i = 1e7
|
||||
while (i) do
|
||||
i=i-1
|
||||
Reference in New Issue
Block a user