Repository: hylang/hy

Issue:
Empty form crashes compiler
An empty form will crash the compiler as shown below. One would think, that this wouldn't matter, but I accidentally left a `()` in a 300 line file and it was quite hard to catch. A normal error with a line number would be nice

```
felix@alienware:~$ hy --version
hy 0.18.0
felix@alienware:~$ echo "()" > foo.hy && hy foo.hy
Traceback (most recent call last):
  File "/home/felix/.pyenv/versions/3.8.0/bin/hy", line 8, in <module>
    sys.exit(hy_main())
  File "/home/felix/.pyenv/versions/3.8.0/lib/python3.8/runpy.py", line 261, in run_path
    code, fname = _get_code_from_file(run_name, path_name)
  File "<frozen importlib._bootstrap_external>", line 916, in get_code
hy.errors.HyCompileError: Internal Compiler Bug 😱
⤷ Traceback (most recent call last):
  File "/home/felix/.pyenv/versions/3.8.0/lib/python3.8/site-packages/hy/compiler.py", line 433, in compile
    ret = self.compile_atom(tree)
  File "/home/felix/.pyenv/versions/3.8.0/lib/python3.8/site-packages/hy/compiler.py", line 427, in compile_atom
    return Result() + _model_compilers[type(atom)](self, atom)
  File "/home/felix/.pyenv/versions/3.8.0/lib/python3.8/site-packages/hy/compiler.py", line 1730, in compile_expression
    expr = macroexpand(expr, self.module, self)
  File "/home/felix/.pyenv/versions/3.8.0/lib/python3.8/site-packages/hy/macros.py", line 316, in macroexpand
    fn = tree[0]
  File "/home/felix/.pyenv/versions/3.8.0/lib/python3.8/site-packages/hy/models.py", line 278, in __getitem__
    ret = super(HySequence, self).__getitem__(item)
IndexError: tuple index out of range
```



Discussion:

Resolving patch:
diff --git a/hy/macros.py b/hy/macros.py
--- a/hy/macros.py
+++ b/hy/macros.py
@@ -308,10 +308,7 @@ def macroexpand(tree, module, compiler=None, once=False):
 
     assert not compiler or compiler.module == module
 
-    while True:
-
-        if not isinstance(tree, HyExpression) or tree == []:
-            break
+    while isinstance(tree, HyExpression) and tree:
 
         fn = tree[0]
         if fn in ("quote", "quasiquote") or not isinstance(fn, HySymbol):


Test patch:
diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py
--- a/tests/compilers/test_ast.py
+++ b/tests/compilers/test_ast.py
@@ -7,7 +7,7 @@
 
 from hy import HyString
 from hy.compiler import hy_compile, hy_eval
-from hy.errors import HyCompileError, HyLanguageError, HyError
+from hy.errors import HyLanguageError, HyError
 from hy.lex import hy_parse
 from hy.lex.exceptions import LexException, PrematureEndOfInput
 from hy._compat import PY36
@@ -36,14 +36,11 @@ def can_eval(expr):
 def cant_compile(expr):
     with pytest.raises(HyError) as excinfo:
         hy_compile(hy_parse(expr), __name__)
-
-    if issubclass(excinfo.type, HyLanguageError):
-        assert excinfo.value.msg
-        return excinfo.value
-    elif issubclass(excinfo.type, HyCompileError):
-        # Anything that can't be compiled should raise a user friendly
-        # error, otherwise it's a compiler bug.
-        return excinfo.value
+    # Anything that can't be compiled should raise a user friendly
+    # error, otherwise it's a compiler bug.
+    assert issubclass(excinfo.type, HyLanguageError)
+    assert excinfo.value.msg
+    return excinfo.value
 
 
 def s(x):