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
|
||||
and not the empty initializer INIT operator.
|
||||
|
||||
There shall be at most one M\_LET macro per line of source code.
|
||||
|
||||
Example:
|
||||
|
||||
M_LET(a, STRING_OPLIST) { do something with a } or
|
||||
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 .
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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__
|
||||
|
||||
|
||||
/* Initialize the container 'dest' as per 'oplist'
|
||||
and fill it with the given VA arguments.
|
||||
NOTE: If the REVERSE operator exists, it is a list,
|
||||
so reverse the final order.
|
||||
/* Defer the evaluation of the given expression until the closing brace.
|
||||
M_DEFER(code) { }
|
||||
Example:
|
||||
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, ...) \
|
||||
(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) \
|
||||
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, ...) \
|
||||
(void)(M_GET_INIT oplist (dest) , \
|
||||
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(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)
|
||||
|
||||
Reference in new issue
Block a user