Merge pull request #824 from kirbyfan64/short-circuit

Make and/or short-circuit
This commit is contained in:
Morten Linderud 2015-07-31 23:57:25 +02:00
commit b6c3289bbe
2 changed files with 89 additions and 12 deletions

View File

@ -1676,17 +1676,78 @@ class HyASTCompiler(object):
@builds("and")
@builds("or")
@checkargs(min=2)
def compile_logical_or_and_and_operator(self, expression):
ops = {"and": ast.And,
"or": ast.Or}
ops = {"and": (ast.And, "True"),
"or": (ast.Or, "None")}
operator = expression.pop(0)
values, ret, _ = self._compile_collect(expression)
opnode, default = ops[operator]
root_line, root_column = operator.start_line, operator.start_column
if len(expression) == 0:
return ast.Name(id=default,
ctx=ast.Load(),
lineno=root_line,
col_offset=root_column)
elif len(expression) == 1:
return self.compile(expression[0])
ret = Result()
values = list(map(self.compile, expression))
has_stmt = any(value.stmts for value in values)
if has_stmt:
# Compile it to an if...else sequence
var = self.get_anon_var()
name = ast.Name(id=var,
ctx=ast.Store(),
lineno=root_line,
col_offset=root_column)
expr_name = ast.Name(id=var,
ctx=ast.Load(),
lineno=root_line,
col_offset=root_column)
ret += ast.BoolOp(op=ops[operator](),
lineno=operator.start_line,
col_offset=operator.start_column,
values=values)
def make_assign(value, node=None):
if node is None:
line, column = root_line, root_column
else:
line, column = node.lineno, node.col_offset
return ast.Assign(targets=[ast.Name(id=var,
ctx=ast.Store(),
lineno=line,
col_offset=column)],
value=value,
lineno=line,
col_offset=column)
root = []
current = root
for i, value in enumerate(values):
if value.stmts:
node = value.stmts[0]
current.extend(value.stmts)
else:
node = value.expr
current.append(make_assign(value.force_expr, value.force_expr))
if i == len(values)-1:
# Skip a redundant 'if'.
break
if operator == "and":
cond = expr_name
elif operator == "or":
cond = ast.UnaryOp(op=ast.Not(),
operand=expr_name,
lineno=node.lineno,
col_offset=node.col_offset)
current.append(ast.If(test=cond,
body=[],
lineno=node.lineno,
col_offset=node.col_offset,
orelse=[]))
current = current[-1].body
ret = sum(root, ret)
ret += Result(expr=expr_name, temp_variables=[expr_name, name])
else:
ret += ast.BoolOp(op=opnode(),
lineno=root_line,
col_offset=root_column,
values=[value.force_expr for value in values])
return ret
@builds("=")

View File

@ -782,19 +782,35 @@
(defn test-and []
"NATIVE: test the and function"
(let [[and123 (and 1 2 3)]
[and-false (and 1 False 3)]]
[and-false (and 1 False 3)]
[and-true (and)]
[and-single (and 1)]]
(assert (= and123 3))
(assert (= and-false False))))
(assert (= and-false False))
(assert (= and-true True))
(assert (= and-single 1)))
; short circuiting
(setv a 1)
(and 0 (setv a 2))
(assert (= a 1)))
(defn test-or []
"NATIVE: test the or function"
(let [[or-all-true (or 1 2 3 True "string")]
[or-some-true (or False "hello")]
[or-none-true (or False False)]]
[or-none-true (or False False)]
[or-false (or)]
[or-single (or 1)]]
(assert (= or-all-true 1))
(assert (= or-some-true "hello"))
(assert (= or-none-true False))))
(assert (= or-none-true False))
(assert (= or-false nil))
(assert (= or-single 1)))
; short circuiting
(setv a 1)
(or 1 (setv a 2))
(assert (= a 1)))
(defn test-if-return-branching []