8000 py: Add support for matmul operator @ as per PEP 465. · micropython/micropython@2069c56 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2069c56

Browse files
committed
py: Add support for matmul operator @ as per PEP 465.
To make progress towards MicroPython supporting Python 3.5, adding the matmul operator is important because it's a really "low level" part of the language, being a new token and modifications to the grammar. It doesn't make sense to make it configurable because 1) it would make the grammar and lexer complicated/messy; 2) no other operators are configurable; 3) it's not a feature that can be "dynamically plugged in" via an import. And matmul can be useful as a general purpose user-defined operator, it doesn't have to be just for numpy use. Based on work done by Jim Mussared.
1 parent 14e2032 commit 2069c56

File tree

7 files changed

+34
-25
lines changed

7 files changed

+34
-25
lines changed

py/grammar.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ DEF_RULE_NC(eval_input_2, and(1), tok(NEWLINE))
5555
// varargslist: vfpdef ['=' test] (',' vfpdef ['=' test])* [',' ['*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef]] | '*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef
5656
// vfpdef: NAME
5757

58-
DEF_RULE_NC(decorator, and(4), tok(DEL_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE))
58+
DEF_RULE_NC(decorator, and(4), tok(OP_AT), rule(dotted_name), opt_rule(trailer_paren), tok(NEWLINE))
5959
DEF_RULE_NC(decorators, one_or_more, rule(decorator))
6060
DEF_RULE(decorated, c(decorated), and_ident(2), rule(decorators), rule(decorated_body))
6161
#if MICROPY_PY_ASYNC_AWAIT
@@ -96,7 +96,7 @@ DEF_RULE(simple_stmt_2, c(generic_all_nodes), list_with_end, rule(small_stmt), t
9696
// small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt
9797
// expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)
9898
// testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
99-
// augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
99+
// augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
100100
// # For normal assignments, additional restrictions enforced by the interpreter
101101

102102
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))
@@ -108,7 +108,7 @@ DEF_RULE_NC(expr_stmt_assign, and_ident(2), tok(DEL_EQUAL), rule(expr_stmt_6))
108108
DEF_RULE_NC(expr_stmt_6, or(2), rule(yield_expr), rule(testlist_star_expr))
109109
DEF_RULE(testlist_star_expr, c(generic_tuple), list_with_end, rule(testlist_star_expr_2), tok(DEL_COMMA))
110110
DEF_RULE_NC(testlist_star_expr_2, or(2), rule(star_expr), rule(test))
111-
DEF_RULE_NC(augassign, or(12), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DEL_STAR_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))
111+
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))
112112

113113
// del_stmt: 'del' exprlist
114114
// pass_stmt: 'pass'
@@ -226,7 +226,7 @@ DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(vara
226226
// and_expr: shift_expr ('&' shift_expr)*
227227
// shift_expr: arith_expr (('<<'|'>>') arith_expr)*
228228
// arith_expr: term (('+'|'-') term)*
229-
// term: factor (('*'|'/' DC35 |'%'|'//') factor)*
229+
// term: factor (('*'|'@'|'/'|'%'|'//') factor)*
230230
// factor: ('+'|'-'|'~') factor | power
231231
// power: atom_expr ['**' factor]
232232
// atom_expr: 'await' atom trailer* | atom trailer*
@@ -249,7 +249,7 @@ DEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE))
249249
DEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op))
250250
DEF_RULE_NC(arith_op, or(2), tok(OP_PLUS), tok(OP_MINUS))
251251
DEF_RULE(term, c(term), list, rule(factor), rule(term_op))
252-
DEF_RULE_NC(term_op, or(4), tok(OP_STAR), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH))
252+
DEF_RULE_NC(term_op, or(5), tok(OP_STAR), tok(OP_AT), tok(OP_SLASH), tok(OP_PERCENT), tok(OP_DBL_SLASH))
253253
DEF_RULE_NC(factor, or(2), rule(factor_2), rule(power))
254254
DEF_RULE(factor_2, c(factor_2), and_ident(2), rule(factor_op), rule(factor))
255255
DEF_RULE_NC(factor_op, or(3), tok(OP_PLUS), tok(OP_MINUS), tok(OP_TILDE))

