diff options
| -rw-r--r-- | doc/langref.md | 164 | ||||
| -rw-r--r-- | src/analyze.cpp | 21 | ||||
| -rw-r--r-- | src/parser.cpp | 43 | ||||
| -rw-r--r-- | test/run_tests.cpp | 7 |
4 files changed, 138 insertions, 97 deletions
diff --git a/doc/langref.md b/doc/langref.md index 20d07bc32a..287db13056 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -3,153 +3,153 @@ ## Grammar ``` -Root : many(TopLevelDecl) "EOF" +Root = many(TopLevelDecl) "EOF" -TopLevelDecl : many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl) +TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl) -CImportDecl : "c_import" Block +CImportDecl = "c_import" Block -ErrorValueDecl : "error" "Symbol" ";" +ErrorValueDecl = "error" "Symbol" ";" -GlobalVarDecl : VariableDeclaration ";" +GlobalVarDecl = VariableDeclaration ";" -VariableDeclaration : ("var" | "const") "Symbol" option(":" PrefixOpExpression) "=" Expression +VariableDeclaration = ("var" | "const") "Symbol" option(":" PrefixOpExpression) "=" Expression -ContainerDecl : ("struct" | "enum") "Symbol" "{" many(StructMember) "}" +ContainerDecl = ("struct" | "enum") "Symbol" "{" many(StructMember) "}" -StructMember: many(Directive) option(VisibleMod) (StructField | FnDef) +StructMember = many(Directive) option(VisibleMod) (StructField | FnDef) -StructField : "Symbol" option(":" Expression) ",") +StructField = "Symbol" option(":" Expression) ",") -Import : "import" "String" ";" +Import = "import" "String" ";" -RootExportDecl : "export" "Symbol" "String" ";" +RootExportDecl = "export" "Symbol" "String" ";" -ExternDecl : "extern" FnProto ";" +ExternDecl = "extern" FnProto ";" -FnProto : "fn" "Symbol" ParamDeclList option("->" PrefixOpExpression) +FnProto = "fn" option("Symbol") ParamDeclList option("->" PrefixOpExpression) -Directive : "#" "Symbol" "(" "String" ")" +Directive = "#" "Symbol" "(" "String" ")" -VisibleMod : "pub" | "export" +VisibleMod = "pub" | "export" -FnDef : FnProto Block +FnDef = FnProto Block -ParamDeclList : "(" list(ParamDecl, ",") ")" +ParamDeclList = "(" list(ParamDecl, ",") ")" -ParamDecl : option("noalias") "Symbol" ":" PrefixOpExpression | "..." +ParamDecl = option("noalias") option("Symbol" ":") PrefixOpExpression | "..." -Block : "{" list(option(Statement), ";") "}" +Block = "{" list(option(Statement), ";") "}" -Statement : Label | VariableDeclaration ";" | NonBlockExpression ";" | BlockExpression +Statement = Label | VariableDeclaration ";" | NonBlockExpression ";" | BlockExpression -Label: "Symbol" ":" +Label = "Symbol" ":" -Expression : BlockExpression | NonBlockExpression +Expression = BlockExpression | NonBlockExpression -NonBlockExpression : ReturnExpression | AssignmentExpression +NonBlockExpression = ReturnExpression | AssignmentExpression -AsmExpression : "asm" option("volatile") "(" "String" option(AsmOutput) ")" +AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")" -AsmOutput : ":" list(AsmOutputItem, ",") option(AsmInput) +AsmOutput = ":" list(AsmOutputItem, ",") option(AsmInput) -AsmInput : ":" list(AsmInputItem, ",") option(AsmClobbers) +AsmInput = ":" list(AsmInputItem, ",") option(AsmClobbers) -AsmOutputItem : "[" "Symbol" "]" "String" "(" ("Symbol" | "->" PrefixOpExpression) ")" +AsmOutputItem = "[" "Symbol" "]" "String" "(" ("Symbol" | "->" PrefixOpExpression) ")" -AsmInputItem : "[" "Symbol" "]" "String" "(" Expression ")" +AsmInputItem = "[" "Symbol" "]" "String" "(" Expression ")" -AsmClobbers: ":" list("String", ",") +AsmClobbers= ":" list("String", ",") -UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression +UnwrapExpression = BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression -UnwrapMaybe : "??" BoolOrExpression +UnwrapMaybe = "??" BoolOrExpression -UnwrapError : "%%" option("|" "Symbol" "|") BoolOrExpression +UnwrapError = "%%" option("|" "Symbol" "|") BoolOrExpression -AssignmentExpression : UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression +AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression -AssignmentOperator : "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" +AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" -BlockExpression : IfExpression | Block | WhileExpression | ForExpression | SwitchExpression +BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression -SwitchExpression : "switch" "(" Expression ")" "{" many(SwitchProng) "}" +SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}" -SwitchProng : (list(SwitchItem, ",") | "else") option(":" "(" "Symbol" ")") "=>" Expression "," +SwitchProng = (list(SwitchItem, ",") | "else") option(":" "(" "Symbol" ")") "=>" Expression "," -SwitchItem : Expression | (Expression "..." Expression) +SwitchItem = Expression | (Expression "..." Expression) -WhileExpression : "while" "(" Expression ")" Expression +WhileExpression = "while" "(" Expression ")" Expression -ForExpression : "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expression +ForExpression = "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expression -BoolOrExpression : BoolAndExpression "||" BoolOrExpression | BoolAndExpression +BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression -ReturnExpression : option("%" | "?") "return" option(Expression) +ReturnExpression = option("%" | "?") "return" option(Expression) -IfExpression : IfVarExpression | IfBoolExpression +IfExpression = IfVarExpression | IfBoolExpression -IfBoolExpression : "if" "(" Expression ")" Expression option(Else) +IfBoolExpression = "if" "(" Expression ")" Expression option(Else) -IfVarExpression : "if" "(" ("const" | "var") "Symbol" option(":" PrefixOpExpression) "?=" Expression ")" Expression Option(Else) +IfVarExpression = "if" "(" ("const" | "var") "Symbol" option(":" PrefixOpExpression) "?=" Expression ")" Expression Option(Else) -Else : "else" Expression +Else = "else" Expression -BoolAndExpression : ComparisonExpression "&&" BoolAndExpression | ComparisonExpression +BoolAndExpression = ComparisonExpression "&&" BoolAndExpression | ComparisonExpression -ComparisonExpression : BinaryOrExpression ComparisonOperator BinaryOrExpression | BinaryOrExpression +ComparisonExpression = BinaryOrExpression ComparisonOperator BinaryOrExpression | BinaryOrExpression -ComparisonOperator : "==" | "!=" | "<" | ">" | "<=" | ">=" +ComparisonOperator = "==" | "!=" | "<" | ">" | "<=" | ">=" -BinaryOrExpression : BinaryXorExpression "|" BinaryOrExpression | BinaryXorExpression +BinaryOrExpression = BinaryXorExpression "|" BinaryOrExpression | BinaryXorExpression -BinaryXorExpression : BinaryAndExpression "^" BinaryXorExpression | BinaryAndExpression +BinaryXorExpression = BinaryAndExpression "^" BinaryXorExpression | BinaryAndExpression -BinaryAndExpression : BitShiftExpression "&" BinaryAndExpression | BitShiftExpression +BinaryAndExpression = BitShiftExpression "&" BinaryAndExpression | BitShiftExpression -BitShiftExpression : AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression +BitShiftExpression = AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression -BitShiftOperator : "<<" | ">>" +BitShiftOperator = "<<" | ">>" -AdditionExpression : MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression +AdditionExpression = MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression -AdditionOperator : "+" | "-" | "++" +AdditionOperator = "+" | "-" | "++" -MultiplyExpression : CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression +MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression -CurlySuffixExpression : PrefixOpExpression option(ContainerInitExpression) +CurlySuffixExpression = PrefixOpExpression option(ContainerInitExpression) -MultiplyOperator : "*" | "/" | "%" +MultiplyOperator = "*" | "/" | "%" -PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression +PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression -SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) +SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression) -FieldAccessExpression : "." "Symbol" +FieldAccessExpression = "." "Symbol" -FnCallExpression : "(" list(Expression, ",") ")" +FnCallExpression = "(" list(Expression, ",") ")" -ArrayAccessExpression : "[" Expression "]" +ArrayAccessExpression = "[" Expression "]" -SliceExpression : "[" Expression "..." option(Expression) "]" option("const") +SliceExpression = "[" Expression "..." option(Expression) "]" option("const") -ContainerInitExpression : "{" ContainerInitBody "}" +ContainerInitExpression = "{" ContainerInitBody "}" -ContainerInitBody : list(StructLiteralField, ",") | list(Expression, ",") +ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") -StructLiteralField : "." "Symbol" "=" Expression +StructLiteralField = "." "Symbol" "=" Expression -PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" +PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" -PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol") +PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol") -ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression +ArrayType = "[" option(Expression) "]" option("const") PrefixOpExpression -GotoExpression: "goto" "Symbol" +GotoExpression = "goto" "Symbol" -GroupedExpression : "(" Expression ")" +GroupedExpression = "(" Expression ")" -KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" +KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" ``` ## Operator Precedence @@ -204,9 +204,11 @@ c_ulonglong unsigned long long for ABI compatibility with C ``` ### Boolean Type + The boolean type has the name `bool` and represents either true or false. ### Function Type + TODO ### Fixed-Size Array Type @@ -222,6 +224,7 @@ A slice can be obtained with the slicing syntax: `array[start...end]` Example: `"aoeu"[0...2]` has type `[]u8`. ### Struct Type + TODO ### Enum Type @@ -296,34 +299,44 @@ Hex floating point TODO TODO ``` ### Identifiers + TODO ### Declarations + Declarations have type `void`. #### Function Declarations + TODO #### Variable Declarations + TODO #### Struct Declarations + TODO #### Enum Declarations + TODO ## Built-in Functions + Built-in functions are prefixed with `@`. ### Typeof + TODO ### Sizeof + TODO ### Overflow Arithmetic + Overflow arithmetic functions have defined behavior on overflow or underflow. TODO what is that behaviour? The functions take an integer (TODO float?) type, two variables of the specified type, and a pointer to a variable of the specified type where the result is stored. The functions return a boolean value: true of overflow/underflow occurred, false otherwise. @@ -336,10 +349,13 @@ bool mul_with_overflow(type, a: type, b: type, x: &type) *x = a * b ``` ### Memory Operations + TODO memset and memcpy ### Value Count + TODO ### Max and Min Value + TODO diff --git a/src/analyze.cpp b/src/analyze.cpp index 3e3bf2b5f3..c3d66a26f8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -457,6 +457,10 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t assert(node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &node->data.fn_proto; + if (fn_proto->skip) { + return; + } + TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); fn_table_entry->type_entry = fn_type; fn_type->data.fn.calling_convention = fn_table_entry->internal_linkage ? LLVMFastCallConv : LLVMCCallConv; @@ -932,6 +936,9 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *proto_node) { + if (proto_node->data.fn_proto.skip) { + return; + } AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node; AstNode *struct_node = proto_node->data.fn_proto.struct_node; bool is_extern = proto_node->data.fn_proto.is_extern; @@ -4307,6 +4314,10 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo buf_sprintf("byvalue struct parameters not yet supported on exported functions")); } + if (buf_len(¶m_decl->name) == 0) { + add_node_error(g, param_decl_node, buf_sprintf("missing parameter name")); + } + VariableTableEntry *var = add_local_var(g, param_decl_node, context, ¶m_decl->name, type, true); var->src_arg_index = i; param_decl_node->data.param_decl.variable = var; @@ -4682,6 +4693,15 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast } case NodeTypeFnProto: { + // if the name is missing, we immediately announce an error + Buf *name = &node->data.fn_proto.name; + if (buf_len(name) == 0) { + node->data.fn_proto.skip = true; + add_node_error(g, node, buf_sprintf("missing function name")); + break; + } + + // determine which other top level declarations this function prototype depends on. TopLevelDecl *decl_node = &node->data.fn_proto.top_level_decl; decl_node->deps.init(1); @@ -4692,7 +4712,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast } collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node); - Buf *name = &node->data.fn_proto.name; decl_node->name = name; decl_node->import = import; if (decl_node->deps.size() > 0) { diff --git a/src/parser.cpp b/src/parser.cpp index 170d579956..e717a18941 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -569,35 +569,33 @@ static void ast_parse_directives(ParseContext *pc, int *token_index, } /* -ParamDecl : option("noalias") "Symbol" ":" PrefixOpExpression | "..." +ParamDecl = option("noalias") option("Symbol" ":") PrefixOpExpression | "..." */ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) { - Token *first_token = &pc->tokens->at(*token_index); + Token *token = &pc->tokens->at(*token_index); - if (first_token->id == TokenIdEllipsis) { + if (token->id == TokenIdEllipsis) { *token_index += 1; return nullptr; } - AstNode *node = ast_create_node(pc, NodeTypeParamDecl, first_token); - Token *name_token; + AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token); - if (first_token->id == TokenIdKeywordNoAlias) { + if (token->id == TokenIdKeywordNoAlias) { node->data.param_decl.is_noalias = true; *token_index += 1; - name_token = ast_eat_token(pc, token_index, TokenIdSymbol); - } else if (first_token->id == TokenIdSymbol) { - name_token = first_token; - *token_index += 1; - } else { - ast_invalid_token_error(pc, first_token); + token = &pc->tokens->at(*token_index); } - ast_buf_from_token(pc, name_token, &node->data.param_decl.name); + buf_resize(&node->data.param_decl.name, 0); - Token *colon = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, colon, TokenIdColon); + if (token->id == TokenIdSymbol) { + Token *next_token = &pc->tokens->at(*token_index + 1); + if (next_token->id == TokenIdColon) { + ast_buf_from_token(pc, token, &node->data.param_decl.name); + *token_index += 2; + } + } node->data.param_decl.type = ast_parse_prefix_op_expr(pc, token_index, true); @@ -2179,7 +2177,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato } /* -FnProto : "fn" "Symbol" ParamDeclList option("->" PrefixOpExpression) +FnProto : "fn" option("Symbol") ParamDeclList option("->" PrefixOpExpression) */ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory, ZigList<AstNode*> *directives, VisibMod visib_mod) @@ -2200,11 +2198,12 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand node->data.fn_proto.directives = directives; Token *fn_name = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, fn_name, TokenIdSymbol); - - ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name); - + if (fn_name->id == TokenIdSymbol) { + *token_index += 1; + ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name); + } else { + buf_resize(&node->data.fn_proto.name, 0); + } ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index f41e44562a..940c92769c 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1859,6 +1859,13 @@ fn f(foo: Foo, index: i32) { const result = members[index](); } )SOURCE", 1, ".tmp_source.zig:21:34: error: expected 1 arguments, got 0"); + + add_compile_fail_case("missing function name and param name", R"SOURCE( +fn () {} +fn f(i32) {} + )SOURCE", 2, + ".tmp_source.zig:2:1: error: missing function name", + ".tmp_source.zig:3:6: error: missing parameter name"); } ////////////////////////////////////////////////////////////////////////////// |
