/*
 * mp.h: header file providing macros for 'metaprogramming' custom
 * loop constructions in standard C.
 *
 * Accompanies the article on the web at
 *   https://www.chiark.greenend.org.uk/~sgtatham/mp/
 */

/*
 * mp.h is copyright 2012 Simon Tatham.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * $Id$
 */

/*
 * Macros beginning with 'MPI_' are internal to this header file, and
 * intended only to be used by other macros defined _in_ this header
 * file. Do not refer to them externally.
 */

/* Standard trickery to allow us to macro-expand and then token-paste */
#define MPI_TOKPASTEINNER(x,y) x ## y
#define MPI_TOKPASTE(x,y) MPI_TOKPASTEINNER(x,y)

/* Method of constructing line-unique labels */
#define MPI_LABEL(id1,id2)                                      \
    MPI_TOKPASTE(MPI_LABEL_ ## id1 ## _ ## id2 ## _, __LINE__)

/*
 * Macros beginning with 'MPP_' and 'MPS_' are building blocks
 * intended for metaprogrammers to make useful control constructions
 * from.
 *
 * The prefixes distinguish their syntactic role. MPP_ macros are
 * statement _prefixes_; you would typically build a custom control
 * structure by defining a macro expanding to a sequence of them. MPS_
 * macros are actual statements, which you might use in the various
 * parameters of MPP_ macros that are expected to be statement-shaped.
 */

/*
 * Safety considerations:
 *
 *  - All of these macros are C89-safe, except for MPP_DECLARE if you
 *    pass an actual declaration and not just an assignment, since
 *    that one relies on the C99 (and C++) extension of being able to
 *    write a declaration in the initialisation clause of a for
 *    statement.
 *
 *  - None of these macros uses switch, so case labels from a switch
 *    outside the whole lot may be written inside the suffixed
 *    statement/block.
 *
 *  - All of these constructions use 'goto' with labels constructed
 *    programmatically, using __LINE__ to make them unique between
 *    multiple invocations of the same loop macro. So don't put two
 *    loop macros defined using these building blocks on the same
 *    source line.
 *
 *  - All of these constructions can be prefixed to something that is
 *    syntactically a single C statement, and generate something that
 *    is also a single C statement. So they're if-else safe - you can
 *    use an unbraced one of these constructs followed by an unbraced
 *    statement within the then-clause of an outer if, and the else
 *    will still bind to what it looks as if it ought to.
 *
 *  - Controlling what happens if the user writes a 'break' in the
 *    suffixed statement is unavoidably rather fiddly. The macros
 *    below fall into a few categories:
 *
 *     + naturally transparent to 'break' (MPP_BEFORE, MPP_IF). Macros
 *       of this type will not affect the semantics of 'break' in the
 *       suffixed statement at all - it will terminate the next
 *       innermost loop or switch outside the construction.
 *
 *     + artificially transparent to 'break', by means of deliberately
 *       catching and 'rethrowing' it. (MPP_BREAK_{THROW,CATCH};
 *       MPP_BREAK_HANDLER; MPP_FINALLY.) These macros will propagate
 *       a break outwards to the next containing loop, but in order to
 *       do so they require that there _be_ a next containing loop,
 *       since their expansion can't avoid including a break statement
 *       which they themselves do not wrap in a loop. So you should
 *       only use these when you know there is a containing loop (e.g.
 *       because MPP_WHILE or MPP_DO_WHILE precedes them in your
 *       construction).
 *
 *     + loop constructions. (MPP_WHILE and MPP_DO_WHILE). These
 *       macros give 'break' the obvious semantics of terminating the
 *       loop they define.
 *
 *     + break-unsafe macros, which have to include a C looping
 *       construction to do something not essentially loopy, and hence
 *       have the unfortunate side effect of causing 'break' to only
 *       terminate the suffixed statement itself. On the other hand,
 *       they can be used in contexts where there is no surrounding
 *       loop at all (which is why I don't just fix them to contain a
 *       built-in MPP_BREAK_{THROW,CATCH}).
 *
 *    If you are using these macros to build a looping construct, then
 *    you will probably include an MPP_WHILE or MPP_DO_WHILE in your
 *    stack, and you'll want 'break' to terminate that. So you just
 *    need to be sure that break is correctly propagated from the
 *    suffixed statement back to that loop, which you can do by
 *    sticking to the break-transparent macros where possible and
 *    using MPP_BREAK_{THROW,CATCH} to bypass any break-unsafe macro
 *    such as MPP_DECLARE that you might need to use. Having done
 *    that, 'break' will do what the user expects.
 *
 *    But if you're using the macros to wrap some context around a
 *    statement you still intend to be executed only once, there will
 *    be unavoidable side effects on 'break': you can't use the
 *    artificially break-unsafe macros because the user might use your
 *    construction in a context with no surrounding loop at all, so
 *    you must stick to the naturally break-transparent and the
 *    break-unsafe, and there aren't enough of the former to be really
 *    useful. So you must just live with 'break' acquiring unhelpful
 *    behaviour inside such a macro.
 *
 *  - Almost none of these macros is transparent to 'continue'. The
 *    naturally break-transparent MPP_BEFORE is, but none of the rest
 *    can possibly be, because as soon as you include any loop
 *    construction in the stuff being prefixed to a statement, you
 *    introduce the invariant that 'continue' is equivalent to jumping
 *    to the end of the suffixed statement or block. This is not too
 *    bad if you're defining a custom loop construction (it was quite
 *    likely the behaviour you wanted for continue anyway), but if you
 *    were trying to use MPP_DECLARE and/or MPP_BEFORE_AND_AFTER to
 *    wrap a statement in some context but still only execute it once,
 *    you'd have to be aware of that limitation.
 *
 *  - MPP_FINALLY and MPP_BREAK_HANDLER can only catch non-local exits
 *    from the block _by break_. They are not true C++ try/finally, so
 *    they can't catch other kinds of exit such as return, goto,
 *    longjmp or exit.
 *
 *  - Finally, it almost goes without saying, but don't forget that
 *    snippets of code you use as parameters to these macros must
 *    avoid using commas not contained inside parentheses, or else the
 *    C preprocessor will consider the comma to end that macro
 *    parameter and start the next one. If there is any reason you
 *    really need an unbracketed comma, you can work around this by
 *    one of two methods:
 *     - define a macro that expands to a comma ('#define COMMA ,')
 *       and then use that macro in place of commas in your macro
 *       argument. It won't be expanded to an actual comma until after
 *       the argument-separation has finished.
 *     - if you're allowed to use C99, define a variadic macro that
 *       expands to its unmodified input argument list ('#define
 *       WRAP(...) __VA_ARGS__') and then enclose comma-using code in
 *       WRAP(). Again, this will protect the commas for just long
 *       enough.
 */

/*
 * MPP_BEFORE: run the code given in the argument 'before' and then
 * the suffixed statement.
 *
 * 'before' should have the syntactic form of one or more declarations
 * and statements, except that a trailing semicolon may be omitted.
 * Any declarations will be in scope only within 'before', not within
 * the suffixed statement.
 *
 * This macro, unusually among the collection, is naturally
 * transparent to 'break' and also transparent to 'continue'.
 */
#define MPP_BEFORE(labid,before)                \
    if (1) {                                    \
        before;                                 \
        goto MPI_LABEL(labid, body);            \
    } else                                      \
    MPI_LABEL(labid, body):

/*
 * MPP_AFTER: run the suffixed statement, and then the code given in
 * the argument 'after'.
 *
 * 'after' should have the syntactic form of one or more declarations
 * and statements, except that a trailing semicolon may be omitted.
 * Any declaration in 'after' will be in scope only within 'after'.
 *
 * This macro is break-unsafe - it causes a 'break' to terminate the
 * suffixed statement only. If you need different behaviour, you can
 * use MPP_BREAK_CATCH and MPP_BREAK_THROW to pass a break past it -
 * but beware that in that case the 'after' clause will not be
 * executed, so MPP_FINALLY or MPP_BREAK_HANDLER may be useful too.
 */
#define MPP_AFTER(labid,after)                  \
    if (1)                                      \
        goto MPI_LABEL(labid, body);            \
    else                                        \
        while (1)                               \
            if (1) {                            \
                after;                          \
                break;                          \
            } else                              \
            MPI_LABEL(labid, body):

/*
 * MPP_DECLARE: run the 'declaration' argument before the suffixed
 * statement. The argument may have the form of either a C expression
 * (e.g. an assignment) or a declaration; if the latter, it will be in
 * scope within the suffixed statement.
 *
 * This macro is break-unsafe - it causes a 'break' to terminate the
 * suffixed statement only. If you need different behaviour, you can
 * use MPP_BREAK_CATCH and MPP_BREAK_THROW to pass a break past it.
 */
#define MPP_DECLARE(labid, declaration)                 \
    if (0)                                              \
        ;                                               \
    else                                                \
        for (declaration;;)                             \
            if (1) {                                    \
                goto MPI_LABEL(labid, body);            \
              MPI_LABEL(labid, done): break;            \
            } else                                      \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, done);    \
                    else                                \
                    MPI_LABEL(labid, body):
