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>
* Vasudev Kamath <kamathvasudev@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
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"))

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
==========
.. 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

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
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] == "-":

View File

@ -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))))

View File

@ -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

View File

@ -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)

View File

@ -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")]

View File

@ -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