// once per Binding·TYPE value
#ifdef Binding·TYPE
-#if NOT( FIND_ITEM(Binding·TYPE ,Binding·TYPE_LIST) )
+#if NOT_CONTAINS(Binding·TYPE ,Binding·TYPE_LIST) )
#pragma message( STR_VAL(Binding·TYPE) )
//this is what it takes to append to a list in cpp ...
// once per TM·CVT value
#ifdef TM·CVT
-#if ! FIND_ITEM( TM·CVT ,TM·TYPE_LIST )
+#if NOT_CONTAINS( TM·CVT ,TM·TYPE_LIST )
#define TM·TYPE_LIST APPEND(TM·TYPE_LIST ,TM·TYPE)
// declare 'TM' as a type
#include "cpp_ext_1.c"
/*
- Types must be registered with predicates.
+ CONTAINS requires registration of pattern, as examples:
- // all legal FG·Type are registered here
#define EQ__int__oo__int
#define EQ__float__oo__float
#define EQ__char__oo__char
*/
- #define FIRST_SEEN(type ,list) \
- NOT(FIND_ITEM(type ,list)) )
-
- // CAT(SEP, ...) will soon be added to cpp_ext_1, then this will be:
- // #define Ξ(...) CAT(· ,__VA_ARGS__)
-
- // Individual macros for specific argument counts
- #define _Ξ0()
- #define Ξ0() _Ξ0()
-
- #define _Ξ1(a) a
- #define Ξ1(a) _Ξ1(a)
-
- #define _Ξ2(a ,b) a##·##b
- #define Ξ2(a ,b) _Ξ2(a ,b)
-
- #define _Ξ3(a ,b ,c) a##·##b##·##c
- #define Ξ3(a ,b ,c) _Ξ3(a ,b ,c)
-
- #define _Ξ4(a ,b ,c ,d) a##·##b##·##c##·##d
- #define Ξ4(a ,b ,c ,d) _Ξ4(a ,b ,c ,d)
-
- #define _Ξ5(a ,b ,c ,d ,e) a##·##b##·##c##·##d##·##e
- #define Ξ5(a ,b ,c ,d ,e) _Ξ5(a ,b ,c ,d ,e)
-
- #define _Ξ6(a ,b ,c ,d ,e ,f) a##·##b##·##c##·##d##·##e##·##f
- #define Ξ6(a ,b ,c ,d ,e ,f) _Ξ6(a ,b ,c ,d ,e ,f)
-
- #define _Ξ7(a ,b ,c ,d ,e ,f ,g) a##·##b##·##c##·##d##·##e##·##f##·##g
- #define Ξ7(a ,b ,c ,d ,e ,f ,g) _Ξ7(a ,b ,c ,d ,e ,f ,g)
-
- #define _Ξ8(a ,b ,c ,d ,e ,f ,g ,h) a##·##b##·##c##·##d##·##e##·##f##·##g##·##h
- #define Ξ8(a ,b ,c ,d ,e ,f ,g ,h) _Ξ8(a ,b ,c ,d ,e ,f ,g ,h)
-
- #define _Ξ9(a ,b ,c ,d ,e ,f ,g ,h ,i) a##·##b##·##c##·##d##·##e##·##f##·##g##·##h##·##i
- #define Ξ9(a ,b ,c ,d ,e ,f ,g ,h ,i) _Ξ9(a ,b ,c ,d ,e ,f ,g ,h ,i)
-
- #define _Ξ10(a ,b ,c ,d ,e ,f ,g ,h ,i ,j) a##·##b##·##c##·##d##·##e##·##f##·##g##·##h##·##i##·##j
- #define Ξ10(a ,b ,c ,d ,e ,f ,g ,h ,i ,j) _Ξ10(a ,b ,c ,d ,e ,f ,g ,h ,i ,j)
-
- // Argument counting mechanism
- #define _ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
- #define COUNT_ARGS(...) _ARG_N(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
-
- // Macro name concatenation
- #define _CONCAT(a, b) a##b
- #define CONCAT(a, b) _CONCAT(a, b)
-
- // Selector that chooses the right macro based on argument count
- #define Ξ_EXPAND(count, ...) CONCAT(Ξ, count)(__VA_ARGS__)
- #define Ξ(...) Ξ_EXPAND(COUNT_ARGS(__VA_ARGS__), __VA_ARGS__)
+ #define NOT_CONTAINS(item ,list) BOOL( NOT(CONTAINS(item ,list)) )
+ #define Ξ(...) CAT(· ,__VA_ARGS__)
#endif
#define STR_VAL(...) #__VA_ARGS__ " -> " VAL(__VA_ARGS__)
// print the macro and the evaluation of the macro at run time:
-#define SHOW(expr) printf("%s -> %s\n", #expr, STR(expr))
+#define SHOW(expr) printf("%s -> %s\n", #expr, STR(expr));
/*===========================================================================
Constants
m RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING()()()()()
/*===========================================================================
- Find an item in a list
+ List operations
- number of EVALs required depends upon length of not found list prefix
+ number of EVALs required depends upon length list that is processed
- REST will return nothing on one of two conditions, that the list has
- been exhausted, or that the list is about to exhausted, it has nothing
+ REST will return nothing on one of two conditions: that the list has
+ been exhausted, or that the list is about to be exhausted and it has nothing
after the last comma. To assure that a tailing item always gets sent
to the predicate, even when empty, we append an empty item.
#define WHILE(predicate ,...) EVAL( _WHILE(predicate ,__VA_ARGS__ ,) )
// returns true or false
- #define _HAS_ITEM(item ,...) \
+ #define _CONTAINS(item ,...) \
IF \
(__VA_ARGS__) \
(IF \
( EQ(item ,_FIRST(__VA_ARGS__)) ) \
( 1 ) \
- ( DEFER3(_HAS_ITEM_CONFEDERATE)()(item ,REST(__VA_ARGS__)) ) \
+ ( DEFER3(_CONTAINS_CONFEDERATE)()(item ,REST(__VA_ARGS__)) ) \
) \
()
- #define _HAS_ITEM_CONFEDERATE() _HAS_ITEM
- #define HAS_ITEM(predicate ,...) EVAL( _HAS_ITEM(predicate ,__VA_ARGS__ ,) )
+ #define _CONTAINS_CONFEDERATE() _CONTAINS
+ #define CONTAINS(predicate ,...) EVAL( _CONTAINS(predicate ,__VA_ARGS__ ,) )
// if no list, returns EOL(), else returns last item in the list
#define _LAST(...) \
#define _LAST_s_CONFEDERATE() _LAST_s
#define LAST(...) EVAL( _LAST(__VA_ARGS__ ,) )
- // join tokens with a separator in between, separator can have nothing as a value
-
-
-#define _CAT(sep ,...) \
- IF \
- (__VA_ARGS__) \
- (_CAT_s(sep ,__VA_ARGS__)) \
- ()
-
-#define _CAT_s(sep ,a ,...) \
- IF \
- (__VA_ARGS__) \
- ( CAT3( a ,sep ,DEFER5(_CAT_s_CONFEDERATE())(sep ,__VA_ARGS__)) ) \
- (a)
-
-#define _CAT_s_CONFEDERATE() _CAT_s
+ #define CAT(sep ,...) \
+ IF \
+ (__VA_ARGS__) \
+ (_CAT_s(sep ,__VA_ARGS__)) \
+ ()
-#define CAT(...) EVAL( _CAT(__VA_ARGS__ ,) )
+ #define _CAT_s(sep ,a ,...)\
+ IF \
+ (__VA_ARGS__) \
+ ( EVAL(_CAT_ss(sep ,a ,__VA_ARGS__)) ) \
+ (a)
+ #define _CAT_ss(sep ,accumulator ,a ,...) \
+ IF \
+ (__VA_ARGS__) \
+ ( DEFER2(_CAT_ss_CONFEDERATE)()(sep ,accumulator##sep##a ,__VA_ARGS__) ) \
+ (accumulator##sep##a)
+ #define _CAT_ss_CONFEDERATE() _CAT_ss
/*===========================================================================
Quantifiers
#define AND(...) WHILE(EXISTS ,__VA_ARGS__)
// AKA existence quantification, returns true or false
- #define OR(...) NOT(WHILE(NOT ,__VA_ARGS__)
+ #define OR(...) NOT( WHILE(NOT ,__VA_ARGS__) )
/*===========================================================================
Access
--- /dev/null
+* CATSEP Separator Expansion Notes
+:PROPERTIES:
+:CREATED: [2025-04-01]
+:END:
+
+** Problem
+
+When using `CATSEP` (or `CAT`) to join tokens with a separator, we encountered an issue where passing a macro-defined separator (e.g. `COMMA`) leads to incorrect behavior:
+
+- The macro expands too early.
+- The result is malformed token pasting like `,A` instead of proper separation.
+- This happens because `##` prevents further expansion, so any `sep` macro used in a `##` must already be fully resolved.
+
+** Attempts
+
+We tried multiple versions:
+- Using `DEFER`, `DEFER2`, `DEFER3` to hide expansion.
+- Wrapping the separator in a macro (e.g. `DEFER_SEP()`).
+- Recursive accumulation models with delayed evaluation.
+
+** Findings
+
+- The separator **must not be a macro** when passed as an argument to a `##` operation.
+- Macro arguments are always expanded before `##` is applied, unless blocked (e.g., by an extra layer of indirection).
+- `##` prevents further expansion, so once the macro has been expanded into a literal comma (`,`) or semicolon (`;`), it can no longer be deferred.
+
+** Recommendation
+
+Use raw characters or tokens as separators, not macros. For example:
+
+#+begin_src c
+CAT(, A ,B ,C) // OK makes a token ABC
+CAT(;, A ,B ,C) // OK - [I don't think this works either]
+CAT(__oo__, A ,B ,C) // OK A__oo__B__oo__C
+CAT(COMMA, A ,B ,C) // ❌ COMMA expands too early
+#+end_src
+
+If you must use a macro-defined separator, redesign may be required. For now:
+
+** Conclusion
+
+⛔ **Do not use macro-defined separators in `CAT` or `CATSEP`.**
+
+Leave this as a known limitation and revisit if/when it becomes essential. Better to avoid the rabbit hole for now.
When calling a macro.
Can have space between a macro function name and the argument list.
-2.
+3.
Macros can be called with empty arguments.
int a_macro (a,,b) // -> a + + c
#+END_SRC
- 3. The access macros, FIRST, SECOND ... have a padding character as a first argument.
- The padding character is returned if the list is not long enough for the access.
- It can be left empty.
+4.
- FIRST(,) will return the empty_token.
+The COMMA macro, though defined, can't be used in any two level or more deep macro calls, because it will expand to a comma on the first level. It perhaps could be wrapped in a function that is given a deferred call, and then have eval expand it, dunno.
printf("\n");
//--------------------------------------------------------------------------
- // HAS_ITEM: returns 1 if item found
+ // CONTAINS: returns 1 if item found
// HAS requires the EQ templates to be set for each case.
//--------------------------------------------------------------------------
SHOW( EQ(B ,B) );
printf("\n");
- SHOW( HAS_ITEM(C ,A ,B ,C ,D) ); // → 1
- SHOW( HAS_ITEM(Z ,A ,B ,C ,D) ); // → ε
+ SHOW( CONTAINS(C ,A ,B ,C ,D) ); // → 1
+ SHOW( CONTAINS(Z ,A ,B ,C ,D) ); // → ε
printf("\n");
// CAT: join items with a separator
//--------------------------------------------------------------------------
- // SHOW( CAT( ;, A ,B ,C ,D ,Z) ); // → Z
+ // SHOW( CAT( SEMICOLON, A ,B ,C ,D ,Z) ); // → Z
+ SHOW( CAT(__oo__,A ,B ,C) ); // →
SHOW( CAT(,A ,B ,C) ); // →
- SHOW( CAT( COMMA, A ,B ,C ,D ,Z) ); // → Z
SHOW( CAT(,A ,B ,) ); // →
SHOW( CAT(,1) );
SHOW( CAT(,) ); // → ε
//--------------------------------------------------------------------------
// AND: true if all items are true (non-empty)
//--------------------------------------------------------------------------
-#if 0
SHOW( AND(1 ,X ,0) ); // → 1
SHOW( AND(1 ,X ,) ); // → ε
printf("\n");
SHOW( OR( , , ,X) ); // → 1
SHOW( OR( , , ,) ); // → ε
printf("\n");
-#endif
+
}
+/*
+ 2025-04-01T04:44:40Z[developer]
+ Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example_cpp§
+ > gcc try_ext_1.c
+
+ 2025-04-01T04:44:44Z[developer]
+ Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example_cpp§
+ > ./a.out
+ EVAL(EXAMPLE_CHAIN(3)) -> 3 + 1 + 1
+
+ FIND(IS_X ,A ,B ,X ,Y ,Z) -> X
+ FIND(IS_X ,A ,B ,C ,D) -> EOL()
+
+ EQ(A ,B) ->
+ EQ(B ,B) -> 1
+
+ CONTAINS(C ,A ,B ,C ,D) -> 1
+ CONTAINS(Z ,A ,B ,C ,D) ->
+
+ WHILE(NON_Z ,A ,B ,C ,Z ,D ,E) ->
+ WHILE(NON_Z ,A ,B ,C) -> 1
+
+ EXISTS() ->
+ EXISTS(0) -> 1
+ EXISTS(1) -> 1
+ EXISTS(X) -> 1
+ WHILE(EXISTS ,1 ,X , ) ->
+ WHILE(EXISTS ,1 , ,X ,0) ->
+ WHILE(EXISTS ,1 ,X ,0) -> 1
+
+ LAST(A ,B ,C ,D ,Z) -> Z
+ LAST(A ,B ,) ->
+ LAST() ->
+
+ CAT(__oo__,A ,B ,C) -> A__oo__B__oo__C
+ CAT(,A ,B ,C) -> ABC
+ CAT(,A ,B ,) -> AB
+ CAT(,1) -> 1
+ CAT(,) ->
+
+ AND(1 ,X ,0) -> 1
+ AND(1 ,X ,) ->
+
+ OR( , , ,X) -> 1
+ OR( , , ,) ->
+
+*/