Merge branch 'master' into pr/171
This commit is contained in:
commit
9811b7514e
@ -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
|
||||
|
@ -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
|
||||
----------
|
||||
|
||||
|
@ -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!
|
||||
|
@ -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
|
||||
|
@ -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():
|
||||
|
@ -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)))
|
||||
|
Loading…
Reference in New Issue
Block a user