diff --git a/vlib/builtin/float_test.v b/vlib/builtin/float_test.v index 850d6824ab..09503561fa 100644 --- a/vlib/builtin/float_test.v +++ b/vlib/builtin/float_test.v @@ -1,4 +1,6 @@ fn test_float_decl() { + //z := 1f + //assert z > 0 x1 := 1e10 x2 := -2e16 x3 := 1e-15 diff --git a/vlib/builtin/utf8.v b/vlib/builtin/utf8.v index e85eec4cee..6df511bfdd 100644 --- a/vlib/builtin/utf8.v +++ b/vlib/builtin/utf8.v @@ -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-- } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 7e15dc4d9c..01fff0cf36 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 0307baa33a..2da086a9ca 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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]));') diff --git a/vlib/v/tests/if_expression_test.v b/vlib/v/tests/if_expression_test.v index 96c8ca611d..b5b82faacb 100644 --- a/vlib/v/tests/if_expression_test.v +++ b/vlib/v/tests/if_expression_test.v @@ -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 } diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 5eac2c9885..b6eaebff87 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -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) }