Use model patterns for import
and require
In the process, I've banned the syntax `(import [foo])` in favor of `(import foo)`.
This commit is contained in:
parent
11f1c149ef
commit
9368e4bc4e
1
NEWS.rst
1
NEWS.rst
@ -34,6 +34,7 @@ Other Breaking Changes
|
|||||||
* `HyKeyword` no longer inherits from the string type and has been
|
* `HyKeyword` no longer inherits from the string type and has been
|
||||||
made into its own object type.
|
made into its own object type.
|
||||||
* `(except)` is no longer allowed. Use `(except [])` instead.
|
* `(except)` is no longer allowed. Use `(except [])` instead.
|
||||||
|
* `(import [foo])` is no longer allowed. Use `(import foo)` instead.
|
||||||
|
|
||||||
New Features
|
New Features
|
||||||
------------------------------
|
------------------------------
|
||||||
|
@ -186,8 +186,8 @@ def ideas_macro(ETname):
|
|||||||
|
|
||||||
""")])
|
""")])
|
||||||
|
|
||||||
require("hy.cmdline", "__console__", all_macros=True)
|
require("hy.cmdline", "__console__", assignments="ALL")
|
||||||
require("hy.cmdline", "__main__", all_macros=True)
|
require("hy.cmdline", "__main__", assignments="ALL")
|
||||||
|
|
||||||
SIMPLE_TRACEBACKS = True
|
SIMPLE_TRACEBACKS = True
|
||||||
|
|
||||||
|
173
hy/compiler.py
173
hy/compiler.py
@ -1050,76 +1050,6 @@ class HyASTCompiler(object):
|
|||||||
node = asty.YieldFrom if expr[0] == "yield-from" else asty.Await
|
node = asty.YieldFrom if expr[0] == "yield-from" else asty.Await
|
||||||
return ret + node(expr, value=ret.force_expr)
|
return ret + node(expr, value=ret.force_expr)
|
||||||
|
|
||||||
@builds("import")
|
|
||||||
def compile_import_expression(self, expr):
|
|
||||||
expr = copy.deepcopy(expr)
|
|
||||||
def _compile_import(expr, module, names=None, importer=asty.Import):
|
|
||||||
if not names:
|
|
||||||
names = [ast.alias(name=ast_str(module, piecewise=True), asname=None)]
|
|
||||||
|
|
||||||
ast_module = ast_str(module, piecewise=True)
|
|
||||||
module = ast_module.lstrip(".")
|
|
||||||
level = len(ast_module) - len(module)
|
|
||||||
if not module:
|
|
||||||
module = None
|
|
||||||
|
|
||||||
return Result() + importer(
|
|
||||||
expr, module=module, names=names, level=level)
|
|
||||||
|
|
||||||
expr.pop(0) # index
|
|
||||||
rimports = Result()
|
|
||||||
while len(expr) > 0:
|
|
||||||
iexpr = expr.pop(0)
|
|
||||||
|
|
||||||
if not isinstance(iexpr, (HySymbol, HyList)):
|
|
||||||
raise HyTypeError(iexpr, "(import) requires a Symbol "
|
|
||||||
"or a List.")
|
|
||||||
|
|
||||||
if isinstance(iexpr, HySymbol):
|
|
||||||
rimports += _compile_import(expr, iexpr)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(iexpr, HyList) and len(iexpr) == 1:
|
|
||||||
rimports += _compile_import(expr, iexpr.pop(0))
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(iexpr, HyList) and iexpr:
|
|
||||||
module = iexpr.pop(0)
|
|
||||||
entry = iexpr[0]
|
|
||||||
if entry == HyKeyword("as"):
|
|
||||||
if not len(iexpr) == 2:
|
|
||||||
raise HyTypeError(iexpr,
|
|
||||||
"garbage after aliased import")
|
|
||||||
iexpr.pop(0) # :as
|
|
||||||
alias = iexpr.pop(0)
|
|
||||||
names = [ast.alias(name=ast_str(module, piecewise=True),
|
|
||||||
asname=ast_str(alias))]
|
|
||||||
rimports += _compile_import(expr, ast_str(module), names)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(entry, HyList):
|
|
||||||
names = []
|
|
||||||
while entry:
|
|
||||||
sym = entry.pop(0)
|
|
||||||
if entry and isinstance(entry[0], HyKeyword):
|
|
||||||
entry.pop(0)
|
|
||||||
alias = ast_str(entry.pop(0))
|
|
||||||
else:
|
|
||||||
alias = None
|
|
||||||
names.append(ast.alias(name=(str(sym) if sym == "*" else ast_str(sym)),
|
|
||||||
asname=alias))
|
|
||||||
|
|
||||||
rimports += _compile_import(expr, module,
|
|
||||||
names, asty.ImportFrom)
|
|
||||||
continue
|
|
||||||
|
|
||||||
raise HyTypeError(
|
|
||||||
entry,
|
|
||||||
"Unknown entry (`%s`) in the HyList" % (entry)
|
|
||||||
)
|
|
||||||
|
|
||||||
return rimports
|
|
||||||
|
|
||||||
@special("get", [FORM, oneplus(FORM)])
|
@special("get", [FORM, oneplus(FORM)])
|
||||||
def compile_index_expression(self, expr, name, obj, indices):
|
def compile_index_expression(self, expr, name, obj, indices):
|
||||||
indices, ret, _ = self._compile_collect(indices)
|
indices, ret, _ = self._compile_collect(indices)
|
||||||
@ -1315,53 +1245,70 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
return operand
|
return operand
|
||||||
|
|
||||||
@builds("require")
|
@special(["import", "require"], [many(
|
||||||
def compile_require(self, expression):
|
SYM |
|
||||||
|
brackets(SYM, sym(":as"), SYM) |
|
||||||
|
brackets(SYM, brackets(many(SYM + maybe(sym(":as") + SYM)))))])
|
||||||
|
def compile_import_or_require(self, expr, root, entries):
|
||||||
"""
|
"""
|
||||||
TODO: keep track of what we've imported in this run and then
|
TODO for `require`: keep track of what we've imported in this run and
|
||||||
"unimport" it after we've completed `thing' so that we don't pollute
|
then "unimport" it after we've completed `thing' so that we don't
|
||||||
other envs.
|
pollute other envs.
|
||||||
"""
|
"""
|
||||||
for entry in expression[1:]:
|
ret = Result()
|
||||||
|
|
||||||
|
for entry in entries:
|
||||||
|
assignments = "ALL"
|
||||||
|
prefix = ""
|
||||||
|
|
||||||
if isinstance(entry, HySymbol):
|
if isinstance(entry, HySymbol):
|
||||||
# e.g., (require foo)
|
# e.g., (import foo)
|
||||||
__import__(entry)
|
module, prefix = entry, entry
|
||||||
require(entry, self.module_name, all_macros=True,
|
elif isinstance(entry, HyList) and isinstance(entry[1], HySymbol):
|
||||||
prefix=entry)
|
# e.g., (import [foo :as bar])
|
||||||
elif isinstance(entry, HyList) and len(entry) == 2:
|
module, prefix = entry
|
||||||
# e.g., (require [foo [bar baz :as MyBaz bing]])
|
|
||||||
# or (require [foo [*]])
|
|
||||||
module, names = entry
|
|
||||||
if not isinstance(names, HyList):
|
|
||||||
raise HyTypeError(names,
|
|
||||||
"(require) name lists should be HyLists")
|
|
||||||
__import__(module)
|
|
||||||
if '*' in names:
|
|
||||||
if len(names) != 1:
|
|
||||||
raise HyTypeError(names, "* in a (require) name list "
|
|
||||||
"must be on its own")
|
|
||||||
require(module, self.module_name, all_macros=True)
|
|
||||||
else:
|
|
||||||
assignments = {}
|
|
||||||
while names:
|
|
||||||
if len(names) > 1 and names[1] == HyKeyword("as"):
|
|
||||||
k, _, v = names[:3]
|
|
||||||
del names[:3]
|
|
||||||
assignments[k] = v
|
|
||||||
else:
|
|
||||||
symbol = names.pop(0)
|
|
||||||
assignments[symbol] = symbol
|
|
||||||
require(module, self.module_name, assignments=assignments)
|
|
||||||
elif (isinstance(entry, HyList) and len(entry) == 3
|
|
||||||
and entry[1] == HyKeyword("as")):
|
|
||||||
# e.g., (require [foo :as bar])
|
|
||||||
module, _, prefix = entry
|
|
||||||
__import__(module)
|
|
||||||
require(module, self.module_name, all_macros=True,
|
|
||||||
prefix=prefix)
|
|
||||||
else:
|
else:
|
||||||
raise HyTypeError(entry, "unrecognized (require) syntax")
|
# e.g., (import [foo [bar baz :as MyBaz bing]])
|
||||||
return Result()
|
# or (import [foo [*]])
|
||||||
|
module, kids = entry
|
||||||
|
kids = kids[0]
|
||||||
|
if (HySymbol('*'), None) in kids:
|
||||||
|
if len(kids) != 1:
|
||||||
|
star = kids[kids.index((HySymbol('*'), None))][0]
|
||||||
|
raise HyTypeError(star, "* in an import name list "
|
||||||
|
"must be on its own")
|
||||||
|
else:
|
||||||
|
assignments = [(k, v or k) for k, v in kids]
|
||||||
|
|
||||||
|
if root == HySymbol("import"):
|
||||||
|
ast_module = ast_str(module, piecewise=True)
|
||||||
|
module = ast_module.lstrip(".")
|
||||||
|
level = len(ast_module) - len(module)
|
||||||
|
if assignments == "ALL" and prefix == "":
|
||||||
|
node = asty.ImportFrom
|
||||||
|
names = [ast.alias(name="*", asname=None)]
|
||||||
|
elif assignments == "ALL":
|
||||||
|
node = asty.Import
|
||||||
|
names = [ast.alias(
|
||||||
|
name=ast_module,
|
||||||
|
asname=ast_str(prefix)
|
||||||
|
if prefix and prefix != module
|
||||||
|
else None)]
|
||||||
|
else:
|
||||||
|
node = asty.ImportFrom
|
||||||
|
names = [
|
||||||
|
ast.alias(
|
||||||
|
name=ast_str(k),
|
||||||
|
asname=None if v == k else ast_str(v))
|
||||||
|
for k, v in assignments]
|
||||||
|
ret += node(
|
||||||
|
expr, module=module or None, names=names, level=level)
|
||||||
|
else: # root == HySymbol("require")
|
||||||
|
__import__(module)
|
||||||
|
require(module, self.module_name,
|
||||||
|
assignments=assignments, prefix=prefix)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
@special(["and", "or"], [many(FORM)])
|
@special(["and", "or"], [many(FORM)])
|
||||||
def compile_logical_or_and_and_operator(self, expr, operator, args):
|
def compile_logical_or_and_and_operator(self, expr, operator, args):
|
||||||
|
14
hy/macros.py
14
hy/macros.py
@ -80,11 +80,10 @@ def tag(name):
|
|||||||
return _
|
return _
|
||||||
|
|
||||||
|
|
||||||
def require(source_module, target_module,
|
def require(source_module, target_module, assignments, prefix=""):
|
||||||
all_macros=False, assignments={}, prefix=""):
|
|
||||||
"""Load macros from `source_module` in the namespace of
|
"""Load macros from `source_module` in the namespace of
|
||||||
`target_module`. `assignments` maps old names to new names, but is
|
`target_module`. `assignments` maps old names to new names, or
|
||||||
ignored if `all_macros` is true. If `prefix` is nonempty, it is
|
should be the string "ALL". If `prefix` is nonempty, it is
|
||||||
prepended to the name of each imported macro. (This means you get
|
prepended to the name of each imported macro. (This means you get
|
||||||
macros named things like "mymacromodule.mymacro", which looks like
|
macros named things like "mymacromodule.mymacro", which looks like
|
||||||
an attribute of a module, although it's actually just a symbol
|
an attribute of a module, although it's actually just a symbol
|
||||||
@ -97,17 +96,18 @@ def require(source_module, target_module,
|
|||||||
seen_names = set()
|
seen_names = set()
|
||||||
if prefix:
|
if prefix:
|
||||||
prefix += "."
|
prefix += "."
|
||||||
assignments = {mangle(str_type(k)): v for k, v in assignments.items()}
|
if assignments != "ALL":
|
||||||
|
assignments = {mangle(str_type(k)): v for k, v in assignments}
|
||||||
|
|
||||||
for d in _hy_macros, _hy_tag:
|
for d in _hy_macros, _hy_tag:
|
||||||
for name, macro in d[source_module].items():
|
for name, macro in d[source_module].items():
|
||||||
seen_names.add(name)
|
seen_names.add(name)
|
||||||
if all_macros:
|
if assignments == "ALL":
|
||||||
d[target_module][mangle(prefix + name)] = macro
|
d[target_module][mangle(prefix + name)] = macro
|
||||||
elif name in assignments:
|
elif name in assignments:
|
||||||
d[target_module][mangle(prefix + assignments[name])] = macro
|
d[target_module][mangle(prefix + assignments[name])] = macro
|
||||||
|
|
||||||
if not all_macros:
|
if assignments != "ALL":
|
||||||
unseen = frozenset(assignments.keys()).difference(seen_names)
|
unseen = frozenset(assignments.keys()).difference(seen_names)
|
||||||
if unseen:
|
if unseen:
|
||||||
raise ImportError("cannot require names: " + repr(list(unseen)))
|
raise ImportError("cannot require names: " + repr(list(unseen)))
|
||||||
|
@ -238,10 +238,10 @@ class HySequence(HyObject, list):
|
|||||||
An abstract type for sequence-like models to inherit from.
|
An abstract type for sequence-like models to inherit from.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def replace(self, other):
|
def replace(self, other, recursive=True):
|
||||||
for x in self:
|
if recursive:
|
||||||
replace_hy_obj(x, other)
|
for x in self:
|
||||||
|
replace_hy_obj(x, other)
|
||||||
HyObject.replace(self, other)
|
HyObject.replace(self, other)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@ -1396,8 +1396,6 @@
|
|||||||
(import [os.path [basename :as bn]])
|
(import [os.path [basename :as bn]])
|
||||||
(assert (= bn basename))
|
(assert (= bn basename))
|
||||||
|
|
||||||
(import [sys])
|
|
||||||
|
|
||||||
;; Multiple stuff to import
|
;; Multiple stuff to import
|
||||||
(import sys [os.path [dirname]]
|
(import sys [os.path [dirname]]
|
||||||
[os.path :as op]
|
[os.path :as op]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user