parser: allow missing fn name and missing param names

now these problems are caught in analyzer

this is for purpose of function type, see #14
This commit is contained in:
Andrew Kelley 2016-01-28 18:58:28 -07:00
parent ff028525e5
commit 2bb2e61ee2
4 changed files with 138 additions and 97 deletions

View File

@ -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

View File

@ -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(&param_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, &param_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) {

View File

@ -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);

View File

@ -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");
}
//////////////////////////////////////////////////////////////////////////////