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

#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;
}