mirror of
https://github.com/vlang/v.git
synced 2025-09-14 23:12:33 +03:00
670 lines
15 KiB
Text
670 lines
15 KiB
Text
// this file is just to test the scanner & parser so there may
|
|
// be a bunch of stuff in here that does not really make sense
|
|
/* multi
|
|
line
|
|
comment */
|
|
/*// nested comment a */
|
|
/* // nested comment b */
|
|
/*/* nested comment c */*/
|
|
[has_globals]
|
|
module main
|
|
|
|
import mod_a
|
|
import mod_b.submod_a
|
|
import mod_c { sym_a, TypeA, TypeB[T] }
|
|
|
|
#include <header_a.h>
|
|
#flag -L lib_a
|
|
__global (
|
|
global_a string
|
|
global_b = 'global_b_value'
|
|
)
|
|
|
|
const (
|
|
const_a = 1
|
|
const_b = 'two'
|
|
)
|
|
// we don't want this parsed as `TypeA[unsafe]`
|
|
__global global_before_fn_with_attr_a TypeA
|
|
|
|
[unsafe]
|
|
pub fn fn_with_attr_after_global_a() {}
|
|
|
|
type AliasA = int
|
|
type SumTypeA = StructA | int | string | []string
|
|
|
|
pub type OptionalA = ?int
|
|
|
|
pub type DatabasePool[T] = fn (tid int) T
|
|
|
|
pub type C.BOOL = bool
|
|
|
|
// we don't want this to be parsed as:
|
|
// `type FnA = fn() fn...`
|
|
type FnA = fn()
|
|
fn fn_after_type_fn_a() int {}
|
|
// we don't want this to be parsed as:
|
|
// `type FnA = fn() ?fn...`
|
|
type FnB = fn() ?
|
|
fn fn_after_type_fn_b() int {}
|
|
|
|
pub const const_array_followed_by_attribute_a = ['a', 'b']
|
|
[attribute_after_array_init]
|
|
fn fn_with_attribute_after_array_init() { println('v') }
|
|
|
|
[attribute_a]
|
|
@[attribute_b]
|
|
enum EnumA {
|
|
value_a [json: 'ValueA']
|
|
value_b @[json: 'ValueB']
|
|
// NOTE: will not work with old attribute syntax due to ambiguity
|
|
value_c = 2 @[json: 'ValueC']
|
|
}
|
|
|
|
enum EnumB as u16 {
|
|
value_a
|
|
value_b
|
|
}
|
|
|
|
[attribute_a: 'attribute_a_val'; attribute_b]
|
|
@[attribute_c: 'attribute_c_val']
|
|
@[attribute_d]
|
|
['/product/edit'; post]
|
|
struct StructA {
|
|
field_a int
|
|
field_b string
|
|
field_c fn(int) int
|
|
field_d string = 'foo'
|
|
field_e int = 1 + 2 + (4*4)
|
|
// NOTE: will not work with old attribute syntax due to ambiguity
|
|
field_f string = 'bar' @[attribute_a; attribute_b]
|
|
field_g int = 111 @[attribute_a; attribute_b]
|
|
field_h int = field_h_default() @[attribute_a]
|
|
}
|
|
|
|
fn StructA.static_method_a() int {
|
|
return 1
|
|
}
|
|
|
|
// TODO: modifiers
|
|
struct StructB {
|
|
StructA // embedded
|
|
mut:
|
|
field_a int [attribute_a: 'value_a']
|
|
field_b string @[attribute_b: 'value_b']
|
|
field_c struct {
|
|
field_a string
|
|
field_b int = 1
|
|
}
|
|
}
|
|
|
|
struct StructC {
|
|
StructA
|
|
foo.StructA
|
|
mut: // TODO: modifiers
|
|
field_a int
|
|
field_b string
|
|
}
|
|
|
|
struct StructD {
|
|
field_a shared int
|
|
field_b shared []int = [0]
|
|
}
|
|
|
|
struct StructD {
|
|
field_a ?&StructD
|
|
}
|
|
|
|
struct C.StructA {}
|
|
|
|
interface InterfaceA {
|
|
field_a string
|
|
method_a() string
|
|
method_b(string) string
|
|
}
|
|
|
|
// TODO: modifiers
|
|
interface InterfaceB {
|
|
InterfaceA // embedded
|
|
mut:
|
|
method_a(string) string
|
|
}
|
|
|
|
interface InterfaceGenericA[T] {
|
|
field_a T
|
|
}
|
|
|
|
fn C.external_fn_a(arg_a int) int
|
|
|
|
__global total_m = 0
|
|
[unsafe]
|
|
fn fn_with_comment_and_attribute_a() {}
|
|
|
|
[attribute_a: 'attribute_a_val'; attribute_b]
|
|
[attribute_c: 'attribute_c_val']
|
|
[attribute_d]
|
|
fn fn_a(arg_a string, arg_b int) int {
|
|
println('fn_a($arg_a, $arg_b)')
|
|
return 1
|
|
}
|
|
|
|
// TODO: error on missing name/type
|
|
// fn fn_b(arg_a string, arg_b, arg_c, arg_d int) int {
|
|
fn fn_b(arg_a string, arg_b int, arg_c int, arg_d int) int {
|
|
println('fn_b($arg_a, $arg_b, $arg_c, $arg_d)')
|
|
return 1
|
|
}
|
|
|
|
fn fn_c(arg_a [][]StructA, arg_b [4]StructA) [][]StructA {
|
|
println('fn_b($arg_a, $arg_b)')
|
|
return arg_a
|
|
}
|
|
|
|
fn fn_d(arg_a GenericStructA[int], arg_b moda.GenericStructA[int]) {
|
|
println('fn_d($arg_a, $arg_b)')
|
|
}
|
|
|
|
fn C.fn_d(GenericStructA[int], moda.GenericStructA[int])
|
|
|
|
fn fn_optional_a() ?int {
|
|
return 1
|
|
}
|
|
|
|
fn fn_optional_b() ?int {
|
|
return fn_optional_a()?
|
|
}
|
|
|
|
fn fn_optional_c() ?&StructD {
|
|
a := StructD{
|
|
field_a: &StructD{}
|
|
}
|
|
dump(a.field_a)
|
|
dump(a.field_a?.field_a)
|
|
assert a.field_a?.field_a == none
|
|
return a.field_a?
|
|
}
|
|
|
|
fn fn_opt_c() ?int {
|
|
return fn_optional_a()!
|
|
}
|
|
|
|
fn fn_result_a() ! {
|
|
return 1
|
|
}
|
|
|
|
fn fn_result_b() !int {
|
|
return 1
|
|
}
|
|
|
|
|
|
fn fn_multi_return_a() (int, int) {
|
|
return 1,2
|
|
}
|
|
|
|
fn fn_multi_return_optional_a() ?(int, int) {
|
|
return 1,2
|
|
}
|
|
|
|
fn fn_variadic_a(arg_a int, arg_b ...string) {
|
|
fn_variadic_b(...arg_b)
|
|
fn_variadic_b(...['a', 'b', 'c', 'd'])
|
|
}
|
|
|
|
fn fn_variadic_b(arg_a ...string) {
|
|
println(arg_a)
|
|
}
|
|
|
|
fn fn_arg_struct_int_a(arg_a StructA, arg_b int) {
|
|
println(arg_a)
|
|
}
|
|
|
|
fn (rec &StructA) method_a(arg_a string, arg_b int) int {
|
|
println('StructA.method_a($arg_a, $arg_b)')
|
|
return 1
|
|
}
|
|
|
|
// TODO: operator overload (last missing parser feature, I think :D)
|
|
pub fn (a StructA) == (b StructA) bool {
|
|
return a.field_a == b.field_a
|
|
}
|
|
|
|
fn channel_test(arg_a chan string) {
|
|
ch := chan int{cap: 20}
|
|
ch <- 111
|
|
rec := <-ch
|
|
}
|
|
|
|
fn spawn_test() {
|
|
t := spawn fn() {
|
|
for i in 0..100 {
|
|
println('$i...')
|
|
}
|
|
}()
|
|
t.wait()
|
|
}
|
|
|
|
fn fn_result_a() !int {
|
|
array_a := [1,2,3,4]
|
|
return array_a[0]!
|
|
}
|
|
|
|
fn main_a() {
|
|
a := 1
|
|
b, c := 1, 2
|
|
array_init_a := [1,2,3,4]
|
|
array_init_b := [1,2,3,4]!
|
|
array_init_c := [array_init_a]
|
|
array_init_d := []string{len: 2, cap: 2}
|
|
array_init_e := [][]string{}
|
|
array_init_f := [2][]int{init:[1]}
|
|
array_init_g := [2][][][][]int{}
|
|
array_init_h := [2][][][][2]int{}
|
|
// TODO: better error for missing `]`
|
|
// array_init_i := [['a','b','c','d']
|
|
array_init_i := [['a','b','c','d']]
|
|
array_init_j := []&StructA{}
|
|
array_init_k := [fn(arg_a int) int { return 1 }]
|
|
array_init_i := [fn() int { return 1 }()]
|
|
array_init_thread_a := []thread int{cap: 16}
|
|
expr_a expr_b // TODO: error ?
|
|
expr_a; expr_b // TODO: error
|
|
map_init_long_string_string := map[string]string{}
|
|
map_init_long_string_array_string := map[string][]string{}
|
|
mut map_init_short_string_string := {'key_a': 'value_a'}
|
|
map_init_short_string_string = {} // test empty
|
|
map_init_short_string_array_string := {'key_a': ['value_a', 'value_b']}
|
|
map_init_short_ident_string := {key_a: 'value_a'} // unsupported key type
|
|
mut map_init_short_enum_value_init_expr := map[EnumA]StructA{}
|
|
// make sure we don't chain `StructA{field_a: 1}.value_b` as SelectorExpr
|
|
map_init_short_enum_value_init_expr = {
|
|
.value_a: StructA{
|
|
field_a: 1
|
|
}
|
|
.value_b: StructA{
|
|
field_a: 1
|
|
}
|
|
.value_c: StructA{
|
|
field_a: 1
|
|
}
|
|
}
|
|
struct_init_a := StructA{field_a: 1, field_b: 'v'}
|
|
struct_init_b := foo.StructA{field_a: 1, field_b: 'v'}
|
|
struct_init_c := StructA{1, 'v'}
|
|
// NOTE: no longer supported. will error
|
|
// assoc_old_a := {struct_a|field_a: 111}
|
|
// assoc_old_b := {
|
|
// ...struct_a
|
|
// field_a: 1
|
|
// }
|
|
assoc_current_a := StructA{
|
|
...struct_a
|
|
// field_a: 1
|
|
}
|
|
string_literal_v_a := 'string literal a'
|
|
string_literal_v_b := "string literal b"
|
|
string_literal_c_a := c'c string literal a'
|
|
string_literal_raw_a := r'string $literal raw a'
|
|
thred_init_a := thread int{cap: 20}
|
|
call_a := fn_a('string', 1)
|
|
call_b := fn_b('string', 1, a, b)
|
|
call_c := array_init_g[0](1)
|
|
call_d := struct_a.method_a('string', 1)
|
|
call_e := struct_a.field_c(1)
|
|
call_f := array_init_k[0]()
|
|
call_g := array_init_k[fn() { return 0 }()]()
|
|
call_h := array_init_k[array_init_b[0]]()
|
|
call_config_syntax_a := fn_arg_struct_int_a(field_a: 1, field_b: 'b', 2)
|
|
call_lambda_expr_a := array_init_a.sorted(|x,y| x > y)
|
|
call_lambda_expr_b := f(|| 1)
|
|
call_selector_a := 'hello v world'
|
|
.split(' v ')
|
|
.join(' ')
|
|
call_comptime_a := $fn_a('string', 1)
|
|
// comptime call as expr stmt only
|
|
$fn_a('string', 1)
|
|
$compile_warn('compile warn')
|
|
cast_a := u8(1)
|
|
cast_b := &[]u8([1,2,3,4])
|
|
// the following casts should error later about not being
|
|
// able to cast array types, unless it gets implemented.
|
|
cast_c := []u8([1,2,3,4])
|
|
cast_d := [][][]u8([[[1,2,3,4]]])
|
|
cast_d := ?&?int(a)
|
|
fn_literal_a := fn(param_a int, param_b int) int {
|
|
return param_a+param_b
|
|
}
|
|
fn_literal_call_a := fn_literal_a(2, 4)
|
|
fn_literal_direct_call_a := fn(param_a int, param_b int) int {
|
|
return param_a+param_b
|
|
}(2, 4)
|
|
fn_literal_capturing_vars_a := fn [infix_a, infix_b] (param_a int, param_b int) int {
|
|
return (infix_a+infix_b)*(param_a+param_b)
|
|
}
|
|
fn_literal_capturing_vars_direct_call_a := fn [infix_a, infix_b] (param_a int, param_b int) int {
|
|
return (infix_a+infix_b)*(param_a+param_b)
|
|
}(2, 4)
|
|
index_a := array_init_a[0]
|
|
index_a := array_init_a[a]
|
|
index_b := struct_a.field_b[1]
|
|
index_c := [StructA{}][0] // direct index after init
|
|
index_d := [[1,2,3,4]][0][1] // unlimited chaining (add more examples)
|
|
index_e := [fn() []StructA { return [fn() []StructA { return [StructA{}] }()][0] }()[0]][0] // more chaining
|
|
index_f := fn() []string { return ['a', 'b'] }()[0]
|
|
index_g := array_init_e[0] or { ['e', 'f'] }[0]
|
|
index_range_a := array_init_a[0..2]
|
|
index_range_b := array_init_a[2..]
|
|
index_range_c := array_init_a[..2]
|
|
index_range_d := array_init_a[1+2..1+2]
|
|
index_range_e := array_init_a[1+2..]
|
|
index_range_f := array_init_a[..1+2]
|
|
index_range_g := array_init_a[1+2...1+2]
|
|
index_range_h := array_init_a[1+2...]
|
|
index_range_i := array_init_a[...1+2]
|
|
index_range_j := [[1,2,3,4]][0][2..4]
|
|
index_range_k := [[1,2,3,4]][0][2...4]
|
|
index_or_a := array_init_a[0] or { 1 }
|
|
index_or_b := array_init_c[0] or { [5,6,7,8] }[0]
|
|
index_or_c := fn() []int { return [array_init_a[0] or { 1 }] }()[0] or { 1 }
|
|
index_or_d := match index_a {
|
|
int { array_init_a }
|
|
else { [5,6,7,8] }
|
|
}[0] or { 1 }
|
|
infix_a := 1 * 2
|
|
infix_b := 1 + 2 * 3 / 4 + 5
|
|
infix_c := infix_a * 4 * 2 + 11 / 2
|
|
infix_d := a == b && c == d
|
|
infix_and_paren_expr_a := ((((infix_b + 1) * 2) + 111) * 2) / 2
|
|
infix_and_paren_expr_b := (((((x * array_init_a[0] +
|
|
array_init_a[1]) * x + array_init_a[2]) * x + array_init_a[3]) * x +
|
|
array_init_a[4]) * x + array_init_a[5]) * x + array_init_a[6]
|
|
prefix_a := &StructA{}
|
|
prefix_b := &&StructA{}
|
|
prefix_c := -infix_a + 2
|
|
prefix_optional_a := ?mod_a.StructA{}
|
|
prefix_optional_b := ?mod_a.StructA(none)
|
|
assert a == 1
|
|
assert a == 1, 'a does not equal 1'
|
|
assert c <= 2, 'c is greater than 2'
|
|
if val := array_init_a[0] {
|
|
println(val)
|
|
}
|
|
if res_a := fn_optional_a() {
|
|
println('if guard: $res_a')
|
|
}
|
|
if res_a, res_b := fn_multi_return_optional_a() {
|
|
println('if guard: $res_a, $res_b')
|
|
}
|
|
if res_a, res_b := fn_optional_a(), fn_optional_b() {
|
|
println('if guard: ${res_a}, ${res_b}')
|
|
}
|
|
if err == IError(MyError{}) {
|
|
println('err == IError(MyError{})')
|
|
}
|
|
if struct_init_a == (StructA{}) {
|
|
println('struct_init_a == (StructA{})')
|
|
}
|
|
// TODO: tricky
|
|
// if struct_init_a == StructA{} {
|
|
// println('struct_init_a == StructA{}')
|
|
// }
|
|
// if StructA{} == StructA{} {
|
|
// println('StructA{} == StructA{}')
|
|
// }
|
|
// if struct_init_a is StructA {
|
|
// println(1)
|
|
// }
|
|
if struct_init_a is []StructA {
|
|
println(1)
|
|
}
|
|
if a == 1 {
|
|
println('1 a == $s')
|
|
}
|
|
else if a == 2 {
|
|
println('2 a == $s')
|
|
}
|
|
else {
|
|
println('a == $s')
|
|
}
|
|
if (if a > 0 {
|
|
1
|
|
} else {
|
|
2
|
|
}) < 2 {
|
|
println('if expr in if cond < 2')
|
|
}
|
|
if a > 0 { StructA{} } else { StructB{} }.method_a()
|
|
$if linux {
|
|
println('linux')
|
|
}
|
|
$else $if windows {
|
|
println('windows')
|
|
}
|
|
$else {
|
|
println('other')
|
|
}
|
|
$if option_a ? {
|
|
println('custom option: `v -d option_a`')
|
|
}
|
|
$if T is $array {
|
|
println('T is array')
|
|
}
|
|
$else $if T is $struct {
|
|
println('T is struct')
|
|
}
|
|
$if T in [?int, ?int] {
|
|
println('option int')
|
|
}
|
|
for val_a in array_init_a {
|
|
println(val_a)
|
|
}
|
|
// TODO: error (unless first 2 are allowed? 0..10 and 0..infinity)
|
|
// the third one definitely needs to error
|
|
// for val_a in ..10 {}
|
|
// for val_a in 0.. {}
|
|
// for val_a in .. {}
|
|
for val_a in 0..10 {
|
|
println(val_a)
|
|
}
|
|
for key_a, val_a in array_init_a {
|
|
println(key_a)
|
|
println(val_a)
|
|
}
|
|
for key_a, mut val_a in array_init_a {
|
|
println(key_a)
|
|
println(val_a)
|
|
}
|
|
for idx_a in 0 .. a + 1 {
|
|
println(idx_a)
|
|
}
|
|
for key, value in {
|
|
'a': 'apple'
|
|
'b': 'bananna'
|
|
} {
|
|
println('${key}: ${value}')
|
|
}
|
|
for mut left_node is ast.InfixExpr {
|
|
if left_node.op == .and && mut left_node.right is ast.InfixExpr {
|
|
if left_node.right.op == .key_is {
|
|
println('xx')
|
|
}
|
|
}
|
|
}
|
|
for a:=0; a<=100; a++ {
|
|
println(a)
|
|
}
|
|
for mut a:=0; a<=100; {
|
|
a++
|
|
println(a)
|
|
}
|
|
for a, b := 0, 1; a < 4; a++ {
|
|
println('$a - $b')
|
|
}
|
|
for a, b, c, d := 0, 1, 2, 3; a < 4; a++ {
|
|
println('$a - $b')
|
|
}
|
|
// currently erroring in this case
|
|
// for a := 1 {}
|
|
for ; x < 100; {
|
|
println(x)
|
|
}
|
|
for x < 100 {
|
|
println(x)
|
|
}
|
|
for ; ; {
|
|
println('infinite loop')
|
|
}
|
|
for {
|
|
println('infinite loop')
|
|
}
|
|
$for x == 1 {
|
|
println('comptime for')
|
|
}
|
|
$for field in U.fields {
|
|
// TODO: parser needs to handle
|
|
// currently just skipping past
|
|
if val.$(field.name).str() != 'Option(none)' {
|
|
fields_len++
|
|
}
|
|
}
|
|
for_label_a: for i := 4; true; i++ {
|
|
println(i)
|
|
for {
|
|
if i < 7 {
|
|
continue for_label_a
|
|
} else {
|
|
break for_label_a
|
|
}
|
|
}
|
|
}
|
|
// fn literals
|
|
// capture list & generic params
|
|
fn [a, b] [T] () {
|
|
println('captured vars: ${a}, ${b}')
|
|
}[int]()
|
|
// capture list only
|
|
fn [a, b] () {
|
|
println('captured vars: ${a}, ${b}')
|
|
}()
|
|
// generic params only
|
|
fn [T] () {
|
|
println(typeof(T))
|
|
}[int]()
|
|
sumtype_a := SumTypeA(111)
|
|
as_cast_a := sumtype_a as int
|
|
// NOTE: or for as is not currently supported
|
|
// I may remove it unless supported is added
|
|
as_cast_b := sumtype_a as int or {
|
|
println('cast error')
|
|
}
|
|
match sumtype_a {
|
|
StructA { println('StructA') }
|
|
int { println('int') }
|
|
string { println('string') }
|
|
[]string { println('[]string') }
|
|
}
|
|
mut ptr_a := &voidptr(0)
|
|
unsafe {
|
|
*ptr_a = 0
|
|
(*ptr_a) = *ptr_a - 1
|
|
((*ptr_a)) = *ptr_a - 1
|
|
*(ptr_a) = *ptr_a - 1
|
|
*((ptr_a)) = *ptr_a - 1
|
|
(*(ptr_a)) = *ptr_a - 1
|
|
}
|
|
mut ptr_b := &voidptr(0)
|
|
unsafe {
|
|
*ptr_b = 0
|
|
}
|
|
unsafe_a := unsafe { mut d := 1 d++ d }
|
|
unsafe_a := unsafe { mut d := 1; d++; d }
|
|
unsafe_b := unsafe {
|
|
mut d := 1
|
|
d++
|
|
d
|
|
}
|
|
shared array_int_shared_a := []int{}
|
|
shared array_string_shared_a := []String{}
|
|
lock {
|
|
array_int_shared_a << 1
|
|
array_int_shared_a << 2
|
|
}
|
|
lock array_string_shared_a {
|
|
array_string_shared_a << 'a'
|
|
array_string_shared_a << 'b'
|
|
}
|
|
lock array_int_shared; rlock array_string_shared {
|
|
array_int_shared << 3
|
|
println(array_string_shared[0])
|
|
}
|
|
lock a,b; rlock c,d; lock e,f; rlock g,h {
|
|
println('silly lock test')
|
|
}
|
|
fn_a('string', unsafe {*ptr_a})
|
|
{
|
|
block_test_a := 1
|
|
}
|
|
|
|
ch_a := chan int{}
|
|
_ = <-ch_a or {
|
|
println('channel closed')
|
|
}
|
|
select {
|
|
a := <-ch_a
|
|
b := <-ch_a { b+=2 }
|
|
c := <-ch_a or {
|
|
panic('channel closed')
|
|
}
|
|
500 * time.millisecond {
|
|
eprintln('> more than 0.5s passed without a channel being ready')
|
|
}
|
|
}
|
|
__asm {
|
|
ldrex tmp, [addr]
|
|
strex tmp, value, [addr]
|
|
}
|
|
sql := 'test_ident_named_sql'
|
|
db_a := sqlite.connect('db_a') or {
|
|
panic('could not connect to db: ${err}')
|
|
}
|
|
nr_items := sql db {
|
|
select count from items
|
|
}
|
|
users := sql db {
|
|
select from User where name == 'first${user_suffix}'
|
|
}
|
|
|
|
// TODO: REMOVE BELOW - TEMP TESTING OR MOVE TO APPROPRIATE PLACE ABOVE
|
|
|
|
x.member.free()
|
|
x.member.submember1.free()
|
|
x.member.submember1.submember2.free()
|
|
x.y = cmdline.option(current_args, arg, '10').int()
|
|
x.y = cmdline.option(current_args, arg,
|
|
'10').int()
|
|
|
|
assert 'href="${url('/test')}"' == 'href="/test.html"'
|
|
assert '"${show_info('abc')}"' == '"abc"'
|
|
|
|
// TODO: confirm there are no cases where
|
|
// there is ambiguity with `|` infix expr
|
|
// lines_indents := lines
|
|
// .filter(|line| !line.is_blank())``
|
|
// .map(|line| line.indent_width())
|
|
|
|
// TODO:
|
|
for mut x is MyType {
|
|
println(x)
|
|
}
|
|
|
|
ms := t.swatches[name].elapsed().microseconds()
|
|
|
|
if !v.pref.is_bare && v.pref.build_mode != .build_module &&
|
|
v.pref.os in [.linux, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
|
|
}
|
|
|
|
rng.shuffle[T](mut res, config_)!
|
|
|
|
|
|
link_cmd := '${call(it.replace('.c',
|
|
'.o')).join(' ')}'
|
|
}
|