Allow keyword args in method calls before the obj (#1167)
Unlike Python, Hy allows the programmer to intermingle positional and keyword arguments. This change removes an exception to that rule for method calls, in which the method callee always had to be the first thing after the method. Thus, `(.split :sep "o" "foo")` now compiles to `"foo".split(sep="o")` instead of `HyKeyword("sep").split("o", "foo")`.
This commit is contained in:
parent
7aaf5f5330
commit
ed930edefe
@ -2068,12 +2068,25 @@ class HyASTCompiler(object):
|
||||
|
||||
# Get the object we're calling the method on
|
||||
# (extracted with the attribute access DSL)
|
||||
if len(expression) < 2:
|
||||
raise HyTypeError(expression,
|
||||
"attribute access requires object")
|
||||
|
||||
i = 1
|
||||
if len(expression) != 2:
|
||||
# If the expression has only one object,
|
||||
# always use that as the callee.
|
||||
# Otherwise, hunt for the first thing that
|
||||
# isn't a keyword argument or its value.
|
||||
while i < len(expression):
|
||||
if isinstance(expression[i], HyKeyword):
|
||||
# Skip the keyword argument and its value.
|
||||
i += 1
|
||||
else:
|
||||
# Use expression[i].
|
||||
break
|
||||
i += 1
|
||||
else:
|
||||
raise HyTypeError(expression,
|
||||
"attribute access requires object")
|
||||
func = self.compile(HyExpression(
|
||||
[HySymbol(".").replace(fn), expression.pop(1)] +
|
||||
[HySymbol(".").replace(fn), expression.pop(i)] +
|
||||
attrs))
|
||||
|
||||
# And get the method
|
||||
|
@ -397,26 +397,32 @@
|
||||
|
||||
(defclass X [object] [])
|
||||
(defclass M [object]
|
||||
[meth (fn [self &rest args]
|
||||
(.join " " (+ (, "meth") args)))])
|
||||
[meth (fn [self &rest args &kwargs kwargs]
|
||||
(.join " " (+ (, "meth") args
|
||||
(tuple (map (fn [k] (get kwargs k)) (sorted (.keys kwargs)))))))])
|
||||
|
||||
(setv x (X))
|
||||
(setv m (M))
|
||||
|
||||
(assert (= (.meth m) "meth"))
|
||||
(assert (= (.meth m "foo" "bar") "meth foo bar"))
|
||||
(assert (= (.meth :b "1" :a "2" m "foo" "bar") "meth foo bar 2 1"))
|
||||
(assert (= (apply .meth [m "foo" "bar"]) "meth foo bar"))
|
||||
|
||||
(setv x.p m)
|
||||
(assert (= (.p.meth x) "meth"))
|
||||
(assert (= (.p.meth x "foo" "bar") "meth foo bar"))
|
||||
(assert (= (.p.meth :b "1" :a "2" x "foo" "bar") "meth foo bar 2 1"))
|
||||
(assert (= (apply .p.meth [x "foo" "bar"]) "meth foo bar"))
|
||||
|
||||
(setv x.a (X))
|
||||
(setv x.a.b m)
|
||||
(assert (= (.a.b.meth x) "meth"))
|
||||
(assert (= (.a.b.meth x "foo" "bar") "meth foo bar"))
|
||||
(assert (= (apply .a.b.meth [x "foo" "bar"]) "meth foo bar")))
|
||||
(assert (= (.a.b.meth :b "1" :a "2" x "foo" "bar") "meth foo bar 2 1"))
|
||||
(assert (= (apply .a.b.meth [x "foo" "bar"]) "meth foo bar"))
|
||||
|
||||
(assert (is (.isdigit :foo) False)))
|
||||
|
||||
|
||||
(defn test-do []
|
||||
|
Loading…
Reference in New Issue
Block a user