| @@ -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); | |||
| } | |||
| } | |||
| } | |||