PageRenderTime 49ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/source/blender/editors/space_text/text_format_osl.c

https://repo.or.cz/blender.git
C | 376 lines | 287 code | 34 blank | 55 comment | 180 complexity | ad139b94ce45c059efc665434c18095a MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, MIT
  1. /*
  2. * This program is free software; you can redistribute it and/or
  3. * modify it under the terms of the GNU General Public License
  4. * as published by the Free Software Foundation; either version 2
  5. * of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * GNU General Public License for more details.
  10. *
  11. * You should have received a copy of the GNU General Public License
  12. * along with this program; if not, write to the Free Software Foundation,
  13. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. */
  15. /** \file
  16. * \ingroup sptext
  17. */
  18. #include <string.h>
  19. #include "BLI_blenlib.h"
  20. #include "DNA_space_types.h"
  21. #include "DNA_text_types.h"
  22. #include "BKE_text.h"
  23. #include "text_format.h"
  24. /* *** Local Functions (for format_line) *** */
  25. static int txtfmt_osl_find_builtinfunc(const char *string)
  26. {
  27. int i, len;
  28. /* Keep aligned args for readability. */
  29. /* clang-format off */
  30. /* list is from
  31. * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
  32. */
  33. if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
  34. } else if (STR_LITERAL_STARTSWITH(string, "closure", len)) { i = len;
  35. } else if (STR_LITERAL_STARTSWITH(string, "color", len)) { i = len;
  36. } else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
  37. } else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len;
  38. } else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len;
  39. } else if (STR_LITERAL_STARTSWITH(string, "emit", len)) { i = len;
  40. } else if (STR_LITERAL_STARTSWITH(string, "float", len)) { i = len;
  41. } else if (STR_LITERAL_STARTSWITH(string, "for", len)) { i = len;
  42. } else if (STR_LITERAL_STARTSWITH(string, "if", len)) { i = len;
  43. } else if (STR_LITERAL_STARTSWITH(string, "illuminance", len)) { i = len;
  44. } else if (STR_LITERAL_STARTSWITH(string, "illuminate", len)) { i = len;
  45. } else if (STR_LITERAL_STARTSWITH(string, "int", len)) { i = len;
  46. } else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) { i = len;
  47. } else if (STR_LITERAL_STARTSWITH(string, "normal", len)) { i = len;
  48. } else if (STR_LITERAL_STARTSWITH(string, "output", len)) { i = len;
  49. } else if (STR_LITERAL_STARTSWITH(string, "point", len)) { i = len;
  50. } else if (STR_LITERAL_STARTSWITH(string, "public", len)) { i = len;
  51. } else if (STR_LITERAL_STARTSWITH(string, "return", len)) { i = len;
  52. } else if (STR_LITERAL_STARTSWITH(string, "string", len)) { i = len;
  53. } else if (STR_LITERAL_STARTSWITH(string, "struct", len)) { i = len;
  54. } else if (STR_LITERAL_STARTSWITH(string, "vector", len)) { i = len;
  55. } else if (STR_LITERAL_STARTSWITH(string, "void", len)) { i = len;
  56. } else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
  57. } else { i = 0;
  58. }
  59. /* clang-format on */
  60. /* If next source char is an identifier (eg. 'i' in "definite") no match */
  61. if (i == 0 || text_check_identifier(string[i])) {
  62. return -1;
  63. }
  64. return i;
  65. }
  66. static int txtfmt_osl_find_reserved(const char *string)
  67. {
  68. int i, len;
  69. /* Keep aligned args for readability. */
  70. /* clang-format off */
  71. /* list is from...
  72. * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
  73. */
  74. if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len;
  75. } else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
  76. } else if (STR_LITERAL_STARTSWITH(string, "catch", len)) { i = len;
  77. } else if (STR_LITERAL_STARTSWITH(string, "char", len)) { i = len;
  78. } else if (STR_LITERAL_STARTSWITH(string, "const", len)) { i = len;
  79. } else if (STR_LITERAL_STARTSWITH(string, "delete", len)) { i = len;
  80. } else if (STR_LITERAL_STARTSWITH(string, "default", len)) { i = len;
  81. } else if (STR_LITERAL_STARTSWITH(string, "double", len)) { i = len;
  82. } else if (STR_LITERAL_STARTSWITH(string, "enum", len)) { i = len;
  83. } else if (STR_LITERAL_STARTSWITH(string, "extern", len)) { i = len;
  84. } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
  85. } else if (STR_LITERAL_STARTSWITH(string, "friend", len)) { i = len;
  86. } else if (STR_LITERAL_STARTSWITH(string, "goto", len)) { i = len;
  87. } else if (STR_LITERAL_STARTSWITH(string, "inline", len)) { i = len;
  88. } else if (STR_LITERAL_STARTSWITH(string, "long", len)) { i = len;
  89. } else if (STR_LITERAL_STARTSWITH(string, "new", len)) { i = len;
  90. } else if (STR_LITERAL_STARTSWITH(string, "operator", len)) { i = len;
  91. } else if (STR_LITERAL_STARTSWITH(string, "private", len)) { i = len;
  92. } else if (STR_LITERAL_STARTSWITH(string, "protected", len)) { i = len;
  93. } else if (STR_LITERAL_STARTSWITH(string, "short", len)) { i = len;
  94. } else if (STR_LITERAL_STARTSWITH(string, "signed", len)) { i = len;
  95. } else if (STR_LITERAL_STARTSWITH(string, "sizeof", len)) { i = len;
  96. } else if (STR_LITERAL_STARTSWITH(string, "static", len)) { i = len;
  97. } else if (STR_LITERAL_STARTSWITH(string, "switch", len)) { i = len;
  98. } else if (STR_LITERAL_STARTSWITH(string, "template", len)) { i = len;
  99. } else if (STR_LITERAL_STARTSWITH(string, "this", len)) { i = len;
  100. } else if (STR_LITERAL_STARTSWITH(string, "throw", len)) { i = len;
  101. } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
  102. } else if (STR_LITERAL_STARTSWITH(string, "try", len)) { i = len;
  103. } else if (STR_LITERAL_STARTSWITH(string, "typedef", len)) { i = len;
  104. } else if (STR_LITERAL_STARTSWITH(string, "uniform", len)) { i = len;
  105. } else if (STR_LITERAL_STARTSWITH(string, "union", len)) { i = len;
  106. } else if (STR_LITERAL_STARTSWITH(string, "unsigned", len)) { i = len;
  107. } else if (STR_LITERAL_STARTSWITH(string, "varying", len)) { i = len;
  108. } else if (STR_LITERAL_STARTSWITH(string, "virtual", len)) { i = len;
  109. } else if (STR_LITERAL_STARTSWITH(string, "volatile", len)) { i = len;
  110. } else { i = 0;
  111. }
  112. /* clang-format on */
  113. /* If next source char is an identifier (eg. 'i' in "definite") no match */
  114. if (i == 0 || text_check_identifier(string[i])) {
  115. return -1;
  116. }
  117. return i;
  118. }
  119. /* Checks the specified source string for a OSL special name. This name must
  120. * start at the beginning of the source string and must be followed by a non-
  121. * identifier (see text_check_identifier(char)) or null character.
  122. *
  123. * If a special name is found, the length of the matching name is returned.
  124. * Otherwise, -1 is returned. */
  125. static int txtfmt_osl_find_specialvar(const char *string)
  126. {
  127. int i, len;
  128. /* Keep aligned args for readability. */
  129. /* clang-format off */
  130. /* OSL shader types */
  131. if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len;
  132. } else if (STR_LITERAL_STARTSWITH(string, "surface", len)) { i = len;
  133. } else if (STR_LITERAL_STARTSWITH(string, "volume", len)) { i = len;
  134. } else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) { i = len;
  135. } else { i = 0;
  136. }
  137. /* clang-format on */
  138. /* If next source char is an identifier (eg. 'i' in "definite") no match */
  139. if (i == 0 || text_check_identifier(string[i])) {
  140. return -1;
  141. }
  142. return i;
  143. }
  144. /* matches py 'txtfmt_osl_find_decorator' */
  145. static int txtfmt_osl_find_preprocessor(const char *string)
  146. {
  147. if (string[0] == '#') {
  148. int i = 1;
  149. /* Whitespace is ok '# foo' */
  150. while (text_check_whitespace(string[i])) {
  151. i++;
  152. }
  153. while (text_check_identifier(string[i])) {
  154. i++;
  155. }
  156. return i;
  157. }
  158. return -1;
  159. }
  160. static char txtfmt_osl_format_identifier(const char *str)
  161. {
  162. char fmt;
  163. /* Keep aligned args for readability. */
  164. /* clang-format off */
  165. if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
  166. } else if ((txtfmt_osl_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
  167. } else if ((txtfmt_osl_find_reserved(str)) != -1) { fmt = FMT_TYPE_RESERVED;
  168. } else if ((txtfmt_osl_find_preprocessor(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE;
  169. } else { fmt = FMT_TYPE_DEFAULT;
  170. }
  171. /* clang-format on */
  172. return fmt;
  173. }
  174. static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_next)
  175. {
  176. FlattenString fs;
  177. const char *str;
  178. char *fmt;
  179. char cont_orig, cont, find, prev = ' ';
  180. int len, i;
  181. /* Get continuation from previous line */
  182. if (line->prev && line->prev->format != NULL) {
  183. fmt = line->prev->format;
  184. cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
  185. BLI_assert((FMT_CONT_ALL & cont) == cont);
  186. }
  187. else {
  188. cont = FMT_CONT_NOP;
  189. }
  190. /* Get original continuation from this line */
  191. if (line->format != NULL) {
  192. fmt = line->format;
  193. cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
  194. BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
  195. }
  196. else {
  197. cont_orig = 0xFF;
  198. }
  199. len = flatten_string(st, &fs, line->line);
  200. str = fs.buf;
  201. if (!text_check_format_len(line, len)) {
  202. flatten_string_free(&fs);
  203. return;
  204. }
  205. fmt = line->format;
  206. while (*str) {
  207. /* Handle escape sequences by skipping both \ and next char */
  208. if (*str == '\\') {
  209. *fmt = prev;
  210. fmt++;
  211. str++;
  212. if (*str == '\0') {
  213. break;
  214. }
  215. *fmt = prev;
  216. fmt++;
  217. str += BLI_str_utf8_size_safe(str);
  218. continue;
  219. }
  220. /* Handle continuations */
  221. else if (cont) {
  222. /* C-Style comments */
  223. if (cont & FMT_CONT_COMMENT_C) {
  224. if (*str == '*' && *(str + 1) == '/') {
  225. *fmt = FMT_TYPE_COMMENT;
  226. fmt++;
  227. str++;
  228. *fmt = FMT_TYPE_COMMENT;
  229. cont = FMT_CONT_NOP;
  230. }
  231. else {
  232. *fmt = FMT_TYPE_COMMENT;
  233. }
  234. /* Handle other comments */
  235. }
  236. else {
  237. find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
  238. if (*str == find) {
  239. cont = 0;
  240. }
  241. *fmt = FMT_TYPE_STRING;
  242. }
  243. str += BLI_str_utf8_size_safe(str) - 1;
  244. }
  245. /* Not in a string... */
  246. else {
  247. /* Deal with comments first */
  248. if (*str == '/' && *(str + 1) == '/') {
  249. /* fill the remaining line */
  250. text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
  251. }
  252. /* C-Style (multi-line) comments */
  253. else if (*str == '/' && *(str + 1) == '*') {
  254. cont = FMT_CONT_COMMENT_C;
  255. *fmt = FMT_TYPE_COMMENT;
  256. fmt++;
  257. str++;
  258. *fmt = FMT_TYPE_COMMENT;
  259. }
  260. else if (*str == '"' || *str == '\'') {
  261. /* Strings */
  262. find = *str;
  263. cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
  264. *fmt = FMT_TYPE_STRING;
  265. }
  266. /* Whitespace (all ws. has been converted to spaces) */
  267. else if (*str == ' ') {
  268. *fmt = FMT_TYPE_WHITESPACE;
  269. }
  270. /* Numbers (digits not part of an identifier and periods followed by digits) */
  271. else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
  272. (*str == '.' && text_check_digit(*(str + 1)))) {
  273. *fmt = FMT_TYPE_NUMERAL;
  274. }
  275. /* Punctuation */
  276. else if ((*str != '#') && text_check_delim(*str)) {
  277. *fmt = FMT_TYPE_SYMBOL;
  278. }
  279. /* Identifiers and other text (no previous ws. or delims. so text continues) */
  280. else if (prev == FMT_TYPE_DEFAULT) {
  281. str += BLI_str_utf8_size_safe(str) - 1;
  282. *fmt = FMT_TYPE_DEFAULT;
  283. }
  284. /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
  285. else {
  286. /* Keep aligned args for readability. */
  287. /* clang-format off */
  288. /* Special vars(v) or built-in keywords(b) */
  289. /* keep in sync with 'txtfmt_osl_format_identifier()' */
  290. if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
  291. } else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
  292. } else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
  293. } else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
  294. }
  295. /* clang-format on */
  296. if (i > 0) {
  297. if (prev == FMT_TYPE_DIRECTIVE) { /* can contain utf8 */
  298. text_format_fill(&str, &fmt, prev, i);
  299. }
  300. else {
  301. text_format_fill_ascii(&str, &fmt, prev, i);
  302. }
  303. }
  304. else {
  305. str += BLI_str_utf8_size_safe(str) - 1;
  306. *fmt = FMT_TYPE_DEFAULT;
  307. }
  308. }
  309. }
  310. prev = *fmt;
  311. fmt++;
  312. str++;
  313. }
  314. /* Terminate and add continuation char */
  315. *fmt = '\0';
  316. fmt++;
  317. *fmt = cont;
  318. /* If continuation has changed and we're allowed, process the next line */
  319. if (cont != cont_orig && do_next && line->next) {
  320. txtfmt_osl_format_line(st, line->next, do_next);
  321. }
  322. flatten_string_free(&fs);
  323. }
  324. void ED_text_format_register_osl(void)
  325. {
  326. static TextFormatType tft = {NULL};
  327. static const char *ext[] = {"osl", NULL};
  328. tft.format_identifier = txtfmt_osl_format_identifier;
  329. tft.format_line = txtfmt_osl_format_line;
  330. tft.ext = ext;
  331. ED_text_format_register(&tft);
  332. }