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

302 строки
8.4 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 '0': *out++ = '\a'; ++p; break;
  39. case 'a': *out++ = '\a'; ++p; break;
  40. case 'b': *out++ = '\b'; ++p; break;
  41. case 'f': *out++ = '\f'; ++p; break;
  42. case 'n': *out++ = '\n'; ++p; break;
  43. case 'r': *out++ = '\r'; ++p; break;
  44. case 't': *out++ = '\t'; ++p; break;
  45. case 'v': *out++ = '\v'; ++p; break;
  46. case '"':
  47. case '\'':
  48. case '\\':
  49. *out++ = *p++;
  50. case '?':
  51. break;
  52. case 'x':
  53. case 'X':
  54. if (!isxdigit(p[1]) || !isxdigit(p[2])) {
  55. int_err = "Invalid character on hexadecimal escape.";
  56. } else {
  57. *out++ = (char)(get_nibble(p[1]) * 0x10 + get_nibble(p[2]));
  58. p += 3;
  59. }
  60. break;
  61. default:
  62. int_err = "Unexpected '\\' with no escape sequence.";
  63. break;
  64. }
  65. }
  66. }
  67. /* Set the end of string. */
  68. *out = '\0';
  69. if (int_err)
  70. return false;
  71. return true;
  72. }
  73. proc read_entire_file(char* filename) -> char* {
  74. char *fileContent = nullptr;
  75. FILE *fp = fopen(filename, "r");
  76. if (fp) {
  77. /* Go to the end of the file. */
  78. if (fseek(fp, 0L, SEEK_END) == 0) {
  79. /* Get the size of the file. */
  80. long bufsize = ftell(fp);
  81. if (bufsize == -1) {
  82. fputs("Empty file", stderr);
  83. goto closeFile;
  84. }
  85. /* Go back to the start of the file. */
  86. if (fseek(fp, 0L, SEEK_SET) != 0) {
  87. fputs("Error reading file", stderr);
  88. goto closeFile;
  89. }
  90. /* Allocate our buffer to that size. */
  91. fileContent = (char*)calloc(bufsize, sizeof(char));
  92. /* Read the entire file into memory. */
  93. size_t newLen = fread(fileContent, sizeof(char), bufsize, fp);
  94. fileContent[newLen] = '\0';
  95. if ( ferror( fp ) != 0 ) {
  96. fputs("Error reading file", stderr);
  97. }
  98. }
  99. closeFile:
  100. fclose(fp);
  101. }
  102. return fileContent;
  103. /* Don't forget to call free() later! */
  104. }
  105. proc read_expression() -> char* {
  106. char* line = (char*)malloc(100);
  107. char* linep = line;
  108. size_t lenmax = 100, len = lenmax;
  109. int c;
  110. int nesting = 0;
  111. if(line == NULL)
  112. return NULL;
  113. for(;;) {
  114. c = fgetc(stdin);
  115. if(c == EOF)
  116. break;
  117. if(--len == 0) {
  118. len = lenmax;
  119. char * linen = (char*)realloc(linep, lenmax *= 2);
  120. if(linen == NULL) {
  121. free(linep);
  122. return NULL;
  123. }
  124. line = linen + (line - linep);
  125. linep = linen;
  126. }
  127. *line = (char)c;
  128. if(*line == '(')
  129. ++nesting;
  130. else if(*line == ')')
  131. --nesting;
  132. else if(*line == '\n')
  133. if (nesting == 0)
  134. break;
  135. line++;
  136. }
  137. (*line)--; // we dont want the \n actually
  138. *line = '\0';
  139. return linep;
  140. }
  141. proc read_line() -> char* {
  142. char* line = (char*)malloc(100), * linep = line;
  143. size_t lenmax = 100, len = lenmax;
  144. int c;
  145. int nesting = 0;
  146. if(line == NULL)
  147. return NULL;
  148. for(;;) {
  149. c = fgetc(stdin);
  150. if(c == EOF)
  151. break;
  152. if(--len == 0) {
  153. len = lenmax;
  154. char* linen = (char*)realloc(linep, lenmax *= 2);
  155. if(linen == NULL) {
  156. free(linep);
  157. return NULL;
  158. }
  159. line = linen + (line - linep);
  160. linep = linen;
  161. }
  162. *line = (char)c;
  163. if(*line == '(')
  164. ++nesting;
  165. else if(*line == ')')
  166. --nesting;
  167. else if(*line == '\n')
  168. if (nesting == 0)
  169. break;
  170. line++;
  171. }
  172. (*line)--; // we dont want the \n actually
  173. *line = '\0';
  174. return linep;
  175. }
  176. Log_Level log_level = Log_Level::Debug;
  177. proc log_message(Log_Level type, char* message) -> void {
  178. if (type > log_level)
  179. return;
  180. const char* prefix;
  181. switch (type) {
  182. case Log_Level::Critical: prefix = "CRITICAL"; break;
  183. case Log_Level::Warning: prefix = "WARNING"; break;
  184. case Log_Level::Info: prefix = "INFO"; break;
  185. case Log_Level::Debug: prefix = "DEBUG"; break;
  186. default: return;
  187. }
  188. printf("%s: %s\n",prefix, message);
  189. }
  190. proc panic(char* message) -> void {
  191. log_message(Log_Level::Critical, message);
  192. exit(1);
  193. }
  194. proc print(Lisp_Object* node, bool print_quotes = false, FILE* file = stdout) -> void {
  195. switch (node->type) {
  196. case (Lisp_Object_Type::Nil): fprintf(file, "()"); break;
  197. case (Lisp_Object_Type::T): fprintf(file, "t"); break;
  198. case (Lisp_Object_Type::Number): fprintf(file, "%f", node->value.number); break;
  199. case (Lisp_Object_Type::Symbol): fprintf(file, "%s", Memory::get_c_str(node->value.identifier)); break;
  200. case (Lisp_Object_Type::Keyword): fprintf(file, ":%s", Memory::get_c_str(node->value.identifier)); break;
  201. case (Lisp_Object_Type::CFunction): fprintf(file, "[C-function]"); break;
  202. case (Lisp_Object_Type::String): {
  203. if (print_quotes)
  204. fprintf(file, "\"%s\"", Memory::get_c_str(node->value.string));
  205. else
  206. fprintf(file, "%s", Memory::get_c_str(node->value.string));
  207. } break;
  208. case (Lisp_Object_Type::Function): {
  209. if (node->value.function.type == Function_Type::Lambda)
  210. fprintf(file, "[lambda]");
  211. else if (node->value.function.type == Function_Type::Special_Lambda)
  212. fprintf(file, "[special-lambda]");
  213. else if (node->value.function.type == Function_Type::Macro)
  214. fprintf(file, "[macro]");
  215. else
  216. assert(false);
  217. } break;
  218. case (Lisp_Object_Type::Pair): {
  219. Lisp_Object* head = node;
  220. fprintf(file, "(");
  221. // NOTE(Felix): We cold do a while true here, however in case
  222. // we want to print a broken list (for logging the error) we
  223. // should do mo checks.
  224. while (head) {
  225. print(head->value.pair.first, print_quotes, file);
  226. head = head->value.pair.rest;
  227. if (!head)
  228. return;
  229. if (head->type != Lisp_Object_Type::Pair)
  230. break;
  231. fprintf(file, " ");
  232. }
  233. if (head->type != Lisp_Object_Type::Nil) {
  234. fprintf(file, " . ");
  235. print(head);
  236. }
  237. fprintf(file, ")");
  238. } break;
  239. }
  240. }
  241. proc print_error_location() -> void {
  242. if (error->location) {
  243. printf("%s (line %d, position %d)",
  244. Memory::get_c_str(error->location->file),
  245. error->location->line,
  246. error->location->column);
  247. } else {
  248. printf("no source code location avaliable");
  249. }
  250. }
  251. proc log_error() -> void {
  252. printf("%s%s%s\n", console_red,
  253. Error_Type_to_string(error->type),
  254. console_normal);
  255. printf(" in: %s", console_cyan);
  256. print_error_location();
  257. printf("%s\n", console_normal);
  258. }