Compare commits

..

13 Commits

Author SHA1 Message Date
Alexander Medvednikov b7f2ef78b2
all: atomic int fixes
ci/woodpecker/push/vc Pipeline was successful Details
ci/woodpecker/push/docker Pipeline was successful Details
ci/woodpecker/push/arch Pipeline was successful Details
2022-04-27 21:07:11 +02:00
yuyi 2d9fa62941
math: fix error for math.abs(0.0)/math.abs(0) (related #14165) (#14191) 2022-04-27 21:07:11 +02:00
yuyi 8b085a32a5
cgen: fix error for generic sumtype casting to typenode (#14188) 2022-04-27 21:07:10 +02:00
tzSharing 604f4f5e44
gg: fix gg.draw_rounded_rect_empty() graphical abnormalities and some optimizations (#14186) 2022-04-27 21:07:10 +02:00
playX c37bb48e9c
checker: allow + - * on pointers for translated code (#14183) 2022-04-27 21:07:10 +02:00
R cqls 609464bc9c
gg: some stuff required to have svg and png screenshots working on v ui (#14180) 2022-04-27 21:07:10 +02:00
yuyi 8a75d68421
cgen: split up array_init() (#14178) 2022-04-27 21:07:10 +02:00
Larpon 07d465cbaa
strconv: add missing doc strings (#14164) 2022-04-27 21:07:10 +02:00
yuyi 14cec11cc6
cgen: fix error for cast to empty interface (fix #14162) (#14176) 2022-04-27 21:07:10 +02:00
Brian Callahan 9bc422a071
sokol: support compilation on OpenBSD (#14169) 2022-04-27 21:07:09 +02:00
yuyi 2b0f0820e6
ast, checker, cgen: fix error for multi-return in or expr (fix #14167) (#14172) 2022-04-27 21:07:09 +02:00
playX 0302cd69bd
checker: allow indexing through alias to int (#14177) 2022-04-27 21:07:09 +02:00
playX cab53d0e75
checker: c2v fixes (#14161) 2022-04-27 21:07:09 +02:00
32 changed files with 644 additions and 329 deletions

View File

@ -482,3 +482,6 @@ fn C.glTexImage2D()
// used by ios for println
fn C.WrappedNSLog(str &u8)
// absolute value
fn C.abs(number int) int

View File

@ -578,3 +578,8 @@ pub fn (b u8) repeat(count int) string {
}
return unsafe { ret.vstring_with_len(new_len) }
}
// for atomic ints, internal
fn _Atomic__int_str(x int) string {
return x.str()
}

View File

@ -211,66 +211,111 @@ pub fn (ctx &Context) draw_rect_filled(x f32, y f32, w f32, h f32, c gx.Color) {
sgl.end()
}
// draw_rounded_rect_empty draws the outline of a rounded rectangle
// draw_rounded_rect_empty draws the outline of a rounded rectangle with a thickness of 1 px.
// `x`,`y` is the top-left corner of the rectangle.
// `w` is the width, `h` is the height.
// `radius` is the radius of the corner-rounding in pixels.
// `c` is the color of the outline.
pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius f32, c gx.Color) {
mut theta := f32(0)
mut xx := f32(0)
mut yy := f32(0)
r := radius * ctx.scale
nx := x * ctx.scale
ny := y * ctx.scale
if w <= 0 || h <= 0 || radius < 0 {
return
}
if c.a != 255 {
sgl.load_pipeline(ctx.timage_pip)
}
sgl.c4b(c.r, c.g, c.b, c.a)
mut new_radius := radius
if w >= h && radius > h / 2 {
new_radius = h / 2
} else if radius > w / 2 {
new_radius = w / 2
}
r := new_radius * ctx.scale
sx := x * ctx.scale // start point x
sy := y * ctx.scale
width := w * ctx.scale
height := h * ctx.scale
segments := 2 * math.pi * r
segdiv := segments / 4
rb := 0
lb := int(rb + segdiv)
lt := int(lb + segdiv)
rt := int(lt + segdiv)
sgl.c4b(c.r, c.g, c.b, c.a)
// circle center coordinates
ltx := sx + r
lty := sy + r
rtx := sx + width - r
rty := lty
rbx := rtx
rby := sy + height - r
lbx := ltx
lby := rby
mut rad := f32(0)
mut dx := f32(0)
mut dy := f32(0)
// left top quarter
sgl.begin_line_strip()
// left top
lx := nx + r
ly := ny + r
theta_coeff := 2 * f32(math.pi) / segments
for i in lt .. rt {
theta = theta_coeff * f32(i)
xx = r * math.cosf(theta)
yy = r * math.sinf(theta)
sgl.v2f(xx + lx, yy + ly)
for i in 0 .. 31 {
if r == 0 {
break
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(ltx - dx, lty - dy)
}
// right top
mut rx := nx + width - r
mut ry := ny + r
for i in rt .. int(segments) {
theta = theta_coeff * f32(i)
xx = r * math.cosf(theta)
yy = r * math.sinf(theta)
sgl.v2f(xx + rx, yy + ry)
sgl.end()
// right top quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
if r == 0 {
break
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rtx + dx, rty - dy)
}
// right bottom
mut rbx := rx
mut rby := ny + height - r
for i in rb .. lb {
theta = theta_coeff * f32(i)
xx = r * math.cosf(theta)
yy = r * math.sinf(theta)
sgl.v2f(xx + rbx, yy + rby)
sgl.end()
// right bottom quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
if r == 0 {
break
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rbx + dx, rby + dy)
}
// left bottom
mut lbx := lx
mut lby := ny + height - r
for i in lb .. lt {
theta = theta_coeff * f32(i)
xx = r * math.cosf(theta)
yy = r * math.sinf(theta)
sgl.v2f(xx + lbx, yy + lby)
sgl.end()
// left bottom quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
if r == 0 {
break
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(lbx - dx, lby + dy)
}
sgl.v2f(lx + xx, ly)
sgl.end()
// Currently don't use 'gg.draw_line()' directly, it will repeatedly execute '*ctx.scale'.
sgl.begin_lines()
// top
sgl.v2f(ltx, sy)
sgl.v2f(rtx, sy)
// right
sgl.v2f(rtx + r, rty)
sgl.v2f(rtx + r, rby)
// bottom
sgl.v2f(lbx, lby + r)
sgl.v2f(rbx, rby + r)
// left
sgl.v2f(sx, lty)
sgl.v2f(sx, lby)
sgl.end()
}
@ -280,87 +325,91 @@ pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius
// `radius` is the radius of the corner-rounding in pixels.
// `c` is the color of the filled.
pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radius f32, c gx.Color) {
assert w > 0 && h > 0 && radius >= 0
if w <= 0 || h <= 0 || radius < 0 {
return
}
if c.a != 255 {
sgl.load_pipeline(ctx.timage_pip)
}
sgl.c4b(c.r, c.g, c.b, c.a)
mut xx := f32(0)
mut yy := f32(0)
mut radians := f32(0)
mut new_radius := radius
if w >= h && radius > h / 2 {
new_radius = h / 2
} else if radius > w / 2 {
new_radius = w / 2
}
r := new_radius * ctx.scale
nx := x * ctx.scale
ny := y * ctx.scale
sx := x * ctx.scale // start point x
sy := y * ctx.scale
width := w * ctx.scale
height := h * ctx.scale
// circle center coordinates
ltx := sx + r
lty := sy + r
rtx := sx + width - r
rty := lty
rbx := rtx
rby := sy + height - r
lbx := ltx
lby := rby
mut rad := f32(0)
mut dx := f32(0)
mut dy := f32(0)
// left top quarter
sgl.begin_triangle_strip()
ltx := nx + r
lty := ny + r
for i in 0 .. 91 {
for i in 0 .. 31 {
if r == 0 {
break
}
radians = f32(math.radians(i))
xx = r * math.cosf(radians)
yy = r * math.sinf(radians)
sgl.v2f(ltx - xx, lty - yy)
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(ltx - dx, lty - dy)
sgl.v2f(ltx, lty)
}
sgl.end()
// right top quarter
sgl.begin_triangle_strip()
rtx := nx + width - r
rty := ny + r
for i in 0 .. 91 {
for i in 0 .. 31 {
if r == 0 {
break
}
radians = f32(math.radians(i))
xx = r * math.cosf(radians)
yy = r * math.sinf(radians)
sgl.v2f(rtx + xx, rty - yy)
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rtx + dx, rty - dy)
sgl.v2f(rtx, rty)
}
sgl.end()
// right bottom quarter
sgl.begin_triangle_strip()
rbx := nx + width - r
rby := ny + height - r
for i in 0 .. 91 {
for i in 0 .. 31 {
if r == 0 {
break
}
radians = f32(math.radians(i))
xx = r * math.cosf(radians)
yy = r * math.sinf(radians)
sgl.v2f(rbx + xx, rby + yy)
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rbx + dx, rby + dy)
sgl.v2f(rbx, rby)
}
sgl.end()
// left bottom quarter
sgl.begin_triangle_strip()
lbx := nx + r
lby := ny + height - r
for i in 0 .. 91 {
for i in 0 .. 31 {
if r == 0 {
break
}
radians = f32(math.radians(i))
xx = r * math.cosf(radians)
yy = r * math.sinf(radians)
sgl.v2f(lbx - xx, lby + yy)
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(lbx - dx, lby + dy)
sgl.v2f(lbx, lby)
}
sgl.end()
@ -368,24 +417,24 @@ pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radiu
// Separate drawing is to prevent transparent color overlap
// top rectangle
sgl.begin_quads()
sgl.v2f(ltx, ny)
sgl.v2f(rtx, ny)
sgl.v2f(ltx, sy)
sgl.v2f(rtx, sy)
sgl.v2f(rtx, rty)
sgl.v2f(ltx, lty)
sgl.end()
// middle rectangle
sgl.begin_quads()
sgl.v2f(nx, ny + r)
sgl.v2f(sx, lty)
sgl.v2f(rtx + r, rty)
sgl.v2f(rbx + r, rby)
sgl.v2f(nx, lby)
sgl.v2f(sx, lby)
sgl.end()
// bottom rectangle
sgl.begin_quads()
sgl.v2f(lbx, lby)
sgl.v2f(rbx, rby)
sgl.v2f(rbx, ny + height)
sgl.v2f(lbx, ny + height)
sgl.v2f(rbx, rby + r)
sgl.v2f(lbx, rby + r)
sgl.end()
}

24
vlib/gg/gg_ui.c.v 100644
View File

@ -0,0 +1,24 @@
module gg
import gx
import sokol.sgl
// Stuff for ui from now for screenshot (that would be interesting for gg if screenshot is implemented also for gg)
// required for ui.DrawDevice interface (with &gg.Context as an instance)
pub fn (ctx &Context) scissor_rect(x int, y int, w int, h int) {
sgl.scissor_rect(int(dpi_scale() * x), int(dpi_scale() * y), int(dpi_scale() * w),
int(dpi_scale() * h), true)
}
pub fn (ctx &Context) has_text_style() bool {
return false
}
pub fn (ctx &Context) set_text_style(font_name string, font_path string, size int, color gx.Color, align int, vertical_align int) {}
// default draw_text (draw_text_def but without set_cfg)
pub fn (ctx &Context) draw_text_default(x int, y int, text string) {
scale := if ctx.ft.scale == 0 { f32(1) } else { ctx.ft.scale }
ctx.ft.fons.draw_text(x * scale, y * scale, text) // TODO: check offsets/alignment
}

View File

@ -408,6 +408,16 @@ fn test_abs() {
}
}
fn test_abs_zero() {
ret1 := abs(0)
println(ret1)
assert '$ret1' == '0'
ret2 := abs(0.0)
println(ret2)
assert '$ret2' == '0'
}
fn test_floor() {
for i := 0; i < math.vf_.len; i++ {
f := floor(math.vf_[i])

View File

@ -18,5 +18,5 @@ pub fn max<T>(a T, b T) T {
// abs returns the absolute value of `a`
[inline]
pub fn abs<T>(a T) T {
return if a > 0 { a } else { -a }
return if a < 0 { -a } else { a }
}

View File

@ -10,6 +10,7 @@ pub const (
#flag darwin -fobjc-arc
#flag linux -lX11 -lGL -lXcursor -lXi -lpthread
#flag freebsd -L/usr/local/lib -lX11 -lGL -lXcursor -lXi
#flag openbsd -L/usr/X11R6/lib -lX11 -lGL -lXcursor -lXi
#flag windows -lgdi32
// METAL
$if macos {
@ -27,6 +28,7 @@ $if ios {
// OPENGL
#flag linux -DSOKOL_GLCORE33
#flag freebsd -DSOKOL_GLCORE33
#flag openbsd -DSOKOL_GLCORE33
//#flag darwin -framework OpenGL -framework Cocoa -framework QuartzCore
// D3D
#flag windows -DSOKOL_GLCORE33
@ -41,6 +43,7 @@ $if ios {
#flag windows -DSOKOL_NO_ENTRY
#flag windows -DSOKOL_WIN32_FORCE_MAIN
#flag freebsd -DSOKOL_NO_ENTRY
#flag openbsd -DSOKOL_NO_ENTRY
#flag solaris -DSOKOL_NO_ENTRY
// TODO end

View File

@ -322,7 +322,7 @@ fn f32_to_decimal(mant u32, exp u32) Dec32 {
// String Functions
//=============================================================================
// f32_to_str return a string in scientific notation with max n_digit after the dot
// f32_to_str returns a `string` in scientific notation with max `n_digit` after the dot.
pub fn f32_to_str(f f32, n_digit int) string {
mut u1 := Uf32{}
u1.f = f
@ -349,7 +349,7 @@ pub fn f32_to_str(f f32, n_digit int) string {
return d.get_string_32(neg, n_digit, 0)
}
// f32_to_str return a string in scientific notation with max n_digit after the dot
// f32_to_str_pad returns a `string` in scientific notation with max `n_digit` after the dot.
pub fn f32_to_str_pad(f f32, n_digit int) string {
mut u1 := Uf32{}
u1.f = f

View File

@ -331,7 +331,7 @@ fn f64_to_decimal(mant u64, exp u64) Dec64 {
// String Functions
//=============================================================================
// f64_to_str return a string in scientific notation with max n_digit after the dot
// f64_to_str returns `f` as a `string` in scientific notation with max `n_digit` digits after the dot.
pub fn f64_to_str(f f64, n_digit int) string {
mut u1 := Uf64{}
u1.f = f
@ -356,7 +356,7 @@ pub fn f64_to_str(f f64, n_digit int) string {
return d.get_string_64(neg, n_digit, 0)
}
// f64_to_str return a string in scientific notation with max n_digit after the dot
// f64_to_str returns `f` as a `string` in scientific notation with max `n_digit` digits after the dot.
pub fn f64_to_str_pad(f f64, n_digit int) string {
mut u1 := Uf64{}
u1.f = f

View File

@ -89,6 +89,7 @@ pub mut:
rm_tail_zero bool // remove the tail zeros from floats
}
// format_str returns a `string` formatted according to the options set in `p`.
[manualfree]
pub fn format_str(s string, p BF_param) string {
if p.len0 <= 0 {

View File

@ -9,7 +9,7 @@ module strconv
import strings
// strings.Builder version of format_str
// format_str_sb is a `strings.Builder` version of `format_str`.
pub fn format_str_sb(s string, p BF_param, mut sb strings.Builder) {
if p.len0 <= 0 {
sb.write_string(s)
@ -40,7 +40,7 @@ const (
digit_pairs = '00102030405060708090011121314151617181910212223242526272829203132333435363738393041424344454647484940515253545556575859506162636465666768696071727374757677787970818283848586878889809192939495969798999'
)
// format_dec_sb format a u64
// format_dec_sb formats an u64 using a `strings.Builder`.
[direct_array_access]
pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
mut n_char := dec_digits(d)
@ -135,8 +135,9 @@ pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
return
}
// f64_to_str_lnd1 formats a f64 to a `string` with `dec_digit` digits after the dot.
[direct_array_access; manualfree]
pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
fn f64_to_str_lnd1(f f64, dec_digit int) string {
unsafe {
// we add the rounding value
s := f64_to_str(f + dec_round[dec_digit], 18)
@ -311,7 +312,7 @@ pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
}
}
// strings.Builder version of format_fl
// format_fl is a `strings.Builder` version of format_fl.
[direct_array_access; manualfree]
pub fn format_fl(f f64, p BF_param) string {
unsafe {
@ -388,6 +389,7 @@ pub fn format_fl(f f64, p BF_param) string {
}
}
// format_es returns a f64 as a `string` formatted according to the options set in `p`.
[direct_array_access; manualfree]
pub fn format_es(f f64, p BF_param) string {
unsafe {
@ -458,6 +460,7 @@ pub fn format_es(f f64, p BF_param) string {
}
}
// remove_tail_zeros strips traling zeros from `s` and return the resulting `string`.
[direct_array_access]
pub fn remove_tail_zeros(s string) string {
unsafe {

View File

@ -18,21 +18,33 @@ inspired by the Go version here:
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
*/
// ftoa_64 returns a string in scientific notation with max 17 digits after the dot.
//
// Example: assert strconv.ftoa_64(123.1234567891011121) == '1.2312345678910111e+02'
[inline]
pub fn ftoa_64(f f64) string {
return f64_to_str(f, 17)
}
// ftoa_long_64 returns `f` as a `string` in decimal notation with a maximum of 17 digits after the dot.
//
// Example: assert strconv.f64_to_str_l(123.1234567891011121) == '123.12345678910111'
[inline]
pub fn ftoa_long_64(f f64) string {
return f64_to_str_l(f)
}
// ftoa_32 returns a `string` in scientific notation with max 8 digits after the dot.
//
// Example: assert strconv.ftoa_32(34.1234567) == '3.4123455e+01'
[inline]
pub fn ftoa_32(f f32) string {
return f32_to_str(f, 8)
}
// ftoa_long_32 returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot.
//
// Example: assert strconv.ftoa_long_32(34.1234567) == '34.12346'
[inline]
pub fn ftoa_long_32(f f32) string {
return f32_to_str_l(f)

View File

@ -25,7 +25,9 @@ f64 to string with string format
*/
// TODO: Investigate precision issues
// f32_to_str_l return a string with the f32 converted in a string in decimal notation
// f32_to_str_l returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot.
//
// Example: assert strconv.f32_to_str_l(34.1234567) == '34.12346'
[manualfree]
pub fn f32_to_str_l(f f32) string {
s := f32_to_str(f, 6)
@ -34,6 +36,10 @@ pub fn f32_to_str_l(f f32) string {
return res
}
// f32_to_str_l_no_dot returns `f` as a `string` in decimal notation with a maximum of 6 digits after the dot.
// The decimal digits after the dot can be omitted.
//
// Example: assert strconv.f32_to_str_l_no_dot(34.) == '34'
[manualfree]
pub fn f32_to_str_l_no_dot(f f32) string {
s := f32_to_str(f, 6)
@ -42,6 +48,9 @@ pub fn f32_to_str_l_no_dot(f f32) string {
return res
}
// f64_to_str_l returns `f` as a `string` in decimal notation with a maximum of 18 digits after the dot.
//
// Example: assert strconv.f64_to_str_l(123.1234567891011121) == '123.12345678910111'
[manualfree]
pub fn f64_to_str_l(f f64) string {
s := f64_to_str(f, 18)
@ -50,6 +59,10 @@ pub fn f64_to_str_l(f f64) string {
return res
}
// f64_to_str_l_no_dot returns `f` as a `string` in decimal notation with a maximum of 18 digits after the dot.
// The decimal digits after the dot can be omitted.
//
// Example: assert strconv.f64_to_str_l_no_dot (34.) == '34'
[manualfree]
pub fn f64_to_str_l_no_dot(f f64) string {
s := f64_to_str(f, 18)
@ -58,7 +71,10 @@ pub fn f64_to_str_l_no_dot(f f64) string {
return res
}
// f64_to_str_l return a string with the f64 converted in a string in decimal notation
// fxx_to_str_l_parse returns a `string` in decimal notation converted from a
// floating-point `string` in scientific notation.
//
// Example: assert strconv.fxx_to_str_l_parse('34.22e+00') == '34.22'
[manualfree]
pub fn fxx_to_str_l_parse(s string) string {
// check for +inf -inf Nan
@ -181,7 +197,11 @@ pub fn fxx_to_str_l_parse(s string) string {
return unsafe { tos(res.data, r_i) }
}
// f64_to_str_l return a string with the f64 converted in a string in decimal notation
// fxx_to_str_l_parse_no_dot returns a `string` in decimal notation converted from a
// floating-point `string` in scientific notation.
// The decimal digits after the dot can be omitted.
//
// Example: assert strconv.fxx_to_str_l_parse_no_dot ('34.e+01') == '340'
[manualfree]
pub fn fxx_to_str_l_parse_no_dot(s string) string {
// check for +inf -inf Nan

View File

@ -22,10 +22,18 @@ enum Char_parse_state {
reset_params
}
// v_printf prints a sprintf-like formated `string` to the terminal.
pub fn v_printf(str string, pt ...voidptr) {
print(v_sprintf(str, ...pt))
}
// v_sprintf returns a sprintf-like formated `string`.
//
// Example:
// ```v
// x := 3.141516
// assert strconv.v_sprintf('aaa %G', x) == 'aaa 3.141516'
// ```
[manualfree]
pub fn v_sprintf(str string, pt ...voidptr) string {
mut res := strings.new_builder(pt.len * 16)
@ -628,7 +636,7 @@ pub fn format_fl_old(f f64, p BF_param) string {
}
[manualfree]
pub fn format_es_old(f f64, p BF_param) string {
fn format_es_old(f f64, p BF_param) string {
unsafe {
mut s := ''
mut fs := f64_to_str_pad(if f > 0 { f } else { -f }, p.len1)
@ -692,7 +700,7 @@ pub fn format_es_old(f f64, p BF_param) string {
}
}
pub fn remove_tail_zeros_old(s string) string {
fn remove_tail_zeros_old(s string) string {
mut i := 0
mut last_zero_start := -1
mut dot_pos := -1

View File

@ -25,7 +25,8 @@ pub fn (mut t Table) parse_cflag(cflg string, mod string, ctimedefines []string)
return none
}
mut fos := ''
mut allowed_os_overrides := ['linux', 'darwin', 'freebsd', 'windows', 'mingw', 'solaris']
mut allowed_os_overrides := ['linux', 'darwin', 'freebsd', 'openbsd', 'windows', 'mingw',
'solaris']
allowed_os_overrides << ctimedefines
for os_override in allowed_os_overrides {
if !flag.starts_with(os_override) {

View File

@ -1156,7 +1156,7 @@ pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int {
mut name := '('
mut cname := 'multi_return'
for i, mr_typ in mr_typs {
mr_type_sym := t.sym(mr_typ)
mr_type_sym := t.sym(mktyp(mr_typ))
ref, cref := if mr_typ.is_ptr() { '&', 'ref_' } else { '', '' }
name += '$ref$mr_type_sym.name'
cname += '_$cref$mr_type_sym.cname'

View File

@ -127,7 +127,7 @@ pub fn (t Type) atomic_typename() string {
idx := t.idx()
match idx {
ast.u32_type_idx { return 'atomic_uint' }
ast.int_type_idx { return 'atomic_int' }
ast.int_type_idx { return '_Atomic int' }
ast.u64_type_idx { return 'atomic_ullong' }
ast.i64_type_idx { return 'atomic_llong' }
else { return 'unknown_atomic' }
@ -1161,6 +1161,10 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string]
nr_muls--
res = 'shared ' + res
}
if typ.has_flag(.atomic_f) {
nr_muls--
res = 'atomic ' + res
}
if nr_muls > 0 && !typ.has_flag(.variadic) {
res = strings.repeat(`&`, nr_muls) + res
}

View File

@ -19,6 +19,10 @@ pub fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
if expected == ast.voidptr_type {
return true
}
if expected == ast.bool_type && (got.is_any_kind_of_pointer() || got.is_int()) {
return true
}
if expected.is_any_kind_of_pointer() { //&& !got.is_any_kind_of_pointer() {
// Allow `int` as `&i8` etc in C code.
deref := expected.deref()
@ -244,6 +248,20 @@ pub fn (mut c Checker) check_basic(got ast.Type, expected ast.Type) bool {
return true
}
got_sym, exp_sym := c.table.sym(got), c.table.sym(expected)
// multi return
if exp_sym.kind == .multi_return && got_sym.kind == .multi_return {
exp_types := exp_sym.mr_info().types
got_types := got_sym.mr_info().types.map(ast.mktyp(it))
if exp_types.len != got_types.len {
return false
}
for i in 0 .. exp_types.len {
if !c.check_types(got_types[i], exp_types[i]) {
return false
}
}
return true
}
// array/map as argument
if got_sym.kind in [.array, .map, .array_fixed] && exp_sym.kind == got_sym.kind {
if c.table.type_to_str(got) == c.table.type_to_str(expected).trim('&') {

View File

@ -702,8 +702,13 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
&& c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive() {
left_sym = c.table.sym((left_sym.info as ast.Alias).parent_type)
}
if c.pref.translated && node.op in [.plus, .minus, .mul]
&& left_type.is_any_kind_of_pointer()
&& (right_type.is_any_kind_of_pointer() || right_type.is_int()) {
return_type = left_type
}
// Check if the alias type is not a primitive then allow using operator overloading for aliased `arrays` and `maps`
if !c.pref.translated && left_sym.kind == .alias && left_sym.info is ast.Alias
else if !c.pref.translated && left_sym.kind == .alias && left_sym.info is ast.Alias
&& !(c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive()) {
if left_sym.has_method(node.op.str()) {
if method := left_sym.find_method(node.op.str()) {
@ -3775,7 +3780,9 @@ fn (mut c Checker) check_index(typ_sym &ast.TypeSymbol, index ast.Expr, index_ty
// if typ_sym.kind == .array && (!(ast.type_idx(index_type) in ast.number_type_idxs) &&
// index_type_sym.kind != .enum_) {
if typ_sym.kind in [.array, .array_fixed, .string] {
if !(index_type.is_int() || index_type_sym.kind == .enum_) {
if !(index_type.is_int() || index_type_sym.kind == .enum_
|| (index_type_sym.kind == .alias
&& (index_type_sym.info as ast.Alias).parent_type.is_int())) {
type_str := if typ_sym.kind == .string {
'non-integer string index `$index_type_sym.name`'
} else {

View File

@ -35,7 +35,8 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
if node.is_range {
high_type := c.expr(node.high)
high_type_idx := high_type.idx()
if typ_idx in ast.integer_type_idxs && high_type_idx !in ast.integer_type_idxs {
if typ_idx in ast.integer_type_idxs && high_type_idx !in ast.integer_type_idxs
&& high_type_idx != ast.void_type_idx {
c.error('range types do not match', node.cond.pos())
} else if typ_idx in ast.float_type_idxs || high_type_idx in ast.float_type_idxs {
c.error('range type can not be float', node.cond.pos())

View File

@ -217,16 +217,6 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
if is_noreturn_callexpr(last_expr.expr) {
continue
}
node_sym := c.table.sym(node.typ)
last_sym := c.table.sym(last_expr.typ)
if node_sym.kind == .multi_return && last_sym.kind == .multi_return {
node_types := node_sym.mr_info().types
last_types := last_sym.mr_info().types.map(ast.mktyp(it))
if node_types == last_types {
continue
}
}
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
node.pos)
}

View File

@ -22,182 +22,165 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
array_styp = g.typ(array_type.typ)
g.write('HEAP($array_styp, ')
}
len := node.exprs.len
if array_type.unaliased_sym.kind == .array_fixed {
if node.has_it {
g.inside_lambda = true
tmp := g.new_tmp_var()
mut s := g.go_before_stmt(0)
s_ends_with_ln := s.ends_with('\n')
s = s.trim_space()
ret_typ := g.typ(node.typ)
elem_typ := g.typ(node.elem_type)
g.empty_line = true
g.write('$ret_typ $tmp =')
g.write('{')
if node.has_val {
for i, expr in node.exprs {
if expr.is_auto_deref_var() {
g.write('*')
}
g.write('0')
if i != node.exprs.len - 1 {
g.write(', ')
}
}
} else if node.has_default {
g.write('0')
info := array_type.unaliased_sym.info as ast.ArrayFixed
for _ in 1 .. info.size {
g.fixed_array_init(node, array_type)
} else if len == 0 {
// `[]int{len: 6, cap:10, init:22}`
g.array_init_with_fields(node, elem_type, is_amp, shared_styp)
} else {
// `[1, 2, 3]`
elem_styp := g.typ(elem_type.typ)
noscan := g.check_noscan(elem_type.typ)
if elem_type.unaliased_sym.kind == .function {
g.write('new_array_from_c_array($len, $len, sizeof(voidptr), _MOV((voidptr[$len]){')
} else if g.is_empty_struct(elem_type) {
g.write('new_array_from_c_array${noscan}($len, $len, sizeof(voidptr), _MOV(($elem_styp[$len]){')
} else {
g.write('new_array_from_c_array${noscan}($len, $len, sizeof($elem_styp), _MOV(($elem_styp[$len]){')
}
if len > 8 {
g.writeln('')
g.write('\t\t')
}
for i, expr in node.exprs {
if node.expr_types[i] == ast.string_type && expr !is ast.StringLiteral
&& expr !is ast.StringInterLiteral {
g.write('string_clone(')
g.expr(expr)
g.write(')')
} else {
g.expr_with_cast(expr, node.expr_types[i], node.elem_type)
}
if i != len - 1 {
if i > 0 && i & 7 == 0 { // i > 0 && i % 8 == 0
g.writeln(',')
g.write('\t\t')
} else {
g.write(', ')
g.write('0')
}
} else {
g.write('0')
}
g.write('}')
g.writeln(';')
g.writeln('{')
g.indent++
g.writeln('$elem_typ* pelem = ($elem_typ*)$tmp;')
g.writeln('int _len = (int)sizeof($tmp) / sizeof($elem_typ);')
g.writeln('for(int it=0; it<_len; it++, pelem++) {')
g.indent++
g.write('*pelem = ')
g.expr(node.default_expr)
g.writeln(';')
g.indent--
g.writeln('}')
g.indent--
g.writeln('}')
if s_ends_with_ln {
g.writeln(s)
} else {
g.write(s)
}
g.write(tmp)
g.inside_lambda = false
return
}
need_tmp_var := g.inside_call && !g.inside_struct_init && node.exprs.len == 0
mut stmt_str := ''
mut tmp_var := ''
if need_tmp_var {
tmp_var = g.new_tmp_var()
stmt_str = g.go_before_stmt(0)
ret_typ := g.typ(node.typ)
g.empty_line = true
g.write('$ret_typ $tmp_var = ')
g.write('}))')
if g.is_shared {
g.write('}, sizeof($shared_styp))')
} else if is_amp {
g.write(')')
}
}
}
fn (mut g Gen) fixed_array_init(node ast.ArrayInit, array_type Type) {
if node.has_it {
g.inside_lambda = true
tmp := g.new_tmp_var()
mut s := g.go_before_stmt(0)
s_ends_with_ln := s.ends_with('\n')
s = s.trim_space()
ret_typ := g.typ(node.typ)
elem_typ := g.typ(node.elem_type)
g.empty_line = true
g.write('$ret_typ $tmp =')
g.write('{')
if node.has_val {
for i, expr in node.exprs {
if expr.is_auto_deref_var() {
g.write('*')
}
g.expr(expr)
g.write('0')
if i != node.exprs.len - 1 {
g.write(', ')
}
}
} else if node.has_default {
g.expr(node.default_expr)
g.write('0')
info := array_type.unaliased_sym.info as ast.ArrayFixed
for _ in 1 .. info.size {
g.write(', ')
g.expr(node.default_expr)
g.write('0')
}
} else {
g.write('0')
}
g.write('}')
if need_tmp_var {
g.writeln(';')
g.write(stmt_str)
g.write(tmp_var)
g.writeln(';')
g.writeln('{')
g.indent++
g.writeln('$elem_typ* pelem = ($elem_typ*)$tmp;')
g.writeln('int _len = (int)sizeof($tmp) / sizeof($elem_typ);')
g.writeln('for(int it=0; it<_len; it++, pelem++) {')
g.indent++
g.write('*pelem = ')
g.expr(node.default_expr)
g.writeln(';')
g.indent--
g.writeln('}')
g.indent--
g.writeln('}')
if s_ends_with_ln {
g.writeln(s)
} else {
g.write(s)
}
g.write(tmp)
g.inside_lambda = false
return
}
need_tmp_var := g.inside_call && !g.inside_struct_init && node.exprs.len == 0
mut stmt_str := ''
mut tmp_var := ''
if need_tmp_var {
tmp_var = g.new_tmp_var()
stmt_str = g.go_before_stmt(0)
ret_typ := g.typ(node.typ)
g.empty_line = true
g.write('$ret_typ $tmp_var = ')
}
g.write('{')
if node.has_val {
for i, expr in node.exprs {
if expr.is_auto_deref_var() {
g.write('*')
}
g.expr(expr)
if i != node.exprs.len - 1 {
g.write(', ')
}
}
} else if node.has_default {
g.expr(node.default_expr)
info := array_type.unaliased_sym.info as ast.ArrayFixed
for _ in 1 .. info.size {
g.write(', ')
g.expr(node.default_expr)
}
} else {
g.write('0')
}
g.write('}')
if need_tmp_var {
g.writeln(';')
g.write(stmt_str)
g.write(tmp_var)
}
}
// `[]int{len: 6, cap: 10, init: it * it}`
fn (mut g Gen) array_init_with_fields(node ast.ArrayInit, elem_type Type, is_amp bool, shared_styp string) {
elem_styp := g.typ(elem_type.typ)
noscan := g.check_noscan(elem_type.typ)
if node.exprs.len == 0 {
is_default_array := elem_type.unaliased_sym.kind == .array && node.has_default
is_default_map := elem_type.unaliased_sym.kind == .map && node.has_default
if node.has_it { // []int{len: 6, init: it * it} when variable it is used in init expression
g.inside_lambda = true
tmp := g.new_tmp_var()
mut s := g.go_before_stmt(0)
s_ends_with_ln := s.ends_with('\n')
s = s.trim_space()
ret_typ := g.typ(node.typ)
elem_typ := g.typ(node.elem_type)
g.empty_line = true
g.write('$ret_typ $tmp =')
if is_default_array {
g.write('__new_array_with_array_default${noscan}(')
} else if is_default_map {
g.write('__new_array_with_map_default${noscan}(')
} else {
g.write('__new_array_with_default${noscan}(')
}
if node.has_len {
g.expr(node.len_expr)
g.write(', ')
} else {
g.write('0, ')
}
if node.has_cap {
g.expr(node.cap_expr)
g.write(', ')
} else {
g.write('0, ')
}
if elem_type.unaliased_sym.kind == .function || g.is_empty_struct(elem_type) {
g.write('sizeof(voidptr), ')
} else {
g.write('sizeof($elem_styp), ')
}
if is_default_array {
g.write('($elem_styp[]){')
g.expr(node.default_expr)
g.write('}[0])')
} else if node.has_len && node.elem_type == ast.string_type {
g.write('&($elem_styp[]){')
g.write('_SLIT("")')
g.write('})')
} else if node.has_len && elem_type.unaliased_sym.kind in [.array, .map] {
g.write('(voidptr)&($elem_styp[]){')
g.write(g.type_default(node.elem_type))
g.write('}[0])')
} else {
g.write('0)')
}
if g.is_shared {
g.write('}, sizeof($shared_styp))')
} else if is_amp {
g.write(')')
}
g.writeln(';')
g.writeln('{')
g.indent++
g.writeln('$elem_typ* pelem = ($elem_typ*)${tmp}.data;')
g.writeln('for(int it=0; it<${tmp}.len; it++, pelem++) {')
g.indent++
g.write('*pelem = ')
g.expr(node.default_expr)
g.writeln(';')
g.indent--
g.writeln('}')
g.indent--
g.writeln('}')
if s_ends_with_ln {
g.writeln(s)
} else {
g.write(s)
}
g.write(tmp)
g.inside_lambda = false
return
}
is_default_array := elem_type.unaliased_sym.kind == .array && node.has_default
is_default_map := elem_type.unaliased_sym.kind == .map && node.has_default
if node.has_it { // []int{len: 6, init: it * it} when variable it is used in init expression
g.inside_lambda = true
tmp := g.new_tmp_var()
mut s := g.go_before_stmt(0)
s_ends_with_ln := s.ends_with('\n')
s = s.trim_space()
ret_typ := g.typ(node.typ)
elem_typ := g.typ(node.elem_type)
g.empty_line = true
g.write('$ret_typ $tmp =')
if is_default_array {
g.write('__new_array_with_array_default${noscan}(')
} else if is_default_map {
@ -222,14 +205,10 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
} else {
g.write('sizeof($elem_styp), ')
}
if is_default_array || is_default_map {
if is_default_array {
g.write('($elem_styp[]){')
g.expr(node.default_expr)
g.write('}[0])')
} else if node.has_default {
g.write('&($elem_styp[]){')
g.expr_with_cast(node.default_expr, node.default_type, node.elem_type)
g.write('})')
} else if node.has_len && node.elem_type == ast.string_type {
g.write('&($elem_styp[]){')
g.write('_SLIT("")')
@ -246,39 +225,71 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
} else if is_amp {
g.write(')')
}
g.writeln(';')
g.writeln('{')
g.indent++
g.writeln('$elem_typ* pelem = ($elem_typ*)${tmp}.data;')
g.writeln('for(int it=0; it<${tmp}.len; it++, pelem++) {')
g.indent++
g.write('*pelem = ')
g.expr(node.default_expr)
g.writeln(';')
g.indent--
g.writeln('}')
g.indent--
g.writeln('}')
if s_ends_with_ln {
g.writeln(s)
} else {
g.write(s)
}
g.write(tmp)
g.inside_lambda = false
return
}
len := node.exprs.len
if elem_type.unaliased_sym.kind == .function {
g.write('new_array_from_c_array($len, $len, sizeof(voidptr), _MOV((voidptr[$len]){')
} else if g.is_empty_struct(elem_type) {
g.write('new_array_from_c_array${noscan}($len, $len, sizeof(voidptr), _MOV(($elem_styp[$len]){')
if is_default_array {
g.write('__new_array_with_array_default${noscan}(')
} else if is_default_map {
g.write('__new_array_with_map_default${noscan}(')
} else {
g.write('new_array_from_c_array${noscan}($len, $len, sizeof($elem_styp), _MOV(($elem_styp[$len]){')
g.write('__new_array_with_default${noscan}(')
}
if len > 8 {
g.writeln('')
g.write('\t\t')
if node.has_len {
g.expr(node.len_expr)
g.write(', ')
} else {
g.write('0, ')
}
for i, expr in node.exprs {
if node.expr_types[i] == ast.string_type && expr !is ast.StringLiteral
&& expr !is ast.StringInterLiteral {
g.write('string_clone(')
g.expr(expr)
g.write(')')
} else {
g.expr_with_cast(expr, node.expr_types[i], node.elem_type)
}
if i != len - 1 {
if i > 0 && i & 7 == 0 { // i > 0 && i % 8 == 0
g.writeln(',')
g.write('\t\t')
} else {
g.write(', ')
}
}
if node.has_cap {
g.expr(node.cap_expr)
g.write(', ')
} else {
g.write('0, ')
}
if elem_type.unaliased_sym.kind == .function || g.is_empty_struct(elem_type) {
g.write('sizeof(voidptr), ')
} else {
g.write('sizeof($elem_styp), ')
}
if is_default_array || is_default_map {
g.write('($elem_styp[]){')
g.expr(node.default_expr)
g.write('}[0])')
} else if node.has_default {
g.write('&($elem_styp[]){')
g.expr_with_cast(node.default_expr, node.default_type, node.elem_type)
g.write('})')
} else if node.has_len && node.elem_type == ast.string_type {
g.write('&($elem_styp[]){')
g.write('_SLIT("")')
g.write('})')
} else if node.has_len && elem_type.unaliased_sym.kind in [.array, .map] {
g.write('(voidptr)&($elem_styp[]){')
g.write(g.type_default(node.elem_type))
g.write('}[0])')
} else {
g.write('0)')
}
g.write('}))')
if g.is_shared {
g.write('}, sizeof($shared_styp))')
} else if is_amp {

View File

@ -384,18 +384,18 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
clean_interface_v_type_name = util.strip_main_name(clean_interface_v_type_name)
fn_builder.writeln('static string indent_${str_fn_name}($styp x, int indent_count) { /* gen_str_for_interface */')
for typ in info.types {
subtype := g.table.sym(typ)
sub_sym := g.table.sym(ast.mktyp(typ))
mut func_name := g.get_str_fn(typ)
sym_has_str_method, str_method_expects_ptr, _ := subtype.str_method_info()
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
sym_has_str_method, str_method_expects_ptr, _ := sub_sym.str_method_info()
if should_use_indent_func(sub_sym.kind) && !sym_has_str_method {
func_name = 'indent_$func_name'
}
// str_intp
deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' }
if typ == ast.string_type {
mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname'
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
mut val := '${func_name}(${deref}($sub_sym.cname*)x._$sub_sym.cname'
if should_use_indent_func(sub_sym.kind) && !sym_has_str_method {
val += ', indent_count'
}
val += ')'
@ -403,11 +403,11 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
{_SLIT("${clean_interface_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}},
{_SLIT("\')"), 0, {.d_c = 0 }}
}))'
fn_builder.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)')
fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)')
fn_builder.write_string(' return $res;')
} else {
mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname'
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
mut val := '${func_name}(${deref}($sub_sym.cname*)x._$sub_sym.cname'
if should_use_indent_func(sub_sym.kind) && !sym_has_str_method {
val += ', indent_count'
}
val += ')'
@ -415,7 +415,7 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
{_SLIT("${clean_interface_v_type_name}("), $c.si_s_code, {.d_s = $val}},
{_SLIT(")"), 0, {.d_c = 0 }}
}))'
fn_builder.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)')
fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)')
fn_builder.write_string(' return $res;\n')
}
}

View File

@ -195,6 +195,7 @@ mut:
referenced_fns shared map[string]bool // functions that have been referenced
nr_closures int
expected_cast_type ast.Type // for match expr of sumtypes
or_expr_return_type ast.Type // or { 0, 1 } return type
anon_fn bool
tests_inited bool
has_main bool
@ -858,16 +859,16 @@ pub fn (mut g Gen) write_typeof_functions() {
g.definitions.writeln('static char * v_typeof_interface_${sym.cname}(int sidx);')
g.writeln('static char * v_typeof_interface_${sym.cname}(int sidx) { /* $sym.name */ ')
for t in inter_info.types {
subtype := g.table.sym(t)
g.writeln('\tif (sidx == _${sym.cname}_${subtype.cname}_index) return "${util.strip_main_name(subtype.name)}";')
sub_sym := g.table.sym(ast.mktyp(t))
g.writeln('\tif (sidx == _${sym.cname}_${sub_sym.cname}_index) return "${util.strip_main_name(sub_sym.name)}";')
}
g.writeln('\treturn "unknown ${util.strip_main_name(sym.name)}";')
g.writeln('}')
g.writeln('')
g.writeln('static int v_typeof_interface_idx_${sym.cname}(int sidx) { /* $sym.name */ ')
for t in inter_info.types {
subtype := g.table.sym(t)
g.writeln('\tif (sidx == _${sym.cname}_${subtype.cname}_index) return ${int(t)};')
sub_sym := g.table.sym(ast.mktyp(t))
g.writeln('\tif (sidx == _${sym.cname}_${sub_sym.cname}_index) return ${int(t)};')
}
g.writeln('\treturn ${int(ityp)};')
g.writeln('}')
@ -1318,7 +1319,11 @@ pub fn (mut g Gen) write_interface_typesymbol_declaration(sym ast.TypeSymbol) {
g.type_definitions.writeln('\tunion {')
g.type_definitions.writeln('\t\tvoid* _object;')
for variant in info.types {
vcname := g.table.sym(variant).cname
mk_typ := ast.mktyp(variant)
if mk_typ != variant && mk_typ in info.types {
continue
}
vcname := g.table.sym(mk_typ).cname
g.type_definitions.writeln('\t\t$vcname* _$vcname;')
}
g.type_definitions.writeln('\t};')
@ -2084,11 +2089,11 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
g.expr(expr)
return
}
if exp_sym.info is ast.Interface && got_type_raw.idx() != expected_type.idx()
if exp_sym.info is ast.Interface && got_type.idx() != expected_type.idx()
&& !expected_type.has_flag(.optional) {
if expr is ast.StructInit && !got_type.is_ptr() {
g.inside_cast_in_heap++
got_styp := g.cc_type(got_type_raw.ref(), true)
got_styp := g.cc_type(got_type.ref(), true)
// TODO: why does cc_type even add this in the first place?
exp_styp := exp_sym.cname
mut fname := 'I_${got_styp}_to_Interface_$exp_styp'
@ -2099,7 +2104,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
got_styp)
g.inside_cast_in_heap--
} else {
got_styp := g.cc_type(got_type_raw, true)
got_styp := g.cc_type(got_type, true)
got_is_shared := got_type.has_flag(.shared_f)
exp_styp := if got_is_shared { '__shared__$exp_sym.cname' } else { exp_sym.cname }
// If it's shared, we need to use the other caster:
@ -3864,6 +3869,8 @@ fn (mut g Gen) concat_expr(node ast.ConcatExpr) {
mut styp := g.typ(node.return_type)
if g.inside_return {
styp = g.typ(g.fn_decl.return_type)
} else if g.inside_or_block {
styp = g.typ(g.or_expr_return_type)
}
sym := g.table.sym(node.return_type)
is_multi := sym.kind == .multi_return
@ -4933,6 +4940,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
g.writeln('if (${cvar_name}.state != 0) { /*or block*/ ')
}
if or_block.kind == .block {
g.or_expr_return_type = return_type.clear_flag(.optional)
if g.inside_or_block {
g.writeln('\terr = ${cvar_name}.err;')
} else {
@ -4970,6 +4978,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
g.writeln(';')
}
}
g.or_expr_return_type = ast.void_type
} else if or_block.kind == .propagate {
if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) {
// In main(), an `opt()?` call is sugar for `opt() or { panic(err) }`
@ -5198,9 +5207,10 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
// Make sure the sum type can be cast to this type (the types
// are the same), otherwise panic.
// g.insert_before('
styp := g.typ(node.typ)
sym := g.table.sym(node.typ)
mut expr_type_sym := g.table.sym(node.expr_type)
unwrapped_node_typ := g.unwrap_generic(node.typ)
styp := g.typ(unwrapped_node_typ)
sym := g.table.sym(unwrapped_node_typ)
mut expr_type_sym := g.table.sym(g.unwrap_generic(node.expr_type))
if mut expr_type_sym.info is ast.SumType {
dot := if node.expr_type.is_ptr() { '->' } else { '.' }
g.write('/* as */ *($styp*)__as_cast(')
@ -5214,9 +5224,8 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
g.write(')')
g.write(dot)
// g.write('typ, /*expected:*/$node.typ)')
sidx := g.type_sidx(node.typ)
expected_sym := g.table.sym(node.typ)
g.write('_typ, $sidx) /*expected idx: $sidx, name: $expected_sym.name */ ')
sidx := g.type_sidx(unwrapped_node_typ)
g.write('_typ, $sidx) /*expected idx: $sidx, name: $sym.name */ ')
// fill as cast name table
for variant in expr_type_sym.info.variants {
@ -5329,10 +5338,10 @@ fn (mut g Gen) interface_table() string {
iinidx_minimum_base := 1000 // Note: NOT 0, to avoid map entries set to 0 later, so `if already_generated_mwrappers[name] > 0 {` works.
mut current_iinidx := iinidx_minimum_base
for st in inter_info.types {
st_sym := g.table.sym(st)
st_sym := g.table.sym(ast.mktyp(st))
// cctype is the Cleaned Concrete Type name, *without ptr*,
// i.e. cctype is always just Cat, not Cat_ptr:
cctype := g.cc_type(st, true)
cctype := g.cc_type(ast.mktyp(st), true)
$if debug_interface_table ? {
eprintln('>> interface name: $isym.name | concrete type: $st.debug() | st symname: $st_sym.name')
}

View File

@ -401,10 +401,13 @@ pub fn (mut p Parser) parse_type() ast.Type {
p.error_with_pos('cannot use `mut` on struct field type', p.tok.pos())
}
}
if p.tok.kind == .key_mut || is_shared || is_atomic {
if p.tok.kind == .key_mut || is_shared { // || is_atomic {
nr_muls++
p.next()
}
if is_atomic {
p.next()
}
if p.tok.kind == .mul {
p.error('use `&Type` instead of `*Type` when declaring references')
return 0

View File

@ -0,0 +1,23 @@
import term
import os
import runtime
import time
struct App {
mut:
idx atomic int
}
fn test_atomic() {
mut app := &App{}
for i in 0 .. 10 {
go app.run()
}
time.sleep(2 * time.second)
println('idx=$app.idx')
assert app.idx == 10
}
fn (mut app App) run() {
app.idx++
}

View File

@ -0,0 +1,29 @@
interface Any {}
fn thing(any Any) string {
return match any {
int { 'int${*any:17}' }
f64 { 'f64${*any:20}' }
else { 'literal type tag?${any:10}' }
}
}
fn test_cast_to_empty_interface() {
mut ret_strings := []string{}
mut arr := [Any(int(11)), int(22), Any(8888), 9999, Any(f64(1.11)), f64(2.22), Any(8.88), 9.99]
for i in arr {
println(thing(i))
ret_strings << thing(i)
}
assert ret_strings.len == 8
assert ret_strings[0] == 'int 11'
assert ret_strings[1] == 'int 22'
assert ret_strings[2] == 'int 8888'
assert ret_strings[3] == 'int 9999'
assert ret_strings[4] == 'f64 1.110'
assert ret_strings[5] == 'f64 2.220'
assert ret_strings[6] == 'f64 8.880'
assert ret_strings[7] == 'f64 9.990'
}

View File

@ -0,0 +1,50 @@
module main
struct Empty {}
struct Node<T> {
value T
mut:
next Tree<T>
}
type Tree<T> = Empty | Node<T>
fn create<T>() Tree<T> {
empty := Empty{}
mut curr := Node<T>{10, empty}
for _ in 0 .. 10 {
curr.next = Node<T>{20, empty}
}
return curr
}
fn create_node<T>(args []T) Tree<T> {
empty := Empty{}
if args.len == 0 {
return empty
}
mut curr := Node<T>{args[0], empty}
for i := 1; i < args.len; i += 1 {
curr.next = Node<T>{args[i], empty}
curr = curr.next as Node<T>
}
return curr
}
fn merge_nodes<T>(head Tree<T>) Tree<T> {
println('$head')
return Empty{}
}
fn test_generic_sumtype_cast() {
node := create_node<int>([0, 3, 1, 0, 4, 5, 2, 0])
merge_nodes(node)
create<int>()
assert true
}

View File

@ -0,0 +1,31 @@
fn multi_return1() ?(int, int) {
return 1, 2
}
fn multi_return2() ?(i64, i64) {
return 11, 22
}
fn multi_return3() ?(int, i64) {
return 11, 22
}
fn test_multi_return_in_or_expr() {
a1, b1 := multi_return1() or { 0, -1 }
println('$a1, $b1')
assert a1 == 1
assert b1 == 2
a2, b2 := multi_return2() or { 0, -1 }
println('$a2, $b2')
assert a2 == 11
assert b2 == 22
a3, b3 := multi_return3() or { 0, -1 }
println('$a3, $b3')
assert a3 == 11
assert b3 == 22
}

View File

@ -59,13 +59,13 @@ pub fn (mut bmp BitMap) clear() {
}
// transform matrix applied to the text
fn (bmp &BitMap) trf_txt(p &Point) (int, int) {
pub fn (bmp &BitMap) trf_txt(p &Point) (int, int) {
return int(p.x * bmp.tr_matrix[0] + p.y * bmp.tr_matrix[3] + bmp.tr_matrix[6]), int(
p.x * bmp.tr_matrix[1] + p.y * bmp.tr_matrix[4] + bmp.tr_matrix[7])
}
// transform matrix applied to the char
fn (bmp &BitMap) trf_ch(p &Point) (int, int) {
pub fn (bmp &BitMap) trf_ch(p &Point) (int, int) {
return int(p.x * bmp.ch_matrix[0] + p.y * bmp.ch_matrix[3] + bmp.ch_matrix[6]), int(
p.x * bmp.ch_matrix[1] + p.y * bmp.ch_matrix[4] + bmp.ch_matrix[7])
}

View File

@ -20,7 +20,7 @@ pub struct Text_block {
cut_lines bool = true // force to cut the line if the length is over the text block width
}
fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_cw int) f32 {
pub fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_cw int) f32 {
num_spaces := txt.count(' ')
if num_spaces < 1 {
return 0

View File

@ -771,7 +771,7 @@ fn (mut tf TTF_File) read_cmap(offset u32) {
* CMAPS 0/4
*
******************************************************************************/
fn (mut tf TTF_File) map_code(char_code int) u16 {
pub fn (mut tf TTF_File) map_code(char_code int) u16 {
mut index := 0
for i in 0 .. tf.cmaps.len {
mut cmap := tf.cmaps[i]
@ -1006,13 +1006,13 @@ fn (mut tf TTF_File) read_kern_table() {
}
}
fn (mut tf TTF_File) reset_kern() {
pub fn (mut tf TTF_File) reset_kern() {
for i in 0 .. tf.kern.len {
tf.kern[i].reset()
}
}
fn (mut tf TTF_File) next_kern(glyph_index int) (int, int) {
pub fn (mut tf TTF_File) next_kern(glyph_index int) (int, int) {
mut x := 0
mut y := 0
for i in 0 .. tf.kern.len {