diff --git a/hy/compiler.py b/hy/compiler.py index 34402bc..46a2deb 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -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 diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 261b49a..6893b4b 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -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 []