We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Hy Repl's behaviour on multiline strings
Hy Repl throws a `LexException` when attempting to write a multiline docstring. 

```
 => (defn a []
...   "This is a dummy fn that really does
LexException: Could not identify the next token at line -1, column -1
```


--- 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/lex/parser.py`
Content:
```
1 # Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the "Software"),
5 # to deal in the Software without restriction, including without limitation
6 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 # and/or sell copies of the Software, and to permit persons to whom the
8 # Software is furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 # DEALINGS IN THE SOFTWARE.
20 
21 import sys
22 from functools import wraps
23 
24 from rply import ParserGenerator
25 
26 from hy.models.complex import HyComplex
27 from hy.models.cons import HyCons
28 from hy.models.dict import HyDict
29 from hy.models.expression import HyExpression
30 from hy.models.float import HyFloat
31 from hy.models.integer import HyInteger
32 from hy.models.keyword import HyKeyword
33 from hy.models.list import HyList
34 from hy.models.string import HyString
35 from hy.models.symbol import HySymbol
36 
37 from .lexer import lexer
38 from .exceptions import LexException, PrematureEndOfInput
39 
40 
41 pg = ParserGenerator(
42     [rule.name for rule in lexer.rules] + ['$end'],
43     cache_id="hy_parser"
44 )
45 
46 
47 def set_boundaries(fun):
48     @wraps(fun)
49     def wrapped(p):
50         start = p[0].source_pos
51         end = p[-1].source_pos
52         ret = fun(p)
53         ret.start_line = start.lineno
54         ret.start_column = start.colno
55         if start is not end:
56             ret.end_line = end.lineno
57             ret.end_column = end.colno
58         else:
59             ret.end_line = start.lineno
60             ret.end_column = start.colno + len(p[0].value)
61         return ret
62     return wrapped
63 
64 
65 def set_quote_boundaries(fun):
66     @wraps(fun)
67     def wrapped(p):
68         start = p[0].source_pos
69         ret = fun(p)
70         ret.start_line = start.lineno
71         ret.start_column = start.colno
72         ret.end_line = p[-1].end_line
73         ret.end_column = p[-1].end_column
74         return ret
75     return wrapped
76 
77 
78 @pg.production("main : HASHBANG real_main")
79 def main_hashbang(p):
80     return p[1]
81 
82 
83 @pg.production("main : real_main")
84 def main(p):
85     return p[0]
86 
87 
88 @pg.production("real_main : list_contents")
89 def real_main(p):
90     return p[0]
91 
92 
93 @pg.production("real_main : $end")
94 def real_main_empty(p):
95     return []
96 
97 
98 def reject_spurious_dots(*items):
99     "Reject the spurious dots from items"
100     for list in items:
101         for tok in list:
102             if tok == "." and type(tok) == HySymbol:
103                 raise LexException("Malformed dotted list",
104                                    tok.start_line, tok.start_column)
105 
106 
107 @pg.production("paren : LPAREN list_contents RPAREN")
108 @set_boundaries
109 def paren(p):
110     cont = p[1]
111 
112     # Dotted lists are expressions of the form
113     # (a b c . d)
114     # that evaluate to nested cons cells of the form
115     # (a . (b . (c . d)))
116     if len(cont) >= 3 and isinstance(cont[-2], HySymbol) and cont[-2] == ".":
117 
118         reject_spurious_dots(cont[:-2], cont[-1:])
119 
120         if len(cont) == 3:
121             # Two-item dotted list: return the cons cell directly
122             return HyCons(cont[0], cont[2])
123         else:
124             # Return a nested cons cell
125             return HyCons(cont[0], paren([p[0], cont[1:], p[2]]))
126 
127     # Warn preemptively on a malformed dotted list.
128     # Only check for dots after the first item to allow for a potential
129     # attribute accessor shorthand
130     reject_spurious_dots(cont[1:])
131 
132     return HyExpression(p[1])
133 
134 
135 @pg.production("paren : LPAREN RPAREN")
136 @set_boundaries
137 def empty_paren(p):
138     return HyExpression([])
139 
140 
141 @pg.production("list_contents : term list_contents")
142 def list_contents(p):
143     return [p[0]] + p[1]
144 
145 
146 @pg.production("list_contents : term")
147 def list_contents_single(p):
148     return [p[0]]
149 
150 
151 @pg.production("term : identifier")
152 @pg.production("term : paren")
153 @pg.production("term : dict")
154 @pg.production("term : list")
155 @pg.production("term : string")
156 def term(p):
157     return p[0]
158 
159 
160 @pg.production("term : QUOTE term")
161 @set_quote_boundaries
162 def term_quote(p):
163     return HyExpression([HySymbol("quote"), p[1]])
164 
165 
166 @pg.production("term : QUASIQUOTE term")
167 @set_quote_boundaries
168 def term_quasiquote(p):
169     return HyExpression([HySymbol("quasiquote"), p[1]])
170 
171 
172 @pg.production("term : UNQUOTE term")
173 @set_quote_boundaries
174 def term_unquote(p):
175     return HyExpression([HySymbol("unquote"), p[1]])
176 
177 
178 @pg.production("term : UNQUOTESPLICE term")
179 @set_quote_boundaries
180 def term_unquote_splice(p):
181     return HyExpression([HySymbol("unquote_splice"), p[1]])
182 
183 
184 @pg.production("term : HASHREADER term")
185 @set_quote_boundaries
186 def hash_reader(p):
187     st = p[0].getstr()[1]
188     str_object = HyString(st)
189     expr = p[1]
190     return HyExpression([HySymbol("dispatch_reader_macro"), str_object, expr])
191 
192 
193 @pg.production("dict : LCURLY list_contents RCURLY")
194 @set_boundaries
195 def t_dict(p):
196     return HyDict(p[1])
197 
198 
199 @pg.production("dict : LCURLY RCURLY")
200 @set_boundaries
201 def empty_dict(p):
202     return HyDict([])
203 
204 
205 @pg.production("list : LBRACKET list_contents RBRACKET")
206 @set_boundaries
207 def t_list(p):
208     return HyList(p[1])
209 
210 
211 @pg.production("list : LBRACKET RBRACKET")
212 @set_boundaries
213 def t_empty_list(p):
214     return HyList([])
215 
216 
217 if sys.version_info[0] >= 3:
218     def uni_hystring(s):
219         return HyString(eval(s))
220 else:
221     def uni_hystring(s):
222         return HyString(eval('u'+s))
223 
224 
225 @pg.production("string : STRING")
226 @set_boundaries
227 def t_string(p):
228     # remove trailing quote
229     s = p[0].value[:-1]
230     # get the header
231     header, s = s.split('"', 1)
232     # remove unicode marker
233     header = header.replace("u", "")
234     # build python string
235     s = header + '"""' + s + '"""'
236     return uni_hystring(s)
237 
238 
239 @pg.production("identifier : IDENTIFIER")
240 @set_boundaries
241 def t_identifier(p):
242     obj = p[0].value
243 
244     try:
245         return HyInteger(obj)
246     except ValueError:
247         pass
248 
249     try:
250         return HyFloat(obj)
251     except ValueError:
252         pass
253 
254     if obj != 'j':
255         try:
256             return HyComplex(obj)
257         except ValueError:
258             pass
259 
260     table = {
261         "true": "True",
262         "false": "False",
263         "nil": "None",
264         "null": "None",
265     }
266 
267     if obj in table:
268         return HySymbol(table[obj])
269 
270     if obj.startswith(":"):
271         return HyKeyword(obj)
272 
273     def mangle(p):
274         if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
275             p = p[1:-1].upper()
276 
277         if "-" in p and p != "-":
278             p = p.replace("-", "_")
279 
280         if p.endswith("?") and p != "?":
281             p = "is_%s" % (p[:-1])
282 
283         return p
284 
285     obj = ".".join([mangle(part) for part in obj.split(".")])
286 
287     return HySymbol(obj)
288 
289 
290 @pg.error
291 def error_handler(token):
292     tokentype = token.gettokentype()
293     if tokentype == '$end':
294         raise PrematureEndOfInput("Premature end of input")
295     else:
296         raise LexException(
297             "Ran into a %s where it wasn't expected." % tokentype,
298             token.source_pos.lineno, token.source_pos.colno)
299 
300 
301 parser = pg.build()
302
```

Path: `hy/lex/lexer.py`
Content:
```
1 # Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a
4 # copy of this software and associated documentation files (the "Software"),
5 # to deal in the Software without restriction, including without limitation
6 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 # and/or sell copies of the Software, and to permit persons to whom the
8 # Software is furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 # DEALINGS IN THE SOFTWARE.
20 
21 from rply import LexerGenerator
22 
23 
24 lg = LexerGenerator()
25 
26 
27 # A regexp for something that should end a quoting/unquoting operator
28 # i.e. a space or a closing brace/paren/curly
29 end_quote = r'(?![\s\)\]\}])'
30 
31 
32 lg.add('LPAREN', r'\(')
33 lg.add('RPAREN', r'\)')
34 lg.add('LBRACKET', r'\[')
35 lg.add('RBRACKET', r'\]')
36 lg.add('LCURLY', r'\{')
37 lg.add('RCURLY', r'\}')
38 lg.add('QUOTE', r'\'%s' % end_quote)
39 lg.add('QUASIQUOTE', r'`%s' % end_quote)
40 lg.add('UNQUOTESPLICE', r'~@%s' % end_quote)
41 lg.add('UNQUOTE', r'~%s' % end_quote)
42 lg.add('HASHBANG', r'#!.*[^\r\n]')
43 lg.add('HASHREADER', r'#.')
44 
45 
46 lg.add('STRING', r'''(?x)
47     (?:u|r|ur|ru)? # prefix
48     "  # start string
49     (?:
50        | [^"\\]             # non-quote or backslash
51        | \\.                # or escaped single character
52        | \\x[0-9a-fA-F]{2}  # or escaped raw character
53        | \\u[0-9a-fA-F]{4}  # or unicode escape
54        | \\U[0-9a-fA-F]{8}  # or long unicode escape
55     )* # one or more times
56     "  # end string
57 ''')
58 
59 
60 lg.add('IDENTIFIER', r'[^()\[\]{}\'"\s;]+')
61 
62 
63 lg.ignore(r';.*(?=\r|\n|$)')
64 lg.ignore(r'\s+')
65 
66 
67 lexer = lg.build()
68
```
--- 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()

```

