Commit c627f9ea18

Andrew Kelley <superjoe30@gmail.com>
2017-12-19 07:19:49
wip bring back export keyword
1 parent 1fdebc1
doc/langref.html.in
@@ -5819,9 +5819,11 @@ TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
 
 ErrorValueDecl = "error" Symbol ";"
 
-GlobalVarDecl = VariableDeclaration ";"
+GlobalVarDecl = option("export") VariableDeclaration ";"
 
-VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression
+LocalVarDecl = option("comptime") VariableDeclaration
+
+VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression
 
 ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
 
@@ -5831,9 +5833,9 @@ UseDecl = "use" Expression ";"
 
 ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
 
-FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr)
+FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr)
 
-FnDef = option("inline" | "extern") FnProto Block
+FnDef = option("inline" | "export") FnProto Block
 
 ParamDeclList = "(" list(ParamDecl, ",") ")"
 
@@ -5841,7 +5843,7 @@ ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
 
 Block = "{" many(Statement) option(Expression) "}"
 
-Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
+Statement = Label | LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
 
 Label = Symbol ":"
 
@@ -5947,7 +5949,7 @@ StructLiteralField = "." Symbol "=" Expression
 
 PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
 
-PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
+PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl
 
 ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr
 
src/all_types.hpp
@@ -315,12 +315,6 @@ struct TldVar {
     VariableTableEntry *var;
     Buf *extern_lib_name;
     Buf *section_name;
-
-    size_t export_count;
-    union {
-        TldExport *tld; // if export_count == 1
-        TldExport **tld_list; // if export_count > 1
-    } export_data;
 };
 
 struct TldFn {
@@ -428,6 +422,7 @@ struct AstNodeFnProto {
     AstNode *return_type;
     bool is_var_args;
     bool is_extern;
+    bool is_export;
     bool is_inline;
     CallingConvention cc;
     AstNode *fn_def_node;
@@ -485,7 +480,8 @@ struct AstNodeVariableDeclaration {
     VisibMod visib_mod;
     Buf *symbol;
     bool is_const;
-    bool is_inline;
+    bool is_comptime;
+    bool is_export;
     bool is_extern;
     // one or both of type and expr will be non null
     AstNode *type;
src/analyze.cpp
@@ -1062,7 +1062,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
     AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
 
     if (fn_proto->cc == CallingConventionUnspecified) {
-        bool extern_abi = fn_proto->is_extern;
+        bool extern_abi = fn_proto->is_extern || fn_proto->is_export;
         fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified;
     } else {
         fn_type_id->cc = fn_proto->cc;
@@ -2675,6 +2675,26 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) {
 }
 
 static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
+    bool is_export = false;
+    if (tld->id == TldIdVar) {
+        assert(tld->source_node->type == NodeTypeVariableDeclaration);
+        is_export = tld->source_node->data.variable_declaration.is_export;
+    } else if (tld->id == TldIdFn) {
+        assert(tld->source_node->type == NodeTypeFnProto);
+        is_export = tld->source_node->data.fn_proto.is_export;
+    }
+    if (is_export) {
+        g->resolve_queue.append(tld);
+
+        auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node);
+        if (entry) {
+            AstNode *other_source_node = entry->value;
+            ErrorMsg *msg = add_node_error(g, tld->source_node,
+                    buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name)));
+            add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here"));
+        }
+    }
+
     {
         auto entry = decls_scope->decl_table.put_unique(tld->name, tld);
         if (entry) {
@@ -3006,6 +3026,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
 
     bool is_const = var_decl->is_const;
     bool is_extern = var_decl->is_extern;
+    bool is_export = var_decl->is_export;
 
     TypeTableEntry *explicit_type = nullptr;
     if (var_decl->type) {
@@ -3013,8 +3034,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
         explicit_type = validate_var_type(g, var_decl->type, proposed_type);
     }
 
+    assert(!is_export || !is_extern);
+
     VarLinkage linkage;
-    if (is_extern) {
+    if (is_export) {
+        linkage = VarLinkageExport;
+    } else if (is_extern) {
         linkage = VarLinkageExternal;
     } else {
         linkage = VarLinkageInternal;
src/ir.cpp
@@ -5066,7 +5066,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
     bool is_const = variable_declaration->is_const;
     bool is_extern = variable_declaration->is_extern;
     IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node,
-        ir_should_inline(irb->exec, scope) || variable_declaration->is_inline);
+        ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime);
     VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol,
         is_const, is_const, is_shadowable, is_comptime);
     // we detect IrInstructionIdDeclVar in gen_block to make sure the next node
src/parser.cpp
@@ -676,7 +676,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
 }
 
 /*
-PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
+PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl
 KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
 */
 static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
