Compiler Design

Delta: An Incremental Compiler
Step 12: If/Else If/Else statements

Description

Modify the if/else statement from step 11 in order to add support for elseif clauses. This kind of clause allows checking multiple expressions and execute a block of code as soon as one of the conditions evaluates to true (any non-zero value). Similar to the else clause, the elseif clause is optional. However, unlike else, for which there can be only one, there can be an arbitrary number of elseif clauses following an if.

The syntax for the if/elseif/else statement is:

\( \; \; \; \; \texttt{if} \; \textit{expression}_1 \texttt{\{} \; \)
\( \; \; \; \; \; \; \; \; \textit{statements}_1 \)
\( \; \; \; \; \texttt{\} } \)
\( \; \; \; \; \texttt{else if} \; \textit{expression}_2 \; \texttt{\{} \; \)
\( \; \; \; \; \; \; \; \; \textit{statements}_2 \)
\( \; \; \; \; \texttt{\} } \)
\( \; \; \; \; \vdots \)
\( \; \; \; \; \texttt{else if} \; \textit{expression}_n \; \texttt{\{} \; \)
\( \; \; \; \; \; \; \; \; \textit{statements}_n \)
\( \; \; \; \; \texttt{\} } \)
\( \; \; \; \; \texttt{else \{} \; \)
\( \; \; \; \; \; \; \; \; \textit{statements}_{n+1} \)
\( \; \; \; \; \texttt{\} } \)

Example

The Delta program:

var x, y;
x = 5;
if x - 5 {
    y = 1;
} else if x * 0 {
    y = 2;
} else if x - 1 {
    y = 3;
} else {
    y = 4;
}
y

should produce the following WAT code:

(module
  (func
    (export "_start")
    (result i32)
    (local $x i32)
    (local $y i32)
    i32.const 5
    local.set $x
    local.get $x
    i32.const 5
    i32.sub
    if
    i32.const 1
    local.set $y
    else
    local.get $x
    i32.const 0
    i32.mul
    if
    i32.const 2
    local.set $y
    else
    local.get $x
    i32.const 1
    i32.sub
    if
    i32.const 3
    local.set $y
    else
    i32.const 4
    local.set $y
    end
    end
    end
    local.get $y
  )
)

The above WAT function’s return value should be:

3

Unit Tests

# File: tests/test_12_if_elseif_else.py

from unittest import TestCase
from delta import Compiler, SyntaxMistake


class TestIfElseIfElse(TestCase):

    def setUp(self):
        self.c = Compiler('program_start')

    def test_syntax_mistake1(self):
        with self.assertRaises(SyntaxMistake):
            self.c.realize('if true {} else if {}')

    def test_if_elseif_else_1(self):
        self.assertEqual(3,
                         self.c.realize(
                            '''
                            var x, y;
                            x = 5;
                            if x - 5 {
                                y = 1;
                            } else if x * 0 {
                                y = 2;
                            } else if x - 1 {
                                y = 3;
                            } else {
                                y = 4;
                            }
                            y
                            '''))

    def test_if_elseif_else_2(self):
        self.assertEqual(0,
                         self.c.realize(
                            '''
                            var x, y;
                            x = 5;
                            if x - 5 {
                                y = 1;
                            } else if x * 0 {
                                y = 2;
                            } else if x - x {
                                y = 3;
                            } else if x / x - 1 {
                                y = 4;
                            }
                            y
                            '''))

    def test_if_elseif_else_3(self):
        self.assertEqual(5,
                         self.c.realize(
                            '''
                            var x, y;
                            x = 5;
                            if x - 5 {
                                y = 1;
                            } else if x * 0 {
                                y = 2;
                            } else if x - x {
                                y = 3;
                            } else if x / x - 1 {
                                y = 4;
                            } else {
                                y = x;
                            }
                            y
                            '''))

    def test_if_elseif_else_4(self):
        self.assertEqual(1,
                         self.c.realize(
                            '''
                            var x, y;
                            x = 5;
                            if x {
                                y = 1;
                            } else if x * 0 {
                                y = 2;
                            } else if x - x {
                                y = 3;
                            } else if x / x - 1 {
                                y = 4;
                            } else {
                                y = x;
                            }
                            y
                            '''))

    def test_if_elseif_else_5(self):
        self.assertEqual(3,
                         self.c.realize(
                            '''
                            var x, y;
                            x = 5;
                            if x - 5 {
                                y = 1;
                            } else if x * 0 {
                                y = 2;
                            } else if x - 1 {
                                y = 3;
                            } else if x / x - 1 {
                                y = 4;
                            } else {
                                y = x;
                            }
                            y
                            '''))

    def test_if_elseif_else_6(self):
        self.assertEqual(27,
                         self.c.realize(
                            '''
                            var a, b, c;
                            a = 4;
                            b = 2 * a - 5;
                            c = a * b;
                            if a - a {
                                a = a * 2;
                                b = b - 1;
                                c = c + 1;
                            } else if a - b {
                                a = a * 3;
                                b = b - 2;
                                c = c + 2;
                            } else if c + 1 {
                                a = a * 4;
                                b = b - 3;
                                c = c + 3;
                            } else {
                                a = a * 5;
                                b = b - 4;
                                c = c + 4;
                            }
                            a + b + c
                            '''))