script_class_parser.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #include "script_class_parser.h"
  2. #include "core/map.h"
  3. #include "core/os/os.h"
  4. #include "../utils/string_utils.h"
  5. ScriptClassParser::Token ScriptClassParser::get_token() {
  6. while (true) {
  7. switch (code[idx]) {
  8. case '\n': {
  9. line++;
  10. idx++;
  11. break;
  12. };
  13. case 0: {
  14. return TK_EOF;
  15. } break;
  16. case '{': {
  17. idx++;
  18. return TK_CURLY_BRACKET_OPEN;
  19. };
  20. case '}': {
  21. idx++;
  22. return TK_CURLY_BRACKET_CLOSE;
  23. };
  24. case '[': {
  25. idx++;
  26. return TK_BRACKET_OPEN;
  27. };
  28. case ']': {
  29. idx++;
  30. return TK_BRACKET_CLOSE;
  31. };
  32. case '<': {
  33. idx++;
  34. return TK_OP_LESS;
  35. };
  36. case '>': {
  37. idx++;
  38. return TK_OP_GREATER;
  39. };
  40. case ':': {
  41. idx++;
  42. return TK_COLON;
  43. };
  44. case ',': {
  45. idx++;
  46. return TK_COMMA;
  47. };
  48. case '.': {
  49. idx++;
  50. return TK_PERIOD;
  51. };
  52. case '#': {
  53. //compiler directive
  54. while (code[idx] != '\n' && code[idx] != 0) {
  55. idx++;
  56. }
  57. continue;
  58. } break;
  59. case '/': {
  60. switch (code[idx + 1]) {
  61. case '*': { // block comment
  62. idx += 2;
  63. while (true) {
  64. if (code[idx] == 0) {
  65. error_str = "Unterminated comment";
  66. error = true;
  67. return TK_ERROR;
  68. } else if (code[idx] == '*' && code[idx + 1] == '/') {
  69. idx += 2;
  70. break;
  71. } else if (code[idx] == '\n') {
  72. line++;
  73. }
  74. idx++;
  75. }
  76. } break;
  77. case '/': { // line comment skip
  78. while (code[idx] != '\n' && code[idx] != 0) {
  79. idx++;
  80. }
  81. } break;
  82. default: {
  83. value = "/";
  84. idx++;
  85. return TK_SYMBOL;
  86. }
  87. }
  88. continue; // a comment
  89. } break;
  90. case '\'':
  91. case '"': {
  92. bool verbatim = idx != 0 && code[idx - 1] == '@';
  93. CharType begin_str = code[idx];
  94. idx++;
  95. String tk_string = String();
  96. while (true) {
  97. if (code[idx] == 0) {
  98. error_str = "Unterminated String";
  99. error = true;
  100. return TK_ERROR;
  101. } else if (code[idx] == begin_str) {
  102. if (verbatim && code[idx + 1] == '"') { // `""` is verbatim string's `\"`
  103. idx += 2; // skip next `"` as well
  104. continue;
  105. }
  106. idx += 1;
  107. break;
  108. } else if (code[idx] == '\\' && !verbatim) {
  109. //escaped characters...
  110. idx++;
  111. CharType next = code[idx];
  112. if (next == 0) {
  113. error_str = "Unterminated String";
  114. error = true;
  115. return TK_ERROR;
  116. }
  117. CharType res = 0;
  118. switch (next) {
  119. case 'b': res = 8; break;
  120. case 't': res = 9; break;
  121. case 'n': res = 10; break;
  122. case 'f': res = 12; break;
  123. case 'r':
  124. res = 13;
  125. break;
  126. case '\"': res = '\"'; break;
  127. case '\\':
  128. res = '\\';
  129. break;
  130. default: {
  131. res = next;
  132. } break;
  133. }
  134. tk_string += res;
  135. } else {
  136. if (code[idx] == '\n')
  137. line++;
  138. tk_string += code[idx];
  139. }
  140. idx++;
  141. }
  142. value = tk_string;
  143. return TK_STRING;
  144. } break;
  145. default: {
  146. if (code[idx] <= 32) {
  147. idx++;
  148. break;
  149. }
  150. 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)) {
  151. value = String::chr(code[idx]);
  152. idx++;
  153. return TK_SYMBOL;
  154. }
  155. if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) {
  156. //a number
  157. const CharType *rptr;
  158. double number = String::to_double(&code[idx], &rptr);
  159. idx += (rptr - &code[idx]);
  160. value = number;
  161. return TK_NUMBER;
  162. } else if ((code[idx] == '@' && code[idx + 1] != '"') || code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) {
  163. String id;
  164. id += code[idx];
  165. idx++;
  166. while (code[idx] == '_' || (code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || (code[idx] >= '0' && code[idx] <= '9') || code[idx] > 127) {
  167. id += code[idx];
  168. idx++;
  169. }
  170. value = id;
  171. return TK_IDENTIFIER;
  172. } else if (code[idx] == '@' && code[idx + 1] == '"') {
  173. // begin of verbatim string
  174. idx++;
  175. } else {
  176. error_str = "Unexpected character.";
  177. error = true;
  178. return TK_ERROR;
  179. }
  180. }
  181. }
  182. }
  183. }
  184. Error ScriptClassParser::_skip_type_parameters() {
  185. Token tk;
  186. while (true) {
  187. tk = get_token();
  188. if (tk == TK_IDENTIFIER) {
  189. tk = get_token();
  190. if (tk == TK_OP_LESS) {
  191. Error err = _skip_type_parameters();
  192. if (err)
  193. return err;
  194. continue;
  195. } else if (tk != TK_COMMA) {
  196. error_str = "Unexpected token: " + itos(tk);
  197. error = true;
  198. return ERR_PARSE_ERROR;
  199. }
  200. } else if (tk == TK_OP_LESS) {
  201. error_str = "Expected identifier before `<`.";
  202. error = true;
  203. return ERR_PARSE_ERROR;
  204. } else if (tk == TK_OP_GREATER) {
  205. return OK;
  206. } else {
  207. error_str = "Unexpected token: " + itos(tk);
  208. error = true;
  209. return ERR_PARSE_ERROR;
  210. }
  211. }
  212. }
  213. Error ScriptClassParser::_parse_class_base(Vector<String> &r_base) {
  214. Token tk;
  215. while (true) {
  216. tk = get_token();
  217. if (tk == TK_IDENTIFIER) {
  218. bool generic = false;
  219. String name = value;
  220. tk = get_token();
  221. if (tk == TK_OP_LESS) {
  222. generic = true;
  223. Error err = _skip_type_parameters();
  224. if (err)
  225. return err;
  226. } else if (tk == TK_COMMA) {
  227. Error err = _parse_class_base(r_base);
  228. if (err)
  229. return err;
  230. } else if (tk != TK_CURLY_BRACKET_OPEN) {
  231. error_str = "Unexpected token: " + itos(tk);
  232. error = true;
  233. return ERR_PARSE_ERROR;
  234. }
  235. r_base.push_back(!generic ? name : String()); // no generics, please
  236. return OK;
  237. } else {
  238. error_str = "Unexpected token: " + itos(tk);
  239. error = true;
  240. return ERR_PARSE_ERROR;
  241. }
  242. }
  243. }
  244. Error ScriptClassParser::_parse_namespace_name(String &r_name, int &r_curly_stack) {
  245. Token tk = get_token();
  246. if (tk == TK_IDENTIFIER) {
  247. r_name += String(value);
  248. } else {
  249. error_str = "Unexpected token: " + itos(tk);
  250. error = true;
  251. return ERR_PARSE_ERROR;
  252. }
  253. tk = get_token();
  254. if (tk == TK_PERIOD) {
  255. r_name += ".";
  256. return _parse_namespace_name(r_name, r_curly_stack);
  257. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  258. r_curly_stack++;
  259. return OK;
  260. } else {
  261. error_str = "Unexpected token: " + itos(tk);
  262. error = true;
  263. return ERR_PARSE_ERROR;
  264. }
  265. }
  266. Error ScriptClassParser::parse(const String &p_code) {
  267. code = p_code;
  268. idx = 0;
  269. line = 0;
  270. error_str = String();
  271. error = false;
  272. value = Variant();
  273. classes.clear();
  274. Token tk = get_token();
  275. Map<int, NameDecl> name_stack;
  276. int curly_stack = 0;
  277. int type_curly_stack = 0;
  278. while (!error && tk != TK_EOF) {
  279. if (tk == TK_IDENTIFIER && String(value) == "class") {
  280. tk = get_token();
  281. if (tk == TK_IDENTIFIER) {
  282. String name = value;
  283. int at_level = type_curly_stack;
  284. ClassDecl class_decl;
  285. for (Map<int, NameDecl>::Element *E = name_stack.front(); E; E = E->next()) {
  286. const NameDecl &name_decl = E->value();
  287. if (name_decl.type == NameDecl::NAMESPACE_DECL) {
  288. if (E != name_stack.front())
  289. class_decl.namespace_ += ".";
  290. class_decl.namespace_ += name_decl.name;
  291. } else {
  292. class_decl.name += name_decl.name + ".";
  293. }
  294. }
  295. class_decl.name += name;
  296. class_decl.nested = type_curly_stack > 0;
  297. bool generic = false;
  298. while (true) {
  299. tk = get_token();
  300. if (tk == TK_COLON) {
  301. Error err = _parse_class_base(class_decl.base);
  302. if (err)
  303. return err;
  304. curly_stack++;
  305. type_curly_stack++;
  306. break;
  307. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  308. curly_stack++;
  309. type_curly_stack++;
  310. break;
  311. } else if (tk == TK_OP_LESS && !generic) {
  312. generic = true;
  313. Error err = _skip_type_parameters();
  314. if (err)
  315. return err;
  316. } else {
  317. error_str = "Unexpected token: " + itos(tk);
  318. error = true;
  319. return ERR_PARSE_ERROR;
  320. }
  321. }
  322. NameDecl name_decl;
  323. name_decl.name = name;
  324. name_decl.type = NameDecl::CLASS_DECL;
  325. name_stack[at_level] = name_decl;
  326. if (!generic) { // no generics, thanks
  327. classes.push_back(class_decl);
  328. } else if (OS::get_singleton()->is_stdout_verbose()) {
  329. String full_name = class_decl.namespace_;
  330. if (full_name.length())
  331. full_name += ".";
  332. full_name += class_decl.name;
  333. OS::get_singleton()->print(String("Ignoring generic class declaration: " + class_decl.name).utf8());
  334. }
  335. }
  336. } else if (tk == TK_IDENTIFIER && String(value) == "struct") {
  337. String name;
  338. int at_level = type_curly_stack;
  339. while (true) {
  340. tk = get_token();
  341. if (tk == TK_IDENTIFIER && name.empty()) {
  342. name = String(value);
  343. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  344. if (name.empty()) {
  345. error_str = "Expected identifier after keyword `struct`. Found `{`.";
  346. error = true;
  347. return ERR_PARSE_ERROR;
  348. }
  349. curly_stack++;
  350. type_curly_stack++;
  351. break;
  352. } else if (tk == TK_EOF) {
  353. error_str = "Expected `{` after struct decl. Found `EOF`.";
  354. error = true;
  355. return ERR_PARSE_ERROR;
  356. }
  357. }
  358. NameDecl name_decl;
  359. name_decl.name = name;
  360. name_decl.type = NameDecl::STRUCT_DECL;
  361. name_stack[at_level] = name_decl;
  362. } else if (tk == TK_IDENTIFIER && String(value) == "namespace") {
  363. if (type_curly_stack > 0) {
  364. error_str = "Found namespace nested inside type.";
  365. error = true;
  366. return ERR_PARSE_ERROR;
  367. }
  368. String name;
  369. int at_level = curly_stack;
  370. Error err = _parse_namespace_name(name, curly_stack);
  371. if (err)
  372. return err;
  373. NameDecl name_decl;
  374. name_decl.name = name;
  375. name_decl.type = NameDecl::NAMESPACE_DECL;
  376. name_stack[at_level] = name_decl;
  377. } else if (tk == TK_CURLY_BRACKET_OPEN) {
  378. curly_stack++;
  379. } else if (tk == TK_CURLY_BRACKET_CLOSE) {
  380. curly_stack--;
  381. if (name_stack.has(curly_stack)) {
  382. if (name_stack[curly_stack].type != NameDecl::NAMESPACE_DECL)
  383. type_curly_stack--;
  384. name_stack.erase(curly_stack);
  385. }
  386. }
  387. tk = get_token();
  388. }
  389. if (!error && tk == TK_EOF && curly_stack > 0) {
  390. error_str = "Reached EOF with missing close curly brackets.";
  391. error = true;
  392. }
  393. if (error)
  394. return ERR_PARSE_ERROR;
  395. return OK;
  396. }
  397. Error ScriptClassParser::parse_file(const String &p_filepath) {
  398. String source;
  399. Error ferr = read_all_file_utf8(p_filepath, source);
  400. if (ferr != OK) {
  401. if (ferr == ERR_INVALID_DATA) {
  402. 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.");
  403. }
  404. ERR_FAIL_V(ferr);
  405. }
  406. return parse(source);
  407. }
  408. String ScriptClassParser::get_error() {
  409. return error_str;
  410. }
  411. Vector<ScriptClassParser::ClassDecl> ScriptClassParser::get_classes() {
  412. return classes;
  413. }