From 8bcf97eede4673695d78eed45f4aaf9c374cc818 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Wed, 23 Oct 2024 17:41:22 +0200 Subject: [PATCH 1/6] While: Add new `while` expression --- src/lang/lang.h | 10 ++++++---- src/lang/passes/call_stmts.cc | 2 +- src/lang/passes/flatten.cc | 23 ++++++++++++++++++++++- src/lang/passes/grouping.cc | 2 ++ src/lang/passes/parse.cc | 16 +++++++++++++--- tests/exprs/while.vpy | 8 ++++++++ 6 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 tests/exprs/while.vpy diff --git a/src/lang/lang.h b/src/lang/lang.h index aa1cd97..220e256 100644 --- a/src/lang/lang.h +++ b/src/lang/lang.h @@ -10,6 +10,7 @@ using namespace trieste; inline const TokenDef Ident{"ident", trieste::flag::print}; inline const TokenDef Assign{"assign"}; inline const TokenDef For{"for"}; +inline const TokenDef While{"while"}; inline const TokenDef If{"if"}; inline const TokenDef Else{"else"}; inline const TokenDef Block{"block"}; @@ -34,15 +35,16 @@ namespace verona::wf inline const auto cmp_values = Ident | Lookup | Null; inline const auto key = Ident | Lookup | String; inline const auto operand = Lookup | Call | Method | Ident; - inline const auto Cond = Eq | Neq; + inline const auto Cond = Eq | Neq | Call | Method; inline const auto grouping = (Top <<= File) | (File <<= Body) | (Body <<= Block) | (Block <<= - (Assign | If | For | Func | Return | ReturnValue | Call | Method)++) | + (Assign | If | For | While | Func | Return | ReturnValue | Call | + Method)++) | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) | (Take <<= (Lhs >>= lv)) | (Lookup <<= (Op >>= operand) * (Rhs >>= key)) | - (If <<= (Op >>= Cond) * Block * Block) | + (If <<= (Op >>= Cond) * Block * Block) | (While <<= (Op >>= Cond) * Block) | (For <<= (Key >>= Ident) * (Value >>= Ident) * (Op >>= lv) * Block) | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) | (Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) | @@ -66,7 +68,7 @@ inline const auto RV = inline const auto CMP_V = T(Ident, Lookup, Null); inline const auto KEY = T(Ident, Lookup, String); inline const auto OPERAND = T(Lookup, Call, Method, Ident); -inline const auto COND = T(Eq, Neq); +inline const auto COND = T(Eq, Neq, Call, Method); // Parsing && AST construction Parse parser(); diff --git a/src/lang/passes/call_stmts.cc b/src/lang/passes/call_stmts.cc index 84bd886..2d53166 100644 --- a/src/lang/passes/call_stmts.cc +++ b/src/lang/passes/call_stmts.cc @@ -6,7 +6,7 @@ namespace verona::wf inline const auto call_stmts = grouping | (Block <<= - (Assign | If | For | Func | Return | ReturnValue | Call | Method | + (Assign | If | For | While | Func | Return | ReturnValue | Call | Method | ClearStack | Print)++); } diff --git a/src/lang/passes/flatten.cc b/src/lang/passes/flatten.cc index 283628e..99f621a 100644 --- a/src/lang/passes/flatten.cc +++ b/src/lang/passes/flatten.cc @@ -71,6 +71,27 @@ PassDef flatten() // Join << (Label << (Ident ^ join_label)); }, + + T(While)[While] << (COND[Op] * (T(Block) << Any++[Block])) >> + [](auto& _) { + auto start_label = new_jump_label(); + auto break_label = new_jump_label(); + + auto while_head = expr_header(_(While)); + + return Seq + // Loop header + << (Label << (Ident ^ start_label)) << _(Op) + << (JumpFalse ^ break_label) + << create_print(_(While), while_head + " (Next)") + // Loop body + << _[Block] + << (Jump ^ start_label) + // Loop end + << (Label << (Ident ^ break_label)) + << create_print(_(While), while_head + " (Break)"); + }, + T(For)[For] << (T(Ident)[Key] * T(Ident)[Value] * LV[Op] * (T(Block) << Any++[Block]) * End) >> @@ -102,8 +123,8 @@ PassDef flatten() << create_print(_(For), for_head + " (Next)") // Block << _[Block] - // Final cleanup << (Jump ^ start_label) + // Final cleanup << ((Label ^ "break:") << (Ident ^ break_label)) << create_print(_(For), for_head + " (Break)") << ((Assign ^ ("drop " + std::string(_(Value)->location().view()))) diff --git a/src/lang/passes/grouping.cc b/src/lang/passes/grouping.cc index e827d8e..1ef3050 100644 --- a/src/lang/passes/grouping.cc +++ b/src/lang/passes/grouping.cc @@ -94,6 +94,8 @@ PassDef grouping() return create_from(For, _(For)) << _(Key) << _(Value) << _(Op) << _(Block); }, + (T(While) << (T(Group) * COND[Op] * (T(Group) << T(Block)[Block]))) >> + [](auto& _) { return While << _(Op) << _(Block); }, T(Func)[Func] << ((T(Group) << End) * diff --git a/src/lang/passes/parse.cc b/src/lang/passes/parse.cc index 2930608..5c58d7b 100644 --- a/src/lang/passes/parse.cc +++ b/src/lang/passes/parse.cc @@ -7,14 +7,15 @@ namespace verona::wf inline const auto parse_tokens = Ident | Lookup | Empty | Drop | Take | Null | String | Parens; inline const auto parse_groups = - Group | Assign | If | Else | Block | For | Func | List | Return; + Group | Assign | If | Else | Block | For | Func | List | Return | While; inline const auto parser = (Top <<= File) | (File <<= parse_groups++) | (Assign <<= Group++) | (If <<= Group * (Op >>= Cond) * Group) | (Else <<= Group * Group) | (Group <<= (parse_tokens | Block | List)++) | (Block <<= (parse_tokens | parse_groups)++) | (Eq <<= Group * Group) | (Neq <<= Group * Group) | (Lookup <<= Group) | - (For <<= Group * List * Group * Group) | (List <<= Group++) | + (For <<= Group * List * Group * Group) | + (While <<= Group * (Op >>= Cond) * Group) | (List <<= Group++) | (Parens <<= (Group | List)++) | (Func <<= Group * Group * Group) | (Return <<= Group++); } @@ -100,6 +101,7 @@ trieste::Parse parser() m.term({List, Parens}); m.extend(Parens); }, + "," >> [](auto& m) { m.seq(List); }, "return\\b" >> [](auto& m) { m.seq(Return); }, "for\\b" >> [](auto& m) { m.seq(For); }, @@ -108,7 +110,11 @@ trieste::Parse parser() // In should always be in a list from the identifiers. m.term({List}); }, - "," >> [](auto& m) { m.seq(List); }, + "while\\b" >> + [](auto& m) { + m.term(); + m.seq(While); + }, "if\\b" >> [](auto& m) { @@ -138,6 +144,10 @@ trieste::Parse parser() { toc = Func; } + else if (m.in(While)) + { + toc = While; + } else { m.error("unexpected colon"); diff --git a/tests/exprs/while.vpy b/tests/exprs/while.vpy new file mode 100644 index 0000000..cf4b331 --- /dev/null +++ b/tests/exprs/while.vpy @@ -0,0 +1,8 @@ +lst = {} +lst.next = {} +lst.next.next = {} +lst.next.next.next = {} + +obj = lst +while obj != null: + obj = obj.next From 95224c55dfc9688ea09efbf7e3de6951bf820529 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 24 Oct 2024 10:59:37 +0200 Subject: [PATCH 2/6] Lang: Allow calls in comparisons --- src/lang/lang.h | 11 ++++++----- src/lang/passes/grouping.cc | 9 ++++++--- src/lang/passes/parse.cc | 4 ++-- tests/exprs/while.vpy | 17 +++++++++++++++++ 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/lang/lang.h b/src/lang/lang.h index 220e256..8b72bbd 100644 --- a/src/lang/lang.h +++ b/src/lang/lang.h @@ -32,10 +32,10 @@ namespace verona::wf { inline const auto lv = Ident | Lookup; inline const auto rv = lv | Empty | Null | String | Call | Method | Take; - inline const auto cmp_values = Ident | Lookup | Null; + inline const auto cmp_values = Ident | Lookup | Null | Call | Method; inline const auto key = Ident | Lookup | String; inline const auto operand = Lookup | Call | Method | Ident; - inline const auto Cond = Eq | Neq | Call | Method; + inline const auto cond = Eq | Neq; inline const auto grouping = (Top <<= File) | (File <<= Body) | (Body <<= Block) | @@ -44,7 +44,8 @@ namespace verona::wf Method)++) | (Assign <<= (Lhs >>= lv) * (Rhs >>= rv)) | (Take <<= (Lhs >>= lv)) | (Lookup <<= (Op >>= operand) * (Rhs >>= key)) | - (If <<= (Op >>= Cond) * Block * Block) | (While <<= (Op >>= Cond) * Block) | + (If <<= (Op >>= cond) * Block * Block) | (While <<= (Op >>= cond) * Block) | + (While <<= (Op >>= cond) * Block) | (For <<= (Key >>= Ident) * (Value >>= Ident) * (Op >>= lv) * Block) | (Eq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) | (Neq <<= (Lhs >>= cmp_values) * (Rhs >>= cmp_values)) | @@ -65,10 +66,10 @@ namespace verona::wf inline const auto LV = T(Ident, Lookup); inline const auto RV = T(Empty, Ident, Lookup, Null, String, Call, Method, Take); -inline const auto CMP_V = T(Ident, Lookup, Null); +inline const auto CMP_V = T(Ident, Lookup, Null, Call, Method); inline const auto KEY = T(Ident, Lookup, String); inline const auto OPERAND = T(Lookup, Call, Method, Ident); -inline const auto COND = T(Eq, Neq, Call, Method); +inline const auto COND = T(Eq, Neq); // Parsing && AST construction Parse parser(); diff --git a/src/lang/passes/grouping.cc b/src/lang/passes/grouping.cc index 1ef3050..e415cf8 100644 --- a/src/lang/passes/grouping.cc +++ b/src/lang/passes/grouping.cc @@ -61,9 +61,12 @@ PassDef grouping() << ((T(Group) << LV[Lhs] * End) * ((T(Group) << (RV[Rhs] * End)) / (RV[Rhs] * End)) * End) >> [](auto& _) { return Assign << _[Lhs] << _[Rhs]; }, - COND[Op] - << ((T(Group) << CMP_V[Lhs] * End) * (T(Group) << CMP_V[Rhs] * End) * - End) >> + + COND[Op] << (Any[Lhs] * (T(Group) << CMP_V[Rhs] * End) * End) >> + [](auto& _) { + return create_from(_(Op)->type(), _(Op)) << _[Lhs] << _[Rhs]; + }, + COND[Op] << ((T(Group) << CMP_V[Lhs] * End) * Any[Rhs] * End) >> [](auto& _) { return create_from(_(Op)->type(), _(Op)) << _[Lhs] << _[Rhs]; }, diff --git a/src/lang/passes/parse.cc b/src/lang/passes/parse.cc index 5c58d7b..f949ad3 100644 --- a/src/lang/passes/parse.cc +++ b/src/lang/passes/parse.cc @@ -10,12 +10,12 @@ namespace verona::wf Group | Assign | If | Else | Block | For | Func | List | Return | While; inline const auto parser = (Top <<= File) | (File <<= parse_groups++) | - (Assign <<= Group++) | (If <<= Group * (Op >>= Cond) * Group) | + (Assign <<= Group++) | (If <<= Group * (Op >>= cond) * Group) | (Else <<= Group * Group) | (Group <<= (parse_tokens | Block | List)++) | (Block <<= (parse_tokens | parse_groups)++) | (Eq <<= Group * Group) | (Neq <<= Group * Group) | (Lookup <<= Group) | (For <<= Group * List * Group * Group) | - (While <<= Group * (Op >>= Cond) * Group) | (List <<= Group++) | + (While <<= Group * (Op >>= cond) * Group) | (List <<= Group++) | (Parens <<= (Group | List)++) | (Func <<= Group * Group * Group) | (Return <<= Group++); } diff --git a/tests/exprs/while.vpy b/tests/exprs/while.vpy index cf4b331..ac62556 100644 --- a/tests/exprs/while.vpy +++ b/tests/exprs/while.vpy @@ -6,3 +6,20 @@ lst.next.next.next = {} obj = lst while obj != null: obj = obj.next + +# Always false +x = {} +x.bool = False +while x.bool == True: + never = "mind" + +# Function +def bool(self): + return False +while bool({}) == True: + never = "mind" + +# Method condition +x.bool = bool +while x.bool() == True: + never = "mind" From 4e47453addb10f9a8941ec91c37c92aaeabcfc97 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 24 Oct 2024 11:14:00 +0200 Subject: [PATCH 3/6] Lang: Add syntactic sugar for simple conditions --- src/lang/passes/grouping.cc | 4 ++++ src/lang/passes/parse.cc | 4 ++-- tests/exprs/while.vpy | 15 ++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/lang/passes/grouping.cc b/src/lang/passes/grouping.cc index e415cf8..3b4a0eb 100644 --- a/src/lang/passes/grouping.cc +++ b/src/lang/passes/grouping.cc @@ -97,6 +97,10 @@ PassDef grouping() return create_from(For, _(For)) << _(Key) << _(Value) << _(Op) << _(Block); }, + In(While) * ((T(Group) << End) * (!COND)[Op]) >> + [](auto& _) { + return Seq << Group << (Eq << _(Op) << (Ident ^ "True")); + }, (T(While) << (T(Group) * COND[Op] * (T(Group) << T(Block)[Block]))) >> [](auto& _) { return While << _(Op) << _(Block); }, diff --git a/src/lang/passes/parse.cc b/src/lang/passes/parse.cc index f949ad3..3420929 100644 --- a/src/lang/passes/parse.cc +++ b/src/lang/passes/parse.cc @@ -10,12 +10,12 @@ namespace verona::wf Group | Assign | If | Else | Block | For | Func | List | Return | While; inline const auto parser = (Top <<= File) | (File <<= parse_groups++) | - (Assign <<= Group++) | (If <<= Group * (Op >>= cond) * Group) | + (Assign <<= Group++) | (If <<= Group * (Op >>= (cond | Group)) * Group) | (Else <<= Group * Group) | (Group <<= (parse_tokens | Block | List)++) | (Block <<= (parse_tokens | parse_groups)++) | (Eq <<= Group * Group) | (Neq <<= Group * Group) | (Lookup <<= Group) | (For <<= Group * List * Group * Group) | - (While <<= Group * (Op >>= cond) * Group) | (List <<= Group++) | + (While <<= Group * (Op >>= (cond | Group)) * Group) | (List <<= Group++) | (Parens <<= (Group | List)++) | (Func <<= Group * Group * Group) | (Return <<= Group++); } diff --git a/tests/exprs/while.vpy b/tests/exprs/while.vpy index ac62556..de922c7 100644 --- a/tests/exprs/while.vpy +++ b/tests/exprs/while.vpy @@ -7,19 +7,32 @@ obj = lst while obj != null: obj = obj.next -# Always false +# Identifiers +cond = False +while cond == True: + never = "mind" +while cond: + never = "mind" + +# Fields x = {} x.bool = False while x.bool == True: never = "mind" +while x.bool: + never = "mind" # Function def bool(self): return False while bool({}) == True: never = "mind" +while bool({}): + never = "mind" # Method condition x.bool = bool while x.bool() == True: never = "mind" +while x.bool(): + never = "mind" From 5e065c8a9da7bacf9254a9396e13f00824ad9505 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 24 Oct 2024 12:04:21 +0200 Subject: [PATCH 4/6] Lang: Make comparisons a bit more flexible --- src/lang/lang.h | 9 +++++---- src/lang/passes/grouping.cc | 9 +++++---- src/lang/passes/parse.cc | 7 ++++--- tests/exprs/ifs.vpy | 11 ++++++++++- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/lang/lang.h b/src/lang/lang.h index 8b72bbd..93c65fc 100644 --- a/src/lang/lang.h +++ b/src/lang/lang.h @@ -30,12 +30,13 @@ inline const TokenDef Compile{"compile"}; namespace verona::wf { + inline const auto cond = Eq | Neq; inline const auto lv = Ident | Lookup; - inline const auto rv = lv | Empty | Null | String | Call | Method | Take; + inline const auto rv = + lv | Empty | Null | String | Call | Method | Take | cond; inline const auto cmp_values = Ident | Lookup | Null | Call | Method; inline const auto key = Ident | Lookup | String; inline const auto operand = Lookup | Call | Method | Ident; - inline const auto cond = Eq | Neq; inline const auto grouping = (Top <<= File) | (File <<= Body) | (Body <<= Block) | @@ -63,13 +64,13 @@ namespace verona::wf (Func <<= Body) | (Label <<= Ident)[Ident]; } +inline const auto COND = T(Eq, Neq); inline const auto LV = T(Ident, Lookup); inline const auto RV = - T(Empty, Ident, Lookup, Null, String, Call, Method, Take); + T(Empty, Ident, Lookup, Null, String, Call, Method, Take, Eq, Neq); inline const auto CMP_V = T(Ident, Lookup, Null, Call, Method); inline const auto KEY = T(Ident, Lookup, String); inline const auto OPERAND = T(Lookup, Call, Method, Ident); -inline const auto COND = T(Eq, Neq); // Parsing && AST construction Parse parser(); diff --git a/src/lang/passes/grouping.cc b/src/lang/passes/grouping.cc index 3b4a0eb..9f50bbc 100644 --- a/src/lang/passes/grouping.cc +++ b/src/lang/passes/grouping.cc @@ -62,6 +62,11 @@ PassDef grouping() ((T(Group) << (RV[Rhs] * End)) / (RV[Rhs] * End)) * End) >> [](auto& _) { return Assign << _[Lhs] << _[Rhs]; }, + // Normalize `if x:` -> `if x == True` + In(If, While) * ((T(Group) << End) * (!COND)[Op]) >> + [](auto& _) { + return Seq << Group << (Eq << _(Op) << (Ident ^ "True")); + }, COND[Op] << (Any[Lhs] * (T(Group) << CMP_V[Rhs] * End) * End) >> [](auto& _) { return create_from(_(Op)->type(), _(Op)) << _[Lhs] << _[Rhs]; @@ -97,10 +102,6 @@ PassDef grouping() return create_from(For, _(For)) << _(Key) << _(Value) << _(Op) << _(Block); }, - In(While) * ((T(Group) << End) * (!COND)[Op]) >> - [](auto& _) { - return Seq << Group << (Eq << _(Op) << (Ident ^ "True")); - }, (T(While) << (T(Group) * COND[Op] * (T(Group) << T(Block)[Block]))) >> [](auto& _) { return While << _(Op) << _(Block); }, diff --git a/src/lang/passes/parse.cc b/src/lang/passes/parse.cc index 3420929..b5857ec 100644 --- a/src/lang/passes/parse.cc +++ b/src/lang/passes/parse.cc @@ -10,14 +10,15 @@ namespace verona::wf Group | Assign | If | Else | Block | For | Func | List | Return | While; inline const auto parser = (Top <<= File) | (File <<= parse_groups++) | - (Assign <<= Group++) | (If <<= Group * (Op >>= (cond | Group)) * Group) | + (Assign <<= Group * (Lhs >>= (Group | cond))) | + (If <<= Group * (Op >>= (cond | Group)) * Group) | (Else <<= Group * Group) | (Group <<= (parse_tokens | Block | List)++) | (Block <<= (parse_tokens | parse_groups)++) | (Eq <<= Group * Group) | (Neq <<= Group * Group) | (Lookup <<= Group) | (For <<= Group * List * Group * Group) | (While <<= Group * (Op >>= (cond | Group)) * Group) | (List <<= Group++) | (Parens <<= (Group | List)++) | (Func <<= Group * Group * Group) | - (Return <<= Group++); + (Return <<= (Group | cond)++); } struct Indent @@ -34,7 +35,7 @@ trieste::Parse parser() indent->push_back({0, File}); auto update_indent = [indent](detail::Make& m, size_t this_indent) { - m.term({Assign, Return}); + m.term({Eq, Neq, Assign, Return}); if (this_indent > indent->back().indent) { diff --git a/tests/exprs/ifs.vpy b/tests/exprs/ifs.vpy index 8f5b9e1..236dd24 100644 --- a/tests/exprs/ifs.vpy +++ b/tests/exprs/ifs.vpy @@ -1,4 +1,3 @@ - # Build a region a = {} a["self"] = a @@ -21,5 +20,15 @@ else: d = {} drop d +cond = f.a != a +if cond: + dummy = "created" + +def check(): + c = False + return c == True +if check(): + this = "is false" + drop a drop f From eccdaeb07165640974ac143233152d09df3cb428 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 24 Oct 2024 13:29:53 +0200 Subject: [PATCH 5/6] Test: Add loop based linked list --- ...{recursive_list.vpy => list_recursive.vpy} | 0 tests/list_while.vpy | 60 +++++++++++++++++++ 2 files changed, 60 insertions(+) rename tests/{recursive_list.vpy => list_recursive.vpy} (100%) create mode 100644 tests/list_while.vpy diff --git a/tests/recursive_list.vpy b/tests/list_recursive.vpy similarity index 100% rename from tests/recursive_list.vpy rename to tests/list_recursive.vpy diff --git a/tests/list_while.vpy b/tests/list_while.vpy new file mode 100644 index 0000000..72c9690 --- /dev/null +++ b/tests/list_while.vpy @@ -0,0 +1,60 @@ +def new_list(): + def insert(self, item): + node = self.head + while node.next != null: + node = node.next + + node.next = {} + node.next.data = item + node.next.prev = node + + def contains(self, item): + node = self.head + while node.next != null: + if node.data == item: + return True + node = node.next + return False + + def remove(self, item): + node = self.head + while node.next != null: + if node.data == item: + node.prev.next = node.next + if node.next != null: + node.next.prev = node.prev + return True + node = node.next + return False + + list = {} + list.head = {} + list.insert = take insert + list.contains = take contains + list.remove = take remove + return list + +# Dyrona doesn't freeze shared objects automatically (yet) +def freeze_and_hide_proto(value): + proto = value["__proto__"] + freeze(proto) + mermaid_hide(proto) +freeze_and_hide_proto(freeze_and_hide_proto) +freeze_and_hide_proto("string") +drop freeze_and_hide_proto + +list = new_list() + +# Required to not leak memory +region(list) + +value = "x" + +list.insert({}) +list.insert({}) +list.insert(value) +list.insert({}) +list.remove(value) + +drop value +drop list From 2fb5b1ddb7af4a68a5d50b9a46c8ed1e18b6a85d Mon Sep 17 00:00:00 2001 From: xFrednet Date: Thu, 24 Oct 2024 15:06:25 +0200 Subject: [PATCH 6/6] Test: Add comments and add `unreachable()` --- src/rt/core/builtin.cc | 5 +++++ tests/exprs/ifs.vpy | 16 ++++++++++------ tests/exprs/while.vpy | 24 ++++++++++++------------ 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/rt/core/builtin.cc b/src/rt/core/builtin.cc index 4810b02..5dae61d 100644 --- a/src/rt/core/builtin.cc +++ b/src/rt/core/builtin.cc @@ -103,6 +103,11 @@ namespace rt::core return std::nullopt; }); + + add_builtin("unreachable", [](auto, auto, auto) { + ui::error("this method should never be called"); + return std::nullopt; + }); } void init_builtins(ui::UI* ui) diff --git a/tests/exprs/ifs.vpy b/tests/exprs/ifs.vpy index 236dd24..41add39 100644 --- a/tests/exprs/ifs.vpy +++ b/tests/exprs/ifs.vpy @@ -5,30 +5,34 @@ a["self"] = a f = {} f.a = a +# Check if with else (This should be true) if a == f.a: b = f.a c = {} + # Check empty lines in blocks: drop b drop c else: + # Check parsing nested if's if f.b == None: - e = {} - drop e + unreachable() else: - d = {} - drop d + unreachable() +# Check identifier as the condition cond = f.a != a if cond: - dummy = "created" + unreachable() +# Check function call as the condition def check(): c = False + # Check return condition result return c == True if check(): - this = "is false" + unreachable() drop a drop f diff --git a/tests/exprs/while.vpy b/tests/exprs/while.vpy index de922c7..968a1a0 100644 --- a/tests/exprs/while.vpy +++ b/tests/exprs/while.vpy @@ -7,32 +7,32 @@ obj = lst while obj != null: obj = obj.next -# Identifiers +# Check identifiers in the condition cond = False while cond == True: - never = "mind" + unreachable() while cond: - never = "mind" + unreachable() -# Fields +# Check field access in the condition x = {} x.bool = False while x.bool == True: - never = "mind" + unreachable() while x.bool: - never = "mind" + unreachable() -# Function +# Check function calls in the condition def bool(self): return False while bool({}) == True: - never = "mind" + unreachable() while bool({}): - never = "mind" + unreachable() -# Method condition +# Check method calls in the condition x.bool = bool while x.bool() == True: - never = "mind" + unreachable() while x.bool(): - never = "mind" + unreachable()