@@ -791,13 +791,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo
     if (container_decl)
         return container_decl;
 
-    if (token->id == TokenIdKeywordExtern) {
-        *token_index += 1;
-        AstNode *node = ast_parse_fn_proto(pc, token_index, true, VisibModPrivate);
-        node->data.fn_proto.is_extern = true;
-        return node;
-    }
-
     if (!mandatory)
         return nullptr;
 
@@ -1534,38 +1527,20 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) {
 }
 
 /*
-VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression
+VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression
 */
 static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory,
-        VisibMod visib_mod)
+        VisibMod visib_mod, bool is_comptime, bool is_export)
 {
     Token *first_token = &pc->tokens->at(*token_index);
     Token *var_token;
 
     bool is_const;
-    bool is_comptime;
-    if (first_token->id == TokenIdKeywordCompTime) {
-        is_comptime = true;
-        var_token = &pc->tokens->at(*token_index + 1);
-
-        if (var_token->id == TokenIdKeywordVar) {
-            is_const = false;
-        } else if (var_token->id == TokenIdKeywordConst) {
-            is_const = true;
-        } else if (mandatory) {
-            ast_invalid_token_error(pc, var_token);
-        } else {
-            return nullptr;
-        }
-
-        *token_index += 2;
-    } else if (first_token->id == TokenIdKeywordVar) {
-        is_comptime = false;
+    if (first_token->id == TokenIdKeywordVar) {
         is_const = false;
         var_token = first_token;
         *token_index += 1;
     } else if (first_token->id == TokenIdKeywordConst) {
-        is_comptime = false;
         is_const = true;
         var_token = first_token;
         *token_index += 1;
@@ -1577,7 +1552,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to
 
     AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token);
 
-    node->data.variable_declaration.is_inline = is_comptime;
+    node->data.variable_declaration.is_comptime = is_comptime;
     node->data.variable_declaration.is_const = is_const;
     node->data.variable_declaration.visib_mod = visib_mod;
 
@@ -1620,6 +1595,50 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to
     return node;
 }
 
+/*
+GlobalVarDecl = option("export") VariableDeclaration ";"
+*/
+static AstNode *ast_parse_global_var_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) {
+    Token *first_token = &pc->tokens->at(*token_index);
+
+    bool is_export = false;;
+    if (first_token->id == TokenIdKeywordExport) {
+        *token_index += 1;
+        is_export = true;
+    }
+
+    AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, is_export);
+    if (node == nullptr) {
+        if (is_export) {
+            *token_index -= 1;
+        }
+        return nullptr;
+    }
+    return node;
+}
+
+/*
+LocalVarDecl = option("comptime") VariableDeclaration
+*/
+static AstNode *ast_parse_local_var_decl(ParseContext *pc, size_t *token_index) {
+    Token *first_token = &pc->tokens->at(*token_index);
+
+    bool is_comptime = false;;
+    if (first_token->id == TokenIdKeywordCompTime) {
+        *token_index += 1;
+        is_comptime = true;
+    }
+
+    AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate, is_comptime, false);
+    if (node == nullptr) {
+        if (is_comptime) {
+            *token_index -= 1;
+        }
+        return nullptr;
+    }
+    return node;
+}
+
 /*
 BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression
 */
@@ -2171,7 +2190,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
     for (;;) {
         AstNode *statement_node = ast_parse_label(pc, token_index, false);
         if (!statement_node)
-            statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate);
+            statement_node = ast_parse_local_var_decl(pc, token_index);
         if (!statement_node)
             statement_node = ast_parse_defer_expr(pc, token_index);
         if (!statement_node)
@@ -2213,13 +2232,14 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
 }
 
 /*
-FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr)
+FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("-&gt;" TypeExpr)
 */
 static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
     Token *first_token = &pc->tokens->at(*token_index);
     Token *fn_token;
 
     CallingConvention cc;
