Skip to content

py/parse: Recognise const int assignments with type hints. #17643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions py/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,15 @@ static bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *nu
return false;
}

#if MICROPY_COMP_CONST
static bool is_const_atom_expr_normal(mp_parse_node_t node) {
return MP_PARSE_NODE_IS_STRUCT_KIND(node, RULE_atom_expr_normal)
&& MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t *)node)->nodes[0])
&& MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)node)->nodes[0]) == MP_QSTR_const
&& MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t *)node)->nodes[1], RULE_trailer_paren);
}
#endif

static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
// this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4
// it does not do partial folding, eg 1 + 2 + x -> 3 + x
Expand Down Expand Up @@ -797,21 +806,26 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
if (!MP_PARSE_NODE_IS_NULL(pn1)
&& !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign)
|| MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_assign_list))) {
// this node is of the form <x> = <y>
// this node is of the form <x> = <y> or <x> : int = <y>
mp_parse_node_t pn0 = peek_result(parser, 1);
if (MP_PARSE_NODE_IS_ID(pn0)
&& MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal)
&& MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t *)pn1)->nodes[0])
&& MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn1)->nodes[0]) == MP_QSTR_const
&& MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t *)pn1)->nodes[1], RULE_trailer_paren)
) {
&& ((MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_annassign) &&
MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t *)pn1)->nodes[0]) &&
MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn1)->nodes[0]) == MP_QSTR_int &&
is_const_atom_expr_normal(((mp_parse_node_struct_t *)pn1)->nodes[1]))
|| is_const_atom_expr_normal(pn1))) {
// code to assign dynamic constants: id = const(value)

// get the id
qstr id = MP_PARSE_NODE_LEAF_ARG(pn0);

// get the value
mp_parse_node_t pn_value = ((mp_parse_node_struct_t *)((mp_parse_node_struct_t *)pn1)->nodes[1])->nodes[0];
mp_parse_node_t pn_value;
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_annassign)) {
pn_value = ((mp_parse_node_struct_t *)(((mp_parse_node_struct_t *)(((mp_parse_node_struct_t *)pn1)->nodes[1]))->nodes[1]))->nodes[0];
} else {
pn_value = ((mp_parse_node_struct_t *)((mp_parse_node_struct_t *)pn1)->nodes[1])->nodes[0];
}
if (!mp_parse_node_is_const(pn_value)) {
mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
MP_ERROR_TEXT("not a constant"));
Expand Down
48 changes: 48 additions & 0 deletions tests/micropython/const2_annotated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# check that consts are not replaced in anything except standalone identifiers

from micropython import const

X: int = const(1)
Y: int = const(2)
Z: int = const(3)

# import that uses a constant
import micropython as X

print(globals()["X"])


# function name that matches a constant
def X():
print("function X", X)


globals()["X"]()


# arguments that match a constant
def f(X, *Y, **Z):
pass


f(1)


# class name that matches a constant
class X:
def f(self):
print("class X", X)


globals()["X"]().f()


# constant within a class
class A:
C1: int = const(4)

def X(self):
print("method X", Y, C1, self.C1)


A().X()
4 changes: 4 additions & 0 deletions tests/micropython/const2_annotated.py.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<module 'micropython'>
function X 1
class X 1
method X 2 4 4
30 changes: 30 additions & 0 deletions tests/micropython/const_annotated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# test constant optimisation
# This test will only work when MICROPY_COMP_CONST is enabled.

from micropython import const

X: int = const(123)
Y: int = const(X + 456)

print(X, Y + 1)


def f():
print(X, Y + 1)


f()

_X: int = const(12)
_Y: int = const(_X + 34)

print(_X, _Y)


class A:
Z: int = const(1)
_Z: int = const(2)
print(Z, _Z)


print(hasattr(A, "Z"), hasattr(A, "_Z"))
5 changes: 5 additions & 0 deletions tests/micropython/const_annotated.py.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
123 580
123 580
12 46
1 2
True False
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy