The Robot World Repo on GitHub
The Forth Repo on GitHub

I’m going to try some further work on CASE, keeping it simple. Just pushing it forward a bit, if I can. I think we get a nice increment. Odd approach to testing.

Here’s my test:

    def test_for_discussion(self):
        f = Forth()
        test = (': TEST'
                '  2 CASE'
                '    1 OF 111 ENDOF'
                '    2 OF 222 ENDOF'
                '  ENDCASE '
                ';')
        expected_stack = [222]
        f.process_line(test)
        w = f.find_word('TEST')
        assert str(w) == ''

And the first cut at code, just to get through the process_line:

class Lexicon:
    def define_case_of_endof_endcase(self):
        ...
        def _of(f):
            pass

        def _endof(f):
            pass

        self.pw('OF', _of, immediate=True)
        self.pw('ENDOF', _endof, immediate=True)
        ...

The test result looks good so far:

Expected :''
Actual   :': TEST *# 2 *# 1 *# 111 *# 2 *# 222 DROP ;'

I think I’ll just go ahead and start punching in code. That’s not as ambitious as I was thinking at the end of this morning’s article, but I feel more casual this afternoon. I’ll try not to go too far off the rails.

        def _of(f):
            f.word_list.append(f.find_word('OVER'))
            f.word_list.append(f.find_word('='))
            f.word_list.append(f.find_word('0BR'))
            f.word_list.append(0)
            f.word_list.append(f.find_word('DROP'))

We do not have 0BR, which does less harm than you might imagine, giving this error:

(': TEST *# 2 *# 1 OVER = None 0 DROP *# 111 *# 2 OVER = None 0 DROP *# 222 '
 'DROP ;') 
!= ''

That’s about what we’d expect. I’ll define a trivial 0BR and BR now. That gives me this:

Expected :''
Actual   :': TEST *# 2 *# 1 OVER = 0BR 0 DROP *# 111 *# 2 OVER = 0BR 0 DROP *# 222 DROP ;'

I am liking how this is going. It’s not really TDD, mind you, but I’m getting a nice view of the code being generated. When it is what I think I want, I’ll copy that string, as in an Approval Test.

I think we just need the branches now (and the filling in of the zeros, of course). Those are done by the ENDOF, if I’m not mistaken.

        def _endof(f):
            f.word_list.append(f.find_word('BR'))
            f.word_list.append(0)

And the result:

': TEST *# 2 *# 1 OVER = 0BR 0 DROP *# 111 BR 0 *# 2 OVER = 0BR 0 DROP *# 222 '
 'BR 0 DROP ;') 
!= ''

I think that except for the filling in of the zeros after the branch words, and of course the implementation of those words, we’re nearly there. This appears to be the code that I expect. I’ll comment out the assertion on the test so that I can save this code: I think it’s nearly OK.

Commit: decent sketch of OF-ENDOF, lays out correct code, ready for branch fixup.

Let’s sum up, I’m just whiling away a few minutes here. Forty minutes since the top of the page.

Summary

We see in the duplication in _of and _endof what I was getting at about just stuffing things into the word definition. We should be able to clean things up by focusing on removing that duplication.

I think it’s just a matter of fixing up the branches and implementing 0BR and BR. We already have a version of 0BR somewhere, probably somewhere around IF. So, even though we know that “just” usually means we are about to fall off a cliff, I’m feeling optimistic!

We should talk about this odd approach to testing. Essentially I’m just looking at the output to see if it’s OK, but I’m recording those results in a test as they come to be what I want. I think it’s possible that I could go in smaller steps, perhaps just somehow compiling the OF or something, and maybe that would be better now that I think of it. But coming in, I wasn’t able to think of that. Perhaps if you had been here, you’d have helped me see that possibility.

We’ll explore that notion next time. For now, we have a very nice increment of progress.

See you next time!