mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Required parens code moved to semantic analysis. Make || and && have different levels since parens cannot be enforced.
This commit is contained in:
@@ -237,11 +237,12 @@ typedef enum
|
||||
PREC_ASSIGNMENT, // =, *=, /=, %=, +=, etc
|
||||
PREC_TRY_ELSE, // try and else
|
||||
PREC_TERNARY, // ?:
|
||||
PREC_LOGICAL, // && ||
|
||||
PREC_OR, // ||
|
||||
PREC_AND, // &&
|
||||
PREC_RELATIONAL, // < > <= >= == !=
|
||||
PREC_ADDITIVE, // + -
|
||||
PREC_BIT, // ^ | &
|
||||
PREC_SHIFT, // << >> >>>
|
||||
PREC_SHIFT, // << >>
|
||||
PREC_MULTIPLICATIVE, // * / %
|
||||
PREC_UNARY, // ! - + ~ * & prefix ++/--
|
||||
PREC_CALL, // . () [] postfix ++/--
|
||||
|
||||
@@ -5,21 +5,6 @@
|
||||
#include "compiler_internal.h"
|
||||
#include "parser_internal.h"
|
||||
|
||||
#define BINOP_PREC_REQ_LEN 40
|
||||
int BINOP_PREC_REQ[BINOP_PREC_REQ_LEN] = {
|
||||
// bitwise operations
|
||||
[BINARYOP_BIT_OR] = 1,
|
||||
[BINARYOP_BIT_XOR] = 1,
|
||||
[BINARYOP_BIT_AND] = 1,
|
||||
|
||||
// comparison operations
|
||||
[BINARYOP_GT] = 2,
|
||||
[BINARYOP_GE] = 2,
|
||||
[BINARYOP_LT] = 2,
|
||||
[BINARYOP_LE] = 2,
|
||||
[BINARYOP_NE] = 2,
|
||||
[BINARYOP_EQ] = 2
|
||||
};
|
||||
|
||||
typedef Expr *(*ParseFn)(Context *context, Expr *);
|
||||
|
||||
@@ -389,21 +374,6 @@ static Expr *parse_failable(Context *context, Expr *left_side)
|
||||
}
|
||||
|
||||
|
||||
bool unclear_op_precedence(Expr *left_side, Expr * main_expr, Expr *right_side)
|
||||
{
|
||||
int precedence_main = BINOP_PREC_REQ[main_expr->binary_expr.operator];
|
||||
if (left_side->expr_kind == EXPR_BINARY)
|
||||
{
|
||||
int precedence_left = BINOP_PREC_REQ[left_side->binary_expr.operator];
|
||||
return precedence_left && (precedence_left == precedence_main);
|
||||
}
|
||||
if (right_side->expr_kind == EXPR_BINARY)
|
||||
{
|
||||
int precedence_right = BINOP_PREC_REQ[right_side->binary_expr.operator];
|
||||
return precedence_right && (precedence_right == precedence_main);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Expr *parse_binary(Context *context, Expr *left_side)
|
||||
{
|
||||
@@ -429,12 +399,6 @@ static Expr *parse_binary(Context *context, Expr *left_side)
|
||||
expr->binary_expr.left = left_side;
|
||||
expr->binary_expr.right = right_side;
|
||||
|
||||
// check if both sides have a binary operation where the precedence is unclear. Example: a ^ b | c
|
||||
if (unclear_op_precedence(left_side, expr, right_side))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "You need to add explicit parentheses.");
|
||||
}
|
||||
|
||||
expr->span.end_loc = right_side->span.end_loc;
|
||||
return expr;
|
||||
}
|
||||
@@ -1141,8 +1105,8 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_AT] = { parse_macro_expansion, NULL, PREC_NONE },
|
||||
[TOKEN_STRING] = { parse_string_literal, NULL, PREC_NONE },
|
||||
[TOKEN_REAL] = { parse_double, NULL, PREC_NONE },
|
||||
[TOKEN_OR] = { NULL, parse_binary, PREC_LOGICAL },
|
||||
[TOKEN_AND] = { parse_unary_expr, parse_binary, PREC_LOGICAL },
|
||||
[TOKEN_OR] = { NULL, parse_binary, PREC_OR },
|
||||
[TOKEN_AND] = { parse_unary_expr, parse_binary, PREC_AND },
|
||||
[TOKEN_EQ] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
[TOKEN_PLUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
[TOKEN_MINUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
|
||||
@@ -11,6 +11,27 @@
|
||||
|
||||
static inline bool sema_cast_rvalue(Context *context, Type *to, Expr *expr);
|
||||
|
||||
int BINOP_PREC_REQ[BINARYOP_LAST] =
|
||||
{
|
||||
// bitwise operations
|
||||
[BINARYOP_BIT_OR] = 1,
|
||||
[BINARYOP_BIT_XOR] = 1,
|
||||
[BINARYOP_BIT_AND] = 1,
|
||||
|
||||
// comparison operations
|
||||
[BINARYOP_GT] = 2,
|
||||
[BINARYOP_GE] = 2,
|
||||
[BINARYOP_LT] = 2,
|
||||
[BINARYOP_LE] = 2,
|
||||
[BINARYOP_NE] = 2,
|
||||
[BINARYOP_EQ] = 2,
|
||||
|
||||
[BINARYOP_SHR] = 3,
|
||||
[BINARYOP_SHL] = 3,
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl)
|
||||
{
|
||||
@@ -4147,7 +4168,7 @@ static bool sema_expr_analyse_shift_assign(Context *context, Expr *expr, Expr *l
|
||||
|
||||
static bool sema_expr_analyse_and(Context *context, Expr *expr, Expr *left, Expr *right)
|
||||
{
|
||||
if (!sema_analyse_expr(context, type_bool, left) & sema_analyse_expr(context, type_bool, right)) return false;
|
||||
if (!sema_analyse_expr(context, type_bool, left) || !sema_analyse_expr(context, type_bool, right)) return false;
|
||||
if (!cast_implicit(left, type_bool) || !cast_implicit(right, type_bool)) return false;
|
||||
|
||||
expr_set_type(expr, type_bool);
|
||||
@@ -4705,12 +4726,34 @@ static inline bool sema_expr_analyse_taddr(Context *context, Type *to, Expr *exp
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool unclear_op_precedence(Expr *left_side, Expr * main_expr, Expr *right_side)
|
||||
{
|
||||
int precedence_main = BINOP_PREC_REQ[main_expr->binary_expr.operator];
|
||||
if (left_side->expr_kind == EXPR_BINARY)
|
||||
{
|
||||
int precedence_left = BINOP_PREC_REQ[left_side->binary_expr.operator];
|
||||
return precedence_left && (precedence_left == precedence_main);
|
||||
}
|
||||
if (right_side->expr_kind == EXPR_BINARY)
|
||||
{
|
||||
int precedence_right = BINOP_PREC_REQ[right_side->binary_expr.operator];
|
||||
return precedence_right && (precedence_right == precedence_main);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
assert(expr->resolve_status == RESOLVE_RUNNING);
|
||||
Expr *left = expr->binary_expr.left;
|
||||
Expr *right = expr->binary_expr.right;
|
||||
|
||||
// check if both sides have a binary operation where the precedence is unclear. Example: a ^ b | c
|
||||
if (unclear_op_precedence(left, expr, right))
|
||||
{
|
||||
SEMA_ERROR(expr, "You need to add explicit parentheses to clarify precedence.");
|
||||
return expr_poison(expr);
|
||||
}
|
||||
// Don't push down bool conversions for example.
|
||||
if (to && !type_is_numeric(to)) to = NULL;
|
||||
switch (expr->binary_expr.operator)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
func void test()
|
||||
{
|
||||
int x = 3 ^ 5 & 6; // #error: You need to add explicit parentheses.
|
||||
int x = 3 ^ 5 & 6; // #error: You need to add explicit parentheses to clarify precedence
|
||||
}
|
||||
|
||||
13
test/test_suite/precedence/required_parens.c3
Normal file
13
test/test_suite/precedence/required_parens.c3
Normal file
@@ -0,0 +1,13 @@
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
func void main()
|
||||
{
|
||||
int i = 0;
|
||||
int j = i ^ i | i; // #error: You need to add explicit parentheses to clarify precedence.
|
||||
bool x = i == j == i; // #error: You need to add explicit parentheses to clarify precedence.
|
||||
int k = i >> j << k; // #error: You need to add explicit parentheses to clarify precedence.
|
||||
bool xk = i && j || i;
|
||||
int y = i + j + i;
|
||||
int yy = i * i / i + i - i;
|
||||
}
|
||||
Reference in New Issue
Block a user