checker: require () in a && b || c

pull/5182/head
Alexander Medvednikov 2020-06-02 22:21:40 +02:00
parent 0a84f0feb5
commit 63b8cdea7a
6 changed files with 61 additions and 47 deletions

View File

@ -1,4 +1,6 @@
fn test_float_decl() {
//z := 1f
//assert z > 0
x1 := 1e10
x2 := -2e16
x3 := 1e-15

View File

@ -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--
}
}

View File

@ -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)
}

View File

@ -1915,10 +1915,12 @@ 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() {
} else {
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()))
@ -1940,6 +1942,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
}
}
}
}
fn (mut g Gen) match_expr(node ast.MatchExpr) {
// println('match expr typ=$it.expr_type')
@ -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]));')

View File

@ -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
}

View File

@ -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)
}