add function assignment

This commit is contained in:
William Bell
2025-10-21 20:34:33 +01:00
parent 70ba81bebc
commit c8394228b3
14 changed files with 139 additions and 52 deletions

View File

@@ -33,7 +33,6 @@ typedef enum {
field__address, field__address,
__call__, __call__,
__number__, __number__,
field_log,
field_length, field_length,
__getattribute__, __getattribute__,
__set_attr__, __set_attr__,

View File

@@ -32,13 +32,6 @@ int yywrap(void * unused_param) {
":" { return TOKEN_COLON; } ":" { return TOKEN_COLON; }
"=" { return TOKEN_ASSIGN; } "=" { 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; } "not"[ \t]+"in" { return TOKEN_NOT_IN; }
"in" { return TOKEN_IN; } "in" { return TOKEN_IN; }

View File

@@ -17,13 +17,6 @@ typedef enum {
TOKEN_INDENT, TOKEN_INDENT,
TOKEN_ASSIGN, TOKEN_ASSIGN,
TOKEN_ASSIGN_PLUS,
TOKEN_ASSIGN_MINUS,
TOKEN_ASSIGN_FLOORDIV,
TOKEN_ASSIGN_SLASH,
TOKEN_ASSIGN_MODULO,
TOKEN_ASSIGN_STAR,
TOKEN_ASSIGN_CARET,
// Operators // Operators
TOKEN_CARET, // ^ (Exponentiation) TOKEN_CARET, // ^ (Exponentiation)
@@ -31,8 +24,8 @@ typedef enum {
TOKEN_SLASH, // / (Division) TOKEN_SLASH, // / (Division)
TOKEN_FLOORDIV, // // (Floor Division) TOKEN_FLOORDIV, // // (Floor Division)
TOKEN_MODULO, // % (Modulo) TOKEN_MODULO, // % (Modulo)
TOKEN_PLUS, // + (Addition)
TOKEN_MINUS, // - (Subtraction) TOKEN_MINUS, // - (Subtraction)
TOKEN_PLUS, // + (Addition)
TOKEN_LT, // < TOKEN_LT, // <
TOKEN_GT, // > TOKEN_GT, // >
TOKEN_LE, // <= TOKEN_LE, // <=

View File

@@ -7,25 +7,38 @@
#include "assign.h" #include "assign.h"
#include "../../../lexer/token.h" #include "../../../lexer/token.h"
#include "../../../memory.h" #include "../../../memory.h"
#include "../../function/function.h"
#include "../../parser.h" #include "../../parser.h"
#include "../../string/string.h"
#include "../access/access.h"
#include "../call/call.h" #include "../call/call.h"
#include "../identifier/identifier.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
ParsedValueReturn parse_assign(char *file, DArray *tokens, ParsedValueReturn parse_assign(char *file, DArray *tokens,
ParsedValue *assign_to, size_t *index) { ParsedValue *assign_to, size_t *index) {
Token *token = darray_get(tokens, *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) { switch (assign_to->type) {
case AST_IDENTIFIER: case AST_IDENTIFIER:
case AST_ACCESS: case AST_ACCESS:
break; break;
case AST_CALL:; case AST_CALL:;
ParsedCall *call = assign_to->data; ParsedCall *call = assign_to->data;
darray_init(&function_args, sizeof(char *));
for (size_t i = 0; i < call->args.size; i++) { 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_parsed(assign_to);
free(assign_to); free(assign_to);
darray_free(&function_args, free_parameter);
return (ParsedValueReturn){ return (ParsedValueReturn){
create_err( create_err(
token->line, token->column, token->length, file, "Syntax Error", 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."), "only use letters, digits, or _, and can't be keywords."),
NULL}; NULL};
} }
char *param = strdup(((ParsedIdentifier *)arg->data)->name);
darray_push(&function_args, &param);
}
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; break;
default:; default:;
@@ -44,36 +83,40 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
free(assign_to); free(assign_to);
return (ParsedValueReturn){err, NULL}; 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)); ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
assign->to = assign_to; assign->to = assign_to;
assign->type = token->type; assign->type = 0;
assign->from = NULL; assign->from = NULL;
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
parsedValue->type = AST_ASSIGN; parsedValue->type = AST_ASSIGN;
parsedValue->data = assign; parsedValue->data = assign;
(*index)++;
ArErr err = error_if_finished(file, tokens, index); ArErr err = error_if_finished(file, tokens, index);
if (err.exists) { if (err.exists) {
free_parsed(parsedValue); free_parsed(parsedValue);
free(parsedValue); free(parsedValue);
return (ParsedValueReturn){err, NULL}; 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; 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}; return (ParsedValueReturn){no_err, parsedValue};
} }

View File

@@ -158,13 +158,6 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
token = darray_get(tokens, *index); token = darray_get(tokens, *index);
switch (token->type) { switch (token->type) {
case TOKEN_ASSIGN: 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); output = parse_assign(file, tokens, output.value, index);
break; break;
case TOKEN_LPAREN: case TOKEN_LPAREN:

View File

@@ -95,7 +95,7 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc,
string_object->value.as_str->length); string_object->value.as_str->length);
string_length += string_object->value.as_str->length; string_length += string_object->value.as_str->length;
} else { } else {
char *string_obj = "<object>"; char *string_obj = "{...}";
size_t length = strlen(string_obj); size_t length = strlen(string_obj);
string = realloc(string, string_length + length); string = realloc(string, string_length + length);
memcpy(string + string_length, string_obj, length); memcpy(string + string_length, string_obj, length);

View File

@@ -39,7 +39,7 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
"__string__", "__string__",
"__subtract__", "__subtract__",
"__multiply__", "__multiply__",
"__divide__", "__divide__",
"__new__", "__new__",
"__init__", "__init__",
"__boolean__", "__boolean__",
@@ -49,7 +49,6 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
"address", "address",
"__call__", "__call__",
"__number__", "__number__",
"log",
"length", "length",
"__getattribute__", "__getattribute__",
"__set_attr__", "__set_attr__",

View File

@@ -31,6 +31,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#if defined(_WIN32)
#include <windows.h>
#else
extern char **environ;
#endif
ArgonObject *ARGON_METHOD_TYPE; ArgonObject *ARGON_METHOD_TYPE;
Stack *Global_Scope = NULL; Stack *Global_Scope = NULL;
@@ -692,11 +697,11 @@ void bootstrap_types() {
create_ARGON_DICTIONARY_TYPE(); 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); size_t length = strlen(name);
uint64_t hash = siphash64_bytes(name, length, siphash_key); uint64_t hash = siphash64_bytes(name, length, siphash_key);
ArgonObject *key = new_string_object(name, length, 0, hash); 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() { void bootstrap_globals() {
@@ -712,11 +717,56 @@ void bootstrap_globals() {
add_to_scope(Global_Scope, "divide", DIVIDE_FUNCTION); add_to_scope(Global_Scope, "divide", DIVIDE_FUNCTION);
add_to_scope(Global_Scope, "dictionary", ARGON_DICTIONARY_TYPE); add_to_scope(Global_Scope, "dictionary", ARGON_DICTIONARY_TYPE);
ArgonObject *argon_term = new_class(); struct hashmap_GC *argon_term = createHashmap_GC();
add_builtin_field(argon_term, __init__, ARGON_NULL); add_to_hashmap(argon_term, "log",
add_builtin_field(argon_term, field_log,
create_argon_native_function("log", 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) { int compare_by_order(const void *a, const void *b) {
@@ -800,6 +850,13 @@ Stack *create_scope(Stack *prev, bool force) {
return prev; 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, void runtime(Translated _translated, RuntimeState _state, Stack *stack,
ArErr *err) { ArErr *err) {
static void *const dispatch_table[] = { static void *const dispatch_table[] = {

View File

@@ -91,6 +91,8 @@ Stack *create_scope(Stack *prev, bool force);
void add_to_scope(Stack *stack, char *name, ArgonObject *value); 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, void runtime(Translated translated, RuntimeState state, Stack *stack,
ArErr *err); ArErr *err);

View File

@@ -8,7 +8,6 @@
#include "../../hash_data/hash_data.h" #include "../../hash_data/hash_data.h"
#include "../../parser/assignable/access/access.h" #include "../../parser/assignable/access/access.h"
#include "../../parser/assignable/identifier/identifier.h" #include "../../parser/assignable/identifier/identifier.h"
#include "../../parser/string/string.h"
#include "../translator.h" #include "../translator.h"
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
@@ -71,6 +70,7 @@ size_t translate_parsed_assignment(Translated *translated,
push_instruction_byte(translated, OP_CALL); push_instruction_byte(translated, OP_CALL);
translated->registerAssignment--; translated->registerAssignment--;
break; break;
default: default:
fprintf(stderr, "panic: unsupported assignment\n"); fprintf(stderr, "panic: unsupported assignment\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@@ -0,0 +1 @@
term.log(()=10)

1
tests/env.ar Normal file
View File

@@ -0,0 +1 @@
term.log("hello,", env.USER+'.', 'how is', env.XDG_SESSION_TYPE+'?')

View File

@@ -1,4 +1,4 @@
term.log(global."hello world") term.log(global)
let i = 1e8 let i = 1e8
while (i) do while (i) do
i=i-1 i=i-1

View File

@@ -0,0 +1,6 @@
let i = 10
let x = 1
while (i) do
x = x * 1e100000000
term.log(i=i-1)
term.log(x)