script_class_parser.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  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_COMMA) {
  230. error_str = "Unexpected token: " + get_token_name(tk);
  231. error = true;
  232. return ERR_PARSE_ERROR;
  233. }
  234. } else if (tk == TK_OP_LESS) {
  235. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found " + get_token_name(TK_OP_LESS);
  236. error = true;
  237. return ERR_PARSE_ERROR;
  238. } else if (tk == TK_OP_GREATER) {
  239. return OK;
  240. } else {
  241. error_str = "Unexpected token: " + get_token_name(tk);
  242. error = true;
  243. return ERR_PARSE_ERROR;
  244. }
  245. }
  246. }
  247. Error ScriptClassParser::_parse_type_full_name(String &r_full_name) {
  248. Token tk = get_token();
  249. if (tk != TK_IDENTIFIER) {
  250. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk);
  251. error = true;
  252. return ERR_PARSE_ERROR;
  253. }
  254. r_full_name += String(value);
  255. if (code[idx] != '.') // We only want to take the next token if it's a period
  256. return OK;
  257. tk = get_token();
  258. CRASH_COND(tk != TK_PERIOD); // Assertion
  259. r_full_name += ".";
  260. return _parse_type_full_name(r_full_name);
  261. }
  262. Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
  263. String name;
  264. Error err = _parse_type_full_name(name);
  265. if (err)
  266. return err;
  267. Token tk = get_token();
  268. if (tk == TK_OP_LESS) {
  269. // We don't add it to the base list if it's generic
  270. Error err = _skip_generic_type_params();
  271. if (err)
  272. return err;
  273. } else if (tk == TK_COMMA) {
  274. Error err = _parse_class_base(r_base);
  275. if (err)
  276. return err;
  277. r_base.push_back(name);
  278. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  279. r_base.push_back(name);
  280. } else {
  281. error_str = "Unexpected token: " + get_token_name(tk);
  282. error = true;
  283. return ERR_PARSE_ERROR;
  284. }
  285. return OK;
  286. }
  287. Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) {
  288. Token tk = get_token();
  289. if (tk == TK_IDENTIFIER) {
  290. r_name += String(value);
  291. } else {
  292. error_str = "Unexpected token: " + get_token_name(tk);
  293. error = true;
  294. return ERR_PARSE_ERROR;
  295. }
  296. tk = get_token();
  297. if (tk == TK_PERIOD) {
  298. r_name += ".";
  299. return _parse_namespace_name(r_name, r_curly_stack);
  300. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  301. r_curly_stack++;
  302. return OK;
  303. } else {
  304. error_str = "Unexpected token: " + get_token_name(tk);
  305. error = true;
  306. return ERR_PARSE_ERROR;
  307. }
  308. }
  309. Error ScriptClassParser::parse(const String &p_code) {
  310. code = p_code;
  311. idx = 0;
  312. line = 0;
  313. error_str = String();
  314. error = false;
  315. value = Variant();
  316. classes.clear();
  317. Token tk = get_token();
  318. Map<int, NameDecl> name_stack;
  319. int curly_stack = 0;
  320. int type_curly_stack = 0;
  321. while (!error && tk != TK_EOF) {
  322. if (tk == TK_IDENTIFIER && String(value) == "class") {
  323. tk = get_token();
  324. if (tk == TK_IDENTIFIER) {
  325. String name = value;
  326. int at_level = type_curly_stack;
  327. ClassDecl class_decl;
  328. for (Map<int, NameDecl>::Element *E = name_stack.front(); E; E = E->next()) {
  329. const NameDecl &name_decl = E->value();
  330. if (name_decl.type == NameDecl::NAMESPACE_DECL) {
  331. if (E != name_stack.front())
  332. class_decl.namespace_ += ".";
  333. class_decl.namespace_ += name_decl.name;
  334. } else {
  335. class_decl.name += name_decl.name + ".";
  336. }
  337. }
  338. class_decl.name += name;
  339. class_decl.nested = type_curly_stack > 0;
  340. bool generic = false;
  341. while (true) {
  342. tk = get_token();
  343. if (tk == TK_COLON) {
  344. Error err = _parse_class_base(class_decl.base);
  345. if (err)
  346. return err;
  347. curly_stack++;
  348. type_curly_stack++;
  349. break;
  350. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  351. curly_stack++;
  352. type_curly_stack++;
  353. break;
  354. } else if (tk == TK_OP_LESS && !generic) {
  355. generic = true;
  356. Error err = _skip_generic_type_params();
  357. if (err)
  358. return err;
  359. } else {
  360. error_str = "Unexpected token: " + get_token_name(tk);
  361. error = true;
  362. return ERR_PARSE_ERROR;
  363. }
  364. }
  365. NameDecl name_decl;
  366. name_decl.name = name;
  367. name_decl.type = NameDecl::CLASS_DECL;
  368. name_stack[at_level] = name_decl;
  369. if (!generic) { // no generics, thanks
  370. classes.push_back(class_decl);
  371. } else if (OS::get_singleton()->is_stdout_verbose()) {
  372. String full_name = class_decl.namespace_;
  373. if (full_name.length())
  374. full_name += ".";
  375. full_name += class_decl.name;
  376. OS::get_singleton()->print(String("Ignoring generic class declaration: " + class_decl.name).utf8());
  377. }
  378. }
  379. } else if (tk == TK_IDENTIFIER && String(value) == "struct") {
  380. String name;
  381. int at_level = type_curly_stack;
  382. while (true) {
  383. tk = get_token();
  384. if (tk == TK_IDENTIFIER && name.empty()) {
  385. name = String(value);
  386. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  387. if (name.empty()) {
  388. error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword `struct`, found " + get_token_name(TK_CURLY_BRACKET_OPEN);
  389. error = true;
  390. return ERR_PARSE_ERROR;
  391. }
  392. curly_stack++;
  393. type_curly_stack++;
  394. break;
  395. } else if (tk == TK_EOF) {
  396. error_str = "Expected " + get_token_name(TK_CURLY_BRACKET_OPEN) + " after struct decl, found " + get_token_name(TK_EOF);
  397. error = true;
  398. return ERR_PARSE_ERROR;
  399. }
  400. }
  401. NameDecl name_decl;
  402. name_decl.name = name;
  403. name_decl.type = NameDecl::STRUCT_DECL;
  404. name_stack[at_level] = name_decl;
  405. } else if (tk == TK_IDENTIFIER && String(value) == "namespace") {
  406. if (type_curly_stack > 0) {
  407. error_str = "Found namespace nested inside type.";
  408. error = true;
  409. return ERR_PARSE_ERROR;
  410. }
  411. String name;
  412. int at_level = curly_stack;
  413. Error err = _parse_namespace_name(name, curly_stack);
  414. if (err)
  415. return err;
  416. NameDecl name_decl;
  417. name_decl.name = name;
  418. name_decl.type = NameDecl::NAMESPACE_DECL;
  419. name_stack[at_level] = name_decl;
  420. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  421. curly_stack++;
  422. } else if (tk == TK_CURLY_BRACKET_CLOSE) {
  423. curly_stack--;
  424. if (name_stack.has(curly_stack)) {
  425. if (name_stack[curly_stack].type != NameDecl::NAMESPACE_DECL)
  426. type_curly_stack--;
  427. name_stack.erase(curly_stack);
  428. }
  429. }
  430. tk = get_token();
  431. }
  432. if (!error && tk == TK_EOF && curly_stack > 0) {
  433. error_str = "Reached EOF with missing close curly brackets.";
  434. error = true;
  435. }
  436. if (error)
  437. return ERR_PARSE_ERROR;
  438. return OK;
  439. }
  440. Error ScriptClassParser::parse_file(const String &p_filepath) {
  441. String source;
  442. Error ferr = read_all_file_utf8(p_filepath, source);
  443. if (ferr != OK) {
  444. if (ferr == ERR_INVALID_DATA) {
  445. 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.");
  446. }
  447. ERR_FAIL_V(ferr);
  448. }
  449. return parse(source);
  450. }
  451. String ScriptClassParser::get_error() {
  452. return error_str;
  453. }
  454. Vector<ScriptClassParser::ClassDecl> ScriptClassParser::get_classes() {
  455. return classes;
  456. }