Merge branch 'master' into pr/593

This commit is contained in:
Tuukka Turto 2014-06-24 23:23:48 +03:00
commit f3ecb96119
15 changed files with 238 additions and 104 deletions

View File

@ -305,7 +305,7 @@ Some example usage:
Yeah, really!
;; assuming that (side-effect) is a function that we want to call for each
;; and every value in the list, but which return values we do not care
;; and every value in the list, but whose return value we do not care about
=> (list-comp (do (side-effect x)
... (if (< x 5) (* 2 x)
... (* 4 x)))
@ -416,7 +416,7 @@ Parameters may have following keywords in front of them:
arguments may be specified after this one.
The following code example defines a function that can be given 0 to n
numerical parameters. It then sums every odd number and substracts
numerical parameters. It then sums every odd number and subtracts
every even number.
.. code-block:: clj
@ -1293,23 +1293,48 @@ file is automatically closed after it has been processed.
with-decorator
--------------
`with-decorator` is used to wrap a function with another. The function performing
decoration should accept a single value, the function being decorated and return
a new function. `with-decorator` takes two parameters, the function performing
decoration and the function being decorated.
In the following example, `inc-decorator` is used to decorate function `addition`
with a function that takes two parameters and calls the decorated function with
values that are incremented by 1. When decorated `addition` is called with values
1 and 1, the end result will be 4 (1+1 + 1+1).
`with-decorator` is used to wrap a function with another. The function
performing decoration should accept a single value, the function being
decorated and return a new function. `with-decorator` takes a minimum
of two parameters, the function performing decoration and the function
being decorated. More than one decorator function can be applied, they
will be applied in order from outermost to innermost, ie. the first
decorator will be the outermost one & so on. Decorators with arguments
are called just like a function call.
.. code-block:: clj
=> (defn inc-decorator [func]
(with-decorator decorator-fun
(defn some-function [] ...)
(with-decorator decorator1 decorator2 ...
(defn some-function [] ...)
(with-decorator (decorator arg) ..
(defn some-function [] ...)
In the following example, `inc-decorator` is used to decorate function
`addition` with a function that takes two parameters and calls the
decorated function with values that are incremented by 1. When
decorated `addition` is called with values 1 and 1, the end result
will be 4 (1+1 + 1+1).
.. code-block:: clj
=> (defn inc-decorator [func]
... (fn [value-1 value-2] (func (+ value-1 1) (+ value-2 1))))
=> (defn inc2-decorator [func]
... (fn [value-1 value-2] (func (+ value-1 2) (+ value-2 2))))
=> (with-decorator inc-decorator (defn addition [a b] (+ a b)))
=> (addition 1 1)
4
=> (with-decorator inc2-decorator inc-decorator
... (defn addition [a b] (+ a b)))
=> (addition 1 1)
8
.. _with-gensyms:

View File

@ -23,7 +23,6 @@ from hy.version import __version__, __appname__ # NOQA
from hy.models.expression import HyExpression # NOQA
from hy.models.lambdalist import HyLambdaListKeyword # NOQA
from hy.models.integer import HyInteger # NOQA
from hy.models.keyword import HyKeyword # NOQA
from hy.models.complex import HyComplex # NOQA

View File

@ -47,7 +47,7 @@ from hy.models.expression import HyExpression
from hy.models.string import HyString
from hy.models.symbol import HySymbol
from hy._compat import builtins
from hy._compat import builtins, PY3
class HyQuitter(object):
@ -327,6 +327,7 @@ def hyc_main():
# entry point for cmd line script "hy2py"
def hy2py_main():
import platform
module_name = "<STDIN>"
options = dict(prog="hy2py", usage="%(prog)s [options] FILE",
@ -349,17 +350,42 @@ def hy2py_main():
if options.with_source:
hst = import_file_to_hst(options.args[0])
print(hst)
# need special printing on Windows in case the
# codepage doesn't support utf-8 characters
if PY3 and platform.system() == "Windows":
for h in hst:
try:
print(h)
except:
print(str(h).encode('utf-8'))
else:
print(hst)
print()
print()
_ast = import_file_to_ast(options.args[0], module_name)
if options.with_ast:
print(astor.dump(_ast))
if PY3 and platform.system() == "Windows":
_print_for_windows(astor.dump(_ast))
else:
print(astor.dump(_ast))
print()
print()
if not options.without_python:
print(astor.codegen.to_source(_ast))
if PY3 and platform.system() == "Windows":
_print_for_windows(astor.codegen.to_source(_ast))
else:
print(astor.codegen.to_source(_ast))
parser.exit(0)
# need special printing on Windows in case the
# codepage doesn't support utf-8 characters
def _print_for_windows(src):
for line in src.split("\n"):
try:
print(line)
except:
print(line.encode('utf-8'))

View File

@ -1,10 +1,10 @@
# -*- encoding: utf-8 -*-
#
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
# Copyright (c) 2013, 2014 Paul Tagliamonte <paultag@debian.org>
# Copyright (c) 2013 Julien Danjou <julien@danjou.info>
# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>
# Copyright (c) 2013 James King <james@agentultra.com>
# Copyright (c) 2013 Bob Tolbert <bob@tolbert.org>
# Copyright (c) 2013, 2014 Bob Tolbert <bob@tolbert.org>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
@ -24,7 +24,6 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models.lambdalist import HyLambdaListKeyword
from hy.models.expression import HyExpression
from hy.models.keyword import HyKeyword
from hy.models.integer import HyInteger
@ -430,6 +429,7 @@ class HyASTCompiler(object):
def _parse_lambda_list(self, exprs):
""" Return FunctionDef parameter values from lambda list."""
ll_keywords = ("&rest", "&optional", "&key", "&kwargs")
ret = Result()
args = []
defaults = []
@ -439,10 +439,7 @@ class HyASTCompiler(object):
for expr in exprs:
if isinstance(expr, HyLambdaListKeyword):
if expr not in expr._valid_types:
raise HyTypeError(expr, "{0} is not a valid "
"lambda-keyword.".format(repr(expr)))
if expr in ll_keywords:
if expr == "&rest" and lambda_keyword is None:
lambda_keyword = expr
elif expr == "&optional":
@ -616,7 +613,7 @@ class HyASTCompiler(object):
return imports, ret.replace(form), False
elif isinstance(form, (HySymbol, HyLambdaListKeyword)):
elif isinstance(form, HySymbol):
return imports, HyExpression([HySymbol(name),
HyString(form)]).replace(form), False
@ -707,7 +704,8 @@ class HyASTCompiler(object):
lineno=expr.start_line,
col_offset=expr.start_column)
returnable = Result(expr=expr_name, temp_variables=[expr_name, name])
returnable = Result(expr=expr_name, temp_variables=[expr_name, name],
contains_yield=body.contains_yield)
body += ast.Assign(targets=[name],
value=body.force_expr,
@ -999,7 +997,10 @@ class HyASTCompiler(object):
@checkargs(max=1)
def compile_yield_expression(self, expr):
expr.pop(0)
ret = Result(contains_yield=True)
if PY33:
ret = Result(contains_yield=False)
else:
ret = Result(contains_yield=True)
value = None
if expr != []:

View File

@ -84,18 +84,20 @@
(defmacro ap-first [predfn lst]
"Yield the first element that passes `predfn`"
`(let [[n (gensym)]]
(ap-each ~lst (when ~predfn (setv n it) (break)))
n))
(with-gensyms [n]
`(let [[~n None]]
(ap-each ~lst (when ~predfn (setv ~n it) (break)))
~n)))
(defmacro ap-last [predfn lst]
"Yield the last element that passes `predfn`"
`(let [[n (gensym)]]
(ap-each ~lst (none? n)
(when ~predfn
(setv n it)))
n))
(with-gensyms [n]
`(let [[~n None]]
(ap-each ~lst (none? ~n)
(when ~predfn
(setv ~n it)))
~n)))
(defmacro ap-reduce [form lst &optional [initial-value None]]

View File

@ -1,3 +1,4 @@
STDLIB = [
"hy.core.language"
"hy.core.language",
"hy.core.shadow"
]

View File

@ -92,7 +92,8 @@
(setv map itertools.imap)
(setv zip itertools.izip)
(setv range xrange)
(setv input raw_input))
(setv input raw_input)
(setv reduce reduce))
(do
(setv reduce functools.reduce)
(setv filterfalse itertools.filterfalse)
@ -331,10 +332,12 @@
(_numeric_check n)
(= n 0))
(def *exports* '[butlast calling-module-name coll? cons cons? cycle dec distinct
disassemble drop drop-while empty? even? every? first filter
flatten float? gensym identity inc instance? integer
integer? integer-char? iterable? iterate iterator? keyword?
list* macroexpand macroexpand-1 map neg? nil? none? nth
numeric? odd? pos? range remove repeat repeatedly rest second
some string string? take take-nth take-while zero? zip zipwith])
(def *exports* '[butlast calling-module-name coll? cons cons? cycle
dec distinct disassemble drop drop-while empty? even?
every? first filter flatten float? gensym identity
inc instance? integer integer? integer-char?
iterable? iterate iterator? keyword? list*
macroexpand macroexpand-1 map neg? nil? none? nth
numeric? odd? pos? range remove repeat repeatedly
rest reduce second some string string? take take-nth
take-while zero? zip zipwith])

61
hy/core/shadow.hy Normal file
View File

@ -0,0 +1,61 @@
;; Copyright (c) 2014 Paul Tagliamonte <paultag@debian.org>
;; Copyright (c) 2014 James King <james@agentultra.com>
;; Permission is hereby granted, free of charge, to any person obtaining a
;; copy of this software and associated documentation files (the "Software"),
;; to deal in the Software without restriction, including without limitation
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
;; and/or sell copies of the Software, and to permit persons to whom the
;; Software is furnished to do so, subject to the following conditions:
;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;; DEALINGS IN THE SOFTWARE.
;;;; Hy shadow functions
(import operator)
(defn + [&rest args]
"Shadow + operator for when we need to import / map it against something"
(if (= (len args) 0)
0
(sum args))) ; shortcut here.
(defn - [&rest args]
"Shadow - operator for when we need to import / map it against something"
(let [[count (len args)]]
(if (= count 0)
(raise (TypeError "Need at least 1 argument to subtract"))
(if (= count 1)
(- (get args 0))
(reduce operator.sub args)))))
(defn * [&rest args]
"Shadow * operator for when we need to import / map it against something"
(if (= (len args) 0)
1 ; identity
(reduce operator.mul args)))
(defn / [&rest args]
"Shadow / operator for when we need to import / map it against something"
(let [[count (len args)]]
(if (= count 0)
(raise (TypeError "Need at least 1 argument to divide"))
(if (= count 1)
(operator.truediv 1 (get args 0))
(reduce operator.truediv args)))))
(setv *exports* ['+ '- '* '/])

View File

@ -30,7 +30,6 @@ from hy.models.expression import HyExpression
from hy.models.float import HyFloat
from hy.models.integer import HyInteger
from hy.models.keyword import HyKeyword
from hy.models.lambdalist import HyLambdaListKeyword
from hy.models.list import HyList
from hy.models.string import HyString
from hy.models.symbol import HySymbol
@ -271,9 +270,6 @@ def t_identifier(p):
if obj.startswith(":"):
return HyKeyword(obj)
if obj.startswith("&"):
return HyLambdaListKeyword(obj)
def mangle(p):
if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
p = p[1:-1].upper()

View File

@ -1,39 +0,0 @@
# Copyright (c) 2013 James King <james@agentultra.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from hy.models.string import HyString
class HyLambdaListKeyword(HyString):
"""
Hy LambdaListKeyword. Demarcates arguments in an argument list.
(defun my-fun (x &rest xs &optional (foo "default string")))
becomes:
def my_fun(x, *xs, foo="default string"):
pass
"""
_valid_types = ["&rest", "&optional", "&key", "&kwargs"]
def __init__(self, string):
self += string

View File

@ -21,7 +21,6 @@
from hy.models.expression import HyExpression
from hy.models.integer import HyInteger
from hy.models.lambdalist import HyLambdaListKeyword
from hy.models.float import HyFloat
from hy.models.complex import HyComplex
from hy.models.symbol import HySymbol
@ -85,14 +84,6 @@ def test_lex_expression_integer():
assert objs == [HyExpression([HySymbol("foo"), HyInteger(2)])]
def test_lex_lambda_list_keyword():
""" Make sure expressions can produce lambda list keywords """
objs = tokenize("(x &rest xs)")
assert objs == [HyExpression([HySymbol("x"),
HyLambdaListKeyword("&rest"),
HySymbol("xs")])]
def test_lex_symbols():
""" Make sure that symbols are valid expressions"""
objs = tokenize("foo ")

View File

@ -87,12 +87,14 @@
(defn test-ap-first []
"NATIVE: testing anaphoric first"
(assert-equal (ap-first (> it 5) (range 10)) 6)
(assert-equal (ap-first (even? it) [1 2 3 4]) 2))
(assert-equal (ap-first (even? it) [1 2 3 4]) 2)
(assert-equal (ap-first (> it 10) (range 10)) None))
(defn test-ap-last []
"NATIVE: testing anaphoric last"
(assert-equal (ap-last (> it 5) (range 10)) 9)
(assert-equal (ap-last (even? it) [1 2 3 4]) 4))
(assert-equal (ap-last (even? it) [1 2 3 4]) 4)
(assert-equal (ap-last (> it 10) (range 10)) None))
(defn test-ap-reduce []
"NATIVE: testing anaphoric reduce"

View File

@ -3,6 +3,7 @@
[sys :as systest])
(import sys)
(import [hy._compat [PY33 PY34]])
(defn test-sys-argv []
"NATIVE: test sys.argv"
@ -448,6 +449,29 @@
(for [y (gen)] (setv ret (+ ret y)))
(assert (= ret 10)))
(defn test-yield-with-return []
"NATIVE: test yield with return"
(defn gen [] (yield 3) "goodbye")
(if PY33
(do (setv gg (gen))
(assert (= 3 (next gg)))
(try (next gg)
(except [e StopIteration] (assert (hasattr e "value"))
(assert (= (getattr e "value") "goodbye")))))
(do (setv gg (gen))
(assert (= 3 (next gg)))
(try (next gg)
(except [e StopIteration] (assert (not (hasattr e "value"))))))))
(defn test-yield-in-try []
"NATIVE: test yield in try"
(defn gen []
(let [[x 1]]
(try (yield x)
(finally (print x)))))
(setv output (list (gen)))
(assert (= [1] output)))
(defn test-first []
"NATIVE: test firsty things"
@ -975,3 +999,10 @@
"NATIVE: test keyword quoting magic"
(assert (= :foo "\ufdd0:foo"))
(assert (= `:foo "\ufdd0:foo")))
(defn test-only-parse-lambda-list-in-defn []
"NATIVE: test lambda lists are only parsed in defn"
(try
(foo [&rest spam] 1)
(catch [NameError] True)
(else (raise AssertionError))))

View File

@ -77,12 +77,6 @@
(assert (= q qq)))
(defn test-quote-lambdalistkeyword []
"NATIVE: test quoting lambda list keywords"
(setv opt (quote &optional))
(assert (isinstance opt hy.HyLambdaListKeyword))
(assert (= (str opt) "&optional")))
(defmacro doodle [&rest body]
`(do ~@body))

View File

@ -0,0 +1,41 @@
(defn test-shadow-addition []
"NATIVE: test shadow addition"
(let [[x +]]
(assert (= (x) 0))
(assert (= (x 1 2 3 4) 10))
(assert (= (x 1 2 3 4 5) 15))))
(defn test-shadow-subtraction []
"NATIVE: test shadow subtraction"
(let [[x -]]
(assert (try
(x)
(catch [TypeError] True)
(else (throw AssertionError))))
(assert (= (x 1) -1))
(assert (= (x 2 1) 1))
(assert (= (x 2 1 1) 0))))
(defn test-shadow-multiplication []
"NATIVE: test shadow multiplication"
(let [[x *]]
(assert (= (x) 1))
(assert (= (x 3) 3))
(assert (= (x 3 3) 9))))
(defn test-shadow-division []
"NATIVE: test shadow division"
(let [[x /]]
(assert (try
(x)
(catch [TypeError] True)
(else (throw AssertionError))))
(assert (= (x 1) 1))
(assert (= (x 8 2) 4))
(assert (= (x 8 2 2) 2))
(assert (= (x 8 2 2 2) 1))))