From 0afbbeb68c88215fc440a0d3f8723f6070f6f658 Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Sun, 12 Jan 2014 18:53:08 -0500 Subject: [PATCH 01/13] Add (recur) for functions and stuff. --- hy/contrib/loop.hy | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/hy/contrib/loop.hy b/hy/contrib/loop.hy index 73526fa..91b24d9 100644 --- a/hy/contrib/loop.hy +++ b/hy/contrib/loop.hy @@ -55,6 +55,23 @@ (recursive-replace old-term new-term term)] [True term]) [term body]))) + +(defmacro/g! fnr [signature &rest body] + (let [[new-body (recursive-replace 'recur g!recur-fn body)]] + `(do + (import [hy.contrib.loop [--trampoline--]]) + (def ~g!recur-fn + (--trampoline-- (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 loop [bindings &rest body] ;; Use inside functions like so: ;; (defun factorial [n] From 5b78735011d43cf4a95e780c4885bfeb8e9123d8 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 13 Jan 2014 16:15:43 +0100 Subject: [PATCH 02/13] hy/cmdline.py: Add support for running with --spy -i There's no reason why one would need to choose between --spy and -i, so pass down options.spy to run_icommand, and then to HyREPL, so we can have both. Signed-off-by: Gergely Nagy --- hy/cmdline.py | 6 +++--- tests/test_bin.py | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/hy/cmdline.py b/hy/cmdline.py index b09595f..98f10cd 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -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='', 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] == "-": diff --git a/tests/test_bin.py b/tests/test_bin.py index d18dd31..3d3f3e1 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -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 From 5a64f187264eef2ef9a8bcffac6ad3adc0ca5a3d Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Mon, 13 Jan 2014 20:37:25 -0500 Subject: [PATCH 03/13] Refactor (loop) in terms of fnr; change to use decorator. --- hy/contrib/loop.hy | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/hy/contrib/loop.hy b/hy/contrib/loop.hy index 91b24d9..2c2690a 100644 --- a/hy/contrib/loop.hy +++ b/hy/contrib/loop.hy @@ -1,6 +1,7 @@ ;;; Hy tail-call optimization ;; ;; Copyright (c) 2014 Clinton Dreisbach +;; Copyright (c) 2014 Paul R. Tagliamonte ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), @@ -60,19 +61,19 @@ (let [[new-body (recursive-replace 'recur g!recur-fn body)]] `(do (import [hy.contrib.loop [--trampoline--]]) - (def ~g!recur-fn - (--trampoline-- (fn [~@signature] - ~@new-body))) + (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 loop [bindings &rest body] +(defmacro/g! loop [bindings &rest body] ;; Use inside functions like so: ;; (defun factorial [n] ;; (loop [[i n] @@ -84,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)))) From 25459177ebd380dbf2808a940914bab051439380 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Tue, 14 Jan 2014 05:59:44 +0200 Subject: [PATCH 04/13] Move "hy on meth" example to eg/. --- eg/flask/meth_example.hy | 27 +++++++++++++++++++++++++++ hy/contrib/meth.hy | 30 ++---------------------------- 2 files changed, 29 insertions(+), 28 deletions(-) create mode 100644 eg/flask/meth_example.hy diff --git a/eg/flask/meth_example.hy b/eg/flask/meth_example.hy new file mode 100644 index 0000000..4df70d7 --- /dev/null +++ b/eg/flask/meth_example.hy @@ -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}) diff --git a/hy/contrib/meth.hy b/hy/contrib/meth.hy index 18203ea..11e637c 100644 --- a/hy/contrib/meth.hy +++ b/hy/contrib/meth.hy @@ -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 From a619295dd7807ec75145572979cdaefda7bdc353 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 13 Jan 2014 21:41:01 +0100 Subject: [PATCH 05/13] bin/hy2py: Add a bunch of command-line options The hy2py tool has been very useful for me, but most of the time, it's only a part of its output that one is interested in. The whole output, with source code, AST and python code together is one big monstrosity. So instead of printing all that, lets have a few handy command-line options to control which part gets printed. By default, only the generated python source is, as that's what the name of the tool implies. Also, don't run it. That's what hy is for. Signed-off-by: Gergely Nagy --- bin/hy2py | 45 ++++++++++++++++++++++++++++++--------------- tests/test_bin.py | 2 +- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/bin/hy2py b/bin/hy2py index 3af8a62..3bcade4 100755 --- a/bin/hy2py +++ b/bin/hy2py @@ -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 = "" -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")) diff --git a/tests/test_bin.py b/tests/test_bin.py index d18dd31..d3ac8a2 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -126,7 +126,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 From cd66f18e2e7adc79acb9f5e4fd42352b38b7a186 Mon Sep 17 00:00:00 2001 From: rubberduckdev Date: Thu, 16 Jan 2014 02:40:46 +0200 Subject: [PATCH 06/13] Rewording Not sure if the rewording is much better. --- docs/language/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 96c4086..902dd92 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -548,7 +548,7 @@ for ------- `for` is used to call a function for each element in a list or vector. -Results are discarded and None is returned instead. Example code iterates over +The results of each call are discarded and the for expression returns None instead. Example code iterates over collection and calls side-effect to each element in the collection: .. code-block:: clj From ceb615d0102f92fee4703fb888f73f57d9ec5e2c Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 13 Jan 2014 22:19:25 +0100 Subject: [PATCH 07/13] hy/lex/parser.py: Move most of the identifier mangling into a def As a refactoring step, move the identifier mangling done in t_identifier into a separate def. Signed-off-by: Gergely Nagy --- hy/lex/parser.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hy/lex/parser.py b/hy/lex/parser.py index 72f0d8f..1eee798 100644 --- a/hy/lex/parser.py +++ b/hy/lex/parser.py @@ -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 = mangle(obj) return HySymbol(obj) From e49ad3b3d5c53f236db6c8f747a4c64424104f89 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 13 Jan 2014 22:27:44 +0100 Subject: [PATCH 08/13] tests/lex/test_lex.py: Add a few tests to cover identifier mangling Signed-off-by: Gergely Nagy --- tests/lex/test_lex.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index af9f286..e8b7a9c 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -266,3 +266,31 @@ 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")] From 8ef02a54b5f3e6471963eac6c1308f043dfd7e24 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 13 Jan 2014 22:36:53 +0100 Subject: [PATCH 09/13] hy/lex/parser.py: Add support for sub-object mangling With this patch, every identifier is split up along dots, each part gets separately mangled, and then it is all joined back together. This allows for fun stuff like (.foo? (Foo)), and even more contrived examples. Signed-off-by: Gergely Nagy --- hy/lex/parser.py | 2 +- tests/lex/test_lex.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hy/lex/parser.py b/hy/lex/parser.py index 1eee798..f7264fb 100644 --- a/hy/lex/parser.py +++ b/hy/lex/parser.py @@ -254,7 +254,7 @@ def t_identifier(p): return p - obj = mangle(obj) + obj = ".".join([mangle(part) for part in obj.split(".")]) return HySymbol(obj) diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index e8b7a9c..93f862c 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -294,3 +294,11 @@ def test_lex_mangling_qmark(): 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")] From a35ecc41bd925888b7c6572b556974d2960ba346 Mon Sep 17 00:00:00 2001 From: Foxboron Date: Tue, 14 Jan 2014 02:38:16 +0100 Subject: [PATCH 10/13] Fix reader macros to actually be macros --- docs/language/readermacros.rst | 34 +++++++++++++++++++---------- hy/compiler.py | 21 ++++++++++++++++-- hy/core/macros.hy | 10 --------- hy/lex/parser.py | 4 ++-- hy/macros.py | 20 ++++++++++++++--- tests/lex/test_lex.py | 2 +- tests/native_tests/reader_macros.hy | 18 +++++++++------ 7 files changed, 73 insertions(+), 36 deletions(-) diff --git a/docs/language/readermacros.rst b/docs/language/readermacros.rst index 0c05d9c..a87b98d 100644 --- a/docs/language/readermacros.rst +++ b/docs/language/readermacros.rst @@ -24,19 +24,28 @@ Syntax => #^1+2+3+4+3+2 1+2+3+4+3+2 +Hy got no literal for tuples. Lets say you dislike `(, ...)` and want something +else. This is a problem reader macros are able to solve in a neat way. + +:: + + => (defreader t [expr] `(, ~@expr)) + => #t(1 2 3) + (1, 2, 3) + +You could even do like clojure, and have a litteral for regular expressions! + +:: + + => (import re) + => (defreader r [expr] `(re.compile ~expr)) + => #r".*" + <_sre.SRE_Pattern object at 0xcv7713ph15#> + Implementation ============== -Hy uses ``defreader`` to define the reader symbol, and ``#`` as the dispatch -character. ``#`` expands into ``(dispatch_reader_macro ...)`` where the symbol -and expression is quoted, and then passed along to the correct function:: - - => (defreader ^ ...) - => #^() - ;=> (dispatch_reader_macro '^ '()) - - ``defreader`` takes a single character as symbol name for the reader macro, anything longer will return an error. Implementation wise, ``defreader`` expands into a lambda covered with a decorator, this decorater saves the @@ -47,14 +56,17 @@ lambda in a dict with its module name and symbol. => (defreader ^ [expr] (print expr)) ;=> (with_decorator (hy.macros.reader ^) (fn [expr] (print expr))) - -Anything passed along is quoted, thus given to the function defined. +``#`` expands into ``(dispatch_reader_macro ...)`` where the symbol +and expression is passed to the correct function. :: + => #^() + ;=> (dispatch_reader_macro ^ ()) => #^"Hello" "Hello" + .. warning:: Because of a limitation in Hy's lexer and parser, reader macros can't redefine defined syntax such as ``()[]{}``. This will most likely be diff --git a/hy/compiler.py b/hy/compiler.py index e9be303..93e6526 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -38,8 +38,8 @@ from hy.models.dict import HyDict from hy.errors import HyCompileError, HyTypeError import hy.macros -from hy.macros import require, macroexpand from hy._compat import str_type, long_type, PY27, PY33, PY3, PY34 +from hy.macros import require, macroexpand, reader_macroexpand import hy.importer import traceback @@ -1980,7 +1980,7 @@ class HyASTCompiler(object): return ret @builds("defreader") - @checkargs(min=2, max=3) + @checkargs(min=2) def compile_reader(self, expression): expression.pop(0) name = expression.pop(0) @@ -2002,6 +2002,23 @@ class HyASTCompiler(object): return ret + @builds("dispatch_reader_macro") + @checkargs(exact=2) + def compile_dispatch_reader_macro(self, expression): + expression.pop(0) # dispatch-reader-macro + str_char = expression.pop(0) + if not type(str_char) == HyString: + raise HyTypeError( + str_char, + "Trying to expand a reader macro using `{0}' instead " + "of string".format(type(str_char).__name__), + ) + + module = self.module_name + expr = reader_macroexpand(str_char, expression.pop(0), module) + + return self.compile(expr) + @builds("eval_and_compile") def compile_eval_and_compile(self, expression): expression[0] = HySymbol("progn") diff --git a/hy/core/macros.hy b/hy/core/macros.hy index 79d7c12..9219975 100644 --- a/hy/core/macros.hy +++ b/hy/core/macros.hy @@ -181,13 +181,3 @@ (setv -args (cdr (car -args)))) `(apply ~-fun [~@-args] (dict (sum ~-okwargs []))))) - - -(defmacro dispatch-reader-macro [char &rest body] - "Dispatch a reader macro based on the character" - (import [hy.macros]) - (setv str_char (get char 1)) - (if (not (in str_char hy.macros._hy_reader_chars)) - (raise (hy.compiler.HyTypeError char (.format "There is no reader macro with the character `{0}`" str_char)))) - `(do (import [hy.macros [_hy_reader]]) - ((get (get _hy_reader --name--) ~char) ~(get body 0)))) diff --git a/hy/lex/parser.py b/hy/lex/parser.py index 72f0d8f..aac626a 100644 --- a/hy/lex/parser.py +++ b/hy/lex/parser.py @@ -154,8 +154,8 @@ def term_unquote_splice(p): @set_quote_boundaries def hash_reader(p): st = p[0].getstr()[1] - str_object = HyExpression([HySymbol("quote"), HyString(st)]) - expr = HyExpression([HySymbol("quote"), p[1]]) + str_object = HyString(st) + expr = p[1] return HyExpression([HySymbol("dispatch_reader_macro"), str_object, expr]) diff --git a/hy/macros.py b/hy/macros.py index d98b328..b155799 100644 --- a/hy/macros.py +++ b/hy/macros.py @@ -43,7 +43,6 @@ EXTRA_MACROS = [ _hy_macros = defaultdict(dict) _hy_reader = defaultdict(dict) -_hy_reader_chars = set() def macro(name): @@ -85,8 +84,6 @@ def reader(name): module_name = None _hy_reader[module_name][name] = fn - # Ugly hack to get some error handling - _hy_reader_chars.add(name) return fn return _ @@ -209,3 +206,20 @@ def macroexpand_1(tree, module_name): return ntree return tree + + +def reader_macroexpand(char, tree, module_name): + """Expand the reader macro "char" with argument `tree`.""" + load_macros(module_name) + + if not char in _hy_reader[module_name]: + raise HyTypeError( + char, + "`{0}' is not a reader macro in module '{1}'".format( + char, + module_name, + ), + ) + + expr = _hy_reader[module_name][char](tree) + return _wrap_value(expr).replace(tree) diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index af9f286..eb95e80 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -258,7 +258,7 @@ def test_reader_macro(): """Ensure reader macros are handles properly""" entry = tokenize("#^()") assert entry[0][0] == HySymbol("dispatch_reader_macro") - assert entry[0][1] == HyExpression([HySymbol("quote"), HyString("^")]) + assert entry[0][1] == HyString("^") assert len(entry[0]) == 3 diff --git a/tests/native_tests/reader_macros.hy b/tests/native_tests/reader_macros.hy index e43220b..84a48a5 100644 --- a/tests/native_tests/reader_macros.hy +++ b/tests/native_tests/reader_macros.hy @@ -23,10 +23,14 @@ (assert (= #+2 3))) -(defn test-reader-macro-compile-docstring [] - "Test if we can compile with a docstring" - (try - (defreader d [] - "Compiles with docstrings") - (except [Exception] - (assert False)))) +(defn test-reader-macros-macros [] + "Test if defreader is actually a macro" + (defreader t [expr] + `(, ~@expr)) + + (def a #t[1 2 3]) + + (assert (= (type a) tuple)) + (assert (= (, 1 2 3) a))) + + From db9b9c68765eea2fb766ba2ed3676514ed0e72e6 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Fri, 17 Jan 2014 03:56:12 +0200 Subject: [PATCH 11/13] Move all contrib.meth tests to tests/native_tests/contrib/. --- tests/__init__.py | 2 +- tests/contrib/__init__.hy | 0 tests/{contrib/test_meth.hy => native_tests/contrib/meth.hy} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 tests/contrib/__init__.hy rename tests/{contrib/test_meth.hy => native_tests/contrib/meth.hy} (97%) diff --git a/tests/__init__.py b/tests/__init__.py index 5508950..2df7cf0 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -15,4 +15,4 @@ from .native_tests.reader_macros import * # noqa from .native_tests.with_test import * # noqa from .native_tests.contrib.anaphoric import * # noqa from .native_tests.contrib.loop import * # noqa -from .contrib.test_meth import * # noqa +from .native_tests.contrib.meth import * # noqa diff --git a/tests/contrib/__init__.hy b/tests/contrib/__init__.hy deleted file mode 100644 index e69de29..0000000 diff --git a/tests/contrib/test_meth.hy b/tests/native_tests/contrib/meth.hy similarity index 97% rename from tests/contrib/test_meth.hy rename to tests/native_tests/contrib/meth.hy index 2f13cfd..446bb81 100644 --- a/tests/contrib/test_meth.hy +++ b/tests/native_tests/contrib/meth.hy @@ -3,7 +3,7 @@ (defclass FakeMeth [] "Mocking decorator class" [[rules {}] - [route (fn [self rule &kwargs options] + [route (fn [self rule &kwargs options] (fn [f] (assoc self.rules rule (, f options)) f))]]) From d273ad112f795b79d11879b7189a0600aba84d71 Mon Sep 17 00:00:00 2001 From: rubberduckdev Date: Fri, 17 Jan 2014 18:20:41 +0200 Subject: [PATCH 12/13] Rewording and reformatting plaintext Is this rewording unwieldy? --- docs/language/api.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 902dd92..7e06579 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -548,8 +548,10 @@ for ------- `for` is used to call a function for each element in a list or vector. -The results of each call are discarded and the for expression returns None instead. Example code iterates over -collection and calls side-effect to each element in the collection: +The results of each call are discarded and the for expression returns +None instead. The example code iterates over `collection` and +for each `element` in `collection` calls the `side-effect` +function with `element` as its argument: .. code-block:: clj From 27962fb4412f2cbc1bdd664702d0e1cb2bc0198b Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Fri, 17 Jan 2014 20:28:24 +0100 Subject: [PATCH 13/13] Light copy-editing --- docs/language/readermacros.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/language/readermacros.rst b/docs/language/readermacros.rst index a87b98d..392feb6 100644 --- a/docs/language/readermacros.rst +++ b/docs/language/readermacros.rst @@ -24,7 +24,7 @@ Syntax => #^1+2+3+4+3+2 1+2+3+4+3+2 -Hy got no literal for tuples. Lets say you dislike `(, ...)` and want something +Hy has no literal for tuples. Lets say you dislike `(, ...)` and want something else. This is a problem reader macros are able to solve in a neat way. :: @@ -33,7 +33,7 @@ else. This is a problem reader macros are able to solve in a neat way. => #t(1 2 3) (1, 2, 3) -You could even do like clojure, and have a litteral for regular expressions! +You could even do like clojure, and have a literal for regular expressions! ::