1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

compiler: make compiler an ordinary vlib/compiler module

* Move compiler/ under vlib/compiler/ .

* Add a minimal compiler/main.v driver program.

* Cleanup compiler/main.v .

* Make most compiler tests pass again.

* Apply the fix by @joe-conigliaro , so that the rest of the compiler tests are fixed too.

* Thanks to @avitkauskas, now the vlib/vcompiler/tests/str_gen_test.v test does not need to be special cased anymore.

* Reapply @joe-conigliaro fix for vgen.
This commit is contained in:
Delyan Angelov
2019-10-13 16:37:43 +03:00
committed by Alexander Medvednikov
parent 59d4535f84
commit 53c64abdeb
71 changed files with 1095 additions and 1080 deletions

View File

@@ -0,0 +1,21 @@
#include <stdio.h>
int increment_val(int n) {
return n + 2;
}
// ~26% faster
void increment_ptr(int* n) {
*n += 2;
}
int main() {
int n = 0;
for (int i = 0; i < 1000000000; i++) {
n = increment_val(n);
//increment_ptr(&n);
}
printf("%d\n", n);
return 0;
}

View File

@@ -0,0 +1,51 @@
fn foo() string {
println('foo()')
return 'foo'
}
fn foo2() string {
println('start')
defer { println('defer') }
defer { println('defer2') }
println('end')
return foo()
}
fn test_defer() {
assert foo2() == 'foo'
}
fn set_num(i int, n mut Num) {
defer { n.val+=1 }
println("Hi")
if i < 5 {
return
} else {
n.val+=1
}
}
fn set_num_opt(n mut Num) ?int {
defer { n.val = 1 }
return 99
}
struct Num {
mut:
val int
}
fn test_defer_early_exit() {
mut sum := Num{0}
for i in 0..10 {
set_num(i, mut sum)
}
println("sum: $sum.val")
assert sum.val == 15
}
fn test_defer_option() {
mut ok := Num{0}
set_num_opt(mut ok)
assert ok.val == 1
}

View File

@@ -0,0 +1,24 @@
enum Color {
red
blue
green
}
fn test_enum() {
assert Color.red == Color.red
assert Color.blue == Color.blue
assert Color.green == Color.green
assert Color.red == .red
assert Color.blue == .blue
assert Color.green == .green
assert Color.red != Color.blue
assert Color.red != Color.green
assert Color.blue != Color.green
mut color := Color.red
assert color == Color.red
color = .green
assert color == Color.green
}

View File

@@ -0,0 +1,32 @@
fn test_fixed_array_can_be_assigned(){
x := 2.32
mut v := [8]f32
v = [1.0, x, 3.0,4.0,5.0,6.0,7.0,8.0]!!
assert v[1] == x
}
fn test_fixed_array_can_be_used_in_declaration(){
x := 2.32
v := [1.0, x, 3.0,4.0,5.0,6.0,7.0,8.0]!!
assert v[1] == x
}
struct Context {
pub mut:
vb [8]f32
}
fn test_fixed_array_can_be_assigned_to_a_struct_field(){
mut ctx := Context{}
x := 2.32
ctx.vb = [1.1, x, 3.3, 4.4, 5.0, 6.0, 7.0, 8.9]!!
assert ctx.vb[1] == x
assert ctx.vb[7] == 8.9
/*
println( ctx.vb[0] )
println( ctx.vb[1] )
println( ctx.vb[2] )
println( ctx.vb[3] )
*/
}

View File

@@ -0,0 +1,19 @@
struct UserData {
test string
}
fn test_fn_multiple_returns() {
name, age, groups, data := fn_mr_get_user()
assert name == 'joe'
assert age == 34
assert groups[0] == 'admins'
assert groups[1] == 'users'
assert data.test == 'Test Data'
println('name: $name | age: $age | groups: ' + groups.join(',') + ' | data: $data.test')
}
fn fn_mr_get_user() (string, int, []string, UserData) {
groups := ['admins', 'users']
data := UserData{test: 'Test Data'}
return 'joe',34,groups,data
}

