44
44
#include "lib/utils/pyexec.h"
45
45
#include "genhdr/mpversion.h"
46
46
47
+ #if CIRCUITPY_ATEXIT
48
+ #include "shared-module/atexit/__init__.h"
49
+ #endif
50
+
47
51
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL ;
48
52
int pyexec_system_exit = 0 ;
49
53
@@ -58,6 +62,7 @@ STATIC bool repl_display_debugging_info = 0;
58
62
#define EXEC_FLAG_SOURCE_IS_VSTR (16)
59
63
#define EXEC_FLAG_SOURCE_IS_FILENAME (32)
60
64
#define EXEC_FLAG_SOURCE_IS_READER (64)
65
+ #define EXEC_FLAG_SOURCE_IS_ATEXIT (128)
61
66
62
67
// parses, compiles and executes the code in the lexer
63
68
// frees the lexer before returning
@@ -81,52 +86,65 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
81
86
nlr .ret_val = NULL ;
82
87
if (nlr_push (& nlr ) == 0 ) {
83
88
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 ))
89
91
#endif
90
92
{
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
102
124
}
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.
105
128
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 ();
107
131
}
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 ();
122
132
}
123
133
124
134
// execute code
125
135
mp_hal_set_interrupt_char (CHAR_CTRL_C ); // allow ctrl-C to interrupt us
126
136
#if MICROPY_REPL_INFO
127
137
start = mp_hal_ticks_ms ();
128
138
#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
+ }
130
148
mp_hal_set_interrupt_char (-1 ); // disable interrupt
131
149
mp_handle_pending (true); // handle any pending exceptions (and any callbacks)
132
150
nlr_pop ();
@@ -741,6 +759,12 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
741
759
}
742
760
#endif
743
761
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
+
744
768
#if MICROPY_REPL_INFO
745
769
mp_obj_t pyb_set_repl_info (mp_obj_t o_value ) {
746
770
repl_display_debugging_info = mp_obj_get_int (o_value );
0 commit comments