Repository navigation
Conversation
|
See #1492, but still not there yet as this is only concerned with a single dimension. Maybe the nicest would be to let |
|
|
|
Beyond that, though, any complains with this approach? |
da2c263 to
95e31ba
Compare
|
|
||
| indices, ret, _ = self._compile_collect(expr[1:]) | ||
| ret += self.compile(expr[0]) | ||
| if isinstance(expr[1], HyExpression) and expr[1][0] == "slice": |
There was a problem hiding this comment.
This will trigger on the string "slice" instead of just the symbol. You may also need to check that expr[1] is nonempty.
|
Don't forget about those test failures. |
|
One issue with this approach is that |
95e31ba to
99be9be
Compare
Oh right, is there any suggestions on how to deal with this? Should I promote |
|
|
So if I understand this correctly, I should compile the expression and then peek inside the results of that? |
|
No, I don't think you need to; I think it will suffice to check for the symbol |
|
It should be possible to compile it first and check the AST instead of checking the symbol, but the code will probably be a bit wordier that way. |
|
Right, so I'm not seeing an easy way to do this. Either I check the Maybe I should add Or maybe this idea isn't workable then and we'll just have to live with the slightly less optimal code generation.
|
|
It's true that both the name |
|
Ah, sorry, I've misunderstood you entirely. Okay, so let me see if I'm following: you're suggesting that the |
6fa7486 to
404c0c8
Compare
|
Okay, merged #1491 into this PR, need to just rework tests, but I think this should do the trick. The following code compiled as expected on both 2 and 3: (get foo (slice 1 2 3) ... bar)will compile to foo[1:2:3][...][bar]The optimization currently falls apart when we use a tuple to have a multidimensional slice, but I think we can merge this and leave that as a separate PR. Just need to fix the tests and add new ones... |
93b4855 to
9e38081
Compare
7671dd0 to
12aa09b
Compare
Bingo.
No, leave
Sounds good. Let us know when you want us to take a look again. |
|
I think it can stand for review now. The code now properly emits the exact same AST that python does, multi or single dimension. I took another step further and I deconstruct tuples when used as arguments to (get foo 1 2 (slice 3 4) ... (slice 5 6))
(get foo (, 1 2 (slice 3 4) ... (slice 5 6)))generating the following equivalent Python: foo[1][2][3:4][...][5:6]
foo[(1), (2), 3:4, (...), 5:6]The second example generates the following AST: Module(
body=[
Expr(
value=Subscript(value=Name(id='foo'),
slice=ExtSlice(
dims=[Index(value=Num(n=1)),
Index(value=Num(n=2)),
Slice(lower=Num(n=3), upper=Num(n=4), step=None),
Index(value=Ellipsis), # and just `Ellipsis` on PY2
Slice(lower=Num(n=5), upper=Num(n=6), step=None)])))])This should put in place all the groundwork for the proposed #1481 change. |
| return (isinstance(x, HyExpression) | ||
| and len(x) > 0 | ||
| and isinstance(x[0], HySymbol) | ||
| and x[0] in (kind, "__builtin__" + kind)) |
There was a problem hiding this comment.
Shouldn't this be x[0] == "__builtins__." + kind? You don't want to allow kind alone because then you'll trigger on slice alone, which might be rebound. Also, you need the period, and note the "s" in __builtins__.
There was a problem hiding this comment.
Well __builtins__.slice doesn't work because __builtins__ is a dictionary, not an object. So we'd have to either change that too or write (get __builtins__ "slice"). And I'm not particularly eager to use that large expression down every time I want a slice to be slightly faster (and to be honest, same for __builtins__.slice).
If we don't feel comfortable with rewriting slice, I can just drop that entire part of the PR.
There was a problem hiding this comment.
Well
__builtins__.slicedoesn't work because__builtins__is a dictionary, not an object.
Are you sure?
$ python2
Python 2.7.14 (default, Sep 23 2017, 22:06:14)
[GCC 7.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> __builtins__.slice
<type 'slice'>
$ python3
Python 3.6.3 (default, Oct 3 2017, 21:45:48)
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> __builtins__.slice
<class 'slice'>
There was a problem hiding this comment.
hy complains though:
=> (cut [1 2 3] 1 2 3)
Traceback (most recent call last):
File "/home/simon/src/hy/hy/importer.py", line 201, in hy_eval
return eval(ast_compile(expr, "<eval>", "eval"), namespace)
File "<eval>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'slice'
=> (type __builtins__)
<class 'dict'>
There was a problem hiding this comment.
Huh, that's a bizarre bug. We don't set __builtins__ anywhere in our code and yet Hy still sees a different object than Python does.
There was a problem hiding this comment.
Oh shoot, that's a feature. Since we hope to be setting __main__ appropriately someday, we can't safely use get nor attribute lookup. I'm afraid I'm not sure what design would make sense, then.
There was a problem hiding this comment.
I'm honestly quite comfortable letting slice mean slice here and just documenting the behaviour. We already prevent slice from being assigned to. Overriding __builtins__.slice in Python also won't change the behaviour of the : operator.
I could also add a check to make sure no slice macro has been defined and/or add slice* to force the construction of a slice object and that probable covers 99% of weird use cases.
There was a problem hiding this comment.
We already prevent
slicefrom being assigned to.
Are you sure?
hy 0.13.0+211.g5c34296 using CPython(default) 3.6.3 on Linux
=> (setv slice "foo")
=> slice
'foo'
Anyway, if we want to make get recognize a magic symbol, why not use : rather than slice? So you'd write e.g. (get foo (: 3 4)) to mean foo[3:4]. This is concise, and literal keywords are already magical as function arguments.
There was a problem hiding this comment.
I do like this better. My concern was that : is HyKeyword(":"), but there's less room for things to blow up.
Are you sure?
Yes your right.
I think I was playing @builds("slice") at the time I tested it and forgot that I had put that in there.
|
|
||
| # How the subscript is constructed will depend on if any of | ||
| # the components subclass ast,slice. If they do, then we have | ||
| # to construct an ExtSlice instead of a Tuple. |
There was a problem hiding this comment.
Is there any reason not to always use ExtSlice instead of a tuple? That would simplify things a bit, if we could use ExtSlice for any multidimensional index.
There was a problem hiding this comment.
Not sure, but I suspect its fine. I figured it made the most send to match exactly what Python does.
There was a problem hiding this comment.
Oh, to expand on this, its probably worth at least merging the identical behaviour. If a simplification works, that's awesome, but that can be added next and at least there's always something more technically correct to revert to.
|
|
||
| (defmacro cut [node &rest body] | ||
| "Take a subset of a list and create a new list from it." | ||
| `(get ~node (__builtin__slice ~@body))) |
| if symbol == "...": | ||
| if not PY3: | ||
| raise HyTypeError(symbol, 'ellipsis is only supported in ' | ||
| 'slices in Python 2') |
There was a problem hiding this comment.
The error message might be better worded as "in Python 2, ellipsis is only supported in slices".
These don't seem to be equivalent: |
|
I think you misunderstood - I'm not saying those two lines of Python are equivalent. Let me rephrase, and remove some noise from that complicated expression: There is now support for multidimensional slices while also preserving chaining. I do it by destructing the tuple - which should be safe __getitem__ interface will present it as a tuple in the first place. |
Refactor to add a proper slice ast compiler. Look for "slice" and handle them specially inside subscripts to emit python slice ast.
5c34296 to
e8799b6
Compare
|
Is this more to your taste then? |
e8799b6 to
6508066
Compare
6508066 to
7a456a5
Compare
|
Yes, it is. I'll take a closer look tomorrow. |
7a456a5 to
d0e0289
Compare
Kodiologist
left a comment
There was a problem hiding this comment.
Finally, don't forget to document : and .... Otherwise, this PR is looking good.
| * new `doc` macro and `#doc` tag macro | ||
| * support for PEP 492 with `fn/a`, `defn/a`, `with/a` and `for/a` | ||
| * remove `def` | ||
| * optimize `slice` inside subscriptions to generate slice AST |
There was a problem hiding this comment.
Update this line for the change to :.
| (get (CutTest) (: 1 6))) | ||
|
|
||
|
|
||
| (defn test-cut [] |
There was a problem hiding this comment.
Shouldn't test-cut be removed from native_tests/langauge.hy now that it's in native_tests/native_macros.hy?
| @checkargs(min=2) | ||
| def compile_index_expression(self, expr): | ||
| expr.pop(0) # index | ||
| def compile_index_expression(self, exprs): |
There was a problem hiding this comment.
The reason we call this sort of parameter expr rather than exprs is because it's set to a single HyExpression.
| if isinstance(other, ast.slice): | ||
| raise TypeError("Can't add %r with slice specific syntax %r" % ( | ||
| self, other)) | ||
|
|
There was a problem hiding this comment.
I get how the nature of ast.slice really bit you during the development of this PR, but will this check really be useful for later programmers?
| ret = Result() | ||
|
|
||
| for expr in exprs: | ||
| if expr_startswith(HyKeyword(":"), expr): |
There was a problem hiding this comment.
Unfortunately, this check isn't strict enough (it allows (get [1 2 3 4 5] ("\ufdd0:" 1 2))) because equality of Hy model objects is very loose about type (#1363). You probably need to check the type of expr explicitly.
There was a problem hiding this comment.
Would it maybe make sense to have a crack at #1363 and fix that first?
There was a problem hiding this comment.
I can wait, honestly. I'd rather see it some in on a more solid foundation.
|
I won't be able to get this done till tomorrow, but I'm thinking of adding some examples to the documentation as well citing numpy. |
At least in Python3, |
|
@vodik, how are we doing here? |
|
Closed for lack of response. |
Proof that its possible to optimize slicing. This code:
Is now equivalent to:
I've also demoted
cutto a macro as its now redundant, but imho still a useful form (still nicer to use when updating a list in place:(setv (cut foo) [1 2 3])