Blender V5.0
shader_preprocess_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
6
7#include "gpu_testing.hh"
8
9namespace blender::gpu::tests {
10
12{
13 using namespace shader;
14 using namespace std;
15
16 string input = "test (u, u(s,(s,s)), u) {t{{}},t,{};(,)} {u{}} end";
19
21 "test (u! u(s!(s!s))! u) {t{{}},t,{};(!)} {u{}} end");
22
23 vector<string> split_expect{"test (u, u(s,(s,s", "", ", u", " {t{{}},t,{};(,", "} {u{}} end"};
25 EXPECT_EQ_VECTOR(split_expect, split_result);
26
27 string input2 = "u, u(s,(s,s)), u";
28 vector<string> split_expect2{"u", " u(s,(s,s))", " u"};
30 input2, ',', '(', ')');
31 EXPECT_EQ_VECTOR(split_expect2, split_result2);
32
33 string input_reference = "void func(int &a, int (&c)[2]) {{ int &b = a; }} int &b = a;";
34 int fn_ref_count = 0, arg_ref_count = 0, global_ref_count = 0;
36 input_reference, [&](int parenthesis_depth, int bracket_depth, char & /*c*/) {
37 if ((parenthesis_depth == 1 || parenthesis_depth == 2) && bracket_depth == 0) {
38 arg_ref_count += 1;
39 }
40 else if (bracket_depth > 0) {
41 fn_ref_count += 1;
42 }
43 else if (bracket_depth == 0 && parenthesis_depth == 0) {
44 global_ref_count += 1;
45 }
46 });
47 EXPECT_EQ(arg_ref_count, 2);
48 EXPECT_EQ(fn_ref_count, 1);
49 EXPECT_EQ(global_ref_count, 1);
50}
51GPU_TEST(preprocess_utilities);
52
53static std::string process_test_string(std::string str,
54 std::string &first_error,
55 shader::metadata::Source *r_metadata = nullptr,
58{
59 using namespace shader;
60 Preprocessor preprocessor;
62 std::string result = preprocessor.process(
63 language,
64 str,
65 "test.glsl",
66 true,
67 true,
68 [&](int /*err_line*/, int /*err_char*/, const std::string & /*line*/, const char *err_msg) {
69 if (first_error.empty()) {
70 first_error = err_msg;
71 }
72 },
73 metadata);
74
75 if (r_metadata != nullptr) {
76 *r_metadata = metadata;
77 }
78
79 /* Strip first line directive as they are platform dependent. */
80 size_t newline = result.find('\n');
81 return result.substr(newline + 1);
82}
83
85{
86 using namespace shader;
87 using namespace std;
88 {
89 string input = R"(
90#include "a.hh"
91#include "b.glsl"
92#if 0
93# include "c.hh"
94#else
95# include "d.hh"
96#endif
97#if !defined(GPU_SHADER)
98# include "e.hh"
99#endif
100)";
101 string expect =
102 R"(static void test(GPUSource &source, GPUFunctionDictionary *g_functions, GPUPrintFormatMap *g_formats) {
103 source.add_dependency("a.hh");
104 source.add_dependency("b.glsl");
105 source.add_dependency("d.hh");
106 UNUSED_VARS(source, g_functions, g_formats);
107}
108)";
109 string error;
112 EXPECT_EQ(expect, metadata.serialize("test"));
113 EXPECT_EQ(error, "");
114 }
115}
117
118static void test_preprocess_unroll()
119{
120 using namespace shader;
121 using namespace std;
122
123 {
124 string input = R"(
125[[gpu::unroll]] for (int i = 2; i < 4; i++, y++) { content += i; })";
126 string expect = R"(
127
128#line 2
129 {int i = 2;
130#line 2
131 { content += i; }
132#line 2
133 i++, y++;
134#line 2
135 { content += i; }
136#line 2
137 i++, y++;
138#line 2
139 })";
140 string error;
142 EXPECT_EQ(output, expect);
143 EXPECT_EQ(error, "");
144 }
145 {
146 string input = R"(
147[[gpu::unroll]] for (int i = 2; i < 4 && i < y; i++, y++) { cont += i; })";
148 string expect = R"(
149
150#line 2
151 {int i = 2;
152#line 2
153 if(i < 4 && i < y)
154#line 2
155 { cont += i; }
156#line 2
157 i++, y++;
158#line 2
159 if(i < 4 && i < y)
160#line 2
161 { cont += i; }
162#line 2
163 i++, y++;
164#line 2
165 })";
166 string error;
168 EXPECT_EQ(output, expect);
169 EXPECT_EQ(error, "");
170 }
171 {
172 string input = R"(
173[[gpu::unroll(2)]] for (; i < j;) { content += i; })";
174 string expect = R"(
176{
177#line 2
178 if(i < j)
179#line 2
180 { content += i; }
181#line 2
182 if(i < j)
183#line 2
184 { content += i; }
185#line 2
186 })";
187 string error;
189 EXPECT_EQ(output, expect);
190 EXPECT_EQ(error, "");
191 }
192 {
193 string input = R"(
194[[gpu::unroll(2)]] for (; i < j;) { [[gpu::unroll(2)]] for (; j < k;) {} })";
195 string expect = R"(
196
197{
198#line 2
199 if(i < j)
200#line 2
201 {
202{
203#line 2
204 if(j < k)
205#line 2
206 {}
207#line 2
208 if(j < k)
209#line 2
210 {}
211#line 2
212 } }
213#line 2
214 if(i < j)
215#line 2
216 {
217{
218#line 2
219 if(j < k)
220#line 2
221 {}
222#line 2
223 if(j < k)
224#line 2
225 {}
226#line 2
227 } }
228#line 2
229 })";
230 string error;
232 EXPECT_EQ(output, expect);
233 EXPECT_EQ(error, "");
234 }
235 {
236 string input = R"([[gpu::unroll(2)]] for (; i < j;) { break; })";
237 string error;
239 EXPECT_EQ(error, "Unrolled loop cannot contain \"break\" statement.");
240 }
241 {
242 string input = R"([[gpu::unroll(2)]] for (; i < j;) { continue; })";
243 string error;
245 EXPECT_EQ(error, "Unrolled loop cannot contain \"continue\" statement.");
246 }
247 {
248 string input = R"(
249[[gpu::unroll(2)]] for (; i < j;) { for (; j < k;) {break;continue;} })";
250 string expect = R"(
251
252{
253#line 2
254 if(i < j)
255#line 2
256 { for (; j < k;) {break;continue;} }
257#line 2
258 if(i < j)
259#line 2
260 { for (; j < k;) {break;continue;} }
261#line 2
262 })";
263 string error;
265 EXPECT_EQ(output, expect);
266 EXPECT_EQ(error, "");
267 }
268 {
269 string input = R"([[gpu::unroll]] for (int i = 3; i > 2; i++) {})";
270 string error;
272 EXPECT_EQ(error, "Unsupported condition in unrolled loop.");
273 }
274 {
275 string input = R"(
276[[gpu::unroll_define(2)]] for (int i = 0; i < DEFINE; i++) { a = i; })";
277 string expect = R"(
278
279{
280#if DEFINE > 0
281#line 2
282 { a = 0; }
283#endif
284#if DEFINE > 1
285#line 2
286 { a = 1; }
287#endif
288#line 2
289 })";
290 string error;
292 EXPECT_EQ(output, expect);
293 EXPECT_EQ(error, "");
294 }
295}
296GPU_TEST(preprocess_unroll);
297
298static void test_preprocess_template()
299{
300 using namespace shader;
301 using namespace std;
302
303 {
304 string input = R"(
305template<typename T>
306void func(T a) {a;}
307template void func<float>(float a);
308)";
309 string expect = R"(
310
311
312#line 3
313void func(float a) {a;}
314#line 5
315)";
316 string error;
318 EXPECT_EQ(output, expect);
319 EXPECT_EQ(error, "");
320 }
321 {
322 string input = R"(
323template<typename T, int i>
324void func(T a) {
325 a;
326}
327template void func<float, 1>(float a);
328)";
329 string expect = R"(
331
333
334#line 3
335void funcTfloatT1(float a) {
336 a;
337}
338#line 7
339)";
340 string error;
342 EXPECT_EQ(output, expect);
343 EXPECT_EQ(error, "");
344 }
345 {
346 string input = R"(
347template<> void func<T, Q>(T a) {a}
348)";
349 string expect = R"(
350 void funcTTTQ(T a) {a}
351)";
352 string error;
354 EXPECT_EQ(output, expect);
355 EXPECT_EQ(error, "");
356 }
357 {
358 string input = R"(
359template<typename T, int i = 0> void func(T a) {a;}
360)";
361 string error;
363 EXPECT_EQ(error, "Default arguments are not supported inside template declaration");
364 }
365 {
366 string input = R"(
367template void func(float a);
368)";
369 string error;
371 EXPECT_EQ(error, "Template instantiation unsupported syntax");
373 {
374 string input = R"(func<float, 1>(a);)";
375 string expect = R"(funcTfloatT1(a);)";
376 string error;
378 EXPECT_EQ(output, expect);
379 EXPECT_EQ(error, "");
380 }
381}
382GPU_TEST(preprocess_template);
383
385{
386 using namespace shader;
387 using namespace std;
388
389 {
390 string input = R"(
391template<typename T>
392struct A { T a; };
393template struct A<float>;
394)";
395 string expect = R"(
396
397
398#line 3
399struct ATfloat { float a; };
400#line 4
401#line 5
402)";
403 string error;
405 EXPECT_EQ(output, expect);
406 EXPECT_EQ(error, "");
407 }
408 {
409 string input = R"(
410template<> struct A<float>{
411 float a;
412};
413)";
414 string expect = R"(
415 struct ATfloat{
416 float a;
417};
418#line 5
419)";
420 string error;
422 EXPECT_EQ(output, expect);
423 EXPECT_EQ(error, "");
424 }
425 {
426 string input = R"(
427void func(A<float> a) {}
428)";
429 string expect = R"(
430void func(ATfloat a) {}
431)";
432 string error;
434 EXPECT_EQ(output, expect);
435 EXPECT_EQ(error, "");
436 }
437}
438GPU_TEST(preprocess_template_struct);
439
440static void test_preprocess_reference()
441{
442 using namespace shader;
443 using namespace std;
444
445 {
446 string input = R"(void func() { auto &a = b; a.a = 0; c = a(a); a_c_a = a; })";
447 string expect = R"(void func() { b.a = 0; c = a(b); a_c_a = b; })";
448 string error;
450 EXPECT_EQ(output, expect);
451 EXPECT_EQ(error, "");
452 }
453 {
454 string input = R"(void func() { const int &a = b; a.a = 0; c = a(a); })";
455 string expect = R"(void func() { b.a = 0; c = a(b); })";
456 string error;
458 EXPECT_EQ(output, expect);
459 EXPECT_EQ(error, "");
460 }
461 {
462 string input = R"(void func() { const int i = 0; auto &a = b[i]; a.a = 0; })";
463 string expect = R"(void func() { const int i = 0; b[i].a = 0; })";
464 string error;
466 EXPECT_EQ(output, expect);
467 EXPECT_EQ(error, "");
468 }
469 {
470 string input = R"(void func() { auto &a = b(0); })";
471 string error;
473 EXPECT_EQ(error, "Reference definitions cannot contain function calls.");
474 }
475 {
476 string input = R"(void func() { int i = 0; auto &a = b[i++]; })";
477 string error;
479 EXPECT_EQ(error, "Reference definitions cannot have side effects.");
480 }
481 {
482 string input = R"(void func() { auto &a = b[0 + 1]; })";
483 string error;
486 "Array subscript inside reference declaration must be a single variable or a "
487 "constant, not an expression.");
488 }
489 {
490 string input = R"(void func() { auto &a = b[c]; })";
491 string error;
494 "Cannot locate array subscript variable declaration. "
495 "If it is a global variable, assign it to a temporary const variable for "
496 "indexing inside the reference.");
497 }
498 {
499 string input = R"(void func() { int c = 0; auto &a = b[c]; })";
500 string error;
502 EXPECT_EQ(error, "Array subscript variable must be declared as const qualified.");
503 }
504 {
505 string input = R"(auto &a = b;)";
506 string error;
508 EXPECT_EQ(error, "Reference is defined inside a global or unterminated scope.");
509 }
510}
511GPU_TEST(preprocess_reference);
512
514{
515 using namespace shader;
516 using namespace std;
517
518 {
519 string input = R"(
520int func(int a, int b = 0)
521{
522 return a + b;
523}
524)";
525 string expect = R"(
526int func(int a, int b )
527{
528 return a + b;
529}
530#line 2
531int func(int a)
532{
533#line 2
534 return func(a, 0);
536#line 6
537)";
538 string error;
540 EXPECT_EQ(output, expect);
541 EXPECT_EQ(error, "");
542 }
543 {
544 string input = R"(
545int func(int a = 0, const int b = 0)
546{
547 return a + b;
548}
549)";
550 string expect = R"(
551int func(int a , const int b )
552{
553 return a + b;
554}
555#line 2
556int func(int a)
557{
558#line 2
559 return func(a, 0);
560}
561#line 2
562int func()
563{
564#line 2
565 return func(0);
566}
567#line 6
568)";
569 string error;
571 EXPECT_EQ(output, expect);
572 EXPECT_EQ(error, "");
573 }
574 {
575 string input = R"(
576int2 func(int2 a = int2(0, 0)) {
577 return a;
578}
579)";
580 string expect = R"(
581int2 func(int2 a ) {
582 return a;
583}
584#line 2
585int2 func()
586{
587#line 2
588 return func(int2(0, 0));
589}
590#line 5
591)";
592 string error;
594 EXPECT_EQ(output, expect);
595 EXPECT_EQ(error, "");
596 }
597 {
598 string input = R"(
599void func(int a = 0) {
600 a;
601}
602)";
603 string expect = R"(
604void func(int a ) {
605 a;
606}
607#line 2
608void func()
609{
610#line 2
611 func(0);
612}
613#line 5
614)";
615 string error;
617 EXPECT_EQ(output, expect);
618 EXPECT_EQ(error, "");
619 }
620}
621GPU_TEST(preprocess_default_arguments);
622
623static void test_preprocess_namespace()
624{
625 using namespace shader;
626 using namespace std;
627
628 {
629 string input = R"(
630namespace A {
631struct S {};
632int func(int a)
633{
634 S s;
635 return B::func(int a);
636}
637int func2(int a)
638{
639 T s;
640 s.S;
641 s.func;
642 return func(int a);
643}
644}
645)";
646 string expect = R"(
647
648struct A_S {int _pad;};
649#line 4
650int A_func(int a)
651{
652 A_S s;
653 return B_func(int a);
654}
655int A_func2(int a)
656{
657 T s;
658 s.S;
659 s.func;
660 return A_func(int a);
661}
662
663)";
664 string error;
666 EXPECT_EQ(output, expect);
667 EXPECT_EQ(error, "");
668 }
669 {
670 string input = R"(
671namespace A::B {
672int func(int a)
673{
674 return a;
675}
676int func2(int a)
677{
678 return func(int a);
679}
680}
681)";
682 string expect = R"(
683
684int A_B_func(int a)
685{
686 return a;
687}
688int A_B_func2(int a)
689{
690 return A_B_func(int a);
691}
692
693)";
694 string error;
696 EXPECT_EQ(output, expect);
697 EXPECT_EQ(error, "");
698 }
699 {
700 string input = R"(
701namespace A {
702namespace B {
703int func(int a)
704{
705 return a;
706}
707}
708}
709)";
710 string error;
712 EXPECT_EQ(error, "Nested namespaces are unsupported.");
713 }
714 {
715 string input = R"(
716namespace A {
717int test(int a) {}
718int func(int a)
719{
720 using B::test;
721 return test(a);
722}
723}
724)";
725 string expect = R"(
726
727int A_test(int a) {}
728int A_func(int a)
729{
730
731 return B_test(a);
732}
733
734)";
735 string error;
737 EXPECT_EQ(output, expect);
738 EXPECT_EQ(error, "");
739 }
740 {
741 string input = R"(
742int func(int a)
743{
744 using B = A::S;
745 B b;
746 using C = A::F;
747 C f = A::B();
748 f = B();
749 B d;
750}
751)";
752 string expect = R"(
753int func(int a)
754{
755
756 A_S b;
757
758 A_F f = A_B();
759 f = B();
760 A_S d;
761}
762)";
763 string error;
765 EXPECT_EQ(output, expect);
766 EXPECT_EQ(error, "");
767 }
768 {
769 string input = R"(
770namespace A::B {
771void func() {}
772struct S {};
773}
774namespace A::B {
775using A::B::func;
776using S = A::B::S;
777void test() {
778 S s;
779 func();
780}
781}
782)";
783 string expect = R"(
784
785void A_B_func() {}
786struct A_B_S {int _pad;};
787#line 5
788
789
790
791
792void A_B_test() {
793 A_B_S s;
794 A_B_func();
795}
796
797)";
798 string error;
800 EXPECT_EQ(output, expect);
801 EXPECT_EQ(error, "");
802 }
803 {
804 string input = R"(
805using B = A::T;
806)";
807 string error;
809 EXPECT_EQ(error, "The `using` keyword is not allowed in global scope.");
810 }
811 {
812 string input = R"(
813namespace A {
814using namespace B;
815}
816)";
817 string error;
820 "Unsupported `using namespace`. "
821 "Add individual `using` directives for each needed symbol.");
822 }
823 {
824 string input = R"(
825namespace A {
826using B::func;
827}
828)";
829 string error;
832 "The `using` keyword is only allowed in namespace scope to make visible symbols "
833 "from the same namespace declared in another scope, potentially from another "
834 "file.");
835 }
836 {
837 string input = R"(
838namespace A {
839using C = B::func;
840}
841)";
842 string error;
845 "The `using` keyword is only allowed in namespace scope to make visible symbols "
846 "from the same namespace declared in another scope, potentially from another "
847 "file.");
848 }
849 {
850 /* Template on the same line as function signature inside a namespace.
851 * Template instantiation with other functions. */
852 string input = R"(
853namespace NS {
854template<typename T> T read(T a)
855{
856 return a;
857}
858template float read<float>(float);
859float write(float a){ return a; }
860}
861)";
862
863 string expect = R"(
864
865
866
867
868
869#line 3
870float NS_read(float a)
871{
872 return a;
873}
874#line 8
875float NS_write(float a){ return a; }
876
877)";
878 string error;
880 EXPECT_EQ(output, expect);
881 EXPECT_EQ(error, "");
882 }
883 {
884 /* Struct with member function inside namespace. */
885 string input = R"(
886namespace NS {
887struct S {
888 static S static_method(S s) {
889 return S(0);
890 }
891 S other_method(int s) {
892 return S(0);
893 }
894};
895} // End of namespace
896)";
897
898 string expect = R"(
899
900struct NS_S {
901
902
903
904
905
906
907int _pad;};
908#line 4
909 NS_S NS_S_static_method(NS_S s) {
910 return NS_S(0);
911 }
912#line 7
913 NS_S other_method(inout NS_S _inout_sta this_ _inout_end, int s) {
914 return NS_S(0);
915 }
916#line 11
917
918)";
919 string error;
921 EXPECT_EQ(output, expect);
922 EXPECT_EQ(error, "");
923 }
924}
925GPU_TEST(preprocess_namespace);
926
927static void test_preprocess_swizzle()
928{
929 using namespace shader;
930 using namespace std;
931
932 {
933 string input = R"(a.xyzw().aaa().xxx().grba().yzww; aaaa();)";
934 string expect = R"(a.xyzw .aaa .xxx .grba .yzww; aaaa();)";
935 string error;
937 EXPECT_EQ(output, expect);
938 EXPECT_EQ(error, "");
939 }
940}
941GPU_TEST(preprocess_swizzle);
942
943static void test_preprocess_enum()
944{
945 using namespace shader;
946 using namespace std;
947
948 {
949 string input = R"(
950enum class enum_class : int {
951 VALUE = 0,
952};
953)";
954 string expect = R"(
955
956
957
958#line 2
959#define enum_class int
960#line 3
961constant static constexpr int enum_class_VALUE = 0;
962#line 5
963)";
964 string error;
966 EXPECT_EQ(output, expect);
967 EXPECT_EQ(error, "");
968 }
969 {
970 string input = R"(
971enum class enum_class {
972 VALUE = 0,
973};
974)";
975 string error;
977 EXPECT_EQ(error, "enum declaration must explicitly use an underlying type");
978 }
979}
980GPU_TEST(preprocess_enum);
981
982#ifdef __APPLE__ /* This processing is only done for metal compatibility. */
983static void test_preprocess_matrix_constructors()
984{
985 using namespace shader;
986 using namespace std;
987
988 {
989 string input = R"(mat3(a); mat3 a; my_mat4x4(a); mat2x2(a); mat3x2(a);)";
990 string expect = R"(__mat3x3(a); mat3 a; my_mat4x4(a); __mat2x2(a); mat3x2(a);)";
991 string error;
992 string output = process_test_string(input, error, nullptr, Preprocessor::SourceLanguage::GLSL);
993 EXPECT_EQ(output, expect);
994 EXPECT_EQ(error, "");
995 }
996}
997GPU_TEST(preprocess_matrix_constructors);
998#endif
999
1001{
1002 using namespace shader;
1003 using namespace std;
1004
1005 {
1006 string input = R"(
1007[[gpu::vertex_function]] void my_func() {
1008 return;
1009}
1010)";
1011 string expect = R"(
1012 void my_func() {
1013#if defined(GPU_VERTEX_SHADER)
1014#line 3
1015 return;
1016#endif
1017#line 4
1018}
1019)";
1020 string error;
1022 EXPECT_EQ(output, expect);
1023 EXPECT_EQ(error, "");
1024 }
1025}
1026GPU_TEST(preprocess_stage_attribute);
1027
1029{
1030 using namespace shader;
1031 using namespace std;
1032
1033 {
1034 string input = R"(
1035void my_func() {
1036 interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1037}
1038)";
1039 string expect = R"(
1040void my_func() {
1041#if defined(CREATE_INFO_draw_resource_id_varying)
1042#line 3
1043 interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1044#endif
1045#line 4
1046}
1047)";
1048 string error;
1050 EXPECT_EQ(output, expect);
1051 EXPECT_EQ(error, "");
1052 }
1053 {
1054 string input = R"(
1055uint my_func() {
1056 uint i = 0;
1057 i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1058 return i;
1059}
1060)";
1061 string expect = R"(
1062uint my_func() {
1063#if defined(CREATE_INFO_draw_resource_id_varying)
1064#line 3
1065 uint i = 0;
1066 i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1067 return i;
1068#else
1069#line 3
1070 return uint(0);
1071#endif
1072#line 6
1073}
1074)";
1075 string error;
1077 EXPECT_EQ(output, expect);
1078 EXPECT_EQ(error, "");
1079 }
1080 {
1081 string input = R"(
1082uint my_func() {
1083 uint i = 0;
1084 {
1085 i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1086 }
1087 return i;
1088}
1089)";
1090 string expect = R"(
1091uint my_func() {
1092 uint i = 0;
1093 {
1094#if defined(CREATE_INFO_draw_resource_id_varying)
1095#line 5
1096 i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1097#endif
1098#line 6
1099 }
1100 return i;
1101}
1102)";
1103 string error;
1105 EXPECT_EQ(output, expect);
1106 EXPECT_EQ(error, "");
1107 }
1108 {
1109 string input = R"(
1110uint my_func() {
1111 uint i = 0;
1112 {
1113 i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1114 i += buffer_get(draw_resource_id, resource_id_buf)[0];
1115 }
1116 return i;
1117}
1118)";
1119 string expect = R"(
1120uint my_func() {
1121 uint i = 0;
1122 {
1123#if defined(CREATE_INFO_draw_resource_id_varying)
1124#line 5
1125#if defined(CREATE_INFO_draw_resource_id)
1126#line 5
1127 i += interface_get(draw_resource_id_varying, drw_ResourceID_iface).resource_index;
1128 i += buffer_get(draw_resource_id, resource_id_buf)[0];
1129#endif
1130#line 7
1131#endif
1132#line 7
1133 }
1134 return i;
1135}
1136)";
1137 string error;
1139 EXPECT_EQ(output, expect);
1140 EXPECT_EQ(error, "");
1141 }
1142 {
1143 /* Guard in template. */
1144 string input = R"(
1145template<> uint my_func<uint>(uint i) {
1146 return buffer_get(draw_resource_id, resource_id_buf)[i];
1147}
1148)";
1149 string expect = R"(
1150 uint my_funcTuint(uint i) {
1151#if defined(CREATE_INFO_draw_resource_id)
1152#line 3
1153 return buffer_get(draw_resource_id, resource_id_buf)[i];
1154#else
1155#line 3
1156 return uint(0);
1157#endif
1158#line 4
1159}
1160)";
1161 string error;
1163 EXPECT_EQ(output, expect);
1164 EXPECT_EQ(error, "");
1165 }
1166}
1167GPU_TEST(preprocess_resource_guard);
1168
1169static void test_preprocess_empty_struct()
1170{
1171 using namespace shader;
1172 using namespace std;
1173
1174 {
1175 string input = R"(
1176class S {};
1177struct T {};
1178struct U {
1179 static void fn() {}
1180};
1181)";
1182 string expect = R"(
1183struct S {int _pad;};
1184#line 3
1185struct T {int _pad;};
1186#line 4
1187struct U {
1188
1189int _pad;};
1190#line 5
1191 void U_fn() {}
1192#line 7
1193)";
1194 string error;
1196 EXPECT_EQ(output, expect);
1197 EXPECT_EQ(error, "");
1198 }
1199}
1200GPU_TEST(preprocess_empty_struct);
1201
1203{
1204 using namespace shader;
1205 using namespace std;
1206
1207 {
1208 string input = R"(
1209class S {
1210 private:
1211 int member;
1212 int this_member;
1213
1214 public:
1215 static S construct()
1216 {
1217 S a;
1218 a.member = 0;
1219 a.this_member = 0;
1220 return a;
1221 }
1222
1223 int another_member;
1224
1225 S function(int i)
1226 {
1227 this->member = i;
1228 this_member++;
1229 return *this;
1230 }
1231
1232 int size() const
1233 {
1234 return this->member;
1235 }
1236};
1237
1238void main()
1239{
1240 S s = S::construct();
1241 f.f();
1242 f(0).f();
1243 f().f();
1244 l.o.t();
1245 l.o(0).t();
1246 l.o().t();
1247 l[0].o();
1248 l.o[0].t();
1249 l.o().t[0];
1250}
1251)";
1252 string expect = R"(
1253struct S {
1254
1255 int member;
1256 int this_member;
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267 int another_member;
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280};
1281#line 8
1282 S S_construct()
1283 {
1284 S a;
1285 a.member = 0;
1286 a.this_member = 0;
1287 return a;
1288 }
1289#line 18
1290 S function(inout S _inout_sta this_ _inout_end, int i)
1291 {
1292 this_.member = i;
1293 this_member++;
1294 return this_;
1295 }
1296#line 25
1297 int size(const S this_)
1298 {
1299 return this_.member;
1300 }
1301#line 30
1302
1303void main()
1304{
1305 S s = S_construct();
1306 f(f);
1307 f(f(0));
1308 f(f());
1309 t(l.o);
1310 t(o(l, 0));
1311 t(o(l));
1312 o(l[0]);
1313 t(l.o[0]);
1314 o(l).t[0];
1315}
1316)";
1317 string error;
1319 EXPECT_EQ(output, expect);
1320 EXPECT_EQ(error, "");
1321 }
1322}
1323GPU_TEST(preprocess_struct_methods);
1324
1325static void test_preprocess_parser()
1326{
1327 using namespace std;
1328 using namespace shader::parser;
1329
1330 ParserData::report_callback no_err_report = [](int, int, string, const char *) {};
1331
1332 {
1333 string input = R"(
13341;
13351.0;
13362e10;
13372e10f;
13382.e10f;
13392.0e-1f;
13402.0e-1;
13412.0e-1f;
13420xFF;
13430xFFu;
1344)";
1345 string expect = R"(
13460;0;0;0;0;0;0;0;0;0;)";
1347 EXPECT_EQ(Parser(input, no_err_report).data_get().token_types, expect);
1348 }
1349 {
1350 string input = R"(
1351struct T {
1352 int t = 1;
1353};
1354class B {
1355 T t;
1356};
1357)";
1358 string expect = R"(
1359sw{ww=0;};Sw{ww;};)";
1360 EXPECT_EQ(Parser(input, no_err_report).data_get().token_types, expect);
1361 }
1362 {
1363 string input = R"(
1364namespace T {}
1365namespace T::U::V {}
1366)";
1367 string expect = R"(
1368nw{}nw::w::w{})";
1369 string expect_scopes = R"(GNN)";
1370 EXPECT_EQ(Parser(input, no_err_report).data_get().token_types, expect);
1371 EXPECT_EQ(Parser(input, no_err_report).data_get().scope_types, expect_scopes);
1372 }
1373 {
1374 string input = R"(
1375void f(int t = 0) {
1376 int i = 0, u = 2, v = {1.0f};
1377 {
1378 v = i = u, v++;
1379 if (v == i) {
1380 return;
1381 }
1382 }
1383}
1384)";
1385 string expect = R"(
1386ww(ww=0){ww=0,w=0,w={0};{w=w=w,wP;i(wEw){r;}}})";
1387 EXPECT_EQ(Parser(input, no_err_report).data_get().token_types, expect);
1388 }
1389 {
1390 Parser parser("float i;", no_err_report);
1391 parser.insert_after(Token::from_position(&parser.data_get(), 0), "A ");
1392 parser.insert_after(Token::from_position(&parser.data_get(), 0), "B ");
1393 EXPECT_EQ(parser.result_get(), "float A B i;");
1394 }
1395 {
1396 string input = R"(
1397A
1398#line 100
1399B
1400)";
1401 Parser parser(input, no_err_report);
1402 string expect = R"(
1403w#w0
1404w)";
1405 EXPECT_EQ(parser.data_get().token_types, expect);
1406
1407 Token A = Token::from_position(&parser.data_get(), 1);
1408 Token B = Token::from_position(&parser.data_get(), 6);
1409
1410 EXPECT_EQ(A.str(), "A");
1411 EXPECT_EQ(B.str(), "B");
1412 EXPECT_EQ(A.line_number(), 2);
1413 EXPECT_EQ(B.line_number(), 100);
1414 }
1415}
1416GPU_TEST(preprocess_parser);
1417
1418} // namespace blender::gpu::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#define A
std::string process(SourceLanguage language, std::string str, const std::string &filename, bool do_parse_function, bool do_small_type_linting, report_callback report_error, metadata::Source &r_metadata)
static std::string get_content_between_balanced_pair(const std::string &input, char start_delimiter, char end_delimiter, const bool backwards=false)
static void reference_search(std::string &str, std::function< void(int, int, char &)> callback)
static std::string replace_char_between_balanced_pair(const std::string &input, const char start_delimiter, const char end_delimiter, const char from, const char to)
static std::vector< std::string > split_string_not_between_balanced_pair(const std::string &str, const char delimiter, const char pair_start, const char pair_end)
static std::vector< std::string > split_string(const std::string &str, const char delimiter)
#define str(s)
#define input
#define output
#define GPU_TEST(test_name)
static int preprocess_include(char *maindata, const int maindata_len)
Definition makesdna.cc:566
#define B
static void error(const char *str)
PBVHData & data_get(blender::bke::pbvh::Tree &pbvh)
static void test_preprocess_namespace()
static void test_preprocess_reference()
static void test_preprocess_default_arguments()
static void test_preprocess_stage_attribute()
static std::string process_test_string(std::string str, std::string &first_error, shader::metadata::Source *r_metadata=nullptr, shader::Preprocessor::SourceLanguage language=shader::Preprocessor::SourceLanguage::BLENDER_GLSL)
static void test_preprocess_empty_struct()
static void test_preprocess_resource_guard()
static void test_preprocess_struct_methods()
static void test_preprocess_template_struct()
static void test_preprocess_utilities()
static void test_preprocess_include()