shader_preprocessor.cpp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. /*************************************************************************/
  2. /* shader_preprocessor.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "shader_preprocessor.h"
  31. #include "core/math/expression.h"
  32. const char32_t CURSOR = 0xFFFF;
  33. // Tokenizer
  34. void ShaderPreprocessor::Tokenizer::add_generated(const ShaderPreprocessor::Token &p_t) {
  35. generated.push_back(p_t);
  36. }
  37. char32_t ShaderPreprocessor::Tokenizer::next() {
  38. if (index < size) {
  39. return code[index++];
  40. }
  41. return 0;
  42. }
  43. int ShaderPreprocessor::Tokenizer::get_line() const {
  44. return line;
  45. }
  46. int ShaderPreprocessor::Tokenizer::get_index() const {
  47. return index;
  48. }
  49. void ShaderPreprocessor::Tokenizer::get_and_clear_generated(Vector<ShaderPreprocessor::Token> *r_out) {
  50. for (int i = 0; i < generated.size(); i++) {
  51. r_out->push_back(generated[i]);
  52. }
  53. generated.clear();
  54. }
  55. void ShaderPreprocessor::Tokenizer::backtrack(char32_t p_what) {
  56. while (index >= 0) {
  57. char32_t c = code[index];
  58. if (c == p_what) {
  59. break;
  60. }
  61. index--;
  62. }
  63. }
  64. char32_t ShaderPreprocessor::Tokenizer::peek() {
  65. if (index < size) {
  66. return code[index];
  67. }
  68. return 0;
  69. }
  70. LocalVector<ShaderPreprocessor::Token> ShaderPreprocessor::Tokenizer::advance(char32_t p_what) {
  71. LocalVector<ShaderPreprocessor::Token> tokens;
  72. while (index < size) {
  73. char32_t c = code[index++];
  74. tokens.push_back(ShaderPreprocessor::Token(c, line));
  75. if (c == '\n') {
  76. add_generated(ShaderPreprocessor::Token('\n', line));
  77. line++;
  78. }
  79. if (c == p_what || c == 0) {
  80. return tokens;
  81. }
  82. }
  83. return LocalVector<ShaderPreprocessor::Token>();
  84. }
  85. void ShaderPreprocessor::Tokenizer::skip_whitespace() {
  86. while (is_char_space(peek())) {
  87. next();
  88. }
  89. }
  90. String ShaderPreprocessor::Tokenizer::get_identifier(bool *r_is_cursor, bool p_started) {
  91. if (r_is_cursor != nullptr) {
  92. *r_is_cursor = false;
  93. }
  94. LocalVector<char32_t> text;
  95. while (true) {
  96. char32_t c = peek();
  97. if (is_char_end(c) || c == '(' || c == ')' || c == ',' || c == ';') {
  98. break;
  99. }
  100. if (is_whitespace(c) && p_started) {
  101. break;
  102. }
  103. if (!is_whitespace(c)) {
  104. p_started = true;
  105. }
  106. char32_t n = next();
  107. if (n == CURSOR) {
  108. if (r_is_cursor != nullptr) {
  109. *r_is_cursor = true;
  110. }
  111. } else {
  112. if (p_started) {
  113. text.push_back(n);
  114. }
  115. }
  116. }
  117. String id = vector_to_string(text);
  118. if (!id.is_valid_identifier()) {
  119. return "";
  120. }
  121. return id;
  122. }
  123. String ShaderPreprocessor::Tokenizer::peek_identifier() {
  124. const int original = index;
  125. String id = get_identifier();
  126. index = original;
  127. return id;
  128. }
  129. ShaderPreprocessor::Token ShaderPreprocessor::Tokenizer::get_token() {
  130. while (index < size) {
  131. const char32_t c = code[index++];
  132. const Token t = ShaderPreprocessor::Token(c, line);
  133. switch (c) {
  134. case ' ':
  135. case '\t':
  136. skip_whitespace();
  137. return ShaderPreprocessor::Token(' ', line);
  138. case '\n':
  139. line++;
  140. return t;
  141. default:
  142. return t;
  143. }
  144. }
  145. return ShaderPreprocessor::Token(char32_t(0), line);
  146. }
  147. ShaderPreprocessor::Tokenizer::Tokenizer(const String &p_code) {
  148. code = p_code;
  149. line = 0;
  150. index = 0;
  151. size = code.size();
  152. }
  153. // ShaderPreprocessor::CommentRemover
  154. String ShaderPreprocessor::CommentRemover::get_error() const {
  155. if (comments_open != 0) {
  156. return "Block comment mismatch";
  157. }
  158. return "";
  159. }
  160. int ShaderPreprocessor::CommentRemover::get_error_line() const {
  161. if (comments_open != 0) {
  162. return comment_line_open;
  163. }
  164. return -1;
  165. }
  166. char32_t ShaderPreprocessor::CommentRemover::peek() const {
  167. if (index < code.size()) {
  168. return code[index];
  169. }
  170. return 0;
  171. }
  172. bool ShaderPreprocessor::CommentRemover::advance(char32_t p_what) {
  173. while (index < code.size()) {
  174. char32_t c = code[index++];
  175. if (c == '\n') {
  176. line++;
  177. stripped.push_back('\n');
  178. }
  179. if (c == p_what) {
  180. return true;
  181. }
  182. }
  183. return false;
  184. }
  185. String ShaderPreprocessor::CommentRemover::strip() {
  186. stripped.clear();
  187. index = 0;
  188. line = 0;
  189. comment_line_open = 0;
  190. comments_open = 0;
  191. strings_open = 0;
  192. while (index < code.size()) {
  193. char32_t c = code[index++];
  194. if (c == CURSOR) {
  195. // Cursor. Maintain.
  196. stripped.push_back(c);
  197. } else if (c == '"') {
  198. if (strings_open <= 0) {
  199. strings_open++;
  200. } else {
  201. strings_open--;
  202. }
  203. stripped.push_back(c);
  204. } else if (c == '/' && strings_open == 0) {
  205. char32_t p = peek();
  206. if (p == '/') { // Single line comment.
  207. advance('\n');
  208. } else if (p == '*') { // Start of a block comment.
  209. index++;
  210. comment_line_open = line;
  211. comments_open++;
  212. while (advance('*')) {
  213. if (peek() == '/') { // End of a block comment.
  214. comments_open--;
  215. index++;
  216. break;
  217. }
  218. }
  219. } else {
  220. stripped.push_back(c);
  221. }
  222. } else if (c == '*' && strings_open == 0) {
  223. if (peek() == '/') { // Unmatched end of a block comment.
  224. comment_line_open = line;
  225. comments_open--;
  226. } else {
  227. stripped.push_back(c);
  228. }
  229. } else if (c == '\n') {
  230. line++;
  231. stripped.push_back(c);
  232. } else {
  233. stripped.push_back(c);
  234. }
  235. }
  236. return vector_to_string(stripped);
  237. }
  238. ShaderPreprocessor::CommentRemover::CommentRemover(const String &p_code) {
  239. code = p_code;
  240. index = 0;
  241. line = 0;
  242. comment_line_open = 0;
  243. comments_open = 0;
  244. strings_open = 0;
  245. }
  246. // ShaderPreprocessor::Token
  247. ShaderPreprocessor::Token::Token() {
  248. text = 0;
  249. line = -1;
  250. }
  251. ShaderPreprocessor::Token::Token(char32_t p_text, int p_line) {
  252. text = p_text;
  253. line = p_line;
  254. }
  255. // ShaderPreprocessor
  256. bool ShaderPreprocessor::is_char_word(char32_t p_char) {
  257. if ((p_char >= '0' && p_char <= '9') ||
  258. (p_char >= 'a' && p_char <= 'z') ||
  259. (p_char >= 'A' && p_char <= 'Z') ||
  260. p_char == '_') {
  261. return true;
  262. }
  263. return false;
  264. }
  265. bool ShaderPreprocessor::is_char_space(char32_t p_char) {
  266. return p_char == ' ' || p_char == '\t';
  267. }
  268. bool ShaderPreprocessor::is_char_end(char32_t p_char) {
  269. return p_char == '\n' || p_char == 0;
  270. }
  271. String ShaderPreprocessor::vector_to_string(const LocalVector<char32_t> &p_v, int p_start, int p_end) {
  272. const int stop = (p_end == -1) ? p_v.size() : p_end;
  273. const int count = stop - p_start;
  274. String result;
  275. result.resize(count + 1);
  276. for (int i = 0; i < count; i++) {
  277. result[i] = p_v[p_start + i];
  278. }
  279. result[count] = 0; // Ensure string is null terminated for length() to work.
  280. return result;
  281. }
  282. String ShaderPreprocessor::tokens_to_string(const LocalVector<Token> &p_tokens) {
  283. LocalVector<char32_t> result;
  284. for (uint32_t i = 0; i < p_tokens.size(); i++) {
  285. result.push_back(p_tokens[i].text);
  286. }
  287. return vector_to_string(result);
  288. }
  289. void ShaderPreprocessor::process_directive(Tokenizer *p_tokenizer) {
  290. bool is_cursor;
  291. String directive = p_tokenizer->get_identifier(&is_cursor, true);
  292. if (is_cursor) {
  293. state->completion_type = COMPLETION_TYPE_DIRECTIVE;
  294. }
  295. if (directive == "if") {
  296. process_if(p_tokenizer);
  297. } else if (directive == "ifdef") {
  298. process_ifdef(p_tokenizer);
  299. } else if (directive == "ifndef") {
  300. process_ifndef(p_tokenizer);
  301. } else if (directive == "else") {
  302. process_else(p_tokenizer);
  303. } else if (directive == "endif") {
  304. process_endif(p_tokenizer);
  305. } else if (directive == "define") {
  306. process_define(p_tokenizer);
  307. } else if (directive == "undef") {
  308. process_undef(p_tokenizer);
  309. } else if (directive == "include") {
  310. process_include(p_tokenizer);
  311. } else if (directive == "pragma") {
  312. process_pragma(p_tokenizer);
  313. } else {
  314. set_error(RTR("Unknown directive."), p_tokenizer->get_line());
  315. }
  316. }
  317. void ShaderPreprocessor::process_define(Tokenizer *p_tokenizer) {
  318. const int line = p_tokenizer->get_line();
  319. String label = p_tokenizer->get_identifier();
  320. if (label.is_empty()) {
  321. set_error(RTR("Invalid macro name."), line);
  322. return;
  323. }
  324. if (state->defines.has(label)) {
  325. set_error(RTR("Macro redefinition."), line);
  326. return;
  327. }
  328. if (p_tokenizer->peek() == '(') {
  329. // Macro has arguments.
  330. p_tokenizer->get_token();
  331. Vector<String> args;
  332. while (true) {
  333. String name = p_tokenizer->get_identifier();
  334. if (name.is_empty()) {
  335. set_error(RTR("Invalid argument name."), line);
  336. return;
  337. }
  338. args.push_back(name);
  339. p_tokenizer->skip_whitespace();
  340. char32_t next = p_tokenizer->get_token().text;
  341. if (next == ')') {
  342. break;
  343. } else if (next != ',') {
  344. set_error(RTR("Expected a comma in the macro argument list."), line);
  345. return;
  346. }
  347. }
  348. Define *define = memnew(Define);
  349. define->arguments = args;
  350. define->body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
  351. state->defines[label] = define;
  352. } else {
  353. // Simple substitution macro.
  354. Define *define = memnew(Define);
  355. define->body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
  356. state->defines[label] = define;
  357. }
  358. }
  359. void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
  360. const int line = p_tokenizer->get_line();
  361. if (state->skip_stack_else.is_empty()) {
  362. set_error(RTR("Unmatched else."), line);
  363. return;
  364. }
  365. if (state->previous_region != nullptr) {
  366. state->previous_region->to_line = line - 1;
  367. }
  368. p_tokenizer->advance('\n');
  369. bool skip = state->skip_stack_else[state->skip_stack_else.size() - 1];
  370. state->skip_stack_else.remove_at(state->skip_stack_else.size() - 1);
  371. Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_filename];
  372. int index = vec.size() - 1;
  373. if (index >= 0) {
  374. SkippedCondition *cond = vec[index];
  375. if (cond->end_line == -1) {
  376. cond->end_line = p_tokenizer->get_line();
  377. }
  378. }
  379. if (state->save_regions) {
  380. add_region(line + 1, !skip, state->previous_region->parent);
  381. }
  382. if (skip) {
  383. Vector<String> ends;
  384. ends.push_back("endif");
  385. next_directive(p_tokenizer, ends);
  386. }
  387. }
  388. void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
  389. state->condition_depth--;
  390. if (state->condition_depth < 0) {
  391. set_error(RTR("Unmatched endif."), p_tokenizer->get_line());
  392. return;
  393. }
  394. if (state->previous_region != nullptr) {
  395. state->previous_region->to_line = p_tokenizer->get_line() - 1;
  396. state->previous_region = state->previous_region->parent;
  397. }
  398. Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_filename];
  399. int index = vec.size() - 1;
  400. if (index >= 0) {
  401. SkippedCondition *cond = vec[index];
  402. if (cond->end_line == -1) {
  403. cond->end_line = p_tokenizer->get_line();
  404. }
  405. }
  406. p_tokenizer->advance('\n');
  407. }
  408. void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
  409. const int line = p_tokenizer->get_line();
  410. String body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
  411. if (body.is_empty()) {
  412. set_error(RTR("Missing condition."), line);
  413. return;
  414. }
  415. Error error = expand_macros(body, line, body);
  416. if (error != OK) {
  417. return;
  418. }
  419. Expression expression;
  420. Vector<String> names;
  421. error = expression.parse(body, names);
  422. if (error != OK) {
  423. set_error(expression.get_error_text(), line);
  424. return;
  425. }
  426. Variant v = expression.execute(Array(), nullptr, false);
  427. if (v.get_type() == Variant::NIL) {
  428. set_error(RTR("Condition evaluation error."), line);
  429. return;
  430. }
  431. bool success = v.booleanize();
  432. start_branch_condition(p_tokenizer, success);
  433. if (state->save_regions) {
  434. add_region(line + 1, success, state->previous_region);
  435. }
  436. }
  437. void ShaderPreprocessor::process_ifdef(Tokenizer *p_tokenizer) {
  438. const int line = p_tokenizer->get_line();
  439. String label = p_tokenizer->get_identifier();
  440. if (label.is_empty()) {
  441. set_error(RTR("Invalid macro name."), line);
  442. return;
  443. }
  444. p_tokenizer->skip_whitespace();
  445. if (!is_char_end(p_tokenizer->peek())) {
  446. set_error(RTR("Invalid ifdef."), line);
  447. return;
  448. }
  449. p_tokenizer->advance('\n');
  450. bool success = state->defines.has(label);
  451. start_branch_condition(p_tokenizer, success);
  452. if (state->save_regions) {
  453. add_region(line + 1, success, state->previous_region);
  454. }
  455. }
  456. void ShaderPreprocessor::process_ifndef(Tokenizer *p_tokenizer) {
  457. const int line = p_tokenizer->get_line();
  458. String label = p_tokenizer->get_identifier();
  459. if (label.is_empty()) {
  460. set_error(RTR("Invalid macro name."), line);
  461. return;
  462. }
  463. p_tokenizer->skip_whitespace();
  464. if (!is_char_end(p_tokenizer->peek())) {
  465. set_error(RTR("Invalid ifndef."), line);
  466. return;
  467. }
  468. p_tokenizer->advance('\n');
  469. bool success = !state->defines.has(label);
  470. start_branch_condition(p_tokenizer, success);
  471. if (state->save_regions) {
  472. add_region(line + 1, success, state->previous_region);
  473. }
  474. }
  475. void ShaderPreprocessor::process_include(Tokenizer *p_tokenizer) {
  476. const int line = p_tokenizer->get_line();
  477. p_tokenizer->advance('"');
  478. String path = tokens_to_string(p_tokenizer->advance('"'));
  479. for (int i = 0; i < path.length(); i++) {
  480. if (path[i] == '\n') {
  481. break; //stop parsing
  482. }
  483. if (path[i] == CURSOR) {
  484. state->completion_type = COMPLETION_TYPE_INCLUDE_PATH;
  485. break;
  486. }
  487. }
  488. path = path.substr(0, path.length() - 1);
  489. p_tokenizer->skip_whitespace();
  490. if (path.is_empty() || !is_char_end(p_tokenizer->peek())) {
  491. set_error(RTR("Invalid path."), line);
  492. return;
  493. }
  494. Ref<Resource> res = ResourceLoader::load(path);
  495. if (res.is_null()) {
  496. set_error(RTR("Shader include load failed. Does the shader include exist? Is there a cyclic dependency?"), line);
  497. return;
  498. }
  499. Ref<ShaderInclude> shader_inc = res;
  500. if (shader_inc.is_null()) {
  501. set_error(RTR("Shader include resource type is wrong."), line);
  502. return;
  503. }
  504. String included = shader_inc->get_code();
  505. if (!included.is_empty()) {
  506. uint64_t code_hash = included.hash64();
  507. if (state->cyclic_include_hashes.find(code_hash)) {
  508. set_error(RTR("Cyclic include found."), line);
  509. return;
  510. }
  511. }
  512. state->shader_includes.insert(shader_inc);
  513. const String real_path = shader_inc->get_path();
  514. if (state->includes.has(real_path)) {
  515. // Already included, skip.
  516. // This is a valid check because 2 separate include paths could use some
  517. // of the same shared functions from a common shader include.
  518. return;
  519. }
  520. // Mark as included.
  521. state->includes.insert(real_path);
  522. state->include_depth++;
  523. if (state->include_depth > 25) {
  524. set_error(RTR("Shader max include depth exceeded."), line);
  525. return;
  526. }
  527. String old_filename = state->current_filename;
  528. state->current_filename = real_path;
  529. ShaderPreprocessor processor;
  530. int prev_condition_depth = state->condition_depth;
  531. state->condition_depth = 0;
  532. FilePosition fp;
  533. fp.file = state->current_filename;
  534. fp.line = line;
  535. state->include_positions.push_back(fp);
  536. String result;
  537. processor.preprocess(state, included, result);
  538. add_to_output("@@>" + real_path + "\n"); // Add token for enter include path
  539. add_to_output(result);
  540. add_to_output("\n@@<\n"); // Add token for exit include path
  541. // Reset to last include if there are no errors. We want to use this as context.
  542. if (state->error.is_empty()) {
  543. state->current_filename = old_filename;
  544. state->include_positions.pop_back();
  545. } else {
  546. return;
  547. }
  548. state->include_depth--;
  549. state->condition_depth = prev_condition_depth;
  550. }
  551. void ShaderPreprocessor::process_pragma(Tokenizer *p_tokenizer) {
  552. const int line = p_tokenizer->get_line();
  553. bool is_cursor;
  554. const String label = p_tokenizer->get_identifier(&is_cursor);
  555. if (is_cursor) {
  556. state->completion_type = COMPLETION_TYPE_PRAGMA;
  557. }
  558. if (label.is_empty()) {
  559. set_error(RTR("Invalid pragma directive."), line);
  560. return;
  561. }
  562. // Rxplicitly handle pragma values here.
  563. // If more pragma options are created, then refactor into a more defined structure.
  564. if (label == "disable_preprocessor") {
  565. state->disabled = true;
  566. } else {
  567. set_error(RTR("Invalid pragma directive."), line);
  568. return;
  569. }
  570. p_tokenizer->advance('\n');
  571. }
  572. void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) {
  573. const int line = p_tokenizer->get_line();
  574. const String label = p_tokenizer->get_identifier();
  575. if (label.is_empty() || !state->defines.has(label)) {
  576. set_error(RTR("Invalid name."), line);
  577. return;
  578. }
  579. p_tokenizer->skip_whitespace();
  580. if (!is_char_end(p_tokenizer->peek())) {
  581. set_error(RTR("Invalid undef."), line);
  582. return;
  583. }
  584. memdelete(state->defines[label]);
  585. state->defines.erase(label);
  586. }
  587. void ShaderPreprocessor::add_region(int p_line, bool p_enabled, Region *p_parent_region) {
  588. Region region;
  589. region.file = state->current_filename;
  590. region.enabled = p_enabled;
  591. region.from_line = p_line;
  592. region.parent = p_parent_region;
  593. state->previous_region = &state->regions[region.file].push_back(region)->get();
  594. }
  595. void ShaderPreprocessor::start_branch_condition(Tokenizer *p_tokenizer, bool p_success) {
  596. state->condition_depth++;
  597. if (p_success) {
  598. state->skip_stack_else.push_back(true);
  599. } else {
  600. SkippedCondition *cond = memnew(SkippedCondition());
  601. cond->start_line = p_tokenizer->get_line();
  602. state->skipped_conditions[state->current_filename].push_back(cond);
  603. Vector<String> ends;
  604. ends.push_back("else");
  605. ends.push_back("endif");
  606. if (next_directive(p_tokenizer, ends) == "else") {
  607. state->skip_stack_else.push_back(false);
  608. } else {
  609. state->skip_stack_else.push_back(true);
  610. }
  611. }
  612. }
  613. void ShaderPreprocessor::expand_output_macros(int p_start, int p_line_number) {
  614. String line = vector_to_string(output, p_start, output.size());
  615. Error error = expand_macros(line, p_line_number - 1, line); // We are already on next line, so -1.
  616. if (error != OK) {
  617. return;
  618. }
  619. output.resize(p_start);
  620. add_to_output(line);
  621. }
  622. Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) {
  623. Vector<Pair<String, Define *>> active_defines;
  624. active_defines.resize(state->defines.size());
  625. int index = 0;
  626. for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) {
  627. active_defines.set(index++, Pair<String, Define *>(E->key(), E->get()));
  628. }
  629. return expand_macros(p_string, p_line, active_defines, r_expanded);
  630. }
  631. Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, Vector<Pair<String, Define *>> p_defines, String &r_expanded) {
  632. r_expanded = p_string;
  633. // When expanding macros we must only evaluate them once.
  634. // Later we continue expanding but with the already
  635. // evaluated macros removed.
  636. for (int i = 0; i < p_defines.size(); i++) {
  637. Pair<String, Define *> define_pair = p_defines[i];
  638. Error error = expand_macros_once(r_expanded, p_line, define_pair, r_expanded);
  639. if (error != OK) {
  640. return error;
  641. }
  642. // Remove expanded macro and recursively replace remaining.
  643. p_defines.remove_at(i);
  644. return expand_macros(r_expanded, p_line, p_defines, r_expanded);
  645. }
  646. return OK;
  647. }
  648. Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, Pair<String, Define *> p_define_pair, String &r_expanded) {
  649. String result = p_line;
  650. const String &key = p_define_pair.first;
  651. const Define *define = p_define_pair.second;
  652. int index_start = 0;
  653. int index = 0;
  654. while (find_match(result, key, index, index_start)) {
  655. String body = define->body;
  656. if (define->arguments.size() > 0) {
  657. // Complex macro with arguments.
  658. int args_start = index + key.length();
  659. int args_end = p_line.find(")", args_start);
  660. if (args_start == -1 || args_end == -1) {
  661. set_error(RTR("Missing macro argument parenthesis."), p_line_number);
  662. return FAILED;
  663. }
  664. String values = result.substr(args_start + 1, args_end - (args_start + 1));
  665. Vector<String> args = values.split(",");
  666. if (args.size() != define->arguments.size()) {
  667. set_error(RTR("Invalid macro argument count."), p_line_number);
  668. return FAILED;
  669. }
  670. // Insert macro arguments into the body.
  671. for (int i = 0; i < args.size(); i++) {
  672. String arg_name = define->arguments[i];
  673. int arg_index_start = 0;
  674. int arg_index = 0;
  675. while (find_match(body, arg_name, arg_index, arg_index_start)) {
  676. body = body.substr(0, arg_index) + args[i] + body.substr(arg_index + arg_name.length(), body.length() - (arg_index + arg_name.length()));
  677. // Manually reset arg_index_start to where the arg value of the define finishes.
  678. // This ensures we don't skip the other args of this macro in the string.
  679. arg_index_start = arg_index + args[i].length() + 1;
  680. }
  681. }
  682. result = result.substr(0, index) + " " + body + " " + result.substr(args_end + 1, result.length());
  683. } else {
  684. result = result.substr(0, index) + body + result.substr(index + key.length(), result.length() - (index + key.length()));
  685. // Manually reset index_start to where the body value of the define finishes.
  686. // This ensures we don't skip another instance of this macro in the string.
  687. index_start = index + body.length() + 1;
  688. break;
  689. }
  690. }
  691. r_expanded = result;
  692. return OK;
  693. }
  694. bool ShaderPreprocessor::find_match(const String &p_string, const String &p_value, int &r_index, int &r_index_start) {
  695. // Looks for value in string and then determines if the boundaries
  696. // are non-word characters. This method semi-emulates \b in regex.
  697. r_index = p_string.find(p_value, r_index_start);
  698. while (r_index > -1) {
  699. if (r_index > 0) {
  700. if (is_char_word(p_string[r_index - 1])) {
  701. r_index_start = r_index + 1;
  702. r_index = p_string.find(p_value, r_index_start);
  703. continue;
  704. }
  705. }
  706. if (r_index + p_value.length() < p_string.length()) {
  707. if (is_char_word(p_string[r_index + p_value.length()])) {
  708. r_index_start = r_index + p_value.length() + 1;
  709. r_index = p_string.find(p_value, r_index_start);
  710. continue;
  711. }
  712. }
  713. // Return and shift index start automatically for next call.
  714. r_index_start = r_index + p_value.length() + 1;
  715. return true;
  716. }
  717. return false;
  718. }
  719. String ShaderPreprocessor::next_directive(Tokenizer *p_tokenizer, const Vector<String> &p_directives) {
  720. const int line = p_tokenizer->get_line();
  721. int nesting = 0;
  722. while (true) {
  723. p_tokenizer->advance('#');
  724. String id = p_tokenizer->peek_identifier();
  725. if (id.is_empty()) {
  726. break;
  727. }
  728. if (nesting == 0) {
  729. for (int i = 0; i < p_directives.size(); i++) {
  730. if (p_directives[i] == id) {
  731. p_tokenizer->backtrack('#');
  732. return id;
  733. }
  734. }
  735. }
  736. if (id == "ifdef" || id == "ifndef" || id == "if") {
  737. nesting++;
  738. } else if (id == "endif") {
  739. nesting--;
  740. }
  741. }
  742. set_error(RTR("Can't find matching branch directive."), line);
  743. return "";
  744. }
  745. void ShaderPreprocessor::add_to_output(const String &p_str) {
  746. for (int i = 0; i < p_str.length(); i++) {
  747. output.push_back(p_str[i]);
  748. }
  749. }
  750. void ShaderPreprocessor::set_error(const String &p_error, int p_line) {
  751. if (state->error.is_empty()) {
  752. state->error = p_error;
  753. FilePosition fp;
  754. fp.line = p_line + 1;
  755. state->include_positions.push_back(fp);
  756. }
  757. }
  758. ShaderPreprocessor::Define *ShaderPreprocessor::create_define(const String &p_body) {
  759. ShaderPreprocessor::Define *define = memnew(Define);
  760. define->body = p_body;
  761. return define;
  762. }
  763. void ShaderPreprocessor::clear() {
  764. if (state_owner && state != nullptr) {
  765. for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) {
  766. memdelete(E->get());
  767. }
  768. for (const RBMap<String, Vector<SkippedCondition *>>::Element *E = state->skipped_conditions.front(); E; E = E->next()) {
  769. for (SkippedCondition *condition : E->get()) {
  770. memdelete(condition);
  771. }
  772. }
  773. memdelete(state);
  774. }
  775. state_owner = false;
  776. state = nullptr;
  777. }
  778. Error ShaderPreprocessor::preprocess(State *p_state, const String &p_code, String &r_result) {
  779. clear();
  780. output.clear();
  781. state = p_state;
  782. CommentRemover remover(p_code);
  783. String stripped = remover.strip();
  784. String error = remover.get_error();
  785. if (!error.is_empty()) {
  786. set_error(error, remover.get_error_line());
  787. return FAILED;
  788. }
  789. // Track code hashes to prevent cyclic include.
  790. uint64_t code_hash = p_code.hash64();
  791. state->cyclic_include_hashes.push_back(code_hash);
  792. Tokenizer p_tokenizer(stripped);
  793. int last_size = 0;
  794. bool has_symbols_before_directive = false;
  795. while (true) {
  796. const Token &t = p_tokenizer.get_token();
  797. if (t.text == 0) {
  798. break;
  799. }
  800. if (state->disabled) {
  801. // Preprocessor was disabled.
  802. // Read the rest of the file into the output.
  803. output.push_back(t.text);
  804. continue;
  805. } else {
  806. // Add autogenerated tokens.
  807. Vector<Token> generated;
  808. p_tokenizer.get_and_clear_generated(&generated);
  809. for (int i = 0; i < generated.size(); i++) {
  810. output.push_back(generated[i].text);
  811. }
  812. }
  813. if (t.text == '#') {
  814. if (has_symbols_before_directive) {
  815. set_error(RTR("Invalid symbols placed before directive."), p_tokenizer.get_line());
  816. state->cyclic_include_hashes.erase(code_hash); // Remove this hash.
  817. return FAILED;
  818. }
  819. process_directive(&p_tokenizer);
  820. } else {
  821. if (is_char_end(t.text)) {
  822. expand_output_macros(last_size, p_tokenizer.get_line());
  823. last_size = output.size();
  824. has_symbols_before_directive = false;
  825. } else if (!is_char_space(t.text)) {
  826. has_symbols_before_directive = true;
  827. }
  828. output.push_back(t.text);
  829. }
  830. if (!state->error.is_empty()) {
  831. state->cyclic_include_hashes.erase(code_hash); // Remove this hash.
  832. return FAILED;
  833. }
  834. }
  835. state->cyclic_include_hashes.erase(code_hash); // Remove this hash.
  836. if (!state->disabled) {
  837. if (state->condition_depth != 0) {
  838. set_error(RTR("Unmatched conditional statement."), p_tokenizer.line);
  839. return FAILED;
  840. }
  841. expand_output_macros(last_size, p_tokenizer.get_line());
  842. }
  843. r_result = vector_to_string(output);
  844. return OK;
  845. }
  846. Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filename, String &r_result, String *r_error_text, List<FilePosition> *r_error_position, List<Region> *r_regions, HashSet<Ref<ShaderInclude>> *r_includes, List<ScriptLanguage::CodeCompletionOption> *r_completion_options, IncludeCompletionFunction p_include_completion_func) {
  847. State pp_state;
  848. if (!p_filename.is_empty()) {
  849. pp_state.current_filename = p_filename;
  850. pp_state.save_regions = r_regions != nullptr;
  851. }
  852. Error err = preprocess(&pp_state, p_code, r_result);
  853. if (err != OK) {
  854. if (r_error_text) {
  855. *r_error_text = pp_state.error;
  856. }
  857. if (r_error_position) {
  858. *r_error_position = pp_state.include_positions;
  859. }
  860. }
  861. if (r_regions) {
  862. *r_regions = pp_state.regions[p_filename];
  863. }
  864. if (r_includes) {
  865. *r_includes = pp_state.shader_includes;
  866. }
  867. if (r_completion_options) {
  868. switch (pp_state.completion_type) {
  869. case COMPLETION_TYPE_DIRECTIVE: {
  870. List<String> options;
  871. get_keyword_list(&options, true);
  872. for (const String &E : options) {
  873. ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
  874. r_completion_options->push_back(option);
  875. }
  876. } break;
  877. case COMPLETION_TYPE_PRAGMA: {
  878. List<String> options;
  879. ShaderPreprocessor::get_pragma_list(&options);
  880. for (const String &E : options) {
  881. ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
  882. r_completion_options->push_back(option);
  883. }
  884. } break;
  885. case COMPLETION_TYPE_INCLUDE_PATH: {
  886. if (p_include_completion_func && r_completion_options) {
  887. p_include_completion_func(r_completion_options);
  888. }
  889. } break;
  890. default: {
  891. }
  892. }
  893. }
  894. return err;
  895. }
  896. void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords) {
  897. r_keywords->push_back("define");
  898. if (p_include_shader_keywords) {
  899. r_keywords->push_back("else");
  900. }
  901. r_keywords->push_back("endif");
  902. if (p_include_shader_keywords) {
  903. r_keywords->push_back("if");
  904. }
  905. r_keywords->push_back("ifdef");
  906. r_keywords->push_back("ifndef");
  907. r_keywords->push_back("include");
  908. r_keywords->push_back("pragma");
  909. r_keywords->push_back("undef");
  910. }
  911. void ShaderPreprocessor::get_pragma_list(List<String> *r_pragmas) {
  912. r_pragmas->push_back("disable_preprocessor");
  913. }
  914. ShaderPreprocessor::ShaderPreprocessor() {
  915. }
  916. ShaderPreprocessor::~ShaderPreprocessor() {
  917. clear();
  918. }