Repository: hylang/hy

Issue:
add 3.5 matmul bits
We should do a sweep against 3.5 and find the new features to add -- I think AST stayed pretty stable



Discussion:

Resolving patch:
diff --git a/hy/_compat.py b/hy/_compat.py
--- a/hy/_compat.py
+++ b/hy/_compat.py
@@ -42,6 +42,7 @@ def wr_long(f, x):
 PY3 = sys.version_info[0] >= 3
 PY33 = sys.version_info >= (3, 3)
 PY34 = sys.version_info >= (3, 4)
+PY35 = sys.version_info >= (3, 5)
 
 if PY3:
     str_type = str
diff --git a/hy/compiler.py b/hy/compiler.py
--- a/hy/compiler.py
+++ b/hy/compiler.py
@@ -38,7 +38,8 @@
 from hy.errors import HyCompileError, HyTypeError
 
 import hy.macros
-from hy._compat import str_type, long_type, PY27, PY33, PY3, PY34, raise_empty
+from hy._compat import (
+    str_type, long_type, PY27, PY33, PY3, PY34, PY35, raise_empty)
 from hy.macros import require, macroexpand, reader_macroexpand
 import hy.importer
 
@@ -121,6 +122,13 @@ def _dec(fn):
     return _dec
 
 
+def builds_if(_type, condition):
+    if condition:
+        return builds(_type)
+    else:
+        return lambda fn: fn
+
+
 class Result(object):
     """
     Smart representation of the result of a hy->AST compilation
@@ -1638,6 +1646,7 @@ def compile_compare_op_expression(self, expression):
     @builds("|")
     @builds("^")
     @builds("&")
+    @builds_if("@", PY35)
     @checkargs(min=2)
     def compile_maths_expression(self, expression):
         ops = {"+": ast.Add,
@@ -1652,6 +1661,8 @@ def compile_maths_expression(self, expression):
                "|": ast.BitOr,
                "^": ast.BitXor,
                "&": ast.BitAnd}
+        if PY35:
+            ops.update({"@": ast.MatMult})
 
         inv = expression.pop(0)
         op = ops[inv]
@@ -1711,6 +1722,7 @@ def compile_maths_expression_sub(self, expression):
     @builds("|=")
     @builds("^=")
     @builds("&=")
+    @builds_if("@=", PY35)
     @checkargs(2)
     def compile_augassign_expression(self, expression):
         ops = {"+=": ast.Add,
@@ -1725,6 +1737,8 @@ def compile_augassign_expression(self, expression):
                "|=": ast.BitOr,
                "^=": ast.BitXor,
                "&=": ast.BitAnd}
+        if PY35:
+            ops.update({"@=": ast.MatMult})
 
         op = ops[expression[0]]
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -45,7 +45,7 @@
 make things work nicer, and lets Python and the Hy lisp variant play
 nice together. """
 
-install_requires = ['rply>=0.7.0', 'astor>=0.3', 'clint>=0.4']
+install_requires = ['rply>=0.7.0', 'astor>=0.5', 'clint>=0.4']
 if sys.version_info[:2] < (2, 7):
     install_requires.append('argparse>=1.2.1')
     install_requires.append('importlib>=1.0.2')


Test patch:
diff --git a/tests/native_tests/mathematics.hy b/tests/native_tests/mathematics.hy
--- a/tests/native_tests/mathematics.hy
+++ b/tests/native_tests/mathematics.hy
@@ -1,3 +1,5 @@
+(import [hy._compat [PY35]])
+
 (setv square (fn [x]
                (* x x)))
 
@@ -140,3 +142,52 @@
 (defn overflow-int-to-long []
   "NATIVE: test if int does not raise an overflow exception"
   (assert (integer? (+ 1 1000000000000000000000000))))
+
+
+(defclass HyTestMatrix [list]
+  [[--matmul--
+    (fn [self other]
+      (let [[n (len self)]
+            [m (len (. other [0]))]
+            [result []]]
+        (for [i (range m)]
+          (let [[result-row []]]
+            (for [j (range n)]
+              (let [[dot-product 0]]
+                (for [k (range (len (. self [0])))]
+                  (+= dot-product (* (. self [i] [k])
+                                     (. other [k] [j]))))
+                (.append result-row dot-product)))
+            (.append result result-row)))
+        result))]])
+
+(def first-test-matrix (HyTestMatrix [[1 2 3]
+                                      [4 5 6]
+                                      [7 8 9]]))
+
+(def second-test-matrix (HyTestMatrix [[2 0 0]
+                                       [0 2 0]
+                                       [0 0 2]]))
+
+(def product-of-test-matrices (HyTestMatrix [[ 2  4  6]
+                                             [ 8 10 12]
+                                             [14 16 18]]))
+
+(defn test-matmul []
+  "NATIVE: test matrix multiplication"
+  (if PY35
+    (assert (= (@ first-test-matrix second-test-matrix)
+               product-of-test-matrices))
+    ;; Python <= 3.4
+    (let [[matmul-attempt (try (@ first-test-matrix second-test-matrix)
+                               (catch [e [Exception]] e))]]
+      (assert (isinstance matmul-attempt NameError)))))
+
+(defn test-augassign-matmul []
+  "NATIVE: test augmented-assignment matrix multiplication"
+  (let [[matrix first-test-matrix]
+        [matmul-attempt (try (@= matrix second-test-matrix)
+                              (catch [e [Exception]] e))]]
+    (if PY35
+      (assert (= product-of-test-matrices matrix))
+      (assert (isinstance matmul-attempt NameError)))))