You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
1.8 KiB
97 lines
1.8 KiB
#include <state.h>
|
|
#include "dev.h"
|
|
|
|
const _sm_state_opt _sm_state_opt_default = {
|
|
._opt_INTERMEDIATE_RETURNS = true,
|
|
};
|
|
|
|
/// A generator that just returns `nullptr` (end). Used for yielding without calling in to another generator.
|
|
///
|
|
/// NOTE: To avoid uselessly creating a stack frame for calls to this generator, its address is (TODO) directly compared to when switching into a deeper generator, and then skipped entirely.
|
|
sm_yield _sm_noop(sm_state*)
|
|
{
|
|
return (sm_yield)nullptr;
|
|
}
|
|
|
|
EX_C sm_state* sm_new_state()
|
|
{
|
|
auto state = box<sm_state>();
|
|
state->current = box<_sm_frame, true>();
|
|
state->opt = _sm_state_opt_default;
|
|
return state;
|
|
}
|
|
|
|
inline static void sm_free_user(_sm_user* data)
|
|
{
|
|
if (data->free) {
|
|
free(data->_ptr);
|
|
}
|
|
}
|
|
|
|
void sm_free_output(_sm_user* data)
|
|
{
|
|
if(!data) return;
|
|
|
|
if(data->set)
|
|
sm_free_user(data);
|
|
data->set = data->free = false;
|
|
|
|
}
|
|
|
|
inline static void _sm_free_page(_sm_user_page* page)
|
|
{
|
|
for (int i=0;i<_SM_STACK_SIZE;i++) sm_free_user(&page->data[i]);
|
|
}
|
|
|
|
inline static void _sm_free_all_pages(_sm_user_page* page)
|
|
{
|
|
while(page)
|
|
{
|
|
_sm_free_page(page);
|
|
auto old = page;
|
|
page = page->next;
|
|
free(old);
|
|
}
|
|
}
|
|
|
|
EX_C void sm_free_state(sm_state* state)
|
|
{
|
|
_sm_frame* frame = unbox(state).current;
|
|
|
|
while(frame)
|
|
{
|
|
if(frame->rval) {
|
|
sm_free_user(frame->rval);
|
|
unbox(frame->rval);
|
|
}
|
|
|
|
_sm_free_all_pages(frame->user.next);
|
|
_sm_free_page(&frame->user);
|
|
|
|
frame = unbox(frame).prev;
|
|
}
|
|
}
|
|
|
|
void _sm_pop_stack(sm_state* state)
|
|
{
|
|
if(!state->current) return;
|
|
|
|
auto last = unbox(state->current);
|
|
state->current = last.prev;
|
|
|
|
if(last.rval)
|
|
{
|
|
sm_free_user(last.rval);
|
|
unbox(last.rval);
|
|
}
|
|
_sm_free_all_pages(last.user.next);
|
|
_sm_free_page(&last.user);
|
|
}
|
|
|
|
void _sm_push_stack(sm_state* state)
|
|
{
|
|
auto next = box<_sm_frame, true>();
|
|
next->prev = state->current;
|
|
state->current = next;
|
|
}
|