Merge branch 'master' into pr/593
This commit is contained in:
commit
f3ecb96119
@ -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.
|
||||
`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.
|
||||
|
||||
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
|
||||
|
||||
(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:
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
# 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:
|
||||
if PY3 and platform.system() == "Windows":
|
||||
_print_for_windows(astor.dump(_ast))
|
||||
else:
|
||||
print(astor.dump(_ast))
|
||||
print()
|
||||
print()
|
||||
|
||||
if not options.without_python:
|
||||
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'))
|
||||
|
@ -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,6 +997,9 @@ class HyASTCompiler(object):
|
||||
@checkargs(max=1)
|
||||
def compile_yield_expression(self, expr):
|
||||
expr.pop(0)
|
||||
if PY33:
|
||||
ret = Result(contains_yield=False)
|
||||
else:
|
||||
ret = Result(contains_yield=True)
|
||||
|
||||
value = None
|
||||
|
@ -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)
|
||||
(with-gensyms [n]
|
||||
`(let [[~n None]]
|
||||
(ap-each ~lst (none? ~n)
|
||||
(when ~predfn
|
||||
(setv n it)))
|
||||
n))
|
||||
(setv ~n it)))
|
||||
~n)))
|
||||
|
||||
|
||||
(defmacro ap-reduce [form lst &optional [initial-value None]]
|
||||
|
@ -1,3 +1,4 @@
|
||||
STDLIB = [
|
||||
"hy.core.language"
|
||||
"hy.core.language",
|
||||
"hy.core.shadow"
|
||||
]
|
||||
|
@ -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
61
hy/core/shadow.hy
Normal 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* ['+ '- '* '/])
|
@ -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()
|
||||
|
@ -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
|
@ -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 ")
|
||||
|
@ -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"
|
||||
|
@ -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))))
|
||||
|
@ -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))
|
||||
|
||||
|
41
tests/native_tests/shadow.hy
Normal file
41
tests/native_tests/shadow.hy
Normal 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))))
|
Loading…
x
Reference in New Issue
Block a user