Commit 2bb2e61ee2
Changed files (4)
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
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) {
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);
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");
}
//////////////////////////////////////////////////////////////////////////////