1733 lines
No EOL
30 KiB
Text
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: |