Commit d4b8852d78

Andrew Kelley <superjoe30@gmail.com>
2016-01-10 19:48:54
parsing enum declarations
1 parent 75d5786
doc/langref.md
@@ -32,16 +32,24 @@ zig          |        C equivalent    | Description
 ```
 Root : many(TopLevelDecl) token(EOF)
 
-TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration
+TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration | EnumDecl
 
 VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
 
-StructDecl : many(Directive) option(FnVisibleMod) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
+StructDecl : many(Directive) option(FnVisibleMod) token(Struct) StructPayload
+
+StructPayload: token(Symbol) token(LBrace) many(StructMember) token(RBrace)
+
+EnumDecl : many(Directive) option(FnVisibleMod) token(Enum) token(Symbol) token(LBrace) many(EnumField) token(RBrace)
 
 StructMember: StructField | FnDecl
 
 StructField : token(Symbol) token(Colon) Type token(Comma)
 
+EnumField : (EnumDiscriminant | StructPayload) token(Comma)
+
+EnumDiscriminant : token(Symbol) option(token(Eq) Expression)
+
 Use : many(Directive) token(Use) token(String) token(Semicolon)
 
 RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
@@ -160,7 +168,9 @@ SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression)
 
 PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
 
-PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression)
+PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression) | NamespaceSymbol
+
+NamespaceSymbol : token(Symbol) token(ColonColon) token(Symbol)
 
 StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
 
src/analyze.cpp
@@ -63,6 +63,8 @@ static AstNode *first_executing_node(AstNode *node) {
         case NodeTypeAsmExpr:
         case NodeTypeStructDecl:
         case NodeTypeStructField:
+        case NodeTypeEnumDecl:
+        case NodeTypeEnumField:
         case NodeTypeStructValueExpr:
         case NodeTypeStructValueField:
         case NodeTypeWhileExpr:
@@ -894,6 +896,11 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
                 // struct member fns will get resolved independently
                 break;
             }
+        case NodeTypeEnumDecl:
+            {
+                zig_panic("TODO resolve enum decl");
+                break;
+            }
         case NodeTypeVariableDeclaration:
             {
                 VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
@@ -936,6 +943,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructField:
+        case NodeTypeEnumField:
         case NodeTypeStructValueExpr:
         case NodeTypeStructValueField:
         case NodeTypeCompilerFnExpr:
@@ -2490,6 +2498,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
         case NodeTypeLabel:
         case NodeTypeStructDecl:
         case NodeTypeStructField:
+        case NodeTypeEnumDecl:
+        case NodeTypeEnumField:
         case NodeTypeStructValueField:
         case NodeTypeCompilerFnExpr:
             zig_unreachable();
@@ -2589,13 +2599,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
         case NodeTypeFnDef:
             analyze_top_level_fn_def(g, import, node);
             break;
-        case NodeTypeRootExportDecl:
-        case NodeTypeExternBlock:
-            // already looked at these in the preview pass
-            break;
-        case NodeTypeUse:
-            // already took care of this
-            break;
         case NodeTypeStructDecl:
             {
                 for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
@@ -2604,8 +2607,12 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
                 }
                 break;
             }
+        case NodeTypeRootExportDecl:
+        case NodeTypeExternBlock:
+        case NodeTypeUse:
+        case NodeTypeEnumDecl:
         case NodeTypeVariableDeclaration:
-            // handled in resolve phase
+            // already took care of these
             break;
         case NodeTypeDirective:
         case NodeTypeParamDecl:
@@ -2639,6 +2646,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructField:
+        case NodeTypeEnumField:
         case NodeTypeStructValueExpr:
         case NodeTypeStructValueField:
         case NodeTypeCompilerFnExpr:
@@ -2772,6 +2780,8 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
         case NodeTypeLabel:
         case NodeTypeStructDecl:
         case NodeTypeStructField:
+        case NodeTypeEnumDecl:
+        case NodeTypeEnumField:
         case NodeTypeStructValueField:
             zig_unreachable();
     }
@@ -2879,6 +2889,11 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
                     detect_top_level_decl_deps(g, import, fn_def_node);
                 }
 
+                break;
+            }
+        case NodeTypeEnumDecl:
+            {
+                zig_panic("TODO detect enum top level decl deps");
                 break;
             }
         case NodeTypeExternBlock:
@@ -2974,6 +2989,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructField:
+        case NodeTypeEnumField:
         case NodeTypeStructValueExpr:
         case NodeTypeStructValueField:
         case NodeTypeCompilerFnExpr:
src/codegen.cpp
@@ -1754,6 +1754,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
         case NodeTypeUse:
         case NodeTypeStructDecl:
         case NodeTypeStructField:
+        case NodeTypeEnumDecl:
+        case NodeTypeEnumField:
         case NodeTypeStructValueField:
         case NodeTypeCompilerFnExpr:
             zig_unreachable();
src/parser.cpp
@@ -144,6 +144,10 @@ const char *node_type_str(NodeType node_type) {
             return "StructDecl";
         case NodeTypeStructField:
             return "StructField";
+        case NodeTypeEnumDecl:
+            return "EnumDecl";
+        case NodeTypeEnumField:
+            return "EnumField";
         case NodeTypeStructValueExpr:
             return "StructValueExpr";
         case NodeTypeStructValueField:
@@ -429,6 +433,24 @@ void ast_print(AstNode *node, int indent) {
             fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name));
             ast_print(node->data.struct_field.type, indent + 2);
             break;
+        case NodeTypeEnumDecl:
+            fprintf(stderr, "%s '%s'\n",
+                    node_type_str(node->type), buf_ptr(&node->data.enum_decl.name));
+            for (int i = 0; i < node->data.enum_decl.fields.length; i += 1) {
+                AstNode *child = node->data.enum_decl.fields.at(i);
+                ast_print(child, indent + 2);
+            }
+            break;
+        case NodeTypeEnumField:
+            fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.enum_field.name));
+            if (node->data.enum_field.val_expr) {
+                ast_print(node->data.enum_field.val_expr, indent + 2);
+            }
+            for (int i = 0; i < node->data.enum_field.fields.length; i += 1) {
+                AstNode *child = node->data.enum_field.fields.at(i);
+                ast_print(child, indent + 2);
+            }
+            break;
         case NodeTypeStructValueExpr:
             fprintf(stderr, "%s\n", node_type_str(node->type));
             ast_print(node->data.struct_val_expr.type, indent + 2);
@@ -2705,7 +2727,106 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
 }
 
 /*
-StructDecl : many(Directive) option(FnVisibleMod) token(Struct) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
+EnumDecl : many(Directive) option(FnVisibleMod) token(Enum) token(Symbol) token(LBrace) many(EnumField) token(RBrace)
+EnumField : (EnumDiscriminant | StructPayload) token(Comma)
+EnumDiscriminant : token(Symbol) option(token(Eq) Expression)
+*/
+static AstNode *ast_parse_enum_decl(ParseContext *pc, int *token_index) {
+    Token *first_token = &pc->tokens->at(*token_index);
+
+    VisibMod visib_mod;
+    if (first_token->id == TokenIdKeywordPub) {
+        Token *next_token = &pc->tokens->at(*token_index + 1);
+        if (next_token->id == TokenIdKeywordEnum) {
+            visib_mod = VisibModPub;
+            *token_index += 2;
+        } else {
+            return nullptr;
+        }
+    } else if (first_token->id == TokenIdKeywordExport) {
+        Token *next_token = &pc->tokens->at(*token_index + 1);
+        if (next_token->id == TokenIdKeywordEnum) {
+            visib_mod = VisibModExport;
+            *token_index += 2;
+        } else {
+            return nullptr;
+        }
+    } else if (first_token->id == TokenIdKeywordEnum) {
+        visib_mod = VisibModPrivate;
+        *token_index += 1;
+    } else {
+        return nullptr;
+    }
+
+    Token *enum_name = ast_eat_token(pc, token_index, TokenIdSymbol);
+    AstNode *node = ast_create_node(pc, NodeTypeEnumDecl, first_token);
+    ast_buf_from_token(pc, enum_name, &node->data.enum_decl.name);
+    node->data.enum_decl.visib_mod = visib_mod;
+
+    node->data.enum_decl.directives = pc->directive_list;
+    pc->directive_list = nullptr;
+
+    ast_eat_token(pc, token_index, TokenIdLBrace);
+
+    for (;;) {
+        Token *token = &pc->tokens->at(*token_index);
+
+        if (token->id == TokenIdRBrace) {
+            *token_index += 1;
+            break;
+        } else if (token->id == TokenIdSymbol) {
+            AstNode *field_node = ast_create_node(pc, NodeTypeEnumField, token);
+            *token_index += 1;
+
+            ast_buf_from_token(pc, token, &field_node->data.enum_field.name);
+
+            Token *eq_tok = &pc->tokens->at(*token_index);
+            if (eq_tok->id == TokenIdEq) {
+                *token_index += 1;
+
+                field_node->data.enum_field.val_expr = ast_parse_expression(pc, token_index, true);
+            } else if (eq_tok->id == TokenIdLBrace) {
+                *token_index += 1;
+
+                for (;;) {
+                    Token *token = &pc->tokens->at(*token_index);
+
+                    if (token->id == TokenIdRBrace) {
+                        *token_index += 1;
+                        break;
+                    } else if (token->id == TokenIdSymbol) {
+                        AstNode *sub_field_node = ast_create_node(pc, NodeTypeStructField, token);
+                        *token_index += 1;
+
+                        ast_buf_from_token(pc, token, &sub_field_node->data.struct_field.name);
+
+                        ast_eat_token(pc, token_index, TokenIdColon);
+
+                        sub_field_node->data.struct_field.type = ast_parse_type(pc, token_index);
+
+                        ast_eat_token(pc, token_index, TokenIdComma);
+
+                        field_node->data.enum_decl.fields.append(sub_field_node);
+                    } else {
+                        ast_invalid_token_error(pc, token);
+                    }
+                }
+            }
+
+            ast_eat_token(pc, token_index, TokenIdComma);
+
+            node->data.enum_decl.fields.append(field_node);
+        } else {
+            ast_invalid_token_error(pc, token);
+        }
+    }
+
+    return node;
+}
+
+/*
+StructDecl : many(Directive) option(FnVisibleMod) token(Struct) StructPayload
+StructPayload: token(Symbol) token(LBrace) many(StructMember) token(RBrace)
 StructMember: StructField | FnDecl
 StructField : token(Symbol) token(Colon) Type token(Comma)
 */
@@ -2737,9 +2858,7 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
         return nullptr;
     }
 
-    Token *struct_name = &pc->tokens->at(*token_index);
-    *token_index += 1;
-    ast_expect_token(pc, struct_name, TokenIdSymbol);
+    Token *struct_name = ast_eat_token(pc, token_index, TokenIdSymbol);
 
     AstNode *node = ast_create_node(pc, NodeTypeStructDecl, first_token);
     ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name);
@@ -2798,7 +2917,7 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
 }
 
 /*
-TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration
+TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration | EnumDecl
 */
 static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
     for (;;) {
@@ -2837,6 +2956,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
             continue;
         }
 
+        AstNode *enum_node = ast_parse_enum_decl(pc, token_index);
+        if (enum_node) {
+            top_level_decls->append(enum_node);
+            continue;
+        }
+
         if (pc->directive_list->length > 0) {
             ast_error(pc, directive_token, "invalid directive");
         }
src/parser.hpp
@@ -59,6 +59,8 @@ enum NodeType {
     NodeTypeStructField,
     NodeTypeStructValueExpr,
     NodeTypeStructValueField,
+    NodeTypeEnumDecl,
+    NodeTypeEnumField,
     NodeTypeCompilerFnExpr,
     NodeTypeCompilerFnType,
 };
@@ -316,6 +318,19 @@ struct AstNodeStructField {
     ZigList<AstNode *> *directives;
 };
 
+struct AstNodeEnumDecl {
+    Buf name;
+    ZigList<AstNode *> fields;
+    ZigList<AstNode *> *directives;
+    VisibMod visib_mod;
+};
+
+struct AstNodeEnumField {
+    Buf name;
+    ZigList<AstNode *> fields; // length 0 means simple enum
+    AstNode *val_expr;
+};
+
 struct AstNodeStringLiteral {
     Buf buf;
     bool c;
@@ -411,6 +426,8 @@ struct AstNode {
         AstNodeFieldAccessExpr field_access_expr;
         AstNodeStructDecl struct_decl;
         AstNodeStructField struct_field;
+        AstNodeEnumDecl enum_decl;
+        AstNodeEnumField enum_field;
         AstNodeStringLiteral string_literal;
         AstNodeCharLiteral char_literal;
         AstNodeNumberLiteral number_literal;
src/tokenizer.cpp
@@ -235,6 +235,8 @@ static void end_token(Tokenize *t) {
         t->cur_tok->id = TokenIdKeywordAsm;
     } else if (mem_eql_str(token_mem, token_len, "struct")) {
         t->cur_tok->id = TokenIdKeywordStruct;
+    } else if (mem_eql_str(token_mem, token_len, "enum")) {
+        t->cur_tok->id = TokenIdKeywordEnum;
     } else if (mem_eql_str(token_mem, token_len, "while")) {
         t->cur_tok->id = TokenIdKeywordWhile;
     } else if (mem_eql_str(token_mem, token_len, "continue")) {
@@ -1021,6 +1023,7 @@ static const char * token_name(Token *token) {
         case TokenIdKeywordVolatile: return "Volatile";
         case TokenIdKeywordAsm: return "Asm";
         case TokenIdKeywordStruct: return "Struct";
+        case TokenIdKeywordEnum: return "Enum";
         case TokenIdKeywordWhile: return "While";
         case TokenIdKeywordContinue: return "Continue";
         case TokenIdKeywordBreak: return "Break";
src/tokenizer.hpp
@@ -32,6 +32,7 @@ enum TokenId {
     TokenIdKeywordAsm,
     TokenIdKeywordVolatile,
     TokenIdKeywordStruct,
+    TokenIdKeywordEnum,
     TokenIdKeywordWhile,
     TokenIdKeywordContinue,
     TokenIdKeywordBreak,