File
Blob: src/workerd/jsg/macro-meta.h
| 1 | // Copyright (c) 2017-2022 Cloudflare, Inc. |
| 2 | // Licensed under the Apache 2.0 license found in the LICENSE file or at: |
| 3 | // https://opensource.org/licenses/Apache-2.0 |
| 4 | |
| 5 | #pragma once |
| 6 | // INTERNAL IMPLEMENTATION FILE |
| 7 | // |
| 8 | // Some macro metaprogramming helpers. |
| 9 | |
| 10 | // ======================================================================================= |
| 11 | // TODO(cleanup): Move these macros to libkj. |
| 12 | |
| 13 | #define JSG_STRING_LITERAL_(...) #__VA_ARGS__ |
| 14 | #define JSG_STRING_LITERAL(...) JSG_STRING_LITERAL_(__VA_ARGS__) |
| 15 | // JSG_STRING_LITERAL(foo, bar) expands to the string literal: "foo, bar". |
| 16 | // |
| 17 | // This is the standard two-step "stringify after macro expansion" idiom: arguments are |
| 18 | // macro-expanded first, then stringified. Useful when callers pass identifiers that are themselves |
| 19 | // macros and you want to capture the expanded value (e.g. `JSG_STRING_LITERAL(__LINE__)` -> |
| 20 | // `"123"`). |
| 21 | // |
| 22 | // Do NOT use this to stringify user-supplied source-code blocks -- the implicit expansion will |
| 23 | // silently corrupt identifiers that happen to collide with platform header macros. On Darwin, for |
| 24 | // example, `<stdio.h>` defines `stdin`/`stdout`/`stderr` as `__stdinp`/`__stdoutp`/`__stderrp`, so |
| 25 | // `JSG_STRING_LITERAL({ stdin: 1 })` produces `"{ __stdinp: 1 }"` rather than the literal text. |
| 26 | // For source-code blocks, stringify directly with `#__VA_ARGS__` at the outermost macro that |
| 27 | // captures the user's tokens (see `JSG_TS_OVERRIDE` in jsg.h for an example). |
| 28 | |
| 29 | #define JSG_EXPAND(...) __VA_ARGS__ |
| 30 | // Identity macro. Often useful in macro hacking. |
| 31 | |
| 32 | #define JSG_IF_NONEMPTY_( \ |
| 33 | dummy, part1, part2, part3, part4, part5, part6, part7, part8, result, ...) \ |
| 34 | JSG_EXPAND result |
| 35 | #define JSG_IF_NONEMPTY_2_(...) dummy, ##__VA_ARGS__ |
| 36 | #define JSG_IF_NONEMPTY_3_(...) JSG_IF_NONEMPTY_(__VA_ARGS__) |
| 37 | #define JSG_IF_NONEMPTY(arg, ...) \ |
| 38 | JSG_IF_NONEMPTY_3_(JSG_IF_NONEMPTY_2_(arg), (__VA_ARGS__), (__VA_ARGS__), (__VA_ARGS__), \ |
| 39 | (__VA_ARGS__), (__VA_ARGS__), (__VA_ARGS__), (__VA_ARGS__), (__VA_ARGS__), ()) |
| 40 | |
| 41 | #define JSG_CAT(a, b) a##b |
| 42 | // Paste two preprocessor tokens together. Useful in macro hacking. |
| 43 | |
| 44 | // If the first argument is empty, expands to nothing. |
| 45 | // |
| 46 | // If the first argument is not empty, expands to the remaining arguments. |
| 47 | // |
| 48 | // So: |
| 49 | // JSG_IF_NONEMPTY(, foo, bar) -> |
| 50 | // JSG_IF_NONEMPTY(x, foo, bar) -> foo, bar |
| 51 | // |
| 52 | // (We support multiple "arguments" because often the output needs to contain commas, e.g. because |
| 53 | // it's a template type and the preprocessor doesn't recognize <...> as a grouping.) |
| 54 | |
| 55 | #define JSG_FOR_EACH_(op, param, A1, A2, A3, A4, A5, A6, A7, A8, B1, B2, B3, B4, B5, B6, B7, B8, \ |
| 56 | C1, C2, C3, C4, C5, C6, C7, C8, D1, D2, D3, D4, D5, D6, D7, D8, E1, E2, E3, E4, E5, E6, E7, \ |
| 57 | E8, F1, F2, F3, F4, F5, F6, F7, F8, sentinel, ...) \ |
| 58 | JSG_IF_NONEMPTY(A1, op(param, A1)) \ |
| 59 | JSG_IF_NONEMPTY(A2, , op(param, A2)) \ |
| 60 | JSG_IF_NONEMPTY(A3, , op(param, A3)) \ |
| 61 | JSG_IF_NONEMPTY(A4, , op(param, A4)) \ |
| 62 | JSG_IF_NONEMPTY(A5, , op(param, A5)) \ |
| 63 | JSG_IF_NONEMPTY(A6, , op(param, A6)) \ |
| 64 | JSG_IF_NONEMPTY(A7, , op(param, A7)) \ |
| 65 | JSG_IF_NONEMPTY(A8, , op(param, A8)) \ |
| 66 | JSG_IF_NONEMPTY(B1, , op(param, B1)) \ |
| 67 | JSG_IF_NONEMPTY(B2, , op(param, B2)) \ |
| 68 | JSG_IF_NONEMPTY(B3, , op(param, B3)) \ |
| 69 | JSG_IF_NONEMPTY(B4, , op(param, B4)) \ |
| 70 | JSG_IF_NONEMPTY(B5, , op(param, B5)) \ |
| 71 | JSG_IF_NONEMPTY(B6, , op(param, B6)) \ |
| 72 | JSG_IF_NONEMPTY(B7, , op(param, B7)) \ |
| 73 | JSG_IF_NONEMPTY(B8, , op(param, B8)) \ |
| 74 | JSG_IF_NONEMPTY(C1, , op(param, C1)) \ |
| 75 | JSG_IF_NONEMPTY(C2, , op(param, C2)) \ |
| 76 | JSG_IF_NONEMPTY(C3, , op(param, C3)) \ |
| 77 | JSG_IF_NONEMPTY(C4, , op(param, C4)) \ |
| 78 | JSG_IF_NONEMPTY(C5, , op(param, C5)) \ |
| 79 | JSG_IF_NONEMPTY(C6, , op(param, C6)) \ |
| 80 | JSG_IF_NONEMPTY(C7, , op(param, C7)) \ |
| 81 | JSG_IF_NONEMPTY(C8, , op(param, C8)) \ |
| 82 | JSG_IF_NONEMPTY(D1, , op(param, D1)) \ |
| 83 | JSG_IF_NONEMPTY(D2, , op(param, D2)) \ |
| 84 | JSG_IF_NONEMPTY(D3, , op(param, D3)) \ |
| 85 | JSG_IF_NONEMPTY(D4, , op(param, D4)) \ |
| 86 | JSG_IF_NONEMPTY(D5, , op(param, D5)) \ |
| 87 | JSG_IF_NONEMPTY(D6, , op(param, D6)) \ |
| 88 | JSG_IF_NONEMPTY(D7, , op(param, D7)) \ |
| 89 | JSG_IF_NONEMPTY(D8, , op(param, D8)) \ |
| 90 | JSG_IF_NONEMPTY(E1, , op(param, E1)) \ |
| 91 | JSG_IF_NONEMPTY(E2, , op(param, E2)) \ |
| 92 | JSG_IF_NONEMPTY(E3, , op(param, E3)) \ |
| 93 | JSG_IF_NONEMPTY(E4, , op(param, E4)) \ |
| 94 | JSG_IF_NONEMPTY(E5, , op(param, E5)) \ |
| 95 | JSG_IF_NONEMPTY(E6, , op(param, E6)) \ |
| 96 | JSG_IF_NONEMPTY(E7, , op(param, E7)) \ |
| 97 | JSG_IF_NONEMPTY(E8, , op(param, E8)) \ |
| 98 | JSG_IF_NONEMPTY(F1, , op(param, F1)) \ |
| 99 | JSG_IF_NONEMPTY(F2, , op(param, F2)) \ |
| 100 | JSG_IF_NONEMPTY(F3, , op(param, F3)) \ |
| 101 | JSG_IF_NONEMPTY(F4, , op(param, F4)) \ |
| 102 | JSG_IF_NONEMPTY(F5, , op(param, F5)) \ |
| 103 | JSG_IF_NONEMPTY(F6, , op(param, F6)) \ |
| 104 | JSG_IF_NONEMPTY(F7, , op(param, F7)) \ |
| 105 | JSG_IF_NONEMPTY(F8, , op(param, F8)) \ |
| 106 | JSG_IF_NONEMPTY(sentinel, error_JSG_FOR_EACH_only_supports_48_parameters) |
| 107 | |
| 108 | #define JSG_FOR_EACH(op, param, ...) \ |
| 109 | JSG_FOR_EACH_(op, param, ##__VA_ARGS__, , , , , , , , , , , , , , , , , , , , , , , , , , , , , \ |
| 110 | , , , , , , , , , , , , , , , , , , , , ) |
| 111 | // JSG_FOR_EACH(op, param, A, B, C, ...) expands to: op(param, A), op(param, B), op(param, C) ... |
| 112 | // |
| 113 | // Currently only supports up to 48 params. |