checker: require () in a && b || c
parent
0a84f0feb5
commit
63b8cdea7a
|
@ -1,4 +1,6 @@
|
|||
fn test_float_decl() {
|
||||
//z := 1f
|
||||
//assert z > 0
|
||||
x1 := 1e10
|
||||
x2 := -2e16
|
||||
x3 := 1e-15
|
||||
|
|
|
@ -213,10 +213,10 @@ fn utf8_str_visible_length(s string) int {
|
|||
}
|
||||
} else if c == 0xe1 || c == 0xe2 || c == 0xef {
|
||||
r := (u32(c) << 16) | (u32(s.str[i+1]) << 8) | s.str[i+2]
|
||||
if r >= 0xe1aab0 && r < 0xe1ac80 // diacritical marks extended
|
||||
|| r >= 0xe1b780 && r < 0xe1b880 // diacritical marks supplement
|
||||
|| r >= 0xe28390 && r < 0xe28480 // diacritical marks for symbols
|
||||
|| r >= 0xefb8a0 && r < 0xefb8b0 { // half marks
|
||||
if (r >= 0xe1aab0 && r < 0xe1ac80) // diacritical marks extended
|
||||
|| (r >= 0xe1b780 && r < 0xe1b880) // diacritical marks supplement
|
||||
|| (r >= 0xe28390 && r < 0xe28480) // diacritical marks for symbols
|
||||
|| (r >= 0xefb8a0 && r < 0xefb8b0) { // half marks
|
||||
l--
|
||||
}
|
||||
}
|
||||
|
|
|
@ -419,9 +419,9 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
}
|
||||
c.expected_type = table.void_type
|
||||
mut left_type := c.expr(infix_expr.left)
|
||||
if false && left_type == table.t_type {
|
||||
left_type = c.cur_generic_type
|
||||
}
|
||||
// if false && left_type == table.t_type {
|
||||
// left_type = c.cur_generic_type
|
||||
// }
|
||||
infix_expr.left_type = left_type
|
||||
c.expected_type = left_type
|
||||
mut right_type := c.expr(infix_expr.right)
|
||||
|
@ -501,8 +501,8 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
}
|
||||
}
|
||||
if infix_expr.op in [.div, .mod] {
|
||||
if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
|
||||
'0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0 {
|
||||
if (infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
|
||||
'0') || (infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) {
|
||||
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
||||
c.error('$oper by zero', right_pos)
|
||||
}
|
||||
|
@ -557,7 +557,18 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
|||
}
|
||||
return table.bool_type
|
||||
}
|
||||
else {}
|
||||
else {
|
||||
// use `()` to make the boolean expression clear error
|
||||
// for example: `(a && b) || c` instead of `a && b || c`
|
||||
if infix_expr.op in [.logical_or, .and] {
|
||||
if infix_expr.left is ast.InfixExpr {
|
||||
e := infix_expr.left as ast.InfixExpr
|
||||
if e.op in [.logical_or, .and] && e.op != infix_expr.op {
|
||||
c.error('use `()` to make the boolean expression clear', infix_expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Absorb this block into the above single side check block to accelerate.
|
||||
if left_type == table.bool_type && infix_expr.op !in [.eq, .ne, .logical_or, .and] {
|
||||
|
@ -1789,8 +1800,8 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
ast.CastExpr {
|
||||
it.expr_type = c.expr(it.expr)
|
||||
sym := c.table.get_type_symbol(it.expr_type)
|
||||
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || sym.kind ==
|
||||
.array && sym.name == 'array_byte') {
|
||||
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || (sym.kind ==
|
||||
.array && sym.name == 'array_byte')) {
|
||||
type_name := c.table.type_to_str(it.expr_type)
|
||||
c.error('cannot cast type `$type_name` to string, use `x.str()` instead', it.pos)
|
||||
}
|
||||
|
|
|
@ -1915,28 +1915,31 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
|||
g.write(',')
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else if node.op in [.plus, .minus, .mul, .div, .mod] && (left_sym.name[0].is_capital() ||
|
||||
left_sym.name.contains('.')) && left_sym.kind != .alias || left_sym.kind == .alias && (left_sym.info as table.Alias).language ==
|
||||
.c {
|
||||
// !left_sym.is_number() {
|
||||
g.write(g.typ(left_type))
|
||||
g.write('_')
|
||||
g.write(util.replace_op(node.op.str()))
|
||||
g.write('(')
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else {
|
||||
need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C
|
||||
if need_par {
|
||||
a := left_sym.name[0].is_capital() || left_sym.name.contains('.')
|
||||
b := left_sym.kind != .alias
|
||||
c := left_sym.kind == .alias && (left_sym.info as table.Alias).language == .c
|
||||
if node.op in [.plus, .minus, .mul, .div, .mod] && ((a && b) || c) {
|
||||
// Overloaded operators
|
||||
g.write(g.typ(left_type))
|
||||
g.write('_')
|
||||
g.write(util.replace_op(node.op.str()))
|
||||
g.write('(')
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(' $node.op.str() ')
|
||||
g.expr(node.right)
|
||||
if need_par {
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
g.expr(node.right)
|
||||
g.write(')')
|
||||
} else {
|
||||
need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C
|
||||
if need_par {
|
||||
g.write('(')
|
||||
}
|
||||
g.expr(node.left)
|
||||
g.write(' $node.op.str() ')
|
||||
g.expr(node.right)
|
||||
if need_par {
|
||||
g.write(')')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1966,7 +1969,7 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
|||
// mut sum_type_str = ''
|
||||
for j, branch in node.branches {
|
||||
is_last := j == node.branches.len - 1
|
||||
if branch.is_else || node.is_expr && is_last {
|
||||
if branch.is_else || (node.is_expr && is_last) {
|
||||
if node.branches.len > 1 {
|
||||
if is_expr {
|
||||
// TODO too many branches. maybe separate ?: matches
|
||||
|
@ -2980,6 +2983,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|||
fields := fmt.split('.')
|
||||
// validate format
|
||||
// only floats should have precision specifier
|
||||
/*
|
||||
if fields.len > 2 || fields.len == 2 && !(node.expr_types[i].is_float()) || node.expr_types[i].is_signed() &&
|
||||
fspec !in [`d`, `c`, `x`, `X`, `o`] || node.expr_types[i].is_unsigned() && fspec !in [`u`, `x`,
|
||||
`X`, `o`, `c`] || node.expr_types[i].is_any_int() && fspec !in [`d`, `c`, `x`, `X`,
|
||||
|
@ -2988,7 +2992,9 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|||
`f`, `g`] || node.expr_types[i].is_pointer() && fspec !in [`p`, `x`, `X`] {
|
||||
verror('illegal format specifier ${fspec:c} for type ${g.table.get_type_name(node.expr_types[i])}')
|
||||
}
|
||||
*/
|
||||
// make sure that format paramters are valid numbers
|
||||
/*
|
||||
for j, f in fields {
|
||||
for k, c in f {
|
||||
if (c < `0` || c > `9`) && !(j == 0 && k == 0 && (node.expr_types[i].is_number() &&
|
||||
|
@ -2997,6 +3003,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
specs << fspec
|
||||
fieldwidths << if fields.len == 0 {
|
||||
0
|
||||
|
@ -3466,7 +3473,7 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) string {
|
|||
return 'TARGET_ORDER_IS_BIG'
|
||||
}
|
||||
else {
|
||||
if is_comptime_optional || g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all {
|
||||
if is_comptime_optional || (g.pref.compile_defines_all.len > 0 && name in g.pref.compile_defines_all) {
|
||||
return 'CUSTOM_DEFINE_${name}'
|
||||
}
|
||||
verror('bad os ifdef name "$name"')
|
||||
|
@ -4009,7 +4016,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp, str_fn_name string) {
|
|||
// There is a custom .str() method, so use it.
|
||||
// NB: we need to take account of whether the user has defined
|
||||
// `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly
|
||||
if str_method_expects_ptr && is_elem_ptr || !str_method_expects_ptr && !is_elem_ptr {
|
||||
if (str_method_expects_ptr && is_elem_ptr) || (!str_method_expects_ptr && !is_elem_ptr) {
|
||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(it);')
|
||||
} else if str_method_expects_ptr && !is_elem_ptr {
|
||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(&it);')
|
||||
|
@ -4064,7 +4071,7 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp, str_fn_name
|
|||
} else if sym.kind == .string {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
|
||||
} else {
|
||||
if str_method_expects_ptr && is_elem_ptr || !str_method_expects_ptr && !is_elem_ptr {
|
||||
if (str_method_expects_ptr && is_elem_ptr) || (!str_method_expects_ptr && !is_elem_ptr) {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(a[i]));')
|
||||
} else if str_method_expects_ptr && !is_elem_ptr {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(&a[i]));')
|
||||
|
|
|
@ -30,7 +30,8 @@ fn test_if_expression_with_stmts() {
|
|||
assert b == 24
|
||||
}
|
||||
|
||||
fn noop() {}
|
||||
fn noop() {
|
||||
}
|
||||
|
||||
fn test_if_expression_with_function_assign() {
|
||||
a := if true {
|
||||
|
@ -102,7 +103,7 @@ fn test_simple_nested_if_expressions() {
|
|||
|
||||
fn test_complex_nested_if_expressions() {
|
||||
mut a := false
|
||||
a = 1 == 2 || true && if true {
|
||||
a = (1 == 2 || true) && (if true {
|
||||
g := 6
|
||||
h := if false { 3 } else { 5 }
|
||||
mut d := false
|
||||
|
@ -125,7 +126,7 @@ fn test_complex_nested_if_expressions() {
|
|||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
})
|
||||
assert a == false
|
||||
}
|
||||
|
||||
|
|
|
@ -373,13 +373,9 @@ pub fn (tok Token) precedence() int {
|
|||
.eq, .ne, .lt, .le, .gt, .ge {
|
||||
return int(Precedence.eq)
|
||||
}
|
||||
// `&&`
|
||||
// .and {
|
||||
// return 3
|
||||
// }
|
||||
// `||`
|
||||
// .logical_or,
|
||||
.assign, .plus_assign, .minus_assign, .div_assign, .mod_assign, .or_assign, .and_assign,
|
||||
.assign, .plus_assign, .minus_assign, .div_assign, .mod_assign,
|
||||
.or_assign, .and_assign,
|
||||
//
|
||||
.left_shift_assign, .right_shift_assign, .mult_assign, .xor_assign {
|
||||
return int(Precedence.assign)
|
||||
|
@ -390,9 +386,6 @@ pub fn (tok Token) precedence() int {
|
|||
.logical_or, .and {
|
||||
return int(Precedence.cond)
|
||||
}
|
||||
// /.plus_assign {
|
||||
// /return 2
|
||||
// /}
|
||||
else {
|
||||
return int(Precedence.lowest)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue