Merge branch 'master' into pr/171

This commit is contained in:
Paul Tagliamonte 2013-05-09 20:39:49 -04:00
commit 9811b7514e
6 changed files with 206 additions and 34 deletions

View File

@ -181,6 +181,12 @@ latex_elements = {
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Stuff for unicode characters
'utf8extra': r'''
\DeclareUnicodeCharacter{2698}{FLOWER}
\DeclareUnicodeCharacter{2665}{HEART}
''',
}
# Grouping the document tree into LaTeX files. List of tuples

View File

@ -24,8 +24,8 @@ languages.
* UTF-8 entities will be encoded using
`punycode <http://en.wikipedia.org/wiki/Punycode>`_ and prefixed with
`__hy_`. For instance, `⚘` will become `__hy_w7h`, and `♥` will become
`__hy_g6h`.
`hy_`. For instance, `⚘` will become `hy_w7h`, and `♥` will become
`hy_g6h`.
* Symbols that contain dashes will have them replaced with underscores. For
example, `render-template` will become `render_template`.
@ -38,6 +38,37 @@ Hy features a number 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.
import
------
`import` is used to import modules, like in Python. There are several forms
of import you can use.
.. code-block:: clj
;; Imports each of these modules
;;
;; Python:
;; import sys
;; import os.path
(import sys os.path)
;; Import from a module
;;
;; Python: from os.path import exists, isdir, isfile
(import [os.path [exists isdir isfile]])
;; Import with an alias
;;
;; Python: import sys as systest
(import [sys :as systest])
;; You can list as many imports as you like of different types.
(import [tests.resources [kwtest function-with-a-dash]]
[os.path [exists isdir isfile]]
[sys :as systest])
do / progn
----------

View File

@ -188,6 +188,8 @@ hy. Let's experiment with this in the hy interpreter::
... "cat" "meow"}
...
{'dog': 'bark', 'cat': 'meow'}
=> (, 1 2 3)
(1, 2, 3)
(You may notice that at present, the common lisp method of quoting
things like so:
@ -375,6 +377,106 @@ In hy, you could do these like:
; (8, 'A'), (8, 'B'), (8, 'C'), (8, 'D'), (8, 'E'), (8, 'F'), (8, 'G'), (8, 'H')]
Python has support for various fancy argument and keyword arguments.
In python we might see::
>>> def optional_arg(pos1, pos2, keyword1=None, keyword2=42):
... return [pos1, pos2, keyword1, keyword2]
...
>>> optional_arg(1, 2)
[1, 2, None, 42]
>>> optional_arg(1, 2, 3, 4)
[1, 2, 3, 4]
>>> optional_arg(keyword1=1, pos2=2, pos1=3, keyword2=4)
[3, 2, 1, 4]
The same thing in Hy::
=> (defn optional_arg [pos1 pos2 &optional keyword1 [keyword2 88]]
... [pos1 pos2 keyword1 keyword2])
=> (optional_arg 1 2)
[1 2 None 42]
=> (optional_arg 1 2 3 4)
[1 2 3 4]
=> (kwapply (optional_arg)
... {"keyword1" 1
... "pos2" 2
... "pos1" 3
... "keyword2" 4})
...
[3, 2, 1, 4]
See how we use kwapply to handle the fancy pssing? :)
There's also a dictionary-style keyword arguments construction that
looks like:
.. code-block:: clj
(defn another_style [&key {"key1" "val1" "key2" "val2"}]
[key1 key2])
The difference here is that since it's a dictionary, you can't rely on
any specific ordering to the arguments.
Hy also supports ``*args`` and ``**kwargs``. In Python::
def some_func(foo, bar, *args, **kwargs):
import pprint
pprint.pprint((foo, bar, args, kwargs))
The Hy equivalent:
.. code-block:: clj
(defn some_func [foo bar &rest args &kwargs kwargs]
(import pprint)
(pprint.pprint (, foo bar args kwargs)))
Finally, of course we need classes! In python we might have a class
like::
class FooBar (object):
def __init__(self, x):
self.x = x
def get_x(self):
return self.x
In Hy:
.. code-block:: clj
(defclass FooBar [object]
[[--init--
(fn [self x]
(setv self.x x)
; Currently needed for --init-- because __init__ needs None
; Hopefully this will go away :)
None)]
[get-x
(fn [self]
self.x)]])
You can also do class-level attributes. In Python::
class Customer(models.Model):
name = models.CharField(max_length=255)
address = models.TextField()
notes = models.TextField()
In Hy:
.. code-block:: clj
(defclass Customer [models.Model]
[[name (kwapply (models.CharField) {"max_length" 255})]
[address (models.TextField)]
[notes (models.TextField)]])
Protips!
========
@ -414,7 +516,7 @@ Which, of course, expands out to:
(wc (grep (cat "/usr/share/dict/words") "-E" "^hy") "-l")
Much more readable, no! Use the threading macro!
Much more readable, no? Use the threading macro!
TODO
@ -422,7 +524,6 @@ TODO
- How do I index into arrays or dictionaries?
- How do I do array ranges? e.g. x[5:] or y[2:10]
- How do I define classes?
- Blow your mind with macros!
- Where's my banana???
- Mention that you can import .hy files in .py files and vice versa!

View File

@ -573,8 +573,24 @@ class HyASTCompiler(object):
# (try something…)
body = self.compile(body)
# XXX we will likely want to make this a tempvar
body += body.expr_as_stmt()
var = self.get_anon_var()
name = ast.Name(id=ast_str(var), arg=ast_str(var),
ctx=ast.Store(),
lineno=expr.start_line,
col_offset=expr.start_column)
expr_name = ast.Name(id=ast_str(var), arg=ast_str(var),
ctx=ast.Load(),
lineno=expr.start_line,
col_offset=expr.start_column)
returnable = Result(expr=expr_name, temp_variables=[expr_name, name])
body += ast.Assign(targets=[name],
value=body.force_expr,
lineno=expr.start_line,
col_offset=expr.start_column)
body = body.stmts
if not body:
body = [ast.Pass(lineno=expr.start_line,
@ -590,7 +606,7 @@ class HyASTCompiler(object):
raise HyTypeError(e, "Empty list not allowed in `try'")
if e[0] in (HySymbol("except"), HySymbol("catch")):
handler_results += self.compile(e)
handler_results += self._compile_catch_expression(e, name)
handlers.append(handler_results.stmts.pop())
elif e[0] == HySymbol("else"):
if orelse:
@ -642,7 +658,7 @@ class HyASTCompiler(object):
body=body,
handlers=handlers,
orelse=orelse,
finalbody=finalbody)
finalbody=finalbody) + returnable
if finalbody:
if handlers:
@ -655,30 +671,34 @@ class HyASTCompiler(object):
handlers=handlers,
body=body,
orelse=orelse)],
finalbody=finalbody)
finalbody=finalbody) + returnable
return ret + ast.TryFinally(
lineno=expr.start_line,
col_offset=expr.start_column,
body=body,
finalbody=finalbody)
finalbody=finalbody) + returnable
return ret + ast.TryExcept(
lineno=expr.start_line,
col_offset=expr.start_column,
handlers=handlers,
body=body,
orelse=orelse)
orelse=orelse) + returnable
@builds("catch")
@builds("except")
def compile_catch_expression(self, expr):
@builds("catch")
def magic_internal_form(self, expr):
raise TypeError("Error: `%s' can't be used like that." % (expr[0]))
def _compile_catch_expression(self, expr, var):
catch = expr.pop(0) # catch
try:
exceptions = expr.pop(0)
except IndexError:
exceptions = HyList()
# exceptions catch should be either:
# [[list of exceptions]]
# or
@ -689,6 +709,7 @@ class HyASTCompiler(object):
# [exception]
# or
# []
if not isinstance(exceptions, HyList):
raise HyTypeError(exceptions,
"`%s' exceptions list is not a list" % catch)
@ -736,7 +757,10 @@ class HyASTCompiler(object):
"`%s' needs a valid exception list" % catch)
body = self._compile_branch(expr)
# XXX tempvar handling magic
body += ast.Assign(targets=[var],
value=body.force_expr,
lineno=expr.start_line,
col_offset=expr.start_column)
body += body.expr_as_stmt()
body = body.stmts

