diff --git a/hy/compiler.py b/hy/compiler.py index aa993b7..4c8dea0 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -2059,19 +2059,24 @@ class HyASTCompiler(object): if fn.startswith("."): # (.split "test test") -> "test test".split() + # (.a.b.c x) -> (.c (. x a b)) -> x.a.b.c() - # Get the attribute name - ofn = fn - fn = HySymbol(ofn[1:]) - fn.replace(ofn) + # Get the method name (the last named attribute + # in the chain of attributes) + attrs = [HySymbol(a).replace(fn) for a in fn.split(".")[1:]] + fn = attrs.pop() - # Get the object we want to take an attribute from + # 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") - func = self.compile(expression.pop(1)) - # And get the attribute + func = self.compile(HyExpression( + [HySymbol(".").replace(fn), expression.pop(1)] + + attrs)) + + # And get the method func += ast.Attribute(lineno=fn.start_line, col_offset=fn.start_column, value=func.force_expr, diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index b06b714..39ed389 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -399,7 +399,30 @@ (defn test-dotted [] "NATIVE: test dotted invocation" - (assert (= (.join " " ["one" "two"]) "one two"))) + (assert (= (.join " " ["one" "two"]) "one two")) + + (defclass X [object] []) + (defclass M [object] + [meth (fn [self &rest args] + (.join " " (+ (, "meth") args)))]) + + (setv x (X)) + (setv m (M)) + + (assert (= (.meth m) "meth")) + (assert (= (.meth m "foo" "bar") "meth foo bar")) + (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 (= (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"))) (defn test-do []