View File

@@ -0,0 +1,121 @@
// 1 line comment
/* 1 line comment */
/*
multi line comment (1)
multi line comment (2)
multi line comment (3)
*/
/*
multi line comment (1)
/*
nested comment
*/
/*nested comment*/
/*nested comment
*/
/* nested comment */
/* /* nested comment */ */
multi line comment (2)
*/
type myfn fn (int) string
type myfn2 fn (a int, b int) int
type myfn3 fn (int, int)
fn myfn4(string)
fn foobar()
fn slopediv(num u32, den u32) int
type f1 fn ()
type f2 fn (voidptr)
type f3 fn (voidptr, voidptr)
type f4 fn (voidptr) int
type f5 fn (int, int) int
type f6 fn (int, int)
fn C.atoi(byteptr) int
fn foo() {
}
type actionf_v fn ()
type actionf_p1 fn (voidptr)
type actionf_p2 fn (voidptr, voidptr)
// TODO
fn modify_array(a mut []int) {
a[0] = 10
for i in 0..a.len {
a[i] = a[i] * 2
}
//a << 888
}
fn test_mut_array() {
mut nums := [1, 2, 3]
modify_array(mut nums)
//assert nums.len == 4
// println(nums)
assert nums[0] == 20
assert nums[1] == 4
assert nums[2] == 6
//assert nums[3] == 888
// workaround for // [91, 32, -33686272] windows bug
println(nums.clone())
}
fn mod_struct(user mut User) {
user.age++
}
struct User {
mut:
age int
}
fn test_mut_struct() {
mut user := User{18}
mod_struct(mut user)
assert user.age == 19
}
fn mod_ptr(buf mut byteptr) {
buf[0] = 77
}
fn test_mut_ptr() {
buf := malloc(10)
mod_ptr(mut buf)
assert buf[0] == 77
}
fn high_fn(f fn(int) int) {
}
fn high_fn_array(f fn(a []int) []int) {
}
fn high_fn_multi_return(a int, b fn (c []int, d []string) ([]int, []string)) {
}
fn test_fns() {
// no asserts for now, just test function declarations above
}

View File

@@ -0,0 +1,15 @@
struct VaTestGroup {
name string
}
fn variadic_test_a(name string, groups ...VaTestGroup) {
assert groups.len == 2
assert groups[0].name == 'users'
assert groups[1].name == 'admins'
}
fn test_fn_variadic() {
group1 := VaTestGroup{name: 'users'}
group2 := VaTestGroup{name: 'admins'}
variadic_test_a('joe', group1, group2)
}

View File

@@ -0,0 +1,32 @@
struct Dog {
breed string
}
fn (d Dog) speak() {
println('dog.speak()')
}
fn (d Dog) name() string {
return 'old gray'
}
interface Speaker {
name() string
speak()
}
interface Speak2er {
speak()
name() string
}
fn perform_speak(s Speaker) bool {
s.speak()
return true
}
fn test_perform_speak() {
d := Dog{}
assert perform_speak(d)
}

View File

@@ -0,0 +1,7 @@
module local
pub fn local_fn() bool {
return true
}

View File

@@ -0,0 +1,7 @@
import compiler.tests.local
fn test_local_module_is_callable() {
assert local.local_fn()
}

View File

@@ -0,0 +1,88 @@
enum Color{
red, green, blue
}
fn test_match_integers() {
// a := 3
// mut b := 0
// match a {
// 2 => println('two')
// 3 => println('three')
// b = 3
// 4 => println('four')
// else => println('???')
// }
// assert b == 3
assert match 2 {
1 => {2}
2 => {3}
else => {5}
} == 3
assert match 0 {
1 => {2}
2 => {3}
else => 5
} == 5
assert match 1 {
else => {5}
} == 5
mut a := 0
match 2 {
0 => {a = 1}
1 => {a = 2}
else => {
a = 3
println('a is $a')
}
}
assert a == 3
a = 0
match 1 {
0 => {a = 1}
1 => {
a = 2
a = a + 2
a = a + 2
}
}
assert a == 6
a = 0
match 1 {
else => {
a = -2
}
}
assert a == -2
}
fn test_match_enums(){
mut b := Color.red
match b{
.red => {
b = .green
}
.green => {b = .blue}
else => {
println('b is ${b.str()}')
b = .red
}
}
assert b == .green
match b{
.red => {
b = .green
}
else => {
println('b is ${b.str()}')
b = .blue
}
}
assert b == .blue
}

