201 lines
5.4 KiB
C
201 lines
5.4 KiB
C
// Kyler Olsen
|
|
// YREA SLS
|
|
// Interpreter
|
|
// November 2025
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "sls/string.h"
|
|
#include "sls/interpreter.h"
|
|
#include "sls/lexer.h"
|
|
#include "sls/hash_table.h"
|
|
#include "sls/builtin.h"
|
|
|
|
static const size_t HASH_TABLE_BUCKET_COUNT = 256;
|
|
|
|
const char *STACK_TYPES_NAMES[] = {
|
|
"Identifier",
|
|
"64-bit Integer",
|
|
"32-bit Integer",
|
|
"16-bit Integer",
|
|
"8-bit Integer",
|
|
"64-bit U Integer",
|
|
"32-bit U Integer",
|
|
"16-bit U Integer",
|
|
"8-bit U Integer",
|
|
"Float",
|
|
"Double",
|
|
"Character",
|
|
"Boolean",
|
|
"Token String",
|
|
};
|
|
|
|
const size_t STACK_TYPE_COUNT = sizeof(STACK_TYPES_NAMES) / sizeof(*STACK_TYPES_NAMES);
|
|
|
|
static inline Boolean hash_table_put_funcs(HashTable *ht, SlsStr key, FunctionItem *item) {
|
|
return hash_table_put(ht, key, (void *)item);
|
|
}
|
|
|
|
static inline FunctionItem *hash_table_get_funcs(const HashTable *ht, SlsStr key, FunctionItem *default_item) {
|
|
return (FunctionItem*)hash_table_get(ht, key, (void *)default_item);
|
|
}
|
|
|
|
Boolean push_token(InterpreterState *interpreter_state, Token token) {
|
|
StackType type;
|
|
switch (token.type) {
|
|
case TOKEN_EOF:
|
|
return TRUE;
|
|
case TOKEN_IDENTIFIER:
|
|
type = STACK_IDENTIFIER;
|
|
break;
|
|
case TOKEN_INTEGER:
|
|
switch (token.integer_literal.type) {
|
|
case INTEGER_I64:
|
|
type = STACK_I64;
|
|
break;
|
|
case INTEGER_I32:
|
|
type = STACK_I32;
|
|
break;
|
|
case INTEGER_I16:
|
|
type = STACK_I16;
|
|
break;
|
|
case INTEGER_I8:
|
|
type = STACK_I8;
|
|
break;
|
|
case INTEGER_U64:
|
|
type = STACK_U64;
|
|
break;
|
|
case INTEGER_U32:
|
|
type = STACK_U32;
|
|
break;
|
|
case INTEGER_U16:
|
|
type = STACK_U16;
|
|
break;
|
|
case INTEGER_U8:
|
|
type = STACK_U8;
|
|
break;
|
|
}
|
|
break;
|
|
case TOKEN_FLOAT:
|
|
type = STACK_FLOAT;
|
|
break;
|
|
case TOKEN_DOUBLE:
|
|
type = STACK_DOUBLE;
|
|
break;
|
|
case TOKEN_CHARACTER:
|
|
type = STACK_CHARACTER;
|
|
break;
|
|
case TOKEN_STRING:
|
|
return FALSE;
|
|
case TOKEN_BOOLEAN:
|
|
type = STACK_BOOLEAN;
|
|
break;
|
|
case TOKEN_ARRAY:
|
|
return FALSE;
|
|
case TOKEN_TOKEN_STRING:
|
|
type = STACK_TOKEN_STRING;
|
|
break;
|
|
case TOKEN_TYPE_TUPLE:
|
|
return FALSE;
|
|
}
|
|
|
|
StackItem *item = (StackItem *)malloc(sizeof(StackItem));
|
|
if (item == NULL) return FALSE;
|
|
item->type = type;
|
|
item->next = interpreter_state->stack;
|
|
interpreter_state->stack = item;
|
|
|
|
switch (type) {
|
|
case STACK_IDENTIFIER:
|
|
item->identifier = token.identifier;
|
|
break;
|
|
case STACK_I64:
|
|
item->i64 = (int64_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_I32:
|
|
item->i32 = (int32_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_I16:
|
|
item->i16 = (int16_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_I8:
|
|
item->i8 = (int8_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_U64:
|
|
item->u64 = (uint64_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_U32:
|
|
item->u32 = (uint32_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_U16:
|
|
item->u16 = (uint16_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_U8:
|
|
item->u8 = (uint8_t)token.integer_literal.value;
|
|
break;
|
|
case STACK_FLOAT:
|
|
item->f32 = token.float_literal;
|
|
break;
|
|
case STACK_DOUBLE:
|
|
item->f64 = token.double_literal;
|
|
break;
|
|
case STACK_CHARACTER:
|
|
item->character = token.character_literal;
|
|
break;
|
|
case STACK_BOOLEAN:
|
|
item->boolean = token.boolean_literal;
|
|
break;
|
|
case STACK_TOKEN_STRING:
|
|
item->token_string = copy_token_string(token.token_string);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Boolean execute_func(InterpreterState *interpreter_state, SlsStr key) {
|
|
FunctionItem *func = hash_table_get_funcs(interpreter_state->functions, key, NULL);
|
|
if (func == NULL) return FALSE;
|
|
switch (func->type) {
|
|
case FUNCTION_BUILTIN:
|
|
return func->builtin(interpreter_state);
|
|
case FUNCTION_TOKEN_STRING:
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
Boolean execute(InterpreterState *interpreter_state, LexerTokenResult *token) {
|
|
if (token->result.type == TOKEN_IDENTIFIER && !token->result.identifier.is_literal)
|
|
return execute_func(interpreter_state, token->result.identifier.name);
|
|
else
|
|
return push_token(interpreter_state, token->result);
|
|
}
|
|
|
|
InterpreterState *interpreter_create() {
|
|
InterpreterState *interpreter_state = (InterpreterState *)malloc(sizeof(InterpreterState));
|
|
if (interpreter_state == NULL)
|
|
return NULL;
|
|
interpreter_state->stack = NULL;
|
|
interpreter_state->functions = init_hash_table(HASH_TABLE_BUCKET_COUNT);
|
|
if (!load_builtins(interpreter_state)) {
|
|
interpreter_delete(interpreter_state);
|
|
return NULL;
|
|
}
|
|
return interpreter_state;
|
|
}
|
|
|
|
void clean_stack(StackItem *item) {
|
|
if (item == NULL) return;
|
|
if (item->type == STACK_TOKEN_STRING)
|
|
clean_token_string(item->token_string);
|
|
clean_stack(item->next);
|
|
free(item);
|
|
}
|
|
|
|
void interpreter_delete(InterpreterState *interpreter_state) {
|
|
clean_stack(interpreter_state->stack);
|
|
del_hash_table(interpreter_state->functions);
|
|
free(interpreter_state);
|
|
}
|