Skip to content

Commit 84bc469

Browse files
authored
Merge pull request micropython#8720 from jepler/codeop-compile_command
Add codeop.compile_command
2 parents 165f993 + afd6fe4 commit 84bc469

File tree

9 files changed

+193
-22
lines changed

9 files changed

+193
-22
lines changed

.github/actions/deps/external/action.yml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ runs:
2525
inputs.port != 'espressif'
2626
uses: carlosperate/arm-none-eabi-gcc-action@v1
2727
with:
28+
# When changing this update what Windows grabs too!
2829
release: '13.2.Rel1'
2930

3031
# espressif

.github/workflows/build.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,9 @@ jobs:
249249
python3 -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))"
250250
- name: Install dependencies
251251
run: |
252-
wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-10-2020-q4-major-win32.zip
252+
wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-mingw-w64-i686-arm-none-eabi.zip
253253
unzip -q -d /tmp gcc-arm.zip
254-
tar -C /tmp/gcc-arm-none-* -cf - . | tar -C /usr/local -xf -
254+
tar -C /tmp/arm-gnu-toolchain* -cf - . | tar -C /usr/local -xf -
255255
pip install wheel
256256
# requirements_dev.txt doesn't install on windows. (with msys2 python)
257257
# instead, pick a subset for what we want to do

ports/unix/variants/coverage/mpconfigvariant.mk

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ SRC_BITMAP := \
3535
shared-bindings/audiomixer/Mixer.c \
3636
shared-bindings/audiomixer/MixerVoice.c \
3737
shared-bindings/bitmaptools/__init__.c \
38+
shared-bindings/codeop/__init__.c \
3839
shared-bindings/displayio/Bitmap.c \
3940
shared-bindings/jpegio/__init__.c \
4041
shared-bindings/jpegio/JpegDecoder.c \
@@ -87,6 +88,7 @@ CFLAGS += \
8788
-DCIRCUITPY_AUDIOMIXER=1 \
8889
-DCIRCUITPY_AUDIOCORE_DEBUG=1 \
8990
-DCIRCUITPY_BITMAPTOOLS=1 \
91+
-DCIRCUITPY_CODEOP=1 \
9092
-DCIRCUITPY_DISPLAYIO_UNIX=1 \
9193
-DCIRCUITPY_FUTURE=1 \
9294
-DCIRCUITPY_GIFIO=1 \

py/circuitpy_defns.mk

+4
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ endif
168168
ifeq ($(CIRCUITPY_CANIO),1)
169169
SRC_PATTERNS += canio/%
170170
endif
171+
ifeq ($(CIRCUITPY_CODEOP),1)
172+
SRC_PATTERNS += codeop/%
173+
endif
171174
ifeq ($(CIRCUITPY_COUNTIO),1)
172175
SRC_PATTERNS += countio/%
173176
endif
@@ -547,6 +550,7 @@ $(filter $(SRC_PATTERNS), \
547550
__future__/__init__.c \
548551
camera/ImageFormat.c \
549552
canio/Match.c \
553+
codeop/__init__.c \
550554
countio/Edge.c \
551555
digitalio/Direction.c \
552556
digitalio/DriveMode.c \

py/circuitpy_mpconfig.mk

+3
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA)
182182
CIRCUITPY_CANIO ?= 0
183183
CFLAGS += -DCIRCUITPY_CANIO=$(CIRCUITPY_CANIO)
184184

185+
CIRCUITPY_CODEOP ?= $(CIRCUITPY_FULL_BUILD)
186+
CFLAGS += -DCIRCUITPY_CODEOP=$(CIRCUITPY_CODEOP)
187+
185188
CIRCUITPY_COLLECTIONS ?= 1
186189
CFLAGS += -DCIRCUITPY_COLLECTIONS=$(CIRCUITPY_COLLECTIONS)
187190

py/makeqstrdata.py

+68-12
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,73 @@
250250
"zip",
251251
]
252252

253+
# These qstrs have to be sorted early (preferably right after static_qstr_list) because they are required to fit in 8-bit values
254+
# however they should never be *forced* to appear
255+
# repeats len, hash, int from the static qstr list, but this doesn't hurt anything.
256+
eightbit_qstr_list = [
257+
"__abs__",
258+
"__add__",
259+
"__and__",
260+
"__bool__",
261+
"__complex__",
262+
"__contains__",
263+
"__delete__",
264+
"__divmod__",
265+
"__eq__",
266+
"__float__",
267+
"__floordiv__",
268+
"__ge__",
269+
"__get__",
270+
"__gt__",
271+
"__hash__",
272+
"__iadd__",
273+
"__iand__",
274+
"__ifloordiv__",
275+
"__ilshift__",
276+
"__imatmul__",
277+
"__imod__",
278+
"__imul__",
279+
"__int__",
280+
"__invert__",
281+
"__ior__",
282+
"__ipow__",
283+
"__irshift__",
284+
"__isub__",
285+
"__itruediv__",
286+
"__ixor__",
287+
"__le__",
288+
"__len__",
289+
"__lshift__",
290+
"__lt__",
291+
"__matmul__",
292+
"__mod__",
293+
"__mul__",
294+
"__ne__",
295+
"__neg__",
296+
"__or__",
297+
"__pos__",
298+
"__pow__",
299+
"__radd__",
300+
"__rand__",
301+
"__rfloordiv__",
302+
"__rlshift__",
303+
"__rmatmul__",
304+
"__rmod__",
305+
"__rmul__",
306+
"__ror__",
307+
"__rpow__",
308+
"__rrshift__",
309+
"__rshift__",
310+
"__rsub__",
311+
"__rtruediv__",
312+
"__rxor__",
313+
"__set__",
314+
"__sizeof__",
315+
"__sub__",
316+
"__truediv__",
317+
"__xor__",
318+
]
319+
253320

