| @@ -0,0 +1,177 @@ | |||||
| namespace Parser { | |||||
| proc eat_comment_line(char* text, int* index_in_text) -> void { | |||||
| // safety check if we are actually starting a comment here | |||||
| if (text[*index_in_text] != ';') | |||||
| return; | |||||
| // eat the comment line | |||||
| do { | |||||
| ++(*index_in_text); | |||||
| ++parser_col; | |||||
| } while (text[(*index_in_text)] != '\n' && | |||||
| text[(*index_in_text)] != '\r' && | |||||
| text[(*index_in_text)] != '\0'); | |||||
| } | |||||
| proc eat_whitespace(char* text, int* index_in_text) -> void { | |||||
| // skip whitespaces | |||||
| while (text[(*index_in_text)] == ' ' || | |||||
| text[(*index_in_text)] == '\t' || | |||||
| text[(*index_in_text)] == '\n' || | |||||
| text[(*index_in_text)] == '\r') | |||||
| { | |||||
| if (text[(*index_in_text)] == '\n') { | |||||
| ++parser_line; | |||||
| parser_col = 0; | |||||
| } | |||||
| ++parser_col; | |||||
| ++(*index_in_text); | |||||
| } | |||||
| } | |||||
| proc eat_until_code(char* text, int* index_in_text) -> void { | |||||
| int position_before; | |||||
| do { | |||||
| position_before = *index_in_text; | |||||
| eat_comment_line(text, index_in_text); | |||||
| eat_whitespace(text, index_in_text); | |||||
| } while (position_before != *index_in_text); | |||||
| } | |||||
| proc step_char(int* index_in_text) { | |||||
| ++(*index_in_text); | |||||
| ++parser_col; | |||||
| } | |||||
| proc step_char_and_eat_until_code(char* text, int* index_in_text) { | |||||
| step_char(index_in_text); | |||||
| eat_until_code(text, index_in_text); | |||||
| } | |||||
| proc parse_fancy_delimiter(char* text, int* index_in_text, char l_delimiter, char r_delimiter, Lisp_Object* first_elem) -> Lisp_Object* { | |||||
| if (text[*index_in_text] != l_delimiter) { | |||||
| create_parsing_error("a fancy cannot be parsed here"); | |||||
| return nullptr; | |||||
| } | |||||
| Lisp_Objcet* ret; | |||||
| Lisp_Objcet* head; | |||||
| try ret = Memory::create_lisp_object_pair(first_elem, Memory::nil); | |||||
| head = ret; | |||||
| step_char(index_in_text); | |||||
| while (text[*index_in_text] != r_delimiter) { | |||||
| eat_until_code(text, index_in_text); | |||||
| Lisp_Object* element; | |||||
| try element = parse_expression(text, index_in_text); | |||||
| try head.value.pair.rest = Memory::create_lisp_object_pair(element, Memory::nil); | |||||
| head = head.value.pair.rest; | |||||
| } | |||||
| ++*index_in_text; | |||||
| return ret; | |||||
| } | |||||
| proc parse_list(char* text, int* index_in_text) -> Lisp_Object* { | |||||
| if (text[*index_in_text] != '(') { | |||||
| create_parsing_error("a list cannot be parsed here"); | |||||
| return nullptr; | |||||
| } | |||||
| step_char_and_eat_until_code(); | |||||
| if (text[*index_in_text] == ')') { | |||||
| return meory::nil; | |||||
| } | |||||
| Lisp_Object* first_elem; | |||||
| Lisp_Objcet* ret; | |||||
| Lisp_Objcet* head; | |||||
| try first_elem = parse_epression(text, index_in_text); | |||||
| try ret = Memory::create_lisp_object_pair(first_elem, Memory::nil); | |||||
| head = ret; | |||||
| while (text[*index_in_text] != r_delimiter) { | |||||
| eat_until_code(text, index_in_text); | |||||
| Lisp_Object* element; | |||||
| try element = parse_expression(text, index_in_text); | |||||
| try head.value.pair.rest = Memory::create_lisp_object_pair(element, Memory::nil); | |||||
| head = head.value.pair.rest; | |||||
| } | |||||
| } | |||||
| proc maybe_expand_short_form(char* text, int* index_in_text) -> Lisp_Object* { | |||||
| Lisp_Object* vector_sym = Memory::get_or_create_lisp_object_symbol("vector"); | |||||
| Lisp_Object* hash_map_sym = Memory::get_or_create_lisp_object_symbol("hash-map"); | |||||
| Lisp_Object* quote_sym = Memory::get_or_create_lisp_object_symbol("quote"); | |||||
| Lisp_Object* quasiquote_sym = Memory::get_or_create_lisp_object_symbol("quasiquote"); | |||||
| Lisp_Object* unquote_sym = Memory::get_or_create_lisp_object_symbol("unquote"); | |||||
| Lisp_Object* unquote_splicing_sym = Memory::get_or_create_lisp_object_symbol("unquote-splicing"); | |||||
| Lisp_Object* ret; | |||||
| Lisp_Object* expr; | |||||
| switch (text[*index_in_text]) { | |||||
| case '\'': { | |||||
| // quote | |||||
| step_char_and_eat_until_code(text, index_in_text); | |||||
| expr = parse_expresion(text, index_in_text); | |||||
| try ret = Memory::create_lisp_object_pair(quote_sym, expr); | |||||
| } break; | |||||
| case '`': { | |||||
| // quasiquote | |||||
| step_char_and_eat_until_code(text, index_in_text); | |||||
| expr = parse_expresion(text, index_in_text); | |||||
| try ret = Memory::create_lisp_object_pair(quasiquote_sym, expr); | |||||
| } break; | |||||
| case ',': { | |||||
| if (text[*index_in_text+1] == '@') { | |||||
| // unquote-splicing | |||||
| step_char(text, index_in_text); | |||||
| step_char_and_eat_until_code(itext, index_in_text); | |||||
| expr = parse_expresion(text, index_in_text); | |||||
| try ret = Memory::create_lisp_object_pair(unquote_splicing_sym, expr); | |||||
| } else { | |||||
| // unquote | |||||
| expr = parse_expresion(text, index_in_text); | |||||
| try ret = Memory::create_lisp_object_pair(unquote_sym, expr); | |||||
| step_char_and_eat_until_code(text, index_in_text); | |||||
| } | |||||
| } break; | |||||
| case '[': { | |||||
| // vector | |||||
| try ret = parse_fancy_delimiter(text, index_in_text, '[', ']', vector_sym); | |||||
| } break; | |||||
| case '{': { | |||||
| // hashmap | |||||
| try ret = parse_fancy_delimiter(text, index_in_text, '{', '}', hash_map_sym); | |||||
| try parse_hash_map(text, index_in_text); | |||||
| } break; | |||||
| default: break; | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| proc parse_expression(char* text, int* index_in_text) -> Lisp_Object* { | |||||
| Lisp_Object* ret; | |||||
| try ret = maybe_expand_short_form(text, index_in_text); | |||||
| if (ret) | |||||
| return ret; | |||||
| if (text[*index_in_text] == '(') { | |||||
| try ret = parse_list(text, index_in_text); | |||||
| } | |||||
| } | |||||
| } | |||||