We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Exclamation mark ! is not mangled
I noticed that https://github.com/hylang/hyway/blob/master/conway.hy uses "!" in `set!` and `get!`, but Hy doesn't mangle "!" into something else.  The variable is added to the module as-is.  That means it'll be hard to reach it from normal Python code.  Also, hy2py on Hy code with `set!` returns invalid syntax: `def set!(`.


--- 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.set import HySet
35 from hy.models.string import HyString
36 from hy.models.symbol import HySymbol
37 
38 from .lexer import lexer
39 from .exceptions import LexException, PrematureEndOfInput
40 
41 
42 pg = ParserGenerator(
43     [rule.name for rule in lexer.rules] + ['$end'],
44     cache_id="hy_parser"
45 )
46 
47 
48 def set_boundaries(fun):
49     @wraps(fun)
50     def wrapped(p):
51         start = p[0].source_pos
52         end = p[-1].source_pos
53         ret = fun(p)
54         ret.start_line = start.lineno
55         ret.start_column = start.colno
56         if start is not end:
57             ret.end_line = end.lineno
58             ret.end_column = end.colno
59         else:
60             ret.end_line = start.lineno
61             ret.end_column = start.colno + len(p[0].value)
62         return ret
63     return wrapped
64 
65 
66 def set_quote_boundaries(fun):
67     @wraps(fun)
68     def wrapped(p):
69         start = p[0].source_pos
70         ret = fun(p)
71         ret.start_line = start.lineno
72         ret.start_column = start.colno
73         ret.end_line = p[-1].end_line
74         ret.end_column = p[-1].end_column
75         return ret
76     return wrapped
77 
78 
79 @pg.production("main : HASHBANG real_main")
80 def main_hashbang(p):
81     return p[1]
82 
83 
84 @pg.production("main : real_main")
85 def main(p):
86     return p[0]
87 
88 
89 @pg.production("real_main : list_contents")
90 def real_main(p):
91     return p[0]
92 
93 
94 @pg.production("real_main : $end")
95 def real_main_empty(p):
96     return []
97 
98 
99 def reject_spurious_dots(*items):
100     "Reject the spurious dots from items"
101     for list in items:
102         for tok in list:
103             if tok == "." and type(tok) == HySymbol:
104                 raise LexException("Malformed dotted list",
105                                    tok.start_line, tok.start_column)
106 
107 
108 @pg.production("paren : LPAREN list_contents RPAREN")
109 @set_boundaries
110 def paren(p):
111     cont = p[1]
112 
113     # Dotted lists are expressions of the form
114     # (a b c . d)
115     # that evaluate to nested cons cells of the form
116     # (a . (b . (c . d)))
117     if len(cont) >= 3 and isinstance(cont[-2], HySymbol) and cont[-2] == ".":
118 
119         reject_spurious_dots(cont[:-2], cont[-1:])
120 
121         if len(cont) == 3:
122             # Two-item dotted list: return the cons cell directly
123             return HyCons(cont[0], cont[2])
124         else:
125             # Return a nested cons cell
126             return HyCons(cont[0], paren([p[0], cont[1:], p[2]]))
127 
128     # Warn preemptively on a malformed dotted list.
129     # Only check for dots after the first item to allow for a potential
130     # attribute accessor shorthand
131     reject_spurious_dots(cont[1:])
132 
133     return HyExpression(p[1])
134 
135 
136 @pg.production("paren : LPAREN RPAREN")
137 @set_boundaries
138 def empty_paren(p):
139     return HyExpression([])
140 
141 
142 @pg.production("list_contents : term list_contents")
143 def list_contents(p):
144     return [p[0]] + p[1]
145 
146 
147 @pg.production("list_contents : term")
148 def list_contents_single(p):
149     return [p[0]]
150 
151 
152 @pg.production("term : identifier")
153 @pg.production("term : paren")
154 @pg.production("term : dict")
155 @pg.production("term : list")
156 @pg.production("term : set")
157 @pg.production("term : string")
158 def term(p):
159     return p[0]
160 
161 
162 @pg.production("term : QUOTE term")
163 @set_quote_boundaries
164 def term_quote(p):
165     return HyExpression([HySymbol("quote"), p[1]])
166 
167 
168 @pg.production("term : QUASIQUOTE term")
169 @set_quote_boundaries
170 def term_quasiquote(p):
171     return HyExpression([HySymbol("quasiquote"), p[1]])
172 
173 
174 @pg.production("term : UNQUOTE term")
175 @set_quote_boundaries
176 def term_unquote(p):
177     return HyExpression([HySymbol("unquote"), p[1]])
178 
179 
180 @pg.production("term : UNQUOTESPLICE term")
181 @set_quote_boundaries
182 def term_unquote_splice(p):
183     return HyExpression([HySymbol("unquote_splice"), p[1]])
184 
185 
186 @pg.production("term : HASHREADER term")
187 @set_quote_boundaries
188 def hash_reader(p):
189     st = p[0].getstr()[1]
190     str_object = HyString(st)
191     expr = p[1]
192     return HyExpression([HySymbol("dispatch_reader_macro"), str_object, expr])
193 
194 
195 @pg.production("set : HLCURLY list_contents RCURLY")
196 @set_boundaries
197 def t_set(p):
198     return HySet(p[1])
199 
200 
201 @pg.production("set : HLCURLY RCURLY")
202 @set_boundaries
203 def empty_set(p):
204     return HySet([])
205 
206 
207 @pg.production("dict : LCURLY list_contents RCURLY")
208 @set_boundaries
209 def t_dict(p):
210     return HyDict(p[1])
211 
212 
213 @pg.production("dict : LCURLY RCURLY")
214 @set_boundaries
215 def empty_dict(p):
216     return HyDict([])
217 
218 
219 @pg.production("list : LBRACKET list_contents RBRACKET")
220 @set_boundaries
221 def t_list(p):
222     return HyList(p[1])
223 
224 
225 @pg.production("list : LBRACKET RBRACKET")
226 @set_boundaries
227 def t_empty_list(p):
228     return HyList([])
229 
230 
231 if sys.version_info[0] >= 3:
232     def uni_hystring(s):
233         return HyString(eval(s))
234 else:
235     def uni_hystring(s):
236         return HyString(eval('u'+s))
237 
238 
239 @pg.production("string : STRING")
240 @set_boundaries
241 def t_string(p):
242     # remove trailing quote
243     s = p[0].value[:-1]
244     # get the header
245     header, s = s.split('"', 1)
246     # remove unicode marker
247     header = header.replace("u", "")
248     # build python string
249     s = header + '"""' + s + '"""'
250     return uni_hystring(s)
251 
252 
253 @pg.production("string : PARTIAL_STRING")
254 def t_partial_string(p):
255     # Any unterminated string requires more input
256     raise PrematureEndOfInput("Premature end of input")
257 
258 
259 @pg.production("identifier : IDENTIFIER")
260 @set_boundaries
261 def t_identifier(p):
262     obj = p[0].value
263 
264     try:
265         return HyInteger(obj)
266     except ValueError:
267         pass
268 
269     if '/' in obj:
270         try:
271             lhs, rhs = obj.split('/')
272             return HyExpression([HySymbol('fraction'), HyInteger(lhs),
273                                  HyInteger(rhs)])
274         except ValueError:
275             pass
276 
277     try:
278         return HyFloat(obj)
279     except ValueError:
280         pass
281 
282     if obj != 'j':
283         try:
284             return HyComplex(obj)
285         except ValueError:
286             pass
287 
288     table = {
289         "true": "True",
290         "false": "False",
291         "nil": "None",
292         "null": "None",
293     }
294 
295     if obj in table:
296         return HySymbol(table[obj])
297 
298     if obj.startswith(":"):
299         return HyKeyword(obj)
300 
301     def mangle(p):
302         if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
303             p = p[1:-1].upper()
304 
305         if "-" in p and p != "-":
306             p = p.replace("-", "_")
307 
308         if p.endswith("?") and p != "?":
309             p = "is_%s" % (p[:-1])
310 
311         return p
312 
313     obj = ".".join([mangle(part) for part in obj.split(".")])
314 
315     return HySymbol(obj)
316 
317 
318 @pg.error
319 def error_handler(token):
320     tokentype = token.gettokentype()
321     if tokentype == '$end':
322         raise PrematureEndOfInput("Premature end of input")
323     else:
324         raise LexException(
325             "Ran into a %s where it wasn't expected." % tokentype,
326             token.source_pos.lineno, token.source_pos.colno)
327 
328 
329 parser = pg.build()
330
```
--- 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/parser.py b/hy/lex/parser.py
--- a/hy/lex/parser.py
+++ b/hy/lex/parser.py
@@ -308,6 +308,9 @@
         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(".")])

{"golden_diff": "diff --git a/hy/lex/parser.py b/hy/lex/parser.py\n--- a/hy/lex/parser.py\n+++ b/hy/lex/parser.py\n@@ -308,6 +308,9 @@\n         if p.endswith(\"?\") and p != \"?\":\n             p = \"is_%s\" % (p[:-1])\n \n+        if p.endswith(\"!\") and p != \"!\":\n+            p = \"%s_bang\" % (p[:-1])\n+\n         return p\n \n     obj = \".\".join([mangle(part) for part in obj.split(\".\")])\n", "issue": "Exclamation mark ! is not mangled\nI noticed that https://github.com/hylang/hyway/blob/master/conway.hy uses \"!\" in `set!` and `get!`, but Hy doesn't mangle \"!\" into something else.  The variable is added to the module as-is.  That means it'll be hard to reach it from normal Python code.  Also, hy2py on Hy code with `set!` returns invalid syntax: `def set!(`.\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.set import HySet\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 : set\")\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(\"set : HLCURLY list_contents RCURLY\")\n@set_boundaries\ndef t_set(p):\n    return HySet(p[1])\n\n\n@pg.production(\"set : HLCURLY RCURLY\")\n@set_boundaries\ndef empty_set(p):\n    return HySet([])\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    if '/' in obj:\n        try:\n            lhs, rhs = obj.split('/')\n            return HyExpression([HySymbol('fraction'), HyInteger(lhs),\n                                 HyInteger(rhs)])\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"}], "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.set import HySet\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 : set\")\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(\"set : HLCURLY list_contents RCURLY\")\n@set_boundaries\ndef t_set(p):\n    return HySet(p[1])\n\n\n@pg.production(\"set : HLCURLY RCURLY\")\n@set_boundaries\ndef empty_set(p):\n    return HySet([])\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    if '/' in obj:\n        try:\n            lhs, rhs = obj.split('/')\n            return HyExpression([HySymbol('fraction'), HyInteger(lhs),\n                                 HyInteger(rhs)])\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        if p.endswith(\"!\") and p != \"!\":\n            p = \"%s_bang\" % (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"}]}