chroma/lexers/testdata/v/v.actual
2025-03-22 20:46:00 +13:00

1733 lines
No EOL
30 KiB
Text

module main
// main module
import os { input, user_os }
import time
import math
type MyTime = time.Time
fn main() {
println('hello world')
println(sub(100, 50))
n := write_log(.return_error) or {
println('Error: $err')
0
}
println('$n bytes written')
// Functions can be passed to other functions
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
})
println(res) // "10"
// You can even have an array/map of functions:
fns := [sqr, cube]
println(fns[0](10)) // "100"
fns_map := {
'sqr': sqr
'cube': cube
}
println(fns_map['cube'](2)) // "8"
}
fn add(x int, y int) int {
return x + y
}
fn sub(x int, y int) int {
return x - y
}
// This is a single line comment.
/*
This is a multiline comment.
/* It can be nested. */
*/
fn foo() (int, int) {
return 2, 3
}
a, b := foo()
println(a) // 2
println(b) // 3
c, _ := foo() // ignore values using `_`
name := 'Bob'
assert name.len == 3
s := r'hello\nworld'
// all int literals are supported
assert '0xc3'.int() == 195
assert '0o10'.int() == 8
assert '0b1111_0000_1010'.int() == 3850
assert '-0b1111_0000_1010'.int() == -3850
name := 'Bob'
println('Hello, $name!') // Hello, Bob!
x := 123.4567
println('[${x:.2}]')
println('[${x:10}]')
println('[${int(x):-10}]')
println('[${int(x):010}]')
println('[${int(x):b}]')
println('[${int(x):o}]')
println('[${int(x):X}]')
println('[${10.0000:.2}]')
println('[${10.0000:.2f}]')
rocket := `🚀`
assert rocket.bytes() == [u8(0xf0), 0x9f, 0x9a, 0x80]
assert `\x61` == `a`
assert `\141` == `a`
assert `\u0061` == `a`
// multibyte literals work too
assert `\u2605` == `★`
assert `\u2605`.bytes() == [u8(0xe2), 0x98, 0x85]
assert `\xe2\x98\x85`.bytes() == [u8(0xe2), 0x98, 0x85]
assert `\342\230\205`.bytes() == [u8(0xe2), 0x98, 0x85]
a := 0x7B
b := 0b01111011
c := 0o173
num := 1_000_000
three := 0b0_11
float_num := 3_122.55
hexa := 0xF_F
oct := 0o17_3
a := i64(123)
b := u8(42)
c := i16(12345)
f := 1.0
f1 := f64(3.14)
f2 := f32(3.14)
f0 := 42e1 // 420
f1 := 123e-2 // 1.23
f2 := 456e+2 // 45600
mut nums := [1, 2, 3]
nums << 4
println(nums)
nums << [5, 6, 7]
mut names := ['John']
names << 'Peter'
names << 'Sam'
names := ['John', 'Peter', 'Sam']
println('Alex' in names) // "false"
mut nums := [1, 2, 3]
println(nums.len) // "3"
println(nums.cap) // "3" or greater
nums = [] // The array is now empty
println(nums.len) // "0"
mut a := []int{len: 10000, cap: 30000, init: 3}
users := []int{}
mut numbers := []int{cap: 1000}
println(numbers.len) // 0
// Now appending elements won't reallocate
for i in 0 .. 1000 {
numbers << i
}
mut square := []int{len: 6, init: it * it}
// square == [0, 1, 4, 9, 16, 25]
struct Point {
x int
y int
}
struct Line {
p1 Point
p2 Point
}
type ObjectSumType = Line | Point
mut object_list := []ObjectSumType{}
object_list << Point{1, 1}
object_list << Line{
p1: Point{3, 3}
p2: Point{4, 4}
}
dump(object_list)
/*
object_list: [ObjectSumType(Point{
x: 1
y: 1
}), ObjectSumType(Line{
p1: Point{
x: 3
y: 3
}
p2: Point{
x: 4
y: 4
}
})]
*/
mut a := [][]int{len: 2, init: []int{len: 3}}
a[0][1] = 2
nums := [1, 2, 3, 4, 5, 6]
even := nums.filter(it % 2 == 0)
println(even) // [2, 4, 6]
// filter can accept anonymous functions
even_fn := nums.filter(fn (x int) bool {
return x % 2 == 0
})
println(even_fn)
nums := [1, 2, 3]
println(nums.any(it == 2)) // true
println(nums.all(it >= 2)) // false
mut numbers := [1, 3, 2]
numbers.sort() // 1, 2, 3
numbers.sort(a > b) // 3, 2, 1
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
users.sort(a.name > b.name) // reverse sort by User.name string field
custom_sort_fn := fn (a &User, b &User) int {
// return -1 when a comes before b
// return 0, when both are in same order
// return 1 when b comes before a
if a.name == b.name {
if a.age < b.age {
return 1
}
if a.age > b.age {
return -1
}
return 0
}
if a.name < b.name {
return -1
} else if a.name > b.name {
return 1
}
return 0
}
users.sort_with_compare(custom_sort_fn)
nums := [0, 10, 20, 30, 40]
println(nums[1..4]) // [10, 20, 30]
println(nums[..4]) // [0, 10, 20, 30]
println(nums[1..]) // [10, 20, 30, 40]
mut a := [0, 1, 2, 3, 4, 5]
mut b := a[2..4].clone()
a := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
println(a#[-3..]) // [7, 8, 9]
println(a#[-20..]) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
println(a#[-20..-8]) // [0, 1]
println(a#[..-3]) // [0, 1, 2, 3, 4, 5, 6]
// empty arrays
println(a#[-20..-10]) // []
println(a#[20..10]) // []
println(a#[20..30]) // []
files := ['pippo.jpg', '01.bmp', '_v.txt', 'img_02.jpg', 'img_01.JPG']
filtered := files.filter(it#[-4..].to_lower() == '.jpg').map(it.to_upper())
mut fnums := [3]int{} // fnums is a fixed size array with 3 elements.
fnums[0] = 1
fnums[1] = 10
fnums[2] = 100
println(fnums) // => [1, 10, 100]
println(typeof(fnums).name) // => [3]int
anums := fnums[..]
mut m := map[string]int{} // a map with `string` keys and `int` values
m['one'] = 1
m['two'] = 2
println(m['one']) // "1"
println(m['bad_key']) // "0"
println('bad_key' in m) // Use `in` to detect whether such key exists
println(m.keys()) // ['one', 'two']
m.delete('two')
numbers := {
'one': 1
'two': 2
}
println(numbers)
arr := [1, 2, 3]
large_index := 999
val := arr[large_index] or { panic('out of bounds') }
println(val)
// you can also do this, if you want to *propagate* the access error:
val2 := arr[333]?
println(val2)
name := os.input('Enter your name: ')
println('Hello, $name!')
fn (mut t MyTime) century() int {
return int(1.0 + math.trunc(f64(t.year) * 0.009999794661191))
}
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()')
}
a := 10
b := 20
if a < b {
println('$a < $b')
} else if a > b {
println('$a > $b')
} else {
println('$a == $b')
}
num := 777
s := if num % 2 == 0 { 'even' } else { 'odd' }
println(s)
// "odd"
struct Abc {
val string
}
struct Xyz {
foo string
}
type Alphabet = Abc | Xyz
x := Alphabet(Abc{'test'}) // sum type
if x is Abc {
// x is automatically casted to Abc and can be used here
println(x)
}
if x !is Abc {
println('Not Abc')
}
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)
}
}
nums := [1, 2, 3]
println(1 in nums) // true
println(4 !in nums) // true
m := {
'one': 1
'two': 2
}
println('one' in m) // true
println('three' !in m) // true
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] {
// ...
}
mut numbers := [0, 1, 2]
for mut num in numbers {
num++
}
struct SquareIterator {
arr []int
mut:
idx int
}
fn (mut iter SquareIterator) next() ?int {
if iter.idx >= iter.arr.len {
return error('')
}
defer {
iter.idx++
}
return iter.arr[iter.idx] * iter.arr[iter.idx]
}
nums := [1, 2, 3, 4, 5]
iter := SquareIterator{
arr: nums
}
for squared in iter {
println(squared)
}
m := {
'one': 1
'two': 2
}
for key, value in m {
println('$key -> $value')
// Output: one -> 1
// two -> 2
}
mut sum := 0
mut i := 0
for i <= 100 {
sum += i
i++
}
mut num := 0
for {
num += 2
if num >= 10 {
break
}
}
for i := 0; i < 10; i += 2 {
// Don't print 6
if i == 6 {
continue
}
println(i)
}
outer: for i := 4; true; i++ {
println(i)
for {
if i < 7 {
continue outer
} else {
break outer
}
}
}
match os {
'darwin' { println('macOS.') }
'linux' { println('Linux.') }
else { println(os) }
}
s := match number {
1 { 'one' }
2 { 'two' }
else { 'many' }
}
match true {
2 > 4 { println('if') }
3 == 4 { println('else if') }
2 == 2 { println('else if2') }
else { println('else') }
}
enum Color {
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 }
}
}
c := `v`
typ := match c {
`0`...`9` { 'digit' }
`A`...`Z` { 'uppercase' }
`a`...`z` { 'lowercase' }
else { 'other' }
}
enum State {
normal
write_log
return_error
}
// write log file and return number of bytes written
fn write_log(s State) ?int {
mut f := os.create('log.txt')?
defer {
f.close()
}
if s == .write_log {
// `f.close()` will be called after `f.write()` has been
// executed, but before `write_log()` finally returns the
// number of bytes written to `main()`
return f.writeln('This is a log file')
} else if s == .return_error {
// the file will be closed after the `error()` function
// has returned - so the error message will still report
// it as open
return error('nothing written; file open: $f.is_opened')
}
// the file will be closed here, too
return 0
}
[params]
struct ButtonConfig {
text string
is_disabled bool
width int = 70
height int = 20
}
struct Button {
text string
width int
height int
}
fn new_button(c ButtonConfig) &Button {
return &Button{
width: c.width
height: c.height
text: c.text
}
}
button := new_button(text: 'Click me', width: 100)
// the height is unset, so it's the default value
assert button.height == 20
new_button(ButtonConfig{text:'Click me', width:100})
struct Foo {
a int // private immutable (default)
mut:
b int // private mutable
c int // (you can list multiple fields with the same access modifier)
pub:
d int // public immutable (readonly)
pub mut:
e int // public, but mutable only in parent module
__global:
// (not recommended to use, that's why the 'global' keyword starts with __)
f int // public and mutable both inside and outside parent module
}
struct User {
age int
}
fn (u User) can_register() bool {
return u.age > 16
}
user := User{
age: 10
}
println(user.can_register()) // "false"
user2 := User{
age: 20
}
println(user2.can_register()) // "true"
struct Size {
mut:
width int
height int
}
fn (s &Size) area() int {
return s.width * s.height
}
struct Button {
Size
title string
}
mut button := Button{
title: 'Click me'
height: 2
}
button.width = 3
assert button.area() == 6
assert button.Size.area() == 6
mut button := Button{
Size: Size{
width: 3
height: 2
}
}
struct Rgba32_Component {
r byte
g byte
b byte
a byte
}
union Rgba32 {
Rgba32_Component
value u32
}
clr1 := Rgba32{
value: 0x008811FF
}
clr2 := Rgba32{
Rgba32_Component: Rgba32_Component{
a: 128
}
}
sz := sizeof(Rgba32)
unsafe {
println('Size: ${sz}B,clr1.b: $clr1.b,clr2.b: $clr2.b')
}
fn multiply_by_2(mut arr []int) {
for i in 0 .. arr.len {
arr[i] *= 2
}
}
mut nums := [1, 2, 3]
multiply_by_2(mut nums)
println(nums)
// "[2, 4, 6]"
struct User {
name string
age int
is_registered bool
}
fn register(u User) User {
return User{
...u
is_registered: true
}
}
mut user := User{
name: 'abc'
age: 23
}
user = register(user)
println(user)
fn sum(a ...int) int {
mut total := 0
for x in a {
total += x
}
return total
}
println(sum()) // 0
println(sum(1)) // 1
println(sum(2, 3)) // 5
// using array decomposition
a := [2, 3, 4]
println(sum(...a)) // <-- using prefix ... here. output: 9
b := [5, 6, 7]
println(sum(...b)) // output: 18
fn sqr(n int) int {
return n * n
}
fn cube(n int) int {
return n * n * n
}
fn run(value int, op fn (int) int) int {
return op(value)
}
my_int := 1
my_closure := fn [my_int] () {
println(my_int)
}
my_closure() // prints 1
fn new_counter() fn () int {
mut i := 0
return fn [mut i] () int {
i++
return i
}
}
c := new_counter()
println(c()) // 1
println(c()) // 2
println(c()) // 3
mut i := 0
mut ref := &i
print_counter := fn [ref] () {
println(*ref)
}
print_counter() // 0
i = 10
print_counter() // 10
struct Foo {
abc int
}
fn (foo &Foo) bar() {
println(foo.abc)
}
struct Node<T> {
val T
left &Node<T>
right &Node<T>
}
const (
pi = 3.14
world = '世界'
)
const e = 2.71828
struct Color {
r int
g int
b int
}
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)
)
module mymodule
pub const golden_ratio = 1.61803
fn calc() {
println(mymodule.golden_ratio)
}
pub fn say_hi() {
println('hello from mymodule!')
}
fn factorial(n u32) u32 {
if dump(n <= 1) {
return dump(1)
}
return dump(n * factorial(n - 1))
}
fn init() {
// your setup code here ...
}
struct Dog {
breed string
}
fn (d Dog) speak() string {
return 'woof'
}
struct Cat {
breed string
}
fn (c Cat) speak() string {
return 'meow'
}
// unlike Go and like TypeScript, V's interfaces can define fields, not just methods.
interface Speaker {
breed string
speak() string
}
fn main() {
dog := Dog{'Leonberger'}
cat := Cat{'Siamese'}
mut arr := []Speaker{}
arr << dog
arr << cat
for item in arr {
println('a $item.breed says: $item.speak()')
}
}
pub interface Reader {
mut:
read(mut buf []byte) ?int
}
pub interface Writer {
mut:
write(buf []byte) ?int
}
// ReaderWriter embeds both Reader and Writer.
// The effect is the same as copy/pasting all of the
// Reader and all of the Writer methods/fields into
// ReaderWriter.
pub interface ReaderWriter {
Reader
Writer
}
type Filter = fn (string) string
fn filter(s string, f Filter) string {
return f(s)
}
my_filter := Filter(uppercase)
my_filter := uppercase
enum Color {
@none
red
green
blue
}
color := Color.@none
enum Cycle {
one
two
three
}
fn (c Cycle) next() Cycle {
match c {
.one {
return .two
}
.two {
return .three
}
.three {
return .one
}
}
}
mut c := Cycle.one
for _ in 0 .. 10 {
println(c)
c = c.next()
}
struct Empty {}
struct Node {
value f64
left Tree
right Tree
}
type Tree = Empty | Node
// sum up all node values
fn sum(tree Tree) f64 {
return match tree {
Empty { 0 }
Node { tree.value + sum(tree.left) + sum(tree.right) }
}
}
fn main() {
left := Node{0.2, Empty{}, Empty{}}
right := Node{0.3, Empty{}, Node{0.4, Empty{}, Empty{}}}
tree := Node{0.5, left, right}
println(sum(tree)) // 0.2 + 0.3 + 0.4 + 0.5 = 1.4
}
struct Moon {}
struct Mars {}
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!')
}
}
if mut w is Mars {
assert typeof(w).name == 'Mars'
if w.dust_storm() {
println('bad weather!')
}
}
fn (m Moon) moon_walk() {}
fn (m Mars) shiver() {}
fn (v Venus) sweat() {}
fn pass_time(w World) {
match w {
// using the shadowed match variable, in this case `w` (smart cast)
Moon { w.moon_walk() }
Mars { w.shiver() }
else {}
}
}
struct User {
id int
name string
}
struct Repo {
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')
}
fn main() {
repo := Repo{
users: [User{1, 'Andrew'}, User{2, 'Bob'}, User{10, 'Charles'}]
}
user := repo.find_user_by_id(10) or {
println(err) // "User 10 not found"
return
}
println(user.id) // "10"
println(user.name) // "Charles"
}
import net.http
fn f(url string) ?string {
resp := http.get(url)?
return resp.text
}
resp := http.get(url) or { return err }
if resp := http.get('https://google.com') {
println(resp.text) // resp is a http.Response, not an optional
} else {
println(err)
}
fn do_something(s string) !string {
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'
b := do_something('bar') or { 'default' } // b will be 'default'
println(a)
println(b)
struct Repo<T> {
db DB
}
struct User {
id int
name string
}
struct Post {
id int
user_id int
title string
body string
}
fn new_repo<T>(db DB) Repo<T> {
return Repo<T>{db: db}
}
// This is a generic function. V will generate it for every type it's used with.
fn (r Repo<T>) find_by_id(id int) ?T {
table_name := T.name // in this example getting the name of the type gives us the table name
return r.db.query_one<T>('select * from $table_name where id = ?', id)
}
db := new_db()
users_repo := new_repo<User>(db) // returns Repo<User>
posts_repo := new_repo<Post>(db) // returns Repo<Post>
user := users_repo.find_by_id(1)? // find_by_id<User>
post := posts_repo.find_by_id(1)? // find_by_id<Post>
fn compare<T>(a T, b T) int {
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
fn p(a f64, b f64) { // ordinary function without return value
c := math.sqrt(a * a + b * b)
println(c)
}
fn main() {
go p(3, 4)
// p will be run in parallel thread
}
fn get_hypot(a f64, b f64) f64 {
c := sqrt(a * a + b * b)
return c
}
fn main() {
g := go get_hypot(54.06, 2.08) // spawn thread and get handle to it
h1 := get_hypot(2.32, 16.74) // do some other calculation here
h2 := g.wait() // get result from spawned thread
println('Results: $h1, $h2') // prints `Results: 16.9, 54.1`
}
fn task(id int, duration int) {
println('task $id begin')
time.sleep(duration * time.millisecond)
println('task $id end')
}
fn main() {
mut threads := []thread{}
threads << go task(1, 500)
threads << go task(2, 900)
threads << go task(3, 100)
threads.wait()
println('done')
}
fn expensive_computing(i int) int {
return i * i
}
fn main() {
mut threads := []thread int{}
for i in 1 .. 10 {
threads << go expensive_computing(i)
}
// Join all tasks
r := threads.wait()
println('All jobs finished: $r')
}
ch := chan int{} // unbuffered - "synchronous"
ch2 := chan f64{cap: 100} // buffer length 100
ch := chan int{}
ch2 := chan f64{}
// ...
ch.close()
// ...
m := <-ch or {
println('channel has been closed')
}
// propagate error
y := <-ch2 ?
fn main() {
ch := chan f64{}
ch2 := chan f64{}
ch3 := chan f64{}
mut b := 0.0
c := 1.0
// ... setup go threads that will send on ch/ch2
go fn (the_channel chan f64) {
time.sleep(5 * time.millisecond)
the_channel <- 1.0
}(ch)
go fn (the_channel chan f64) {
time.sleep(1 * time.millisecond)
the_channel <- 1.0
}(ch2)
go fn (the_channel chan f64) {
_ := <-the_channel
}(ch3)
select {
a := <-ch {
// do something with `a`
eprintln('> a: $a')
}
b = <-ch2 {
// do something with predeclared variable `b`
eprintln('> b: $b')
}
ch3 <- c {
// do something if `c` was sent
time.sleep(5 * time.millisecond)
eprintln('> c: $c was send on channel ch3')
}
500 * time.millisecond {
// do something if no channel has become ready within 0.5s
eprintln('> more than 0.5s passed without a channel being ready')
}
}
eprintln('> done')
}
struct Abc {
x int
}
a := 2.13
ch := chan f64{}
res := ch.try_push(a) // try to perform `ch <- a`
println(res)
l := ch.len // number of elements in queue
c := ch.cap // maximum queue length
is_closed := ch.closed // bool flag - has `ch` been closed
println(l)
println(c)
mut b := Abc{}
ch2 := chan Abc{}
res2 := ch2.try_pop(mut b) // try to perform `b = <-ch2`
struct St {
mut:
x int // data to be shared
}
fn (shared b St) g() {
lock b {
// read/modify/write b.x
}
}
fn main() {
shared a := St{
x: 10
}
go a.g()
// ...
rlock a {
// read a.x
}
}
import json
struct Foo {
x int
}
struct User {
name string [required]
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, error: $err')
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)?
println(foos[0].x)
println(foos[1].x)
struct User {
name string
score i64
}
mut data := map[string]int{}
user := &User{
name: 'Pierre'
score: 1024
}
data['x'] = 42
data['y'] = 360
println(json.encode(data)) // {"x":42,"y":360}
println(json.encode(user)) // {"name":"Pierre","score":1024}
fn test_hello() {
assert hello() == 'Hello world'
}
import strconv
fn test_atoi() ? {
assert strconv.atoi('1')? == 1
assert strconv.atoi('one')? == 1 // test will fail
}
fn test_subtest() {
res := os.execute('${os.quoted_path(@VEXE)} other_test.v')
assert res.exit_code == 1
assert res.output.contains('other_test.v does not exist')
}
os.execute('${os.quoted_path("{test}. \${another test}. \{and another\}")} other_test.v')
struct RefStruct {
mut:
r &MyStruct
}
[heap]
struct MyStruct {
n int
}
fn main() {
m := MyStruct{}
mut r := RefStruct{
r: &m
}
r.g()
println('r: $r')
}
fn (mut r RefStruct) g() {
s := MyStruct{
n: 7
}
r.f(&s) // reference to `s` inside `r` is passed back to `main() `
}
fn (mut r RefStruct) f(s &MyStruct) {
r.r = s // would trigger error without `[heap]`
}
import sqlite
// sets a custom table name. Default is struct name (case-sensitive)
[table: 'customers']
struct Customer {
id int [primary; sql: serial] // a field named `id` of integer type must be the first field
name string [nonull]
nr_orders int
country string [nonull]
}
db := sqlite.connect('customers.db')?
sql db {
create table Customer
}
// select count(*) from customers
nr_customers := sql db {
select count from Customer
}
println('number of all customers: $nr_customers')
// V syntax can be used to build queries
uk_customers := sql db {
select from Customer where country == 'uk' && nr_orders > 0
}
println(uk_customers.len)
for customer in uk_customers {
println('$customer.id - $customer.name')
}
// by adding `limit 1` we tell V that there will be only one object
customer := sql db {
select from Customer where id == 1 limit 1
}
println('$customer.id - $customer.name')
// insert a new customer
new_customer := Customer{
name: 'Bob'
nr_orders: 10
}
sql db {
insert new_customer into Customer
}
// clearall clears all bits in the array
fn clearall() {
}
// copy_all recursively copies all elements of the array by their value,
// # Some Heading
// if `dupes` is false all duplicate values are eliminated in the process.
// ----------------------------------------
fn copy_all(dupes bool) {
// ...
}
fn main() {
sw := time.new_stopwatch()
println('Hello world')
println('Greeting the world took: ${sw.elapsed().nanoseconds()}ns')
}
// allocate 2 uninitialized bytes & return a reference to them
mut p := unsafe { malloc(2) }
p[0] = `h` // Error: pointer indexing is only allowed in `unsafe` blocks
unsafe {
p[0] = `h` // OK
p[1] = `i`
}
p++ // Error: pointer arithmetic is only allowed in `unsafe` blocks
unsafe {
p++ // OK
}
assert *p == `i`
struct Foo {
a int
b int
}
assert sizeof(Foo) == 8
assert __offsetof(Foo, a) == 0
assert __offsetof(Foo, b) == 4
#flag -lsqlite3
#include "sqlite3.h"
// See also the example from https://www.sqlite.org/quickstart.html
struct C.sqlite3 {
}
struct C.sqlite3_stmt {
}
type FnSqlite3Callback = fn (voidptr, int, &&char, &&char) int
fn C.sqlite3_open(&char, &&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 and leave out the C. prefix
fn C.sqlite3_prepare_v2(&C.sqlite3, &char, int, &&C.sqlite3_stmt, &&char) int
fn C.sqlite3_step(&C.sqlite3_stmt)
fn C.sqlite3_finalize(&C.sqlite3_stmt)
fn C.sqlite3_exec(db &C.sqlite3, sql &char, cb FnSqlite3Callback, cb_arg voidptr, emsg &&char) int
fn C.sqlite3_free(voidptr)
fn my_callback(arg voidptr, howmany int, cvalues &&char, cnames &&char) int {
unsafe {
for i in 0 .. howmany {
print('| ${cstring_to_vstring(cnames[i])}: ${cstring_to_vstring(cvalues[i]):20} ')
}
}
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(c'users.db', &db)
// C.sqlite3_open(db_path.str, &db)
query := 'select count(*) from users'
stmt := &C.sqlite3_stmt(0)
// NB: you can also use the `.str` field of a V string,
// to get its C style zero terminated representation
C.sqlite3_prepare_v2(db, &char(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 := &char(0)
query_all_users := 'select * from users'
rc := C.sqlite3_exec(db, &char(query_all_users.str), my_callback, voidptr(7), &error_msg)
if rc != C.SQLITE_OK {
eprintln(unsafe { cstring_to_vstring(error_msg) })
C.sqlite3_free(error_msg)
}
C.sqlite3_close(db)
}
[export: 'my_custom_c_name']
fn foo() {
}
$if windows {
#include "@VEXEROOT/thirdparty/stdatomic/win/atomic.h"
} $else {
#include "@VEXEROOT/thirdparty/stdatomic/nix/atomic.h"
}
// declare functions we want to use - V does not parse the C header
fn C.atomic_store_u32(&u32, u32)
fn C.atomic_load_u32(&u32) u32
fn C.atomic_compare_exchange_weak_u32(&u32, &u32, u32) bool
fn C.atomic_compare_exchange_strong_u32(&u32, &u32, u32) bool
const num_iterations = 10000000
// see section "Global Variables" below
__global (
atom u32 // ordinary variable but used as atomic
)
fn change() int {
mut races_won_by_change := 0
for {
mut cmp := u32(17) // addressable value to compare with and to store the found value
// atomic version of `if atom == 17 { atom = 23 races_won_by_change++ } else { cmp = atom }`
if C.atomic_compare_exchange_strong_u32(&atom, &cmp, 23) {
races_won_by_change++
} else {
if cmp == 31 {
break
}
cmp = 17 // re-assign because overwritten with value of atom
}
}
return races_won_by_change
}
fn main() {
C.atomic_store_u32(&atom, 17)
t := go change()
mut races_won_by_main := 0
mut cmp17 := u32(17)
mut cmp23 := u32(23)
for i in 0 .. num_iterations {
// atomic version of `if atom == 17 { atom = 23 races_won_by_main++ }`
if C.atomic_compare_exchange_strong_u32(&atom, &cmp17, 23) {
races_won_by_main++
} else {
cmp17 = 17
}
desir := if i == num_iterations - 1 { u32(31) } else { u32(17) }
// atomic version of `for atom != 23 {} atom = desir`
for !C.atomic_compare_exchange_weak_u32(&atom, &cmp23, desir) {
cmp23 = 23
}
}
races_won_by_change := t.wait()
atom_new := C.atomic_load_u32(&atom)
println('atom: $atom_new, #exchanges: ${races_won_by_main + races_won_by_change}')
// prints `atom: 31, #exchanges: 10000000`)
println('races won by\n- `main()`: $races_won_by_main\n- `change()`: $races_won_by_change')
}
import sync
__global (
sem sync.Semaphore // needs initialization in `init()`
mtx sync.RwMutex // needs initialization in `init()`
f1 = f64(34.0625) // explicily initialized
shmap shared map[string]f64 // initialized as empty `shared` map
f2 f64 // initialized to `0.0`
)
fn init() {
sem.init(0)
mtx.init()
}
#flag linux -lsdl2
#flag linux -Ivig
#flag linux -DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=1
#flag linux -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1
#flag linux -DIMGUI_IMPL_API=
#pkgconfig r_core
#pkgconfig --cflags --libs r_core
$if $pkgconfig('mysqlclient') {
#pkgconfig mysqlclient
} $else $if $pkgconfig('mariadb') {
#pkgconfig mariadb
}
#flag -I @VMODROOT/c
#flag @VMODROOT/c/implementation.o
#include "header.h"
fn main() {
// Support for multiple conditions in one branch
$if ios || android {
println('Running on a mobile device!')
}
$if linux && x64 {
println('64-bit Linux.')
}
// Usage as expression
os := $if windows { 'Windows' } $else { 'UNIX' }
println('Using $os')
// $else-$if branches
$if tinyc {
println('tinyc')
} $else $if clang {
println('clang')
} $else $if gcc {
println('gcc')
} $else {
println('different compiler')
}
$if test {
println('testing')
}
// v -cg ...
$if debug {
println('debugging')
}
// v -prod ...
$if prod {
println('production build')
}
// v -d option ...
$if option ? {
println('custom option')
}
}
fn main() {
embedded_file := $embed_file('v.png', .zlib) // compressed using zlib
os.write_file('exported.png', embedded_file.to_string())?
compile_time_env := $env('ENV_VAR')
println(compile_time_env)
}
fn build() string {
name := 'Peter'
age := 25
numbers := [1, 2, 3]
return $tmpl('1.txt')
}
$if linux {
$compile_error('Linux is not supported')
}
eprintln('file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @MOD + '.' + @FN)
import v.vmod
vm := vmod.decode( @VMOD_FILE ) or { panic(err) }
eprintln('$vm.name $vm.version\n $vm.description')
fn main() {
$for field in User.fields {
$if field.typ is string {
println('$field.name is of type string')
}
}
}
struct Vec {
x int
y int
}
fn (a Vec) str() string {
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 main() {
a := Vec{2, 3}
b := Vec{4, 5}
mut c := Vec{1, 2}
println(a + b) // "{6, 8}"
println(a - b) // "{-2, -2}"
c += a
println(c) // "{3, 5}"
}
a := 100
b := 20
mut c := 0
asm amd64 {
mov eax, a
add eax, b
mov c, eax
; =r (c) as c // output
; r (a) as a // input
r (b) as b
}
println('a: $a') // 100
println('b: $b') // 20
println('c: $c') // 120
// [flag] enables Enum types to be used as bitfields
[flag]
enum BitField {
read
write
other
}
fn main() {
assert 1 == int(BitField.read)
assert 2 == int(BitField.write)
mut bf := BitField.read
assert bf.has(.read | .other) // test if *at least one* of the flags is set
assert !bf.all(.read | .other) // test if *all* of the flags is set
bf.set(.write | .other)
assert bf.has(.read | .write | .other)
assert bf.all(.read | .write | .other)
bf.toggle(.other)
assert bf == BitField.read | .write
assert bf.all(.read | .write)
assert !bf.has(.other)
}
// Calling this function will result in a deprecation warning
[deprecated]
fn old_function() {
}
// It can also display a custom deprecation message
[deprecated: 'use new_function() instead']
[deprecated_after: '2021-05-27']
fn legacy_function() {}
// This function's calls will be inlined.
[inline]
fn inlined_function() {
}
// This function's calls will NOT be inlined.
[noinline]
fn function() {
}
[if debug]
fn foo() {
}
fn bar() {
foo() // will not be called if `-d debug` is not passed
}
if x {
// ...
if y {
unsafe {
goto my_label
}
}
// ...
}
my_label: