xor with more than two input parameters is not well defined and people
have different expectations on how it should behave. Avoid confusion by
sticking with two parameters only.
Added xor to complement and, or, not operators. Standard python
falsey/truthy semantics are followed. This implementation works for
two or more parameters.
Python 3.5's PEP 448 ("Additional Unpacking Generalizations") allows the
iterable- and dictionary- unpacking operators to be used more than once;
the implementation (see https://hg.python.org/cpython/rev/a65f685ba8c0)
gets rid of the optional `starargs` and `kwargs` arguments to `ast.Call`
and `ast.ClassDef`, instead using `ast.Starred` and `ast.keyword`
objects inside of the normal `args` and `keywords` lists,
respectively. This commit allows Hy's `apply` to work correctly with
this revised AST when running under Python 3.5.
As reported in issue #748, there was a bug in which passing a lambda
as the value of a :keyword argument would fail—
$ hy --spy
hy 0.10.1 using CPython(default) 3.4.0 on Linux
=> (sorted (range 10) :key (fn [x] (- x)))
from hy.core.language import range
sorted(range(10), key=_hy_anon_fn_1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name '_hy_anon_fn_1' is not defined
The function call would appear in the generated AST without being
preceded by the appropriate function definition corresponding to the
anonymous function argument value in the Hy source, causing either a
NameError (as in the example above), or erroneous reuse of whatever
function was already pointed to by the `_hy_anon_fn_` name referenced
in the list of keywords passed to `ast.Call`.
This commit aims to fix the problem by handling it in same way that
the expression/statement gap is bridged many other places in the
compiler, by adding the compiled value of the keyword argument to the
Result object being built during `_compile_collect`, with the
understanding that any Python statements implied by the argument value
will be appropriately preserved therein.
This code is heavily, *heavily* based off of Guillermo Vaya
(willyfrog)'s work... instead of defining its own keyword arg though, it
uses the "standard" :kwarg type, which is the main difference from
willyfrog's original branch.
Included tests and some documentation in the tutorial.
Also documented "apply" separately as an example of reproducing
*args and **kwargs.
When (fn) or (defn) does not get an arglist as first/second parameter,
emit a more descriptive error message, rather than an ugly traceback.
Fixes#716.
Reported-by: Joakim Tall
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Python has the keyword.iskeyword method we can leverage for Python
keywords, but we also need to address Hy builtins like 'get' or
'slice'.
And to make behavior compatible with Python 2 or 3, we also make
a special case to prevent assignment to False, True or None as
well as the Hy versions: false, true, null, and nil.
For non-Hy modules, we also check to make sure the symbol is not
part of the compiler. This allows shadow.hy to override "+" but
prevents general use from re-defn-ing 'get' or 'do'.
As noted in #600, Python 3 allows a return inside a generator
method, that raises a StopIteration and passes the return value
inside the 'value' attr of the exception.
To allow this behaviour we simple set 'contains_yield' while compiling
'yield', thus allowing a return statement, but only for Python 3. Then
when compiling the try-except, we check for contains_yield to decide
whether there will be a return.
This allows code like:
(defn gen []
(yield 3)
"goodbye")
to compile in both Py2 and Py3. The return value is simply ignored in
Python 2.
hy2py in Python 2 gives:
def g():
yield 3L
u'goodbye'
while hy2py in Python 3 gives:
def g():
yield 3
return 'goodbye'
Turns out return in yield started in Python 3.3
As a result:
* functions such as `nth` should work correctly on iterators;
* `nth` will raise `IndexError` (in a fashion consistent with `get`)
when the index is out of bounds;
* `take`, etc. will raise `ValueError` instead of returning
an ambiguous value if the index is negative;
* `map`, `zip`, `range`, `input`, `filter` work the same way (Py3k one)
on both Python 2 and 3 (see #523 and #331).
Also small DRYing in try handling.
Previously, writing a bare (try (foo)) would invoke Pokemon
exception catching (gotta catch 'em all) instead of the correct
behavior, which is to raise the exception if no handler is provided.
Note that this is a cute feature of Hy, as a `try` with no `except`
is a syntax error. We avoid the syntax error here because we don't
use Python's compiler, which is the only thing that can throw
Syntax Errors. :D
Fixes#555.
When calling get with more than two arguments, treat the rest as indexes
into the expression from the former. That is, (get foo "bar" "baz")
would translate to foo["bar"]["baz"], and so on.
This fixes#362.
Requested-by: Sean B. Palmer <sean@miscoranda.com>
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Apply didn't work on method calls (i.e. `(apply .foo [bar]) broke).
This slipped through because there were no tests of this behavior. I noticed
it while trying to merge the `meth` fixes.
The fancypants Hy award goes to Nick for coming up with the quoted
symbol hack for exports. This broke with foo?, since the export string
needs to be is_foo, but using a quoted string will pick up the change
due to it being a Symbol.
Mad clown love for that, @olasd.
This gets rid of the dichotomy between bootstrap.py and macros.hy,
by making both files hy modules.
I added some error checking to make the macros more resilient. The
biggest (user-visible) change is the change in cond, which now only
accepts lists as arguments. Tests updated accordingly.
Closes: #176 (whoops, no more bootstrap)
This will let us implement common functions seen in other lisps,
and allow them to be importable, without explicit imports. The goal
is to keep this as small as we can; we don't want too much magic.
I've added `take' and `drop' as examples of what we can do.
A macro is available in the module where it was defined and
in any module that does a require of the defining module.
Only macros defined in hy.core are globally available.
Fixes#181
The new and improved (import) can handle all cases import-as and
import-from did, so drop the latter two from the language. To do this,
the import builtin had to be changed a little: if there's a single
import statement to return, return it as-is, otherwise return a list of
imports.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This also fixes a bug in the pass optimize missing branch where the code is
something like: [stmt, [], stmt]; in such case we want to filter out [], so
if we end up with [] we can optimize it. This fix is needed otherwise (do)
inside (do) are not properly optimized.
Signed-off-by: Julien Danjou <julien@danjou.info>
With these changes, the import function will become a lot smarter, and
will combine all of import, import-from and import-as in a hyly lispy
syntax:
(import sys os whatever_else)
(import [sys [exit argv]] [os :as real_os]
[whatever_else [some_function :as sf]])
That is, each argument of import can be:
- A plain symbol, which will be imported
- A list, which will be handled specially
If the argument is a list, the first element will always be the module
name to import, the second member can be either of these:
- A list of symbols to import
- The ':as' keyword
- Nothing
If it is the ':as' keyword, the third argument must be an alias. If it
is a list of symbols to import, we'll iterate through that list too. If
any symbol is followed by an ':as' keyword, we'll pick all three, and
treat the third member as an alias. If there is nothing else in the
list, we'll import the module as-is.
All this combined fixes#113.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This implements keywords, ":" prefixed symbols that are able to look
themselves up in a collection. They're internally stored as strings that
start with "\ufdd0".
This fixes#22.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This is a bit tricky, since we'll also have to support `finally' in the end,
I've introduced an Else statement on my own to be able to recognize it.
This fixes#74
Signed-off-by: Julien Danjou <julien@danjou.info>
The (or) function is to be constructed similarly to (and), so refactor
the compile_and_operator function to handle or aswell.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The function takes at least two arguments, and turns it into a pythonic
and statement, which returns the last True-ish value, or False.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>