+    bool is_extern = false;
     if (first_token->id == TokenIdKeywordColdCC) {
         *token_index += 1;
         fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
@@ -2232,8 +2252,13 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
         *token_index += 1;
         fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
         cc = CallingConventionStdcall;
+    } else if (first_token->id == TokenIdKeywordExtern) {
+        *token_index += 1;
+        fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
+        cc = CallingConventionC;
     } else if (first_token->id == TokenIdKeywordFn) {
         fn_token = first_token;
+        is_extern = true;
         *token_index += 1;
         cc = CallingConventionUnspecified;
     } else if (mandatory) {
@@ -2246,6 +2271,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
     AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
     node->data.fn_proto.visib_mod = visib_mod;
     node->data.fn_proto.cc = cc;
+    node->data.fn_proto.is_extern = is_extern;
 
     Token *fn_name = &pc->tokens->at(*token_index);
 
@@ -2286,35 +2312,35 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
 }
 
 /*
-FnDef = option("inline" | "extern") FnProto Block
+FnDef = option("inline" | "export") FnProto Block
 */
 static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
     Token *first_token = &pc->tokens->at(*token_index);
     bool is_inline;
-    bool is_extern;
+    bool is_export;
     if (first_token->id == TokenIdKeywordInline) {
         *token_index += 1;
         is_inline = true;
-        is_extern = false;
-    } else if (first_token->id == TokenIdKeywordExtern) {
+        is_export = false;
+    } else if (first_token->id == TokenIdKeywordExport) {
         *token_index += 1;
-        is_extern = true;
+        is_export = true;
         is_inline = false;
     } else {
         is_inline = false;
-        is_extern = false;
+        is_export = false;
     }
 
     AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, visib_mod);
     if (!fn_proto) {
-        if (is_inline || is_extern) {
+        if (is_inline || is_export) {
             *token_index -= 1;
         }
         return nullptr;
     }
 
     fn_proto->data.fn_proto.is_inline = is_inline;
-    fn_proto->data.fn_proto.is_extern = is_extern;
+    fn_proto->data.fn_proto.is_export = is_export;
 
     Token *semi_token = &pc->tokens->at(*token_index);
     if (semi_token->id == TokenIdSemicolon) {
@@ -2360,7 +2386,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo
         return fn_proto_node;
     }
 
-    AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod);
+    AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, false);
     if (var_decl_node) {
         ast_eat_token(pc, token_index, TokenIdSemicolon);
 
@@ -2473,7 +2499,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
             continue;
         }
 
-        AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod);
+        AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod);
         if (var_decl_node) {
             ast_eat_token(pc, token_index, TokenIdSemicolon);
             node->data.container_decl.decls.append(var_decl_node);
@@ -2566,7 +2592,7 @@ static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index)
 
 /*
 TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl
-TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
+TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl)
 */
 static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList<AstNode *> *top_level_decls) {
     for (;;) {
@@ -2615,7 +2641,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig
             continue;
         }
 
-        AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod);
+        AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod);
         if (var_decl_node) {
             ast_eat_token(pc, token_index, TokenIdSemicolon);
             top_level_decls->append(var_decl_node);
src/tokenizer.cpp
@@ -119,6 +119,7 @@ static const struct ZigKeyword zig_keywords[] = {
     {"else", TokenIdKeywordElse},
     {"enum", TokenIdKeywordEnum},
     {"error", TokenIdKeywordError},
+    {"export", TokenIdKeywordExport},
     {"extern", TokenIdKeywordExtern},
     {"false", TokenIdKeywordFalse},
     {"fn", TokenIdKeywordFn},
@@ -1518,6 +1519,7 @@ const char * token_name(TokenId id) {
         case TokenIdKeywordElse: return "else";
         case TokenIdKeywordEnum: return "enum";
         case TokenIdKeywordError: return "error";
+        case TokenIdKeywordExport: return "export";
         case TokenIdKeywordExtern: return "extern";
         case TokenIdKeywordFalse: return "false";
         case TokenIdKeywordFn: return "fn";
src/tokenizer.hpp
@@ -59,6 +59,7 @@ enum TokenId {
     TokenIdKeywordElse,
     TokenIdKeywordEnum,
     TokenIdKeywordError,
+    TokenIdKeywordExport,
     TokenIdKeywordExtern,
     TokenIdKeywordFalse,
     TokenIdKeywordFn,