different extern syntax and simplify parsing top level decls

This commit is contained in:
Andrew Kelley 2016-01-26 13:08:21 -07:00
parent bc89614996
commit 5afe473a86
8 changed files with 175 additions and 354 deletions

View File

@ -5,31 +5,33 @@
```
Root : many(TopLevelDecl) "EOF"
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
TopLevelDecl : many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl)
ErrorValueDecl : option(FnVisibleMod) "error" "Symbol"
CImportDecl : "c_import" Block
VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" option(":" PrefixOpExpression) "=" Expression
ErrorValueDecl : "error" "Symbol" ";"
ContainerDecl : many(Directive) option(FnVisibleMod) ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
GlobalVarDecl : VariableDeclaration ";"
StructMember: StructField | FnDecl
VariableDeclaration : ("var" | "const") "Symbol" option(":" PrefixOpExpression) "=" Expression
ContainerDecl : ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
StructMember: many(Directive) option(VisibleMod) (StructField | FnDef)
StructField : "Symbol" option(":" Expression) ",")
Import : many(Directive) "import" "String" ";"
Import : "import" "String" ";"
RootExportDecl : many(Directive) "export" "Symbol" "String" ";"
RootExportDecl : "export" "Symbol" "String" ";"
ExternBlock : many(Directive) "extern" "{" many(FnDecl) "}"
ExternDecl : "extern" FnProto ";"
FnProto : many(Directive) option(FnVisibleMod) "fn" "Symbol" ParamDeclList option("->" PrefixOpExpression)
FnProto : "fn" "Symbol" ParamDeclList option("->" PrefixOpExpression)
Directive : "#" "Symbol" "(" "String" ")"
FnVisibleMod : "pub" | "export"
FnDecl : FnProto ";"
VisibleMod : "pub" | "export"
FnDef : FnProto Block

View File

@ -14,7 +14,7 @@ syn keyword zigConditional if else switch
syn keyword zigRepeat while for
syn keyword zigConstant null undefined
syn keyword zigKeyword fn import
syn keyword zigKeyword fn import c_import
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 void unreachable type error
syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong

View File

@ -1,9 +1,7 @@
#link("c")
export executable "hello";
#link("c")
extern {
fn printf(__format: &const u8, ...) -> c_int;
}
extern fn printf(__format: &const u8, ...) -> c_int;
export fn main(argc: c_int, argv: &&u8) -> c_int {
printf(c"Hello, world!\n");

View File

@ -121,7 +121,6 @@ enum NodeType {
NodeTypeFnDecl,
NodeTypeParamDecl,
NodeTypeBlock,
NodeTypeExternBlock,
NodeTypeDirective,
NodeTypeReturnExpr,
NodeTypeVariableDeclaration,
@ -178,11 +177,10 @@ struct AstNodeFnProto {
ZigList<AstNode *> params;
AstNode *return_type;
bool is_var_args;
bool is_extern;
// populated by semantic analyzer:
// the extern block this fn proto is inside. can be null.
AstNode *extern_node;
// the struct decl node this fn proto is inside. can be null.
AstNode *struct_node;
// the function definition this fn proto is inside. can be null.
@ -247,6 +245,7 @@ struct AstNodeVariableDeclaration {
// one or both of type and expr will be non null
AstNode *type;
AstNode *expr;
ZigList<AstNode *> *directives;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
@ -255,8 +254,9 @@ struct AstNodeVariableDeclaration {
};
struct AstNodeErrorValueDecl {
VisibMod visib_mod;
Buf name;
VisibMod visib_mod;
ZigList<AstNode *> *directives;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
@ -378,11 +378,6 @@ struct AstNodeFieldAccessExpr {
StructValExprCodeGen resolved_struct_val_expr; // for enum values
};
struct AstNodeExternBlock {
ZigList<AstNode *> *directives;
ZigList<AstNode *> fn_decls;
};
struct AstNodeDirective {
Buf name;
Buf param;
@ -418,6 +413,7 @@ struct AstNodePrefixOpExpr {
struct AstNodeUse {
Buf path;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
// populated by semantic analyzer
ImportTableEntry *import;
@ -559,6 +555,7 @@ struct AstNodeStructField {
Buf name;
AstNode *type;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
};
struct AstNodeStringLiteral {
@ -697,7 +694,6 @@ struct AstNode {
AstNodeErrorValueDecl error_value_decl;
AstNodeBinOpExpr bin_op_expr;
AstNodeUnwrapErrorExpr unwrap_err_expr;
AstNodeExternBlock extern_block;
AstNodeDirective directive;
AstNodePrefixOpExpr prefix_op_expr;
AstNodeFnCallExpr fn_call_expr;

View File

@ -45,7 +45,6 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeBlock:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeReturnExpr:
case NodeTypeVariableDeclaration:
@ -897,8 +896,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
AstNode *proto_node)
{
AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node;
AstNode *extern_node = proto_node->data.fn_proto.extern_node;
AstNode *struct_node = proto_node->data.fn_proto.struct_node;
bool is_extern = proto_node->data.fn_proto.is_extern;
TypeTableEntry *struct_type;
if (struct_node) {
assert(struct_node->type == NodeTypeStructDecl);
@ -914,7 +913,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
auto entry = fn_table->maybe_get(proto_name);
bool skip = false;
bool is_internal = (proto_node->data.fn_proto.visib_mod != VisibModExport);
bool is_c_compat = !is_internal || extern_node;
bool is_c_compat = !is_internal || is_extern;
bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate);
if (entry) {
add_node_error(g, proto_node,
@ -922,7 +921,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
proto_node->data.fn_proto.skip = true;
skip = true;
}
if (!extern_node && proto_node->data.fn_proto.is_var_args) {
if (!is_extern && proto_node->data.fn_proto.is_var_args) {
add_node_error(g, proto_node,
buf_sprintf("variadic arguments only allowed in extern functions"));
}
@ -935,7 +934,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
fn_table_entry->proto_node = proto_node;
fn_table_entry->fn_def_node = fn_def_node;
fn_table_entry->internal_linkage = !is_c_compat;
fn_table_entry->is_extern = extern_node;
fn_table_entry->is_extern = is_extern;
fn_table_entry->label_table.init(8);
fn_table_entry->member_of_struct = struct_type;
@ -950,7 +949,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
g->fn_protos.append(fn_table_entry);
if (!extern_node) {
if (!is_extern) {
g->fn_defs.append(fn_table_entry);
}
@ -1021,19 +1020,6 @@ static void resolve_error_value_decl(CodeGen *g, ImportTableEntry *import, AstNo
static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) {
case NodeTypeExternBlock:
for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
AstNode *directive_node = node->data.extern_block.directives->at(i);
Buf *name = &directive_node->data.directive.name;
Buf *param = &directive_node->data.directive.param;
if (buf_eql_str(name, "link")) {
g->link_table.put(param, true);
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
}
}
break;
case NodeTypeFnProto:
preview_fn_proto(g, import, node);
break;
@ -4051,7 +4037,6 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeParamDecl:
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeExternBlock:
case NodeTypeFnDef:
case NodeTypeUse:
case NodeTypeLabel:
@ -4155,15 +4140,14 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
break;
}
case NodeTypeRootExportDecl:
case NodeTypeExternBlock:
case NodeTypeUse:
case NodeTypeVariableDeclaration:
case NodeTypeErrorValueDecl:
case NodeTypeFnProto:
// already took care of these
break;
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeFnProto:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeRoot:
@ -4350,7 +4334,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
break;
case NodeTypeVariableDeclaration:
case NodeTypeFnProto:
case NodeTypeExternBlock:
case NodeTypeRootExportDecl:
case NodeTypeFnDef:
case NodeTypeRoot:
@ -4453,16 +4436,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
break;
}
case NodeTypeExternBlock:
for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
assert(fn_decl->type == NodeTypeFnDecl);
AstNode *fn_proto = fn_decl->data.fn_decl.fn_proto;
fn_proto->data.fn_proto.extern_node = node;
detect_top_level_decl_deps(g, import, fn_proto);
}
resolve_top_level_decl(g, import, node);
break;
case NodeTypeFnDef:
node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;
detect_top_level_decl_deps(g, import, node->data.fn_def.fn_proto);
@ -4786,7 +4759,6 @@ Expr *get_resolved_expr(AstNode *node) {
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeUse:
case NodeTypeStructDecl:
@ -4832,7 +4804,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeBlock:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:

View File

@ -2249,7 +2249,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeUse:
case NodeTypeStructDecl:
@ -3001,18 +3000,6 @@ static void init(CodeGen *g, Buf *source_path) {
}
static bool directives_contains_link_libc(ZigList<AstNode*> *directives) {
for (int i = 0; i < directives->length; i += 1) {
AstNode *directive_node = directives->at(i);
if (buf_eql_str(&directive_node->data.directive.name, "link") &&
buf_eql_str(&directive_node->data.directive.param, "c"))
{
return true;
}
}
return false;
}
static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
char *dot1 = strstr(buf_ptr(buf), ".");
if (!dot1)
@ -3114,6 +3101,11 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
Buf *param = &directive_node->data.directive.param;
if (buf_eql_str(name, "version")) {
set_root_export_version(g, param, directive_node);
} else if (buf_eql_str(name, "link")) {
g->link_table.put(param, true);
if (buf_eql_str(param, "c")) {
g->link_libc = true;
}
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
@ -3204,8 +3196,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
if (buf_eql_str(proto_name, "main") && !is_private) {
g->have_exported_main = true;
}
} else if (top_level_decl->type == NodeTypeExternBlock) {
g->link_libc = directives_contains_link_libc(top_level_decl->data.extern_block.directives);
}
}

View File

@ -105,8 +105,6 @@ const char *node_type_str(NodeType node_type) {
return "ArrayAccessExpr";
case NodeTypeSliceExpr:
return "SliceExpr";
case NodeTypeExternBlock:
return "ExternBlock";
case NodeTypeDirective:
return "Directive";
case NodeTypeReturnExpr:
@ -258,15 +256,6 @@ void ast_print(AstNode *node, int indent) {
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
break;
}
case NodeTypeExternBlock:
{
fprintf(stderr, "%s\n", node_type_str(node->type));
for (int i = 0; i < node->data.extern_block.fn_decls.length; i += 1) {
AstNode *child = node->data.extern_block.fn_decls.at(i);
ast_print(child, indent + 2);
}
break;
}
case NodeTypeFnDecl:
fprintf(stderr, "%s\n", node_type_str(node->type));
ast_print(node->data.fn_decl.fn_proto, indent + 2);
@ -482,9 +471,9 @@ struct ParseContext {
Buf *buf;
AstNode *root;
ZigList<Token> *tokens;
ZigList<AstNode *> *directive_list;
ImportTableEntry *owner;
ErrColor err_color;
bool parsed_root_export;
uint32_t *next_node_index;
};
@ -2146,56 +2135,32 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
}
/*
VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
VariableDeclaration : ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
*/
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) {
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index);
VisibMod visib_mod;
bool is_const;
if (first_token->id == TokenIdKeywordPub) {
Token *next_token = &pc->tokens->at(*token_index + 1);
if (next_token->id == TokenIdKeywordVar ||
next_token->id == TokenIdKeywordConst)
{
visib_mod = VisibModPub;
is_const = (next_token->id == TokenIdKeywordConst);
*token_index += 2;
} else if (mandatory) {
ast_invalid_token_error(pc, next_token);
} else {
return nullptr;
}
} else if (first_token->id == TokenIdKeywordExport) {
Token *next_token = &pc->tokens->at(*token_index + 1);
if (next_token->id == TokenIdKeywordVar ||
next_token->id == TokenIdKeywordConst)
{
visib_mod = VisibModExport;
is_const = (next_token->id == TokenIdKeywordConst);
*token_index += 2;
} else if (mandatory) {
ast_invalid_token_error(pc, next_token);
} else {
return nullptr;
}
} else if (first_token->id == TokenIdKeywordVar ||
first_token->id == TokenIdKeywordConst)
{
visib_mod = VisibModPrivate;
is_const = (first_token->id == TokenIdKeywordConst);
*token_index += 1;
if (first_token->id == TokenIdKeywordVar) {
is_const = false;
} else if (first_token->id == TokenIdKeywordConst) {
is_const = true;
} else if (mandatory) {
ast_invalid_token_error(pc, first_token);
} else {
return nullptr;
}
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, first_token);
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.visib_mod = visib_mod;
node->data.variable_declaration.directives = directives;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
ast_buf_from_token(pc, name_token, &node->data.variable_declaration.symbol);
@ -2643,7 +2608,8 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
if (statement_node) {
semicolon_expected = false;
} else {
statement_node = ast_parse_variable_declaration_expr(pc, token_index, false);
statement_node = ast_parse_variable_declaration_expr(pc, token_index, false,
nullptr, VisibModPrivate);
if (statement_node) {
semicolon_expected = true;
} else {
@ -2677,47 +2643,25 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
}
/*
FnProto : many(Directive) option(FnVisibleMod) "fn" "Symbol" ParamDeclList option("->" PrefixOpExpression)
FnProto : "fn" "Symbol" ParamDeclList option("->" PrefixOpExpression)
*/
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) {
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
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 == TokenIdKeywordFn) {
visib_mod = VisibModPub;
*token_index += 2;
} else if (mandatory) {
ast_invalid_token_error(pc, first_token);
if (first_token->id != TokenIdKeywordFn) {
if (mandatory) {
ast_expect_token(pc, first_token, TokenIdKeywordFn);
} else {
return nullptr;
}
} else if (first_token->id == TokenIdKeywordExport) {
Token *next_token = &pc->tokens->at(*token_index + 1);
if (next_token->id == TokenIdKeywordFn) {
visib_mod = VisibModExport;
*token_index += 2;
} else if (mandatory) {
ast_invalid_token_error(pc, first_token);
} else {
return nullptr;
}
} else if (first_token->id == TokenIdKeywordFn) {
visib_mod = VisibModPrivate;
*token_index += 1;
} else if (mandatory) {
ast_invalid_token_error(pc, first_token);
} else {
return nullptr;
}
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeFnProto, first_token);
node->data.fn_proto.visib_mod = visib_mod;
node->data.fn_proto.directives = pc->directive_list;
pc->directive_list = nullptr;
node->data.fn_proto.directives = directives;
Token *fn_name = &pc->tokens->at(*token_index);
*token_index += 1;
@ -2743,107 +2687,59 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
/*
FnDef : FnProto Block
*/
static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory);
static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, directives, visib_mod);
if (!fn_proto)
return nullptr;
AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDef, fn_proto);
node->data.fn_def.fn_proto = fn_proto;
node->data.fn_def.body = ast_parse_block(pc, token_index, true);
normalize_parent_ptrs(node);
return node;
}
/*
FnDecl : FnProto token(Semicolon)
ExternDecl : "extern" FnProto ";"
*/
static AstNode *ast_parse_fn_decl(ParseContext *pc, int *token_index) {
AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, true);
AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDecl, fn_proto);
node->data.fn_decl.fn_proto = fn_proto;
Token *semicolon = &pc->tokens->at(*token_index);
*token_index += 1;
ast_expect_token(pc, semicolon, TokenIdSemicolon);
normalize_parent_ptrs(node);
return node;
}
/*
Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
*/
/*
ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
*/
static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool mandatory) {
static AstNode *ast_parse_extern_decl(ParseContext *pc, int *token_index, bool mandatory,
ZigList<AstNode *> *directives, VisibMod visib_mod)
{
Token *extern_kw = &pc->tokens->at(*token_index);
if (extern_kw->id != TokenIdKeywordExtern) {
if (mandatory)
if (mandatory) {
ast_invalid_token_error(pc, extern_kw);
else
return nullptr;
}
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeExternBlock, extern_kw);
node->data.extern_block.directives = pc->directive_list;
pc->directive_list = nullptr;
Token *l_brace = &pc->tokens->at(*token_index);
*token_index += 1;
ast_expect_token(pc, l_brace, TokenIdLBrace);
for (;;) {
Token *directive_token = &pc->tokens->at(*token_index);
assert(!pc->directive_list);
pc->directive_list = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, pc->directive_list);
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdRBrace) {
if (pc->directive_list->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
pc->directive_list = nullptr;
*token_index += 1;
normalize_parent_ptrs(node);
return node;
} else {
AstNode *child = ast_parse_fn_decl(pc, token_index);
node->data.extern_block.fn_decls.append(child);
return nullptr;
}
}
*token_index += 1;
AstNode *node = ast_parse_fn_proto(pc, token_index, true, directives, visib_mod);
zig_unreachable();
ast_eat_token(pc, token_index, TokenIdSemicolon);
node->data.fn_proto.is_extern = true;
normalize_parent_ptrs(node);
return node;
}
/*
RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
RootExportDecl : "export" "Symbol" "String" ";"
*/
static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, bool mandatory) {
assert(mandatory == false);
Token *export_kw = &pc->tokens->at(*token_index);
if (export_kw->id != TokenIdKeywordExport)
return nullptr;
Token *export_type = &pc->tokens->at(*token_index + 1);
static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index,
ZigList<AstNode*> *directives)
{
Token *export_type = &pc->tokens->at(*token_index);
if (export_type->id != TokenIdSymbol)
return nullptr;
*token_index += 2;
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeRootExportDecl, export_kw);
node->data.root_export_decl.directives = pc->directive_list;
pc->directive_list = nullptr;
AstNode *node = ast_create_node(pc, NodeTypeRootExportDecl, export_type);
node->data.root_export_decl.directives = directives;
ast_buf_from_token(pc, export_type, &node->data.root_export_decl.type);
@ -2862,11 +2758,13 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
}
/*
Use : many(Directive) token(Use) token(String) token(Semicolon)
Import : "import" "String" ";"
*/
static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
Token *use_kw = &pc->tokens->at(*token_index);
if (use_kw->id != TokenIdKeywordImport)
static AstNode *ast_parse_import(ParseContext *pc, int *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *import_kw = &pc->tokens->at(*token_index);
if (import_kw->id != TokenIdKeywordImport)
return nullptr;
*token_index += 1;
@ -2878,59 +2776,35 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
*token_index += 1;
ast_expect_token(pc, semicolon, TokenIdSemicolon);
AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
AstNode *node = ast_create_node(pc, NodeTypeUse, import_kw);
node->data.use.visib_mod = visib_mod;
node->data.use.directives = directives;
parse_string_literal(pc, use_name, &node->data.use.path, nullptr, nullptr);
node->data.use.directives = pc->directive_list;
pc->directive_list = nullptr;
normalize_parent_ptrs(node);
return node;
}
/*
ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
StructMember: StructField | FnDecl
StructField : token(Symbol) option(token(Colon) Expression) token(Comma))
ContainerDecl : ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
StructMember: many(Directive) option(VisibleMod) (StructField | FnDef)
StructField : "Symbol" option(":" Expression) ",")
*/
static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *first_token = &pc->tokens->at(*token_index);
VisibMod visib_mod;
ContainerKind kind;
if (first_token->id == TokenIdKeywordPub) {
Token *next_token = &pc->tokens->at(*token_index + 1);
if (next_token->id == TokenIdKeywordStruct ||
next_token->id == TokenIdKeywordEnum)
{
visib_mod = VisibModPub;
kind = (next_token->id == TokenIdKeywordStruct) ? ContainerKindStruct : ContainerKindEnum;
*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 == TokenIdKeywordStruct ||
next_token->id == TokenIdKeywordEnum)
{
visib_mod = VisibModExport;
kind = (next_token->id == TokenIdKeywordStruct) ? ContainerKindStruct : ContainerKindEnum;
*token_index += 2;
} else {
return nullptr;
}
} else if (first_token->id == TokenIdKeywordStruct ||
first_token->id == TokenIdKeywordEnum)
{
visib_mod = VisibModPrivate;
kind = (first_token->id == TokenIdKeywordStruct) ? ContainerKindStruct : ContainerKindEnum;
*token_index += 1;
if (first_token->id == TokenIdKeywordStruct) {
kind = ContainerKindStruct;
} else if (first_token->id == TokenIdKeywordEnum) {
kind = ContainerKindEnum;
} else {
return nullptr;
}
*token_index += 1;
Token *struct_name = ast_eat_token(pc, token_index, TokenIdSymbol);
@ -2938,19 +2812,28 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
node->data.struct_decl.kind = kind;
ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name);
node->data.struct_decl.visib_mod = visib_mod;
node->data.struct_decl.directives = directives;
ast_eat_token(pc, token_index, TokenIdLBrace);
node->data.struct_decl.directives = pc->directive_list;
pc->directive_list = nullptr;
for (;;) {
assert(!pc->directive_list);
pc->directive_list = allocate<ZigList<AstNode*>>(1);
Token *directive_token = &pc->tokens->at(*token_index);
ast_parse_directives(pc, token_index, pc->directive_list);
ZigList<AstNode *> *directive_list = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, directive_list);
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false);
Token *visib_tok = &pc->tokens->at(*token_index);
VisibMod visib_mod;
if (visib_tok->id == TokenIdKeywordPub) {
*token_index += 1;
visib_mod = VisibModPub;
} else if (visib_tok->id == TokenIdKeywordExport) {
*token_index += 1;
visib_mod = VisibModExport;
} else {
visib_mod = VisibModPrivate;
}
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, directive_list, visib_mod);
if (fn_def_node) {
node->data.struct_decl.fns.append(fn_def_node);
continue;
@ -2959,10 +2842,9 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdRBrace) {
if (pc->directive_list->length > 0) {
if (directive_list->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
pc->directive_list = nullptr;
*token_index += 1;
break;
@ -2970,8 +2852,8 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
*token_index += 1;
field_node->data.struct_field.directives = pc->directive_list;
pc->directive_list = nullptr;
field_node->data.struct_field.visib_mod = visib_mod;
field_node->data.struct_field.directives = directive_list;
ast_buf_from_token(pc, token, &field_node->data.struct_field.name);
@ -2997,47 +2879,24 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
}
/*
ErrorValueDecl : option(FnVisibleMod) "error" "Symbol"
ErrorValueDecl : "error" "Symbol" ";"
*/
static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, bool mandatory) {
static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
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 == TokenIdKeywordError) {
visib_mod = VisibModPub;
*token_index += 2;
} else if (mandatory) {
ast_invalid_token_error(pc, next_token);
} else {
return nullptr;
}
} else if (first_token->id == TokenIdKeywordExport) {
Token *next_token = &pc->tokens->at(*token_index + 1);
if (next_token->id == TokenIdKeywordError) {
visib_mod = VisibModExport;
*token_index += 2;
} else if (mandatory) {
ast_invalid_token_error(pc, next_token);
} else {
return nullptr;
}
} else if (first_token->id == TokenIdKeywordError) {
visib_mod = VisibModPrivate;
*token_index += 1;
} else if (mandatory) {
ast_invalid_token_error(pc, first_token);
} else {
if (first_token->id != TokenIdKeywordError) {
return nullptr;
}
*token_index += 1;
Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
ast_eat_token(pc, token_index, TokenIdSemicolon);
AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
node->data.error_value_decl.visib_mod = visib_mod;
node->data.error_value_decl.directives = directives;
ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name);
normalize_parent_ptrs(node);
@ -3045,63 +2904,79 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b
}
/*
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
TopLevelDecl : many(Directive) option(FnVisibleMod) (FnDef | ExternFnProto | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl | CImportDecl)
*/
static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) {
Token *directive_token = &pc->tokens->at(*token_index);
assert(!pc->directive_list);
pc->directive_list = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, pc->directive_list);
ZigList<AstNode *> *directives = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, directives);
AstNode *root_export_decl_node = ast_parse_root_export_decl(pc, token_index, false);
if (root_export_decl_node) {
top_level_decls->append(root_export_decl_node);
continue;
Token *visib_tok = &pc->tokens->at(*token_index);
VisibMod visib_mod;
if (visib_tok->id == TokenIdKeywordPub) {
*token_index += 1;
visib_mod = VisibModPub;
} else if (visib_tok->id == TokenIdKeywordExport) {
*token_index += 1;
visib_mod = VisibModExport;
} else {
visib_mod = VisibModPrivate;
}
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false);
bool try_to_parse_root_export = (visib_mod == VisibModExport && !pc->parsed_root_export);
pc->parsed_root_export = true;
if (try_to_parse_root_export) {
AstNode *root_export_decl_node = ast_parse_root_export_decl(pc, token_index, directives);
if (root_export_decl_node) {
top_level_decls->append(root_export_decl_node);
continue;
}
}
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, directives, visib_mod);
if (fn_def_node) {
top_level_decls->append(fn_def_node);
continue;
}
AstNode *extern_node = ast_parse_extern_block(pc, token_index, false);
if (extern_node) {
top_level_decls->append(extern_node);
AstNode *fn_proto_node = ast_parse_extern_decl(pc, token_index, false, directives, visib_mod);
if (fn_proto_node) {
top_level_decls->append(fn_proto_node);
continue;
}
AstNode *use_node = ast_parse_use(pc, token_index);
if (use_node) {
top_level_decls->append(use_node);
AstNode *import_node = ast_parse_import(pc, token_index, directives, visib_mod);
if (import_node) {
top_level_decls->append(import_node);
continue;
}
AstNode *struct_node = ast_parse_struct_decl(pc, token_index);
AstNode *struct_node = ast_parse_struct_decl(pc, token_index, directives, visib_mod);
if (struct_node) {
top_level_decls->append(struct_node);
continue;
}
if (pc->directive_list->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
pc->directive_list = nullptr;
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false);
AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false,
directives, visib_mod);
if (var_decl_node) {
ast_eat_token(pc, token_index, TokenIdSemicolon);
top_level_decls->append(var_decl_node);
continue;
}
AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, false);
AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, directives, visib_mod);
if (error_value_node) {
top_level_decls->append(error_value_node);
continue;
}
if (directives->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
return;
}
zig_unreachable();
@ -3175,10 +3050,6 @@ void normalize_parent_ptrs(AstNode *node) {
case NodeTypeBlock:
set_list_fields(&node->data.block.statements);
break;
case NodeTypeExternBlock:
set_list_fields(node->data.extern_block.directives);
set_list_fields(&node->data.extern_block.fn_decls);
break;
case NodeTypeDirective:
// none
break;

View File

@ -97,10 +97,8 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source
static void add_compiling_test_cases(void) {
add_simple_case("hello world with libc", R"SOURCE(
#link("c")
extern {
fn puts(s: &const u8) -> c_int;
}
export executable "test";
extern fn puts(s: &const u8) -> c_int;
export fn main(argc: c_int, argv: &&u8) -> c_int {
puts(c"Hello, world!");
return 0;
@ -482,9 +480,8 @@ pub fn main(args: [][]u8) -> %void {
add_simple_case("number literals", R"SOURCE(
#link("c")
extern {
fn printf(__format: &const u8, ...) -> c_int;
}
export executable "test";
extern fn printf(__format: &const u8, ...) -> c_int;
export fn main(argc: c_int, argv: &&u8) -> c_int {
printf(c"\n");
@ -1321,13 +1318,11 @@ fn a() {}
add_compile_fail_case("bad directive", R"SOURCE(
#bogus1("")
extern {
fn b();
}
extern fn b();
#bogus2("")
fn a() {}
)SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'",
".tmp_source.zig:6:1: error: invalid directive: 'bogus2'");
".tmp_source.zig:4:1: error: invalid directive: 'bogus2'");
add_compile_fail_case("unreachable with return", R"SOURCE(
fn a() -> unreachable {return;}
@ -1668,11 +1663,9 @@ fn f() {
)SOURCE", 1, ".tmp_source.zig:6:9: error: multiple else prongs in switch expression");
add_compile_fail_case("global variable initializer must be constant expression", R"SOURCE(
extern {
fn foo() -> i32;
}
extern fn foo() -> i32;
const x = foo();
)SOURCE", 1, ".tmp_source.zig:5:11: error: global variable initializer requires constant expression");
)SOURCE", 1, ".tmp_source.zig:3:11: error: global variable initializer requires constant expression");
add_compile_fail_case("non compile time string concatenation", R"SOURCE(
fn f(s: []u8) -> []u8 {