4444#include "lib/utils/pyexec.h"
4545#include "genhdr/mpversion.h"
4646
47+ #if CIRCUITPY_ATEXIT
48+ #include "shared-module/atexit/__init__.h"
49+ #endif
50+
4751pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL ;
4852int pyexec_system_exit = 0 ;
4953
@@ -58,6 +62,7 @@ STATIC bool repl_display_debugging_info = 0;
5862#define EXEC_FLAG_SOURCE_IS_VSTR (16)
5963#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
6064#define EXEC_FLAG_SOURCE_IS_READER (64)
65+ #define EXEC_FLAG_SOURCE_IS_ATEXIT (128)
6166
6267// parses, compiles and executes the code in the lexer
6368// frees the lexer before returning
@@ -81,52 +86,65 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
8186 nlr .ret_val = NULL ;
8287 if (nlr_push (& nlr ) == 0 ) {
8388 mp_obj_t module_fun ;
84- #if MICROPY_MODULE_FROZEN_MPY
85- if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE ) {
86- // source is a raw_code object, create the function
87- module_fun = mp_make_function_from_raw_code (source , MP_OBJ_NULL , MP_OBJ_NULL );
88- } else
89+ #if CIRCUITPY_ATEXIT
90+ if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT ))
8991 #endif
9092 {
91- #if MICROPY_ENABLE_COMPILER
92- mp_lexer_t * lex ;
93- if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR ) {
94- const vstr_t * vstr = source ;
95- lex = mp_lexer_new_from_str_len (MP_QSTR__lt_stdin_gt_ , vstr -> buf , vstr -> len , 0 );
96- } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER ) {
97- lex = mp_lexer_new (MP_QSTR__lt_stdin_gt_ , * (mp_reader_t * )source );
98- } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME ) {
99- lex = mp_lexer_new_from_file (source );
100- } else {
101- lex = (mp_lexer_t * )source ;
93+ #if MICROPY_MODULE_FROZEN_MPY
94+ if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE ) {
95+ // source is a raw_code object, create the function
96+ module_fun = mp_make_function_from_raw_code (source , MP_OBJ_NULL , MP_OBJ_NULL );
97+ } else
98+ #endif
99+ {
100+ #if MICROPY_ENABLE_COMPILER
101+ mp_lexer_t * lex ;
102+ if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR ) {
103+ const vstr_t * vstr = source ;
104+ lex = mp_lexer_new_from_str_len (MP_QSTR__lt_stdin_gt_ , vstr -> buf , vstr -> len , 0 );
105+ } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER ) {
106+ lex = mp_lexer_new (MP_QSTR__lt_stdin_gt_ , * (mp_reader_t * )source );
107+ } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME ) {
108+ lex = mp_lexer_new_from_file (source );
109+ } else {
110+ lex = (mp_lexer_t * )source ;
111+ }
112+ // source is a lexer, parse and compile the script
113+ qstr source_name = lex -> source_name ;
114+ if (input_kind == MP_PARSE_FILE_INPUT ) {
115+ mp_store_global (MP_QSTR___file__ , MP_OBJ_NEW_QSTR (source_name ));
116+ }
117+ mp_parse_tree_t parse_tree = mp_parse (lex , input_kind );
118+ module_fun = mp_compile (& parse_tree , source_name , exec_flags & EXEC_FLAG_IS_REPL );
119+ // Clear the parse tree because it has a heap pointer we don't need anymore.
120+ * ((uint32_t volatile * )& parse_tree .chunk ) = 0 ;
121+ #else
122+ mp_raise_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("script compilation not supported" ));
123+ #endif
102124 }
103- // source is a lexer, parse and compile the script
104- qstr source_name = lex -> source_name ;
125+
126+ // If the code was loaded from a file it's likely to be running for a while so we'll long
127+ // live it and collect any garbage before running.
105128 if (input_kind == MP_PARSE_FILE_INPUT ) {
106- mp_store_global (MP_QSTR___file__ , MP_OBJ_NEW_QSTR (source_name ));
129+ module_fun = make_obj_long_lived (module_fun , 6 );
130+ gc_collect ();
107131 }
108- mp_parse_tree_t parse_tree = mp_parse (lex , input_kind );
109- module_fun = mp_compile (& parse_tree , source_name , exec_flags & EXEC_FLAG_IS_REPL );
110- // Clear the parse tree because it has a heap pointer we don't need anymore.
111- * ((uint32_t volatile * )& parse_tree .chunk ) = 0 ;
112- #else
113- mp_raise_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("script compilation not supported" ));
114- #endif
115- }
116-
117- // If the code was loaded from a file it's likely to be running for a while so we'll long
118- // live it and collect any garbage before running.
119- if (input_kind == MP_PARSE_FILE_INPUT ) {
120- module_fun = make_obj_long_lived (module_fun , 6 );
121- gc_collect ();
122132 }
123133
124134 // execute code
125135 mp_hal_set_interrupt_char (CHAR_CTRL_C ); // allow ctrl-C to interrupt us
126136 #if MICROPY_REPL_INFO
127137 start = mp_hal_ticks_ms ();
128138 #endif
129- mp_call_function_0 (module_fun );
139+ #if CIRCUITPY_ATEXIT
140+ if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT ) {
141+ atexit_callback_t * callback = (atexit_callback_t * )source ;
142+ mp_call_function_n_kw (callback -> func , callback -> n_pos , callback -> n_kw , callback -> args );
143+ } else
144+ #endif
145+ {
146+ mp_call_function_0 (module_fun );
147+ }
130148 mp_hal_set_interrupt_char (-1 ); // disable interrupt
131149 mp_handle_pending (true); // handle any pending exceptions (and any callbacks)
132150 nlr_pop ();
@@ -741,6 +759,12 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
741759}
742760#endif
743761
762+ #if CIRCUITPY_ATEXIT
763+ int pyexec_exit_handler (const void * source , pyexec_result_t * result ) {
764+ return parse_compile_execute (source , MP_PARSE_FILE_INPUT , EXEC_FLAG_SOURCE_IS_ATEXIT , result );
765+ }
766+ #endif
767+
744768#if MICROPY_REPL_INFO
745769mp_obj_t pyb_set_repl_info (mp_obj_t o_value ) {
746770 repl_display_debugging_info = mp_obj_get_int (o_value );
0 commit comments