py/lexer.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ STATIC void indent_pop(mp_lexer_t *lex) {
174174
// this means if the start of two ops are the same then they are equal til the last char
175175

176176
STATIC const char *const tok_enc =
177-
"()[]{},:;@~" // singles
177+
"()[]{},:;~" // singles
178178
"<e=c<e=" // < <= << <<=
179179
">e=c>e=" // > >= >> >>=
180180
"*e=c*e=" // * *= ** **=
@@ -185,6 +185,7 @@ STATIC const char *const tok_enc =
185185
"/e=c/e=" // / /= // //=
186186
"%e=" // % %=
187187
"^e=" // ^ ^=
188+
"@e=" // @ @=
188189
"=e=" // = ==
189190
"!."; // start of special cases: != . ...
190191

@@ -193,7 +194,7 @@ STATIC const uint8_t tok_enc_kind[] = {
193194
MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE,
194195
MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE,
195196
MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE,
196-
MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_DEL_AT, MP_TOKEN_OP_TILDE,
197+
MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_COLON, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_OP_TILDE,
197198

198199
MP_TOKEN_OP_LESS, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_DEL_DBL_LESS_EQUAL,
199200
MP_TOKEN_OP_MORE, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_DEL_DBL_MORE_EQUAL,
@@ -205,6 +206,7 @@ STATIC const uint8_t tok_enc_kind[] = {
205206
MP_TOKEN_OP_SLASH, MP_TOKEN_DEL_SLASH_EQUAL, MP_TOKEN_OP_DBL_SLASH, MP_TOKEN_DEL_DBL_SLASH_EQUAL,
206207
MP_TOKEN_OP_PERCENT, MP_TOKEN_DEL_PERCENT_EQUAL,
207208
MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL,
209+
MP_TOKEN_OP_AT, MP_TOKEN_DEL_AT_EQUAL,
208210
MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL,
209211
};
210212

py/lexer.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ typedef enum _mp_token_kind_t {
106106
MP_TOKEN_OP_MORE_EQUAL,
107107
MP_TOKEN_OP_NOT_EQUAL,
108108

109-
// Order of these 12 matches corresponding mp_binary_op_t operator
109+
// Order of these 13 matches corresponding mp_binary_op_t operator
110110
MP_TOKEN_OP_PIPE,
111111
MP_TOKEN_OP_CARET,
112112
MP_TOKEN_OP_AMPERSAND,
@@ -115,12 +115,13 @@ typedef enum _mp_token_kind_t {
115115
MP_TOKEN_OP_PLUS,
116116
MP_TOKEN_OP_MINUS,
117117
MP_TOKEN_OP_STAR,
118+
MP_TOKEN_OP_AT,
118119
MP_TOKEN_OP_DBL_SLASH,
119120
MP_TOKEN_OP_SLASH,
120121
MP_TOKEN_OP_PERCENT,
121122
MP_TOKEN_OP_DBL_STAR,
122123

123-
// Order of these 12 matches corresponding mp_binary_op_t operator
124+
// Order of these 13 matches corresponding mp_binary_op_t operator
124125
MP_TOKEN_DEL_PIPE_EQUAL,
125126
MP_TOKEN_DEL_CARET_EQUAL,
126127
MP_TOKEN_DEL_AMPERSAND_EQUAL,
@@ -129,6 +130,7 @@ typedef enum _mp_token_kind_t {
129130
MP_TOKEN_DEL_PLUS_EQUAL,
130131
MP_TOKEN_DEL_MINUS_EQUAL,
131132
MP_TOKEN_DEL_STAR_EQUAL,
133+
MP_TOKEN_DEL_AT_EQUAL,
132134
MP_TOKEN_DEL_DBL_SLASH_EQUAL,
133135
MP_TOKEN_DEL_SLASH_EQUAL,
134136
MP_TOKEN_DEL_PERCENT_EQUAL,
@@ -144,7 +146,6 @@ typedef enum _mp_token_kind_t {
144146
MP_TOKEN_DEL_COLON,
145147
MP_TOKEN_DEL_PERIOD,
146148
MP_TOKEN_DEL_SEMICOLON,
147-
MP_TOKEN_DEL_AT,
148149
MP_TOKEN_DEL_EQUAL,
149150
MP_TOKEN_DEL_MINUS_MORE, DC35
150151
} mp_token_kind_t;

py/objtype.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
478478
[MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__,
479479
#if MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS
480480
[MP_BINARY_OP_INPLACE_MULTIPLY] = MP_QSTR___imul__,
481+
[MP_BINARY_OP_INPLACE_MAT_MULTIPLY] = MP_QSTR___imatmul__,
481482
[MP_BINARY_OP_INPLACE_FLOOR_DIVIDE] = MP_QSTR___ifloordiv__,
482483
[MP_BINARY_OP_INPLACE_TRUE_DIVIDE] = MP_QSTR___itruediv__,
483484
[MP_BINARY_OP_INPLACE_MODULO] = MP_QSTR___imod__,
@@ -493,6 +494,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
493494
[MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,
494495
#if MICROPY_PY_ALL_SPECIAL_METHODS
495496
[MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__,
497+
[MP_BINARY_OP_MAT_MULTIPLY] = MP_QSTR___matmul__,
496498
[MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__,
497499
[MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__,
498500
[MP_BINARY_OP_MODULO] = MP_QSTR___mod__,
@@ -510,6 +512,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
510512
[MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__,
511513
#if MICROPY_PY_ALL_SPECIAL_METHODS
512514
[MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__,
515+
[MP_BINARY_OP_REVERSE_MAT_MULTIPLY] = MP_QSTR___rmatmul__,
513516
[MP_BINARY_OP_REVERSE_FLOOR_DIVIDE] = MP_QSTR___rfloordiv__,
514517
[MP_BINARY_OP_REVERSE_TRUE_DIVIDE] = MP_QSTR___rtruediv__,
515518
[MP_BINARY_OP_REVERSE_MODULO] = MP_QSTR___rmod__,

py/parse.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ STATIC const uint16_t rule_arg_combined_table[] = {
135135
#define RULE_EXPAND(x) x
136136
#define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule))
< 2F8B code>137137
#define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__))
138-
#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) __VA_ARGS__
139-
#define RULE_PADDING_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r,
138+
#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) __VA_ARGS__
139+
#define RULE_PADDING_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r,
140140

141141
// Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table
142142
enum {
@@ -155,8 +155,8 @@ enum {
155155
// Macro to compute the start of a rule in rule_arg_combined_table
156156
#define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule))
157157
#define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__))
158-
#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13
159-
#define RULE_ARG_OFFSET_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r,
158+
#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) _14
159+
#define RULE_ARG_OFFSET_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r,
160160

161161
// Use the above enum values to create a table of offsets for each rule's arg
162162
// data, which indexes rule_arg_combined_table. The offsets require 9 bits of
@@ -632,7 +632,7 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
632632
} else if (rule_id == RULE_shift_expr
633633
|| rule_id == RULE_arith_expr
634634
|| rule_id == RULE_term) {
635-
// folding for binary ops: << >> + - * / % //
635+
// folding for binary ops: << >> + - * @ / % //
636636
mp_parse_node_t pn = peek_result(parser, num_args - 1);
637637
if (!mp_parse_node_get_int_maybe(pn, &arg0)) {
638638
return false;
@@ -644,8 +644,8 @@ STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
644644
return false;
645645
}
646646
mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i));
647-
if (tok == MP_TOKEN_OP_SLASH || tok == MP_TOKEN_OP_DBL_STAR) {
648-
// Can't fold / or **
647+
if (tok == MP_TOKEN_OP_AT || tok == MP_TOKEN_OP_SLASH || tok == MP_TOKEN_OP_DBL_STAR) {
648+
// Can't fold @ or / or **
649649
return false;
650650
}
651651
mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS);

py/runtime0.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ typedef enum {
8181
MP_BINARY_OP_IS,
8282
MP_BINARY_OP_EXCEPTION_MATCH,
8383

84-
// 12 inplace arithmetic operations; order matches corresponding mp_token_kind_t
84+
// 13 inplace arithmetic operations; order matches corresponding mp_token_kind_t
8585
MP_BINARY_OP_INPLACE_OR,
8686
MP_BINARY_OP_INPLACE_XOR,
8787
MP_BINARY_OP_INPLACE_AND,
@@ -90,12 +90,13 @@ typedef enum {
9090
MP_BINARY_OP_INPLACE_ADD,
9191
MP_BINARY_OP_INPLACE_SUBTRACT,
9292
MP_BINARY_OP_INPLACE_MULTIPLY,
93+
MP_BINARY_OP_INPLACE_MAT_MULTIPLY,
9394
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
9495
MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
9596
MP_BINARY_OP_INPLACE_MODULO,
9697
MP_BINARY_OP_INPLACE_POWER,
9798

98-
// 12 normal arithmetic operations; order matches corresponding mp_token_kind_t
99+
// 13 normal arithmetic operations; order matches corresponding mp_token_kind_t
99100
MP_BINARY_OP_OR,
100101
MP_BINARY_OP_XOR,
101102
MP_BINARY_OP_AND,
@@ -104,6 +105,7 @@ typedef enum {
104105
MP_BINARY_OP_ADD,
105106
MP_BINARY_OP_SUBTRACT,
106107
MP_BINARY_OP_MULTIPLY,
108+
MP_BINARY_OP_MAT_MULTIPLY,
107109
MP_BINARY_OP_FLOOR_DIVIDE,
108110
MP_BINARY_OP_TRUE_DIVIDE,
109111
MP_BINARY_OP_MODULO,
@@ -123,6 +125,7 @@ typedef enum {
123125
MP_BINARY_OP_REVERSE_ADD,
124126
MP_BINARY_OP_REVERSE_SUBTRACT,
125127
MP_BINARY_OP_REVERSE_MULTIPLY,
128+
MP_BINARY_OP_REVERSE_MAT_MULTIPLY,
126129
MP_BINARY_OP_REVERSE_FLOOR_DIVIDE,
127130
MP_BINARY_OP_REVERSE_TRUE_DIVIDE,
128131
MP_BINARY_OP_REVERSE_MODULO,

tests/cmdline/cmd_showbc.py.exp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
4343
bc=\\d\+ line=126
4444
00 LOAD_CONST_NONE
4545
01 LOAD_CONST_FALSE
46-
02 BINARY_OP 26 __add__
46+
02 BINARY_OP 27 __add__
4747
03 LOAD_CONST_TRUE
48-
04 BINARY_OP 26 __add__
48+
04 BINARY_OP 27 __add__
4949
05 STORE_FAST 0
5050
06 LOAD_CONST_SMALL_INT 0
5151
07 STORE_FAST 0
@@ -84,7 +84,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
8484
\\d\+ STORE_FAST 7
8585
\\d\+ LOAD_FAST 0
8686
\\d\+ LOAD_DEREF 14
87-
\\d\+ BINARY_OP 26 __add__
87+
58 BINARY_OP 27 __add__
8888
\\d\+ STORE_FAST 8
8989
\\d\+ LOAD_FAST 0
9090
\\d\+ UNARY_OP 1
@@ -363,7 +363,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
363363
42 STORE_FAST_N 19
364364
44 LOAD_FAST 9
365365
45 LOAD_FAST_N 19
366-
47 BINARY_OP 26 __add__
366+
47 BINARY_OP 27 __add__
367367
48 POP_TOP
368368
49 LOAD_CONST_NONE
369369
50 RETURN_VALUE
@@ -520,7 +520,7 @@ arg names: *
520520
bc=\\d\+ line=113
521521
00 LOAD_DEREF 0
522522
02 LOAD_CONST_SMALL_INT 1
523-
03 BINARY_OP 26 __add__
523+
03 BINARY_OP 27 __add__
524524
04 STORE_FAST 1
525525
05 LOAD_CONST_SMALL_INT 1
526526
06 STORE_DEREF 0
@@ -539,7 +539,7 @@ arg names: * b
539539
bc=\\d\+ line=139
540540
00 LOAD_FAST 1
541541
01 LOAD_DEREF 0
542-
03 BINARY_OP 26 __add__
542+
03 BINARY_OP 27 __add__
543543
04 RETURN_VALUE
544544
mem: total=\\d\+, current=\\d\+, peak=\\d\+
545545
stack: \\d\+ out of \\d\+

0 commit comments

Comments
 (0)
0