diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 0989dc0932..095751b359 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -578,18 +578,6 @@ pub fn (s string) bool() bool { return s == 'true' || s == 't' // TODO: t for pg, remove } -// int returns the value of the string as an integer `'1'.int() == 1`. -@[inline] -pub fn (s string) int() int { - return int(strconv.common_parse_int(s, 0, 32, false, false) or { 0 }) -} - -// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`. -@[inline] -pub fn (s string) i64() i64 { - return strconv.common_parse_int(s, 0, 64, false, false) or { 0 } -} - // i8 returns the value of the string as i8 `'1'.i8() == i8(1)`. @[inline] pub fn (s string) i8() i8 { @@ -602,6 +590,24 @@ pub fn (s string) i16() i16 { return i16(strconv.common_parse_int(s, 0, 16, false, false) or { 0 }) } +// i32 returns the value of the string as i32 `'1'.i32() == i32(1)`. +@[inline] +pub fn (s string) i32() i32 { + return i32(strconv.common_parse_int(s, 0, 32, false, false) or { 0 }) +} + +// int returns the value of the string as an integer `'1'.int() == 1`. +@[inline] +pub fn (s string) int() int { + return int(strconv.common_parse_int(s, 0, 32, false, false) or { 0 }) +} + +// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`. +@[inline] +pub fn (s string) i64() i64 { + return strconv.common_parse_int(s, 0, 64, false, false) or { 0 } +} + // f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`. @[inline] pub fn (s string) f32() f32 { @@ -614,12 +620,6 @@ pub fn (s string) f64() f64 { return strconv.atof64(s) or { 0 } } -// u8 returns the value of the string as u8 `'1'.u8() == u8(1)`. -@[inline] -pub fn (s string) u8() u8 { - return u8(strconv.common_parse_uint(s, 0, 8, false, false) or { 0 }) -} - // u8_array returns the value of the hex/bin string as u8 array. // hex string example: `'0x11223344ee'.u8_array() == [u8(0x11),0x22,0x33,0x44,0xee]`. // bin string example: `'0b1101_1101'.u8_array() == [u8(0xdd)]`. @@ -673,6 +673,12 @@ pub fn (s string) u8_array() []u8 { return []u8{} } +// u8 returns the value of the string as u8 `'1'.u8() == u8(1)`. +@[inline] +pub fn (s string) u8() u8 { + return u8(strconv.common_parse_uint(s, 0, 8, false, false) or { 0 }) +} + // u16 returns the value of the string as u16 `'1'.u16() == u16(1)`. @[inline] pub fn (s string) u16() u16 { diff --git a/vlib/toml/toml.v b/vlib/toml/toml.v index a1544a00fe..dc6e589a8d 100644 --- a/vlib/toml/toml.v +++ b/vlib/toml/toml.v @@ -58,70 +58,70 @@ fn decode_struct[T](doc Any, mut typ T) { typ.$(field.name) = value.time() } $else $if field.is_array { arr := value.array() - match typeof(typ.$(field.name)).name { - '[]string' { typ.$(field.name) = arr.as_strings() } - '[]int' { typ.$(field.name) = arr.map(it.int()) } - '[]i64' { typ.$(field.name) = arr.map(it.i64()) } - '[]u64' { typ.$(field.name) = arr.map(it.u64()) } - '[]f32' { typ.$(field.name) = arr.map(it.f32()) } - '[]f64' { typ.$(field.name) = arr.map(it.f64()) } - '[]bool' { typ.$(field.name) = arr.map(it.bool()) } - '[]toml.DateTime' { typ.$(field.name) = arr.map(it.datetime()) } - '[]toml.Date' { typ.$(field.name) = arr.map(it.date()) } - '[]toml.Time' { typ.$(field.name) = arr.map(it.time()) } + match field.typ { + []string { typ.$(field.name) = arr.as_strings() } + []int { typ.$(field.name) = arr.map(it.int()) } + []i64 { typ.$(field.name) = arr.map(it.i64()) } + []u64 { typ.$(field.name) = arr.map(it.u64()) } + []f32 { typ.$(field.name) = arr.map(it.f32()) } + []f64 { typ.$(field.name) = arr.map(it.f64()) } + []bool { typ.$(field.name) = arr.map(it.bool()) } + []DateTime { typ.$(field.name) = arr.map(it.datetime()) } + []Date { typ.$(field.name) = arr.map(it.date()) } + []Time { typ.$(field.name) = arr.map(it.time()) } else {} } } $else $if field.is_map { mut mmap := value.as_map() - match typeof(typ.$(field.name)).name { - 'map[string]string' { + match field.typ { + map[string]string { typ.$(field.name) = mmap.as_strings() } // Should be cleaned up to use the more modern lambda syntax // |k, v| k, v.int() // Unfortunately lambdas have issues with multiple return at the time of writing - 'map[string]int' { + map[string]int { typ.$(field.name) = maps.to_map[string, Any, string, int](mmap, fn (k string, v Any) (string, int) { return k, v.int() }) } - 'map[string]i64' { + map[string]i64 { typ.$(field.name) = maps.to_map[string, Any, string, i64](mmap, fn (k string, v Any) (string, i64) { return k, v.i64() }) } - 'map[string]u64' { + map[string]u64 { typ.$(field.name) = maps.to_map[string, Any, string, u64](mmap, fn (k string, v Any) (string, u64) { return k, v.u64() }) } - 'map[string]f32' { + map[string]f32 { typ.$(field.name) = maps.to_map[string, Any, string, f32](mmap, fn (k string, v Any) (string, f32) { return k, v.f32() }) } - 'map[string]f64' { + map[string]f64 { typ.$(field.name) = maps.to_map[string, Any, string, f64](mmap, fn (k string, v Any) (string, f64) { return k, v.f64() }) } - 'map[string]bool' { + map[string]bool { typ.$(field.name) = maps.to_map[string, Any, string, bool](mmap, fn (k string, v Any) (string, bool) { return k, v.bool() }) } - 'map[string]toml.DateTime' { + map[string]DateTime { typ.$(field.name) = maps.to_map[string, Any, string, DateTime](mmap, fn (k string, v Any) (string, DateTime) { return k, v.datetime() }) } - 'map[string]toml.Date' { + map[string]Date { typ.$(field.name) = maps.to_map[string, Any, string, Date](mmap, fn (k string, v Any) (string, Date) { return k, v.date() }) } - 'map[string]toml.Time' { + map[string]Time { typ.$(field.name) = maps.to_map[string, Any, string, Time](mmap, fn (k string, v Any) (string, Time) { return k, v.time() }) diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 31030097f0..be1a5921d4 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -322,7 +322,15 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym c.error('struct instances cannot be matched by type name, they can only be matched to other instances of the same struct type', branch.pos) } - if mut expr is ast.TypeNode && cond_sym.is_primitive() { + mut is_comptime := false + if c.comptime.inside_comptime_for { + // it is a compile-time field.typ checking + if mut node.cond is ast.SelectorExpr { + is_comptime = node.cond.expr_type == c.field_data_type + && node.cond.field_name == 'typ' + } + } + if mut expr is ast.TypeNode && cond_sym.is_primitive() && !is_comptime { c.error('matching by type can only be done for sum types, generics, interfaces, `${node.cond}` is none of those', branch.pos) } @@ -442,7 +450,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym expect_str := c.table.type_to_str(node.cond_type) c.error('cannot match alias type `${expect_str}` with `${expr_str}`', expr.pos()) - } else if !c.check_types(expr_type, node.cond_type) { + } else if !c.check_types(expr_type, node.cond_type) && !is_comptime { expr_str := c.table.type_to_str(expr_type) expect_str := c.table.type_to_str(node.cond_type) c.error('cannot match `${expect_str}` with `${expr_str}`', expr.pos()) diff --git a/vlib/v/parser/if_match.v b/vlib/v/parser/if_match.v index 961aaf0d6f..420d3a43c4 100644 --- a/vlib/v/parser/if_match.v +++ b/vlib/v/parser/if_match.v @@ -212,6 +212,8 @@ fn (mut p Parser) is_only_array_type() bool { next_kind := p.peek_token(i + 1).kind if next_kind == .name { return true + } else if next_kind == .question && p.peek_token(i + 2).kind == .name { + return true } else if next_kind == .lsbr { continue } else { diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index af07051d65..845aca777e 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -603,7 +603,7 @@ fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_dot b p.next() p.check(.dot) } - if !p.known_import(mod) && !p.pref.is_fmt { + if mod != p.mod && !p.known_import(mod) && !p.pref.is_fmt { mut msg := 'unknown module `${mod}`' if mod.len > mod_last_part.len && p.known_import(mod_last_part) { msg += '; did you mean `${mod_last_part}`?' diff --git a/vlib/v/tests/comptime_match_type_test.v b/vlib/v/tests/comptime_match_type_test.v new file mode 100644 index 0000000000..391c6c1716 --- /dev/null +++ b/vlib/v/tests/comptime_match_type_test.v @@ -0,0 +1,21 @@ +struct Test { + a int + b []int + c map[int]string + d []?int +} + +fn test_main() { + mut i := 1 + $for f in Test.fields { + type_name := typeof(f.$(f.name)).name + match f.typ { + int { assert i == 1, '1. ${f.name} is ${type_name}' } + []int { assert i == 2, '2. ${f.name} is ${type_name}' } + map[int]string { assert i == 3, '3. ${f.name} is ${type_name}' } + []?int { assert i == 4, '4. ${f.name} is ${type_name}' } + else {} + } + i++ + } +} diff --git a/vlib/x/json2/decoder.v b/vlib/x/json2/decoder.v index c0a977aefa..6127aa67a2 100644 --- a/vlib/x/json2/decoder.v +++ b/vlib/x/json2/decoder.v @@ -179,7 +179,7 @@ fn decode_struct[T](_ T, res map[string]Any) !T { } $else $if field.typ is i16 { typ.$(field.name) = res[json_name]!.int() } $else $if field.typ is i32 { - typ.$(field.name) = i32(res[field.name]!.int()) + typ.$(field.name) = i32(res[field.name]!.i32()) } $else $if field.typ is i64 { typ.$(field.name) = res[json_name]!.i64() } $else $if field.typ is ?u8 { @@ -250,38 +250,40 @@ fn decode_struct[T](_ T, res map[string]Any) !T { } } $else $if field.is_array { arr := res[field.name]! as []Any - match typeof(typ.$(field.name)).name { - '[]bool' { typ.$(field.name) = arr.map(it.bool()) } - '[]?bool' { typ.$(field.name) = arr.map(?bool(it.bool())) } - '[]f32' { typ.$(field.name) = arr.map(it.f32()) } - '[]?f32' { typ.$(field.name) = arr.map(?f32(it.f32())) } - '[]f64' { typ.$(field.name) = arr.map(it.f64()) } - '[]?f64' { typ.$(field.name) = arr.map(?f64(it.f64())) } - '[]i8' { typ.$(field.name) = arr.map(it.i8()) } - '[]?i8' { typ.$(field.name) = arr.map(?i8(it.i8())) } - '[]i16' { typ.$(field.name) = arr.map(it.i16()) } - '[]?i16' { typ.$(field.name) = arr.map(?i16(it.i16())) } - '[]i64' { typ.$(field.name) = arr.map(it.i64()) } - '[]?i64' { typ.$(field.name) = arr.map(?i64(it.i64())) } - '[]int' { typ.$(field.name) = arr.map(it.int()) } - '[]?int' { typ.$(field.name) = arr.map(?int(it.int())) } - '[]string' { typ.$(field.name) = arr.map(it.str()) } - '[]?string' { typ.$(field.name) = arr.map(?string(it.str())) } + // vfmt off + match field.typ { + []bool { typ.$(field.name) = arr.map(it.bool()) } + []?bool { typ.$(field.name) = arr.map(?bool(it.bool())) } + []f32 { typ.$(field.name) = arr.map(it.f32()) } + []?f32 { typ.$(field.name) = arr.map(?f32(it.f32())) } + []f64 { typ.$(field.name) = arr.map(it.f64()) } + []?f64 { typ.$(field.name) = arr.map(?f64(it.f64())) } + []i8 { typ.$(field.name) = arr.map(it.i8()) } + []?i8 { typ.$(field.name) = arr.map(?i8(it.i8())) } + []i16 { typ.$(field.name) = arr.map(it.i16()) } + []?i16 { typ.$(field.name) = arr.map(?i16(it.i16())) } + []i32 { typ.$(field.name) = arr.map(it.i32()) } + []?i32 { typ.$(field.name) = arr.map(?i32(it.i32())) } + []i64 { typ.$(field.name) = arr.map(it.i64()) } + []?i64 { typ.$(field.name) = arr.map(?i64(it.i64())) } + []int { typ.$(field.name) = arr.map(it.int()) } + []?int { typ.$(field.name) = arr.map(?int(it.int())) } + []string { typ.$(field.name) = arr.map(it.str()) } + []?string { typ.$(field.name) = arr.map(?string(it.str())) } // NOTE: Using `!` on `to_time()` inside the array method causes a builder error - 2024/04/01. - '[]time.Time' { typ.$(field.name) = arr.map(it.to_time() or { time.Time{} }) } - // vfmt off - '[]?time.Time' { typ.$(field.name) = arr.map(?time.Time(it.to_time() or { time.Time{} })) } - // vfmt on - '[]u8' { typ.$(field.name) = arr.map(it.u64()) } - '[]?u8' { typ.$(field.name) = arr.map(?u8(it.u64())) } - '[]u16' { typ.$(field.name) = arr.map(it.u64()) } - '[]?u16' { typ.$(field.name) = arr.map(?u16(it.u64())) } - '[]u32' { typ.$(field.name) = arr.map(it.u64()) } - '[]?u32' { typ.$(field.name) = arr.map(?u32(it.u64())) } - '[]u64' { typ.$(field.name) = arr.map(it.u64()) } - '[]?u64' { typ.$(field.name) = arr.map(?u64(it.u64())) } + []time.Time { typ.$(field.name) = arr.map(it.to_time() or { time.Time{} }) } + []?time.Time { typ.$(field.name) = arr.map(?time.Time(it.to_time() or { time.Time{} })) } + []u8 { typ.$(field.name) = arr.map(it.u64()) } + []?u8 { typ.$(field.name) = arr.map(?u8(it.u64())) } + []u16 { typ.$(field.name) = arr.map(it.u64()) } + []?u16 { typ.$(field.name) = arr.map(?u16(it.u64())) } + []u32 { typ.$(field.name) = arr.map(it.u64()) } + []?u32 { typ.$(field.name) = arr.map(?u32(it.u64())) } + []u64 { typ.$(field.name) = arr.map(it.u64()) } + []?u64 { typ.$(field.name) = arr.map(?u64(it.u64())) } else {} } + // vfmt on } $else $if field.is_struct { typ.$(field.name) = decode_struct(typ.$(field.name), res[field.name]!.as_map())! } $else $if field.is_alias { diff --git a/vlib/x/json2/json2.v b/vlib/x/json2/json2.v index 508daa4b26..fea8590376 100644 --- a/vlib/x/json2/json2.v +++ b/vlib/x/json2/json2.v @@ -5,13 +5,13 @@ module json2 import time -// i8 - TODO +// i8 uses `Any` as a 16-bit integer. pub fn (f Any) i8() i8 { match f { i8 { return f } - i16, int, i64, u8, u16, u32, u64, f32, f64, bool { + i16, i32, int, i64, u8, u16, u32, u64, f32, f64, bool { return i8(f) } string { @@ -23,13 +23,13 @@ pub fn (f Any) i8() i8 { } } -// i16 - TODO +// i16 uses `Any` as a 16-bit integer. pub fn (f Any) i16() i16 { match f { i16 { return f } - i8, int, i64, u8, u16, u32, u64, f32, f64, bool { + i8, i32, int, i64, u8, u16, u32, u64, f32, f64, bool { return i16(f) } string { @@ -47,7 +47,7 @@ pub fn (f Any) int() int { int { return f } - i8, i16, i64, u8, u16, u32, u64, f32, f64, bool { + i8, i16, i32, i64, u8, u16, u32, u64, f32, f64, bool { return int(f) } string { @@ -59,13 +59,31 @@ pub fn (f Any) int() int { } } +// i32 uses `Any` as a 32-bit integer. +pub fn (f Any) i32() i32 { + match f { + i32 { + return f + } + i8, i16, int, i64, u8, u16, u32, u64, f32, f64, bool { + return i32(f) + } + string { + return f.i32() + } + else { + return 0 + } + } +} + // i64 uses `Any` as a 64-bit integer. pub fn (f Any) i64() i64 { match f { i64 { return f } - i8, i16, int, u8, u16, u32, u64, f32, f64, bool { + i8, i16, i32, int, u8, u16, u32, u64, f32, f64, bool { return i64(f) } string { @@ -83,7 +101,7 @@ pub fn (f Any) u64() u64 { u64 { return f } - u8, u16, u32, i8, i16, int, i64, f32, f64, bool { + u8, u16, u32, i8, i16, i32, int, i64, f32, f64, bool { return u64(f) } string { @@ -101,7 +119,7 @@ pub fn (f Any) f32() f32 { f32 { return f } - bool, i8, i16, int, i64, u8, u16, u32, u64, f64 { + bool, i8, i16, i32, int, i64, u8, u16, u32, u64, f64 { return f32(f) } string { @@ -119,7 +137,7 @@ pub fn (f Any) f64() f64 { f64 { return f } - i8, i16, int, i64, u8, u16, u32, u64, f32 { + i8, i16, i32, int, i64, u8, u16, u32, u64, f32 { return f64(f) } string { @@ -150,7 +168,7 @@ pub fn (f Any) bool() bool { return false } } - i8, i16, int, i64 { + i8, i16, i32, int, i64 { return i64(f) != 0 } u8, u16, u32, u64 { @@ -266,6 +284,8 @@ pub fn map_from[T](t T) map[string]Any { m[field.name] = t.$(field.name).str().i8() } $else $if field.typ is i16 { m[field.name] = t.$(field.name).str().i16() + } $else $if field.typ is i32 { + m[field.name] = t.$(field.name).str().i32() } $else $if field.typ is int { m[field.name] = t.$(field.name).str().int() } $else $if field.typ is i64 { diff --git a/vlib/x/json2/types.v b/vlib/x/json2/types.v index 9a96c93d19..65d35a8825 100644 --- a/vlib/x/json2/types.v +++ b/vlib/x/json2/types.v @@ -9,6 +9,7 @@ pub type Any = Null | f32 | f64 | i16 + | i32 | i64 | i8 | int