From 23c4a7ebd13685f70b17907f7e375df1a683a6f2 Mon Sep 17 00:00:00 2001 From: William Bell <62452284+Ugric@users.noreply.github.com> Date: Sun, 7 Sep 2025 21:03:57 +0100 Subject: [PATCH] add not and or, while also improving performance. --- .gitignore | 1 + anonymous-function-test.ar | 8 -- app.py | 3 - debug_arbin.py | 130 ------------------ final_test.ar | 56 -------- gentest.py | 10 -- perf.data | Bin 0 -> 144208 bytes perf.data.old | Bin 0 -> 138728 bytes src/arobject.h | 1 + src/err.c | 3 +- src/parser/not/not.c | 50 +++++++ src/parser/not/not.h | 20 +++ src/parser/operations/operations.c | 6 +- .../parentheses-and-anonymous-function.c | 6 + src/parser/parser.c | 17 ++- src/parser/parser.h | 3 +- src/returnTypes.h | 2 +- src/runtime/assignment/assignment.c | 1 + src/runtime/call/call.c | 3 +- src/runtime/internals/hashmap/hashmap.c | 19 +-- src/runtime/objects/number/number.c | 1 - src/runtime/objects/string/string.c | 12 +- src/runtime/objects/string/string.h | 3 + src/runtime/runtime.c | 49 ++++--- src/shell.c | 16 ++- src/shell.h | 2 +- src/translator/bytecode_spec.md | 10 +- src/translator/if/if.c | 1 - src/translator/operation/operation.c | 13 +- src/translator/translator.c | 16 ++- src/translator/translator.h | 3 +- src/translator/while/while.c | 12 +- test.ar | 94 ------------- test.py | 38 ----- testing.ar | 47 ------- tests/iteration-test.ar | 3 + 36 files changed, 201 insertions(+), 458 deletions(-) delete mode 100644 anonymous-function-test.ar delete mode 100644 app.py delete mode 100644 debug_arbin.py delete mode 100644 final_test.ar delete mode 100644 gentest.py create mode 100644 perf.data create mode 100644 perf.data.old create mode 100644 src/parser/not/not.c create mode 100644 src/parser/not/not.h delete mode 100644 test.ar delete mode 100644 test.py delete mode 100644 testing.ar create mode 100644 tests/iteration-test.ar diff --git a/.gitignore b/.gitignore index 987f111..7ba7c8b 100644 --- a/.gitignore +++ b/.gitignore @@ -64,5 +64,6 @@ build *.yy.c *.yy.h +__isotope__ __arcache__ argon_modules \ No newline at end of file diff --git a/anonymous-function-test.ar b/anonymous-function-test.ar deleted file mode 100644 index fcda09c..0000000 --- a/anonymous-function-test.ar +++ /dev/null @@ -1,8 +0,0 @@ -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 \ No newline at end of file diff --git a/app.py b/app.py deleted file mode 100644 index 0bacd2d..0000000 --- a/app.py +++ /dev/null @@ -1,3 +0,0 @@ -i = 1_000_000 -while i: - i=i-1 \ No newline at end of file diff --git a/debug_arbin.py b/debug_arbin.py deleted file mode 100644 index 78d6216..0000000 --- a/debug_arbin.py +++ /dev/null @@ -1,130 +0,0 @@ -# SPDX-FileCopyrightText: 2025 William Bell -# -# SPDX-License-Identifier: GPL-3.0-or-later - -import struct -from enum import Enum, EnumMeta, auto - -class AutoEnumMeta(EnumMeta): - @classmethod - def __prepare__(metacls, clsname, bases, **kwargs): - d = super().__prepare__(clsname, bases, **kwargs) - d['_next_value'] = 254 - return d - - def _generate_next_value_(cls, name, start, count, last_values): - value = cls._next_value - cls._next_value += 1 - return value - -class OperationType(Enum, metaclass=AutoEnumMeta): - OP_LOAD_CONST = auto() - OP_DECLARE = auto() - OP_LOAD_NULL = auto() - OP_JUMP = auto() - -class Types(Enum, metaclass=AutoEnumMeta): - TYPE_OP_STRING = auto() - TYPE_OP_NUMBER = auto() - -def read_arbin(filename): - with open(filename, "rb") as f: - # Read and verify file identifier (4 bytes) - file_id = f.read(4) - if file_id != b"ARBI": - raise ValueError("Invalid file identifier") - - # Read version number (uint64_t, little-endian) - version_number, = struct.unpack(" int: - print("OP_LOAD_CONST ", end="") - i+=1 - register = data["bytecode"][i] - print("To Register",register,"", end="") - i+=1 - match data["bytecode"][i]: - case Types.TYPE_OP_STRING.value: - print("TYPE_OP_STRING ", end="") - case Types.TYPE_OP_NUMBER.value: - print("TYPE_OP_NUMBER ", end="") - i+=1 - length = data["bytecode"][i] - i+=1 - offset = data["bytecode"][i] - i+=1 - print("Length",length,"", end="") - print("Offset",offset,"") - registers[register] = data["constants"][offset:offset+length].decode() - print("const value:", registers[register]) - return i - - def OP_DECLARE(registers,data, i) -> int: - print("OP_DECLARE ", end="") - i+=1 - length = data["bytecode"][i] - i+=1 - offset = data["bytecode"][i] - i+=1 - from_register = data["bytecode"][i] - i+=1 - print("Name Length",length,"", end="") - print("Name Offset",offset,"", end="") - print("From Register",from_register,"") - print("output: let", data['constants'][offset:offset+length].decode(),'=',registers[from_register]) - return i - def OP_LOAD_NULL(registers,data, i) -> int: - print("OP_LOAD_NULL ", end="") - i+=1 - to_register = data["bytecode"][i] - i+=1 - print("To Register",to_register,"") - registers[to_register] = "null" - return i -if __name__ == "__main__": - filename = "out.arbin" - data = read_arbin(filename) - print(f"Version: {data['version']}") - print(f"Register Count: {data['register_count']}") - print(f"Constants Size: {data['constants_size']} bytes") - print(f"Bytecode Length: {data['bytecode_size']} elements") - - registers = ["null"]*data['register_count'] - - i=0 - while i= 3) do - let filename = json.parse(disposition[2].splitN("=", 2)[1]) - req.files[name] = __makeFile(filename, headers["content-type"], body) - else do - req.formdata[name] = body.to("string") - res.next() - - -let formdata(req, res) = do - req.formdata = {} - req.files = {} - - if (req.method != "POST") return res.next() - if ("content-type" not in req.headers) return res.next() - let loweredContentType = req.headers["content-type"].lower() - if (loweredContentType.startswith("multipart/form-data")) return __multipart(req, res) - else if (loweredContentType.startswith("application/x-www-form-urlencoded")) req.formdata = url.decodeURLQuery(req.buffer.body.to("string")) - else if (loweredContentType.startswith("application/json")) req.formdata = json.parse(req.buffer.body.to("string")) - else req.files.file = __makeFile("file", req.headers["content-type"], req.buffer.body) - res.next() \ No newline at end of file diff --git a/gentest.py b/gentest.py deleted file mode 100644 index 69a8498..0000000 --- a/gentest.py +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-FileCopyrightText: 2025 William Bell -# -# SPDX-License-Identifier: GPL-3.0-or-later - -import random -import sys - -for i in range(10000000): - sys.stdout.write("\"hello world\"\n") - diff --git a/perf.data b/perf.data new file mode 100644 index 0000000000000000000000000000000000000000..4f3708648cfdccddadb16fe2f77684ecd59218f9 GIT binary patch literal 144208 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 + +ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index) { + bool invert = true; + (*index)++; + while (tokens->size > *index) { + Token *token = darray_get(tokens, *index); + if (token->type != TOKEN_EXCLAMATION) { + ParsedValueReturn value = + parse_token_full(file, tokens, index, true, false); + if (value.err.exists) { + return value; + } else if (!value.value) { + return (ParsedValueReturn){create_err(token->line, token->column, + token->length, file, + "Syntax Error", "expected value"), + NULL}; + } + + ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); + ParsedToBool *parsedToBool = checked_malloc(sizeof(ParsedToBool)); + parsedToBool->value = value.value; + parsedToBool->invert = invert; + parsedValue->data = parsedToBool; + parsedValue->type = AST_TO_BOOL; + return (ParsedValueReturn){no_err, parsedValue}; + } + invert = !invert; + (*index)++; + } + ArErr err = error_if_finished(file, tokens, index); + return (ParsedValueReturn){err, NULL}; +} + +void free_not(void *ptr) { + ParsedValue *parsedValue = ptr; + ParsedToBool *parsedToBool = parsedValue->data; + free_parsed(parsedToBool->value); + free(parsedToBool->value); + free(parsedToBool); +} \ No newline at end of file diff --git a/src/parser/not/not.h b/src/parser/not/not.h new file mode 100644 index 0000000..c29fdd8 --- /dev/null +++ b/src/parser/not/not.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef NOT_H +#define NOT_H +#include "../parser.h" + +typedef struct { + bool invert; + ParsedValue*value; +} ParsedToBool; + +ParsedValueReturn parse_not(char *file, DArray *tokens, size_t *index); + +void free_not(void *ptr); + +#endif // NOT_H \ No newline at end of file diff --git a/src/parser/operations/operations.c b/src/parser/operations/operations.c index 1bcd5e2..fe4b46d 100644 --- a/src/parser/operations/operations.c +++ b/src/parser/operations/operations.c @@ -42,24 +42,22 @@ ParsedValue convert_to_operation(DArray *to_operate_on, DArray *operations) { operationStruct->column = operation.column; operationStruct->length = operation.length; darray_init(&operationStruct->to_operate_on, sizeof(ParsedValue)); - size_t last_position = 0; size_t to_operate_on_last_position = 0; for (size_t i = 0; i < positions.size; i++) { size_t *position = darray_get(&positions, i); DArray to_operate_on_slice = darray_slice( to_operate_on, to_operate_on_last_position, (*position) + 1); DArray operations_slice = - darray_slice(operations, last_position, *position); + darray_slice(operations, to_operate_on_last_position, (*position)); ParsedValue result = convert_to_operation(&to_operate_on_slice, &operations_slice); darray_push(&operationStruct->to_operate_on, &result); - last_position = (*position); to_operate_on_last_position = (*position) + 1; } DArray to_operate_on_slice = darray_slice( to_operate_on, to_operate_on_last_position, to_operate_on->size); DArray operations_slice = - darray_slice(operations, last_position, operations->size); + darray_slice(operations, to_operate_on_last_position, operations->size); ParsedValue result = convert_to_operation(&to_operate_on_slice, &operations_slice); darray_push(&operationStruct->to_operate_on, &result); diff --git a/src/parser/parentheses-and-anonymous-function/parentheses-and-anonymous-function.c b/src/parser/parentheses-and-anonymous-function/parentheses-and-anonymous-function.c index 0e502ac..2a3a63e 100644 --- a/src/parser/parentheses-and-anonymous-function/parentheses-and-anonymous-function.c +++ b/src/parser/parentheses-and-anonymous-function/parentheses-and-anonymous-function.c @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2025 William Bell + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + #include "parentheses-and-anonymous-function.h" #include "../../memory.h" #include "../assignable/identifier/identifier.h" diff --git a/src/parser/parser.c b/src/parser/parser.c index 65481d9..62222f6 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 "parentheses-and-anonymous-function/parentheses-and-anonymous-function.h" #include "dowrap/dowrap.h" #include "function/function.h" #include "if/if.h" @@ -21,8 +20,10 @@ #include "literals/literals.h" #include "number/number.h" #include "operations/operations.h" +#include "parentheses-and-anonymous-function/parentheses-and-anonymous-function.h" #include "return/return.h" #include "string/string.h" +#include "not/not.h" #include "while/while.h" #include #include @@ -32,10 +33,10 @@ #include const char *ValueTypeNames[] = { - "string", "assign", "identifier", "number", - "if statement", "access", "call", "declaration", - "null", "boolean", "do wrap", "operations", - "list", "dictionary", "function", "return", "while loop"}; + "string", "assign", "identifier", "number", "if statement", + "access", "call", "declaration", "null", "boolean", + "do wrap", "operations", "list", "dictionary", "function", + "return", "while loop", "not"}; ArErr error_if_finished(char *file, DArray *tokens, size_t *index) { if ((*index) >= tokens->size) { @@ -138,6 +139,9 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index, case TOKEN_LBRACE: output = parse_dictionary(file, tokens, index); break; + case TOKEN_EXCLAMATION: + output = parse_not(file, tokens, index); + break; default: return (ParsedValueReturn){create_err(token->line, token->column, token->length, file, "Syntax Error", @@ -271,5 +275,8 @@ void free_parsed(void *ptr) { case AST_RETURN: free_parsed_return(parsed); break; + case AST_TO_BOOL: + free_not(parsed); + break; } } \ No newline at end of file diff --git a/src/parser/parser.h b/src/parser/parser.h index eafd728..c188f9b 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -50,7 +50,8 @@ typedef enum { AST_DICTIONARY, AST_FUNCTION, AST_RETURN, - AST_WHILE + AST_WHILE, + AST_TO_BOOL } ValueType; extern const char *ValueTypeNames[]; diff --git a/src/returnTypes.h b/src/returnTypes.h index c1fe11f..7130006 100644 --- a/src/returnTypes.h +++ b/src/returnTypes.h @@ -9,7 +9,7 @@ #include #include "arobject.h" -#define ERR_MSG_MAX_LEN 256 +#define ERR_MSG_MAX_LEN 64 typedef struct ArErr { bool exists; diff --git a/src/runtime/assignment/assignment.c b/src/runtime/assignment/assignment.c index 761630f..60d37d3 100644 --- a/src/runtime/assignment/assignment.c +++ b/src/runtime/assignment/assignment.c @@ -21,6 +21,7 @@ void runtime_assignment(Translated *translated, RuntimeState *state, if (exists) { hashmap_insert_GC(current_stack->scope, hash, key, state->registers[from_register], 0); + return; } } hashmap_insert_GC(stack->scope, hash, key, state->registers[from_register], diff --git a/src/runtime/call/call.c b/src/runtime/call/call.c index a3ce6b6..d368253 100644 --- a/src/runtime/call/call.c +++ b/src/runtime/call/call.c @@ -6,7 +6,6 @@ #include "call.h" #include "../../hash_data/hash_data.h" -#include "../objects/literals/literals.h" #include "../objects/string/string.h" #include #include @@ -156,7 +155,7 @@ void run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv, *state->currentStackFramePointer, (*state->currentStackFramePointer)->depth + 1}; for (size_t i = 0; i < new_stackFrame.translated.registerCount; i++) { - new_stackFrame.state.registers[i] = ARGON_NULL; + new_stackFrame.state.registers[i] = NULL; } if (CStackFrame) { runtime(new_stackFrame.translated, new_stackFrame.state, diff --git a/src/runtime/internals/hashmap/hashmap.c b/src/runtime/internals/hashmap/hashmap.c index bcc7d2b..6eb0edd 100644 --- a/src/runtime/internals/hashmap/hashmap.c +++ b/src/runtime/internals/hashmap/hashmap.c @@ -15,18 +15,19 @@ #include struct hashmap_GC *createHashmap_GC() { - size_t size = 8; - struct hashmap_GC *t = - (struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC)); - t->size = size; - t->order = 1; - t->list = (struct node_GC **)ar_alloc(sizeof(struct node_GC *) * size); - memset(t->list, 0, sizeof(struct node_GC *) * size); - t->count = 0; - return t; + size_t size = 8; + struct hashmap_GC *t = + (struct hashmap_GC *)ar_alloc(sizeof(struct hashmap_GC) + sizeof(struct node_GC *) * size); + t->size = size; + t->order = 1; + t->list = (struct node_GC **)((char*)t + sizeof(struct hashmap_GC)); + memset(t->list, 0, sizeof(struct node_GC *) * size); + t->count = 0; + return t; } void clear_hashmap_GC(struct hashmap_GC *t) { + if (!t->count) return; t->order = 1; t->count = 0; memset(t->list, 0, sizeof(struct node_GC *) * t->size); diff --git a/src/runtime/objects/number/number.c b/src/runtime/objects/number/number.c index 69fe289..7a87f75 100644 --- a/src/runtime/objects/number/number.c +++ b/src/runtime/objects/number/number.c @@ -7,7 +7,6 @@ #include "number.h" #include "../functions/functions.h" #include "../string/string.h" -#include #include #include #include diff --git a/src/runtime/objects/string/string.c b/src/runtime/objects/string/string.c index 02704bc..e56edbd 100644 --- a/src/runtime/objects/string/string.c +++ b/src/runtime/objects/string/string.c @@ -13,15 +13,14 @@ ArgonObject *ARGON_STRING_TYPE = NULL; -ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, +ArgonObject *new_string_object_without_memcpy(char *data, size_t length, uint64_t prehash, uint64_t hash) { ArgonObject *object = new_object(); add_builtin_field(object, __class__, ARGON_STRING_TYPE); add_builtin_field(object, field_length, new_number_object_from_int64(length)); object->type = TYPE_STRING; - object->value.as_str.data = ar_alloc_atomic(length); - memcpy(object->value.as_str.data, data, length); + object->value.as_str.data = data; object->value.as_str.prehash = prehash; object->value.as_str.hash_computed = hash; object->value.as_str.hash = hash; @@ -30,6 +29,13 @@ ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, return object; } +ArgonObject *new_string_object(char *data, size_t length, uint64_t prehash, + uint64_t hash) { + char*data_copy = ar_alloc_atomic(length); + memcpy(data_copy, data, length); + return new_string_object_without_memcpy(data_copy,length, prehash, hash); +} + ArgonObject *new_string_object_null_terminated(char *data) { return new_string_object(data, strlen(data), 0, 0); } \ No newline at end of file diff --git a/src/runtime/objects/string/string.h b/src/runtime/objects/string/string.h index f093741..ba10dc7 100644 --- a/src/runtime/objects/string/string.h +++ b/src/runtime/objects/string/string.h @@ -10,6 +10,9 @@ extern ArgonObject *ARGON_STRING_TYPE; +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); diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index a567b3f..70f4c61 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -359,12 +359,11 @@ ArgonObject *ARGON_STRING_TYPE___add__(size_t argc, ArgonObject **argv, return ARGON_NULL; } size_t length = argv[0]->value.as_str.length + argv[1]->value.as_str.length; - char *concat = malloc(length); + char *concat = ar_alloc_atomic(length); memcpy(concat, argv[0]->value.as_str.data, argv[0]->value.as_str.length); memcpy(concat + argv[0]->value.as_str.length, argv[1]->value.as_str.data, argv[1]->value.as_str.length); - ArgonObject *object = new_string_object(concat, length, 0, 0); - free(concat); + ArgonObject *object = new_string_object_without_memcpy(concat, length, 0, 0); return object; } @@ -485,6 +484,7 @@ void bootstrap_types() { ARGON_NULL_TYPE = new_object(); add_builtin_field(ARGON_NULL_TYPE, __base__, BASE_CLASS); ARGON_NULL = new_object(); + ARGON_NULL->type = TYPE_NULL; add_builtin_field(ARGON_NULL, __class__, ARGON_NULL_TYPE); ARGON_NULL->as_bool = false; @@ -681,22 +681,27 @@ RuntimeState init_runtime_state(Translated translated, char *path) { NULL, {0, 0, 0}, {}}; - for (size_t i = 0;iscope = createHashmap_GC(); - stack->prev = prev; - return stack; + if (!prev || prev->scope->count) { + Stack *stack = ar_alloc(sizeof(Stack)); + stack->fake_new_scopes = 0; + stack->scope = createHashmap_GC(); + stack->prev = prev; + return stack; + } + prev->fake_new_scopes++; + return prev; } void runtime(Translated _translated, RuntimeState _state, Stack *stack, ArErr *err) { - static void *dispatch_table[] = { + static void *const dispatch_table[] = { [OP_LOAD_STRING] = &&DO_LOAD_STRING, [OP_DECLARE] = &&DO_DECLARE, [OP_LOAD_NULL] = &&DO_LOAD_NULL, @@ -720,7 +725,8 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, [OP_SUBTRACTION] = &&DO_SUBTRACTION, [OP_LOAD_ACCESS_FUNCTION] = &&DO_LOAD_ACCESS_FUNCTION, [OP_MULTIPLICATION] = &&DO_MULTIPLICATION, - [OP_DIVISION] = &&DO_DIVISION}; + [OP_DIVISION] = &&DO_DIVISION, + [OP_NOT] = &&DO_NOT}; _state.head = 0; StackFrame *currentStackFrame = ar_alloc(sizeof(StackFrame)); @@ -756,15 +762,16 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, runtime_assignment(translated, state, currentStackFrame->stack); continue; DO_BOOL: { - uint8_t to_register = pop_byte(translated, state); - if (likely(state->registers[to_register]->type != TYPE_OBJECT)) { - state->registers[to_register] = - state->registers[to_register]->as_bool ? ARGON_TRUE : ARGON_FALSE; + if (state->registers[0] == ARGON_TRUE || + state->registers[0] == ARGON_FALSE) + continue; + if (likely(state->registers[0]->type != TYPE_OBJECT)) { + state->registers[0] = + state->registers[0]->as_bool ? ARGON_TRUE : ARGON_FALSE; continue; } ArgonObject *args[] = {ARGON_BOOL_TYPE, state->registers[0]}; - state->registers[to_register] = - ARGON_BOOL_TYPE___new__(2, args, err, state); + state->registers[0] = ARGON_BOOL_TYPE___new__(2, args, err, state); continue; } DO_JUMP_IF_FALSE: { @@ -775,6 +782,10 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, } continue; } + DO_NOT: + state->registers[0] = + state->registers[0] == ARGON_FALSE ? ARGON_TRUE : ARGON_FALSE; + continue; DO_JUMP: state->head = pop_bytecode(translated, state); continue; @@ -785,6 +796,10 @@ void runtime(Translated _translated, RuntimeState _state, Stack *stack, clear_hashmap_GC(currentStackFrame->stack->scope); continue; DO_POP_SCOPE: + if (currentStackFrame->stack->fake_new_scopes) { + currentStackFrame->stack->fake_new_scopes--; + goto DO_EMPTY_SCOPE; + } currentStackFrame->stack = currentStackFrame->stack->prev; continue; DO_INIT_CALL: { diff --git a/src/shell.c b/src/shell.c index a380368..0a36a92 100644 --- a/src/shell.c +++ b/src/shell.c @@ -91,7 +91,8 @@ int execute_code(FILE *stream, char *path, Stack *scope, hashmap_free(__translated.constants.hashmap, NULL); Translated translated = { - __translated.registerCount, __translated.registerAssignment, NULL, {}, {}, __translated.path}; + __translated.registerCount, __translated.registerAssignment, NULL, {}, {}, + __translated.path}; translated.bytecode.data = ar_alloc(__translated.bytecode.capacity); memcpy(translated.bytecode.data, __translated.bytecode.data, __translated.bytecode.capacity); @@ -198,11 +199,13 @@ int shell() { totranslatelength = 0; }; int indent = 0; + int last_indent = 0; char textBefore[] = ">>> "; // Dynamic array of lines do { + last_indent = indent; // indent string size_t isz = (size_t)indent * 4; char *indentStr = (char *)malloc(isz + 1); @@ -253,7 +256,7 @@ int shell() { strcpy(textBefore, "... "); free(indentStr); - } while (indent > 0); + } while (indent > 0 || last_indent != 0); totranslate = realloc(totranslate, totranslatelength + 1); totranslate[totranslatelength] = '\0'; RuntimeState runtime_state; @@ -263,9 +266,12 @@ int shell() { if (resp) { continue; } - ArErr err = no_err; - argon_call(output_object, 1, (ArgonObject *[]){runtime_state.registers[0]}, - &err, &runtime_state); + if (runtime_state.registers[0]) { + ArErr err = no_err; + argon_call(output_object, 1, + (ArgonObject *[]){runtime_state.registers[0]}, &err, + &runtime_state); + } totranslatelength = 0; } diff --git a/src/shell.h b/src/shell.h index 7c7b1f3..e75a179 100644 --- a/src/shell.h +++ b/src/shell.h @@ -9,4 +9,4 @@ int shell(); -#endif // ARGON_SHELL_H \ No newline at end of file +#endif // ARGON_SHELL_H \ No newline at end of file diff --git a/src/translator/bytecode_spec.md b/src/translator/bytecode_spec.md index 1e45868..f1d5788 100644 --- a/src/translator/bytecode_spec.md +++ b/src/translator/bytecode_spec.md @@ -71,9 +71,7 @@ initilises a function to a given register. ## OP_BOOL -converts a value in a given register into true or false depending on the result from \_\_bool\_\_ - -1. the register to read and write to. (*) +converts a value in register 0 into true or false depending on the result from \_\_bool\_\_ (using asBool if the object is a primitive) ## OP_JUMP_IF_FALSE @@ -181,4 +179,8 @@ performs an division between register A and register B, storing the result in re 1. the register A (*) 2. the register B (*) -2. the register C (*) \ No newline at end of file +2. the register C (*) + +## OP_NOT + +inverts the boolean value in register 0. \ No newline at end of file diff --git a/src/translator/if/if.c b/src/translator/if/if.c index d21e393..e6088ea 100644 --- a/src/translator/if/if.c +++ b/src/translator/if/if.c @@ -40,7 +40,6 @@ size_t translate_parsed_if(Translated *translated, DArray *parsedIf, return 0; } push_instruction_byte(translated, OP_BOOL); - push_instruction_byte(translated, 0); push_instruction_byte(translated, OP_JUMP_IF_FALSE); push_instruction_byte(translated, 0); uint64_t last_jump_index = push_instruction_code(translated, 0); diff --git a/src/translator/operation/operation.c b/src/translator/operation/operation.c index bd234e0..cb46c38 100644 --- a/src/translator/operation/operation.c +++ b/src/translator/operation/operation.c @@ -11,7 +11,7 @@ size_t translate_operation(Translated *translated, ParsedOperation *operation, ArErr *err) { - if (operation->operation == TOKEN_AND) { + if (operation->operation == TOKEN_AND || operation->operation == TOKEN_OR) { size_t *jump_to_if_false = checked_malloc(operation->to_operate_on.size * sizeof(size_t)); uint8_t registerA = translated->registerAssignment++; @@ -21,7 +21,7 @@ size_t translate_operation(Translated *translated, ParsedOperation *operation, uint64_t position = translate_parsed( translated, darray_get(&operation->to_operate_on, i), err); if (i == 0) - position = first; + first = position; if (err->exists) { free(jump_to_if_false); return first; @@ -31,16 +31,21 @@ size_t translate_operation(Translated *translated, ParsedOperation *operation, push_instruction_byte(translated, registerA); push_instruction_byte(translated, OP_BOOL); - push_instruction_byte(translated, registerA); + if (operation->operation == TOKEN_OR) push_instruction_byte(translated, OP_NOT); push_instruction_byte(translated, OP_JUMP_IF_FALSE); - push_instruction_byte(translated, registerA); + push_instruction_byte(translated, 0); 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); } + push_instruction_byte(translated, OP_COPY_TO_REGISTER); + push_instruction_byte(translated, registerA); + push_instruction_byte(translated, 0); + push_instruction_byte(translated, OP_LOAD_NULL); + push_instruction_byte(translated, registerA); free(jump_to_if_false); return first; diff --git a/src/translator/translator.c b/src/translator/translator.c index cbba858..efbea54 100644 --- a/src/translator/translator.c +++ b/src/translator/translator.c @@ -6,10 +6,11 @@ #include "translator.h" #include "../hash_data/hash_data.h" +#include "../parser/not/not.h" #include "access/access.h" +#include "assignment/assignment.h" #include "call/call.h" #include "declaration/declaration.h" -#include "assignment/assignment.h" #include "dowrap/dowrap.h" #include "function/function.h" #include "identifier/identifier.h" @@ -148,7 +149,8 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue, case AST_IF: return translate_parsed_if(translated, (DArray *)parsedValue->data, err); case AST_WHILE: - return translate_parsed_while(translated, (ParsedWhile *)parsedValue->data, err); + return translate_parsed_while(translated, (ParsedWhile *)parsedValue->data, + err); case AST_DOWRAP: return translate_parsed_dowrap(translated, (DArray *)parsedValue->data, err); @@ -165,7 +167,15 @@ size_t translate_parsed(Translated *translated, ParsedValue *parsedValue, err); case AST_ASSIGN: return translate_parsed_assignment(translated, - (ParsedAssign *)parsedValue->data, err); + (ParsedAssign *)parsedValue->data, err); + case AST_TO_BOOL: { + size_t first = translate_parsed( + translated, ((ParsedToBool *)parsedValue->data)->value, err); + push_instruction_byte(translated, OP_BOOL); + if (((ParsedToBool *)parsedValue->data)->invert) + push_instruction_byte(translated, OP_NOT); + return first; + } } return 0; } diff --git a/src/translator/translator.h b/src/translator/translator.h index 3a63935..370bbce 100644 --- a/src/translator/translator.h +++ b/src/translator/translator.h @@ -38,7 +38,8 @@ typedef enum { OP_SUBTRACTION, OP_LOAD_ACCESS_FUNCTION, OP_MULTIPLICATION, - OP_DIVISION + OP_DIVISION, + OP_NOT } OperationType; void arena_resize(ConstantArena *arena, size_t new_size); diff --git a/src/translator/while/while.c b/src/translator/while/while.c index 2787abb..713667c 100644 --- a/src/translator/while/while.c +++ b/src/translator/while/while.c @@ -18,12 +18,12 @@ size_t translate_parsed_while(Translated *translated, ParsedWhile *parsedWhile, translated->return_jumps = &return_jumps; } size_t first = push_instruction_byte(translated, OP_NEW_SCOPE); - size_t start_of_loop = translate_parsed(translated, parsedWhile->condition, err); + size_t start_of_loop = + translate_parsed(translated, parsedWhile->condition, err); if (err->exists) { return 0; } push_instruction_byte(translated, OP_BOOL); - push_instruction_byte(translated, 0); push_instruction_byte(translated, OP_JUMP_IF_FALSE); push_instruction_byte(translated, 0); uint64_t jump_index = push_instruction_code(translated, 0); @@ -31,9 +31,8 @@ size_t translate_parsed_while(Translated *translated, ParsedWhile *parsedWhile, push_instruction_byte(translated, OP_EMPTY_SCOPE); push_instruction_byte(translated, OP_JUMP); push_instruction_code(translated, start_of_loop); - - - + set_instruction_code(translated, jump_index, translated->bytecode.size); + push_instruction_byte(translated, OP_POP_SCOPE); if (translated->return_jumps) { push_instruction_byte(translated, OP_JUMP); size_t skip_return = push_instruction_code(translated, 0); @@ -50,8 +49,5 @@ size_t translate_parsed_while(Translated *translated, ParsedWhile *parsedWhile, darray_free(&return_jumps, NULL); translated->return_jumps = old_return_jumps; } - - set_instruction_code(translated, jump_index, - translated->bytecode.size); return first; } \ No newline at end of file diff --git a/test.ar b/test.ar deleted file mode 100644 index 04ba1bc..0000000 --- a/test.ar +++ /dev/null @@ -1,94 +0,0 @@ -# SPDX-FileCopyrightText: 2025 William Bell - -# SPDX-License-Identifier: GPL-3.0-or-later - -"h" -"e" -"ll" -"o" -" " -"wo" -"rl" -"d" -"world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello world" -"hello\u0000world" -"🇬🇧" -"\u0000" -"hello" - -let hello = "helllo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nbruhhhhh" - -1.24323234e2312324 - -let a, - b = "hello", - c, - d = 42, - temp_result, - compute_area(radius) = 3.1415, - identity(x) = x, - f(x)=do - term.log("hello world") - do - term.log('hello world') - term.log("hello world") - , - g(y, z), - result, - z = 0, - extremely_long_variable_name_to_test_limits, - cache_value = compute_area(5), - placeholder_fn_with_no_body(arg1, arg2, arg3), - total = identity(100), - deeply_nested_args_function(arg1, arg2, arg3, arg4, arg5), - sum = a, - another, - another_function(), - just_null_here, - x - - - - -if (x) do - term.log("hello world") - term.log("hello world") -else term.log("bruh") - - - - - - - -mm=x/2/4/2/4354/534/534//534//3422*404203420234+3432423324&&430234230||4320423040230423^384239423043024923%4432042304920.3432423423 - -let X = [ - 'hello world', - 'wow', - 10 -] - -term.log(x[0:1:1]) - -let y = { - 'hello':test, - world:'nice' -} - -term.log(y['hello'],y.world) \ No newline at end of file diff --git a/test.py b/test.py deleted file mode 100644 index b81251c..0000000 --- a/test.py +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-FileCopyrightText: 2025 William Bell -# -# SPDX-License-Identifier: GPL-3.0-or-later - -import string -from itertools import product -import sys - -def generate_names(max_width, skip_keywords=None): - if skip_keywords is None: - skip_keywords = {"if", "else", "while", "forever", "for", "break", "continue", - "return", "let", "import", "from", "do", "true", "false", "null", - "delete", "not", "try", "catch", "in", "or", "and", "elif"} - else: - skip_keywords = set(skip_keywords) - - chars = string.ascii_lowercase - first = True - write = sys.stdout.write - - for length in range(1, max_width + 1): - print(length, file=sys.stderr) - i = 0 - for p in product(chars, repeat=length): - name = ''.join(p) - if name in skip_keywords: - continue - write('let ') - write(name) - write(' = null\n') - first = False - if i>10000000: - break - i+=1 - -# Example usage: -max_width = 5 -generate_names(max_width) diff --git a/testing.ar b/testing.ar deleted file mode 100644 index 13ab4e8..0000000 --- a/testing.ar +++ /dev/null @@ -1,47 +0,0 @@ -let say_hi(name) = do - let z(y) = do - return y - let u = z( - do - return name - ) - - return "hello "+u+", how are you?" -term.log(say_hi("william") -, say_hi) - -let a = 9 -let b = 10 -term.log(string(a)+'+'+string(b)+'='+string(a+b)) - - -let call(f) = do - term.log(f) - - return f() - - -term.log( - call( - ()=call( - ()=do - term.log('hello testing testing') - return call( - ()=call( - ()=do - term.log("hello this is a test of anonymous functions. hopefully this works :)") - - return say_hi("test") - ) - ) - ) - ) -) -call(()=do - term.log(( - (x)=x - )( - 10000675435574942378423458324823473205237523053278452368578032472390453275238558438905348905894035890348905349805345485843578934268954328902589607469328905490832678934728969834689057843267854736890256743928563256749016078596789416895657435690769013674516750941765438576867893726789543789345678576846715416789058903890549045839804538905389045890435890349580348905894035890435784785236523656237985678342523678 - ) - ) -) \ No newline at end of file diff --git a/tests/iteration-test.ar b/tests/iteration-test.ar new file mode 100644 index 0000000..f858c3e --- /dev/null +++ b/tests/iteration-test.ar @@ -0,0 +1,3 @@ +let i = 1e6 +while (i) do + i = i-1 \ No newline at end of file