Commit 0311b35a21

Andrew Kelley <superjoe30@gmail.com>
2016-01-16 01:40:12
reduce precedence of {} suffix operator
this makes []u8 {1, 2, 3, 4} work for array literal
1 parent 74b1665
Changed files (2)
doc/langref.md
@@ -34,7 +34,7 @@ Root : many(TopLevelDecl) token(EOF)
 
 TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | ContainerDecl | VariableDeclaration
 
-VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))
+VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) PrefixOpExpression option(token(Eq) Expression))
 
 ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
 
@@ -48,7 +48,7 @@ RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token
 
 ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
 
-FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(UnwrapMaybeExpression)
+FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(PrefixOpExpression)
 
 Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
 
@@ -60,7 +60,7 @@ FnDef : FnProto token(FatArrow) Block
 
 ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
 
-ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)
+ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) PrefixOpExpression | token(Ellipsis)
 
 Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
 
@@ -78,7 +78,7 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
 
 AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
 
-AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) UnwrapMaybeExpression) token(RParen)
+AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) PrefixOpExpression) token(RParen)
 
 AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
 
@@ -102,7 +102,7 @@ IfExpression : IfVarExpression | IfBoolExpression
 
 IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
 
-IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) UnwrapMaybeExpression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
+IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) PrefixOpExpression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
 
 Else : token(Else) Expression
 
@@ -126,13 +126,15 @@ AdditionExpression : MultiplyExpression AdditionOperator AdditionExpression | Mu
 
 AdditionOperator : token(Plus) | token(Minus)
 
-MultiplyExpression : PrefixOpExpression MultiplyOperator MultiplyExpression | PrefixOpExpression
+MultiplyExpression : CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression
+
+CurlySuffixExpression : PrefixOpExpression option(ContainerInitExpression)
 
 MultiplyOperator : token(Star) | token(Slash) | token(Percent)
 
 PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
 
-SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
+SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
 
 FieldAccessExpression : token(Dot) token(Symbol)
 
@@ -152,7 +154,7 @@ PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampers
 
 PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression
 
-ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) UnwrapMaybeExpression
+ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) PrefixOpExpression
 
 GotoExpression: token(Goto) token(Symbol)
 
