Merge branch 'master' into pr/443

This commit is contained in:
Nicolas Dandrimont 2014-01-17 20:25:09 +01:00
commit eedebd12b3
12 changed files with 158 additions and 81 deletions

View File

@ -36,3 +36,4 @@
* Tuukka Turto <tuukka.turto@oktaeder.net> * Tuukka Turto <tuukka.turto@oktaeder.net>
* Vasudev Kamath <kamathvasudev@gmail.com> * Vasudev Kamath <kamathvasudev@gmail.com>
* Yuval Langer <yuval.langer@gmail.com> * Yuval Langer <yuval.langer@gmail.com>
* Fatih Kadir Akın <fka@fatihak.in>

View File

@ -1,24 +1,39 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function 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 argparse
import_file_to_hst) import sys
import astor.codegen import astor.codegen
import sys
module_name = "<STDIN>" module_name = "<STDIN>"
hst = import_file_to_hst(sys.argv[1]) parser = argparse.ArgumentParser(
print(str(hst).encode("utf-8")) prog="hy2py",
print("") usage="%(prog)s [options] FILE",
print("") formatter_class=argparse.RawDescriptionHelpFormatter)
_ast = import_file_to_ast(sys.argv[1], module_name) parser.add_argument("--with-source", "-s", action="store_true",
print("") help="Show the parsed source structure")
print("") parser.add_argument("--with-ast", "-a", action="store_true",
print(astor.dump(_ast).encode("utf-8")) help="Show the generated AST")
print("") parser.add_argument("--without-python", "-np", action="store_true",
print("") help="Do not show the python code generated from the AST")
print(astor.codegen.to_source(_ast).encode("utf-8")) 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"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
docs/_static/cuddles-transparent.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -2,20 +2,20 @@
Quickstart Quickstart
========== ==========
.. image:: _static/cuddles.png .. image:: _static/cuddles-transparent-small.png
:alt: Karen Rustard's Cuddles :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>`_ <https://pypi.python.org/pypi/virtualenv>`_
2. activate your Python virtual environment 2. Activate your Virtual Python Environment
3. ``pip install hy`` 3. Install `hy from PyPI <https://pypi.python.org/pypi/hy>`_ with ``pip install hy``
4. start a REPL with ``hy`` 4. Start a REPL with ``hy``
5. type stuff in the REPL:: 5. Type stuff in the REPL::
=> (print "Hy!") => (print "Hy!")
Hy! Hy!
@ -25,20 +25,19 @@ HOW TO GET HY REAL FAST:
etc 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. OMG! That's amazing! I want to write a hy program.
7. open up an elite programming editor 7. Open up an elite programming editor and type::
8. 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`` 8. Save as ``awesome.hy``
10. run:: 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 10. Take a deep breath so as to not hyperventilate
12. smile villainously and sneak off to your hydeaway and do 11. Smile villainously and sneak off to your hydeaway and do
unspeakable things unspeakable things

27
eg/flask/meth_example.hy Normal file
View 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})

View File

@ -214,8 +214,8 @@ def run_repl(hr=None, spy=False):
return 0 return 0
def run_icommand(source): def run_icommand(source, spy=False):
hr = HyREPL() hr = HyREPL(spy)
hr.runsource(source, filename='<input>', symbol='single') hr.runsource(source, filename='<input>', symbol='single')
return run_repl(hr) return run_repl(hr)
@ -270,7 +270,7 @@ def cmdline_handler(scriptname, argv):
if options.icommand: if options.icommand:
# User did "hy -i ..." # User did "hy -i ..."
return run_icommand(options.icommand) return run_icommand(options.icommand, spy=options.spy)
if options.args: if options.args:
if options.args[0] == "-": if options.args[0] == "-":

View File

@ -1,6 +1,7 @@
;;; Hy tail-call optimization ;;; Hy tail-call optimization
;; ;;
;; Copyright (c) 2014 Clinton Dreisbach <clinton@dreisbach.us> ;; 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 ;; Permission is hereby granted, free of charge, to any person obtaining a
;; copy of this software and associated documentation files (the "Software"), ;; copy of this software and associated documentation files (the "Software"),
@ -55,7 +56,24 @@
(recursive-replace old-term new-term term)] (recursive-replace old-term new-term term)]
[True term]) [term body]))) [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: ;; Use inside functions like so:
;; (defun factorial [n] ;; (defun factorial [n]
;; (loop [[i n] ;; (loop [[i n]
@ -67,13 +85,7 @@
;; If recur is used in a non-tail-call position, None is returned, which ;; 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 ;; causes chaos. Fixing this to detect if recur is in a tail-call position
;; and erroring if not is a giant TODO. ;; and erroring if not is a giant TODO.
(with-gensyms [recur-fn] (let [[fnargs (map (fn [x] (first x)) bindings)]
(let [[fnargs (map (fn [x] (first x)) bindings)] [initargs (map second bindings)]]
[initargs (map second bindings)] `(do (defnr ~g!recur-fn [~@fnargs] ~@body)
[new-body (recursive-replace 'recur recur-fn body)]] (~g!recur-fn ~@initargs))))
`(do
(import [hy.contrib.loop [--trampoline--]])
(def ~recur-fn
(--trampoline-- (fn [~@fnargs]
~@new-body)))
(~recur-fn ~@initargs)))))

View File

@ -1,5 +1,5 @@
;;; Meth ;;; Hy on Meth
;; based on paultag's meth library to access a Flask based application ;;; based on paultag's meth library to access a Flask based application
(defmacro route-with-methods [name path methods params &rest code] (defmacro route-with-methods [name path methods params &rest code]
"Same as route but with an extra methods array to specify HTTP methods" "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] (defmacro delete-route [name path params &rest code]
"Delete request" "Delete request"
`(route-with-methods ~name ~path ["DELETE"] ~params ~@code)) `(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

View File

@ -242,14 +242,19 @@ def t_identifier(p):
if obj.startswith("&"): if obj.startswith("&"):
return HyLambdaListKeyword(obj) return HyLambdaListKeyword(obj)
if obj.startswith("*") and obj.endswith("*") and obj not in ("*", "**"): def mangle(p):
obj = obj[1:-1].upper() if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
p = p[1:-1].upper()
if "-" in obj and obj != "-": if "-" in p and p != "-":
obj = obj.replace("-", "_") p = p.replace("-", "_")
if obj.endswith("?") and obj != "?": if p.endswith("?") and p != "?":
obj = "is_%s" % (obj[:-1]) p = "is_%s" % (p[:-1])
return p
obj = ".".join([mangle(part) for part in obj.split(".")])
return HySymbol(obj) return HySymbol(obj)

View File

@ -266,3 +266,39 @@ def test_lex_comment_382():
"""Ensure that we can tokenize sources with a comment at the end""" """Ensure that we can tokenize sources with a comment at the end"""
entry = tokenize("foo ;bar\n;baz") entry = tokenize("foo ;bar\n;baz")
assert entry == [HySymbol("foo")] 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")]

View File

@ -76,6 +76,14 @@ def test_bin_hy_icmd():
assert "figlet" in output 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(): def test_bin_hy_missing_file():
ret = run_cmd("hy foobarbaz") ret = run_cmd("hy foobarbaz")
assert ret[0] == 2 assert ret[0] == 2
@ -126,7 +134,7 @@ def test_hy2py():
for f in filenames: for f in filenames:
if f.endswith(".hy"): if f.endswith(".hy"):
i += 1 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 ret[0] == 0, f
assert len(ret[1]) > 1, f assert len(ret[1]) > 1, f
assert len(ret[2]) == 0, f assert len(ret[2]) == 0, f