Commit 214d9f11 authored by Tom Niget's avatar Tom Niget

Add support for for-else and while-else

parent cd79036c
......@@ -26,12 +26,19 @@ class FunctionVisitor(BlockVisitor):
def visit_For(self, node: ast.For) -> Iterable[str]:
if not isinstance(node.target, ast.Name):
raise NotImplementedError(node)
if node.orelse:
yield "auto"
yield node.orelse_variable
yield "= true;"
yield f"for (auto {node.target.id} : "
yield from self.expr().visit(node.iter)
yield ")"
yield from self.emit_block(node.inner_scope, node.body)
yield from self.emit_block(node.inner_scope, node.body) # TODO: why not reuse the scope used for analysis? same in while
if node.orelse:
raise NotImplementedError(node, "orelse")
yield "if ("
yield node.orelse_variable
yield ")"
yield from self.emit_block(node.inner_scope, node.orelse)
def visit_If(self, node: ast.If) -> Iterable[str]:
yield "if ("
......@@ -58,12 +65,19 @@ class FunctionVisitor(BlockVisitor):
yield ";"
def visit_While(self, node: ast.While) -> Iterable[str]:
if node.orelse:
yield "auto"
yield node.orelse_variable
yield "= true;"
yield "while ("
yield from self.expr().visit(node.test)
yield ")"
yield from self.emit_block(node.inner_scope, node.body)
if node.orelse:
raise NotImplementedError(node, "orelse")
yield "if ("
yield node.orelse_variable
yield ")"
yield from self.emit_block(node.inner_scope, node.orelse)
def visit_Global(self, node: ast.Global) -> Iterable[str]:
yield ""
......@@ -84,6 +98,9 @@ class FunctionVisitor(BlockVisitor):
yield "}"
def visit_Break(self, node: ast.Break) -> Iterable[str]:
if (loop := self.scope.is_in_loop()).orelse:
yield loop.orelse_variable
yield " = false;"
yield "break;"
def visit_Try(self, node: ast.Try) -> Iterable[str]:
......
......@@ -226,14 +226,17 @@ class ScoperBlockVisitor(ScoperVisitor):
def visit_While(self, node: ast.While):
scope = self.scope.child(ScopeKind.FUNCTION_INNER)
scope.is_loop = True
scope.is_loop = node
node.inner_scope = scope
self.expr().visit(node.test)
body_scope = scope.child(ScopeKind.FUNCTION_INNER)
body_visitor = ScoperBlockVisitor(body_scope, self.root_decls)
body_visitor.visit_block(node.body)
if node.orelse:
raise NotImplementedError(node.orelse)
orelse_scope = scope.child(ScopeKind.FUNCTION_INNER)
orelse_visitor = ScoperBlockVisitor(orelse_scope, self.root_decls)
orelse_visitor.visit_block(node.orelse)
node.orelse_variable = f"orelse_{id(node)}"
def visit_PlainBlock(self, node: PlainBlock):
scope = self.scope.child(ScopeKind.FUNCTION_INNER)
......@@ -243,7 +246,7 @@ class ScoperBlockVisitor(ScoperVisitor):
def visit_For(self, node: ast.For):
scope = self.scope.child(ScopeKind.FUNCTION_INNER)
scope.is_loop = True
scope.is_loop = node
node.inner_scope = scope
assert isinstance(node.target, ast.Name)
var_var = TypeVariable()
......@@ -256,7 +259,10 @@ class ScoperBlockVisitor(ScoperVisitor):
body_visitor = ScoperBlockVisitor(body_scope, self.root_decls)
body_visitor.visit_block(node.body)
if node.orelse:
raise NotImplementedError(node.orelse)
orelse_scope = scope.child(ScopeKind.FUNCTION_INNER)
orelse_visitor = ScoperBlockVisitor(orelse_scope, self.root_decls)
orelse_visitor.visit_block(node.orelse)
node.orelse_variable = f"orelse_{id(node)}"
def visit_Expr(self, node: ast.Expr):
self.expr().visit(node.value)
......
import ast
from dataclasses import field, dataclass
from enum import Enum
from typing import Optional, Dict, List, Any
......@@ -55,7 +56,7 @@ class Scope:
obj_type: Optional[BaseType] = None
has_return: bool = False
class_: Optional["Scope"] = None
is_loop: bool = False
is_loop: Optional[ast.For | ast.While] = None
@staticmethod
def make_global():
......@@ -63,12 +64,12 @@ class Scope:
res.global_scope = res
return res
def is_in_loop(self) -> bool:
def is_in_loop(self) -> Optional[ast.For | ast.While]:
if self.is_loop:
return True
return self.is_loop
if self.parent is not None and self.kind != ScopeKind.FUNCTION:
return self.parent.is_in_loop()
return False
return None
def child(self, kind: ScopeKind):
res = Scope(self, kind, self.function, self.global_scope)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment