Skip to content

Commit 635543c

Browse files
committed
py, compiler: Implement compiling of relative imports.
1 parent 2e9eb2d commit 635543c

File tree

1 file changed

+67
-31
lines changed

1 file changed

+67
-31
lines changed

py/compile.c

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,31 +1236,35 @@ void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
12361236
}
12371237
}
12381238

1239-
// q1 holds the base, q2 the full name
1240-
// eg a -> q1=q2=a
1241-
// a.b.c -> q1=a, q2=a.b.c
1242-
void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) {
1239+
// q_base holds the base of the name
1240+
// eg a -> q_base=a
1241+
// a.b.c -> q_base=a
1242+
void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
12431243
bool is_as = false;
12441244
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) {
12451245
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
12461246
// a name of the form x as y; unwrap it
1247-
*q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
1247+
*q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
12481248
pn = pns->nodes[0];
12491249
is_as = true;
12501250
}
1251-
if (MP_PARSE_NODE_IS_ID(pn)) {
1251+
if (MP_PARSE_NODE_IS_NULL(pn)) {
1252+
// empty name (eg, from . import x)
1253+
*q_base = MP_QSTR_;
1254+
EMIT_ARG(import_name, MP_QSTR_); // import the empty string
1255+
} else if (MP_PARSE_NODE_IS_ID(pn)) {
12521256
// just a simple name
1253-
*q2 = MP_PARSE_NODE_LEAF_ARG(pn);
1257+
qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn);
12541258
if (!is_as) {
1255-
*q1 = *q2;
1259+
*q_base = q_full;
12561260
}
1257-
EMIT_ARG(import_name, *q2);
1261+
EMIT_ARG(import_name, q_full);
12581262
} else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
12591263
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
12601264
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dotted_name) {
12611265
// a name of the form a.b.c
12621266
if (!is_as) {
1263-
*q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
1267+
*q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
12641268
}
12651269
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
12661270
int len = n - 1;
@@ -1278,42 +1282,74 @@ void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) {
12781282
memcpy(str_dest, str_src, str_src_len);
12791283
str_dest += str_src_len;
12801284
}
1281-
*q2 = qstr_build_end(q_ptr);
1282-
EMIT_ARG(import_name, *q2);
1285+
qstr q_full = qstr_build_end(q_ptr);
1286+
EMIT_ARG(import_name, q_full);
12831287
if (is_as) {
12841288
for (int i = 1; i < n; i++) {
12851289
EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
12861290
}
12871291
}
12881292
} else {
1289-
// TODO not implemented
1290-
// This covers relative imports starting with dot(s) like "from .foo import"
1291-
compile_syntax_error(comp, pn, "Relative imports not implemented");
1292-
return;
1293+
// shouldn't happen
1294+
assert(0);
12931295
}
12941296
} else {
1295-
// TODO not implemented
1296-
// This covers relative imports with dots only like "from .. import"
1297-
compile_syntax_error(comp, pn, "Relative imports not implemented");
1298-
return;
1297+
// shouldn't happen
1298+
assert(0);
12991299
}
13001300
}
13011301

13021302
void compile_dotted_as_name(compiler_t *comp, mp_parse_node_t pn) {
1303-
EMIT_ARG(load_const_small_int, 0); // ??
1304-
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
1305-
qstr q1, q2;
1306-
do_import_name(comp, pn, &q1, &q2);
1307-
EMIT_ARG(store_id, q1);
1303+
EMIT_ARG(load_const_small_int, 0); // level 0 import
1304+
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // not importing from anything
1305+
qstr q_base;
1306+
do_import_name(comp, pn, &q_base);
1307+
EMIT_ARG(store_id, q_base);
13081308
}
13091309

13101310
void compile_import_name(compiler_t *comp, mp_parse_node_struct_t *pns) {
13111311
apply_to_single_or_list(comp, pns->nodes[0], PN_dotted_as_names, compile_dotted_as_name);
13121312
}
13131313

13141314
void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
1315+
mp_parse_node_t pn_import_source = pns->nodes[0];
1316+
1317+
// extract the preceeding .'s (if any) for a relative import, to compute the import level
1318+
uint import_level = 0;
1319+
do {
1320+
mp_parse_node_t pn_rel;
1321+
if (MP_PARSE_NODE_IS_TOKEN(pn_import_source) || MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_one_or_more_period_or_ellipsis)) {
1322+
// This covers relative imports with dots only like "from .. import"
1323+
pn_rel = pn_import_source;
1324+
pn_import_source = MP_PARSE_NODE_NULL;
1325+
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn_import_source, PN_import_from_2b)) {
1326+
// This covers relative imports starting with dot(s) like "from .foo import"
1327+
mp_parse_node_struct_t *pns_2b = (mp_parse_node_struct_t*)pn_import_source;
1328+
pn_rel = pns_2b->nodes[0];
1329+
pn_import_source = pns_2b->nodes[1];
1330+
assert(!MP_PARSE_NODE_IS_NULL(pn_import_source)); // should not be
1331+
} else {
1332+
// Not a relative import
1333+
break;
1334+
}
1335+
1336+
// get the list of . and/or ...'s
1337+
mp_parse_node_t *nodes;
1338+
int n = list_get(&pn_rel, PN_one_or_more_period_or_ellipsis, &nodes);
1339+
1340+
// count the total number of .'s
1341+
for (int i = 0; i < n; i++) {
1342+
if (MP_PARSE_NODE_IS_TOKEN_KIND(nodes[i], MP_TOKEN_DEL_PERIOD)) {
1343+
import_level++;
1344+
} else {
1345+
// should be an MP_TOKEN_ELLIPSIS
1346+
import_level += 3;
1347+
}
1348+
}
1349+
} while (0);
1350+
13151351
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
1316-
EMIT_ARG(load_const_small_int, 0); // level 0 for __import__
1352+
EMIT_ARG(load_const_small_int, import_level);
13171353

13181354
// build the "fromlist" tuple
13191355
#if MICROPY_EMIT_CPYTHON
@@ -1324,12 +1360,12 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
13241360
#endif
13251361

13261362
// do the import
1327-
qstr dummy_q, id1;
1328-
do_import_name(comp, pns->nodes[0], &dummy_q, &id1);
1363+
qstr dummy_q;
1364+
do_import_name(comp, pn_import_source, &dummy_q);
13291365
EMIT(import_star);
13301366

13311367
} else {
1332-
EMIT_ARG(load_const_small_int, 0); // level 0 for __import__
1368+
EMIT_ARG(load_const_small_int, import_level);
13331369

13341370
// build the "fromlist" tuple
13351371
mp_parse_node_t *pn_nodes;
@@ -1369,8 +1405,8 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
13691405
#endif
13701406

13711407
// do the import
1372-
qstr dummy_q, id1;
1373-
do_import_name(comp, pns->nodes[0], &dummy_q, &id1);
1408+
qstr dummy_q;
1409+
do_import_name(comp, pn_import_source, &dummy_q);
13741410
for (int i = 0; i < n; i++) {
13751411
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name));
13761412
mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i];

0 commit comments

Comments
 (0)