script_class_parser.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. #include "script_class_parser.h"
  2. #include "core/map.h"
  3. #include "core/os/os.h"
  4. #include "../utils/string_utils.h"
  5. const char *ScriptClassParser::token_names[ScriptClassParser::TK_MAX] = {
  6. "[",
  7. "]",
  8. "{",
  9. "}",
  10. ".",
  11. ":",
  12. ",",
  13. "Symbol",
  14. "Identifier",
  15. "String",
  16. "Number",
  17. "<",
  18. ">",
  19. "EOF",
  20. "Error"
  21. };
  22. String ScriptClassParser::get_token_name(ScriptClassParser::Token p_token) {
  23. ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>");
  24. return token_names[p_token];
  25. }
  26. ScriptClassParser::Token ScriptClassParser::get_token() {
  27. while (true) {
  28. switch (code[idx]) {
  29. case '\n': {
  30. line++;
  31. idx++;
  32. break;
  33. };
  34. case 0: {
  35. return TK_EOF;
  36. } break;
  37. case '{': {
  38. idx++;
  39. return TK_CURLY_BRACKET_OPEN;
  40. };
  41. case '}': {
  42. idx++;
  43. return TK_CURLY_BRACKET_CLOSE;
  44. };
  45. case '[': {
  46. idx++;
  47. return TK_BRACKET_OPEN;
  48. };
  49. case ']': {
  50. idx++;
  51. return TK_BRACKET_CLOSE;
  52. };
  53. case '<': {
  54. idx++;
  55. return TK_OP_LESS;
  56. };
  57. case '>': {
  58. idx++;
  59. return TK_OP_GREATER;
  60. };
  61. case ':': {
  62. idx++;
  63. return TK_COLON;
  64. };
  65. case ',': {
  66. idx++;
  67. return TK_COMMA;
  68. };
  69. case '.': {
  70. idx++;
  71. return TK_PERIOD;
  72. };
  73. case '#': {
  74. //compiler directive
  75. while (code[idx] != '\n' && code[idx] != 0) {
  76. idx++;
  77. }
  78. continue;
  79. } break;
  80. case '/': {
  81. switch (code[idx + 1]) {
  82. case '*': { // block comment
  83. idx += 2;
  84. while (true) {
  85. if (code[idx] == 0) {
  86. error_str = "Unterminated comment";
  87. error = true;
  88. return TK_ERROR;
  89. } else if (code[idx] == '*' && code[idx + 1] == '/') {
  90. idx += 2;
  91. break;
  92. } else if (code[idx] == '\n') {
  93. line++;
  94. }
  95. idx++;
  96. }
  97. } break;
  98. case '/': { // line comment skip
  99. while (code[idx] != '\n' && code[idx] != 0) {
  100. idx++;
  101. }
  102. } break;
  103. default: {
  104. value = "/";
  105. idx++;
  106. return TK_SYMBOL;
  107. }
  108. }
  109. continue; // a comment
  110. } break;
  111. case '\'':
  112. case '"': {
  113. bool verbatim = idx != 0 && code[idx - 1] == '@';
  114. CharType begin_str = code[idx];
  115. idx++;
  116. String tk_string = String();
  117. while (true) {
  118. if (code[idx] == 0) {
  119. error_str = "Unterminated String";
  120. error = true;
  121. return TK_ERROR;
  122. } else if (code[idx] == begin_str) {
  123. if (verbatim && code[idx + 1] == '"') { // `""` is verbatim string's `\"`
  124. idx += 2; // skip next `"` as well
  125. continue;
  126. }
  127. idx += 1;
  128. break;
  129. } else if (code[idx] == '\\' && !verbatim) {
  130. //escaped characters...
  131. idx++;
  132. CharType next = code[idx];
  133. if (next == 0) {
  134. error_str = "Unterminated String";
  135. error = true;
  136. return TK_ERROR;
  137. }
  138. CharType res = 0;
  139. switch (next) {
  140. case 'b': res = 8; break;
  141. case 't': res = 9; break;
  142. case 'n': res = 10; break;
  143. case 'f': res = 12; break;
  144. case 'r':
  145. res = 13;
  146. break;
  147. case '\"': res = '\"'; break;
  148. case '\\':
  149. res = '\\';
  150. break;
  151. default: {
  152. res = next;
  153. } break;
  154. }
  155. tk_string += res;
  156. } else {
  157. if (code[idx] == '\n')
  158. line++;
  159. tk_string += code[idx];
  160. }
  161. idx++;
  162. }
  163. value = tk_string;
  164. return TK_STRING;
  165. } break;
  166. default: {
  167. if (code[idx] <= 32) {
  168. idx++;
  169. break;
  170. }
  171. if ((code[idx] >= 33 && code[idx] <= 47) || (code[idx] >= 58 && code[idx] <= 63) || (code[idx] >= 91 && code[idx] <= 94) || code[idx] == 96 || (code[idx] >= 123 && code[idx] <= 127)) {
  172. value = String::chr(code[idx]);
  173. idx++;
  174. return TK_SYMBOL;
  175. }
  176. if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) {
  177. //a number
  178. const CharType *rptr;
  179. double number = String::to_double(&code[idx], &rptr);
  180. idx += (rptr - &code[idx]);
  181. value = number;
  182. return TK_NUMBER;
  183. } else if ((code[idx] == '@' && code[idx + 1] != '"') || code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) {
  184. String id;
  185. id += code[idx];
  186. idx++;
  187. while (code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || (code[idx] >= '0' && code[idx] <= '9') || code[idx] > 127) {
  188. id += code[idx];
  189. idx++;
  190. }
  191. value = id;
  192. return TK_IDENTIFIER;
  193. } else if (code[idx] == '@' && code[idx + 1] == '"') {
  194. // begin of verbatim string
  195. idx++;
  196. } else {
  197. error_str = "Unexpected character.";
  198. error = true;
  199. return TK_ERROR;
  200. }
  201. }
  202. }
  203. }
  204. }
  205. Error ScriptClassParser::_skip_generic_type_params() {
  206. Token tk;
  207. while (true) {
  208. tk = get_token();
  209. if (tk == TK_IDENTIFIER) {
  210. tk = get_token();
  211. if (tk == TK_PERIOD) {
  212. while (true) {
  213. tk = get_token();
  214. if (tk != TK_IDENTIFIER) {
  215. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
  216. error = true;
  217. return ERR_PARSE_ERROR;
  218. }
  219. tk = get_token();
  220. if (tk != TK_PERIOD)
  221. break;
  222. }
  223. }
  224. if (tk == TK_OP_LESS) {
  225. Error err = _skip_generic_type_params();
  226. if (err)
  227. return err;
  228. continue;
  229. } else if (tk == TK_OP_GREATER) {
  230. return OK;
  231. } else if (tk != TK_COMMA) {
  232. error_str = "Unexpected token: " + get_token_name(tk);
  233. error = true;
  234. return ERR_PARSE_ERROR;
  235. }
  236. } else if (tk == TK_OP_LESS) {
  237. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found " + get_token_name(TK_OP_LESS);
  238. error = true;
  239. return ERR_PARSE_ERROR;
  240. } else if (tk == TK_OP_GREATER) {
  241. return OK;
  242. } else {
  243. error_str = "Unexpected token: " + get_token_name(tk);
  244. error = true;
  245. return ERR_PARSE_ERROR;
  246. }
  247. }
  248. }
  249. Error ScriptClassParser::_parse_type_full_name(String &r_full_name) {
  250. Token tk = get_token();
  251. if (tk != TK_IDENTIFIER) {
  252. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
  253. error = true;
  254. return ERR_PARSE_ERROR;
  255. }
  256. r_full_name += String(value);
  257. if (code[idx] != '.') // We only want to take the next token if it's a period
  258. return OK;
  259. tk = get_token();
  260. CRASH_COND(tk != TK_PERIOD); // Assertion
  261. r_full_name += ".";
  262. return _parse_type_full_name(r_full_name);
  263. }
  264. Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
  265. String name;
  266. Error err = _parse_type_full_name(name);
  267. if (err)
  268. return err;
  269. Token tk = get_token();
  270. bool generic = false;
  271. if (tk == TK_OP_LESS) {
  272. Error err = _skip_generic_type_params();
  273. if (err)
  274. return err;
  275. // We don't add it to the base list if it's generic
  276. generic = true;
  277. tk = get_token();
  278. }
  279. if (tk == TK_COMMA) {
  280. Error err = _parse_class_base(r_base);
  281. if (err)
  282. return err;
  283. } else if (tk == TK_IDENTIFIER && String(value) == "where") {
  284. Error err = _parse_type_constraints();
  285. if (err) {
  286. return err;
  287. }
  288. // An open curly bracket was parsed by _parse_type_constraints, so we can exit
  289. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  290. // we are finished when we hit the open curly bracket
  291. } else {
  292. error_str = "Unexpected token: " + get_token_name(tk);
  293. error = true;
  294. return ERR_PARSE_ERROR;
  295. }
  296. if (!generic) {
  297. r_base.push_back(name);
  298. }
  299. return OK;
  300. }
  301. Error ScriptClassParser::_parse_type_constraints() {
  302. Token tk = get_token();
  303. if (tk != TK_IDENTIFIER) {
  304. error_str = "Unexpected token: " + get_token_name(tk);
  305. error = true;
  306. return ERR_PARSE_ERROR;
  307. }
  308. tk = get_token();
  309. if (tk != TK_COLON) {
  310. error_str = "Unexpected token: " + get_token_name(tk);
  311. error = true;
  312. return ERR_PARSE_ERROR;
  313. }
  314. while (true) {
  315. tk = get_token();
  316. if (tk == TK_IDENTIFIER) {
  317. if (String(value) == "where") {
  318. return _parse_type_constraints();
  319. }
  320. tk = get_token();
  321. if (tk == TK_PERIOD) {
  322. while (true) {
  323. tk = get_token();
  324. if (tk != TK_IDENTIFIER) {
  325. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
  326. error = true;
  327. return ERR_PARSE_ERROR;
  328. }
  329. tk = get_token();
  330. if (tk != TK_PERIOD)
  331. break;
  332. }
  333. }
  334. }
  335. if (tk == TK_COMMA) {
  336. continue;
  337. } else if (tk == TK_IDENTIFIER && String(value) == "where") {
  338. return _parse_type_constraints();
  339. } else if (tk == TK_SYMBOL && String(value) == "(") {
  340. tk = get_token();
  341. if (tk != TK_SYMBOL || String(value) != ")") {
  342. error_str = "Unexpected token: " + get_token_name(tk);
  343. error = true;
  344. return ERR_PARSE_ERROR;
  345. }
  346. } else if (tk == TK_OP_LESS) {
  347. Error err = _skip_generic_type_params();
  348. if (err)
  349. return err;
  350. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  351. return OK;
  352. } else {
  353. error_str = "Unexpected token: " + get_token_name(tk);
  354. error = true;
  355. return ERR_PARSE_ERROR;
  356. }
  357. }
  358. }
  359. Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) {
  360. Token tk = get_token();
  361. if (tk == TK_IDENTIFIER) {
  362. r_name += String(value);
  363. } else {
  364. error_str = "Unexpected token: " + get_token_name(tk);
  365. error = true;
  366. return ERR_PARSE_ERROR;
  367. }
  368. tk = get_token();
  369. if (tk == TK_PERIOD) {
  370. r_name += ".";
  371. return _parse_namespace_name(r_name, r_curly_stack);
  372. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  373. r_curly_stack++;
  374. return OK;
  375. } else {
  376. error_str = "Unexpected token: " + get_token_name(tk);
  377. error = true;
  378. return ERR_PARSE_ERROR;
  379. }
  380. }
  381. Error ScriptClassParser::parse(const String &p_code) {
  382. code = p_code;
  383. idx = 0;
  384. line = 0;
  385. error_str = String();
  386. error = false;
  387. value = Variant();
  388. classes.clear();
  389. Token tk = get_token();
  390. Map<int, NameDecl> name_stack;
  391. int curly_stack = 0;
  392. int type_curly_stack = 0;
  393. while (!error && tk != TK_EOF) {
  394. if (tk == TK_IDENTIFIER && String(value) == "class") {
  395. tk = get_token();
  396. if (tk == TK_IDENTIFIER) {
  397. String name = value;
  398. int at_level = type_curly_stack;
  399. ClassDecl class_decl;
  400. for (Map<int, NameDecl>::Element *E = name_stack.front(); E; E = E->next()) {
  401. const NameDecl &name_decl = E->value();
  402. if (name_decl.type == NameDecl::NAMESPACE_DECL) {
  403. if (E != name_stack.front())
  404. class_decl.namespace_ += ".";
  405. class_decl.namespace_ += name_decl.name;
  406. } else {
  407. class_decl.name += name_decl.name + ".";
  408. }
  409. }
  410. class_decl.name += name;
  411. class_decl.nested = type_curly_stack > 0;
  412. bool generic = false;
  413. while (true) {
  414. tk = get_token();
  415. if (tk == TK_COLON) {
  416. Error err = _parse_class_base(class_decl.base);
  417. if (err)
  418. return err;
  419. curly_stack++;
  420. type_curly_stack++;
  421. break;
  422. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  423. curly_stack++;
  424. type_curly_stack++;
  425. break;
  426. } else if (tk == TK_OP_LESS && !generic) {
  427. generic = true;
  428. Error err = _skip_generic_type_params();
  429. if (err)
  430. return err;
  431. } else if (tk == TK_IDENTIFIER && String(value) == "where") {
  432. Error err = _parse_type_constraints();
  433. if (err) {
  434. return err;
  435. }
  436. // An open curly bracket was parsed by _parse_type_constraints, so we can exit
  437. curly_stack++;
  438. type_curly_stack++;
  439. break;
  440. } else {
  441. error_str = "Unexpected token: " + get_token_name(tk);
  442. error = true;
  443. return ERR_PARSE_ERROR;
  444. }
  445. }
  446. NameDecl name_decl;
  447. name_decl.name = name;
  448. name_decl.type = NameDecl::CLASS_DECL;
  449. name_stack[at_level] = name_decl;
  450. if (!generic) { // no generics, thanks
  451. classes.push_back(class_decl);
  452. } else if (OS::get_singleton()->is_stdout_verbose()) {
  453. String full_name = class_decl.namespace_;
  454. if (full_name.length())
  455. full_name += ".";
  456. full_name += class_decl.name;
  457. OS::get_singleton()->print(String("Ignoring generic class declaration: " + class_decl.name).utf8());
  458. }
  459. }
  460. } else if (tk == TK_IDENTIFIER && String(value) == "struct") {
  461. String name;
  462. int at_level = type_curly_stack;
  463. while (true) {
  464. tk = get_token();
  465. if (tk == TK_IDENTIFIER && name.empty()) {
  466. name = String(value);
  467. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  468. if (name.empty()) {
  469. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword `struct`, found " + get_token_name(TK_CURLY_BRACKET_OPEN);
  470. error = true;
  471. return ERR_PARSE_ERROR;
  472. }
  473. curly_stack++;
  474. type_curly_stack++;
  475. break;
  476. } else if (tk == TK_EOF) {
  477. error_str = "Expected " + get_token_name(TK_CURLY_BRACKET_OPEN) + " after struct decl, found " + get_token_name(TK_EOF);
  478. error = true;
  479. return ERR_PARSE_ERROR;
  480. }
  481. }
  482. NameDecl name_decl;
  483. name_decl.name = name;
  484. name_decl.type = NameDecl::STRUCT_DECL;
  485. name_stack[at_level] = name_decl;
  486. } else if (tk == TK_IDENTIFIER && String(value) == "namespace") {
  487. if (type_curly_stack > 0) {
  488. error_str = "Found namespace nested inside type.";
  489. error = true;
  490. return ERR_PARSE_ERROR;
  491. }
  492. String name;
  493. int at_level = curly_stack;
  494. Error err = _parse_namespace_name(name, curly_stack);
  495. if (err)
  496. return err;
  497. NameDecl name_decl;
  498. name_decl.name = name;
  499. name_decl.type = NameDecl::NAMESPACE_DECL;
  500. name_stack[at_level] = name_decl;
  501. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  502. curly_stack++;
  503. } else if (tk == TK_CURLY_BRACKET_CLOSE) {
  504. curly_stack--;
  505. if (name_stack.has(curly_stack)) {
  506. if (name_stack[curly_stack].type != NameDecl::NAMESPACE_DECL)
  507. type_curly_stack--;
  508. name_stack.erase(curly_stack);
  509. }
  510. }
  511. tk = get_token();
  512. }
  513. if (!error && tk == TK_EOF && curly_stack > 0) {
  514. error_str = "Reached EOF with missing close curly brackets.";
  515. error = true;
  516. }
  517. if (error)
  518. return ERR_PARSE_ERROR;
  519. return OK;
  520. }
  521. Error ScriptClassParser::parse_file(const String &p_filepath) {
  522. String source;
  523. Error ferr = read_all_file_utf8(p_filepath, source);
  524. if (ferr != OK) {
  525. if (ferr == ERR_INVALID_DATA) {
  526. ERR_EXPLAIN("File '" + p_filepath + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
  527. }
  528. ERR_FAIL_V(ferr);
  529. }
  530. return parse(source);
  531. }
  532. String ScriptClassParser::get_error() {
  533. return error_str;
  534. }
  535. Vector<ScriptClassParser::ClassDecl> ScriptClassParser::get_classes() {
  536. return classes;
  537. }