From 82cd81e9630cd19bb314561acef7d54e67ac3c30 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Wed, 13 Aug 2025 16:22:22 +0300 Subject: [PATCH] builtin,vdoc: fix the examples for the builtin methods, so that `v doc -check-examples -time -f ansi vlib/builtin/` pass --- cmd/tools/vdoc/run_examples.v | 14 +++++---- vlib/builtin/array.v | 47 ++++++++++++++++--------------- vlib/builtin/chan_option_result.v | 4 +-- vlib/builtin/int.v | 4 +-- vlib/builtin/map.v | 2 +- vlib/builtin/string.v | 8 +++--- 6 files changed, 41 insertions(+), 38 deletions(-) diff --git a/cmd/tools/vdoc/run_examples.v b/cmd/tools/vdoc/run_examples.v index ac7442ea14..ebd2a3d4c7 100644 --- a/cmd/tools/vdoc/run_examples.v +++ b/cmd/tools/vdoc/run_examples.v @@ -16,6 +16,7 @@ fn (mut vd VDoc) process_all_examples(contents []doc.DocNode) { } const normalised_default_vmodules_path = os.vmodules_dir().replace('\\', '/') +const vdoc_max_fails = os.getenv_opt('VDOC_MAX_FAILS') or { '999' }.int() fn get_mod_name_by_file_path(file_path string) string { mut mcache := vmod.get_cache() @@ -51,9 +52,11 @@ fn (mut vd VDoc) run_examples(dn doc.DocNode) { os.rm(sfile) or {} } } - mut failures := 0 - mut oks := 0 for example in examples { + if vd.example_failures >= vdoc_max_fails { + eprintln('> vdoc: too many examples failed in ${vd.cfg.run_examples} mode') + exit(1) + } code := example.all_after('Example:').all_after('example:').trim_space() mod_name := get_mod_name_by_file_path(dn.file_path) vsource_path := os.join_path(efolder, 'example_${rand.ulid()}.v') @@ -61,6 +64,7 @@ fn (mut vd VDoc) run_examples(dn doc.DocNode) { import_clause := if mod_name in ['builtin', ''] { '' } else { 'import ${mod_name}\n' } source := '${import_clause}fn main() {\n\t${code}\n}\n' os.write_file(vsource_path, source) or { continue } + vd.vprintln('>>> vd.example_oks: ${vd.example_oks:5} | vd.example_failures: ${vd.example_failures:5} | examples.len: ${examples.len} | source.len: ${source.len:5} | dn.name: ${dn.name}') cmd := '${os.quoted_path(vexe)} ${voptions} ${os.quoted_path(vsource_path)}' res := os.execute(cmd) if res.exit_code != 0 { @@ -68,12 +72,10 @@ fn (mut vd VDoc) run_examples(dn doc.DocNode) { eprintln(' cmd: ${cmd}') eprintln(' result:') eprintln(res.output) - failures++ + vd.example_failures++ continue } example_program_source_files << vsource_path - oks++ + vd.example_oks++ } - vd.example_failures += failures - vd.example_oks += oks } diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index fbbf1f552a..c9cf163366 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -369,7 +369,7 @@ pub fn (mut a array) delete(i int) { // Example: // ```v // mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9] -// b := a[..9] // creates a `slice` of `a`, not a clone +// b := unsafe { a[..9] } // creates a `slice` of `a`, not a clone // a.delete_many(4, 3) // replaces `a` with a modified clone // dump(a) // a: [1, 2, 3, 4, 8, 9] // `a` is now different // dump(b) // b: [1, 2, 3, 4, 5, 6, 7, 8, 9] // `b` is still the same @@ -413,7 +413,7 @@ pub fn (mut a array) delete_many(i int, size int) { // clear clears the array without deallocating the allocated data. // It does it by setting the array length to `0` -// Example: a.clear() // `a.len` is now 0 +// Example: mut a := [1,2]; a.clear(); assert a.len == 0 pub fn (mut a array) clear() { a.len = 0 } @@ -430,7 +430,7 @@ pub fn (mut a array) reset() { // trim trims the array length to `index` without modifying the allocated data. // If `index` is greater than `len` nothing will be changed. -// Example: a.trim(3) // `a.len` is now <= 3 +// Example: mut a := [1,2,3,4]; a.trim(3); assert a.len == 10 pub fn (mut a array) trim(index int) { if index < a.len { a.len = index @@ -520,11 +520,14 @@ pub fn (a array) last() voidptr { // Example: // ```v // mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9] -// b := a[..9] // creates a "view" into the same memory -// c := a.pop() // c == 9 +// b := unsafe{ a[..9] } // creates a "view" (also called a slice) into the same memory +// c := a.pop() +// assert c == 9 // a[1] = 5 // dump(a) // a: [1, 5, 3, 4, 5, 6, 7, 8] // dump(b) // b: [1, 5, 3, 4, 5, 6, 7, 8, 9] +// assert a.len == 8 +// assert b.len == 9 // ``` pub fn (mut a array) pop() voidptr { // in a sense, this is the opposite of `a << x` @@ -816,9 +819,9 @@ pub fn (a &array) free() { // Each function takes a boolean test expression as its single argument. // These test expressions may use `it` as a pointer to a single element at a time. // -// Example: array.filter(it < 5) // create an array of elements less than 5 -// Example: array.filter(it % 2 == 1) // create an array of only odd elements -// Example: array.filter(it.name[0] == `A`) // create an array of elements whose `name` field starts with 'A' +// Example: a := [10,20,30,3,5,99]; assert a.filter(it < 5) == [3,5] // create an array of elements less than 5 +// Example: a := [10,20,30,3,5,99]; assert a.filter(it % 2 == 1) == [3,5,99] // create an array of only odd elements +// Example: struct Named { name string }; a := [Named{'Abc'}, Named{'Bcd'}, Named{'Az'}]; assert a.filter(it.name[0] == `A`).len == 2 pub fn (a array) filter(predicate fn (voidptr) bool) array // any tests whether at least one element in the array passes the test. @@ -827,15 +830,15 @@ pub fn (a array) filter(predicate fn (voidptr) bool) array // It returns `true` if it finds an element passing the test. Otherwise, // it returns `false`. It doesn't modify the array. // -// Example: array.any(it % 2 == 1) // will return true if any element is odd -// Example: array.any(it.name == 'Bob') // will yield `true` if any element has `.name == 'Bob'` +// Example: a := [2,3,4]; assert a.any(it % 2 == 1) // 3 is odd, so this will pass +// Example: struct Named { name string }; a := [Named{'Bob'}, Named{'Bilbo'}]; assert a.any(it.name == 'Bob') // the first element will match pub fn (a array) any(predicate fn (voidptr) bool) bool // count counts how many elements in array pass the test. // Ignore the function signature. `count` does not take an actual callback. Rather, it // takes an `it` expression. // -// Example: array.count(it % 2 == 1) // will return how many elements are odd +// Example: a := [10,3,5,7]; assert a.count(it % 2 == 1) == 3 // will return how many elements are odd pub fn (a array) count(predicate fn (voidptr) bool) int // all tests whether all elements in the array pass the test. @@ -844,7 +847,7 @@ pub fn (a array) count(predicate fn (voidptr) bool) int // It returns `false` if any element fails the test. Otherwise, // it returns `true`. It doesn't modify the array. // -// Example: array.all(it % 2 == 1) // will return true if every element is odd +// Example: a := [3,5,7,9]; assert a.all(it % 2 == 1) // will return true if every element is odd pub fn (a array) all(predicate fn (voidptr) bool) bool // map creates a new array populated with the results of calling a provided function @@ -873,9 +876,9 @@ pub fn (a array) map(callback fn (voidptr) voidptr) array // The expression uses 2 'magic' variables `a` and `b` as pointers to the two elements // being compared. // -// Example: array.sort() // will sort the array in ascending order -// Example: array.sort(b < a) // will sort the array in descending order -// Example: array.sort(b.name < a.name) // will sort descending by the .name field +// Example: mut aa := [5,2,1,10]; aa.sort(); assert aa == [1,2,5,10] // will sort the array in ascending order +// Example: mut aa := [5,2,1,10]; aa.sort(b < a); assert aa == [10,5,2,1] // will sort the array in descending order +// Example: struct Named { name string }; mut aa := [Named{'Abc'}, Named{'Xyz'}]; aa.sort(b.name < a.name); assert aa.map(it.name) == ['Abc', 'Xyz'] // will sort descending by the .name field pub fn (mut a array) sort(callback fn (voidptr, voidptr) int) // sorted returns a sorted copy of the original array. The original array is *NOT* modified. @@ -894,9 +897,8 @@ pub fn (a &array) sorted(callback fn (voidptr, voidptr) int) array // // Example: // ```v -// fn main() { -// mut a := ['hi', '1', '5', '3'] -// a.sort_with_compare(fn (a &string, b &string) int { +// mut a := ['hi', '1', '5', '3'] +// a.sort_with_compare(fn (a &string, b &string) int { // if a < b { // return -1 // } @@ -904,9 +906,8 @@ pub fn (a &array) sorted(callback fn (voidptr, voidptr) int) array // return 1 // } // return 0 -// }) -// assert a == ['1', '3', '5', 'hi'] -// } +// }) +// assert a == ['1', '3', '5', 'hi'] // ``` pub fn (mut a array) sort_with_compare(callback fn (voidptr, voidptr) int) { $if freestanding { @@ -934,7 +935,7 @@ pub fn (a &array) sorted_with_compare(callback fn (voidptr, voidptr) int) array // It will return `true` if the array contains an element with this value. // It is similar to `.any` but does not take an `it` expression. // -// Example: [1, 2, 3].contains(4) == false +// Example: assert [1, 2, 3].contains(4) == false pub fn (a array) contains(value voidptr) bool // index returns the first index at which a given element can be found in the array or `-1` if the value is not found. @@ -955,7 +956,7 @@ pub fn (mut a []string) free() { // to arrays of different types in different ways. // str returns a string representation of an array of strings. -// Example: ['a', 'b', 'c'].str() // => "['a', 'b', 'c']". +// Example: assert ['a', 'b', 'c'].str() == "['a', 'b', 'c']" @[direct_array_access; manualfree] pub fn (a []string) str() string { mut sb_len := 4 // 2x" + 1x, + 1xspace diff --git a/vlib/builtin/chan_option_result.v b/vlib/builtin/chan_option_result.v index 7e5d85f39a..8c200f6243 100644 --- a/vlib/builtin/chan_option_result.v +++ b/vlib/builtin/chan_option_result.v @@ -118,7 +118,7 @@ fn trace_error(x string) { } // error returns a default error instance containing the error given in `message`. -// Example: if ouch { return error('an error occurred') } +// Example: f := fn (ouch bool) ! { if ouch { return error('an error occurred') } }; f(false)! @[inline] pub fn error(message string) IError { trace_error(message) @@ -128,7 +128,7 @@ pub fn error(message string) IError { } // error_with_code returns a default error instance containing the given `message` and error `code`. -// Example: if ouch { return error_with_code('an error occurred', 1) } +// Example: f := fn (ouch bool) ! { if ouch { return error_with_code('an error occurred', 1) } }; f(false)! @[inline] pub fn error_with_code(message string, code int) IError { trace_error('${message} | code: ${code}') diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 81887dcb62..c69679d93d 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -538,8 +538,8 @@ pub fn (b u8) str_escaped() string { } // is_capital returns `true`, if the byte is a Latin capital letter. -// Example: assert `H`.is_capital() == true -// Example: assert `h`.is_capital() == false +// Example: assert u8(`H`).is_capital() == true +// Example: assert u8(`h`).is_capital() == false @[inline] pub fn (c u8) is_capital() bool { return c >= `A` && c <= `Z` diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index c39ab898dc..6a130504a9 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -324,7 +324,7 @@ pub fn (mut m map) move() map { // clear clears the map without deallocating the allocated data. // It does it by setting the map length to `0` -// Example: a.clear() // `a.len` and `a.key_values.len` is now 0 +// Example: mut m := {'abc': 'xyz', 'def': 'aaa'}; m.clear(); assert m.len == 0 pub fn (mut m map) clear() { unsafe { if m.key_values.all_deleted != 0 { diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index cd6fe38977..3f9cad4806 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -872,7 +872,7 @@ fn (s string) plus_two(a string, b string) string { // split_any splits the string to an array by any of the `delim` chars. // If the delimiter string is empty then `.split()` is used. -// Example: "first row\nsecond row".split_any(" \n") == ['first', 'row', 'second', 'row'] +// Example: assert "first row\nsecond row".split_any(" \n") == ['first', 'row', 'second', 'row'] @[direct_array_access] pub fn (s string) split_any(delim string) []string { mut res := []string{} @@ -903,7 +903,7 @@ pub fn (s string) split_any(delim string) []string { // rsplit_any splits the string to an array by any of the `delim` chars in reverse order. // If the delimiter string is empty then `.rsplit()` is used. -// Example: "first row\nsecond row".rsplit_any(" \n") == ['row', 'second', 'row', 'first'] +// Example: assert "first row\nsecond row".rsplit_any(" \n") == ['row', 'second', 'row', 'first'] @[direct_array_access] pub fn (s string) rsplit_any(delim string) []string { mut res := []string{} @@ -1837,7 +1837,7 @@ pub fn (s string) trim(cutset string) string { } // trim_indexes gets the new start and end indices of a string when any of the characters given in `cutset` were stripped from the start and end of the string. Should be used as an input to `substr()`. If the string contains only the characters in `cutset`, both values returned are zero. -// Example: left, right := '-hi-'.trim_indexes('-') +// Example: left, right := '-hi-'.trim_indexes('-'); assert left == 1; assert right == 3 @[direct_array_access] pub fn (s string) trim_indexes(cutset string) (int, int) { mut pos_left := 0 @@ -2965,7 +2965,7 @@ pub: // wrap wraps the string `s` when each line exceeds the width specified in `width` . // (default value is 80), and will use `end` (default value is '\n') as a line break. -// Example: `assert 'Hello, my name is Carl and I am a delivery'.wrap(width: 20) == 'Hello, my name is\nCarl and I am a\ndelivery'` +// Example: assert 'Hello, my name is Carl and I am a delivery'.wrap(width: 20) == 'Hello, my name is\nCarl and I am a\ndelivery' pub fn (s string) wrap(config WrapConfig) string { if config.width <= 0 { return ''