From: Thomas Walker Lynch Date: Tue, 1 Apr 2025 05:09:09 +0000 (+0000) Subject: working cpp_ext_0 and cpp_ext_1 X-Git-Url: https://git.reasoningtechnology.com/style/static/git-favicon.png?a=commitdiff_plain;h=8e1caab4892ad977057ff0037c263172b0304845;p=N working cpp_ext_0 and cpp_ext_1 --- diff --git "a/developer/cc\360\237\226\211/Binding.lib.c" "b/developer/cc\360\237\226\211/Binding.lib.c" index cdf6bb5..4296c2e 100644 --- "a/developer/cc\360\237\226\211/Binding.lib.c" +++ "b/developer/cc\360\237\226\211/Binding.lib.c" @@ -25,7 +25,7 @@ Template parameters: // 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 ... diff --git "a/developer/cc\360\237\226\211/TM.lib.c" "b/developer/cc\360\237\226\211/TM.lib.c" index 75d54af..3300f37 100644 --- "a/developer/cc\360\237\226\211/TM.lib.c" +++ "b/developer/cc\360\237\226\211/TM.lib.c" @@ -59,7 +59,7 @@ // 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 diff --git "a/developer/cc\360\237\226\211/cpp_ext.c" "b/developer/cc\360\237\226\211/cpp_ext.c" index 680bbf5..b1bb1d1 100644 --- "a/developer/cc\360\237\226\211/cpp_ext.c" +++ "b/developer/cc\360\237\226\211/cpp_ext.c" @@ -6,9 +6,8 @@ #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 @@ -16,57 +15,8 @@ */ - #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 diff --git "a/developer/cc\360\237\226\211/cpp_ext_0.c" "b/developer/cc\360\237\226\211/cpp_ext_0.c" index e196e92..635bab9 100644 --- "a/developer/cc\360\237\226\211/cpp_ext_0.c" +++ "b/developer/cc\360\237\226\211/cpp_ext_0.c" @@ -34,7 +34,7 @@ DEBUG #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 diff --git "a/developer/cc\360\237\226\211/cpp_ext_1.c" "b/developer/cc\360\237\226\211/cpp_ext_1.c" index 5f8a5b4..63d63f7 100644 --- "a/developer/cc\360\237\226\211/cpp_ext_1.c" +++ "b/developer/cc\360\237\226\211/cpp_ext_1.c" @@ -56,12 +56,12 @@ DROPE_EMPTY_RIGHT 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. @@ -95,17 +95,17 @@ DROPE_EMPTY_RIGHT #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(...) \ @@ -121,26 +121,25 @@ DROPE_EMPTY_RIGHT #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 @@ -150,7 +149,7 @@ DROPE_EMPTY_RIGHT #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 diff --git "a/developer/document\360\237\226\211/cpp_CAT_and_comma.org" "b/developer/document\360\237\226\211/cpp_CAT_and_comma.org" new file mode 100644 index 0000000..1507b5c --- /dev/null +++ "b/developer/document\360\237\226\211/cpp_CAT_and_comma.org" @@ -0,0 +1,44 @@ +* 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. diff --git "a/developer/document\360\237\226\211/cpp_gothyas.txt" "b/developer/document\360\237\226\211/cpp_gothyas.txt" index c2cd602..62d78c8 100644 --- "a/developer/document\360\237\226\211/cpp_gothyas.txt" +++ "b/developer/document\360\237\226\211/cpp_gothyas.txt" @@ -15,7 +15,7 @@ When defining a macro: 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. @@ -24,10 +24,8 @@ 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. diff --git a/developer/example_cpp/try_ext_1.c b/developer/example_cpp/try_ext_1.c index 8e87532..b0b5eaa 100644 --- a/developer/example_cpp/try_ext_1.c +++ b/developer/example_cpp/try_ext_1.c @@ -32,7 +32,7 @@ int main(void){ 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. //-------------------------------------------------------------------------- @@ -40,8 +40,8 @@ int main(void){ 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"); @@ -79,9 +79,9 @@ int main(void){ // 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(,) ); // → ε @@ -90,7 +90,6 @@ int main(void){ //-------------------------------------------------------------------------- // AND: true if all items are true (non-empty) //-------------------------------------------------------------------------- -#if 0 SHOW( AND(1 ,X ,0) ); // → 1 SHOW( AND(1 ,X ,) ); // → ε printf("\n"); @@ -102,5 +101,52 @@ int main(void){ 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( , , ,) -> + +*/