diff --git a/docs/language/api.rst b/docs/language/api.rst index 67ef630..8bb86a9 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -357,7 +357,9 @@ attributes of the new class as two item vectors. .. code-block:: clj (defclass class-name [super-class-1 super-class-2] - [[attribute value]]) + [attribute value] + + (defn method [self] (print "hello!"))) Both values and functions can be bound on the new class as shown by the example below: @@ -365,9 +367,10 @@ below: .. code-block:: clj => (defclass Cat [] - ... [[age None] - ... [colour "white"] - ... [speak (fn [self] (print "Meow"))]]) + ... [age None + ... colour "white"] + ... + ... (defn speak [self] (print "Meow"))) => (def spot (Cat)) => (setv spot.colour "Black") diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 6b32b30..1eedea1 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -477,17 +477,14 @@ In Hy: (defclass FooBar [object] "Yet Another Example Class" - [[--init-- - (fn [self x] - (setv self.x x) - ; Currently needed for --init-- because __init__ needs None - ; Hopefully this will go away :) - None)] - [get-x - (fn [self] - "Return our copy of x" - self.x)]]) + (defn --init-- [self x] + (setv self.x x) + None) + + (defn get-x [self] + "Return our copy of x" + self.x)) You can also do class-level attributes. In Python:: @@ -502,9 +499,9 @@ In Hy: .. code-block:: clj (defclass Customer [models.Model] - [[name (models.CharField :max-length 255})] - [address (models.TextField)] - [notes (models.TextField)]]) + [name (models.CharField :max-length 255}) + address (models.TextField) + notes (models.TextField)]) Hy <-> Python interop ===================== diff --git a/hy/compiler.py b/hy/compiler.py index cd00530..dfc2bb1 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -2238,15 +2238,15 @@ class HyASTCompiler(object): @builds("defclass") @checkargs(min=1) - def compile_class_expression(self, expression): - expression.pop(0) # class + def compile_class_expression(self, expressions): + expressions.pop(0) # class - class_name = expression.pop(0) + class_name = expressions.pop(0) - if expression: - base_list = expression.pop(0) + if expressions: + base_list = expressions.pop(0) if not isinstance(base_list, HyList): - raise HyTypeError(expression, + raise HyTypeError(expressions, "Bases class must be a list") bases_expr, bases, _ = self._compile_collect(base_list) else: @@ -2256,8 +2256,8 @@ class HyASTCompiler(object): body = Result() # grab the doc string, if there is one - if expression and isinstance(expression[0], HyString): - docstring = expression.pop(0) + if expressions and isinstance(expressions[0], HyString): + docstring = expressions.pop(0) symb = HySymbol("__doc__") symb.start_line = docstring.start_line symb.start_column = docstring.start_column @@ -2266,31 +2266,25 @@ class HyASTCompiler(object): docstring.start_column) body += body.expr_as_stmt() - if expression: - try: - body_expression = iter(expression.pop(0)) - except TypeError: - raise HyTypeError( - expression, - "Wrong argument type for defclass attributes definition.") - for b in body_expression: - if isinstance(b, HyExpression): - b = macroexpand(b, self.module_name) - if len(b) != 2: - raise HyTypeError( - expression, - "Wrong number of argument in defclass attribute.") - body += self._compile_assign(b[0], b[1], - b.start_line, b.start_column) - body += body.expr_as_stmt() + if expressions and isinstance(expressions[0], HyList) \ + and not isinstance(expressions[0], HyExpression): + expr = expressions.pop(0) + body += self.compile( + HyExpression([ + HySymbol("setv") + ] + expr).replace(expr) + ) + + for expression in expressions: + body += self.compile(macroexpand(expression, self.module_name)) if not body.stmts: - body += ast.Pass(lineno=expression.start_line, - col_offset=expression.start_column) + body += ast.Pass(lineno=expressions.start_line, + col_offset=expressions.start_column) return bases + ast.ClassDef( - lineno=expression.start_line, - col_offset=expression.start_column, + lineno=expressions.start_line, + col_offset=expressions.start_column, decorator_list=[], name=ast_str(class_name), keywords=[], diff --git a/tests/native_tests/contrib/meth.hy b/tests/native_tests/contrib/meth.hy index 446bb81..d07adeb 100644 --- a/tests/native_tests/contrib/meth.hy +++ b/tests/native_tests/contrib/meth.hy @@ -2,12 +2,11 @@ (defclass FakeMeth [] "Mocking decorator class" - [[rules {}] - [route (fn [self rule &kwargs options] - (fn [f] - (assoc self.rules rule (, f options)) - f))]]) - + [rules {}] + (defn route [self rule &kwargs options] + (fn [f] + (assoc self.rules rule (, f options)) + f))) (defn test_route [] (let [[app (FakeMeth)]] diff --git a/tests/native_tests/defclass.hy b/tests/native_tests/defclass.hy index badb74c..3da9aa4 100644 --- a/tests/native_tests/defclass.hy +++ b/tests/native_tests/defclass.hy @@ -23,7 +23,7 @@ (defn test-defclass-attrs [] "NATIVE: test defclass attributes" (defclass A [] - [[x 42]]) + [x 42]) (assert (= A.x 42)) (assert (= (getattr (A) "x") 42))) @@ -31,9 +31,9 @@ (defn test-defclass-attrs-fn [] "NATIVE: test defclass attributes with fn" (defclass B [] - [[x 42] - [y (fn [self value] - (+ self.x value))]]) + [x 42 + y (fn [self value] + (+ self.x value))]) (assert (= B.x 42)) (assert (= (.y (B) 5) 47)) (let [[b (B)]] @@ -44,17 +44,17 @@ (defn test-defclass-dynamic-inheritance [] "NATIVE: test defclass with dynamic inheritance" (defclass A [((fn [] (if true list dict)))] - [[x 42]]) + [x 42]) (assert (isinstance (A) list)) (defclass A [((fn [] (if false list dict)))] - [[x 42]]) + [x 42]) (assert (isinstance (A) dict))) (defn test-defclass-no-fn-leak [] "NATIVE: test defclass attributes with fn" (defclass A [] - [[x (fn [] 1)]]) + [x (fn [] 1)]) (try (do (x) @@ -64,13 +64,13 @@ (defn test-defclass-docstring [] "NATIVE: test defclass docstring" (defclass A [] - [[--doc-- "doc string"] - [x 1]]) + [--doc-- "doc string" + x 1]) (setv a (A)) (assert (= a.__doc__ "doc string")) (defclass B [] "doc string" - [[x 1]]) + [x 1]) (setv b (B)) (assert (= b.x 1)) (assert (= b.__doc__ "doc string")) @@ -78,7 +78,7 @@ "begin a very long multi-line string to make sure that it comes out the way we hope and can span 3 lines end." - [[x 1]]) + [x 1]) (setv mL (MultiLine)) (assert (= mL.x 1)) (assert (in "begin" mL.__doc__)) @@ -86,8 +86,26 @@ (defn test-defclass-macroexpand [] "NATIVE: test defclass with macro expand" - (defmacro M [] `[x (fn [self x] (setv self._x x))]) - (defclass A [] [(M)]) + (defmacro M [] `(defn x [self x] (setv self._x x))) + (defclass A [] (M)) (setv a (A)) (a.x 1) (assert (= a._x 1))) + +(defn test-defclass-syntax [] + "NATIVE: test defclass syntax with properties and methods and side-effects" + (setv foo 1) + (defclass A [] + [x 1 + y 2] + (global foo) + (setv foo 2) + (defn greet [self] + "Greet the caller" + + "hello!")) + (setv a (A)) + (assert (= a.x 1)) + (assert (= a.y 2)) + (assert foo 2) + (assert (.greet a) "hello")) diff --git a/tests/native_tests/mathematics.hy b/tests/native_tests/mathematics.hy index e9a8945..7660363 100644 --- a/tests/native_tests/mathematics.hy +++ b/tests/native_tests/mathematics.hy @@ -145,21 +145,21 @@ (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))]]) + [--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] diff --git a/tests/native_tests/with_decorator.hy b/tests/native_tests/with_decorator.hy index 2c8e930..5c5772d 100644 --- a/tests/native_tests/with_decorator.hy +++ b/tests/native_tests/with_decorator.hy @@ -13,7 +13,7 @@ (with-decorator bardec (defclass cls [] - [[my_attr 456]])) + [my_attr 456])) (defn test-decorator-clobbing [] "NATIVE: Tests whether nested decorators work" diff --git a/tests/native_tests/with_test.hy b/tests/native_tests/with_test.hy index b094f35..7b51923 100644 --- a/tests/native_tests/with_test.hy +++ b/tests/native_tests/with_test.hy @@ -1,16 +1,13 @@ (defclass WithTest [object] - [(--init-- - (fn [self val] - (setv self.val val) - None)) + (defn --init-- [self val] + (setv self.val val) + None) - (--enter-- - (fn [self] - self.val)) + (defn --enter-- [self] + self.val) - (--exit-- - (fn [self type value traceback] - (setv self.val None)))]) + (defn --exit-- [self type value traceback] + (setv self.val None))) (defn test-single-with [] "NATIVE: test a single with"