implement %% operator

See #23
This commit is contained in:
Andrew Kelley
2016-01-25 13:53:40 -07:00
parent bcb18338cd
commit 6db6609df8
10 changed files with 249 additions and 53 deletions

View File

@@ -95,6 +95,8 @@ const char *node_type_str(NodeType node_type) {
return "Block";
case NodeTypeBinOpExpr:
return "BinOpExpr";
case NodeTypeUnwrapErrorExpr:
return "UnwrapErrorExpr";
case NodeTypeFnCallExpr:
return "FnCallExpr";
case NodeTypeArrayAccessExpr:
@@ -273,6 +275,14 @@ void ast_print(AstNode *node, int indent) {
ast_print(node->data.bin_op_expr.op1, indent + 2);
ast_print(node->data.bin_op_expr.op2, indent + 2);
break;
case NodeTypeUnwrapErrorExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
ast_print(node->data.unwrap_err_expr.op1, indent + 2);
if (node->data.unwrap_err_expr.symbol) {
ast_print(node->data.unwrap_err_expr.symbol, indent + 2);
}
ast_print(node->data.unwrap_err_expr.op2, indent + 2);
break;
case NodeTypeFnCallExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
ast_print(node->data.fn_call_expr.fn_ref_expr, indent + 2);
@@ -964,7 +974,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
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_unwrap_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) {
@@ -1032,7 +1042,7 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
}
/*
ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)
ParamDecl : option("noalias") "Symbol" ":" PrefixOpExpression | "..."
*/
static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -1154,7 +1164,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
}
/*
ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) UnwrapMaybeExpression
ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
*/
static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *l_bracket = &pc->tokens->at(*token_index);
@@ -1207,7 +1217,7 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
}
/*
AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) UnwrapMaybeExpression token(RParen)
AsmOutputItem : "[" "Symbol" "]" "String" "(" ("Symbol" | "->" PrefixOpExpression) ")"
*/
static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {
ast_eat_token(pc, token_index, TokenIdLBracket);
@@ -2132,7 +2142,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
}
/*
VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))
VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
*/
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -2454,38 +2464,55 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda
}
/*
UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
UnwrapMaybe : "??" BoolOrExpression
UnwrapError : "%%" option("|" "Symbol" "|") BoolOrExpression
*/
// this is currently the first child expression of assignment
static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory) {
static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
if (!lhs)
return nullptr;
Token *token = &pc->tokens->at(*token_index);
if (token->id != TokenIdDoubleQuestion) {
if (token->id == TokenIdDoubleQuestion) {
*token_index += 1;
AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = lhs;
node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
node->data.bin_op_expr.op2 = rhs;
normalize_parent_ptrs(node);
return node;
} else if (token->id == TokenIdPercentPercent) {
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeUnwrapErrorExpr, token);
node->data.unwrap_err_expr.op1 = lhs;
Token *maybe_bar_tok = &pc->tokens->at(*token_index);
if (maybe_bar_tok->id == TokenIdBinOr) {
*token_index += 1;
node->data.unwrap_err_expr.symbol = ast_parse_symbol(pc, token_index);
ast_eat_token(pc, token_index, TokenIdBinOr);
}
node->data.unwrap_err_expr.op2 = ast_parse_expression(pc, token_index, true);
normalize_parent_ptrs(node);
return node;
} else {
return lhs;
}
*token_index += 1;
AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = lhs;
node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
node->data.bin_op_expr.op2 = rhs;
normalize_parent_ptrs(node);
return node;
}
/*
AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
AssignmentExpression : UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
*/
static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *lhs = ast_parse_unwrap_maybe_expr(pc, token_index, mandatory);
AstNode *lhs = ast_parse_unwrap_expr(pc, token_index, mandatory);
if (!lhs)
return nullptr;
@@ -2494,7 +2521,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
if (ass_op == BinOpTypeInvalid)
return lhs;
AstNode *rhs = ast_parse_unwrap_maybe_expr(pc, token_index, true);
AstNode *rhs = ast_parse_unwrap_expr(pc, token_index, true);
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = lhs;
@@ -2646,7 +2673,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
}
/*
FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(UnwrapMaybeExpression)
FnProto : many(Directive) option(FnVisibleMod) "fn" "Symbol" ParamDeclList option(PrefixOpExpression)
*/
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -3164,6 +3191,11 @@ void normalize_parent_ptrs(AstNode *node) {
set_field(&node->data.bin_op_expr.op1);
set_field(&node->data.bin_op_expr.op2);
break;
case NodeTypeUnwrapErrorExpr:
set_field(&node->data.unwrap_err_expr.op1);
set_field(&node->data.unwrap_err_expr.symbol);
set_field(&node->data.unwrap_err_expr.op2);
break;
case NodeTypeNumberLiteral:
// none
break;