Last active
August 31, 2016 13:51
-
-
Save lpereira/aef57db85f81d27598f3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
package main | |
import "fmt" | |
func main() { | |
fmt.Println("counting"); | |
for i := 0; i < 10; i++ { | |
defer fmt.Println(i); | |
} | |
fmt.Println("done"); | |
} | |
*/ | |
#include <alloca.h> | |
#include <stdarg.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
enum plain_type { | |
INT, | |
STRINGZ | |
/* STRINGPGM may be useful on an Arduino (constant strings in program | |
memory) */ | |
/* COMPOSITE will have two varargs in Println: the Stringer, | |
and the ptr to the data */ | |
}; | |
void panic(void) | |
{ | |
printf("Panic!\n"); | |
exit(1); | |
} | |
/* fmt.c */ | |
void fmt__Println(int nargs, ...) | |
{ | |
va_list ap; | |
va_start(ap, nargs); | |
for (; nargs; nargs--) { | |
enum plain_type type = va_arg(ap, enum plain_type); | |
switch (type) { | |
case INT: | |
printf("%d", va_arg(ap, int)); | |
break; | |
case STRINGZ: | |
printf("%s", va_arg(ap, const char *)); | |
break; | |
} | |
} | |
va_end(ap); | |
putchar('\n'); | |
} | |
/* defer-support.h */ | |
struct defer_stack { | |
struct defer_stack *next; | |
void *ptr; | |
}; | |
#define CONCAT_IMPL(a_, b_) a_ ## b_ | |
#define CONCAT(a_, b_) CONCAT_IMPL(a_, b_) | |
/* The alloca() idea might be used as an alternative for the malloc() version *if* the current | |
* function is not being called as a goroutine, which might be implemented in a fashion similar | |
* to Simon Tatham's coroutines with a context struct. The computed gotos thing, though, is | |
* a lot nicer than creating function for each deferred statement. */ | |
#define DEFER_NO_CLOSURE(...) \ | |
do { \ | |
struct defer_stack *defer_tmp = alloca(sizeof(*defer_tmp) __VA_ARGS__); \ | |
defer_tmp->next = __defer_stack; \ | |
defer_tmp->ptr = &&CONCAT(__defer_stmt, __COUNTER__); \ | |
__defer_stack = defer_tmp; \ | |
} while(0) | |
#define DEFER(closure_) \ | |
do { \ | |
DEFER_NO_CLOSURE(+ sizeof(closure_)); \ | |
memcpy(__defer_stack + 1, &closure_, sizeof(closure_)); \ | |
} while(0) | |
#define DISPATCH_DEFER() goto *__defer_stack->ptr; | |
#define NEXT_DEFER() \ | |
do { \ | |
__defer_stack = __defer_stack->next; \ | |
DISPATCH_DEFER(); \ | |
} while(0) | |
/* main.c */ | |
struct main__defer0_closure { | |
int i; | |
}; | |
int main(void) | |
{ | |
/* Prologue */ | |
struct defer_stack *__defer_stack = &(struct defer_stack) { .ptr = &&__defer_end }; | |
/* End prologue */ | |
/* Function */ | |
fmt__Println(1, STRINGZ, "counting"); | |
DEFER_NO_CLOSURE(); | |
for (int i = 0; i < 10; i++) { | |
DEFER(((struct main__defer0_closure) { .i = i })); | |
} | |
fmt__Println(1, STRINGZ, "done"); | |
DEFER_NO_CLOSURE(); | |
/* Function end */ | |
/* Epilogue */ | |
/* Deferred statements */ | |
DISPATCH_DEFER(); | |
__defer_stmt0: | |
fmt__Println(1, STRINGZ, "finally"); | |
NEXT_DEFER(); | |
__defer_stmt1: | |
do { | |
struct main__defer0_closure *closure = (void *)(__defer_stack + 1); | |
fmt__Println(1, INT, closure->i); | |
NEXT_DEFER(); | |
} while(0); | |
__defer_stmt2: | |
fmt__Println(1, STRINGZ, "oooh, goto works"); | |
NEXT_DEFER(); | |
__defer_end: | |
/* Unref */ | |
/* -- nothing to collect -- */ | |
/* End epilogue */ | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
package main | |
import "fmt" | |
func main() { | |
fmt.Println("counting"); | |
for i := 0; i < 10; i++ { | |
defer fmt.Println(i); | |
} | |
fmt.Println("done"); | |
} | |
*/ | |
#include <stdarg.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
enum plain_type { | |
INT, | |
STRINGZ | |
/* STRINGPGM may be useful on an Arduino (constant strings in program | |
memory) */ | |
}; | |
void panic(void) | |
{ | |
printf("Panic!\n"); | |
exit(1); | |
} | |
/* fmt.c */ | |
void fmt__Println(int nargs, ...) | |
{ | |
/* This is pretty crude until interfaces are figured out */ | |
va_list ap; | |
va_start(ap, nargs); | |
for (; nargs; nargs--) { | |
enum plain_type type = va_arg(ap, enum plain_type); | |
switch (type) { | |
case INT: | |
printf("%d", va_arg(ap, int)); | |
break; | |
case STRINGZ: | |
printf("%s", va_arg(ap, const char *)); | |
break; | |
} | |
} | |
va_end(ap); | |
putchar('\n'); | |
} | |
/* defer.c */ | |
/* The linked list here might be useful: http://250bpm.com/blog:56 */ | |
/* Also, computed gotos instead of function calls */ | |
struct defer_stack { | |
struct defer_stack *next; | |
void (*cb)(void *closure); | |
char closure[]; | |
}; | |
void defer__RunDeferredStatements(struct defer_stack *defer_stack) | |
{ | |
while (defer_stack) { | |
struct defer_stack *tmp = defer_stack; | |
defer_stack->cb(defer_stack->closure); | |
defer_stack = defer_stack->next; | |
free(tmp); | |
} | |
} | |
struct defer_stack *defer__PushDeferred(struct defer_stack *defer_stack, | |
void (*cb)(void *data), void *closure, size_t sz) | |
{ | |
struct defer_stack *node = malloc(sizeof(*node) + sz); | |
if (!node) | |
panic(); | |
node->next = defer_stack; | |
node->cb = cb; | |
memcpy(node->closure, closure, sz); | |
return node; | |
} | |
/* main.c */ | |
struct main__closure { | |
struct defer_stack *defer_stack; | |
}; | |
static void main__defer(struct main__closure *main__closure) | |
{ | |
defer__RunDeferredStatements(main__closure->defer_stack); | |
/* NB: unref refcounted variables from closure here as this shouldn't have a GC */ | |
} | |
struct main__defer0_closure { | |
int i; | |
}; | |
static void main__defer0(void *data) | |
{ | |
struct main__defer0_closure *closure = data; | |
fmt__Println(1, INT, closure->i); | |
} | |
int main(void) | |
{ | |
struct main__closure main__closure __attribute__((cleanup(main__defer))) = {}; | |
fmt__Println(1, STRINGZ, "counting"); | |
for (int i = 0; i < 10; i++) { | |
struct main__defer0_closure defer0_closure = { | |
.i = i | |
}; | |
main__closure.defer_stack = defer__PushDeferred( | |
main__closure.defer_stack, &main__defer0, | |
&defer0_closure, sizeof(defer0_closure)); | |
} | |
fmt__Println(1, STRINGZ, "done"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment