aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c109
1 files changed, 107 insertions, 2 deletions
diff --git a/src/parser.c b/src/parser.c
index 6bf2f1d..7c01c75 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -26,6 +26,11 @@ static i64 global_vars_offset = 0;
static Lexer *lexer_stack[LEXER_STACK_SIZE];
static i64 lexer_stack_count = 0;
+#define DEFINED_STRUCT_SIZE 128
+static Type *defined_structs[DEFINED_STRUCT_SIZE];
+static i64 defined_structs_count = 0;
+
+
Token do_assert_token(Token token, TokenType type, char *filename, int line)
{
if (token.type != type) {
@@ -43,6 +48,22 @@ Token do_assert_token(Token token, TokenType type, char *filename, int line)
* Some helpers
*/
+void push_struct_definition(Type *type)
+{
+ assert(defined_structs_count < DEFINED_STRUCT_SIZE);
+ defined_structs[defined_structs_count++] = type;
+}
+
+Type *find_custom_type_definition(Token *token)
+{
+ for (i64 i = 0; i < defined_structs_count; i++) {
+ if (strcmp(defined_structs[i]->struct_name, token->value.as_string) == 0) {
+ return defined_structs[i];
+ }
+ }
+ return NULL;
+}
+
void block_stack_push(Node *block)
{
assert(block_stack_count < BLOCK_STACK_SIZE);
@@ -164,7 +185,13 @@ Type *parse_type(Lexer *lexer)
Lexer_next(lexer);
type = type_new(TYPE_CHAR);
} else {
- die_location(token.loc, "Unexpected type found: %s", token_type_to_str(token.type));
+ assert_token(token, TOKEN_IDENTIFIER);
+ // TODO: Don't allow a type to contain itself.
+ // TODO: Don't allow a type to contain an array of itself.
+ type = find_custom_type_definition(&token);
+ if (!type)
+ die_location(token.loc, "Could not find what type `%s` is referencing", token.value.as_string);
+ Lexer_next(lexer);
}
for (;;) {
@@ -370,7 +397,7 @@ Node *parse_factor(Lexer *lexer)
expr = Node_new(OP_BWINV);
expr->unary_expr = parse_factor(lexer);
expr = handle_unary_expr_types(expr, &token);
-
+
// ++x is changed to (x = x + 1)
} else if (token.type == TOKEN_PLUSPLUS) {
Lexer_next(lexer);
@@ -454,6 +481,26 @@ Node *parse_factor(Lexer *lexer)
die_location(token.loc, "Post-incrementing is not supported\n");
} else if (token.type == TOKEN_MINUSMINUS) {
die_location(token.loc, "Post-decrementing is not supported\n");
+ } else if (token.type == TOKEN_DOT) {
+ // TODO: Pointer to struct
+ if (!is_struct_or_struct_ptr(expr->expr_type))
+ die_location(token.loc, "Cannot access member of non-struct type");
+
+ bool is_ptr = expr->expr_type->type == TYPE_PTR;
+ Type *struct_type = is_ptr ? expr->expr_type->ptr : expr->expr_type;
+ Lexer_next(lexer);
+ Token field_token = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER);
+ i64 index = find_field_index(struct_type, field_token.value.as_string);
+ if (index == -1)
+ die_location(field_token.loc, "Struct `%s` does not have a field named `%s`", type_to_str(struct_type), field_token.value.as_string);
+
+ Node *member = Node_new(OP_MEMBER);
+ member->expr_type = struct_type->fields.type[index];
+ member->member.expr = expr;
+ member->member.offset = struct_type->fields.offset[index];
+ member->member.is_ptr = (expr->expr_type->type == TYPE_PTR);
+ expr = member;
+
} else {
break;
}
@@ -683,6 +730,9 @@ void parse_func_args(Lexer *lexer, Node *func)
assert_token(Lexer_next(lexer), TOKEN_COLON);
Type *type = parse_type(lexer);
+ if (type->type == TYPE_STRUCT)
+ die_location(token.loc, "Structs cannot be passed as arguments, maybe pass a pointer?");
+
i64 new_count = func->func.num_args + 1;
func->func.args = realloc(func->func.args, sizeof(Variable) * new_count);
Variable *var = &func->func.args[func->func.num_args++];
@@ -763,6 +813,57 @@ Lexer *remove_lexer()
return lexer_stack[lexer_stack_count - 1];
}
+Type *parse_struct_declaration(Lexer *lexer, bool is_global) {
+ i64 prev_struct_count = defined_structs_count;
+
+ assert_token(Lexer_next(lexer), TOKEN_STRUCT);
+
+ Type *struct_type = type_new(TYPE_STRUCT);
+
+ Token token = Lexer_peek(lexer);
+ // For nested temporary structs we don't need a name
+ if (token.type != TOKEN_IDENTIFIER && is_global)
+ die_location(token.loc, "You need to specify a name for the struct defined globally.");
+
+ // But if they do provide one, we'll add it to the list of defined structs so they
+ // it can referenced internally.
+ bool has_name = false;
+ if (token.type == TOKEN_IDENTIFIER) {
+ struct_type->struct_name = token.value.as_string;
+ push_struct_definition(struct_type);
+ Lexer_next(lexer);
+ has_name = true;
+ }
+
+ assert_token(Lexer_next(lexer), TOKEN_OPEN_BRACE);
+
+ token = Lexer_peek(lexer);
+ while (token.type != TOKEN_CLOSE_BRACE) {
+ token = assert_token(Lexer_next(lexer), TOKEN_IDENTIFIER);
+ assert_token(Lexer_next(lexer), TOKEN_COLON);
+
+ // We want to allow nested temporary structs.
+ Type *type;
+ Token next = Lexer_peek(lexer);
+ if (next.type == TOKEN_STRUCT) {
+ type = parse_struct_declaration(lexer, false);
+ } else {
+ type = parse_type(lexer);
+ }
+
+ push_field(struct_type, token.value.as_string, type);
+ assert_token(Lexer_next(lexer), TOKEN_SEMICOLON);
+ token = Lexer_peek(lexer);
+ }
+ assert_token(Lexer_next(lexer), TOKEN_CLOSE_BRACE);
+
+ // If this is not being defined globally, we want to remove it from the namespace.
+ if (!is_global)
+ defined_structs_count = prev_struct_count;
+
+ return struct_type;
+}
+
Node *parse_program(Lexer *lexer)
{
initialize_builtins();
@@ -778,6 +879,8 @@ Node *parse_program(Lexer *lexer)
} else if (token.type == TOKEN_LET) {
Node *var_decl = parse_var_declaration(lexer);
Node_add_child(program, var_decl);
+ } else if (token.type == TOKEN_STRUCT) {
+ parse_struct_declaration(lexer, true);
} else if (token.type == TOKEN_IMPORT) {
// TODO: Handle circular imports
// TODO: Handle complex import graphs (#pragma once)
@@ -788,6 +891,8 @@ Node *parse_program(Lexer *lexer)
char *filename = token.value.as_string;
lexer = Lexer_new_open_file(filename);
push_new_lexer(lexer);
+ } else if (token.type == TOKEN_SEMICOLON) {
+ Lexer_next(lexer);
} else {
die_location(token.loc, "Unexpected token in parse_program: `%s`\n", token_type_to_str(token.type));
exit(1);