├── py2hy └── __init__.py ├── requirements.txt ├── AUTHORS ├── MANIFEST.in ├── .gitignore ├── conftest.py ├── tox.ini ├── Makefile ├── .travis.yml ├── make.bat ├── setup.py ├── demo ├── game.py ├── game.hy ├── makengamesolver.py └── makengamesolver.hy ├── README.md ├── tests ├── test_compiling.hy └── test_ops.hy ├── src └── py2hy │ ├── prettyprinter.hy │ └── py2hy.hy ├── tools ├── parse_pygrammarspecs.py ├── pygrammarspecs.txt └── template.hy └── LICENSE /py2hy/__init__.py: -------------------------------------------------------------------------------- 1 | import hy -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | hy==0.13.0 -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | * Hikaru Ikuta -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include README.md 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | /Notes 3 | .DS_Store 4 | /.cache 5 | /py2hy.egg-info 6 | *pycache* 7 | /.tox 8 | /dist 9 | *.pyc 10 | .coveralls.yml 11 | /py2hy/*.py -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | import _pytest 2 | import hy 3 | 4 | def pytest_collect_file(parent, path): 5 | if path.ext == ".hy" and "tests" in path.dirname: 6 | return _pytest.python.pytest_pycollect_makemodule(path, parent) -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py33,py34,py35,py36 3 | 4 | [testenv] 5 | passenv = 6 | TERM 7 | deps = 8 | coveralls 9 | pytest 10 | -rrequirements.txt 11 | commands = 12 | pip install -e . 13 | pytest 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make template 3 | make compilehy 4 | 5 | template: 6 | python tools/parse_pygrammarspecs.py > tools/template.hy 7 | 8 | compilehy: 9 | for f in src/py2hy/*.hy; do g=`echo $$f | sed -e 's/.hy$$/.py/' | sed -e 's/^src\///'`;\ 10 | hy2py $$f > $$g; done 11 | python -m compileall . 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.3" 4 | - "3.4" 5 | - "3.5" 6 | - "3.6" 7 | sudo: false 8 | install: 9 | - pip install coveralls 10 | - pip install --upgrade pytest 11 | - pip install -r requirements.txt 12 | - pip install -e . 13 | script: 14 | coverage run --source=py2hy setup.py test 15 | cache: pip 16 | after_success: 17 | - coveralls 18 | notifications: 19 | email: 20 | - woodrush924@gmail.com -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | if "%1" == "all" goto :all 4 | if "%1" == "" goto :all 5 | goto :body 6 | 7 | :all 8 | call :template 9 | call :compilehy 10 | goto :EOF 11 | 12 | 13 | :body 14 | 15 | if "%1" == "template" ( 16 | :template 17 | python tools/parse_pygrammarspecs.py > tools/template.hy 18 | goto :EOF 19 | ) 20 | 21 | if "%1" == "compilehy" ( 22 | :template 23 | for %%f in (src/py2hy/*.hy) do ( 24 | hy2py src/py2hy/%%f > py2hy/%%~nf.py 25 | ) 26 | python -m compileall . 27 | goto :EOF 28 | ) 29 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | import subprocess 4 | subprocess.call(['make', 'compilehy']) 5 | 6 | setup( 7 | name="py2hy", 8 | version="0.8.0", 9 | description="Python to Hy compiler", 10 | long_description="""Compiles Python code to Hy.""", 11 | url="https://github.com/woodrush/py2hy", 12 | author="Hikaru Ikuta", 13 | author_email="woodrush924@gmail.com", 14 | license="LGPL-3", 15 | keywords="sample setuptools development", 16 | packages=find_packages(exclude=["tests*"]), 17 | install_requires = ["hy==0.13.0"], 18 | package_data={ 19 | "py2hy": ["*.py", "__pycache__/*"], 20 | }, 21 | classifiers=[ 22 | "Development Status :: 3 - Alpha", 23 | "Intended Audience :: Developers", 24 | "Topic :: Software Development :: Build Tools", 25 | "License :: DFSG approved", 26 | "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", 27 | "Operating System :: OS Independent", 28 | "Programming Language :: Lisp", 29 | "Programming Language :: Python", 30 | "Programming Language :: Python :: 3", 31 | "Programming Language :: Python :: 3.3", 32 | "Programming Language :: Python :: 3.4", 33 | "Programming Language :: Python :: 3.5", 34 | "Programming Language :: Python :: 3.6", 35 | "Topic :: Software Development :: Code Generators", 36 | "Topic :: Software Development :: Compilers", 37 | "Topic :: Software Development :: Libraries" 38 | ], 39 | entry_points={ 40 | "console_scripts": [ 41 | "py2hy=py2hy.py2hy:main", 42 | ], 43 | }, 44 | ) 45 | -------------------------------------------------------------------------------- /demo/game.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def game(): 4 | args = [] 5 | inventory = [] 6 | def setargs(l): 7 | nonlocal args 8 | args = l.rstrip() 9 | def getPromptObj(l): 10 | return ("p",l,setargs) 11 | def getNextObj(): 12 | return ("n",) 13 | 14 | print("You wake up to find yourself laying down inside a dark cave.") 15 | print("What will you do?") 16 | yield getPromptObj((("0","Check your bag"), ("1","Call for help"))) 17 | 18 | if args == "0": 19 | print("You found a lighter inside your bag.") 20 | inventory.append("lighter") 21 | elif args == "1": 22 | print("Your voice echos through the cave...") 23 | yield getNextObj() 24 | 25 | while True: 26 | print("What will you do next?") 27 | yield getPromptObj((("0","Stand up"), ("1", "Continue laying down"))) 28 | if args == "0": 29 | print("You find a way leading outside of the cave.") 30 | break 31 | else: 32 | print("You spend several minutes in the dark, but no help seems to arrive...") 33 | print("To be continued...") 34 | 35 | def gameloop(game): 36 | for o in game: 37 | if not o: 38 | break 39 | if o[0] == "n": 40 | print("Hit enter to continue...") 41 | sys.stdin.readline() 42 | yield "" 43 | elif o[0] == "p": 44 | d = o[1] 45 | for k in d: 46 | print(k[0], k[1]) 47 | print("> ",end='',flush=True) 48 | choice = sys.stdin.readline() 49 | o[2](choice) 50 | yield "" 51 | 52 | def trynext(g): 53 | try: 54 | next(g) 55 | except Exception as e: 56 | pass 57 | 58 | if __name__ == '__main__': 59 | for i in gameloop(game()): 60 | pass -------------------------------------------------------------------------------- /demo/game.hy: -------------------------------------------------------------------------------- 1 | (import [sys]) 2 | (defclass Py2HyReturnException [Exception] 3 | (defn __init__ [self retvalue] 4 | (setv self.retvalue retvalue))) 5 | (defn game [] 6 | (setv args []) 7 | (setv inventory []) 8 | (defn setargs [l] 9 | (nonlocal args) 10 | (setv args (l.rstrip))) 11 | (defn getPromptObj [l] 12 | (, "p" l setargs)) 13 | (defn getNextObj [] 14 | (, "n")) 15 | (print "You wake up to find yourself laying down inside a dark cave.") 16 | (print "What will you do?") 17 | (yield (getPromptObj (, (, "0" "Check your bag") (, "1" "Call for help")))) 18 | (cond 19 | [(= args "0") 20 | (do 21 | (print "You found a lighter inside your bag.") 22 | (inventory.append "lighter"))] 23 | [(= args "1") 24 | (print "Your voice echos through the cave...")] 25 | [True 26 | (do)]) 27 | (yield (getNextObj)) 28 | (while True 29 | (print "What will you do next?") 30 | (yield (getPromptObj (, (, "0" "Stand up") (, "1" "Continue laying down")))) 31 | (if (= args "0") 32 | (do 33 | (print "You find a way leading outside of the cave.") 34 | (break)) 35 | (do 36 | (print "You spend several minutes in the dark, but no help seems to arrive...")))) 37 | (print "To be continued...")) 38 | (defn gameloop [game] 39 | (for [o game] 40 | (when (not o) 41 | (break)) 42 | (cond 43 | [(= (get o 0) "n") 44 | (do 45 | (print "Hit enter to continue...") 46 | (sys.stdin.readline) 47 | (yield))] 48 | [(= (get o 0) "p") 49 | (do 50 | (setv d (get o 1)) 51 | (for [k d] 52 | (print (get k 0) (get k 1))) 53 | (print "> " :end "" :flush True) 54 | (setv choice (sys.stdin.readline)) 55 | ((get o 2) choice) 56 | (yield))] 57 | [True 58 | (do)]))) 59 | (defn trynext [g] 60 | (try 61 | (try 62 | (next g) 63 | (except [e Py2HyReturnException] 64 | (raise e)) 65 | (except [e Exception] 66 | (do))) 67 | (except [e Py2HyReturnException] 68 | e.retvalue))) 69 | (when (= __name__ "__main__") 70 | (for [i (gameloop (game))] 71 | (do))) 72 | -------------------------------------------------------------------------------- /demo/makengamesolver.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | from itertools import combinations 3 | from collections import Counter 4 | from operator import * 5 | import random 6 | 7 | random.seed(0) 8 | numlist = sorted([random.randint(1,100) for i in range(100)]) 9 | targetNum = 10 10 | searchMode = 0 11 | # 0: Randomized search (fast for long number lists, doesn't stop if no solutions exist) 12 | # 1: Ordered search (good for short number lists, stops as soon as one solution is found) 13 | # 2: Exhaustive search 14 | 15 | #====================================================================== 16 | oplist = [sub, add, truediv, mul] if searchMode == 0 else [add, sub, truediv, mul] # Order is important 17 | ophash = {add:"+", sub:"-", mul:"*", truediv:"/"} 18 | commutativeops = [add, mul] 19 | #====================================================================== 20 | def allEquationsFrom(numComb): 21 | if len(numComb) == 1: 22 | yield (str(numComb[0]), numComb[0]) 23 | else: 24 | for op in oplist: 25 | for i in shuffled(range(1,len(numComb))) if (op not in commutativeops) else shuffled(range(1,2+int((len(numComb)-1)/2))): 26 | for leftComb in combinations(Counter(numComb), i): 27 | for leftEq in allEquationsFrom(leftComb): 28 | for rightEq in allEquationsFrom(listSubtraction(numComb,leftComb)): 29 | yield eqValPair(op, leftEq, rightEq) 30 | 31 | def eqValPair(op, leftPair, rightPair): 32 | try: val = op(leftPair[1],rightPair[1]) 33 | except: val = "NaN" 34 | return ("(" + leftPair[0] + ophash[op] + rightPair[0] + ")", val) 35 | 36 | def shuffled(orig): 37 | dest = list(orig) 38 | random.shuffle(dest) 39 | return dest 40 | 41 | def listSubtraction(U,S): 42 | return list((Counter(U) - Counter(S)).elements()) 43 | 44 | #====================================================================== 45 | def randomizedSearch(targetNum, numlist): 46 | while True: 47 | iterCounter = 0 48 | for x in allEquationsFrom(numlist): 49 | iterCounter += 1 50 | if iterCounter >= 100: 51 | break 52 | elif(x[1] == targetNum): 53 | print(str(targetNum) + " = " + x[0]) 54 | return 55 | 56 | def orderedSearch(targetNum, numlist): 57 | solutionCount = 0 58 | for x in allEquationsFrom(numlist): 59 | if(x[1] == targetNum): 60 | print(str(targetNum) + " = " + x[0]) 61 | solutionCount += 1 62 | if searchMode == 1: 63 | return 64 | print(str(solutionCount) + " equations make " + str(targetNum) + " for these numbers (searched exhaustively)") 65 | 66 | #====================================================================== 67 | if __name__ == '__main__': 68 | print(numlist) 69 | print("Calculating...") 70 | (randomizedSearch if searchMode == 0 else orderedSearch)(targetNum, numlist) -------------------------------------------------------------------------------- /demo/makengamesolver.hy: -------------------------------------------------------------------------------- 1 | (import [itertools [combinations]]) 2 | (defclass Py2HyReturnException [Exception] 3 | (defn __init__ [self retvalue] 4 | (setv self.retvalue retvalue))) 5 | (import [collections [Counter]]) 6 | (import [operator [*]]) 7 | (import [random]) 8 | (random.seed 0) 9 | (setv numlist (sorted (list_comp (random.randint 1 100) [i (range 100)]))) 10 | (setv targetNum 10) 11 | (setv searchMode 0) 12 | (setv oplist (if (= searchMode 0) 13 | [sub add truediv mul] 14 | [add sub truediv mul])) 15 | (setv ophash {add "+" sub "-" mul "*" truediv "/"}) 16 | (setv commutativeops [add mul]) 17 | (defn allEquationsFrom [numComb] 18 | (if (= (len numComb) 1) 19 | (do 20 | (yield (, (str (get numComb 0)) (get numComb 0)))) 21 | (do 22 | (for [op oplist] 23 | (for [i (if (not_in op commutativeops) (shuffled (range 1 (len numComb))) (shuffled (range 1 (+ 2 (int (/ (- (len numComb) 1) 2))))))] 24 | (for [leftComb (combinations (Counter numComb) i)] 25 | (for [leftEq (allEquationsFrom leftComb)] 26 | (for [rightEq (allEquationsFrom (listSubtraction numComb leftComb))] 27 | (yield (eqValPair op leftEq rightEq)))))))))) 28 | (defn eqValPair [op leftPair rightPair] 29 | (try 30 | (do 31 | (try 32 | (setv val (op (get leftPair 1) (get rightPair 1))) 33 | (except [e Py2HyReturnException] 34 | (raise e)) 35 | (except [] 36 | (setv val "NaN"))) 37 | (raise (Py2HyReturnException (, (+ (+ (+ (+ "(" (get leftPair 0)) (get ophash op)) (get rightPair 0)) ")") val)))) 38 | (except [e Py2HyReturnException] 39 | e.retvalue))) 40 | (defn shuffled [orig] 41 | (setv dest (list orig)) 42 | (random.shuffle dest) 43 | dest) 44 | (defn listSubtraction [U S] 45 | (list ((. (- (Counter U) (Counter S)) elements)))) 46 | (defn randomizedSearch [targetNum numlist] 47 | (try 48 | (while True 49 | (setv iterCounter 0) 50 | (for [x (allEquationsFrom numlist)] 51 | (+= iterCounter 1) 52 | (cond 53 | [(>= iterCounter 100) 54 | (break)] 55 | [(= (get x 1) targetNum) 56 | (do 57 | (print (+ (+ (str targetNum) " = ") (get x 0))) 58 | (raise (Py2HyReturnException None)))] 59 | [True 60 | (do)]))) 61 | (except [e Py2HyReturnException] 62 | e.retvalue))) 63 | (defn orderedSearch [targetNum numlist] 64 | (try 65 | (do 66 | (setv solutionCount 0) 67 | (for [x (allEquationsFrom numlist)] 68 | (when (= (get x 1) targetNum) 69 | (print (+ (+ (str targetNum) " = ") (get x 0))) 70 | (+= solutionCount 1) 71 | (when (= searchMode 1) 72 | (raise (Py2HyReturnException None))))) 73 | (print (+ (+ (+ (str solutionCount) " equations make ") (str targetNum)) " for these numbers (searched exhaustively)"))) 74 | (except [e Py2HyReturnException] 75 | e.retvalue))) 76 | (when (= __name__ "__main__") 77 | (print numlist) 78 | (print "Calculating...") 79 | ((if (= searchMode 0) 80 | randomizedSearch 81 | orderedSearch) targetNum numlist)) 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # py2hy 2 | 3 | [![Build Status](https://travis-ci.org/woodrush/py2hy.svg?branch=master)](https://travis-ci.org/woodrush/py2hy) 4 | [![Coverage Status](https://coveralls.io/repos/github/woodrush/py2hy/badge.svg?branch=master)](https://coveralls.io/github/woodrush/py2hy?branch=master) 5 | 6 | py2hy is a compiler that compiles Python AST to 7 | [Hy](https://github.com/hylang/hy). 8 | 9 | py2hy was used to create [HyHy](https://github.com/woodrush/hy/tree/hyhy), 10 | the Hy language rewritten entirely in Hy. 11 | 12 | Other Working demos are available in [demo/](demo/). 13 | 14 | 15 | ## Requirements 16 | 17 | - Python >= 3.3 18 | - Hy == 0.13.0 19 | 20 | Currently, py2hy is based on Python 3.6's 21 | [AST specs](https://docs.python.org/3.6/library/ast.html), and most tested in 22 | Python 3.6. 23 | 24 | 25 | ## Usage 26 | 27 | ```bash 28 | py2hy src.py 29 | ``` 30 | 31 | ### Generating the Grammar Template 32 | To parse the [Python AST specs](https://docs.python.org/3.6/library/ast.html) 33 | and generate the grammar template, do 34 | 35 | ```bash 36 | make template # i.e. `python tools/parse_pygrammarspecs.py > tools/template.hy` 37 | ``` 38 | 39 | 40 | ## How it works 41 | ### The Transformation 42 | The main idea is to treat the Python AST as if it was an S-expression, then 43 | treat the Python AST keywords as if they were Hy macros, and let Hy 44 | recursively `macroexpand-1` the expression. For example, the `Return` Python 45 | AST node has a field named `value`, so it would first be seen as the Hy code 46 | `(Return :value value)`. `py2hy` then treats this as if it was a 47 | macroexpansion of a macro named `Return`, producing Hy code. 48 | 49 | The original implementation actually used Hy's macro system and 50 | `macroexpand-1` for the transformation. The current implementation uses the 51 | Python class system for an equivalent functionality and improved speed. 52 | 53 | ### Generating the Grammar Template 54 | Running the [parser](lib/parse_pygrammarspecs.py) for the 55 | [Python AST specs](https://docs.python.org/3.6/library/ast.html) creates a 56 | [template script](template.hy) to be [filled in](py2hy.hy) to create 57 | `py2hy.hy`, a set of definitions of the transformations from Python AST to Hy. 58 | This tool would be useful to create a `py2hy` for different versions of the 59 | Python AST specs. 60 | 61 | ### The `return` statement 62 | At the time of writing, the `return` statement is not implemented in Hy. Here, 63 | `return` is implemented in a similar manner mentioned in 64 | [the Hy issues](https://github.com/hylang/hy/issues/739#issuecomment-68392695). 65 | For every `def` that contains a `return` statement, the entire function body is 66 | wrapped in a `try` clause that catches a `Py2HyReturnException`. The `return` 67 | statement is replaced by a `raise` statement that raises `Py2HyReturnException` 68 | containing the value to be returned. `Py2HyReturnException` is defined in the 69 | top of the entire script when the script contains any `return` statements. 70 | 71 | 72 | ## Notes 73 | ### Precompiling for the Travis CI Test 74 | Since Travis CI is currently incompatible with Hy code, py2hy precompiles all 75 | of its Hy portions to Python when installing. 76 | 77 | 78 | ## Contributing 79 | py2hy currently does not have a full set of `pytest` tests. Contribution is 80 | highly appreciated! 81 | 82 | 83 | ## License 84 | All of the code is licensed under the GNU Lesser General Public License version 85 | 3. See `LICENSE` for details. -------------------------------------------------------------------------------- /tests/test_compiling.hy: -------------------------------------------------------------------------------- 1 | (import [hy] 2 | [ast] 3 | [pytest] 4 | [py2hy.py2hy [py2hy :as py2hy_]]) 5 | 6 | (defn py2hy [py] 7 | (setv x (->> py (ast.parse) (py2hy_) (drop 1) (list))) 8 | (if (= 1 (len x)) 9 | (first x) 10 | x)) 11 | 12 | (defmacro asserteq [x y] 13 | `(assert (= ~x ~y))) 14 | 15 | (defsharp t [f] 16 | `#@((pytest.mark.skip :reason "TODO") 17 | ~f)) 18 | 19 | #t 20 | (defn test_Module [] 21 | ) 22 | 23 | #t 24 | (defn test_Interactive [] 25 | ) 26 | 27 | #t 28 | (defn test_Expression [] 29 | ) 30 | 31 | #t 32 | (defn test_Suite [] 33 | ) 34 | 35 | #t 36 | (defn test_FunctionDef [] 37 | ) 38 | 39 | #t 40 | (defn test_AsyncFunctionDef [] 41 | ) 42 | 43 | #t 44 | (defn test_ClassDef [] 45 | ) 46 | 47 | #t 48 | (defn test_Return [] 49 | ) 50 | 51 | #t 52 | (defn test_Delete [] 53 | ) 54 | 55 | #t 56 | (defn test_Assign [] 57 | ) 58 | 59 | #t 60 | (defn test_AugAssign [] 61 | ) 62 | 63 | #t 64 | (defn test_AnnAssign [] 65 | ) 66 | 67 | #t 68 | (defn test_For [] 69 | ) 70 | 71 | #t 72 | (defn test_AsyncFor [] 73 | ) 74 | 75 | #t 76 | (defn test_While [] 77 | ) 78 | 79 | #t 80 | (defn test_If [] 81 | ) 82 | 83 | #t 84 | (defn test_With [] 85 | ) 86 | 87 | #t 88 | (defn test_AsyncWith [] 89 | ) 90 | 91 | #t 92 | (defn test_Raise [] 93 | ) 94 | 95 | #t 96 | (defn test_Try [] 97 | ) 98 | 99 | #t 100 | (defn test_Assert [] 101 | ) 102 | 103 | #t 104 | (defn test_Import [] 105 | ) 106 | 107 | #t 108 | (defn test_ImportFrom [] 109 | ) 110 | 111 | #t 112 | (defn test_Global [] 113 | ) 114 | 115 | #t 116 | (defn test_Nonlocal [] 117 | ) 118 | 119 | #t 120 | (defn test_Expr [] 121 | ) 122 | 123 | #t 124 | (defn test_Pass [] 125 | ) 126 | 127 | #t 128 | (defn test_Break [] 129 | ) 130 | 131 | #t 132 | (defn test_Continue [] 133 | ) 134 | 135 | #t 136 | (defn test_BoolOp [] 137 | ) 138 | 139 | #t 140 | (defn test_BinOp [] 141 | ) 142 | 143 | #t 144 | (defn test_UnaryOp [] 145 | ) 146 | 147 | #t 148 | (defn test_Lambda [] 149 | ) 150 | 151 | #t 152 | (defn test_IfExp [] 153 | ) 154 | 155 | #t 156 | (defn test_Dict [] 157 | ) 158 | 159 | #t 160 | (defn test_Set [] 161 | ) 162 | 163 | #t 164 | (defn test_ListComp [] 165 | ) 166 | 167 | #t 168 | (defn test_SetComp [] 169 | ) 170 | 171 | #t 172 | (defn test_DictComp [] 173 | ) 174 | 175 | #t 176 | (defn test_GeneratorExp [] 177 | ) 178 | 179 | #t 180 | (defn test_Await [] 181 | ) 182 | 183 | #t 184 | (defn test_Yield [] 185 | ) 186 | 187 | #t 188 | (defn test_YieldFrom [] 189 | ) 190 | 191 | #t 192 | (defn test_Compare [] 193 | ) 194 | 195 | #t 196 | (defn test_Call [] 197 | ) 198 | 199 | #t 200 | (defn test_Num [] 201 | ) 202 | 203 | #t 204 | (defn test_Str [] 205 | ) 206 | 207 | #t 208 | (defn test_FormattedValue [] 209 | ) 210 | 211 | #t 212 | (defn test_JoinedStr [] 213 | ) 214 | 215 | #t 216 | (defn test_Bytes [] 217 | ) 218 | 219 | #t 220 | (defn test_NameConstant [] 221 | ) 222 | 223 | #t 224 | (defn test_Ellipsis [] 225 | ) 226 | 227 | #t 228 | (defn test_Constant [] 229 | ) 230 | 231 | #t 232 | (defn test_Attribute [] 233 | ) 234 | 235 | #t 236 | (defn test_Subscript [] 237 | ) 238 | 239 | #t 240 | (defn test_Starred [] 241 | ) 242 | 243 | #t 244 | (defn test_Name [] 245 | ) 246 | 247 | #t 248 | (defn test_List [] 249 | ) 250 | 251 | #t 252 | (defn test_Tuple [] 253 | ) 254 | 255 | #t 256 | (defn test_Load [] 257 | ) 258 | 259 | #t 260 | (defn test_Store [] 261 | ) 262 | 263 | #t 264 | (defn test_Del [] 265 | ) 266 | 267 | #t 268 | (defn test_AugLoad [] 269 | ) 270 | 271 | #t 272 | (defn test_AugStore [] 273 | ) 274 | 275 | #t 276 | (defn test_Param [] 277 | ) 278 | 279 | #t 280 | (defn test_Slice [] 281 | ) 282 | 283 | #t 284 | (defn test_ExtSlice [] 285 | ) 286 | 287 | #t 288 | (defn test_Index [] 289 | ) 290 | 291 | #t 292 | (defn test_comprehension [] 293 | ) 294 | 295 | #t 296 | (defn test_ExceptHandler [] 297 | ) 298 | 299 | #t 300 | (defn test_arguments [] 301 | ) 302 | 303 | #t 304 | (defn test_arg [] 305 | ) 306 | 307 | #t 308 | (defn test_keyword [] 309 | ) 310 | 311 | #t 312 | (defn test_alias [] 313 | ) 314 | 315 | #t 316 | (defn test_withitem [] 317 | ) 318 | 319 | -------------------------------------------------------------------------------- /tests/test_ops.hy: -------------------------------------------------------------------------------- 1 | (import [hy] 2 | [ast] 3 | [sys] 4 | [pytest] 5 | [py2hy.py2hy [py2hy :as py2hy_]] 6 | [builtins]) 7 | 8 | ;; Remove the `do` at the top for simplicity 9 | (defn py2hy [py] 10 | (setv x (->> py (ast.parse) (py2hy_) (drop 1) (list))) 11 | (if (= 1 (len x)) 12 | (first x) 13 | x)) 14 | 15 | (defn assert-eqexpr-eqvalue 16 | [pysource hyexpr] 17 | (defn helper [x y] 18 | (assert (= x y))) 19 | ;; Readability for pytest failures 20 | (helper (py2hy pysource) hyexpr) 21 | (assert (= (builtins.eval pysource) (eval hyexpr)))) 22 | 23 | (defmacro defoptest [testname oplist testbody] 24 | `(defmacro ~(hy.models.HySymbol testname) [] 25 | (setv oplist ~oplist) 26 | `(do 27 | ~@(map (fn [x] 28 | (apply 29 | (fn [astname hyop pyop] 30 | `(defn ~(hy.models.HySymbol (+ "test_" astname)) [] 31 | ~~testbody)) 32 | x)) 33 | oplist)))) 34 | 35 | (defoptest test_binaryops 36 | [["Add" `+ "+"] 37 | ["Sub" `- "-"] 38 | ["Mult" `* "*"] 39 | ["Div" `/ "/"] 40 | ["Mod" `% "%"] 41 | ["LShift" `<< "<<"] 42 | ["RShift" `>> ">>"] 43 | ["BitOr" `| "|"] 44 | ["BitXor" `^ "^"] 45 | ["BitAnd" `& "&"] 46 | ["FloorDiv" `// "//"]] 47 | `(do 48 | (assert-eqexpr-eqvalue 49 | (+ "5" ~pyop "4" ~pyop "3") 50 | `(~'~hyop (~'~hyop 5 4) 3)) 51 | (assert-eqexpr-eqvalue 52 | (+ "5" ~pyop "(4" ~pyop "3)") 53 | `(~'~hyop 5 (~'~hyop 4 3))) 54 | (assert-eqexpr-eqvalue 55 | (+ "(5" ~pyop "4)" ~pyop "3") 56 | `(~'~hyop (~'~hyop 5 4) 3)))) 57 | 58 | (defoptest test_pow 59 | [["Pow" `** "**"]] 60 | `(do 61 | ;; `**` is right associative 62 | (assert-eqexpr-eqvalue 63 | (+ "5" ~pyop "4" ~pyop "3") 64 | `(~'~hyop 5 (~'~hyop 4 3))) 65 | (assert-eqexpr-eqvalue 66 | (+ "5" ~pyop "(4" ~pyop "3)") 67 | `(~'~hyop 5 (~'~hyop 4 3))) 68 | (assert-eqexpr-eqvalue 69 | (+ "(5" ~pyop "4)" ~pyop "3") 70 | `(~'~hyop (~'~hyop 5 4) 3)))) 71 | 72 | (defoptest test_matmult 73 | [["MatMult" `@ "@"]] 74 | `(when (>= sys.version_info (, 3 5)) 75 | (assert (= (py2hy (+ "5" ~pyop "4" ~pyop "3")) 76 | `(~'~hyop (~'~hyop 5 4) 3))) 77 | (assert (= (py2hy (+ "5" ~pyop "(4" ~pyop "3)")) 78 | `(~'~hyop 5 (~'~hyop 4 3)))) 79 | (assert (= (py2hy (+ "(5" ~pyop "4)" ~pyop "3")) 80 | `(~'~hyop (~'~hyop 5 4) 3))))) 81 | 82 | (defoptest test_boolops 83 | [["And" `and "and"] 84 | ["Or" `or "or"]] 85 | `(do 86 | (assert-eqexpr-eqvalue 87 | ~(.join " " ["True" pyop "False" pyop "True"]) 88 | `(~'~hyop True False True)) 89 | (assert-eqexpr-eqvalue 90 | ~(.join " " ["True" pyop "(False" pyop "True)"]) 91 | `(~'~hyop True (~'~hyop False True))) 92 | (assert-eqexpr-eqvalue 93 | ~(.join " " ["(True" pyop "False" pyop "True)"]) 94 | `(~'~hyop True False True)))) 95 | 96 | (defoptest test_unaryops 97 | [["Invert" `~ "~"] 98 | ["Not" `not "not"] 99 | ["UAdd" `+ "+"] 100 | ["USub" `- "-"]] 101 | `(do 102 | (assert-eqexpr-eqvalue 103 | ~(.join " " [pyop "True"]) 104 | `(~'~hyop True)))) 105 | 106 | (defoptest test_compops 107 | [["Eq" `= "=="] 108 | ["NotEq" `!= "!="] 109 | ["Lt" `< "<"] 110 | ["LtE" `<= "<="] 111 | ["Gt" `> ">"] 112 | ["GtE" `>= ">="] 113 | ["Is" `is "is"] 114 | ["IsNot" `is-not "is not"]] 115 | `(do 116 | (assert-eqexpr-eqvalue 117 | ~(.join " " ["5" pyop "4" pyop "3"]) 118 | `(and (~'~hyop 5 4) (~'~hyop 4 3))) 119 | (assert-eqexpr-eqvalue 120 | ~(.join " " ["5" pyop "(4" pyop "3)"]) 121 | `(~'~hyop 5 (~'~hyop 4 3))) 122 | (assert-eqexpr-eqvalue 123 | ~(.join " " ["(5" pyop "4)" pyop "3"]) 124 | `(~'~hyop (~'~hyop 5 4) 3)))) 125 | 126 | (defoptest test_compops_list 127 | [["In" `in "in"] 128 | ["NotIn" `not-in "not in"]] 129 | `(do 130 | (assert-eqexpr-eqvalue 131 | ~(.join " " ["5" pyop "[5, 3]"]) 132 | `(~'~hyop 5 [5 3])))) 133 | 134 | (defn test_compops_mixed [] 135 | (assert-eqexpr-eqvalue 136 | "1<2<=3" `(and (< 1 2) (<= 2 3)))) 137 | 138 | (defn test_arithmeticops_mixed [] 139 | (assert-eqexpr-eqvalue 140 | "1*2+3/4*5" `(+ (* 1 2) (* (/ 3 4) 5)))) 141 | 142 | (test_binaryops) 143 | (test_pow) 144 | (test_matmult) 145 | (test_boolops) 146 | (test_unaryops) 147 | (test_compops) 148 | (test_compops_list) 149 | -------------------------------------------------------------------------------- /src/py2hy/prettyprinter.hy: -------------------------------------------------------------------------------- 1 | (import [hy] 2 | [re]) 3 | 4 | (defn add [x y] 5 | (+ x y)) 6 | 7 | (defclass Py2HyNewline [object] 8 | (setv indent-stack [-1]) 9 | (setv indent-head -1) 10 | 11 | (with-decorator classmethod 12 | (defn printer [self] 13 | (setv self.indent-head (last self.indent-stack)) 14 | (+ "\n" (* " " self.indent-head)))) 15 | 16 | (with-decorator classmethod 17 | (defn push-indent-stack [self] 18 | (self.indent-stack.append self.indent-head))) 19 | 20 | (with-decorator classmethod 21 | (defn pop-indent-stack [self] 22 | (self.indent-stack.pop) 23 | (setv self.indent-head (last self.indent-stack)))) 24 | 25 | (with-decorator classmethod 26 | (defn add-indent-head [self level] 27 | (+= self.indent-head level)))) 28 | 29 | (defn newliner [iter] 30 | (drop-last 1 (interleave iter (repeat (Py2HyNewline))))) 31 | 32 | (defn format-newline [l] 33 | (cond 34 | [(= hy.models.HyExpression (type l)) 35 | (do 36 | (setv f (first l)) 37 | (cond 38 | [(= f 'defclass) `(defclass ~(nth l 1) 39 | ~@(newliner (map format-newline (drop 2 l))))] 40 | [(= f 'defn) `(defn ~(nth l 1) 41 | ~@(newliner (map format-newline (drop 2 l))))] 42 | [(= f 'except) `(except ~@(newliner (map format-newline (drop 1 l))))] 43 | [(= f 'while) `(while ~@(newliner (map format-newline (drop 1 l))))] 44 | [(= f 'when) `(when ~@(newliner (map format-newline (drop 1 l))))] 45 | [(= f 'for) `(for ~@(newliner (map format-newline (drop 1 l))))] 46 | [(= f 'if) `(if ~@(newliner (map format-newline (drop 1 l))))] 47 | [(= f 'with-decorator) `(~@(newliner (map format-newline l)))] 48 | [(= f 'try) `(~@(newliner (map format-newline l)))] 49 | [(= f 'do) `(~@(newliner (map format-newline l)))] 50 | [(= f 'cond) 51 | `(cond ~(Py2HyNewline) 52 | ~@(newliner (map (fn [x] `[~@(newliner (map format-newline x))]) 53 | (drop 1 l))))] 54 | [True `(~@(map format-newline l))]))] 55 | [True 56 | l])) 57 | 58 | (defn recursiveprint [l] 59 | (cond 60 | [(= hy.models.HyExpression (type l)) 61 | (do 62 | (if (= hy.models.HyExpression (type (first l))) 63 | (Py2HyNewline.add-indent-head 1) 64 | (Py2HyNewline.add-indent-head 2)) 65 | (Py2HyNewline.push-indent-stack) 66 | (if (= 0 (len l)) 67 | (do 68 | (setv ret "()")) 69 | (do 70 | (setv ret (+ "(" 71 | (recursiveprint (first l)) 72 | (reduce add 73 | (map (fn [x] 74 | (+ 75 | (if (= Py2HyNewline (type x)) 76 | "" " ") 77 | (recursiveprint x))) 78 | (drop 1 l)) 79 | "") 80 | ")")))) 81 | (Py2HyNewline.pop-indent-stack) 82 | ret)] 83 | [(= hy.models.HyList (type l)) 84 | (do 85 | (Py2HyNewline.add-indent-head 1) 86 | (Py2HyNewline.push-indent-stack) 87 | (if (= 0 (len l)) 88 | (do 89 | (setv ret "[]")) 90 | (do 91 | (setv ret (+ "[" 92 | (recursiveprint (first l)) 93 | (reduce add 94 | (map (fn [x] 95 | (+ 96 | (if (= Py2HyNewline (type x)) 97 | "" " ") 98 | (recursiveprint x))) 99 | (drop 1 l)) 100 | "") 101 | "]")))) 102 | (Py2HyNewline.pop-indent-stack) 103 | ret)] 104 | [(= hy.models.HySymbol (type l)) 105 | (do 106 | (setv r (l.__repr__)) 107 | (Py2HyNewline.add-indent-head (+ 1 (len r))) 108 | r)] 109 | [(= Py2HyNewline (type l)) 110 | (Py2HyNewline.printer)] 111 | [True 112 | (l.__repr__)])) 113 | 114 | (defn prettyprinter [expr] 115 | ; Modify `__repr__` to suppress `'` and for escaping 116 | (setv hy.models.HySymbol.__repr__ 117 | (fn [self] (+ "" self)) 118 | hy.models.HyInteger.__repr__ 119 | (fn [self] (+ "" (str self))) 120 | hy.models.HyFloat.__repr__ 121 | (fn [self] (+ "" (str self))) 122 | hy.models.HyComplex.__repr__ 123 | (fn [self] (+ "" (str self))) 124 | hy.models.HyKeyword.__repr__ 125 | (fn [self] (.join "" (drop 1 self))) 126 | hy.models.HyString.__repr__ 127 | (fn [self] (+ "\"" (->> self 128 | (re.sub "\\\\" (+ "\\\\" "\\\\")) 129 | (re.sub "\"" "\\\"")) "\"")) 130 | hy.models.HyBytes.__repr__ 131 | (fn [self] (.__repr__ `[~@(list-comp (int x) [x self])]))) 132 | (->> expr (format-newline) (take-nth 2) (drop 1) (map recursiveprint) (.join "\n"))) -------------------------------------------------------------------------------- /tools/parse_pygrammarspecs.py: -------------------------------------------------------------------------------- 1 | # Usage: 2 | # python parse_pygrammarspecs.py > template.hy 3 | 4 | from pyparsing import * 5 | import re 6 | 7 | #============================================================================== 8 | # Model definition 9 | #============================================================================== 10 | module = Forward() 11 | body = Forward() 12 | datatypedeclarationwithattr = Forward() 13 | classdeclaration = Forward() 14 | classdeclarationwithattr = Forward() 15 | datatypedeclaration = Forward() 16 | classdefexpression = Forward() 17 | classdef = Forward() 18 | datatypedef = Forward() 19 | argpairs = Forward() 20 | argpair = Forward() 21 | attributeclause = Forward() 22 | 23 | w = Word(alphanums + '_*?') 24 | groupname = w.copy() 25 | classname = w.copy() 26 | argtype = w.copy() 27 | argname = w.copy() 28 | 29 | attrindicator = "#withattributes" 30 | groupindicator = "#group" 31 | datatypeindicator = "#datatype" 32 | attributetag = Empty().setParseAction(lambda s,l,t: [attrindicator]) 33 | grouptag = Empty().setParseAction(lambda s,l,t: [groupindicator]) 34 | datatypetag = Empty().setParseAction(lambda s,l,t: [datatypeindicator]) 35 | 36 | module << (Literal("module").suppress() 37 | + Literal("Python").suppress() 38 | + nestedExpr('{', '}', content=body)) 39 | body << OneOrMore(classdeclarationwithattr 40 | | classdeclaration 41 | | datatypedeclarationwithattr 42 | | datatypedeclaration) 43 | classdeclarationwithattr << Group(attributetag 44 | + grouptag 45 | + groupname 46 | + Literal("=").suppress() 47 | + classdefexpression 48 | + attributeclause) 49 | classdeclaration << Group(grouptag 50 | + groupname 51 | + Literal("=").suppress() 52 | + classdefexpression) 53 | datatypedeclarationwithattr << Group(attributetag 54 | + datatypetag 55 | + Group(groupname 56 | + Literal("=").suppress() 57 | + datatypedef) 58 | + attributeclause) 59 | datatypedeclaration << Group(datatypetag 60 | + Group(groupname 61 | + Literal("=").suppress() 62 | + datatypedef)) 63 | classdefexpression << delimitedList(classdef, delim='|') 64 | classdef << (Group(classname + nestedExpr('(', ')', content=argpairs)) 65 | | Group(classname + Group(Empty()))) 66 | datatypedef << nestedExpr('(', ')', content=argpairs) 67 | argpairs << delimitedList(argpair, delim=',') 68 | argpair << Group(argtype + argname) 69 | attributeclause << (Literal("attributes").suppress() 70 | + nestedExpr('(', ')', content=argpairs)) 71 | 72 | 73 | #============================================================================== 74 | # Parsing 75 | #============================================================================== 76 | with open("./tools/pygrammarspecs.txt", 'r') as f: 77 | data = f.read() 78 | # Delete comments 79 | data = re.sub("--.*", "", data) 80 | parsedlist = module.parseString(data).asList()[0] 81 | 82 | # Print templates for py2hy AST transform declarations 83 | def fprint(fname, fargs): 84 | keylist = map(lambda l: l[1], fargs) 85 | docstring = map(lambda l: l[1] + " (" + l[0] + ")" 86 | + (" [optional]" if l[0].endswith("?") else "") 87 | + (" [list]" if l[0].endswith("*") else ""), fargs) 88 | if len(fargs) > 0: 89 | print("(defsyntax " + fname + " [" + " ".join(keylist) + "]") 90 | print(" \"Args:") 91 | print(" " + "\n ".join(docstring) + "\"") 92 | print(" None)") 93 | else: 94 | # Constant expression 95 | print("(defsyntax " + fname + " []") 96 | print(" \"Constant expression\" None)") 97 | print() 98 | 99 | print("; Auto-generated template\n") 100 | for decl in parsedlist: 101 | it = iter(decl) 102 | varpairs_append = [] 103 | if decl[0] == attrindicator: 104 | # Popping `decl` affects `it` as well 105 | varpairs_append = decl.pop() 106 | next(it) 107 | typetag = next(it) 108 | if typetag == groupindicator: 109 | groupname = next(it) 110 | print(";==============================================================================") 111 | print("; Classgroup `" + groupname + "`") 112 | print(";==============================================================================") 113 | for syntaxdef in it: 114 | fname, fargs = syntaxdef 115 | fprint(fname, fargs + varpairs_append) 116 | elif typetag == datatypeindicator: 117 | syntaxdef = next(it) 118 | fname, fargs = syntaxdef 119 | print(";==============================================================================") 120 | print("; Datatype `" + fname + "`") 121 | print(";==============================================================================") 122 | fprint(fname, fargs + varpairs_append) 123 | print() 124 | -------------------------------------------------------------------------------- /tools/pygrammarspecs.txt: -------------------------------------------------------------------------------- 1 | -- Reference: 2 | -- Python 3.6.2 Documentation » The Python Standard Library 3 | -- 32. Python Language Services » 32.2. ast — Abstract Syntax Trees 4 | -- https://docs.python.org/3/library/ast.html#ast.AST._fields 5 | 6 | -- ASDL's 7 builtin types are: 7 | -- identifier, int, string, bytes, object, singleton, constant 8 | -- 9 | -- singleton: None, True or False 10 | -- constant can be None, whereas None means "no value" for object. 11 | 12 | module Python 13 | { 14 | mod = Module(stmt* body) 15 | | Interactive(stmt* body) 16 | | Expression(expr body) 17 | 18 | -- not really an actual node but useful in Jython's typesystem. 19 | | Suite(stmt* body) 20 | 21 | stmt = FunctionDef(identifier name, arguments args, 22 | stmt* body, expr* decorator_list, expr? returns) 23 | | AsyncFunctionDef(identifier name, arguments args, 24 | stmt* body, expr* decorator_list, expr? returns) 25 | 26 | | ClassDef(identifier name, 27 | expr* bases, 28 | keyword* keywords, 29 | stmt* body, 30 | expr* decorator_list) 31 | | Return(expr? value) 32 | 33 | | Delete(expr* targets) 34 | | Assign(expr* targets, expr value) 35 | | AugAssign(expr target, operator op, expr value) 36 | -- 'simple' indicates that we annotate simple name without parens 37 | | AnnAssign(expr target, expr annotation, expr? value, int simple) 38 | 39 | -- use 'orelse' because else is a keyword in target languages 40 | | For(expr target, expr iter, stmt* body, stmt* orelse) 41 | | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse) 42 | | While(expr test, stmt* body, stmt* orelse) 43 | | If(expr test, stmt* body, stmt* orelse) 44 | | With(withitem* items, stmt* body) 45 | | AsyncWith(withitem* items, stmt* body) 46 | 47 | | Raise(expr? exc, expr? cause) 48 | | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) 49 | | Assert(expr test, expr? msg) 50 | 51 | | Import(alias* names) 52 | | ImportFrom(identifier? module, alias* names, int? level) 53 | 54 | | Global(identifier* names) 55 | | Nonlocal(identifier* names) 56 | | Expr(expr value) 57 | | Pass | Break | Continue 58 | 59 | -- XXX Jython will be different 60 | -- col_offset is the byte offset in the utf8 string the parser uses 61 | attributes (int lineno, int col_offset) 62 | 63 | -- BoolOp() can use left & right? 64 | expr = BoolOp(boolop op, expr* values) 65 | | BinOp(expr left, operator op, expr right) 66 | | UnaryOp(unaryop op, expr operand) 67 | | Lambda(arguments args, expr body) 68 | | IfExp(expr test, expr body, expr orelse) 69 | | Dict(expr* keys, expr* values) 70 | | Set(expr* elts) 71 | | ListComp(expr elt, comprehension* generators) 72 | | SetComp(expr elt, comprehension* generators) 73 | | DictComp(expr key, expr value, comprehension* generators) 74 | | GeneratorExp(expr elt, comprehension* generators) 75 | -- the grammar constrains where yield expressions can occur 76 | | Await(expr value) 77 | | Yield(expr? value) 78 | | YieldFrom(expr value) 79 | -- need sequences for compare to distinguish between 80 | -- x < 4 < 3 and (x < 4) < 3 81 | | Compare(expr left, cmpop* ops, expr* comparators) 82 | | Call(expr func, expr* args, keyword* keywords) 83 | | Num(object n) -- a number as a PyObject. 84 | | Str(string s) -- need to specify raw, unicode, etc? 85 | | FormattedValue(expr value, int? conversion, expr? format_spec) 86 | | JoinedStr(expr* values) 87 | | Bytes(bytes s) 88 | | NameConstant(singleton value) 89 | | Ellipsis 90 | | Constant(constant value) 91 | 92 | -- the following expression can appear in assignment context 93 | | Attribute(expr value, identifier attr, expr_context ctx) 94 | | Subscript(expr value, slice slice, expr_context ctx) 95 | | Starred(expr value, expr_context ctx) 96 | | Name(identifier id, expr_context ctx) 97 | | List(expr* elts, expr_context ctx) 98 | | Tuple(expr* elts, expr_context ctx) 99 | 100 | -- col_offset is the byte offset in the utf8 string the parser uses 101 | attributes (int lineno, int col_offset) 102 | 103 | expr_context = Load | Store | Del | AugLoad | AugStore | Param 104 | 105 | slice = Slice(expr? lower, expr? upper, expr? step) 106 | | ExtSlice(slice* dims) 107 | | Index(expr value) 108 | 109 | boolop = And | Or 110 | 111 | operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift 112 | | RShift | BitOr | BitXor | BitAnd | FloorDiv 113 | 114 | unaryop = Invert | Not | UAdd | USub 115 | 116 | cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn 117 | 118 | comprehension = (expr target, expr iter, expr* ifs, int is_async) 119 | 120 | excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body) 121 | attributes (int lineno, int col_offset) 122 | 123 | arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, 124 | arg? kwarg, expr* defaults) 125 | 126 | arg = (identifier arg, expr? annotation) 127 | attributes (int lineno, int col_offset) 128 | 129 | -- keyword arguments supplied to call (NULL identifier for **kwargs) 130 | keyword = (identifier? arg, expr value) 131 | 132 | -- import name with optional 'as' alias. 133 | alias = (identifier name, identifier? asname) 134 | 135 | withitem = (expr context_expr, expr? optional_vars) 136 | } 137 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /tools/template.hy: -------------------------------------------------------------------------------- 1 | ; Auto-generated template 2 | 3 | ;============================================================================== 4 | ; Classgroup `mod` 5 | ;============================================================================== 6 | (defsyntax Module [body] 7 | "Args: 8 | body (stmt*) [list]" 9 | None) 10 | 11 | (defsyntax Interactive [body] 12 | "Args: 13 | body (stmt*) [list]" 14 | None) 15 | 16 | (defsyntax Expression [body] 17 | "Args: 18 | body (expr)" 19 | None) 20 | 21 | (defsyntax Suite [body] 22 | "Args: 23 | body (stmt*) [list]" 24 | None) 25 | 26 | 27 | ;============================================================================== 28 | ; Classgroup `stmt` 29 | ;============================================================================== 30 | (defsyntax FunctionDef [name args body decorator_list returns lineno col_offset] 31 | "Args: 32 | name (identifier) 33 | args (arguments) 34 | body (stmt*) [list] 35 | decorator_list (expr*) [list] 36 | returns (expr?) [optional] 37 | lineno (int) 38 | col_offset (int)" 39 | None) 40 | 41 | (defsyntax AsyncFunctionDef [name args body decorator_list returns lineno col_offset] 42 | "Args: 43 | name (identifier) 44 | args (arguments) 45 | body (stmt*) [list] 46 | decorator_list (expr*) [list] 47 | returns (expr?) [optional] 48 | lineno (int) 49 | col_offset (int)" 50 | None) 51 | 52 | (defsyntax ClassDef [name bases keywords body decorator_list lineno col_offset] 53 | "Args: 54 | name (identifier) 55 | bases (expr*) [list] 56 | keywords (keyword*) [list] 57 | body (stmt*) [list] 58 | decorator_list (expr*) [list] 59 | lineno (int) 60 | col_offset (int)" 61 | None) 62 | 63 | (defsyntax Return [value lineno col_offset] 64 | "Args: 65 | value (expr?) [optional] 66 | lineno (int) 67 | col_offset (int)" 68 | None) 69 | 70 | (defsyntax Delete [targets lineno col_offset] 71 | "Args: 72 | targets (expr*) [list] 73 | lineno (int) 74 | col_offset (int)" 75 | None) 76 | 77 | (defsyntax Assign [targets value lineno col_offset] 78 | "Args: 79 | targets (expr*) [list] 80 | value (expr) 81 | lineno (int) 82 | col_offset (int)" 83 | None) 84 | 85 | (defsyntax AugAssign [target op value lineno col_offset] 86 | "Args: 87 | target (expr) 88 | op (operator) 89 | value (expr) 90 | lineno (int) 91 | col_offset (int)" 92 | None) 93 | 94 | (defsyntax AnnAssign [target annotation value simple lineno col_offset] 95 | "Args: 96 | target (expr) 97 | annotation (expr) 98 | value (expr?) [optional] 99 | simple (int) 100 | lineno (int) 101 | col_offset (int)" 102 | None) 103 | 104 | (defsyntax For [target iter body orelse lineno col_offset] 105 | "Args: 106 | target (expr) 107 | iter (expr) 108 | body (stmt*) [list] 109 | orelse (stmt*) [list] 110 | lineno (int) 111 | col_offset (int)" 112 | None) 113 | 114 | (defsyntax AsyncFor [target iter body orelse lineno col_offset] 115 | "Args: 116 | target (expr) 117 | iter (expr) 118 | body (stmt*) [list] 119 | orelse (stmt*) [list] 120 | lineno (int) 121 | col_offset (int)" 122 | None) 123 | 124 | (defsyntax While [test body orelse lineno col_offset] 125 | "Args: 126 | test (expr) 127 | body (stmt*) [list] 128 | orelse (stmt*) [list] 129 | lineno (int) 130 | col_offset (int)" 131 | None) 132 | 133 | (defsyntax If [test body orelse lineno col_offset] 134 | "Args: 135 | test (expr) 136 | body (stmt*) [list] 137 | orelse (stmt*) [list] 138 | lineno (int) 139 | col_offset (int)" 140 | None) 141 | 142 | (defsyntax With [items body lineno col_offset] 143 | "Args: 144 | items (withitem*) [list] 145 | body (stmt*) [list] 146 | lineno (int) 147 | col_offset (int)" 148 | None) 149 | 150 | (defsyntax AsyncWith [items body lineno col_offset] 151 | "Args: 152 | items (withitem*) [list] 153 | body (stmt*) [list] 154 | lineno (int) 155 | col_offset (int)" 156 | None) 157 | 158 | (defsyntax Raise [exc cause lineno col_offset] 159 | "Args: 160 | exc (expr?) [optional] 161 | cause (expr?) [optional] 162 | lineno (int) 163 | col_offset (int)" 164 | None) 165 | 166 | (defsyntax Try [body handlers orelse finalbody lineno col_offset] 167 | "Args: 168 | body (stmt*) [list] 169 | handlers (excepthandler*) [list] 170 | orelse (stmt*) [list] 171 | finalbody (stmt*) [list] 172 | lineno (int) 173 | col_offset (int)" 174 | None) 175 | 176 | (defsyntax Assert [test msg lineno col_offset] 177 | "Args: 178 | test (expr) 179 | msg (expr?) [optional] 180 | lineno (int) 181 | col_offset (int)" 182 | None) 183 | 184 | (defsyntax Import [names lineno col_offset] 185 | "Args: 186 | names (alias*) [list] 187 | lineno (int) 188 | col_offset (int)" 189 | None) 190 | 191 | (defsyntax ImportFrom [module names level lineno col_offset] 192 | "Args: 193 | module (identifier?) [optional] 194 | names (alias*) [list] 195 | level (int?) [optional] 196 | lineno (int) 197 | col_offset (int)" 198 | None) 199 | 200 | (defsyntax Global [names lineno col_offset] 201 | "Args: 202 | names (identifier*) [list] 203 | lineno (int) 204 | col_offset (int)" 205 | None) 206 | 207 | (defsyntax Nonlocal [names lineno col_offset] 208 | "Args: 209 | names (identifier*) [list] 210 | lineno (int) 211 | col_offset (int)" 212 | None) 213 | 214 | (defsyntax Expr [value lineno col_offset] 215 | "Args: 216 | value (expr) 217 | lineno (int) 218 | col_offset (int)" 219 | None) 220 | 221 | (defsyntax Pass [lineno col_offset] 222 | "Args: 223 | lineno (int) 224 | col_offset (int)" 225 | None) 226 | 227 | (defsyntax Break [lineno col_offset] 228 | "Args: 229 | lineno (int) 230 | col_offset (int)" 231 | None) 232 | 233 | (defsyntax Continue [lineno col_offset] 234 | "Args: 235 | lineno (int) 236 | col_offset (int)" 237 | None) 238 | 239 | 240 | ;============================================================================== 241 | ; Classgroup `expr` 242 | ;============================================================================== 243 | (defsyntax BoolOp [op values lineno col_offset] 244 | "Args: 245 | op (boolop) 246 | values (expr*) [list] 247 | lineno (int) 248 | col_offset (int)" 249 | None) 250 | 251 | (defsyntax BinOp [left op right lineno col_offset] 252 | "Args: 253 | left (expr) 254 | op (operator) 255 | right (expr) 256 | lineno (int) 257 | col_offset (int)" 258 | None) 259 | 260 | (defsyntax UnaryOp [op operand lineno col_offset] 261 | "Args: 262 | op (unaryop) 263 | operand (expr) 264 | lineno (int) 265 | col_offset (int)" 266 | None) 267 | 268 | (defsyntax Lambda [args body lineno col_offset] 269 | "Args: 270 | args (arguments) 271 | body (expr) 272 | lineno (int) 273 | col_offset (int)" 274 | None) 275 | 276 | (defsyntax IfExp [test body orelse lineno col_offset] 277 | "Args: 278 | test (expr) 279 | body (expr) 280 | orelse (expr) 281 | lineno (int) 282 | col_offset (int)" 283 | None) 284 | 285 | (defsyntax Dict [keys values lineno col_offset] 286 | "Args: 287 | keys (expr*) [list] 288 | values (expr*) [list] 289 | lineno (int) 290 | col_offset (int)" 291 | None) 292 | 293 | (defsyntax Set [elts lineno col_offset] 294 | "Args: 295 | elts (expr*) [list] 296 | lineno (int) 297 | col_offset (int)" 298 | None) 299 | 300 | (defsyntax ListComp [elt generators lineno col_offset] 301 | "Args: 302 | elt (expr) 303 | generators (comprehension*) [list] 304 | lineno (int) 305 | col_offset (int)" 306 | None) 307 | 308 | (defsyntax SetComp [elt generators lineno col_offset] 309 | "Args: 310 | elt (expr) 311 | generators (comprehension*) [list] 312 | lineno (int) 313 | col_offset (int)" 314 | None) 315 | 316 | (defsyntax DictComp [key value generators lineno col_offset] 317 | "Args: 318 | key (expr) 319 | value (expr) 320 | generators (comprehension*) [list] 321 | lineno (int) 322 | col_offset (int)" 323 | None) 324 | 325 | (defsyntax GeneratorExp [elt generators lineno col_offset] 326 | "Args: 327 | elt (expr) 328 | generators (comprehension*) [list] 329 | lineno (int) 330 | col_offset (int)" 331 | None) 332 | 333 | (defsyntax Await [value lineno col_offset] 334 | "Args: 335 | value (expr) 336 | lineno (int) 337 | col_offset (int)" 338 | None) 339 | 340 | (defsyntax Yield [value lineno col_offset] 341 | "Args: 342 | value (expr?) [optional] 343 | lineno (int) 344 | col_offset (int)" 345 | None) 346 | 347 | (defsyntax YieldFrom [value lineno col_offset] 348 | "Args: 349 | value (expr) 350 | lineno (int) 351 | col_offset (int)" 352 | None) 353 | 354 | (defsyntax Compare [left ops comparators lineno col_offset] 355 | "Args: 356 | left (expr) 357 | ops (cmpop*) [list] 358 | comparators (expr*) [list] 359 | lineno (int) 360 | col_offset (int)" 361 | None) 362 | 363 | (defsyntax Call [func args keywords lineno col_offset] 364 | "Args: 365 | func (expr) 366 | args (expr*) [list] 367 | keywords (keyword*) [list] 368 | lineno (int) 369 | col_offset (int)" 370 | None) 371 | 372 | (defsyntax Num [n lineno col_offset] 373 | "Args: 374 | n (object) 375 | lineno (int) 376 | col_offset (int)" 377 | None) 378 | 379 | (defsyntax Str [s lineno col_offset] 380 | "Args: 381 | s (string) 382 | lineno (int) 383 | col_offset (int)" 384 | None) 385 | 386 | (defsyntax FormattedValue [value conversion format_spec lineno col_offset] 387 | "Args: 388 | value (expr) 389 | conversion (int?) [optional] 390 | format_spec (expr?) [optional] 391 | lineno (int) 392 | col_offset (int)" 393 | None) 394 | 395 | (defsyntax JoinedStr [values lineno col_offset] 396 | "Args: 397 | values (expr*) [list] 398 | lineno (int) 399 | col_offset (int)" 400 | None) 401 | 402 | (defsyntax Bytes [s lineno col_offset] 403 | "Args: 404 | s (bytes) 405 | lineno (int) 406 | col_offset (int)" 407 | None) 408 | 409 | (defsyntax NameConstant [value lineno col_offset] 410 | "Args: 411 | value (singleton) 412 | lineno (int) 413 | col_offset (int)" 414 | None) 415 | 416 | (defsyntax Ellipsis [lineno col_offset] 417 | "Args: 418 | lineno (int) 419 | col_offset (int)" 420 | None) 421 | 422 | (defsyntax Constant [value lineno col_offset] 423 | "Args: 424 | value (constant) 425 | lineno (int) 426 | col_offset (int)" 427 | None) 428 | 429 | (defsyntax Attribute [value attr ctx lineno col_offset] 430 | "Args: 431 | value (expr) 432 | attr (identifier) 433 | ctx (expr_context) 434 | lineno (int) 435 | col_offset (int)" 436 | None) 437 | 438 | (defsyntax Subscript [value slice ctx lineno col_offset] 439 | "Args: 440 | value (expr) 441 | slice (slice) 442 | ctx (expr_context) 443 | lineno (int) 444 | col_offset (int)" 445 | None) 446 | 447 | (defsyntax Starred [value ctx lineno col_offset] 448 | "Args: 449 | value (expr) 450 | ctx (expr_context) 451 | lineno (int) 452 | col_offset (int)" 453 | None) 454 | 455 | (defsyntax Name [id ctx lineno col_offset] 456 | "Args: 457 | id (identifier) 458 | ctx (expr_context) 459 | lineno (int) 460 | col_offset (int)" 461 | None) 462 | 463 | (defsyntax List [elts ctx lineno col_offset] 464 | "Args: 465 | elts (expr*) [list] 466 | ctx (expr_context) 467 | lineno (int) 468 | col_offset (int)" 469 | None) 470 | 471 | (defsyntax Tuple [elts ctx lineno col_offset] 472 | "Args: 473 | elts (expr*) [list] 474 | ctx (expr_context) 475 | lineno (int) 476 | col_offset (int)" 477 | None) 478 | 479 | 480 | ;============================================================================== 481 | ; Classgroup `expr_context` 482 | ;============================================================================== 483 | (defsyntax Load [] 484 | "Constant expression" None) 485 | 486 | (defsyntax Store [] 487 | "Constant expression" None) 488 | 489 | (defsyntax Del [] 490 | "Constant expression" None) 491 | 492 | (defsyntax AugLoad [] 493 | "Constant expression" None) 494 | 495 | (defsyntax AugStore [] 496 | "Constant expression" None) 497 | 498 | (defsyntax Param [] 499 | "Constant expression" None) 500 | 501 | 502 | ;============================================================================== 503 | ; Classgroup `slice` 504 | ;============================================================================== 505 | (defsyntax Slice [lower upper step] 506 | "Args: 507 | lower (expr?) [optional] 508 | upper (expr?) [optional] 509 | step (expr?) [optional]" 510 | None) 511 | 512 | (defsyntax ExtSlice [dims] 513 | "Args: 514 | dims (slice*) [list]" 515 | None) 516 | 517 | (defsyntax Index [value] 518 | "Args: 519 | value (expr)" 520 | None) 521 | 522 | 523 | ;============================================================================== 524 | ; Classgroup `boolop` 525 | ;============================================================================== 526 | (defsyntax And [] 527 | "Constant expression" None) 528 | 529 | (defsyntax Or [] 530 | "Constant expression" None) 531 | 532 | 533 | ;============================================================================== 534 | ; Classgroup `operator` 535 | ;============================================================================== 536 | (defsyntax Add [] 537 | "Constant expression" None) 538 | 539 | (defsyntax Sub [] 540 | "Constant expression" None) 541 | 542 | (defsyntax Mult [] 543 | "Constant expression" None) 544 | 545 | (defsyntax MatMult [] 546 | "Constant expression" None) 547 | 548 | (defsyntax Div [] 549 | "Constant expression" None) 550 | 551 | (defsyntax Mod [] 552 | "Constant expression" None) 553 | 554 | (defsyntax Pow [] 555 | "Constant expression" None) 556 | 557 | (defsyntax LShift [] 558 | "Constant expression" None) 559 | 560 | (defsyntax RShift [] 561 | "Constant expression" None) 562 | 563 | (defsyntax BitOr [] 564 | "Constant expression" None) 565 | 566 | (defsyntax BitXor [] 567 | "Constant expression" None) 568 | 569 | (defsyntax BitAnd [] 570 | "Constant expression" None) 571 | 572 | (defsyntax FloorDiv [] 573 | "Constant expression" None) 574 | 575 | 576 | ;============================================================================== 577 | ; Classgroup `unaryop` 578 | ;============================================================================== 579 | (defsyntax Invert [] 580 | "Constant expression" None) 581 | 582 | (defsyntax Not [] 583 | "Constant expression" None) 584 | 585 | (defsyntax UAdd [] 586 | "Constant expression" None) 587 | 588 | (defsyntax USub [] 589 | "Constant expression" None) 590 | 591 | 592 | ;============================================================================== 593 | ; Classgroup `cmpop` 594 | ;============================================================================== 595 | (defsyntax Eq [] 596 | "Constant expression" None) 597 | 598 | (defsyntax NotEq [] 599 | "Constant expression" None) 600 | 601 | (defsyntax Lt [] 602 | "Constant expression" None) 603 | 604 | (defsyntax LtE [] 605 | "Constant expression" None) 606 | 607 | (defsyntax Gt [] 608 | "Constant expression" None) 609 | 610 | (defsyntax GtE [] 611 | "Constant expression" None) 612 | 613 | (defsyntax Is [] 614 | "Constant expression" None) 615 | 616 | (defsyntax IsNot [] 617 | "Constant expression" None) 618 | 619 | (defsyntax In [] 620 | "Constant expression" None) 621 | 622 | (defsyntax NotIn [] 623 | "Constant expression" None) 624 | 625 | 626 | ;============================================================================== 627 | ; Datatype `comprehension` 628 | ;============================================================================== 629 | (defsyntax comprehension [target iter ifs is_async] 630 | "Args: 631 | target (expr) 632 | iter (expr) 633 | ifs (expr*) [list] 634 | is_async (int)" 635 | None) 636 | 637 | 638 | ;============================================================================== 639 | ; Classgroup `excepthandler` 640 | ;============================================================================== 641 | (defsyntax ExceptHandler [type name body lineno col_offset] 642 | "Args: 643 | type (expr?) [optional] 644 | name (identifier?) [optional] 645 | body (stmt*) [list] 646 | lineno (int) 647 | col_offset (int)" 648 | None) 649 | 650 | 651 | ;============================================================================== 652 | ; Datatype `arguments` 653 | ;============================================================================== 654 | (defsyntax arguments [args vararg kwonlyargs kw_defaults kwarg defaults] 655 | "Args: 656 | args (arg*) [list] 657 | vararg (arg?) [optional] 658 | kwonlyargs (arg*) [list] 659 | kw_defaults (expr*) [list] 660 | kwarg (arg?) [optional] 661 | defaults (expr*) [list]" 662 | None) 663 | 664 | 665 | ;============================================================================== 666 | ; Datatype `arg` 667 | ;============================================================================== 668 | (defsyntax arg [arg annotation lineno col_offset] 669 | "Args: 670 | arg (identifier) 671 | annotation (expr?) [optional] 672 | lineno (int) 673 | col_offset (int)" 674 | None) 675 | 676 | 677 | ;============================================================================== 678 | ; Datatype `keyword` 679 | ;============================================================================== 680 | (defsyntax keyword [arg value] 681 | "Args: 682 | arg (identifier?) [optional] 683 | value (expr)" 684 | None) 685 | 686 | 687 | ;============================================================================== 688 | ; Datatype `alias` 689 | ;============================================================================== 690 | (defsyntax alias [name asname] 691 | "Args: 692 | name (identifier) 693 | asname (identifier?) [optional]" 694 | None) 695 | 696 | 697 | ;============================================================================== 698 | ; Datatype `withitem` 699 | ;============================================================================== 700 | (defsyntax withitem [context_expr optional_vars] 701 | "Args: 702 | context_expr (expr) 703 | optional_vars (expr?) [optional]" 704 | None) 705 | 706 | 707 | -------------------------------------------------------------------------------- /src/py2hy/py2hy.hy: -------------------------------------------------------------------------------- 1 | (import [hy] 2 | [hy.extra.reserved] 3 | [ast] 4 | [re] 5 | [argparse] 6 | [py2hy.prettyprinter [prettyprinter]]) 7 | 8 | ;;; Stable version Hy compatibility 9 | ;;; For splicing None as an empty list 10 | (defsharp A [expr] 11 | `(if (is None ~expr) 12 | [] 13 | ~expr)) 14 | ;;; deftag -> defsharp 15 | (defmacro deftag [name args &rest body] 16 | `(defsharp ~(hy.models.HySymbol name) ~args 17 | ~@body)) 18 | 19 | (defn add [x y] 20 | (+ x y)) 21 | 22 | (defn expand-form [x] 23 | (if (hasattr x "expand") 24 | (x.expand) 25 | (cond 26 | [(is None x) None] 27 | [(= int (type x)) (hy.models.HyInteger x)] 28 | [(= float (type x)) (hy.models.HyFloat x)] 29 | [(= complex (type x)) (hy.models.HyComplex x)] 30 | [(= bool (type x)) (hy.models.HySymbol (hy.models.HySymbol (str x)))] 31 | [(= list (type x)) (hy.models.HyList x)] 32 | [(= bytes (type x)) (hy.models.HyBytes x)] 33 | [True (hy.models.HySymbol x)]))) 34 | 35 | (defn do-if-long [l] 36 | (setv l (list l)) 37 | (if (= 1 (len l)) (first l) `(do ~@#A l))) 38 | 39 | ;;; TODO: use (hy.extra.reserved.names) 40 | (setv hy_reserved_keywords 41 | `[fn defn defclass cond]) 42 | (defn py2hy_mangle_identifier [x] 43 | (if (in x hy_reserved_keywords) 44 | (hy.models.HySymbol (+ x "_py2hy_mangling")) 45 | x)) 46 | 47 | (deftag l [body] 48 | `(hy.models.HyList (list (map expand-form ~body)))) 49 | 50 | (deftag e [x] 51 | `(expand-form ~x)) 52 | 53 | (deftag k [key] 54 | `(. self ~key)) 55 | 56 | (defmacro defsyntax [name keys &rest body] 57 | `(do 58 | (when (hasattr ast '~name) 59 | (setv (. (. ast ~name) expand) 60 | (fn [self] 61 | ~@#A body))))) 62 | 63 | (defmacro defconstantexpression [&rest transformdicts] 64 | `(do 65 | ~@(reduce add 66 | (map (fn [transformdict] 67 | `[~@(list-comp 68 | `(defsyntax ~(hy.models.HySymbol astname) [] 69 | "Constant expression" ~hysymbol) 70 | [[astname hysymbol] (transformdict.items)])]) 71 | transformdicts)))) 72 | 73 | ;;;============================================================================= 74 | ;;; Classgroup `mod` 75 | ;;;============================================================================= 76 | (defsyntax Module [body] 77 | "Args: 78 | body (stmt*) [list]" 79 | (setv bodylist #l #k body 80 | body (iter bodylist)) 81 | (setv n (first body)) 82 | (setv r (if (in "Py2HyReturnException" (bodylist.__repr__)) 83 | `[(defclass Py2HyReturnException [Exception] 84 | (defn __init__ [self retvalue] 85 | (setv self.retvalue retvalue)))])) 86 | 87 | ; `from __future__ import *` must be imported at the top of the file 88 | `(do 89 | ~@#A (if (and (= hy.models.HyExpression (type n)) 90 | (= 'import (first n))) 91 | `[~n ~@#A r] 92 | `[~@#A r ~n]) 93 | ~@#A body)) 94 | 95 | (defsyntax Interactive [body] 96 | "Args: 97 | body (stmt*) [list]" 98 | None) 99 | 100 | (defsyntax Expression [body] 101 | "Args: 102 | body (expr)" 103 | None) 104 | 105 | (defsyntax Suite [body] 106 | "Args: 107 | body (stmt*) [list]" 108 | None) 109 | 110 | 111 | ;;;============================================================================= 112 | ;;; Classgroup `stmt` 113 | ;;;============================================================================= 114 | (defsyntax FunctionDef [name args body decorator_list returns lineno col_offset] 115 | "Args: 116 | name (identifier) 117 | args (arguments) 118 | body (stmt*) [list] 119 | decorator_list (expr*) [list] 120 | returns (expr?) [optional] 121 | lineno (int) 122 | col_offset (int)" 123 | (setv body #l #k body 124 | decorator_list #l #k decorator_list) 125 | (setv main_body 126 | (cond 127 | ; If there are no `return` statements in the entire body, 128 | ; don't add the `try` construct 129 | ; Note: - `return` statements must be recursively searched 130 | ; inside `if`, `when` statements. 131 | ; - This is a simple solution (a necessary condition) to that. 132 | [(not-in "Py2HyReturnException" (.__repr__ body)) 133 | `(defn ~(py2hy_mangle_identifier #e #k name) ~#e #k args 134 | ~@#A body)] 135 | ; Optimize tail-returns to tail expressions. 136 | ; i.e. if there is only one `return` statement and it is in the tail 137 | ; of the function body, optimize it as a tail expression. 138 | ; Note: This cannot find `return` statements that are inside 139 | ; other AST nodes such as `if`, `for`, etc. 140 | [(and (not-in "Py2HyReturnException" 141 | (.__repr__ (list (drop-last 1 body)))) 142 | (= ast.Return (type (last #k body)))) 143 | `(defn ~(py2hy_mangle_identifier #e #k name) ~#e #k args 144 | ~@#A #l (drop-last 1 #k body) 145 | ~#e (. (last #k body) value))] 146 | ; Keep docstrings 147 | [(= hy.models.HyString (type (first body))) 148 | `(defn ~(py2hy_mangle_identifier #e #k name) ~#e #k args 149 | ~(first body) 150 | (try 151 | ~(do-if-long (rest body)) 152 | (except [e Py2HyReturnException] 153 | e.retvalue)))] 154 | [True 155 | `(defn ~(py2hy_mangle_identifier #e #k name) ~#e #k args 156 | (try 157 | ~(do-if-long body) 158 | (except [e Py2HyReturnException] 159 | e.retvalue)))])) 160 | (if decorator_list 161 | `(with-decorator 162 | ~@#A decorator_list 163 | ~main_body) 164 | main_body)) 165 | 166 | (defsyntax AsyncFunctionDef [name args body decorator_list returns lineno 167 | col_offset] 168 | "Args: 169 | name (identifier) 170 | args (arguments) 171 | body (stmt*) [list] 172 | decorator_list (expr*) [list] 173 | returns (expr?) [optional] 174 | lineno (int) 175 | col_offset (int)" 176 | None) 177 | 178 | (defsyntax ClassDef [name bases keywords body decorator_list lineno col_offset] 179 | "Args: 180 | name (identifier) 181 | bases (expr*) [list] 182 | keywords (keyword*) [list] 183 | body (stmt*) [list] 184 | decorator_list (expr*) [list] 185 | lineno (int) 186 | col_offset (int)" 187 | ; TODO: defclass 188 | `(defclass ~(py2hy_mangle_identifier #e #k name) [~@#A #l #k bases] 189 | ~@#A #l #k body)) 190 | 191 | (defsyntax Return [value lineno col_offset] 192 | "Args: 193 | value (expr?) [optional] 194 | lineno (int) 195 | col_offset (int)" 196 | `(raise (Py2HyReturnException ~#e #k value))) 197 | 198 | (defsyntax Delete [targets lineno col_offset] 199 | "Args: 200 | targets (expr*) [list] 201 | lineno (int) 202 | col_offset (int)" 203 | `(del ~@#A #l #k targets)) 204 | 205 | (defsyntax Assign [targets value lineno col_offset] 206 | "Args: 207 | targets (expr*) [list] 208 | value (expr) 209 | lineno (int) 210 | col_offset (int)" 211 | 212 | (setv targets #l #k targets) 213 | (setv g (if (or (< 1 (len targets)) 214 | (= ', (first (first targets)))) 215 | (hy.models.HySymbol (+ "_py2hy_anon_var_" 216 | (.join "" (drop 1 (gensym))))) 217 | #e #k value)) 218 | (setv typedict {ast.Tuple 219 | (fn [target value] 220 | (reduce add (map (fn [l] ((get typedict (type (first l))) 221 | (first l) 222 | (second l))) 223 | (zip target.elts 224 | (map 225 | (fn [t] `(get ~(second t) ~(first t))) 226 | (enumerate (repeat value))))))) 227 | ast.Subscript 228 | (fn [target value] 229 | (setv target #e target) 230 | `[(assoc ~(get target 1) ~(get target 2) ~value)]) 231 | ast.Attribute 232 | (fn [target value] 233 | (setv target #e target) 234 | `[(setv ~target ~value)]) 235 | ast.Name 236 | (fn [target value] 237 | (setv target #e target) 238 | (if (= '_ target) 239 | `[(do)] 240 | `[(setv ~target ~value)]))}) 241 | (setv ret `[~@#A (if (or (< 1 (len targets)) 242 | (= ', (first (first targets)))) 243 | [`(setv ~g ~#e #k value)]) 244 | ~@#A (reduce add 245 | (map (fn [l] `[~@#A ((get typedict 246 | (type (first l))) 247 | (first l) (second l))]) 248 | (zip #k targets 249 | (repeat g))))]) 250 | ; Optimization 251 | (setv ret `[~@#A (list-comp x [x ret] (not (= '(do) x)))]) 252 | (if (= 1 (len ret)) 253 | (first ret) 254 | `(do ~@#A ret))) 255 | 256 | (defsyntax AugAssign [target op value lineno col_offset] 257 | "Args: 258 | target (expr) 259 | op (operator) 260 | value (expr) 261 | lineno (int) 262 | col_offset (int)" 263 | (setv op2aug {`+ `+= 264 | `- `-= 265 | `* `*= 266 | `/ `/= 267 | `% `%= 268 | `** `**= 269 | `<< `<<= 270 | `>> `>>= 271 | `| `|= 272 | `^ `^= 273 | `// `//= 274 | `bitand `&=}) 275 | `(~(get op2aug #e #k op) ~#e #k target ~#e #k value)) 276 | 277 | (defsyntax AnnAssign [target annotation value simple lineno col_offset] 278 | "Args: 279 | target (expr) 280 | annotation (expr) 281 | value (expr?) [optional] 282 | simple (int) 283 | lineno (int) 284 | col_offset (int)" 285 | None) 286 | 287 | (defsyntax For [target iter body orelse lineno col_offset] 288 | "Args: 289 | target (expr) 290 | iter (expr) 291 | body (stmt*) [list] 292 | orelse (stmt*) [list] 293 | lineno (int) 294 | col_offset (int)" 295 | (setv target #e #k target) 296 | `(for [~@#A (if (= ', (first target)) 297 | [`[~@#A (rest target)]] 298 | [target]) 299 | ~#e #k iter] 300 | ~@#A #l #k body)) 301 | 302 | (defsyntax AsyncFor [target iter body orelse lineno col_offset] 303 | "Args: 304 | target (expr) 305 | iter (expr) 306 | body (stmt*) [list] 307 | orelse (stmt*) [list] 308 | lineno (int) 309 | col_offset (int)" 310 | None) 311 | 312 | (defsyntax While [test body orelse lineno col_offset] 313 | "Args: 314 | test (expr) 315 | body (stmt*) [list] 316 | orelse (stmt*) [list] 317 | lineno (int) 318 | col_offset (int)" 319 | `(while ~#e #k test 320 | ~@#A #l #k body)) 321 | 322 | (defsyntax If [test body orelse lineno col_offset] 323 | "Args: 324 | test (expr) 325 | body (stmt*) [list] 326 | orelse (stmt*) [list] 327 | lineno (int) 328 | col_offset (int)" 329 | (setv orelseast #k orelse 330 | orelse #l orelseast 331 | body #l #k body) 332 | (cond 333 | [(= 'cond (first orelse)) 334 | `(cond 335 | [~#e #k 336 | test ~(do-if-long body)] 337 | ~@#A (drop 1 body))] 338 | [(and (-> orelseast (len) (= 1)) 339 | (-> orelseast (first) (type) (= ast.If))) 340 | `(cond 341 | [~#e #k test 342 | ~(do-if-long #l #k body)] 343 | [~#e (. (first orelseast) test) 344 | ~(do-if-long #l (. (first orelseast) body))] 345 | [True 346 | ~(do-if-long #l (. (first orelseast) orelse))])] 347 | [orelse 348 | `(if ~#e #k test 349 | (do 350 | ~@#A #l #k body) 351 | (do 352 | ~@#A orelse))] 353 | [True 354 | `(when ~#e #k test 355 | ~@#A #l #k body)])) 356 | 357 | (defsyntax With [items body lineno col_offset] 358 | "Args: 359 | items (withitem*) [list] 360 | body (stmt*) [list] 361 | lineno (int) 362 | col_offset (int)" 363 | (defn nest-with [l] 364 | (if (empty? l) 365 | #l #k body 366 | `[(with [~@#A (first l)] 367 | ~@#A (nest-with (list (drop 1 l))))])) 368 | (first (nest-with #l #k items))) 369 | 370 | (defsyntax AsyncWith [items body lineno col_offset] 371 | "Args: 372 | items (withitem*) [list] 373 | body (stmt*) [list] 374 | lineno (int) 375 | col_offset (int)" 376 | None) 377 | 378 | (defsyntax Raise [exc cause lineno col_offset] 379 | "Args: 380 | exc (expr?) [optional] 381 | cause (expr?) [optional] 382 | lineno (int) 383 | col_offset (int)" 384 | ; TODO: cause 385 | (setv exc #e #k exc) 386 | `(raise ~@#A (if exc [exc]))) 387 | 388 | (defsyntax Try [body handlers orelse finalbody lineno col_offset] 389 | "Args: 390 | body (stmt*) [list] 391 | handlers (excepthandler*) [list] 392 | orelse (stmt*) [list] 393 | finalbody (stmt*) [list] 394 | lineno (int) 395 | col_offset (int)" 396 | (setv orelse #l #k orelse 397 | finalbody #l #k finalbody) 398 | `(try 399 | ~(do-if-long #l #k body) 400 | (except [e Py2HyReturnException] 401 | (raise e)) 402 | ~@#A #l #k handlers 403 | ~@#A (if (< 0 (len orelse)) 404 | `[(else 405 | ~@#A orelse)]) 406 | ~@#A (if (< 0 (len finalbody)) 407 | `[(finally 408 | ~@#A finalbody)]))) 409 | 410 | (defsyntax Assert [test msg lineno col_offset] 411 | "Args: 412 | test (expr) 413 | msg (expr?) [optional] 414 | lineno (int) 415 | col_offset (int)" 416 | (setv msg #e #k msg) 417 | `(assert ~#e #k test ~@#A (if msg [msg]))) 418 | 419 | (defsyntax Import [names lineno col_offset] 420 | "Args: 421 | names (alias*) [list] 422 | lineno (int) 423 | col_offset (int)" 424 | `(import ~@#A #l #k names)) 425 | 426 | (defsyntax ImportFrom [module names level lineno col_offset] 427 | "Args: 428 | module (identifier?) [optional] 429 | names (alias*) [list] 430 | level (int?) [optional] 431 | lineno (int) 432 | col_offset (int)" 433 | `(import [~#e #k module [~@#A (reduce add #l #k names)]])) 434 | 435 | (defsyntax Global [names lineno col_offset] 436 | "Args: 437 | names (identifier*) [list] 438 | lineno (int) 439 | col_offset (int)" 440 | `(global ~@#A (map py2hy_mangle_identifier #l #k names))) 441 | 442 | (defsyntax Nonlocal [names lineno col_offset] 443 | "Args: 444 | names (identifier*) [list] 445 | lineno (int) 446 | col_offset (int)" 447 | `(nonlocal ~@#A (map py2hy_mangle_identifier #l #k names))) 448 | 449 | (defsyntax Expr [value lineno col_offset] 450 | "Args: 451 | value (expr) 452 | lineno (int) 453 | col_offset (int)" 454 | #e #k value) 455 | 456 | (defsyntax Pass [lineno col_offset] 457 | "Args: 458 | lineno (int) 459 | col_offset (int)" 460 | `(do)) 461 | 462 | (defsyntax Break [lineno col_offset] 463 | "Args: 464 | lineno (int) 465 | col_offset (int)" 466 | `(break)) 467 | 468 | (defsyntax Continue [lineno col_offset] 469 | "Args: 470 | lineno (int) 471 | col_offset (int)" 472 | `(continue)) 473 | 474 | 475 | ;;;============================================================================= 476 | ;;; Classgroup `expr` 477 | ;;;============================================================================= 478 | (defsyntax BoolOp [op values lineno col_offset] 479 | "Args: 480 | op (boolop) 481 | values (expr*) [list] 482 | lineno (int) 483 | col_offset (int)" 484 | `(~#e #k op ~@#A #l #k values)) 485 | 486 | (defsyntax BinOp [left op right lineno col_offset] 487 | "Args: 488 | left (expr) 489 | op (operator) 490 | right (expr) 491 | lineno (int) 492 | col_offset (int)" 493 | `(~#e #k op ~#e #k left ~#e #k right)) 494 | 495 | (defsyntax UnaryOp [op operand lineno col_offset] 496 | "Args: 497 | op (unaryop) 498 | operand (expr) 499 | lineno (int) 500 | col_offset (int)" 501 | `(~#e #k op ~#e #k operand)) 502 | 503 | (defsyntax Lambda [args body lineno col_offset] 504 | "Args: 505 | args (arguments) 506 | body (expr) 507 | lineno (int) 508 | col_offset (int)" 509 | `(fn ~#e #k args ~#e #k body)) 510 | 511 | (defsyntax IfExp [test body orelse lineno col_offset] 512 | "Args: 513 | test (expr) 514 | body (expr) 515 | orelse (expr) 516 | lineno (int) 517 | col_offset (int)" 518 | `(if ~#e #k test 519 | ~#e #k body 520 | ~#e #k orelse)) 521 | 522 | (defsyntax Dict [keys values lineno col_offset] 523 | "Args: 524 | keys (expr*) [list] 525 | values (expr*) [list] 526 | lineno (int) 527 | col_offset (int)" 528 | `{~@#A (interleave #l #k keys #l #k values)}) 529 | 530 | (defsyntax Set [elts lineno col_offset] 531 | "Args: 532 | elts (expr*) [list] 533 | lineno (int) 534 | col_offset (int)" 535 | `(set ~@#A #l #k elts)) 536 | 537 | (defsyntax ListComp [elt generators lineno col_offset] 538 | "Args: 539 | elt (expr) 540 | generators (comprehension*) [list] 541 | lineno (int) 542 | col_offset (int)" 543 | `(list-comp ~#e #k elt 544 | ~@#A (reduce (fn [x y] (+ x y)) #l #k generators))) 545 | 546 | (defsyntax SetComp [elt generators lineno col_offset] 547 | "Args: 548 | elt (expr) 549 | generators (comprehension*) [list] 550 | lineno (int) 551 | col_offset (int)" 552 | `(set-comp ~#e #k elt 553 | ~@#A (reduce (fn [x y] (+ x y)) #l #k generators))) 554 | 555 | (defsyntax DictComp [key value generators lineno col_offset] 556 | "Args: 557 | key (expr) 558 | value (expr) 559 | generators (comprehension*) [list] 560 | lineno (int) 561 | col_offset (int)" 562 | `(dict-comp ~#e #k key 563 | ~#e #k value 564 | ~@#A (reduce (fn [x y] (+ x y)) #l #k generators))) 565 | 566 | (defsyntax GeneratorExp [elt generators lineno col_offset] 567 | "Args: 568 | elt (expr) 569 | generators (comprehension*) [list] 570 | lineno (int) 571 | col_offset (int)" 572 | `(genexpr ~#e #k elt 573 | ~@#A (reduce (fn [x y] (+ x y)) #l #k generators))) 574 | 575 | (defsyntax Await [value lineno col_offset] 576 | "Args: 577 | value (expr) 578 | lineno (int) 579 | col_offset (int)" 580 | None) 581 | 582 | (defsyntax Yield [value lineno col_offset] 583 | "Args: 584 | value (expr?) [optional] 585 | lineno (int) 586 | col_offset (int)" 587 | (setv value #e #k value) 588 | `(yield ~@#A (if value [value]))) 589 | 590 | (defsyntax YieldFrom [value lineno col_offset] 591 | "Args: 592 | value (expr) 593 | lineno (int) 594 | col_offset (int)" 595 | `(yield_from ~@#A (if value [value]))) 596 | 597 | (defsyntax Compare [left ops comparators lineno col_offset] 598 | "Args: 599 | left (expr) 600 | ops (cmpop*) [list] 601 | comparators (expr*) [list] 602 | lineno (int) 603 | col_offset (int)" 604 | (setv ops #l #k ops 605 | comparators #l #k comparators 606 | left #e #k left) 607 | (setv resultlist 608 | (map 609 | (fn [x] 610 | `(~(first x) ~(second x) ~(get x 2))) 611 | (zip ops 612 | (+ [left] comparators) 613 | comparators))) 614 | (if (< 1 (len comparators)) 615 | `(and ~@#A resultlist) 616 | (first resultlist))) 617 | 618 | (defsyntax Call [func args keywords lineno col_offset] 619 | "Args: 620 | func (expr) 621 | args (expr*) [list] 622 | keywords (keyword*) [list] 623 | lineno (int) 624 | col_offset (int)" 625 | (setv keywords #l #k keywords) 626 | `(~#e #k func 627 | ~@#A #l #k args 628 | ~@#A (if keywords 629 | (reduce (fn [x y] (if (first y) 630 | (+ x y) 631 | `[(~'unpack_mapping ~(second y))])) 632 | (map (fn [l] [(if (get l 0) 633 | (hy.models.HyKeyword (+ ":" (get l 0))) 634 | None) (get l 1)]) 635 | #l #k keywords) 636 | [])))) 637 | 638 | (defsyntax Num [n lineno col_offset] 639 | "Args: 640 | n (object) 641 | lineno (int) 642 | col_offset (int)" 643 | #e #k n) 644 | 645 | (defsyntax Str [s lineno col_offset] 646 | "Args: 647 | s (string) 648 | lineno (int) 649 | col_offset (int)" 650 | (hy.models.HyString #e #k s)) 651 | 652 | (defsyntax FormattedValue [value conversion format_spec lineno col_offset] 653 | "Args: 654 | value (expr) 655 | conversion (int?) [optional] 656 | format_spec (expr?) [optional] 657 | lineno (int) 658 | col_offset (int)" 659 | None) 660 | 661 | (defsyntax JoinedStr [values lineno col_offset] 662 | "Args: 663 | values (expr*) [list] 664 | lineno (int) 665 | col_offset (int)" 666 | #e #k values) 667 | 668 | (defsyntax Bytes [s lineno col_offset] 669 | "Args: 670 | s (bytes) 671 | lineno (int) 672 | col_offset (int)" 673 | `(hy.models.HyBytes ~#e #k s)) 674 | 675 | (defsyntax NameConstant [value lineno col_offset] 676 | "Args: 677 | value (Constant) 678 | lineno (int) 679 | col_offset (int)" 680 | #e #k value) 681 | 682 | (defsyntax Ellipsis [lineno col_offset] 683 | "Args: 684 | lineno (int) 685 | col_offset (int)" 686 | None) 687 | 688 | (defsyntax Constant [value lineno col_offset] 689 | "Args: 690 | value (constant) 691 | lineno (int) 692 | col_offset (int)" 693 | #e #k value) 694 | 695 | (defsyntax Attribute [value attr ctx lineno col_offset] 696 | "Args: 697 | value (expr) 698 | attr (identifier) 699 | ctx (expr_context) 700 | lineno (int) 701 | col_offset (int)" 702 | ; (setv s (gensym) 703 | ; a (hy.models.HySymbol (+ s "." #e #k attr))) 704 | ; (print (type a)) 705 | ; (print a) 706 | ; `(do 707 | ; (setv ~s ~#e #k value) 708 | ; ~a) 709 | (setv value #e #k value) 710 | (cond 711 | [ 712 | ; False 713 | (= hy.models.HySymbol (type value)) 714 | (hy.models.HySymbol (+ (str value) "." #k attr))] 715 | [True 716 | `(. ~#e #k value ~#e #k attr)])) 717 | 718 | (defsyntax Subscript [value slice ctx lineno col_offset] 719 | "Args: 720 | value (expr) 721 | slice (slice) 722 | ctx (expr_context) 723 | lineno (int) 724 | col_offset (int)" 725 | `(get ~#e #k value ~#e #k slice)) 726 | 727 | (defsyntax Starred [value ctx lineno col_offset] 728 | "Args: 729 | value (expr) 730 | ctx (expr_context) 731 | lineno (int) 732 | col_offset (int)" 733 | `(~'unpack_iterable ~#e #k value)) 734 | 735 | (defsyntax Name [id ctx lineno col_offset] 736 | "Args: 737 | id (identifier) 738 | ctx (expr_context) 739 | lineno (int) 740 | col_offset (int)" 741 | (py2hy_mangle_identifier #e #k id)) 742 | 743 | (defsyntax List [elts ctx lineno col_offset] 744 | "Args: 745 | elts (expr*) [list] 746 | ctx (expr_context) 747 | lineno (int) 748 | col_offset (int)" 749 | `[~@#A #l #k elts]) 750 | 751 | (defsyntax Tuple [elts ctx lineno col_offset] 752 | "Args: 753 | elts (expr*) [list] 754 | ctx (expr_context) 755 | lineno (int) 756 | col_offset (int)" 757 | `(, ~@#A #l #k elts)) 758 | 759 | 760 | ;;;============================================================================= 761 | ;;; Classgroup `expr_context` 762 | ;;;============================================================================= 763 | (defsyntax Load [] 764 | "Constant expression") 765 | 766 | (defsyntax Store [] 767 | "Constant expression") 768 | 769 | (defsyntax Del [] 770 | "Constant expression") 771 | 772 | (defsyntax AugLoad [] 773 | "Constant expression") 774 | 775 | (defsyntax AugStore [] 776 | "Constant expression") 777 | 778 | (defsyntax Param [] 779 | "Constant expression") 780 | 781 | 782 | ;;;============================================================================= 783 | ;;; Classgroup `slice` 784 | ;;;============================================================================= 785 | (defsyntax Slice [lower upper step] 786 | "Args: 787 | lower (expr?) [optional] 788 | upper (expr?) [optional] 789 | step (expr?) [optional]" 790 | `(slice ~#e #k lower ~#e #k upper ~#e #k step)) 791 | 792 | (defsyntax ExtSlice [dims] 793 | "Args: 794 | dims (slice*) [list]" 795 | None) 796 | 797 | (defsyntax Index [value] 798 | "Args: 799 | value (expr)" 800 | #e #k value) 801 | 802 | 803 | ;;;============================================================================= 804 | ;;; Constant expressions 805 | ;;;============================================================================= 806 | (defconstantexpression 807 | ;; Classgroup `boolop` 808 | {And `and 809 | Or `or} 810 | ;; Classgroup `operator` 811 | {Add `+ 812 | Sub `- 813 | Mult `* 814 | MatMult `@ 815 | Div `/ 816 | Mod `% 817 | Pow `** 818 | LShift `<< 819 | RShift `>> 820 | BitOr `| 821 | BitXor `^ 822 | BitAnd `& 823 | FloorDiv `//} 824 | ;; Classgroup `unaryop` 825 | {Invert `~ 826 | Not `not 827 | UAdd `+ 828 | USub `-} 829 | ;; Classgroup `cmpop` 830 | {Eq `= 831 | NotEq `!= 832 | Lt `< 833 | LtE `<= 834 | Gt `> 835 | GtE `>= 836 | Is `is 837 | IsNot `is-not 838 | In `in 839 | NotIn `not-in}) 840 | 841 | ;;;============================================================================= 842 | ;;; Datatype `comprehension` 843 | ;;;============================================================================= 844 | (defsyntax comprehension [target iter ifs is_async] 845 | "Args: 846 | target (expr) 847 | iter (expr) 848 | ifs (expr*) [list] 849 | is_async (int)" 850 | (setv target #e #k target 851 | ifs #l #k ifs) 852 | `[[~@#A (if (= ', (first target)) 853 | [`[~@#A (rest target)]] 854 | [target]) 855 | ~#e #k iter] 856 | ~@#A (if (< 0 (len ifs)) 857 | `[(and ~@#A ifs)])]) 858 | 859 | 860 | ;;;============================================================================= 861 | ;;; Classgroup `excepthandler` 862 | ;;;============================================================================= 863 | (defsyntax ExceptHandler [type name body lineno col_offset] 864 | "Args: 865 | type (expr?) [optional] 866 | name (identifier?) [optional] 867 | body (stmt*) [list] 868 | lineno (int) 869 | col_offset (int)" 870 | (setv e_name (py2hy_mangle_identifier #e #k name) 871 | e_type #e #k type) 872 | `(except [~@#A (if e_name [e_name]) 873 | ~@#A (cond 874 | [(is None e_type) None] 875 | [(= ', (first e_type)) [`[~@#A (rest e_type)]]] 876 | [True [e_type]])] 877 | ~@#A #l #k body)) 878 | 879 | 880 | ;;;============================================================================= 881 | ;;; Datatype `arguments` 882 | ;;;============================================================================= 883 | (defsyntax arguments [args vararg kwonlyargs kw_defaults kwarg defaults] 884 | "Args: 885 | args (arg*) [list] 886 | vararg (arg?) [optional] 887 | kwonlyargs (arg*) [list] 888 | kw_defaults (expr*) [list] 889 | kwarg (arg?) [optional] 890 | defaults (expr*) [list]" 891 | ; TODO: kwonlyargs 892 | (setv args #l #k args 893 | vararg #e #k vararg 894 | kwarg #e #k kwarg 895 | defaults #l #k defaults 896 | kwonlyargs #l #k kwonlyargs 897 | kw_defaults #l #k kw_defaults) 898 | (defn take-last [n l] 899 | (defn len [iter] 900 | (sum (list-comp 1 [x iter]))) 901 | (drop (- (len l) n) l)) 902 | `[~@#A (drop-last (len defaults) args) 903 | ~@#A (if defaults 904 | `[&optional 905 | ~@#A (list-comp `[~x ~y] 906 | [[x y] (zip (take-last (len defaults) args) 907 | defaults)])]) 908 | ~@#A (if kwonlyargs 909 | `[&kwonly 910 | ~@#A (drop-last (len kw_defaults) kwonlyargs) 911 | ~@#A (list-comp `[~x ~y] 912 | [[x y] (zip (take-last (len kw_defaults) kwonlyargs) 913 | kw_defaults)])]) 914 | ~@#A (if kwarg `[&kwargs ~kwarg]) 915 | ~@#A (if vararg `[&rest ~vararg])]) 916 | 917 | 918 | ;;;============================================================================= 919 | ;;; Datatype `arg` 920 | ;;;============================================================================= 921 | (defsyntax arg [arg annotation lineno col_offset] 922 | "Args: 923 | arg (identifier) 924 | annotation (expr?) [optional] 925 | lineno (int) 926 | col_offset (int)" 927 | ; TODO: use `annotation` 928 | `~(py2hy_mangle_identifier #e #k arg)) 929 | 930 | 931 | ;;;============================================================================= 932 | ;;; Datatype `keyword` 933 | ;;;============================================================================= 934 | (defsyntax keyword [arg value] 935 | "Args: 936 | arg (identifier?) [optional] 937 | value (expr)" 938 | ; The python code 939 | ; 940 | ; f(*args, **kwargs) 941 | ; 942 | ; Becomes compiled to the AST 943 | ; 944 | ; Call(func=Name(id='f', ctx=Load()), 945 | ; args=[Starred(value=Name(id='args', ctx=Load()), ctx=Load())], 946 | ; keywords=[keyword(arg=None, value=Name(id='kwargs', ctx=Load()))]) 947 | `(~(py2hy_mangle_identifier #e #k arg) ~#e #k value)) 948 | 949 | 950 | ;;;============================================================================= 951 | ;;; Datatype `alias` 952 | ;;;============================================================================= 953 | (defsyntax alias [name asname] 954 | "Args: 955 | name (identifier) 956 | asname (identifier?) [optional]" 957 | (if #e #k asname 958 | `[~#e #k name :as ~#e #k asname] 959 | `[~#e #k name])) 960 | 961 | 962 | ;;;============================================================================= 963 | ;;; Datatype `withitem` 964 | ;;;============================================================================= 965 | (defsyntax withitem [context_expr optional_vars] 966 | "Args: 967 | context_expr (expr) 968 | optional_vars (expr?) [optional]" 969 | (setv optional_vars #e #k optional_vars) 970 | `(~@#A (if optional_vars [optional_vars]) 971 | ~#e #k context_expr)) 972 | 973 | (defn py2hy_print [ast] 974 | (print (-> ast (.expand) (prettyprinter)))) 975 | 976 | (defn py2hy_file [filepath &optional [dumpast False]] 977 | (setv astobj (-> filepath (open "r") (.read) (ast.parse))) 978 | (if dumpast 979 | (do 980 | (print (ast.dump codeobj))) 981 | (do 982 | (py2hy_print astobj)))) 983 | 984 | (defn py2hy [ast] 985 | (ast.expand)) 986 | 987 | (defn main [] 988 | (setv parser (argparse.ArgumentParser)) 989 | (parser.add_argument "filepath") 990 | (parser.add_argument "--ast" :action "store_true") 991 | (setv args (parser.parse_args)) 992 | (py2hy_file args.filepath args.ast)) 993 | 994 | (if (= __name__ "__main__") 995 | (main)) --------------------------------------------------------------------------------