Add special exception and handling for wrapper errors

This commit is contained in:
Brandon T. Willard 2018-11-13 12:11:51 -06:00 committed by Kodi Arfer
parent 4ae4baac2a
commit 9e62903d8a
4 changed files with 34 additions and 15 deletions

View File

@ -207,6 +207,15 @@ class HySyntaxError(HyLanguageError, SyntaxError):
"""Error during the Lexing of a Hython expression.""" """Error during the Lexing of a Hython expression."""
class HyWrapperError(HyError, TypeError):
"""Errors caused by language model object wrapping.
These can be caused by improper user-level use of a macro, so they're
not really "internal". If they arise due to anything else, they're an
internal/compiler problem, though.
"""
def _module_filter_name(module_name): def _module_filter_name(module_name):
try: try:
compiler_loader = pkgutil.get_loader(module_name) compiler_loader = pkgutil.get_loader(module_name)

View File

@ -342,10 +342,10 @@ def macroexpand(tree, module, compiler=None, once=False):
with macro_exceptions(module, tree, compiler): with macro_exceptions(module, tree, compiler):
obj = m(module.__name__, *tree[1:], **opts) obj = m(module.__name__, *tree[1:], **opts)
if isinstance(obj, HyExpression): if isinstance(obj, HyExpression):
obj.module = inspect.getmodule(m) obj.module = inspect.getmodule(m)
tree = replace_hy_obj(obj, tree) tree = replace_hy_obj(obj, tree)
if once: if once:
break break

View File

@ -7,6 +7,7 @@ from contextlib import contextmanager
from math import isnan, isinf from math import isnan, isinf
from hy import _initialize_env_var from hy import _initialize_env_var
from hy._compat import PY3, str_type, bytes_type, long_type, string_types from hy._compat import PY3, str_type, bytes_type, long_type, string_types
from hy.errors import HyWrapperError
from fractions import Fraction from fractions import Fraction
from clint.textui import colored from clint.textui import colored
@ -64,7 +65,7 @@ def wrap_value(x):
new = _wrappers.get(type(x), lambda y: y)(x) new = _wrappers.get(type(x), lambda y: y)(x)
if not isinstance(new, HyObject): if not isinstance(new, HyObject):
raise TypeError("Don't know how to wrap {!r}: {!r}".format(type(x), x)) raise HyWrapperError("Don't know how to wrap {!r}: {!r}".format(type(x), x))
if isinstance(x, HyObject): if isinstance(x, HyObject):
new = new.replace(x, recursive=False) new = new.replace(x, recursive=False)
if not hasattr(new, "start_column"): if not hasattr(new, "start_column"):

View File

