1919#include "map.h"
2020#include "builtin.h"
2121
22+ #define PATH_SEP_CHAR '/'
23+
2224mp_obj_t sys_path ;
2325
24- mp_obj_t mp_builtin___import__ (int n_args , mp_obj_t * args ) {
25- /*
26- printf("import:\n");
27- for (int i = 0; i < n; i++) {
28- printf(" ");
29- mp_obj_print(args[i]);
30- printf("\n");
26+ mp_import_stat_t stat_dir_or_file (vstr_t * path ) {
27+ //printf("stat %s\n", vstr_str(path));
28+ mp_import_stat_t stat = mp_import_stat (vstr_str (path ));
29+ if (stat == MP_IMPORT_STAT_DIR ) {
30+ return stat ;
3131 }
32- */
33-
34- qstr mod_name = mp_obj_str_get_qstr (args [0 ]);
35-
36- mp_obj_t loaded = mp_obj_module_get (mod_name );
37- if (loaded != MP_OBJ_NULL ) {
38- return loaded ;
32+ vstr_add_str (path , ".py" );
33+ stat = mp_import_stat (vstr_str (path ));
34+ if (stat == MP_IMPORT_STAT_FILE ) {
35+ return stat ;
3936 }
37+ return MP_IMPORT_STAT_NO_EXIST ;
38+ }
4039
41- // find the file to import
42- uint mod_name_len ;
43- const byte * mod_name_p = qstr_data (mod_name , & mod_name_len );
44- mp_lexer_t * lex = NULL ;
45-
40+ mp_import_stat_t find_file (const char * file_str , uint file_len , vstr_t * dest ) {
41+ // extract the list of paths
4642 uint path_num = 0 ;
4743 mp_obj_t * path_items ;
4844 if (sys_path != MP_OBJ_NULL ) {
4945 mp_obj_list_get (sys_path , & path_num , & path_items );
5046 }
5147
5248 if (path_num == 0 ) {
53- CHECKBUF (fname , PATH_MAX );
54- CHECKBUF_APPEND (fname , mod_name_p , mod_name_len );
55- CHECKBUF_APPEND (fname , ".py" , sizeof (".py" ) - 1 );
56- CHECKBUF_APPEND_0 (fname );
57- lex = mp_lexer_new_from_file (fname );
49+ // sys_path is empty, so just use the given file name
50+ vstr_add_strn (dest , file_str , file_len );
51+ return stat_dir_or_file (dest );
5852 } else {
53+ // go through each path looking for a directory or file
5954 for (int i = 0 ; i < path_num ; i ++ ) {
60- CHECKBUF ( fname , PATH_MAX );
55+ vstr_reset ( dest );
6156 uint p_len ;
6257 const byte * p = mp_obj_str_get_data (path_items [i ], & p_len );
6358 if (p_len > 0 ) {
64- CHECKBUF_APPEND ( fname , p , p_len );
65- CHECKBUF_APPEND ( fname , "/" , 1 );
59+ vstr_add_strn ( dest , ( const char * ) p , p_len );
60+ vstr_add_char ( dest , PATH_SEP_CHAR );
6661 }
67- CHECKBUF_APPEND (fname , mod_name_p , mod_name_len );
68- CHECKBUF_APPEND (fname , ".py" , sizeof (".py" ) - 1 );
69- CHECKBUF_APPEND_0 (fname );
70- lex = mp_lexer_new_from_file (fname );
71- if (lex != NULL ) {
72- break ;
62+ vstr_add_strn (dest , file_str , file_len );
63+ mp_import_stat_t stat = stat_dir_or_file (dest );
64+ if (stat != MP_IMPORT_STAT_NO_EXIST ) {
65+ return stat ;
7366 }
7467 }
68+
69+ // could not find a directory or file
70+ return MP_IMPORT_STAT_NO_EXIST ;
7571 }
72+ }
73+
74+ void do_load (mp_obj_t module_obj , vstr_t * file ) {
75+ // create the lexer
76+ mp_lexer_t * lex = mp_lexer_new_from_file (vstr_str (file ));
7677
7778 if (lex == NULL ) {
78- nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_ImportError , "ImportError: No module named '%s'" , mod_name_p ));
79+ // we verified the file exists using stat, but lexer could still fail
80+ nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_ImportError , "ImportError: No module named '%s'" , vstr_str (file )));
7981 }
80- qstr source_name = mp_lexer_source_name (lex );
8182
82- // create a new module object
83- mp_obj_t module_obj = mp_obj_new_module (mod_name );
83+ qstr source_name = mp_lexer_source_name (lex );
8484
8585 // save the old context
8686 mp_map_t * old_locals = rt_locals_get ();
@@ -111,7 +111,7 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
111111 // TODO handle compile error correctly
112112 rt_locals_set (old_locals );
113113 rt_globals_set (old_globals );
114- return mp_const_none ;
114+ return ;
115115 }
116116
117117 // complied successfully, execute it
@@ -127,7 +127,84 @@ mp_obj_t mp_builtin___import__(int n_args, mp_obj_t *args) {
127127 }
128128 rt_locals_set (old_locals );
129129 rt_globals_set (old_globals );
130+ }
131+
132+ mp_obj_t mp_builtin___import__ (int n_args , mp_obj_t * args ) {
133+ /*
134+ printf("import:\n");
135+ for (int i = 0; i < n; i++) {
136+ printf(" ");
137+ mp_obj_print(args[i]);
138+ printf("\n");
139+ }
140+ */
141+
142+ // check if module already exists
143+ mp_obj_t module_obj = mp_obj_module_get (mp_obj_str_get_qstr (args [0 ]));
144+ if (module_obj != MP_OBJ_NULL ) {
145+ return module_obj ;
146+ }
147+
148+ uint mod_len ;
149+ const char * mod_str = (const char * )mp_obj_str_get_data (args [0 ], & mod_len );
150+
151+ uint last = 0 ;
152+ vstr_t * path = vstr_new ();
153+ module_obj = MP_OBJ_NULL ;
154+ uint i ;
155+ for (i = 1 ; i <= mod_len ; i ++ ) {
156+ if (i == mod_len || mod_str [i ] == '.' ) {
157+ // create a qstr for the module name up to this depth
158+ qstr mod_name = qstr_from_strn (mod_str , i );
159+
160+ // find the file corresponding to the module name
161+ mp_import_stat_t stat ;
162+ if (vstr_len (path ) == 0 ) {
163+ // first module in the dotted-name; search for a directory or file
164+ stat = find_file (mod_str , i , path );
165+ } else {
166+ // latter module in the dotted-name; append to path
167+ vstr_add_char (path , PATH_SEP_CHAR );
168+ vstr_add_strn (path , mod_str + last , i - last );
169+ stat = stat_dir_or_file (path );
170+ }
171+ last = i + 1 ;
172+
173+ // fail if we couldn't find the file
174+ if (stat == MP_IMPORT_STAT_NO_EXIST ) {
175+ nlr_jump (mp_obj_new_exception_msg_varg (MP_QSTR_ImportError , "ImportError: No module named '%s'" , qstr_str (mod_name )));
176+ }
177+
178+ module_obj = mp_obj_module_get (mod_name );
179+ if (module_obj == MP_OBJ_NULL ) {
180+ // module not already loaded, so load it!
181+
182+ module_obj = mp_obj_new_module (mod_name );
183+
184+ if (stat == MP_IMPORT_STAT_DIR ) {
185+ vstr_add_char (path , PATH_SEP_CHAR );
186+ vstr_add_str (path , "__init__.py" );
187+ if (mp_import_stat (vstr_str (path )) == MP_IMPORT_STAT_FILE ) {
188+ do_load (module_obj , path );
189+ }
190+ vstr_cut_tail (path , 12 ); // cut off /__init__.py
191+ } else { // MP_IMPORT_STAT_FILE
192+ do_load (module_obj , path );
193+ break ;
194+ }
195+ }
196+ }
197+ }
198+
199+ if (i < mod_len ) {
200+ // we loaded a package, now need to load objects from within that package
201+ // TODO
202+ assert (0 );
203+ }
204+
205+ vstr_free (path );
130206
131207 return module_obj ;
132208}
209+
133210MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mp_builtin___import___obj , 1 , 5 , mp_builtin___import__ );
0 commit comments