how directly can we translate
Initially I intended to have multiple backends but the path of least resistance is to use C as the backend for now and to come back to the idea of multiple backends later.
Given that - just what do I need to do to kick start things; how much effort is required? Let's start with some simple code:
FibonacciState :: {a, b: Integer = 1}.
[self next] [:FibonacciState -> return: Integer |
next := a.
a := b.
b := next + a.
return next].
generator: FibonacciState.
{Range | start: 1, stop: 100} -> generator -> stdout.
Let's see if we can translate it line by line:
struct FibonacciState {a: int, b: int};
int FibonacciState_next_int(struct FibonacciState* self);
void Program_start();
int FibonacciState_next_int(struct FibonacciState* self) {
int next = self->a;
self->a = self->b;
self->b = next + a;
return next;
}
void Program_start(void) {
struct FibonacciState generator;
generator.a = 1;
generator.b = 1;
struct Range tmp1;
tmp1.start = 1;
tmp1.stop = 100;
int tmp2 = tmp1.start;
while(tmp2 <= tmp1.stop) {
int tmp3 = FibonacciState_next_int(&generator);
write_IO_int(Console_stdout, tmp3);
tmp2++;
}
}
Hm. Not too bad. Let's stick with a fairly strict C subset to keep things simple. Methods are translated to ArgType1_MethodName_ArgType2_ArgType3_..._ReturnType which makes them easy to call when embeddeding STZ in to a C program.
I took some liberties here and kept things simplified by mapping Integer to a straight C int. That's probably not how it'll work in the end but it's a close enough facsimile to get started.
I also inlined all the blocks as described in a previous post to simplify execution. Writing blocks you pass around in C is a bit painful after all. The → methods in STZ are a bit more complex than this straight translation too but not so much that it wouldn't look roughly like what we ended up with.
All the types in the example are 1:1 mappings to type definitions; no generics means no extra compilation to resolve the types ahead of time. Something still needs to call Program_start(); to make this program work.
I'm also not sure we can use while() like that and have it map correctly to STZ. Really we should use a goto label to simulate a tail-call:
int tmp2 = tmp1.start;
loop:
int tmp3 = FibonnaciState_next_int(&generator);
write_IO_int(stdout, tmp3);
if (tmp2 <= tmp1.stop) {
tmp2++;
goto loop;
}
Next time I will try and dig in to the → or next> methods to see how we build up our i/o framework and how it translates in to inlined blocks that ultimately end up with simple C code. Hopefully simple C code.