4343#include "extmod/modplatform.h"
4444#include "genhdr/mpversion.h"
4545
46- // CIRCUITPY-CHANGE: atexit support
46+ // CIRCUITPY-CHANGE: add atexit support
4747#if CIRCUITPY_ATEXIT
4848#include "shared-module/atexit/__init__.h"
4949#endif
@@ -84,57 +84,71 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
8484 nlr_buf_t nlr ;
8585 nlr .ret_val = NULL ;
8686 if (nlr_push (& nlr ) == 0 ) {
87- // CIRCUITPY-CHANGE
88- mp_obj_t module_fun = mp_const_none ;
89- // CIRCUITPY-CHANGE
87+ #if MICROPY_PYEXEC_ENABLE_VM_ABORT
88+ nlr_set_abort (& nlr );
89+ #endif
90+
91+ // CIRCUITPY-CHANGE: move declaration for easier handling of atexit #if.
92+ // Also make it possible to determine if module_fun was set.
93+ mp_obj_t module_fun = NULL ;
94+
95+ // CIRCUITPY-CHANGE: add atexit support
9096 #if CIRCUITPY_ATEXIT
91- if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT ))
97+ if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT ) {
98+ atexit_callback_t * callback = (atexit_callback_t * )source ;
99+ mp_call_function_n_kw (callback -> func , callback -> n_pos , callback -> n_kw , callback -> args );
100+ } else
92101 #endif
93- // CIRCUITPY-CHANGE: multiple code changes
94- {
95- #if MICROPY_MODULE_FROZEN_MPY
96- if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE ) {
97- // source is a raw_code object, create the function
98- const mp_frozen_module_t * frozen = source ;
99- mp_module_context_t * ctx = m_new_obj (mp_module_context_t );
100- ctx -> module .globals = mp_globals_get ();
101- ctx -> constants = frozen -> constants ;
102- module_fun = mp_make_function_from_proto_fun (frozen -> proto_fun , ctx , NULL );
103- } else
104- #endif
105- {
106- #if MICROPY_ENABLE_COMPILER
107- mp_lexer_t * lex ;
108- if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR ) {
109- const vstr_t * vstr = source ;
110- lex = mp_lexer_new_from_str_len (MP_QSTR__lt_stdin_gt_ , vstr -> buf , vstr -> len , 0 );
111- } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER ) {
112- lex = mp_lexer_new (MP_QSTR__lt_stdin_gt_ , * (mp_reader_t * )source );
113- } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME ) {
114- lex = mp_lexer_new_from_file (qstr_from_str (source ));
115- } else {
116- lex = (mp_lexer_t * )source ;
117- }
118- // source is a lexer, parse and compile the script
119- qstr source_name = lex -> source_name ;
120- // CIRCUITPY-CHANGE
121- #if MICROPY_MODULE___FILE__
122- if (input_kind == MP_PARSE_FILE_INPUT ) {
123- mp_store_global (MP_QSTR___file__ , MP_OBJ_NEW_QSTR (source_name ));
124- }
125- #endif
126102
127- mp_parse_tree_t parse_tree = mp_parse (lex , input_kind );
128- module_fun = mp_compile (& parse_tree , source_name , exec_flags & EXEC_FLAG_IS_REPL );
129- #else
130- mp_raise_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("script compilation not supported" ));
131- #endif
103+ #if MICROPY_MODULE_FROZEN_MPY
104+ if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE ) {
105+ // source is a raw_code object, create the function
106+ const mp_frozen_module_t * frozen = source ;
107+ mp_module_context_t * ctx = m_new_obj (mp_module_context_t );
108+ ctx -> module .globals = mp_globals_get ();
109+ ctx -> constants = frozen -> constants ;
110+ module_fun = mp_make_function_from_proto_fun (frozen -> proto_fun , ctx , NULL );
111+ } else
112+ #endif
113+ {
114+ #if MICROPY_ENABLE_COMPILER
115+ mp_lexer_t * lex ;
116+ if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR ) {
117+ const vstr_t * vstr = source ;
118+ lex = mp_lexer_new_from_str_len (MP_QSTR__lt_stdin_gt_ , vstr -> buf , vstr -> len , 0 );
119+ } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER ) {
120+ lex = mp_lexer_new (MP_QSTR__lt_stdin_gt_ , * (mp_reader_t * )source );
121+ } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME ) {
122+ lex = mp_lexer_new_from_file (qstr_from_str (source ));
123+ } else {
124+ lex = (mp_lexer_t * )source ;
132125 }
133-
134- // If the code was loaded from a file, collect any garbage before running.
126+ // source is a lexer, parse and compile the script
127+ qstr source_name = lex -> source_name ;
128+ #if MICROPY_MODULE___FILE__
135129 if (input_kind == MP_PARSE_FILE_INPUT ) {
136- gc_collect ();
130+ mp_store_global (MP_QSTR___file__ , MP_OBJ_NEW_QSTR (source_name ));
131+ }
132+ #endif
133+ mp_parse_tree_t parse_tree = mp_parse (lex , input_kind );
134+ #if defined(MICROPY_UNIX_COVERAGE )
135+ // allow to print the parse tree in the coverage build
136+ if (mp_verbose_flag >= 3 ) {
137+ printf ("----------------\n" );
138+ mp_parse_node_print (& mp_plat_print , parse_tree .root , 0 );
139+ printf ("----------------\n" );
137140 }
141+ #endif
142+ module_fun = mp_compile (& parse_tree , source_name , exec_flags & EXEC_FLAG_IS_REPL );
143+ #else
144+ mp_raise_msg (& mp_type_RuntimeError , MP_ERROR_TEXT ("script compilation not supported" ));
145+ #endif
146+ }
147+
148+ // CIRCUITPY-CHANGE: garbage collect after loading
149+ // If the code was loaded from a file, collect any garbage before running.
150+ if (input_kind == MP_PARSE_FILE_INPUT ) {
151+ gc_collect ();
138152 }
139153
140154 // execute code
@@ -144,22 +158,19 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
144158 #if MICROPY_REPL_INFO
145159 start = mp_hal_ticks_ms ();
146160 #endif
147- // CIRCUITPY-CHANGE
148- #if CIRCUITPY_ATEXIT
149- if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT ) {
150- atexit_callback_t * callback = (atexit_callback_t * )source ;
151- mp_call_function_n_kw (callback -> func , callback -> n_pos , callback -> n_kw , callback -> args );
152- } else
161+ #if MICROPY_PYEXEC_COMPILE_ONLY
162+ if (!mp_compile_only )
153163 #endif
154- // CIRCUITPY-CHANGE
155- if (module_fun != mp_const_none ) {
156- mp_call_function_0 (module_fun );
164+ {
165+ // CIRCUITPY-CHANGE: if atexit function was called, there is nothing to call.
166+ if (module_fun != NULL ) {
167+ mp_call_function_0 (module_fun );
168+ }
157169 }
158170 mp_hal_set_interrupt_char (-1 ); // disable interrupt
159171 mp_handle_pending (true); // handle any pending exceptions (and any callbacks)
160172 nlr_pop ();
161- // CIRCUITPY-CHANGE
162- ret = 0 ;
173+ ret = PYEXEC_NORMAL_EXIT ;
163174 if (exec_flags & EXEC_FLAG_PRINT_EOF ) {
164175 mp_hal_stdout_tx_strn ("\x04" , 1 );
165176 }
@@ -178,36 +189,66 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
178189 mp_hal_stdout_tx_strn ("\x04" , 1 );
179190 }
180191
181- // check for SystemExit
182-
183- // CIRCUITPY-CHANGE
192+ // CIRCUITPY-CHANGE: Name and use some values.
184193 // nlr.ret_val is an exception object.
185194 mp_obj_t exception_obj = (mp_obj_t )nlr .ret_val ;
195+ const mp_obj_type_t * exception_obj_type = mp_obj_get_type (exception_obj );
186196
187- if (mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (mp_obj_get_type (exception_obj )), MP_OBJ_FROM_PTR (& mp_type_SystemExit ))) {
188- // at the moment, the value of SystemExit is unused
197+ #if MICROPY_PYEXEC_ENABLE_VM_ABORT
198+ if (nlr .ret_val == NULL ) { // abort
199+ ret = PYEXEC_ABORT ;
200+ } else
201+ #endif
202+
203+ if (mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (exception_obj_type ), MP_OBJ_FROM_PTR (& mp_type_SystemExit ))) { // system exit
204+ #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING
205+ // None is an exit value of 0; an int is its value; anything else is 1
206+ mp_obj_t val = mp_obj_exception_get_value (MP_OBJ_FROM_PTR (nlr .ret_val ));
207+ if (val != mp_const_none ) {
208+ if (mp_obj_is_int (val )) {
209+ ret = (int )mp_obj_int_get_truncated (val );
210+ } else {
211+ mp_obj_print_helper (MICROPY_ERROR_PRINTER , val , PRINT_STR );
212+ mp_print_str (MICROPY_ERROR_PRINTER , "\n" );
213+ ret = PYEXEC_UNHANDLED_EXCEPTION ;
214+ }
215+ } else {
216+ ret = PYEXEC_NORMAL_EXIT ;
217+ }
218+ // Set PYEXEC_FORCED_EXIT flag so REPL knows to exit
219+ ret |= PYEXEC_FORCED_EXIT ;
220+ #else
189221 ret = PYEXEC_FORCED_EXIT ;
190- // CIRCUITPY-CHANGE
191- #if CIRCUITPY_ALARM
192- } else if (mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (mp_obj_get_type (exception_obj )), MP_OBJ_FROM_PTR (& mp_type_DeepSleepRequest ))) {
222+ #endif
223+ // CIRCUITPY-CHANGE: support DeepSleepRequest
224+ #if CIRCUITPY_ALARM
225+ } else if (mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (exception_obj_type ), MP_OBJ_FROM_PTR (& mp_type_DeepSleepRequest ))) {
193226 ret = PYEXEC_DEEP_SLEEP ;
194- #endif
227+ #endif
228+ // CIRCUITPY-CHANGE: supprt ReloadException
195229 } else if (exception_obj == MP_OBJ_FROM_PTR (& MP_STATE_VM (mp_reload_exception ))) {
196230 ret = PYEXEC_RELOAD ;
197- } else {
198- mp_obj_print_exception (& mp_plat_print , exception_obj );
199- ret = PYEXEC_EXCEPTION ;
231+ } else { // other exception
232+ mp_obj_print_exception (& mp_plat_print , MP_OBJ_FROM_PTR (nlr .ret_val ));
233+ ret = PYEXEC_UNHANDLED_EXCEPTION ;
234+ #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING
235+ if (mp_obj_is_subclass_fast (MP_OBJ_FROM_PTR (((mp_obj_base_t * )nlr .ret_val )-> type ), MP_OBJ_FROM_PTR (& mp_type_KeyboardInterrupt ))) { // keyboard interrupt
236+ ret = PYEXEC_KEYBOARD_INTERRUPT ;
237+ }
238+ #endif
200239 }
201-
202240 }
241+
242+ // CIRCUITPY_CHANGE: Fill in result out argument.
203243 if (result != NULL ) {
204244 result -> return_code = ret ;
205- #if CIRCUITPY_ALARM
206245 // Don't set the exception object if we exited for deep sleep.
207- if (ret != 0 && ret != PYEXEC_DEEP_SLEEP ) {
208- #else
209- if ( ret != 0 ) {
246+ if (ret != 0
247+ #if CIRCUITPY_ALARM
248+ && ret != PYEXEC_DEEP_SLEEP
210249 #endif
250+ )
251+ {
211252 mp_obj_t return_value = (mp_obj_t )nlr .ret_val ;
212253 result -> exception = return_value ;
213254 result -> exception_line = -1 ;
@@ -224,6 +265,10 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input
224265 }
225266 }
226267
268+ #if MICROPY_PYEXEC_ENABLE_VM_ABORT
269+ nlr_set_abort (NULL );
270+ #endif
271+
227272 #if MICROPY_REPL_INFO
228273 // display debugging info if wanted
229274 if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING ) && repl_display_debugging_info ) {
@@ -776,6 +821,7 @@ int pyexec_friendly_repl(void) {
776821 if (ret & (PYEXEC_FORCED_EXIT | PYEXEC_RELOAD )) {
777822 return ret ;
778823 }
824+ mp_hal_stdio_mode_raw ();
779825 }
780826}
781827
0 commit comments