/* (The 'if(0) ; else' at the start of the above is just in case we
 * encounter an old-style compiler that considers variables declared
 * in for statements to have scope extending beyond the for statement.
 * Putting another layer outside the 'for' ensures that the variable's
 * scope is constrained to _that_ layer even if not to the for itself,
 * and it doesn't leak into the calling scope. */

/*
 * MPP_WHILE: run the suffixed statement within a 'while (condition)'
 * loop.
 *
 * In fact, just writing 'while (condition)' works fine for this, but
 * it's nice to make it look like the rest of these macros!
 *
 * This macro defines an actual loop, and 'break' in the suffixed
 * statement terminates that loop as you would expect.
 */
#define MPP_WHILE(labid, condition)             \
    while (condition)

/*
 * MPP_DO_WHILE: run the suffixed statement within a loop with the
 * semantics of 'do suffixed-statement while (condition)'.
 *
 * This macro defines an actual loop, and 'break' in the suffixed
 * statement terminates that loop as you would expect.
 */
#define MPP_DO_WHILE(labid, condition)          \
    if (1)                                      \
        goto MPI_LABEL(labid, body);            \
    else                                        \
        while (condition)                       \
        MPI_LABEL(labid, body):

/*
 * MPP_IF: run the suffixed statement only if 'condition' is true.
 *
 * This macro is naturally transparent to 'break' and also transparent
 * to 'continue'.
 */