View File

@@ -0,0 +1,18 @@
import os
import time as t
import crypto.sha256 as s2
import (
math
log as l
crypto.sha512 as s5
)
fn test_import() {
assert os.SUCCESS == os.SUCCESS &&
t.month_days[0] == t.month_days[0] &&
s2.Size == s2.Size &&
math.pi == math.pi &&
l.INFO == l.INFO &&
s5.Size == s5.Size
}

View File

@@ -0,0 +1,49 @@
fn test_flag_parsing() {
mut rest := '-lGlfw -f gl2,-ltest_nice_meme,-l cc,-Ldl test.o a.o ' //, whatever.o'
result := ['-l', 'Glfw',
'-f', 'gl2',
'-l', 'test_nice_meme',
'-l', 'cc',
'-L', 'dl',
'', 'test.o',
'', 'a.o']
mut flags := []string
for {
mut base := rest
fl := if rest.starts_with('-') {
base = rest.right(2).trim_space()
rest.left(2)
} else {
''
}
// Which ever one of these is lowest we use
// TODO: we really shouldnt support all of these cmon
mut lowest := base.index('-')
for x in [base.index(' '), base.index(',')] {
if (x < lowest && x != -1) || lowest == -1 {
lowest = x
}
}
arg := if lowest != -1 {
rest = base.right(lowest).trim_space().trim(',')
base.left(lowest).trim_space().trim(',')
} else {
rest = ''
base.trim_space()
}
flags << fl
flags << arg
if rest.len == 0 {
break
}
}
for i, f in flags {
assert f == result[i]
}
}

View File

@@ -0,0 +1,52 @@
struct A {
pub mut:
v []int
}
struct B {
pub mut:
a []A
}
fn foo(b int, a mut []int) {
a[0] = 7
//a << 4
}
fn test_mut() {
mut numbers := [1,2,3]
foo(7, mut numbers)
assert numbers.len == 3
// TODO bring back once << works with mutable args
//assert numbers.len == 4
//assert numbers[0] == 7
//assert numbers[3] == 4
println(numbers)
n := 1
mut b := &n
*b = 10
//mut b := mut a
//b = 10
}
fn test_mut_2() {
zero := 0
mut b := B{}
b.a << A{}
b.a[0].v = [9, 8, 7]
b.a[0].v << 6
b.a[zero].v << 5
b.a[0].v[zero] = 3
b.a[0].v[b.a[zero].v[zero]] += 1b.a[0].v[b.a[0].v[zero]] += 1
assert b.a[0].v.len == 5
assert b.a[0].v[0] == 3
assert b.a[0].v[1] == 8
assert b.a[0].v[2] == 7
assert b.a[0].v[3] == 8
assert b.a[0].v[4] == 5
}

View File

@@ -0,0 +1,48 @@
fn opt_err() ?string {return error('hi')}
fn test_err(){
v := opt_err() or {
assert err == 'hi'
return
}
assert false
println(v) // suppress not used error
}
fn err_call(ok bool) ?int {
if !ok {
return error('Not ok!')
}
return 42
}
fn ret_none() ?int {
//return error('wtf') //none
return none
}
fn test_option_for_base_type_without_variable() {
val := err_call(true) or {
panic(err)
}
assert val == 42
println('hm')
val2 := ret_none() or {
println('yep')
return
}
println('$val2 should have been `none`')
assert false
// This is invalid:
// x := 5 or {
// return
// }
}
fn test_if_opt() {
if val := err_call(false) {
assert val == 42
}
assert 1 == 1
println('nice')
}

View File

