post-scarcity/src/c/payloads/stack.c
Simon Brooke f915a9993f Fixed assigning arguments to slots in the frame; also fixed a bug in bind...
But did that by switching away from using Lisp calling convention, because
that broke horribly. This is bad news and must be sorted out.
2026-04-16 17:13:20 +01:00

115 lines
3.3 KiB
C

/**
* payloads/stack.h
*
* a Lisp stack frame.
*
* Sits in a pso4.
*
* (c) 2026 Simon Brooke <simon@journeyman.cc>
* Licensed under GPL version 2.0, or, at your option, any later version.
*/
#include <stdarg.h>
#include "debug.h"
#include "memory/node.h"
#include "memory/pointer.h"
#include "memory/pso.h"
#include "memory/pso2.h"
#include "memory/pso4.h"
#include "memory/tags.h"
#include "payloads/cons.h"
#include "ops/reverse.h"
/**
* @brief Construct a stack frame with this `previous` pointer, and arguments
* taken from the remaining arguments to this function, which should all be
* struct pso_pointer.
*
* @return a pso_pointer to the stack frame.
*/
struct pso_pointer make_frame( int arg_count, struct pso_pointer previous,
... ) {
va_list args;
va_start( args, previous );
struct pso_pointer frame_pointer = allocate( STACKTAG, 4 );
struct pso4 *frame = ( struct pso4 * ) pointer_to_object( frame_pointer );
#ifdef DEBUG
debug_printf( DEBUG_ALLOC, 0,
L"\nAllocating stack frame with %d arguments at page %d, "
L"offset %d...\n",
arg_count, frame_pointer.page, frame_pointer.offset );
#endif
frame->payload.stack_frame.previous = previous;
if ( stackp( previous ) ) {
struct pso4 *op = pointer_to_pso4( previous );
frame->payload.stack_frame.depth = op->payload.stack_frame.depth + 1;
} else {
frame->payload.stack_frame.depth = 0;
}
debug_printf( DEBUG_ALLOC, 1, L"depth is %d...\n",
frame->payload.stack_frame.depth );
int cursor = 0;
frame->payload.stack_frame.args = arg_count;
for ( ; cursor < arg_count && cursor < args_in_frame; cursor++ ) {
struct pso_pointer argument = va_arg( args, struct pso_pointer );
frame->payload.stack_frame.arg[cursor] = inc_ref( argument );
}
if ( cursor < arg_count ) {
struct pso_pointer more_args = nil;
for ( ; cursor < arg_count; cursor++ ) {
more_args =
c_cons( va_arg( args, struct pso_pointer ), more_args );
}
frame->payload.stack_frame.more = c_reverse( more_args );
} else {
for ( ; cursor < args_in_frame; cursor++ ) {
frame->payload.stack_frame.arg[cursor] = nil;
}
}
debug_printf( DEBUG_ALLOC, 1,
L"Allocation of frame at page %d, offset %d completed.\n",
frame_pointer.page, frame_pointer.offset );
return frame_pointer;
}
/**
* @brief When a stack frame is freed, all its pointers must be decremented.
*
* Lisp calling conventions; one expected arg, the pointer to the object to
* be destroyed.
*/
struct pso_pointer destroy_stack_frame( struct pso_pointer fp,
struct pso_pointer env ) {
if ( stackp( fp ) ) {
struct pso4 *frame = pointer_to_pso4( fp );
dec_ref( frame->payload.stack_frame.previous );
dec_ref( frame->payload.stack_frame.function );
dec_ref( frame->payload.stack_frame.more );
for ( int i = 0; i < args_in_frame; i++ ) {
dec_ref( frame->payload.stack_frame.arg[i] );
}
frame->payload.stack_frame.args = 0;
frame->payload.stack_frame.depth = 0;
}
return nil;
}