/*
 * Basically, we are trying to do this in C PreProcessor (a.k.a CPP)::
 *
 *   int start = 1;
 *   int end = 20;
 *   for (i = start; i != end; i ++) {
 *     for (j = start; j != end; j ++)
 *       printf("%2d x %2d = %3d\n", i, j, (i * j));
 *     printf("\n");
 *   }
 *
 * References:  
 *   goo.gl/1HGxJX
 *   goo.gl/wcfeFK
 */

#define START (1,  )
#define END   (0, 2)   // this is 20
#define PRINT_FORMAT "%2d x %2d = %3d\n"

/* Let's start with some utility functions */
#define EAT(...)
#ifndef DEBUG
#define TEST(...) EAT
#endif

#define LITERAL(x) #x
#define CAT_0(x, y)  x ## y
#define CAT_1(x, y)  CAT_0(x, y)
#define CAT(x, y) CAT_1(x, y)

#define EXPAND(...) __VA_ARGS__

#define EMPTY()  // empty
#define DEFER_0(...)  __VA_ARGS__ EMPTY()  // defer once
#define DEFER_1(...) __VA_ARGS__ DEFER_0(EMPTY) ()
#define DEFER_2(...) __VA_ARGS__ DEFER_1(EMPTY) ()
#define DEFER_3(...) __VA_ARGS__ DEFER_2(EMPTY) ()
#define DEFER_4(...) __VA_ARGS__ DEFER_3(EMPTY) ()
#define DEFER_5(...) __VA_ARGS__ DEFER_4(EMPTY) ()
#define DEFER_6(...) __VA_ARGS__ DEFER_5(EMPTY) ()
#define DEFER_7(...) __VA_ARGS__ DEFER_6(EMPTY) ()
#define DEFER_8(...) __VA_ARGS__ DEFER_7(EMPTY) ()
#define DEFER_9(...) __VA_ARGS__ DEFER_8(EMPTY) ()

#define EVAL_1(...)  __VA_ARGS__  /* evaluate 1 time */
#define EVAL_2(...)  EVAL_1(EVAL_1(EVAL_1(__VA_ARGS__)))
#define EVAL_3(...)  EVAL_2(EVAL_2(EVAL_2(__VA_ARGS__)))
#define EVAL_4(...)  EVAL_3(EVAL_3(EVAL_3(__VA_ARGS__)))
#define EVAL_5(...)  EVAL_4(EVAL_4(EVAL_4(__VA_ARGS__)))
#define EVAL_6(...)  EVAL_5(EVAL_5(EVAL_5(__VA_ARGS__)))
#define EVAL_7(...)  EVAL_6(EVAL_6(EVAL_6(__VA_ARGS__)))
#define EVAL_8(...)  EVAL_7(EVAL_7(EVAL_7(__VA_ARGS__)))
#define EVAL_9(...)  EVAL_8(EVAL_8(EVAL_8(__VA_ARGS__)))

#define EVAL__1(...)  __VA_ARGS__
#define INNER_EVAL(...) EVAL__1(EVAL__1(__VA_ARGS__))

#define IF_1(TRUE_BLOCK, ...) TRUE_BLOCK
#define IF_0(TRUE_BLOCK, ...) __VA_ARGS__

#define IIF(cond) CAT(IF_, cond)

#define CHECK_N(_, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0, 0)
#define PROBE(x) x, 1,

/*
 * NOT(0) = 1, NOT(otherwise) = 0
 */
#define NOT(x) CHECK(CAT(NOT_, x))
#define NOT_0 PROBE(~)

/*
 * BOOLEAN OPERATIONS
 */
#define XOR(a, b) CHECK(CAT(CAT(XOR_, a), b))
#define XOR_10 PROBE(1)
#define XOR_01 PROBE(1)

#define AND(a, b) CHECK(CAT(CAT(AND_, a), b))
#define AND_11 PROBE(1)

#define OR(a, b) CHECK(CAT(CAT(OR_, a), b))
#define OR_01 PROBE(1)
#define OR_10 PROBE(1)
#define OR_11 PROBE(1)

/* 0 => 1, 1 => 0 */
#define COMP(BIT) CAT(COMP_, BIT)
#define COMP_0 1
#define COMP_1 0
/* END OF BOOLEAN OPERATIONS */

/*
 * DECIMAL OPERATIONS
 */
#define DEC_INC(a) CAT(DEC_INC_, a)
#define DEC_INC_0 1
#define DEC_INC_1 2
#define DEC_INC_2 3
#define DEC_INC_3 4
#define DEC_INC_4 5
#define DEC_INC_5 6
#define DEC_INC_6 7
#define DEC_INC_7 8
#define DEC_INC_8 9
#define DEC_INC_9 0