@@ -0,0 +1,2 @@
*.repl text=auto eol=lf

3
vlib/compiler/tests/repl/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
run
*.repl.result.txt
*.repl.expected.txt

View File

@@ -0,0 +1,25 @@
# V REPL Tests Script
### How to write a new test
- Create a new file named `*.repl`
- Write the input to be given to REPL
- Add `===output===`
- Write the output expected
### Notes
Keep in mind, that the way V repl works for now, every non empty line
would cause a new recompilation of the entire repl content that was
collected so far.
*Longer REPL files would cause measurably*
*longer recompilation/testing times.*
Also, longer repl files would be slower to debug when they fail,
*It is better to have several smaller files vs one huge REPL file.*
### Example :
```
a := 1
println(a)
===output===
1

View File

@@ -0,0 +1,4 @@
arr := ['1', '2', '3', '4']
println(arr)
===output===
["1", "2", "3", "4"]

View File

@@ -0,0 +1,16 @@
struct A { mut: v int } struct B { a A } struct C { mut: b B } struct D { mut: c C } struct E { mut: v []int } struct F { e []E }
mut b := B{} b = B{A{2}}
println('b is: ' + b.a.v.str())
mut c := C{} c.b = B{}
mut d := D{} d.c.b = B{}
f := F{[E{[10,20,30]},E{[100,200,300,400]}]}
println('f.e[0].v.len: ${f.e[0].v.len}')
println('f.e[1].v.len: ${f.e[1].v.len}')
===output===
b is: 2
f.e[0].v.len: 3
f.e[1].v.len: 4

View File

@@ -0,0 +1,78 @@
/* 1 */ struct A { mut: v int }
/* 2 */ struct B { a A }
/* 3 */ struct C { mut: b B }
/* 4 */ struct D { mut: c C }
/* 5 */ struct E { mut: v []int }
/* 6 */ struct F { e []E }
/* 7 */ mut s := 'hello world'
/*( 8)*/ s.len = 0 // Error (field len immutable)
/* 8 */ mut b := B{}
/*( 9)*/ b.a.v = 1 // Error (field a immutable)
/*( 9)*/ b.a = A{} // Error (field a immutable)
/* 9 */ b = B{A{2}} // Correct
/* 10 */ mut c := C{}
/* 11 */ c.b = B{} // Correct
/*(12)*/ c.b.a = A{} // Error (field a immutable)
/*(12)*/ c.b.a.v = 1 // Error (field a immutable)
/* 12 */ c2 := C{}
/*(13)*/ c2.b = B{} // Error (c2 immutable)
/* 13 */ mut d := D{}
/* 14 */ d.c.b = B{} // Correct
/* 15 */ mut f := F{}
/*(16)*/ f.e << E{} // Error (field e immutable)
/*(16)*/ f.e[0].v << 1 // Error (field e immutable)
/* 16 */ e := E{}
/*(17)*/ e.v << 1 // Error (e immutable)
===output===
.vrepl_temp.v:27:14: cannot modify immutable field `len` (type `string`)
declare the field with `mut:`
struct string {
mut:
len int
}
.vrepl_temp.v:30:14: cannot modify immutable field `a` (type `B`)
declare the field with `mut:`
struct B {
mut:
a A
}
.vrepl_temp.v:29:12: cannot modify immutable field `a` (type `B`)
declare the field with `mut:`
struct B {
mut:
a A
}
.vrepl_temp.v:41:14: cannot modify immutable field `a` (type `B`)
declare the field with `mut:`
struct B {
mut:
a A
}
.vrepl_temp.v:42:16: cannot modify immutable field `a` (type `B`)
declare the field with `mut:`
struct B {
mut:
a A
}
.vrepl_temp.v:44:15: `c2` is immutable
.vrepl_temp.v:53:12: cannot modify immutable field `e` (type `F`)
declare the field with `mut:`
struct F {
mut:
e []E
}
.vrepl_temp.v:54:17: cannot modify immutable field `e` (type `F`)
declare the field with `mut:`
struct F {
mut:
e []E
}
.vrepl_temp.v:57:17: `e` is immutable (can't <<)

View File

@@ -0,0 +1,18 @@
if true {
println('foo')
}
for i := 0; i < 4; i++ {
println(i)
}
if false {
println('foo')
} else {
println('bar')
}
===output===
foo
0
1
2
3
bar

View File

@@ -0,0 +1,7 @@
num := 1
string := 'Hello'
num
string
===output===
1
Hello

View File

@@ -0,0 +1,4 @@
struct Empty{} ee := Empty{}
println('OK')
===output===
OK

View File

@@ -0,0 +1,3 @@
println(a)
===output===
.vrepl.v:2:9: undefined: `a`

View File

@@ -0,0 +1,5 @@
a
33
===output===
.vrepl_temp.v:3:9: undefined: `a`
33

View File

@@ -0,0 +1,11 @@
fn test() {
println('foo')
}
test()
fn test2(a int) {
println(a)
}
test2(42)
===output===
foo
42

View File

@@ -0,0 +1,30 @@
mut s := 'hello world'
s.len = 0 // Error (field len immutable)
mut a := []string
a.len = 0 // Error (field len immutable)
mut ints := []int
ints.len = 0 // Error (field len immutable)
println('BYE')
===output===
.vrepl_temp.v:3:5: cannot modify immutable field `len` (type `string`)
declare the field with `mut:`
struct string {
mut:
len int
}
.vrepl_temp.v:4:5: cannot modify immutable field `len` (type `array`)
declare the field with `mut:`
struct array {
mut:
len int
}
.vrepl_temp.v:5:8: cannot modify immutable field `len` (type `array`)
declare the field with `mut:`
struct array {
mut:
len int
}
BYE

View File

@@ -0,0 +1,5 @@
a := 'Hello'
b := 'World'
println('$a $b')
===output===
Hello World

View File

@@ -0,0 +1,10 @@
name := 'Bob'
age := 20
large_number := i64(9999999999)
println(name)
println(age)
println(large_number)
===output===
Bob
20
9999999999

View File

@@ -0,0 +1,7 @@
println('Hello World')
println('Foo Bar')
println('dlroW olleH')
===output===
Hello World
Foo Bar
dlroW olleH

View File

@@ -0,0 +1,9 @@
'abc'
'abc'+'xyz'
'{'
'}'
===output===
abc
abcxyz
{
}

View File

@@ -0,0 +1,5 @@
===output===

View File

@@ -0,0 +1 @@
===output===

View File

@@ -0,0 +1,7 @@
println('Hello, world!')
println('Привет, мир!')
println('你好世界')
===output===
Hello, world!
Привет, мир!
你好世界

View File

@@ -0,0 +1,40 @@
import os
import compiler.tests.repl.runner
import benchmark
fn test_the_v_compiler_can_be_invoked() {
vexec := runner.full_path_to_v()
println('vexecutable: $vexec')
assert vexec != ''
vcmd := '$vexec --version'
r := os.exec(vcmd) or { panic(err) }
//println('"$vcmd" exit_code: $r.exit_code | output: $r.output')
assert r.exit_code == 0
vcmd_error := '$vexec nonexisting.v'
r_error := os.exec(vcmd_error) or { panic(err) }
//println('"$vcmd_error" exit_code: $r_error.exit_code | output: $r_error.output')
assert r_error.exit_code == 1
assert r_error.output == '`nonexisting.v` does not exist'
}
fn test_all_v_repl_files() {
options := runner.new_options()
mut bmark := benchmark.new_benchmark()
for file in options.files {
bmark.step()
fres := runner.run_repl_file(options.wd, options.vexec, file) or {
bmark.fail()
eprintln( bmark.step_message(err) )
assert false
continue
}
bmark.ok()
println( bmark.step_message(fres) )
assert true
}
bmark.stop()
println( bmark.total_message('total time spent running REPL files') )
}

View File

@@ -0,0 +1,24 @@
module main
import vcompiler.tests.repl.runner
import log
import benchmark
fn main(){
logger := &log.Log{log.DEBUG, 'terminal'}
options := runner.new_options()
mut bmark := benchmark.new_benchmark()
for file in options.files {
bmark.step()
fres := runner.run_repl_file(options.wd, options.vexec, file) or {
bmark.fail()
logger.error( bmark.step_message( err ) )
continue
}
bmark.ok()
logger.info( bmark.step_message( fres ) )
}
bmark.stop()
logger.info( bmark.total_message('total time spent running REPL files') )
}

View File

@@ -0,0 +1,93 @@
module runner
import os
struct RunnerOptions {
pub:
wd string
vexec string
files []string
}
pub fn full_path_to_v() string {
vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' }
vexec := os.dir(os.dir(os.dir(os.dir(os.dir( os.executable() ))))) + os.path_separator + vname
/*
args := os.args
vreal := os.realpath('v')
myself := os.realpath( os.executable() )
wd := os.getwd() + os.path_separator
println('args are: $args')
println('vreal : $vreal')
println('myself : $myself')
println('wd : $wd')
*/
return vexec
}
fn find_working_diff_command() ?string {
for diffcmd in ['colordiff', 'diff', 'colordiff.exe', 'diff.exe'] {
p := os.exec('$diffcmd --version') or { continue }
if p.exit_code == 0 { return diffcmd }
}
return error('no working diff command found')
}
fn diff_files( file_result, file_expected string ) string {
diffcmd := find_working_diff_command() or { return err }
diff := os.exec('$diffcmd --minimal --text --unified=2 $file_result $file_expected') or { return 'found diff command "$diffcmd" does not work' }
return diff.output
}
pub fn run_repl_file(wd string, vexec string, file string) ?string {
fcontent := os.read_file(file) or { return error('Could not read file $file') }
content := fcontent.replace('\r', '')
input := content.all_before('===output===\n')
output := content.all_after('===output===\n')
input_temporary_filename := 'input_temporary_filename.txt'
os.write_file(input_temporary_filename, input)
r := os.exec('$vexec runrepl < $input_temporary_filename') or {
os.rm(input_temporary_filename)
return error('Could not execute "$vexec runrepl < $input_temporary_filename" ')
}
os.rm(input_temporary_filename)
result := r.output.replace('\r','').replace('>>> ', '').replace('>>>', '').replace('... ', '').all_after('Use Ctrl-C or `exit` to exit\n').replace(wd, '' )
if result != output {
file_result := '${file}.result.txt'
file_expected := '${file}.expected.txt'
os.write_file( file_result, result )
os.write_file( file_expected, output )
diff := diff_files( file_result, file_expected )
return error('Difference found in REPL file: $file
====> Got :
|$result|
====> Expected :
|$output|
====> Diff :
$diff
')
} else {
return 'Repl file $file is OK'
}
}
pub fn new_options() RunnerOptions {
wd := os.getwd() + os.path_separator
vexec := full_path_to_v()
mut files := []string
if os.args.len > 1 {
files = os.args.right(1)
} else {
files = os.walk_ext('.', '.repl')
}
return RunnerOptions {
wd: wd
vexec: vexec
files: files
}
}

View File

@@ -0,0 +1,4 @@
a := 1
println(a)
===output===
1

View File

@@ -0,0 +1,23 @@
struct Zest { val int }
fn (t Zest) get_a_finger_to_the_moon() voidptr {
return voidptr(0)
}
fn get_the_dao_way() voidptr {
return voidptr(0)
}
fn test_returning_a_void_pointer_from_a_method() {
t := &Zest{ val: 123 }
z := voidptr(0)
assert z == t.get_a_finger_to_the_moon()
assert t.get_a_finger_to_the_moon() == 0
}
fn test_returning_a_void_pointer_from_a_function() {
z := voidptr(0)
assert z == get_the_dao_way()
assert get_the_dao_way() == 0
}

View File

@@ -0,0 +1,18 @@
struct Foo {
number int
str string
f f64
}
fn test_array_str() {
f := Foo{34, 'hello', 1.2}
println(f)
//s := f.str()
//println(s)
n := [1, 2, 3]
assert n.str() == '[1, 2, 3]'
println(n) // make sure the array is printable
n2 := [4,5,6]
//assert n2.str() == '[4, 5, 6]'
println(n2)
}

View File

@@ -0,0 +1,29 @@
fn test_excape_dollar_in_string() {
i := 42
assert '($i)' == '(42)'
assert '(\$i)'.contains('i') && !'(\$i)'.contains('42')
assert !'(\\$i)'.contains('i') && '(\\$i)'.contains('42') && '(\\$i)'.contains('\\')
assert '(\\\$i)'.contains('i') && !'(\\\$i)'.contains('42') && '(\\$i)'.contains('\\')
assert !'(\\\\$i)'.contains('i') && '(\\\\$i)'.contains('42') && '(\\\\$i)'.contains('\\\\')
assert '(${i})' == '(42)'
assert '(\${i})'.contains('i') && !'(\${i})'.contains('42')
assert !'(\\${i})'.contains('i') && '(\\${i})'.contains('42') && '(\\${i})'.contains('\\')
assert '(\\\${i})'.contains('i') && !'(\\\${i})'.contains('42') && '(\\${i})'.contains('\\')
assert !'(\\\\${i})'.contains('i') && '(\\\\${i})'.contains('42') && '(\\\\${i})'.contains('\\\\')
assert i==42
}
fn test_implicit_str() {
i := 42
assert 'int $i' == 'int 42'
assert '$i' == '42'
check := '$i' == '42'
assert check
text := '$i' + '42'
assert text == '4242'
}

View File

@@ -0,0 +1,120 @@
struct A{
mut:
val int
nums []int
}
struct B{
mut:
a A
}
struct C {
mut:
b B
nums []int
aarr []A
num int
}
struct User {
name string
age int
}
struct Foo {
@type string
}
//We need to make sure that this compiles with all the reserved names.
struct ReservedKeywords {
delete int
exit int
unix int
error int
malloc int
calloc int
free int
panic int
auto int
char int
do int
double int
extern int
float int
inline int
long int
register int
restrict int
short int
signed int
typedef int
unsigned int
void int
volatile int
while int
}
fn test_struct_levels() {
mut c := C{}
assert c.nums.len == 0
c.nums << 3
assert c.nums.len == 1
assert c.nums[0] == 3
c.nums[0] = 4
assert c.nums[0] == 4
c.b.a.val = 34
assert c.b.a.val == 34
c.b.a.nums = [0].repeat(0)
c.b.a.nums << 0
c.b.a.nums << 2
assert c.b.a.nums.len == 2
assert c.b.a.nums[0] == 0
assert c.b.a.nums[1] == 2
c.b.a.nums [0] = 7
assert c.b.a.nums[0] == 7
c.aarr << A{val:8}
assert c.aarr.len == 1
assert c.aarr[0].val == 8
c.num = 20
assert c.num == 20
c.aarr[0].val = 10
assert c.aarr[0].val == 10
}
fn test_struct_str() {
u := User{'Bob', 30}
println(u) // make sure the struct is printable
// assert u.str() == '{name:"Bob", age:30}' // TODO
}
fn test_at() {
foo := Foo{ @type: 'test' }
println(foo.@type)
}
fn test_reserved_keywords() {
//Make sure we can initialize them correctly using full syntax.
rk_holder := ReservedKeywords{0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}
//Test a few as it'll take too long to test all. If it's initialized
//correctly, other fields are also probably valid.
assert rk_holder.unix == 5
assert rk_holder.while == 3
rk_holder2 := ReservedKeywords{inline: 9, volatile: 11}
//Make sure partial initialization works too.
assert rk_holder2.inline == 9
assert rk_holder2.volatile == 11
assert rk_holder2.while == 0 //Zero value as not specified.
}
struct User2 {
mut:
name string
}
fn test_mutable_fields() {
mut u := User2{}
u.name = 'Peter'
assert u.name == 'Peter'
}