Merge pull request #824 from kirbyfan64/short-circuit
Make and/or short-circuit
This commit is contained in:
commit
b6c3289bbe
@ -1676,17 +1676,78 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
@builds("and")
|
@builds("and")
|
||||||
@builds("or")
|
@builds("or")
|
||||||
@checkargs(min=2)
|
|
||||||
def compile_logical_or_and_and_operator(self, expression):
|
def compile_logical_or_and_and_operator(self, expression):
|
||||||
ops = {"and": ast.And,
|
ops = {"and": (ast.And, "True"),
|
||||||
"or": ast.Or}
|
"or": (ast.Or, "None")}
|
||||||
operator = expression.pop(0)
|
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](),
|
def make_assign(value, node=None):
|
||||||
lineno=operator.start_line,
|
if node is None:
|
||||||
col_offset=operator.start_column,
|
line, column = root_line, root_column
|
||||||
values=values)
|
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
|
return ret
|
||||||
|
|
||||||
@builds("=")
|
@builds("=")
|
||||||
|
@ -782,19 +782,35 @@
|
|||||||
(defn test-and []
|
(defn test-and []
|
||||||
"NATIVE: test the and function"
|
"NATIVE: test the and function"
|
||||||
(let [[and123 (and 1 2 3)]
|
(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 (= 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 []
|
(defn test-or []
|
||||||
"NATIVE: test the or function"
|
"NATIVE: test the or function"
|
||||||
(let [[or-all-true (or 1 2 3 True "string")]
|
(let [[or-all-true (or 1 2 3 True "string")]
|
||||||
[or-some-true (or False "hello")]
|
[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-all-true 1))
|
||||||
(assert (= or-some-true "hello"))
|
(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 []
|
(defn test-if-return-branching []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user