Skip to content

Commit 13b1a5e

Browse files
committed
redo pyexec.c to be more like upstream; fix a bunch of tests
1 parent 5df1105 commit 13b1a5e

18 files changed

+243
-183
lines changed

ports/unix/main.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ static void stderr_print_strn(void *env, const char *str, size_t len) {
9292

9393
const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
9494

95-
#define FORCED_EXIT (0x100)
95+
// CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT
96+
// #define FORCED_EXIT (0x100)
9697
// If exc is SystemExit, return value where FORCED_EXIT bit set,
9798
// and lower 8 bits are SystemExit value. For all other exceptions,
9899
// return 1.
@@ -105,7 +106,8 @@ static int handle_uncaught_exception(mp_obj_base_t *exc) {
105106
if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) {
106107
val = 1;
107108
}
108-
return FORCED_EXIT | (val & 255);
109+
// CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT
110+
return PYEXEC_FORCED_EXIT | (val & 255);
109111
}
110112

111113
// Report all other exceptions
@@ -236,7 +238,8 @@ static int do_repl(void) {
236238

237239
int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true);
238240
free(line);
239-
if (ret & FORCED_EXIT) {
241+
// CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT
242+
if (ret & PYEXEC_FORCED_EXIT) {
240243
return ret;
241244
}
242245
}

ports/unix/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
// CIRCUITPY-CHANGE
4545
#define CIRCUITPY_MICROPYTHON_ADVANCED (1)
4646
#define MICROPY_PY_ASYNC_AWAIT (1)
47+
#define MICROPY_PY_DOUBLE_TYPECODE (1)
4748
#define MICROPY_PY_UCTYPES (0)
4849

4950
#ifndef MICROPY_CONFIG_ROM_LEVEL

py/objarray.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
807807
MP_DEFINE_CONST_OBJ_TYPE(
808808
mp_type_bytearray,
809809
MP_QSTR_bytearray,
810-
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER,
810+
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE,
811811
make_new, bytearray_make_new,
812812
print, array_print,
813813
iter, array_iterator_new,
@@ -846,7 +846,7 @@ MP_DEFINE_CONST_DICT(memoryview_locals_dict, memoryview_locals_dict_table);
846846
MP_DEFINE_CONST_OBJ_TYPE(
847847
mp_type_memoryview,
848848
MP_QSTR_memoryview,
849-
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER,
849+
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE,
850850
make_new, memoryview_make_new,
851851
iter, array_iterator_new,
852852
unary_op, array_unary_op,

shared/runtime/pyexec.c

Lines changed: 120 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
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

tests/cmdline/repl_autocomplete.py.exp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
CircuitPython \.\+ version
2-
Use \.\+
1+
2+
Adafruit CircuitPython \.\+ version
33
>>> # tests for autocompletion
44
>>> import sys
55
>>> not_exist.
@@ -11,4 +11,4 @@ Use \.\+
1111
>>> i.lower('ABC')
1212
'abc'
1313
>>> None.
14-
>>>
14+
>>> \$

tests/cmdline/repl_autocomplete_underscore.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ def __init__(self):
77
self.public_attr = 1
88
self._private_attr = 2
99
self.__very_private = 3
10-
10+
1111
def public_method(self):
1212
pass
13-
13+
1414
def _private_method(self):
1515
pass
16-
16+
1717
@property
1818
def public_property(self):
1919
return 42
20-
21-
@property
20+
21+
@property
2222
def _private_property(self):
2323
return 99
2424

0 commit comments

Comments
 (0)