/** * payloads/stack.c * * The execution stack. * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. */ #include "memory/node.h" #include "memory/pointer.h" #include "memory/pso2.h" #include "memory/pso4.h" #include "memory/tags.h" #include "payloads/cons.h" #include "payloads/stack.h" /** * @brief The maximum depth of stack before we throw an exception. * * `0` is interpeted as `unlimited`. */ uint32_t stack_limit = 0; /** * Fetch a pointer to the value of the local variable at this index. * * TODO: I think the first argument would be better as a pso_pointer. */ struct pso_pointer fetch_arg( struct pso4 *frame, unsigned int index ) { struct pso_pointer result = nil; // TODO check that the frame is indeed a frame! if ( index < frame->payload.stack_frame.args ) { result = frame->payload.stack_frame.arg[index]; } else { struct pso_pointer p = frame->payload.stack_frame.more; for ( int i = args_in_frame; i < index; i++ ) { p = pointer_to_object( p )->payload.cons.cdr; } result = pointer_to_object( p )->payload.cons.car; } return result; } /** * @brief Return the environment from the stack frame identified by this * `frame_pointer` * * @param frame_pointer a pointer to a stack frame. */ struct pso_pointer fetch_env( struct pso_pointer frame_pointer ) { return stackp( frame_pointer ) ? pointer_to_pso4( frame_pointer )->payload.stack_frame.env : nil; } /** * Push a binding (and therefore a reference) for this `local` onto the * stack_frame indicated by this `frame_pointer`, thereby protecting the * `local` from garbage collection until the frame itself is disposed of. * * This is a hack. For Lisp functions, where the stack frames are set up * and torn down by eval/apply, it shouldn't be necessary. */ struct pso_pointer push_local( struct pso_pointer frame_pointer, struct pso_pointer local ) { if ( stackp( frame_pointer ) ) { struct pso4 *frame = pointer_to_pso4( frame_pointer ); struct pso_pointer l = make_cons( frame_pointer, local, frame->payload.stack_frame.locals ); frame->payload.stack_frame.locals = l; } return local; }