@@ -164,9 +166,9 @@ KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token
 ## Operator Precedence
 
 ```
-x() x[] x{} x.y
-!x -x ~x *x &x
-as
+x() x[] x.y
+!x -x ~x *x &x ?x
+x{}
 * / %
 + -
 << >>
src/parser.cpp
@@ -903,6 +903,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
 static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
 static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);
 static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory);
+static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);
 
 static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
     if (token->id == token_id) {
@@ -998,7 +999,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
     *token_index += 1;
     ast_expect_token(pc, colon, TokenIdColon);
 
-    node->data.param_decl.type = ast_parse_unwrap_maybe_expr(pc, token_index, true);
+    node->data.param_decl.type = ast_parse_prefix_op_expr(pc, token_index, true);
 
     return node;
 }
@@ -1114,7 +1115,7 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bo
         node->data.array_type.is_const = true;
     }
 
-    node->data.array_type.child_type = ast_parse_unwrap_maybe_expr(pc, token_index, true);
+    node->data.array_type.child_type = ast_parse_prefix_op_expr(pc, token_index, true);
 
     return node;
 }
@@ -1159,7 +1160,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
     if (token->id == TokenIdSymbol) {
         ast_buf_from_token(pc, token, &asm_output->variable_name);
     } else if (token->id == TokenIdArrow) {
-        asm_output->return_type = ast_parse_unwrap_maybe_expr(pc, token_index, true);
+        asm_output->return_type = ast_parse_prefix_op_expr(pc, token_index, true);
     } else {
         ast_invalid_token_error(pc, token);
     }
@@ -1402,81 +1403,23 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
 }
 
 /*
-SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
-FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
-ArrayAccessExpression : token(LBracket) Expression token(RBracket)
-SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))
-FieldAccessExpression : token(Dot) token(Symbol)
+CurlySuffixExpression : PrefixOpExpression option(ContainerInitExpression)
 ContainerInitExpression : token(LBrace) ContainerInitBody token(RBrace)
 ContainerInitBody : list(StructLiteralField, token(Comma)) | list(Expression, token(Comma))
-StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
 */
-static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
-    AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
-    if (!primary_expr) {
+static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index, bool mandatory) {
+    AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, mandatory);
+    if (!prefix_op_expr) {
         return nullptr;
     }
 
     while (true) {
         Token *first_token = &pc->tokens->at(*token_index);
-        if (first_token->id == TokenIdLParen) {
-            *token_index += 1;
-
-            AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token);
-            node->data.fn_call_expr.fn_ref_expr = primary_expr;
-            ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
-
-            primary_expr = node;
-        } else if (first_token->id == TokenIdLBracket) {
-            *token_index += 1;
-
-            AstNode *expr_node = ast_parse_expression(pc, token_index, true);
-
-            Token *ellipsis_or_r_bracket = &pc->tokens->at(*token_index);
-
-            if (ellipsis_or_r_bracket->id == TokenIdEllipsis) {
-                *token_index += 1;
-
-                AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, first_token);
-                node->data.slice_expr.array_ref_expr = primary_expr;
-                node->data.slice_expr.start = expr_node;
-                node->data.slice_expr.end = ast_parse_expression(pc, token_index, false);
-
-                ast_eat_token(pc, token_index, TokenIdRBracket);
-
-                Token *const_tok = &pc->tokens->at(*token_index);
-                if (const_tok->id == TokenIdKeywordConst) {
-                    *token_index += 1;
-                    node->data.slice_expr.is_const = true;
-                }
-
-                primary_expr = node;
-            } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) {
-                *token_index += 1;
-
-                AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, first_token);
-                node->data.array_access_expr.array_ref_expr = primary_expr;
-                node->data.array_access_expr.subscript = expr_node;
-
-                primary_expr = node;
-            } else {
-                ast_invalid_token_error(pc, first_token);
-            }
-        } else if (first_token->id == TokenIdDot) {
-            *token_index += 1;
-
-            Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
-
-            AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
-            node->data.field_access_expr.struct_expr = primary_expr;
-            ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
-
-            primary_expr = node;
-        } else if (first_token->id == TokenIdLBrace) {
+        if (first_token->id == TokenIdLBrace) {
             *token_index += 1;
 
             AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, first_token);
-            node->data.container_init_expr.type = primary_expr;
+            node->data.container_init_expr.type = prefix_op_expr;
 
             Token *token = &pc->tokens->at(*token_index);
             if (token->id == TokenIdDot) {
@@ -1536,6 +1479,81 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
                 }
             }
 
+            prefix_op_expr = node;
+        } else {
+            return prefix_op_expr;
+        }
+    }
+}
+
+/*
+SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
+FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
+ArrayAccessExpression : token(LBracket) Expression token(RBracket)
+SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))
+FieldAccessExpression : token(Dot) token(Symbol)
+StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
+*/
+static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
+    AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
+    if (!primary_expr) {
+        return nullptr;
+    }
+
+    while (true) {
+        Token *first_token = &pc->tokens->at(*token_index);
+        if (first_token->id == TokenIdLParen) {
+            *token_index += 1;
+
+            AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token);
+            node->data.fn_call_expr.fn_ref_expr = primary_expr;
+            ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
+
+            primary_expr = node;
+        } else if (first_token->id == TokenIdLBracket) {
+            *token_index += 1;
+
+            AstNode *expr_node = ast_parse_expression(pc, token_index, true);
+
+            Token *ellipsis_or_r_bracket = &pc->tokens->at(*token_index);
+
+            if (ellipsis_or_r_bracket->id == TokenIdEllipsis) {
+                *token_index += 1;
+
+                AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, first_token);
+                node->data.slice_expr.array_ref_expr = primary_expr;
+                node->data.slice_expr.start = expr_node;
+                node->data.slice_expr.end = ast_parse_expression(pc, token_index, false);
+
+                ast_eat_token(pc, token_index, TokenIdRBracket);
+
+                Token *const_tok = &pc->tokens->at(*token_index);
+                if (const_tok->id == TokenIdKeywordConst) {
+                    *token_index += 1;
+                    node->data.slice_expr.is_const = true;
+                }
+
+                primary_expr = node;
+            } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) {
+                *token_index += 1;
+
+                AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, first_token);
+                node->data.array_access_expr.array_ref_expr = primary_expr;
+                node->data.array_access_expr.subscript = expr_node;
+
+                primary_expr = node;
+            } else {
+                ast_invalid_token_error(pc, first_token);
+            }
+        } else if (first_token->id == TokenIdDot) {
+            *token_index += 1;
+
+            Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
+
+            AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
+            node->data.field_access_expr.struct_expr = primary_expr;
+            ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
+
             primary_expr = node;
         } else {
             return primary_expr;
@@ -1623,10 +1641,10 @@ static BinOpType ast_parse_mult_op(ParseContext *pc, int *token_index, bool mand
 }
 
 /*
-MultiplyExpression : PrefixOpExpression MultiplyOperator MultiplyExpression | PrefixOpExpression
+MultiplyExpression : CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression
 */
 static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool mandatory) {
-    AstNode *operand_1 = ast_parse_prefix_op_expr(pc, token_index, mandatory);
+    AstNode *operand_1 = ast_parse_curly_suffix_expr(pc, token_index, mandatory);
     if (!operand_1)
         return nullptr;
 
@@ -1636,7 +1654,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man
         if (mult_op == BinOpTypeInvalid)
             return operand_1;
 
-        AstNode *operand_2 = ast_parse_prefix_op_expr(pc, token_index, true);
+        AstNode *operand_2 = ast_parse_curly_suffix_expr(pc, token_index, true);
 
         AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
         node->data.bin_op_expr.op1 = operand_1;
@@ -1948,7 +1966,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
             node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
         } else if (eq_or_colon->id == TokenIdColon) {
             *token_index += 1;
-            node->data.if_var_expr.var_decl.type = ast_parse_unwrap_maybe_expr(pc, token_index, true);
+            node->data.if_var_expr.var_decl.type = ast_parse_prefix_op_expr(pc, token_index, true);
 
             ast_eat_token(pc, token_index, TokenIdMaybeAssign);
             node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
@@ -2028,7 +2046,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
         node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
         return node;
     } else if (eq_or_colon->id == TokenIdColon) {
-        node->data.variable_declaration.type = ast_parse_unwrap_maybe_expr(pc, token_index, true);
+        node->data.variable_declaration.type = ast_parse_prefix_op_expr(pc, token_index, true);
         Token *eq_token = &pc->tokens->at(*token_index);
         if (eq_token->id == TokenIdEq) {
             *token_index += 1;
@@ -2394,7 +2412,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
     ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
 
     Token *next_token = &pc->tokens->at(*token_index);
-    node->data.fn_proto.return_type = ast_parse_unwrap_maybe_expr(pc, token_index, false);
+    node->data.fn_proto.return_type = ast_parse_prefix_op_expr(pc, token_index, false);
     if (!node->data.fn_proto.return_type) {
         node->data.fn_proto.return_type = ast_create_void_type_node(pc, next_token);
     }