Fix operator precedence and introduce auto-deref

This commit is contained in:
Mid 2025-10-02 13:44:18 +03:00
parent 07e3604a8c
commit d46b104d5c

View File

@ -286,7 +286,20 @@ AST *nct_parse_expression(Parser *P, int lOP) {
expect(P, TOKEN_PAREN_R);
}
while(maybe(P, TOKEN_DOT)) {
while(maybe(P, TOKEN_DOT) || maybe(P, TOKEN_PAREN_L) || maybe(P, TOKEN_SQUAREN_L)) {
Token op = P->tokens[P->i - 1];
if(op.type == TOKEN_DOT) {
while(type_is_any_pointer(e->expression.type)) {
AST *deref = alloc_node(P, sizeof(ASTExprUnaryOp));
deref->nodeKind = AST_EXPR_UNARY_OP;
deref->exprUnOp.operator = UNOP_DEREF;
deref->exprUnOp.operand = (AST*) e;
deref->exprUnOp.type = type_dereference(e->expression.type);
e = (AST*) deref;
}
assert(e->expression.type->type == TYPE_TYPE_RECORD);
Token fieldTok = expect(P, TOKEN_IDENTIFIER);
@ -311,6 +324,123 @@ AST *nct_parse_expression(Parser *P, int lOP) {
}
e = (AST*) d;
} else if(op.type == TOKEN_PAREN_L) {
// Convert a call like foo() to (&foo)()
if(e->expression.type->type == TYPE_TYPE_FUNCTION) {
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
ref->nodeKind = AST_EXPR_UNARY_OP;
ref->type = type_pointer_wrap(e->expression.type);
ref->operator = UNOP_REF;
ref->operand = e;
e = (AST*) ref;
}
if(e->expression.type->type != TYPE_TYPE_POINTER || e->expression.type->pointer.of->type != TYPE_TYPE_FUNCTION) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types or function pointers may be called.");
}
Type *ftype = e->expression.type->pointer.of;
ASTExprCall *call = alloc_node(P, sizeof(*call));
call->nodeKind = AST_EXPR_CALL;
call->type = ftype->function.ret;
call->what = e;
call->args = NULL;
int argCount = 0;
if(!maybe(P, TOKEN_PAREN_R)) {
while(peek(P, 0).type != TOKEN_PAREN_R && peek(P, 0).type != TOKEN_COMMA) {
call->args = realloc(call->args, (argCount + 1) * sizeof(AST*));
call->args[argCount] = ast_cast_expr(nct_parse_expression(P, 0), ftype->function.args[argCount]);
argCount++;
if(maybe(P, TOKEN_PAREN_R)) {
break;
} else expect(P, TOKEN_COMMA);
}
}
if(argCount != ftype->function.argCount) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Mismatched number of arguments");
}
e = (AST*) call;
} else if(op.type == TOKEN_SQUAREN_L) {
P->scope = scope_new(P->scope);
P->i--;
if(parse_parametrization(P)) {
// Generic type parametrization
// Generic functions are not first-class
assert(e->nodeKind == AST_EXPR_VAR);
assert(e->exprVar.thing != NULL);
assert(e->exprVar.thing->kind == SCOPEITEM_SYMBOL);
char *cname = parametrize_function_name(e->expression.type, e->exprVar.thing->data.symbol.name, P->scope);
ScopeItem *cvte = scope_find(P->scope, cname);
if(!cvte) {
stahp_token(&P->tokens[P->i], "Parametrization %s not found.", cname);
}
e = exprvar(P, cvte);
} else {
// Array access
expect(P, TOKEN_SQUAREN_L);
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
ref->nodeKind = AST_EXPR_UNARY_OP;
ref->operator = UNOP_REF;
ref->operand = e;
ref->type = type_pointer_wrap(e->expression.type->array.of);
ASTExprBinaryOp *child = alloc_node(P, sizeof(*child));
child->nodeKind = AST_EXPR_BINARY_OP;
child->operands[0] = (AST*) ref;
child->operands[1] = nct_parse_expression(P, 0);
child->operator = BINOP_ADD;
child->type = ref->type;
if(e->expression.type->type != TYPE_TYPE_ARRAY) {
stahp_token(&P->tokens[P->i], "Attempt to index a non-array type");
}
int typesize = type_size(e->expression.type->array.of);
if(typesize != 1) {
ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale));
scale->nodeKind = AST_EXPR_PRIMITIVE;
scale->type = type_u(8 * arch_gpr_size());
scale->val = typesize;
ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul));
mul->nodeKind = AST_EXPR_BINARY_OP;
mul->type = child->operands[1]->expression.type;
mul->operator = BINOP_MUL;
mul->operands[0] = (AST*) scale;
mul->operands[1] = child->operands[1];
child->operands[1] = (AST*) mul;
}
ASTExprUnaryOp *unop = alloc_node(P, sizeof(*unop));
unop->nodeKind = AST_EXPR_UNARY_OP;
unop->type = e->expression.type->array.of;
unop->operator = UNOP_DEREF;
unop->operand = (AST*) child;
expect(P, TOKEN_SQUAREN_R);
e = (AST*) unop;
}
P->scope = P->scope->parent;
} else abort();
}
return e;
@ -369,128 +499,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
}
} else return nct_parse_expression(P, lOP + 1);
} else if(lOP == 5) {
AST *ret = nct_parse_expression(P, lOP + 1);
while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_SQUAREN_L) {
if(maybe(P, TOKEN_PAREN_L)) {
if(ret->expression.type->type == TYPE_TYPE_FUNCTION) {
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
ref->nodeKind = AST_EXPR_UNARY_OP;
ref->type = type_pointer_wrap(ret->expression.type);
ref->operator = UNOP_REF;
ref->operand = ret;
ret = (AST*) ref;
}
if(ret->expression.type->type != TYPE_TYPE_POINTER || ret->expression.type->pointer.of->type != TYPE_TYPE_FUNCTION) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types or function pointers may be called.");
}
Type *ftype = ret->expression.type->pointer.of;
ASTExprCall *call = alloc_node(P, sizeof(*call));
call->nodeKind = AST_EXPR_CALL;
call->type = ftype->function.ret;
call->what = ret;
call->args = NULL;
int argCount = 0;
if(!maybe(P, TOKEN_PAREN_R)) {
while(peek(P, 0).type != TOKEN_PAREN_R && peek(P, 0).type != TOKEN_COMMA) {
call->args = realloc(call->args, (argCount + 1) * sizeof(AST*));
call->args[argCount] = ast_cast_expr(nct_parse_expression(P, 0), ftype->function.args[argCount]);
argCount++;
if(maybe(P, TOKEN_PAREN_R)) {
break;
} else expect(P, TOKEN_COMMA);
}
}
if(argCount != ftype->function.argCount) {
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Mismatched number of arguments");
}
ret = (AST*) call;
} else if(peek(P, 0).type == TOKEN_SQUAREN_L) {
P->scope = scope_new(P->scope);
if(parse_parametrization(P)) {
// Generic type parametrization
// Generic functions are not first-class
assert(ret->nodeKind == AST_EXPR_VAR);
assert(ret->exprVar.thing != NULL);
assert(ret->exprVar.thing->kind == SCOPEITEM_SYMBOL);
char *cname = parametrize_function_name(ret->expression.type, ret->exprVar.thing->data.symbol.name, P->scope);
ScopeItem *cvte = scope_find(P->scope, cname);
if(!cvte) {
stahp_token(&P->tokens[P->i], "Parametrization %s not found.", cname);
}
ret = exprvar(P, cvte);
} else {
// Array access
expect(P, TOKEN_SQUAREN_L);
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
ref->nodeKind = AST_EXPR_UNARY_OP;
ref->operator = UNOP_REF;
ref->operand = ret;
ref->type = type_pointer_wrap(ret->expression.type->array.of);
ASTExprBinaryOp *child = alloc_node(P, sizeof(*child));
child->nodeKind = AST_EXPR_BINARY_OP;
child->operands[0] = (AST*) ref;
child->operands[1] = nct_parse_expression(P, 0);
child->operator = BINOP_ADD;
child->type = ref->type;
if(ret->expression.type->type != TYPE_TYPE_ARRAY) {
stahp_token(&P->tokens[P->i], "Attempt to index a non-array type");
}
int typesize = type_size(ret->expression.type->array.of);
if(typesize != 1) {
ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale));
scale->nodeKind = AST_EXPR_PRIMITIVE;
scale->type = type_u(8 * arch_gpr_size());
scale->val = typesize;
ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul));
mul->nodeKind = AST_EXPR_BINARY_OP;
mul->type = child->operands[1]->expression.type;
mul->operator = BINOP_MUL;
mul->operands[0] = (AST*) scale;
mul->operands[1] = child->operands[1];
child->operands[1] = (AST*) mul;
}
ASTExprUnaryOp *unop = alloc_node(P, sizeof(*unop));
unop->nodeKind = AST_EXPR_UNARY_OP;
unop->type = ret->expression.type->array.of;
unop->operator = UNOP_DEREF;
unop->operand = (AST*) child;
expect(P, TOKEN_SQUAREN_R);
ret = (AST*) unop;
}
P->scope = P->scope->parent;
} else abort();
}
return ret;
return nct_parse_expression(P, lOP + 1);
} else if(lOP == 4) {
AST *ret = nct_parse_expression(P, lOP + 1);
@ -582,35 +591,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
} else if(lOP == 1) {
AST *ret = nct_parse_expression(P, lOP + 1);
if(peek(P, 0).type == TOKEN_DOUBLE_AMPERSAND || peek(P, 0).type == TOKEN_DOUBLE_VERTICAL_BAR) {
while(1) {
BinaryOp op;
if(maybe(P, TOKEN_DOUBLE_AMPERSAND)) op = BINOP_LOGICAL_AND;
else if(maybe(P, TOKEN_DOUBLE_VERTICAL_BAR)) op = BINOP_LOGICAL_OR;
else break;
ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop));
astop->nodeKind = AST_EXPR_BINARY_OP;
astop->type = NULL;
astop->operator = op;
astop->operands[0] = ret;
ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression;
if(operand->type->type != TYPE_TYPE_PRIMITIVE) {
stahp_token(&P->tokens[P->i], "Invalid combination of operator and operand types.");
}
binop_implicit_cast(astop);
ret = (AST*) astop;
}
}
return ret;
} else if(lOP == 0) {
AST *ret = nct_parse_expression(P, lOP + 1);
if(peek(P, 0).type == TOKEN_DOUBLE_EQUALS || peek(P, 0).type == TOKEN_EXCLAMATION_EQUALS || peek(P, 0).type == TOKEN_LESS || peek(P, 0).type == TOKEN_GREATER || peek(P, 0).type == TOKEN_LEQUAL || peek(P, 0).type == TOKEN_GEQUAL) {
while(1) {
BinaryOp op;
@ -622,6 +602,33 @@ AST *nct_parse_expression(Parser *P, int lOP) {
else if(maybe(P, TOKEN_GEQUAL)) op = BINOP_GEQUAL;
else break;
ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop));
astop->nodeKind = AST_EXPR_BINARY_OP;
astop->type = type_u(1);
astop->operator = op;
astop->operands[0] = ret;
ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression;
if(operand->type->type != TYPE_TYPE_PRIMITIVE) {
stahp_token(&P->tokens[P->i], "Invalid combination of operator and operand types.");
}
ret = (AST*) astop;
}
}
return ret;
} else if(lOP == 0) {
AST *ret = nct_parse_expression(P, lOP + 1);
if(peek(P, 0).type == TOKEN_DOUBLE_AMPERSAND || peek(P, 0).type == TOKEN_DOUBLE_VERTICAL_BAR) {
while(1) {
BinaryOp op;
if(maybe(P, TOKEN_DOUBLE_AMPERSAND)) op = BINOP_LOGICAL_AND;
else if(maybe(P, TOKEN_DOUBLE_VERTICAL_BAR)) op = BINOP_LOGICAL_OR;
else break;
ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop));
astop->nodeKind = AST_EXPR_BINARY_OP;
astop->type = NULL;