/** * environment/environment.c * * Initialise a MINIMAL environment. * * (c) 2026 Simon Brooke * Licensed under GPL version 2.0, or, at your option, any later version. */ #include #include "debug.h" #include "environment/function_bindings.h" #include "environment/privileged_keywords.h" #include "memory/memory.h" #include "memory/node.h" #include "memory/pointer.h" #include "memory/pso.h" #include "memory/pso2.h" #include "memory/tags.h" #include "ops/bind.h" #include "ops/string_ops.h" #include "payloads/psse_string.h" #include "ops/stack_ops.h" #include "ops/truth.h" #include "payloads/stack.h" /** * @brief Flag to prevent re-initialisation. */ bool environment_initialised = false; /** * @brief Initialise a minimal environment, so that Lisp can be bootstrapped. * * @param node the index of the node we are initialising. * @return a proto-environment on success, else an exception. */ struct pso_pointer initialise_environment( uint32_t node ) { struct pso_pointer result = initialise_memory( node ); struct pso_pointer frame_pointer = nil; // can't have a frame pointer before we've initialised nil and t if ( c_truep( result ) ) { debug_print( U"Initialising `nil`... ", DEBUG_BOOTSTRAP, 0 ); struct pso_pointer n = allocate( frame_pointer, NILTAG, 2 ); if ( ( n.page == 0 ) && ( n.offset == 0 ) ) { struct pso2 *object = pointer_to_object( n ); object->payload.cons.car = nil; object->payload.cons.cdr = nil; nil = n; lock_object( nil ); debug_print( U"success\n", DEBUG_BOOTSTRAP, 0 ); } else { result = nil; debug_print( U"fail\n", DEBUG_BOOTSTRAP, 0 ); } } if ( !c_nilp( result ) ) { debug_print( U"Initialising `t`... ", DEBUG_BOOTSTRAP, 0 ); struct pso_pointer n = allocate( frame_pointer, TRUETAG, 2 ); // offset is in words, and size of a pso2 is four words if ( ( n.page == 0 ) && ( n.offset == 4 ) ) { struct pso2 *object = pointer_to_object( n ); object->payload.string.character = L't'; object->payload.cons.cdr = t; t = n; lock_object( t ); debug_print( U"success\n", DEBUG_BOOTSTRAP, 0 ); } else { result = nil; debug_print( U"fail\n", DEBUG_BOOTSTRAP, 0 ); } } if ( !exceptionp( result ) ) { result = lisp_bind( make_frame ( 3, frame_pointer, c_string_to_lisp_symbol( frame_pointer, U"niU" ), nil, nil ) ); debug_print( U"Environment after binding `nil`: ", DEBUG_BOOTSTRAP, 0 ); debug_print_object( result, DEBUG_BOOTSTRAP, 0 ); result = lisp_bind( make_frame ( 3, frame_pointer, c_string_to_lisp_symbol( frame_pointer, U"t" ), t, result ) ); environment_initialised = true; debug_print( U"Environment after binding `t`: ", DEBUG_BOOTSTRAP, 0 ); debug_print_object( result, DEBUG_BOOTSTRAP, 0 ); debug_print( U"\nEnvironment initialised successfully.\n", DEBUG_BOOTSTRAP, 0 ); } initialise_privileged_keywords(frame_pointer); result = initialise_function_bindings(push_local( frame_pointer, make_frame_with_env(0, frame_pointer, result))); dec_ref(frame_pointer); return result; }