@ -162,8 +162,8 @@
") ")
;; expand the macro twice, should use a different ;; expand the macro twice, should use a different
;; gensym each time ;; gensym each time
(setv _ast1 (hy-compile (hy-parse macro1) "foo")) (setv _ast1 (hy-compile (hy-parse macro1) __name__))
(setv _ast2 (hy-compile (hy-parse macro1) "foo")) (setv _ast2 (hy-compile (hy-parse macro1) __name__))
(setv s1 (to_source _ast1)) (setv s1 (to_source _ast1))
(setv s2 (to_source _ast2)) (setv s2 (to_source _ast2))
;; and make sure there is something new that starts with _;G| ;; and make sure there is something new that starts with _;G|
@ -189,8 +189,8 @@
") ")
;; expand the macro twice, should use a different ;; expand the macro twice, should use a different
;; gensym each time ;; gensym each time
(setv _ast1 (hy-compile (hy-parse macro1) "foo")) (setv _ast1 (hy-compile (hy-parse macro1) __name__))
(setv _ast2 (hy-compile (hy-parse macro1) "foo")) (setv _ast2 (hy-compile (hy-parse macro1) __name__))
(setv s1 (to_source _ast1)) (setv s1 (to_source _ast1))
(setv s2 (to_source _ast2)) (setv s2 (to_source _ast2))
(assert (in (mangle "_;a|") s1)) (assert (in (mangle "_;a|") s1))
@ -213,8 +213,8 @@
") ")
;; expand the macro twice, should use a different ;; expand the macro twice, should use a different
;; gensym each time ;; gensym each time
(setv _ast1 (hy-compile (hy-parse macro1) "foo")) (setv _ast1 (hy-compile (hy-parse macro1) __name__))
(setv _ast2 (hy-compile (hy-parse macro1) "foo")) (setv _ast2 (hy-compile (hy-parse macro1) __name__))
(setv s1 (to_source _ast1)) (setv s1 (to_source _ast1))
(setv s2 (to_source _ast2)) (setv s2 (to_source _ast2))
(assert (in (mangle "_;res|") s1)) (assert (in (mangle "_;res|") s1))
@ -224,7 +224,7 @@
;; defmacro/g! didn't like numbers initially because they ;; defmacro/g! didn't like numbers initially because they
;; don't have a startswith method and blew up during expansion ;; don't have a startswith method and blew up during expansion
(setv macro2 "(defmacro/g! two-point-zero [] `(+ (float 1) 1.0))") (setv macro2 "(defmacro/g! two-point-zero [] `(+ (float 1) 1.0))")
(assert (hy-compile (hy-parse macro2) "foo"))) (assert (hy-compile (hy-parse macro2) __name__)))
(defn test-defmacro! [] (defn test-defmacro! []
;; defmacro! must do everything defmacro/g! can ;; defmacro! must do everything defmacro/g! can
@ -243,8 +243,8 @@
") ")
;; expand the macro twice, should use a different ;; expand the macro twice, should use a different
;; gensym each time ;; gensym each time
(setv _ast1 (hy-compile (hy-parse macro1) "foo")) (setv _ast1 (hy-compile (hy-parse macro1) __name__))
(setv _ast2 (hy-compile (hy-parse macro1) "foo")) (setv _ast2 (hy-compile (hy-parse macro1) __name__))
(setv s1 (to_source _ast1)) (setv s1 (to_source _ast1))
(setv s2 (to_source _ast2)) (setv s2 (to_source _ast2))
(assert (in (mangle "_;res|") s1)) (assert (in (mangle "_;res|") s1))
@ -254,7 +254,7 @@
;; defmacro/g! didn't like numbers initially because they ;; defmacro/g! didn't like numbers initially because they
;; don't have a startswith method and blew up during expansion ;; don't have a startswith method and blew up during expansion
(setv macro2 "(defmacro! two-point-zero [] `(+ (float 1) 1.0))") (setv macro2 "(defmacro! two-point-zero [] `(+ (float 1) 1.0))")
(assert (hy-compile (hy-parse macro2) "foo")) (assert (hy-compile (hy-parse macro2) __name__))
(defmacro! foo! [o!foo] `(do ~g!foo ~g!foo)) (defmacro! foo! [o!foo] `(do ~g!foo ~g!foo))
;; test that o! becomes g! ;; test that o! becomes g!
@ -507,4 +507,13 @@ in expansions."
(assert (= (cut expected 0 -1) (cut output 0 -1))) (assert (= (cut expected 0 -1) (cut output 0 -1)))
(assert (or (= (get expected -1) (get output -1)) (assert (or (= (get expected -1) (get output -1))
;; Handle PyPy's peculiarities ;; Handle PyPy's peculiarities
(= (.replace (get expected -1) "global " "") (get output -1))))) (= (.replace (get expected -1) "global " "") (get output -1))))
;; This should throw a `HyWrapperError` that gets turned into a
;; `HyMacroExpansionError`.
(with [excinfo (pytest.raises HyMacroExpansionError)]
(eval '(do (defmacro wrap-error-test []
(fn []))
(wrap-error-test))))
(assert (in "HyWrapperError" (str excinfo.value))))