Skip to content

Instantly share code, notes, and snippets.

@oreyg
Created December 8, 2023 22:42
Show Gist options
  • Save oreyg/95b21f3ceafc14a7c4f60d8e348c12d7 to your computer and use it in GitHub Desktop.
Save oreyg/95b21f3ceafc14a7c4f60d8e348c12d7 to your computer and use it in GitHub Desktop.
#include "hscript.h"
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <assert.h>
HSId HScript_new_id()
{
int lr = rand() * -1;
int hr = rand();
uint32_t* plr = (uint32_t*)(&lr);
uint32_t* phr = (uint32_t*)(&hr);
return ((size_t)(*phr) << 32) | (*plr);
}
uint64_t inline HScript_to_pot(uint64_t n)
{
if (n == 0)
{
return 1;
}
--n;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
return n + 1;
}
//#define HScript_resize_auto(x, co, ct) HScript_resize(x, sizeof((*(x)[0])), co, ct)
//#define HScript_grow(x, co) HScript_resize_auto(x, co, co + 1)
//#define HScript_shrink(x, co) HScript_resize_auto(x, co, co - 1)
static inline bool HScript_resize(void** buffer, size_t block_size, size_t original_block_count, size_t target_block_count)
{
HS_ASSERT_RETURN(buffer != NULL, false);
if (target_block_count == 0 && (*buffer) != NULL)
{
free(*buffer);
(*buffer) = NULL;
return true;
}
const size_t orig_pot = HScript_to_pot(block_size * original_block_count);
const size_t next_pot = HScript_to_pot(block_size * target_block_count);
if (orig_pot != next_pot)
{
void* new_mem = realloc(*buffer, next_pot);
if (new_mem)
{
(*buffer) = new_mem;
}
return new_mem != NULL;
}
return true;
}
static inline void HScript_to_uppercase(char* uppercase, size_t max_uppercase)
{
for (size_t i = 0; i < max_uppercase; ++i)
{
uppercase[i] = toupper(uppercase[i]);
}
uppercase[max_uppercase - 1] = 0;
}
static inline int HScript_compare_id_defn(const HSDefn* first, const HSDefn* second)
{
return first->id < second->id ? -1 : first->id == second->id ? 0 : 1;
}
static inline int HScript_compare_id_node(const HSNode* first, const HSNode* second)
{
return first->node_id < second->node_id ? -1 : first->node_id == second->node_id ? 0 : 1;
}
static inline int HScript_compare_id_link(const HSLink* first, const HSLink* second)
{
return first->id < second->id ? -1 : first->id == second->id ? 0 : 1;
}
static inline int HScript_compare_func(const HSFuncReg* first, const HSFuncReg* second)
{
return strcmp(first->fun_name, second->fun_name);
}
int HScript_compare_defn_name(const HSDefn* first, const HSDefn* second)
{
return strcmp(first->name, second->name);
}
int HScript_compare_defn_name2(const void* first, const void* second)
{
return strcmp((*(HSDefn**)(first))->name, (*(HSDefn**)second)->name);
}
static void HScript_process_unresolved(HSFnContext* context)
{
printf("Unresolved function called\n");
}
// MurMur64
uint64_t HScript_hash64(const void* key, size_t len, uint64_t seed)
{
const uint64_t m = 0xc6a4a7935bd1e995ULL;
const int r = 47;
uint64_t h = seed ^ (len * m);
const uint64_t* data = (const uint64_t*)key;
const uint64_t* end = data + (len / 8);
while (data != end)
{
uint64_t k = *data++;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
}
const unsigned char* data2 = (const unsigned char*)data;
switch (len & 7)
{
case 7: h ^= (uint64_t)(data2[6]) << 48;
case 6: h ^= (uint64_t)(data2[5]) << 40;
case 5: h ^= (uint64_t)(data2[4]) << 32;
case 4: h ^= (uint64_t)(data2[3]) << 24;
case 3: h ^= (uint64_t)(data2[2]) << 16;
case 2: h ^= (uint64_t)(data2[1]) << 8;
case 1: h ^= (uint64_t)(data2[0]);
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
bool HScript_index_defn_names(HSRawContext* context, HSIndex* str)
{
const bool success = HScript_resize(&str->obj, sizeof(uintptr_t*), str->arr_size, context->defns_size);
if (success)
{
for (size_t i = 0; i < context->defns_size; i++)
{
str->obj[i] = (uintptr_t)&context->defns[i];
}
qsort(str->obj, context->defns_size, sizeof(uintptr_t*), HScript_compare_defn_name2);
str->arr_size = context->defns_size;
return true;
}
else
{
HS_ASSERT_RETURN(false, false);
}
return false;
}
void HScript_index_initialize(HSIndex* str)
{
str->obj = 0;
str->arr_size = 0;
}
void HScript_index_reset(HSIndex* str)
{
if (str->obj)
{
free(str->obj);
}
str->arr_size = 0;
}
ESArgType HScript_parse_typename(const char* type, size_t size)
{
char uppercase[HS_TYPE_MAX_SIZE];
memset(uppercase, 0, HS_TYPE_MAX_SIZE);
strncpy_s(uppercase, HS_TYPE_MAX_SIZE, type, size);
HScript_to_uppercase(uppercase, HS_TYPE_MAX_SIZE);
if (strncmp(uppercase, "EXECUTION", HS_TYPE_MAX_SIZE) == 0)
{
return HS_EXECUTION;
}
else if (strncmp(uppercase, "INT", HS_TYPE_MAX_SIZE) == 0)
{
return HS_INT;
}
else if (strncmp(uppercase, "FLOAT", HS_TYPE_MAX_SIZE) == 0)
{
return HS_FLOAT;
}
else if (strncmp(uppercase, "BOOLEAN", HS_TYPE_MAX_SIZE) == 0)
{
return HS_BOOLEAN;
}
else if (strncmp(uppercase, "ENTITY", HS_TYPE_MAX_SIZE) == 0)
{
return HS_ENTITY;
}
else if (strncmp(uppercase, "OBJECT", HS_TYPE_MAX_SIZE) == 0)
{
return HS_OBJECT;
}
else if (strncmp(uppercase, "ARRAY", HS_TYPE_MAX_SIZE) == 0)
{
return HS_ARRAY;
}
else if (strncmp(uppercase, "BOOL", HS_TYPE_MAX_SIZE) == 0)
{
return HS_BOOLEAN;
}
else if (strncmp(uppercase, "EXEC", HS_TYPE_MAX_SIZE) == 0)
{
return HS_EXECUTION;
}
else if (strncmp(uppercase, "I", HS_TYPE_MAX_SIZE) == 0)
{
return HS_INT;
}
else if (strncmp(uppercase, "F", HS_TYPE_MAX_SIZE) == 0)
{
return HS_FLOAT;
}
else if (strncmp(uppercase, "B", HS_TYPE_MAX_SIZE) == 0)
{
return HS_BOOLEAN;
}
else if (strncmp(uppercase, "E", HS_TYPE_MAX_SIZE) == 0)
{
return HS_EXECUTION;
}
return HS_TYPE_ERROR;
}
HSDefn* HScript_defn_find(HSDefn* defns, size_t defn_count, HSId id)
{
//for (size_t i = 0; i < defn_count; i++)
//{
// if (defns[i].id == id)
// {
// return &defns[i];
// }
//}
//
//return NULL;
HSDefn search_defn;
search_defn.id = id;
return bsearch(&search_defn, defns, defn_count, sizeof(HSDefn), HScript_compare_id_defn);
}
HSNode* HScript_node_find(HSNode* nodes, size_t node_count, HSId id)
{
//for (size_t i = 0; i < node_count; i++)
//{
// if (nodes[i].node_id == id)
// {
// return &nodes[i];
// }
//}
//
//return NULL;
HSNode search_node;
search_node.node_id = id;
return bsearch(&search_node, nodes, node_count, sizeof(HSNode), HScript_compare_id_node);
}
HSDefnArg* HScript_defn_find_argument(HSDefn* defn, const char* name)
{
for (size_t i = 0; i < defn->i_size; i++)
{
HSDefnArg* arg = &defn->inputs[i];
if (strcmp(arg->name, name) == 0)
{
return arg;
}
}
for (size_t i = 0; i < defn->o_size; i++)
{
HSDefnArg* arg = &defn->outputs[i];
if (strcmp(arg->name, name) == 0)
{
return arg;
}
}
return NULL;
}
HSNodeArg* HScript_node_find_argument(HSNode* node, const char* name)
{
for (size_t i = 0; i < node->args_size; i++)
{
HSNodeArg* arg = &node->args[i];
if (strcmp(arg->name, name) == 0)
{
return arg;
}
}
return NULL;
}
HSLink* HScript_link_find_source(HSLink* links, size_t link_count, HSId id, const char* name)
{
for (size_t i = 0; i < link_count; i++)
{
if (links[i].node_source_id == id && strcmp(links[i].arg_source_name, name) == 0)
{
return &links[i];
}
}
return NULL;
}
HSLink* HScript_link_find_target(HSLink* links, size_t link_count, HSId id, const char* name)
{
for (size_t i = 0; i < link_count; i++)
{
if (links[i].node_target_id == id && strcmp(links[i].arg_target_name, name) == 0)
{
return &links[i];
}
}
return NULL;
}
HSFuncReg* HScript_func_find(HSFuncReg* funcs, size_t func_count, const char* name)
{
for (size_t i = 0; i < func_count; i++)
{
if (strcmp(funcs[i].fun_name, name) == 0)
{
return &funcs[i];
}
}
return NULL;
}
bool HScript_validate_next_node(HSNodeError* error, HSDefn* defns, size_t defn_count, HSNode* nodes, size_t node_count)
{
for (size_t i = error->next_idx; i < node_count; i++)
{
HSNode* node = &nodes[i];
HSDefn* defn = HScript_defn_find(defns, defn_count, node->defn_id);
error->next_idx = i + 1;
error->next_arg_idx = 0;
error->proc_node = node;
error->proc_defn = defn;
if (defn == NULL)
{
error->node_id = node->node_id;
error->node_arg_name = "";
error->node_arg_type = HS_TYPE_ERROR;
error->defn_arg_type = HS_TYPE_ERROR;
error->state = HS_NODE_DEF_MISSING;
return i < node_count;
}
if (HScript_validate_next_node_arg(error))
{
return true;
}
}
error->node_id = HS_NIL_VALUE;
error->node_arg_name = "";
error->node_arg_type = HS_TYPE_ERROR;
error->defn_arg_type = HS_TYPE_ERROR;
error->next_idx = node_count;
error->next_arg_idx = 0;
error->proc_node = NULL;
error->proc_defn = NULL;
error->state = HS_NODE_SUCCESS;
return false;
}
bool HScript_validate_next_link(HSLinkError* error, HSNode* nodes, size_t node_count, HSLink* links, size_t link_count)
{
for (size_t i = error->next_idx; i < link_count; i++)
{
HSLink* link = &links[i];
// TO-DO: Check that there are no duplicate links
HSNode* node_source = HScript_node_find(nodes, node_count, link->node_source_id);
HSNode* node_target = HScript_node_find(nodes, node_count, link->node_target_id);
ESArgType source_type = HS_TYPE_ERROR;
if (node_source != NULL)
{
HSNodeArg* arg = HScript_node_find_argument(node_source, link->arg_source_name);
if (arg != NULL)
{
source_type = arg->type;
}
}
ESArgType target_type = HS_TYPE_ERROR;
if (node_target != NULL)
{
HSNodeArg* arg = HScript_node_find_argument(node_target, link->arg_target_name);
if (arg != NULL)
{
target_type = arg->type;
}
}
if (node_source == NULL)
{
error->link_id = link->id;
error->source_node_id = link->node_source_id;
error->target_node_id = link->node_target_id;
error->source_node = node_source;
error->target_node = node_target;
error->source_name = link->arg_source_name;
error->source_name = link->arg_target_name;
error->source_type = source_type;
error->target_type = target_type;
error->state = HS_LINK_SOURCE_NODE_MISSING;
error->next_idx = i + 1;
return true;
}
else if (source_type == HS_TYPE_ERROR)
{
error->link_id = link->id;
error->source_node_id = link->node_source_id;
error->target_node_id = link->node_target_id;
error->source_node = node_source;
error->target_node = node_target;
error->source_name = link->arg_source_name;
error->source_name = link->arg_target_name;
error->source_type = source_type;
error->target_type = target_type;
error->state = HS_LINK_SOURCE_ARG_MISSING;
error->next_idx = i + 1;
return true;
}
if (node_target == NULL)
{
error->link_id = link->id;
error->source_node_id = link->node_source_id;
error->target_node_id = link->node_target_id;
error->source_node = node_source;
error->target_node = node_target;
error->source_name = link->arg_source_name;
error->source_name = link->arg_target_name;
error->source_type = source_type;
error->target_type = target_type;
error->state = HS_LINK_TARGET_NODE_MISSING;
error->next_idx = i + 1;
return true;
}
else if (target_type == HS_TYPE_ERROR)
{
error->link_id = link->id;
error->source_node_id = link->node_source_id;
error->target_node_id = link->node_target_id;
error->source_node = node_source;
error->target_node = node_target;
error->source_name = link->arg_source_name;
error->source_name = link->arg_target_name;
error->source_type = source_type;
error->target_type = target_type;
error->state = HS_LINK_TARGET_ARG_MISSING;
error->next_idx = i + 1;
return true;
}
if (node_source != NULL && node_target != NULL && source_type != target_type)
{
error->link_id = link->id;
error->source_node_id = link->node_source_id;
error->target_node_id = link->node_target_id;
error->source_node = node_source;
error->target_node = node_target;
error->source_name = link->arg_source_name;
error->source_name = link->arg_target_name;
error->source_type = source_type;
error->target_type = target_type;
error->state = HS_LINK_TYPE_MISMATCH;
error->next_idx = i + 1;
return true;
}
}
error->link_id = HS_NIL_VALUE;
error->source_node_id = HS_NIL_VALUE;
error->target_node_id = HS_NIL_VALUE;
error->source_node = NULL;
error->target_node = NULL;
error->source_name = "";
error->source_name = "";
error->source_type = HS_TYPE_ERROR;
error->target_type = HS_TYPE_ERROR;
error->state = HS_LINK_SUCCESS;
error->next_idx = node_count;
return false;
}
bool HScript_validate_next_defn(HSDefnError* error, HSDefn* defns, size_t defn_count, size_t start_idx)
{
error->defn_id = HS_NIL_VALUE;
return false;
}
bool HScript_validate_next_node_arg(HSNodeError* error)
{
HSNode* node = error->proc_node;
HSDefn* defn = error->proc_defn;
for (size_t j = error->next_arg_idx; j < node->args_size; j++)
{
HSNodeArg* node_arg = &node->args[j];
HSDefnArg* defn_arg = HScript_defn_find_argument(defn, node_arg->name);
if (defn_arg == NULL)
{
error->node_arg_name = node_arg->name;
error->node_arg_type = node_arg->type;
error->defn_arg_type = HS_TYPE_ERROR;
error->state = HS_NODE_ARG_NAME_MISMATCH;
error->next_arg_idx = j + 1;
return j < node->args_size;
}
if (defn_arg->type != node_arg->type)
{
error->node_arg_name = node_arg->name;
error->node_arg_type = node_arg->type;
error->defn_arg_type = defn_arg->type;
error->state = HS_NODE_ARG_TYPE_MISMATCH;
error->next_arg_idx = j + 1;
return j < node->args_size;
}
}
error->node_arg_name = "";
error->node_arg_type = HS_TYPE_ERROR;
error->defn_arg_type = HS_TYPE_ERROR;
error->state = HS_NODE_ARG_TYPE_MISMATCH;
error->next_arg_idx = node->args_size;
return false;
}
bool HScript_stringify_argument_type(ESArgType argument_type, char* buffer, size_t size)
{
if (size < 32)
{
return false;
}
memset(buffer, 0, size);
switch (argument_type)
{
case HS_EXECUTION:
{
const char str[] = "execution";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
case HS_INT:
{
const char str[] = "integer";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
case HS_FLOAT:
{
const char str[] = "float";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
case HS_BOOLEAN:
{
const char str[] = "boolean";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
case HS_ENTITY:
{
const char str[] = "entity";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
case HS_OBJECT:
{
const char str[] = "object";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
case HS_STRUCT:
{
const char str[] = "struct";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
case HS_ARRAY:
{
const char str[] = "array";
strncpy_s(buffer, sizeof(str), str, size);
}
break;
default:
{
const char str[] = "error";
strncpy_s(buffer, sizeof(str), str, size);
}
}
return true;
}
bool HScript_stringify_node_error(HSNodeError* error, char* buffer, size_t size)
{
if (size < 256)
{
return false;
}
memset(buffer, 0, size);
switch (error->state)
{
case HS_NODE_DEF_MISSING:
{
snprintf(buffer, size, "Can't find definition for node with Id '%llu'.", error->node_id);
}
break;
case HS_NODE_ARG_NAME_MISMATCH:
{
snprintf(buffer, size, "Can't find argument '%s' for node with Id '%llu'.", error->node_arg_name, error->node_id);
}
break;
case HS_NODE_ARG_TYPE_MISMATCH:
{
char node_arg_typename[32];
char defn_arg_typename[32];
if (HScript_stringify_argument_type(error->node_arg_type, node_arg_typename, sizeof(node_arg_typename)) &&
HScript_stringify_argument_type(error->defn_arg_type, defn_arg_typename, sizeof(defn_arg_typename)))
{
snprintf(buffer, size, "Type mismatch in argument '%s': '%s' and '%s' for node with Id '%llu'.", error->node_arg_name, node_arg_typename, defn_arg_typename, error->node_id);
}
else
{
return false;
}
}
break;
default:
{
const char str[] = "Can't process error.";
strncpy_s(buffer, sizeof(str), str, size);
}
}
return true;
}
bool HScript_stringify_link_error(HSLinkError* error, char* buffer, size_t size)
{
if (size < 256)
{
return false;
}
switch (error->state)
{
case HS_LINK_SOURCE_NODE_MISSING:
{
snprintf(buffer, size, "Can't find source node for link with Id '%llu'.", error->link_id);
}
break;
case HS_LINK_TARGET_NODE_MISSING:
{
snprintf(buffer, size, "Can't find target node for link with Id '%llu'.", error->link_id);
}
break;
case HS_LINK_SOURCE_ARG_MISSING:
{
snprintf(buffer, size, "Can't find source argument '%s' for link with Id '%llu'.", error->source_name, error->link_id);
}
break;
case HS_LINK_TARGET_ARG_MISSING:
{
snprintf(buffer, size, "Can't find target argument '%s' for link with Id '%llu'.", error->target_name, error->link_id);
}
break;
case HS_LINK_TYPE_MISMATCH:
{
char source_type[32];
char target_type[32];
if (HScript_stringify_argument_type(error->source_type, source_type, sizeof(source_type)) &&
HScript_stringify_argument_type(error->target_type, target_type, sizeof(target_type)))
{
snprintf(buffer, size, "Type mismatch between arguments '%s' ('%s') and '%s' ('%s').", error->source_name, source_type, error->target_name, target_type);
}
else
{
return false;
}
}
break;
default:
{
const char str[] = "Can't process error.";
strncpy_s(buffer, sizeof(str), str, size);
}
}
return true;
}
bool HScript_rawcontext_build_nodes(HSRawContext* context)
{
// -- Populate defaults start
for (size_t i = 0; i < context->nodes_size; i++)
{
HSNode* node = &context->nodes[i];
HSDefn* defn = HScript_defn_find(context->defns, context->defns_size, node->defn_id);
if (!defn)
{
continue;
}
for (size_t j = 0; j < defn->i_size; j++)
{
HSNodeArg* arg = HScript_node_find_argument(node, defn->inputs[j].name);
if (arg == NULL)
{
HSNodeArg new_arg;
new_arg.name = defn->inputs[j].name;
new_arg.type = defn->inputs[j].type;
new_arg.value = defn->inputs[j].value;
new_arg.dflt = true;
HScript_node_arg_push(context, node, &new_arg);
}
}
for (size_t j = 0; j < defn->o_size; j++)
{
HSNodeArg* arg = HScript_node_find_argument(node, defn->outputs[j].name);
if (arg == NULL)
{
HSNodeArg new_arg;
new_arg.name = defn->outputs[j].name;
new_arg.type = defn->outputs[j].type;
new_arg.value = defn->outputs[j].value;
new_arg.dflt = true;
HScript_node_arg_push(context, node, &new_arg);
}
}
HSFuncReg* func = HScript_func_find(context->funcs, context->funcs_size, defn->name);
if (func)
{
node->func = func->fun_ptr;
}
else
{
node->func = HScript_process_unresolved;
}
}
// Arguments in nodes should match the order in which they are declared
for (size_t i = 0; i < context->nodes_size; i++)
{
HSNode* node = &context->nodes[i];
HSDefn* defn = HScript_defn_find(context->defns, context->defns_size, node->defn_id);
if (!defn)
{
continue;
}
node->i_size = defn->i_size;
for (size_t j = 0; j < defn->i_size; j++)
{
HSNodeArg* arg = HScript_node_find_argument(node, defn->inputs[j].name);
const size_t arg_idx = (arg - node->args);
if (arg != NULL && (node->args - arg) != j)
{
HSNodeArg tmp = node->args[j];
node->args[j] = (*arg);
(*arg) = tmp;
}
}
for (size_t j = 0; j < defn->o_size; j++)
{
HSNodeArg* arg = HScript_node_find_argument(node, defn->outputs[j].name);
const size_t tgt_idx = j + defn->i_size;
const size_t arg_idx = arg - node->args;
if (arg != NULL && arg_idx != tgt_idx)
{
HSNodeArg tmp = node->args[tgt_idx];
node->args[tgt_idx] = (*arg);
(*arg) = tmp;
}
}
}
// -- Populate defaults end
return true;
}
bool HScript_rawcontext_build_links(HSRawContext* context)
{
// -- Link all nodes
for (size_t i = 0; i < context->nodes_size; i++)
{
HSNode* node = &context->nodes[i];
for (size_t j = 0; j < node->args_size; j++)
{
node->args[j].cnode = 0;
node->args[j].carg = 0;
}
}
for (size_t i = 0; i < context->links_size; i++)
{
HSLink* link = &context->links[i];
HSNode* source_node = HScript_node_find(context->nodes, context->nodes_size, link->node_source_id);
if (source_node == NULL)
{
continue;
}
HSNodeArg* source_arg = HScript_node_find_argument(source_node, link->arg_source_name);
if (source_arg == NULL)
{
continue;
}
HSNode* target_node = HScript_node_find(context->nodes, context->nodes_size, link->node_target_id);
if (target_node == NULL)
{
continue;
}
HSNodeArg* target_arg = HScript_node_find_argument(target_node, link->arg_target_name);
if (target_arg == NULL)
{
continue;
}
uintptr_t source_idx = (uintptr_t)(source_arg - source_node->args);
uintptr_t target_idx = (uintptr_t)(target_arg - target_node->args);
source_arg->cnode = target_node;
source_arg->carg = target_idx;
target_arg->cnode = source_node;
target_arg->carg = source_idx;
}
// -- Link all nodes end
return true;
}
bool HScript_rawcontext_build_string(HSRawContext* context)
{
// -- String copy start
size_t string_len = 0;
// Calc string lengths for definitions
for (size_t i = 0; i < context->defns_size; i++)
{
HSDefn* defn = &context->defns[i];
string_len += strnlen_s(defn->name, 1024) + 1;
// Inputs
for (size_t j = 0; j < defn->i_size; j++)
{
HSDefnArg* arg = &defn->inputs[j];
string_len += strnlen_s(arg->name, 1024) + 1;
}
// Outputs
for (size_t j = 0; j < defn->o_size; j++)
{
HSDefnArg* arg = &defn->outputs[j];
string_len += strnlen_s(arg->name, 1024) + 1;
}
}
// Calc string lengths for nodes
for (size_t i = 0; i < context->nodes_size; i++)
{
HSNode* node = &context->nodes[i];
for (size_t j = 0; j < node->args_size; j++)
{
HSNodeArg* arg = &node->args[j];
string_len += strnlen_s(arg->name, 1024) + 1;
}
}
// Calc string lenghts for links
for (size_t i = 0; i < context->links_size; i++)
{
HSLink* link = &context->links[i];
string_len += strnlen_s(link->arg_source_name, 1024) + 1;
string_len += strnlen_s(link->arg_target_name, 1024) + 1;
}
// Calc string lenghts for funcs
for (size_t i = 0; i < context->funcs_size; i++)
{
HSFuncReg* func = &context->funcs[i];
string_len += strnlen_s(func->fun_name, 1024) + 1;
}
const size_t pot_size = HScript_to_pot(string_len);
char* buffer = malloc(pot_size);
HS_ASSERT_RETURN(buffer != NULL, false);
memset(buffer, 0, pot_size);
string_len = 0;
#define HSScript_move_str_to_buff(arg) {\
const size_t len = strnlen_s(arg, 1024) + 1; \
memcpy(buffer + string_len, arg, len); \
arg = buffer + string_len; \
string_len += len; \
}
// String copy for defns
for (size_t i = 0; i < context->defns_size; i++)
{
HSDefn* defn = &context->defns[i];
HSScript_move_str_to_buff(defn->name);
for (size_t j = 0; j < defn->i_size; j++)
{
HSScript_move_str_to_buff(defn->inputs[j].name);
}
for (size_t j = 0; j < defn->o_size; j++)
{
HSScript_move_str_to_buff(defn->outputs[j].name);
}
}
// String copy for nodes
for (size_t i = 0; i < context->nodes_size; i++)
{
HSNode* node = &context->nodes[i];
for (size_t j = 0; j < node->args_size; j++)
{
HSScript_move_str_to_buff(node->args[j].name);
}
}
// String copy for links
for (size_t i = 0; i < context->links_size; i++)
{
HSScript_move_str_to_buff(context->links[i].arg_source_name);
HSScript_move_str_to_buff(context->links[i].arg_target_name);
}
// String copy for funcs
for (size_t i = 0; i < context->funcs_size; i++)
{
HSScript_move_str_to_buff(context->funcs[i].fun_name);
}
#undef HSScript_move_str_to_buff
if (context->string_pool != NULL)
{
free(context->string_pool);
}
context->string_pool = buffer;
context->string_pool_size = string_len;
// -- String copy end
return true;
}
bool HScript_rawcontext_commit(HSRawContext* context)
{
// -- Sort all data start
qsort(context->defns, context->defns_size, sizeof(HSDefn), HScript_compare_id_defn);
qsort(context->nodes, context->nodes_size, sizeof(HSNode), HScript_compare_id_node);
qsort(context->links, context->links_size, sizeof(HSLink), HScript_compare_id_link);
qsort(context->funcs, context->funcs_size, sizeof(HSFuncReg), HScript_compare_func);
// -- Sort all data end
HScript_rawcontext_build_nodes(context);
HScript_rawcontext_build_links(context);
HScript_rawcontext_build_string(context);
return true;
}
bool HScript_rawcontext_clone(HSRawContext* first, HSRawContext* second)
{
//Don't forget to call rawcontext reset
HS_ASSERT_RETURN(second->defns == NULL &&
second->funcs == NULL &&
second->links == NULL &&
second->nodes == NULL &&
second->string_pool == NULL, false);
if (first->funcs)
{
const bool bfunc = HScript_resize(&second->funcs, sizeof(HSFuncReg), 0, first->funcs_size);
HS_ASSERT_RETURN(bfunc, false);
memcpy(second->funcs, first->funcs, first->funcs_size * sizeof(HSFuncReg));
second->funcs_size = first->funcs_size;
}
if (first->defns)
{
const bool bdefn = HScript_resize(&second->defns, sizeof(HSDefn), 0, first->defns_size);
HS_ASSERT_RETURN(bdefn, false);
memcpy(second->defns, first->defns, first->defns_size * sizeof(HSDefn));
second->defns_size = first->defns_size;
}
if (first->nodes)
{
const bool bnode = HScript_resize(&second->nodes, sizeof(HSNode), 0, first->nodes_size);
HS_ASSERT_RETURN(bnode, false);
memcpy(second->nodes, first->nodes, first->nodes_size * sizeof(HSNode));
second->nodes_size = first->nodes_size;
}
if (first->links)
{
const bool blink = HScript_resize(&second->links, sizeof(HSLink), 0, first->links_size);
HS_ASSERT_RETURN(blink, false);
memcpy(second->links, first->links, first->links_size * sizeof(HSLink));
second->links_size = first->links_size;
}
HScript_rawcontext_commit(first);
return true;
}
void HSFn_context_reset(HSFnContext* context)
{
memset(context, 0, sizeof(HSFnContext));
}
void HSFn_push_bytes(HSFnContext* context, HSByte* data, const uint32_t size)
{
HS_ASSERT_VOID(size > 0);
HS_ASSERT_VOID(context->stack_pos + size < HS_FNCTX_STACK_DEFAULT_SIZE);
HS_ASSERT_VOID(context->stpop_len < HS_FNCTX_STACK_DEFAULT_DEPTH);
context->stpop[context->stpop_len] = context->stack_pos;
context->stpop_len++;
memcpy(&context->stack[context->stack_pos], data, size);
context->stack_pos += size;
}
bool HSFn_pop_bytes(HSFnContext* context, HSByte** data, uint32_t* size)
{
if (context->stpop_len == 0)
{
(*size) = 0;
(*data) = NULL;
// Make sure that your function pushed all data
HS_ASSERT_RETURN(false, false);
}
(*size) = context->stack_pos - context->stpop[context->stpop_len - 1];
(*data) = &context->stack[context->stack_pos - (*size)];
context->stpop_len--;
context->stack_pos = context->stpop[context->stpop_len];
return true;
}
void HSFn_push_int(HSFnContext* context, int arg)
{
HSFn_push_bytes(context, (HSByte*)&arg, sizeof(int));
}
void HSFn_push_float(HSFnContext* context, float arg)
{
HSFn_push_bytes(context, (HSByte*)&arg, sizeof(float));
}
void HSFn_push_pstr(HSFnContext* context, const char* arg)
{
HSFn_push_bytes(context, (HSByte*)&arg, sizeof(const char*));
}
void HSFn_push_bool(HSFnContext* context, bool arg)
{
HSFn_push_bytes(context, (HSByte*)&arg, sizeof(bool));
}
void HSFn_push_id(HSFnContext* context, uint64_t arg)
{
HSFn_push_bytes(context, (HSByte*)&arg, sizeof(uint64_t));
}
void HSFn_push_pobj(HSFnContext* context, void* arg)
{
HSFn_push_bytes(context, (HSByte*)&arg, sizeof(void*));
}
void HSFn_push_exec(HSFnContext* context, uint32_t arg)
{
HS_ASSERT_VOID(context->stexe_len < HS_FNCTX_STEXE_DEFAULT_SIZE);
HSExecPl payload;
payload.index = arg;
payload.node = 0;
context->stexe[context->stexe_len] = payload;
context->stexe_len++;
}
int HSFn_pop_int(HSFnContext* context)
{
HSByte* data;
uint32_t size;
if (HSFn_pop_bytes(context, &data, &size))
{
if (size == sizeof(int))
{
return *((int*)data);
}
}
return 0;
}
float HSFn_pop_float(HSFnContext* context)
{
HSByte* data;
uint32_t size;
if (HSFn_pop_bytes(context, &data, &size))
{
if (size == sizeof(float))
{
return *((float*)data);
}
}
return 0.0f;
}
const char* HSFn_pop_pstr(HSFnContext* context)
{
HSByte* data;
uint32_t size;
if (HSFn_pop_bytes(context, &data, &size))
{
if (size == sizeof(const char*))
{
return (const char*)data;
}
}
return "";
}
bool HSFn_pop_bool(HSFnContext* context)
{
HSByte* data;
uint32_t size;
if (HSFn_pop_bytes(context, &data, &size))
{
if (size == sizeof(bool))
{
return *((bool*)data);
}
}
return false;
}
uint64_t HSFn_pop_id(HSFnContext* context)
{
HSByte* data;
uint32_t size;
if (HSFn_pop_bytes(context, &data, &size))
{
if (size == sizeof(uint64_t))
{
return *((uint64_t*)data);
}
}
return HS_NIL_VALUE;
}
void* HSFn_pop_pobj(HSFnContext* context)
{
HSByte* data;
uint32_t size;
if (HSFn_pop_bytes(context, &data, &size))
{
if (size == sizeof(uint64_t))
{
return (void*)data;
}
}
return NULL;
}
bool HSFn_pop_exec(HSFnContext* context, uintptr_t* arg)
{
if (context->stexe_len == 0)
{
return false;
}
context->stexe_len--;
(*arg) = context->stexe[context->stexe_len].node;
return true;
}
HSExecPl* HSFn_peek_exec(HSFnContext* context, size_t index)
{
if (index >= HS_FNCTX_STEXE_DEFAULT_SIZE)
{
return false;
}
return &context->stexe[context->stexe_len - index - 1];
}
void HSFn_push_loopb(HSFnContext* context, uint32_t index)
{
HS_ASSERT_VOID(context->loopb_len < HS_FNCTX_LOOPB_DEFAULT_SIZE);
context->loopb[context->loopb_len].payload = context->node;
context->loopb[context->loopb_len].index = index;
context->loopb_len++;
}
bool HSFn_pop_loopb(HSFnContext* context, uintptr_t* loopback_node)
{
if (context->loopb_len == 0)
{
return false;
}
context->loopb_len--;
(*loopback_node) = context->loopb[context->loopb_len].payload;
return true;
}
bool HSFn_check_loopb(HSFnContext* context, uint32_t* index)
{
HSLoopPl* pl = &context->loopb[context->loopb_len];
if (pl->payload == context->node)
{
(*index) = context->loopb[context->loopb_len].index;
return true;
}
return false;
}
void HScript_rawcontext_initialize(HSRawContext* context)
{
context->funcs = NULL;
context->defns = NULL;
context->nodes = NULL;
context->links = NULL;
context->funcs_size = 0;
context->defns_size = 0;
context->links_size = 0;
context->nodes_size = 0;
context->string_pool_size = 0;
context->string_pool = NULL;
srand(HS_RANDOM_HASH_SEED);
}
void HScript_rawcontext_reset(HSRawContext* context)
{
for (size_t i = 0; i < context->defns_size; i++)
{
HSDefn* defn = &context->defns[i];
if (defn->inputs)
{
free(defn->inputs);
defn->inputs = NULL;
defn->i_size = 0;
}
if (defn->outputs)
{
free(defn->outputs);
defn->outputs = NULL;
defn->o_size = 0;
}
}
for (size_t i = 0; i < context->nodes_size; i++)
{
HSNode* node = &context->nodes[i];
if (node->args)
{
free(node->args);
node->args = NULL;
node->args_size = 0;
}
}
context->funcs_size = 0;
context->defns_size = 0;
context->links_size = 0;
context->nodes_size = 0;
context->string_pool_size = 0;
HS_RELEASE(context->string_pool);
HS_RELEASE(context->funcs);
HS_RELEASE(context->defns);
HS_RELEASE(context->nodes);
HS_RELEASE(context->links);
}
void HScript_func_push(HSRawContext* context, HSFuncReg* func)
{
const bool success = HScript_resize(&context->funcs, sizeof(HSFuncReg), context->funcs_size, context->funcs_size + 1);
HS_ASSERT(success);
context->funcs[context->funcs_size] = *func;
context->funcs_size++;
}
HSDefn* HScript_defn_push(HSRawContext* context, HSDefn* defn)
{
const bool success = HScript_resize(&context->defns, sizeof(HSDefn), context->defns_size, context->defns_size + 1);
HS_ASSERT_RETURN(success, NULL);
HSDefn* new_defn = &context->defns[context->defns_size];
*new_defn = *defn;
context->defns_size++;
new_defn->inputs = NULL;
new_defn->i_size = 0;
new_defn->outputs = NULL;
new_defn->o_size = 0;
if (defn->inputs != NULL && defn->i_size > 0)
{
HScript_defn_input_push_many(context, new_defn, defn->inputs, defn->i_size);
}
if (defn->outputs != NULL && defn->o_size > 0)
{
HScript_defn_output_push_many(context, new_defn, defn->outputs, defn->o_size);
}
return new_defn;
}
HSNode* HScript_node_push(HSRawContext* context, HSNode* node)
{
const bool success = HScript_resize(&context->nodes, sizeof(HSNode), context->nodes_size, context->nodes_size + 1);
HS_ASSERT_RETURN(success, NULL);
HSNode* new_node = &context->nodes[context->nodes_size];
*new_node = *node;
context->nodes_size++;
new_node->args = NULL;
new_node->args_size = 0;
new_node->i_size = 0;
if (node->args != NULL && node->args_size > 0)
{
HScript_node_arg_push_many(context, node, new_node->args, new_node->args_size);
}
return new_node;
}
HSLink* HScript_link_push(HSRawContext* context, HSLink* link)
{
const bool success = HScript_resize(&context->links, sizeof(HSLink), context->links_size, context->links_size + 1);
HS_ASSERT_RETURN(success, NULL);
HSLink* new_link = &context->links[context->links_size];
*new_link = *link;
context->links_size++;
return new_link;
}
void HScript_defn_remove(HSRawContext* context, HSDefn* defn)
{
if ((uintptr_t)defn >= (uintptr_t) context->defns &&
(uintptr_t)defn < (uintptr_t)&context->defns[context->nodes_size])
{
size_t idx = (defn - context->defns);
memmove(context->defns, context->defns + 1, context->defns_size - idx);
context->defns_size--;
}
else
{
HS_ASSERT(false);
}
}
void HScript_node_remove(HSRawContext* context, HSNode* node)
{
if ((uintptr_t)node >= (uintptr_t) context->nodes &&
(uintptr_t)node < (uintptr_t)&context->nodes[context->nodes_size])
{
size_t idx = (node - context->nodes);
memmove(context->nodes, context->nodes + 1, context->nodes_size - idx);
context->nodes_size--;
}
else
{
HS_ASSERT(false);
}
}
void HScript_link_remove(HSRawContext* context, HSLink* link)
{
if ((uintptr_t)link >= (uintptr_t) context->links &&
(uintptr_t)link < (uintptr_t)&context->links[context->links_size])
{
size_t idx = (link - context->links);
memmove(context->links, context->links + 1, context->links_size - idx);
context->links_size--;
}
else
{
HS_ASSERT(false);
}
}
void HScript_node_arg_push(HSRawContext* context, HSNode* node, HSNodeArg* arg)
{
HS_ASSERT(HScript_node_find_argument(node, arg->name) == NULL);
const bool success = HScript_resize(&node->args, sizeof(HSNodeArg), node->args_size, node->args_size + 1);
HS_ASSERT(success);
arg->cnode = NULL;
arg->carg = 0;
node->args[node->args_size] = *arg;
++node->args_size;
}
void HScript_defn_input_push(HSRawContext* context, HSDefn* defn, HSDefnArg* arg)
{
HS_ASSERT(HScript_defn_find_argument(defn, arg->name) == NULL);
const bool success = HScript_resize(&defn->inputs, sizeof(HSDefnArg), defn->i_size, defn->i_size + 1);
HS_ASSERT(success);
defn->inputs[defn->i_size] = *arg;
++defn->i_size;
}
void HScript_defn_output_push(HSRawContext* context, HSDefn* defn, HSDefnArg* arg)
{
HS_ASSERT(HScript_defn_find_argument(defn, arg->name) == NULL);
const bool success = HScript_resize(&defn->outputs, sizeof(HSDefnArg), defn->o_size, defn->o_size + 1);
HS_ASSERT(success);
defn->outputs[defn->o_size] = *arg;
++defn->o_size;
}
void HScript_node_arg_push_many(HSRawContext* context, HSNode* node, HSNodeArg* arg, size_t arg_size)
{
const bool success = HScript_resize(&node->args, sizeof(HSNodeArg), node->args_size, node->args_size + arg_size);
HS_ASSERT(success);
memcpy(&(node->args[node->args_size]), arg, arg_size * sizeof(HSNodeArg));
node->args_size += arg_size;
}
void HScript_defn_input_push_many(HSRawContext* context, HSDefn* defn, HSDefnArg* arg, size_t arg_size)
{
const bool success = HScript_resize(&defn->inputs, sizeof(HSDefnArg), defn->i_size, defn->i_size + arg_size);
HS_ASSERT(success);
memcpy(&(defn->inputs[defn->i_size]), arg, arg_size * sizeof(HSDefnArg));
defn->i_size += arg_size;
}
void HScript_defn_output_push_many(HSRawContext* context, HSDefn* defn, HSDefnArg* arg, size_t arg_size)
{
const bool success = HScript_resize(&defn->outputs, sizeof(HSDefnArg), defn->o_size, defn->o_size + arg_size);
HS_ASSERT(success);
memcpy(&(defn->outputs[defn->o_size]), arg, arg_size * sizeof(HSDefnArg));
defn->o_size += arg_size;
}
void HScript_node_arg_remove(HSRawContext* context, HSNode* node, HSNodeArg* arg)
{
if ((uintptr_t)arg >= (uintptr_t) node->args &&
(uintptr_t)arg < (uintptr_t) (node->args + node->args_size))
{
const size_t tail = (size_t)(node->args + node->args_size - arg - 1);
memmove(arg, arg + 1, (size_t)(node->args + node->args_size - arg) * sizeof(HSNodeArg));
const bool success = HScript_resize(&node->args, sizeof(HSNodeArg), node->args_size, node->args_size - 1);
if (success)
{
node->args_size--;
}
}
else
{
HS_ASSERT(false);
}
}
void HScript_defn_input_remove(HSRawContext* context, HSDefn* defn, HSDefnArg* arg)
{
if ((uintptr_t)arg >= (uintptr_t) defn->inputs &&
(uintptr_t)arg < (uintptr_t)(defn->inputs + defn->i_size))
{
const size_t tail = (size_t)(defn->inputs + defn->i_size - arg - 1);
memmove(arg, arg + 1, tail * sizeof(HSNodeArg));
const bool success = HScript_resize(&defn->inputs, sizeof(HSNodeArg), defn->i_size, defn->i_size - 1);
if (success)
{
defn->i_size--;
}
}
else
{
HS_ASSERT(false);
}
}
void HScript_defn_output_remove(HSRawContext* context, HSDefn* defn, HSDefnArg* arg)
{
if ((uintptr_t)arg >= (uintptr_t) defn->outputs &&
(uintptr_t)arg < (uintptr_t)(defn->outputs + defn->o_size))
{
const size_t tail = (size_t)(defn->outputs + defn->o_size - arg - 1);
memmove(arg, arg + 1, tail * sizeof(HSNodeArg));
const bool success = HScript_resize(&defn->outputs, sizeof(HSNodeArg), defn->o_size, defn->o_size - 1);
if (success)
{
defn->o_size--;
}
}
else
{
HS_ASSERT(false);
}
}
void HScript_strcontext_initialize(HSStrContext* context)
{
context->strs = NULL;
context->arr_size = 0;
}
void HScript_strcontext_reset(HSStrContext* context)
{
if (context->strs)
{
for (size_t i = 0; i < context->arr_size; i++)
{
free(context->strs[i]);
context->strs[i] = NULL;
}
free(context->strs);
context->strs = NULL;
}
context->arr_size = 0;
}
char* HScript_strcontext_push(HSStrContext* context, const char* string, size_t len)
{
HS_ASSERT_RETURN(len != 0, NULL);
const bool success = HScript_resize((void**)&context->strs, sizeof(char*), context->arr_size, context->arr_size + 1);
HS_ASSERT_RETURN(success, NULL);
char** out_str = &context->strs[context->arr_size];
(*out_str) = malloc(len + 1);
HS_ASSERT_RETURN(*out_str, NULL);
memcpy(*out_str, string, len);
(*out_str)[len] = 0;
context->arr_size++;
return *out_str;
}
void HScript_interpret_call(HSRawContext* context, HSFnContext* fn_context, HSNode* node)
{
if (node->func == NULL)
{
return;
}
for (size_t i = 0; i < node->i_size; i++)
{
HSNodeArg* node_arg = &node->args[i];
switch (node_arg->type)
{
case HS_INT:
{
HSFn_push_int(fn_context, node_arg->value.as_int);
}
break;
case HS_FLOAT:
{
HSFn_push_float(fn_context, node_arg->value.as_float);
}
break;
case HS_BOOLEAN:
{
HSFn_push_bool(fn_context, node_arg->value.as_bool);
}
break;
case HS_ENTITY:
{
HSFn_push_pobj(fn_context, node_arg->value.as_object);
}
break;
case HS_OBJECT:
{
HSFn_push_pobj(fn_context, node_arg->value.as_object);
}
break;
}
}
fn_context->node = (uintptr_t)node;
node->func(fn_context);
//if (fn_context->stexe_len == 0)
//{
// HSFn_push_exec(fn_context, 0);
//}
size_t exec_index = 0;
for (size_t i = node->i_size; i < node->args_size; i++)
{
HSNodeArg* node_arg = &node->args[i];
switch (node_arg->type)
{
case HS_INT:
{
node_arg->value.as_int = HSFn_pop_int(fn_context);
}
break;
case HS_FLOAT:
{
node_arg->value.as_float = HSFn_pop_float(fn_context);
}
break;
case HS_BOOLEAN:
{
node_arg->value.as_bool = HSFn_pop_bool(fn_context);
}
break;
case HS_ENTITY:
{
node_arg->value.as_object = HSFn_pop_pobj(fn_context);
}
break;
case HS_OBJECT:
{
node_arg->value.as_object = HSFn_pop_pobj(fn_context);
}
break;
}
// Check if we have next node in chain
HSNode* target_node = node_arg->cnode;
if (target_node == NULL)
{
continue;
}
// Apply value
HSNodeArg* target_arg = &target_node->args[node_arg->carg];
target_arg->value = node_arg->value;
// Do nothing if thats not execution pin
if (node_arg->type != HS_EXECUTION)
{
continue;
}
// Push execution to loop
size_t j = 0;
HSExecPl* exec;
while (exec = HSFn_peek_exec(fn_context, j))
{
if (exec->index == exec_index)
{
exec_index++;
exec->node = (intptr_t)target_node;
}
j++;
}
}
}
bool HScript_interpret(HSRawContext* context, HSFnContext* fn_context)
{
HS_ASSERT_RETURN(context != NULL && fn_context != NULL, false);
bool loop = true;
while (loop)
{
uintptr_t node = 0;
loop = HSFn_pop_exec(fn_context, &node);
if (node)
{
HScript_interpret_call(context, fn_context, (HSNode*)node);
node = 0;
}
uintptr_t loopb = 0;
if (!loop && HSFn_pop_loopb(fn_context, &loopb))
{
loop = true;
HScript_interpret_call(context, fn_context, (HSNode*)loopb);
}
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment