Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

370 строки
9.9 KiB

  1. proc string_equal(const char input[], const char check[]) -> bool {
  2. int i;
  3. for(i = 0; input[i] != '\0' || check[i] != '\0'; i++) {
  4. if(input[i] != check[i]) {
  5. return false;
  6. }
  7. }
  8. return true;
  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 unescape_string(char* in) -> bool {
  27. if (!in)
  28. return true;
  29. char *out = in, *p = in;
  30. const char *int_err = nullptr;
  31. while (*p && !int_err) {
  32. if (*p != '\\') {
  33. /* normal case */
  34. *out++ = *p++;
  35. } else {
  36. /* escape sequence */
  37. switch (*++p) {
  38. case 'a': *out++ = '\a'; ++p; break;
  39. case 'b': *out++ = '\b'; ++p; break;
  40. case 'f': *out++ = '\f'; ++p; break;
  41. case 'n': *out++ = '\n'; ++p; break;
  42. case 'r': *out++ = '\r'; ++p; break;
  43. case 't': *out++ = '\t'; ++p; break;
  44. case 'v': *out++ = '\v'; ++p; break;
  45. case '"':
  46. case '\'':
  47. case '\\':
  48. *out++ = *p++;
  49. case '?':
  50. break;
  51. // case 'x':
  52. // case 'X':
  53. // if (!isxdigit(p[1]) || !isxdigit(p[2])) {
  54. // int_err = "Invalid character on hexadecimal escape.";
  55. // } else {
  56. // *out++ = (char)(get_nibble(p[1]) * 0x10 + get_nibble(p[2]));
  57. // p += 3;
  58. // }
  59. // break;
  60. default:
  61. int_err = "Unexpected '\\' with no escape sequence.";
  62. break;
  63. }
  64. }
  65. }
  66. /* Set the end of string. */
  67. *out = '\0';
  68. if (int_err)
  69. return false;
  70. return true;
  71. }
  72. proc read_entire_file(char* filename) -> char* {
  73. char *fileContent = nullptr;
  74. FILE *fp = fopen(filename, "r");
  75. if (fp) {
  76. /* Go to the end of the file. */
  77. if (fseek(fp, 0L, SEEK_END) == 0) {
  78. /* Get the size of the file. */
  79. long bufsize = ftell(fp);
  80. if (bufsize == -1) {
  81. fputs("Empty file", stderr);
  82. goto closeFile;
  83. }
  84. /* Go back to the start of the file. */
  85. if (fseek(fp, 0L, SEEK_SET) != 0) {
  86. fputs("Error reading file", stderr);
  87. goto closeFile;
  88. }
  89. /* Allocate our buffer to that size. */
  90. fileContent = (char*)calloc(bufsize, sizeof(char));
  91. /* Read the entire file into memory. */
  92. size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
  93. fileContent[newLen] = '\0';
  94. if ( ferror( fp ) != 0 ) {
  95. fputs("Error reading file", stderr);
  96. }
  97. }
  98. closeFile:
  99. fclose(fp);
  100. }
  101. return fileContent;
  102. /* Don't forget to call free() later! */
  103. }
  104. proc read_expression() -> char* {
  105. char* line = (char*)malloc(100);
  106. char* linep = line;
  107. size_t lenmax = 100, len = lenmax;
  108. int c;
  109. int nesting = 0;
  110. if(line == NULL)
  111. return NULL;
  112. for(;;) {
  113. c = fgetc(stdin);
  114. if(c == EOF)
  115. break;
  116. if(--len == 0) {
  117. len = lenmax;
  118. char * linen = (char*)realloc(linep, lenmax *= 2);
  119. if(linen == NULL) {
  120. free(linep);
  121. return NULL;
  122. }
  123. line = linen + (line - linep);
  124. linep = linen;
  125. }
  126. *line = (char)c;
  127. if(*line == '(')
  128. ++nesting;
  129. else if(*line == ')')
  130. --nesting;
  131. else if(*line == '\n')
  132. if (nesting == 0)
  133. break;
  134. line++;
  135. }
  136. (*line)--; // we dont want the \n actually
  137. *line = '\0';
  138. return linep;
  139. }
  140. proc read_line() -> char* {
  141. char* line = (char*)malloc(100), * linep = line;
  142. size_t lenmax = 100, len = lenmax;
  143. int c;
  144. int nesting = 0;
  145. if(line == NULL)
  146. return NULL;
  147. for(;;) {
  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 == NULL) {
  155. free(linep);
  156. return NULL;
  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. Log_Level log_level = Log_Level::Debug;
  176. proc log_message(Log_Level type, char* message) -> void {
  177. if (type > log_level)
  178. return;
  179. const char* prefix;
  180. switch (type) {
  181. case Log_Level::Critical: prefix = "CRITICAL"; break;
  182. case Log_Level::Warning: prefix = "WARNING"; break;
  183. case Log_Level::Info: prefix = "INFO"; break;
  184. case Log_Level::Debug: prefix = "DEBUG"; break;
  185. default: return;
  186. }
  187. printf("%s: %s\n",prefix, message);
  188. }
  189. proc panic(char* message) -> void {
  190. log_message(Log_Level::Critical, message);
  191. exit(1);
  192. }
  193. proc print(Lisp_Object* node) -> void {
  194. switch (node->type) {
  195. case (Lisp_Object_Type::Nil): {
  196. printf("nil");
  197. } break;
  198. case (Lisp_Object_Type::T): {
  199. printf("t");
  200. } break;
  201. case (Lisp_Object_Type::Number): {
  202. printf("%f", node->value.number->value);
  203. } break;
  204. case (Lisp_Object_Type::String): {
  205. printf("\"%s\"", Memory::get_c_str(node->value.string));
  206. } break;
  207. case (Lisp_Object_Type::Symbol): {
  208. printf("%s", Memory::get_c_str(node->value.symbol->identifier));
  209. } break;
  210. case (Lisp_Object_Type::Keyword): {
  211. printf(":%s", Memory::get_c_str(node->value.keyword->identifier));
  212. } break;
  213. case (Lisp_Object_Type::Function): {
  214. if (node->value.function->type == Function_Type::Lambda)
  215. printf("[lambda]");
  216. else if (node->value.function->type == Function_Type::Special_Lambda)
  217. printf("[special-lambda]");
  218. else if (node->value.function->type == Function_Type::Macro)
  219. printf("[macro]");
  220. else
  221. assert(false);
  222. } break;
  223. case (Lisp_Object_Type::CFunction): {
  224. printf("[C-function]");
  225. } break;
  226. case (Lisp_Object_Type::Pair): {
  227. Lisp_Object* head = node;
  228. printf("(");
  229. // NOTE(Felix): We cold do a while true here, however in case
  230. // we want to print a broken list (for logging the error) we
  231. // should do mo checks.
  232. while (head) {
  233. print(head->value.pair->first);
  234. head = head->value.pair->rest;
  235. if (!head)
  236. return;
  237. if (head->type != Lisp_Object_Type::Pair)
  238. break;
  239. printf(" ");
  240. }
  241. if (head->type != Lisp_Object_Type::Nil) {
  242. printf(" . ");
  243. print(head);
  244. }
  245. printf(")");
  246. } break;
  247. }
  248. }
  249. // XXX(Felix): obv code dublicate
  250. proc fprint(FILE* f, Lisp_Object* node) -> void {
  251. switch (node->type) {
  252. case (Lisp_Object_Type::Nil): {
  253. fprintf(f, "nil");
  254. } break;
  255. case (Lisp_Object_Type::T): {
  256. fprintf(f, "t");
  257. } break;
  258. case (Lisp_Object_Type::Number): {
  259. fprintf(f, "%f", node->value.number->value);
  260. } break;
  261. case (Lisp_Object_Type::String): {
  262. fprintf(f, "\"%s\"", Memory::get_c_str(node->value.string));
  263. } break;
  264. case (Lisp_Object_Type::Symbol): {
  265. fprintf(f, "%s", Memory::get_c_str(node->value.symbol->identifier));
  266. } break;
  267. case (Lisp_Object_Type::Keyword): {
  268. fprintf(f, ":%s", Memory::get_c_str(node->value.keyword->identifier));
  269. } break;
  270. case (Lisp_Object_Type::Function): {
  271. if (node->value.function->type == Function_Type::Lambda)
  272. fprintf(f, "[lambda]");
  273. else if (node->value.function->type == Function_Type::Special_Lambda)
  274. fprintf(f, "[special-lambda]");
  275. else if (node->value.function->type == Function_Type::Macro)
  276. fprintf(f, "[macro]");
  277. else
  278. assert(false);
  279. } break;
  280. case (Lisp_Object_Type::CFunction): {
  281. fprintf(f, "[C-function]");
  282. } break;
  283. case (Lisp_Object_Type::Pair): {
  284. Lisp_Object* head = node;
  285. fprintf(f, "(");
  286. // NOTE(Felix): We cold do a while true here, however in case
  287. // we want to print a broken list (for logging the error) we
  288. // should do mo checks.
  289. while (head) {
  290. fprint(f, head->value.pair->first);
  291. head = head->value.pair->rest;
  292. if (!head)
  293. return;
  294. if (head->type != Lisp_Object_Type::Pair)
  295. break;
  296. fprintf(f, " ");
  297. }
  298. if (head->type != Lisp_Object_Type::Nil) {
  299. fprintf(f, " . ");
  300. print(head);
  301. }
  302. fprintf(f, ")");
  303. } break;
  304. }
  305. }
  306. proc print_error_location() -> void {
  307. if (error->location) {
  308. printf("%s (line %d, position %d)",
  309. Memory::get_c_str(error->location->file),
  310. error->location->line,
  311. error->location->column);
  312. } else {
  313. printf("no source code location avaliable");
  314. }
  315. }
  316. proc log_error() -> void {
  317. printf("%s%s%s\n", console_red,
  318. Error_Type_to_string(error->type),
  319. console_normal);
  320. printf(" in: %s", console_cyan);
  321. print_error_location();
  322. printf("%s\n", console_normal);
  323. }