#define DEC_EQUIV(a, b) CHECK(CAT(CAT(DEC_EQUIV_, a), b))
#define DEC_EQUIV_00 PROBE(1)
#define DEC_EQUIV_11 PROBE(1)
#define DEC_EQUIV_22 PROBE(1)
#define DEC_EQUIV_33 PROBE(1)
#define DEC_EQUIV_44 PROBE(1)
#define DEC_EQUIV_55 PROBE(1)
#define DEC_EQUIV_66 PROBE(1)
#define DEC_EQUIV_77 PROBE(1)
#define DEC_EQUIV_88 PROBE(1)
#define DEC_EQUIV_99 PROBE(1)
/* END OF DECIMAL OPERATIONS */

/* Basically, BOOL(x) := !!x */
#define BOOL(x) COMP(NOT(x))
#define IF(N, ...)  IIF(BOOL(N))
#define WHEN(N) IF(N)(EXPAND, EAT)

#define EXPAND_TEST_EXISTS(...) GOOD, EXISTS(__VA_ARGS__) ) EAT (
#define DO_EXPAND_TEST_EXISTS(x) (CAT(EXPAND_TEST_, x), DOESNT_EXIST)

#define GET_TEST_EXISTS_VALUE_(_, value) value
#define GET_TEST_EXISTS_VALUE(x) GET_TEST_EXISTS_VALUE_ x

#define TEST_EXISTS(x) GET_TEST_EXISTS_VALUE ( DO_EXPAND_TEST_EXISTS (x) )

TEST(EXISTS) (
    EXISTS(FOO)  TEST_EXISTS(EXISTS(FOO))
    DOESNT_EXIST TEST_EXISTS(FOO)
)

#define EXTRACT_VALUE(exist_value) CAT(EXTRACT_VALUE_, exist_value)
#define EXTRACT_VALUE_EXISTS(...) __VA_ARGS__

#define CONVERT_EXISTS_TO_BOOL(value) CAT(CONVERT_EXISTS_TO_BOOL_, value)
#define CONVERT_EXISTS_TO_BOOL_EXISTS(...) 1
#define CONVERT_EXISTS_TO_BOOL_DOESNT_EXIST 0

#define TRY_EXTRACT_EXISTS(value, ...) \
  IF(CONVERT_EXISTS_TO_BOOL(TEST_EXISTS(value))) \
    (EXTRACT_VALUE(value), __VA_ARGS__)

TEST(TRY_EXTRACT_EXISTS) (
    FOO      TRY_EXTRACT_EXISTS(EXISTS(FOO), DEFAULT)
    DEFUALT  TRY_EXTRACT_EXISTS(FOO, DEFAULT)
)

/*
 * We are going to represent a number by list of digits, e.g.
 *
 *   1 => (1, )
 *   13 => (3, 1)
 *
 * Let's define some list operations.
 */
#define HEAD(head, ...) head
#define TAIL(head, ...) __VA_ARGS__

#define ENCLOSE(...)  ( __VA_ARGS__ )
#define EXPLODE_(...)  __VA_ARGS__
#define EXPLODE(...)  EXPLODE_  __VA_ARGS__

#define EXPLODE_INDIRECT() EXPLODE_
#define IS_LIST_EMPTY(...) \
  TRY_EXTRACT_EXISTS( \
      DEFER_0(HEAD) (__VA_ARGS__ EXISTS(1)), \
      0)
TEST(IS_LIST_EMPTY) (
    1 IS_LIST_EMPTY()
    0 IS_LIST_EMPTY(0)
    0 IS_LIST_EMPTY(0, 0)
)

#define EMPTY_LIST_TO_ZERO(...) \
  IF (IS_LIST_EMPTY(__VA_ARGS__)) ( \
      (0, ), \
      (__VA_ARGS__))

/*
 * Now, let's define INCrease function, where,
 *
 *   INC LIST_REPR(N) = LIST_REPR(N + 1)
 *
 * E.g.
 *
 *   INC(1, ) = (2, )
 *   INC(9, ) = (0, 1)
 */
#define INC_INDIRECT() INC_NO_EVAL

#define TRY_CARRY(x) CHECK(CAT(TRY_CARRY_, x), x)
#define TRY_CARRY_DEC_INC_ PROBE(~)

#define INC_NO_EVAL(head, ...) \
  DEFER_1(EXPLODE_INDIRECT) () \
  IF (DEC_INC(head)) ( \
      (TRY_CARRY(DEC_INC(head)), __VA_ARGS__), \
      (0, DEFER_2(INC_INDIRECT) () (__VA_ARGS__)) \
  )

#define INC(...) (INNER_EVAL(INC_NO_EVAL(__VA_ARGS__)))
TEST(INC) (
    (1, ) INC(0)
    (2, ) INC(1)
    (0, 2) INC(9, 1)
    /*
     * Oops, this is actually (0, 0, EXPLODE_INDIRECT () (1, ))
     * Can't count to 100 Orz...
     * possible fix is to make INNER_EVAL evaluates more times.
     */
    (0, 0, 1) INC(9, 9)
)

/*
 * Apply @func_before and @func_after to each elements of a list.
 */
