util.h

Utilitary stuff.

Defines

ML99_catEval(a, b)

Concatenates a with b and evaluates the result.

Examples

#include <metalang99/util.h>

#define ABC123 v(Billie Jean)

// Billie Jean
ML99_catEval(v(ABC), v(123))

// ERROR: 123ABC is not a valid Metalang99 term.
ML99_catEval(v(123), v(ABC))

Deprecated:

I have seen no single use case over time. Please, open an issue if you need this function.

ML99_cat(a, b)

Concatenates a with b, leaving the result unevaluated.

Examples

#include <metalang99/util.h>

#define ABC123 Billie Jean

// Billie Jean
ML99_cat(v(ABC), v(123))

// 123ABC
ML99_cat(v(123), v(ABC))
ML99_cat3(a, b, c)

The same as ML99_cat but deals with 3 parameters.

ML99_cat4(a, b, c, d)

The same as ML99_cat but deals with 4 parameters.

ML99_stringify(...)

Stringifies provided arguments.

Examples

#include <metalang99/util.h>

// "Billie Jean"
ML99_stringify(v(Billie Jean))
ML99_empty(...)

Evaluates to nothing.

ML99_id(...)

Evaluates to its arguments.

Examples

#include <metalang99/util.h>

// 1, 2, 3
ML99_id(v(1, 2, 3))
ML99_const(x, a)

Evaluates to x, skipping a.

Examples

#include <metalang99/util.h>

// 123
ML99_const(v(123), v(5))
ML99_flip(f)

Reverses the order of arguments of the binary function f.

Examples

#include <metalang99/util.h>

// ABC123
ML99_appl2(ML99_flip(v(ML99_catUnevaluated)), v(123), v(ABC))
ML99_uncomma(...)

Accepts terms and evaluates them with the space-separator.

Examples

#include <metalang99/util.h>

// 1 2 3
ML99_uncomma(ML99_QUOTE(v(1), v(2), v(3)))
ML99_reify(f)

Turns f into a Metalang99-compliant metafunction with the arity of 1, which can be then called by ML99_appl.

f can be any C function or function-like macro.

Examples

#include <metalang99/util.h>
#include <metalang99/variadics.h>

#define F(x) @x

// @1 @2 @3
ML99_variadicsForEach(ML99_reify(v(F)), v(1, 2, 3))

Without ML99_reify, you would need to write some additional boilerplate:

#define F_IMPL(x) v(@x)
#define F_ARITY   1
ML99_todo(f)

Indicates not yet implemented functionality of the macro f.

ML99_todo is the same as ML99_unimplemented except that the former conveys an intent that the functionality is to be implemented later but ML99_unimplemented makes no such claims.

Examples

#include <metalang99/util.h>

// A not-yet implemented error.
ML99_todo(v(F))

See also

Rust’s std::todo! (thanks for the idea!)

ML99_todoWithMsg(f, message)

The same as ML99_todo but emits a caller-supplied message.

message must be a string literal.

Examples

#include <metalang99/util.h>

// A not-yet-implemented error.
ML99_todoWithMsg(v(F), v("your message"))
ML99_unimplemented(f)

Indicates unimplemented functionality of the macro f.

ML99_unimplemented is the same as ML99_todo except that the latter conveys an intent that the functionality is to be implemented later but ML99_unimplemented makes no such claims.

Examples

#include <metalang99/util.h>

// A not-implemented error.
ML99_unimplemented(v(F))

See also

Rust’s std::unimplemented! (thanks for the idea!)

ML99_unimplementedWithMsg(f, message)

The same as ML99_unimplemented but emits a caller-supplied message.

message must be a string literal.

Examples

#include <metalang99/util.h>

// A not-implemented error.
ML99_unimplementedWithMsg(v(F), v("your message"))
ML99_GEN_SYM(prefix, id)

Generates a unique identifier id in the namespace prefix.

Let FOO be the name of an enclosing macro. Then FOO_ must be specified for prefix, and id should be given any meaningful name (this makes debugging easier).

Examples

#include <metalang99/util.h>

#define FOO(...) FOO_NAMED(ML99_GEN_SYM(FOO_, x), __VA_ARGS__)
#define FOO_NAMED(x_sym, ...) \
     do { int x_sym = 5; __VA_ARGS__ } while (0)

// `x` here will not conflict with the `x` inside `FOO`.
FOO({
    int x = 7;
    printf("x is %d\n", x); // x is 7
});

Note

Two identical calls to ML99_GEN_SYM will yield different identifiers, therefore, to refer to the result later, you must save it in an auxiliary macro’s parameter, as shown in the example above.

Note

ML99_GEN_SYM is defined only if __COUNTER__ is defined, which must be a macro yielding integral literals starting from 0 incremented by 1 each time it is called. Currently, it is supported at least by Clang, GCC, TCC, and MSVC.

ML99_TRAILING_SEMICOLON(...)

Forces a caller to put a trailing semicolon.

It is useful when defining macros, to make them formatted as complete statements.

Examples

#include <metalang99/util.h>

#define MY_MACRO(fn_name, val_ty, val) \
    inline static val_ty fn_name(void) { return val; } \
    ML99_TRAILING_SEMICOLON()

// Defines a function that always returns 0.
MY_MACRO(zero, int, 0);

Note

ML99_TRAILING_SEMICOLON is to be used outside of functions: unlike the do { ... } while (0) idiom, this macro expands to a C declaration.

ML99_CAT_PRIMITIVE(a, b)

Concatenates a with b as-is, without expanding them.

Examples

#include <metalang99/util.h>

// This macro will not be expanded.
#define ABC 7

// ABC123
ML99_CAT_PRIMITIVE(ABC, 123)
ML99_CAT3_PRIMITIVE(a, b, c)

The same as ML99_CAT_PRIMITIVE but deals with 3 parameters.

ML99_CAT4_PRIMITIVE(a, b, c, d)

The same as ML99_CAT_PRIMITIVE but deals with 4 parameters.

ML99_STRINGIFY_PRIMITIVE(...)

Stringifies x as-is, without expanding it.

Examples

#include <metalang99/util.h>

// This macro will not be expanded.
#define ABC 7

// "ABC"
ML99_STRINGIFY_PRIMITIVE(ABC)
ML99_LPAREN(...)

Expands to an opening parenthesis (().

This is helpful when you want to delay macro arguments passing: just type BAR ML99_LPAREN() initial args... at the end of some macro FOO and complete the invocation of BAR with the rest of args...) in future.

This macro consumes all its arguments.

Deprecated:

This macro results in code that is difficult to reason about.

ML99_RPAREN(...)

The same as ML99_LPAREN but emits a closing parenthesis.

Deprecated:

For the same reason as ML99_LPAREN.

ML99_COMMA(...)

Expands to a single comma, consuming all arguments.

ML99_GCC_PRAGMA(str)

If you are compiling on GCC, this macro expands to _Pragma(str), otherwise to emptiness.

ML99_CLANG_PRAGMA(str)

The same as ML99_GCC_PRAGMA but for Clang.

ML99_CAT(a, b)
ML99_CAT3(a, b, c)
ML99_CAT4(a, b, c, d)
ML99_STRINGIFY(...)
ML99_EMPTY(...)
ML99_ID(...)