254321
# this must match the equivalent function in qstr.c
255322
def compute_hash(qstr, bytes_hash):
@@ -337,18 +404,7 @@ def parse_input_headers_with_translations(infiles):
337404
order = len(qstrs)
338405
# but put special method names like __add__ at the top of list, so
339406
# that their id's fit into a byte
340-
if ident == "":
341-
# Sort empty qstr above all still
342-
order = -200000
343-
elif ident == "__dir__":
344-
# Put __dir__ after empty qstr for builtin dir() to work
345-
order = -190000
346-
elif ident.startswith("__"):
347-
order -= 100000
348-
# CIRCUITPY-CHANGE
349-
elif ident.startswith("_lt"):
350-
order -= 100000
351-
elif ident.startswith("_gt"):
407+
if ident in eightbit_qstr_list:
352408
order -= 100000
353409
qstrs[ident] = (order, ident, qstr)
354410

shared-bindings/codeop/__init__.c

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2023 Jeff Epler for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
#include <string.h>
27+
28+
#include "py/builtin.h"
29+
#include "py/obj.h"
30+
#include "py/runtime.h"
31+
#include "py/repl.h"
32+
33+
STATIC const char *get_arg_str(mp_obj_t arg, qstr name) {
34+
return mp_obj_str_get_str(mp_arg_validate_type_string(arg, name));
35+
}
36+
37+
//| """Utilities to compile possibly incomplete Python source code."""
38+
//|
39+
40+
//| def compile_command(source: str, filename: str = "<input>", symbol: str = "single"):
41+
//| """Compile a command and determine whether it is incomplete
42+
//|
43+
//| The 'completeness' determination is slightly different than in standard Python
44+
//| (it's whatever the internal function ``mp_repl_continue_with_input`` does).
45+
//| In particular, it's important that the code not end with a newline character
46+
//| or it is likely to be treated as a complete command."""
47+
//|
48+
STATIC mp_obj_t compile_command(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
49+
enum { ARG_source, ARG_filename, ARG_symbol };
50+
static const mp_arg_t allowed_args[] = {
51+
{ MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } },
52+
{ MP_QSTR_filename, MP_ARG_OBJ, { .u_obj = MP_ROM_QSTR(MP_QSTR__lt_input_gt_) } },
53+
{ MP_QSTR_symbol, MP_ARG_OBJ, { .u_obj = MP_ROM_QSTR(MP_QSTR_single) } },
54+
};
55+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
56+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
57+
58+
const char *source = get_arg_str(args[ARG_source].u_obj, MP_QSTR_source);
59+
if (mp_repl_continue_with_input(source)) {
60+
return mp_const_none;
61+
}
62+
63+
return mp_call_function_n_kw((mp_obj_t)&mp_builtin_compile_obj, 3, 0, &args[0].u_obj);
64+
}
65+
MP_DEFINE_CONST_FUN_OBJ_KW(compile_command_obj, 1, compile_command);
66+
67+
STATIC const mp_rom_map_elem_t codeop_module_globals_table[] = {
68+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_codeop) },
69+
{ MP_ROM_QSTR(MP_QSTR_compile_command), MP_ROM_PTR(&compile_command_obj) },
70+
};
71+
72+
STATIC MP_DEFINE_CONST_DICT(codeop_module_globals, codeop_module_globals_table);
73+
74+
const mp_obj_module_t codeop_module = {
75+
.base = { &mp_type_module },
76+
.globals = (mp_obj_dict_t *)&codeop_module_globals,
77+
};
78+
79+
MP_REGISTER_MODULE(MP_QSTR_codeop, codeop_module);

tests/circuitpython/codeop_compile.py

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
try:
2+
from codeop import compile_command
3+
except ImportError:
4+
print("SKIP")
5+
raise SystemExit
6+
7+
8+
def test(snippet):
9+
result = compile_command(snippet)
10+
print("None" if result is None else "<code>")
11+
12+
13+
# Complete command
14+
test("3+3")
15+
16+
# Complete command
17+
test("if 1:\n print('hi mom')\n")
18+
19+
# Incomplete command
20+
test("if 1:")
21+
22+
# Incomplete multiline string
23+
test("'''I'm sure it's OK")
24+
25+
# Incomplete parenthesized expression
26+
test("[1, 2")

tests/unix/extra_coverage.py.exp

+8-8
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ port
5353
builtins micropython __future__ _asyncio
5454
_thread aesio array audiocore
5555
audiomixer binascii bitmaptools cexample
56-
cmath collections cppexample displayio
57-
errno example_package gc
58-
hashlib heapq io jpegio
59-
json locale math os
60-
platform qrio rainbowio random
61-
re select struct synthio
62-
sys time traceback uctypes
63-
ulab zlib
56+
cmath codeop collections cppexample
57+
displayio errno example_package
58+
gc hashlib heapq io
59+
jpegio json locale math
60+
os platform qrio rainbowio
61+
random re select struct
62+
synthio sys time traceback
63+
uctypes ulab zlib
6464
me
6565

6666
rainbowio random

0 commit comments

Comments
 (0)