Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,37 @@
|
||||
module main
|
||||
|
||||
fn main() {
|
||||
a := 1
|
||||
b := [1,2,3,4]
|
||||
// c := b[0
|
||||
|
||||
if x == {}
|
||||
|
||||
as_cast_a := sum_type_a as
|
||||
|
||||
if x == 100 {
|
||||
|
||||
}
|
||||
|
||||
if y == 200 {
|
||||
|
||||
}
|
||||
|
||||
// TODO: check line
|
||||
// arr := [2]{}
|
||||
|
||||
|
||||
|
||||
// for x in 1..10 {
|
||||
// println(x)
|
||||
// }
|
||||
}
|
||||
|
||||
fn fn_a() ? {
|
||||
|
||||
}
|
||||
|
||||
fn fn_b() {
|
||||
a := 1
|
||||
println('hello')
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// End-to-end test for v2's conditional struct field parsing.
|
||||
// Exercises `$if cond { ... }` / `$else $if` / `$else` blocks and the
|
||||
// per-field `@[if cond ?]` attribute. Compiled and run via the v2 binary.
|
||||
|
||||
module main
|
||||
|
||||
struct Container {
|
||||
name string
|
||||
$if !no_log ? {
|
||||
logger string = 'default'
|
||||
}
|
||||
always int = 42
|
||||
$if my_feature ? {
|
||||
feature_val string = 'on'
|
||||
} $else {
|
||||
feature_val string = 'off'
|
||||
}
|
||||
dev_menu string = 'dev' @[if !no_dev_menu ?]
|
||||
never_built string = 'nope' @[if absent_flag ?]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
c := Container{
|
||||
name: 'app'
|
||||
}
|
||||
assert c.name == 'app'
|
||||
assert c.logger == 'default'
|
||||
assert c.always == 42
|
||||
// `my_feature` is not defined → `$else` branch contributes the field.
|
||||
assert c.feature_val == 'off'
|
||||
// `no_dev_menu` is not defined → `!no_dev_menu` is true → field kept.
|
||||
assert c.dev_menu == 'dev'
|
||||
println('conditional_struct_field_test PASS')
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
module main
|
||||
|
||||
struct StructA {}
|
||||
|
||||
fn f[T](x T) {
|
||||
d := x + x
|
||||
println(d)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f(123)
|
||||
f('abc')
|
||||
// f(main)
|
||||
f(StructA{})
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
module main
|
||||
|
||||
fn main() {
|
||||
// generic_fn_a[int](1, 'hello')
|
||||
// generic_fn_b[int, string](1, 'hello')
|
||||
// generic_fn_a(1, 'hello')
|
||||
generic_fn_b(1, 'hello')
|
||||
generic_fn_c(['foo'], {'a': 'apple', 'b': 'bananna'})
|
||||
generic_fn_d(fn(int, string) {
|
||||
println(1)
|
||||
})
|
||||
generic_fn_e(fn(int, fn(map[string]string) string) {
|
||||
println(1)
|
||||
})
|
||||
}
|
||||
|
||||
// fn generic_fn_a[T](param_a T, param_b string) {
|
||||
// println(param_a)
|
||||
// println(param_b)
|
||||
// }
|
||||
|
||||
fn generic_fn_b[T,Y](param_a T, param_b Y) {
|
||||
a := []T{}
|
||||
b := map[T]int{}
|
||||
c := map[T]Y{}
|
||||
dump(a)
|
||||
dump(b)
|
||||
dump(c)
|
||||
}
|
||||
|
||||
fn generic_fn_c[T,Y](param_a []T, param_b map[Y]T) {
|
||||
println(param_a)
|
||||
}
|
||||
|
||||
fn generic_fn_d[T,Y](param_a fn(T, Y)) {
|
||||
println(param_a)
|
||||
}
|
||||
|
||||
fn generic_fn_e[T,Y]( fn(T, fn(map[Y]Y) Y) ) {
|
||||
println(param_a)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
module main
|
||||
|
||||
type Expr = Ident | SelectorExpr
|
||||
|
||||
struct Ident {
|
||||
name string
|
||||
}
|
||||
|
||||
struct SelectorExpr {
|
||||
lhs Expr
|
||||
rhs Expr
|
||||
// op int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := Ident{
|
||||
name: 'foo'
|
||||
}
|
||||
node := Expr(a)
|
||||
if a.name == 'bar' {
|
||||
} else if node !in [Ident, SelectorExpr] {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Module Mutable Fields Example
|
||||
|
||||
This is a V2 fixture for `pub module_mut:` struct fields.
|
||||
|
||||
It demonstrates a field that is public for reading, but mutable only from the
|
||||
module that declares the struct. A separate `pub mut:` field is included to show
|
||||
the difference with a publicly mutable field.
|
||||
|
||||
The sources are stored as `.vv2` so shared V1/vfmt paths do not parse V2-only
|
||||
syntax directly. To try it manually, copy the files to temporary `.v` files and
|
||||
compile them with `-v2`.
|
||||
|
||||
Expected behavior:
|
||||
|
||||
- `counter.value` can be read from `main`;
|
||||
- `counter.value` is changed through `state.Counter.inc()`, inside module
|
||||
`state`;
|
||||
- `counter.label` can be changed from `main` because it is under `pub mut:`;
|
||||
- direct external mutation like `counter.value++` must be rejected.
|
||||
@@ -0,0 +1,17 @@
|
||||
module main
|
||||
|
||||
import state
|
||||
|
||||
fn main() {
|
||||
mut counter := state.new_counter('jobs')
|
||||
assert counter.value == 0
|
||||
assert counter.inc() == 1
|
||||
assert counter.inc() == 2
|
||||
assert counter.value == 2
|
||||
|
||||
counter.label = 'builds'
|
||||
assert counter.label == 'builds'
|
||||
|
||||
// This must stay rejected outside module `state`:
|
||||
// counter.value++
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
module state
|
||||
|
||||
pub struct Counter {
|
||||
pub module_mut:
|
||||
value int
|
||||
pub mut:
|
||||
label string
|
||||
}
|
||||
|
||||
pub fn new_counter(label string) Counter {
|
||||
return Counter{
|
||||
label: label
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Counter) inc() int {
|
||||
c.value++
|
||||
return c.value
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Module Storage Example
|
||||
|
||||
This is a V2 fixture for module-scoped `__global` storage.
|
||||
|
||||
It is intentionally stored as `.vv2` source so shared V1/vfmt paths do not parse
|
||||
V2-only public module-storage syntax directly. The regression test copies these
|
||||
files to temporary `.v` files and compiles them with `-v2`.
|
||||
|
||||
Run:
|
||||
|
||||
```sh
|
||||
./v test vlib/v2_toberemoved/types/module_storage_test.v
|
||||
```
|
||||
@@ -0,0 +1,12 @@
|
||||
module main
|
||||
|
||||
import state
|
||||
|
||||
fn main() {
|
||||
assert state.total_ticks == 0
|
||||
assert state.tick() == 1
|
||||
assert state.tick() == 2
|
||||
state.total_ticks += 10
|
||||
assert state.total_ticks == 12
|
||||
assert state.private_tick_count() == 2
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
module state
|
||||
|
||||
__global mut private_ticks = 0
|
||||
pub __global mut total_ticks = 0
|
||||
|
||||
fn bump_private() {
|
||||
private_ticks += 1
|
||||
}
|
||||
|
||||
pub fn tick() int {
|
||||
bump_private()
|
||||
total_ticks += 1
|
||||
return private_ticks
|
||||
}
|
||||
|
||||
pub fn private_tick_count() int {
|
||||
return private_ticks
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
module main
|
||||
|
||||
struct StructA {
|
||||
name string = 'struct a'
|
||||
b StructB = StructB{}
|
||||
}
|
||||
|
||||
struct StructB {
|
||||
name string = 'struct b'
|
||||
c StructC = StructC{}
|
||||
}
|
||||
|
||||
struct StructC {
|
||||
name string = 'struct c'
|
||||
d StructD = StructD{}
|
||||
}
|
||||
|
||||
struct StructD {
|
||||
name string = 'struct d'
|
||||
e StructE = StructE{}
|
||||
}
|
||||
|
||||
struct StructE {
|
||||
name string = 'struct e'
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := StructA{}
|
||||
e := a.b.c.d.e
|
||||
println(e.name)
|
||||
println(a.b.c.d.e.name)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
module main
|
||||
|
||||
fn test_main() {
|
||||
string_literal_raw_a := r'raw string Literal b'
|
||||
string_literal_inter_a := 'a == abc${a:2f} && and b == abc${b}...'
|
||||
string_literal_inter_b := '${@MOD}.${@METHOD} - ${fn_call(unsafe { 1 })}'
|
||||
string_literal_inter_c := '${mod.fn_call(1)} | ${mod.fn_call('a').join(' ')} > out'
|
||||
// NOTE: d) tests nested quotes of same kind (although why is this allowed?)
|
||||
string_literal_inter_d := '${mod.fn_call(1)} | ${mod.fn_call(unsafe { 1 }, mod.fn_call('a')).join(' ')} > out'
|
||||
string_literal_inter_e := '${mod.fn_call(1)} | ${mod.fn_call(mod.fn_call('a')).join(' ')} > out'
|
||||
// TODO: remember to talk to alex to confirm behaviour of nested strings
|
||||
// x := 'hello ${foo('${x}')} ${x}'
|
||||
}
|
||||
|
||||
fn test_basic() {
|
||||
pi := 3.14159265359
|
||||
pi_name := 'Pi'
|
||||
pi_symbol := `π`
|
||||
pi_description := '${pi_name} (${pi_symbol}) is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, approximately equal ${pi:.5}.'
|
||||
}
|
||||
@@ -0,0 +1,670 @@
|
||||
// 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(' ')}'
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// this file is just to test the parser so there may be a
|
||||
// bunch of stuff in here that does not really make sense
|
||||
|
||||
const len_a = 6
|
||||
struct StructA {
|
||||
// NOTE: ideally attributes would not use `[]`
|
||||
// it would eliminate these issues completely.
|
||||
|
||||
// ambiguous: return `!` followed by attribute or
|
||||
// result w/ fixed array `![attribute_a]func_b`?
|
||||
// rely on newline and space between `!` and `[`,
|
||||
// or check later if we are using a var or const?
|
||||
// try eliminate this type of thing from the syntax.
|
||||
// TODO/FIXME: currently broken, must fix.
|
||||
func_a fn() ! [attribute_a]
|
||||
// this is fine
|
||||
func_b fn() ![len_a]u8
|
||||
|
||||
// fixed - parse as attribute, not as index of `'foo'`
|
||||
field_c string = 'foo' [attribute_a]
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// this file is just to test the parser so there may be a
|
||||
// bunch of stuff in here that does not really make sense
|
||||
module main
|
||||
|
||||
struct GenericStructA[T] {
|
||||
field_a T
|
||||
}
|
||||
|
||||
struct GenericStructB[T,U] {
|
||||
field_a T
|
||||
field_b U
|
||||
}
|
||||
|
||||
fn fn_generic_a[T](param_a T, param_b string, param_c int) int {
|
||||
println('fn_generic_a: ${param_a.type}, ${param_b.type}, ${param_c.type}')
|
||||
return 1
|
||||
}
|
||||
|
||||
fn fn_generic_b[T,Y](param_a T, param_b Y) int {
|
||||
println('fn_generic_a: ${param_a.type}, ${param_b.type}')
|
||||
}
|
||||
|
||||
fn fn_generic_c[fn[U,I](U, I) U, Y](param_a T, param_b Y) int {
|
||||
println('fn_generic_c')
|
||||
return 1
|
||||
}
|
||||
|
||||
fn test_generic_struct_init() {
|
||||
a := GenericStructA[int] {
|
||||
field_a: 1
|
||||
}
|
||||
}
|
||||
|
||||
fn fn_generic_init_a[T](param_a T) {
|
||||
// TODO: infer correct init after type checking
|
||||
// eg. array, chan, map, or struct init.
|
||||
mut a := T{}
|
||||
for k, v in param_a {
|
||||
a[k] = v
|
||||
}
|
||||
println(a)
|
||||
}
|
||||
|
||||
fn test_generic_init() {
|
||||
fn_generic_init_a[map[string]string]({'a': 'apple'})
|
||||
}
|
||||
|
||||
// assoc works with generic structs although
|
||||
// this will probably never be supported or used
|
||||
fn test_generic_assoc() {
|
||||
struct_a := GenericStructB[int,int]{field_a: 1, field_b: 2}
|
||||
assoc_struct_b := GenericStructB[int,int]{
|
||||
...struct_b
|
||||
field_a: 10
|
||||
field_b: 20
|
||||
}
|
||||
}
|
||||
|
||||
fn test_generic_call() {
|
||||
call_generic_a := fn_generic_a[GenericStructA](GenericStructA{}, 'string', 1)
|
||||
fn_generic_b[int,int](1,2)
|
||||
}
|
||||
|
||||
fn test_generic_complex_or_nested() {
|
||||
fn_generic_c[fn[U,I](U, I) U, I](fn[U,I](param_a U, param_b I) U {}, 1)
|
||||
|
||||
fn_generic_b[GenericStructA[Y],int](GenericStructA[int]{}, 1)
|
||||
fn_generic_b[GenericStructA[Y],GenericStructA[Y]](GenericStructA[int]{}, 1)
|
||||
struct_a := GenericStructA[int]{field_a: 1}
|
||||
|
||||
fn_generic_b[[]string,map[string]string{}](1, 1) // TODO: error
|
||||
|
||||
fn_a := fn(param_a string, param_b int, param_c int) {}
|
||||
fn_b := fn(param_a string, param_b int, param_c int) {}
|
||||
fn_c := fn(param_a string, param_b int, param_c int) {}
|
||||
fn_a('a', a < b, a < b, c)
|
||||
fn_a('a', foo: a < b, a < b, c)
|
||||
fn_b('a', fn_generic_c[fn[T,Y](int),int](1))
|
||||
fn_b('a', fn_generic_c[fn[T,Y](int),int](a < if (fn_generic_b[int,int](1,2) > 2) { 1 } else { 2 }, 2), 1)
|
||||
fn_b('a', moda.fn_generic_b[fn[T,Y](int),int](a < if (fn_generic_b[int,int](1,2) > 2) { 1 } else { 2 }, 2), fn_generic_b[int,int](1,2))
|
||||
fn_b('a', modb.submodb.fn_generic_b[int,int](fn_generic_b[int,int](fn_generic_b[int,int](1,2) < (fn_generic_b[int,int](1,2) - 2), 2)),fn_generic_b[int,int](1,2))
|
||||
|
||||
fn_c(fn_generic_b[GenericStructB[int,int]](GenericStructB<int>{}, 1), moda.fn_generic_b[GenericStructB[int,int]](GenericStructB[int]{}, 1))
|
||||
fn_c(a < fn_generic_b[GenericStructB[GenericStructA[int],int]](GenericStructB[int]{}, 1), moda.fn_generic_b[GenericStructB[int,int]](GenericStructB<int>{}, 1))
|
||||
|
||||
// return if x < 64 { fn_generic_b[int,int](1,2) } else { fn_generic_b[int,int](1, 2) < (fn_generic_b[int,int](1, 2) - 2) }
|
||||
return fn_generic_b[int,int](1, 2) < b, c > d, e < f, g > h, fn_generic_b[int,int](fn_generic_b[int,int](fn_generic_b[int,int](1, 2), 2), 2) > j, k < l, m
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Target Codegen Example
|
||||
|
||||
This is a V2 fixture for target-specific `cleanc` generation.
|
||||
|
||||
It is intentionally stored as `.vv2` source so shared V1/vfmt paths do not parse
|
||||
V2-only or experimental command-line contracts directly. The builder E2E test
|
||||
reads these files, writes them as temporary `.v` files, and runs the real
|
||||
`cmd/v2` CLI.
|
||||
|
||||
The fixture is a compact demonstration of the supported user-facing contract:
|
||||
|
||||
- implicit host OS selection when `-os` is omitted;
|
||||
- explicit `-os` overrides for concrete targets;
|
||||
- `-os cross` preserving portable directive guards;
|
||||
- pure `-freestanding -os none` generation with no concrete OS selected;
|
||||
- advanced `-fhooks` isolation with `--skip-builtin --skip-type-check`;
|
||||
- capability-specific `output`, `panic`, and `alloc` hook behavior.
|
||||
|
||||
V2 uses `cleanc` by default. `-b` is only needed when selecting a non-default
|
||||
backend explicitly.
|
||||
|
||||
The regression tests keep unsupported/error-only programs inline in the test
|
||||
file, so this directory stays readable as an example rather than a catalogue of
|
||||
expected failures.
|
||||
|
||||
Fixture roles:
|
||||
|
||||
- `target_directives.vv2`: host/default target and concrete `-os` overrides.
|
||||
- `cross_directives.vv2`: `-os cross` preserving portable directive guards.
|
||||
- `freestanding_directives.vv2`: freestanding target directive selection.
|
||||
- `freestanding_none.vv2`: pure `-freestanding -os none` platform contract.
|
||||
- `freestanding_output.vv2`: `output` hook example.
|
||||
- `freestanding_panic.vv2`: `panic` hook example.
|
||||
- `freestanding_alloc.vv2`: `alloc` hook example.
|
||||
- `freestanding_empty.vv2`: minimal source used for runtime-contract checks.
|
||||
@@ -0,0 +1,8 @@
|
||||
module main
|
||||
|
||||
#include linux <target_marker_linux.h>
|
||||
#include macos <target_marker_macos.h>
|
||||
#include windows <target_marker_windows.h>
|
||||
#include cross <target_marker_cross.h>
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,12 @@
|
||||
module main
|
||||
|
||||
struct Box {
|
||||
value int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
b := &Box{
|
||||
value: 7
|
||||
}
|
||||
_ = b.value
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module main
|
||||
|
||||
#include linux <target_marker_linux.h>
|
||||
#include windows <target_marker_windows.h>
|
||||
#include freestanding <target_marker_freestanding.h>
|
||||
#flag freestanding -DPLATFORM_MARKER_FREESTANDING
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,3 @@
|
||||
module main
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,9 @@
|
||||
module main
|
||||
|
||||
#include freestanding <platform_none.h>
|
||||
#flag freestanding -DPLATFORM_NONE_FREESTANDING
|
||||
fn C.platform_none_tick() int
|
||||
|
||||
fn main() {
|
||||
_ := C.platform_none_tick()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module main
|
||||
|
||||
fn main() {
|
||||
println('x')
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module main
|
||||
|
||||
fn main() {
|
||||
panic('x')
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module main
|
||||
|
||||
#include linux <target_marker_linux.h>
|
||||
#include macos <target_marker_macos.h>
|
||||
#include windows <target_marker_windows.h>
|
||||
#include freestanding <target_marker_freestanding.h>
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,135 @@
|
||||
module main
|
||||
|
||||
fn test_typeof_fn() {
|
||||
assert typeof(fn (s string, x u32) (int, f32)).name == 'fn (string, u32) (int, f32)'
|
||||
}
|
||||
|
||||
fn test_typeof_fn_literal() {
|
||||
assert typeof(fn (i int) int {return i+1}).name == 'TODO'
|
||||
}
|
||||
|
||||
fn test_typeof_int() {
|
||||
assert typeof(int).idx == 7
|
||||
assert typeof(int).name == 'int'
|
||||
}
|
||||
|
||||
fn test_typeof_u32() {
|
||||
assert typeof(u32).idx == 12
|
||||
assert typeof(u32).name == 'u32'
|
||||
}
|
||||
|
||||
fn test_typeof_string() {
|
||||
assert typeof(string).idx == 20
|
||||
assert typeof(string).name == 'string'
|
||||
|
||||
assert typeof[string]().idx == 20
|
||||
}
|
||||
|
||||
fn test_typeof_optional_type() {
|
||||
assert typeof(?string).name == '?string'
|
||||
}
|
||||
|
||||
fn test_typeof_result_type() {
|
||||
assert typeof(!string).name == '!string'
|
||||
}
|
||||
|
||||
fn test_typeof_array_type() {
|
||||
assert typeof([]string).name == '[]string'
|
||||
assert typeof(['a', 'b']).name == '[]string'
|
||||
}
|
||||
|
||||
fn test_typeof_array_index() {
|
||||
assert typeof(['a', 'b'][0]).name == 'string'
|
||||
}
|
||||
|
||||
fn test_typeof_map_type() {
|
||||
assert typeof(map[string]int).name == 'map[string]int'
|
||||
}
|
||||
|
||||
fn test_typeof_nil() {
|
||||
assert typeof(nil).name == 'nil'
|
||||
}
|
||||
|
||||
fn test_typeof_none() {
|
||||
assert typeof(none).name == 'none'
|
||||
}
|
||||
|
||||
fn test_typeof_pointer() {
|
||||
assert typeof(&string).name == '&string'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
struct MyStruct {}
|
||||
|
||||
struct MyGenericStruct[T] {}
|
||||
|
||||
struct MyGenericStruct2[T, U] {}
|
||||
|
||||
fn test_typeof_struct_type() {
|
||||
assert typeof(MyStruct).name == 'MyStruct'
|
||||
assert typeof(MyGenericStruct).name == 'MyGenericStruct'
|
||||
assert typeof(MyGenericStruct[int]).name == 'MyGenericStruct<int>'
|
||||
assert typeof(MyGenericStruct[string]).name == 'MyGenericStruct<string>'
|
||||
assert typeof(MyGenericStruct2).name == 'MyGenericStruct2'
|
||||
assert typeof(MyGenericStruct2[string, int]).name == 'MyGenericStruct2<string, int>'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
union MyUnion {
|
||||
x int
|
||||
s string
|
||||
}
|
||||
|
||||
fn test_typeof_union_type() {
|
||||
assert typeof(MyUnion).name == 'MyUnion'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
type Abc = int | string
|
||||
|
||||
fn test_typeof_sumtype() {
|
||||
assert typeof(Abc).name == 'Abc'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
enum EFoo {
|
||||
a
|
||||
b
|
||||
c
|
||||
}
|
||||
|
||||
fn test_typeof_enum() {
|
||||
assert typeof(EFoo).name == 'EFoo'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
type AnAlias = int
|
||||
|
||||
fn test_typeof_alias() {
|
||||
assert typeof(AnAlias).name == 'AnAlias'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
fn abc[T](x T) string {
|
||||
return typeof(T).name
|
||||
}
|
||||
|
||||
fn test_typeof_generic_type() {
|
||||
assert abc<int>(123) == 'int'
|
||||
assert abc<string>('xyz') == 'string'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
fn test_typeof_idx_comparison() {
|
||||
i := 123
|
||||
u := u32(5)
|
||||
assert typeof(int).idx == typeof(i).idx
|
||||
assert typeof(u32).idx == typeof(u).idx
|
||||
}
|
||||
Reference in new issue
Block a user