Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

577 wiersze
20 KiB

  1. namespace Slime {
  2. proc string_equal(const char input[], const char check[]) -> bool {
  3. if (input == check) return true;
  4. for(int i = 0; input[i] == check[i]; i++) {
  5. if (input[i] == '\0')
  6. return true;
  7. }
  8. return false;
  9. }
  10. proc string_equal(String str, const char check[]) -> bool {
  11. return string_equal(Memory::get_c_str(str), check);
  12. }
  13. proc string_equal(const char check[], String str) -> bool {
  14. return string_equal(Memory::get_c_str(str), check);
  15. }
  16. proc string_equal(String str1, String str2) -> bool {
  17. return string_equal(Memory::get_c_str(str1), Memory::get_c_str(str2));
  18. }
  19. proc get_nibble(char c) -> char {
  20. if (c >= 'A' && c <= 'F')
  21. return (c - 'A') + 10;
  22. else if (c >= 'a' && c <= 'f')
  23. return (c - 'a') + 10;
  24. return (c - '0');
  25. }
  26. proc escape_string(char* in) -> char* {
  27. // TODO(Felix): add more escape sequences
  28. int i = 0, count = 0;
  29. while (in[i] != '\0') {
  30. switch (in[i]) {
  31. case '\\':
  32. case '\n':
  33. case '\t':
  34. ++count;
  35. default: break;
  36. }
  37. ++i;
  38. }
  39. char* ret = (char*)malloc((i+count+1)*sizeof(char));
  40. // copy in
  41. i = 0;
  42. int j = 0;
  43. while (in[i] != '\0') {
  44. switch (in[i]) {
  45. case '\\': ret[j++] = '\\'; ret[j++] = '\\'; break;
  46. case '\n': ret[j++] = '\\'; ret[j++] = 'n'; break;
  47. case '\t': ret[j++] = '\\'; ret[j++] = 't'; break;
  48. default: ret[j++] = in[i];
  49. }
  50. ++i;
  51. }
  52. ret[j++] = '\0';
  53. return ret;
  54. }
  55. proc unescape_string(char* in) -> int {
  56. if (!in) return 0;
  57. char *out = in, *p = in;
  58. const char *int_err = nullptr;
  59. while (*p && !int_err) {
  60. if (*p != '\\') {
  61. /* normal case */
  62. *out++ = *p++;
  63. } else {
  64. /* escape sequence */
  65. switch (*++p) {
  66. case '0': *out++ = '\a'; ++p; break;
  67. case 'a': *out++ = '\a'; ++p; break;
  68. case 'b': *out++ = '\b'; ++p; break;
  69. case 'f': *out++ = '\f'; ++p; break;
  70. case 'n': *out++ = '\n'; ++p; break;
  71. case 'r': *out++ = '\r'; ++p; break;
  72. case 't': *out++ = '\t'; ++p; break;
  73. case 'v': *out++ = '\v'; ++p; break;
  74. case '"':
  75. case '\'':
  76. case '\\':
  77. *out++ = *p++;
  78. case '?':
  79. break;
  80. case 'x':
  81. case 'X':
  82. if (!isxdigit(p[1]) || !isxdigit(p[2])) {
  83. create_parsing_error(
  84. "The string '%s' at %s:%d:%d could not be unescaped. "
  85. "(Invalid character on hexadecimal escape at char %d)",
  86. in, Parser::parser_file, Parser::parser_line, Parser::parser_col,
  87. (p+1)-in);
  88. } else {
  89. *out++ = (char)(get_nibble(p[1]) * 0x10 + get_nibble(p[2]));
  90. p += 3;
  91. }
  92. break;
  93. default:
  94. create_parsing_error(
  95. "The string '%s' at %s:%d:%d could not be unescaped. "
  96. "(Unexpected '\\' with no escape sequence at char %d)",
  97. in, Parser::parser_file, Parser::parser_line, Parser::parser_col,
  98. (p+1)-in);
  99. }
  100. }
  101. }
  102. /* Set the end of string. */
  103. *out = '\0';
  104. return (int)(out - in);
  105. }
  106. proc read_entire_file(char* filename) -> char* {
  107. profile_with_comment(filename);
  108. char *fileContent = nullptr;
  109. FILE *fp = fopen(filename, "r");
  110. if (fp) {
  111. /* Go to the end of the file. */
  112. if (fseek(fp, 0L, SEEK_END) == 0) {
  113. /* Get the size of the file. */
  114. long bufsize = ftell(fp) + 1;
  115. if (bufsize == 0) {
  116. fputs("Empty file", stderr);
  117. goto closeFile;
  118. }
  119. /* Go back to the start of the file. */
  120. if (fseek(fp, 0L, SEEK_SET) != 0) {
  121. fputs("Error reading file", stderr);
  122. goto closeFile;
  123. }
  124. /* Allocate our buffer to that size. */
  125. fileContent = (char*)calloc(bufsize, sizeof(char));
  126. /* Read the entire file into memory. */
  127. size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
  128. fileContent[newLen] = '\0';
  129. if (ferror(fp) != 0) {
  130. fputs("Error reading file", stderr);
  131. }
  132. }
  133. closeFile:
  134. fclose(fp);
  135. }
  136. return fileContent;
  137. /* Don't forget to call free() later! */
  138. }
  139. proc read_expression() -> char* {
  140. char* line = (char*)malloc(100);
  141. if(line == nullptr)
  142. return nullptr;
  143. char* linep = line;
  144. size_t lenmax = 100, len = lenmax;
  145. int c;
  146. int nesting = 0;
  147. while (true) {
  148. c = fgetc(stdin);
  149. if(c == EOF)
  150. break;
  151. if(--len == 0) {
  152. len = lenmax;
  153. char * linen = (char*)realloc(linep, lenmax *= 2);
  154. if(linen == nullptr) {
  155. free(linep);
  156. return nullptr;
  157. }
  158. line = linen + (line - linep);
  159. linep = linen;
  160. }
  161. *line = (char)c;
  162. if(*line == '(')
  163. ++nesting;
  164. else if(*line == ')')
  165. --nesting;
  166. else if(*line == '\n')
  167. if (nesting == 0)
  168. break;
  169. line++;
  170. }
  171. (*line)--; // we dont want the \n actually
  172. *line = '\0';
  173. return linep;
  174. }
  175. proc read_line() -> char* {
  176. char* line = (char*)malloc(100), * linep = line;
  177. size_t lenmax = 100, len = lenmax;
  178. int c;
  179. int nesting = 0;
  180. if(line == nullptr)
  181. return nullptr;
  182. for(;;) {
  183. c = fgetc(stdin);
  184. if(c == EOF)
  185. break;
  186. if(--len == 0) {
  187. len = lenmax;
  188. char* linen = (char*)realloc(linep, lenmax *= 2);
  189. if(linen == nullptr) {
  190. free(linep);
  191. return nullptr;
  192. }
  193. line = linen + (line - linep);
  194. linep = linen;
  195. }
  196. *line = (char)c;
  197. if(*line == '(')
  198. ++nesting;
  199. else if(*line == ')')
  200. --nesting;
  201. else if(*line == '\n')
  202. if (nesting == 0)
  203. break;
  204. line++;
  205. }
  206. (*line)--; // we dont want the \n actually
  207. *line = '\0';
  208. return linep;
  209. }
  210. proc log_message(Log_Level type, const char* message) -> void {
  211. if (type > Globals::log_level)
  212. return;
  213. const char* prefix;
  214. switch (type) {
  215. case Log_Level::Critical: prefix = "CRITICAL"; break;
  216. case Log_Level::Warning: prefix = "WARNING"; break;
  217. case Log_Level::Info: prefix = "INFO"; break;
  218. case Log_Level::Debug: prefix = "DEBUG"; break;
  219. default: return;
  220. }
  221. printf("%s: %s\n",prefix, message);
  222. }
  223. char* wchar_to_char(const wchar_t* pwchar) {
  224. // get the number of characters in the string.
  225. int currentCharIndex = 0;
  226. char currentChar = (char)pwchar[currentCharIndex];
  227. while (currentChar != '\0')
  228. {
  229. currentCharIndex++;
  230. currentChar = (char)pwchar[currentCharIndex];
  231. }
  232. const int charCount = currentCharIndex + 1;
  233. // allocate a new block of memory size char (1 byte) instead of wide char (2 bytes)
  234. char* filePathC = (char*)malloc(sizeof(char) * charCount);
  235. for (int i = 0; i < charCount; i++)
  236. {
  237. // convert to char (1 byte)
  238. char character = (char)pwchar[i];
  239. *filePathC = character;
  240. filePathC += sizeof(char);
  241. }
  242. filePathC += '\0';
  243. filePathC -= (sizeof(char) * charCount);
  244. return filePathC;
  245. }
  246. const wchar_t* char_to_wchar(const char* c) {
  247. const size_t cSize = strlen(c)+1;
  248. wchar_t* wc = new wchar_t[cSize];
  249. mbstowcs (wc, c, cSize);
  250. return wc;
  251. }
  252. proc string_buider_to_string(Array_List<char*> string_builder) -> char* {
  253. size_t len = 1;
  254. int idx = 0;
  255. for (auto str : string_builder) {
  256. len += strlen(str);
  257. }
  258. char* res = (char*)(malloc(sizeof(char) * len));
  259. res[0] = '\0';
  260. for (auto str : string_builder) {
  261. strcat(res, str);
  262. }
  263. return res;
  264. }
  265. proc lisp_object_to_string(Lisp_Object* node, bool print_repr) -> char* {
  266. char* temp;
  267. Array_List<char*> string_builder;
  268. string_builder.alloc();
  269. defer {
  270. string_builder.dealloc();
  271. };
  272. switch (Memory::get_type(node)) {
  273. case (Lisp_Object_Type::Nil): return strdup("()");
  274. case (Lisp_Object_Type::T): return strdup("t");
  275. case (Lisp_Object_Type::Continuation): return strdup("[continuation]");
  276. case (Lisp_Object_Type::Pointer): return strdup("[pointer]");
  277. case (Lisp_Object_Type::Number): {
  278. if (abs(node->value.number - (int)node->value.number) < 0.000001f)
  279. asprintf(&temp, "%d", (int)node->value.number);
  280. else
  281. asprintf(&temp, "%f", node->value.number);
  282. return temp;
  283. }
  284. case (Lisp_Object_Type::Keyword): {
  285. asprintf(&temp, ":%s", Memory::get_c_str(node->value.symbol));
  286. return temp;
  287. }
  288. case (Lisp_Object_Type::Symbol): {
  289. asprintf(&temp, "%s", Memory::get_c_str(node->value.symbol));
  290. return temp;
  291. }
  292. case (Lisp_Object_Type::HashMap): {
  293. for_hash_map (*(node->value.hashMap)) {
  294. char* k = lisp_object_to_string(key, true);
  295. char* v = lisp_object_to_string((Lisp_Object*)value, true);
  296. asprintf(&temp, " %s -> %s\n", k, v);
  297. string_builder.append(temp);
  298. free(v);
  299. free(k);
  300. }
  301. temp = string_buider_to_string(string_builder);
  302. // free all asprintfs
  303. for (auto str : string_builder) {
  304. free(str);
  305. }
  306. return temp;
  307. }
  308. case (Lisp_Object_Type::String): {
  309. if (print_repr) {
  310. char* escaped = escape_string(Memory::get_c_str(node->value.string));
  311. asprintf(&temp, "\"%s\"", escaped);
  312. free(escaped);
  313. return temp;
  314. } else
  315. return strdup(Memory::get_c_str(node->value.string));
  316. } break;
  317. case (Lisp_Object_Type::Vector): {
  318. string_builder.append(strdup("["));
  319. if (node->value.vector.length > 0)
  320. string_builder.append(lisp_object_to_string(node->value.vector.data, print_repr));
  321. for (int i = 1; i < node->value.vector.length; ++i) {
  322. string_builder.append(strdup(" "));
  323. string_builder.append(lisp_object_to_string(node->value.vector.data+i, print_repr));
  324. }
  325. string_builder.append(strdup("]"));
  326. temp = string_buider_to_string(string_builder);
  327. for (auto str : string_builder) {
  328. free(str);
  329. }
  330. return temp;
  331. } break;
  332. case (Lisp_Object_Type::Function): {
  333. if (node->userType) {
  334. asprintf(&temp, "[%s]", Memory::get_c_str(node->userType->value.symbol));
  335. return temp;
  336. }
  337. if (node->value.function->is_c) {
  338. // NOTE(Felix): try to find the symbol it is bound to
  339. // in global env
  340. Lisp_Object* name = (Lisp_Object*)(get_root_environment()->hm.search_key_to_object(node));
  341. if (name) {
  342. switch (node->value.function->type.c_function_type) {
  343. case C_Function_Type::cFunction: asprintf(&temp, "[c-function %s]",name->value.symbol.data); break;
  344. case C_Function_Type::cSpecial: asprintf(&temp, "[c-special %s]", name->value.symbol.data); break;
  345. case C_Function_Type::cMacro: asprintf(&temp, "[c-macro %s]", name->value.symbol.data); break;
  346. default: return strdup("[c-??]");
  347. }
  348. } else {
  349. switch (node->value.function->type.c_function_type) {
  350. case C_Function_Type::cFunction: asprintf(&temp, "[c-function]"); break;
  351. case C_Function_Type::cSpecial: asprintf(&temp, "[c-special]"); break;
  352. case C_Function_Type::cMacro: asprintf(&temp, "[c-macro]"); break;
  353. default: return strdup("[c-??]");
  354. }
  355. }
  356. return temp;
  357. } else {
  358. switch (node->value.function->type.lisp_function_type) {
  359. case Lisp_Function_Type::Lambda: return strdup("[lambda]");
  360. case Lisp_Function_Type::Macro: return strdup("[macro]");
  361. default: return strdup("[??]");
  362. }
  363. }
  364. } break;
  365. case (Lisp_Object_Type::Pair): {
  366. // TODO
  367. Lisp_Object* head = node;
  368. defer {
  369. for (auto str : string_builder) {
  370. free(str);
  371. }
  372. };
  373. // first check if it is a quotation form, in that case we want
  374. // to print it prettier
  375. if (Memory::get_type(head->value.pair.first) == Lisp_Object_Type::Symbol) {
  376. String identifier = head->value.pair.first->value.symbol;
  377. auto symbol = head->value.pair.first;
  378. auto quote_sym = Memory::get_symbol("quote");
  379. auto unquote_sym = Memory::get_symbol("unquote");
  380. auto quasiquote_sym = Memory::get_symbol("quasiquote");
  381. auto unquote_splicing_sym = Memory::get_symbol("unquote-splicing");
  382. if (symbol == quote_sym || symbol == unquote_sym || symbol == unquote_splicing_sym)
  383. {
  384. if (symbol == quote_sym)
  385. string_builder.append(strdup("\'"));
  386. else if (symbol == unquote_sym)
  387. string_builder.append(strdup(","));
  388. else if (symbol == unquote_splicing_sym)
  389. string_builder.append(strdup(",@"));
  390. assert_type(head->value.pair.rest, Lisp_Object_Type::Pair);
  391. assert("The list must end here.",
  392. head->value.pair.rest->value.pair.rest == Memory::nil);
  393. string_builder.append(lisp_object_to_string(head->value.pair.rest->value.pair.first, print_repr));
  394. return string_buider_to_string(string_builder);
  395. } else if (symbol == quasiquote_sym) {
  396. string_builder.append(strdup("`"));
  397. assert_type(head->value.pair.rest, Lisp_Object_Type::Pair);
  398. string_builder.append(lisp_object_to_string(head->value.pair.rest->value.pair.first, print_repr));
  399. return string_buider_to_string(string_builder);
  400. }
  401. }
  402. string_builder.append(strdup("("));
  403. // NOTE(Felix): We could do a while true here, however in case
  404. // we want to print a broken list (for logging the error) we
  405. // should do more checks.
  406. while (head) {
  407. string_builder.append(lisp_object_to_string(head->value.pair.first, print_repr));
  408. head = head->value.pair.rest;
  409. if (!head) break;
  410. if (Memory::get_type(head) != Lisp_Object_Type::Pair) break;
  411. string_builder.append(strdup(" "));
  412. }
  413. if (head && Memory::get_type(head) != Lisp_Object_Type::Nil) {
  414. string_builder.append(strdup(" . "));
  415. string_builder.append(lisp_object_to_string(head, print_repr));
  416. }
  417. string_builder.append(strdup(")"));
  418. return string_buider_to_string(string_builder);
  419. }
  420. default:
  421. create_generic_error("A Lisp_Object of type-id %d cannot be converted to a string",
  422. (int)(Memory::get_type(node)));
  423. return nullptr;
  424. }
  425. }
  426. proc print(Lisp_Object* node, bool print_repr, FILE* file) -> void {
  427. char* string = nullptr;
  428. defer {
  429. free(string);
  430. };
  431. string = lisp_object_to_string(node, print_repr);
  432. fputs(string, file);
  433. }
  434. proc print_single_call(Lisp_Object* obj) -> void {
  435. printf(console_cyan);
  436. print(obj, true);
  437. printf(console_normal);
  438. printf("\n at ");
  439. if (obj->sourceCodeLocation) {
  440. printf("%s (line %d, position %d)",
  441. Memory::get_c_str(
  442. obj->sourceCodeLocation->file),
  443. obj->sourceCodeLocation->line,
  444. obj->sourceCodeLocation->column);
  445. } else {
  446. fputs("no source code location avaliable", stdout);
  447. }
  448. }
  449. proc print_current_execution() -> void {
  450. using Globals::Current_Execution::cs;
  451. using Globals::Current_Execution::pcs;
  452. using Globals::Current_Execution::nass;
  453. using Globals::Current_Execution::ams;
  454. printf("cs:\n ");
  455. for (int i = 0; i < cs.next_index; ++i) {
  456. char* t = lisp_object_to_string(cs.data[i], true);
  457. printf(" %d: %s\n ", i, t);
  458. defer {
  459. free(t);
  460. };
  461. }
  462. printf("\npcs:\n ");
  463. for (auto lo : pcs) {
  464. print(lo, true);
  465. printf("\n ");
  466. }
  467. printf("\nnnas:\n ");
  468. for (auto nas: nass) {
  469. printf("nas:\n ");
  470. for (auto na : nas) {
  471. printf(" - %s\n ", [&]
  472. {
  473. switch(na) {
  474. case NasAction::Macro_Write_Back: return "Macro_Write_Back";
  475. case NasAction::And_Then_Action: return "And_Then_Action";
  476. case NasAction::Pop_Environment: return "Pop_Environment";
  477. case NasAction::Define_Var: return "Define_Var";
  478. case NasAction::Eval: return "Eval";
  479. case NasAction::Step: return "Step";
  480. case NasAction::TM: return "TM";
  481. case NasAction::Pop: return "Pop";
  482. case NasAction::If: return "If";
  483. }
  484. return "??";
  485. }());
  486. }
  487. }
  488. printf("\nams:\n ");
  489. for (auto am : ams) {
  490. printf("%d\n ", am);
  491. }
  492. }
  493. proc log_error() -> void {
  494. fputs("\n", stdout);
  495. fputs(console_red, stdout);
  496. fputs(Memory::get_c_str(Globals::error->message), stdout);
  497. puts(console_normal);
  498. fputs(" in: ", stdout);
  499. print_current_execution();
  500. puts(console_normal);
  501. }
  502. }