#define MPP_IF(labid, condition)                \
    if (!(condition))                           \
        ;                                       \
    else

/*
 * MPP_BREAK_THROW and MPP_BREAK_CATCH: propagate 'break' control flow
 * transfers past other prefixes that mess about with them.
 *
 * Write an MPP_BREAK_CATCH, then other metaprogramming prefixes from
 * this collection, and then an MPP_BREAK_THROW with the same label
 * id. If the statement following the MPP_BREAK_THROW terminates by
 * 'break', then the effect will be as if the MPP_BREAK_CATCH had
 * terminated by 'break', regardless of how the in-between prefixes
 * would have handled a 'break'.
 *
 * These macros are artificially transparent to 'break': they pass
 * break through, but include a 'break' statement at the top level of
 * MPP_BREAK_CATCH, so that must always be contained inside some loop
 * or switch construction.
 *
 * We also provide MPS_BREAK_THROW, which is a statement-type macro
 * that manufactures a break event and passes it to a specified
 * MPP_BREAK_CATCH.
 */
#define MPP_BREAK_CATCH(labid)                  \
    if (0)                                      \
    MPI_LABEL(labid, catch): break;             \
    else

#define MPP_BREAK_THROW(labid)                          \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, finish):;                        \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, catch);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

#define MPS_BREAK_THROW(labid) goto MPI_LABEL(labid, catch)

/*
 * MPP_BREAK_HANDLER: handle a 'break' in the suffixed statement by
 * executing the provided handler code and then terminating as if by
 * break.
 *
 * 'handler' should have the syntactic form of one or more
 * declarations and statements, except that a trailing semicolon may
 * be omitted.
 *
 * This macro is artificially transparent to 'break': it passes break
 * through, but includes a 'break' statement at the top level, so it
 * must always be contained inside some loop or switch construction.
 */
