Skip to content

Commit

Permalink
py/compile: Implement PEP 526, syntax for variable annotations.
Browse files Browse the repository at this point in the history
This addition to the grammar was introduced in Python 3.6.  It allows
annotating the type of a varilable, like:

    x: int = 123
    s: str

The implementation in this commit is quite simple and just ignores the
annotation (the int and str bits above).  The reason to implement this is
to allow Python 3.6+ code that uses this feature to compile under
MicroPython without change, and for users to use type checkers.

In the future viper could use this syntax as a way to give types to
variables, which is currently done in a bit of an ad-hoc way, eg
x = int(123).  And this syntax could potentially be used in the inline
assembler to define labels in an way that's easier to read.
  • Loading branch information
dpgeorge committed Jun 16, 2020
1 parent 131b0de commit f2e267d
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 10 deletions.
31 changes: 24 additions & 7 deletions py/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1981,7 +1981,8 @@ STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
#endif

STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
mp_parse_node_t pn_rhs = pns->nodes[1];
if (MP_PARSE_NODE_IS_NULL(pn_rhs)) {
if (comp->is_repl && comp->scope_cur->kind == SCOPE_MODULE) {
// for REPL, evaluate then print the expression
compile_load_id(comp, MP_QSTR___repl_print__);
Expand All @@ -1999,10 +2000,26 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
EMIT(pop_top); // discard last result since this is a statement and leaves nothing on the stack
}
}
} else if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pns->nodes[1];
} else if (MP_PARSE_NODE_IS_STRUCT(pn_rhs)) {
mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pn_rhs;
int kind = MP_PARSE_NODE_STRUCT_KIND(pns1);
if (kind == PN_expr_stmt_augassign) {
if (kind == PN_annassign) {
// the annotation is in pns1->nodes[0] and is ignored
if (MP_PARSE_NODE_IS_NULL(pns1->nodes[1])) {
// an annotation of the form "x: y"
// inside a function this declares "x" as a local
if (comp->scope_cur->kind == SCOPE_FUNCTION) {
if (MP_PARSE_NODE_IS_ID(pns->nodes[0])) {
qstr lhs = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
scope_find_or_add_id(comp->scope_cur, lhs, ID_INFO_KIND_LOCAL);
}
}
} else {
// an assigned annotation of the form "x: y = z"
pn_rhs = pns1->nodes[1];
goto plain_assign;
}
} else if (kind == PN_expr_stmt_augassign) {
c_assign(comp, pns->nodes[0], ASSIGN_AUG_LOAD); // lhs load for aug assign
compile_node(comp, pns1->nodes[1]); // rhs
assert(MP_PARSE_NODE_IS_TOKEN(pns1->nodes[0]));
Expand All @@ -2027,10 +2044,10 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
} else {
plain_assign:
#if MICROPY_COMP_DOUBLE_TUPLE_ASSIGN
if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr)
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_rhs, PN_testlist_star_expr)
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)) {
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t *)pns->nodes[0];
pns1 = (mp_parse_node_struct_t *)pns->nodes[1];
pns1 = (mp_parse_node_struct_t *)pn_rhs;
uint32_t n_pns0 = MP_PARSE_NODE_STRUCT_NUM_NODES(pns0);
// Can only optimise a tuple-to-tuple assignment when all of the following hold:
// - equal number of items in LHS and RHS tuples
Expand Down Expand Up @@ -2070,7 +2087,7 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
#endif

compile_node(comp, pns->nodes[1]); // rhs
compile_node(comp, pn_rhs); // rhs
c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store
}
} else {
Expand Down
8 changes: 5 additions & 3 deletions py/grammar.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,20 +98,22 @@ DEF_RULE_NC(simple_stmt, and_ident(2), rule(simple_stmt_2), tok(NEWLINE))
DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), tok(DEL_SEMICOLON))

// small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt
// expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)
// expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)
// testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
// annassign: ':' test ['=' (yield_expr|testlist_star_expr)]
// augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
// # For normal assignments, additional restrictions enforced by the interpreter
// # For normal and annotated assignments, additional restrictions enforced by the interpreter

DEF_RULE_NC(small_stmt, or(8), rule(del_stmt), rule(pass_stmt), rule(flow_stmt), rule(import_stmt), rule(global_stmt), rule(nonlocal_stmt), rule(assert_stmt), rule(expr_stmt))
DEF_RULE(expr_stmt, c(expr_stmt), and(2), rule(testlist_star_expr), opt_rule(expr_stmt_2))
DEF_RULE_NC(expr_stmt_2, or(2), rule(expr_stmt_augassign), rule(expr_stmt_assign_list))
DEF_RULE_NC(expr_stmt_2, or(3), rule(annassign), rule(expr_stmt_augassign), rule(expr_stmt_assign_list))
DEF_RULE_NC(expr_stmt_augassign, and_ident(2), rule(augassign), rule(expr_stmt_6))
DEF_RULE_NC(expr_stmt_assign_list, one_or_more, rule(expr_stmt_assign))
DEF_RULE_NC(expr_stmt_assign, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6))
DEF_RULE_NC(expr_stmt_6, or(2), rule(yield_expr), rule(testlist_star_expr))
DEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA))
DEF_RULE_NC(testlist_star_expr_2, or(2), rule(star_expr), rule(test))
DEF_RULE_NC(annassign, and(3), tok(DEL_COLON), rule(test), opt_rule(expr_stmt_assign))
DEF_RULE_NC(augassign, or(13), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_EQUAL), tok(DEL_AT_EQUAL), tok(DEL_SLASH_EQUAL), tok(DEL_PERCENT_EQUAL), tok(DEL_AMPERSAND_EQUAL), tok(DEL_PIPE_EQUAL), tok(DEL_CARET_EQUAL), tok(DEL_DBL_LESS_EQUAL), tok(DEL_DBL_MORE_EQUAL), tok(DEL_DBL_STAR_EQUAL), tok(DEL_DBL_SLASH_EQUAL))

// del_stmt: 'del' exprlist
Expand Down

0 comments on commit f2e267d

Please sign in to comment.