Merge branch 'master' of https://github.com/vlang/v into add-rsa
commit
8f9e37a58f
|
@ -55,6 +55,9 @@ jobs:
|
||||||
cd '${{env.MY_V_PATH}}'
|
cd '${{env.MY_V_PATH}}'
|
||||||
ls -la
|
ls -la
|
||||||
make
|
make
|
||||||
|
## prebuild cmd/tools/builders/js_builder, to minimise the
|
||||||
|
## chances of a sporadic "Killed" when running the tests later
|
||||||
|
./v -b js run examples/hello_world.v
|
||||||
- name: v doctor
|
- name: v doctor
|
||||||
run: |
|
run: |
|
||||||
cd '${{env.MY_V_PATH}}'
|
cd '${{env.MY_V_PATH}}'
|
||||||
|
|
|
@ -21,6 +21,7 @@ const (
|
||||||
hide_warnings = '-hide-warnings' in os.args || '-w' in os.args
|
hide_warnings = '-hide-warnings' in os.args || '-w' in os.args
|
||||||
show_progress = os.getenv('GITHUB_JOB') == '' && '-silent' !in os.args
|
show_progress = os.getenv('GITHUB_JOB') == '' && '-silent' !in os.args
|
||||||
non_option_args = cmdline.only_non_options(os.args[2..])
|
non_option_args = cmdline.only_non_options(os.args[2..])
|
||||||
|
is_verbose = os.getenv('VERBOSE') != ''
|
||||||
)
|
)
|
||||||
|
|
||||||
struct CheckResult {
|
struct CheckResult {
|
||||||
|
@ -75,7 +76,7 @@ fn main() {
|
||||||
res += mdfile.check()
|
res += mdfile.check()
|
||||||
}
|
}
|
||||||
if res.errors == 0 && show_progress {
|
if res.errors == 0 && show_progress {
|
||||||
term.clear_previous_line()
|
clear_previous_line()
|
||||||
}
|
}
|
||||||
if res.warnings > 0 || res.errors > 0 || res.oks > 0 {
|
if res.warnings > 0 || res.errors > 0 || res.oks > 0 {
|
||||||
println('\nWarnings: $res.warnings | Errors: $res.errors | OKs: $res.oks')
|
println('\nWarnings: $res.warnings | Errors: $res.errors | OKs: $res.oks')
|
||||||
|
@ -131,9 +132,7 @@ fn eline(file_path string, lnumber int, column int, message string) string {
|
||||||
return btext('$file_path:${lnumber + 1}:${column + 1}:') + btext(rtext(' error: $message'))
|
return btext('$file_path:${lnumber + 1}:${column + 1}:') + btext(rtext(' error: $message'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const default_command = 'compile'
|
||||||
default_command = 'compile'
|
|
||||||
)
|
|
||||||
|
|
||||||
struct VCodeExample {
|
struct VCodeExample {
|
||||||
mut:
|
mut:
|
||||||
|
@ -160,7 +159,7 @@ mut:
|
||||||
|
|
||||||
fn (mut f MDFile) progress(message string) {
|
fn (mut f MDFile) progress(message string) {
|
||||||
if show_progress {
|
if show_progress {
|
||||||
term.clear_previous_line()
|
clear_previous_line()
|
||||||
println('File: ${f.path:-30s}, Lines: ${f.lines.len:5}, $message')
|
println('File: ${f.path:-30s}, Lines: ${f.lines.len:5}, $message')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,6 +393,7 @@ fn (mut f MDFile) debug() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmdexecute(cmd string) int {
|
fn cmdexecute(cmd string) int {
|
||||||
|
verbose_println(cmd)
|
||||||
res := os.execute(cmd)
|
res := os.execute(cmd)
|
||||||
if res.exit_code < 0 {
|
if res.exit_code < 0 {
|
||||||
return 1
|
return 1
|
||||||
|
@ -405,6 +405,7 @@ fn cmdexecute(cmd string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn silent_cmdexecute(cmd string) int {
|
fn silent_cmdexecute(cmd string) int {
|
||||||
|
verbose_println(cmd)
|
||||||
res := os.execute(cmd)
|
res := os.execute(cmd)
|
||||||
return res.exit_code
|
return res.exit_code
|
||||||
}
|
}
|
||||||
|
@ -426,6 +427,7 @@ fn (mut f MDFile) check_examples() CheckResult {
|
||||||
}
|
}
|
||||||
fname := os.base(f.path).replace('.md', '_md')
|
fname := os.base(f.path).replace('.md', '_md')
|
||||||
uid := rand.ulid()
|
uid := rand.ulid()
|
||||||
|
cfile := os.join_path(os.temp_dir(), '${uid}.c')
|
||||||
vfile := os.join_path(os.temp_dir(), 'check_${fname}_example_${e.sline}__${e.eline}__${uid}.v')
|
vfile := os.join_path(os.temp_dir(), 'check_${fname}_example_${e.sline}__${e.eline}__${uid}.v')
|
||||||
mut should_cleanup_vfile := true
|
mut should_cleanup_vfile := true
|
||||||
// eprintln('>>> checking example $vfile ...')
|
// eprintln('>>> checking example $vfile ...')
|
||||||
|
@ -438,8 +440,7 @@ fn (mut f MDFile) check_examples() CheckResult {
|
||||||
fmt_res := if nofmt { 0 } else { get_fmt_exit_code(vfile, vexe) }
|
fmt_res := if nofmt { 0 } else { get_fmt_exit_code(vfile, vexe) }
|
||||||
match command {
|
match command {
|
||||||
'compile' {
|
'compile' {
|
||||||
res := cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -o x.c ${os.quoted_path(vfile)}')
|
res := cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors ${os.quoted_path(vfile)}')
|
||||||
os.rm('x.c') or {}
|
|
||||||
if res != 0 || fmt_res != 0 {
|
if res != 0 || fmt_res != 0 {
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
eprintln(eline(f.path, e.sline, 0, 'example failed to compile'))
|
eprintln(eline(f.path, e.sline, 0, 'example failed to compile'))
|
||||||
|
@ -454,9 +455,26 @@ fn (mut f MDFile) check_examples() CheckResult {
|
||||||
}
|
}
|
||||||
oks++
|
oks++
|
||||||
}
|
}
|
||||||
|
'cgen' {
|
||||||
|
res := cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -o ${os.quoted_path(cfile)} ${os.quoted_path(vfile)}')
|
||||||
|
os.rm(cfile) or {}
|
||||||
|
if res != 0 || fmt_res != 0 {
|
||||||
|
if res != 0 {
|
||||||
|
eprintln(eline(f.path, e.sline, 0, 'example failed to generate C code'))
|
||||||
|
}
|
||||||
|
if fmt_res != 0 {
|
||||||
|
eprintln(eline(f.path, e.sline, 0, 'example is not formatted'))
|
||||||
|
}
|
||||||
|
eprintln(vcontent)
|
||||||
|
should_cleanup_vfile = false
|
||||||
|
errors++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
oks++
|
||||||
|
}
|
||||||
'globals' {
|
'globals' {
|
||||||
res := cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -enable-globals -o x.c ${os.quoted_path(vfile)}')
|
res := cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -enable-globals -o ${os.quoted_path(cfile)} ${os.quoted_path(vfile)}')
|
||||||
os.rm('x.c') or {}
|
os.rm(cfile) or {}
|
||||||
if res != 0 || fmt_res != 0 {
|
if res != 0 || fmt_res != 0 {
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
eprintln(eline(f.path, e.sline, 0, '`example failed to compile with -enable-globals'))
|
eprintln(eline(f.path, e.sline, 0, '`example failed to compile with -enable-globals'))
|
||||||
|
@ -472,7 +490,8 @@ fn (mut f MDFile) check_examples() CheckResult {
|
||||||
oks++
|
oks++
|
||||||
}
|
}
|
||||||
'live' {
|
'live' {
|
||||||
res := cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -live -o x.c ${os.quoted_path(vfile)}')
|
res := cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -live -o ${os.quoted_path(cfile)} ${os.quoted_path(vfile)}')
|
||||||
|
os.rm(cfile) or {}
|
||||||
if res != 0 || fmt_res != 0 {
|
if res != 0 || fmt_res != 0 {
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
eprintln(eline(f.path, e.sline, 0, 'example failed to compile with -live'))
|
eprintln(eline(f.path, e.sline, 0, 'example failed to compile with -live'))
|
||||||
|
@ -488,8 +507,8 @@ fn (mut f MDFile) check_examples() CheckResult {
|
||||||
oks++
|
oks++
|
||||||
}
|
}
|
||||||
'failcompile' {
|
'failcompile' {
|
||||||
res := silent_cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -o x.c ${os.quoted_path(vfile)}')
|
res := silent_cmdexecute('${os.quoted_path(vexe)} -w -Wfatal-errors -o ${os.quoted_path(cfile)} ${os.quoted_path(vfile)}')
|
||||||
os.rm('x.c') or {}
|
os.rm(cfile) or {}
|
||||||
if res == 0 || fmt_res != 0 {
|
if res == 0 || fmt_res != 0 {
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
eprintln(eline(f.path, e.sline, 0, '`failcompile` example compiled'))
|
eprintln(eline(f.path, e.sline, 0, '`failcompile` example compiled'))
|
||||||
|
@ -533,7 +552,7 @@ fn (mut f MDFile) check_examples() CheckResult {
|
||||||
}
|
}
|
||||||
'nofmt' {}
|
'nofmt' {}
|
||||||
else {
|
else {
|
||||||
eprintln(eline(f.path, e.sline, 0, 'unrecognized command: "$command", use one of: wip/ignore/compile/failcompile/oksyntax/badsyntax'))
|
eprintln(eline(f.path, e.sline, 0, 'unrecognized command: "$command", use one of: wip/ignore/compile/cgen/failcompile/oksyntax/badsyntax/nofmt'))
|
||||||
should_cleanup_vfile = false
|
should_cleanup_vfile = false
|
||||||
errors++
|
errors++
|
||||||
}
|
}
|
||||||
|
@ -548,3 +567,16 @@ fn (mut f MDFile) check_examples() CheckResult {
|
||||||
oks: oks
|
oks: oks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verbose_println(message string) {
|
||||||
|
if is_verbose {
|
||||||
|
println(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_previous_line() {
|
||||||
|
if is_verbose {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
term.clear_previous_line()
|
||||||
|
}
|
||||||
|
|
|
@ -259,7 +259,15 @@ fn (foptions &FormatOptions) post_process_file(file string, formatted_file_path
|
||||||
file_bak := '${file}.bak'
|
file_bak := '${file}.bak'
|
||||||
os.cp(file, file_bak) or {}
|
os.cp(file, file_bak) or {}
|
||||||
}
|
}
|
||||||
|
mut perms_to_restore := u32(0)
|
||||||
|
$if !windows {
|
||||||
|
fm := os.inode(file)
|
||||||
|
perms_to_restore = fm.bitmask()
|
||||||
|
}
|
||||||
os.mv_by_cp(formatted_file_path, file) or { panic(err) }
|
os.mv_by_cp(formatted_file_path, file) or { panic(err) }
|
||||||
|
$if !windows {
|
||||||
|
os.chmod(file, int(perms_to_restore)) or { panic(err) }
|
||||||
|
}
|
||||||
eprintln('Reformatted file: $file')
|
eprintln('Reformatted file: $file')
|
||||||
} else {
|
} else {
|
||||||
eprintln('Already formatted file: $file')
|
eprintln('Already formatted file: $file')
|
||||||
|
|
|
@ -13,6 +13,7 @@ Flags:
|
||||||
NB: There are several special keywords, which you can put after the code fences for v.
|
NB: There are several special keywords, which you can put after the code fences for v.
|
||||||
These are:
|
These are:
|
||||||
compile - Default, can be omitted. The example will be compiled and formatting is verified.
|
compile - Default, can be omitted. The example will be compiled and formatting is verified.
|
||||||
|
cgen - The example produces C code, which may not be compilable (when external libs are not installed). Formatting is verified.
|
||||||
live - Compile hot reload examples with the ´-live´ flag set and verify formatting.
|
live - Compile hot reload examples with the ´-live´ flag set and verify formatting.
|
||||||
ignore - Ignore the example, useful for examples that just use the syntax highlighting
|
ignore - Ignore the example, useful for examples that just use the syntax highlighting
|
||||||
failcompile - Known failing compilation. Useful for examples demonstrating compiler errors.
|
failcompile - Known failing compilation. Useful for examples demonstrating compiler errors.
|
||||||
|
|
122
doc/docs.md
122
doc/docs.md
|
@ -163,7 +163,7 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
NB: there are several special keywords, which you can put after the code fences for v:
|
NB: there are several special keywords, which you can put after the code fences for v:
|
||||||
compile, live, ignore, failcompile, oksyntax, badsyntax, wip, nofmt
|
compile, cgen, live, ignore, failcompile, oksyntax, badsyntax, wip, nofmt
|
||||||
For more details, do: `v check-md`
|
For more details, do: `v check-md`
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -1393,7 +1393,7 @@ println(s)
|
||||||
You can check the current type of a sum type using `is` and its negated form `!is`.
|
You can check the current type of a sum type using `is` and its negated form `!is`.
|
||||||
|
|
||||||
You can do it either in an `if`:
|
You can do it either in an `if`:
|
||||||
```v
|
```v cgen
|
||||||
struct Abc {
|
struct Abc {
|
||||||
val string
|
val string
|
||||||
}
|
}
|
||||||
|
@ -2789,38 +2789,52 @@ For more information, see [Dynamic casts](#dynamic-casts).
|
||||||
|
|
||||||
#### Interface method definitions
|
#### Interface method definitions
|
||||||
|
|
||||||
Also unlike Go, an interface may implement a method.
|
Also unlike Go, an interface can have it's own methods, similar to how
|
||||||
These methods are not implemented by structs which implement that interface.
|
structs can have their methods. These 'interface methods' do not have
|
||||||
|
to be implemented, by structs which implement that interface.
|
||||||
|
They are just a convenient way to write `i.some_function()` instead of
|
||||||
|
`some_function(i)`, similar to how struct methods can be looked at, as
|
||||||
|
a convenience for writing `s.xyz()` instead of `xyz(s)`.
|
||||||
|
|
||||||
When a struct is wrapped in an interface that has implemented a method
|
N.B. This feature is NOT a "default implementation" like in C#.
|
||||||
with the same name as one implemented by this struct, only the method
|
|
||||||
implemented on the interface is called.
|
For example, if a struct `cat` is wrapped in an interface `a`, that has
|
||||||
|
implemented a method with the same name `speak`, as a method implemented by
|
||||||
|
the struct, and you do `a.speak()`, *only* the interface method is called:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
struct Cat {}
|
|
||||||
|
|
||||||
fn (c Cat) speak() string {
|
|
||||||
return 'meow!'
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Adoptable {}
|
interface Adoptable {}
|
||||||
|
|
||||||
fn (a Adoptable) speak() string {
|
fn (a Adoptable) speak() string {
|
||||||
return 'adopt me!'
|
return 'adopt me!'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_adoptable() Adoptable {
|
struct Cat {}
|
||||||
return Cat{}
|
|
||||||
|
fn (c Cat) speak() string {
|
||||||
|
return 'meow!'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Dog {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
cat := Cat{}
|
cat := Cat{}
|
||||||
assert cat.speak() == 'meow!'
|
assert dump(cat.speak()) == 'meow!'
|
||||||
a := new_adoptable()
|
//
|
||||||
assert a.speak() == 'adopt me!'
|
a := Adoptable(cat)
|
||||||
|
assert dump(a.speak()) == 'adopt me!' // call Adoptable's `speak`
|
||||||
if a is Cat {
|
if a is Cat {
|
||||||
println(a.speak()) // meow!
|
// Inside this `if` however, V knows that `a` is not just any
|
||||||
|
// kind of Adoptable, but actually a Cat, so it will use the
|
||||||
|
// Cat `speak`, NOT the Adoptable `speak`:
|
||||||
|
dump(a.speak()) // meow!
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
b := Adoptable(Dog{})
|
||||||
|
assert dump(b.speak()) == 'adopt me!' // call Adoptable's `speak`
|
||||||
|
// if b is Dog {
|
||||||
|
// dump(b.speak()) // error: unknown method or field: Dog.speak
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -5102,40 +5116,42 @@ For all supported options check the latest help:
|
||||||
|
|
||||||
#### `$if` condition
|
#### `$if` condition
|
||||||
```v
|
```v
|
||||||
// Support for multiple conditions in one branch
|
fn main() {
|
||||||
$if ios || android {
|
// Support for multiple conditions in one branch
|
||||||
println('Running on a mobile device!')
|
$if ios || android {
|
||||||
}
|
println('Running on a mobile device!')
|
||||||
$if linux && x64 {
|
}
|
||||||
println('64-bit Linux.')
|
$if linux && x64 {
|
||||||
}
|
println('64-bit Linux.')
|
||||||
// Usage as expression
|
}
|
||||||
os := $if windows { 'Windows' } $else { 'UNIX' }
|
// Usage as expression
|
||||||
println('Using $os')
|
os := $if windows { 'Windows' } $else { 'UNIX' }
|
||||||
// $else-$if branches
|
println('Using $os')
|
||||||
$if tinyc {
|
// $else-$if branches
|
||||||
println('tinyc')
|
$if tinyc {
|
||||||
} $else $if clang {
|
println('tinyc')
|
||||||
println('clang')
|
} $else $if clang {
|
||||||
} $else $if gcc {
|
println('clang')
|
||||||
println('gcc')
|
} $else $if gcc {
|
||||||
} $else {
|
println('gcc')
|
||||||
println('different compiler')
|
} $else {
|
||||||
}
|
println('different compiler')
|
||||||
$if test {
|
}
|
||||||
println('testing')
|
$if test {
|
||||||
}
|
println('testing')
|
||||||
// v -cg ...
|
}
|
||||||
$if debug {
|
// v -cg ...
|
||||||
println('debugging')
|
$if debug {
|
||||||
}
|
println('debugging')
|
||||||
// v -prod ...
|
}
|
||||||
$if prod {
|
// v -prod ...
|
||||||
println('production build')
|
$if prod {
|
||||||
}
|
println('production build')
|
||||||
// v -d option ...
|
}
|
||||||
$if option ? {
|
// v -d option ...
|
||||||
println('custom option')
|
$if option ? {
|
||||||
|
println('custom option')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,9 @@ pub fn (mut a array) insert(i int, val voidptr) {
|
||||||
panic('array.insert: index out of range (i == $i, a.len == $a.len)')
|
panic('array.insert: index out of range (i == $i, a.len == $a.len)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a.ensure_cap(a.len + 1)
|
if a.len >= a.cap {
|
||||||
|
a.ensure_cap(a.len + 1)
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
vmemmove(a.get_unsafe(i + 1), a.get_unsafe(i), (a.len - i) * a.element_size)
|
vmemmove(a.get_unsafe(i + 1), a.get_unsafe(i), (a.len - i) * a.element_size)
|
||||||
a.set_unsafe(i, val)
|
a.set_unsafe(i, val)
|
||||||
|
@ -569,7 +571,9 @@ fn (mut a array) set(i int, val voidptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut a array) push(val voidptr) {
|
fn (mut a array) push(val voidptr) {
|
||||||
a.ensure_cap(a.len + 1)
|
if a.len >= a.cap {
|
||||||
|
a.ensure_cap(a.len + 1)
|
||||||
|
}
|
||||||
unsafe { vmemmove(&byte(a.data) + a.element_size * a.len, val, a.element_size) }
|
unsafe { vmemmove(&byte(a.data) + a.element_size * a.len, val, a.element_size) }
|
||||||
a.len++
|
a.len++
|
||||||
}
|
}
|
||||||
|
@ -578,16 +582,15 @@ fn (mut a array) push(val voidptr) {
|
||||||
// `val` is array.data and user facing usage is `a << [1,2,3]`
|
// `val` is array.data and user facing usage is `a << [1,2,3]`
|
||||||
[unsafe]
|
[unsafe]
|
||||||
pub fn (mut a3 array) push_many(val voidptr, size int) {
|
pub fn (mut a3 array) push_many(val voidptr, size int) {
|
||||||
|
a3.ensure_cap(a3.len + size)
|
||||||
if a3.data == val && !isnil(a3.data) {
|
if a3.data == val && !isnil(a3.data) {
|
||||||
// handle `arr << arr`
|
// handle `arr << arr`
|
||||||
copy := a3.clone()
|
copy := a3.clone()
|
||||||
a3.ensure_cap(a3.len + size)
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// vmemcpy(a.data, copy.data, copy.element_size * copy.len)
|
// vmemcpy(a.data, copy.data, copy.element_size * copy.len)
|
||||||
vmemcpy(a3.get_unsafe(a3.len), copy.data, a3.element_size * size)
|
vmemcpy(a3.get_unsafe(a3.len), copy.data, a3.element_size * size)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a3.ensure_cap(a3.len + size)
|
|
||||||
if !isnil(a3.data) && !isnil(val) {
|
if !isnil(a3.data) && !isnil(val) {
|
||||||
unsafe { vmemcpy(a3.get_unsafe(a3.len), val, a3.element_size * size) }
|
unsafe { vmemcpy(a3.get_unsafe(a3.len), val, a3.element_size * size) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1166,7 +1166,9 @@ fn test_array_int_pop() {
|
||||||
assert a.len == 3
|
assert a.len == 3
|
||||||
assert z == 4
|
assert z == 4
|
||||||
x1 := a.pop()
|
x1 := a.pop()
|
||||||
|
println(x1)
|
||||||
x2 := a.pop()
|
x2 := a.pop()
|
||||||
|
println(x2)
|
||||||
final := a.pop()
|
final := a.pop()
|
||||||
assert final == 1
|
assert final == 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ fn test_hex() {
|
||||||
b := 1234
|
b := 1234
|
||||||
assert b.hex() == '4d2'
|
assert b.hex() == '4d2'
|
||||||
b1 := -1
|
b1 := -1
|
||||||
|
println(b1)
|
||||||
// assert b1.hex() == 'ffffffff'
|
// assert b1.hex() == 'ffffffff'
|
||||||
// unsigned tests
|
// unsigned tests
|
||||||
// assert u8(12).hex() == '0c'
|
// assert u8(12).hex() == '0c'
|
||||||
|
|
|
@ -372,6 +372,9 @@ fn test_map_assign() {
|
||||||
'r': u16(6)
|
'r': u16(6)
|
||||||
's': 5
|
's': 5
|
||||||
}}
|
}}
|
||||||
|
println(a)
|
||||||
|
println(b)
|
||||||
|
println(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_postfix_op_directly() {
|
fn test_postfix_op_directly() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import strings
|
// import strings
|
||||||
|
|
||||||
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
|
@ -636,6 +636,7 @@ fn test_for_loop_two() {
|
||||||
|
|
||||||
fn test_quote() {
|
fn test_quote() {
|
||||||
a := `'`
|
a := `'`
|
||||||
|
println(a)
|
||||||
println('testing double quotes')
|
println('testing double quotes')
|
||||||
b := 'hi'
|
b := 'hi'
|
||||||
assert b == 'hi'
|
assert b == 'hi'
|
||||||
|
@ -727,6 +728,7 @@ fn test_raw() {
|
||||||
|
|
||||||
fn test_raw_with_quotes() {
|
fn test_raw_with_quotes() {
|
||||||
raw := r"some'" + r'"thing' // " should be escaped in the generated C code
|
raw := r"some'" + r'"thing' // " should be escaped in the generated C code
|
||||||
|
println(raw)
|
||||||
// assert raw[0] == `s`
|
// assert raw[0] == `s`
|
||||||
// assert raw[5] == `"`
|
// assert raw[5] == `"`
|
||||||
// assert raw[6] == `t`
|
// assert raw[6] == `t`
|
||||||
|
|
|
@ -7,7 +7,7 @@ user's keyboard/mouse input.
|
||||||
|
|
||||||
## Example:
|
## Example:
|
||||||
|
|
||||||
```v
|
```v cgen
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import gg
|
import gg
|
||||||
|
|
|
@ -20,6 +20,22 @@ pub:
|
||||||
execute bool
|
execute bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bitmask returns a 3 bit sequence in the order RWE where
|
||||||
|
// the bit is set to 1 if the value is true or 0 otherwise.
|
||||||
|
pub fn (p FilePermission) bitmask() u32 {
|
||||||
|
mut mask := u32(0)
|
||||||
|
if p.read {
|
||||||
|
mask |= 4
|
||||||
|
}
|
||||||
|
if p.write {
|
||||||
|
mask |= 2
|
||||||
|
}
|
||||||
|
if p.execute {
|
||||||
|
mask |= 1
|
||||||
|
}
|
||||||
|
return mask
|
||||||
|
}
|
||||||
|
|
||||||
struct FileMode {
|
struct FileMode {
|
||||||
pub:
|
pub:
|
||||||
typ FileType
|
typ FileType
|
||||||
|
@ -28,6 +44,12 @@ pub:
|
||||||
others FilePermission
|
others FilePermission
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bitmask returns a 9 bit sequence in the order owner + group + others.
|
||||||
|
// This is a valid bitmask to use with `os.chmod`.
|
||||||
|
pub fn (m FileMode) bitmask() u32 {
|
||||||
|
return m.owner.bitmask() << 6 | m.group.bitmask() << 3 | m.others.bitmask()
|
||||||
|
}
|
||||||
|
|
||||||
// inode returns the mode of the file/inode containing inode type and permission information
|
// inode returns the mode of the file/inode containing inode type and permission information
|
||||||
// it supports windows for regular files but it doesn't matter if you use owner, group or others when checking permissions on windows
|
// it supports windows for regular files but it doesn't matter if you use owner, group or others when checking permissions on windows
|
||||||
pub fn inode(path string) FileMode {
|
pub fn inode(path string) FileMode {
|
||||||
|
|
|
@ -41,3 +41,16 @@ fn test_inode_file_owner_permission() {
|
||||||
assert mode.owner.write
|
assert mode.owner.write
|
||||||
assert !mode.owner.execute
|
assert !mode.owner.execute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_inode_file_permissions_bitmask() {
|
||||||
|
if user_os() == 'windows' {
|
||||||
|
println('> skipping ${@FN} on windows')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
filename := './test3.txt'
|
||||||
|
mut file := open_file(filename, 'w', 0o641) or { return }
|
||||||
|
file.close()
|
||||||
|
mode := inode(filename)
|
||||||
|
rm(filename) or {}
|
||||||
|
assert mode.bitmask() == 0o641
|
||||||
|
}
|
||||||
|
|
|
@ -2024,6 +2024,11 @@ pub fn (mut re RE) match_base(in_txt &byte, in_txt_len int) (int, int) {
|
||||||
|
|
||||||
re.prog[state.pc].group_rep++ // increase repetitions
|
re.prog[state.pc].group_rep++ // increase repetitions
|
||||||
// println("GROUP $group_index END ${re.prog[state.pc].group_rep}")
|
// println("GROUP $group_index END ${re.prog[state.pc].group_rep}")
|
||||||
|
if re.prog[state.pc].group_rep > in_txt_len - 1 {
|
||||||
|
m_state = .ist_quant_ng
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
m_state = .ist_quant_pg
|
m_state = .ist_quant_pg
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,11 @@ match_test_suite = [
|
||||||
TestItem{"a", r"\S+",0,1},
|
TestItem{"a", r"\S+",0,1},
|
||||||
TestItem{"aaaa", r"\S+",0,4},
|
TestItem{"aaaa", r"\S+",0,4},
|
||||||
TestItem{"aaaa ", r"\S+",0,4},
|
TestItem{"aaaa ", r"\S+",0,4},
|
||||||
|
|
||||||
|
// multiple dot char
|
||||||
|
TestItem{"aba", r"a*(b*)*a",0,3},
|
||||||
|
TestItem{"/*x*/", r"/\**(.*)\**/",0,5},
|
||||||
|
TestItem{"/*x*/", r"/*(.*)*/",0,5},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -591,6 +596,21 @@ fn test_regex_func(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn my_repl_1(re regex.RE, in_txt string, start int, end int) string {
|
||||||
|
s0 := re.get_group_by_id(in_txt,0)
|
||||||
|
println("[$start, $end] => ${s0}")
|
||||||
|
return "a" + s0.to_upper()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_regex_func_replace1(){
|
||||||
|
txt := "abbabbbabbbbaabba"
|
||||||
|
query := r"a(b+)"
|
||||||
|
mut re := regex.regex_opt(query) or { panic(err) }
|
||||||
|
result := re.replace_by_fn(txt, my_repl_1)
|
||||||
|
|
||||||
|
assert result == "aBBaBBBaBBBBaaBBa"
|
||||||
|
}
|
||||||
|
|
||||||
fn my_repl(re regex.RE, in_txt string, start int, end int) string {
|
fn my_repl(re regex.RE, in_txt string, start int, end int) string {
|
||||||
s0 := re.get_group_by_id(in_txt,0)[0..1] + "X"
|
s0 := re.get_group_by_id(in_txt,0)[0..1] + "X"
|
||||||
s1 := re.get_group_by_id(in_txt,1)[0..1] + "X"
|
s1 := re.get_group_by_id(in_txt,1)[0..1] + "X"
|
||||||
|
@ -598,7 +618,6 @@ fn my_repl(re regex.RE, in_txt string, start int, end int) string {
|
||||||
return "${s0}${s1}${s2}"
|
return "${s0}${s1}${s2}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// test regex replace function
|
// test regex replace function
|
||||||
fn test_regex_func_replace(){
|
fn test_regex_func_replace(){
|
||||||
filler := "E il primo dei tre regni dell'Oltretomba cristiano visitato da Dante nel corso del viaggio, con la guida di Virgilio."
|
filler := "E il primo dei tre regni dell'Oltretomba cristiano visitato da Dante nel corso del viaggio, con la guida di Virgilio."
|
||||||
|
|
|
@ -212,7 +212,7 @@ pub fn (mut re RE) find(in_txt string) (int, int) {
|
||||||
[direct_array_access]
|
[direct_array_access]
|
||||||
pub fn (mut re RE) find_from(in_txt string, start int) (int, int) {
|
pub fn (mut re RE) find_from(in_txt string, start int) (int, int) {
|
||||||
old_flag := re.flag
|
old_flag := re.flag
|
||||||
re.flag |= f_src // enable search mode
|
// re.flag |= f_src // enable search mode
|
||||||
|
|
||||||
mut i := start
|
mut i := start
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
|
|
|
@ -11,7 +11,7 @@ Each `.h` file in the sokol source code is well-documented as can be seen here:
|
||||||
|
|
||||||
## Example from `@VROOTDIR/examples/sokol/sounds/simple_sin_tones.v`:
|
## Example from `@VROOTDIR/examples/sokol/sounds/simple_sin_tones.v`:
|
||||||
|
|
||||||
```v
|
```v cgen
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
import sokol.audio
|
import sokol.audio
|
||||||
|
|
|
@ -446,6 +446,18 @@ pub fn (t &Table) find_method_with_embeds(sym &TypeSymbol, method_name string) ?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (t &Table) get_embed_methods(sym &TypeSymbol) []Fn {
|
||||||
|
mut methods := []Fn{}
|
||||||
|
if sym.info is Struct {
|
||||||
|
for embed in sym.info.embeds {
|
||||||
|
embed_sym := t.sym(embed)
|
||||||
|
methods << embed_sym.methods
|
||||||
|
methods << t.get_embed_methods(embed_sym)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methods
|
||||||
|
}
|
||||||
|
|
||||||
fn (t &Table) register_aggregate_field(mut sym TypeSymbol, name string) ?StructField {
|
fn (t &Table) register_aggregate_field(mut sym TypeSymbol, name string) ?StructField {
|
||||||
if sym.kind != .aggregate {
|
if sym.kind != .aggregate {
|
||||||
t.panic('Unexpected type symbol: $sym.kind')
|
t.panic('Unexpected type symbol: $sym.kind')
|
||||||
|
@ -1428,7 +1440,11 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||||
if typ == 0 {
|
if typ == 0 {
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
return typ.derive_add_muls(generic_type).clear_flag(.generic)
|
if typ.has_flag(.generic) {
|
||||||
|
return typ.derive_add_muls(generic_type).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
return typ.derive_add_muls(generic_type).clear_flag(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match mut sym.info {
|
match mut sym.info {
|
||||||
Array {
|
Array {
|
||||||
|
@ -1443,7 +1459,11 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||||
}
|
}
|
||||||
if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types) {
|
if typ := t.resolve_generic_to_concrete(elem_type, generic_names, concrete_types) {
|
||||||
idx := t.find_or_register_array_with_dims(typ, dims)
|
idx := t.find_or_register_array_with_dims(typ, dims)
|
||||||
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
if typ.has_flag(.generic) {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArrayFixed {
|
ArrayFixed {
|
||||||
|
@ -1451,7 +1471,11 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||||
concrete_types)
|
concrete_types)
|
||||||
{
|
{
|
||||||
idx := t.find_or_register_array_fixed(typ, sym.info.size, None{})
|
idx := t.find_or_register_array_fixed(typ, sym.info.size, None{})
|
||||||
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
if typ.has_flag(.generic) {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Chan {
|
Chan {
|
||||||
|
@ -1459,16 +1483,24 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||||
concrete_types)
|
concrete_types)
|
||||||
{
|
{
|
||||||
idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
|
idx := t.find_or_register_chan(typ, typ.nr_muls() > 0)
|
||||||
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
if typ.has_flag(.generic) {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FnType {
|
FnType {
|
||||||
mut func := sym.info.func
|
mut func := sym.info.func
|
||||||
|
mut has_generic := false
|
||||||
if func.return_type.has_flag(.generic) {
|
if func.return_type.has_flag(.generic) {
|
||||||
if typ := t.resolve_generic_to_concrete(func.return_type, generic_names,
|
if typ := t.resolve_generic_to_concrete(func.return_type, generic_names,
|
||||||
concrete_types)
|
concrete_types)
|
||||||
{
|
{
|
||||||
func.return_type = typ
|
func.return_type = typ
|
||||||
|
if typ.has_flag(.generic) {
|
||||||
|
has_generic = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func.params = func.params.clone()
|
func.params = func.params.clone()
|
||||||
|
@ -1478,12 +1510,19 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||||
concrete_types)
|
concrete_types)
|
||||||
{
|
{
|
||||||
param.typ = typ
|
param.typ = typ
|
||||||
|
if typ.has_flag(.generic) {
|
||||||
|
has_generic = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func.name = ''
|
func.name = ''
|
||||||
idx := t.find_or_register_fn_type('', func, true, false)
|
idx := t.find_or_register_fn_type('', func, true, false)
|
||||||
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
if has_generic {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MultiReturn {
|
MultiReturn {
|
||||||
mut types := []Type{}
|
mut types := []Type{}
|
||||||
|
@ -1498,7 +1537,11 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||||
}
|
}
|
||||||
if type_changed {
|
if type_changed {
|
||||||
idx := t.find_or_register_multi_return(types)
|
idx := t.find_or_register_multi_return(types)
|
||||||
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
if types.any(it.has_flag(.generic)) {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map {
|
Map {
|
||||||
|
@ -1519,7 +1562,11 @@ pub fn (mut t Table) resolve_generic_to_concrete(generic_type Type, generic_name
|
||||||
}
|
}
|
||||||
if type_changed {
|
if type_changed {
|
||||||
idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
|
idx := t.find_or_register_map(unwrapped_key_type, unwrapped_value_type)
|
||||||
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
if unwrapped_key_type.has_flag(.generic) || unwrapped_value_type.has_flag(.generic) {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).set_flag(.generic)
|
||||||
|
} else {
|
||||||
|
return new_type(idx).derive_add_muls(generic_type).clear_flag(.generic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Struct, Interface, SumType {
|
Struct, Interface, SumType {
|
||||||
|
|
|
@ -963,6 +963,13 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||||
}
|
}
|
||||||
if func.generic_names.len > 0 {
|
if func.generic_names.len > 0 {
|
||||||
if has_generic {
|
if has_generic {
|
||||||
|
if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names,
|
||||||
|
node.concrete_types)
|
||||||
|
{
|
||||||
|
if typ.has_flag(.generic) {
|
||||||
|
node.return_type = typ
|
||||||
|
}
|
||||||
|
}
|
||||||
return node.return_type
|
return node.return_type
|
||||||
} else if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names,
|
} else if typ := c.table.resolve_generic_to_concrete(func.return_type, func.generic_names,
|
||||||
concrete_types)
|
concrete_types)
|
||||||
|
|
|
@ -2471,10 +2471,8 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
||||||
}
|
}
|
||||||
// Generic dereferencing logic
|
// Generic dereferencing logic
|
||||||
neither_void := ast.voidptr_type !in [got_type, expected_type]
|
neither_void := ast.voidptr_type !in [got_type, expected_type]
|
||||||
to_shared := expected_type.has_flag(.shared_f) && !got_type_raw.has_flag(.shared_f)
|
if expected_type.has_flag(.shared_f) && !got_type_raw.has_flag(.shared_f)
|
||||||
&& !expected_type.has_flag(.optional)
|
&& !expected_type.has_flag(.optional) {
|
||||||
// from_shared := got_type_raw.has_flag(.shared_f) && !expected_type.has_flag(.shared_f)
|
|
||||||
if to_shared {
|
|
||||||
shared_styp := exp_styp[0..exp_styp.len - 1] // `shared` implies ptr, so eat one `*`
|
shared_styp := exp_styp[0..exp_styp.len - 1] // `shared` implies ptr, so eat one `*`
|
||||||
if got_type_raw.is_ptr() {
|
if got_type_raw.is_ptr() {
|
||||||
g.error('cannot convert reference to `shared`', expr.pos())
|
g.error('cannot convert reference to `shared`', expr.pos())
|
||||||
|
@ -2492,6 +2490,13 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
||||||
g.is_shared = old_is_shared
|
g.is_shared = old_is_shared
|
||||||
g.writeln('}, sizeof($shared_styp))')
|
g.writeln('}, sizeof($shared_styp))')
|
||||||
return
|
return
|
||||||
|
} else if got_type_raw.has_flag(.shared_f) && !expected_type.has_flag(.shared_f) {
|
||||||
|
if expected_type.is_ptr() {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
|
g.expr(expr)
|
||||||
|
g.write('->val')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if got_is_ptr && !expected_is_ptr && neither_void && exp_sym.kind != .placeholder
|
if got_is_ptr && !expected_is_ptr && neither_void && exp_sym.kind != .placeholder
|
||||||
&& expr !is ast.InfixExpr {
|
&& expr !is ast.InfixExpr {
|
||||||
|
@ -3604,10 +3609,15 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||||
}
|
}
|
||||||
// struct embedding
|
// struct embedding
|
||||||
if sym.info in [ast.Struct, ast.Aggregate] {
|
if sym.info in [ast.Struct, ast.Aggregate] {
|
||||||
for embed in node.from_embed_types {
|
for i, embed in node.from_embed_types {
|
||||||
embed_sym := g.table.sym(embed)
|
embed_sym := g.table.sym(embed)
|
||||||
embed_name := embed_sym.embed_name()
|
embed_name := embed_sym.embed_name()
|
||||||
if node.expr_type.is_ptr() {
|
is_left_ptr := if i == 0 {
|
||||||
|
node.expr_type.is_ptr()
|
||||||
|
} else {
|
||||||
|
node.from_embed_types[i - 1].is_ptr()
|
||||||
|
}
|
||||||
|
if is_left_ptr {
|
||||||
g.write('->')
|
g.write('->')
|
||||||
} else {
|
} else {
|
||||||
g.write('.')
|
g.write('.')
|
||||||
|
@ -6310,10 +6320,6 @@ fn (mut g Gen) size_of(node ast.SizeOf) {
|
||||||
g.write('sizeof(${util.no_dots(styp)})')
|
g.write('sizeof(${util.no_dots(styp)})')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &Gen) is_importing_os() bool {
|
|
||||||
return 'os' in g.table.imports
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) go_expr(node ast.GoExpr) {
|
fn (mut g Gen) go_expr(node ast.GoExpr) {
|
||||||
line := g.go_before_stmt(0)
|
line := g.go_before_stmt(0)
|
||||||
mut handle := ''
|
mut handle := ''
|
||||||
|
@ -6797,16 +6803,13 @@ static inline __shared__$interface_name ${shared_fn_name}(__shared__$cctype* x)
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
if st_sym.info is ast.Struct {
|
t_methods := g.table.get_embed_methods(st_sym)
|
||||||
for embed in st_sym.info.embeds {
|
for t_method in t_methods {
|
||||||
embed_sym := g.table.sym(embed)
|
if t_method.name !in method_names {
|
||||||
for embed_method in embed_sym.methods {
|
methods << t_method
|
||||||
if embed_method.name !in method_names {
|
|
||||||
methods << embed_method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for method in methods {
|
for method in methods {
|
||||||
mut name := method.name
|
mut name := method.name
|
||||||
if inter_info.parent_type.has_flag(.generic) {
|
if inter_info.parent_type.has_flag(.generic) {
|
||||||
|
@ -6834,6 +6837,7 @@ static inline __shared__$interface_name ${shared_fn_name}(__shared__$cctype* x)
|
||||||
styp := g.cc_type(method.params[0].typ, true)
|
styp := g.cc_type(method.params[0].typ, true)
|
||||||
mut method_call := '${styp}_$name'
|
mut method_call := '${styp}_$name'
|
||||||
if !method.params[0].typ.is_ptr() {
|
if !method.params[0].typ.is_ptr() {
|
||||||
|
method_call = '${cctype}_$name'
|
||||||
// inline void Cat_speak_Interface_Animal_method_wrapper(Cat c) { return Cat_speak(*c); }
|
// inline void Cat_speak_Interface_Animal_method_wrapper(Cat c) { return Cat_speak(*c); }
|
||||||
iwpostfix := '_Interface_${interface_name}_method_wrapper'
|
iwpostfix := '_Interface_${interface_name}_method_wrapper'
|
||||||
methods_wrapper.write_string('static inline ${g.typ(method.return_type)} ${cctype}_$name${iwpostfix}(')
|
methods_wrapper.write_string('static inline ${g.typ(method.return_type)} ${cctype}_$name${iwpostfix}(')
|
||||||
|
@ -6865,9 +6869,13 @@ static inline __shared__$interface_name ${shared_fn_name}(__shared__$cctype* x)
|
||||||
embed_sym := g.table.sym(embed_types.last())
|
embed_sym := g.table.sym(embed_types.last())
|
||||||
method_name := '${embed_sym.cname}_$method.name'
|
method_name := '${embed_sym.cname}_$method.name'
|
||||||
methods_wrapper.write_string('${method_name}(${fargs[0]}')
|
methods_wrapper.write_string('${method_name}(${fargs[0]}')
|
||||||
for embed in embed_types {
|
for idx_embed, embed in embed_types {
|
||||||
esym := g.table.sym(embed)
|
esym := g.table.sym(embed)
|
||||||
methods_wrapper.write_string('->$esym.embed_name()')
|
if idx_embed == 0 || embed_types[idx_embed - 1].is_any_kind_of_pointer() {
|
||||||
|
methods_wrapper.write_string('->$esym.embed_name()')
|
||||||
|
} else {
|
||||||
|
methods_wrapper.write_string('.$esym.embed_name()')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
methods_wrapper.writeln('${fargs[1..].join(', ')});')
|
methods_wrapper.writeln('${fargs[1..].join(', ')});')
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
fn test_generics_with_complex_nested_generics_type() {
|
||||||
|
mut buf := []byte{}
|
||||||
|
initial<string, u64>(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initial<K, V>(buf []byte) map[K]V {
|
||||||
|
mut ret := map[K]V{}
|
||||||
|
for _ in 0 .. 3 {
|
||||||
|
k := get<K>(buf)
|
||||||
|
v := get<V>(buf)
|
||||||
|
ret[k] = v
|
||||||
|
}
|
||||||
|
println(ret)
|
||||||
|
assert '$ret' == "{'get': 22}"
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get<T>(buf []byte) T {
|
||||||
|
$if T is string {
|
||||||
|
return buf.bytestr() + 'get'
|
||||||
|
} $else $if T is u64 {
|
||||||
|
return u64(22)
|
||||||
|
} $else {
|
||||||
|
panic('oops!')
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
fn test_interface_with_multi_nested_embed() {
|
||||||
|
mut win := &Window{}
|
||||||
|
mut ll := &LinearLayout{}
|
||||||
|
mut lbl := &Label{
|
||||||
|
x: 10
|
||||||
|
y: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
ll.add(mut lbl)
|
||||||
|
win.add(mut ll)
|
||||||
|
|
||||||
|
win.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
pub struct Window {
|
||||||
|
mut:
|
||||||
|
initables []&Initable
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Initable {
|
||||||
|
mut:
|
||||||
|
init(&Window)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut w Window) add(mut initable Initable) {
|
||||||
|
w.initables << initable
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Container {
|
||||||
|
mut:
|
||||||
|
layout()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut w Window) init() {
|
||||||
|
for wd in w.initables {
|
||||||
|
if mut wd is Container {
|
||||||
|
mut c := wd as Container
|
||||||
|
c.layout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Rect {
|
||||||
|
mut:
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (r Rect) get_pos() (int, int) {
|
||||||
|
return r.x, r.y
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LayoutBase {
|
||||||
|
Rect
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Base {
|
||||||
|
LayoutBase
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut b Base) init(window &Window) {}
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
pub struct Label {
|
||||||
|
Base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface Layoutable {
|
||||||
|
get_pos() (int, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
pub struct LinearLayout {
|
||||||
|
Base
|
||||||
|
mut:
|
||||||
|
layoutables []Layoutable
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ll LinearLayout) add(mut l Layoutable) {
|
||||||
|
ll.layoutables << l
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ll LinearLayout) layout() {
|
||||||
|
for mut wl in ll.layoutables {
|
||||||
|
x, y := wl.get_pos()
|
||||||
|
println('$x, $y')
|
||||||
|
assert x == 10
|
||||||
|
assert y == 20
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
fn test_interface_with_multi_nested_embed() {
|
||||||
|
mut ll := &LinearLayout{}
|
||||||
|
mut lbl := &Label{
|
||||||
|
x: 10
|
||||||
|
y: 20
|
||||||
|
}
|
||||||
|
ll.add(mut lbl)
|
||||||
|
|
||||||
|
println(ll)
|
||||||
|
|
||||||
|
assert ll.x == 10
|
||||||
|
assert ll.y == 20
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Rect {
|
||||||
|
mut:
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (r Rect) get_pos() (int, int) {
|
||||||
|
return r.x, r.y
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LayoutBase {
|
||||||
|
Rect
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Base {
|
||||||
|
LayoutBase
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut b Base) init() {}
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
pub struct Label {
|
||||||
|
Base
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface Layoutable {
|
||||||
|
get_pos() (int, int)
|
||||||
|
mut:
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
pub struct LinearLayout {
|
||||||
|
Base
|
||||||
|
mut:
|
||||||
|
layoutables []Layoutable
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut ll LinearLayout) add(mut l Layoutable) {
|
||||||
|
x, y := l.get_pos()
|
||||||
|
ll.x += x
|
||||||
|
ll.y += y
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
struct AA {
|
||||||
|
b shared BB
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BB {
|
||||||
|
a &int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CC {
|
||||||
|
a BB
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_struct_shared_field_init() {
|
||||||
|
a := 3
|
||||||
|
table := &AA{
|
||||||
|
b: BB{&a}
|
||||||
|
}
|
||||||
|
c := CC{
|
||||||
|
a: table.b
|
||||||
|
}
|
||||||
|
assert *c.a.a == 3
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import io
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sport = 12380
|
sport = 12380
|
||||||
|
localserver = 'localhost:$sport'
|
||||||
exit_after_time = 12000 // milliseconds
|
exit_after_time = 12000 // milliseconds
|
||||||
vexe = os.getenv('VEXE')
|
vexe = os.getenv('VEXE')
|
||||||
vweb_logfile = os.getenv('VWEB_LOGFILE')
|
vweb_logfile = os.getenv('VWEB_LOGFILE')
|
||||||
|
@ -116,7 +117,7 @@ fn assert_common_http_headers(x http.Response) ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_client_index() ? {
|
fn test_http_client_index() ? {
|
||||||
x := http.get('http://127.0.0.1:$sport/') or { panic(err) }
|
x := http.get('http://$localserver/') or { panic(err) }
|
||||||
assert_common_http_headers(x) ?
|
assert_common_http_headers(x) ?
|
||||||
assert x.header.get(.content_type) ? == 'text/plain'
|
assert x.header.get(.content_type) ? == 'text/plain'
|
||||||
assert x.text == 'Welcome to VWeb'
|
assert x.text == 'Welcome to VWeb'
|
||||||
|
@ -124,9 +125,9 @@ fn test_http_client_index() ? {
|
||||||
|
|
||||||
fn test_http_client_404() ? {
|
fn test_http_client_404() ? {
|
||||||
url_404_list := [
|
url_404_list := [
|
||||||
'http://127.0.0.1:$sport/zxcnbnm',
|
'http://$localserver/zxcnbnm',
|
||||||
'http://127.0.0.1:$sport/JHKAJA',
|
'http://$localserver/JHKAJA',
|
||||||
'http://127.0.0.1:$sport/unknown',
|
'http://$localserver/unknown',
|
||||||
]
|
]
|
||||||
for url in url_404_list {
|
for url in url_404_list {
|
||||||
res := http.get(url) or { panic(err) }
|
res := http.get(url) or { panic(err) }
|
||||||
|
@ -135,39 +136,39 @@ fn test_http_client_404() ? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_client_simple() ? {
|
fn test_http_client_simple() ? {
|
||||||
x := http.get('http://127.0.0.1:$sport/simple') or { panic(err) }
|
x := http.get('http://$localserver/simple') or { panic(err) }
|
||||||
assert_common_http_headers(x) ?
|
assert_common_http_headers(x) ?
|
||||||
assert x.header.get(.content_type) ? == 'text/plain'
|
assert x.header.get(.content_type) ? == 'text/plain'
|
||||||
assert x.text == 'A simple result'
|
assert x.text == 'A simple result'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_client_html_page() ? {
|
fn test_http_client_html_page() ? {
|
||||||
x := http.get('http://127.0.0.1:$sport/html_page') or { panic(err) }
|
x := http.get('http://$localserver/html_page') or { panic(err) }
|
||||||
assert_common_http_headers(x) ?
|
assert_common_http_headers(x) ?
|
||||||
assert x.header.get(.content_type) ? == 'text/html'
|
assert x.header.get(.content_type) ? == 'text/html'
|
||||||
assert x.text == '<h1>ok</h1>'
|
assert x.text == '<h1>ok</h1>'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_client_settings_page() ? {
|
fn test_http_client_settings_page() ? {
|
||||||
x := http.get('http://127.0.0.1:$sport/bilbo/settings') or { panic(err) }
|
x := http.get('http://$localserver/bilbo/settings') or { panic(err) }
|
||||||
assert_common_http_headers(x) ?
|
assert_common_http_headers(x) ?
|
||||||
assert x.text == 'username: bilbo'
|
assert x.text == 'username: bilbo'
|
||||||
//
|
//
|
||||||
y := http.get('http://127.0.0.1:$sport/kent/settings') or { panic(err) }
|
y := http.get('http://$localserver/kent/settings') or { panic(err) }
|
||||||
assert_common_http_headers(y) ?
|
assert_common_http_headers(y) ?
|
||||||
assert y.text == 'username: kent'
|
assert y.text == 'username: kent'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_client_user_repo_settings_page() ? {
|
fn test_http_client_user_repo_settings_page() ? {
|
||||||
x := http.get('http://127.0.0.1:$sport/bilbo/gostamp/settings') or { panic(err) }
|
x := http.get('http://$localserver/bilbo/gostamp/settings') or { panic(err) }
|
||||||
assert_common_http_headers(x) ?
|
assert_common_http_headers(x) ?
|
||||||
assert x.text == 'username: bilbo | repository: gostamp'
|
assert x.text == 'username: bilbo | repository: gostamp'
|
||||||
//
|
//
|
||||||
y := http.get('http://127.0.0.1:$sport/kent/golang/settings') or { panic(err) }
|
y := http.get('http://$localserver/kent/golang/settings') or { panic(err) }
|
||||||
assert_common_http_headers(y) ?
|
assert_common_http_headers(y) ?
|
||||||
assert y.text == 'username: kent | repository: golang'
|
assert y.text == 'username: kent | repository: golang'
|
||||||
//
|
//
|
||||||
z := http.get('http://127.0.0.1:$sport/missing/golang/settings') or { panic(err) }
|
z := http.get('http://$localserver/missing/golang/settings') or { panic(err) }
|
||||||
assert z.status() == .not_found
|
assert z.status() == .not_found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +183,7 @@ fn test_http_client_json_post() ? {
|
||||||
age: 123
|
age: 123
|
||||||
}
|
}
|
||||||
json_for_ouser := json.encode(ouser)
|
json_for_ouser := json.encode(ouser)
|
||||||
mut x := http.post_json('http://127.0.0.1:$sport/json_echo', json_for_ouser) or { panic(err) }
|
mut x := http.post_json('http://$localserver/json_echo', json_for_ouser) or { panic(err) }
|
||||||
$if debug_net_socket_client ? {
|
$if debug_net_socket_client ? {
|
||||||
eprintln('/json_echo endpoint response: $x')
|
eprintln('/json_echo endpoint response: $x')
|
||||||
}
|
}
|
||||||
|
@ -191,7 +192,7 @@ fn test_http_client_json_post() ? {
|
||||||
nuser := json.decode(User, x.text) or { User{} }
|
nuser := json.decode(User, x.text) or { User{} }
|
||||||
assert '$ouser' == '$nuser'
|
assert '$ouser' == '$nuser'
|
||||||
//
|
//
|
||||||
x = http.post_json('http://127.0.0.1:$sport/json', json_for_ouser) or { panic(err) }
|
x = http.post_json('http://$localserver/json', json_for_ouser) or { panic(err) }
|
||||||
$if debug_net_socket_client ? {
|
$if debug_net_socket_client ? {
|
||||||
eprintln('/json endpoint response: $x')
|
eprintln('/json endpoint response: $x')
|
||||||
}
|
}
|
||||||
|
@ -213,7 +214,7 @@ $contents\r
|
||||||
--$boundary--\r
|
--$boundary--\r
|
||||||
'
|
'
|
||||||
mut x := http.fetch(
|
mut x := http.fetch(
|
||||||
url: 'http://127.0.0.1:$sport/form_echo'
|
url: 'http://$localserver/form_echo'
|
||||||
method: .post
|
method: .post
|
||||||
header: http.new_header(
|
header: http.new_header(
|
||||||
key: .content_type
|
key: .content_type
|
||||||
|
@ -228,7 +229,7 @@ $contents\r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_client_shutdown_does_not_work_without_a_cookie() {
|
fn test_http_client_shutdown_does_not_work_without_a_cookie() {
|
||||||
x := http.get('http://127.0.0.1:$sport/shutdown') or {
|
x := http.get('http://$localserver/shutdown') or {
|
||||||
assert err.msg == ''
|
assert err.msg == ''
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -240,7 +241,7 @@ fn testsuite_end() {
|
||||||
// This test is guaranteed to be called last.
|
// This test is guaranteed to be called last.
|
||||||
// It sends a request to the server to shutdown.
|
// It sends a request to the server to shutdown.
|
||||||
x := http.fetch(
|
x := http.fetch(
|
||||||
url: 'http://127.0.0.1:$sport/shutdown'
|
url: 'http://$localserver/shutdown'
|
||||||
method: .get
|
method: .get
|
||||||
cookies: {
|
cookies: {
|
||||||
'skey': 'superman'
|
'skey': 'superman'
|
||||||
|
@ -268,7 +269,7 @@ fn simple_tcp_client(config SimpleTcpClientConfig) ?string {
|
||||||
mut tries := 0
|
mut tries := 0
|
||||||
for tries < config.retries {
|
for tries < config.retries {
|
||||||
tries++
|
tries++
|
||||||
client = net.dial_tcp('127.0.0.1:$sport') or {
|
client = net.dial_tcp(localserver) or {
|
||||||
if tries > config.retries {
|
if tries > config.retries {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,8 @@ fn main() {
|
||||||
timeout: timeout
|
timeout: timeout
|
||||||
global_config: config
|
global_config: config
|
||||||
}
|
}
|
||||||
eprintln('>> webserver: started on http://127.0.0.1:$app.port/ , with maximum runtime of $app.timeout milliseconds.')
|
eprintln('>> webserver: started on http://localhost:$app.port/ , with maximum runtime of $app.timeout milliseconds.')
|
||||||
// vweb.run<App>(mut app, http_port)
|
vweb.run_at(app, 'localhost', http_port)
|
||||||
vweb.run(app, http_port)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn (mut app App) init_server() {
|
// pub fn (mut app App) init_server() {
|
||||||
|
|
|
@ -376,10 +376,16 @@ interface DbInterface {
|
||||||
db voidptr
|
db voidptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// run_app
|
// run - start a new VWeb server, listening to all available addresses, at the specified `port`
|
||||||
[manualfree]
|
|
||||||
pub fn run<T>(global_app &T, port int) {
|
pub fn run<T>(global_app &T, port int) {
|
||||||
mut l := net.listen_tcp(.ip6, ':$port') or { panic('failed to listen $err.code $err') }
|
run_at<T>(global_app, '', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run_at - start a new VWeb server, listening only on a specific address `host`, at the specified `port`
|
||||||
|
// Example: `vweb.run_at(app, 'localhost', 8099)`
|
||||||
|
[manualfree]
|
||||||
|
pub fn run_at<T>(global_app &T, host string, port int) {
|
||||||
|
mut l := net.listen_tcp(.ip, '$host:$port') or { panic('failed to listen $err.code $err') }
|
||||||
|
|
||||||
// Parsing methods attributes
|
// Parsing methods attributes
|
||||||
mut routes := map[string]Route{}
|
mut routes := map[string]Route{}
|
||||||
|
|
Loading…
Reference in New Issue