1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
#include <emscripten.h>
EM_JS(void, test_remove_cpp_comments_in_shaders, (void), {
var numFailed = 0;
function test(input, expected) {
var obtained = remove_cpp_comments_in_shaders(input);
function remove_nl(t) { return t.replace(/\\n/g, "\\\\\\n")}
if (obtained == expected) {
out(`OK: '${remove_nl(input)}' -> '${remove_nl(expected)}'`);
} else {
err(`\\nFailed! \\nInput: '${remove_nl(input)}'\\nObtained: '${remove_nl(obtained)}'\\nExpected: '${remove_nl(expected)}'\\n`);
++numFailed;
}
}
test('foo(); // test // test2 // test3', 'foo(); '); // Test that C++ comments '//' are removed
test('foo(); / /// test', 'foo(); / '); // Test that no confusion with slightly similar looking inputs
test('foo(); // /*', 'foo(); '); // Test that // takes away /*
test('foo(); //\nbar();', 'foo(); \nbar();'); // Test that // ends at the next newline
test('foo(); //*\nbar(); */', 'foo(); \nbar(); */'); // Test that //* is interpreted as //
test('foo(); /* aaa', 'foo(); '); // Test that on malformed /* without ending */, we remove all content up to end of string
test('foo(); /*\neee\n*/bar();', 'foo(); bar();'); // Test that /* */ works over multiple lines
test('foo(); /* // */bar();', 'foo(); bar();'); // Test that // comments inside /* */ comments are not processed
test('foo(); /*eee*//bar();', 'foo(); /bar();'); // Test that // comment as part of /* */ is not processed
test('foo(); /* a /* b */ c */', 'foo(); c */'); // Test that /* */ should not nest
// Verify known gotchas/quirks due to partial support: these are broken by design, as shaders do not support strings.
test('" // comment inside a string "', '" '); // Test that (unfortunately) comments will be removed even if they exist inside "" strings
test("' // comment inside a string '", "' "); // Test that (unfortunately) comments will be removed even if they exist inside '' strings
test('" // comment inside a multi\nline string "', '" \nline string "'); // Test that (unfortunately) newline inside string breaks a comment
test('" /* C comment inside a string */ "', '" "'); // Test that (unfortunately) C comments will also be removed inside strings
if (numFailed) throw numFailed + ' tests failed!';
});
EM_JS_DEPS(main, "$preprocess_c_code,$remove_cpp_comments_in_shaders");
EM_JS(void, test_c_preprocessor, (void), {
var numFailed = 0;
function test(input, expected) {
var obtained = preprocess_c_code(input);
function remove_nl(t) { return t.replace(/\\n/g, String.fromCharCode(92) + 'n'); }
if (obtained == expected) {
out(`OK: '${remove_nl(input)}' -> '${remove_nl(expected)}'`);
} else {
err(`\\nFailed! \\nInput: '${remove_nl(input)}'\\nObtained: '${remove_nl(obtained)}'\\nExpected: '${remove_nl(expected)}'\\n`);
++numFailed;
}
}
test('A\n #ifdef FOO\n B\n #endif', 'A\n'); // Test #ifdef not taken (also test whitespace at the beginning of a line)
test(' #define FOO 1\nA\n#ifdef FOO\n B\n #endif', 'A\n B\n'); // Test #ifdef taken
test(' #define FOO 0\nA\n#ifdef FOO\n B\n #endif', 'A\n B\n'); // Test #ifdef should be taken when var #defined to 0.
test('A\n#ifndef FOO\nB\n#endif', 'A\nB\n'); // Test #ifndef taken
test('#define FOO 1\nA\n#ifndef FOO\nB\n#endif', 'A\n'); // Test #ifndef not taken
test('#define FOO 0\nA\n#ifndef FOO\nB\n#endif', 'A\n'); // Test #ifndef not taken when #defined to 0.
test('#define FOO 1\nA\n#ifdef FOO\nB\n#endif\n#undef FOO\n#ifdef FOO\nC\n#endif\n', 'A\nB\n'); // Test #undef
test('#define FOO 1\nA\n#ifdef FOO\nB\n#endif\n#undef FOO\n#ifndef FOO\nC\n#endif\n', 'A\nB\nC\n'); // Test #undef
test('A\n#ifdef FOO\nB\n#else\nC\n#endif', 'A\nC\n'); // Test #ifdef-#else-#endif not taken
test('A\n#define FOO 0\n#ifdef FOO\nB\n#else\nC\n#endif', 'A\nB\n'); // Test #ifdef-#else-#endif taken
test(' #define FOO 0\nA\n#if FOO\n B\n#else \n C\n #endif', 'A\n C\n'); // Test #if-#else-#endif not taken
test(' #define FOO 10\nA\n#if FOO\n B\n#else \n C\n #endif', 'A\n B\n'); // Test #if-#else-#endif taken
test('#define FOO 1\n#define BAR 0\n#if FOO && BAR\nB\n#endif', ""); // Test && operator yielding negative
test('#define FOO 1\n#define BAR 1\n#if FOO && BAR\nB\n#endif', 'B\n'); // Test && operator yielding positive
test('#define FOO\t1\n#define BAR\t \t1\n#if FOO \t \t &&BAR\t\nB\n#endif', 'B\n'); // Test more complex whitespace around &&
test('#define FOO 1\n#define BAR 1\n#if (FOO && BAR)\nB\n#endif', 'B\n'); // Test parentheses around &&
test('#define FOO 1\n#define BAR 1\n#if (((FOO && BAR)))\nB\n#endif', 'B\n'); // Test nested parenthesess around &&
test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if FOO&&BAR||BAZ\nB\n#endif', 'B\n'); // Test precedence of && and ||
test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if (FOO&&BAR)||BAZ\nB\n#endif', 'B\n'); // Test parentheses with && and ||
test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if FOO&&(BAR||BAZ)\nB\n#endif', ""); // Test parentheses with && and ||
test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if FOO||BAR&&BAZ\nB\n#endif', 'B\n'); // Test parentheses with && and ||
test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if (FOO||BAR)&&BAZ\nB\n#endif', ""); // Test parentheses with && and ||
test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if FOO||(BAR&&BAZ)\nB\n#endif', 'B\n'); // Test parentheses with && and ||
test('#define FOO 1\n#define BAR 1\n#define BAZ 0\n#if FOO&&BAR&&BAZ\nB\n#endif', ""); // Test two &&s
test('#define FOO 0\n#define BAR 1\n#define BAZ 1\n#if FOO&&BAR&&BAZ\nB\n#endif', ""); // Test two &&s
test('#define FOO 1\n#define BAR 0\n#define BAZ 1\n#if FOO&&BAR&&BAZ\nB\n#endif', ""); // Test two &&s
test('#define FOO 1\n#define BAR 1\n#define BAZ 1\n#if FOO&&BAR&&BAZ\nB\n#endif', 'B\n'); // Test two &&s
test('#define FOO 1\n#define BAR 0\n#define BAZ 0\n#if FOO||BAR||BAZ\nB\n#endif', 'B\n'); // Test two ||s
test('#define FOO 0\n#define BAR 1\n#define BAZ 0\n#if FOO||BAR||BAZ\nB\n#endif', 'B\n'); // Test two ||s
test('#define FOO 0\n#define BAR 0\n#define BAZ 1\n#if FOO||BAR||BAZ\nB\n#endif', 'B\n'); // Test two ||s
test('#define FOO 0\n#define BAR 0\n#define BAZ 0\n#if FOO||BAR||BAZ\nB\n#endif', ""); // Test two ||s
test('#define FOO 1\n#if FOO < 3\nB\n#endif', 'B\n'); // Test <
test('#define FOO 1\n#if FOO < 1\nB\n#endif', ""); // Test <
test('#define FOO 1\n#if FOO > 0\nB\n#endif', 'B\n'); // Test >
test('#define FOO 1\n#if FOO > 1\nB\n#endif', ""); // Test >
test('#define FOO 1\n#if FOO <= 1\nB\n#endif', 'B\n'); // Test <=
test('#define FOO 1\n#if FOO <= 0\nB\n#endif', ""); // Test <=
test('#define FOO 1\n#if FOO >= 1\nB\n#endif', 'B\n'); // Test >=
test('#define FOO 1\n#if FOO >= 2\nB\n#endif', ""); // Test >=
test('#define FOO 0\n#define BAR 0\n#if FOO\n#if BAR\n1\n#else\n2\n#endif\n#else\n#if BAR\n3\n#else\n4\n#endif\n#endif', '4\n'); // Test nested #if-#elses
test('#define FOO 0\n#define BAR 1\n#if FOO\n#if BAR\n1\n#else\n2\n#endif\n#else\n#if BAR\n3\n#else\n4\n#endif\n#endif', '3\n'); // Test nested #if-#elses
test('#define FOO 1\n#define BAR 0\n#if FOO\n#if BAR\n1\n#else\n2\n#endif\n#else\n#if BAR\n3\n#else\n4\n#endif\n#endif', '2\n'); // Test nested #if-#elses
test('#define FOO 1\n#define BAR 1\n#if FOO\n#if BAR\n1\n#else\n2\n#endif\n#else\n#if BAR\n3\n#else\n4\n#endif\n#endif', '1\n'); // Test nested #if-#elses
test('#define FOO 1\n#define BAR 2\n#if FOO < 3 && BAR < 4\nB\n#endif', 'B\n'); // Test evaluation of && and <
test('#define FOO 1\n#define BAR 2\n#if FOO < 3 && BAR < 2\nB\n#endif', ""); // Test evaluation of && and <
test('#define FOO 1\n#define BAR 2\n#if FOO == 1 && BAR == 2\nB\n#endif', 'B\n'); // Test evaluation of && and ==
test('#define FOO 1\n#define BAR 2\n#if FOO == 1 && BAR != 2\nB\n#endif', ""); // Test evaluation of && and !=
test('#define FOO 1\n#define BAR 2\n#if FOO < 3 || BAR < 0\nB\n#endif', 'B\n'); // Test evaluation of || and <
test('#define FOO 1\n#define BAR 2\n#if FOO < 1 || BAR < 2\nB\n#endif', ""); // Test evaluation of || and <
test('#define FOO 1\n#define BAR 2\n#if FOO == 1 || BAR == 3\nB\n#endif', 'B\n'); // Test evaluation of || and ==
test('#define FOO 1\n#define BAR 2\n#if FOO != 1 || BAR != 2\nB\n#endif', ""); // Test evaluation of || and !=
test('#define FOO 1\n#define BAR 2\n#if FOO < 2 && BAR > 1 && FOO <= 1 && BAR >= 2 && FOO == 1 && BAR != 1\nB\n#endif', 'B\n'); // Test complex comparisons
test('#define FOO 1\n#define BAR 2\n#if FOO < 2 && BAR > 1 && FOO <= 1 && BAR >= 2 && FOO == 1 && BAR != 2\nB\n#endif', ""); // Test complex comparisons
test('#define FOO 1\n#define BAR 1\n#if FOO == BAR\nB\n#endif', 'B\n'); // Test comparison of two vars against each other
test('#define FOO 1\n#define BAR 1\n#if FOO != BAR\nB\n#endif', ""); // Test comparison of two vars against each other
test('#define FOO 1\n#define BAR 2\n#if FOO == BAR\nB\n#endif', ""); // Test comparison of two vars against each other
test('#define FOO 1\n#define BAR 2\n#if FOO != BAR\nB\n#endif', 'B\n'); // Test comparison of two vars against each other
test('#define FOO 0\n#if !FOO\nB\n#endif', 'B\n'); // Test unary !
test('#define FOO 1\n#if !FOO\nB\n#endif', ""); // Test unary !
test('#define FOO 1\n#define BAR 0\n#if !FOO && BAR\nB\n#endif', ""); // Test unary ! and && precedence
test('#define FOO 1\n#define BAR 0\n#if FOO && !BAR\nB\n#endif', 'B\n'); // Test unary ! and && precedence
test('#define FOO 0\n#define BAR 1\n#if !(FOO && BAR)\nB\n#endif', 'B\n'); // Test unary ! and && precedence with parentheses
test('#define FOO 1\n#define BAR 1\n#if !(FOO && BAR)\nB\n#endif', ""); // Test unary ! and && precedence with parentheses
test('#define FOO 1\n#if !!FOO\nB\n#endif', 'B\n'); // Test double !!
test('#define FOO 1\n#if !!(FOO)\nB\n#endif', 'B\n'); // Test double !!
test('#define FOO 1\n#if !(!FOO)\nB\n#endif', 'B\n'); // Test double !!
test('#define FOO 1\n#if ((!((!((!!!FOO))))))\nB\n#endif', ""); // Test complex ! and ()
test('#define M12 1\n#define M22 0\n#if M12 == 1 && M22 == 0\nB\n#endif', 'B\n'); // Test including a number in a variable name
test('#define M12 1\n#define M22 0\n#if M22 == 1 && M12 == 0\nB\n#endif', ""); // Test including a number in a variable name
test('#define FOO 42\nFOO\n', '42\n'); // Test expanding a preprocessor symbol
test('#define FOO 42\n#define BAR FOO\nBAR\n', '42\n'); // Test chained expanding a preprocessor symbol
test('#define MACRO(x) x\nMACRO(42)\n', '42\n'); // Test one-parameter preprocessor macro
test('#define MACRO(x,y) x\nMACRO(42, 53)\n', '42\n'); // Test a two-parameter preprocessor macro
test('#define MACRO( \t x , y ) \t x \t\nMACRO(42, 53)\n', '42\n'); // Test a macro with odd whitescape in it
test('#define MACRO(x,y,z) x+y<=z\nMACRO(42,15,30)\n', '42+15<=30\n'); // Test three-arg macro
test('#define FOO 1\n#define BAR 2\n#define BAZ 1\n#define MACRO(x,y,z) x<y&&z\n#if MACRO(FOO,BAR,BAZ)\nA\n#endif', 'A\n'); // Test three-arg macro in an #if comparison
test('#define FOO 1\n#define BAR 2\n#define BAZ 0\n#define MACRO(x,y,z) x<y&&z\n#if MACRO(FOO,BAR,BAZ)\nA\n#endif', ""); // Test three-arg macro in an #if comparison
test('#if 1>2&&0\nA\n#endif', ""); // Test precedence between > and &&
test('#if 0&&1>2\nA\n#endif', ""); // Test precedence between > and &&
test('#if 2<3&&1\nA\n#endif', "A\n"); // Test precedence between > and &&
test('#if 1&&2<3\nA\n#endif', "A\n"); // Test precedence between > and &&
test('#if 1+2<=3\nA\n#endif', 'A\n'); // Test arithmetic + and comparison op precedence
test('#if 1+2 <3\nA\n#endif', ""); // Test arithmetic + and comparison op precedence
test('#if 1+2*0\nA\n#endif', "A\n"); // Test arithmetic + and * precedence
test('#if 1+1*2==4\nA\n#endif', ""); // Test arithmetic + and * precedence
test('#if 5/2==2\nA\n#endif', "A\n"); // Test arithmetic integer divide /
test('#if defined(FOO)\nA\n#endif', ""); // Test defined() macro
test('#define FOO 0\n#if defined(FOO)\nA\n#endif', "A\n"); // Test defined() macro
test('#define FOO 0\n#if !defined(FOO)\nA\n#endif', ""); // Test that !defined() works
test('#define FOO 0\n#if defined FOO \nA\n#endif', "A\n"); // Test defined without using parens
test('#define FOO 0\n#if ! defined FOO \nA\n#endif', ""); // Test that ! defined works, with odd whitespace
test('#define FOO 0\n#if defined FOO \nA\n#endif', "A\n"); // Test defined without using parens, with odd whitespace
test('#define FOO 0\n#if defined (FOO) \nA\n#endif', "A\n"); // Test defined with parens and whitespace
test('#define FOO 0\n#if defined ( FOO ) \nA\n#endif', "A\n"); // Test defined with parens and whitespace
test('#define FOO 0\n#undef FOO\n#if defined(FOO)\nA\n#endif', ""); // Test defined() macro after #undef
test('#define FOO 0\n#if defined FOO && BAR \nA\n#endif', ""); // Test that defined operator binds tighter than &&
test('#define SAMPLE_TEXTURE_2D texture \nvec4 c = SAMPLE_TEXTURE_2D(tex, texCoord);\n', 'vec4 c = texture(tex, texCoord);\n'); // Test expanding a non-macro to a macro-like call site
test('#extension GL_EXT_shader_texture_lod : enable\n', '#extension GL_EXT_shader_texture_lod : enable\n'); // Test that GLSL preprocessor macros are preserved
test('#version 300 es\n', '#version 300 es\n'); // Test that GLSL preprocessor macros are preserved
test('#pragma foo\n', '#pragma foo\n'); // Test that GLSL preprocessor macros are preserved
test('#define FOO() bar\nFOO()\n', 'bar\n'); // Test preprocessor macros that do not take in any parameters
test('#define FOO 1\n#if FOO\n#define BAR this_is_right\n#else\n#define BAR this_is_wrong\n#endif\nBAR', 'this_is_right\n'); // Test nested #defines in both sides of an #if-#else block.
test('\n#define FOO 1\nFOO\n', '\n1\n'); // Test that preprocessor is not confused by an input that starts with a \n
test('#line 162 "foo.glsl"\n', '#line 162 "foo.glsl"\n'); // Test that #line directives are retained in the output
if (numFailed) throw numFailed + ' tests failed!';
});
int main()
{
test_remove_cpp_comments_in_shaders();
test_c_preprocessor();
}
|