checker: require () in a && b || c
parent
0a84f0feb5
commit
63b8cdea7a
|
@ -1,4 +1,6 @@
|
||||||
fn test_float_decl() {
|
fn test_float_decl() {
|
||||||
|
//z := 1f
|
||||||
|
//assert z > 0
|
||||||
x1 := 1e10
|
x1 := 1e10
|
||||||
x2 := -2e16
|
x2 := -2e16
|
||||||
x3 := 1e-15
|
x3 := 1e-15
|
||||||
|
|
|
@ -213,10 +213,10 @@ fn utf8_str_visible_length(s string) int {
|
||||||
}
|
}
|
||||||
} else if c == 0xe1 || c == 0xe2 || c == 0xef {
|
} else if c == 0xe1 || c == 0xe2 || c == 0xef {
|
||||||
r := (u32(c) << 16) | (u32(s.str[i+1]) << 8) | s.str[i+2]
|
r := (u32(c) << 16) | (u32(s.str[i+1]) << 8) | s.str[i+2]
|
||||||
if r >= 0xe1aab0 && r < 0xe1ac80 // diacritical marks extended
|
if (r >= 0xe1aab0 && r < 0xe1ac80) // diacritical marks extended
|
||||||
|| r >= 0xe1b780 && r < 0xe1b880 // diacritical marks supplement
|
|| (r >= 0xe1b780 && r < 0xe1b880) // diacritical marks supplement
|
||||||
|| r >= 0xe28390 && r < 0xe28480 // diacritical marks for symbols
|
|| (r >= 0xe28390 && r < 0xe28480) // diacritical marks for symbols
|
||||||
|| r >= 0xefb8a0 && r < 0xefb8b0 { // half marks
|
|| (r >= 0xefb8a0 && r < 0xefb8b0) { // half marks
|
||||||
l--
|
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
|
c.expected_type = table.void_type
|
||||||
mut left_type := c.expr(infix_expr.left)
|
mut left_type := c.expr(infix_expr.left)
|
||||||
if false && left_type == table.t_type {
|
// if false && left_type == table.t_type {
|
||||||
left_type = c.cur_generic_type
|
// left_type = c.cur_generic_type
|
||||||
}
|
// }
|
||||||
infix_expr.left_type = left_type
|
infix_expr.left_type = left_type
|
||||||
c.expected_type = left_type
|
c.expected_type = left_type
|
||||||
mut right_type := c.expr(infix_expr.right)
|
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.op in [.div, .mod] {
|
||||||
if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
|
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 {
|
'0') || (infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) {
|
||||||
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
||||||
c.error('$oper by zero', right_pos)
|
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
|
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.
|
// 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] {
|
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 {
|
ast.CastExpr {
|
||||||
it.expr_type = c.expr(it.expr)
|
it.expr_type = c.expr(it.expr)
|
||||||
sym := c.table.get_type_symbol(it.expr_type)
|
sym := c.table.get_type_symbol(it.expr_type)
|
||||||
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || sym.kind ==
|
if it.typ == table.string_type && !(sym.kind in [.byte, .byteptr] || (sym.kind ==
|
||||||
.array && sym.name == 'array_byte') {
|
.array && sym.name == 'array_byte')) {
|
||||||
type_name := c.table.type_to_str(it.expr_type)
|
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)
|
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.write(',')
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
g.write(')')
|
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 {
|
} else {
|
||||||
need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C
|
a := left_sym.name[0].is_capital() || left_sym.name.contains('.')
|
||||||
if need_par {
|
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.write('(')
|
||||||
}
|
g.expr(node.left)
|
||||||
g.expr(node.left)
|
g.write(', ')
|
||||||
g.write(' $node.op.str() ')
|
g.expr(node.right)
|
||||||
g.expr(node.right)
|
|
||||||
if need_par {
|
|
||||||
g.write(')')
|
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 = ''
|
// mut sum_type_str = ''
|
||||||
for j, branch in node.branches {
|
for j, branch in node.branches {
|
||||||
is_last := j == node.branches.len - 1
|
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 node.branches.len > 1 {
|
||||||
if is_expr {
|
if is_expr {
|
||||||
// TODO too many branches. maybe separate ?: matches
|
// TODO too many branches. maybe separate ?: matches
|
||||||
|
@ -2980,6 +2983,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
fields := fmt.split('.')
|
fields := fmt.split('.')
|
||||||
// validate format
|
// validate format
|
||||||
// only floats should have precision specifier
|
// 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() &&
|
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`,
|
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`,
|
`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`] {
|
`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])}')
|
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
|
// make sure that format paramters are valid numbers
|
||||||
|
/*
|
||||||
for j, f in fields {
|
for j, f in fields {
|
||||||
for k, c in f {
|
for k, c in f {
|
||||||
if (c < `0` || c > `9`) && !(j == 0 && k == 0 && (node.expr_types[i].is_number() &&
|
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
|
specs << fspec
|
||||||
fieldwidths << if fields.len == 0 {
|
fieldwidths << if fields.len == 0 {
|
||||||
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'
|
return 'TARGET_ORDER_IS_BIG'
|
||||||
}
|
}
|
||||||
else {
|
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}'
|
return 'CUSTOM_DEFINE_${name}'
|
||||||
}
|
}
|
||||||
verror('bad os ifdef name "$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.
|
// There is a custom .str() method, so use it.
|
||||||
// NB: we need to take account of whether the user has defined
|
// NB: we need to take account of whether the user has defined
|
||||||
// `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly
|
// `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);')
|
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(it);')
|
||||||
} else if str_method_expects_ptr && !is_elem_ptr {
|
} else if str_method_expects_ptr && !is_elem_ptr {
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(&it);')
|
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 {
|
} else if sym.kind == .string {
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
|
||||||
} else {
|
} 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]));')
|
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 {
|
} 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]));')
|
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
|
assert b == 24
|
||||||
}
|
}
|
||||||
|
|
||||||
fn noop() {}
|
fn noop() {
|
||||||
|
}
|
||||||
|
|
||||||
fn test_if_expression_with_function_assign() {
|
fn test_if_expression_with_function_assign() {
|
||||||
a := if true {
|
a := if true {
|
||||||
|
@ -102,7 +103,7 @@ fn test_simple_nested_if_expressions() {
|
||||||
|
|
||||||
fn test_complex_nested_if_expressions() {
|
fn test_complex_nested_if_expressions() {
|
||||||
mut a := false
|
mut a := false
|
||||||
a = 1 == 2 || true && if true {
|
a = (1 == 2 || true) && (if true {
|
||||||
g := 6
|
g := 6
|
||||||
h := if false { 3 } else { 5 }
|
h := if false { 3 } else { 5 }
|
||||||
mut d := false
|
mut d := false
|
||||||
|
@ -125,7 +126,7 @@ fn test_complex_nested_if_expressions() {
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
assert a == false
|
assert a == false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -373,13 +373,9 @@ pub fn (tok Token) precedence() int {
|
||||||
.eq, .ne, .lt, .le, .gt, .ge {
|
.eq, .ne, .lt, .le, .gt, .ge {
|
||||||
return int(Precedence.eq)
|
return int(Precedence.eq)
|
||||||
}
|
}
|
||||||
// `&&`
|
|
||||||
// .and {
|
|
||||||
// return 3
|
|
||||||
// }
|
|
||||||
// `||`
|
|
||||||
// .logical_or,
|
// .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 {
|
.left_shift_assign, .right_shift_assign, .mult_assign, .xor_assign {
|
||||||
return int(Precedence.assign)
|
return int(Precedence.assign)
|
||||||
|
@ -390,9 +386,6 @@ pub fn (tok Token) precedence() int {
|
||||||
.logical_or, .and {
|
.logical_or, .and {
|
||||||
return int(Precedence.cond)
|
return int(Precedence.cond)
|
||||||
}
|
}
|
||||||
// /.plus_assign {
|
|
||||||
// /return 2
|
|
||||||
// /}
|
|
||||||
else {
|
else {
|
||||||
return int(Precedence.lowest)
|
return int(Precedence.lowest)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue