From d4b8852d784b6f180e5329efa8d418397ee7f1ef Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Jan 2016 11:48:54 -0700 Subject: [PATCH] parsing enum declarations --- doc/langref.md | 16 ++++-- src/analyze.cpp | 32 ++++++++--- src/codegen.cpp | 2 + src/parser.cpp | 135 ++++++++++++++++++++++++++++++++++++++++++++-- src/parser.hpp | 17 ++++++ src/tokenizer.cpp | 3 ++ src/tokenizer.hpp | 1 + 7 files changed, 190 insertions(+), 16 deletions(-) diff --git a/doc/langref.md b/doc/langref.md index c8cc3c588b..e6eca3005e 100644 --- a/doc/langref.md +++ b/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) diff --git a/src/analyze.cpp b/src/analyze.cpp index 5ad695384b..be5d9b035c 100644 --- a/src/analyze.cpp +++ b/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: diff --git a/src/codegen.cpp b/src/codegen.cpp index 87a3b35107..4df4960596 100644 --- a/src/codegen.cpp +++ b/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(); diff --git a/src/parser.cpp b/src/parser.cpp index 31f9aadcd8..bcdb58b545 100644 --- a/src/parser.cpp +++ b/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 *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"); } diff --git a/src/parser.hpp b/src/parser.hpp index e5e4dec363..a0b6555664 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -59,6 +59,8 @@ enum NodeType { NodeTypeStructField, NodeTypeStructValueExpr, NodeTypeStructValueField, + NodeTypeEnumDecl, + NodeTypeEnumField, NodeTypeCompilerFnExpr, NodeTypeCompilerFnType, }; @@ -316,6 +318,19 @@ struct AstNodeStructField { ZigList *directives; }; +struct AstNodeEnumDecl { + Buf name; + ZigList fields; + ZigList *directives; + VisibMod visib_mod; +}; + +struct AstNodeEnumField { + Buf name; + ZigList 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; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a9b09df46a..b49166a126 100644 --- a/src/tokenizer.cpp +++ b/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"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index a7b7a77138..5c99d172a0 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -32,6 +32,7 @@ enum TokenId { TokenIdKeywordAsm, TokenIdKeywordVolatile, TokenIdKeywordStruct, + TokenIdKeywordEnum, TokenIdKeywordWhile, TokenIdKeywordContinue, TokenIdKeywordBreak,