#define FOR_EACH_INDIRECT() FOR_EACH
#define FOR_EACH(func_before, func_after, ...) \
  WHEN (NOT(IS_LIST_EMPTY(__VA_ARGS__))) ( \
      DEFER_1(func_before) (HEAD(__VA_ARGS__)) \
      DEFER_1(FOR_EACH_INDIRECT) () ( \
          func_before, func_after, TAIL(__VA_ARGS__) \
      ) \
      DEFER_1(func_after) (HEAD(__VA_ARGS__)) \
  )

TEST(FOR_EACH) (
    /* PRINT(1) PRINT(2) PRINT(3) PRINT(4) */
    EVAL_7(FOR_EACH(PRINT, EAT, 1, 2, 3, 4))
    /* PRINT(4) PRINT(3) PRINT(2) PRINT(1) */
    EVAL_7(FOR_EACH(EAT, PRINT, 1, 2, 3, 4))
)

#define BOTH_EMPTY(list_a, list_b) \
  AND(IS_LIST_EMPTY list_a, IS_LIST_EMPTY list_b)

TEST(BOTH_EMPTY) (
    1 BOTH_EMPTY( ( ), ( ) )
    0 BOTH_EMPTY( (1), ( ) )
    0 BOTH_EMPTY( ( ), (1) )
    0 BOTH_EMPTY( (1), (1) )
)

#define IS_HEAD_EQUAL(list_a, list_b) \
  DEC_EQUIV ( HEAD list_a, HEAD list_b )

TEST(IS_HEAD_EQUAL) (
    0 IS_HEAD_EQUAL( ( ), ( ) )
    0 IS_HEAD_EQUAL( (1), ( ) )
    0 IS_HEAD_EQUAL( ( ), (1, 1) )
    1 IS_HEAD_EQUAL( (1), (1) )
    0 IS_HEAD_EQUAL( (1), (0) )
    1 IS_HEAD_EQUAL( (1), (1, 0) )
)

#define IS_LIST_EQUAL_INDIRECT() IS_LIST_EQUAL_NO_EVAL
#define IS_LIST_EQUAL_NO_EVAL(a, b) \
    IF( BOTH_EMPTY( a, b ) ) ( \
        1, \
        /* else */ \
        IF( IS_HEAD_EQUAL(a, b) ) ( \
          DEFER_2(IS_LIST_EQUAL_INDIRECT) () ((TAIL a), (TAIL b)), \
          0) \
    )
#define IS_LIST_EQUAL(a, b) INNER_EVAL(IS_LIST_EQUAL_NO_EVAL(a, b))
#define IS_LIST_NOT_EQUAL(a, b) NOT(IS_LIST_EQUAL(a, b))

TEST(IS_LIST_EQUAL) (
    1 NOT(IS_LIST_EQUAL((1, 2), (1, 3)))
    1 IS_LIST_NOT_EQUAL((1, 2), (1, 3))
    0 IS_LIST_NOT_EQUAL((0, 1), (0, 1))
    1 IS_LIST_NOT_EQUAL((0,  1), (1))
    1 IS_LIST_NOT_EQUAL((), (1))
    1 IS_LIST_NOT_EQUAL((1, 0, 1), (1, 0, 0, 1))
)

#define FOLD_INDIRECT() FOLD_NO_EVAL
#define FOLD_NO_EVAL(func, list, init) \
    IF ( IS_LIST_EMPTY list)  ( \
        init, \
        DEFER_1(FOLD_INDIRECT) () (func, (TAIL list), func(init, HEAD list)) \
    )
#define FOLD(func, list, init) INNER_EVAL(FOLD_NO_EVAL(func, list, init))

#define TAC(x, y) CAT(y, x)
#define TO_INT(list) CAT(, FOLD(TAC, list, ))
TEST(TO_INT) (
    102 TO_INT(INC(1, 0, 1))
)

#define IS_LIST_NOT_EQUAL_() IS_LIST_NOT_EQUAL

#define FOR_LOOP_INDIRECT() FOR_LOOP_NO_EVAL
#define FOR_LOOP_NO_EVAL(index, max, macro, ...) \
    WHEN ( IS_LIST_NOT_EQUAL (index, max) ) ( \
        DEFER_1(macro) (index,  __VA_ARGS__) \
        FOR_LOOP_INDIRECT EMPTY EMPTY () () () ( \
            ENCLOSE( EXPLODE( DEFER_1(INC) index ) ), \
            max, \
            macro, \
            __VA_ARGS__ \
        ) \
    )

#define FOR_LOOP(...) EVAL_2(EVAL_1(EVAL_1(FOR_LOOP_NO_EVAL(__VA_ARGS__))))

#define PRINT(list_b, list_a) \
    printf(PRINT_FORMAT, \
        TO_INT (list_a), \
        TO_INT (list_b), \
        (TO_INT (list_a)) * (TO_INT (list_b)));

#define INNER_LOOP(x, ...) \
    FOR_LOOP_NO_EVAL(START, END, PRINT, x) \
    printf("\n");

#ifndef DEBUG
#include <stdio.h>
int main() {
  EVAL_7(FOR_LOOP(START, END, INNER_LOOP))
}
#endif
