I have tried to play a bit with a couple of macros to try to implement yield syntactic sugar in C. Having such a convoluted transformation, my context is not being saved.
#include<stdio.h>
#include<stdlib.h>
#include<setjmp.h>
struct yield_ctx__{jmp_buf fw,bw;long last_line;};
typedef struct yield_ctx__* yield_ctx;
#define with(x)\
for(volatile yield_ctx yield_requires_with_block__=(yield_ctx)x;\
((yield_requires_with_block__==NULL)?\
(yield_requires_with_block__=(yield_ctx)malloc(sizeof(struct yield_ctx__)),\
yield_requires_with_block__->last_line=__LINE__,\
(x=yield_requires_with_block__)!=NULL)\
:(x!=NULL))\
&&((yield_requires_with_block__->last_line=setjmp(yield_requires_with_block__->bw))?\
(longjmp(yield_requires_with_block__->fw,yield_requires_with_block__->last_line),\
(x!=NULL))\
:(x!=NULL))\
;free(yield_requires_with_block__))
#define yield \
if(\
(yield_requires_with_block__->last_line<__LINE__+4)?\
(setjmp(yield_requires_with_block__->fw)==__LINE__+3)\
:1)\
{if(yield_requires_with_block__->last_line<__LINE__+1)\
longjmp(yield_requires_with_block__->bw,__LINE__);\
} else return
int func_test(yield_ctx ctx, int nr)
{
if (ctx==NULL) printf("No context!\n");
with(ctx)
{
printf("Context created!\n");
yield 1*nr;
printf("Called back!\n");
yield 2*nr;
printf("Finished!\n");
}
return 3*nr;
}
int main()
{
yield_ctx ctx=NULL;
printf("%i.Welcome to yield!! Happy Coding :)\n",func_test(ctx,2));
printf("%i.Welcome to yield!! Happy Coding :)\n",func_test(ctx,2));
printf("%i.Welcome to yield!! Happy Coding :)\n",func_test(ctx,2));
return 0;
}
when I run it it always runs the first part of the function, even though there is a save point at first yield.
The example is split in the following components:
- with macro is hiding a for loop that creates a local variable called yield_requires_with_block out of provided x parameter, naming is selected to provide a useful error if yield is used without with
- the second part of the for loop tests various scenarios of contexts, creates setjmp return point and jumps to saved point in the function. Line numbers are passed to prevent repeating the same setjmp, this condition should in most cases resolve to true
- in case we exit the with statement, free the context memory. The compiler will force a final return after the with statement.
- the second macro, yield tests and sets a jump exchange
I am an amateur and like to play with different concepts in code, I'm sure it's something I'm missing. Edit: per observations I have renamed the types and the inner variable. I also split the macros in multiple lines and added explicit testing of pointers to use in boolean expressions.