diff --git a/README.md b/README.md index 36ca359b8a..1604e1b582 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ ## Key Features of V - Simplicity: the language can be learned in less than an hour -- Fast compilation: ≈80k loc/s with a Clang backend, +- Fast compilation: ≈80k loc/s with a Clang backend, ≈1 million loc/s with x64 and tcc backends *(Intel i5-7500, SSD, no optimization)* - Easy to develop: V compiles itself in less than a second - Performance: as fast as C (V's main backend compiles to human readable C) @@ -81,7 +81,7 @@ v up ### C compiler -It's recommended to use Clang or GCC or Visual Studio. +It's recommended to use Clang or GCC or Visual Studio. If you are doing development, you most likely already have one of those installed. Otherwise, follow these instructions: @@ -90,8 +90,8 @@ Otherwise, follow these instructions: - [Installing a C compiler on Windows](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows) -However, if none is found when running `make` on Linux or Windows, -TCC would be downloaded and set as an alternative C backend. +However, if none is found when running `make` on Linux or Windows, +TCC would be downloaded and set as an alternative C backend. It's very lightweight (several MB) so this shouldn't take too long. ### Symlinking @@ -227,9 +227,9 @@ https://github.com/vlang/ui ```v fn main() { - for i in 0..3 { - println('Hello from V.js') - } + for i in 0 .. 3 { + println('Hello from V.js') + } } ``` diff --git a/cmd/tools/check-md.v b/cmd/tools/check-md.v index 0a7a3e1abf..30b20a5639 100644 --- a/cmd/tools/check-md.v +++ b/cmd/tools/check-md.v @@ -102,7 +102,6 @@ fn eline(file_path string, lnumber int, column int, message string) string { return btext('$file_path:${lnumber + 1}:${column + 1}:') + btext(rtext(' error: $message')) } -// const ( default_command = 'compile' ) @@ -190,16 +189,23 @@ fn (mut f MDFile) check_examples() (int, int) { vfile := os.join_path(os.temp_dir(), 'check_${fname}_example_${e.sline}__${e.eline}__${uid}.v') mut should_cleanup_vfile := true // eprintln('>>> checking example $vfile ...') - vcontent := e.text.join('\n') + vcontent := e.text.join('\n') + '\n' os.write_file(vfile, vcontent) or { panic(err) } mut acommands := e.command.split(' ') + nofmt := 'nofmt' in acommands for command in acommands { match command { 'compile' { res := os.system('"$vexe" -w -Wfatal-errors -o x.c $vfile') os.rm('x.c') or { } - if res != 0 { - eprintln(eline(f.path, e.sline, 0, 'example failed to compile')) + fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') } + if res != 0 || fmt_res != 0 { + if res != 0 { + eprintln(eline(f.path, e.sline, 0, 'example failed to compile')) + } + if fmt_res != 0 { + eprintln(eline(f.path, e.sline, 0, 'example is not formatted')) + } eprintln(vcontent) should_cleanup_vfile = false errors++ @@ -209,8 +215,14 @@ fn (mut f MDFile) check_examples() (int, int) { } 'live' { res := os.system('"$vexe" -w -Wfatal-errors -live -o x.c $vfile') - if res != 0 { - eprintln(eline(f.path, e.sline, 0, 'example failed to compile with -live')) + fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') } + if res != 0 || fmt_res != 0 { + if res != 0 { + eprintln(eline(f.path, e.sline, 0, 'example failed to compile with -live')) + } + if fmt_res != 0 { + eprintln(eline(f.path, e.sline, 0, 'example is not formatted')) + } eprintln(vcontent) should_cleanup_vfile = false errors++ @@ -232,8 +244,14 @@ fn (mut f MDFile) check_examples() (int, int) { } 'oksyntax' { res := os.system('"$vexe" -w -Wfatal-errors -check-syntax $vfile') - if res != 0 { - eprintln(eline(f.path, e.sline, 0, '`oksyntax` example with invalid syntax')) + fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') } + if res != 0 || fmt_res != 0 { + if res != 0 { + eprintln(eline(f.path, e.sline, 0, '`oksyntax` example with invalid syntax')) + } + if fmt_res != 0 { + eprintln(eline(f.path, e.sline, 0, '`oksyntax` example is not formatted')) + } eprintln(vcontent) should_cleanup_vfile = false errors++ @@ -252,6 +270,7 @@ fn (mut f MDFile) check_examples() (int, int) { } oks++ } + 'nofmt' {} else { eprintln(eline(f.path, e.sline, 0, 'unrecognized command: "$command", use one of: wip/ignore/compile/failcompile/oksyntax/badsyntax')) should_cleanup_vfile = false diff --git a/doc/docs.md b/doc/docs.md index f0dbea6006..9e56603fcc 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -112,7 +112,7 @@ These are: ```v fn main() { - println('hello world') + println('hello world') } ``` @@ -150,8 +150,8 @@ println('hello world') ```v // This is a single line comment. - -/* This is a multiline comment. +/* +This is a multiline comment. /* It can be nested. */ */ ``` @@ -160,16 +160,16 @@ println('hello world') ```v fn main() { - println(add(77, 33)) - println(sub(100, 50)) + println(add(77, 33)) + println(sub(100, 50)) } fn add(x int, y int) int { - return x + y + return x + y } fn sub(x int, y int) int { - return x - y + return x - y } ``` @@ -185,7 +185,7 @@ or thinking about the order of files and declarations. ### Returning multiple values -```v +```v nofmt fn foo() (int, int) { return 2, 3 } @@ -198,7 +198,7 @@ c, _ := foo() // ignore values using `_` ### Variable number of arguments -```v +```v nofmt fn sum(a ...int) int { mut total := 0 for x in a { @@ -286,7 +286,7 @@ All variables need to be declared in V. ```v fn main() { - age := 21 + age := 21 } ``` @@ -368,7 +368,7 @@ negative values). ### Strings -```v +```v nofmt name := 'Bob' println(name.len) println(name[0]) // indexing gives a byte B @@ -402,7 +402,7 @@ Both single and double quotes can be used to denote strings. For consistency, For raw strings, prepend `r`. Raw strings are not escaped: -```v +```v nofmt s := r'hello\nworld' println(s) // "hello\nworld" ``` @@ -411,7 +411,7 @@ println(s) // "hello\nworld" Basic interpolation syntax is pretty simple - use `$` before a variable name. The variable will be converted to a string and embedded into the literal: -```v +```v nofmt name := 'Bob' println('Hello, $name!') // Hello, Bob! ``` @@ -422,7 +422,7 @@ Format specifiers similar to those in C's `printf()` are also supported. `f`, `g`, `x`, etc. are optional and specify the output format. The compiler takes care of the storage size, so there is no `hd` or `llu`. -```v +```v nofmt x := 123.4567 println('x = ${x:4.2f}') println('[${x:10}]') // pad with spaces on the left @@ -431,7 +431,7 @@ println('[${int(x):-10}]') // pad with spaces on the right ### String operators -```v +```v nofmt name := 'Bob' bobby := name + 'by' // + is used to concatenate strings println(bobby) // "Bobby" @@ -485,7 +485,7 @@ All of these will be assigned the same value, 123. They will all have type V also supports writing numbers with `_` as separator: -```v +```v nofmt num := 1_000_000 // same as 1000000 three := 0b0_11 // same as 0b11 float_num := 3_122.55 // same as 3122.55 @@ -513,7 +513,7 @@ will have the type of `f64`. ### Arrays -```v +```v nofmt mut nums := [1, 2, 3] println(nums) // "[1, 2, 3]" println(nums[1]) // "2" @@ -545,7 +545,7 @@ See [Access modifiers](#access-modifiers). #### Array operations -```v +```v nofmt mut nums := [1, 2, 3] nums << 4 println(nums) // "[1, 2, 3, 4]" @@ -573,13 +573,14 @@ During initialization you can specify the capacity of the array (`cap`), its ini and the default element (`init`): ```v -arr := []int{ len: 5, init: -1 } // `[-1, -1, -1, -1, -1]` +arr := []int{len: 5, init: -1} +// `[-1, -1, -1, -1, -1]` ``` Setting the capacity improves performance of insertions, as it reduces the number of reallocations needed: -```v +```v nofmt mut numbers := []int{ cap: 1000 } println(numbers.len) // 0 // Now appending elements won't reallocate @@ -597,7 +598,7 @@ with `s := arr.str()`. Arrays can be efficiently filtered and mapped with the `.filter()` and `.map()` methods: -```v +```v nofmt nums := [1, 2, 3, 4, 5, 6] even := nums.filter(it % 2 == 0) println(even) // [2, 4, 6] @@ -624,14 +625,14 @@ println(upper_fn) // ['HELLO', 'WORLD'] Arrays can have more than one dimension. 2d array example: -```v +```v nofmt mut a := [][]int{len:2, init: []int{len:3}} a[0][1] = 2 println(a) // [[0, 2, 0], [0, 0, 0]] ``` 3d array example: -```v +```v nofmt mut a := [][][]int{len:2, init: [][]int{len:3, init: []int{len:2}}} a[0][1][1] = 2 println(a) // [[[0, 0], [0, 2], [0, 0]], [[0, 0], [0, 0], [0, 0]]] @@ -642,13 +643,13 @@ println(a) // [[[0, 0], [0, 2], [0, 0]], [[0, 0], [0, 0], [0, 0]]] Sorting arrays of all kinds is very simple and intuitive. Special variables `a` and `b` are used when providing a custom sorting condition. -```v +```v nofmt mut numbers := [1, 3, 2] numbers.sort() // 1, 2, 3 numbers.sort(a > b) // 3, 2, 1 ``` -```v +```v nofmt struct User { age int name string } mut users := [User{21, 'Bob'}, User{20, 'Zarkon'}, User{25, 'Alice'}] users.sort(a.age < b.age) // sort by User.age int field @@ -657,7 +658,7 @@ users.sort(a.name > b.name) // reverse sort by User.name string field ### Maps -```v +```v nofmt mut m := map[string]int // Only maps with string keys are allowed for now m['one'] = 1 m['two'] = 2 @@ -683,9 +684,9 @@ Modules can be imported using the `import` keyword: import os fn main() { - // read text from stdin - name := os.input('Enter your name: ') - println('Hello, $name!') + // read text from stdin + name := os.input('Enter your name: ') + println('Hello, $name!') } ``` This program can use any public definitions from the `os` module, such @@ -701,7 +702,7 @@ which module is being called. This is especially useful in large code bases. You can also import specific functions and types from modules directly: -```v +```v nofmt import os { input } import crypto.sha256 { sum } import time { Time } @@ -744,17 +745,17 @@ import time type MyTime = time.Time fn (mut t MyTime) century() int { - return 1 + t.year % 100 + return 1 + t.year % 100 } fn main() { - mut my_time := MyTime{ - year: 2020, - month: 12, - day: 25 - } - println(time.new_time(my_time).utc_string()) - println('Century: ${my_time.century()}') + mut my_time := MyTime{ + year: 2020 + month: 12 + day: 25 + } + println(time.new_time(my_time).utc_string()) + println('Century: $my_time.century()') } ``` @@ -766,11 +767,11 @@ fn main() { a := 10 b := 20 if a < b { - println('$a < $b') + println('$a < $b') } else if a > b { - println('$a > $b') + println('$a > $b') } else { - println('$a == $b') + println('$a == $b') } ``` @@ -782,20 +783,16 @@ there are no parentheses surrounding the condition and the braces are always req ```v num := 777 -s := if num % 2 == 0 { - 'even' -} -else { - 'odd' -} -println(s) // "odd" +s := if num % 2 == 0 { 'even' } else { 'odd' } +println(s) +// "odd" ``` #### Type checks and casts You can check the current type of a sum type using `is` and its negated form `!is`. You can do it either in an `if`: -```v +```v nofmt struct Abc { val string } @@ -816,47 +813,46 @@ if x !is Abc { or using `match`: ```v oksyntax match x { - Abc { - // x is automatically casted to Abc and can be used here - println(x) - } - Xyz { - // x is automatically casted to Xyz and can be used here - println(x) - } + Abc { + // x is automatically casted to Abc and can be used here + println(x) + } + Xyz { + // x is automatically casted to Xyz and can be used here + println(x) + } } ``` This works also with struct fields: ```v struct MyStruct { - x int + x int } + struct MyStruct2 { - y string + y string } type MySumType = MyStruct | MyStruct2 struct Abc { - bar MySumType + bar MySumType } x := Abc{ - bar: MyStruct{123} // MyStruct will be converted to MySumType type automatically + bar: MyStruct{123} // MyStruct will be converted to MySumType type automatically } - if x.bar is MyStruct { - // x.bar is automatically casted - println(x.bar) + // x.bar is automatically casted + println(x.bar) } - match x.bar { - MyStruct { - // x.bar is automatically casted - println(x.bar) - } - else {} + MyStruct { + // x.bar is automatically casted + println(x.bar) + } + else {} } ``` @@ -868,20 +864,18 @@ to tell the compiler that you're aware of what you're doing. It works like this: ```v oksyntax mut x := MySumType(MyStruct{123}) - if mut x is MyStruct { - // x is casted to MyStruct even it's mutable - // without the mut keyword that wouldn't work - println(x) + // x is casted to MyStruct even it's mutable + // without the mut keyword that wouldn't work + println(x) } - // same with match match mut x { - MyStruct { - // x is casted to MyStruct even it's mutable - // without the mut keyword that wouldn't work - println(x) - } + MyStruct { + // x is casted to MyStruct even it's mutable + // without the mut keyword that wouldn't work + println(x) + } } ``` @@ -889,7 +883,7 @@ match mut x { `in` allows to check whether an array or a map contains an element. -```v +```v nofmt nums := [1, 2, 3] println(1 in nums) // true @@ -900,16 +894,23 @@ println('one' in m) // true It's also useful for writing boolean expressions that are clearer and more compact: ```v -enum Token { plus minus div mult } -struct Parser { token Token } -parser := Parser{} -if parser.token == .plus || parser.token == .minus || - parser.token == .div || parser.token == .mult { - // ... +enum Token { + plus + minus + div + mult } +struct Parser { + token Token +} + +parser := Parser{} +if parser.token == .plus || parser.token == .minus || parser.token == .div || parser.token == .mult { + // ... +} if parser.token in [.plus, .minus, .div, .mult] { - // ... + // ... } ``` @@ -922,7 +923,7 @@ V has only one looping keyword: `for`, with several forms. #### Array `for` -```v +```v nofmt numbers := [1, 2, 3, 4, 5] for num in numbers { println(num) @@ -939,10 +940,10 @@ If an index is required, an alternative form `for index, value in arr` can be us Note, that the value is read-only. If you need to modify the array while looping, you have to use indexing: -```v +```v nofmt mut numbers := [0, 1, 2] for i, _ in numbers { - numbers[i]++ + numbers[i]++ } println(numbers) // [1, 2, 3] ``` @@ -950,7 +951,7 @@ When an identifier is just a single underscore, it is ignored. #### Map `for` -```v +```v nofmt m := {'one':1, 'two':2} for key, value in m { println("$key -> $value") // Output: one -> 1 @@ -958,7 +959,7 @@ for key, value in m { ``` Either key or value can be ignored by using a single underscore as the identifer. -```v +```v nofmt m := {'one':1, 'two':2} // iterate over keys @@ -976,8 +977,8 @@ for _, value in m { ```v // Prints '01234' -for i in 0..5 { - print(i) +for i in 0 .. 5 { + print(i) } ``` `low..high` means an *exclusive* range, which represents all values @@ -985,12 +986,12 @@ from `low` up to *but not including* `high`. #### Condition `for` -```v +```v nofmt mut sum := 0 mut i := 0 for i <= 100 { - sum += i - i++ + sum += i + i++ } println(sum) // "5050" ``` @@ -1001,13 +1002,13 @@ Again, there are no parentheses surrounding the condition, and the braces are al #### Bare `for` -```v +```v nofmt mut num := 0 for { - num += 2 - if num >= 10 { - break - } + num += 2 + if num >= 10 { + break + } } println(num) // "10" ``` @@ -1018,11 +1019,11 @@ The condition can be omitted, resulting in an infinite loop. ```v for i := 0; i < 10; i += 2 { - // Don't print 6 - if i == 6 { - continue - } - println(i) + // Don't print 6 + if i == 6 { + continue + } + println(i) } ``` @@ -1039,11 +1040,14 @@ You can also use `break` and `continue` followed by a label name to refer to an loop: ```v -outer: for i := 4;; i++ { +outer: for i := 4; true; i++ { println(i) for { - if i < 7 {continue outer} - else {break outer} + if i < 7 { + continue outer + } else { + break outer + } } } ``` @@ -1062,9 +1066,9 @@ The above code prints: os := 'windows' print('V is running on ') match os { - 'darwin' { println('macOS.') } - 'linux' { println('Linux.') } - else { println(os) } + 'darwin' { println('macOS.') } + 'linux' { println('Linux.') } + else { println(os) } } ``` @@ -1075,9 +1079,9 @@ The else branch will be run when no other branches match. ```v number := 2 s := match number { - 1 { 'one' } - 2 { 'two' } - else { 'many'} + 1 { 'one' } + 2 { 'two' } + else { 'many' } } ``` @@ -1085,16 +1089,16 @@ A match expression returns the final expression from each branch. ```v enum Color { - red - blue - green + red + blue + green } fn is_red_or_blue(c Color) bool { - return match c { - .red, .blue { true } // comma can be used to test multiple values - .green { false } - } + return match c { + .red, .blue { true } // comma can be used to test multiple values + .green { false } + } } ``` @@ -1105,12 +1109,13 @@ when all the branches are exhaustive. ```v c := `v` typ := match c { - `0`...`9` { 'digit' } - `A`...`Z` { 'uppercase' } - `a`...`z` { 'lowercase' } - else { 'other' } + `0`...`9` { 'digit' } + `A`...`Z` { 'uppercase' } + `a`...`z` { 'lowercase' } + else { 'other' } } -println(typ) // 'lowercase' +println(typ) +// 'lowercase' ``` You can also use ranges as `match` patterns. If the value falls within the range @@ -1131,22 +1136,24 @@ until the surrounding function returns. import os fn read_log() { - mut ok := false - mut f := os.open('log.txt') or { panic(err) } - defer { f.close() } - // ... - if !ok { - // defer statement will be called here, the file will be closed - return - } - // ... - // defer statement will be called here, the file will be closed + mut ok := false + mut f := os.open('log.txt') or { panic(err) } + defer { + f.close() + } + // ... + if !ok { + // defer statement will be called here, the file will be closed + return + } + // ... + // defer statement will be called here, the file will be closed } ``` ## Structs -```v +```v nofmt struct Point { x int y int @@ -1171,9 +1178,10 @@ and get a reference to it, use the `&` prefix: ```v struct Point { - x int - y int + x int + y int } + p := &Point{10, 10} // References have the same syntax for accessing fields println(p.x) @@ -1194,12 +1202,13 @@ mut: } struct Button { -mut: - Widget - title string + Widget + title string } -mut button := Button{title: 'Click me'} +mut button := Button{ + title: 'Click me' +} button.x = 3 ``` Without embedding we'd have to name the `Widget` field and do: @@ -1212,10 +1221,10 @@ button.widget.x = 3 ```v struct Foo { - n int // n is 0 by default - s string // s is '' by default - a []int // a is `[]int{}` by default - pos int = -1 // custom default value + n int // n is 0 by default + s string // s is '' by default + a []int // a is `[]int{}` by default + pos int = -1 // custom default value } ``` @@ -1228,7 +1237,7 @@ It's also possible to define custom default values. ```v struct Foo { - n int [required] + n int [required] } ``` @@ -1245,14 +1254,20 @@ _ = Foo{} ### Short struct literal syntax ```v -struct Point{ - x int - y int +struct Point { + x int + y int } -mut p := Point{x: 10, y: 20} +mut p := Point{ + x: 10 + y: 20 +} // you can omit the struct name when it's already known -p = {x: 30, y: 4} +p = { + x: 30 + y: 4 +} assert p.y == 4 ``` @@ -1266,27 +1281,27 @@ literal syntax can be used instead: ```v struct ButtonConfig { - text string - is_disabled bool - width int = 70 - height int = 20 + text string + is_disabled bool + width int = 70 + height int = 20 } struct Button { - text string - width int - height int + text string + width int + height int } fn new_button(c ButtonConfig) &Button { - return &Button{ - width: c.width - height: c.height - text: c.text - } + return &Button{ + width: c.width + height: c.height + text: c.text + } } -button := new_button(text:'Click me', width:100) +button := new_button(text: 'Click me', width: 100) // the height is unset, so it's the default value assert button.height == 20 ``` @@ -1305,7 +1320,7 @@ Struct fields are private and immutable by default (making structs immutable as Their access modifiers can be changed with `pub` and `mut`. In total, there are 5 possible options: -```v +```v nofmt struct Foo { a int // private immutable (default) mut: @@ -1347,7 +1362,7 @@ no need in getters/setters or properties. ### Methods -```v +```v nofmt struct User { age int } @@ -1390,7 +1405,7 @@ intended for low-level applications like kernels and drivers. It is possible to modify function arguments by using the keyword `mut`: -```v +```v nofmt struct User { name string mut: @@ -1412,14 +1427,15 @@ so `register()` can change the user object. The same works with non-receiver arg ```v fn multiply_by_2(mut arr []int) { - for i in 0..arr.len { - arr[i] *= 2 - } + for i in 0 .. arr.len { + arr[i] *= 2 + } } mut nums := [1, 2, 3] multiply_by_2(mut nums) -println(nums) // "[2, 4, 6]" +println(nums) +// "[2, 4, 6]" ``` Note, that you have to add `mut` before `nums` when calling this function. This makes @@ -1438,12 +1454,23 @@ instead of `register(mut user)`. V makes it easy to return a modified version of an object: ```v -struct User{ name string age int is_registered bool } -fn register(u User) User { - return { u | is_registered: true } +struct User { + name string + age int + is_registered bool } -mut user := User{name: 'abc' age: 23} +fn register(u User) User { + return { + u | + is_registered: true + } +} + +mut user := User{ + name: 'abc' + age: 23 +} user = register(user) println(user) ``` @@ -1452,39 +1479,39 @@ println(user) ```v fn sqr(n int) int { - return n * n + return n * n } -fn run(value int, op fn(int) int) int { - return op(value) +fn run(value int, op fn (int) int) int { + return op(value) } -fn main() { - println(run(5, sqr)) // "25" - - // Anonymous functions can be declared inside other functions: - double_fn := fn(n int) int { - return n + n - } - println(run(5, double_fn)) // "10" - - // Functions can be passed around without assigning them to variables: - res := run(5, fn(n int) int { - return n + n - }) +fn main() { + println(run(5, sqr)) // "25" + // Anonymous functions can be declared inside other functions: + double_fn := fn (n int) int { + return n + n + } + println(run(5, double_fn)) // "10" + // Functions can be passed around without assigning them to variables: + res := run(5, fn (n int) int { + return n + n + }) } ``` ## References ```v -struct Foo{} +struct Foo { +} + fn (foo Foo) bar_method() { - // ... + // ... } fn bar_function(foo Foo) { - // ... + // ... } ``` @@ -1499,10 +1526,12 @@ You can ensure that the struct is always passed by reference by adding `&`: ```v -struct Foo{ abc int } +struct Foo { + abc int +} fn (foo &Foo) bar() { - println(foo.abc) + println(foo.abc) } ``` @@ -1524,8 +1553,8 @@ struct Node { ```v const ( - pi = 3.14 - world = '世界' + pi = 3.14 + world = '世界' ) println(pi) @@ -1541,19 +1570,28 @@ V constants are more flexible than in most languages. You can assign more comple ```v struct Color { - r int - g int - b int + r int + g int + b int } -fn rgb(r, g, b int) Color { return Color{r: r, g: g, b: b} } +fn rgb(r int, g int, b int) Color { + return Color{ + r: r + g: g + b: b + } +} const ( - numbers = [1, 2, 3] - - red = Color{r: 255, g: 0, b: 0} - // evaluate function call at compile-time - blue = rgb(0, 0, 255) + numbers = [1, 2, 3] + red = Color{ + r: 255 + g: 0 + b: 0 + } + // evaluate function call at compile-time + blue = rgb(0, 0, 255) ) println(numbers) @@ -1580,7 +1618,7 @@ println('Top cities: $top_cities.filter(.usa)') `println` is a simple yet powerful builtin function. It can print anything: strings, numbers, arrays, maps, structs. -```v +```v nofmt struct User{ name string age int } println(1) // "1" println('hi') // "hi" @@ -1593,14 +1631,20 @@ If you want to define a custom print value for your type, simply define a ```v struct Color { - r int - g int - b int + r int + g int + b int } -pub fn (c Color) str() string { return '{$c.r, $c.g, $c.b}' } +pub fn (c Color) str() string { + return '{$c.r, $c.g, $c.b}' +} -red := Color{r: 255, g: 0, b: 0} +red := Color{ + r: 255 + g: 0 + b: 0 +} println(red) ``` @@ -1663,7 +1707,7 @@ you can use a module `init` function: ```v fn init() { - // your setup code here ... + // your setup code here ... } ``` @@ -1676,32 +1720,31 @@ particularly useful for initializing a C library. ```v struct Dog { - breed string + breed string } struct Cat { } fn (d Dog) speak() string { - return 'woof' + return 'woof' } fn (c Cat) speak() string { - return 'meow' + return 'meow' } interface Speaker { - speak() string + speak() string } dog := Dog{'Leonberger'} cat := Cat{} - mut arr := []Speaker{} arr << dog arr << cat for item in arr { - item.speak() + item.speak() } ``` @@ -1711,20 +1754,20 @@ There is no explicit declaration of intent, no "implements" keyword. We can test the underlying type of an interface using dynamic cast operators: ```v oksyntax fn announce(s Speaker) { - if s is Dog { - println('a $s.breed') // `s` is automatically cast to `Dog` (smart cast) - } else if s is Cat { - println('a cat') - } else { - println('something else') - } + if s is Dog { + println('a $s.breed') // `s` is automatically cast to `Dog` (smart cast) + } else if s is Cat { + println('a cat') + } else { + println('something else') + } } ``` For more information, see [Dynamic casts](#dynamic-casts). ### Enums -```v +```v nofmt enum Color { red green blue } @@ -1739,7 +1782,6 @@ match color { .green { println('the color was green') } .blue { println('the color was blue') } } - ``` Enum match must be exhaustive or have an `else` branch. @@ -1751,11 +1793,16 @@ A sum type instance can hold a value of several different types. Use the `type` keyword to declare a sum type: ```v -struct Moon {} -struct Mars {} -struct Venus {} +struct Moon { +} -type World = Moon | Mars | Venus +struct Mars { +} + +struct Venus { +} + +type World = Mars | Moon | Venus sum := World(Moon{}) assert sum.type_name() == 'Moon' @@ -1770,24 +1817,30 @@ To check whether a sum type instance holds a certain type, use `sum is Type`. To cast a sum type to one of its variants you can use `sum as Type`: ```v -struct Moon {} -struct Mars {} -struct Venus {} +struct Moon { +} -type World = Moon | Mars | Venus +struct Mars { +} -fn (m Mars) dust_storm() bool { return true } +struct Venus { +} + +type World = Mars | Moon | Venus + +fn (m Mars) dust_storm() bool { + return true +} fn main() { - mut w := World(Moon{}) - assert w is Moon - - w = Mars{} - // use `as` to access the Mars instance - mars := w as Mars - if mars.dust_storm() { - println('bad weather!') - } + mut w := World(Moon{}) + assert w is Moon + w = Mars{} + // use `as` to access the Mars instance + mars := w as Mars + if mars.dust_storm() { + println('bad weather!') + } } ``` @@ -1798,10 +1851,10 @@ A safer way is to use a smart cast. ```v oksyntax if w is Mars { - assert typeof(w).name == 'Mars' - if w.dust_storm() { - println('bad weather!') - } + assert typeof(w).name == 'Mars' + if w.dust_storm() { + println('bad weather!') + } } ``` `w` has type `Mars` inside the body of the `if` statement. This is @@ -1823,26 +1876,33 @@ complex expression than just a variable name. You can also use `match` to determine the variant: ```v -struct Moon {} -struct Mars {} -struct Venus {} +struct Moon { +} -type World = Moon | Mars | Venus +struct Mars { +} -fn open_parachutes(n int) { println(n) } +struct Venus { +} + +type World = Mars | Moon | Venus + +fn open_parachutes(n int) { + println(n) +} fn land(w World) { - match w { - Moon {} // no atmosphere - Mars { - // light atmosphere - open_parachutes(3) - } - Venus { - // heavy atmosphere - open_parachutes(1) - } - } + match w { + Moon {} // no atmosphere + Mars { + // light atmosphere + open_parachutes(3) + } + Venus { + // heavy atmosphere + open_parachutes(1) + } + } } ``` @@ -1890,33 +1950,35 @@ It will not work on struct fields, array indexes, or map keys. Option types are declared with `?Type`: ```v struct User { - id int - name string + id int + name string } struct Repo { - users []User + users []User } fn (r Repo) find_user_by_id(id int) ?User { - for user in r.users { - if user.id == id { - // V automatically wraps this into an option type - return user - } - } - return error('User $id not found') + for user in r.users { + if user.id == id { + // V automatically wraps this into an option type + return user + } + } + return error('User $id not found') } fn main() { - repo := Repo { - users: [User{1, 'Andrew'}, User {2, 'Bob'}, User {10, 'Charles'}] - } - user := repo.find_user_by_id(10) or { // Option types must be handled by `or` blocks - return - } - println(user.id) // "10" - println(user.name) // "Charles" + repo := Repo{ + users: [User{1, 'Andrew'}, User{2, 'Bob'}, + User{10, 'Charles'}, + ] + } + user := repo.find_user_by_id(10) or { // Option types must be handled by `or` blocks + return + } + println(user.id) // "10" + println(user.name) // "Charles" } ``` @@ -1937,8 +1999,8 @@ to the `error()` function. `err` is empty if `none` was returned. ```v oksyntax user := repo.find_user_by_id(7) or { - println(err) // "User 7 not found" - return + println(err) // "User 7 not found" + return } ``` @@ -1951,8 +2013,8 @@ propagate the error: import net.http fn f(url string) ?string { - resp := http.get(url) ? - return resp.text + resp := http.get(url) ? + return resp.text } ``` @@ -1966,9 +2028,7 @@ any further. The body of `f` is essentially a condensed version of: ```v ignore - resp := http.get(url) or { - return error(err) - } + resp := http.get(url) or { return error(err) } return resp.text ``` @@ -1976,9 +2036,7 @@ The body of `f` is essentially a condensed version of: The second method is to break from execution early: ```v oksyntax -user := repo.find_user_by_id(7) or { - return -} +user := repo.find_user_by_id(7) or { return } ``` Here, you can either call `panic()` or `exit()`, which will stop the execution of the @@ -1994,10 +2052,12 @@ The third method is to provide a default value at the end of the `or` block. In case of an error, that value would be assigned instead, so it must have the same type as the content of the `Option` being handled. -```v +```v nofmt fn do_something(s string) ?string { - if s == 'foo' { return 'foo' } - return error('invalid string') // Could be `return none` as well + if s == 'foo' { + return 'foo' + } + return error('invalid string') // Could be `return none` as well } a := do_something('foo') or { 'default' } // a will be 'foo' @@ -2011,10 +2071,11 @@ The fourth method is to use `if` unwrapping: ```v import net.http + if resp := http.get('https://google.com') { - println(resp.text) // resp is a http.Response, not an optional + println(resp.text) // resp is a http.Response, not an optional } else { - println(err) + println(err) } ``` Above, `http.get` returns a `?http.Response`. `resp` is only in scope for the first @@ -2052,15 +2113,15 @@ runtime parameter types. This is why `find_by_id` can omit ``, because the receiver argument `r` uses a generic type `T`. Another example: -```v +```v nofmt fn compare(a T, b T) int { - if a < b { - return -1 - } - if a > b { - return 1 - } - return 0 + if a < b { + return -1 + } + if a > b { + return 1 + } + return 0 } // compare @@ -2090,30 +2151,31 @@ thread. Soon coroutines and a scheduler will be implemented. import sync import time -fn task(id, duration int, mut wg sync.WaitGroup) { - println("task ${id} begin") - time.sleep_ms(duration) - println("task ${id} end") - wg.done() +fn task(id int, duration int, mut wg sync.WaitGroup) { + println('task $id begin') + time.sleep_ms(duration) + println('task $id end') + wg.done() } fn main() { - mut wg := sync.new_waitgroup() - wg.add(3) - go task(1, 500, mut wg) - go task(2, 900, mut wg) - go task(3, 100, mut wg) - wg.wait() - println('done') + mut wg := sync.new_waitgroup() + wg.add(3) + go task(1, 500, mut wg) + go task(2, 900, mut wg) + go task(3, 100, mut wg) + wg.wait() + println('done') } -// Output: task 1 begin -// task 2 begin -// task 3 begin -// task 3 end -// task 1 end -// task 2 end -// done +// Output: +// task 1 begin +// task 2 begin +// task 3 begin +// task 3 end +// task 1 end +// task 2 end +// done ``` ### Channels @@ -2125,7 +2187,7 @@ Channels can be buffered or unbuffered and it is possible to `select` from multi Channels have the type `chan objtype`. An optional buffer length can specified as the `cap` property in the declaration: -```v +```v nofmt ch := chan int{} // unbuffered - "synchronous" ch2 := chan f64{cap: 100} // buffer length 100 ``` @@ -2135,28 +2197,31 @@ a property of the individual channel object. Channels can be passed to coroutine variables: ```v +import sync + fn f(ch chan int) { - // ... + // ... } fn main() { - ch := chan int{} - go f(ch) - // ... + ch := chan int{} + go f(ch) + // ... } ``` Objects can be pushed to channels using the arrow operator. The same operator can be used to pop objects from the other end: -```v +```v nofmt +import sync + mut ch := chan int{} mut ch2 := chan f64{} n := 5 x := 7.3 ch <- n // push ch2 <- x - mut y := f64(0.0) m := <-ch // pop creating new variable y = <-ch2 // pop into existing variable @@ -2234,7 +2299,9 @@ if select { #### Special Channel Features For special purposes there are some builtin properties and methods: -```v +```v nofmt +import sync + struct Abc{x int} a := 2.13 @@ -2251,6 +2318,7 @@ println(c) // mut ch2 := chan f64{} // res2 := ch2.try_pop(mut b) // try to perform `b = <-ch2 ``` + The `try_push/pop()` methods will return immediately with one of the results `.success`, `.not_ready` or `.closed` - dependent on whether the object has been transferred or the reason why not. @@ -2266,17 +2334,14 @@ import sync struct St { mut: - x int // share data + x int // share data mtx &sync.Mutex } fn (mut b St) g() { - b.mtx.m_lock() // read/modify/write b.x - b.mtx.unlock() - } fn caller() { @@ -2285,12 +2350,9 @@ fn caller() { mtx: sync.new_mutex() } go a.g() - a.mtx.m_lock() // read/modify/write a.x - a.mtx.unlock() - } ``` @@ -2302,29 +2364,27 @@ import json struct Foo { x int } + struct User { - name string - age int - - // Use the `skip` attribute to skip certain fields - foo Foo [skip] - - // If the field name is different in JSON, it can be specified - last_name string [json:lastName] + name string + age int + // Use the `skip` attribute to skip certain fields + foo Foo [skip] + // If the field name is different in JSON, it can be specified + last_name string [json: lastName] } data := '{ "name": "Frodo", "lastName": "Baggins", "age": 25 }' user := json.decode(User, data) or { - eprintln('Failed to decode json') - return + eprintln('Failed to decode json') + return } println(user.name) println(user.last_name) println(user.age) - // You can also decode JSON arrays: sfoos := '[{"x":123},{"x":456}]' -foos := json.decode([]Foo, sfoos)? +foos := json.decode([]Foo, sfoos) ? println(foos[0].x) println(foos[1].x) ``` @@ -2343,7 +2403,10 @@ No runtime reflection is used. This results in much better performance. ### Asserts ```v -fn foo(mut v []int) { v[0] = 1 } +fn foo(mut v []int) { + v[0] = 1 +} + mut v := [20] foo(mut v) assert v[0] < 4 @@ -2359,13 +2422,16 @@ unexpected value. Assert statements can be used in any function. ```v // hello.v module main + fn hello() string { - return 'Hello world' + return 'Hello world' } + fn main() { - println(hello()) + println(hello()) } ``` + ```v failcompile module main // hello_test.v @@ -2416,18 +2482,19 @@ to be leak free. For example: ```v import strings + fn draw_text(s string, x int, y int) { - // ... + // ... } fn draw_scene() { - // ... - name1 := 'abc' - name2 := 'def ghi' - draw_text('hello $name1', 10, 10) - draw_text('hello $name2', 100, 10) - draw_text(strings.repeat(`X`, 10000), 10, 50) - // ... + // ... + name1 := 'abc' + name2 := 'def ghi' + draw_text('hello $name1', 10, 10) + draw_text('hello $name2', 100, 10) + draw_text(strings.repeat(`X`, 10000), 10, 50) + // ... } ``` @@ -2439,16 +2506,19 @@ These two strings are small, V will use a preallocated buffer for them. ```v -struct User{ name string } +struct User { + name string +} + fn test() []int { - number := 7 // stack variable - user := User{} // struct allocated on stack - numbers := [1, 2, 3] // array allocated on heap, will be freed as the function exits - println(number) - println(user) - println(numbers) - numbers2 := [4, 5, 6] // array that's being returned, won't be freed here - return numbers2 + number := 7 // stack variable + user := User{} // struct allocated on stack + numbers := [1, 2, 3] // array allocated on heap, will be freed as the function exits + println(number) + println(user) + println(numbers) + numbers2 := [4, 5, 6] // array that's being returned, won't be freed here + return numbers2 } ``` @@ -2468,7 +2538,7 @@ V's ORM provides a number of benefits: - Readability and simplicity. (You don't need to manually parse the results of a query and then manually construct objects from the parsed results.) -```v +```v nofmt import sqlite struct Customer { // struct name has to be the same as the table name (for now) id int // a field named `id` of integer type must be the first field @@ -2513,7 +2583,6 @@ Documentation for each function/type/const must be placed right before the decla ```v // clearall clears all bits in the array fn clearall() { - } ``` @@ -2569,10 +2638,11 @@ You can sort on column 3 (average time per function) using: You can also use stopwatches to measure just portions of your code explicitly: ```v import time -fn main(){ - sw := time.new_stopwatch({}) - println('Hello world') - println('Greeting the world took: ${sw.elapsed().nanoseconds()}ns') + +fn main() { + sw := time.new_stopwatch({}) + println('Hello world') + println('Greeting the world took: ${sw.elapsed().nanoseconds()}ns') } ``` @@ -2628,53 +2698,62 @@ surrounding code). ```v #flag -lsqlite3 #include "sqlite3.h" - // See also the example from https://www.sqlite.org/quickstart.html -struct C.sqlite3{} -struct C.sqlite3_stmt{} +struct C.sqlite3 { +} -type FnSqlite3Callback = fn(voidptr, int, &charptr, &charptr) int +struct C.sqlite3_stmt { +} + +type FnSqlite3Callback = fn (voidptr, int, &charptr, &charptr) int fn C.sqlite3_open(charptr, &&C.sqlite3) int + fn C.sqlite3_close(&C.sqlite3) int + fn C.sqlite3_column_int(stmt &C.sqlite3_stmt, n int) int + // ... you can also just define the type of parameter & leave out the C. prefix fn C.sqlite3_prepare_v2(&sqlite3, charptr, int, &&sqlite3_stmt, &charptr) int + fn C.sqlite3_step(&sqlite3_stmt) + fn C.sqlite3_finalize(&sqlite3_stmt) -fn C.sqlite3_exec(db &sqlite3, sql charptr, FnSqlite3Callback, cb_arg voidptr, emsg &charptr) int + +fn C.sqlite3_exec(db &sqlite3, sql charptr, FnSqlite3Callback voidptr, cb_arg voidptr, emsg &charptr) int + fn C.sqlite3_free(voidptr) fn my_callback(arg voidptr, howmany int, cvalues &charptr, cnames &charptr) int { - for i in 0..howmany { - print('| ${cstring_to_vstring(cnames[i])}: ${cstring_to_vstring(cvalues[i]):20} ') + for i in 0 .. howmany { + print('| ${cstring_to_vstring(cnames[i])}: ${cstring_to_vstring(cvalues[i]):20} ') } - println('|') - return 0 + println('|') + return 0 } fn main() { - db := &C.sqlite3(0) // this means `sqlite3* db = 0` - // passing a string literal to a C function call results in a C string, not a V string - C.sqlite3_open('users.db', &db) - // C.sqlite3_open(db_path.str, &db) - // you can also use `.str byteptr` field to convert a V string to a C char pointer - query := 'select count(*) from users' - stmt := &C.sqlite3_stmt(0) - C.sqlite3_prepare_v2(db, query.str, - 1, &stmt, 0) - C.sqlite3_step(stmt) - nr_users := C.sqlite3_column_int(stmt, 0) - C.sqlite3_finalize(stmt) - println('There are $nr_users users in the database.') - // - error_msg := charptr(0) - query_all_users := 'select * from users' - rc := C.sqlite3_exec(db, query_all_users.str, my_callback, 7, &error_msg) - if rc != C.SQLITE_OK { - eprintln( cstring_to_vstring(error_msg) ) - C.sqlite3_free(error_msg) - } - C.sqlite3_close(db) + db := &C.sqlite3(0) // this means `sqlite3* db = 0` + // passing a string literal to a C function call results in a C string, not a V string + C.sqlite3_open('users.db', &db) + // C.sqlite3_open(db_path.str, &db) + // you can also use `.str byteptr` field to convert a V string to a C char pointer + query := 'select count(*) from users' + stmt := &C.sqlite3_stmt(0) + C.sqlite3_prepare_v2(db, query.str, -1, &stmt, 0) + C.sqlite3_step(stmt) + nr_users := C.sqlite3_column_int(stmt, 0) + C.sqlite3_finalize(stmt) + println('There are $nr_users users in the database.') + // + error_msg := charptr(0) + query_all_users := 'select * from users' + rc := C.sqlite3_exec(db, query_all_users.str, my_callback, 7, &error_msg) + if rc != C.SQLITE_OK { + eprintln(cstring_to_vstring(error_msg)) + C.sqlite3_free(error_msg) + } + C.sqlite3_close(db) } ``` @@ -2818,39 +2897,34 @@ use `v help`, `v help build` and `v help build-c`. ```v // Support for multiple conditions in one branch $if ios || android { - println('Running on a mobile device!') + println('Running on a mobile device!') } $if linux && x64 { - println('64-bit Linux.') + println('64-bit Linux.') } - // Usage as expression os := $if windows { 'Windows' } $else { 'UNIX' } println('Using $os') - // $else-$if branches $if tinyc { - println('tinyc') + println('tinyc') } $else $if clang { - println('clang') + println('clang') } $else $if gcc { - println('gcc') + println('gcc') } $else { - println('different compiler') + println('different compiler') } - $if test { - println('testing') + println('testing') } - // v -cg ... $if debug { - println('debugging') + println('debugging') } - // v -d option ... $if option ? { - println('custom option') + println('custom option') } ``` @@ -2884,7 +2958,7 @@ that are substituted at compile time: That allows you to do the following example, useful while debugging/logging/tracing your code: ```v -eprintln( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @MOD + '.' + @FN) +eprintln('file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @MOD + '.' + @FN) ``` Another example, is if you want to embed the version/name from v.mod *inside* your executable: @@ -2968,33 +3042,27 @@ fn decode_User(data string) User { ```v struct Vec { - x int - y int + x int + y int } fn (a Vec) str() string { - return '{$a.x, $a.y}' + return '{$a.x, $a.y}' } -fn (a Vec) + (b Vec) Vec { - return Vec { - a.x + b.x, - a.y + b.y - } +fn (a Vec) +(b Vec) Vec { + return Vec{a.x + b.x, a.y + b.y} } -fn (a Vec) - (b Vec) Vec { - return Vec { - a.x - b.x, - a.y - b.y - } +fn (a Vec) -(b Vec) Vec { + return Vec{a.x - b.x, a.y - b.y} } fn main() { - a := Vec{2, 3} - b := Vec{4, 5} - println(a + b) // "{6, 8}" - println(a - b) // "{-2, -2}" + a := Vec{2, 3} + b := Vec{4, 5} + println(a + b) // "{6, 8}" + println(a - b) // "{-2, -2}" } ``` @@ -3051,10 +3119,10 @@ Run `v translate test.cpp` and V will generate `test.v`: ```v fn main() { - mut s := []string{} - s << 'V is ' - s << 'awesome' - println(s.len) + mut s := []string{} + s << 'V is ' + s << 'awesome' + println(s.len) } ``` @@ -3082,16 +3150,15 @@ import os [live] fn print_message() { - println('Hello! Modify this message while the program is running.') + println('Hello! Modify this message while the program is running.') } fn main() { - for { - print_message() - time.sleep_ms(500) - } + for { + print_message() + time.sleep_ms(500) + } } - ``` Build this example with `v -live message.v`. @@ -3177,11 +3244,13 @@ and applies only to the following declaration. ```v // Calling this function will result in a deprecation warning [deprecated] -fn old_function() {} +fn old_function() { +} // This function's calls will be inlined. [inline] -fn inlined_function() {} +fn inlined_function() { +} // The following struct can only be used as a reference (`&Window`) and allocated on the heap. [ref_only] @@ -3191,15 +3260,17 @@ struct Window { // V will not generate this function and all its calls if the provided flag is false. // To use a flag, use `v -d flag` [if debug] -fn foo() { } +fn foo() { +} fn bar() { - foo() // will not be called if `-d debug` is not passed + foo() // will not be called if `-d debug` is not passed } // For C interop only, tells V that the following struct is defined with `typedef struct` in C [typedef] -struct C.Foo { } +struct C.Foo { +} // Used in Win32 API code when you need to pass callback function [windows_stdcall] diff --git a/tutorials/building-a-simple-web-blog-with-vweb.md b/tutorials/building-a-simple-web-blog-with-vweb.md index 4f36bd4404..aff547a5dc 100644 --- a/tutorials/building-a-simple-web-blog-with-vweb.md +++ b/tutorials/building-a-simple-web-blog-with-vweb.md @@ -75,8 +75,11 @@ pub fn (mut app App) index() vweb.Result { return vweb.Result{} } -pub fn (app &App) init() {} -pub fn (app &App) init_once() {} +pub fn (app &App) init() { +} + +pub fn (app &App) init_once() { +} ``` Run it with @@ -103,6 +106,8 @@ no routing rules either: ```v oksyntax import vweb +import time + fn (mut app App) time() vweb.Result { app.vweb.text(time.now().format()) return vweb.Result{} @@ -341,10 +346,11 @@ Create `new.html`: ```v oksyntax import vweb + pub fn (mut app App) new_article() vweb.Result { title := app.vweb.form['title'] text := app.vweb.form['text'] - if title == '' || text == '' { + if title == '' || text == '' { app.vweb.text('Empty text/title') return vweb.Result{} } @@ -380,6 +386,8 @@ in V is very simple: ```v oksyntax import vweb +import json + pub fn (mut app App) articles() vweb.Result { articles := app.find_all_articles() app.vweb.json(json.encode(articles)) diff --git a/vlib/benchmark/README.md b/vlib/benchmark/README.md index 8e059d248a..bb6667a0c0 100644 --- a/vlib/benchmark/README.md +++ b/vlib/benchmark/README.md @@ -1,42 +1,43 @@ Example usage of this module: -``` +```v import benchmark + mut bmark := benchmark.new_benchmark() // by default the benchmark will be verbose, i.e. it will include timing information // if you want it to be silent, set bmark.verbose = false for { - bmark.step() // call this when you want to advance the benchmark. - // The timing info in bmark.step_message will be measured starting from the last call to bmark.step - .... - - //bmark.fail() // call this if the step failed - //bmark.step_message(('failed') - - bmark.ok() // call this when the step succeeded - println( bmark.step_message('ok') + bmark.step() // call this when you want to advance the benchmark. + // The timing info in bmark.step_message will be measured starting from the last call to bmark.step + // .... + // bmark.fail() // call this if the step failed + // bmark.step_message(('failed') + bmark.ok() // call this when the step succeeded + println(bmark.step_message('ok')) } -bmark.stop() // call when you want to finalize the benchmark -println( bmark.total_message('remarks about the benchmark') ) +bmark.stop() +// call when you want to finalize the benchmark +println(bmark.total_message('remarks about the benchmark')) ``` benchmark.start() and b.measure() are convenience methods, intended to be used in combination. Their goal is to make benchmarking of small snippets of code as *short*, easy to write, and then to read and analyze the results, as possible. + Example: ```v import time import benchmark -mut b := benchmark.start() +mut b := benchmark.start() // your code section 1 ... time.sleep_ms(1500) b.measure('code_1') - // your code section 2 ... time.sleep_ms(500) b.measure('code_2') ``` + ... which will produce on stdout something like this: ```text SPENT 1500.063 ms in code_1 diff --git a/vlib/encoding/csv/README.md b/vlib/encoding/csv/README.md index e71a8650b5..01f3e4eb76 100644 --- a/vlib/encoding/csv/README.md +++ b/vlib/encoding/csv/README.md @@ -5,13 +5,13 @@ import encoding.csv data := 'x,y\na,b,c\n' mut parser := csv.new_reader(data) - // read each line for { - items := parser.read() or {break} - println(items) + items := parser.read() or { break } + println(items) } ``` + It prints: ``` ['x', 'y'] diff --git a/vlib/eventbus/README.md b/vlib/eventbus/README.md index 7aebe6f025..90d2e3d1d7 100644 --- a/vlib/eventbus/README.md +++ b/vlib/eventbus/README.md @@ -35,20 +35,20 @@ fn cb(receiver voidptr, args voidptr, sender voidptr) { // Since V can map structs to voidptr, this also works struct ClickEvent { - x int - y int + x int + y int } // Example case where publisher sends ClickEvent as args. -fn on_press(receiver voidptr, e &ClickEvent, sender voidptr){ - println(e.x) - //your code here... +fn on_press(receiver voidptr, e &ClickEvent, sender voidptr) { + println(e.x) + // your code here... } ``` ## Usage -For **usage across modules** +For **usage across modules** [check the example](https://github.com/vlang/v/tree/master/examples/eventbus). _Note: As a general rule, you will need to **subscribe before publishing**._ @@ -57,25 +57,26 @@ _Note: As a general rule, you will need to **subscribe before publishing**._ ```v oksyntax module main + import eventbus // initialize it globally const ( - eb = eventbus.new() + eb = eventbus.new() ) -fn main(){ - // get a mutable reference to the subscriber +fn main() { + // get a mutable reference to the subscriber mut sub := eb.subscriber - // subscribe to the 'error' event - sub.subscribe("error", on_error) - // start the work + // subscribe to the 'error' event + sub.subscribe('error', on_error) + // start the work do_work() } // the event handler fn on_error(receiver voidptr, e &Error, work &Work) { - println('error occured on ${work.hours}. Error: ${e.message}') + println('error occured on ${work.hours}. Error: $e.message') } ``` @@ -84,20 +85,20 @@ fn on_error(receiver voidptr, e &Error, work &Work) { ```v oksyntax module main -struct Work{ - hours int +struct Work { + hours int } struct Error { - message string + message string } -fn do_work(){ - work := Work{20} - // get a mutable Params instance & put some data into it - error := &Error{"Error: no internet connection."} - // publish the event - eb.publish("error", work, error) +fn do_work() { + work := Work{20} + // get a mutable Params instance & put some data into it + error := &Error{'Error: no internet connection.'} + // publish the event + eb.publish('error', work, error) } ``` diff --git a/vlib/regex/README.md b/vlib/regex/README.md index b66c7ebf68..3d732ee3c3 100644 --- a/vlib/regex/README.md +++ b/vlib/regex/README.md @@ -160,20 +160,17 @@ that is an `[]int` inside the `RE` struct. **example:** ```v oksyntax -text := "cpaz cpapaz cpapapaz" -query:= r"(c(pa)+z ?)+" +text := 'cpaz cpapaz cpapapaz' +query := r'(c(pa)+z ?)+' mut re := regex.regex_opt(query) or { panic(err) } - println(re.get_query()) // #0(c#1(pa)+z ?)+ // #0 and #1 are the ids of the groups, are shown if re.debug is 1 or 2 - start, end := re.match_string(text) // [start=0, end=20] match => [cpaz cpapaz cpapapaz] - mut gi := 0 for gi < re.groups.len { if re.groups[gi] >= 0 { - println("${gi/2} :[${text[re.groups[gi]..re.groups[gi+1]]}]") + println('${gi / 2} :[${text[re.groups[gi]..re.groups[gi + 1]]}]') } gi += 2 } @@ -260,45 +257,42 @@ If the space ends no error is raised, further records will not be saved. ```v oksyntax fn example2() { test_regex() - - text := "tst: 01,23,45 ,56, 78" - query:= r".*:(\s*\d+[\s,]*)+" - + text := 'tst: 01,23,45 ,56, 78' + query := r'.*:(\s*\d+[\s,]*)+' mut re := new() or { panic(err) } - //re.debug = 2 - re.group_csave = [-1].repeat(3*20+1) // we expect max 20 records - - re.compile_opt(query) or { println(err) return } - - q_str := re.get_query() - println("Query: $q_str") - - start, end := re.match_string(text) - if start < 0 { - println("ERROR : ${re.get_parse_error_string(start)}, $start") - } else { - println("found in [$start, $end] => [${text[start..end]}]") - } - - // groups capture - mut gi := 0 - for gi < re.groups.len { - if re.groups[gi] >= 0 { - println("${gi/2} ${re.groups[gi]},${re.groups[gi+1]} :[${text[re.groups[gi]..re.groups[gi+1]]}]") - } - gi += 2 - } - - // continuous saving - gi = 0 - println("num: ${re.group_csave[0]}") - for gi < re.group_csave[0] { - id := re.group_csave[1+gi*3] - st := re.group_csave[1+gi*3+1] - en := re.group_csave[1+gi*3+2] - println("cg id: ${id} [${st}, ${en}] => [${text[st..en]}]") - gi++ - } + // re.debug = 2 + re.group_csave = [-1].repeat(3 * 20 + 1) // we expect max 20 records + re.compile_opt(query) or { + println(err) + return + } + q_str := re.get_query() + println('Query: $q_str') + start, end := re.match_string(text) + if start < 0 { + println('ERROR : ${re.get_parse_error_string(start)}, $start') + } else { + println('found in [$start, $end] => [${text[start..end]}]') + } + // groups capture + mut gi := 0 + for gi < re.groups.len { + if re.groups[gi] >= 0 { + println('${gi / 2} ${re.groups[gi]},${re.groups[gi + 1]} :[${text[re.groups[gi]..re.groups[gi + + 1]]}]') + } + gi += 2 + } + // continuous saving + gi = 0 + println('num: ${re.group_csave[0]}') + for gi < re.group_csave[0] { + id := re.group_csave[1 + gi * 3] + st := re.group_csave[1 + gi * 3 + 1] + en := re.group_csave[1 + gi * 3 + 2] + println('cg id: $id [$st, $en] => [${text[st..en]}]') + gi++ + } } ``` @@ -333,64 +327,61 @@ example: ```v ignore import regex + fn main() { test_regex() - - text := "http://www.ciao.mondo/hello/pippo12_/pera.html" - query:= r"(?Phttps?)|(?:ftps?)://(?P[\w_]+.)+" - + text := 'http://www.ciao.mondo/hello/pippo12_/pera.html' + query := r'(?Phttps?)|(?:ftps?)://(?P[\w_]+.)+' mut re := new() re.debug = 2 - // must provide an array of the right size if want the continuos saving of the groups - re.group_csave = [-1].repeat(3*20+1) - - re.compile_opt(query) or { println(err) return } - - q_str := re.get_query() - println("O.Query: $query") - println("Query : $q_str") - - re.debug = 0 - start, end := re.match_string(text) - if start < 0 { - err_str := re.get_parse_error_string(start) - println("ERROR : $err_str, $start") - } else { - text1 := text[start..end] - println("found in [$start, $end] => [$text1]") - } - - // groups - mut gi := 0 - for gi < re.groups.len { - if re.groups[gi] >= 0 { - println("${gi/2} ${re.groups[gi]},${re.groups[gi+1]} :[${text[re.groups[gi]..re.groups[gi+1]]}]") - } - gi += 2 - } - // continuous saving - gi = 0 - println("num of group item saved: ${re.group_csave[0]}") - for gi < re.group_csave[0] { - id := re.group_csave[1+gi*3] - st := re.group_csave[1+gi*3+1] - en := re.group_csave[1+gi*3+2] - println("cg id: ${id} [${st}, ${en}] => [${text[st..en]}]") - gi++ - } - println("raw array: ${re.group_csave[0..gi*3+2-1]}") - - // named capturing groups - println("named capturing groups:") - for g_name in re.group_map.keys() { - s,e := re.get_group(g_name) - if s >= 0 && e > s { - println("'${g_name}':[$s, $e] => '${text[s..e]}'") - } else { - println("Group [${g_name}] doesn't exist.") - } - } + re.group_csave = [-1].repeat(3 * 20 + 1) + re.compile_opt(query) or { + println(err) + return + } + q_str := re.get_query() + println('O.Query: $query') + println('Query : $q_str') + re.debug = 0 + start, end := re.match_string(text) + if start < 0 { + err_str := re.get_parse_error_string(start) + println('ERROR : $err_str, $start') + } else { + text1 := text[start..end] + println('found in [$start, $end] => [$text1]') + } + // groups + mut gi := 0 + for gi < re.groups.len { + if re.groups[gi] >= 0 { + println('${gi / 2} ${re.groups[gi]},${re.groups[gi + 1]} :[${text[re.groups[gi]..re.groups[gi + + 1]]}]') + } + gi += 2 + } + // continuous saving + gi = 0 + println('num of group item saved: ${re.group_csave[0]}') + for gi < re.group_csave[0] { + id := re.group_csave[1 + gi * 3] + st := re.group_csave[1 + gi * 3 + 1] + en := re.group_csave[1 + gi * 3 + 2] + println('cg id: $id [$st, $en] => [${text[st..en]}]') + gi++ + } + println('raw array: ${re.group_csave[0..gi * 3 + 2 - 1]}') + // named capturing groups + println('named capturing groups:') + for g_name in re.group_map.keys() { + s, e := re.get_group(g_name) + if s >= 0 && e > s { + println("'$g_name':[$s, $e] => '${text[s..e]}'") + } else { + println("Group [$g_name] doesn't exist.") + } + } } ``` @@ -530,17 +521,14 @@ This module has few small utilities to help the writing of regex expressions. the following example code show how to visualize the syntax errors in the compilation phase: ```v oksyntax -query:= r"ciao da ab[ab-]" // there is an error, a range not closed!! +query := r'ciao da ab[ab-]' +// there is an error, a range not closed!! mut re := new() - re.compile_opt(query) or { println(err) } - // output!! - -//query: ciao da ab[ab-] -//err : ----------^ -//ERROR: ERR_SYNTAX_ERROR - +// query: ciao da ab[ab-] +// err : ----------^ +// ERROR: ERR_SYNTAX_ERROR ``` ### **Compiled code** @@ -636,12 +624,12 @@ it is possible to provide an alternative output setting a custom output functio ```v oksyntax // custom print function, the input will be the regex debug string fn custom_print(txt string) { - println("my log: $txt") + println('my log: $txt') } mut re := new() -re.log_func = custom_print // every debug output from now will call this function - +re.log_func = custom_print +// every debug output from now will call this function ``` ## Example code @@ -652,44 +640,45 @@ Here there is a simple code to perform some basically match of strings struct TestObj { source string // source string to parse query string // regex query string - s int // expected match start index - e int // expected match end index + s int // expected match start index + e int // expected match end index } + const ( -tests = [ - TestObj{"this is a good.",r"this (\w+) a",0,9}, - TestObj{"this,these,those. over",r"(th[eio]se?[,. ])+",0,17}, - TestObj{"test1@post.pip.com, pera",r"[\w]+@([\w]+\.)+\w+",0,18}, - TestObj{"cpapaz ole. pippo,",r".*c.+ole.*pi",0,14}, - TestObj{"adce aabe",r"(a(ab)+)|(a(dc)+)e",0,4}, -] + tests = [ + TestObj{'this is a good.', r'this (\w+) a', 0, 9}, + TestObj{'this,these,those. over', r'(th[eio]se?[,. ])+', 0, 17}, + TestObj{'test1@post.pip.com, pera', r'[\w]+@([\w]+\.)+\w+', 0, 18}, + TestObj{'cpapaz ole. pippo,', r'.*c.+ole.*pi', 0, 14}, + TestObj{'adce aabe', r'(a(ab)+)|(a(dc)+)e', 0, 4}, + ] ) fn example() { - for c,tst in tests { + for c, tst in tests { mut re := regex.new() - re.compile_opt(tst.query) or { println(err) continue } - - // print the query parsed with the groups ids - re.debug = 1 // set debug on at minimum level - println("#${c:2d} query parsed: ${re.get_query()}") - re.debug = 0 - - // do the match - start, end := re.match_string(tst.source) - if start >= 0 && end > start { - println("#${c:2d} found in: [$start, $end] => [${tst.source[start..end]}]") - } - - // print the groups - mut gi := 0 - for gi < re.groups.len { - if re.groups[gi] >= 0 { - println("group ${gi/2:2d} :[${tst.source[re.groups[gi]..re.groups[gi+1]]}]") - } - gi += 2 - } - println("") + re.compile_opt(tst.query) or { + println(err) + continue + } + // print the query parsed with the groups ids + re.debug = 1 // set debug on at minimum level + println('#${c:2d} query parsed: $re.get_query()') + re.debug = 0 + // do the match + start, end := re.match_string(tst.source) + if start >= 0 && end > start { + println('#${c:2d} found in: [$start, $end] => [${tst.source[start..end]}]') + } + // print the groups + mut gi := 0 + for gi < re.groups.len { + if re.groups[gi] >= 0 { + println('group ${gi / 2:2d} :[${tst.source[re.groups[gi]..re.groups[gi + 1]]}]') + } + gi += 2 + } + println('') } } diff --git a/vlib/semver/README.md b/vlib/semver/README.md index bb38f4422a..2f3f9bb8ce 100644 --- a/vlib/semver/README.md +++ b/vlib/semver/README.md @@ -8,20 +8,19 @@ A library for working with versions in [semver][semver] format. import semver fn main() { - ver1 := semver.from('1.2.4') or { - println('Invalid version') - return - } - ver2 := semver.from('2.3.4') or { - println('Invalid version') - return - } - - println(ver1.gt(ver2)) - println(ver2.gt(ver1)) - println(ver1.satisfies('>=1.1.0 <2.0.0')) - println(ver2.satisfies('>=1.1.0 <2.0.0')) - println(ver2.satisfies('>=1.1.0 <2.0.0 || >2.2.0')) + ver1 := semver.from('1.2.4') or { + println('Invalid version') + return + } + ver2 := semver.from('2.3.4') or { + println('Invalid version') + return + } + println(ver1.gt(ver2)) + println(ver2.gt(ver1)) + println(ver1.satisfies('>=1.1.0 <2.0.0')) + println(ver2.satisfies('>=1.1.0 <2.0.0')) + println(ver2.satisfies('>=1.1.0 <2.0.0 || >2.2.0')) } ``` diff --git a/vlib/strconv/format.md b/vlib/strconv/format.md index a169d5dbe2..1563ce9b96 100644 --- a/vlib/strconv/format.md +++ b/vlib/strconv/format.md @@ -13,9 +13,10 @@ is replaced by the textual version of the following parameters. ```v import strconv + fn main() { - a := "World" - s := strconv.v_sprintf("Hello %s!", a) + a := 'World' + s := strconv.v_sprintf('Hello %s!', a) println(s) } ``` @@ -49,16 +50,16 @@ The Flags field may be zero or more (in any order) of: #### Width field -The Width field specifies a *maximum* number of characters to output, -and is typically used to pad fixed-width fields in tabulated output, +The Width field specifies a *maximum* number of characters to output, +and is typically used to pad fixed-width fields in tabulated output, it causes truncation of oversized fields. -The width field may be omitted, or it may be a numeric integer value, -or may also be specified by a parameter when indicated by an asterisk `*`. -For example, `v_printf("%*.s", 5, my_string)` will result in ` mystring` being printed, +The width field may be omitted, or it may be a numeric integer value, +or may also be specified by a parameter when indicated by an asterisk `*`. +For example, `v_printf("%*.s", 5, my_string)` will result in ` mystring` being printed, with a total width of 5 characters. -#### Length field +#### Length field The Length field can be omitted or be any of: @@ -71,7 +72,7 @@ The Length field can be omitted or be any of: | | | | | | -#### Type field +#### Type field The Type field can be any of: @@ -93,15 +94,15 @@ The Type field can be any of: various types ```v oksyntax -a0 := u32(10) -b0 := 200 -c0 := byte(12) -s0 := "ciAo" +a0 := u32(10) +b0 := 200 +c0 := byte(12) +s0 := 'ciAo' ch0 := `B` -f0 := 0.312345 -f1 := 200000.0 -sc0 := "ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]" -temp_s = strconv.v_sprintf(sc0 ,a0 ,b0 ,c0 ,s0, b0 ,f0, f1, ch0) +f0 := 0.312345 +f1 := 200000.0 +sc0 := 'ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]' +temp_s = strconv.v_sprintf(sc0, a0, b0, c0, s0, b0, f0, f1, ch0) println(temp_s) ``` @@ -116,8 +117,8 @@ a := byte(12) b := i16(13) c := 14 d := i64(15) -sc1 := "==>%hhd %hd %d %ld" -temp_s = strconv.v_sprintf(sc1, a ,b ,c, d) +sc1 := '==>%hhd %hd %d %ld' +temp_s = strconv.v_sprintf(sc1, a, b, c, d) println(temp_s) ``` @@ -130,10 +131,10 @@ unsigned integer ```v oksyntax a1 := byte(0xff) b1 := u16(0xffff) -c1 := u32(0xffff_ffff) +c1 := u32(0xffffffff) d1 := u64(-1) -sc2 := "%hhu %hu %u %lu" -temp_s = strconv.v_sprintf(sc2, a1 ,b1 ,c1, d1) +sc2 := '%hhu %hu %u %lu' +temp_s = strconv.v_sprintf(sc2, a1, b1, c1, d1) println(temp_s) ``` @@ -146,10 +147,10 @@ hexadecimal ```v oksyntax a1 := byte(0xff) b1 := i16(0xffff) -c1 := u32(0xffff_ffff) +c1 := u32(0xffffffff) d1 := u64(-1) -sc3 := "%hhx %hx %x %lx" -temp_s = strconv.v_sprintf(sc3, a1 ,b1 ,c1, d1) +sc3 := '%hhx %hx %x %lx' +temp_s = strconv.v_sprintf(sc3, a1, b1, c1, d1) println(temp_s) ``` @@ -161,7 +162,7 @@ hexadecimal ```v oksyntax a2 := 125 -sc7 := "[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]" +sc7 := '[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]' temp_s = strconv.v_sprintf(sc7, a2, a2, a2, a2, a2, a2) println(temp_s) ``` @@ -173,11 +174,11 @@ println(temp_s) floating points ```v oksyntax -f0 := 0.312345 -f1 := 200000.0 -f2 := -1234.300e6 -f3 := 1234.300e-6 -sc4 := "[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]" +f0 := 0.312345 +f1 := 200000.0 +f2 := -1234.300e6 +f3 := 1234.300e-6 +sc4 := '[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]' temp_s = strconv.v_sprintf(sc4, f0, f1, f1, f1, f2, f3) println(temp_s) ``` @@ -190,11 +191,11 @@ float automatic notations ```v oksyntax mut ft := -1e-7 -mut x := 0 -sc8 := "[%20g][%20G]|" +mut x := 0 +sc8 := '[%20g][%20G]|' for x < 12 { temp_s = strconv.v_sprintf(sc8, ft, ft) - println("$temp_s\n") + println('$temp_s\n') ft = ft * 10.0 x++ } @@ -220,13 +221,13 @@ for x < 12 { The format module also has some utility functions: -```v oksyntax +```v oksyntax nofmt // calling struct struct BF_param { pad_ch byte = ` ` // padding char len0 int = -1 // default len for whole the number or string len1 int = 6 // number of decimal digits, if needed - positive bool = true // mandatory: the sign of the number passed + positive bool = true // mandatory: the sign of the number passed sign_flag bool = false // flag for print sign as prefix in padding allign Align_text = .right // alignment of the string rm_tail_zero bool = false // remove the tail zeros from floats @@ -243,7 +244,7 @@ fn remove_tail_zeros(s string) string `format_fl` format a float number in normal notation using the parameters in the `BF_param` struct. -`format_es format a float number in scientific notation using the parameters in the BF_param` +`format_es format a float number in scientific notation using the parameters in the BF_param` struct. -`remove_tail_zeros` removes the tailing zeros from a floating point number as string. +`remove_tail_zeros` removes the tailing zeros from a floating point number as string. diff --git a/vlib/term/README.md b/vlib/term/README.md index e73cc8ef12..5a9a42ac30 100644 --- a/vlib/term/README.md +++ b/vlib/term/README.md @@ -17,20 +17,20 @@ import term import os fn main() { - term.clear() // clears the content in the terminal - width, height := term.get_terminal_size() // get the size of the terminal - term.set_cursor_position(x: width / 2, y: height / 2) // now we point the cursor to the middle of the terminal - println(term.strikethrough(term.bright_green("hello world"))) // Print green text - term.set_cursor_position(x: 0, y: height) // Sets the position of the cursor to the bottom of the terminal - mut var := os.input('press q to quit: ') - // Keep prompting until the user presses the q key - for { - if var == 'q' { - break - } else { - var = os.input('press q to quit: ') - } - } + term.clear() // clears the content in the terminal + width, height := term.get_terminal_size() // get the size of the terminal + term.set_cursor_position(x: width / 2, y: height / 2) // now we point the cursor to the middle of the terminal + println(term.strikethrough(term.bright_green('hello world'))) // Print green text + term.set_cursor_position(x: 0, y: height) // Sets the position of the cursor to the bottom of the terminal + mut var := os.input('press q to quit: ') + // Keep prompting until the user presses the q key + for { + if var == 'q' { + break + } else { + var = os.input('press q to quit: ') + } + } } ``` @@ -42,55 +42,40 @@ Here are some functions you should be aware of in the `term `module: ```v oksyntax import term + // returns the height and the width of the terminal width, height := term.get_terminal_size() - // returns the string as green text to be printed on stdout term.ok_message('cool') - // returns the string as red text to be printed on stdout term.fail_message('oh, no') - // returns the string as yellow text to be printed on stdout term.warning_message('be warned') - -//clears the entire terminal and leaves a blank one +// clears the entire terminal and leaves a blank one term.clear() - // colors the output of the output, the available colors are: black,blue,yellow,green,cyan,gray,bright_blue,bright_green,bright_red,bright_black,bright_cyan term.yellow('submarine') - // transforms the given string into bold text term.bold('and beautiful') - // puts a strikethrough into the given string term.strikethrough('the core of the problem') - // underlines the given string term.underline('important') - // colors the background of the output following the given color // the available colors are: black, blue, yellow, green, cyan, gray term.bg_green('field') - // sets the position of the cursor at a given place in the terminal term.set_cursor_position(x: 5, y: 10) - // moves the cursor up term.cursor_up() - // moves the cursor down term.cursor_down() - // moves the cursor to the right term.cursor_forward() - // moves the cursor to the left term.cursor_back() - // shows the cursor term.show_cursor() - // hides the cursor term.hide_cursor() ``` diff --git a/vlib/term/ui/README.md b/vlib/term/ui/README.md index 993e035f81..ea844f98c4 100644 --- a/vlib/term/ui/README.md +++ b/vlib/term/ui/README.md @@ -4,7 +4,7 @@ A V module for designing terminal UI apps #### Quickstart -```v +```v nofmt import term.ui as tui struct App { diff --git a/vlib/v/README.md b/vlib/v/README.md index ccf277beb0..6738b15e5d 100644 --- a/vlib/v/README.md +++ b/vlib/v/README.md @@ -26,18 +26,23 @@ or `Preferences.compile_defines_all` **if any file is defined**. To parse something a new template is created as the first step: ```v import v.table + table := table.new_table() ``` + a new preference is created: ```v import v.pref + pref := pref.Preferences{} ``` + and a new scope is created: ```v import v.ast + scope := ast.Scope{ - parent: 0 + parent: 0 } ``` after that, you can parse your files. @@ -46,6 +51,7 @@ after that, you can parse your files. If you want to parse only text which isn't saved on the disk you can use this function. ```v oksyntax import v.parser + code := '' // table, pref and scope needs to be passed as reference parsed_file := parser.parse_text(code, table, .parse_comments, &pref, &scope) @@ -56,6 +62,7 @@ For parsing files on disk, a path needs to be provided. The paths are collected one step earlier. ```v oksyntax import v.parser + path := '' // table, pref and scope needs to be passed as reference parsed_file := parser.parse_file(path, table, .parse_comments, &pref, &scope) @@ -66,6 +73,7 @@ If you have a batch of paths available which should be parsed, there is also a function which does all the work. ```v oksyntax import v.parser + paths := [''] // table, pref and scope needs to be passed as reference parsed_files := parser.parse_files(paths, table, &pref, &scope) @@ -86,6 +94,7 @@ Then all files from that directory are collected and parsed again like the previ A new checker is created: ```v oksyntax import v.checker + mut checker := checker.new_checker(table, &pref) ``` @@ -105,5 +114,6 @@ checker.check_files(parsed_files) Generating C code works just as this: ```v oksyntax import v.gen + res := gen.cgen(parsed_files, table, &pref) ``` diff --git a/vlib/x/json2/README.md b/vlib/x/json2/README.md index e540f158a5..ab7da3a7e4 100644 --- a/vlib/x/json2/README.md +++ b/vlib/x/json2/README.md @@ -1,10 +1,10 @@ -> The name `json2` was chosen to avoid any unwanted potential conflicts with the +> The name `json2` was chosen to avoid any unwanted potential conflicts with the > existing codegen tailored for the main `json` module which is powered by CJSON. `x.json2` is an experimental JSON parser written from scratch on V. ## Usage -```v oksyntax +```v oksyntax nofmt import x.json2 import net.http @@ -99,7 +99,7 @@ fn main() { ``` ## Using struct tags -`x.json2` can access and use the struct field tags similar to the +`x.json2` can access and use the struct field tags similar to the `json` module by using the comp-time `$for` for structs. ```v ignore @@ -115,7 +115,7 @@ fn (mut p Person) from_json(f json2.Any) { break } } - + match field.name { 'name' { p.name = mp[js_field_name].str() } 'age' { u.age = mp[js_field_name].int() } @@ -153,9 +153,9 @@ fn (mut p Person) from_json(f json2.Any) { ```v oksyntax fn (mut p Person) to_json() string { - obj := f.as_map() - obj['nickname'] = p.name - return obj.str() + obj := f.as_map() + obj['nickname'] = p.name + return obj.str() } ``` @@ -170,6 +170,6 @@ The following list shows the possible outputs when casting a value to an incompa 1. Casting non-array values as array (`arr()`) will return an array with the value as the content. 2. Casting non-map values as map (`as_map()`) will return a map with the value as the content. -3. Casting non-string values to string (`str()`) will return the +3. Casting non-string values to string (`str()`) will return the JSON string representation of the value. 4. Casting non-numeric values to int/float (`int()`/`i64()`/`f32()`/`f64()`) will return zero.