checker: restrict numeric promotions to cases where no data is lost
parent
fc67046bac
commit
013fdb8a4b
|
@ -50,7 +50,7 @@ pub fn new_test_session(_vargs string) TestSession {
|
||||||
skip_files: skip_files
|
skip_files: skip_files
|
||||||
vargs: vargs
|
vargs: vargs
|
||||||
show_ok_tests: !_vargs.contains('-silent')
|
show_ok_tests: !_vargs.contains('-silent')
|
||||||
message_handler: 0
|
message_handler: &TestMessageHandler(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
doc/docs.md
23
doc/docs.md
|
@ -269,6 +269,8 @@ rune // represents a Unicode code point
|
||||||
|
|
||||||
f32 f64
|
f32 f64
|
||||||
|
|
||||||
|
any_int, any_float // internal intermediate types of number literals
|
||||||
|
|
||||||
byteptr // these two are mostly used for C interop
|
byteptr // these two are mostly used for C interop
|
||||||
voidptr
|
voidptr
|
||||||
|
|
||||||
|
@ -277,6 +279,27 @@ any // similar to C's void* and Go's interface{}
|
||||||
|
|
||||||
Please note that unlike C and Go, `int` is always a 32 bit integer.
|
Please note that unlike C and Go, `int` is always a 32 bit integer.
|
||||||
|
|
||||||
|
There is an exceptions to the rule that all operators
|
||||||
|
in V must have values of the same type on both sides. A small primitive type
|
||||||
|
on one side can be automatically promoted if it fits
|
||||||
|
completely into the data range of the type on the other side, i.e. when
|
||||||
|
the promotion does not result in any data loss.
|
||||||
|
These are the allowed possibilities:
|
||||||
|
|
||||||
|
```
|
||||||
|
i8 → i16 → int → i64
|
||||||
|
↘ ↘
|
||||||
|
f32 → f64
|
||||||
|
↗ ↗
|
||||||
|
byte → u16 → u32 → u64 ⬎
|
||||||
|
↘ ↘ ↘ ptr
|
||||||
|
i8 → i16 → int → i64 ⬏
|
||||||
|
```
|
||||||
|
An `int` value for example can be automatically promoted to `f64`
|
||||||
|
or `i64` but not to `f32` or `u32`. (`f32` would mean precission
|
||||||
|
loss for large values and `u32` would mean loss of the sign for
|
||||||
|
negative values).
|
||||||
|
|
||||||
## Strings
|
## Strings
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
|
|
@ -360,9 +360,9 @@ pub fn (b []byte) hex() string {
|
||||||
mut dst_i := 0
|
mut dst_i := 0
|
||||||
for i in b {
|
for i in b {
|
||||||
n0 := i >> 4
|
n0 := i >> 4
|
||||||
hex[dst_i++] = if n0 < 10 { n0 + `0` } else { n0 + 87 }
|
hex[dst_i++] = if n0 < 10 { n0 + `0` } else { n0 + byte(87) }
|
||||||
n1 := i & 0xF
|
n1 := i & 0xF
|
||||||
hex[dst_i++] = if n1 < 10 { n1 + `0` } else { n1 + 87 }
|
hex[dst_i++] = if n1 < 10 { n1 + `0` } else { n1 + byte(87) }
|
||||||
}
|
}
|
||||||
hex[dst_i] = `\0`
|
hex[dst_i] = `\0`
|
||||||
return tos(hex,dst_i)
|
return tos(hex,dst_i)
|
||||||
|
|
|
@ -468,6 +468,10 @@ fn test_in() {
|
||||||
assert !(0 in a)
|
assert !(0 in a)
|
||||||
assert 0 !in a
|
assert 0 !in a
|
||||||
assert 4 !in a
|
assert 4 !in a
|
||||||
|
b := [1, 4, 0]
|
||||||
|
c := [3, 6, 2, 0]
|
||||||
|
assert 0 in b
|
||||||
|
assert 0 in c
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sum(prev int, curr int) int {
|
fn sum(prev int, curr int) int {
|
||||||
|
@ -557,7 +561,7 @@ fn test_map() {
|
||||||
assert strs.map(it.to_upper()) == ['V', 'IS', 'AWESOME']
|
assert strs.map(it.to_upper()) == ['V', 'IS', 'AWESOME']
|
||||||
assert strs.map(it == 'awesome') == [false, false, true]
|
assert strs.map(it == 'awesome') == [false, false, true]
|
||||||
assert strs.map(it.len in nums) == [true, true, false]
|
assert strs.map(it.len in nums) == [true, true, false]
|
||||||
assert strs.map(7) == [7, 7, 7]
|
assert strs.map(int(7)) == [7, 7, 7]
|
||||||
|
|
||||||
// external func
|
// external func
|
||||||
assert nums.map(map_test_helper_1(it)) == [1, 4, 9, 16, 25, 36]
|
assert nums.map(map_test_helper_1(it)) == [1, 4, 9, 16, 25, 36]
|
||||||
|
@ -568,9 +572,9 @@ fn test_map() {
|
||||||
assert []int{len:0}.map(it * 2) == []
|
assert []int{len:0}.map(it * 2) == []
|
||||||
|
|
||||||
// nested maps (where it is of same type)
|
// nested maps (where it is of same type)
|
||||||
assert nums.map( strs.map(7) == [7, 7, 7] ) == [true, true, true, true, true, true]
|
assert nums.map( strs.map(int(7)) == [7, 7, 7] ) == [true, true, true, true, true, true]
|
||||||
assert nums.map( '$it' + strs.map('a')[0] ) == ['1a', '2a', '3a', '4a', '5a', '6a']
|
assert nums.map( '$it' + strs.map('a')[0] ) == ['1a', '2a', '3a', '4a', '5a', '6a']
|
||||||
assert nums.map( it + strs.map(7)[0] ) == [8, 9, 10, 11, 12, 13]
|
assert nums.map( it + strs.map(int(7))[0] ) == [8, 9, 10, 11, 12, 13]
|
||||||
assert nums.map( it + strs.map(it.len)[0] ) == [2, 3, 4, 5, 6, 7]
|
assert nums.map( it + strs.map(it.len)[0] ) == [2, 3, 4, 5, 6, 7]
|
||||||
assert strs.map( it.len + strs.map(it.len)[0] ) == [2, 3, 8]
|
assert strs.map( it.len + strs.map(it.len)[0] ) == [2, 3, 8]
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,17 @@ pub fn (d f64) str() string {
|
||||||
return ftoa.ftoa_64(d)
|
return ftoa.ftoa_64(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (d any_float) str() string {
|
||||||
|
x := f64(d)
|
||||||
|
abs_x := f64_abs(x)
|
||||||
|
if abs_x >= 0.01 && abs_x < 1.0e16 {
|
||||||
|
return ftoa.f64_to_str_l(x)
|
||||||
|
} else {
|
||||||
|
return ftoa.ftoa_64(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// return a string of the input f64 in scientific notation with digit_num deciamals displayed, max 17 digits
|
// return a string of the input f64 in scientific notation with digit_num deciamals displayed, max 17 digits
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (x f64) strsci(digit_num int) string {
|
pub fn (x f64) strsci(digit_num int) string {
|
||||||
|
@ -84,7 +95,7 @@ pub fn (a f64) eq(b f64) bool {
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (a f32) eq(b f32) bool {
|
pub fn (a f32) eq(b f32) bool {
|
||||||
return f32_abs(a - b) <= C.FLT_EPSILON
|
return f32_abs(a - b) <= f32(C.FLT_EPSILON)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a f64) eqbit(b f64) bool {
|
pub fn (a f64) eqbit(b f64) bool {
|
||||||
|
|
|
@ -144,6 +144,11 @@ pub fn (nn u32) str() string {
|
||||||
//return tos(buf + index, (max-index))
|
//return tos(buf + index, (max-index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (n any_int) str() string {
|
||||||
|
return i64(n).str()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (nn i64) str() string {
|
pub fn (nn i64) str() string {
|
||||||
mut n := nn
|
mut n := nn
|
||||||
mut d := i64(0)
|
mut d := i64(0)
|
||||||
|
@ -188,7 +193,7 @@ pub fn (nn i64) str() string {
|
||||||
|
|
||||||
pub fn (nn u64) str() string {
|
pub fn (nn u64) str() string {
|
||||||
mut n := nn
|
mut n := nn
|
||||||
mut d := 0
|
mut d := u64(0)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return '0'
|
return '0'
|
||||||
}
|
}
|
||||||
|
@ -274,7 +279,7 @@ pub fn (nn u16) hex() string {
|
||||||
mut index := max
|
mut index := max
|
||||||
buf[index--] = `\0`
|
buf[index--] = `\0`
|
||||||
for n > 0 {
|
for n > 0 {
|
||||||
d := n & 0xF
|
d := byte(n & 0xF)
|
||||||
n = n >> 4
|
n = n >> 4
|
||||||
buf[index--] = if d < 10 { d + `0` } else { d + 87 }
|
buf[index--] = if d < 10 { d + `0` } else { d + 87 }
|
||||||
}
|
}
|
||||||
|
@ -301,7 +306,7 @@ pub fn (nn u32) hex() string {
|
||||||
mut index := max
|
mut index := max
|
||||||
buf[index--] = `\0`
|
buf[index--] = `\0`
|
||||||
for n > 0 {
|
for n > 0 {
|
||||||
d := n & 0xF
|
d := byte(n & 0xF)
|
||||||
n = n >> 4
|
n = n >> 4
|
||||||
buf[index--] = if d < 10 { d + `0` } else { d + 87 }
|
buf[index--] = if d < 10 { d + `0` } else { d + 87 }
|
||||||
}
|
}
|
||||||
|
@ -328,7 +333,7 @@ pub fn (nn u64) hex() string {
|
||||||
mut index := max
|
mut index := max
|
||||||
buf[index--] = `\0`
|
buf[index--] = `\0`
|
||||||
for n > 0 {
|
for n > 0 {
|
||||||
d := n & 0xF
|
d := byte(n & 0xF)
|
||||||
n = n >> 4
|
n = n >> 4
|
||||||
buf[index--] = if d < 10 { d + `0` } else { d + 87 }
|
buf[index--] = if d < 10 { d + `0` } else { d + 87 }
|
||||||
}
|
}
|
||||||
|
@ -345,6 +350,10 @@ pub fn (nn i64) hex() string {
|
||||||
return u64(nn).hex()
|
return u64(nn).hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (nn any_int) hex() string {
|
||||||
|
return u64(nn).hex()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (nn voidptr) str() string {
|
pub fn (nn voidptr) str() string {
|
||||||
return u64(nn).hex()
|
return u64(nn).hex()
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,7 +214,7 @@ fn test_int_to_hex() {
|
||||||
assert u32(c0).hex() == 'c'
|
assert u32(c0).hex() == 'c'
|
||||||
assert 2147483647.hex() == '7fffffff'
|
assert 2147483647.hex() == '7fffffff'
|
||||||
assert u32(2147483647).hex() == '7fffffff'
|
assert u32(2147483647).hex() == '7fffffff'
|
||||||
assert (-1).hex() == 'ffffffff'
|
assert (-1).hex() == 'ffffffffffffffff'
|
||||||
assert u32(4294967295).hex() == 'ffffffff'
|
assert u32(4294967295).hex() == 'ffffffff'
|
||||||
// 64 bit
|
// 64 bit
|
||||||
assert u64(0).hex() == '0'
|
assert u64(0).hex() == '0'
|
||||||
|
|
|
@ -123,22 +123,22 @@ fn (mut d DenseArray) push(key string, value voidptr) u32 {
|
||||||
if d.cap == d.size {
|
if d.cap == d.size {
|
||||||
d.cap += d.cap >> 3
|
d.cap += d.cap >> 3
|
||||||
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
|
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
|
||||||
d.values = C.realloc(d.values, d.value_bytes * d.cap)
|
d.values = C.realloc(d.values, u32(d.value_bytes) * d.cap)
|
||||||
}
|
}
|
||||||
push_index := d.size
|
push_index := d.size
|
||||||
d.keys[push_index] = key
|
d.keys[push_index] = key
|
||||||
C.memcpy(d.values + push_index * d.value_bytes, value, d.value_bytes)
|
C.memcpy(d.values + push_index * u32(d.value_bytes), value, d.value_bytes)
|
||||||
d.size++
|
d.size++
|
||||||
return push_index
|
return push_index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (d DenseArray) get(i int) voidptr {
|
fn (d DenseArray) get(i int) voidptr {
|
||||||
$if !no_bounds_checking? {
|
$if !no_bounds_checking? {
|
||||||
if i < 0 || i >= d.size {
|
if i < 0 || i >= int(d.size) {
|
||||||
panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)')
|
panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return byteptr(d.keys) + i * sizeof(string)
|
return byteptr(d.keys) + i * int(sizeof(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move all zeros to the end of the array
|
// Move all zeros to the end of the array
|
||||||
|
@ -153,8 +153,8 @@ fn (mut d DenseArray) zeros_to_end() {
|
||||||
d.keys[count] = d.keys[i]
|
d.keys[count] = d.keys[i]
|
||||||
d.keys[i] = tmp_key
|
d.keys[i] = tmp_key
|
||||||
// swap values (TODO: optimize)
|
// swap values (TODO: optimize)
|
||||||
C.memcpy(tmp_value, d.values + count * d.value_bytes, d.value_bytes)
|
C.memcpy(tmp_value, d.values + count * u32(d.value_bytes), d.value_bytes)
|
||||||
C.memcpy(d.values + count * d.value_bytes, d.values + i * d.value_bytes, d.value_bytes)
|
C.memcpy(d.values + count * u32(d.value_bytes), d.values + i * d.value_bytes, d.value_bytes)
|
||||||
C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes)
|
C.memcpy(d.values + i * d.value_bytes, tmp_value, d.value_bytes)
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ fn (mut d DenseArray) zeros_to_end() {
|
||||||
d.size = count
|
d.size = count
|
||||||
d.cap = if count < 8 { u32(8) } else { count }
|
d.cap = if count < 8 { u32(8) } else { count }
|
||||||
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
|
d.keys = &string(C.realloc(d.keys, sizeof(string) * d.cap))
|
||||||
d.values = C.realloc(d.values, d.value_bytes * d.cap)
|
d.values = C.realloc(d.values, u32(d.value_bytes) * d.cap)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct map {
|
pub struct map {
|
||||||
|
@ -280,7 +280,7 @@ fn (mut m map) set(k string, value voidptr) {
|
||||||
for meta == m.metas[index] {
|
for meta == m.metas[index] {
|
||||||
kv_index := m.metas[index + 1]
|
kv_index := m.metas[index + 1]
|
||||||
if fast_string_eq(key, m.key_values.keys[kv_index]) {
|
if fast_string_eq(key, m.key_values.keys[kv_index]) {
|
||||||
C.memcpy(m.key_values.values + kv_index * m.value_bytes , value, m.value_bytes)
|
C.memcpy(m.key_values.values + kv_index * u32(m.value_bytes), value, m.value_bytes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
index += 2
|
index += 2
|
||||||
|
@ -349,7 +349,7 @@ fn (m map) get3(key string, zero voidptr) voidptr {
|
||||||
if meta == m.metas[index] {
|
if meta == m.metas[index] {
|
||||||
kv_index := m.metas[index + 1]
|
kv_index := m.metas[index + 1]
|
||||||
if fast_string_eq(key, m.key_values.keys[kv_index]) {
|
if fast_string_eq(key, m.key_values.keys[kv_index]) {
|
||||||
return voidptr(m.key_values.values + kv_index * m.value_bytes)
|
return voidptr(m.key_values.values + kv_index * u32(m.value_bytes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index += 2
|
index += 2
|
||||||
|
@ -431,10 +431,10 @@ pub fn (d DenseArray) clone() DenseArray {
|
||||||
size: d.size
|
size: d.size
|
||||||
deletes: d.deletes
|
deletes: d.deletes
|
||||||
keys: &string(malloc(d.cap * sizeof(string)))
|
keys: &string(malloc(d.cap * sizeof(string)))
|
||||||
values: byteptr(malloc(d.cap * d.value_bytes))
|
values: byteptr(malloc(d.cap * u32(d.value_bytes)))
|
||||||
}
|
}
|
||||||
C.memcpy(res.keys, d.keys, d.cap * sizeof(string))
|
C.memcpy(res.keys, d.keys, d.cap * sizeof(string))
|
||||||
C.memcpy(res.values, d.values, d.cap * d.value_bytes)
|
C.memcpy(res.values, d.values, d.cap * u32(d.value_bytes))
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -750,7 +750,7 @@ pub fn (s string) ends_with(p string) bool {
|
||||||
pub fn (s string) to_lower() string {
|
pub fn (s string) to_lower() string {
|
||||||
mut b := malloc(s.len + 1)
|
mut b := malloc(s.len + 1)
|
||||||
for i in 0..s.len {
|
for i in 0..s.len {
|
||||||
b[i] = C.tolower(s.str[i])
|
b[i] = byte(C.tolower(s.str[i]))
|
||||||
}
|
}
|
||||||
return tos(b, s.len)
|
return tos(b, s.len)
|
||||||
}
|
}
|
||||||
|
@ -767,7 +767,7 @@ pub fn (s string) is_lower() bool {
|
||||||
pub fn (s string) to_upper() string {
|
pub fn (s string) to_upper() string {
|
||||||
mut b := malloc(s.len + 1)
|
mut b := malloc(s.len + 1)
|
||||||
for i in 0..s.len {
|
for i in 0..s.len {
|
||||||
b[i] = C.toupper(s.str[i])
|
b[i] = byte(C.toupper(s.str[i]))
|
||||||
}
|
}
|
||||||
return tos(b, s.len)
|
return tos(b, s.len)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,33 +13,33 @@ pub fn utf32_to_str(code u32) string {
|
||||||
icode := int(code) // Prevents doing casts everywhere
|
icode := int(code) // Prevents doing casts everywhere
|
||||||
mut buffer := malloc(5)
|
mut buffer := malloc(5)
|
||||||
if icode <= 127/* 0x7F */ {
|
if icode <= 127/* 0x7F */ {
|
||||||
buffer[0] = icode
|
buffer[0] = byte(icode)
|
||||||
return tos(buffer, 1)
|
return tos(buffer, 1)
|
||||||
}
|
}
|
||||||
if icode <= 2047/* 0x7FF */ {
|
if icode <= 2047/* 0x7FF */ {
|
||||||
buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */
|
buffer[0] = 192/*0xC0*/ | byte(icode>>6)/* 110xxxxx */
|
||||||
|
|
||||||
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[1] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
return tos(buffer, 2)
|
return tos(buffer, 2)
|
||||||
}
|
}
|
||||||
if icode <= 65535/* 0xFFFF */ {
|
if icode <= 65535/* 0xFFFF */ {
|
||||||
buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */
|
buffer[0] = 224/*0xE0*/ | byte(icode>>12)/* 1110xxxx */
|
||||||
|
|
||||||
buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[1] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[2] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
return tos(buffer, 3)
|
return tos(buffer, 3)
|
||||||
}
|
}
|
||||||
if icode <= 1114111/* 0x10FFFF */ {
|
if icode <= 1114111/* 0x10FFFF */ {
|
||||||
buffer[0] = 240/*0xF0*/ | (icode>>18)/* 11110xxx */
|
buffer[0] = 240/*0xF0*/ | byte(icode>>18)/* 11110xxx */
|
||||||
|
|
||||||
buffer[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[1] = 128/*0x80*/ | (byte(icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
buffer[2] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[2] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
buffer[3] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[3] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
return tos(buffer, 4)
|
return tos(buffer, 4)
|
||||||
}
|
}
|
||||||
|
@ -51,33 +51,33 @@ pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
|
||||||
icode := int(code) // Prevents doing casts everywhere
|
icode := int(code) // Prevents doing casts everywhere
|
||||||
mut buffer := byteptr(buf)
|
mut buffer := byteptr(buf)
|
||||||
if icode <= 127/* 0x7F */ {
|
if icode <= 127/* 0x7F */ {
|
||||||
buffer[0] = icode
|
buffer[0] = byte(icode)
|
||||||
return tos(buffer, 1)
|
return tos(buffer, 1)
|
||||||
}
|
}
|
||||||
if icode <= 2047/* 0x7FF */ {
|
if icode <= 2047/* 0x7FF */ {
|
||||||
buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */
|
buffer[0] = 192/*0xC0*/ | byte(icode>>6)/* 110xxxxx */
|
||||||
|
|
||||||
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[1] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
return tos(buffer, 2)
|
return tos(buffer, 2)
|
||||||
}
|
}
|
||||||
if icode <= 65535/* 0xFFFF */ {
|
if icode <= 65535/* 0xFFFF */ {
|
||||||
buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */
|
buffer[0] = 224/*0xE0*/ | byte(icode>>12)/* 1110xxxx */
|
||||||
|
|
||||||
buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[1] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[2] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
return tos(buffer, 3)
|
return tos(buffer, 3)
|
||||||
}
|
}
|
||||||
if icode <= 1114111/* 0x10FFFF */ {
|
if icode <= 1114111/* 0x10FFFF */ {
|
||||||
buffer[0] = 240/*0xF0*/ | (icode>>18)/* 11110xxx */
|
buffer[0] = 240/*0xF0*/ | byte(icode>>18)/* 11110xxx */
|
||||||
|
|
||||||
buffer[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[1] = 128/*0x80*/ | (byte(icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
buffer[2] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[2] = 128/*0x80*/ | (byte(icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
buffer[3] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
buffer[3] = 128/*0x80*/ | byte(icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||||
|
|
||||||
return tos(buffer, 4)
|
return tos(buffer, 4)
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ fn (mut cb Clipboard) free() {
|
||||||
fn to_wide(text string) &C.HGLOBAL {
|
fn to_wide(text string) &C.HGLOBAL {
|
||||||
len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len +
|
len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len +
|
||||||
1, C.NULL, 0)
|
1, C.NULL, 0)
|
||||||
buf := C.GlobalAlloc(C.GMEM_MOVEABLE, sizeof(u16) * len_required)
|
buf := C.GlobalAlloc(C.GMEM_MOVEABLE, i64(sizeof(u16)) * len_required)
|
||||||
if buf != C.HGLOBAL(C.NULL) {
|
if buf != C.HGLOBAL(C.NULL) {
|
||||||
mut locked := &u16(C.GlobalLock(buf))
|
mut locked := &u16(C.GlobalLock(buf))
|
||||||
C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, locked, len_required)
|
C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, locked, len_required)
|
||||||
|
|
|
@ -152,8 +152,8 @@ fn ft_load_char(face &C.FT_FaceRec, code i64) Character {
|
||||||
horizontal_bearing_px: gg.vec2((*face).glyph.metrics.horiBearingX >> 6, (*face).glyph.metrics.horiBearingY >> 6)
|
horizontal_bearing_px: gg.vec2((*face).glyph.metrics.horiBearingX >> 6, (*face).glyph.metrics.horiBearingY >> 6)
|
||||||
vertical_bearing_px: gg.vec2((*face).glyph.metrics.vertBearingX >> 6, (*face).glyph.metrics.vertBearingY >> 6) // not used for now
|
vertical_bearing_px: gg.vec2((*face).glyph.metrics.vertBearingX >> 6, (*face).glyph.metrics.vertBearingY >> 6) // not used for now
|
||||||
|
|
||||||
horizontal_advance_px: (*face).glyph.metrics.horiAdvance >> 6
|
horizontal_advance_px: u32((*face).glyph.metrics.horiAdvance) >> 6
|
||||||
vertical_advance_px: (*face).glyph.metrics.vertAdvance >> 6
|
vertical_advance_px: u32((*face).glyph.metrics.vertAdvance) >> 6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
||||||
}
|
}
|
||||||
if !os.exists(font_path) {
|
if !os.exists(font_path) {
|
||||||
eprintln('freetype: font "$font_path" does not exist')
|
eprintln('freetype: font "$font_path" does not exist')
|
||||||
return 0
|
return voidptr(0)
|
||||||
}
|
}
|
||||||
face := &C.FT_FaceRec{
|
face := &C.FT_FaceRec{
|
||||||
glyph: 0
|
glyph: 0
|
||||||
|
@ -289,11 +289,11 @@ fn (mut ctx FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
|
||||||
if cfg.align == gx.align_right {
|
if cfg.align == gx.align_right {
|
||||||
// width := utext.len * 7
|
// width := utext.len * 7
|
||||||
width := wx
|
width := wx
|
||||||
x -= width + 10
|
x -= f32(width + 10)
|
||||||
}
|
}
|
||||||
x *= ctx.scale
|
x *= f32(ctx.scale)
|
||||||
y *= ctx.scale
|
y *= f32(ctx.scale)
|
||||||
y += yoffset
|
y += f32(yoffset)
|
||||||
y = f32(ctx.height) - y // invert y direction
|
y = f32(ctx.height) - y // invert y direction
|
||||||
color := cfg.color
|
color := cfg.color
|
||||||
// Activate corresponding render state
|
// Activate corresponding render state
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn arc_vertices(x, y, r, start_angle, end_angle f32, segments int) []f32 {
|
||||||
mut vertices := []f32{}
|
mut vertices := []f32{}
|
||||||
start_rads := start_angle * 0.0174533 // deg -> rad approx
|
start_rads := start_angle * 0.0174533 // deg -> rad approx
|
||||||
end_rads := end_angle * 0.0174533
|
end_rads := end_angle * 0.0174533
|
||||||
increment := (end_rads - start_rads) / segments
|
increment := (end_rads - start_rads) / f32(segments)
|
||||||
vertices << [x + f32(math.cos(start_rads)) * r, y + f32(math.sin(start_rads)) * r] !
|
vertices << [x + f32(math.cos(start_rads)) * r, y + f32(math.sin(start_rads)) * r] !
|
||||||
mut i := 1
|
mut i := 1
|
||||||
for i < segments {
|
for i < segments {
|
||||||
|
|
|
@ -183,12 +183,12 @@ pub fn buffer_data(typ, size int, arr voidptr, draw_typ int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_data_int(typ int, vertices []int, draw_typ int) {
|
pub fn buffer_data_int(typ int, vertices []int, draw_typ int) {
|
||||||
size := sizeof(int) * vertices.len
|
size := sizeof(int) * u32(vertices.len)
|
||||||
C.glBufferData(typ, size, vertices.data, draw_typ)
|
C.glBufferData(typ, size, vertices.data, draw_typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buffer_data_f32(typ int, vertices []f32, draw_typ int) {
|
pub fn buffer_data_f32(typ int, vertices []f32, draw_typ int) {
|
||||||
size := sizeof(f32) * vertices.len
|
size := sizeof(f32) * u32(vertices.len)
|
||||||
C.glBufferData(typ, size, vertices.data, draw_typ)
|
C.glBufferData(typ, size, vertices.data, draw_typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,11 +263,11 @@ pub fn gen_buffer() u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vertex_attrib_pointer(index, size int, typ int, normalized bool, _stride int, _ptr int) {
|
pub fn vertex_attrib_pointer(index, size int, typ int, normalized bool, _stride int, _ptr int) {
|
||||||
mut stride := _stride
|
mut stride := u32(_stride)
|
||||||
mut ptr := _ptr
|
mut ptr := _ptr
|
||||||
if typ == C.GL_FLOAT {
|
if typ == C.GL_FLOAT {
|
||||||
stride *= sizeof(f32)
|
stride *= sizeof(f32)
|
||||||
ptr *= sizeof(f32)
|
ptr *= int(sizeof(f32))
|
||||||
}
|
}
|
||||||
C.glVertexAttribPointer(index, size, typ, normalized, stride, ptr)
|
C.glVertexAttribPointer(index, size, typ, normalized, stride, ptr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,8 +191,8 @@ pub fn (mut ws Client) close(code int, message string) {
|
||||||
code_ := C.htons(code)
|
code_ := C.htons(code)
|
||||||
message_len := message.len + 2
|
message_len := message.len + 2
|
||||||
mut close_frame := [`0`].repeat(message_len)
|
mut close_frame := [`0`].repeat(message_len)
|
||||||
close_frame[0] = code_ & 0xFF
|
close_frame[0] = byte(code_ & 0xFF)
|
||||||
close_frame[1] = (code_ >> 8)
|
close_frame[1] = byte(code_ >> 8)
|
||||||
code32 = (close_frame[0] << 8) + close_frame[1]
|
code32 = (close_frame[0] << 8) + close_frame[1]
|
||||||
for i in 0 .. message.len {
|
for i in 0 .. message.len {
|
||||||
close_frame[i + 2] = message[i]
|
close_frame[i + 2] = message[i]
|
||||||
|
@ -248,9 +248,9 @@ pub fn (mut ws Client) write(payload byteptr, payload_len int, code OPCode) int
|
||||||
fbdata := byteptr( frame_buf.data )
|
fbdata := byteptr( frame_buf.data )
|
||||||
masking_key := create_masking_key()
|
masking_key := create_masking_key()
|
||||||
mut header := [`0`].repeat(header_len)
|
mut header := [`0`].repeat(header_len)
|
||||||
header[0] = (int(code) | 0x80)
|
header[0] = byte(code) | 0x80
|
||||||
if payload_len <= 125 {
|
if payload_len <= 125 {
|
||||||
header[1] = (payload_len | 0x80)
|
header[1] = byte(payload_len | 0x80)
|
||||||
header[2] = masking_key[0]
|
header[2] = masking_key[0]
|
||||||
header[3] = masking_key[1]
|
header[3] = masking_key[1]
|
||||||
header[4] = masking_key[2]
|
header[4] = masking_key[2]
|
||||||
|
@ -417,7 +417,7 @@ pub fn (mut ws Client) read() int {
|
||||||
} else if frame.opcode in [.text_frame, .binary_frame] {
|
} else if frame.opcode in [.text_frame, .binary_frame] {
|
||||||
data_node:
|
data_node:
|
||||||
l.d('read: recieved text_frame or binary_frame')
|
l.d('read: recieved text_frame or binary_frame')
|
||||||
mut payload := malloc(sizeof(byte) * int(payload_len) + 1)
|
mut payload := malloc(sizeof(byte) * u32(payload_len) + 1)
|
||||||
if payload == 0 {
|
if payload == 0 {
|
||||||
l.f('out of memory')
|
l.f('out of memory')
|
||||||
}
|
}
|
||||||
|
@ -437,7 +437,7 @@ pub fn (mut ws Client) read() int {
|
||||||
size += f.len
|
size += f.len
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut pl := malloc(sizeof(byte) * int(size))
|
mut pl := malloc(sizeof(byte) * u32(size))
|
||||||
if pl == 0 {
|
if pl == 0 {
|
||||||
l.f('out of memory')
|
l.f('out of memory')
|
||||||
}
|
}
|
||||||
|
@ -581,8 +581,8 @@ fn (mut ws Client) send_control_frame(code OPCode, frame_typ string, payload []b
|
||||||
frame_len := header_len + payload.len
|
frame_len := header_len + payload.len
|
||||||
mut control_frame := [`0`].repeat(frame_len)
|
mut control_frame := [`0`].repeat(frame_len)
|
||||||
masking_key := create_masking_key()
|
masking_key := create_masking_key()
|
||||||
control_frame[0] = (int(code) | 0x80)
|
control_frame[0] = byte(code | 0x80)
|
||||||
control_frame[1] = (payload.len | 0x80)
|
control_frame[1] = byte(payload.len | 0x80)
|
||||||
control_frame[2] = masking_key[0]
|
control_frame[2] = masking_key[0]
|
||||||
control_frame[3] = masking_key[1]
|
control_frame[3] = masking_key[1]
|
||||||
control_frame[4] = masking_key[2]
|
control_frame[4] = masking_key[2]
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn getenv(key string) string {
|
||||||
return string_from_wide(s)
|
return string_from_wide(s)
|
||||||
} $else {
|
} $else {
|
||||||
s := C.getenv(key.str)
|
s := C.getenv(key.str)
|
||||||
if s == 0 {
|
if s == voidptr(0) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
// NB: C.getenv *requires* that the result be copied.
|
// NB: C.getenv *requires* that the result be copied.
|
||||||
|
|
|
@ -35,19 +35,19 @@ pub fn inode(path string) FileMode {
|
||||||
C.stat(path.str, &attr)
|
C.stat(path.str, &attr)
|
||||||
|
|
||||||
mut typ := FileType.regular
|
mut typ := FileType.regular
|
||||||
if attr.st_mode & C.S_IFMT == C.S_IFDIR {
|
if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFDIR) {
|
||||||
typ = .directory
|
typ = .directory
|
||||||
}
|
}
|
||||||
$if !windows {
|
$if !windows {
|
||||||
if attr.st_mode & C.S_IFMT == C.S_IFCHR {
|
if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFCHR) {
|
||||||
typ = .character_device
|
typ = .character_device
|
||||||
} else if attr.st_mode & C.S_IFMT == C.S_IFBLK {
|
} else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFBLK) {
|
||||||
typ = .block_device
|
typ = .block_device
|
||||||
} else if attr.st_mode & C.S_IFMT == C.S_IFIFO {
|
} else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFIFO) {
|
||||||
typ = .fifo
|
typ = .fifo
|
||||||
} else if attr.st_mode & C.S_IFMT == C.S_IFLNK {
|
} else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFLNK) {
|
||||||
typ = .symbolic_link
|
typ = .symbolic_link
|
||||||
} else if attr.st_mode & C.S_IFMT == C.S_IFSOCK {
|
} else if attr.st_mode & u32(C.S_IFMT) == u32(C.S_IFSOCK) {
|
||||||
typ = .socket
|
typ = .socket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,38 +56,38 @@ pub fn inode(path string) FileMode {
|
||||||
return FileMode{
|
return FileMode{
|
||||||
typ: typ
|
typ: typ
|
||||||
owner: FilePermission{
|
owner: FilePermission{
|
||||||
read: bool(attr.st_mode & C.S_IREAD)
|
read: bool(attr.st_mode & u32(C.S_IREAD))
|
||||||
write: bool(attr.st_mode & C.S_IWRITE)
|
write: bool(attr.st_mode & u32(C.S_IWRITE))
|
||||||
execute: bool(attr.st_mode & C.S_IEXEC)
|
execute: bool(attr.st_mode & u32(C.S_IEXEC))
|
||||||
}
|
}
|
||||||
group: FilePermission{
|
group: FilePermission{
|
||||||
read: bool(attr.st_mode & C.S_IREAD)
|
read: bool(attr.st_mode & u32(C.S_IREAD))
|
||||||
write: bool(attr.st_mode & C.S_IWRITE)
|
write: bool(attr.st_mode & u32(C.S_IWRITE))
|
||||||
execute: bool(attr.st_mode & C.S_IEXEC)
|
execute: bool(attr.st_mode & u32(C.S_IEXEC))
|
||||||
}
|
}
|
||||||
others: FilePermission{
|
others: FilePermission{
|
||||||
read: bool(attr.st_mode & C.S_IREAD)
|
read: bool(attr.st_mode & u32(C.S_IREAD))
|
||||||
write: bool(attr.st_mode & C.S_IWRITE)
|
write: bool(attr.st_mode & u32(C.S_IWRITE))
|
||||||
execute: bool(attr.st_mode & C.S_IEXEC)
|
execute: bool(attr.st_mode & u32(C.S_IEXEC))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
return FileMode{
|
return FileMode{
|
||||||
typ: typ
|
typ: typ
|
||||||
owner: FilePermission{
|
owner: FilePermission{
|
||||||
read: bool(attr.st_mode & C.S_IRUSR)
|
read: bool(attr.st_mode & u32(C.S_IRUSR))
|
||||||
write: bool(attr.st_mode & C.S_IWUSR)
|
write: bool(attr.st_mode & u32(C.S_IWUSR))
|
||||||
execute: bool(attr.st_mode & C.S_IXUSR)
|
execute: bool(attr.st_mode & u32(C.S_IXUSR))
|
||||||
}
|
}
|
||||||
group: FilePermission{
|
group: FilePermission{
|
||||||
read: bool(attr.st_mode & C.S_IRGRP)
|
read: bool(attr.st_mode & u32(C.S_IRGRP))
|
||||||
write: bool(attr.st_mode & C.S_IWGRP)
|
write: bool(attr.st_mode & u32(C.S_IWGRP))
|
||||||
execute: bool(attr.st_mode & C.S_IXGRP)
|
execute: bool(attr.st_mode & u32(C.S_IXGRP))
|
||||||
}
|
}
|
||||||
others: FilePermission{
|
others: FilePermission{
|
||||||
read: bool(attr.st_mode & C.S_IROTH)
|
read: bool(attr.st_mode & u32(C.S_IROTH))
|
||||||
write: bool(attr.st_mode & C.S_IWOTH)
|
write: bool(attr.st_mode & u32(C.S_IWOTH))
|
||||||
execute: bool(attr.st_mode & C.S_IXOTH)
|
execute: bool(attr.st_mode & u32(C.S_IXOTH))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1090,12 +1090,12 @@ pub fn real_path(fpath string) string {
|
||||||
mut fullpath := vcalloc(max_path_len)
|
mut fullpath := vcalloc(max_path_len)
|
||||||
mut ret := charptr(0)
|
mut ret := charptr(0)
|
||||||
$if windows {
|
$if windows {
|
||||||
ret = C._fullpath(fullpath, fpath.str, max_path_len)
|
ret = charptr(C._fullpath(fullpath, fpath.str, max_path_len))
|
||||||
if ret == 0 {
|
if ret == 0 {
|
||||||
return fpath
|
return fpath
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
ret = C.realpath(fpath.str, fullpath)
|
ret = charptr(C.realpath(fpath.str, fullpath))
|
||||||
if ret == 0 {
|
if ret == 0 {
|
||||||
return fpath
|
return fpath
|
||||||
}
|
}
|
||||||
|
@ -1324,7 +1324,7 @@ pub fn open(path string) ?File {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
cfile := vfopen(path, 'rb')
|
cfile := vfopen(path, 'rb')
|
||||||
if cfile == 0 {
|
if cfile == voidptr(0) {
|
||||||
return error('failed to open file "$path"')
|
return error('failed to open file "$path"')
|
||||||
}
|
}
|
||||||
fd := fileno(cfile)
|
fd := fileno(cfile)
|
||||||
|
@ -1361,7 +1361,7 @@ pub fn create(path string) ?File {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
cfile := vfopen(path, 'wb')
|
cfile := vfopen(path, 'wb')
|
||||||
if cfile == 0 {
|
if cfile == voidptr(0) {
|
||||||
return error('failed to create file "$path"')
|
return error('failed to create file "$path"')
|
||||||
}
|
}
|
||||||
fd := fileno(cfile)
|
fd := fileno(cfile)
|
||||||
|
|
|
@ -146,7 +146,7 @@ pub fn mkdir(path string) ?bool {
|
||||||
// get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor.
|
// get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor.
|
||||||
pub fn get_file_handle(path string) HANDLE {
|
pub fn get_file_handle(path string) HANDLE {
|
||||||
cfile := vfopen(path, 'rb')
|
cfile := vfopen(path, 'rb')
|
||||||
if cfile == 0 {
|
if cfile == voidptr(0) {
|
||||||
return HANDLE(invalid_handle_value)
|
return HANDLE(invalid_handle_value)
|
||||||
}
|
}
|
||||||
handle := HANDLE(C._get_osfhandle(fileno(cfile))) // CreateFile? - hah, no -_-
|
handle := HANDLE(C._get_osfhandle(fileno(cfile))) // CreateFile? - hah, no -_-
|
||||||
|
|
|
@ -59,7 +59,7 @@ const(
|
||||||
const(
|
const(
|
||||||
mantbits32 = u32(23)
|
mantbits32 = u32(23)
|
||||||
expbits32 = u32(8)
|
expbits32 = u32(8)
|
||||||
bias32 = u32(127) // f32 exponent bias
|
bias32 = 127 // f32 exponent bias
|
||||||
maxexp32 = 255
|
maxexp32 = 255
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -189,10 +189,10 @@ pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
|
||||||
if exp == 0 {
|
if exp == 0 {
|
||||||
// We subtract 2 so that the bounds computation has
|
// We subtract 2 so that the bounds computation has
|
||||||
// 2 additional bits.
|
// 2 additional bits.
|
||||||
e2 = 1 - bias32 - mantbits32 - 2
|
e2 = 1 - bias32 - int(mantbits32) - 2
|
||||||
m2 = mant
|
m2 = mant
|
||||||
} else {
|
} else {
|
||||||
e2 = int(exp) - bias32 - mantbits32 - 2
|
e2 = int(exp) - bias32 - int(mantbits32) - 2
|
||||||
m2 = (u32(1) << mantbits32) | mant
|
m2 = (u32(1) << mantbits32) | mant
|
||||||
}
|
}
|
||||||
even := (m2 & 1) == 0
|
even := (m2 & 1) == 0
|
||||||
|
|
|
@ -73,7 +73,7 @@ const(
|
||||||
const(
|
const(
|
||||||
mantbits64 = u32(52)
|
mantbits64 = u32(52)
|
||||||
expbits64 = u32(11)
|
expbits64 = u32(11)
|
||||||
bias64 = u32(1023) // f64 exponent bias
|
bias64 = 1023 // f64 exponent bias
|
||||||
maxexp64 = 2047
|
maxexp64 = 2047
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -220,10 +220,10 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
|
||||||
if exp == 0 {
|
if exp == 0 {
|
||||||
// We subtract 2 so that the bounds computation has
|
// We subtract 2 so that the bounds computation has
|
||||||
// 2 additional bits.
|
// 2 additional bits.
|
||||||
e2 = 1 - bias64 - mantbits64 - 2
|
e2 = 1 - bias64 - int(mantbits64) - 2
|
||||||
m2 = mant
|
m2 = mant
|
||||||
} else {
|
} else {
|
||||||
e2 = int(exp) - bias64 - mantbits64 - 2
|
e2 = int(exp) - bias64 - int(mantbits64) - 2
|
||||||
m2 = (u64(1)<<mantbits64) | mant
|
m2 = (u64(1)<<mantbits64) | mant
|
||||||
}
|
}
|
||||||
even := (m2 & 1) == 0
|
even := (m2 & 1) == 0
|
||||||
|
|
|
@ -65,6 +65,6 @@ pub fn dice_coefficient(s1, s2 string) f32 {
|
||||||
intersection_size++
|
intersection_size++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (2.0 * intersection_size) / (f32(a.len) + f32(b.len) - 2)
|
return (2.0 * f32(intersection_size)) / (f32(a.len) + f32(b.len) - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub fn new_pool_processor(context PoolProcessorConfig) &PoolProcessor {
|
||||||
ntask: 0
|
ntask: 0
|
||||||
ntask_mtx: new_mutex()
|
ntask_mtx: new_mutex()
|
||||||
waitgroup: new_waitgroup()
|
waitgroup: new_waitgroup()
|
||||||
thread_cb: context.callback
|
thread_cb: voidptr(context.callback)
|
||||||
}
|
}
|
||||||
return pool
|
return pool
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub fn new_mutex() &Mutex {
|
||||||
sm := &Mutex{}
|
sm := &Mutex{}
|
||||||
unsafe {
|
unsafe {
|
||||||
mut m := sm
|
mut m := sm
|
||||||
m.mx = C.CreateMutex(0, false, 0)
|
m.mx = MHANDLE(C.CreateMutex(0, false, 0))
|
||||||
if isnil(m.mx) {
|
if isnil(m.mx) {
|
||||||
m.state = .broken // handle broken and mutex state are broken
|
m.state = .broken // handle broken and mutex state are broken
|
||||||
return sm
|
return sm
|
||||||
|
@ -44,7 +44,7 @@ pub fn new_mutex() &Mutex {
|
||||||
pub fn (mut m Mutex) lock() {
|
pub fn (mut m Mutex) lock() {
|
||||||
// if mutex handle not initalized
|
// if mutex handle not initalized
|
||||||
if isnil(m.mx) {
|
if isnil(m.mx) {
|
||||||
m.mx = C.CreateMutex(0, false, 0)
|
m.mx = MHANDLE(C.CreateMutex(0, false, 0))
|
||||||
if isnil(m.mx) {
|
if isnil(m.mx) {
|
||||||
m.state = .broken // handle broken and mutex state are broken
|
m.state = .broken // handle broken and mutex state are broken
|
||||||
return
|
return
|
||||||
|
|
|
@ -106,7 +106,7 @@ pub fn new_time(t Time) Time {
|
||||||
hour: t.hour
|
hour: t.hour
|
||||||
minute: t.minute
|
minute: t.minute
|
||||||
second: t.second
|
second: t.second
|
||||||
unix: t.unix_time()
|
unix: u64(t.unix_time())
|
||||||
}
|
}
|
||||||
// TODO Use the syntax below when it works with reserved keywords like `unix`
|
// TODO Use the syntax below when it works with reserved keywords like `unix`
|
||||||
// return {
|
// return {
|
||||||
|
@ -134,12 +134,12 @@ pub fn (t Time) unix_time() int {
|
||||||
// add_seconds returns a new time struct with an added number of seconds.
|
// add_seconds returns a new time struct with an added number of seconds.
|
||||||
pub fn (t Time) add_seconds(seconds int) Time {
|
pub fn (t Time) add_seconds(seconds int) Time {
|
||||||
// TODO Add(d time.Duration)
|
// TODO Add(d time.Duration)
|
||||||
return unix(t.unix + seconds)
|
return unix(t.unix + u64(seconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
// add_days returns a new time struct with an added number of days.
|
// add_days returns a new time struct with an added number of days.
|
||||||
pub fn (t Time) add_days(days int) Time {
|
pub fn (t Time) add_days(days int) Time {
|
||||||
return unix(t.unix + days * 3600 * 24)
|
return unix(t.unix + u64(i64(days) * 3600 * 24))
|
||||||
}
|
}
|
||||||
|
|
||||||
// since returns a number of seconds elapsed since a given time.
|
// since returns a number of seconds elapsed since a given time.
|
||||||
|
@ -272,7 +272,7 @@ fn convert_ctime(t C.tm) Time {
|
||||||
hour: t.tm_hour
|
hour: t.tm_hour
|
||||||
minute: t.tm_min
|
minute: t.tm_min
|
||||||
second: t.tm_sec
|
second: t.tm_sec
|
||||||
unix: make_unix_time(t)
|
unix: u64(make_unix_time(t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn unix(abs int) Time {
|
||||||
hour: hr
|
hour: hr
|
||||||
minute: min
|
minute: min
|
||||||
second: sec
|
second: sec
|
||||||
unix: abs
|
unix: u64(abs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ import v.table
|
||||||
|
|
||||||
pub fn (c &Checker) check_types(got, expected table.Type) bool {
|
pub fn (c &Checker) check_types(got, expected table.Type) bool {
|
||||||
t := c.table
|
t := c.table
|
||||||
got_idx := got.idx()
|
got_idx := t.unalias_num_type(got).idx()
|
||||||
exp_idx := expected.idx()
|
exp_idx := t.unalias_num_type(expected).idx()
|
||||||
// got_is_ptr := got.is_ptr()
|
// got_is_ptr := got.is_ptr()
|
||||||
exp_is_ptr := expected.is_ptr()
|
exp_is_ptr := expected.is_ptr()
|
||||||
// println('check: $got_type_sym.name, $exp_type_sym.name')
|
// println('check: $got_type_sym.name, $exp_type_sym.name')
|
||||||
|
@ -125,3 +125,119 @@ pub fn (c &Checker) check_types(got, expected table.Type) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (c &Checker) promote(left_type, right_type table.Type) table.Type {
|
||||||
|
if left_type.is_ptr() || left_type.is_pointer() {
|
||||||
|
if right_type.is_int() {
|
||||||
|
return left_type
|
||||||
|
} else {
|
||||||
|
return table.void_type
|
||||||
|
}
|
||||||
|
} else if right_type.is_ptr() || right_type.is_pointer() {
|
||||||
|
if left_type.is_int() {
|
||||||
|
return right_type
|
||||||
|
} else {
|
||||||
|
return table.void_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if left_type == right_type {
|
||||||
|
return left_type // strings, self defined operators
|
||||||
|
}
|
||||||
|
if right_type.is_number() && left_type.is_number() {
|
||||||
|
// sort the operands to save time
|
||||||
|
mut type_hi := left_type
|
||||||
|
mut type_lo := right_type
|
||||||
|
if type_hi.idx() < type_lo.idx() {
|
||||||
|
tmp := type_hi
|
||||||
|
type_hi = type_lo
|
||||||
|
type_lo = tmp
|
||||||
|
}
|
||||||
|
idx_hi := type_hi.idx()
|
||||||
|
idx_lo := type_lo.idx()
|
||||||
|
// the following comparisons rely on the order of the indices in atypes.v
|
||||||
|
if idx_hi == table.any_int_type_idx {
|
||||||
|
return type_lo
|
||||||
|
} else if idx_hi == table.any_flt_type_idx {
|
||||||
|
if idx_lo in table.float_type_idxs {
|
||||||
|
return type_lo
|
||||||
|
} else {
|
||||||
|
return table.void_type
|
||||||
|
}
|
||||||
|
} else if type_hi.is_float() {
|
||||||
|
if idx_hi == table.f32_type_idx {
|
||||||
|
if idx_lo in [table.int_type_idx, table.i64_type_idx, table.u32_type_idx, table.u64_type_idx] {
|
||||||
|
return table.void_type
|
||||||
|
} else {
|
||||||
|
return idx_hi
|
||||||
|
}
|
||||||
|
} else { // f64, any_flt
|
||||||
|
if idx_lo in [table.i64_type_idx, table.u64_type_idx] {
|
||||||
|
return table.void_type
|
||||||
|
} else {
|
||||||
|
return type_hi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if idx_lo >= table.byte_type_idx { // both operands are unsigned
|
||||||
|
return type_hi
|
||||||
|
} else if idx_lo >= table.i8_type_idx && idx_hi <= table.i64_type_idx { // both signed
|
||||||
|
return type_hi
|
||||||
|
} else if idx_hi - idx_lo < (table.byte_type_idx - table.i8_type_idx) {
|
||||||
|
return type_lo // conversion unsigned -> signed if signed type is larger
|
||||||
|
} else {
|
||||||
|
return table.void_type // conversion signed -> unsigned not allowed
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return left_type // default to left if not automatic promotion possible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: promote(), assign_check(), symmetric_check() and check() overlap - should be rearranged
|
||||||
|
pub fn (c &Checker) assign_check(got, expected table.Type) bool {
|
||||||
|
exp_idx := expected.idx()
|
||||||
|
got_idx := got.idx()
|
||||||
|
if exp_idx == got_idx {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if exp_idx == table.voidptr_type_idx || exp_idx == table.byteptr_type_idx {
|
||||||
|
if got.is_ptr() || got.is_pointer() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// allow direct int-literal assignment for pointers for now
|
||||||
|
// maybe in the future optionals should be used for that
|
||||||
|
if expected.is_ptr() || expected.is_pointer() {
|
||||||
|
if got == table.any_int_type {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if got_idx == table.voidptr_type_idx || got_idx == table.byteptr_type_idx {
|
||||||
|
if expected.is_ptr() || expected.is_pointer() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !c.check_types(got, expected) { // TODO: this should go away...
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if c.promote(expected, got) != expected {
|
||||||
|
println('could not promote ${c.table.get_type_symbol(got).name} to ${c.table.get_type_symbol(expected).name}')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (c &Checker) symmetric_check(left, right table.Type) bool {
|
||||||
|
// allow direct int-literal assignment for pointers for now
|
||||||
|
// maybe in the future optionals should be used for that
|
||||||
|
if right.is_ptr() || right.is_pointer() {
|
||||||
|
if left == table.any_int_type {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// allow direct int-literal assignment for pointers for now
|
||||||
|
if left.is_ptr() || left.is_pointer() {
|
||||||
|
if right == table.any_int_type {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.check_types(left, right)
|
||||||
|
}
|
||||||
|
|
|
@ -362,11 +362,11 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
|
||||||
expr_type := c.expr(field.expr)
|
expr_type := c.expr(field.expr)
|
||||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||||
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
field_type_sym := c.table.get_type_symbol(info_field.typ)
|
||||||
if !c.check_types(expr_type, info_field.typ) {
|
if !c.assign_check(expr_type, info_field.typ) {
|
||||||
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
|
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
|
||||||
field.pos)
|
field.pos)
|
||||||
}
|
}
|
||||||
if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_number() {
|
if info_field.typ.is_ptr() && !expr_type.is_ptr() && !expr_type.is_pointer() && !expr_type.is_number() {
|
||||||
c.error('ref', field.pos)
|
c.error('ref', field.pos)
|
||||||
}
|
}
|
||||||
struct_init.fields[i].typ = expr_type
|
struct_init.fields[i].typ = expr_type
|
||||||
|
@ -408,6 +408,10 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
infix_expr.right_type = right_type
|
infix_expr.right_type = right_type
|
||||||
right := c.table.get_type_symbol(right_type)
|
right := c.table.get_type_symbol(right_type)
|
||||||
left := c.table.get_type_symbol(left_type)
|
left := c.table.get_type_symbol(left_type)
|
||||||
|
left_default := c.table.get_type_symbol(c.table.mktyp(left_type))
|
||||||
|
left_pos := infix_expr.left.position()
|
||||||
|
right_pos := infix_expr.right.position()
|
||||||
|
mut return_type := left_type
|
||||||
// Single side check
|
// Single side check
|
||||||
// Place these branches according to ops' usage frequency to accelerate.
|
// Place these branches according to ops' usage frequency to accelerate.
|
||||||
// TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented.
|
// TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented.
|
||||||
|
@ -417,22 +421,22 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
.key_in, .not_in {
|
.key_in, .not_in {
|
||||||
match right.kind {
|
match right.kind {
|
||||||
.array {
|
.array {
|
||||||
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
|
right_sym := c.table.get_type_symbol(c.table.mktyp(right.array_info().elem_type))
|
||||||
if left.kind != right_sym.kind {
|
if left_default.kind != right_sym.kind {
|
||||||
c.error('the data type on the left of `$infix_expr.op.str()` does not match the array item type',
|
c.error('the data type on the left of `$infix_expr.op.str()` (`$left.name`) does not match the array item type (`$right_sym.name`)',
|
||||||
infix_expr.pos)
|
infix_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
key_sym := c.table.get_type_symbol(right.map_info().key_type)
|
key_sym := c.table.get_type_symbol(c.table.mktyp(right.map_info().key_type))
|
||||||
if left.kind != key_sym.kind {
|
if left_default.kind != key_sym.kind {
|
||||||
c.error('the data type on the left of `$infix_expr.op.str()` does not match the map key type',
|
c.error('the data type on the left of `$infix_expr.op.str()` (`$left.name`) does not match the map key type `$key_sym.name`',
|
||||||
infix_expr.pos)
|
infix_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.string {
|
.string {
|
||||||
if left.kind != .string {
|
if left.kind != .string {
|
||||||
c.error('the data type on the left of `$infix_expr.op.str()` must be a string',
|
c.error('the data type on the left of `$infix_expr.op.str()` must be a string (is `$left.name`)',
|
||||||
infix_expr.pos)
|
infix_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,15 +447,43 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
}
|
}
|
||||||
return table.bool_type
|
return table.bool_type
|
||||||
}
|
}
|
||||||
.plus, .minus, .mul, .div {
|
.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe { // binary operators that expect matching types
|
||||||
if infix_expr.op == .div && (infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
|
if left.kind in [.array, .array_fixed, .map, .struct_] {
|
||||||
'0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) {
|
if left.has_method(infix_expr.op.str()) {
|
||||||
c.error('division by zero', infix_expr.right.position())
|
return_type = left_type
|
||||||
|
} else {
|
||||||
|
c.error('mismatched types `$left.name` and `$right.name`', left_pos)
|
||||||
}
|
}
|
||||||
if left.kind in [.array, .array_fixed, .map, .struct_] && !left.has_method(infix_expr.op.str()) {
|
} else if right.kind in [.array, .array_fixed, .map, .struct_] {
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
if right.has_method(infix_expr.op.str()) {
|
||||||
} else if right.kind in [.array, .array_fixed, .map, .struct_] && !right.has_method(infix_expr.op.str()) {
|
return_type = right_type
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
} else {
|
||||||
|
c.error('mismatched types `$left.name` and `$right.name`', right_pos)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
promoted_type := c.promote(c.table.unalias_num_type(left_type), c.table.unalias_num_type(right_type))
|
||||||
|
if promoted_type.idx() == table.void_type_idx {
|
||||||
|
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.pos)
|
||||||
|
} else if promoted_type.is_float() {
|
||||||
|
if infix_expr.op in [.mod, .xor, .amp, .pipe] {
|
||||||
|
side := if left_type == promoted_type { 'left' } else { 'right' }
|
||||||
|
pos := if left_type == promoted_type { left_pos } else { right_pos }
|
||||||
|
name := if left_type == promoted_type { left.name } else { right.name }
|
||||||
|
if infix_expr.op == .mod {
|
||||||
|
c.error('float modulo not allowed, use math.fmod() instead', pos)
|
||||||
|
} else {
|
||||||
|
c.error('$side type of `${infix_expr.op.str()}` cannot be non-integer type $name', pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
oper := if infix_expr.op == .div { 'division' } else { 'modulo' }
|
||||||
|
c.error('$oper by zero', right_pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return_type = promoted_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.left_shift {
|
.left_shift {
|
||||||
|
@ -463,11 +495,10 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
if left_value_sym.kind == .interface_ {
|
if left_value_sym.kind == .interface_ {
|
||||||
if right.kind != .array {
|
if right.kind != .array {
|
||||||
// []Animal << Cat
|
// []Animal << Cat
|
||||||
c.type_implements(right_type, left_value_type, infix_expr.right.position())
|
c.type_implements(right_type, left_value_type, right_pos)
|
||||||
} else {
|
} else {
|
||||||
// []Animal << Cat
|
// []Animal << Cat
|
||||||
c.type_implements(c.table.value_type(right_type), left_value_type,
|
c.type_implements(c.table.value_type(right_type), left_value_type, right_pos)
|
||||||
infix_expr.right.position())
|
|
||||||
}
|
}
|
||||||
return table.void_type
|
return table.void_type
|
||||||
}
|
}
|
||||||
|
@ -481,13 +512,13 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
return table.void_type
|
return table.void_type
|
||||||
}
|
}
|
||||||
s := left.name.replace('array_', '[]')
|
s := left.name.replace('array_', '[]')
|
||||||
c.error('cannot append `$right.name` to `$s`', infix_expr.right.position())
|
c.error('cannot append `$right.name` to `$s`', right_pos)
|
||||||
return table.void_type
|
return table.void_type
|
||||||
} else if !left.is_int() {
|
} else if !left.is_int() {
|
||||||
c.error('cannot shift type $right.name into non-integer type $left.name', infix_expr.left.position())
|
c.error('cannot shift type $right.name into non-integer type $left.name', left_pos)
|
||||||
return table.void_type
|
return table.void_type
|
||||||
} else if !right.is_int() {
|
} else if !right.is_int() {
|
||||||
c.error('cannot shift non-integer type $right.name into type $left.name', infix_expr.right.position())
|
c.error('cannot shift non-integer type $right.name into type $left.name', right_pos)
|
||||||
return table.void_type
|
return table.void_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -499,33 +530,6 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
}
|
}
|
||||||
return table.bool_type
|
return table.bool_type
|
||||||
}
|
}
|
||||||
.amp, .pipe, .xor {
|
|
||||||
if !left.is_int() {
|
|
||||||
c.error('left type of `${infix_expr.op.str()}` cannot be non-integer type $left.name',
|
|
||||||
infix_expr.left.position())
|
|
||||||
} else if !right.is_int() {
|
|
||||||
c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name',
|
|
||||||
infix_expr.right.position())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mod {
|
|
||||||
if left.is_int() && !right.is_int() {
|
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
|
||||||
} else if !left.is_int() && right.is_int() {
|
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
|
||||||
} else if left.kind == .f32 && right.kind == .f32 || left.kind == .f64 && right.kind ==
|
|
||||||
.f64 {
|
|
||||||
c.error('float modulo not allowed, use math.fmod() instead', infix_expr.left.position())
|
|
||||||
} else if left.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
|
||||||
!left.has_method(infix_expr.op.str()) {
|
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
|
||||||
} else if right.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
|
||||||
!right.has_method(infix_expr.op.str()) {
|
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
|
||||||
} else if infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == '0' {
|
|
||||||
c.error('modulo by zero', infix_expr.right.position())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
// 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.
|
||||||
|
@ -539,7 +543,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
infix_expr.pos)
|
infix_expr.pos)
|
||||||
}
|
}
|
||||||
// Dual sides check (compatibility check)
|
// Dual sides check (compatibility check)
|
||||||
if !c.check_types(right_type, left_type) {
|
if !c.symmetric_check(right_type, left_type) {
|
||||||
// for type-unresolved consts
|
// for type-unresolved consts
|
||||||
if left_type == table.void_type || right_type == table.void_type {
|
if left_type == table.void_type || right_type == table.void_type {
|
||||||
return table.void_type
|
return table.void_type
|
||||||
|
@ -550,7 +554,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
|
||||||
return if infix_expr.op.is_relational() {
|
return if infix_expr.op.is_relational() {
|
||||||
table.bool_type
|
table.bool_type
|
||||||
} else {
|
} else {
|
||||||
left_type
|
return_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,7 +682,7 @@ fn (mut c Checker) assign_expr(mut assign_expr ast.AssignExpr) {
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
// Dual sides check (compatibility check)
|
// Dual sides check (compatibility check)
|
||||||
if !c.check_types(right_type, left_type) {
|
if !c.assign_check(right_type, left_type) {
|
||||||
left_type_sym := c.table.get_type_symbol(left_type)
|
left_type_sym := c.table.get_type_symbol(left_type)
|
||||||
right_type_sym := c.table.get_type_symbol(right_type)
|
right_type_sym := c.table.get_type_symbol(right_type)
|
||||||
c.error('cannot assign `$right_type_sym.name` to variable `${assign_expr.left.str()}` of type `$left_type_sym.name`',
|
c.error('cannot assign `$right_type_sym.name` to variable `${assign_expr.left.str()}` of type `$left_type_sym.name`',
|
||||||
|
@ -1268,12 +1272,15 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
||||||
} else if i < assign_stmt.right.len { // only once for multi return
|
} else if i < assign_stmt.right.len { // only once for multi return
|
||||||
c.check_expr_opt_call(assign_stmt.right[i], assign_stmt.right_types[i])
|
c.check_expr_opt_call(assign_stmt.right[i], assign_stmt.right_types[i])
|
||||||
}
|
}
|
||||||
val_type := assign_stmt.right_types[i]
|
mut val_type := assign_stmt.right_types[i]
|
||||||
// check variable name for beginning with capital letter 'Abc'
|
// check variable name for beginning with capital letter 'Abc'
|
||||||
is_decl := assign_stmt.op == .decl_assign
|
is_decl := assign_stmt.op == .decl_assign
|
||||||
if is_decl && ident.name != '_' {
|
if is_decl && ident.name != '_' {
|
||||||
c.check_valid_snake_case(ident.name, 'variable name', ident.pos)
|
c.check_valid_snake_case(ident.name, 'variable name', ident.pos)
|
||||||
}
|
}
|
||||||
|
if assign_stmt.op == .decl_assign {
|
||||||
|
val_type = c.table.mktyp(val_type)
|
||||||
|
}
|
||||||
mut ident_var_info := ident.var_info()
|
mut ident_var_info := ident.var_info()
|
||||||
if assign_stmt.op == .assign {
|
if assign_stmt.op == .assign {
|
||||||
c.fail_if_immutable(ident)
|
c.fail_if_immutable(ident)
|
||||||
|
@ -1301,12 +1308,12 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
|
||||||
if array_init.typ != table.void_type {
|
if array_init.typ != table.void_type {
|
||||||
if array_init.exprs.len == 0 {
|
if array_init.exprs.len == 0 {
|
||||||
if array_init.has_cap {
|
if array_init.has_cap {
|
||||||
if c.expr(array_init.cap_expr) != table.int_type {
|
if c.expr(array_init.cap_expr) !in [table.int_type, table.any_int_type] {
|
||||||
c.error('array cap needs to be an int', array_init.pos)
|
c.error('array cap needs to be an int', array_init.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if array_init.has_len {
|
if array_init.has_len {
|
||||||
if c.expr(array_init.len_expr) != table.int_type {
|
if c.expr(array_init.len_expr) !in [table.int_type, table.any_int_type] {
|
||||||
c.error('array len needs to be an int', array_init.pos)
|
c.error('array len needs to be an int', array_init.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1316,12 +1323,12 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
|
||||||
// a = []
|
// a = []
|
||||||
if array_init.exprs.len == 0 {
|
if array_init.exprs.len == 0 {
|
||||||
if array_init.has_cap {
|
if array_init.has_cap {
|
||||||
if c.expr(array_init.cap_expr) != table.int_type {
|
if c.expr(array_init.cap_expr) !in [table.int_type, table.any_int_type] {
|
||||||
c.error('array cap needs to be an int', array_init.pos)
|
c.error('array cap needs to be an int', array_init.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if array_init.has_len {
|
if array_init.has_len {
|
||||||
if c.expr(array_init.len_expr) != table.int_type {
|
if c.expr(array_init.len_expr) !in [table.int_type, table.any_int_type] {
|
||||||
c.error('array len needs to be an int', array_init.pos)
|
c.error('array len needs to be an int', array_init.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1372,8 +1379,8 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
|
||||||
}
|
}
|
||||||
// The first element's type
|
// The first element's type
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
elem_type = typ
|
elem_type = c.table.mktyp(typ)
|
||||||
c.expected_type = typ
|
c.expected_type = elem_type
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !c.check_types(elem_type, typ) {
|
if !c.check_types(elem_type, typ) {
|
||||||
|
@ -1492,7 +1499,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
c.const_decl = field.name
|
c.const_decl = field.name
|
||||||
c.const_deps << field.name
|
c.const_deps << field.name
|
||||||
typ := c.expr(field.expr)
|
typ := c.expr(field.expr)
|
||||||
it.fields[i].typ = typ
|
it.fields[i].typ = c.table.mktyp(typ)
|
||||||
for cd in c.const_deps {
|
for cd in c.const_deps {
|
||||||
for j, f in it.fields {
|
for j, f in it.fields {
|
||||||
if j != i && cd in field_names && cd == f.name && j !in done_fields {
|
if j != i && cd in field_names && cd == f.name && j !in done_fields {
|
||||||
|
@ -1748,7 +1755,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
return c.enum_val(mut it)
|
return c.enum_val(mut it)
|
||||||
}
|
}
|
||||||
ast.FloatLiteral {
|
ast.FloatLiteral {
|
||||||
return table.f64_type
|
return table.any_flt_type
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
// c.checked_ident = it.name
|
// c.checked_ident = it.name
|
||||||
|
@ -1770,7 +1777,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
return c.infix_expr(mut it)
|
return c.infix_expr(mut it)
|
||||||
}
|
}
|
||||||
ast.IntegerLiteral {
|
ast.IntegerLiteral {
|
||||||
return table.int_type
|
return table.any_int_type
|
||||||
}
|
}
|
||||||
ast.MapInit {
|
ast.MapInit {
|
||||||
return c.map_init(mut it)
|
return c.map_init(mut it)
|
||||||
|
@ -1805,7 +1812,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
||||||
return c.selector_expr(mut it)
|
return c.selector_expr(mut it)
|
||||||
}
|
}
|
||||||
ast.SizeOf {
|
ast.SizeOf {
|
||||||
return table.int_type
|
return table.u32_type
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
if it.language == .c {
|
if it.language == .c {
|
||||||
|
@ -2140,17 +2147,46 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||||
// first branch of if expression
|
// first branch of if expression
|
||||||
node.is_expr = true
|
node.is_expr = true
|
||||||
node.typ = last_expr.typ
|
node.typ = last_expr.typ
|
||||||
} else {
|
continue
|
||||||
|
} else if node.typ in [table.any_flt_type, table.any_int_type] {
|
||||||
|
if node.typ == table.any_int_type {
|
||||||
|
if last_expr.typ.is_int() || last_expr.typ.is_float() {
|
||||||
|
node.typ = last_expr.typ
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else { // node.typ == any_float
|
||||||
|
if last_expr.typ.is_float() {
|
||||||
|
node.typ = last_expr.typ
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if last_expr.typ in [table.any_flt_type, table.any_int_type] {
|
||||||
|
if last_expr.typ == table.any_int_type {
|
||||||
|
if node.typ.is_int() || node.typ.is_float() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else { // expr_type == any_float
|
||||||
|
if node.typ.is_float() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
|
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
c.error('`if` expression requires an expression as the last statement of every branch',
|
c.error('`if` expression requires an expression as the last statement of every branch',
|
||||||
branch.pos)
|
branch.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if only untyped literals were given default to int/f64
|
||||||
|
if node.typ == table.any_int_type {
|
||||||
|
node.typ = table.int_type
|
||||||
|
} else if node.typ == table.any_flt_type {
|
||||||
|
node.typ = table.f64_type
|
||||||
|
}
|
||||||
if expr_required {
|
if expr_required {
|
||||||
if !node.has_else {
|
if !node.has_else {
|
||||||
c.error('`if` expression needs `else` clause', node.pos)
|
c.error('`if` expression needs `else` clause', node.pos)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/add_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int`
|
vlib/v/checker/tests/add_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | A{} + 10
|
3 | A{} + 10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/add_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int`
|
vlib/v/checker/tests/add_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | [1,2,3] + 10
|
2 | [1,2,3] + 10
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/add_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int`
|
vlib/v/checker/tests/add_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | a + 10
|
3 | a + 10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/add_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A`
|
vlib/v/checker/tests/add_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | 10 + A{}
|
3 | 10 + A{}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/add_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int`
|
vlib/v/checker/tests/add_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 10 + [1,2,3]
|
2 | 10 + [1,2,3]
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/add_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int`
|
vlib/v/checker/tests/add_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | 10 + a
|
3 | 10 + a
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/bit_op_wrong_left_type_err.v:2:2: error: left type of `&` cannot be non-integer type f64
|
vlib/v/checker/tests/bit_op_wrong_left_type_err.v:2:2: error: left type of `&` cannot be non-integer type any_float
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 0.5 & 1
|
2 | 0.5 & 1
|
||||||
| ~~~
|
| ~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/bit_op_wrong_right_type_err.v:2:6: error: right type of `|` cannot be non-integer type f64
|
vlib/v/checker/tests/bit_op_wrong_right_type_err.v:2:6: error: right type of `|` cannot be non-integer type any_float
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 1 | 0.5
|
2 | 1 | 0.5
|
||||||
| ~~~
|
| ~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/cast_string_err.v:2:14: error: cannot cast type `int` to string, use `x.str()` instead
|
vlib/v/checker/tests/cast_string_err.v:2:14: error: cannot cast type `any_int` to string, use `x.str()` instead
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := string(1)
|
2 | a := string(1)
|
||||||
| ^
|
| ^
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/div_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int`
|
vlib/v/checker/tests/div_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | A{} / 10
|
3 | A{} / 10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/div_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int`
|
vlib/v/checker/tests/div_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | [1,2,3] / 10
|
2 | [1,2,3] / 10
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/div_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int`
|
vlib/v/checker/tests/div_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | a / 10
|
3 | a / 10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/div_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A`
|
vlib/v/checker/tests/div_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | 10 / A{}
|
3 | 10 / A{}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/div_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int`
|
vlib/v/checker/tests/div_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 10 / [1,2,3]
|
2 | 10 / [1,2,3]
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/div_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int`
|
vlib/v/checker/tests/div_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | 10 / a
|
3 | 10 / a
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/for-in-index-type.v:2:11: error: for in: cannot index `int`
|
vlib/v/checker/tests/for-in-index-type.v:2:11: error: for in: cannot index `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | for a in 52 {
|
2 | for a in 52 {
|
||||||
| ~~
|
| ~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/if_expr_mismatch.v:2:7: error: mismatched types `string` and `int`
|
vlib/v/checker/tests/if_expr_mismatch.v:2:7: error: mismatched types `string` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | s := if true { '12' } else { 12 }
|
2 | s := if true { '12' } else { 12 }
|
||||||
| ~~
|
| ~~
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:10:7: error: the data type on the left of `in` does not match the array item type
|
vlib/v/checker/tests/in_mismatch_type.v:10:7: error: the data type on the left of `in` (`any_int`) does not match the array item type (`string`)
|
||||||
8 | }
|
8 | }
|
||||||
9 | s := 'abcd'
|
9 | s := 'abcd'
|
||||||
10 | if 1 in a_s {
|
10 | if 1 in a_s {
|
||||||
| ~~
|
| ~~
|
||||||
11 | println('ok')
|
11 | println('ok')
|
||||||
12 | }
|
12 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:13:7: error: the data type on the left of `in` does not match the map key type
|
vlib/v/checker/tests/in_mismatch_type.v:13:7: error: the data type on the left of `in` (`any_int`) does not match the map key type `string`
|
||||||
11 | println('ok')
|
11 | println('ok')
|
||||||
12 | }
|
12 | }
|
||||||
13 | if 2 in m {
|
13 | if 2 in m {
|
||||||
| ~~
|
| ~~
|
||||||
14 | println('yeah')
|
14 | println('yeah')
|
||||||
15 | }
|
15 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:16:7: error: the data type on the left of `in` must be a string
|
vlib/v/checker/tests/in_mismatch_type.v:16:7: error: the data type on the left of `in` must be a string (is `any_int`)
|
||||||
14 | println('yeah')
|
14 | println('yeah')
|
||||||
15 | }
|
15 | }
|
||||||
16 | if 3 in s {
|
16 | if 3 in s {
|
||||||
| ~~
|
| ~~
|
||||||
17 | println('dope')
|
17 | println('dope')
|
||||||
18 | }
|
18 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:19:9: error: the data type on the left of `in` must be a string
|
vlib/v/checker/tests/in_mismatch_type.v:19:9: error: the data type on the left of `in` must be a string (is `byte`)
|
||||||
17 | println('dope')
|
17 | println('dope')
|
||||||
18 | }
|
18 | }
|
||||||
19 | if `a` in s {
|
19 | if `a` in s {
|
||||||
|
@ -33,42 +33,42 @@ vlib/v/checker/tests/in_mismatch_type.v:22:7: error: `in` can only be used with
|
||||||
| ~~
|
| ~~
|
||||||
23 | println('right')
|
23 | println('right')
|
||||||
24 | }
|
24 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:25:12: error: the data type on the left of `in` does not match the map key type
|
vlib/v/checker/tests/in_mismatch_type.v:25:12: error: the data type on the left of `in` (`Int`) does not match the map key type `string`
|
||||||
23 | println('right')
|
23 | println('right')
|
||||||
24 | }
|
24 | }
|
||||||
25 | if Int(2) in m {
|
25 | if Int(2) in m {
|
||||||
| ~~
|
| ~~
|
||||||
26 | println('yeah')
|
26 | println('yeah')
|
||||||
27 | }
|
27 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:28:9: error: the data type on the left of `in` does not match the array item type
|
vlib/v/checker/tests/in_mismatch_type.v:28:9: error: the data type on the left of `in` (`string`) does not match the array item type (`int`)
|
||||||
26 | println('yeah')
|
26 | println('yeah')
|
||||||
27 | }
|
27 | }
|
||||||
28 | if '3' in a_i {
|
28 | if '3' in a_i {
|
||||||
| ~~
|
| ~~
|
||||||
29 | println('sure')
|
29 | println('sure')
|
||||||
30 | }
|
30 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:31:9: error: the data type on the left of `in` does not match the array item type
|
vlib/v/checker/tests/in_mismatch_type.v:31:9: error: the data type on the left of `in` (`string`) does not match the array item type (`int`)
|
||||||
29 | println('sure')
|
29 | println('sure')
|
||||||
30 | }
|
30 | }
|
||||||
31 | if '2' in a_i {
|
31 | if '2' in a_i {
|
||||||
| ~~
|
| ~~
|
||||||
32 | println('all right')
|
32 | println('all right')
|
||||||
33 | }
|
33 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:34:7: error: the data type on the left of `!in` does not match the array item type
|
vlib/v/checker/tests/in_mismatch_type.v:34:7: error: the data type on the left of `!in` (`any_int`) does not match the array item type (`string`)
|
||||||
32 | println('all right')
|
32 | println('all right')
|
||||||
33 | }
|
33 | }
|
||||||
34 | if 1 !in a_s {
|
34 | if 1 !in a_s {
|
||||||
| ~~~
|
| ~~~
|
||||||
35 | println('ok')
|
35 | println('ok')
|
||||||
36 | }
|
36 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:37:9: error: the data type on the left of `!in` does not match the array item type
|
vlib/v/checker/tests/in_mismatch_type.v:37:9: error: the data type on the left of `!in` (`string`) does not match the array item type (`int`)
|
||||||
35 | println('ok')
|
35 | println('ok')
|
||||||
36 | }
|
36 | }
|
||||||
37 | if '1' !in a_i {
|
37 | if '1' !in a_i {
|
||||||
| ~~~
|
| ~~~
|
||||||
38 | println('good')
|
38 | println('good')
|
||||||
39 | }
|
39 | }
|
||||||
vlib/v/checker/tests/in_mismatch_type.v:41:7: error: the data type on the left of `!in` does not match the map key type
|
vlib/v/checker/tests/in_mismatch_type.v:41:7: error: the data type on the left of `!in` (`any_int`) does not match the map key type `string`
|
||||||
39 | }
|
39 | }
|
||||||
40 |
|
40 |
|
||||||
41 | if 5 !in m {
|
41 | if 5 !in m {
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
vlib/v/checker/tests/is_type_not_exist.v:4:2: error: cannot use type `any_int` as type `Integer` in argument 1 to `fn_with_sum_type_param`
|
||||||
|
2 |
|
||||||
|
3 | fn main() {
|
||||||
|
4 | fn_with_sum_type_param(1)
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
5 | }
|
||||||
|
6 |
|
||||||
vlib/v/checker/tests/is_type_not_exist.v:8:10: error: is: type `SomethingThatDontExist` does not exist
|
vlib/v/checker/tests/is_type_not_exist.v:8:10: error: is: type `SomethingThatDontExist` does not exist
|
||||||
6 |
|
6 |
|
||||||
7 | fn fn_with_sum_type_param(i Integer) {
|
7 | fn fn_with_sum_type_param(i Integer) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/minus_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int`
|
vlib/v/checker/tests/minus_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | A{} - 10
|
3 | A{} - 10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/minus_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int`
|
vlib/v/checker/tests/minus_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | [1,2,3] - 10
|
2 | [1,2,3] - 10
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/minus_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int`
|
vlib/v/checker/tests/minus_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | a - 10
|
3 | a - 10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/minus_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A`
|
vlib/v/checker/tests/minus_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | 10 - A{}
|
3 | 10 - A{}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/minus_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int`
|
vlib/v/checker/tests/minus_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 10 - [1,2,3]
|
2 | 10 - [1,2,3]
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/minus_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int`
|
vlib/v/checker/tests/minus_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | 10 - a
|
3 | 10 - a
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_left_type_err_a.v:2:2: error: mismatched types `f64` and `int`
|
vlib/v/checker/tests/mod_op_wrong_left_type_err_a.v:2:2: error: float modulo not allowed, use math.fmod() instead
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 0.5 % 1
|
2 | 0.5 % 1
|
||||||
| ~~~
|
| ~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_left_type_err_b.v:2:2: error: mismatched types `array_int` and `int`
|
vlib/v/checker/tests/mod_op_wrong_left_type_err_b.v:2:2: error: mismatched types `array_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | [1,2,3] % 1
|
2 | [1,2,3] % 1
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_left_type_err_c.v:4:2: error: mismatched types `A` and `int`
|
vlib/v/checker/tests/mod_op_wrong_left_type_err_c.v:4:2: error: mismatched types `A` and `any_int`
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | a := A{}
|
3 | a := A{}
|
||||||
4 | a % 1
|
4 | a % 1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_left_type_err_d.v:3:2: error: mismatched types `map_string_int` and `int`
|
vlib/v/checker/tests/mod_op_wrong_left_type_err_d.v:3:2: error: mismatched types `map_string_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | a % 1
|
3 | a % 1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_right_type_err_a.v:2:6: error: mismatched types `int` and `f64`
|
vlib/v/checker/tests/mod_op_wrong_right_type_err_a.v:2:6: error: float modulo not allowed, use math.fmod() instead
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 1 % 0.5
|
2 | 1 % 0.5
|
||||||
| ~~~
|
| ~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_right_type_err_b.v:2:6: error: mismatched types `int` and `array_int`
|
vlib/v/checker/tests/mod_op_wrong_right_type_err_b.v:2:6: error: mismatched types `any_int` and `array_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 1 % [1,2,3]
|
2 | 1 % [1,2,3]
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_right_type_err_c.v:4:6: error: mismatched types `int` and `A`
|
vlib/v/checker/tests/mod_op_wrong_right_type_err_c.v:4:6: error: mismatched types `any_int` and `A`
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | a := A{}
|
3 | a := A{}
|
||||||
4 | 1 % a
|
4 | 1 % a
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mod_op_wrong_right_type_err_d.v:3:6: error: mismatched types `int` and `map_string_int`
|
vlib/v/checker/tests/mod_op_wrong_right_type_err_d.v:3:6: error: mismatched types `any_int` and `map_string_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | 1 % a
|
3 | 1 % a
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mul_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `int`
|
vlib/v/checker/tests/mul_op_wrong_left_type_err_a.v:3:5: error: mismatched types `A` and `any_int`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | A{} * 10
|
3 | A{} * 10
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mul_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `int`
|
vlib/v/checker/tests/mul_op_wrong_left_type_err_b.v:2:5: error: mismatched types `array_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | [1,2,3] * 10
|
2 | [1,2,3] * 10
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mul_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `int`
|
vlib/v/checker/tests/mul_op_wrong_left_type_err_c.v:3:5: error: mismatched types `map_string_int` and `any_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | a * 10
|
3 | a * 10
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
vlib/v/checker/tests/mul_op_wrong_left_type_err_d.v:6:11: error: infix expr: cannot use `any_float` (right expression) as `math.complex.Complex`
|
||||||
|
4 | fn main() {
|
||||||
|
5 | c1 := cmplx.complex(1,-2)
|
||||||
|
6 | c2 := c1 * 2.0
|
||||||
|
| ^
|
||||||
|
7 | println(c2)
|
||||||
|
8 | }
|
|
@ -0,0 +1,8 @@
|
||||||
|
import math
|
||||||
|
import math.complex as cmplx
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
c1 := cmplx.complex(1,-2)
|
||||||
|
c2 := c1 * 2.0
|
||||||
|
println(c2)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mul_op_wrong_right_type_err_a.v:3:10: error: mismatched types `int` and `A`
|
vlib/v/checker/tests/mul_op_wrong_right_type_err_a.v:3:10: error: mismatched types `any_int` and `A`
|
||||||
1 | struct A{}
|
1 | struct A{}
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | 10 * A{}
|
3 | 10 * A{}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mul_op_wrong_right_type_err_b.v:2:10: error: mismatched types `int` and `array_int`
|
vlib/v/checker/tests/mul_op_wrong_right_type_err_b.v:2:10: error: mismatched types `any_int` and `array_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 10 * [1,2,3]
|
2 | 10 * [1,2,3]
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/mul_op_wrong_right_type_err_c.v:3:10: error: mismatched types `int` and `map_string_int`
|
vlib/v/checker/tests/mul_op_wrong_right_type_err_c.v:3:10: error: mismatched types `any_int` and `map_string_int`
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | a := map[string]int
|
2 | a := map[string]int
|
||||||
3 | 10 * a
|
3 | 10 * a
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
vlib/v/checker/tests/mul_op_wrong_right_type_err_d.v:6:12: error: infix expr: cannot use `math.complex.Complex` (right expression) as `any_float`
|
||||||
|
4 | fn main() {
|
||||||
|
5 | c1 := cmplx.complex(1,-2)
|
||||||
|
6 | c2 := 2.0 * c1
|
||||||
|
| ^
|
||||||
|
7 | println(c2)
|
||||||
|
8 | }
|
|
@ -0,0 +1,8 @@
|
||||||
|
import math
|
||||||
|
import math.complex as cmplx
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
c1 := cmplx.complex(1,-2)
|
||||||
|
c2 := 2.0 * c1
|
||||||
|
println(c2)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/return_type.v:2:9: error: cannot use `int` as type `bool` in return argument
|
vlib/v/checker/tests/return_type.v:2:9: error: cannot use `any_int` as type `bool` in return argument
|
||||||
1 | fn test() bool {
|
1 | fn test() bool {
|
||||||
2 | return 100
|
2 | return 100
|
||||||
| ~~~
|
| ~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/shift_op_wrong_left_type_err.v:2:2: error: cannot shift type int into non-integer type f64
|
vlib/v/checker/tests/shift_op_wrong_left_type_err.v:2:2: error: cannot shift type any_int into non-integer type any_float
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 0.5 << 1
|
2 | 0.5 << 1
|
||||||
| ~~~
|
| ~~~
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/shift_op_wrong_right_type_err.v:2:7: error: cannot shift non-integer type f64 into type int
|
vlib/v/checker/tests/shift_op_wrong_right_type_err.v:2:7: error: cannot shift non-integer type any_float into type any_int
|
||||||
1 | fn main() {
|
1 | fn main() {
|
||||||
2 | 1 << 0.5
|
2 | 1 << 0.5
|
||||||
| ~~~
|
| ~~~
|
||||||
|
|
|
@ -272,7 +272,7 @@ pub fn (mut g Gen) finish() {
|
||||||
if g.pref.is_livemain || g.pref.is_liveshared {
|
if g.pref.is_livemain || g.pref.is_liveshared {
|
||||||
g.generate_hotcode_reloader_code()
|
g.generate_hotcode_reloader_code()
|
||||||
}
|
}
|
||||||
if g.fn_main != 0 {
|
if g.fn_main != voidptr(0) {
|
||||||
g.out.writeln('')
|
g.out.writeln('')
|
||||||
g.fn_decl = g.fn_main
|
g.fn_decl = g.fn_main
|
||||||
g.gen_fn_decl(g.fn_main)
|
g.gen_fn_decl(g.fn_main)
|
||||||
|
@ -1728,7 +1728,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
styp := g.typ(left_type)
|
styp := g.typ(g.table.mktyp(left_type))
|
||||||
g.write('_IN($styp, ')
|
g.write('_IN($styp, ')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
|
|
|
@ -847,7 +847,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
|
|
||||||
g.fn_decl = 0
|
g.fn_decl = voidptr(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) {
|
fn (mut g JsGen) fn_args(args []table.Arg, is_variadic bool) {
|
||||||
|
|
|
@ -65,14 +65,14 @@ pub fn (mut g Gen) generate_elf_header() {
|
||||||
g.write64(0) // p_offset
|
g.write64(0) // p_offset
|
||||||
g.write64(segment_start) // p_vaddr addr:050
|
g.write64(segment_start) // p_vaddr addr:050
|
||||||
g.write64(segment_start) //
|
g.write64(segment_start) //
|
||||||
g.file_size_pos = g.buf.len
|
g.file_size_pos = i64(g.buf.len)
|
||||||
g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060
|
g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060
|
||||||
g.write64(0) // p_memsz
|
g.write64(0) // p_memsz
|
||||||
g.write64(0x1000) // p_align
|
g.write64(0x1000) // p_align
|
||||||
// user code starts here at
|
// user code starts here at
|
||||||
// address: 00070 and a half
|
// address: 00070 and a half
|
||||||
println('code_start_pos = $g.buf.len.hex()')
|
println('code_start_pos = $g.buf.len.hex()')
|
||||||
g.code_start_pos = g.buf.len
|
g.code_start_pos = i64(g.buf.len)
|
||||||
g.debug_pos = g.buf.len
|
g.debug_pos = g.buf.len
|
||||||
g.call(placeholder) // call main function, it's not guaranteed to be the first, we don't know its address yet
|
g.call(placeholder) // call main function, it's not guaranteed to be the first, we don't know its address yet
|
||||||
g.println('call fn main')
|
g.println('call fn main')
|
||||||
|
|
|
@ -402,7 +402,7 @@ pub fn (mut g Gen) gen_loop_end(to, label int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) save_main_fn_addr() {
|
pub fn (mut g Gen) save_main_fn_addr() {
|
||||||
g.main_fn_addr = g.buf.len
|
g.main_fn_addr = i64(g.buf.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) {
|
pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode) &Scanner {
|
||||||
}
|
}
|
||||||
raw_text := util.read_file( file_path ) or {
|
raw_text := util.read_file( file_path ) or {
|
||||||
verror(err)
|
verror(err)
|
||||||
return 0
|
return voidptr(0)
|
||||||
}
|
}
|
||||||
mut s := new_scanner(raw_text, comments_mode) // .skip_comments)
|
mut s := new_scanner(raw_text, comments_mode) // .skip_comments)
|
||||||
// s.init_fmt()
|
// s.init_fmt()
|
||||||
|
|
|
@ -195,6 +195,18 @@ pub fn (t &Table) get_type_name(typ Type) string {
|
||||||
return typ_sym.name
|
return typ_sym.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (t &Table) unalias_num_type(typ Type) Type {
|
||||||
|
sym := t.get_type_symbol(typ)
|
||||||
|
if sym.kind == .alias {
|
||||||
|
pt := (sym.info as Alias).parent_typ
|
||||||
|
if pt <= f64_type && pt >= void_type {
|
||||||
|
return pt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
|
||||||
// this will override or register builtin type
|
// this will override or register builtin type
|
||||||
// allows prexisitng types added in register_builtins
|
// allows prexisitng types added in register_builtins
|
||||||
// to be overriden with their real type info
|
// to be overriden with their real type info
|
||||||
|
@ -438,6 +450,21 @@ pub fn (t &Table) value_type(typ Type) Type {
|
||||||
return void_type
|
return void_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (t &Table) mktyp(typ Type) Type {
|
||||||
|
match typ {
|
||||||
|
any_flt_type {
|
||||||
|
return table.f64_type
|
||||||
|
}
|
||||||
|
any_int_type {
|
||||||
|
return table.int_type
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Once we have a module format we can read from module file instead
|
// Once we have a module format we can read from module file instead
|
||||||
// this is not optimal
|
// this is not optimal
|
||||||
pub fn (table &Table) qualify_module(mod, file_path string) string {
|
pub fn (table &Table) qualify_module(mod, file_path string) string {
|
||||||
|
|
|
@ -13,16 +13,16 @@ fn test_int_lit_call_method() {
|
||||||
|
|
||||||
fn test_float_lit_call_method() {
|
fn test_float_lit_call_method() {
|
||||||
x1 := -123.66.str()
|
x1 := -123.66.str()
|
||||||
assert x1 == '-1.2366e+02'
|
assert x1 == '-123.66'
|
||||||
x2 := 12.5e-2.str()
|
x2 := 12.5e-2.str()
|
||||||
assert x2 == '1.25e-01'
|
assert x2 == '0.125'
|
||||||
x3 := .789.str()
|
x3 := .789.str()
|
||||||
assert x3 == '7.89e-01'
|
assert x3 == '0.789'
|
||||||
x4 := .003e2.str()
|
x4 := .003e2.str()
|
||||||
assert x4 == '3.e-01'
|
assert x4 == '0.3'
|
||||||
x5 := 2.e-3.str()
|
x5 := 2.e-3.str()
|
||||||
assert x5 == '2.e-03'
|
assert x5 == '2.e-03'
|
||||||
x6 := 5.0.str()
|
x6 := 5.0.str()
|
||||||
assert x6 == '5.e+00'
|
assert x6 == '5.'
|
||||||
// x7 := 5..str() Syntax `5.` is allowed, but do not call method on it (`5..str()` is parsed as a range). Use `5.0.str()` instead.
|
// x7 := 5..str() Syntax `5.` is allowed, but do not call method on it (`5..str()` is parsed as a range). Use `5.0.str()` instead.
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue