diff --git a/hy/compiler.py b/hy/compiler.py index fac4cfa..51ab4fc 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -459,8 +459,9 @@ class HyASTCompiler(object): try: value = next(exprs_iter) except StopIteration: - msg = "Keyword argument {kw} needs a value" - raise HyCompileError(msg.format(kw=str(expr))) + raise HyTypeError(expr, + "Keyword argument {kw} needs " + "a value.".format(kw=str(expr[1:]))) compiled_value = self.compile(value) ret += compiled_value diff --git a/hy/lex/parser.py b/hy/lex/parser.py index a63be3e..22aaf26 100644 --- a/hy/lex/parser.py +++ b/hy/lex/parser.py @@ -308,6 +308,9 @@ def t_identifier(p): if p.endswith("?") and p != "?": p = "is_%s" % (p[:-1]) + if p.endswith("!") and p != "!": + p = "%s_bang" % (p[:-1]) + return p obj = ".".join([mangle(part) for part in obj.split(".")]) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index c68c609..768e724 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -439,6 +439,16 @@ def test_lambda_list_keywords_mixed(): " (list x xs kwxs kwoxs))") +def test_missing_keyword_argument_value(): + """Ensure the compiler chokes on missing keyword argument values.""" + try: + can_compile("((fn [x] x) :x)") + except HyTypeError as e: + assert(e.message == "Keyword argument :x needs a value.") + else: + assert(False) + + def test_ast_unicode_strings(): """Ensure we handle unicode strings correctly""" @@ -521,7 +531,16 @@ def test_cons_correct(): can_compile("(cons a b)") + def test_bad_setv(): """Ensure setv handles error cases""" cant_compile("(setv if 1)") cant_compile("(setv (a b) [1 2])") + + +def test_defn(): + """Ensure that defn works correctly in various corner cases""" + cant_compile("(defn if [] 1)") + cant_compile("(defn \"hy\" [] 1)") + cant_compile("(defn :hy [] 1)") + can_compile("(defn &hy [] 1)") diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index cc95675..56ed52a 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -326,6 +326,24 @@ def test_lex_mangling_qmark(): assert entry == [HySymbol(".is_foo.bar.is_baz")] +def test_lex_mangling_bang(): + """Ensure that identifiers ending with a bang get mangled ok""" + entry = tokenize("foo!") + assert entry == [HySymbol("foo_bang")] + entry = tokenize("!") + assert entry == [HySymbol("!")] + entry = tokenize("im!foo") + assert entry == [HySymbol("im!foo")] + entry = tokenize(".foo!") + assert entry == [HySymbol(".foo_bang")] + entry = tokenize("foo.bar!") + assert entry == [HySymbol("foo.bar_bang")] + entry = tokenize("foo!.bar") + assert entry == [HySymbol("foo_bang.bar")] + entry = tokenize(".foo!.bar.baz!") + assert entry == [HySymbol(".foo_bang.bar.baz_bang")] + + def test_simple_cons(): """Check that cons gets tokenized correctly""" entry = tokenize("(a . b)")[0] diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index d468533..ec771e6 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -673,6 +673,12 @@ (assert (= 43 (my-fun 42)))) +(defn test-defn-lambdakey [] + "NATIVE: test defn with a &symbol function name" + (defn &hy [] 1) + (assert (= (&hy) 1))) + + (defn test-defn-do [] "NATIVE: test defn evaluation order with do" (setv acc [])