Compiler Design

Delta: An Incremental Compiler
Step 15: Do/While statements

Description

Add support for do/while statements. This kind of statement should start with the do keyword, followed by a list of zero or more statements enclosed inside curly braces (the body), followed by the while keyword, followed by an expression (the condition), and ending with a semicolon. The body is executed at least once, then if the condition evaluates to true (any non-zero value) the body is executed again and the condition is evaluated one more time. The loop stops when the condition evaluates to false (zero).

Make sure to consider do as a Delta reserved keyword from now on.

Example

The Delta program:

var n, r, i;
n = 5;
r = 1;
i = 0;
do {
    i = i + 1;
    r = r * i;
} while n - i;
r

should produce the following WAT code:

(module
  (func
    (export "_start")
    (result i32)
    (local $n i32)
    (local $r i32)
    (local $i i32)
    i32.const 5
    local.set $n
    i32.const 1
    local.set $r
    i32.const 0
    local.set $i
    loop
    local.get $i
    i32.const 1
    i32.add
    local.set $i
    local.get $r
    local.get $i
    i32.mul
    local.set $r
    local.get $n
    local.get $i
    i32.sub
    br_if 0
    end
    local.get $r
  )
)

The above WAT function’s return value should be:

120

Unit Tests

# File: tests/test_15_do_while.py

from unittest import TestCase
from delta import Compiler, SyntaxMistake
from delta.semantics import SemanticMistake


class TestDoWhile(TestCase):

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

    def test_syntax_mistake(self):
        with self.assertRaises(SyntaxMistake):
            self.c.realize('do {} while;')

    def test_semantic_mistake(self):
        with self.assertRaises(SemanticMistake):
            self.c.realize('var do; 0')

    def test_do_while_zero(self):
        self.assertEqual(1,
                         self.c.realize(
                            '''
                            var x, y;
                            x = 1;
                            y = 0;
                            do {
                                x = x - 1;
                                y = 1;
                            } while x;
                            x + y
                            '''))

    def test_do_while_fact(self):
        self.assertEqual(120,
                         self.c.realize(
                            '''
                            var n, r, i;
                            n = 5;
                            r = 1;
                            i = 0;
                            do {
                                i = i + 1;
                                r = r * i;
                            } while n - i;
                            r
                            '''))

    def test_do_while_count_down(self):
        self.assertEqual(0,
                         self.c.realize(
                            '''
                            var i;
                            i = 10;
                            do {
                                i = i - 1;
                            } while i;
                            i
                            '''))

    def test_do_while_skip_body(self):
        self.assertEqual(9,
                         self.c.realize(
                            '''
                            var n;
                            n = 10;
                            do {
                                n = n - 1;
                            } while !n;
                            n
                            '''))

    def test_do_while_fibo(self):
        self.assertEqual(55,
                         self.c.realize(
                            '''
                            var n, a, b;
                            n = 10;
                            a = 0;
                            b = 1;
                            do {
                                var t;
                                t = b;
                                b = a + b;
                                a = t;
                                n = n - 1;
                            } while n;
                            a
                            '''))

    def test_do_while_nested(self):
        self.assertEqual(1500,
                         self.c.realize(
                            '''
                            var r, i;
                            r = 0;
                            i = 10;
                            do {
                                var j;
                                j = 50;
                                do {
                                    var k;
                                    k = 3;
                                    do {
                                        r = r + 1;
                                        k = k - 1;
                                    } while k;
                                    j = j - 1;
                                } while j;
                                i = i - 1;
                            } while i;
                            r
                            '''))