#define MPP_BREAK_HANDLER(labid, handler)               \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, break):                          \
        {handler;}                                      \
        break;                                          \
      MPI_LABEL(labid, finish):;                        \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, break);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

/*
 * MPP_FINALLY: execute the suffixed statement, and execute the
 * provided 'finally' clause after it finishes. If it terminates by
 * 'break', execute the same 'finally' clause but propagate the break
 * to the containing statement.
 *
 * 'finally' should have the syntactic form of one or more
 * declarations and statements, except that a trailing semicolon may
 * be omitted.
 *
 * The 'finally' argument will be double-expanded. Of course it'll
 * only be executed once in any given run, so that's not a concern for
 * function side effects, but don't do anything fiddly like declaring
 * a static variable to which you return a pointer and then expecting
 * the pointer to be the same no matter which copy of 'finally' it
 * came from.
 *
 * This macro is artificially transparent to 'break': it passes break
 * through, but includes a 'break' statement at the top level, so it
 * must always be contained inside some loop or switch construction.
 */
#define MPP_FINALLY(labid, finally)                     \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, break):                          \
        {finally;}                                      \
        break;                                          \
      MPI_LABEL(labid, finish):                         \
        {finally;}                                      \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, break);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

/*
 * MPP_BREAK_STOP: handle a 'break' in the suffixed statement by
 * executing the provided handler code and then terminating as if
 * normally.
 *
 * 'handler' should have the syntactic form of one or more
 * declarations and statements, except that a trailing semicolon may
 * be omitted.
 */
#define MPP_BREAK_STOP(labid, handler)                  \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, break):                          \
        {handler;}                                      \
      MPI_LABEL(labid, finish):;                        \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, break);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

/*
 * MPP_ELSE_ACCEPT, MPS_MAIN_INVOKE, MPS_ELSE_INVOKE: arrange to
 * accept an optional 'else' clause after the suffixed statement, and
 * provide two statement macros which jump to the main clause and the
 * else clause. The main (non-else) clause will be be executed in the
 * default case, and can be invoked again using MPS_MAIN_INVOKE;
 * MPS_ELSE_INVOKE will invoke the else clause.
 *
 * Like MPP_BREAK_THROW and MPP_BREAK_CATCH, these macros should be
 * used in groups with the same label id, so as to match them up to
 * each other. MPS_ELSE_INVOKE and MPS_MAIN_INVOKE will go to the
 * appropriate clauses corresponding to the MPP_ELSE_ACCEPT with the
 * same id.
 */
#define MPP_ELSE_ACCEPT(labid)                  \
    if (1)                                      \
        goto MPI_LABEL(labid, body);            \
    else                                        \
    MPI_LABEL(labid, else):                     \
        if (0)                                  \
        MPI_LABEL(labid, body):

#define MPS_MAIN_INVOKE(labid)                  \
    goto MPI_LABEL(labid, body)

#define MPS_ELSE_INVOKE(labid)                  \
    goto MPI_LABEL(labid, else)

/*
 * MPP_ELSE_GENERAL: like MPP_ELSE_ACCEPT, but also lets you provide a
 * snippet of code that will be run after the else clause terminates
 * and one which will be run after the else clause breaks.
 *
 * You can use MPS_MAIN_INVOKE and MPS_ELSE_INVOKE with this as well
 * as with MPP_ELSE_ACCEPT.
 *
 * Will mess up what happens after the main body, so you'll probably
 * want to follow this macro with others such as MPP_AFTER and
 * something to catch break in the main body too.
 */
#define MPP_ELSE_GENERAL(labid, after, breakhandler)    \
    if (1)                                              \
        goto MPI_LABEL(labid, body);                    \
    else                                                \
        while (1)                                       \
            if (1) {                                    \
                {breakhandler;}                         \
                break;                                  \
            } else                                      \
                while (1)                               \
                    if (1) {                            \
                        {after;}                        \
                        break;                          \
                    } else                              \
                    MPI_LABEL(labid, else):             \
                        if (0)                          \
                        MPI_LABEL(labid, body):
