// Kyler Olsen // YREA SLS // Builtin Functions // November 2025 #include #include #include "sls/bool.h" #include "sls/builtin.h" #include "sls/hash_table.h" #include "sls/interpreter.h" #include "sls/lexer.h" Boolean builtin_addition(InterpreterState *interpreter_state); Boolean builtin_subtraction(InterpreterState *interpreter_state); Boolean builtin_multiplication(InterpreterState *interpreter_state); Boolean builtin_division(InterpreterState *interpreter_state); Boolean builtin_modulus(InterpreterState *interpreter_state); Boolean builtin_exponential(InterpreterState *interpreter_state); Boolean builtin_greater_than(InterpreterState *interpreter_state); Boolean builtin_greater_than_or_equal_to(InterpreterState *interpreter_state); Boolean builtin_less_than(InterpreterState *interpreter_state); Boolean builtin_less_than_or_equal_to(InterpreterState *interpreter_state); Boolean builtin_equal_to(InterpreterState *interpreter_state); Boolean builtin_not_equal_to(InterpreterState *interpreter_state); Boolean builtin_abs(InterpreterState *interpreter_state); Boolean builtin_acos(InterpreterState *interpreter_state); Boolean builtin_and(InterpreterState *interpreter_state); Boolean builtin_asin(InterpreterState *interpreter_state); // Boolean builtin_assert(InterpreterState *interpreter_state); // Boolean builtin_at(InterpreterState *interpreter_state); Boolean builtin_atan(InterpreterState *interpreter_state); Boolean builtin_atan2(InterpreterState *interpreter_state); Boolean builtin_bitand(InterpreterState *interpreter_state); Boolean builtin_bitnot(InterpreterState *interpreter_state); Boolean builtin_bitor(InterpreterState *interpreter_state); Boolean builtin_bitxor(InterpreterState *interpreter_state); Boolean builtin_ceil(InterpreterState *interpreter_state); // Boolean builtin_concat(InterpreterState *interpreter_state); Boolean builtin_cos(InterpreterState *interpreter_state); Boolean builtin_depth(InterpreterState *interpreter_state); Boolean builtin_drop(InterpreterState *interpreter_state); Boolean builtin_dup(InterpreterState *interpreter_state); // Boolean builtin_each(InterpreterState *interpreter_state); // Boolean builtin_ends_with(InterpreterState *interpreter_state); // Boolean builtin_enum(InterpreterState *interpreter_state); // Boolean builtin_enumerate(InterpreterState *interpreter_state); Boolean builtin_eval(InterpreterState *interpreter_state); // Boolean builtin_filter(InterpreterState *interpreter_state); // Boolean builtin_find(InterpreterState *interpreter_state); Boolean builtin_floor(InterpreterState *interpreter_state); // Boolean builtin_fn(InterpreterState *interpreter_state); // Boolean builtin_foldl(InterpreterState *interpreter_state); // Boolean builtin_foldr(InterpreterState *interpreter_state); Boolean builtin_for(InterpreterState *interpreter_state); // Boolean builtin_format(InterpreterState *interpreter_state); // Boolean builtin_get(InterpreterState *interpreter_state); Boolean builtin_if(InterpreterState *interpreter_state); // Boolean builtin_impl(InterpreterState *interpreter_state); // Boolean builtin_implements(InterpreterState *interpreter_state); // Boolean builtin_inher(InterpreterState *interpreter_state); Boolean builtin_lambda(InterpreterState *interpreter_state); // Boolean builtin_length(InterpreterState *interpreter_state); Boolean builtin_ln(InterpreterState *interpreter_state); Boolean builtin_log(InterpreterState *interpreter_state); Boolean builtin_logb(InterpreterState *interpreter_state); // Boolean builtin_map(InterpreterState *interpreter_state); // Boolean builtin_match(InterpreterState *interpreter_state); Boolean builtin_max(InterpreterState *interpreter_state); // Boolean builtin_mean(InterpreterState *interpreter_state); Boolean builtin_min(InterpreterState *interpreter_state); Boolean builtin_not(InterpreterState *interpreter_state); Boolean builtin_or(InterpreterState *interpreter_state); // Boolean builtin_over(InterpreterState *interpreter_state); Boolean builtin_pick(InterpreterState *interpreter_state); Boolean builtin_rand(InterpreterState *interpreter_state); // Boolean builtin_reduce(InterpreterState *interpreter_state); // Boolean builtin_replace(InterpreterState *interpreter_state); // Boolean builtin_reverse(InterpreterState *interpreter_state); Boolean builtin_roll(InterpreterState *interpreter_state); Boolean builtin_rot(InterpreterState *interpreter_state); Boolean builtin_round(InterpreterState *interpreter_state); Boolean builtin_seed(InterpreterState *interpreter_state); // Boolean builtin_set(InterpreterState *interpreter_state); Boolean builtin_shl(InterpreterState *interpreter_state); Boolean builtin_shr(InterpreterState *interpreter_state); Boolean builtin_sin(InterpreterState *interpreter_state); // Boolean builtin_slice(InterpreterState *interpreter_state); // Boolean builtin_split(InterpreterState *interpreter_state); Boolean builtin_sqrt(InterpreterState *interpreter_state); // Boolean builtin_starts_with(InterpreterState *interpreter_state); // Boolean builtin_struct(InterpreterState *interpreter_state); // Boolean builtin_substr(InterpreterState *interpreter_state); // Boolean builtin_sum(InterpreterState *interpreter_state); Boolean builtin_swap(InterpreterState *interpreter_state); Boolean builtin_tan(InterpreterState *interpreter_state); // Boolean builtin_trait(InterpreterState *interpreter_state); // Boolean builtin_transpose(InterpreterState *interpreter_state); // Boolean builtin_trim(InterpreterState *interpreter_state); Boolean builtin_type_of(InterpreterState *interpreter_state); // Boolean builtin_union(InterpreterState *interpreter_state); Boolean builtin_while(InterpreterState *interpreter_state); // Boolean builtin_window(InterpreterState *interpreter_state); // Boolean builtin_zip(InterpreterState *interpreter_state); static inline Boolean hash_table_put_funcs(HashTable *ht, SlsStr key, FunctionItem *item) { return hash_table_put(ht, key, (void *)item); } typedef enum { NUMERIC_FLOAT = 1 << 0, NUMERIC_SIGNED = 1 << 1, NUMERIC_64 = 1 << 2, NUMERIC_32 = 1 << 3, NUMERIC_16 = 1 << 4, NUMERIC_8 = 1 << 5, } NumericTypes; Boolean load_builtins(InterpreterState *interpreter_state) { FunctionItem *func; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_addition}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("+"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_subtraction}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("-"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_multiplication}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("*"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_division}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("/"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_modulus}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("%"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_exponential}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("^"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_greater_than}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR(">"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_greater_than_or_equal_to}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR(">="), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_less_than}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("<"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_less_than_or_equal_to}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("<="), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_equal_to}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("=="), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_not_equal_to}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("!="), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_abs}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("abs"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_acos}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("acos"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_and}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("acos"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_asin}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("asin"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_atan}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("atan"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_atan2}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("atan2"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_bitand}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("bitand"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_bitnot}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("bitnot"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_bitor}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("bitor"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_bitxor}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("bitxor"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_ceil}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("ceil"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_cos}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("cos"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_depth}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("depth"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_drop}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("drop"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_dup}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("dup"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_eval}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("eval"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_floor}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("floor"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_for}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("for"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_if}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("if"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_lambda}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("lambda"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_ln}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("ln"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_log}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("log"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_logb}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("logb"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_max}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("max"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_min}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("min"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_not}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("not"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_or}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("or"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_pick}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("pick"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_rand}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("rand"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_roll}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("roll"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_round}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("round"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_seed}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("seed"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_shl}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("shl"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_shr}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("shr"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_sin}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("sin"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_sqrt}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("sqrt"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_swap}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("swap"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_tan}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("tan"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_type_of}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("type_of"), func)) return FALSE; func = (FunctionItem *)malloc(sizeof(FunctionItem)); if (func == NULL) return FALSE; *func = (FunctionItem){ .type = FUNCTION_BUILTIN, .builtin = *builtin_while}; if (!hash_table_put_funcs(interpreter_state->functions, SLS_STR("while"), func)) return FALSE; return TRUE; } #define NUMERIC_TYPE \ double af = 0; \ uint64_t ai = 0; \ uint64_t type = 0; \ if (interpreter_state->stack == NULL) return FALSE; \ \ switch (interpreter_state->stack->type) { \ case STACK_IDENTIFIER: \ return FALSE; \ case STACK_I64: \ ai = interpreter_state->stack->i64; \ af = interpreter_state->stack->i64; \ type |= NUMERIC_64; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I32: \ ai = interpreter_state->stack->i32; \ af = interpreter_state->stack->i32; \ type |= NUMERIC_32; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I16: \ ai = interpreter_state->stack->i16; \ af = interpreter_state->stack->i16; \ type |= NUMERIC_16; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I8: \ ai = interpreter_state->stack->i8; \ af = interpreter_state->stack->i8; \ type |= NUMERIC_8; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_U64: \ ai = interpreter_state->stack->u64; \ af = interpreter_state->stack->u64; \ type |= NUMERIC_64; \ break; \ case STACK_U32: \ ai = interpreter_state->stack->u32; \ af = interpreter_state->stack->u32; \ type |= NUMERIC_32; \ break; \ case STACK_U16: \ ai = interpreter_state->stack->u16; \ af = interpreter_state->stack->u16; \ type |= NUMERIC_16; \ break; \ case STACK_U8: \ ai = interpreter_state->stack->u8; \ af = interpreter_state->stack->u8; \ type |= NUMERIC_8; \ break; \ case STACK_FLOAT: \ af = interpreter_state->stack->f32; \ type |= NUMERIC_32; \ type |= NUMERIC_FLOAT; \ break; \ case STACK_DOUBLE: \ af = interpreter_state->stack->f64; \ type |= NUMERIC_64; \ type |= NUMERIC_FLOAT; \ break; \ case STACK_CHARACTER: \ ai = interpreter_state->stack->character; \ af = interpreter_state->stack->character; \ break; \ case STACK_BOOLEAN: \ ai = interpreter_state->stack->boolean; \ af = interpreter_state->stack->boolean; \ break; \ case STACK_TOKEN_STRING: \ case STACK_CALLABLE: \ return FALSE; \ } \ #define NUMERIC_TYPES \ double af = 0, bf = 0; \ uint64_t ai = 0, bi = 0; \ uint64_t type = 0; \ if (interpreter_state->stack == NULL) return FALSE; \ if (interpreter_state->stack->next == NULL) return FALSE; \ \ switch (interpreter_state->stack->type) { \ case STACK_IDENTIFIER: \ return FALSE; \ case STACK_I64: \ ai = interpreter_state->stack->i64; \ af = interpreter_state->stack->i64; \ type |= NUMERIC_64; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I32: \ ai = interpreter_state->stack->i32; \ af = interpreter_state->stack->i32; \ type |= NUMERIC_32; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I16: \ ai = interpreter_state->stack->i16; \ af = interpreter_state->stack->i16; \ type |= NUMERIC_16; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I8: \ ai = interpreter_state->stack->i8; \ af = interpreter_state->stack->i8; \ type |= NUMERIC_8; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_U64: \ ai = interpreter_state->stack->u64; \ af = interpreter_state->stack->u64; \ type |= NUMERIC_64; \ break; \ case STACK_U32: \ ai = interpreter_state->stack->u32; \ af = interpreter_state->stack->u32; \ type |= NUMERIC_32; \ break; \ case STACK_U16: \ ai = interpreter_state->stack->u16; \ af = interpreter_state->stack->u16; \ type |= NUMERIC_16; \ break; \ case STACK_U8: \ ai = interpreter_state->stack->u8; \ af = interpreter_state->stack->u8; \ type |= NUMERIC_8; \ break; \ case STACK_FLOAT: \ af = interpreter_state->stack->f32; \ type |= NUMERIC_32; \ type |= NUMERIC_FLOAT; \ break; \ case STACK_DOUBLE: \ af = interpreter_state->stack->f64; \ type |= NUMERIC_64; \ type |= NUMERIC_FLOAT; \ break; \ case STACK_CHARACTER: \ ai = interpreter_state->stack->character; \ af = interpreter_state->stack->character; \ break; \ case STACK_BOOLEAN: \ ai = interpreter_state->stack->boolean; \ af = interpreter_state->stack->boolean; \ break; \ case STACK_TOKEN_STRING: \ case STACK_CALLABLE: \ return FALSE; \ } \ \ switch (interpreter_state->stack->next->type) { \ case STACK_IDENTIFIER: \ return FALSE; \ case STACK_I64: \ bi = interpreter_state->stack->next->i64; \ bf = interpreter_state->stack->next->i64; \ type |= NUMERIC_64; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I32: \ bi = interpreter_state->stack->next->i32; \ bf = interpreter_state->stack->next->i32; \ type |= NUMERIC_32; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I16: \ bi = interpreter_state->stack->next->i16; \ bf = interpreter_state->stack->next->i16; \ type |= NUMERIC_16; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_I8: \ bi = interpreter_state->stack->next->i8; \ bf = interpreter_state->stack->next->i8; \ type |= NUMERIC_8; \ type |= NUMERIC_SIGNED; \ break; \ case STACK_U64: \ bi = interpreter_state->stack->next->u64; \ bf = interpreter_state->stack->next->u64; \ type |= NUMERIC_64; \ break; \ case STACK_U32: \ bi = interpreter_state->stack->next->u32; \ bf = interpreter_state->stack->next->u32; \ type |= NUMERIC_32; \ break; \ case STACK_U16: \ bi = interpreter_state->stack->next->u16; \ bf = interpreter_state->stack->next->u16; \ type |= NUMERIC_16; \ break; \ case STACK_U8: \ bi = interpreter_state->stack->next->u8; \ bf = interpreter_state->stack->next->u8; \ type |= NUMERIC_8; \ break; \ case STACK_FLOAT: \ bf = interpreter_state->stack->next->f32; \ type |= NUMERIC_32; \ type |= NUMERIC_FLOAT; \ break; \ case STACK_DOUBLE: \ bf = interpreter_state->stack->next->f64; \ type |= NUMERIC_64; \ type |= NUMERIC_FLOAT; \ break; \ case STACK_CHARACTER: \ bi = interpreter_state->stack->next->character; \ bf = interpreter_state->stack->next->character; \ break; \ case STACK_BOOLEAN: \ bi = interpreter_state->stack->next->boolean; \ bf = interpreter_state->stack->next->boolean; \ break; \ case STACK_TOKEN_STRING: \ case STACK_CALLABLE: \ return FALSE; \ } \ #define FLOAT_FUNCTION(func) \ (void)ai; \ (void)type; \ \ StackItem *node = interpreter_state->stack; \ interpreter_state->stack = interpreter_state->stack->next; \ node->next = NULL; \ clean_stack(node); \ \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_DOUBLE, \ .double_literal = func(af), \ }); \ #define ARITHMETIC(op) \ StackItem *node = interpreter_state->stack; \ interpreter_state->stack = interpreter_state->stack->next->next; \ node->next->next = NULL; \ clean_stack(node); \ \ if (type & NUMERIC_FLOAT && type & NUMERIC_64) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_DOUBLE, \ .double_literal = bf op af, \ }); \ } else if (type & NUMERIC_FLOAT) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_FLOAT, \ .float_literal = (float)bf op (float)af, \ }); \ } else if (type & NUMERIC_SIGNED && type & NUMERIC_64) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_I64, \ .value = bi op ai, \ }, \ }); \ } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_I32, \ .value = bi op ai, \ }, \ }); \ } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_I16, \ .value = bi op ai, \ }, \ }); \ } else if (type & NUMERIC_SIGNED) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_I8, \ .value = bi op ai, \ }, \ }); \ } else if (type & NUMERIC_64) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_U64, \ .value = bi op ai, \ }, \ }); \ } else if (type & NUMERIC_32) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_U32, \ .value = bi op ai, \ }, \ }); \ } else if (type & NUMERIC_16) { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_U16, \ .value = bi op ai, \ }, \ }); \ } else { \ return push_token(interpreter_state, (Token){ \ .type = TOKEN_INTEGER, \ .integer_literal = (IntegerLiteral){ \ .type = INTEGER_U8, \ .value = bi op ai, \ }, \ }); \ } \ #define TRUTHY \ Boolean value = FALSE; \ switch (conditional->type) { \ case STACK_IDENTIFIER: \ value = FALSE; \ break; \ case STACK_I64: \ value = (conditional->i64) ? TRUE : FALSE; \ break; \ case STACK_I32: \ value = (conditional->i32) ? TRUE : FALSE; \ break; \ case STACK_I16: \ value = (conditional->i16) ? TRUE : FALSE; \ break; \ case STACK_I8: \ value = (conditional->i8) ? TRUE : FALSE; \ break; \ case STACK_U64: \ value = (conditional->u64) ? TRUE : FALSE; \ break; \ case STACK_U32: \ value = (conditional->u32) ? TRUE : FALSE; \ break; \ case STACK_U16: \ value = (conditional->u16) ? TRUE : FALSE; \ break; \ case STACK_U8: \ value = (conditional->u8) ? TRUE : FALSE; \ break; \ case STACK_FLOAT: \ value = (conditional->f32) ? TRUE : FALSE; \ break; \ case STACK_DOUBLE: \ value = (conditional->f64) ? TRUE : FALSE; \ break; \ case STACK_CHARACTER: \ value = (conditional->character) ? TRUE : FALSE; \ break; \ case STACK_BOOLEAN: \ value = conditional->boolean; \ break; \ case STACK_TOKEN_STRING: \ case STACK_CALLABLE: \ value = (conditional->token_string.length && conditional->token_string.tokens[0].type != TOKEN_EOF) ? TRUE : FALSE; \ break; \ } \ Boolean builtin_addition(InterpreterState *interpreter_state) { NUMERIC_TYPES; ARITHMETIC(+); } Boolean builtin_subtraction(InterpreterState *interpreter_state) { NUMERIC_TYPES; ARITHMETIC(-); } Boolean builtin_multiplication(InterpreterState *interpreter_state) { NUMERIC_TYPES; ARITHMETIC(*); } Boolean builtin_division(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; if (af == 0) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_DOUBLE, .double_literal = bf / af, }); } Boolean builtin_modulus(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)af; (void)bf; if (type & NUMERIC_FLOAT) { return FALSE; } else if (ai == 0) { return FALSE; } StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = bi % ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = bi % ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = bi % ai, }, }); } else if (type & NUMERIC_SIGNED) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = bi % ai, }, }); } else if (type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = bi % ai, }, }); } else if (type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U32, .value = bi % ai, }, }); } else if (type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U16, .value = bi % ai, }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U8, .value = bi % ai, }, }); } } Boolean builtin_exponential(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_DOUBLE, .double_literal = pow(bf, af), }); } Boolean builtin_greater_than(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = bf > af, }); } Boolean builtin_greater_than_or_equal_to(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = bf >= af, }); } Boolean builtin_less_than(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = bf < af, }); } Boolean builtin_less_than_or_equal_to(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = bf <= af, }); } Boolean builtin_equal_to(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = bf == af, }); } Boolean builtin_not_equal_to(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)ai; (void)bi; (void)type; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = bf != af, }); } Boolean builtin_abs(InterpreterState *interpreter_state) { NUMERIC_TYPE; if (!((type & NUMERIC_SIGNED) | (type & NUMERIC_FLOAT))) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next; node->next = NULL; clean_stack(node); if (type & NUMERIC_FLOAT && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_DOUBLE, .double_literal = fabs(af), }); } else if (type & NUMERIC_FLOAT) { return push_token(interpreter_state, (Token){ .type = TOKEN_FLOAT, .float_literal = fabs(af), }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = labs((int64_t)ai), }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = labs((int64_t)ai), }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = labs((int64_t)ai), }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = labs((int64_t)ai), }, }); } } Boolean builtin_acos(InterpreterState *interpreter_state) { NUMERIC_TYPE; if (af < -1 || af > 1) return FALSE; FLOAT_FUNCTION(acos); } Boolean builtin_and(InterpreterState *interpreter_state) { NUMERIC_TYPES; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_FLOAT) { return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = (Boolean){ bf && af }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = (Boolean){ bi && ai }, }); } } Boolean builtin_asin(InterpreterState *interpreter_state) { NUMERIC_TYPE; if (af < -1 || af > 1) return FALSE; FLOAT_FUNCTION(asin); } Boolean builtin_atan(InterpreterState *interpreter_state) { NUMERIC_TYPE; FLOAT_FUNCTION(atan); } Boolean builtin_atan2(InterpreterState *interpreter_state) { (void)interpreter_state; return FALSE; } Boolean builtin_bitand(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)af; (void)bf; if (type & NUMERIC_FLOAT) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = bi & ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = bi & ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = bi & ai, }, }); } else if (type & NUMERIC_SIGNED) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = bi & ai, }, }); } else if (type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = bi & ai, }, }); } else if (type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U32, .value = bi & ai, }, }); } else if (type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U16, .value = bi & ai, }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U8, .value = bi & ai, }, }); } } Boolean builtin_bitnot(InterpreterState *interpreter_state) { NUMERIC_TYPE; (void)af; if (type & NUMERIC_FLOAT) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next; node->next = NULL; clean_stack(node); if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = ~ ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = ~ ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = ~ ai, }, }); } else if (type & NUMERIC_SIGNED) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = ~ ai, }, }); } else if (type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = ~ ai, }, }); } else if (type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U32, .value = ~ ai, }, }); } else if (type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U16, .value = ~ ai, }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U8, .value = ~ ai, }, }); } } Boolean builtin_bitor(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)af; (void)bf; if (type & NUMERIC_FLOAT) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = bi | ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = bi | ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = bi | ai, }, }); } else if (type & NUMERIC_SIGNED) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = bi | ai, }, }); } else if (type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = bi | ai, }, }); } else if (type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U32, .value = bi | ai, }, }); } else if (type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U16, .value = bi | ai, }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U8, .value = bi | ai, }, }); } } Boolean builtin_bitxor(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)af; (void)bf; if (type & NUMERIC_FLOAT) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = bi ^ ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = bi ^ ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = bi ^ ai, }, }); } else if (type & NUMERIC_SIGNED) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = bi ^ ai, }, }); } else if (type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = bi ^ ai, }, }); } else if (type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U32, .value = bi ^ ai, }, }); } else if (type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U16, .value = bi ^ ai, }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U8, .value = bi ^ ai, }, }); } } Boolean builtin_ceil(InterpreterState *interpreter_state) { NUMERIC_TYPE; FLOAT_FUNCTION(ceil); } Boolean builtin_cos(InterpreterState *interpreter_state) { NUMERIC_TYPE; FLOAT_FUNCTION(cos); } Boolean builtin_depth(InterpreterState *interpreter_state) { size_t depth = 0; for (StackItem *node = interpreter_state->stack; node; node = node->next) depth++; return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = (uint64_t)depth, }, }); } Boolean builtin_drop(InterpreterState *interpreter_state) { StackItem *node = interpreter_state->stack; if (node == NULL) return FALSE; interpreter_state->stack = node->next; node->next = NULL; clean_stack(node); return TRUE; } Boolean builtin_dup(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; StackItem *item = (StackItem *)malloc(sizeof(StackItem)); if (item == NULL) return FALSE; item->type = interpreter_state->stack->type; item->next = interpreter_state->stack; switch (interpreter_state->stack->type) { case STACK_IDENTIFIER: item->identifier = interpreter_state->stack->identifier; break; case STACK_I64: item->i64 = interpreter_state->stack->i64; break; case STACK_I32: item->i32 = interpreter_state->stack->i32; break; case STACK_I16: item->i16 = interpreter_state->stack->i16; break; case STACK_I8: item->i8 = interpreter_state->stack->i8; break; case STACK_U64: item->u64 = interpreter_state->stack->u64; break; case STACK_U32: item->u32 = interpreter_state->stack->u32; break; case STACK_U16: item->u16 = interpreter_state->stack->u16; break; case STACK_U8: item->u8 = interpreter_state->stack->u8; break; case STACK_FLOAT: item->f32 = interpreter_state->stack->f32; break; case STACK_DOUBLE: item->f64 = interpreter_state->stack->f64; break; case STACK_CHARACTER: item->character = interpreter_state->stack->character; break; case STACK_BOOLEAN: item->boolean = interpreter_state->stack->boolean; break; case STACK_TOKEN_STRING: case STACK_CALLABLE: item->token_string = copy_token_string(interpreter_state->stack->token_string); break; } interpreter_state->stack = item; return TRUE; } Boolean builtin_eval(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; StackItem *code_target = interpreter_state->stack; interpreter_state->stack = code_target->next; code_target->next = NULL; Boolean return_value = FALSE; if (code_target->type == STACK_TOKEN_STRING || code_target->type == STACK_CALLABLE) return_value = execute_token_string(interpreter_state, code_target->token_string); else if (code_target->type == STACK_IDENTIFIER) return_value = execute_func(interpreter_state, code_target->identifier.name); clean_stack(code_target); return return_value; } Boolean builtin_floor(InterpreterState *interpreter_state) { NUMERIC_TYPE; FLOAT_FUNCTION(floor); } Boolean builtin_for(InterpreterState *interpreter_state) { (void)interpreter_state; return FALSE; } Boolean builtin_if(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; StackItem *else_block = interpreter_state->stack; if (else_block->next == NULL) return FALSE; StackItem *then_block = else_block->next; if (then_block->next == NULL) return FALSE; StackItem *conditional = then_block->next; if (!( else_block->type == STACK_TOKEN_STRING || else_block->type == STACK_CALLABLE || else_block->type == STACK_IDENTIFIER )) return FALSE; if (!( then_block->type == STACK_TOKEN_STRING || then_block->type == STACK_CALLABLE || then_block->type == STACK_IDENTIFIER )) return FALSE; interpreter_state->stack = conditional->next; conditional->next = NULL; TRUTHY; Boolean return_value = FALSE; if (value) { if (then_block->type == STACK_TOKEN_STRING || then_block->type == STACK_CALLABLE) return_value = execute_token_string(interpreter_state, then_block->token_string); else if (then_block->type == STACK_IDENTIFIER) return_value = execute_func(interpreter_state, then_block->identifier.name); } else { if (else_block->type == STACK_TOKEN_STRING || else_block->type == STACK_CALLABLE) return_value = execute_token_string(interpreter_state, else_block->token_string); else if (else_block->type == STACK_IDENTIFIER) return_value = execute_func(interpreter_state, else_block->identifier.name); } clean_stack(else_block); return return_value; } Boolean builtin_lambda(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; if (interpreter_state->stack->type != STACK_TOKEN_STRING) return FALSE; interpreter_state->stack->type = STACK_CALLABLE; return TRUE; } Boolean builtin_ln(InterpreterState *interpreter_state) { NUMERIC_TYPE; if (af <= 0) return FALSE; FLOAT_FUNCTION(log); } Boolean builtin_log(InterpreterState *interpreter_state) { NUMERIC_TYPE; if (af <= 0) return FALSE; FLOAT_FUNCTION(log10); } Boolean builtin_logb(InterpreterState *interpreter_state) { (void)interpreter_state; return FALSE; } Boolean builtin_max(InterpreterState *interpreter_state) { (void)interpreter_state; return FALSE; } Boolean builtin_min(InterpreterState *interpreter_state) { (void)interpreter_state; return FALSE; } Boolean builtin_not(InterpreterState *interpreter_state) { NUMERIC_TYPE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_FLOAT) { return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = (Boolean){ !af }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = (Boolean){ !ai }, }); } } Boolean builtin_or(InterpreterState *interpreter_state) { NUMERIC_TYPES; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_FLOAT) { return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = (Boolean){ bf || af }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_BOOLEAN, .boolean_literal = (Boolean){ bi || ai }, }); } } Boolean builtin_pick(InterpreterState *interpreter_state) { NUMERIC_TYPE; (void)af; if (type & NUMERIC_FLOAT) return FALSE; StackItem *picked = interpreter_state->stack->next; for (size_t i = 0; i < ai; i++) { picked = picked->next; if (picked == NULL) return FALSE; } if (picked == NULL) return FALSE; StackItem *node = interpreter_state->stack; if (node == NULL) return FALSE; interpreter_state->stack = node->next; node->next = NULL; clean_stack(node); StackItem *item = (StackItem *)malloc(sizeof(StackItem)); if (item == NULL) return FALSE; item->type = picked->type; item->next = interpreter_state->stack; switch (interpreter_state->stack->type) { case STACK_IDENTIFIER: item->identifier = picked->identifier; break; case STACK_I64: item->i64 = picked->i64; break; case STACK_I32: item->i32 = picked->i32; break; case STACK_I16: item->i16 = picked->i16; break; case STACK_I8: item->i8 = picked->i8; break; case STACK_U64: item->u64 = picked->u64; break; case STACK_U32: item->u32 = picked->u32; break; case STACK_U16: item->u16 = picked->u16; break; case STACK_U8: item->u8 = picked->u8; break; case STACK_FLOAT: item->f32 = picked->f32; break; case STACK_DOUBLE: item->f64 = picked->f64; break; case STACK_CHARACTER: item->character = picked->character; break; case STACK_BOOLEAN: item->boolean = picked->boolean; break; case STACK_TOKEN_STRING: case STACK_CALLABLE: item->token_string = copy_token_string(picked->token_string); break; } interpreter_state->stack = item; return TRUE; } Boolean builtin_rand(InterpreterState *interpreter_state) { return push_token(interpreter_state, (Token){ .type = TOKEN_DOUBLE, .double_literal = rand() / RAND_MAX, }); } Boolean builtin_roll(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; if (interpreter_state->stack->next == NULL) return FALSE; StackItem *times_item = interpreter_state->stack; StackItem *count_item = times_item->next; size_t times; switch (times_item->type) { case STACK_IDENTIFIER: return FALSE; case STACK_I64: if (times_item->i64 < 0) return FALSE; times = times_item->i64; break; case STACK_I32: if (times_item->i32 < 0) return FALSE; times = times_item->i32; break; case STACK_I16: if (times_item->i16 < 0) return FALSE; times = times_item->i16; break; case STACK_I8: if (times_item->i8 < 0) return FALSE; times = times_item->i8; break; case STACK_U64: times = times_item->u64; break; case STACK_U32: times = times_item->u32; break; case STACK_U16: times = times_item->u16; break; case STACK_U8: times = times_item->u8; break; case STACK_FLOAT: return FALSE; case STACK_DOUBLE: return FALSE; case STACK_CHARACTER: times = times_item->character; break; case STACK_BOOLEAN: times = times_item->boolean; break; case STACK_TOKEN_STRING: case STACK_CALLABLE: return FALSE; } size_t count; switch (count_item->type) { case STACK_IDENTIFIER: return FALSE; case STACK_I64: if (count_item->i64 < 0) return FALSE; count = count_item->i64; break; case STACK_I32: if (count_item->i32 < 0) return FALSE; count = count_item->i32; break; case STACK_I16: if (count_item->i16 < 0) return FALSE; count = count_item->i16; break; case STACK_I8: if (count_item->i8 < 0) return FALSE; count = count_item->i8; break; case STACK_U64: count = count_item->u64; break; case STACK_U32: count = count_item->u32; break; case STACK_U16: count = count_item->u16; break; case STACK_U8: count = count_item->u8; break; case STACK_FLOAT: return FALSE; case STACK_DOUBLE: return FALSE; case STACK_CHARACTER: count = count_item->character; break; case STACK_BOOLEAN: count = count_item->boolean; break; case STACK_TOKEN_STRING: case STACK_CALLABLE: return FALSE; } StackItem *head = NULL, *tail = NULL, *prev = NULL; if (count > 0) { StackItem *node = count_item->next; for (size_t i = 0; i < count; i++) { if (node == NULL) return FALSE; if (i == (count - times) - 1) { tail = node; head = node->next; } prev = node; node = node->next; } } if (head == NULL || tail == NULL) return FALSE; interpreter_state->stack = head; tail->next = prev->next; prev->next = count_item->next; count_item->next = NULL; clean_stack(times_item); return TRUE; } Boolean builtin_rot(InterpreterState *interpreter_state) { (void)interpreter_state; return FALSE; } Boolean builtin_round(InterpreterState *interpreter_state) { NUMERIC_TYPE; FLOAT_FUNCTION(round); } Boolean builtin_seed(InterpreterState *interpreter_state) { NUMERIC_TYPE; (void)af; if (type & NUMERIC_FLOAT) { return FALSE; } StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next; node->next = NULL; clean_stack(node); srand(ai); return TRUE; } Boolean builtin_shl(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)af; (void)bf; if (type & NUMERIC_FLOAT) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = bi << ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = bi << ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = bi << ai, }, }); } else if (type & NUMERIC_SIGNED) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = bi << ai, }, }); } else if (type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = bi << ai, }, }); } else if (type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U32, .value = bi << ai, }, }); } else if (type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U16, .value = bi << ai, }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U8, .value = bi << ai, }, }); } } Boolean builtin_shr(InterpreterState *interpreter_state) { NUMERIC_TYPES; (void)af; (void)bf; if (type & NUMERIC_FLOAT) return FALSE; StackItem *node = interpreter_state->stack; interpreter_state->stack = interpreter_state->stack->next->next; node->next->next = NULL; clean_stack(node); if (type & NUMERIC_SIGNED && type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I64, .value = bi >> ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I32, .value = bi >> ai, }, }); } else if (type & NUMERIC_SIGNED && type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I16, .value = bi >> ai, }, }); } else if (type & NUMERIC_SIGNED) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_I8, .value = bi >> ai, }, }); } else if (type & NUMERIC_64) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U64, .value = bi >> ai, }, }); } else if (type & NUMERIC_32) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U32, .value = bi >> ai, }, }); } else if (type & NUMERIC_16) { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U16, .value = bi >> ai, }, }); } else { return push_token(interpreter_state, (Token){ .type = TOKEN_INTEGER, .integer_literal = (IntegerLiteral){ .type = INTEGER_U8, .value = bi >> ai, }, }); } } Boolean builtin_sin(InterpreterState *interpreter_state) { NUMERIC_TYPE; FLOAT_FUNCTION(sin); } Boolean builtin_sqrt(InterpreterState *interpreter_state) { NUMERIC_TYPE; if (af < 0) return FALSE; FLOAT_FUNCTION(sqrt); } Boolean builtin_swap(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; if (interpreter_state->stack->next == NULL) return FALSE; StackItem *a = interpreter_state->stack; StackItem *b = a->next; a->next = b->next; b->next = a; interpreter_state->stack = b; return TRUE; } Boolean builtin_tan(InterpreterState *interpreter_state) { NUMERIC_TYPE; FLOAT_FUNCTION(tan); } Boolean builtin_type_of(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; return push_token(interpreter_state, (Token){ .type = TOKEN_IDENTIFIER, .identifier = (Identifier){ .is_literal = TRUE, .name = sls_str_malloc(STACK_TYPES_TYPES[interpreter_state->stack->type], TYPE_NAMES_SAFE_LENGTH), }, }); } Boolean builtin_while(InterpreterState *interpreter_state) { if (interpreter_state->stack == NULL) return FALSE; StackItem *while_block = interpreter_state->stack; if (while_block->next == NULL) return FALSE; StackItem *conditional_block = while_block->next; if (!( while_block->type == STACK_TOKEN_STRING || while_block->type == STACK_CALLABLE || while_block->type == STACK_IDENTIFIER )) return FALSE; if (!( conditional_block->type == STACK_TOKEN_STRING || conditional_block->type == STACK_CALLABLE || conditional_block->type == STACK_IDENTIFIER )) return FALSE; interpreter_state->stack = conditional_block->next; conditional_block->next = NULL; Boolean return_value = FALSE; while (TRUE) { if (conditional_block->type == STACK_TOKEN_STRING || conditional_block->type == STACK_CALLABLE) return_value = execute_token_string(interpreter_state, conditional_block->token_string); else if (conditional_block->type == STACK_IDENTIFIER) return_value = execute_func(interpreter_state, conditional_block->identifier.name); if (!return_value) break; if (interpreter_state->stack == NULL) return FALSE; StackItem *conditional = interpreter_state->stack; interpreter_state->stack = conditional->next; conditional->next = NULL; TRUTHY; clean_stack(conditional); if (!value) break; if (while_block->type == STACK_TOKEN_STRING || while_block->type == STACK_CALLABLE) return_value = execute_token_string(interpreter_state, while_block->token_string); else if (while_block->type == STACK_IDENTIFIER) return_value = execute_func(interpreter_state, while_block->identifier.name); if (!return_value) break; } clean_stack(while_block); return return_value; }