diff --git a/hy/lex/lexer.py b/hy/lex/lexer.py
--- a/hy/lex/lexer.py
+++ b/hy/lex/lexer.py
@@ -42,8 +42,9 @@
 lg.add('HASHBANG', r'#!.*[^\r\n]')
 lg.add('HASHREADER', r'#.')
 
-
-lg.add('STRING', r'''(?x)
+# A regexp which matches incomplete strings, used to support
+# multi-line strings in the interpreter
+partial_string = r'''(?x)
     (?:u|r|ur|ru)? # prefix
     "  # start string
     (?:
@@ -53,9 +54,10 @@
        | \\u[0-9a-fA-F]{4}  # or unicode escape
        | \\U[0-9a-fA-F]{8}  # or long unicode escape
     )* # one or more times
-    "  # end string
-''')
+'''
 
+lg.add('STRING', r'%s"' % partial_string)
+lg.add('PARTIAL_STRING', partial_string)
 
 lg.add('IDENTIFIER', r'[^()\[\]{}\'"\s;]+')
 
diff --git a/hy/lex/parser.py b/hy/lex/parser.py
--- a/hy/lex/parser.py
+++ b/hy/lex/parser.py
@@ -236,6 +236,12 @@
     return uni_hystring(s)
 
 
+@pg.production("string : PARTIAL_STRING")
+def t_partial_string(p):
+    # Any unterminated string requires more input
+    raise PrematureEndOfInput("Premature end of input")
+
+
 @pg.production("identifier : IDENTIFIER")
 @set_boundaries
 def t_identifier(p):

{"golden_diff": "diff --git a/hy/lex/lexer.py b/hy/lex/lexer.py\n--- a/hy/lex/lexer.py\n+++ b/hy/lex/lexer.py\n@@ -42,8 +42,9 @@\n lg.add('HASHBANG', r'#!.*[^\\r\\n]')\n lg.add('HASHREADER', r'#.')\n \n-\n-lg.add('STRING', r'''(?x)\n+# A regexp which matches incomplete strings, used to support\n+# multi-line strings in the interpreter\n+partial_string = r'''(?x)\n     (?:u|r|ur|ru)? # prefix\n     \"  # start string\n     (?:\n@@ -53,9 +54,10 @@\n        | \\\\u[0-9a-fA-F]{4}  # or unicode escape\n        | \\\\U[0-9a-fA-F]{8}  # or long unicode escape\n     )* # one or more times\n-    \"  # end string\n-''')\n+'''\n \n+lg.add('STRING', r'%s\"' % partial_string)\n+lg.add('PARTIAL_STRING', partial_string)\n \n lg.add('IDENTIFIER', r'[^()\\[\\]{}\\'\"\\s;]+')\n \ndiff --git a/hy/lex/parser.py b/hy/lex/parser.py\n--- a/hy/lex/parser.py\n+++ b/hy/lex/parser.py\n@@ -236,6 +236,12 @@\n     return uni_hystring(s)\n \n \n+@pg.production(\"string : PARTIAL_STRING\")\n+def t_partial_string(p):\n+    # Any unterminated string requires more input\n+    raise PrematureEndOfInput(\"Premature end of input\")\n+\n+\n @pg.production(\"identifier : IDENTIFIER\")\n @set_boundaries\n def t_identifier(p):\n", "issue": "Hy Repl's behaviour on multiline strings\nHy Repl throws a `LexException` when attempting to write a multiline docstring. \n\n```\n => (defn a []\n...   \"This is a dummy fn that really does\nLexException: Could not identify the next token at line -1, column -1\n```\n\n", "before_files": [{"content": "# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a\n# copy of this software and associated documentation files (the \"Software\"),\n# to deal in the Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n# and/or sell copies of the Software, and to permit persons to whom the\n# Software is furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n# DEALINGS IN THE SOFTWARE.\n\nimport sys\nfrom functools import wraps\n\nfrom rply import ParserGenerator\n\nfrom hy.models.complex import HyComplex\nfrom hy.models.cons import HyCons\nfrom hy.models.dict import HyDict\nfrom hy.models.expression import HyExpression\nfrom hy.models.float import HyFloat\nfrom hy.models.integer import HyInteger\nfrom hy.models.keyword import HyKeyword\nfrom hy.models.list import HyList\nfrom hy.models.string import HyString\nfrom hy.models.symbol import HySymbol\n\nfrom .lexer import lexer\nfrom .exceptions import LexException, PrematureEndOfInput\n\n\npg = ParserGenerator(\n    [rule.name for rule in lexer.rules] + ['$end'],\n    cache_id=\"hy_parser\"\n)\n\n\ndef set_boundaries(fun):\n    @wraps(fun)\n    def wrapped(p):\n        start = p[0].source_pos\n        end = p[-1].source_pos\n        ret = fun(p)\n        ret.start_line = start.lineno\n        ret.start_column = start.colno\n        if start is not end:\n            ret.end_line = end.lineno\n            ret.end_column = end.colno\n        else:\n            ret.end_line = start.lineno\n            ret.end_column = start.colno + len(p[0].value)\n        return ret\n    return wrapped\n\n\ndef set_quote_boundaries(fun):\n    @wraps(fun)\n    def wrapped(p):\n        start = p[0].source_pos\n        ret = fun(p)\n        ret.start_line = start.lineno\n        ret.start_column = start.colno\n        ret.end_line = p[-1].end_line\n        ret.end_column = p[-1].end_column\n        return ret\n    return wrapped\n\n\n@pg.production(\"main : HASHBANG real_main\")\ndef main_hashbang(p):\n    return p[1]\n\n\n@pg.production(\"main : real_main\")\ndef main(p):\n    return p[0]\n\n\n@pg.production(\"real_main : list_contents\")\ndef real_main(p):\n    return p[0]\n\n\n@pg.production(\"real_main : $end\")\ndef real_main_empty(p):\n    return []\n\n\ndef reject_spurious_dots(*items):\n    \"Reject the spurious dots from items\"\n    for list in items:\n        for tok in list:\n            if tok == \".\" and type(tok) == HySymbol:\n                raise LexException(\"Malformed dotted list\",\n                                   tok.start_line, tok.start_column)\n\n\n@pg.production(\"paren : LPAREN list_contents RPAREN\")\n@set_boundaries\ndef paren(p):\n    cont = p[1]\n\n    # Dotted lists are expressions of the form\n    # (a b c . d)\n    # that evaluate to nested cons cells of the form\n    # (a . (b . (c . d)))\n    if len(cont) >= 3 and isinstance(cont[-2], HySymbol) and cont[-2] == \".\":\n\n        reject_spurious_dots(cont[:-2], cont[-1:])\n\n        if len(cont) == 3:\n            # Two-item dotted list: return the cons cell directly\n            return HyCons(cont[0], cont[2])\n        else:\n            # Return a nested cons cell\n            return HyCons(cont[0], paren([p[0], cont[1:], p[2]]))\n\n    # Warn preemptively on a malformed dotted list.\n    # Only check for dots after the first item to allow for a potential\n    # attribute accessor shorthand\n    reject_spurious_dots(cont[1:])\n\n    return HyExpression(p[1])\n\n\n@pg.production(\"paren : LPAREN RPAREN\")\n@set_boundaries\ndef empty_paren(p):\n    return HyExpression([])\n\n\n@pg.production(\"list_contents : term list_contents\")\ndef list_contents(p):\n    return [p[0]] + p[1]\n\n\n@pg.production(\"list_contents : term\")\ndef list_contents_single(p):\n    return [p[0]]\n\n\n@pg.production(\"term : identifier\")\n@pg.production(\"term : paren\")\n@pg.production(\"term : dict\")\n@pg.production(\"term : list\")\n@pg.production(\"term : string\")\ndef term(p):\n    return p[0]\n\n\n@pg.production(\"term : QUOTE term\")\n@set_quote_boundaries\ndef term_quote(p):\n    return HyExpression([HySymbol(\"quote\"), p[1]])\n\n\n@pg.production(\"term : QUASIQUOTE term\")\n@set_quote_boundaries\ndef term_quasiquote(p):\n    return HyExpression([HySymbol(\"quasiquote\"), p[1]])\n\n\n@pg.production(\"term : UNQUOTE term\")\n@set_quote_boundaries\ndef term_unquote(p):\n    return HyExpression([HySymbol(\"unquote\"), p[1]])\n\n\n@pg.production(\"term : UNQUOTESPLICE term\")\n@set_quote_boundaries\ndef term_unquote_splice(p):\n    return HyExpression([HySymbol(\"unquote_splice\"), p[1]])\n\n\n@pg.production(\"term : HASHREADER term\")\n@set_quote_boundaries\ndef hash_reader(p):\n    st = p[0].getstr()[1]\n    str_object = HyString(st)\n    expr = p[1]\n    return HyExpression([HySymbol(\"dispatch_reader_macro\"), str_object, expr])\n\n\n@pg.production(\"dict : LCURLY list_contents RCURLY\")\n@set_boundaries\ndef t_dict(p):\n    return HyDict(p[1])\n\n\n@pg.production(\"dict : LCURLY RCURLY\")\n@set_boundaries\ndef empty_dict(p):\n    return HyDict([])\n\n\n@pg.production(\"list : LBRACKET list_contents RBRACKET\")\n@set_boundaries\ndef t_list(p):\n    return HyList(p[1])\n\n\n@pg.production(\"list : LBRACKET RBRACKET\")\n@set_boundaries\ndef t_empty_list(p):\n    return HyList([])\n\n\nif sys.version_info[0] >= 3:\n    def uni_hystring(s):\n        return HyString(eval(s))\nelse:\n    def uni_hystring(s):\n        return HyString(eval('u'+s))\n\n\n@pg.production(\"string : STRING\")\n@set_boundaries\ndef t_string(p):\n    # remove trailing quote\n    s = p[0].value[:-1]\n    # get the header\n    header, s = s.split('\"', 1)\n    # remove unicode marker\n    header = header.replace(\"u\", \"\")\n    # build python string\n    s = header + '\"\"\"' + s + '\"\"\"'\n    return uni_hystring(s)\n\n\n@pg.production(\"identifier : IDENTIFIER\")\n@set_boundaries\ndef t_identifier(p):\n    obj = p[0].value\n\n    try:\n        return HyInteger(obj)\n    except ValueError:\n        pass\n\n    try:\n        return HyFloat(obj)\n    except ValueError:\n        pass\n\n    if obj != 'j':\n        try:\n            return HyComplex(obj)\n        except ValueError:\n            pass\n\n    table = {\n        \"true\": \"True\",\n        \"false\": \"False\",\n        \"nil\": \"None\",\n        \"null\": \"None\",\n    }\n\n    if obj in table:\n        return HySymbol(table[obj])\n\n    if obj.startswith(\":\"):\n        return HyKeyword(obj)\n\n    def mangle(p):\n        if p.startswith(\"*\") and p.endswith(\"*\") and p not in (\"*\", \"**\"):\n            p = p[1:-1].upper()\n\n        if \"-\" in p and p != \"-\":\n            p = p.replace(\"-\", \"_\")\n\n        if p.endswith(\"?\") and p != \"?\":\n            p = \"is_%s\" % (p[:-1])\n\n        return p\n\n    obj = \".\".join([mangle(part) for part in obj.split(\".\")])\n\n    return HySymbol(obj)\n\n\n@pg.error\ndef error_handler(token):\n    tokentype = token.gettokentype()\n    if tokentype == '$end':\n        raise PrematureEndOfInput(\"Premature end of input\")\n    else:\n        raise LexException(\n            \"Ran into a %s where it wasn't expected.\" % tokentype,\n            token.source_pos.lineno, token.source_pos.colno)\n\n\nparser = pg.build()\n", "path": "hy/lex/parser.py"}, {"content": "# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a\n# copy of this software and associated documentation files (the \"Software\"),\n# to deal in the Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n# and/or sell copies of the Software, and to permit persons to whom the\n# Software is furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n# DEALINGS IN THE SOFTWARE.\n\nfrom rply import LexerGenerator\n\n\nlg = LexerGenerator()\n\n\n# A regexp for something that should end a quoting/unquoting operator\n# i.e. a space or a closing brace/paren/curly\nend_quote = r'(?![\\s\\)\\]\\}])'\n\n\nlg.add('LPAREN', r'\\(')\nlg.add('RPAREN', r'\\)')\nlg.add('LBRACKET', r'\\[')\nlg.add('RBRACKET', r'\\]')\nlg.add('LCURLY', r'\\{')\nlg.add('RCURLY', r'\\}')\nlg.add('QUOTE', r'\\'%s' % end_quote)\nlg.add('QUASIQUOTE', r'`%s' % end_quote)\nlg.add('UNQUOTESPLICE', r'~@%s' % end_quote)\nlg.add('UNQUOTE', r'~%s' % end_quote)\nlg.add('HASHBANG', r'#!.*[^\\r\\n]')\nlg.add('HASHREADER', r'#.')\n\n\nlg.add('STRING', r'''(?x)\n    (?:u|r|ur|ru)? # prefix\n    \"  # start string\n    (?:\n       | [^\"\\\\]             # non-quote or backslash\n       | \\\\.                # or escaped single character\n       | \\\\x[0-9a-fA-F]{2}  # or escaped raw character\n       | \\\\u[0-9a-fA-F]{4}  # or unicode escape\n       | \\\\U[0-9a-fA-F]{8}  # or long unicode escape\n    )* # one or more times\n    \"  # end string\n''')\n\n\nlg.add('IDENTIFIER', r'[^()\\[\\]{}\\'\"\\s;]+')\n\n\nlg.ignore(r';.*(?=\\r|\\n|$)')\nlg.ignore(r'\\s+')\n\n\nlexer = lg.build()\n", "path": "hy/lex/lexer.py"}], "after_files": [{"content": "# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a\n# copy of this software and associated documentation files (the \"Software\"),\n# to deal in the Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n# and/or sell copies of the Software, and to permit persons to whom the\n# Software is furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n# DEALINGS IN THE SOFTWARE.\n\nimport sys\nfrom functools import wraps\n\nfrom rply import ParserGenerator\n\nfrom hy.models.complex import HyComplex\nfrom hy.models.cons import HyCons\nfrom hy.models.dict import HyDict\nfrom hy.models.expression import HyExpression\nfrom hy.models.float import HyFloat\nfrom hy.models.integer import HyInteger\nfrom hy.models.keyword import HyKeyword\nfrom hy.models.list import HyList\nfrom hy.models.string import HyString\nfrom hy.models.symbol import HySymbol\n\nfrom .lexer import lexer\nfrom .exceptions import LexException, PrematureEndOfInput\n\n\npg = ParserGenerator(\n    [rule.name for rule in lexer.rules] + ['$end'],\n    cache_id=\"hy_parser\"\n)\n\n\ndef set_boundaries(fun):\n    @wraps(fun)\n    def wrapped(p):\n        start = p[0].source_pos\n        end = p[-1].source_pos\n        ret = fun(p)\n        ret.start_line = start.lineno\n        ret.start_column = start.colno\n        if start is not end:\n            ret.end_line = end.lineno\n            ret.end_column = end.colno\n        else:\n            ret.end_line = start.lineno\n            ret.end_column = start.colno + len(p[0].value)\n        return ret\n    return wrapped\n\n\ndef set_quote_boundaries(fun):\n    @wraps(fun)\n    def wrapped(p):\n        start = p[0].source_pos\n        ret = fun(p)\n        ret.start_line = start.lineno\n        ret.start_column = start.colno\n        ret.end_line = p[-1].end_line\n        ret.end_column = p[-1].end_column\n        return ret\n    return wrapped\n\n\n@pg.production(\"main : HASHBANG real_main\")\ndef main_hashbang(p):\n    return p[1]\n\n\n@pg.production(\"main : real_main\")\ndef main(p):\n    return p[0]\n\n\n@pg.production(\"real_main : list_contents\")\ndef real_main(p):\n    return p[0]\n\n\n@pg.production(\"real_main : $end\")\ndef real_main_empty(p):\n    return []\n\n\ndef reject_spurious_dots(*items):\n    \"Reject the spurious dots from items\"\n    for list in items:\n        for tok in list:\n            if tok == \".\" and type(tok) == HySymbol:\n                raise LexException(\"Malformed dotted list\",\n                                   tok.start_line, tok.start_column)\n\n\n@pg.production(\"paren : LPAREN list_contents RPAREN\")\n@set_boundaries\ndef paren(p):\n    cont = p[1]\n\n    # Dotted lists are expressions of the form\n    # (a b c . d)\n    # that evaluate to nested cons cells of the form\n    # (a . (b . (c . d)))\n    if len(cont) >= 3 and isinstance(cont[-2], HySymbol) and cont[-2] == \".\":\n\n        reject_spurious_dots(cont[:-2], cont[-1:])\n\n        if len(cont) == 3:\n            # Two-item dotted list: return the cons cell directly\n            return HyCons(cont[0], cont[2])\n        else:\n            # Return a nested cons cell\n            return HyCons(cont[0], paren([p[0], cont[1:], p[2]]))\n\n    # Warn preemptively on a malformed dotted list.\n    # Only check for dots after the first item to allow for a potential\n    # attribute accessor shorthand\n    reject_spurious_dots(cont[1:])\n\n    return HyExpression(p[1])\n\n\n@pg.production(\"paren : LPAREN RPAREN\")\n@set_boundaries\ndef empty_paren(p):\n    return HyExpression([])\n\n\n@pg.production(\"list_contents : term list_contents\")\ndef list_contents(p):\n    return [p[0]] + p[1]\n\n\n@pg.production(\"list_contents : term\")\ndef list_contents_single(p):\n    return [p[0]]\n\n\n@pg.production(\"term : identifier\")\n@pg.production(\"term : paren\")\n@pg.production(\"term : dict\")\n@pg.production(\"term : list\")\n@pg.production(\"term : string\")\ndef term(p):\n    return p[0]\n\n\n@pg.production(\"term : QUOTE term\")\n@set_quote_boundaries\ndef term_quote(p):\n    return HyExpression([HySymbol(\"quote\"), p[1]])\n\n\n@pg.production(\"term : QUASIQUOTE term\")\n@set_quote_boundaries\ndef term_quasiquote(p):\n    return HyExpression([HySymbol(\"quasiquote\"), p[1]])\n\n\n@pg.production(\"term : UNQUOTE term\")\n@set_quote_boundaries\ndef term_unquote(p):\n    return HyExpression([HySymbol(\"unquote\"), p[1]])\n\n\n@pg.production(\"term : UNQUOTESPLICE term\")\n@set_quote_boundaries\ndef term_unquote_splice(p):\n    return HyExpression([HySymbol(\"unquote_splice\"), p[1]])\n\n\n@pg.production(\"term : HASHREADER term\")\n@set_quote_boundaries\ndef hash_reader(p):\n    st = p[0].getstr()[1]\n    str_object = HyString(st)\n    expr = p[1]\n    return HyExpression([HySymbol(\"dispatch_reader_macro\"), str_object, expr])\n\n\n@pg.production(\"dict : LCURLY list_contents RCURLY\")\n@set_boundaries\ndef t_dict(p):\n    return HyDict(p[1])\n\n\n@pg.production(\"dict : LCURLY RCURLY\")\n@set_boundaries\ndef empty_dict(p):\n    return HyDict([])\n\n\n@pg.production(\"list : LBRACKET list_contents RBRACKET\")\n@set_boundaries\ndef t_list(p):\n    return HyList(p[1])\n\n\n@pg.production(\"list : LBRACKET RBRACKET\")\n@set_boundaries\ndef t_empty_list(p):\n    return HyList([])\n\n\nif sys.version_info[0] >= 3:\n    def uni_hystring(s):\n        return HyString(eval(s))\nelse:\n    def uni_hystring(s):\n        return HyString(eval('u'+s))\n\n\n@pg.production(\"string : STRING\")\n@set_boundaries\ndef t_string(p):\n    # remove trailing quote\n    s = p[0].value[:-1]\n    # get the header\n    header, s = s.split('\"', 1)\n    # remove unicode marker\n    header = header.replace(\"u\", \"\")\n    # build python string\n    s = header + '\"\"\"' + s + '\"\"\"'\n    return uni_hystring(s)\n\n\n@pg.production(\"string : PARTIAL_STRING\")\ndef t_partial_string(p):\n    # Any unterminated string requires more input\n    raise PrematureEndOfInput(\"Premature end of input\")\n\n\n@pg.production(\"identifier : IDENTIFIER\")\n@set_boundaries\ndef t_identifier(p):\n    obj = p[0].value\n\n    try:\n        return HyInteger(obj)\n    except ValueError:\n        pass\n\n    try:\n        return HyFloat(obj)\n    except ValueError:\n        pass\n\n    if obj != 'j':\n        try:\n            return HyComplex(obj)\n        except ValueError:\n            pass\n\n    table = {\n        \"true\": \"True\",\n        \"false\": \"False\",\n        \"nil\": \"None\",\n        \"null\": \"None\",\n    }\n\n    if obj in table:\n        return HySymbol(table[obj])\n\n    if obj.startswith(\":\"):\n        return HyKeyword(obj)\n\n    def mangle(p):\n        if p.startswith(\"*\") and p.endswith(\"*\") and p not in (\"*\", \"**\"):\n            p = p[1:-1].upper()\n\n        if \"-\" in p and p != \"-\":\n            p = p.replace(\"-\", \"_\")\n\n        if p.endswith(\"?\") and p != \"?\":\n            p = \"is_%s\" % (p[:-1])\n\n        return p\n\n    obj = \".\".join([mangle(part) for part in obj.split(\".\")])\n\n    return HySymbol(obj)\n\n\n@pg.error\ndef error_handler(token):\n    tokentype = token.gettokentype()\n    if tokentype == '$end':\n        raise PrematureEndOfInput(\"Premature end of input\")\n    else:\n        raise LexException(\n            \"Ran into a %s where it wasn't expected.\" % tokentype,\n            token.source_pos.lineno, token.source_pos.colno)\n\n\nparser = pg.build()\n", "path": "hy/lex/parser.py"}, {"content": "# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>\n#\n# Permission is hereby granted, free of charge, to any person obtaining a\n# copy of this software and associated documentation files (the \"Software\"),\n# to deal in the Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n# and/or sell copies of the Software, and to permit persons to whom the\n# Software is furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n# DEALINGS IN THE SOFTWARE.\n\nfrom rply import LexerGenerator\n\n\nlg = LexerGenerator()\n\n\n# A regexp for something that should end a quoting/unquoting operator\n# i.e. a space or a closing brace/paren/curly\nend_quote = r'(?![\\s\\)\\]\\}])'\n\n\nlg.add('LPAREN', r'\\(')\nlg.add('RPAREN', r'\\)')\nlg.add('LBRACKET', r'\\[')\nlg.add('RBRACKET', r'\\]')\nlg.add('LCURLY', r'\\{')\nlg.add('RCURLY', r'\\}')\nlg.add('QUOTE', r'\\'%s' % end_quote)\nlg.add('QUASIQUOTE', r'`%s' % end_quote)\nlg.add('UNQUOTESPLICE', r'~@%s' % end_quote)\nlg.add('UNQUOTE', r'~%s' % end_quote)\nlg.add('HASHBANG', r'#!.*[^\\r\\n]')\nlg.add('HASHREADER', r'#.')\n\n# A regexp which matches incomplete strings, used to support\n# multi-line strings in the interpreter\npartial_string = r'''(?x)\n    (?:u|r|ur|ru)? # prefix\n    \"  # start string\n    (?:\n       | [^\"\\\\]             # non-quote or backslash\n       | \\\\.                # or escaped single character\n       | \\\\x[0-9a-fA-F]{2}  # or escaped raw character\n       | \\\\u[0-9a-fA-F]{4}  # or unicode escape\n       | \\\\U[0-9a-fA-F]{8}  # or long unicode escape\n    )* # one or more times\n'''\n\nlg.add('STRING', r'%s\"' % partial_string)\nlg.add('PARTIAL_STRING', partial_string)\n\nlg.add('IDENTIFIER', r'[^()\\[\\]{}\\'\"\\s;]+')\n\n\nlg.ignore(r';.*(?=\\r|\\n|$)')\nlg.ignore(r'\\s+')\n\n\nlexer = lg.build()\n", "path": "hy/lex/lexer.py"}]}