Compare commits

...

24 Commits

Author SHA1 Message Date
Benjamin Thomas 9b1f7f5e94
doc: suggest a basic auto-reload setup (#14216)
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-29 21:38:24 +02:00
David 'Epper' Marshall 25df4fa143
time: add custom formatter (#14202) 2022-04-29 21:38:24 +02:00
yuyi 2109a6a85c
parser: check interface methods name (fix #14217) (#14218) 2022-04-29 21:38:24 +02:00
yuyi d1a0ac26fd
checker: check struct field name using uppercase letters (#14220) 2022-04-29 21:38:24 +02:00
Wertzui123 735817374e
builtin: ignore C++ 0xE06D7363 exception errors on windows (#14225) 2022-04-29 21:38:24 +02:00
StunxFS f8ed4ab9d0
builtin: add `string.len_utf8()` method (#14208) 2022-04-29 21:38:24 +02:00
StunxFS 3c8b67521b
cgen: fix use of C reserved words inside `defer` statement (fix #14101) (#14211) 2022-04-29 21:38:24 +02:00
Alexander Medvednikov 23117e6802
builtin: define atoi & ftell 2022-04-29 21:38:24 +02:00
spaceface 893e2ff6cb
ast: add a type_size() method (#14213) 2022-04-29 21:38:23 +02:00
David 'Epper' Marshall 7fc9e3a4c1
docs: add a `v fmt -w .` step in the contributing guide (#14210) 2022-04-29 21:38:23 +02:00
StunxFS da71bced46
transformer: minor optimization for `'string literal'.len` (#14207) 2022-04-29 21:38:23 +02:00
playX 59ddaa9ede
checker: disable op overloading on structures for translated code (#14209) 2022-04-29 21:38:23 +02:00
yuyi 134b594e4d
ast, parser: fix complex map init (#14206) 2022-04-29 21:38:23 +02:00
yuyi c2ecfb32d9
cgen: fix go anon fn call with ref argument (fix #14192) (#14197) 2022-04-29 21:38:23 +02:00
yuyi 03d2258b6d
ast: fix error for complex map operating (#14204) 2022-04-29 21:38:23 +02:00
Atom 48749b0b24
arrays: rephrase doc string (#14205) 2022-04-29 21:38:23 +02:00
Delyan Angelov 47dccd56a2
eval: small cleanup in the handling of `$if platform {` 2022-04-29 21:38:23 +02:00
Delyan Angelov 705e260180
eval: make the interpreter backtrace more efficient and informative. 2022-04-29 21:38:23 +02:00
Delyan Angelov 31bee98607
eval: add support for C.read/3, C.malloc/1, `$if openbsd {` 2022-04-29 21:38:23 +02:00
Delyan Angelov 444d8c7a81
pref: add support for `-thread-stack-size 4194304` (default set to 8MB) (#14168) 2022-04-29 21:38:23 +02:00
yuyi 47c18c4570
checker: fix error for array of sumtype appending literal value (#14200) 2022-04-29 21:38:22 +02:00
yuyi bf75a873b5
checker: check error in for_c_stmt with optional call (#14190) 2022-04-29 21:38:22 +02:00
tzSharing f9bd107a84
gg: improve some loops in draw_rounded_rect* methods (#14195) 2022-04-29 21:38:22 +02:00
Delyan Angelov 624f022ddc
ci: fix tcc compilation of atomic_test.v 2022-04-29 21:38:22 +02:00
51 changed files with 1009 additions and 399 deletions

View File

@ -90,6 +90,7 @@ making pullrequests, and you can just do normal git operations such as:
5. When finished with a feature/bugfix/change, you can:
`git checkout -b fix_alabala`
- Don't forget to keep formatting standards, run `v fmt -w YOUR_MODIFIED_FILES` before committing
6. `git push pullrequest` # (NOTE: the `pullrequest` remote was setup on step 4)
7. On GitHub's web interface, go to: https://github.com/vlang/v/pulls

View File

@ -64,11 +64,11 @@ language, very similar to the way it is right now.
### Linux, macOS, Windows, *BSD, Solaris, WSL, Android, etc.
Usually installing V is quite simple if you have an environment that already has a
functional `git` installation.
Usually installing V is quite simple if you have an environment that already has a
functional `git` installation.
* *(* ***PLEASE NOTE:*** *If you run into any trouble or you have a different operating
system or Linux distribution that doesn't install or work immediately, please see
system or Linux distribution that doesn't install or work immediately, please see
[Installation Issues](https://github.com/vlang/v/discussions/categories/installation-issues)
and search for your OS and problem. If you can't find your problem, please add it to an
existing discussion if one exists for your OS, or create a new one if a main discussion

View File

@ -257,7 +257,7 @@ see also `v help build`.
Passing -no-std will remove that flag, and you can then use -cflags ''
to pass the other options for your specific C compiler.
-assert aborts
-assert aborts
Call abort() after an assertion failure. Debuggers usually
install signal handlers for SIGABRT, so your program will stop and you
will get a backtrace. If you are running your program outside of a
@ -267,3 +267,14 @@ see also `v help build`.
Call print_backtrace() after an assertion failure. Note that
backtraces are not implemented yet on all combinations of
platform/compiler.
-thread-stack-size 4194304
Set the thread stack size to 4MB. Use multiples of 4096.
The default is 8MB, which is enough for compiling V programs, with deeply
nested expressions (~40 levels).
It may need to be increased, if you are getting stack overflow errors for
deeply recursive programs like some of the stages of the V compiler itself,
that use relatively few threads.
It may be decreased, to reduce the memory footprint of programs that launch
hundreds/thousands of threads, but where each of the threads does not need
a big stack.

View File

@ -112,9 +112,7 @@ fn (mut app App) time() vweb.Result {
<img width=662 src="https://github.com/vlang/v/blob/master/tutorials/building_a_simple_web_blog_with_vweb/img/time.png?raw=true">
>You have to rebuild and restart the website every time you change the code.
In the future, Vweb will detect changes and recompile the website in the background
while it's running.
>TIP: run the following command to live-reload the server: `v watch run blog.v`
The `.text(string)` method returns a plain text document with the provided
text, which isn't frequently used in websites.

View File

@ -24,7 +24,7 @@ pub fn min<T>(a []T) ?T {
return val
}
// max returns the maximum the maximum value in the array
// max returns the maximum value in the array
// Example: arrays.max([1,2,3,0,9]) // => 9
pub fn max<T>(a []T) ?T {
if a.len == 0 {

View File

@ -243,7 +243,7 @@ fn unhandled_exception_handler(e &ExceptionPointers) int {
match e.exception_record.code {
// These are 'used' by the backtrace printer
// so we dont want to catch them...
0x4001000A, 0x40010006 {
0x4001000A, 0x40010006, 0xE06D7363 {
return 0
}
else {

View File

@ -1,5 +1,7 @@
module builtin
// struct C.FILE {}
// <string.h>
fn C.memcpy(dest voidptr, const_src voidptr, n usize) voidptr
@ -10,11 +12,13 @@ fn C.memmove(dest voidptr, const_src voidptr, n usize) voidptr
fn C.memset(str voidptr, c int, n usize) voidptr
[trusted]
fn C.calloc(int, int) &byte
fn C.calloc(int, int) &u8
fn C.malloc(int) &byte
fn C.atoi(&char) int
fn C.realloc(a &byte, b int) &byte
fn C.malloc(int) &u8
fn C.realloc(a &u8, b int) &u8
fn C.free(ptr voidptr)
@ -120,6 +124,8 @@ fn C.chdir(path &char) int
fn C.rewind(stream &C.FILE) int
fn C.ftell(&C.FILE) int
fn C.stat(&char, voidptr) int
fn C.lstat(path &char, buf &C.stat) int

View File

@ -295,6 +295,17 @@ pub fn (cp &char) vstring_literal_with_len(len int) string {
}
}
// len_utf8 returns the number of runes contained in the string `s`.
pub fn (s string) len_utf8() int {
mut l := 0
mut i := 0
for i < s.len {
l++
i += ((0xe5000000 >> ((unsafe { s.str[i] } >> 3) & 0x1e)) & 3) + 1
}
return l
}
// clone_static returns an independent copy of a given array.
// It should be used only in -autofree generated code.
fn (a string) clone_static() string {

View File

@ -24,6 +24,14 @@ fn test_add() {
assert a.ends_with('3')
}
fn test_len_utf8() {
assert 'Vlang'.len_utf8() == 5
assert 'María'.len_utf8() == 5
assert ''.len_utf8() == 2
assert 'Слово'.len_utf8() == 5
assert 'Λέξη'.len_utf8() == 4
}
fn test_ends_with() {
a := 'browser.v'
assert a.ends_with('.v')

View File

@ -66,6 +66,19 @@ pub fn utf32_decode_to_buffer(code u32, buf &u8) int {
return 0
}
// utf8_str_len returns the number of runes contained in the string.
[deprecated: 'use `string.len_utf8()` instead']
[deprecated_after: '2022-05-28']
pub fn utf8_str_len(s string) int {
mut l := 0
mut i := 0
for i < s.len {
l++
i += ((0xe5000000 >> ((unsafe { s.str[i] } >> 3) & 0x1e)) & 3) + 1
}
return l
}
// Convert utf8 to utf32
// the original implementation did not check for
// valid utf8 in the string, and could result in
@ -134,17 +147,6 @@ fn utf8_len(c u8) int {
return b
}
// Calculate string length for in number of codepoints
pub fn utf8_str_len(s string) int {
mut l := 0
mut i := 0
for i < s.len {
l++
i += ((0xe5000000 >> ((unsafe { s.str[i] } >> 3) & 0x1e)) & 3) + 1
}
return l
}
// Calculate string length for formatting, i.e. number of "characters"
// This is simplified implementation. if you need specification compliant width,
// use utf8.east_asian.display_width.

View File

@ -250,57 +250,47 @@ pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius
mut dx := f32(0)
mut dy := f32(0)
// left top quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
if r == 0 {
break
if r != 0 {
// left top quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(ltx - dx, lty - dy)
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(ltx - dx, lty - dy)
}
sgl.end()
sgl.end()
// right top quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
if r == 0 {
break
// right top quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rtx + dx, rty - dy)
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rtx + dx, rty - dy)
}
sgl.end()
sgl.end()
// right bottom quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
if r == 0 {
break
// right bottom quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rbx + dx, rby + dy)
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(rbx + dx, rby + dy)
}
sgl.end()
sgl.end()
// left bottom quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
if r == 0 {
break
// left bottom quarter
sgl.begin_line_strip()
for i in 0 .. 31 {
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(lbx - dx, lby + dy)
}
rad = f32(math.radians(i * 3))
dx = r * math.cosf(rad)
dy = r * math.sinf(rad)
sgl.v2f(lbx - dx, lby + dy)
sgl.end()
}
sgl.end()
// Currently don't use 'gg.draw_line()' directly, it will repeatedly execute '*ctx.scale'.
sgl.begin_lines()
@ -358,61 +348,51 @@ pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radiu
mut dx := f32(0)
mut dy := f32(0)
// left top quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
if r == 0 {
break
if r != 0 {
// left top quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
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)
}
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()
sgl.end()
// right top quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
if r == 0 {
break
// right top quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
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)
}
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()
sgl.end()
// right bottom quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
if r == 0 {
break
// right bottom quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
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)
}
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()
sgl.end()
// left bottom quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
if r == 0 {
break
// left bottom quarter
sgl.begin_triangle_strip()
for i in 0 .. 31 {
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)
}
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()
}
sgl.end()
// Separate drawing is to prevent transparent color overlap
// top rectangle

View File

@ -1,5 +1,6 @@
module math
module main
import math
import benchmark
const max_iter = 1000
@ -7,8 +8,8 @@ const max_iter = 1000
fn test_benchmark_acos() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = acos(0.5)
for i in 0 .. max_iter {
x = math.acos(0.5)
}
bmark.measure(@FN)
}
@ -16,8 +17,8 @@ fn test_benchmark_acos() {
fn test_benchmark_acosh() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = acosh(1.5)
for i in 0 .. max_iter {
x = math.acosh(1.5)
}
bmark.measure(@FN)
}
@ -25,8 +26,8 @@ fn test_benchmark_acosh() {
fn test_benchmark_asin() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = asin(0.5)
for i in 0 .. max_iter {
x = math.asin(0.5)
}
bmark.measure(@FN)
}
@ -34,8 +35,8 @@ fn test_benchmark_asin() {
fn test_benchmark_asinh() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = asinh(0.5)
for i in 0 .. max_iter {
x = math.asinh(0.5)
}
bmark.measure(@FN)
}
@ -43,8 +44,8 @@ fn test_benchmark_asinh() {
fn test_benchmark_atan() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = atan(0.5)
for i in 0 .. max_iter {
x = math.atan(0.5)
}
bmark.measure(@FN)
}
@ -52,8 +53,8 @@ fn test_benchmark_atan() {
fn test_benchmark_atanh() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = atanh(0.5)
for i in 0 .. max_iter {
x = math.atanh(0.5)
}
bmark.measure(@FN)
}
@ -61,8 +62,8 @@ fn test_benchmark_atanh() {
fn test_benchmark_atan2() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = atan2(0.5, 1)
for i in 0 .. max_iter {
x = math.atan2(0.5, 1)
}
bmark.measure(@FN)
}
@ -70,8 +71,8 @@ fn test_benchmark_atan2() {
fn test_benchmark_cbrt() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = cbrt(10)
for i in 0 .. max_iter {
x = math.cbrt(10)
}
bmark.measure(@FN)
}
@ -79,19 +80,17 @@ fn test_benchmark_cbrt() {
fn test_benchmark_ceil() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = ceil(0.5)
for i in 0 .. max_iter {
x = math.ceil(0.5)
}
bmark.measure(@FN)
}
const copysign_neg = -1.0
fn test_benchmark_copysign() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = copysign(0.5, math.copysign_neg)
for i in 0 .. max_iter {
x = math.copysign(0.5, -1.0)
}
bmark.measure(@FN)
}
@ -99,8 +98,8 @@ fn test_benchmark_copysign() {
fn test_benchmark_cos() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = cos(0.5)
for i in 0 .. max_iter {
x = math.cos(0.5)
}
bmark.measure(@FN)
}
@ -108,8 +107,8 @@ fn test_benchmark_cos() {
fn test_benchmark_cosh() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = cosh(2.5)
for i in 0 .. max_iter {
x = math.cosh(2.5)
}
bmark.measure(@FN)
}
@ -117,8 +116,8 @@ fn test_benchmark_cosh() {
fn test_benchmark_erf() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = erf(0.5)
for i in 0 .. max_iter {
x = math.erf(0.5)
}
bmark.measure(@FN)
}
@ -126,8 +125,8 @@ fn test_benchmark_erf() {
fn test_benchmark_erfc() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = erfc(0.5)
for i in 0 .. max_iter {
x = math.erfc(0.5)
}
bmark.measure(@FN)
}
@ -135,8 +134,8 @@ fn test_benchmark_erfc() {
fn test_benchmark_exp() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = exp(0.5)
for i in 0 .. max_iter {
x = math.exp(0.5)
}
bmark.measure(@FN)
}
@ -144,8 +143,8 @@ fn test_benchmark_exp() {
fn test_benchmark_expm1() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = expm1(0.5)
for i in 0 .. max_iter {
x = math.expm1(0.5)
}
bmark.measure(@FN)
}
@ -153,19 +152,17 @@ fn test_benchmark_expm1() {
fn test_benchmark_exp2() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = exp2(0.5)
for i in 0 .. max_iter {
x = math.exp2(0.5)
}
bmark.measure(@FN)
}
const abs_pos = 0.5
fn test_benchmark_abs() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = abs(math.abs_pos)
for i in 0 .. max_iter {
x = math.abs(0.5)
}
bmark.measure(@FN)
}
@ -173,8 +170,8 @@ fn test_benchmark_abs() {
fn test_benchmark_floor() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = floor(0.5)
for i in 0 .. max_iter {
x = math.floor(0.5)
}
bmark.measure(@FN)
}
@ -182,8 +179,8 @@ fn test_benchmark_floor() {
fn test_benchmark_max() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = max(10, 3)
for i in 0 .. max_iter {
x = math.max(10, 3)
}
bmark.measure(@FN)
}
@ -191,8 +188,8 @@ fn test_benchmark_max() {
fn test_benchmark_min() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = min(10, 3)
for i in 0 .. max_iter {
x = math.min(10, 3)
}
bmark.measure(@FN)
}
@ -200,8 +197,8 @@ fn test_benchmark_min() {
fn test_benchmark_mod() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = mod(10, 3)
for i in 0 .. max_iter {
x = math.mod(10, 3)
}
bmark.measure(@FN)
}
@ -210,8 +207,8 @@ fn test_benchmark_frexp() {
mut x := 0.0
mut y := 0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x, y = frexp(8)
for i in 0 .. max_iter {
x, y = math.frexp(8)
}
bmark.measure(@FN)
}
@ -219,8 +216,8 @@ fn test_benchmark_frexp() {
fn test_benchmark_gamma() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = gamma(2.5)
for i in 0 .. max_iter {
x = math.gamma(2.5)
}
bmark.measure(@FN)
}
@ -228,8 +225,8 @@ fn test_benchmark_gamma() {
fn test_benchmark_hypot() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = hypot(3, 4)
for i in 0 .. max_iter {
x = math.hypot(3, 4)
}
bmark.measure(@FN)
}
@ -237,8 +234,8 @@ fn test_benchmark_hypot() {
fn test_benchmark_ldexp() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = ldexp(0.5, 2)
for i in 0 .. max_iter {
x = math.ldexp(0.5, 2)
}
bmark.measure(@FN)
}
@ -246,8 +243,8 @@ fn test_benchmark_ldexp() {
fn test_benchmark_log_gamma() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = log_gamma(2.5)
for i in 0 .. max_iter {
x = math.log_gamma(2.5)
}
bmark.measure(@FN)
}
@ -255,8 +252,8 @@ fn test_benchmark_log_gamma() {
fn test_benchmark_log() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = log(0.5)
for i in 0 .. max_iter {
x = math.log(0.5)
}
bmark.measure(@FN)
}
@ -264,8 +261,8 @@ fn test_benchmark_log() {
fn test_benchmark_log_b() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = log_b(0.5)
for i in 0 .. max_iter {
x = math.log_b(0.5)
}
bmark.measure(@FN)
}
@ -273,8 +270,8 @@ fn test_benchmark_log_b() {
fn test_benchmark_log1p() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = log1p(0.5)
for i in 0 .. max_iter {
x = math.log1p(0.5)
}
bmark.measure(@FN)
}
@ -282,8 +279,8 @@ fn test_benchmark_log1p() {
fn test_benchmark_log10() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = log10(0.5)
for i in 0 .. max_iter {
x = math.log10(0.5)
}
bmark.measure(@FN)
}
@ -291,8 +288,8 @@ fn test_benchmark_log10() {
fn test_benchmark_log2() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = log2(0.5)
for i in 0 .. max_iter {
x = math.log2(0.5)
}
bmark.measure(@FN)
}
@ -301,8 +298,8 @@ fn test_benchmark_modf() {
mut x := 0.0
mut y := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x, y = modf(1.5)
for i in 0 .. max_iter {
x, y = math.modf(1.5)
}
bmark.measure(@FN)
}
@ -310,8 +307,8 @@ fn test_benchmark_modf() {
fn test_benchmark_nextafter32() {
mut x := f32(0.0)
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = nextafter32(0.5, 1)
for i in 0 .. max_iter {
x = math.nextafter32(0.5, 1)
}
bmark.measure(@FN)
}
@ -319,8 +316,8 @@ fn test_benchmark_nextafter32() {
fn test_benchmark_nextafter64() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = nextafter(0.5, 1)
for i in 0 .. max_iter {
x = math.nextafter(0.5, 1)
}
bmark.measure(@FN)
}
@ -328,8 +325,8 @@ fn test_benchmark_nextafter64() {
fn test_benchmark_pow_int() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = pow(2, 2)
for i in 0 .. max_iter {
x = math.pow(2, 2)
}
bmark.measure(@FN)
}
@ -337,41 +334,35 @@ fn test_benchmark_pow_int() {
fn test_benchmark_pow_frac() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = pow(2.5, 1.5)
for i in 0 .. max_iter {
x = math.pow(2.5, 1.5)
}
bmark.measure(@FN)
}
const pow10pos = int(300)
fn test_benchmark_pow10_pos() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = pow10(math.pow10pos)
for i in 0 .. max_iter {
x = math.pow10(300)
}
bmark.measure(@FN)
}
const pow10neg = int(-300)
fn test_benchmark_pow10_neg() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = pow10(math.pow10neg)
for i in 0 .. max_iter {
x = math.pow10(-300)
}
bmark.measure(@FN)
}
const round_neg = f64(-2.5)
fn test_benchmark_round() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = round(math.round_neg)
for i in 0 .. max_iter {
x = math.round(-2.5)
}
bmark.measure(@FN)
}
@ -379,19 +370,17 @@ fn test_benchmark_round() {
fn test_benchmark_round_to_even() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = round_to_even(math.round_neg)
for i in 0 .. max_iter {
x = math.round_to_even(-2.5)
}
bmark.measure(@FN)
}
const signbit_pos = 2.5
fn test_benchmark_signbit() {
mut x := false
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = signbit(math.signbit_pos)
for i in 0 .. max_iter {
x = math.signbit(2.5)
}
bmark.measure(@FN)
}
@ -399,8 +388,8 @@ fn test_benchmark_signbit() {
fn test_benchmark_sin() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = sin(0.5)
for i in 0 .. max_iter {
x = math.sin(0.5)
}
bmark.measure(@FN)
}
@ -409,8 +398,8 @@ fn test_benchmark_sincos() {
mut x := 0.0
mut y := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x, y = sincos(0.5)
for i in 0 .. max_iter {
x, y = math.sincos(0.5)
}
bmark.measure(@FN)
}
@ -418,17 +407,17 @@ fn test_benchmark_sincos() {
fn test_benchmark_sinh() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = sinh(2.5)
for i in 0 .. max_iter {
x = math.sinh(2.5)
}
bmark.measure(@FN)
}
fn test_benchmark_sqrt_indirect() {
mut x, y := 0.0, 10.0
f := sqrt
f := math.sqrt
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
for i in 0 .. max_iter {
x += f(y)
}
bmark.measure(@FN)
@ -437,17 +426,17 @@ fn test_benchmark_sqrt_indirect() {
fn test_benchmark_sqrt_latency() {
mut x := 10.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = sqrt(x)
for i in 0 .. max_iter {
x = math.sqrt(x)
}
bmark.measure(@FN)
}
fn test_benchmark_sqrt_indirect_latency() {
mut x := 10.0
f := sqrt
f := math.sqrt
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
for i in 0 .. max_iter {
x = f(x)
}
bmark.measure(@FN)
@ -459,7 +448,7 @@ fn is_prime(i int) bool {
// the benefit of using a direct sqrt instruction on systems
// that have one, whereas the obvious loop seems not to
// demonstrate such a benefit.
for j := 2; f64(j) <= sqrt(f64(i)); j++ {
for j := 2; f64(j) <= math.sqrt(f64(i)); j++ {
if i % j == 0 {
return false
}
@ -470,7 +459,7 @@ fn is_prime(i int) bool {
fn test_benchmark_sqrt_prime() {
mut x := false
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
for i in 0 .. max_iter {
x = is_prime(100003)
}
bmark.measure(@FN)
@ -479,8 +468,8 @@ fn test_benchmark_sqrt_prime() {
fn test_benchmark_tan() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = tan(0.5)
for i in 0 .. max_iter {
x = math.tan(0.5)
}
bmark.measure(@FN)
}
@ -488,8 +477,8 @@ fn test_benchmark_tan() {
fn test_benchmark_tanh() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = tanh(2.5)
for i in 0 .. max_iter {
x = math.tanh(2.5)
}
bmark.measure(@FN)
}
@ -497,50 +486,44 @@ fn test_benchmark_tanh() {
fn test_benchmark_trunc() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = trunc(0.5)
for i in 0 .. max_iter {
x = math.trunc(0.5)
}
bmark.measure(@FN)
}
fn test_benchmark_f64_bits() {
mut y := u64(0)
mut x := u64(0)
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
y = f64_bits(math.round_neg)
for i in 0 .. max_iter {
x = math.f64_bits(-2.5)
}
bmark.measure(@FN)
}
const round_u64 = u64(5)
fn test_benchmark_f64_from_bits() {
mut x := 0.0
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = f64_from_bits(math.round_u64)
for i in 0 .. max_iter {
x = math.f64_from_bits(5)
}
bmark.measure(@FN)
}
const round_f32 = f32(-2.5)
fn test_benchmark_f32_bits() {
mut y := u32(0)
mut x := u32(0)
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
y = f32_bits(math.round_f32)
for i in 0 .. max_iter {
x = math.f32_bits(-2.5)
}
bmark.measure(@FN)
}
const round_u32 = u32(5)
fn test_benchmark_f32_from_bits() {
mut x := f32(0.0)
mut bmark := benchmark.start()
for i in 0 .. math.max_iter {
x = f32_from_bits(math.round_u32)
for i in 0 .. max_iter {
x = math.f32_from_bits(5)
}
bmark.measure(@FN)
}

View File

@ -0,0 +1,11 @@
import time
fn test_custom_format() {
date := time.now()
assert date.custom_format('YYYY-MM-DD HH:mm') == date.format()
assert date.custom_format('MMM') == date.smonth()
test_str := 'M MM MMM MMMM\nD DD DDD DDDD\nd dd ddd dddd\nYY YYYY a A\nH HH h hh k kk e\nm mm s ss Z ZZ ZZZ\nDo DDDo Q Qo QQ\nN NN w wo ww\nM/D/YYYY N-HH:mm:ss Qo?a'
println(date.custom_format(test_str))
}

View File

@ -3,6 +3,9 @@
// that can be found in the LICENSE file.
module time
import strings
import math
// format returns a date string in "YYYY-MM-DD HH:MM" format (24h).
pub fn (t Time) format() string {
return t.get_fmt_str(.hyphen, .hhmm24, .yyyymmdd)
@ -53,6 +56,264 @@ pub fn (t Time) md() string {
return t.get_fmt_date_str(.space, .mmmd)
}
// appends ordinal suffix to a number
fn ordinal_suffix(n int) string {
if n > 3 && n < 21 {
return '${n}th'
}
match n % 10 {
1 {
return '${n}st'
}
2 {
return '${n}nd'
}
3 {
return '${n}rd'
}
else {
return '${n}th'
}
}
}
const tokens_2 = ['MM', 'DD', 'Do', 'YY', 'ss', 'kk', 'NN', 'mm', 'hh', 'HH', 'ZZ', 'dd', 'Qo',
'QQ', 'wo', 'ww']
const tokens_3 = ['MMM', 'DDD', 'ZZZ', 'ddd']
const tokens_4 = ['MMMM', 'DDDD', 'DDDo', 'dddd', 'YYYY']
// custom_format returns a date with custom format
// | | Token | Output |
// | :----------- | -------: | :--------- |
// | Month | M | 1 2 ... 11 12 |
// | | Mo | 1st 2nd ... 11th 12th |
// | | MM | 01 02 ... 11 12 |
// | | MMM | Jan Feb ... Nov Dec |
// | | MMMM | January February ... November December |
// | Quarter | Q | 1 2 3 4 |
// | | QQ | 01 02 03 04 |
// | | Qo | 1st 2nd 3rd 4th |
// | Day of Month | D | 1 2 ... 30 31 |
// | | Do | 1st 2nd ... 30th 31st |
// | | DD | 01 02 ... 30 31 |
// | Day of Year | DDD | 1 2 ... 364 365 |
// | | DDDo | 1st 2nd ... 364th 365th |
// | | DDDD | 001 002 ... 364 365 |
// | Day of Week | d | 0 1 ... 5 6 (Sun-Sat) |
// | | c | 1 2 ... 6 7 (Mon-Sun) |
// | | dd | Su Mo ... Fr Sa |
// | | ddd | Sun Mon ... Fri Sat |
// | | dddd | Sunday Monday ... Friday Saturday |
// | Week of Year | w | 1 2 ... 52 53 |
// | | wo | 1st 2nd ... 52nd 53rd |
// | | ww | 01 02 ... 52 53 |
// | Year | YY | 70 71 ... 29 30 |
// | | YYYY | 1970 1971 ... 2029 2030 |
// | Era | N | BC AD |
// | | NN | Before Christ, Anno Domini |
// | AM/PM | A | AM PM |
// | | a | am pm |
// | Hour | H | 0 1 ... 22 23 |
// | | HH | 00 01 ... 22 23 |
// | | h | 1 2 ... 11 12 |
// | | hh | 01 02 ... 11 12 |
// | | k | 1 2 ... 23 24 |
// | | kk | 01 02 ... 23 24 |
// | Minute | m | 0 1 ... 58 59 |
// | | mm | 00 01 ... 58 59 |
// | Second | s | 0 1 ... 58 59 |
// | | ss | 00 01 ... 58 59 |
// | Offset | Z | -7 -6 ... +5 +6 |
// | | ZZ | -0700 -0600 ... +0500 +0600 |
// | | ZZZ | -07:00 -06:00 ... +05:00 +06:00 |
pub fn (t Time) custom_format(s string) string {
mut tokens := []string{}
for i := 0; i < s.len; {
for j := 4; j > 0; j-- {
if i > s.len - j {
continue
}
if j == 1 || (j == 2 && s[i..i + j] in time.tokens_2)
|| (j == 3 && s[i..i + j] in time.tokens_3)
|| (j == 4 && s[i..i + j] in time.tokens_4) {
tokens << s[i..i + j]
i += (j - 1)
break
}
}
i++
}
mut sb := strings.new_builder(128)
for token in tokens {
match token {
'M' {
sb.write_string(t.month.str())
}
'MM' {
sb.write_string('${t.month:02}')
}
'Mo' {
sb.write_string(ordinal_suffix(t.month))
}
'MMM' {
sb.write_string(long_months[t.month - 1][0..3])
}
'MMMM' {
sb.write_string(long_months[t.month - 1])
}
'D' {
sb.write_string(t.day.str())
}
'DD' {
sb.write_string('${t.day:02}')
}
'Do' {
sb.write_string(ordinal_suffix(t.day))
}
'DDD' {
sb.write_string((t.day + days_before[t.month - 1] + int(is_leap_year(t.year))).str())
}
'DDDD' {
sb.write_string('${t.day + days_before[t.month - 1] + int(is_leap_year(t.year)):03}')
}
'DDDo' {
sb.write_string(ordinal_suffix(t.day + days_before[t.month - 1] +
int(is_leap_year(t.year))))
}
'd' {
sb.write_string(t.day_of_week().str())
}
'dd' {
sb.write_string(long_days[t.day_of_week() - 1][0..2])
}
'ddd' {
sb.write_string(long_days[t.day_of_week() - 1][0..3])
}
'dddd' {
sb.write_string(long_days[t.day_of_week() - 1])
}
'YY' {
sb.write_string(t.year.str()[2..4])
}
'YYYY' {
sb.write_string(t.year.str())
}
'H' {
sb.write_string(t.hour.str())
}
'HH' {
sb.write_string('${t.hour:02}')
}
'h' {
sb.write_string((t.hour % 12).str())
}
'hh' {
sb.write_string('${(t.hour % 12):02}')
}
'm' {
sb.write_string(t.minute.str())
}
'mm' {
sb.write_string('${t.minute:02}')
}
's' {
sb.write_string(t.second.str())
}
'ss' {
sb.write_string('${t.second:02}')
}
'k' {
sb.write_string((t.hour + 1).str())
}
'kk' {
sb.write_string('${(t.hour + 1):02}')
}
'w' {
sb.write_string('${math.ceil((t.day + days_before[t.month - 1] +
int(is_leap_year(t.year))) / 7):.0}')
}
'ww' {
sb.write_string('${math.ceil((t.day + days_before[t.month - 1] +
int(is_leap_year(t.year))) / 7):02.0}')
}
'wo' {
sb.write_string(ordinal_suffix(int(math.ceil((t.day + days_before[t.month - 1] +
int(is_leap_year(t.year))) / 7))))
}
'Q' {
sb.write_string('${(t.month % 4) + 1}')
}
'QQ' {
sb.write_string('${(t.month % 4) + 1:02}')
}
'Qo' {
sb.write_string(ordinal_suffix((t.month % 4) + 1))
}
'c' {
sb.write_string('${t.day_of_week() + 1}')
}
'N' {
// TODO integrate BC
sb.write_string('AD')
}
'NN' {
// TODO integrate Before Christ
sb.write_string('Anno Domini')
}
'Z' {
mut hours := offset() / seconds_per_hour
if hours >= 0 {
sb.write_string('+$hours')
} else {
hours = -hours
sb.write_string('-$hours')
}
}
'ZZ' {
// TODO update if minute differs?
mut hours := offset() / seconds_per_hour
if hours >= 0 {
sb.write_string('+${hours:02}00')
} else {
hours = -hours
sb.write_string('-${hours:02}00')
}
}
'ZZZ' {
// TODO update if minute differs?
mut hours := offset() / seconds_per_hour
if hours >= 0 {
sb.write_string('+${hours:02}:00')
} else {
hours = -hours
sb.write_string('-${hours:02}:00')
}
}
'a' {
if t.hour > 12 {
sb.write_string('pm')
} else {
sb.write_string('am')
}
}
'A' {
if t.hour > 12 {
sb.write_string('PM')
} else {
sb.write_string('AM')
}
}
else {
sb.write_string(token)
}
}
}
return sb.str()
}
// clean returns a date string in a following format:
// - a date string in "HH:MM" format (24h) for current day
// - a date string in "MMM D HH:MM" format (24h) for date of current year

View File

@ -2,8 +2,12 @@ module time
pub const (
days_string = 'MonTueWedThuFriSatSun'
long_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
'Sunday']
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
months_string = 'JanFebMarAprMayJunJulAugSepOctNovDec'
long_months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
'September', 'October', 'November', 'December']
// The unsigned zero year for internal calculations.
// Must be 1 mod 400, and times before it will not compute correctly,
// but otherwise can be changed at will.
@ -30,8 +34,6 @@ pub const (
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
]
long_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
'Sunday']
)
// Time contains various time units for a point in time.
@ -83,7 +85,7 @@ pub enum FormatDelimiter {
no_delimiter
}
// smonth returns month name.
// smonth returns month name abbreviation.
pub fn (t Time) smonth() string {
if t.month <= 0 || t.month > 12 {
return '---'
@ -224,10 +226,10 @@ pub fn (t Time) day_of_week() int {
return day_of_week(t.year, t.month, t.day)
}
// weekday_str returns the current day as a string.
// weekday_str returns the current day as a string abbreviation.
pub fn (t Time) weekday_str() string {
i := t.day_of_week() - 1
return time.days_string[i * 3..(i + 1) * 3]
return time.long_days[i][0..3]
}
// weekday_str returns the current day as a string.

View File

@ -520,6 +520,7 @@ pub:
attrs []Attr
ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists
pub mut:
idx int // index in an external container; can be used to refer to the function in a more efficient way, just by its integer index
params []Param
stmts []Stmt
defer_stmts []DeferStmt
@ -707,6 +708,7 @@ pub:
is_generated bool // true for `[generated] module xyz` files; turn off notices
is_translated bool // true for `[translated] module xyz` files; turn off some checks
pub mut:
idx int // index in an external container; can be used to refer to the file in a more efficient way, just by its integer index
path string // absolute path of the source file - '/projects/v/file.v'
path_base string // file name - 'file.v' (useful for tracing)
scope &Scope
@ -2075,6 +2077,17 @@ pub fn (mut lx IndexExpr) recursive_mapset_is_setter(val bool) {
}
}
pub fn (mut lx IndexExpr) recursive_arraymap_set_is_setter() {
lx.is_setter = true
if mut lx.left is IndexExpr {
lx.left.recursive_arraymap_set_is_setter()
} else if mut lx.left is SelectorExpr {
if mut lx.left.expr is IndexExpr {
lx.left.expr.recursive_arraymap_set_is_setter()
}
}
}
// return all the registers for the given architecture
pub fn all_registers(mut t Table, arch pref.Arch) map[string]ScopeObject {
mut res := map[string]ScopeObject{}

View File

@ -44,6 +44,7 @@ pub mut:
mdeprecated_msg map[string]string // module deprecation message
mdeprecated_after map[string]time.Time // module deprecation date
builtin_pub_fns map[string]bool
pointer_size int
}
// used by vls to avoid leaks

View File

@ -0,0 +1,54 @@
import v.builder
import v.parser
import v.pref
struct T01 {
a int
b byte
c int
}
type T02 = string
type T03 = int | string
type T04 = []T03
type T05 = [47]T03
interface T06 {
a int
}
interface T07 {
T06
b int
}
struct T08 {
T01
x string
}
fn test_type_size() ? {
mut pref := pref.new_preferences()
$if x64 {
pref.m64 = true
}
mut b := builder.new_builder(pref)
mut files := b.get_builtin_files()
b.set_module_lookup_paths()
parser.parse_files(files, b.table, b.pref)
b.parse_imports()
parser.parse_file(@FILE, b.table, .parse_comments, b.pref)
mut t := b.table
assert sizeof(T01) == t.type_size(t.type_idxs['main.T01'] ?)
assert sizeof(T02) == t.type_size(t.type_idxs['main.T02'] ?)
assert sizeof(T03) == t.type_size(t.type_idxs['main.T03'] ?)
assert sizeof(T04) == t.type_size(t.type_idxs['main.T04'] ?)
assert sizeof(T05) == t.type_size(t.type_idxs['main.T05'] ?)
assert sizeof(T06) == t.type_size(t.type_idxs['main.T06'] ?)
assert sizeof(T07) == t.type_size(t.type_idxs['main.T07'] ?)
assert sizeof(T08) == t.type_size(t.type_idxs['main.T08'] ?)
println('done')
}

View File

@ -823,6 +823,97 @@ pub fn (t &TypeSymbol) is_builtin() bool {
return t.mod == 'builtin'
}
// type_size returns the size in bytes of `typ`, similarly to C's `sizeof()`.
pub fn (t &Table) type_size(typ Type) int {
if typ.has_flag(.optional) {
return t.type_size(ast.error_type_idx)
}
if typ.nr_muls() > 0 {
return t.pointer_size
}
sym := t.sym(typ)
match sym.kind {
.placeholder, .void, .none_ {
return 0
}
.voidptr, .byteptr, .charptr, .function, .usize, .isize, .any, .thread, .chan {
return t.pointer_size
}
.i8, .u8, .char, .bool {
return 1
}
.i16, .u16 {
return 2
}
.int, .u32, .rune, .f32, .enum_ {
return 4
}
.i64, .u64, .int_literal, .f64, .float_literal {
return 8
}
.alias {
return t.type_size((sym.info as Alias).parent_type)
}
.struct_, .string, .multi_return {
mut max_alignment := 0
mut total_size := 0
types := if sym.info is Struct {
sym.info.fields.map(it.typ)
} else {
(sym.info as MultiReturn).types
}
for ftyp in types {
field_size := t.type_size(ftyp)
alignment := if field_size > t.pointer_size { t.pointer_size } else { field_size }
if alignment > max_alignment {
max_alignment = alignment
}
total_size = round_up(total_size, alignment) + field_size
}
return round_up(total_size, max_alignment)
}
.sum_type, .interface_, .aggregate {
match sym.info {
SumType, Aggregate {
return (sym.info.fields.len + 2) * t.pointer_size
}
Interface {
mut res := (sym.info.fields.len + 2) * t.pointer_size
for etyp in sym.info.embeds {
res += t.type_size(etyp) - 2 * t.pointer_size
}
return res
}
else {
// unreachable
return 0
}
}
}
.array_fixed {
info := sym.info as ArrayFixed
return info.size * t.type_size(info.elem_type)
}
// TODO hardcoded:
.map {
return if t.pointer_size == 8 { 120 } else { 80 }
}
.array {
return if t.pointer_size == 8 { 32 } else { 24 }
}
.generic_inst {
return 0
}
}
}
// round_up rounds the number `n` up to the next multiple `multiple`.
// Note: `multiple` must be a power of 2.
[inline]
fn round_up(n int, multiple int) int {
return (n + multiple - 1) & -multiple
}
// for debugging/errors only, perf is not an issue
pub fn (k Kind) str() string {
return match k {

View File

@ -53,6 +53,7 @@ pub fn new_builder(pref &pref.Preferences) Builder {
if pref.use_color == .never {
util.emanager.set_support_color(false)
}
table.pointer_size = if pref.m64 { 8 } else { 4 }
msvc := find_msvc(pref.m64) or {
if pref.ccompiler == 'msvc' {
// verror('Cannot find MSVC on this OS')

View File

@ -19,6 +19,6 @@ pub fn interpret_v(mut b builder.Builder) {
util.timing_start('INTERPRET')
mut e := eval.new_eval(b.table, b.pref)
e.eval(b.parsed_files)
e.eval(mut b.parsed_files)
util.timing_measure('INTERPRET')
}

View File

@ -709,38 +709,3 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr
c.need_recheck_generic_fns = true
}
}
pub fn (c &Checker) sizeof_integer(a ast.Type) int {
t := if a in ast.unsigned_integer_type_idxs { a.flip_signedness() } else { a }
r := match t {
ast.char_type_idx, ast.i8_type_idx {
1
}
ast.i16_type_idx {
2
}
ast.int_type_idx {
4
}
ast.rune_type_idx {
4
}
ast.i64_type_idx {
8
}
ast.isize_type_idx {
if c.pref.m64 { 8 } else { 4 }
}
ast.int_literal_type {
s := c.table.type_to_str(a)
panic('`$s` has unknown size')
0
}
else {
s := c.table.type_to_str(a)
panic('`$s` is not an integer')
0
}
}
return r
}

View File

@ -643,8 +643,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
} else if is_left_type_signed != is_right_type_signed
&& left_type != ast.int_literal_type_idx
&& right_type != ast.int_literal_type_idx {
ls := c.sizeof_integer(left_type)
rs := c.sizeof_integer(right_type)
ls := c.table.type_size(left_type)
rs := c.table.type_size(right_type)
// prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32
// TODO u32 == i32, change < to <=
if (is_left_type_signed && ls < rs) || (is_right_type_signed && rs < ls) {
@ -702,13 +702,11 @@ 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()) {
&& left_type.is_any_kind_of_pointer() && right_type.is_any_kind_of_pointer() {
return_type = left_type
}
// Check if the alias type is not a primitive then allow using operator overloading for aliased `arrays` and `maps`
else 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()) {
@ -745,7 +743,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
}
}
}
if left_sym.kind in [.array, .array_fixed, .map, .struct_] {
if !c.pref.translated && left_sym.kind in [.array, .array_fixed, .map, .struct_] {
if left_sym.has_method_with_generic_parent(node.op.str()) {
if method := left_sym.find_method_with_generic_parent(node.op.str()) {
return_type = method.return_type
@ -762,7 +761,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
}
}
} else if right_sym.kind in [.array, .array_fixed, .map, .struct_] {
} else if !c.pref.translated && right_sym.kind in [.array, .array_fixed, .map, .struct_] {
if right_sym.has_method_with_generic_parent(node.op.str()) {
if method := right_sym.find_method_with_generic_parent(node.op.str()) {
return_type = method.return_type
@ -935,13 +934,13 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
return ast.void_type
} else if left_value_sym.kind == .sum_type {
if right_final.kind != .array {
if !c.table.is_sumtype_or_in_variant(left_value_type, right_type) {
if !c.table.is_sumtype_or_in_variant(left_value_type, ast.mktyp(right_type)) {
c.error('cannot append `$right_sym.name` to `$left_sym.name`',
right_pos)
}
} else {
right_value_type := c.table.value_type(right_type)
if !c.table.is_sumtype_or_in_variant(left_value_type, right_value_type) {
if !c.table.is_sumtype_or_in_variant(left_value_type, ast.mktyp(right_value_type)) {
c.error('cannot append `$right_sym.name` to `$left_sym.name`',
right_pos)
}

View File

@ -127,30 +127,7 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp
// return expr.val.i64()
// }
ast.SizeOf {
xtype := expr.typ
if xtype.is_real_pointer() {
if c.pref.m64 {
return 8 // 64bit platform
}
return 4 // 32bit platform
}
if int(xtype) == xtype.idx() {
match xtype {
ast.char_type { return 1 }
ast.i8_type { return 1 }
ast.i16_type { return 2 }
ast.int_type { return 4 }
ast.i64_type { return 8 }
//
ast.byte_type { return 1 }
// ast.u8_type { return 1 }
ast.u16_type { return 2 }
ast.u32_type { return 4 }
ast.u64_type { return 8 }
else {}
}
}
return none
return c.table.type_size(expr.typ)
}
ast.FloatLiteral {
x := expr.val.f64()

View File

@ -13,6 +13,16 @@ fn (mut c Checker) for_c_stmt(node ast.ForCStmt) {
}
c.expr(node.cond)
if node.has_inc {
if node.inc is ast.AssignStmt {
for right in node.inc.right {
if right is ast.CallExpr {
if right.or_block.stmts.len > 0 {
c.error('optionals are not allowed in `for statement increment` (yet)',
right.pos)
}
}
}
}
c.stmt(node.inc)
}
c.check_loop_label(node.label, node.pos)

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/for_c_stmt_with_optional_call.vv:15:31: error: optionals are not allowed in `for statement increment` (yet)
13 | for t := 0; t < tests; t++ {
14 | mut v := []bool{len: nmax, init: false}
15 | for x := 0; !v[x]; x = rand.intn(n) or { 0 } {
| ~~~~~~~
16 | v[x] = true
17 | sum++

View File

@ -0,0 +1,31 @@
import rand
import math { abs }
const nmax = 20
fn ana(n int) f64 {
return 1.0 // haven't started
}
fn avg(n int) f64 {
tests := 1e4
mut sum := 0
for t := 0; t < tests; t++ {
mut v := []bool{len: nmax, init: false}
for x := 0; !v[x]; x = rand.intn(n) or { 0 } {
v[x] = true
sum++
}
}
return f64(sum) / tests
}
fn main() {
println(' N average analytical (error)')
println('=== ========= ============ =========')
for n in 1 .. nmax + 1 {
a := avg(n)
b := ana(n)
println('${n:3} ${a:9.4f} ${b:12.4f} (${(abs(a - b) / b * 100):6.2f}%)')
}
}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/interface_method_name_err.vv:2:2: error: method name `Fizz` cannot contain uppercase letters, use snake_case instead
1 | interface Foo {
2 | Fizz()
| ~~~~~~
3 | }
4 |

View File

@ -0,0 +1,6 @@
interface Foo {
Fizz()
}
fn main() {
}

View File

@ -1,13 +1,20 @@
vlib/v/checker/tests/struct_field_name_err.vv:2:2: error: field name `Architecture` cannot contain uppercase letters, use snake_case instead
vlib/v/checker/tests/struct_field_name_err.vv:2:2: error: field name `Foo` cannot contain uppercase letters, use snake_case instead
1 | struct Release {
2 | Architecture []string
| ~~~~~~~~~~~~~~~~~~~~~
3 | Components []string
4 | }
vlib/v/checker/tests/struct_field_name_err.vv:3:2: error: field name `Components` cannot contain uppercase letters, use snake_case instead
2 | Foo string
| ~~~~~~~~~~~~~~~~~~~
3 | Bar &int
4 | Architecture []string
vlib/v/checker/tests/struct_field_name_err.vv:3:2: error: field name `Bar` cannot contain uppercase letters, use snake_case instead
1 | struct Release {
2 | Architecture []string
3 | Components []string
2 | Foo string
3 | Bar &int
| ~~~~~~~~~~~~~~~~~
4 | Architecture []string
5 | }
vlib/v/checker/tests/struct_field_name_err.vv:4:2: error: field name `Architecture` cannot contain uppercase letters, use snake_case instead
2 | Foo string
3 | Bar &int
4 | Architecture []string
| ~~~~~~~~~~~~~~~~~~~~~
4 | }
5 |
5 | }
6 |

View File

@ -1,9 +1,8 @@
struct Release {
Foo string
Bar &int
Architecture []string
Components []string
}
fn main() {
r := Release{}
println(r)
}

View File

@ -30,28 +30,37 @@ pub mut:
return_values []Object
cur_mod string
cur_file string
back_trace []string
//
trace_file_paths []string
trace_function_names []string
back_trace []EvalTrace
}
pub fn (mut e Eval) eval(files []&ast.File) {
e.register_symbols(files)
pub struct EvalTrace {
fn_idx int
file_idx int
line int
}
pub fn (mut e Eval) eval(mut files []&ast.File) {
e.register_symbols(mut files)
// println(files.map(it.path_base))
e.run_func(e.mods['main']['main'] or { ast.EmptyStmt{} } as ast.FnDecl)
}
// first arg is reciever (if method)
pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
e.back_trace << func.name
e.back_trace << EvalTrace{func.idx, func.source_file.idx, func.pos.line_nr}
old_mod := e.cur_mod
e.cur_mod = func.mod
old_file := e.cur_file
e.cur_mod = func.mod
e.cur_file = func.file
defer {
e.cur_mod = old_mod
e.cur_file = old_file
e.back_trace.pop()
}
//
mut args := _args.clone()
if func.params.len != args.len && !func.is_variadic {
e.error('mismatched parameter length for $func.name: got `$args.len`, expected `$func.params.len`')
@ -90,7 +99,7 @@ pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
}
if func.is_method {
print(e.back_trace)
println(func.receiver.typ - 65536)
println(func.receiver.typ.set_nr_muls(0))
e.local_vars[func.receiver.name] = Var{
val: args[0]
scope_idx: e.scope_idx
@ -104,13 +113,18 @@ pub fn (mut e Eval) run_func(func ast.FnDecl, _args ...Object) {
}
}
pub fn (mut e Eval) register_symbols(files []&ast.File) {
for file in files {
// eprintln('registering file: $file.path_base')
pub fn (mut e Eval) register_symbols(mut files []&ast.File) {
for mut file in files {
file.idx = e.trace_file_paths.len
e.trace_file_paths << file.path
mod := file.mod.name
e.register_symbol_stmts(file.stmts[1..], mod, file.path)
// eprintln('registered file: $file.path_base')
for mut stmt in file.stmts {
if mut stmt is ast.FnDecl {
stmt.idx = e.trace_function_names.len
e.trace_function_names << stmt.name
}
}
e.register_symbol_stmts(file.stmts, mod, file.path)
}
for mod, const_files in e.future_register_consts {
e.cur_mod = mod
@ -133,14 +147,16 @@ pub fn (mut e Eval) register_symbols(files []&ast.File) {
}
pub fn (mut e Eval) register_symbol_stmts(stmts []ast.Stmt, mod string, file string) {
for stmt in stmts { // first is just module declaration, so ignore
for stmt in stmts {
e.register_symbol(stmt, mod, file)
}
}
pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) {
match stmt {
ast.Module {}
ast.Module {
// ignore module declarations for now
}
ast.FnDecl {
// this mess because c error
x := ast.Stmt(stmt)
@ -188,7 +204,7 @@ pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) {
}
}
else {
eprintln('unsupported expression')
e.error('unsupported expression')
}
}
}
@ -205,5 +221,11 @@ pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) {
}
fn (e Eval) error(msg string) {
eprintln('> V interpeter backtrace:')
for t in e.back_trace {
file_path := e.trace_file_paths[t.file_idx] or { t.file_idx.str() }
fn_name := e.trace_function_names[t.fn_idx] or { t.fn_idx.str() }
eprintln(' $file_path:${t.line + 1}:$fn_name}')
}
util.verror('interpreter', msg)
}

View File

@ -1,5 +1,6 @@
module eval
import v.pref
import v.ast
import v.util
import math
@ -24,13 +25,21 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
e.error('c does not have methods')
}
match expr.name.all_after('C.') {
'read' {
return Int{C.read(args[0].int_val(), args[1] as voidptr, args[2].int_val()), 64}
}
'write' {
return Int{C.write(args[0].int_val(), args[1] as voidptr,
args[2].int_val()), 32}
args[2].int_val()), 64}
}
'malloc' {
return Ptr{
val: unsafe { C.malloc(args[0].int_val()) }
}
}
'calloc' {
return Ptr{
val: vcalloc(int(args[0].int_val() * args[1].int_val()))
val: unsafe { C.calloc(args[0].int_val(), args[1].int_val()) }
}
}
'getcwd' {
@ -126,27 +135,16 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
do_if = true
} else {
if branch.cond is ast.Ident {
match branch.cond.name {
'windows' {
do_if = e.pref.os == .windows
}
'macos' {
do_if = e.pref.os == .macos
}
'linux' {
do_if = e.pref.os == .linux
}
'android' {
do_if = e.pref.os == .android
}
'freebsd' {
do_if = e.pref.os == .freebsd
}
'prealloc' {
do_if = e.pref.prealloc
}
else {
e.error('unknown compile time if: $branch.cond.name')
if known_os := pref.os_from_string(branch.cond.name) {
do_if = e.pref.os == known_os
} else {
match branch.cond.name {
'prealloc' {
do_if = e.pref.prealloc
}
else {
e.error('unknown compile time if: $branch.cond.name')
}
}
}
} else if branch.cond is ast.PostfixExpr {

View File

@ -299,7 +299,7 @@ fn (mut g Gen) gen_assign_stmt(node_ ast.AssignStmt) {
g.write(' = ${styp}_${util.replace_op(extracted_op)}(')
method := g.table.find_method(left_sym, extracted_op) or {
// the checker will most likely have found this, already...
g.error('assignemnt operator `$extracted_op=` used but no `$extracted_op` method defined',
g.error('assignment operator `$extracted_op=` used but no `$extracted_op` method defined',
node.pos)
ast.Fn{}
}

View File

@ -15,9 +15,10 @@ import v.depgraph
import sync.pool
const (
// Note: some of the words in c_reserved, are not reserved in C,
// but are in C++, or have special meaning in V, thus need escaping too.
// `small` should not be needed, but see: https://stackoverflow.com/questions/5874215/what-is-rpcndr-h
// Note: some of the words in c_reserved, are not reserved in C, but are
// in C++, or have special meaning in V, thus need escaping too. `small`
// should not be needed, but see:
// https://stackoverflow.com/questions/5874215/what-is-rpcndr-h
c_reserved = ['array', 'auto', 'bool', 'break', 'calloc', 'case', 'char', 'class', 'complex',
'const', 'continue', 'default', 'delete', 'do', 'double', 'else', 'enum', 'error', 'exit',
'export', 'extern', 'false', 'float', 'for', 'free', 'goto', 'if', 'inline', 'int', 'link',
@ -1590,10 +1591,6 @@ fn (mut g Gen) stmt(node ast.Stmt) {
if !g.skip_stmt_pos {
g.set_current_pos_as_last_stmt_pos()
}
defer {
}
// println('g.stmt()')
// g.writeln('//// stmt start')
match node {
ast.EmptyStmt {}
ast.AsmStmt {
@ -3146,7 +3143,7 @@ fn (mut g Gen) char_literal(node ast.CharLiteral) {
return
}
// TODO: optimize use L-char instead of u32 when possible
if utf8_str_len(node.val) < node.val.len {
if node.val.len_utf8() < node.val.len {
g.write('((rune)0x$node.val.utf32_code().hex() /* `$node.val` */)')
return
}
@ -3267,8 +3264,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
info := sym.info as ast.ArrayFixed
g.write('$info.size')
return
}
if sym.kind == .chan && (node.field_name == 'len' || node.field_name == 'closed') {
} else if sym.kind == .chan && (node.field_name == 'len' || node.field_name == 'closed') {
g.write('sync__Channel_${node.field_name}(')
g.expr(node.expr)
g.write(')')

View File

@ -300,6 +300,7 @@ const c_common_macros = '
#endif
#ifdef __TINYC__
#define _Atomic volatile
#undef EMPTY_STRUCT_DECLARATION
#define EMPTY_STRUCT_DECLARATION voidptr _dummy_pad
#undef EMPTY_ARRAY_OF_ELEMS

View File

@ -337,7 +337,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
}
info := var.obj as ast.Var
if g.table.sym(info.typ).kind != .function {
g.writeln('${g.typ(info.typ)}$deref $var.name;')
g.writeln('${g.typ(info.typ)}$deref ${c_name(var.name)};')
}
}
}
@ -1777,7 +1777,14 @@ fn (mut g Gen) go_expr(node ast.GoExpr) {
}
} else {
g.writeln('pthread_t thread_$tmp;')
g.writeln('int ${tmp}_thr_res = pthread_create(&thread_$tmp, NULL, (void*)$wrapper_fn_name, $arg_tmp_var);')
mut sthread_attributes := 'NULL'
if g.pref.os != .vinix {
g.writeln('pthread_attr_t thread_${tmp}_attributes;')
g.writeln('pthread_attr_init(&thread_${tmp}_attributes);')
g.writeln('pthread_attr_setstacksize(&thread_${tmp}_attributes, $g.pref.thread_stack_size);')
sthread_attributes = '&thread_${tmp}_attributes'
}
g.writeln('int ${tmp}_thr_res = pthread_create(&thread_$tmp, $sthread_attributes, (void*)$wrapper_fn_name, $arg_tmp_var);')
g.writeln('if (${tmp}_thr_res) panic_error_number(tos3("`go ${name}()`: "), ${tmp}_thr_res);')
if !node.is_expr {
g.writeln('pthread_detach(thread_$tmp);')
@ -1915,6 +1922,13 @@ fn (mut g Gen) go_expr(node ast.GoExpr) {
g.gowrappers.write_string(call_args_str)
} else {
for i in 0 .. expr.args.len {
expected_nr_muls := expr.expected_arg_types[i].nr_muls()
arg_nr_muls := expr.args[i].typ.nr_muls()
if arg_nr_muls > expected_nr_muls {
g.gowrappers.write_string('*'.repeat(arg_nr_muls - expected_nr_muls))
} else if arg_nr_muls < expected_nr_muls {
g.gowrappers.write_string('&'.repeat(expected_nr_muls - arg_nr_muls))
}
g.gowrappers.write_string('arg->arg${i + 1}')
if i != expr.args.len - 1 {
g.gowrappers.write_string(', ')

View File

@ -1,8 +1,8 @@
## Purpose: tests data for the output of V's C code generator
## TLDR: `v vlib/v/gen/c/coutput_test.v`
## TLDR: `v run vlib/v/gen/c/coutput_test.v`
coutput_test.v is a *test runner*, that checks whether the generated C
coutput_test.v is a *test runner*, that checks whether the generated C
source code matches *all* expectations, specified in *.c.must_have files,
in the folder vlib/v/gen/c/testdata/ .

View File

@ -0,0 +1,2 @@
int a = 5;
int b = 7;

View File

@ -0,0 +1,2 @@
5
7

View File

@ -0,0 +1,6 @@
fn main() {
a := 'Vlang'.len
b := r'Vlang\n'.len
println(a)
println(b)
}

View File

@ -423,7 +423,7 @@ pub fn (mut p Parser) expr_with_left(left ast.Expr, precedence int, is_stmt_iden
right := p.expr(precedence - 1)
pos.update_last_line(p.prev_tok.line_nr)
if mut node is ast.IndexExpr {
node.recursive_mapset_is_setter(true)
node.recursive_arraymap_set_is_setter()
}
node = ast.InfixExpr{
left: node

View File

@ -185,6 +185,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
is_field_volatile = true
}
is_embed := ((p.tok.lit.len > 1 && p.tok.lit[0].is_capital()
&& (p.peek_tok.line_nr != p.tok.line_nr || p.peek_tok.kind !in [.name, .amp])
&& (p.peek_tok.kind != .lsbr || p.peek_token(2).kind != .rsbr))
|| p.peek_tok.kind == .dot) && language == .v && p.peek_tok.kind != .key_fn
is_on_top := ast_fields.len == 0 && !(is_field_mut || is_field_global)
@ -515,7 +516,8 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
mut mut_pos := -1
mut ifaces := []ast.InterfaceEmbedding{}
for p.tok.kind != .rcbr && p.tok.kind != .eof {
if p.tok.kind == .name && p.tok.lit.len > 0 && p.tok.lit[0].is_capital() {
if p.tok.kind == .name && p.tok.lit.len > 0 && p.tok.lit[0].is_capital()
&& p.peek_tok.kind != .lpar {
iface_pos := p.tok.pos()
mut iface_name := p.tok.lit
iface_type := p.parse_type()
@ -583,10 +585,6 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
p.error_with_pos('duplicate method `$name`', method_start_pos)
return ast.InterfaceDecl{}
}
if language == .v && util.contains_capital(name) {
p.error('interface methods cannot contain uppercase letters, use snake_case instead')
return ast.InterfaceDecl{}
}
// field_names << name
args2, _, is_variadic := p.fn_args() // TODO merge ast.Param and ast.Arg to avoid this
mut args := [

View File

@ -199,6 +199,7 @@ pub mut:
nofloat bool // for low level code, like kernels: replaces f32 with u32 and f64 with u64
// checker settings:
checker_match_exhaustive_cutoff_limit int = 12
thread_stack_size int = 8388608 // Change with `-thread-stack-size 4194304`. Note: on macos it was 524288, which is too small for more complex programs with many nested callexprs.
}
pub fn parse_args(known_external_commands []string, args []string) (&Preferences, string) {
@ -571,6 +572,10 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
res.message_limit = cmdline.option(current_args, arg, '5').int()
i++
}
'-thread-stack-size' {
res.thread_stack_size = cmdline.option(current_args, arg, res.thread_stack_size.str()).int()
i++
}
'-cc' {
res.ccompiler = cmdline.option(current_args, '-cc', 'cc')
res.build_options << '$arg "$res.ccompiler"'

View File

@ -0,0 +1,20 @@
type Typ_var = f64 | int
fn test_array_of_sumtype_append_literal_type() {
mut arr := []Typ_var{}
// literal int/float type error
arr << 123
arr << 1.23
// cast/wrap in type
arr << int(123)
arr << f64(1.23)
arr << Typ_var(456)
arr << Typ_var(4.56)
println(arr)
assert arr[0] == Typ_var(123)
assert arr[1] == Typ_var(1.23)
}

View File

@ -1,6 +1,3 @@
import term
import os
import runtime
import time
struct App {
@ -13,7 +10,7 @@ fn test_atomic() {
for i in 0 .. 10 {
go app.run()
}
time.sleep(2 * time.second)
time.sleep(200 * time.millisecond)
println('idx=$app.idx')
assert app.idx == 10
}

View File

@ -0,0 +1,40 @@
fn test_complex_map_op1() {
mut test_map := map[string]Point_map{}
test_map['test1'].points['point3'] << Point{10, 20}
test_map['test2'].points['point4'] << Point{50, 60}
println(test_map)
assert test_map.len == 2
assert Point{10, 20} in test_map['test1'].points['point3']
assert Point{50, 60} in test_map['test2'].points['point4']
assert Point{10, 20} !in test_map['test2'].points['point4']
assert Point{1, 2} !in test_map['test1'].points['point3']
}
fn test_complex_map_op2() {
mut test_map := map[string]map[string][]Point{}
test_map['test1']['point3'] << Point{10, 20}
test_map['test2']['point4'] << Point{50, 60}
println(test_map)
assert test_map.len == 2
assert Point{10, 20} in test_map['test1']['point3']
assert Point{50, 60} in test_map['test2']['point4']
assert Point{10, 20} !in test_map['test2']['point4']
assert Point{1, 2} !in test_map['test1']['point3']
}
struct Point {
mut:
x int
y int
}
struct Point_map {
mut:
points map[string][]Point
}

View File

@ -0,0 +1,26 @@
fn f(x u8) u8 {
eprintln('> f: $x')
if x == 0 {
return 0
}
mut local := [131072]u8{}
local[local.len - 1] = x + f(x - 1)
return local[0] + local[local.len - 1]
}
fn abc(depth u8) u8 {
return f(depth)
}
fn test_default_stack_depth() {
$if tinyc && windows {
exit(0) // skip for now testing on windows-tcc
}
// Note: 10 levels of recursing f, requires a little over 1.4MB,
// and would have failed on macos, where the default thread size
// is just 512KB, if V was not changed to have a default for
// `-thread-stack-size` of 8MB.
t := go abc(10)
res := t.wait()
assert res == 55
}

View File

@ -154,3 +154,24 @@ fn num() int {
}
return ret
}
fn close(i int) {
eprintln('Close $i')
}
fn test_defer_with_reserved_words() {
if 1 == 1 {
single := 1
defer {
close(single)
}
}
if 2 == 2 {
double := 9
defer {
close(double)
}
}
eprintln('Done')
assert true
}

View File

@ -0,0 +1,15 @@
struct Foo {
bar string
}
fn test_go_anon_fn_call_with_ref_arg() {
foo := &Foo{
bar: 'hello'
}
g := go fn (foo Foo) string {
return foo.bar
}(foo)
ret := g.wait()
println(ret)
assert ret == 'hello'
}

View File

@ -636,6 +636,12 @@ pub fn (mut t Transformer) expr(mut node ast.Expr) ast.Expr {
}
ast.SelectorExpr {
node.expr = t.expr(mut node.expr)
if mut node.expr is ast.StringLiteral && node.field_name == 'len' {
return ast.IntegerLiteral{
val: node.expr.val.len.str()
pos: node.pos
}
}
}
ast.SizeOf {
node.expr = t.expr(mut node.expr)