prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  repl shouldn't crash
  ```Hy
  => (defmacro bad [] `(macro-error 'x ""))
  <function <lambda> at 0x000001D01D0ED7B8>
  => (bad)
  Traceback (most recent call last):
    File "c:\users\me\documents\github\hy\hy\cmdline.py", line 99, in runsource
      ast_callback)
    File "c:\users\me\documents\github\hy\hy\importer.py", line 198, in hy_eval
      eval(ast_compile(_ast, "<eval_body>", "exec"), namespace)
    File "<eval_body>", line 1, in <module>
  hy.errors.HyMacroExpansionError: <exception str() failed>
  
  During handling of the above exception, another exception occurred:
  
  Traceback (most recent call last):
    File "C:\Users\ME\workspace\hy36-gilch\Scripts\hy-script.py", line 11, in <module>
      load_entry_point('hy', 'console_scripts', 'hy')()
    File "c:\users\me\documents\github\hy\hy\cmdline.py", line 346, in hy_main
      sys.exit(cmdline_handler("hy", sys.argv))
    File "c:\users\me\documents\github\hy\hy\cmdline.py", line 341, in cmdline_handler
      return run_repl(spy=options.spy, output_fn=options.repl_output_fn)
    File "c:\users\me\documents\github\hy\hy\cmdline.py", line 236, in run_repl
      os=platform.system()
    File "C:\Users\ME\AppData\Local\Programs\Python\Python36\lib\code.py", line 233, in interact
      more = self.push(line)
    File "C:\Users\ME\AppData\Local\Programs\Python\Python36\lib\code.py", line 259, in push
      more = self.runsource(source, self.filename)
    File "c:\users\me\documents\github\hy\hy\cmdline.py", line 105, in runsource
      print(e, file=sys.stderr)
    File "c:\users\me\documents\github\hy\hy\errors.py", line 46, in __str__
      line = self.expression.start_line
  AttributeError: 'HySymbol' object has no attribute 'start_line'
  ```
  The repl should report errors, but not exit.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `hy/errors.py`
  Content:
  ```
  1 # -*- encoding: utf-8 -*-
  2 # Copyright 2017 the authors.
  3 # This file is part of Hy, which is free software licensed under the Expat
  4 # license. See the LICENSE.
  5 
  6 import traceback
  7 
  8 from clint.textui import colored
  9 
  10 
  11 class HyError(Exception):
  12     """
  13     Generic Hy error. All internal Exceptions will be subclassed from this
  14     Exception.
  15     """
  16     pass
  17 
  18 
  19 class HyCompileError(HyError):
  20     def __init__(self, exception, traceback=None):
  21         self.exception = exception
  22         self.traceback = traceback
  23 
  24     def __str__(self):
  25         if isinstance(self.exception, HyTypeError):
  26             return str(self.exception)
  27         if self.traceback:
  28             tb = "".join(traceback.format_tb(self.traceback)).strip()
  29         else:
  30             tb = "No traceback available. 😟"
  31         return("Internal Compiler Bug 😱\n⤷ %s: %s\nCompilation traceback:\n%s"
  32                % (self.exception.__class__.__name__,
  33                   self.exception, tb))
  34 
  35 
  36 class HyTypeError(TypeError):
  37     def __init__(self, expression, message):
  38         super(HyTypeError, self).__init__(message)
  39         self.expression = expression
  40         self.message = message
  41         self.source = None
  42         self.filename = None
  43 
  44     def __str__(self):
  45 
  46         line = self.expression.start_line
  47         start = self.expression.start_column
  48         end = self.expression.end_column
  49 
  50         source = []
  51         if self.source is not None:
  52             source = self.source.split("\n")[line-1:self.expression.end_line]
  53 
  54             if line == self.expression.end_line:
  55                 length = end - start
  56             else:
  57                 length = len(source[0]) - start
  58 
  59         result = ""
  60 
  61         result += '  File "%s", line %d, column %d\n\n' % (self.filename,
  62                                                            line,
  63                                                            start)
  64 
  65         if len(source) == 1:
  66             result += '  %s\n' % colored.red(source[0])
  67             result += '  %s%s\n' % (' '*(start-1),
  68                                     colored.green('^' + '-'*(length-1) + '^'))
  69         if len(source) > 1:
  70             result += '  %s\n' % colored.red(source[0])
  71             result += '  %s%s\n' % (' '*(start-1),
  72                                     colored.green('^' + '-'*length))
  73             if len(source) > 2:  # write the middle lines
  74                 for line in source[1:-1]:
  75                     result += '  %s\n' % colored.red("".join(line))
  76                     result += '  %s\n' % colored.green("-"*len(line))
  77 
  78             # write the last line
  79             result += '  %s\n' % colored.red("".join(source[-1]))
  80             result += '  %s\n' % colored.green('-'*(end-1) + '^')
  81 
  82         result += colored.yellow("%s: %s\n\n" %
  83                                  (self.__class__.__name__,
  84                                   self.message.encode('utf-8')))
  85 
  86         return result
  87 
  88 
  89 class HyMacroExpansionError(HyTypeError):
  90     pass
  91 
  92 
  93 class HyIOError(HyError, IOError):
  94     """
  95     Trivial subclass of IOError and HyError, to distinguish between
  96     IOErrors raised by Hy itself as opposed to Hy programs.
  97     """
  98     pass
  99
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/hy/errors.py b/hy/errors.py
  --- a/hy/errors.py
  +++ b/hy/errors.py
  @@ -43,41 +43,47 @@
   
       def __str__(self):
   
  -        line = self.expression.start_line
  -        start = self.expression.start_column
  -        end = self.expression.end_column
  -
  -        source = []
  -        if self.source is not None:
  -            source = self.source.split("\n")[line-1:self.expression.end_line]
  -
  -            if line == self.expression.end_line:
  -                length = end - start
  -            else:
  -                length = len(source[0]) - start
  -
           result = ""
   
  -        result += '  File "%s", line %d, column %d\n\n' % (self.filename,
  -                                                           line,
  -                                                           start)
  -
  -        if len(source) == 1:
  -            result += '  %s\n' % colored.red(source[0])
  -            result += '  %s%s\n' % (' '*(start-1),
  -                                    colored.green('^' + '-'*(length-1) + '^'))
  -        if len(source) > 1:
  -            result += '  %s\n' % colored.red(source[0])
  -            result += '  %s%s\n' % (' '*(start-1),
  -                                    colored.green('^' + '-'*length))
  -            if len(source) > 2:  # write the middle lines
  -                for line in source[1:-1]:
  -                    result += '  %s\n' % colored.red("".join(line))
  -                    result += '  %s\n' % colored.green("-"*len(line))
  -
  -            # write the last line
  -            result += '  %s\n' % colored.red("".join(source[-1]))
  -            result += '  %s\n' % colored.green('-'*(end-1) + '^')
  +        if all(getattr(self.expression, x, None) is not None
  +               for x in ("start_line", "start_column", "end_column")):
  +
  +            line = self.expression.start_line
  +            start = self.expression.start_column
  +            end = self.expression.end_column
  +
  +            source = []
  +            if self.source is not None:
  +                source = self.source.split("\n")[line-1:self.expression.end_line]
  +
  +                if line == self.expression.end_line:
  +                    length = end - start
  +                else:
  +                    length = len(source[0]) - start
  +
  +            result += '  File "%s", line %d, column %d\n\n' % (self.filename,
  +                                                               line,
  +                                                               start)
  +
  +            if len(source) == 1:
  +                result += '  %s\n' % colored.red(source[0])
  +                result += '  %s%s\n' % (' '*(start-1),
  +                                        colored.green('^' + '-'*(length-1) + '^'))
  +            if len(source) > 1:
  +                result += '  %s\n' % colored.red(source[0])
  +                result += '  %s%s\n' % (' '*(start-1),
  +                                        colored.green('^' + '-'*length))
  +                if len(source) > 2:  # write the middle lines
  +                    for line in source[1:-1]:
  +                        result += '  %s\n' % colored.red("".join(line))
  +                        result += '  %s\n' % colored.green("-"*len(line))
  +
  +                # write the last line
  +                result += '  %s\n' % colored.red("".join(source[-1]))
  +                result += '  %s\n' % colored.green('-'*(end-1) + '^')
  +
  +        else:
  +            result += '  File "%s", unknown location\n' % self.filename
   
           result += colored.yellow("%s: %s\n\n" %
                                    (self.__class__.__name__,
  
verification_info: {"golden_diff": "diff --git a/hy/errors.py b/hy/errors.py\n--- a/hy/errors.py\n+++ b/hy/errors.py\n@@ -43,41 +43,47 @@\n \n     def __str__(self):\n \n-        line = self.expression.start_line\n-        start = self.expression.start_column\n-        end = self.expression.end_column\n-\n-        source = []\n-        if self.source is not None:\n-            source = self.source.split(\"\\n\")[line-1:self.expression.end_line]\n-\n-            if line == self.expression.end_line:\n-                length = end - start\n-            else:\n-                length = len(source[0]) - start\n-\n         result = \"\"\n \n-        result += '  File \"%s\", line %d, column %d\\n\\n' % (self.filename,\n-                                                           line,\n-                                                           start)\n-\n-        if len(source) == 1:\n-            result += '  %s\\n' % colored.red(source[0])\n-            result += '  %s%s\\n' % (' '*(start-1),\n-                                    colored.green('^' + '-'*(length-1) + '^'))\n-        if len(source) > 1:\n-            result += '  %s\\n' % colored.red(source[0])\n-            result += '  %s%s\\n' % (' '*(start-1),\n-                                    colored.green('^' + '-'*length))\n-            if len(source) > 2:  # write the middle lines\n-                for line in source[1:-1]:\n-                    result += '  %s\\n' % colored.red(\"\".join(line))\n-                    result += '  %s\\n' % colored.green(\"-\"*len(line))\n-\n-            # write the last line\n-            result += '  %s\\n' % colored.red(\"\".join(source[-1]))\n-            result += '  %s\\n' % colored.green('-'*(end-1) + '^')\n+        if all(getattr(self.expression, x, None) is not None\n+               for x in (\"start_line\", \"start_column\", \"end_column\")):\n+\n+            line = self.expression.start_line\n+            start = self.expression.start_column\n+            end = self.expression.end_column\n+\n+            source = []\n+            if self.source is not None:\n+                source = self.source.split(\"\\n\")[line-1:self.expression.end_line]\n+\n+                if line == self.expression.end_line:\n+                    length = end - start\n+                else:\n+                    length = len(source[0]) - start\n+\n+            result += '  File \"%s\", line %d, column %d\\n\\n' % (self.filename,\n+                                                               line,\n+                                                               start)\n+\n+            if len(source) == 1:\n+                result += '  %s\\n' % colored.red(source[0])\n+                result += '  %s%s\\n' % (' '*(start-1),\n+                                        colored.green('^' + '-'*(length-1) + '^'))\n+            if len(source) > 1:\n+                result += '  %s\\n' % colored.red(source[0])\n+                result += '  %s%s\\n' % (' '*(start-1),\n+                                        colored.green('^' + '-'*length))\n+                if len(source) > 2:  # write the middle lines\n+                    for line in source[1:-1]:\n+                        result += '  %s\\n' % colored.red(\"\".join(line))\n+                        result += '  %s\\n' % colored.green(\"-\"*len(line))\n+\n+                # write the last line\n+                result += '  %s\\n' % colored.red(\"\".join(source[-1]))\n+                result += '  %s\\n' % colored.green('-'*(end-1) + '^')\n+\n+        else:\n+            result += '  File \"%s\", unknown location\\n' % self.filename\n \n         result += colored.yellow(\"%s: %s\\n\\n\" %\n                                  (self.__class__.__name__,\n", "issue": "repl shouldn't crash\n```Hy\r\n=> (defmacro bad [] `(macro-error 'x \"\"))\r\n<function <lambda> at 0x000001D01D0ED7B8>\r\n=> (bad)\r\nTraceback (most recent call last):\r\n  File \"c:\\users\\me\\documents\\github\\hy\\hy\\cmdline.py\", line 99, in runsource\r\n    ast_callback)\r\n  File \"c:\\users\\me\\documents\\github\\hy\\hy\\importer.py\", line 198, in hy_eval\r\n    eval(ast_compile(_ast, \"<eval_body>\", \"exec\"), namespace)\r\n  File \"<eval_body>\", line 1, in <module>\r\nhy.errors.HyMacroExpansionError: <exception str() failed>\r\n\r\nDuring handling of the above exception, another exception occurred:\r\n\r\nTraceback (most recent call last):\r\n  File \"C:\\Users\\ME\\workspace\\hy36-gilch\\Scripts\\hy-script.py\", line 11, in <module>\r\n    load_entry_point('hy', 'console_scripts', 'hy')()\r\n  File \"c:\\users\\me\\documents\\github\\hy\\hy\\cmdline.py\", line 346, in hy_main\r\n    sys.exit(cmdline_handler(\"hy\", sys.argv))\r\n  File \"c:\\users\\me\\documents\\github\\hy\\hy\\cmdline.py\", line 341, in cmdline_handler\r\n    return run_repl(spy=options.spy, output_fn=options.repl_output_fn)\r\n  File \"c:\\users\\me\\documents\\github\\hy\\hy\\cmdline.py\", line 236, in run_repl\r\n    os=platform.system()\r\n  File \"C:\\Users\\ME\\AppData\\Local\\Programs\\Python\\Python36\\lib\\code.py\", line 233, in interact\r\n    more = self.push(line)\r\n  File \"C:\\Users\\ME\\AppData\\Local\\Programs\\Python\\Python36\\lib\\code.py\", line 259, in push\r\n    more = self.runsource(source, self.filename)\r\n  File \"c:\\users\\me\\documents\\github\\hy\\hy\\cmdline.py\", line 105, in runsource\r\n    print(e, file=sys.stderr)\r\n  File \"c:\\users\\me\\documents\\github\\hy\\hy\\errors.py\", line 46, in __str__\r\n    line = self.expression.start_line\r\nAttributeError: 'HySymbol' object has no attribute 'start_line'\r\n```\r\nThe repl should report errors, but not exit.\n", "before_files": [{"content": "# -*- encoding: utf-8 -*-\n# Copyright 2017 the authors.\n# This file is part of Hy, which is free software licensed under the Expat\n# license. See the LICENSE.\n\nimport traceback\n\nfrom clint.textui import colored\n\n\nclass HyError(Exception):\n    \"\"\"\n    Generic Hy error. All internal Exceptions will be subclassed from this\n    Exception.\n    \"\"\"\n    pass\n\n\nclass HyCompileError(HyError):\n    def __init__(self, exception, traceback=None):\n        self.exception = exception\n        self.traceback = traceback\n\n    def __str__(self):\n        if isinstance(self.exception, HyTypeError):\n            return str(self.exception)\n        if self.traceback:\n            tb = \"\".join(traceback.format_tb(self.traceback)).strip()\n        else:\n            tb = \"No traceback available. \ud83d\ude1f\"\n        return(\"Internal Compiler Bug \ud83d\ude31\\n\u2937 %s: %s\\nCompilation traceback:\\n%s\"\n               % (self.exception.__class__.__name__,\n                  self.exception, tb))\n\n\nclass HyTypeError(TypeError):\n    def __init__(self, expression, message):\n        super(HyTypeError, self).__init__(message)\n        self.expression = expression\n        self.message = message\n        self.source = None\n        self.filename = None\n\n    def __str__(self):\n\n        line = self.expression.start_line\n        start = self.expression.start_column\n        end = self.expression.end_column\n\n        source = []\n        if self.source is not None:\n            source = self.source.split(\"\\n\")[line-1:self.expression.end_line]\n\n            if line == self.expression.end_line:\n                length = end - start\n            else:\n                length = len(source[0]) - start\n\n        result = \"\"\n\n        result += '  File \"%s\", line %d, column %d\\n\\n' % (self.filename,\n                                                           line,\n                                                           start)\n\n        if len(source) == 1:\n            result += '  %s\\n' % colored.red(source[0])\n            result += '  %s%s\\n' % (' '*(start-1),\n                                    colored.green('^' + '-'*(length-1) + '^'))\n        if len(source) > 1:\n            result += '  %s\\n' % colored.red(source[0])\n            result += '  %s%s\\n' % (' '*(start-1),\n                                    colored.green('^' + '-'*length))\n            if len(source) > 2:  # write the middle lines\n                for line in source[1:-1]:\n                    result += '  %s\\n' % colored.red(\"\".join(line))\n                    result += '  %s\\n' % colored.green(\"-\"*len(line))\n\n            # write the last line\n            result += '  %s\\n' % colored.red(\"\".join(source[-1]))\n            result += '  %s\\n' % colored.green('-'*(end-1) + '^')\n\n        result += colored.yellow(\"%s: %s\\n\\n\" %\n                                 (self.__class__.__name__,\n                                  self.message.encode('utf-8')))\n\n        return result\n\n\nclass HyMacroExpansionError(HyTypeError):\n    pass\n\n\nclass HyIOError(HyError, IOError):\n    \"\"\"\n    Trivial subclass of IOError and HyError, to distinguish between\n    IOErrors raised by Hy itself as opposed to Hy programs.\n    \"\"\"\n    pass\n", "path": "hy/errors.py"}], "after_files": [{"content": "# -*- encoding: utf-8 -*-\n# Copyright 2017 the authors.\n# This file is part of Hy, which is free software licensed under the Expat\n# license. See the LICENSE.\n\nimport traceback\n\nfrom clint.textui import colored\n\n\nclass HyError(Exception):\n    \"\"\"\n    Generic Hy error. All internal Exceptions will be subclassed from this\n    Exception.\n    \"\"\"\n    pass\n\n\nclass HyCompileError(HyError):\n    def __init__(self, exception, traceback=None):\n        self.exception = exception\n        self.traceback = traceback\n\n    def __str__(self):\n        if isinstance(self.exception, HyTypeError):\n            return str(self.exception)\n        if self.traceback:\n            tb = \"\".join(traceback.format_tb(self.traceback)).strip()\n        else:\n            tb = \"No traceback available. \ud83d\ude1f\"\n        return(\"Internal Compiler Bug \ud83d\ude31\\n\u2937 %s: %s\\nCompilation traceback:\\n%s\"\n               % (self.exception.__class__.__name__,\n                  self.exception, tb))\n\n\nclass HyTypeError(TypeError):\n    def __init__(self, expression, message):\n        super(HyTypeError, self).__init__(message)\n        self.expression = expression\n        self.message = message\n        self.source = None\n        self.filename = None\n\n    def __str__(self):\n\n        result = \"\"\n\n        if all(getattr(self.expression, x, None) is not None\n               for x in (\"start_line\", \"start_column\", \"end_column\")):\n\n            line = self.expression.start_line\n            start = self.expression.start_column\n            end = self.expression.end_column\n\n            source = []\n            if self.source is not None:\n                source = self.source.split(\"\\n\")[line-1:self.expression.end_line]\n\n                if line == self.expression.end_line:\n                    length = end - start\n                else:\n                    length = len(source[0]) - start\n\n            result += '  File \"%s\", line %d, column %d\\n\\n' % (self.filename,\n                                                               line,\n                                                               start)\n\n            if len(source) == 1:\n                result += '  %s\\n' % colored.red(source[0])\n                result += '  %s%s\\n' % (' '*(start-1),\n                                        colored.green('^' + '-'*(length-1) + '^'))\n            if len(source) > 1:\n                result += '  %s\\n' % colored.red(source[0])\n                result += '  %s%s\\n' % (' '*(start-1),\n                                        colored.green('^' + '-'*length))\n                if len(source) > 2:  # write the middle lines\n                    for line in source[1:-1]:\n                        result += '  %s\\n' % colored.red(\"\".join(line))\n                        result += '  %s\\n' % colored.green(\"-\"*len(line))\n\n                # write the last line\n                result += '  %s\\n' % colored.red(\"\".join(source[-1]))\n                result += '  %s\\n' % colored.green('-'*(end-1) + '^')\n\n        else:\n            result += '  File \"%s\", unknown location\\n' % self.filename\n\n        result += colored.yellow(\"%s: %s\\n\\n\" %\n                                 (self.__class__.__name__,\n                                  self.message.encode('utf-8')))\n\n        return result\n\n\nclass HyMacroExpansionError(HyTypeError):\n    pass\n\n\nclass HyIOError(HyError, IOError):\n    \"\"\"\n    Trivial subclass of IOError and HyError, to distinguish between\n    IOErrors raised by Hy itself as opposed to Hy programs.\n    \"\"\"\n    pass\n", "path": "hy/errors.py"}]}