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): ...@@ -26,12 +26,19 @@ class FunctionVisitor(BlockVisitor):
def visit_For(self, node: ast.For) -> Iterable[str]: def visit_For(self, node: ast.For) -> Iterable[str]:
if not isinstance(node.target, ast.Name): if not isinstance(node.target, ast.Name):
raise NotImplementedError(node) raise NotImplementedError(node)
if node.orelse:
yield "auto"
yield node.orelse_variable
yield "= true;"
yield f"for (auto {node.target.id} : " yield f"for (auto {node.target.id} : "
yield from self.expr().visit(node.iter) yield from self.expr().visit(node.iter)
yield ")" 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: 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]: def visit_If(self, node: ast.If) -> Iterable[str]:
yield "if (" yield "if ("
...@@ -58,12 +65,19 @@ class FunctionVisitor(BlockVisitor): ...@@ -58,12 +65,19 @@ class FunctionVisitor(BlockVisitor):
yield ";" yield ";"
def visit_While(self, node: ast.While) -> Iterable[str]: def visit_While(self, node: ast.While) -> Iterable[str]:
if node.orelse:
yield "auto"
yield node.orelse_variable
yield "= true;"
yield "while (" yield "while ("
yield from self.expr().visit(node.test) yield from self.expr().visit(node.test)
yield ")" yield ")"
yield from self.emit_block(node.inner_scope, node.body) yield from self.emit_block(node.inner_scope, node.body)
if node.orelse: 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]: def visit_Global(self, node: ast.Global) -> Iterable[str]:
yield "" yield ""
...@@ -84,6 +98,9 @@ class FunctionVisitor(BlockVisitor): ...@@ -84,6 +98,9 @@ class FunctionVisitor(BlockVisitor):
yield "}" yield "}"
def visit_Break(self, node: ast.Break) -> Iterable[str]: 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;" yield "break;"
def visit_Try(self, node: ast.Try) -> Iterable[str]: def visit_Try(self, node: ast.Try) -> Iterable[str]:
......
...@@ -226,14 +226,17 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -226,14 +226,17 @@ class ScoperBlockVisitor(ScoperVisitor):
def visit_While(self, node: ast.While): def visit_While(self, node: ast.While):
scope = self.scope.child(ScopeKind.FUNCTION_INNER) scope = self.scope.child(ScopeKind.FUNCTION_INNER)
scope.is_loop = True scope.is_loop = node
node.inner_scope = scope node.inner_scope = scope
self.expr().visit(node.test) self.expr().visit(node.test)
body_scope = scope.child(ScopeKind.FUNCTION_INNER) body_scope = scope.child(ScopeKind.FUNCTION_INNER)
body_visitor = ScoperBlockVisitor(body_scope, self.root_decls) body_visitor = ScoperBlockVisitor(body_scope, self.root_decls)
body_visitor.visit_block(node.body) body_visitor.visit_block(node.body)
if node.orelse: 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): def visit_PlainBlock(self, node: PlainBlock):
scope = self.scope.child(ScopeKind.FUNCTION_INNER) scope = self.scope.child(ScopeKind.FUNCTION_INNER)
...@@ -243,7 +246,7 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -243,7 +246,7 @@ class ScoperBlockVisitor(ScoperVisitor):
def visit_For(self, node: ast.For): def visit_For(self, node: ast.For):
scope = self.scope.child(ScopeKind.FUNCTION_INNER) scope = self.scope.child(ScopeKind.FUNCTION_INNER)
scope.is_loop = True scope.is_loop = node
node.inner_scope = scope node.inner_scope = scope
assert isinstance(node.target, ast.Name) assert isinstance(node.target, ast.Name)
var_var = TypeVariable() var_var = TypeVariable()
...@@ -256,7 +259,10 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -256,7 +259,10 @@ class ScoperBlockVisitor(ScoperVisitor):
body_visitor = ScoperBlockVisitor(body_scope, self.root_decls) body_visitor = ScoperBlockVisitor(body_scope, self.root_decls)
body_visitor.visit_block(node.body) body_visitor.visit_block(node.body)
if node.orelse: 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): def visit_Expr(self, node: ast.Expr):
self.expr().visit(node.value) self.expr().visit(node.value)
......
import ast
from dataclasses import field, dataclass from dataclasses import field, dataclass
from enum import Enum from enum import Enum
from typing import Optional, Dict, List, Any from typing import Optional, Dict, List, Any
...@@ -55,7 +56,7 @@ class Scope: ...@@ -55,7 +56,7 @@ class Scope:
obj_type: Optional[BaseType] = None obj_type: Optional[BaseType] = None
has_return: bool = False has_return: bool = False
class_: Optional["Scope"] = None class_: Optional["Scope"] = None
is_loop: bool = False is_loop: Optional[ast.For | ast.While] = None
@staticmethod @staticmethod
def make_global(): def make_global():
...@@ -63,12 +64,12 @@ class Scope: ...@@ -63,12 +64,12 @@ class Scope:
res.global_scope = res res.global_scope = res
return res return res
def is_in_loop(self) -> bool: def is_in_loop(self) -> Optional[ast.For | ast.While]:
if self.is_loop: if self.is_loop:
return True return self.is_loop
if self.parent is not None and self.kind != ScopeKind.FUNCTION: if self.parent is not None and self.kind != ScopeKind.FUNCTION:
return self.parent.is_in_loop() return self.parent.is_in_loop()
return False return None
def child(self, kind: ScopeKind): def child(self, kind: ScopeKind):
res = Scope(self, kind, self.function, self.global_scope) 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