Merge branch 'master' into pr/450
This commit is contained in:
commit
331165da32
2
AUTHORS
2
AUTHORS
@ -35,3 +35,5 @@
|
||||
* Thom Neale <twneale@gmail.com>
|
||||
* Tuukka Turto <tuukka.turto@oktaeder.net>
|
||||
* Vasudev Kamath <kamathvasudev@gmail.com>
|
||||
* Yuval Langer <yuval.langer@gmail.com>
|
||||
* Fatih Kadir Akın <fka@fatihak.in>
|
||||
|
45
bin/hy2py
45
bin/hy2py
@ -1,24 +1,39 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
from hy.importer import (import_file_to_ast, import_file_to_hst)
|
||||
|
||||
from hy.importer import (import_file_to_ast, import_file_to_module,
|
||||
import_file_to_hst)
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import astor.codegen
|
||||
import sys
|
||||
|
||||
module_name = "<STDIN>"
|
||||
|
||||
hst = import_file_to_hst(sys.argv[1])
|
||||
print(str(hst).encode("utf-8"))
|
||||
print("")
|
||||
print("")
|
||||
_ast = import_file_to_ast(sys.argv[1], module_name)
|
||||
print("")
|
||||
print("")
|
||||
print(astor.dump(_ast).encode("utf-8"))
|
||||
print("")
|
||||
print("")
|
||||
print(astor.codegen.to_source(_ast).encode("utf-8"))
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="hy2py",
|
||||
usage="%(prog)s [options] FILE",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument("--with-source", "-s", action="store_true",
|
||||
help="Show the parsed source structure")
|
||||
parser.add_argument("--with-ast", "-a", action="store_true",
|
||||
help="Show the generated AST")
|
||||
parser.add_argument("--without-python", "-np", action="store_true",
|
||||
help="Do not show the python code generated from the AST")
|
||||
parser.add_argument('args', nargs=argparse.REMAINDER, help=argparse.SUPPRESS)
|
||||
|
||||
import_file_to_module(module_name, sys.argv[1])
|
||||
options = parser.parse_args(sys.argv[1:])
|
||||
|
||||
if options.with_source:
|
||||
hst = import_file_to_hst(options.args[0])
|
||||
print(str(hst).encode("utf-8"))
|
||||
print()
|
||||
print()
|
||||
|
||||
_ast = import_file_to_ast(options.args[0], module_name)
|
||||
if options.with_ast:
|
||||
print(astor.dump(_ast).encode("utf-8"))
|
||||
print()
|
||||
print()
|
||||
|
||||
if not options.without_python:
|
||||
print(astor.codegen.to_source(_ast).encode("utf-8"))
|
||||
|
BIN
docs/_static/cuddles-transparent-small.png
vendored
Normal file
BIN
docs/_static/cuddles-transparent-small.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
BIN
docs/_static/cuddles-transparent.png
vendored
Normal file
BIN
docs/_static/cuddles-transparent.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
@ -97,7 +97,7 @@ core team. Additional review is clearly welcome, but we need a minimum of
|
||||
2 signoffs for any change.
|
||||
|
||||
If a core member is sending in a PR, please find 2 core members that don't
|
||||
include them PR submitter. The idea here is that one can work with the PR
|
||||
include the PR submitter. The idea here is that one can work with the PR
|
||||
author, and a second acks the entire change set.
|
||||
|
||||
If the change is adding documentation, feel free to just merge after one
|
||||
|
@ -36,7 +36,7 @@ languages.
|
||||
Builtins
|
||||
========
|
||||
|
||||
Hy features a number special forms that are used to help generate
|
||||
Hy features a number of special forms that are used to help generate
|
||||
correct Python AST. The following are "special" forms, which may have
|
||||
behavior that's slightly unexpected in some situations.
|
||||
|
||||
@ -89,7 +89,7 @@ The following code demonstrates this:
|
||||
---
|
||||
|
||||
`->>` or `threading tail macro` is similar to `threading macro` but instead of
|
||||
inserting each expression into the next expression’s first argument place it
|
||||
inserting each expression into the next expression’s first argument place, it
|
||||
appends it as the last argument. The following code demonstrates this:
|
||||
|
||||
.. code-block:: clj
|
||||
@ -283,7 +283,7 @@ do / progn
|
||||
the `do` and `progn` forms are used to evaluate each of their arguments and
|
||||
return the last one. Return values from every other than the last argument are
|
||||
discarded. It can be used in `lambda` or `list-comp` to perform more complex
|
||||
logic as show by one of the examples.
|
||||
logic as shown by one of the examples.
|
||||
|
||||
Some example usage:
|
||||
|
||||
@ -430,7 +430,7 @@ defmacro
|
||||
`defmacro` is used to define macros. The general format is
|
||||
`(defmacro [parameters] expr)`.
|
||||
|
||||
Following example defines a macro that can be used to swap order of elements in
|
||||
The following example defines a macro that can be used to swap order of elements in
|
||||
code, allowing the user to write code in infix notation, where operator is in
|
||||
between the operands.
|
||||
|
||||
@ -1169,7 +1169,7 @@ yield
|
||||
The generator is iterable and therefore can be used in loops, list
|
||||
comprehensions and other similar constructs.
|
||||
|
||||
Especially the second example shows how generators can be used to generate
|
||||
The function random-numbers shows how generators can be used to generate
|
||||
infinite series without consuming infinite amount of memory.
|
||||
|
||||
.. code-block:: clj
|
||||
|
@ -9,7 +9,7 @@ Core Functions
|
||||
.. _is-coll-fn:
|
||||
|
||||
coll?
|
||||
----
|
||||
-----
|
||||
|
||||
.. versionadded:: 0.9.13
|
||||
|
||||
|
@ -24,19 +24,28 @@ Syntax
|
||||
=> #^1+2+3+4+3+2
|
||||
1+2+3+4+3+2
|
||||
|
||||
Hy has no literal for tuples. Lets say you dislike `(, ...)` and want something
|
||||
else. This is a problem reader macros are able to solve in a neat way.
|
||||
|
||||
::
|
||||
|
||||
=> (defreader t [expr] `(, ~@expr))
|
||||
=> #t(1 2 3)
|
||||
(1, 2, 3)
|
||||
|
||||
You could even do like clojure, and have a literal for regular expressions!
|
||||
|
||||
::
|
||||
|
||||
=> (import re)
|
||||
=> (defreader r [expr] `(re.compile ~expr))
|
||||
=> #r".*"
|
||||
<_sre.SRE_Pattern object at 0xcv7713ph15#>
|
||||
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
Hy uses ``defreader`` to define the reader symbol, and ``#`` as the dispatch
|
||||
character. ``#`` expands into ``(dispatch_reader_macro ...)`` where the symbol
|
||||
and expression is quoted, and then passed along to the correct function::
|
||||
|
||||
=> (defreader ^ ...)
|
||||
=> #^()
|
||||
;=> (dispatch_reader_macro '^ '())
|
||||
|
||||
|
||||
``defreader`` takes a single character as symbol name for the reader macro,
|
||||
anything longer will return an error. Implementation wise, ``defreader``
|
||||
expands into a lambda covered with a decorator, this decorater saves the
|
||||
@ -47,14 +56,17 @@ lambda in a dict with its module name and symbol.
|
||||
=> (defreader ^ [expr] (print expr))
|
||||
;=> (with_decorator (hy.macros.reader ^) (fn [expr] (print expr)))
|
||||
|
||||
|
||||
Anything passed along is quoted, thus given to the function defined.
|
||||
``#`` expands into ``(dispatch_reader_macro ...)`` where the symbol
|
||||
and expression is passed to the correct function.
|
||||
|
||||
::
|
||||
|
||||
=> #^()
|
||||
;=> (dispatch_reader_macro ^ ())
|
||||
=> #^"Hello"
|
||||
"Hello"
|
||||
|
||||
|
||||
.. warning::
|
||||
Because of a limitation in Hy's lexer and parser, reader macros can't
|
||||
redefine defined syntax such as ``()[]{}``. This will most likely be
|
||||
|
@ -2,20 +2,20 @@
|
||||
Quickstart
|
||||
==========
|
||||
|
||||
.. image:: _static/cuddles.png
|
||||
.. image:: _static/cuddles-transparent-small.png
|
||||
:alt: Karen Rustard's Cuddles
|
||||
|
||||
(thanks to Karen Rustad for Cuddles!)
|
||||
(Thanks to Karen Rustad for Cuddles!)
|
||||
|
||||
|
||||
HOW TO GET HY REAL FAST:
|
||||
**HOW TO GET HY REAL FAST**:
|
||||
|
||||
1. create a `Python virtual environment
|
||||
1. Create a `Virtual Python Environment
|
||||
<https://pypi.python.org/pypi/virtualenv>`_
|
||||
2. activate your Python virtual environment
|
||||
3. ``pip install hy``
|
||||
4. start a REPL with ``hy``
|
||||
5. type stuff in the REPL::
|
||||
2. Activate your Virtual Python Environment
|
||||
3. Install `hy from PyPI <https://pypi.python.org/pypi/hy>`_ with ``pip install hy``
|
||||
4. Start a REPL with ``hy``
|
||||
5. Type stuff in the REPL::
|
||||
|
||||
=> (print "Hy!")
|
||||
Hy!
|
||||
@ -25,20 +25,19 @@ HOW TO GET HY REAL FAST:
|
||||
|
||||
etc
|
||||
|
||||
6. hit CTRL-D when you're done
|
||||
6. Hit CTRL-D when you're done
|
||||
|
||||
OMG! That's amazing! I want to write a hy program.
|
||||
|
||||
7. open up an elite programming editor
|
||||
8. type::
|
||||
7. Open up an elite programming editor and type::
|
||||
|
||||
(print "i was going to code in python syntax, but then i got hy")
|
||||
(print "I was going to code in python syntax, but then I got hy.")
|
||||
|
||||
9. save as ``test_program_of_awesome.hy``
|
||||
10. run::
|
||||
8. Save as ``awesome.hy``
|
||||
9. And run your first Hy program::
|
||||
|
||||
hy test_program_of_awesome.hy
|
||||
hy awesome.hy
|
||||
|
||||
11. take a deep breath so as to not hyperventilate
|
||||
12. smile villainously and sneak off to your hydeaway and do
|
||||
10. Take a deep breath so as to not hyperventilate
|
||||
11. Smile villainously and sneak off to your hydeaway and do
|
||||
unspeakable things
|
||||
|
@ -406,7 +406,7 @@ The same thing in Hy::
|
||||
...
|
||||
[3, 2, 1, 4]
|
||||
|
||||
See how we use kwapply to handle the fancy pssing? :)
|
||||
See how we use kwapply to handle the fancy passing? :)
|
||||
|
||||
There's also a dictionary-style keyword arguments construction that
|
||||
looks like:
|
||||
|
27
eg/flask/meth_example.hy
Normal file
27
eg/flask/meth_example.hy
Normal file
@ -0,0 +1,27 @@
|
||||
;;; Simple Flask application
|
||||
;;;
|
||||
;;; Requires to have Flask installed
|
||||
;;;
|
||||
;;; You can test it via:
|
||||
;;;
|
||||
;;; $ curl 127.0.0.1:5151
|
||||
;;; $ curl -X POST 127.0.0.1:5151/post
|
||||
;;; $ curl -X POST 127.0.0.1:5151/both
|
||||
;;; $ curl 127.0.0.1:5151/both
|
||||
|
||||
(import [flask [Flask]])
|
||||
|
||||
(require hy.contrib.meth)
|
||||
|
||||
(setv app (Flask "__main__"))
|
||||
|
||||
(route get-index "/" []
|
||||
(str "Hy world!"))
|
||||
|
||||
(post-route post-index "/post" []
|
||||
(str "Hy post world!"))
|
||||
|
||||
(route-with-methods both-index "/both" ["GET" "POST"] []
|
||||
(str "Hy to both worlds!"))
|
||||
|
||||
(apply app.run [] {"port" 5151})
|
@ -38,6 +38,7 @@ except ImportError:
|
||||
(x >> 24) & 0xff]))
|
||||
import sys
|
||||
|
||||
PY27 = sys.version_info >= (2, 7)
|
||||
PY3 = sys.version_info[0] >= 3
|
||||
PY33 = sys.version_info >= (3, 3)
|
||||
PY34 = sys.version_info >= (3, 4)
|
||||
|
@ -214,8 +214,8 @@ def run_repl(hr=None, spy=False):
|
||||
return 0
|
||||
|
||||
|
||||
def run_icommand(source):
|
||||
hr = HyREPL()
|
||||
def run_icommand(source, spy=False):
|
||||
hr = HyREPL(spy)
|
||||
hr.runsource(source, filename='<input>', symbol='single')
|
||||
return run_repl(hr)
|
||||
|
||||
@ -270,7 +270,7 @@ def cmdline_handler(scriptname, argv):
|
||||
|
||||
if options.icommand:
|
||||
# User did "hy -i ..."
|
||||
return run_icommand(options.icommand)
|
||||
return run_icommand(options.icommand, spy=options.spy)
|
||||
|
||||
if options.args:
|
||||
if options.args[0] == "-":
|
||||
|
134
hy/compiler.py
134
hy/compiler.py
@ -38,8 +38,8 @@ from hy.models.dict import HyDict
|
||||
from hy.errors import HyCompileError, HyTypeError
|
||||
|
||||
import hy.macros
|
||||
from hy.macros import require, macroexpand
|
||||
from hy._compat import str_type, long_type, PY33, PY3, PY34
|
||||
from hy._compat import str_type, long_type, PY27, PY33, PY3, PY34
|
||||
from hy.macros import require, macroexpand, reader_macroexpand
|
||||
import hy.importer
|
||||
|
||||
import traceback
|
||||
@ -1265,41 +1265,114 @@ class HyASTCompiler(object):
|
||||
ctx=ast.Load())
|
||||
return ret
|
||||
|
||||
def _compile_generator_iterables(self, trailers):
|
||||
"""Helper to compile the "trailing" parts of comprehensions:
|
||||
generators and conditions"""
|
||||
|
||||
generators = trailers.pop(0)
|
||||
|
||||
cond = self.compile(trailers.pop(0)) if trailers != [] else Result()
|
||||
|
||||
gen_it = iter(generators)
|
||||
paired_gens = zip(gen_it, gen_it)
|
||||
|
||||
gen_res = Result()
|
||||
gen = []
|
||||
for target, iterable in paired_gens:
|
||||
comp_target = self.compile(target)
|
||||
target = self._storeize(comp_target)
|
||||
gen_res += self.compile(iterable)
|
||||
gen.append(ast.comprehension(
|
||||
target=target,
|
||||
iter=gen_res.force_expr,
|
||||
ifs=[]))
|
||||
|
||||
if cond.expr:
|
||||
gen[-1].ifs.append(cond.expr)
|
||||
|
||||
return gen_res + cond, gen
|
||||
|
||||
@builds("list_comp")
|
||||
@checkargs(min=2, max=3)
|
||||
def compile_list_comprehension(self, expr):
|
||||
# (list-comp expr (target iter) cond?)
|
||||
expr.pop(0)
|
||||
expression = expr.pop(0)
|
||||
tar_it = iter(expr.pop(0))
|
||||
targets = zip(tar_it, tar_it)
|
||||
|
||||
cond = self.compile(expr.pop(0)) if expr != [] else Result()
|
||||
|
||||
generator_res = Result()
|
||||
generators = []
|
||||
for target, iterable in targets:
|
||||
comp_target = self.compile(target)
|
||||
target = self._storeize(comp_target)
|
||||
generator_res += self.compile(iterable)
|
||||
generators.append(ast.comprehension(
|
||||
target=target,
|
||||
iter=generator_res.force_expr,
|
||||
ifs=[]))
|
||||
|
||||
if cond.expr:
|
||||
generators[-1].ifs.append(cond.expr)
|
||||
gen_res, gen = self._compile_generator_iterables(expr)
|
||||
|
||||
compiled_expression = self.compile(expression)
|
||||
ret = compiled_expression + generator_res + cond
|
||||
ret = compiled_expression + gen_res
|
||||
ret += ast.ListComp(
|
||||
lineno=expr.start_line,
|
||||
col_offset=expr.start_column,
|
||||
elt=compiled_expression.force_expr,
|
||||
generators=generators)
|
||||
generators=gen)
|
||||
|
||||
return ret
|
||||
|
||||
@builds("set_comp")
|
||||
@checkargs(min=2, max=3)
|
||||
def compile_set_comprehension(self, expr):
|
||||
if PY27:
|
||||
ret = self.compile_list_comprehension(expr)
|
||||
expr = ret.expr
|
||||
ret.expr = ast.SetComp(
|
||||
lineno=expr.lineno,
|
||||
col_offset=expr.col_offset,
|
||||
elt=expr.elt,
|
||||
generators=expr.generators)
|
||||
|
||||
return ret
|
||||
|
||||
expr[0] = HySymbol("list_comp").replace(expr[0])
|
||||
expr = HyExpression([HySymbol("set"), expr]).replace(expr)
|
||||
return self.compile(expr)
|
||||
|
||||
@builds("dict_comp")
|
||||
@checkargs(min=3, max=4)
|
||||
def compile_dict_comprehension(self, expr):
|
||||
if PY27:
|
||||
expr.pop(0) # dict-comp
|
||||
key = expr.pop(0)
|
||||
value = expr.pop(0)
|
||||
|
||||
gen_res, gen = self._compile_generator_iterables(expr)
|
||||
|
||||
compiled_key = self.compile(key)
|
||||
compiled_value = self.compile(value)
|
||||
ret = compiled_key + compiled_value + gen_res
|
||||
ret += ast.DictComp(
|
||||
lineno=expr.start_line,
|
||||
col_offset=expr.start_column,
|
||||
key=compiled_key.force_expr,
|
||||
value=compiled_value.force_expr,
|
||||
generators=gen)
|
||||
|
||||
return ret
|
||||
|
||||
# In Python 2.6, turn (dict-comp key value [foo]) into
|
||||
# (dict (list-comp (, key value) [foo]))
|
||||
|
||||
expr[0] = HySymbol("list_comp").replace(expr[0])
|
||||
expr[1:3] = [HyExpression(
|
||||
[HySymbol(",")] +
|
||||
expr[1:3]
|
||||
).replace(expr[1])]
|
||||
expr = HyExpression([HySymbol("dict"), expr]).replace(expr)
|
||||
return self.compile(expr)
|
||||
|
||||
@builds("genexpr")
|
||||
def compile_genexpr(self, expr):
|
||||
ret = self.compile_list_comprehension(expr)
|
||||
expr = ret.expr
|
||||
ret.expr = ast.GeneratorExp(
|
||||
lineno=expr.lineno,
|
||||
col_offset=expr.col_offset,
|
||||
elt=expr.elt,
|
||||
generators=expr.generators)
|
||||
return ret
|
||||
|
||||
@builds("apply")
|
||||
@checkargs(min=1, max=3)
|
||||
def compile_apply_expression(self, expr):
|
||||
@ -1907,7 +1980,7 @@ class HyASTCompiler(object):
|
||||
return ret
|
||||
|
||||
@builds("defreader")
|
||||
@checkargs(min=2, max=3)
|
||||
@checkargs(min=2)
|
||||
def compile_reader(self, expression):
|
||||
expression.pop(0)
|
||||
name = expression.pop(0)
|
||||
@ -1929,6 +2002,23 @@ class HyASTCompiler(object):
|
||||
|
||||
return ret
|
||||
|
||||
@builds("dispatch_reader_macro")
|
||||
@checkargs(exact=2)
|
||||
def compile_dispatch_reader_macro(self, expression):
|
||||
expression.pop(0) # dispatch-reader-macro
|
||||
str_char = expression.pop(0)
|
||||
if not type(str_char) == HyString:
|
||||
raise HyTypeError(
|
||||
str_char,
|
||||
"Trying to expand a reader macro using `{0}' instead "
|
||||
"of string".format(type(str_char).__name__),
|
||||
)
|
||||
|
||||
module = self.module_name
|
||||
expr = reader_macroexpand(str_char, expression.pop(0), module)
|
||||
|
||||
return self.compile(expr)
|
||||
|
||||
@builds("eval_and_compile")
|
||||
def compile_eval_and_compile(self, expression):
|
||||
expression[0] = HySymbol("progn")
|
||||
|
@ -1,6 +1,7 @@
|
||||
;;; Hy tail-call optimization
|
||||
;;
|
||||
;; Copyright (c) 2014 Clinton Dreisbach <clinton@dreisbach.us>
|
||||
;; Copyright (c) 2014 Paul R. Tagliamonte <tag@pault.ag>
|
||||
;;
|
||||
;; Permission is hereby granted, free of charge, to any person obtaining a
|
||||
;; copy of this software and associated documentation files (the "Software"),
|
||||
@ -55,7 +56,24 @@
|
||||
(recursive-replace old-term new-term term)]
|
||||
[True term]) [term body])))
|
||||
|
||||
(defmacro loop [bindings &rest body]
|
||||
|
||||
(defmacro/g! fnr [signature &rest body]
|
||||
(let [[new-body (recursive-replace 'recur g!recur-fn body)]]
|
||||
`(do
|
||||
(import [hy.contrib.loop [--trampoline--]])
|
||||
(with-decorator
|
||||
--trampoline--
|
||||
(def ~g!recur-fn (fn [~@signature] ~@new-body)))
|
||||
~g!recur-fn)))
|
||||
|
||||
|
||||
(defmacro defnr [name lambda-list &rest body]
|
||||
(if (not (= (type name) HySymbol))
|
||||
(macro-error name "defnr takes a name as first argument"))
|
||||
`(setv ~name (fnr ~lambda-list ~@body)))
|
||||
|
||||
|
||||
(defmacro/g! loop [bindings &rest body]
|
||||
;; Use inside functions like so:
|
||||
;; (defun factorial [n]
|
||||
;; (loop [[i n]
|
||||
@ -67,13 +85,7 @@
|
||||
;; If recur is used in a non-tail-call position, None is returned, which
|
||||
;; causes chaos. Fixing this to detect if recur is in a tail-call position
|
||||
;; and erroring if not is a giant TODO.
|
||||
(with-gensyms [recur-fn]
|
||||
(let [[fnargs (map (fn [x] (first x)) bindings)]
|
||||
[initargs (map second bindings)]
|
||||
[new-body (recursive-replace 'recur recur-fn body)]]
|
||||
`(do
|
||||
(import [hy.contrib.loop [--trampoline--]])
|
||||
(def ~recur-fn
|
||||
(--trampoline-- (fn [~@fnargs]
|
||||
~@new-body)))
|
||||
(~recur-fn ~@initargs)))))
|
||||
(let [[fnargs (map (fn [x] (first x)) bindings)]
|
||||
[initargs (map second bindings)]]
|
||||
`(do (defnr ~g!recur-fn [~@fnargs] ~@body)
|
||||
(~g!recur-fn ~@initargs))))
|
||||
|
@ -1,5 +1,5 @@
|
||||
;;; Meth
|
||||
;; based on paultag's meth library to access a Flask based application
|
||||
;;; Hy on Meth
|
||||
;;; based on paultag's meth library to access a Flask based application
|
||||
|
||||
(defmacro route-with-methods [name path methods params &rest code]
|
||||
"Same as route but with an extra methods array to specify HTTP methods"
|
||||
@ -25,29 +25,3 @@
|
||||
(defmacro delete-route [name path params &rest code]
|
||||
"Delete request"
|
||||
`(route-with-methods ~name ~path ["DELETE"] ~params ~@code))
|
||||
|
||||
|
||||
;;; Simple example application
|
||||
;;; Requires to have Flask installed
|
||||
|
||||
;; (import [flask [Flask]])
|
||||
;; (setv app (Flask "__main__"))
|
||||
|
||||
;; (require hy.contrib.meth)
|
||||
|
||||
;; (print "setup / with GET")
|
||||
;; (route get-index "/" [] (str "Hy world!"))
|
||||
|
||||
;; (print "setup /post with POST")
|
||||
;; (post-route post-index "/post" [] (str "Hy post world!"))
|
||||
|
||||
;; (route-with-methods both-index "/both" []
|
||||
;; (str "Hy to both worlds!") ["GET" "POST"])
|
||||
|
||||
;; (.run app)
|
||||
|
||||
;;; Now you can do:
|
||||
;;; curl 127.0.0.1:5000
|
||||
;;; curl -X POST 127.0.0.1:5000/post
|
||||
;;; curl -X POST 127.0.0.1:5000/both
|
||||
;;; curl 127.0.0.1:5000/both
|
||||
|
@ -181,13 +181,3 @@
|
||||
(setv -args (cdr (car -args))))
|
||||
|
||||
`(apply ~-fun [~@-args] (dict (sum ~-okwargs [])))))
|
||||
|
||||
|
||||
(defmacro dispatch-reader-macro [char &rest body]
|
||||
"Dispatch a reader macro based on the character"
|
||||
(import [hy.macros])
|
||||
(setv str_char (get char 1))
|
||||
(if (not (in str_char hy.macros._hy_reader_chars))
|
||||
(raise (hy.compiler.HyTypeError char (.format "There is no reader macro with the character `{0}`" str_char))))
|
||||
`(do (import [hy.macros [_hy_reader]])
|
||||
((get (get _hy_reader --name--) ~char) ~(get body 0))))
|
||||
|
@ -154,8 +154,8 @@ def term_unquote_splice(p):
|
||||
@set_quote_boundaries
|
||||
def hash_reader(p):
|
||||
st = p[0].getstr()[1]
|
||||
str_object = HyExpression([HySymbol("quote"), HyString(st)])
|
||||
expr = HyExpression([HySymbol("quote"), p[1]])
|
||||
str_object = HyString(st)
|
||||
expr = p[1]
|
||||
return HyExpression([HySymbol("dispatch_reader_macro"), str_object, expr])
|
||||
|
||||
|
||||
@ -242,14 +242,19 @@ def t_identifier(p):
|
||||
if obj.startswith("&"):
|
||||
return HyLambdaListKeyword(obj)
|
||||
|
||||
if obj.startswith("*") and obj.endswith("*") and obj not in ("*", "**"):
|
||||
obj = obj[1:-1].upper()
|
||||
def mangle(p):
|
||||
if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
|
||||
p = p[1:-1].upper()
|
||||
|
||||
if "-" in obj and obj != "-":
|
||||
obj = obj.replace("-", "_")
|
||||
if "-" in p and p != "-":
|
||||
p = p.replace("-", "_")
|
||||
|
||||
if obj.endswith("?") and obj != "?":
|
||||
obj = "is_%s" % (obj[:-1])
|
||||
if p.endswith("?") and p != "?":
|
||||
p = "is_%s" % (p[:-1])
|
||||
|
||||
return p
|
||||
|
||||
obj = ".".join([mangle(part) for part in obj.split(".")])
|
||||
|
||||
return HySymbol(obj)
|
||||
|
||||
|
20
hy/macros.py
20
hy/macros.py
@ -43,7 +43,6 @@ EXTRA_MACROS = [
|
||||
|
||||
_hy_macros = defaultdict(dict)
|
||||
_hy_reader = defaultdict(dict)
|
||||
_hy_reader_chars = set()
|
||||
|
||||
|
||||
def macro(name):
|
||||
@ -85,8 +84,6 @@ def reader(name):
|
||||
module_name = None
|
||||
_hy_reader[module_name][name] = fn
|
||||
|
||||
# Ugly hack to get some error handling
|
||||
_hy_reader_chars.add(name)
|
||||
return fn
|
||||
return _
|
||||
|
||||
@ -209,3 +206,20 @@ def macroexpand_1(tree, module_name):
|
||||
|
||||
return ntree
|
||||
return tree
|
||||
|
||||
|
||||
def reader_macroexpand(char, tree, module_name):
|
||||
"""Expand the reader macro "char" with argument `tree`."""
|
||||
load_macros(module_name)
|
||||
|
||||
if not char in _hy_reader[module_name]:
|
||||
raise HyTypeError(
|
||||
char,
|
||||
"`{0}' is not a reader macro in module '{1}'".format(
|
||||
char,
|
||||
module_name,
|
||||
),
|
||||
)
|
||||
|
||||
expr = _hy_reader[module_name][char](tree)
|
||||
return _wrap_value(expr).replace(tree)
|
||||
|
@ -258,7 +258,7 @@ def test_reader_macro():
|
||||
"""Ensure reader macros are handles properly"""
|
||||
entry = tokenize("#^()")
|
||||
assert entry[0][0] == HySymbol("dispatch_reader_macro")
|
||||
assert entry[0][1] == HyExpression([HySymbol("quote"), HyString("^")])
|
||||
assert entry[0][1] == HyString("^")
|
||||
assert len(entry[0]) == 3
|
||||
|
||||
|
||||
@ -266,3 +266,39 @@ def test_lex_comment_382():
|
||||
"""Ensure that we can tokenize sources with a comment at the end"""
|
||||
entry = tokenize("foo ;bar\n;baz")
|
||||
assert entry == [HySymbol("foo")]
|
||||
|
||||
|
||||
def test_lex_mangling_star():
|
||||
"""Ensure that mangling starred identifiers works according to plan"""
|
||||
entry = tokenize("*foo*")
|
||||
assert entry == [HySymbol("FOO")]
|
||||
entry = tokenize("*")
|
||||
assert entry == [HySymbol("*")]
|
||||
entry = tokenize("*foo")
|
||||
assert entry == [HySymbol("*foo")]
|
||||
|
||||
|
||||
def test_lex_mangling_hyphen():
|
||||
"""Ensure that hyphens get translated to underscores during mangling"""
|
||||
entry = tokenize("foo-bar")
|
||||
assert entry == [HySymbol("foo_bar")]
|
||||
entry = tokenize("-")
|
||||
assert entry == [HySymbol("-")]
|
||||
|
||||
|
||||
def test_lex_mangling_qmark():
|
||||
"""Ensure that identifiers ending with a question mark get mangled ok"""
|
||||
entry = tokenize("foo?")
|
||||
assert entry == [HySymbol("is_foo")]
|
||||
entry = tokenize("?")
|
||||
assert entry == [HySymbol("?")]
|
||||
entry = tokenize("im?foo")
|
||||
assert entry == [HySymbol("im?foo")]
|
||||
entry = tokenize(".foo?")
|
||||
assert entry == [HySymbol(".is_foo")]
|
||||
entry = tokenize("foo.bar?")
|
||||
assert entry == [HySymbol("foo.is_bar")]
|
||||
entry = tokenize("foo?.bar")
|
||||
assert entry == [HySymbol("is_foo.bar")]
|
||||
entry = tokenize(".foo?.bar.baz?")
|
||||
assert entry == [HySymbol(".is_foo.bar.is_baz")]
|
||||
|
@ -525,7 +525,7 @@
|
||||
(assert (= x 3))))
|
||||
|
||||
|
||||
(defn test-comprehensions []
|
||||
(defn test-list-comprehensions []
|
||||
"NATIVE: test list comprehensions"
|
||||
(assert (= (list-comp (* x 2) (x (range 2))) [0 2]))
|
||||
(assert (= (list-comp (* x 2) (x (range 4)) (% x 2)) [2 6]))
|
||||
@ -536,6 +536,41 @@
|
||||
(assert (= (list-comp j (j [1 2])) [1 2])))
|
||||
|
||||
|
||||
(defn test-set-comprehensions []
|
||||
"NATIVE: test set comprehensions"
|
||||
(assert (instance? set (set-comp x [x (range 2)])))
|
||||
(assert (= (set-comp (* x 2) (x (range 2))) (set [0 2])))
|
||||
(assert (= (set-comp (* x 2) (x (range 4)) (% x 2)) (set [2 6])))
|
||||
(assert (= (set-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2})))
|
||||
(set [2 4])))
|
||||
(assert (= (set-comp (, x y) (x (range 2) y (range 2)))
|
||||
(set [(, 0 0) (, 0 1) (, 1 0) (, 1 1)])))
|
||||
(assert (= (set-comp j (j [1 2])) (set [1 2]))))
|
||||
|
||||
|
||||
(defn test-dict-comprehensions []
|
||||
"NATIVE: test dict comprehensions"
|
||||
(assert (instance? dict (dict-comp x x [x (range 2)])))
|
||||
(assert (= (dict-comp x (* x 2) (x (range 2))) {1 2 0 0}))
|
||||
(assert (= (dict-comp x (* x 2) (x (range 4)) (% x 2)) {3 6 1 2}))
|
||||
(assert (= (dict-comp x (* y 2) ((, x y) (.items {"1" 1 "2" 2})))
|
||||
{"2" 4 "1" 2}))
|
||||
(assert (= (dict-comp (, x y) (+ x y) (x (range 2) y (range 2)))
|
||||
{(, 0 0) 0 (, 1 0) 1 (, 0 1) 1 (, 1 1) 2})))
|
||||
|
||||
|
||||
(defn test-generator-expressions []
|
||||
"NATIVE: test generator expressions"
|
||||
(assert (not (instance? list (genexpr x [x (range 2)]))))
|
||||
(assert (= (list (genexpr (* x 2) (x (range 2)))) [0 2]))
|
||||
(assert (= (list (genexpr (* x 2) (x (range 4)) (% x 2))) [2 6]))
|
||||
(assert (= (list (sorted (genexpr (* y 2) ((, x y) (.items {"1" 1 "2" 2})))))
|
||||
[2 4]))
|
||||
(assert (= (list (genexpr (, x y) (x (range 2) y (range 2))))
|
||||
[(, 0 0) (, 0 1) (, 1 0) (, 1 1)]))
|
||||
(assert (= (list (genexpr j (j [1 2]))) [1 2])))
|
||||
|
||||
|
||||
(defn test-defn-order []
|
||||
"NATIVE: test defn evaluation order"
|
||||
(setv acc [])
|
||||
|
@ -23,10 +23,14 @@
|
||||
(assert (= #+2 3)))
|
||||
|
||||
|
||||
(defn test-reader-macro-compile-docstring []
|
||||
"Test if we can compile with a docstring"
|
||||
(try
|
||||
(defreader d []
|
||||
"Compiles with docstrings")
|
||||
(except [Exception]
|
||||
(assert False))))
|
||||
(defn test-reader-macros-macros []
|
||||
"Test if defreader is actually a macro"
|
||||
(defreader t [expr]
|
||||
`(, ~@expr))
|
||||
|
||||
(def a #t[1 2 3])
|
||||
|
||||
(assert (= (type a) tuple))
|
||||
(assert (= (, 1 2 3) a)))
|
||||
|
||||
|
||||
|
@ -76,6 +76,14 @@ def test_bin_hy_icmd():
|
||||
assert "figlet" in output
|
||||
|
||||
|
||||
def test_bin_hy_icmd_and_spy():
|
||||
ret = run_cmd("hy -i \"(+ [] [])\" --spy", "(+ 1 1)")
|
||||
assert ret[0] == 0
|
||||
output = ret[1]
|
||||
|
||||
assert "([] + [])" in output
|
||||
|
||||
|
||||
def test_bin_hy_missing_file():
|
||||
ret = run_cmd("hy foobarbaz")
|
||||
assert ret[0] == 2
|
||||
@ -126,7 +134,7 @@ def test_hy2py():
|
||||
for f in filenames:
|
||||
if f.endswith(".hy"):
|
||||
i += 1
|
||||
ret = run_cmd("bin/hy2py " + os.path.join(dirpath, f))
|
||||
ret = run_cmd("bin/hy2py -s -a " + os.path.join(dirpath, f))
|
||||
assert ret[0] == 0, f
|
||||
assert len(ret[1]) > 1, f
|
||||
assert len(ret[2]) == 0, f
|
||||
|
Loading…
x
Reference in New Issue
Block a user