Add macros M_LET_IF and M_DEFER to help handling with runtime errors
This commit is contained in:
1 parent
a4ff7c71f2
commit
e893560a48
3 files changed
+120
-9
No files matched your search
@@ -5913,14 +5913,65 @@ then the variable 'v1' will be initialized with the
|
|||||||
contains of 'va_list...' using the specialized initializer operator INIT\_WITH
|
contains of 'va_list...' using the specialized initializer operator INIT\_WITH
|
||||||
and not the empty initializer INIT operator.
|
and not the empty initializer INIT operator.
|
||||||
|
|
||||||
|
There shall be at most one M\_LET macro per line of source code.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
M_LET(a, STRING_OPLIST) { do something with a } or
|
M_LET(a, STRING_OPLIST) { do something with a } or
|
||||||
M_LET(a, b, c, STRING_OPLIST) { do something with a, b & c }
|
M_LET(a, b, c, STRING_OPLIST) { do something with a, b & c }
|
||||||
|
|
||||||
NOTE: The user code can not perform a return or a goto outside the {}
|
NOTE: The user code shall not perform a return or a goto (or longjmp) outside the {} or a call to an exit function
|
||||||
otherwise the clear code of the object won't be called .
|
otherwise the clear code of the object won't be called .
|
||||||
However, you can use the break instruction to quit the block.
|
However, you can use the break instruction to quit the block (the clear function will be exexcuted),
|
||||||
|
and you can chain the M\_LET macro to create several different variables.
|
||||||
|
|
||||||
|
|
||||||
|
##### M\_LET\_IF(init_code, test_code, clear_code)
|
||||||
|
|
||||||
|
This macro defines the variable(s) in 'init_code',
|
||||||
|
executes the next block of instructions where the variable(s) is(are) used if the initialization succeeds by testing 'test_code',
|
||||||
|
then it executes the 'clear_code'.
|
||||||
|
|
||||||
|
'test_code' returns a boolean indicating if the initialization succeeds (true) or not.
|
||||||
|
If the initialization fails, it won't call the 'clear_code'.
|
||||||
|
|
||||||
|
The syntax is the same as a for loop.
|
||||||
|
|
||||||
|
There shall be at most one M\_LET\_IF macro per line of source code.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
M_LET_IF(int *p = malloc(100), p!=0, free(p)) {
|
||||||
|
M_LET_IF( /* nothing */ , mtx_lock(&mut)!=thrd_error, mtx_unlock(&mut)) {
|
||||||
|
printf ("OK! Let's use p in a mutex section\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
The user code shall not perform a return or a goto (or longjmp) outside the {} or a call to an exit function
|
||||||
|
otherwise the clear_code won't be called .
|
||||||
|
However, you can use the break instruction to quit the block (the clear_code will be exexcuted),
|
||||||
|
and you can chain the M\_LET macro to create several different variables.
|
||||||
|
|
||||||
|
##### M\_DEFER(clear_code)
|
||||||
|
|
||||||
|
This macro registers the execution of 'clear_code' when reaching the further closing brace
|
||||||
|
of the next block of instruction.
|
||||||
|
|
||||||
|
There shall be at most one M\_DEFER macro per line of source code.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
m_mutex_lock(mut);
|
||||||
|
M_DEFER(m_mutex_unlock(mut)) {
|
||||||
|
// Use of the critical section.
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
The user code shall not perform a return or a goto (or longjmp) outside the {} or a call to an exit function
|
||||||
|
otherwise the clear_code won't be called .
|
||||||
|
You can use the break instruction to quit the block (the clear_code will be exexcuted),
|
||||||
|
and you can chain the M\_LET macro to create several different variables.
|
||||||
|
|
||||||
|
|
||||||
#### Memory / Error macros
|
#### Memory / Error macros
|
||||||
|
|||||||
@@ -3117,14 +3117,50 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
|||||||
|
|
||||||
/* Transform the va list by adding their number as the first argument of
|
/* Transform the va list by adding their number as the first argument of
|
||||||
the list.
|
the list.
|
||||||
Example: M_VA(a,b,c,d,e) ==> 5,a,b,c,d,e */
|
Example: M_VA(a,b,c,d,e) ==> 5,a,b,c,d,e
|
||||||
|
TODO: Use of a structure instead of an integer to ensure limited syntax control.
|
||||||
|
*/
|
||||||
#define M_VA(...) M_NARGS(__VA_ARGS__), __VA_ARGS__
|
#define M_VA(...) M_NARGS(__VA_ARGS__), __VA_ARGS__
|
||||||
|
|
||||||
|
|
||||||
/* Initialize the container 'dest' as per 'oplist'
|
/* Defer the evaluation of the given expression until the closing brace.
|
||||||
and fill it with the given VA arguments.
|
M_DEFER(code) { }
|
||||||
NOTE: If the REVERSE operator exists, it is a list,
|
Example:
|
||||||
so reverse the final order.
|
M_DEFER(free(p)) {
|
||||||
|
// code using p
|
||||||
|
} // Here p is free
|
||||||
|
*/
|
||||||
|
#define M_DEFER(clear) \
|
||||||
|
M_DEFER_INTERNAL(clear, m_var_ ## __LINE__)
|
||||||
|
|
||||||
|
#define M_DEFER_INTERNAL(clear, cont) \
|
||||||
|
for(bool cont = true; cont; cont = false) \
|
||||||
|
for( (void) 0; cont ; (clear)) \
|
||||||
|
for( (void) 0; cont; cont = false) \
|
||||||
|
|
||||||
|
|
||||||
|
/* Declare a variable, initialize it, continue if the initialization succeeds,
|
||||||
|
and clears the variable afterwards.
|
||||||
|
Otherwise, stop the execution.
|
||||||
|
M_LET_IF(init code, test code, clear code) { code using the variable }
|
||||||
|
Example:
|
||||||
|
M_LET_IF(void * p = malloc(100), p!=0, free(p)) {
|
||||||
|
// code using p
|
||||||
|
} // Here p is free
|
||||||
|
*/
|
||||||
|
#define M_LET_IF(init, test, clear) \
|
||||||
|
M_LET_IF_INTERNAL(init, test, clear, m_var_ ## __LINE__)
|
||||||
|
|
||||||
|
#define M_LET_IF_INTERNAL(init, test, clear, cont) \
|
||||||
|
for(bool cont = true; cont; cont = false) \
|
||||||
|
for( init ; cont && (test) ; (clear)) \
|
||||||
|
for( (void) 0; cont; cont = false) \
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize the container 'dest' as per 'oplist' INIT operator
|
||||||
|
and fill it with the given VA arguments with the PUSH operator.
|
||||||
|
NOTE: If the REVERSE operator exists, it assumes a list,
|
||||||
|
so it reverses the final order.
|
||||||
*/
|
*/
|
||||||
#define M_INIT_VAI(oplist, dest, ...) \
|
#define M_INIT_VAI(oplist, dest, ...) \
|
||||||
(void)(M_GET_INIT oplist (dest) , \
|
(void)(M_GET_INIT oplist (dest) , \
|
||||||
@@ -3134,8 +3170,11 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
|||||||
#define M_INIT_VAI_FUNC(d, a) \
|
#define M_INIT_VAI_FUNC(d, a) \
|
||||||
M_PAIR_2 d (M_PAIR_1 d, a)
|
M_PAIR_2 d (M_PAIR_1 d, a)
|
||||||
|
|
||||||
/* Initialize the container 'dest' as per 'oplist'
|
|
||||||
and fill it with the given VA arguments which are pair of (key,value) */
|
/* Initialize the container 'dest' as per 'oplist' INIT operator
|
||||||
|
and fill it with the given VA argument
|
||||||
|
assumed to be pair (key,value) with the SET_KEY operator.
|
||||||
|
*/
|
||||||
#define M_INIT_KEY_VAI(oplist, dest, ...) \
|
#define M_INIT_KEY_VAI(oplist, dest, ...) \
|
||||||
(void)(M_GET_INIT oplist (dest) , \
|
(void)(M_GET_INIT oplist (dest) , \
|
||||||
M_MAP2_C(M_INIT_KEY_VAI_FUNC, (dest, M_GET_SET_KEY oplist) , __VA_ARGS__))
|
M_MAP2_C(M_INIT_KEY_VAI_FUNC, (dest, M_GET_SET_KEY oplist) , __VA_ARGS__))
|
||||||
|
|||||||
@@ -192,6 +192,27 @@ static void test_let(void)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
assert(b);
|
assert(b);
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
M_LET_IF( assert(c++ == 0), (assert(c++ == 1), true), assert(c++ == 3)) {
|
||||||
|
assert(c++ == 2);
|
||||||
|
}
|
||||||
|
M_LET_IF( assert(c++ == 4), (assert(c++ == 5), false), assert(0)) {
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
assert(c++ == 6);
|
||||||
|
M_LET_IF(int *p = (int*) malloc(sizeof(int)), p!=0, free(p)) {
|
||||||
|
assert(p != NULL);
|
||||||
|
*p = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *p = (int*)malloc(sizeof(int));
|
||||||
|
assert(p != NULL);
|
||||||
|
M_DEFER ( (assert(c++ == 8), free(p)) ) {
|
||||||
|
*p = 4;
|
||||||
|
assert(c++ == 7);
|
||||||
|
}
|
||||||
|
assert(c++ == 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_va(void)
|
static void test_va(void)
|
||||||
|
|||||||
Reference in new issue
Block a user