From af64cbe9969a6369b0ec4d4b8cca6f13896358cc Mon Sep 17 00:00:00 2001 From: Kodi Arfer <git@arfer.net> Date: Sun, 30 Jan 2022 15:15:13 -0500 Subject: [PATCH] Get `hy2py` to cope with e.g. `(setv def 1)` The new loop through the AST doesn't seem to cause a perceptible slowdown. On my system, the test suite took 14.33 s with this change and 14.38 s without it. --- hy/_compat.py | 24 +++++++++++++++++++++++- tests/resources/pydemo.hy | 7 +++++-- tests/test_hy2py.py | 4 ++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/hy/_compat.py b/hy/_compat.py index bcac7a966..eac7ad53c 100644 --- a/hy/_compat.py +++ b/hy/_compat.py @@ -1,3 +1,4 @@ +import ast import platform import sys @@ -10,11 +11,32 @@ if not PY3_9: # Shim `ast.unparse`. - import ast import astor.code_gen ast.unparse = astor.code_gen.to_source +if 'def' in ast.unparse(ast.parse('𝕕𝕖𝕗 = 1')): + # Overwrite `ast.unparse` to backport https://github.com/python/cpython/pull/31012 + import copy + import keyword + true_unparse = ast.unparse + def rewriting_unparse(ast_obj): + ast_obj = copy.deepcopy(ast_obj) + for node in ast.walk(ast_obj): + if type(node) in (ast.Constant, ast.Str): + # Don't touch string literals. + continue + for field in node._fields: + v = getattr(node, field, None) + if (type(v) is str and + keyword.iskeyword(v) and + v not in ('True', 'False', 'None')): + setattr(node, field, + chr(ord(v[0]) - ord('a') + ord('𝐚')) + v[1:]) + return true_unparse(ast_obj) + ast.unparse = rewriting_unparse + + if not PY3_8: # Shim `re.Pattern`. import re diff --git a/tests/resources/pydemo.hy b/tests/resources/pydemo.hy index a7a1ea883..d8287fd9c 100644 --- a/tests/resources/pydemo.hy +++ b/tests/resources/pydemo.hy @@ -9,6 +9,8 @@ Call me Ishmael. Some years ago—never mind how long precisely—having little (setv identifier-that-has☝️💯☝️-to-be-mangled "ponies") (setv 𝔫𝔬𝔯𝔪𝔞𝔩𝔦𝔷𝔢-𝔱𝔥𝔦𝔰 "ok") +(setv def "variable") +(setv 𝕚𝕗 "if") (setv mynumber (+ 1 2)) (setv myhex 0x123) @@ -117,11 +119,12 @@ Call me Ishmael. Some years ago—never mind how long precisely—having little (else (setv ran-try-else True))) -(defn fun [a b [c 9] [d 10] #* args #** kwargs] +(defn fun [a b [c 9] [from 10] #* args #** kwargs] "function docstring" - [a b c d args (sorted (.items kwargs))]) + [a b c from args (sorted (.items kwargs))]) (setv funcall1 (fun 1 2 3 4 "a" "b" "c" :k1 "v1" :k2 "v2")) (setv funcall2 (fun 7 8 #* [9 10 11] #** {"x1" "y1" "x2" "y2"})) +(setv funcall3 (fun "x" "y" :from "spain")) (defn returner [] (return 1) diff --git a/tests/test_hy2py.py b/tests/test_hy2py.py index 5bc348aa8..3f198ba22 100644 --- a/tests/test_hy2py.py +++ b/tests/test_hy2py.py @@ -40,6 +40,9 @@ def assert_stuff(m): assert getattr(m, mangle("identifier-that-has☝️💯☝️-to-be-mangled")) == "ponies" assert m.normalize_this == "ok" + assert getattr(m, "def") == "variable" + assert m.𝕕𝕖𝕗 == "variable" + assert getattr(m, "if") == "if" assert m.mynumber == 3 assert m.myhex == 0x123 @@ -114,6 +117,7 @@ def assert_stuff(m): assert m.fun.__doc__ == "function docstring" assert m.funcall1 == [1, 2, 3, 4, ("a", "b", "c"), [("k1", "v1"), ("k2", "v2")]] assert m.funcall2 == [7, 8, 9, 10, (11,), [("x1", "y1"), ("x2", "y2")]] + assert m.funcall3 == ["x", "y", 9, "spain", (), []] assert m.myret == 1 assert m.myyield == ["a", "b", "c"]