Merge pull request #1536 from vodik/fix-defclass

Fix `defclass`
This commit is contained in:
Kodi Arfer 2018-03-31 12:58:32 -07:00 committed by GitHub
commit 39587e6f23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 10 deletions

View File

@ -27,6 +27,7 @@ Bug Fixes
------------------------------ ------------------------------
* Fix `(return)` so it works correctly to exit a Python 2 generator * Fix `(return)` so it works correctly to exit a Python 2 generator
* Fixed a case where `->` and `->>` duplicated an argument * Fixed a case where `->` and `->>` duplicated an argument
* Fixed bugs that caused `defclass` to drop statements or crash
Misc. Improvements Misc. Improvements
---------------------------- ----------------------------

View File

@ -20,10 +20,8 @@ import hy.inspect
import traceback import traceback
import importlib import importlib
import codecs
import ast import ast
import sys import sys
import keyword
import copy import copy
from collections import defaultdict from collections import defaultdict
@ -2038,7 +2036,10 @@ class HyASTCompiler(object):
def compile_class_expression(self, expressions): def compile_class_expression(self, expressions):
def rewire_init(expr): def rewire_init(expr):
new_args = [] new_args = []
if expr[0] == HySymbol("setv"): if (isinstance(expr, HyExpression)
and len(expr) > 1
and isinstance(expr[0], HySymbol)
and expr[0] == HySymbol("setv")):
pairs = expr[1:] pairs = expr[1:]
while len(pairs) > 0: while len(pairs) > 0:
k, v = (pairs.pop(0), pairs.pop(0)) k, v = (pairs.pop(0), pairs.pop(0))
@ -2070,13 +2071,12 @@ class HyASTCompiler(object):
body = Result() body = Result()
# grab the doc string, if there is one # grab the doc string, if there is one
docstring = None
if expressions and isinstance(expressions[0], HyString): if expressions and isinstance(expressions[0], HyString):
docstring = expressions.pop(0) docstring = expressions.pop(0)
symb = HySymbol("__doc__") if not PY37:
symb.start_line = docstring.start_line body += self.compile(docstring).expr_as_stmt()
symb.start_column = docstring.start_column docstring = None
body += self._compile_assign(symb, docstring)
body += body.expr_as_stmt()
if expressions and isinstance(expressions[0], HyList) \ if expressions and isinstance(expressions[0], HyList) \
and not isinstance(expressions[0], HyExpression): and not isinstance(expressions[0], HyExpression):
@ -2087,7 +2087,8 @@ class HyASTCompiler(object):
body += self.compile(rewire_init(expr)) body += self.compile(rewire_init(expr))
for expression in expressions: for expression in expressions:
body += self.compile(rewire_init(macroexpand(expression, self))) e = self.compile(rewire_init(macroexpand(expression, self)))
body += e + e.expr_as_stmt()
if not body.stmts: if not body.stmts:
body += asty.Pass(expressions) body += asty.Pass(expressions)
@ -2100,7 +2101,8 @@ class HyASTCompiler(object):
starargs=None, starargs=None,
kwargs=None, kwargs=None,
bases=bases_expr, bases=bases_expr,
body=body.stmts) body=body.stmts,
docstring=(None if docstring is None else str_type(docstring)))
@builds("dispatch-tag-macro") @builds("dispatch-tag-macro")
@checkargs(exact=2) @checkargs(exact=2)

View File

@ -212,6 +212,9 @@ def test_ast_good_defclass():
"Make sure AST can compile valid defclass" "Make sure AST can compile valid defclass"
can_compile("(defclass a)") can_compile("(defclass a)")
can_compile("(defclass a [])") can_compile("(defclass a [])")
can_compile("(defclass a [] None 42)")
can_compile("(defclass a [] None \"test\")")
can_compile("(defclass a [] None (print \"foo\"))")
@pytest.mark.skipif(not PY3, reason="Python 3 supports class keywords") @pytest.mark.skipif(not PY3, reason="Python 3 supports class keywords")

View File

@ -127,3 +127,14 @@
(setv b (B)) (setv b (B))
(assert (= a.x 1)) (assert (= a.x 1))
(assert (= b.x 2))) (assert (= b.x 2)))
(defn test-class-sideeffects []
"NATIVE: test that defclass runs all expressions"
(defn set-sentinel []
(setv set-sentinel.set True))
(setv set-sentinel.set False)
(defclass A []
(set-sentinel))
(assert set-sentinel.set))