diff --git a/lc.c b/lc.c index d8e8426..529abad 100644 --- a/lc.c +++ b/lc.c @@ -150,6 +150,14 @@ void print_ast(ast_node *node, int depth) { m = m->next; } break; + case NODE_ENUM: + printf("Enum: %.*s\n", (int)node->expr.enm.name_len, node->expr.enm.name); + variant *v = node->expr.enm.variants; + while (v) { + printf("\t%.*s\n", (int)v->name_len, v->name); + v = v->next; + } + break; case NODE_IF: printf("If:\n"); print_ast(node->expr.whle.condition, depth + 1); diff --git a/parser.c b/parser.c index 02029d7..5ac45cb 100644 --- a/parser.c +++ b/parser.c @@ -727,6 +727,91 @@ static member *parse_member(parser *p) return m; } +static variant *parse_variant(parser *p) +{ + if (!match_peek(p, TOKEN_IDENTIFIER)) { + error(p, "expected identifier."); + return NULL; + } + + variant *v = arena_alloc(p->allocator, sizeof(variant)); + v->name = peek(p)->lexeme; + v->name_len = peek(p)->lexeme_len; + advance(p); + + if (match(p, TOKEN_EQ)) { + v->value = parse_factor(p); + if (!v->value) { + error(p, "expected integer."); + return NULL; + } + + if (v->value->type != NODE_INTEGER) { + error(p, "expected integer."); + return NULL; + } + } + + return v; +} + +static ast_node *parse_enum(parser *p) +{ + ast_node *enm = arena_alloc(p->allocator, sizeof(ast_node)); + enm->type = NODE_ENUM; + if (match_peek(p, TOKEN_IDENTIFIER)) { + /* Named enum */ + enm->expr.enm.name = peek(p)->lexeme; + enm->expr.enm.name_len = peek(p)->lexeme_len; + advance(p); + } else if (!match_peek(p, TOKEN_LCURLY)) { + error(p, "expected identifier or `{`."); + return NULL; + } else { + enm->expr.enm.name = NULL; + enm->expr.enm.name_len = 0; + } + + if (!match(p, TOKEN_LCURLY)) { + error(p, "expected `{`."); + return NULL; + } + + variant *prev = parse_variant(p); + variant *head = prev; + enm->expr.enm.variants = head; + if (!prev) { + error(p, "invalid enum definition. Enums should contain at least 1 variant."); + return NULL; + } + if (!match(p, TOKEN_COMMA)) { + if (!match(p, TOKEN_RCURLY)) { + error(p, "expected `,`."); + return NULL; + } else { + return enm; + } + } + while (!match(p, TOKEN_RCURLY)) { + variant *current = parse_variant(p); + if (!current) { + error(p, "expected variant definition."); + return NULL; + } + prev->next = current; + if (!match(p, TOKEN_COMMA)) { + if (!match_peek(p, TOKEN_RCURLY)) { + error(p, "expected `,`."); + return NULL; + } + } + + prev = current; + } + + return enm; +} + static ast_node *parse_struct(parser *p) { ast_node *structure = arena_alloc(p->allocator, sizeof(ast_node)); @@ -917,6 +1002,10 @@ static ast_node *parse_statement(parser *p) { return parse_struct(p); } + else if (match(p, TOKEN_ENUM)) + { + return parse_enum(p); + } else if (match(p, TOKEN_UNION)) { ast_node *u = parse_struct(p); diff --git a/parser.h b/parser.h index 2fa02b8..837bf70 100644 --- a/parser.h +++ b/parser.h @@ -64,6 +64,13 @@ typedef struct { member *params; } function; +typedef struct _variant { + struct _ast_node *value; + char *name; + usize name_len; + struct _variant *next; +} variant; + typedef enum { NODE_IDENTIFIER, NODE_INTEGER, @@ -184,6 +191,11 @@ typedef struct _ast_node { char *name; usize name_len; } structure; + struct { + variant *variants; + char *name; + usize name_len; + } enm; // enum } expr; } ast_node; diff --git a/test.c b/test.c index 3aebb36..d2ce481 100644 --- a/test.c +++ b/test.c @@ -1,3 +1,5 @@ -if a == x { - printf("hello"); +enum { + a = 3, + b, + c }