diff --git a/bin/test.slime b/bin/test.slime index c8c55d5..644d5de 100644 --- a/bin/test.slime +++ b/bin/test.slime @@ -12,4 +12,6 @@ (defun ! (n) (if (< n 2) 1 - (* n (! (- 1 n))))) + (* n (! (- n 1))))) + +(erros "alskdj") \ No newline at end of file diff --git a/src/ast.c b/src/ast.c index 559c169..11e6787 100644 --- a/src/ast.c +++ b/src/ast.c @@ -237,22 +237,28 @@ typedef struct { Ast_Node_Array_List* keyword_values; } Parsed_Arguments; -Ast_Node* create_ast_node_nil() { +Ast_Node* create_ast_node() { Ast_Node* node = new(Ast_Node); + node->sourceCodeLocation = nullptr; + return node; +} + +Ast_Node* create_ast_node_nil() { + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_Nil; node->value.pair = nullptr; return node; } Ast_Node* create_ast_node_t() { - Ast_Node* node = new(Ast_Node); + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_T; node->value.pair = nullptr; return node; } Ast_Node* create_ast_node_number(double number) { - Ast_Node* node = new(Ast_Node); + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_Number; node->value.number = new(Number); node->value.number->value = number; @@ -260,7 +266,7 @@ Ast_Node* create_ast_node_number(double number) { } Ast_Node* create_ast_node_string(char* str, int length) { - Ast_Node* node = new(Ast_Node); + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_String; node->value.string = new(String); node->value.string->value = str; @@ -269,7 +275,7 @@ Ast_Node* create_ast_node_string(char* str, int length) { } Ast_Node* create_ast_node_symbol(char* identifier) { - Ast_Node* node = new(Ast_Node); + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_Symbol; node->value.symbol = new(Symbol); node->value.symbol->identifier = identifier; @@ -277,7 +283,7 @@ Ast_Node* create_ast_node_symbol(char* identifier) { } Ast_Node* create_ast_node_keyword(char* keyword) { - Ast_Node* node = new(Ast_Node); + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_Keyword; node->value.keyword = new(Keyword); node->value.keyword->identifier = keyword; @@ -326,7 +332,7 @@ Ast_Node* create_ast_node_built_in_function(char* name) { else if (string_equal(name, "while")) type = Built_In_While; else return nullptr; - Ast_Node* node = new(Ast_Node); + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_Built_In_Function; node->value.built_in_function = new(Built_In_Function); node->value.built_in_function->type = type; @@ -334,7 +340,7 @@ Ast_Node* create_ast_node_built_in_function(char* name) { } Ast_Node* create_ast_node_pair(Ast_Node* first, Ast_Node* rest) { - Ast_Node* node = new(Ast_Node); + Ast_Node* node = create_ast_node(); node->type = Ast_Node_Type_Pair; node->value.pair = new(Pair); node->value.pair->first = first; @@ -343,7 +349,7 @@ Ast_Node* create_ast_node_pair(Ast_Node* first, Ast_Node* rest) { } Ast_Node* copy_ast_node(Ast_Node* n) { - Ast_Node* target = new(Ast_Node); + Ast_Node* target = create_ast_node(); *target = *n; return target; } diff --git a/src/helpers.c b/src/helpers.c index 046e8f9..e2fd562 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -227,14 +227,16 @@ char* read_line() { typedef struct { char* file; int line; + int column; } Source_Code_Location; -Source_Code_Location* create_source_code_location(char* file, int line) { +Source_Code_Location* create_source_code_location(char* file, int line, int col) { if (!file) return nullptr; - + Source_Code_Location* ret = new(Source_Code_Location); - ret->file = file; - ret->line = line; + ret->file = file; + ret->line = line; + ret->column = col; return ret; } diff --git a/src/io.c b/src/io.c index 45d1573..523242f 100644 --- a/src/io.c +++ b/src/io.c @@ -98,7 +98,10 @@ void print(Ast_Node* node) { void print_error_location() { if (error->location) { - printf("%s: %d", error->location->file, error->location->line); + printf("%s (line %d, position %d)", + error->location->file, + error->location->line, + error->location->column); } else { printf("no source code location avaliable"); } diff --git a/src/parse.c b/src/parse.c index 130ab69..2688e55 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,5 +1,13 @@ char* parser_file; int parser_line; +int parser_col; + +#define inject_scl(_ret) \ + ret->sourceCodeLocation = new(Source_Code_Location); \ + ret->sourceCodeLocation->file = parser_file; \ + ret->sourceCodeLocation->line = parser_line; \ + ret->sourceCodeLocation->column = parser_col + // TODO(Felix): use the array list macro here? Ast_Node_Array_List* create_Ast_Node_Array_List(int initial_length) { @@ -30,13 +38,10 @@ void eat_comment_line(char* text, int* index_in_text) { // 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'); - - if (text[(*index_in_text)] == '\n') { - ++parser_line; - } } void eat_whitespace(char* text, int* index_in_text) { @@ -44,12 +49,16 @@ void eat_whitespace(char* text, int* index_in_text) { while (text[(*index_in_text)] == ' ' || text[(*index_in_text)] == '\t' || text[(*index_in_text)] == '\n' || - text[(*index_in_text)] == '\r') { + text[(*index_in_text)] == '\r') + { + if (text[(*index_in_text)] == '\n') { + ++parser_line; + parser_col = 0; + } + ++parser_col; ++(*index_in_text); } - if (text[(*index_in_text)] == '\n') { - ++parser_line; - } + } void eat_until_code(char* text, int* index_in_text) { @@ -98,33 +107,43 @@ Ast_Node* parse_number(char* text, int* index_in_text) { double number; char* str_number = read_atom(text, index_in_text); sscanf(str_number, "%lf", &number); - return create_ast_node_number(number); + Ast_Node* ret = create_ast_node_number(number); + inject_scl(ret); + return ret; } Ast_Node* parse_keyword(char* text, int* index_in_text) { // we are now on the colon ++(*index_in_text); + ++parser_col; char* str_keyword = read_atom(text, index_in_text); - return create_ast_node_keyword(str_keyword); + Ast_Node* ret = create_ast_node_keyword(str_keyword); + inject_scl(ret); + return ret; } Ast_Node* parse_symbol(char* text, int* index_in_text) { // we are now at the first char of the symbol char* str_symbol = read_atom(text, index_in_text); - return create_ast_node_symbol(str_symbol); + Ast_Node* ret = create_ast_node_symbol(str_symbol); + inject_scl(ret); + return ret; } Ast_Node* parse_string(char* text, int* index_in_text) { // the first character is the '"' ++(*index_in_text); + ++parser_col; // now we are at the first letter, if this is the closing '"' then // it's easy if (text[*index_in_text] == '"') { char* str = new(char); *str = '\0'; - return create_ast_node_string(str, 0); + Ast_Node* ret = create_ast_node_string(str, 0); + inject_scl(ret); + return ret; } // okay so the first letter was not actually closing the string... @@ -143,7 +162,7 @@ Ast_Node* parse_string(char* text, int* index_in_text) { if (!unescape_string(text+(*index_in_text))) { create_error( Error_Type_Unknown_Error, - create_source_code_location(parser_file, parser_line)); + create_source_code_location(parser_file, parser_line, parser_col)); return nullptr; } strcpy(string, text+(*index_in_text)); @@ -159,7 +178,9 @@ Ast_Node* parse_string(char* text, int* index_in_text) { *index_in_text += string_length +1; // plus one because we want to // go after the quotes - return create_ast_node_string(string, string_length); + Ast_Node* ret = create_ast_node_string(string, string_length); + inject_scl(ret); + return ret; } Ast_Node* parse_atom(char* text, int* index_in_text) { @@ -193,6 +214,7 @@ Ast_Node* parse_atom(char* text, int* index_in_text) { Ast_Node* parse_expression(char* text, int* index_in_text) { if (text[*index_in_text] == '\'') { ++(*index_in_text); + ++parser_col; Ast_Node* result; if (text[*index_in_text] == '(' || text[*index_in_text] == '\'' ) { try { @@ -208,12 +230,14 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { create_ast_node_pair(result, create_ast_node_nil())); } ++(*index_in_text); + ++parser_col; eat_whitespace(text, index_in_text); // if there was actually nothing in the list, return nil if (text[(*index_in_text)] == ')') { ++(*index_in_text); + ++parser_col; return create_ast_node_nil(); } @@ -236,16 +260,18 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { eat_until_code(text, index_in_text); if (text[(*index_in_text)] == '\0') { - create_error(Error_Type_Unexpected_Eof, create_source_code_location(parser_file, parser_line)); + create_error(Error_Type_Unexpected_Eof, create_source_code_location(parser_file, parser_line, parser_col)); return nullptr; } if (text[(*index_in_text)] == ')') { head->value.pair->rest = create_ast_node_nil(); + ++parser_col; ++(*index_in_text); break; } else if (text[(*index_in_text)] == '.') { + ++parser_col; ++(*index_in_text); eat_until_code(text, index_in_text); @@ -257,7 +283,8 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { eat_until_code(text, index_in_text); if (text[(*index_in_text)] != ')') - create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line)); + create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line, parser_col)); + ++parser_col; ++(*index_in_text); break; } else { @@ -269,6 +296,10 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { } Ast_Node* parse_single_expression(char* text) { + parser_file = "stdin"; + parser_line = 1; + parser_col = 1; + int index_in_text = 0; Ast_Node* result; eat_until_code(text, &index_in_text); @@ -283,13 +314,16 @@ Ast_Node* parse_single_expression(char* text) { eat_until_code(text, &index_in_text); if (text[(index_in_text)] == '\0') return result; - create_error(Error_Type_Trailing_Garbage, create_source_code_location(parser_file, parser_line)); + create_error(Error_Type_Trailing_Garbage, create_source_code_location(parser_file, parser_line, parser_col)); return nullptr; } Ast_Node_Array_List* parse_program(char* file_name, char* text) { parser_file = (char*)malloc(strlen(file_name) * sizeof(char) + 1); strcpy(parser_file, file_name); + parser_line = 1; + parser_col = 0; + Ast_Node_Array_List* program = create_Ast_Node_Array_List(16); int index_in_text = 0; @@ -312,9 +346,11 @@ Ast_Node_Array_List* parse_program(char* file_name, char* text) { } break; default: /* syntax error */ - create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line)); + create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line, parser_col)); return nullptr; } } return program; } + +#undef inject_scl