View File

@ -140,39 +140,41 @@ def test_ast_bad_try():
def test_ast_good_catch():
"Make sure AST can compile valid catch"
hy_compile(tokenize("(catch)"))
hy_compile(tokenize("(catch [])"))
hy_compile(tokenize("(catch [Foobar])"))
hy_compile(tokenize("(catch [[]])"))
hy_compile(tokenize("(catch [x FooBar])"))
hy_compile(tokenize("(catch [x [FooBar BarFoo]])"))
hy_compile(tokenize("(catch [x [FooBar BarFoo]])"))
hy_compile(tokenize("(try 1 (catch))"))
hy_compile(tokenize("(try 1 (catch []))"))
hy_compile(tokenize("(try 1 (catch [Foobar]))"))
hy_compile(tokenize("(try 1 (catch [[]]))"))
hy_compile(tokenize("(try 1 (catch [x FooBar]))"))
hy_compile(tokenize("(try 1 (catch [x [FooBar BarFoo]]))"))
hy_compile(tokenize("(try 1 (catch [x [FooBar BarFoo]]))"))
def test_ast_bad_catch():
"Make sure AST can't compile invalid catch"
cant_compile("(catch 1)")
cant_compile("(catch \"A\")")
cant_compile("(catch [1 3])")
cant_compile("(catch [x [FooBar] BarBar])")
cant_compile("(catch 22)") # heh
cant_compile("(try (catch 1))")
cant_compile("(try (catch \"A\"))")
cant_compile("(try (catch [1 3]))")
cant_compile("(try (catch [x [FooBar] BarBar]))")
def test_ast_good_except():
"Make sure AST can compile valid except"
hy_compile(tokenize("(except)"))
hy_compile(tokenize("(except [])"))
hy_compile(tokenize("(except [Foobar])"))
hy_compile(tokenize("(except [[]])"))
hy_compile(tokenize("(except [x FooBar])"))
hy_compile(tokenize("(except [x [FooBar BarFoo]])"))
hy_compile(tokenize("(except [x [FooBar BarFoo]])"))
hy_compile(tokenize("(try 1 (except))"))
hy_compile(tokenize("(try 1 (except []))"))
hy_compile(tokenize("(try 1 (except [Foobar]))"))
hy_compile(tokenize("(try 1 (except [[]]))"))
hy_compile(tokenize("(try 1 (except [x FooBar]))"))
hy_compile(tokenize("(try 1 (except [x [FooBar BarFoo]]))"))
hy_compile(tokenize("(try 1 (except [x [FooBar BarFoo]]))"))
def test_ast_bad_except():
"Make sure AST can't compile invalid except"
cant_compile("(except 1)")
cant_compile("(except [1 3])")
cant_compile("(except [x [FooBar] BarBar])")
cant_compile("(try 1 (except 1))")
cant_compile("(try 1 (except [1 3]))")
cant_compile("(try 1 (except [x [FooBar] BarBar]))")
def test_ast_good_assert():

View File

@ -684,3 +684,11 @@
(if (if 0 True False)
42
43))))
(defn test-try-except-return []
"NATIVE: test we can return from in a try except"
(assert (= ((fn [] (try xxx (except [NameError] (+ 1 1))))) 2))
(setf foo (try xxx (except [NameError] (+ 1 1))))
(assert (= foo 2))
(setf foo (try (+ 2 2) (except [NameError] (+ 1 1))))
(assert (= foo 4)))