Making (import) a lot smarter

With these changes, the import function will become a lot smarter, and
will combine all of import, import-from and import-as in a hyly lispy
syntax:

 (import sys os whatever_else)
 (import [sys [exit argv]] [os :as real_os]
         [whatever_else [some_function :as sf]])

That is, each argument of import can be:

 - A plain symbol, which will be imported
 - A list, which will be handled specially

If the argument is a list, the first element will always be the module
name to import, the second member can be either of these:

 - A list of symbols to import
 - The ':as' keyword
 - Nothing

If it is the ':as' keyword, the third argument must be an alias. If it
is a list of symbols to import, we'll iterate through that list too. If
any symbol is followed by an ':as' keyword, we'll pick all three, and
treat the third member as an alias. If there is nothing else in the
list, we'll import the module as-is.

All this combined fixes #113.

Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This commit is contained in:
Gergely Nagy 2013-04-13 12:50:25 +02:00
parent 1e98889604
commit 5d895c2005
2 changed files with 68 additions and 4 deletions

View File

@ -466,11 +466,47 @@ class HyASTCompiler(object):
@builds("import")
def compile_import_expression(self, expr):
def _compile_import(expr, module, names = None, importer = ast.Import):
return [
importer(
lineno=expr.start_line,
col_offset=expr.start_column,
module=ast_str(module),
names=names or [ast.alias(name=ast_str(module), asname=None)],
level=0)
]
expr.pop(0) # index
return ast.Import(
lineno=expr.start_line,
col_offset=expr.start_column,
names=[ast.alias(name=ast_str(x), asname=None) for x in expr])
rimports = []
while len(expr) > 0:
iexpr = expr.pop(0)
if type(iexpr) == HySymbol:
rimports += _compile_import(expr, iexpr)
elif type(iexpr) == HyList and len(iexpr) == 1:
rimports += _compile_import(expr, iexpr.pop(0))
elif type(iexpr) == HyList:
module = iexpr.pop(0)
if type(iexpr[0]) == HyKeyword and iexpr[0] == HyKeyword(":as"):
assert len(iexpr) == 2, "garbage after aliased import"
iexpr.pop(0) # :as
alias=iexpr.pop(0)
rimports += _compile_import(expr, ast_str(module),
[ast.alias(name=ast_str(module),
asname=ast_str(alias))])
elif type(iexpr[0] == HyList):
symbol_list = iexpr.pop(0)
names = []
while len(symbol_list) > 0:
sym = symbol_list.pop(0)
if len(symbol_list) > 0 and type(symbol_list[0]) == HyKeyword:
symbol_list.pop(0)
alias = ast_str(symbol_list.pop(0))
else:
alias = None
names += [ast.alias(name=ast_str(sym), asname=alias)]
rimports += _compile_import(expr, module, names, ast.ImportFrom)
return rimports
@builds("import_as")
def compile_import_as_expression(self, expr):

View File

@ -546,3 +546,31 @@
(assert (= "foobar" (eval (quote "foobar"))))
(setv x (quote 42))
(assert (= x (eval x))))
(defn test-import-syntax []
"NATIVE: test the import syntax."
; Simple import
(import sys os)
; from os.path import basename
(import [os.path [basename]])
(assert (= (basename "/some/path") "path"))
; import os.path as p
(import [os.path :as p])
(assert (= p.basename basename))
; from os.path import basename as bn
(import [os.path [basename :as bn]])
(assert (= bn basename))
(import [sys])
;; Multiple stuff to import
(import sys [os.path [dirname]]
[os.path :as op]
[os.path [dirname :as dn]])
(assert (= (dirname "/some/path") "/some"))
(assert (= op.dirname dirname))
(assert (= dn dirname)))