`flxc` now has automatic stack closures! Take that, C99! Check this out! :::felix type tiny = "%i8"; type int = "%i32"; typedef bool = 2; fun add : int*int -> int = "%add"; fun sub : int*int -> int = "%sub"; fun eq : int*int -> bool = "%eq"; fun lnot : bool -> bool = "%lnot"; proc exit : int = "exit"; noinline fun foo (x:int) = { val y = 6; return x + y; } noinline proc fake_exit (x:int) { exit x; return; } noinline fun bar (x:int) = { var y = 10; noinline proc baz () { y = 20; return; } baz (); return x + y; } noinline fun x (a:int, b:int, c:tiny) = { val x1 = a; val x2 = b; val x3 = c; noinline fun y (d:int, e:int, f:tiny) = { val y1 = x1; val y2 = x2; val y3 = f; noinline fun z (g:int, h:int, i:tiny) = { val z1 = x1; val z2 = x2; val z3 = i; return z1; } return z (y1,y2,y3); } return y (x1,x2,x3); } fake_exit $ (foo 2) + (bar 3) + (x (1,2,3t));
And the llvm source: :::llvm %0 = type { i32, i32 } %1 = type { i32, i32, i32, i32, i8 } %2 = type { i32, i32, i8 } declare void @exit(i32) define i32 @foo(i32 %x) { entry: %foo.x = alloca i32 ; <i32*> [#uses=2] store i32 %x, i32* %foo.x %0 = load i32* %foo.x ; <i32> [#uses=1] %1 = add i32 %0, 6 ; <i32> [#uses=1] ret i32 %1 } define void @fake_exit(i32 %x) { entry: %fake_exit.x = alloca i32 ; <i32*> [#uses=2] store i32 %x, i32* %fake_exit.x %0 = load i32* %fake_exit.x ; <i32> [#uses=1] call void @exit(i32 %0) ret void } define i32 @bar(i32 %x) { entry: %bar-closure = alloca %0 ; <%0*> [#uses=3] %bar.y = getelementptr %0* %bar-closure, i32 0, i32 0 ; <i32*> [#uses=2] %bar.x = getelementptr %0* %bar-closure, i32 0, i32 1 ; <i32*> [#uses=2] store i32 %x, i32* %bar.x store i32 10, i32* %bar.y call void @bar.baz(%0* %bar-closure) %0 = load i32* %bar.x ; <i32> [#uses=1] %1 = load i32* %bar.y ; <i32> [#uses=1] %2 = add i32 %0, %1 ; <i32> [#uses=1] ret i32 %2 } define void @bar.baz(%0* %bar-closure) { entry: %bar.y = getelementptr %0* %bar-closure, i32 0, i32 0 ; <i32*> [#uses=1] %bar.x = getelementptr %0* %bar-closure, i32 0, i32 1 ; <i32*> [#uses=0] store i32 20, i32* %bar.y ret void } define i32 @x(i32 %a, i32 %b, i8 %c) { entry: %x-closure = alloca %1 ; <%1*> [#uses=6] %x.x1 = getelementptr %1* %x-closure, i32 0, i32 0 ; <i32*> [#uses=2] %x.x2 = getelementptr %1* %x-closure, i32 0, i32 1 ; <i32*> [#uses=2] %x.a = getelementptr %1* %x-closure, i32 0, i32 2 ; <i32*> [#uses=2] %x.b = getelementptr %1* %x-closure, i32 0, i32 3 ; <i32*> [#uses=2] %x.c = getelementptr %1* %x-closure, i32 0, i32 4 ; <i8*> [#uses=2] store i32 %a, i32* %x.a store i32 %b, i32* %x.b store i8 %c, i8* %x.c %0 = load i32* %x.a ; <i32> [#uses=1] store i32 %0, i32* %x.x1 %1 = load i32* %x.b ; <i32> [#uses=1] store i32 %1, i32* %x.x2 %2 = load i32* %x.x1 ; <i32> [#uses=1] %3 = load i32* %x.x2 ; <i32> [#uses=1] %4 = load i8* %x.c ; <i8> [#uses=1] %5 = call i32 @x.y(%1* %x-closure, i32 %2, i32 %3, i8 %4) ; <i32> [#uses=1] ret i32 %5 } define i32 @x.y(%1* %x-closure, i32 %d, i32 %e, i8 %f) { entry: %x.x1 = getelementptr %1* %x-closure, i32 0, i32 0 ; <i32*> [#uses=1] %x.x2 = getelementptr %1* %x-closure, i32 0, i32 1 ; <i32*> [#uses=1] %x.a = getelementptr %1* %x-closure, i32 0, i32 2 ; <i32*> [#uses=0] %x.b = getelementptr %1* %x-closure, i32 0, i32 3 ; <i32*> [#uses=0] %x.c = getelementptr %1* %x-closure, i32 0, i32 4 ; <i8*> [#uses=0] %x.y-closure = alloca %2 ; <%2*> [#uses=4] %x.y.d = getelementptr %2* %x.y-closure, i32 0, i32 0 ; <i32*> [#uses=1] %x.y.e = getelementptr %2* %x.y-closure, i32 0, i32 1 ; <i32*> [#uses=1] %x.y.f = getelementptr %2* %x.y-closure, i32 0, i32 2 ; <i8*> [#uses=2] store i32 %d, i32* %x.y.d store i32 %e, i32* %x.y.e store i8 %f, i8* %x.y.f %0 = load i32* %x.x1 ; <i32> [#uses=1] %1 = load i32* %x.x2 ; <i32> [#uses=1] %2 = load i8* %x.y.f ; <i8> [#uses=1] %3 = call i32 @x.y.z(%1* %x-closure, %2* %x.y-closure, i32 %0, i32 %1, i8 %2) ; <i32> [#uses=1] ret i32 %3 } define i32 @x.y.z(%1* %x-closure, %2* %x.y-closure, i32 %g, i32 %h, i8 %i) { entry: %x.x1 = getelementptr %1* %x-closure, i32 0, i32 0 ; <i32*> [#uses=1] %x.x2 = getelementptr %1* %x-closure, i32 0, i32 1 ; <i32*> [#uses=0] %x.a = getelementptr %1* %x-closure, i32 0, i32 2 ; <i32*> [#uses=0] %x.b = getelementptr %1* %x-closure, i32 0, i32 3 ; <i32*> [#uses=0] %x.c = getelementptr %1* %x-closure, i32 0, i32 4 ; <i8*> [#uses=0] %x.y.d = getelementptr %2* %x.y-closure, i32 0, i32 0 ; <i32*> [#uses=0] %x.y.e = getelementptr %2* %x.y-closure, i32 0, i32 1 ; <i32*> [#uses=0] %x.y.f = getelementptr %2* %x.y-closure, i32 0, i32 2 ; <i8*> [#uses=0] %x.y.z-closure = alloca %2 ; <%2*> [#uses=3] %x.y.z.g = getelementptr %2* %x.y.z-closure, i32 0, i32 0 ; <i32*> [#uses=1] %x.y.z.h = getelementptr %2* %x.y.z-closure, i32 0, i32 1 ; <i32*> [#uses=1] %x.y.z.i = getelementptr %2* %x.y.z-closure, i32 0, i32 2 ; <i8*> [#uses=1] store i32 %g, i32* %x.y.z.g store i32 %h, i32* %x.y.z.h store i8 %i, i8* %x.y.z.i %0 = load i32* %x.x1 ; <i32> [#uses=1] ret i32 %0 } define void @0() { entry: %0 = call i32 @foo(i32 2) ; <i32> [#uses=1] %1 = call i32 @bar(i32 3) ; <i32> [#uses=1] %2 = add i32 %0, %1 ; <i32> [#uses=1] %3 = call i32 @x(i32 1, i32 2, i8 3) ; <i32> [#uses=1] %4 = add i32 %2, %3 ; <i32> [#uses=1] call void @fake_exit(i32 %4) ret void } What to work on next? Polymorphism, or strings? I am a bit tired relying on exit to tell me if the code's working or not. What to do, what to do... ------------------------------------------------------------------------------ Come build with us! The BlackBerry® Developer Conference in SF, CA is the only developer event you need to attend this year. Jumpstart your developing skills, take BlackBerry mobile applications to market and stay ahead of the curve. Join us from November 9-12, 2009. Register now! http://p.sf.net/sfu/devconf _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language