Skip to content

Commit

Permalink
Add support for nested ifs/else-ifs
Browse files Browse the repository at this point in the history
This change brings support for nested `if` or `else if`.
It make possible to process the following code:
```cpp
main: (args) = {
    p : *int;

    a := 1;
    b := 2;
    c := 3;
    d := 4;

    if args.cout == 3 {
        p = a&;
    } else if p = b& {
        if args.cout == 2 {
            p = c&;
        } else {
            if b > 0 {
                p = a&;
            }
            else {
                p = d&;
            }
        }
    } else {
        p = c&;
    }

    std::cout << p* << std::endl;
}
```
And gets generated:
```cpp
auto main(int const argc_, char const* const* const argv_) -> int{
    auto args = cpp2::make_args(argc_, argv_);
    cpp2::deferred_init<int*> p;

    auto a {1};
    auto b {2};
    auto c {3};
    auto d {4};

    if (args.cout==3) {
        p.construct(&a);
    } else if (p.construct(&b)) {
        if (args.cout==2) {
            p.construct(&c);
        }else {
            if (cpp2::cmp_greater(std::move(b),0)) {
                p.construct(&a);
            }
            else {
                p.construct(&d);
            }
        }
    }else {
        p.construct(&c);
    }

    std::cout << *cpp2::assert_not_null(std::move(p.value())) << std::endl;
}
```

Assignements are properly marked as `DEFINITE INITIALIZATION`

```
  0 | function main
  1 |   scope
  2 |     var p *** UNINITIALIZED
  2 |     /var
  2 |     var a
  2 |     /var
  2 |     var b
  2 |     /var
  2 |     var c
  2 |     /var
  2 |     var d
  2 |     /var
  2 |     selection
  3 |       if branch
  4 |         *** (10,9) DEFINITE INITIALIZATION OF p
  4 |         *** use of a
  4 |         /if branch
  3 |       *** (11,15) DEFINITE INITIALIZATION OF p
  3 |       *** use of b
  3 |       if else branch
  4 |         selection
  5 |           if branch
  6 |             *** (13,13) DEFINITE INITIALIZATION OF p
  6 |             *** (13,17) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of c
  6 |             /if branch
  5 |           else branch
  6 |             selection
  7 |               *** (15,16) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of b
  7 |               if branch
  8 |                 *** (16,17) DEFINITE INITIALIZATION OF p
  8 |                 *** (16,21) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of a
  8 |                 /if branch
  7 |               else branch
  8 |                 *** (19,17) DEFINITE INITIALIZATION OF p
  8 |                 *** (19,21) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of d
  8 |                 /else branch
  7 |               /selection
  6 |             /else branch
  5 |           /selection
  4 |         /if else branch
  3 |       else branch
  4 |         *** (23,9) DEFINITE INITIALIZATION OF p
  4 |         *** (23,13) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of c
  4 |         /else branch
  3 |       /selection
  2 |     *** (26,18) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of p
  2 |     /scope
  1 |   /function

```
  • Loading branch information
filipsajdak committed Apr 21, 2023
1 parent 4b90177 commit da1cc61
Showing 1 changed file with 6 additions and 7 deletions.
13 changes: 6 additions & 7 deletions source/sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,7 @@ class sema
branch(int s, bool r) : start{s}, result{r} { }
};
std::vector<branch> branches;
bool in_branch = false;

stack_entry(int p) : pos{p} { }

Expand All @@ -695,7 +696,6 @@ class sema
}
};
std::vector<stack_entry> selection_stack;
bool in_branch = false;

for (
;
Expand Down Expand Up @@ -755,10 +755,10 @@ class sema

// Else if we're inside a selection statement but still in the condition
// portion (there are no branches entered yet)
else if (std::ssize(selection_stack.back().branches) == 0) {
else if (!selection_stack.back().in_branch) {
// If this is a top-level selection statement, handle it the same as
// if we weren't an a selection statement
if (std::ssize(selection_stack) == 1) {
if (std::ssize(selection_stack) >= 1) {
if (sym.assignment_to) {
definite_initializations.push_back( sym.identifier );
}
Expand All @@ -768,7 +768,6 @@ class sema
"local variable " + name
+ " is used in a condition before it was initialized");
}
return sym.assignment_to;
}
// Else we can skip the rest of this selection statement, and record
// this as the result of the next outer selection statement's current branch
Expand Down Expand Up @@ -797,7 +796,7 @@ class sema
+ " is used in a branch before it was initialized");
}

if (!in_branch) {
if (!selection_stack.back().in_branch) {
return sym.assignment_to;
}

Expand Down Expand Up @@ -912,11 +911,11 @@ class sema
)
{
selection_stack.back().branches.emplace_back( pos, false );
in_branch = true;
selection_stack.back().in_branch = true;
}

if ( !sym.start ) {
in_branch = false;
selection_stack.back().in_branch = false;
}
}
}
Expand Down

0 comments on commit da1cc61

Please sign in to comment.