shader_preprocessor.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  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. if (state->skip_stack_else.is_empty()) {
  361. set_error(RTR("Unmatched else."), p_tokenizer->get_line());
  362. return;
  363. }
  364. p_tokenizer->advance('\n');
  365. bool skip = state->skip_stack_else[state->skip_stack_else.size() - 1];
  366. state->skip_stack_else.remove_at(state->skip_stack_else.size() - 1);
  367. Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_include];
  368. int index = vec.size() - 1;
  369. if (index >= 0) {
  370. SkippedCondition *cond = vec[index];
  371. if (cond->end_line == -1) {
  372. cond->end_line = p_tokenizer->get_line();
  373. }
  374. }
  375. if (skip) {
  376. Vector<String> ends;
  377. ends.push_back("endif");
  378. next_directive(p_tokenizer, ends);
  379. }
  380. }
  381. void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
  382. state->condition_depth--;
  383. if (state->condition_depth < 0) {
  384. set_error(RTR("Unmatched endif."), p_tokenizer->get_line());
  385. return;
  386. }
  387. Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_include];
  388. int index = vec.size() - 1;
  389. if (index >= 0) {
  390. SkippedCondition *cond = vec[index];
  391. if (cond->end_line == -1) {
  392. cond->end_line = p_tokenizer->get_line();
  393. }
  394. }
  395. p_tokenizer->advance('\n');
  396. }
  397. void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
  398. int line = p_tokenizer->get_line();
  399. String body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
  400. if (body.is_empty()) {
  401. set_error(RTR("Missing condition."), line);
  402. return;
  403. }
  404. Error error = expand_macros(body, line, body);
  405. if (error != OK) {
  406. return;
  407. }
  408. Expression expression;
  409. Vector<String> names;
  410. error = expression.parse(body, names);
  411. if (error != OK) {
  412. set_error(expression.get_error_text(), line);
  413. return;
  414. }
  415. Variant v = expression.execute(Array(), nullptr, false);
  416. if (v.get_type() == Variant::NIL) {
  417. set_error(RTR("Condition evaluation error."), line);
  418. return;
  419. }
  420. bool success = v.booleanize();
  421. start_branch_condition(p_tokenizer, success);
  422. }
  423. void ShaderPreprocessor::process_ifdef(Tokenizer *p_tokenizer) {
  424. const int line = p_tokenizer->get_line();
  425. String label = p_tokenizer->get_identifier();
  426. if (label.is_empty()) {
  427. set_error(RTR("Invalid macro name."), line);
  428. return;
  429. }
  430. p_tokenizer->skip_whitespace();
  431. if (!is_char_end(p_tokenizer->peek())) {
  432. set_error(RTR("Invalid ifdef."), line);
  433. return;
  434. }
  435. p_tokenizer->advance('\n');
  436. bool success = state->defines.has(label);
  437. start_branch_condition(p_tokenizer, success);
  438. }
  439. void ShaderPreprocessor::process_ifndef(Tokenizer *p_tokenizer) {
  440. const int line = p_tokenizer->get_line();
  441. String label = p_tokenizer->get_identifier();
  442. if (label.is_empty()) {
  443. set_error(RTR("Invalid macro name."), line);
  444. return;
  445. }
  446. p_tokenizer->skip_whitespace();
  447. if (!is_char_end(p_tokenizer->peek())) {
  448. set_error(RTR("Invalid ifndef."), line);
  449. return;
  450. }
  451. p_tokenizer->advance('\n');
  452. bool success = !state->defines.has(label);
  453. start_branch_condition(p_tokenizer, success);
  454. }
  455. void ShaderPreprocessor::process_include(Tokenizer *p_tokenizer) {
  456. const int line = p_tokenizer->get_line();
  457. p_tokenizer->advance('"');
  458. String path = tokens_to_string(p_tokenizer->advance('"'));
  459. for (int i = 0; i < path.length(); i++) {
  460. if (path[i] == '\n') {
  461. break; //stop parsing
  462. }
  463. if (path[i] == CURSOR) {
  464. state->completion_type = COMPLETION_TYPE_INCLUDE_PATH;
  465. break;
  466. }
  467. }
  468. path = path.substr(0, path.length() - 1);
  469. p_tokenizer->skip_whitespace();
  470. if (path.is_empty() || !is_char_end(p_tokenizer->peek())) {
  471. set_error(RTR("Invalid path."), line);
  472. return;
  473. }
  474. Ref<Resource> res = ResourceLoader::load(path);
  475. if (res.is_null()) {
  476. set_error(RTR("Shader include load failed. Does the shader include exist? Is there a cyclic dependency?"), line);
  477. return;
  478. }
  479. Ref<ShaderInclude> shader_inc = res;
  480. if (shader_inc.is_null()) {
  481. set_error(RTR("Shader include resource type is wrong."), line);
  482. return;
  483. }
  484. String included = shader_inc->get_code();
  485. if (!included.is_empty()) {
  486. uint64_t code_hash = included.hash64();
  487. if (state->cyclic_include_hashes.find(code_hash)) {
  488. set_error(RTR("Cyclic include found."), line);
  489. return;
  490. }
  491. }
  492. state->shader_includes.insert(shader_inc);
  493. const String real_path = shader_inc->get_path();
  494. if (state->includes.has(real_path)) {
  495. // Already included, skip.
  496. // This is a valid check because 2 separate include paths could use some
  497. // of the same shared functions from a common shader include.
  498. return;
  499. }
  500. // Mark as included.
  501. state->includes.insert(real_path);
  502. state->include_depth++;
  503. if (state->include_depth > 25) {
  504. set_error(RTR("Shader max include depth exceeded."), line);
  505. return;
  506. }
  507. String old_include = state->current_include;
  508. state->current_include = real_path;
  509. ShaderPreprocessor processor;
  510. int prev_condition_depth = state->condition_depth;
  511. state->condition_depth = 0;
  512. FilePosition fp;
  513. fp.file = state->current_include;
  514. fp.line = line;
  515. state->include_positions.push_back(fp);
  516. String result;
  517. processor.preprocess(state, included, result);
  518. add_to_output("@@>" + real_path + "\n"); // Add token for enter include path
  519. add_to_output(result);
  520. add_to_output("\n@@<\n"); // Add token for exit include path
  521. // Reset to last include if there are no errors. We want to use this as context.
  522. if (state->error.is_empty()) {
  523. state->current_include = old_include;
  524. state->include_positions.pop_back();
  525. } else {
  526. return;
  527. }
  528. state->include_depth--;
  529. state->condition_depth = prev_condition_depth;
  530. }
  531. void ShaderPreprocessor::process_pragma(Tokenizer *p_tokenizer) {
  532. const int line = p_tokenizer->get_line();
  533. bool is_cursor;
  534. const String label = p_tokenizer->get_identifier(&is_cursor);
  535. if (is_cursor) {
  536. state->completion_type = COMPLETION_TYPE_PRAGMA;
  537. }
  538. if (label.is_empty()) {
  539. set_error(RTR("Invalid pragma directive."), line);
  540. return;
  541. }
  542. // Rxplicitly handle pragma values here.
  543. // If more pragma options are created, then refactor into a more defined structure.
  544. if (label == "disable_preprocessor") {
  545. state->disabled = true;
  546. } else {
  547. set_error(RTR("Invalid pragma directive."), line);
  548. return;
  549. }
  550. p_tokenizer->advance('\n');
  551. }
  552. void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) {
  553. const int line = p_tokenizer->get_line();
  554. const String label = p_tokenizer->get_identifier();
  555. if (label.is_empty() || !state->defines.has(label)) {
  556. set_error(RTR("Invalid name."), line);
  557. return;
  558. }
  559. p_tokenizer->skip_whitespace();
  560. if (!is_char_end(p_tokenizer->peek())) {
  561. set_error(RTR("Invalid undef."), line);
  562. return;
  563. }
  564. memdelete(state->defines[label]);
  565. state->defines.erase(label);
  566. }
  567. void ShaderPreprocessor::start_branch_condition(Tokenizer *p_tokenizer, bool p_success) {
  568. state->condition_depth++;
  569. if (p_success) {
  570. state->skip_stack_else.push_back(true);
  571. } else {
  572. SkippedCondition *cond = memnew(SkippedCondition());
  573. cond->start_line = p_tokenizer->get_line();
  574. state->skipped_conditions[state->current_include].push_back(cond);
  575. Vector<String> ends;
  576. ends.push_back("else");
  577. ends.push_back("endif");
  578. if (next_directive(p_tokenizer, ends) == "else") {
  579. state->skip_stack_else.push_back(false);
  580. } else {
  581. state->skip_stack_else.push_back(true);
  582. }
  583. }
  584. }
  585. void ShaderPreprocessor::expand_output_macros(int p_start, int p_line_number) {
  586. String line = vector_to_string(output, p_start, output.size());
  587. Error error = expand_macros(line, p_line_number - 1, line); // We are already on next line, so -1.
  588. if (error != OK) {
  589. return;
  590. }
  591. output.resize(p_start);
  592. add_to_output(line);
  593. }
  594. Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) {
  595. Vector<Pair<String, Define *>> active_defines;
  596. active_defines.resize(state->defines.size());
  597. int index = 0;
  598. for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) {
  599. active_defines.set(index++, Pair<String, Define *>(E->key(), E->get()));
  600. }
  601. return expand_macros(p_string, p_line, active_defines, r_expanded);
  602. }
  603. Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, Vector<Pair<String, Define *>> p_defines, String &r_expanded) {
  604. r_expanded = p_string;
  605. // When expanding macros we must only evaluate them once.
  606. // Later we continue expanding but with the already
  607. // evaluated macros removed.
  608. for (int i = 0; i < p_defines.size(); i++) {
  609. Pair<String, Define *> define_pair = p_defines[i];
  610. Error error = expand_macros_once(r_expanded, p_line, define_pair, r_expanded);
  611. if (error != OK) {
  612. return error;
  613. }
  614. // Remove expanded macro and recursively replace remaining.
  615. p_defines.remove_at(i);
  616. return expand_macros(r_expanded, p_line, p_defines, r_expanded);
  617. }
  618. return OK;
  619. }
  620. Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, Pair<String, Define *> p_define_pair, String &r_expanded) {
  621. String result = p_line;
  622. const String &key = p_define_pair.first;
  623. const Define *define = p_define_pair.second;
  624. int index_start = 0;
  625. int index = 0;
  626. while (find_match(result, key, index, index_start)) {
  627. String body = define->body;
  628. if (define->arguments.size() > 0) {
  629. // Complex macro with arguments.
  630. int args_start = index + key.length();
  631. int args_end = p_line.find(")", args_start);
  632. if (args_start == -1 || args_end == -1) {
  633. set_error(RTR("Missing macro argument parenthesis."), p_line_number);
  634. return FAILED;
  635. }
  636. String values = result.substr(args_start + 1, args_end - (args_start + 1));
  637. Vector<String> args = values.split(",");
  638. if (args.size() != define->arguments.size()) {
  639. set_error(RTR("Invalid macro argument count."), p_line_number);
  640. return FAILED;
  641. }
  642. // Insert macro arguments into the body.
  643. for (int i = 0; i < args.size(); i++) {
  644. String arg_name = define->arguments[i];
  645. int arg_index_start = 0;
  646. int arg_index = 0;
  647. while (find_match(body, arg_name, arg_index, arg_index_start)) {
  648. body = body.substr(0, arg_index) + args[i] + body.substr(arg_index + arg_name.length(), body.length() - (arg_index + arg_name.length()));
  649. // Manually reset arg_index_start to where the arg value of the define finishes.
  650. // This ensures we don't skip the other args of this macro in the string.
  651. arg_index_start = arg_index + args[i].length() + 1;
  652. }
  653. }
  654. result = result.substr(0, index) + " " + body + " " + result.substr(args_end + 1, result.length());
  655. } else {
  656. result = result.substr(0, index) + body + result.substr(index + key.length(), result.length() - (index + key.length()));
  657. // Manually reset index_start to where the body value of the define finishes.
  658. // This ensures we don't skip another instance of this macro in the string.
  659. index_start = index + body.length() + 1;
  660. break;
  661. }
  662. }
  663. r_expanded = result;
  664. return OK;
  665. }
  666. bool ShaderPreprocessor::find_match(const String &p_string, const String &p_value, int &r_index, int &r_index_start) {
  667. // Looks for value in string and then determines if the boundaries
  668. // are non-word characters. This method semi-emulates \b in regex.
  669. r_index = p_string.find(p_value, r_index_start);
  670. while (r_index > -1) {
  671. if (r_index > 0) {
  672. if (is_char_word(p_string[r_index - 1])) {
  673. r_index_start = r_index + 1;
  674. r_index = p_string.find(p_value, r_index_start);
  675. continue;
  676. }
  677. }
  678. if (r_index + p_value.length() < p_string.length()) {
  679. if (is_char_word(p_string[r_index + p_value.length()])) {
  680. r_index_start = r_index + p_value.length() + 1;
  681. r_index = p_string.find(p_value, r_index_start);
  682. continue;
  683. }
  684. }
  685. // Return and shift index start automatically for next call.
  686. r_index_start = r_index + p_value.length() + 1;
  687. return true;
  688. }
  689. return false;
  690. }
  691. String ShaderPreprocessor::next_directive(Tokenizer *p_tokenizer, const Vector<String> &p_directives) {
  692. const int line = p_tokenizer->get_line();
  693. int nesting = 0;
  694. while (true) {
  695. p_tokenizer->advance('#');
  696. String id = p_tokenizer->peek_identifier();
  697. if (id.is_empty()) {
  698. break;
  699. }
  700. if (nesting == 0) {
  701. for (int i = 0; i < p_directives.size(); i++) {
  702. if (p_directives[i] == id) {
  703. p_tokenizer->backtrack('#');
  704. return id;
  705. }
  706. }
  707. }
  708. if (id == "ifdef" || id == "ifndef" || id == "if") {
  709. nesting++;
  710. } else if (id == "endif") {
  711. nesting--;
  712. }
  713. }
  714. set_error(RTR("Can't find matching branch directive."), line);
  715. return "";
  716. }
  717. void ShaderPreprocessor::add_to_output(const String &p_str) {
  718. for (int i = 0; i < p_str.length(); i++) {
  719. output.push_back(p_str[i]);
  720. }
  721. }
  722. void ShaderPreprocessor::set_error(const String &p_error, int p_line) {
  723. if (state->error.is_empty()) {
  724. state->error = p_error;
  725. FilePosition fp;
  726. fp.line = p_line + 1;
  727. state->include_positions.push_back(fp);
  728. }
  729. }
  730. ShaderPreprocessor::Define *ShaderPreprocessor::create_define(const String &p_body) {
  731. ShaderPreprocessor::Define *define = memnew(Define);
  732. define->body = p_body;
  733. return define;
  734. }
  735. void ShaderPreprocessor::clear() {
  736. if (state_owner && state != nullptr) {
  737. for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) {
  738. memdelete(E->get());
  739. }
  740. for (const RBMap<String, Vector<SkippedCondition *>>::Element *E = state->skipped_conditions.front(); E; E = E->next()) {
  741. for (SkippedCondition *condition : E->get()) {
  742. memdelete(condition);
  743. }
  744. }
  745. memdelete(state);
  746. }
  747. state_owner = false;
  748. state = nullptr;
  749. }
  750. Error ShaderPreprocessor::preprocess(State *p_state, const String &p_code, String &r_result) {
  751. clear();
  752. output.clear();
  753. state = p_state;
  754. CommentRemover remover(p_code);
  755. String stripped = remover.strip();
  756. String error = remover.get_error();
  757. if (!error.is_empty()) {
  758. set_error(error, remover.get_error_line());
  759. return FAILED;
  760. }
  761. // Track code hashes to prevent cyclic include.
  762. uint64_t code_hash = p_code.hash64();
  763. state->cyclic_include_hashes.push_back(code_hash);
  764. Tokenizer p_tokenizer(stripped);
  765. int last_size = 0;
  766. bool has_symbols_before_directive = false;
  767. while (true) {
  768. const Token &t = p_tokenizer.get_token();
  769. if (t.text == 0) {
  770. break;
  771. }
  772. if (state->disabled) {
  773. // Preprocessor was disabled.
  774. // Read the rest of the file into the output.
  775. output.push_back(t.text);
  776. continue;
  777. } else {
  778. // Add autogenerated tokens.
  779. Vector<Token> generated;
  780. p_tokenizer.get_and_clear_generated(&generated);
  781. for (int i = 0; i < generated.size(); i++) {
  782. output.push_back(generated[i].text);
  783. }
  784. }
  785. if (t.text == '#') {
  786. if (has_symbols_before_directive) {
  787. set_error(RTR("Invalid symbols placed before directive."), p_tokenizer.get_line());
  788. state->cyclic_include_hashes.erase(code_hash); // Remove this hash.
  789. return FAILED;
  790. }
  791. process_directive(&p_tokenizer);
  792. } else {
  793. if (is_char_end(t.text)) {
  794. expand_output_macros(last_size, p_tokenizer.get_line());
  795. last_size = output.size();
  796. has_symbols_before_directive = false;
  797. } else if (!is_char_space(t.text)) {
  798. has_symbols_before_directive = true;
  799. }
  800. output.push_back(t.text);
  801. }
  802. if (!state->error.is_empty()) {
  803. state->cyclic_include_hashes.erase(code_hash); // Remove this hash.
  804. return FAILED;
  805. }
  806. }
  807. state->cyclic_include_hashes.erase(code_hash); // Remove this hash.
  808. if (!state->disabled) {
  809. if (state->condition_depth != 0) {
  810. set_error(RTR("Unmatched conditional statement."), p_tokenizer.line);
  811. return FAILED;
  812. }
  813. expand_output_macros(last_size, p_tokenizer.get_line());
  814. }
  815. r_result = vector_to_string(output);
  816. return OK;
  817. }
  818. Error ShaderPreprocessor::preprocess(const String &p_code, String &r_result, String *r_error_text, List<FilePosition> *r_error_position, HashSet<Ref<ShaderInclude>> *r_includes, List<ScriptLanguage::CodeCompletionOption> *r_completion_options, IncludeCompletionFunction p_include_completion_func) {
  819. State pp_state;
  820. Error err = preprocess(&pp_state, p_code, r_result);
  821. if (err != OK) {
  822. if (r_error_text) {
  823. *r_error_text = pp_state.error;
  824. }
  825. if (r_error_position) {
  826. *r_error_position = pp_state.include_positions;
  827. }
  828. }
  829. if (r_includes) {
  830. *r_includes = pp_state.shader_includes;
  831. }
  832. if (r_completion_options) {
  833. switch (pp_state.completion_type) {
  834. case COMPLETION_TYPE_DIRECTIVE: {
  835. List<String> options;
  836. get_keyword_list(&options, true);
  837. for (const String &E : options) {
  838. ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
  839. r_completion_options->push_back(option);
  840. }
  841. } break;
  842. case COMPLETION_TYPE_PRAGMA: {
  843. List<String> options;
  844. ShaderPreprocessor::get_pragma_list(&options);
  845. for (const String &E : options) {
  846. ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
  847. r_completion_options->push_back(option);
  848. }
  849. } break;
  850. case COMPLETION_TYPE_INCLUDE_PATH: {
  851. if (p_include_completion_func && r_completion_options) {
  852. p_include_completion_func(r_completion_options);
  853. }
  854. } break;
  855. default: {
  856. }
  857. }
  858. }
  859. return err;
  860. }
  861. void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords) {
  862. r_keywords->push_back("define");
  863. if (p_include_shader_keywords) {
  864. r_keywords->push_back("else");
  865. }
  866. r_keywords->push_back("endif");
  867. if (p_include_shader_keywords) {
  868. r_keywords->push_back("if");
  869. }
  870. r_keywords->push_back("ifdef");
  871. r_keywords->push_back("ifndef");
  872. r_keywords->push_back("include");
  873. r_keywords->push_back("pragma");
  874. r_keywords->push_back("undef");
  875. }
  876. void ShaderPreprocessor::get_pragma_list(List<String> *r_pragmas) {
  877. r_pragmas->push_back("disable_preprocessor");
  878. }
  879. ShaderPreprocessor::ShaderPreprocessor() {
  880. }
  881. ShaderPreprocessor::~ShaderPreprocessor() {
  882. clear();
  883. }