diff --git a/src/arobject.h b/src/arobject.h index 207d84b..9209bbb 100644 --- a/src/arobject.h +++ b/src/arobject.h @@ -33,7 +33,6 @@ typedef enum { field__address, __call__, __number__, - field_log, field_length, __getattribute__, __set_attr__, diff --git a/src/lexer/lex.l b/src/lexer/lex.l index 261e976..964e68e 100644 --- a/src/lexer/lex.l +++ b/src/lexer/lex.l @@ -32,13 +32,6 @@ int yywrap(void * unused_param) { ":" { return TOKEN_COLON; } "=" { return TOKEN_ASSIGN; } -"+=" { return TOKEN_ASSIGN_PLUS; } -"-=" { return TOKEN_ASSIGN_MINUS; } -"//=" { return TOKEN_ASSIGN_FLOORDIV; } -"/=" { return TOKEN_ASSIGN_SLASH; } -"%=" { return TOKEN_ASSIGN_MODULO; } -"*=" { return TOKEN_ASSIGN_STAR; } -"^=" { return TOKEN_ASSIGN_CARET; } "not"[ \t]+"in" { return TOKEN_NOT_IN; } "in" { return TOKEN_IN; } diff --git a/src/lexer/token.h b/src/lexer/token.h index a696b27..99dbb09 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -17,13 +17,6 @@ typedef enum { TOKEN_INDENT, TOKEN_ASSIGN, - TOKEN_ASSIGN_PLUS, - TOKEN_ASSIGN_MINUS, - TOKEN_ASSIGN_FLOORDIV, - TOKEN_ASSIGN_SLASH, - TOKEN_ASSIGN_MODULO, - TOKEN_ASSIGN_STAR, - TOKEN_ASSIGN_CARET, // Operators TOKEN_CARET, // ^ (Exponentiation) @@ -31,8 +24,8 @@ typedef enum { TOKEN_SLASH, // / (Division) TOKEN_FLOORDIV, // // (Floor Division) TOKEN_MODULO, // % (Modulo) - TOKEN_PLUS, // + (Addition) TOKEN_MINUS, // - (Subtraction) + TOKEN_PLUS, // + (Addition) TOKEN_LT, // < TOKEN_GT, // > TOKEN_LE, // <= diff --git a/src/parser/assignable/assign/assign.c b/src/parser/assignable/assign/assign.c index 2fbe491..042595a 100644 --- a/src/parser/assignable/assign/assign.c +++ b/src/parser/assignable/assign/assign.c @@ -7,25 +7,38 @@ #include "assign.h" #include "../../../lexer/token.h" #include "../../../memory.h" +#include "../../function/function.h" #include "../../parser.h" +#include "../../string/string.h" +#include "../access/access.h" #include "../call/call.h" +#include "../identifier/identifier.h" #include #include #include +#include ParsedValueReturn parse_assign(char *file, DArray *tokens, ParsedValue *assign_to, size_t *index) { Token *token = darray_get(tokens, *index); + bool is_function = false; + char *function_name; + bool to_free_function_name = false; + DArray function_args; + ParsedValue *function_assign_to; switch (assign_to->type) { case AST_IDENTIFIER: case AST_ACCESS: break; case AST_CALL:; ParsedCall *call = assign_to->data; + darray_init(&function_args, sizeof(char *)); for (size_t i = 0; i < call->args.size; i++) { - if (((ParsedValue *)darray_get(&call->args, i))->type != AST_IDENTIFIER) { + ParsedValue *arg = darray_get(&call->args, i); + if (arg->type != AST_IDENTIFIER) { free_parsed(assign_to); free(assign_to); + darray_free(&function_args, free_parameter); return (ParsedValueReturn){ create_err( token->line, token->column, token->length, file, "Syntax Error", @@ -34,6 +47,32 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens, "only use letters, digits, or _, and can't be keywords."), NULL}; } + + char *param = strdup(((ParsedIdentifier *)arg->data)->name); + darray_push(&function_args, ¶m); + } + darray_free(&call->args, free_parsed); + is_function = true; + function_assign_to = call->to_call; + switch (function_assign_to->type) { + case AST_IDENTIFIER: + function_name = ((ParsedIdentifier *)function_assign_to->data)->name; + break; + case AST_ACCESS: + if (((ParsedAccess *)function_assign_to->data)->access->type == + AST_STRING) { + ParsedString *name = + ((ParsedAccess *)function_assign_to->data)->access->data; + function_name = checked_malloc(name->length + 1); + function_name[name->length] = 0; + memcpy(function_name, name->string, name->length); + to_free_function_name = true; + break; + } + // FALL THROUGH + default: + function_name = "anonymous"; + break; } break; default:; @@ -44,36 +83,40 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens, free(assign_to); return (ParsedValueReturn){err, NULL}; } + (*index)++; + token = darray_get(tokens, *index); + ParsedValueReturn from = parse_token(file, tokens, index, true); + if (from.err.exists) { + return from; + } + if (!from.value) { + return (ParsedValueReturn){create_err(token->line, token->column, + token->length, file, "Syntax Error", + "expected body"), + NULL}; + } + if (is_function) { + from.value = + create_parsed_function(function_name, function_args, from.value); + if (to_free_function_name) free(function_name); + free(assign_to->data); + free(assign_to); + assign_to = function_assign_to; + } ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign)); assign->to = assign_to; - assign->type = token->type; + assign->type = 0; assign->from = NULL; ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); parsedValue->type = AST_ASSIGN; parsedValue->data = assign; - (*index)++; ArErr err = error_if_finished(file, tokens, index); if (err.exists) { free_parsed(parsedValue); free(parsedValue); return (ParsedValueReturn){err, NULL}; } - token = darray_get(tokens, *index); - ParsedValueReturn from = parse_token(file, tokens, index, true); - if (from.err.exists) { - free_parsed(parsedValue); - free(parsedValue); - return from; - } assign->from = from.value; - if (!assign->from) { - free_parsed(parsedValue); - free(parsedValue); - return (ParsedValueReturn){create_err(token->line, token->column, - token->length, file, "Syntax Error", - "expected body"), - NULL}; - } return (ParsedValueReturn){no_err, parsedValue}; } diff --git a/src/parser/parser.c b/src/parser/parser.c index 62222f6..9be5894 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -158,13 +158,6 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index, token = darray_get(tokens, *index); switch (token->type) { case TOKEN_ASSIGN: - case TOKEN_ASSIGN_CARET: - case TOKEN_ASSIGN_FLOORDIV: - case TOKEN_ASSIGN_MINUS: - case TOKEN_ASSIGN_MODULO: - case TOKEN_ASSIGN_PLUS: - case TOKEN_ASSIGN_SLASH: - case TOKEN_ASSIGN_STAR: output = parse_assign(file, tokens, output.value, index); break; case TOKEN_LPAREN: diff --git a/src/runtime/objects/dictionary/dictionary.c b/src/runtime/objects/dictionary/dictionary.c index 73e36b3..f0d7f58 100644 --- a/src/runtime/objects/dictionary/dictionary.c +++ b/src/runtime/objects/dictionary/dictionary.c @@ -95,7 +95,7 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc, string_object->value.as_str->length); string_length += string_object->value.as_str->length; } else { - char *string_obj = ""; + char *string_obj = "{...}"; size_t length = strlen(string_obj); string = realloc(string, string_length + length); memcpy(string + string_length, string_obj, length); diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index 5dda31c..688388a 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -39,7 +39,7 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = { "__string__", "__subtract__", "__multiply__", - "__divide__", + "__divide__", "__new__", "__init__", "__boolean__", @@ -49,7 +49,6 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = { "address", "__call__", "__number__", - "log", "length", "__getattribute__", "__set_attr__", diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 4b275ab..5e02131 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -31,6 +31,11 @@ #include #include #include +#if defined(_WIN32) +#include +#else +extern char **environ; +#endif ArgonObject *ARGON_METHOD_TYPE; Stack *Global_Scope = NULL; @@ -692,11 +697,11 @@ void bootstrap_types() { create_ARGON_DICTIONARY_TYPE(); } -void add_to_scope(Stack *stack, 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); - hashmap_insert_GC(stack->scope, hash, key, value, 0); + hashmap_insert_GC(hashmap, hash, key, value, 0); } void bootstrap_globals() { @@ -712,11 +717,56 @@ void bootstrap_globals() { add_to_scope(Global_Scope, "divide", DIVIDE_FUNCTION); add_to_scope(Global_Scope, "dictionary", ARGON_DICTIONARY_TYPE); - ArgonObject *argon_term = new_class(); - add_builtin_field(argon_term, __init__, ARGON_NULL); - add_builtin_field(argon_term, field_log, + struct hashmap_GC *argon_term = createHashmap_GC(); + add_to_hashmap(argon_term, "log", create_argon_native_function("log", term_log)); - add_to_scope(Global_Scope, "term", argon_term); + 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; + + 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); + } + } + + 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'; + + 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)); } int compare_by_order(const void *a, const void *b) { @@ -800,6 +850,13 @@ Stack *create_scope(Stack *prev, bool force) { return prev; } +void add_to_scope(Stack *stack, 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); + hashmap_insert_GC(stack->scope, hash, key, value, 0); +} + void runtime(Translated _translated, RuntimeState _state, Stack *stack, ArErr *err) { static void *const dispatch_table[] = { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 580d470..6f91226 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -91,6 +91,8 @@ Stack *create_scope(Stack *prev, bool force); void add_to_scope(Stack *stack, char *name, ArgonObject *value); +void add_to_hashmap(struct hashmap_GC *hashmap, char *name, ArgonObject *value); + void runtime(Translated translated, RuntimeState state, Stack *stack, ArErr *err); diff --git a/src/translator/assignment/assignment.c b/src/translator/assignment/assignment.c index 2bfebdb..72fe12e 100644 --- a/src/translator/assignment/assignment.c +++ b/src/translator/assignment/assignment.c @@ -8,7 +8,6 @@ #include "../../hash_data/hash_data.h" #include "../../parser/assignable/access/access.h" #include "../../parser/assignable/identifier/identifier.h" -#include "../../parser/string/string.h" #include "../translator.h" #include #include @@ -71,6 +70,7 @@ size_t translate_parsed_assignment(Translated *translated, push_instruction_byte(translated, OP_CALL); translated->registerAssignment--; break; + default: fprintf(stderr, "panic: unsupported assignment\n"); exit(EXIT_FAILURE); diff --git a/tests/anonymous_function.ar b/tests/anonymous_function.ar new file mode 100644 index 0000000..db1b060 --- /dev/null +++ b/tests/anonymous_function.ar @@ -0,0 +1 @@ +term.log(()=10) \ No newline at end of file diff --git a/tests/env.ar b/tests/env.ar new file mode 100644 index 0000000..57ebca9 --- /dev/null +++ b/tests/env.ar @@ -0,0 +1 @@ +term.log("hello,", env.USER+'.', 'how is', env.XDG_SESSION_TYPE+'?') \ No newline at end of file diff --git a/tests/iteration-test.ar b/tests/iteration-test.ar index 82abded..4dd03d1 100644 --- a/tests/iteration-test.ar +++ b/tests/iteration-test.ar @@ -1,4 +1,4 @@ -term.log(global."hello world") +term.log(global) let i = 1e8 while (i) do i=i-1 \ No newline at end of file diff --git a/tests/number-memory-leak.ar b/tests/number-memory-leak.ar new file mode 100644 index 0000000..f374c8c --- /dev/null +++ b/tests/number-memory-leak.ar @@ -0,0 +1,6 @@ +let i = 10 +let x = 1 +while (i) do + x = x * 1e100000000 + term.log(i=i-1) +term.log(x) \ No newline at end of file