all: bare metal support (fix `-freestanding`) (#9624)
parent
711e309eef
commit
14434cc86a
|
@ -80,7 +80,7 @@ fn main() {
|
||||||
verror(err.msg)
|
verror(err.msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if is_atty(0) == 0 && files.len == 0 {
|
if os.is_atty(0) == 0 && files.len == 0 {
|
||||||
foptions.format_pipe()
|
foptions.format_pipe()
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ mut:
|
||||||
vstartup_lines []string // lines in the `VSTARTUP` file
|
vstartup_lines []string // lines in the `VSTARTUP` file
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_stdin_a_pipe = (is_atty(0) == 0)
|
const is_stdin_a_pipe = (os.is_atty(0) == 0)
|
||||||
|
|
||||||
const vexe = os.getenv('VEXE')
|
const vexe = os.getenv('VEXE')
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ const (
|
||||||
'vlib/v/tests/generics_test.v', /* multi_generic_args<Foo<int>, Foo<int> >(...) becomes .... Foo<int>>(...) which does not parse */
|
'vlib/v/tests/generics_test.v', /* multi_generic_args<Foo<int>, Foo<int> >(...) becomes .... Foo<int>>(...) which does not parse */
|
||||||
'vlib/v/tests/string_interpolation_test.v' /* TODO byteptr: &byte.str() behaves differently than byteptr.str() */,
|
'vlib/v/tests/string_interpolation_test.v' /* TODO byteptr: &byte.str() behaves differently than byteptr.str() */,
|
||||||
'vlib/v/gen/js/tests/js.v', /* local `hello` fn, gets replaced with module `hello` aliased as `hl` */
|
'vlib/v/gen/js/tests/js.v', /* local `hello` fn, gets replaced with module `hello` aliased as `hl` */
|
||||||
|
'vlib/v/gen/c/cheaders.v' /* the preprocessor directives are formated to the V standard, even though they are in a string literal */,
|
||||||
]
|
]
|
||||||
vfmt_verify_list = [
|
vfmt_verify_list = [
|
||||||
'cmd/',
|
'cmd/',
|
||||||
|
|
|
@ -15,12 +15,12 @@ const (
|
||||||
'vlib/builtin/js/jsfns_node.js.v',
|
'vlib/builtin/js/jsfns_node.js.v',
|
||||||
'vlib/builtin/js/jsfns.js.v',
|
'vlib/builtin/js/jsfns.js.v',
|
||||||
'vlib/builtin/js/jsfns_browser.js.v',
|
'vlib/builtin/js/jsfns_browser.js.v',
|
||||||
// error: expr(): bad token `asm`, on `asm {}`
|
|
||||||
'vlib/builtin/bare/linuxsys_bare.v',
|
|
||||||
// total chaos (duplicated code several times) in array_eq_test.v
|
// total chaos (duplicated code several times) in array_eq_test.v
|
||||||
'vlib/builtin/array_eq_test.v',
|
'vlib/builtin/array_eq_test.v',
|
||||||
// the fn args are removed, then `cb fn (picohttpparser.Request, mut picohttpparser.Response)` can not be reparsed
|
// the fn args are removed, then `cb fn (picohttpparser.Request, mut picohttpparser.Response)` can not be reparsed
|
||||||
'vlib/picoev/picoev.v',
|
'vlib/picoev/picoev.v',
|
||||||
|
// the preprocessor directives are formated to the V standard, even though they are in a string literal
|
||||||
|
'vlib/v/gen/c/cheaders.v',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,47 @@ see also `v help build`.
|
||||||
Build the executable without dependency on libc.
|
Build the executable without dependency on libc.
|
||||||
Supported only on `linux` targets currently.
|
Supported only on `linux` targets currently.
|
||||||
|
|
||||||
|
-bare-builtin-dir <bare-builtin-dir>
|
||||||
|
Use with `-freestanding`. This specifies the directory to the
|
||||||
|
implementation of some basic builtin functions. The list is as follows:
|
||||||
|
memcpy(dest &byte, src &byte, n int) &byte
|
||||||
|
Moves n bytes from dest to src, and returns dest
|
||||||
|
[export: 'malloc']
|
||||||
|
__malloc(n int) &byte
|
||||||
|
Allocates n bytes of memory and returns the pointer to the first byte
|
||||||
|
strlen(s &byte) int
|
||||||
|
Returns the amount of bytes until the first `0`, starting at s
|
||||||
|
realloc(old_area &byte, new_size int) &byte
|
||||||
|
Allocates a new area of size new_size, copies old_area
|
||||||
|
to the new area, and returns a pointer to the new area.
|
||||||
|
memset(s &byte, c int, n int) &byte
|
||||||
|
Sets n bytes starting at s to c (c is casted to a char)
|
||||||
|
and returns s.
|
||||||
|
memmove(dest &byte, src &byte, n int) &byte
|
||||||
|
Like memcpy, but guaranteed to work if dest and src overlap.
|
||||||
|
[export: 'calloc']
|
||||||
|
__calloc(nmemb int, size int) &byte
|
||||||
|
Like malloc, but sets all the bytes to `0` first.
|
||||||
|
getchar() int
|
||||||
|
Read one character from stdin and return it.
|
||||||
|
memcmp(a &byte, b &byte, n int) int
|
||||||
|
Compare two buffers of length n. If a and b are equal, return 0.
|
||||||
|
Otherwise, return the difference between the first different letter.
|
||||||
|
[export: 'free']
|
||||||
|
__free(ptr &byte)
|
||||||
|
Free the block of memory ptr allocated by malloc.
|
||||||
|
vsprintf(str &char, format &char, ap va_list) int
|
||||||
|
See `man vsprintf`.
|
||||||
|
vsnprintf(str &char, size int, format &char, ap va_list) int
|
||||||
|
See `man vsnprintf`.
|
||||||
|
bare_print(buf &byte, len u64)
|
||||||
|
Print len charecters from the buffer pointed to by buf to stdout.
|
||||||
|
bare_eprint(buf &byte, len u64)
|
||||||
|
Print len charecters from the buffer pointed to by buf to stderr.
|
||||||
|
|
||||||
|
The module decleration should be `builtin`. The default linux
|
||||||
|
implementation can be found in `vlib/builtin/linux_bare`.
|
||||||
|
|
||||||
-os <os>, -target-os <os>
|
-os <os>, -target-os <os>
|
||||||
Change the target OS that V tries to compile for.
|
Change the target OS that V tries to compile for.
|
||||||
By default, the target OS is the host system.
|
By default, the target OS is the host system.
|
||||||
|
|
|
@ -58,7 +58,7 @@ fn main() {
|
||||||
if args.len == 0 || args[0] in ['-', 'repl'] {
|
if args.len == 0 || args[0] in ['-', 'repl'] {
|
||||||
// Running `./v` without args launches repl
|
// Running `./v` without args launches repl
|
||||||
if args.len == 0 {
|
if args.len == 0 {
|
||||||
if is_atty(0) != 0 {
|
if os.is_atty(0) != 0 {
|
||||||
println('Welcome to the V REPL (for help with V itself, type `exit`, then run `v help`).')
|
println('Welcome to the V REPL (for help with V itself, type `exit`, then run `v help`).')
|
||||||
} else {
|
} else {
|
||||||
mut args_and_flags := util.join_env_vflags_and_os_args()[1..].clone()
|
mut args_and_flags := util.join_env_vflags_and_os_args()[1..].clone()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Binary Search Tree example by @SleepyRoy
|
// Binary Search Tree example by @SleepyRoy
|
||||||
|
|
||||||
// TODO: make Node.value generic once it's robust enough
|
// TODO: make Node.value generic once it's robust enough
|
||||||
// TODO: `return match` instead of returns everywhere inside match
|
// TODO: `return match` instead of returns everywhere inside match
|
||||||
|
|
||||||
struct Empty {}
|
struct Empty {}
|
||||||
|
|
||||||
|
@ -121,22 +121,46 @@ fn delete(tree Tree, x f64) Tree {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
mut tree := Tree(Empty{})
|
$if !freestanding {
|
||||||
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
mut tree := Tree(Empty{})
|
||||||
for i in input {
|
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||||
tree = insert(tree, i)
|
for i in input {
|
||||||
}
|
tree = insert(tree, i)
|
||||||
println('[1] after insertion tree size is ${size(tree)}') // 11
|
|
||||||
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
|
||||||
for i in del {
|
|
||||||
tree = delete(tree, i)
|
|
||||||
}
|
|
||||||
print('[2] after deletion tree size is ${size(tree)}, ') // 7
|
|
||||||
print('and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
|
||||||
for i in input {
|
|
||||||
if !search(tree, i) {
|
|
||||||
print('$i ')
|
|
||||||
}
|
}
|
||||||
|
println('[1] after insertion tree size is ${size(tree)}') // 11
|
||||||
|
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||||
|
for i in del {
|
||||||
|
tree = delete(tree, i)
|
||||||
|
}
|
||||||
|
print('[2] after deletion tree size is ${size(tree)}, ') // 7
|
||||||
|
print('and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||||
|
for i in input {
|
||||||
|
if !search(tree, i) {
|
||||||
|
print('$i ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println('')
|
||||||
|
} $else {
|
||||||
|
mut tree := Tree(Empty{})
|
||||||
|
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||||
|
for i in input {
|
||||||
|
tree = insert(tree, i)
|
||||||
|
}
|
||||||
|
print('[1] after insertion tree size is ') // 11
|
||||||
|
println(size(tree))
|
||||||
|
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||||
|
for i in del {
|
||||||
|
tree = delete(tree, i)
|
||||||
|
}
|
||||||
|
print('[2] after deletion tree size is ') // 7
|
||||||
|
print(size(tree))
|
||||||
|
print(', and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||||
|
for i in input {
|
||||||
|
if !search(tree, i) {
|
||||||
|
print(i)
|
||||||
|
print(' ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println('')
|
||||||
}
|
}
|
||||||
println('')
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,11 @@ pub fn (a array) repeat(count int) array {
|
||||||
|
|
||||||
// sort_with_compare sorts array in-place using given `compare` function as comparator.
|
// sort_with_compare sorts array in-place using given `compare` function as comparator.
|
||||||
pub fn (mut a array) sort_with_compare(compare voidptr) {
|
pub fn (mut a array) sort_with_compare(compare voidptr) {
|
||||||
C.qsort(mut a.data, a.len, a.element_size, compare)
|
$if freestanding {
|
||||||
|
panic('sort does not work with -freestanding')
|
||||||
|
} $else {
|
||||||
|
C.qsort(mut a.data, a.len, a.element_size, compare)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert inserts a value in the array at index `i`
|
// insert inserts a value in the array at index `i`
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
module builtin
|
|
||||||
|
|
||||||
struct string {
|
|
||||||
len int
|
|
||||||
}
|
|
|
@ -18,12 +18,17 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
|
||||||
// module is less likely to change than function, etc...
|
// module is less likely to change than function, etc...
|
||||||
// During edits, the line number will change most frequently,
|
// During edits, the line number will change most frequently,
|
||||||
// so it is last
|
// so it is last
|
||||||
eprintln('================ V panic ================')
|
$if !freestanding {
|
||||||
eprintln(' module: $mod')
|
eprintln('================ V panic ================')
|
||||||
eprintln(' function: ${fn_name}()')
|
eprintln(' module: $mod')
|
||||||
eprintln(' message: $s')
|
eprintln(' function: ${fn_name}()')
|
||||||
eprintln(' file: $file:$line_no')
|
eprintln(' message: $s')
|
||||||
eprintln('=========================================')
|
eprintln(' file: $file:$line_no')
|
||||||
|
eprintln('=========================================')
|
||||||
|
} $else {
|
||||||
|
eprint('V panic: ')
|
||||||
|
eprintln(s)
|
||||||
|
}
|
||||||
$if exit_after_panic_message ? {
|
$if exit_after_panic_message ? {
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
} $else {
|
} $else {
|
||||||
|
@ -38,7 +43,9 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
|
||||||
}
|
}
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
}
|
}
|
||||||
print_backtrace_skipping_top_frames(1)
|
$if !freestanding {
|
||||||
|
print_backtrace_skipping_top_frames(1)
|
||||||
|
}
|
||||||
$if panics_break_into_debugger ? {
|
$if panics_break_into_debugger ? {
|
||||||
break_if_debugger_attached()
|
break_if_debugger_attached()
|
||||||
}
|
}
|
||||||
|
@ -54,7 +61,8 @@ pub fn panic_optional_not_set(s string) {
|
||||||
// panic prints a nice error message, then exits the process with exit code of 1.
|
// panic prints a nice error message, then exits the process with exit code of 1.
|
||||||
// It also shows a backtrace on most platforms.
|
// It also shows a backtrace on most platforms.
|
||||||
pub fn panic(s string) {
|
pub fn panic(s string) {
|
||||||
eprintln('V panic: $s')
|
eprint('V panic: ')
|
||||||
|
eprintln(s)
|
||||||
$if exit_after_panic_message ? {
|
$if exit_after_panic_message ? {
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
} $else {
|
} $else {
|
||||||
|
@ -69,7 +77,9 @@ pub fn panic(s string) {
|
||||||
}
|
}
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
}
|
}
|
||||||
print_backtrace_skipping_top_frames(1)
|
$if !freestanding {
|
||||||
|
print_backtrace_skipping_top_frames(1)
|
||||||
|
}
|
||||||
$if panics_break_into_debugger ? {
|
$if panics_break_into_debugger ? {
|
||||||
break_if_debugger_attached()
|
break_if_debugger_attached()
|
||||||
}
|
}
|
||||||
|
@ -80,14 +90,13 @@ pub fn panic(s string) {
|
||||||
|
|
||||||
// eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed.
|
// eprintln prints a message with a line end, to stderr. Both stderr and stdout are flushed.
|
||||||
pub fn eprintln(s string) {
|
pub fn eprintln(s string) {
|
||||||
C.fflush(C.stdout)
|
$if freestanding {
|
||||||
C.fflush(C.stderr)
|
// flushing is only a thing with C.FILE from stdio.h, not on the syscall level
|
||||||
// eprintln is used in panics, so it should not fail at all
|
|
||||||
$if android {
|
|
||||||
if s.str == 0 {
|
if s.str == 0 {
|
||||||
C.fprintf(C.stderr, c'eprintln(NIL)\n')
|
bare_eprint(c'eprintln(NIL)\n', 14)
|
||||||
} else {
|
} else {
|
||||||
C.fprintf(C.stderr, c'%.*s\n', s.len, s.str)
|
bare_eprint(s.str, u64(s.len))
|
||||||
|
bare_eprint(c'\n', 1)
|
||||||
}
|
}
|
||||||
} $else $if ios {
|
} $else $if ios {
|
||||||
if s.str == 0 {
|
if s.str == 0 {
|
||||||
|
@ -96,25 +105,35 @@ pub fn eprintln(s string) {
|
||||||
C.WrappedNSLog(s.str)
|
C.WrappedNSLog(s.str)
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
if s.str == 0 {
|
C.fflush(C.stdout)
|
||||||
C.write(2, c'eprintln(NIL)\n', 14)
|
C.fflush(C.stderr)
|
||||||
} else {
|
// eprintln is used in panics, so it should not fail at all
|
||||||
C.write(2, s.str, s.len)
|
$if android {
|
||||||
C.write(2, c'\n', 1)
|
if s.str == 0 {
|
||||||
|
C.fprintf(C.stderr, c'eprintln(NIL)\n')
|
||||||
|
} else {
|
||||||
|
C.fprintf(C.stderr, c'%.*s\n', s.len, s.str)
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
if s.str == 0 {
|
||||||
|
C.write(2, c'eprintln(NIL)\n', 14)
|
||||||
|
} else {
|
||||||
|
C.write(2, s.str, s.len)
|
||||||
|
C.write(2, c'\n', 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
C.fflush(C.stderr)
|
||||||
}
|
}
|
||||||
C.fflush(C.stderr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eprint prints a message to stderr. Both stderr and stdout are flushed.
|
// eprint prints a message to stderr. Both stderr and stdout are flushed.
|
||||||
pub fn eprint(s string) {
|
pub fn eprint(s string) {
|
||||||
C.fflush(C.stdout)
|
$if freestanding {
|
||||||
C.fflush(C.stderr)
|
// flushing is only a thing with C.FILE from stdio.h, not on the syscall level
|
||||||
$if android {
|
|
||||||
if s.str == 0 {
|
if s.str == 0 {
|
||||||
C.fprintf(C.stderr, c'eprint(NIL)')
|
bare_eprint(c'eprint(NIL)\n', 12)
|
||||||
} else {
|
} else {
|
||||||
C.fprintf(C.stderr, c'%.*s', s.len, s.str)
|
bare_eprint(s.str, u64(s.len))
|
||||||
}
|
}
|
||||||
} $else $if ios {
|
} $else $if ios {
|
||||||
// TODO: Implement a buffer as NSLog doesn't have a "print"
|
// TODO: Implement a buffer as NSLog doesn't have a "print"
|
||||||
|
@ -124,13 +143,23 @@ pub fn eprint(s string) {
|
||||||
C.WrappedNSLog(s.str)
|
C.WrappedNSLog(s.str)
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
if s.str == 0 {
|
C.fflush(C.stdout)
|
||||||
C.write(2, c'eprint(NIL)', 11)
|
C.fflush(C.stderr)
|
||||||
} else {
|
$if android {
|
||||||
C.write(2, s.str, s.len)
|
if s.str == 0 {
|
||||||
|
C.fprintf(C.stderr, c'eprint(NIL)')
|
||||||
|
} else {
|
||||||
|
C.fprintf(C.stderr, c'%.*s', s.len, s.str)
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
if s.str == 0 {
|
||||||
|
C.write(2, c'eprint(NIL)', 11)
|
||||||
|
} else {
|
||||||
|
C.write(2, s.str, s.len)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
C.fflush(C.stderr)
|
||||||
}
|
}
|
||||||
C.fflush(C.stderr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// print prints a message to stdout. Unlike `println` stdout is not automatically flushed.
|
// print prints a message to stdout. Unlike `println` stdout is not automatically flushed.
|
||||||
|
@ -141,6 +170,8 @@ pub fn print(s string) {
|
||||||
} $else $if ios {
|
} $else $if ios {
|
||||||
// TODO: Implement a buffer as NSLog doesn't have a "print"
|
// TODO: Implement a buffer as NSLog doesn't have a "print"
|
||||||
C.WrappedNSLog(s.str)
|
C.WrappedNSLog(s.str)
|
||||||
|
} $else $if freestanding {
|
||||||
|
bare_print(s.str, u64(s.len))
|
||||||
} $else {
|
} $else {
|
||||||
C.write(1, s.str, s.len)
|
C.write(1, s.str, s.len)
|
||||||
}
|
}
|
||||||
|
@ -160,6 +191,9 @@ pub fn println(s string) {
|
||||||
C.fprintf(C.stdout, c'println(NIL)\n')
|
C.fprintf(C.stdout, c'println(NIL)\n')
|
||||||
} $else $if ios {
|
} $else $if ios {
|
||||||
C.WrappedNSLog(c'println(NIL)')
|
C.WrappedNSLog(c'println(NIL)')
|
||||||
|
} $else $if freestanding {
|
||||||
|
bare_print(s.str, u64(s.len))
|
||||||
|
bare_print(c'println(NIL)\n', 13)
|
||||||
} $else {
|
} $else {
|
||||||
C.write(1, c'println(NIL)\n', 13)
|
C.write(1, c'println(NIL)\n', 13)
|
||||||
}
|
}
|
||||||
|
@ -169,6 +203,9 @@ pub fn println(s string) {
|
||||||
C.fprintf(C.stdout, c'%.*s\n', s.len, s.str)
|
C.fprintf(C.stdout, c'%.*s\n', s.len, s.str)
|
||||||
} $else $if ios {
|
} $else $if ios {
|
||||||
C.WrappedNSLog(s.str)
|
C.WrappedNSLog(s.str)
|
||||||
|
} $else $if freestanding {
|
||||||
|
bare_print(s.str, u64(s.len))
|
||||||
|
bare_print(c'\n', 1)
|
||||||
} $else {
|
} $else {
|
||||||
C.write(1, s.str, s.len)
|
C.write(1, s.str, s.len)
|
||||||
C.write(1, c'\n', 1)
|
C.write(1, c'\n', 1)
|
||||||
|
@ -205,6 +242,14 @@ pub fn malloc(n int) &byte {
|
||||||
unsafe {
|
unsafe {
|
||||||
res = C.GC_MALLOC(n)
|
res = C.GC_MALLOC(n)
|
||||||
}
|
}
|
||||||
|
} $else $if freestanding {
|
||||||
|
mut e := Errno{}
|
||||||
|
res, e = mm_alloc(u64(n))
|
||||||
|
if e != .enoerror {
|
||||||
|
eprint('malloc() failed: ')
|
||||||
|
eprintln(e.str())
|
||||||
|
panic('malloc() failed')
|
||||||
|
}
|
||||||
} $else {
|
} $else {
|
||||||
res = unsafe { C.malloc(n) }
|
res = unsafe { C.malloc(n) }
|
||||||
}
|
}
|
||||||
|
@ -365,18 +410,6 @@ pub fn memdup(src voidptr, sz int) voidptr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_atty returns 1 if the `fd` file descriptor is open and refers to a terminal
|
|
||||||
pub fn is_atty(fd int) int {
|
|
||||||
$if windows {
|
|
||||||
mut mode := u32(0)
|
|
||||||
osfh := voidptr(C._get_osfhandle(fd))
|
|
||||||
C.GetConsoleMode(osfh, voidptr(&mode))
|
|
||||||
return int(mode)
|
|
||||||
} $else {
|
|
||||||
return C.isatty(fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn v_fixed_index(i int, len int) int {
|
fn v_fixed_index(i int, len int) int {
|
||||||
$if !no_bounds_checking ? {
|
$if !no_bounds_checking ? {
|
||||||
|
|
|
@ -13,6 +13,12 @@ pub fn isnil(v voidptr) bool {
|
||||||
return v == 0
|
return v == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[deprecated: 'use os.is_atty(x) instead']
|
||||||
|
pub fn is_atty(fd int) int {
|
||||||
|
panic('use os.is_atty(x) instead')
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fn on_panic(f fn(int)int) {
|
fn on_panic(f fn(int)int) {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -26,7 +32,9 @@ pub fn print_backtrace() {
|
||||||
// 1 frame for print_backtrace itself
|
// 1 frame for print_backtrace itself
|
||||||
// ... print the rest of the backtrace frames ...
|
// ... print the rest of the backtrace frames ...
|
||||||
// => top 2 frames should be skipped, since they will not be informative to the developer
|
// => top 2 frames should be skipped, since they will not be informative to the developer
|
||||||
print_backtrace_skipping_top_frames(2)
|
$if !freestanding {
|
||||||
|
print_backtrace_skipping_top_frames(2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VCastTypeIndexName {
|
struct VCastTypeIndexName {
|
||||||
|
|
|
@ -85,55 +85,57 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
|
||||||
$if no_backtrace ? {
|
$if no_backtrace ? {
|
||||||
return false
|
return false
|
||||||
} $else {
|
} $else {
|
||||||
$if tinyc {
|
$if !freestanding {
|
||||||
C.tcc_backtrace(c'Backtrace')
|
$if tinyc {
|
||||||
return false
|
C.tcc_backtrace(c'Backtrace')
|
||||||
}
|
return false
|
||||||
buffer := [100]voidptr{}
|
|
||||||
nr_ptrs := C.backtrace(&buffer[0], 100)
|
|
||||||
if nr_ptrs < 2 {
|
|
||||||
eprintln('C.backtrace returned less than 2 frames')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
nr_actual_frames := nr_ptrs - skipframes
|
|
||||||
mut sframes := []string{}
|
|
||||||
//////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
|
|
||||||
csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames)
|
|
||||||
for i in 0 .. nr_actual_frames {
|
|
||||||
sframes << unsafe { tos2(&byte(csymbols[i])) }
|
|
||||||
}
|
|
||||||
for sframe in sframes {
|
|
||||||
executable := sframe.all_before('(')
|
|
||||||
addr := sframe.all_after('[').all_before(']')
|
|
||||||
beforeaddr := sframe.all_before('[')
|
|
||||||
cmd := 'addr2line -e $executable $addr'
|
|
||||||
// taken from os, to avoid depending on the os module inside builtin.v
|
|
||||||
f := C.popen(&char(cmd.str), c'r')
|
|
||||||
if isnil(f) {
|
|
||||||
eprintln(sframe)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
buf := [1000]byte{}
|
buffer := [100]voidptr{}
|
||||||
mut output := ''
|
nr_ptrs := C.backtrace(&buffer[0], 100)
|
||||||
unsafe {
|
if nr_ptrs < 2 {
|
||||||
bp := &buf[0]
|
eprintln('C.backtrace returned less than 2 frames')
|
||||||
for C.fgets(&char(bp), 1000, f) != 0 {
|
return false
|
||||||
output += tos(bp, vstrlen(bp))
|
}
|
||||||
|
nr_actual_frames := nr_ptrs - skipframes
|
||||||
|
mut sframes := []string{}
|
||||||
|
//////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||||
|
csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||||
|
for i in 0 .. nr_actual_frames {
|
||||||
|
sframes << unsafe { tos2(&byte(csymbols[i])) }
|
||||||
|
}
|
||||||
|
for sframe in sframes {
|
||||||
|
executable := sframe.all_before('(')
|
||||||
|
addr := sframe.all_after('[').all_before(']')
|
||||||
|
beforeaddr := sframe.all_before('[')
|
||||||
|
cmd := 'addr2line -e $executable $addr'
|
||||||
|
// taken from os, to avoid depending on the os module inside builtin.v
|
||||||
|
f := C.popen(&char(cmd.str), c'r')
|
||||||
|
if isnil(f) {
|
||||||
|
eprintln(sframe)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
buf := [1000]byte{}
|
||||||
|
mut output := ''
|
||||||
|
unsafe {
|
||||||
|
bp := &buf[0]
|
||||||
|
for C.fgets(&char(bp), 1000, f) != 0 {
|
||||||
|
output += tos(bp, vstrlen(bp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output = output.trim_space() + ':'
|
||||||
|
if C.pclose(f) != 0 {
|
||||||
|
eprintln(sframe)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if output in ['??:0:', '??:?:'] {
|
||||||
|
output = ''
|
||||||
|
}
|
||||||
|
// See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
|
||||||
|
// NB: it is shortened here to just d. , just so that it fits, and so
|
||||||
|
// that the common error file:lineno: line format is enforced.
|
||||||
|
output = output.replace(' (discriminator', ': (d.')
|
||||||
|
eprintln('${output:-55s} | ${addr:14s} | $beforeaddr')
|
||||||
}
|
}
|
||||||
output = output.trim_space() + ':'
|
|
||||||
if C.pclose(f) != 0 {
|
|
||||||
eprintln(sframe)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if output in ['??:0:', '??:?:'] {
|
|
||||||
output = ''
|
|
||||||
}
|
|
||||||
// See http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
|
|
||||||
// NB: it is shortened here to just d. , just so that it fits, and so
|
|
||||||
// that the common error file:lineno: line format is enforced.
|
|
||||||
output = output.replace(' (discriminator', ': (d.')
|
|
||||||
eprintln('${output:-55s} | ${addr:14s} | $beforeaddr')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -77,11 +77,18 @@ fn restore_codepage() {
|
||||||
C.SetConsoleOutputCP(g_original_codepage)
|
C.SetConsoleOutputCP(g_original_codepage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_terminal(fd int) int {
|
||||||
|
mut mode := u32(0)
|
||||||
|
osfh := voidptr(C._get_osfhandle(fd))
|
||||||
|
C.GetConsoleMode(osfh, voidptr(&mode))
|
||||||
|
return int(mode)
|
||||||
|
}
|
||||||
|
|
||||||
fn builtin_init() {
|
fn builtin_init() {
|
||||||
g_original_codepage = C.GetConsoleOutputCP()
|
g_original_codepage = C.GetConsoleOutputCP()
|
||||||
C.SetConsoleOutputCP(C.CP_UTF8)
|
C.SetConsoleOutputCP(C.CP_UTF8)
|
||||||
C.atexit(restore_codepage)
|
C.atexit(restore_codepage)
|
||||||
if is_atty(1) > 0 {
|
if is_terminal(1) > 0 {
|
||||||
C.SetConsoleMode(C.GetStdHandle(C.STD_OUTPUT_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing
|
C.SetConsoleMode(C.GetStdHandle(C.STD_OUTPUT_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing
|
||||||
C.SetConsoleMode(C.GetStdHandle(C.STD_ERROR_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing
|
C.SetConsoleMode(C.GetStdHandle(C.STD_ERROR_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
[unsafe]
|
||||||
|
pub fn memcpy(dest &byte, src &byte, n int) &byte {
|
||||||
|
unsafe {
|
||||||
|
for i in 0 .. n {
|
||||||
|
dest[i] = src[i]
|
||||||
|
}
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[export: 'malloc']
|
||||||
|
[unsafe]
|
||||||
|
fn __malloc(n int) &byte {
|
||||||
|
return unsafe { malloc(n) }
|
||||||
|
}
|
||||||
|
|
||||||
|
[unsafe]
|
||||||
|
fn strlen(s &byte) int {
|
||||||
|
mut i := 0
|
||||||
|
for ; unsafe { s[i] } != 0; i++ {}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
[unsafe]
|
||||||
|
fn realloc(old_area &byte, new_size int) &byte {
|
||||||
|
if old_area == 0 {
|
||||||
|
return unsafe { malloc(new_size) }
|
||||||
|
}
|
||||||
|
if new_size == 0 {
|
||||||
|
unsafe { free(old_area) }
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
old_size := unsafe { *(&u64(old_area - sizeof(u64))) }
|
||||||
|
if new_size <= old_size {
|
||||||
|
return old_area
|
||||||
|
} else {
|
||||||
|
new_area := unsafe { malloc(new_size) }
|
||||||
|
unsafe { memmove(new_area, old_area, int(old_size)) }
|
||||||
|
unsafe { free(old_area) }
|
||||||
|
return new_area
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[unsafe]
|
||||||
|
fn memset(_s &byte, _c int, n int) &byte {
|
||||||
|
c := char(_c)
|
||||||
|
mut s := unsafe { &char(_s) }
|
||||||
|
for i in 0 .. int(n) {
|
||||||
|
unsafe {
|
||||||
|
s[i] = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
[unsafe]
|
||||||
|
fn memmove(dest &byte, src &byte, n int) &byte {
|
||||||
|
mut temp_buf := unsafe { malloc(n) }
|
||||||
|
for i in 0 .. int(n) {
|
||||||
|
unsafe {
|
||||||
|
temp_buf[i] = src[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0 .. int(n) {
|
||||||
|
unsafe {
|
||||||
|
dest[i] = temp_buf[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe { free(temp_buf) }
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
|
[export: 'calloc']
|
||||||
|
[unsafe]
|
||||||
|
fn __calloc(nmemb int, size int) &byte {
|
||||||
|
new_area := unsafe { malloc(nmemb * size) }
|
||||||
|
unsafe { memset(new_area, 0, nmemb * size) }
|
||||||
|
return new_area
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getchar() int {
|
||||||
|
x := byte(0)
|
||||||
|
sys_read(C.stdin, &x, 1)
|
||||||
|
return int(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memcmp(a &byte, b &byte, n int) int {
|
||||||
|
for i in 0 .. int(n) {
|
||||||
|
if unsafe { a[i] != b[i] } {
|
||||||
|
unsafe {
|
||||||
|
return a[i] - b[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
[export: 'free']
|
||||||
|
[unsafe]
|
||||||
|
fn __free(ptr &byte) {
|
||||||
|
err := mm_free(ptr)
|
||||||
|
if err != .enoerror {
|
||||||
|
eprintln('free error:')
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vsprintf(str &char, format &char, ap &byte) int {
|
||||||
|
panic('vsprintf(): string interpolation is not supported in `-freestanding`')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vsnprintf(str &char, size int, format &char, ap &byte) int {
|
||||||
|
panic('vsnprintf(): string interpolation is not supported in `-freestanding`')
|
||||||
|
}
|
||||||
|
|
||||||
|
// not really needed
|
||||||
|
fn bare_read(buf &byte, count u64) (i64, Errno) {
|
||||||
|
return sys_read(0, buf, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bare_print(buf &byte, len u64) {
|
||||||
|
sys_write(1, buf, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bare_eprint(buf &byte, len u64) {
|
||||||
|
sys_write(2, buf, len)
|
||||||
|
}
|
|
@ -0,0 +1,431 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
enum SigIndex {
|
||||||
|
si_signo = 0x00
|
||||||
|
si_code = 0x02
|
||||||
|
si_pid = 0x04
|
||||||
|
si_uid = 0x05
|
||||||
|
si_status = 0x06
|
||||||
|
si_size = 0x80
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Signo {
|
||||||
|
sighup = 1 // Hangup.
|
||||||
|
sigint = 2 // Interactive attention signal.
|
||||||
|
sigquit = 3 // Quit.
|
||||||
|
sigill = 4 // Illegal instruction.
|
||||||
|
sigtrap = 5 // Trace/breakpoint trap.
|
||||||
|
sigabrt = 6 // Abnormal termination.
|
||||||
|
sigbus = 7
|
||||||
|
sigfpe = 8 // Erroneous arithmetic operation.
|
||||||
|
sigkill = 9 // Killed.
|
||||||
|
sigusr1 = 10
|
||||||
|
sigsegv = 11 // Invalid access to memory.
|
||||||
|
sigusr2 = 12
|
||||||
|
sigpipe = 13 // Broken pipe.
|
||||||
|
sigalrm = 14 // Alarm clock.
|
||||||
|
sigterm = 15 // Termination request.
|
||||||
|
sigstkflt = 16
|
||||||
|
sigchld = 17
|
||||||
|
sigcont = 18
|
||||||
|
sigstop = 19
|
||||||
|
sigtstp = 20
|
||||||
|
sigttin = 21 // Background read from control terminal.
|
||||||
|
sigttou = 22 // Background write to control terminal.
|
||||||
|
sigurg = 23
|
||||||
|
sigxcpu = 24 // CPU time limit exceeded.
|
||||||
|
sigxfsz = 25 // File size limit exceeded.
|
||||||
|
sigvtalrm = 26 // Virtual timer expired.
|
||||||
|
sigprof = 27 // Profiling timer expired.
|
||||||
|
sigwinch = 28
|
||||||
|
sigpoll = 29
|
||||||
|
sigsys = 31
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of all the errors returned by syscalls
|
||||||
|
enum Errno {
|
||||||
|
enoerror = 0x00000000
|
||||||
|
eperm = 0x00000001
|
||||||
|
enoent = 0x00000002
|
||||||
|
esrch = 0x00000003
|
||||||
|
eintr = 0x00000004
|
||||||
|
eio = 0x00000005
|
||||||
|
enxio = 0x00000006
|
||||||
|
e2big = 0x00000007
|
||||||
|
enoexec = 0x00000008
|
||||||
|
ebadf = 0x00000009
|
||||||
|
echild = 0x0000000a
|
||||||
|
eagain = 0x0000000b
|
||||||
|
enomem = 0x0000000c
|
||||||
|
eacces = 0x0000000d
|
||||||
|
efault = 0x0000000e
|
||||||
|
enotblk = 0x0000000f
|
||||||
|
ebusy = 0x00000010
|
||||||
|
eexist = 0x00000011
|
||||||
|
exdev = 0x00000012
|
||||||
|
enodev = 0x00000013
|
||||||
|
enotdir = 0x00000014
|
||||||
|
eisdir = 0x00000015
|
||||||
|
einval = 0x00000016
|
||||||
|
enfile = 0x00000017
|
||||||
|
emfile = 0x00000018
|
||||||
|
enotty = 0x00000019
|
||||||
|
etxtbsy = 0x0000001a
|
||||||
|
efbig = 0x0000001b
|
||||||
|
enospc = 0x0000001c
|
||||||
|
espipe = 0x0000001d
|
||||||
|
erofs = 0x0000001e
|
||||||
|
emlink = 0x0000001f
|
||||||
|
epipe = 0x00000020
|
||||||
|
edom = 0x00000021
|
||||||
|
erange = 0x00000022
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MemProt {
|
||||||
|
prot_read = 0x1
|
||||||
|
prot_write = 0x2
|
||||||
|
prot_exec = 0x4
|
||||||
|
prot_none = 0x0
|
||||||
|
prot_growsdown = 0x01000000
|
||||||
|
prot_growsup = 0x02000000
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MapFlags {
|
||||||
|
map_shared = 0x01
|
||||||
|
map_private = 0x02
|
||||||
|
map_shared_validate = 0x03
|
||||||
|
map_type = 0x0f
|
||||||
|
map_fixed = 0x10
|
||||||
|
map_file = 0x00
|
||||||
|
map_anonymous = 0x20
|
||||||
|
map_huge_shift = 26
|
||||||
|
map_huge_mask = 0x3f
|
||||||
|
}
|
||||||
|
|
||||||
|
// const (
|
||||||
|
// fcntlf_dupfd = 0x00000000
|
||||||
|
// fcntlf_exlck = 0x00000004
|
||||||
|
// fcntlf_getfd = 0x00000001
|
||||||
|
// fcntlf_getfl = 0x00000003
|
||||||
|
// fcntlf_getlk = 0x00000005
|
||||||
|
// fcntlf_getlk64 = 0x0000000c
|
||||||
|
// fcntlf_getown = 0x00000009
|
||||||
|
// fcntlf_getowner_uids = 0x00000011
|
||||||
|
// fcntlf_getown_ex = 0x00000010
|
||||||
|
// fcntlf_getsig = 0x0000000b
|
||||||
|
// fcntlf_ofd_getlk = 0x00000024
|
||||||
|
// fcntlf_ofd_setlk = 0x00000025
|
||||||
|
// fcntlf_ofd_setlkw = 0x00000026
|
||||||
|
// fcntlf_owner_pgrp = 0x00000002
|
||||||
|
// fcntlf_owner_pid = 0x00000001
|
||||||
|
// fcntlf_owner_tid = 0x00000000
|
||||||
|
// fcntlf_rdlck = 0x00000000
|
||||||
|
// fcntlf_setfd = 0x00000002
|
||||||
|
// fcntlf_setfl = 0x00000004
|
||||||
|
// fcntlf_setlk = 0x00000006
|
||||||
|
// fcntlf_setlk64 = 0x0000000d
|
||||||
|
// fcntlf_setlkw = 0x00000007
|
||||||
|
// fcntlf_setlkw64 = 0x0000000e
|
||||||
|
// fcntlf_setown = 0x00000008
|
||||||
|
// fcntlf_setown_ex = 0x0000000f
|
||||||
|
// fcntlf_setsig = 0x0000000a
|
||||||
|
// fcntlf_shlck = 0x00000008
|
||||||
|
// fcntlf_unlck = 0x00000002
|
||||||
|
// fcntlf_wrlck = 0x00000001
|
||||||
|
// fcntllock_ex = 0x00000002
|
||||||
|
// fcntllock_mand = 0x00000020
|
||||||
|
// fcntllock_nb = 0x00000004
|
||||||
|
// fcntllock_read = 0x00000040
|
||||||
|
// fcntllock_rw = 0x000000c0
|
||||||
|
// fcntllock_sh = 0x00000001
|
||||||
|
// fcntllock_un = 0x00000008
|
||||||
|
// fcntllock_write = 0x00000080
|
||||||
|
// fcntlo_accmode = 0x00000003
|
||||||
|
// fcntlo_append = 0x00000400
|
||||||
|
// fcntlo_cloexec = 0x00080000
|
||||||
|
// fcntlo_creat = 0x00000040
|
||||||
|
// fcntlo_direct = 0x00004000
|
||||||
|
// fcntlo_directory = 0x00010000
|
||||||
|
// fcntlo_dsync = 0x00001000
|
||||||
|
// fcntlo_excl = 0x00000080
|
||||||
|
// fcntlo_largefile = 0x00008000
|
||||||
|
// fcntlo_ndelay = 0x00000800
|
||||||
|
// fcntlo_noatime = 0x00040000
|
||||||
|
// fcntlo_noctty = 0x00000100
|
||||||
|
// fcntlo_nofollow = 0x00020000
|
||||||
|
// fcntlo_nonblock = 0x00000800
|
||||||
|
// fcntlo_path = 0x00200000
|
||||||
|
// fcntlo_rdonly = 0x00000000
|
||||||
|
// fcntlo_rdwr = 0x00000002
|
||||||
|
// fcntlo_trunc = 0x00000200
|
||||||
|
// fcntlo_wronly = 0x00000001
|
||||||
|
// )
|
||||||
|
|
||||||
|
/*
|
||||||
|
Paraphrased from "man 2 waitid" on Linux
|
||||||
|
|
||||||
|
Upon successful return, waitid() fills in the
|
||||||
|
following fields of the siginfo_t structure
|
||||||
|
pointed to by infop:
|
||||||
|
|
||||||
|
si_pid, offset 0x10, int index 0x04:
|
||||||
|
The process ID of the child.
|
||||||
|
|
||||||
|
si_uid: offset 0x14, int index 0x05
|
||||||
|
The real user ID of the child.
|
||||||
|
|
||||||
|
si_signo: offset 0x00, int index 0x00
|
||||||
|
Always set to SIGCHLD.
|
||||||
|
|
||||||
|
si_status: ofset 0x18, int index 0x06
|
||||||
|
1 the exit status of the child, as given to _exit(2)
|
||||||
|
(or exit(3)) (sc_sys.cld_exited)
|
||||||
|
2 the signal that caused the child to terminate, stop,
|
||||||
|
or continue.
|
||||||
|
3 The si_code field can be used to determine how to
|
||||||
|
interpret this field.
|
||||||
|
|
||||||
|
si_code, set to one of (enum Wi_si_code), offset 0x08, int index 0x02:
|
||||||
|
CLD_EXITED (child called _exit(2));
|
||||||
|
CLD_KILLED (child killed by signal);
|
||||||
|
CLD_DUMPED (child killed by signal, and dumped core);
|
||||||
|
CLD_STOPPED (child stopped by signal);
|
||||||
|
CLD_TRAPPED (traced child has trapped);
|
||||||
|
CLD_CONTINUED (child continued by SIGCONT).
|
||||||
|
*/
|
||||||
|
|
||||||
|
const (
|
||||||
|
wp_sys_wnohang = u64(0x00000001)
|
||||||
|
wp_sys_wuntraced = u64(0x00000002)
|
||||||
|
wp_sys_wstopped = u64(0x00000002)
|
||||||
|
wp_sys_wexited = u64(0x00000004)
|
||||||
|
wp_sys_wcontinued = u64(0x00000008)
|
||||||
|
wp_sys_wnowait = u64(0x01000000) // don't reap, just poll status.
|
||||||
|
wp_sys___wnothread = u64(0x20000000) // don't wait on children of other threads in this group
|
||||||
|
wp_sys___wall = u64(0x40000000) // wait on all children, regardless of type
|
||||||
|
wp_sys___wclone = u64(0x80000000) // wait only on non-sigchld children
|
||||||
|
)
|
||||||
|
|
||||||
|
// First argument to waitid:
|
||||||
|
enum WiWhich {
|
||||||
|
p_all = 0
|
||||||
|
p_pid = 1
|
||||||
|
p_pgid = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
enum WiSiCode {
|
||||||
|
cld_exited = 1 // child has exited
|
||||||
|
cld_killed = 2 // child was killed
|
||||||
|
cld_dumped = 3 // child terminated abnormally
|
||||||
|
cld_trapped = 4 // traced child has trapped
|
||||||
|
cld_stopped = 5 // child has stopped
|
||||||
|
cld_continued = 6 // stopped child has continued
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split_int_errno(rc_in u64) (i64, Errno) {
|
||||||
|
rc := i64(rc_in)
|
||||||
|
if rc < 0 {
|
||||||
|
return i64(-1), Errno(-rc)
|
||||||
|
}
|
||||||
|
return rc, Errno.enoerror
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 sys_read
|
||||||
|
fn sys_read(fd i64, buf &byte, count u64) (i64, Errno) {
|
||||||
|
return split_int_errno(sys_call3(0, u64(fd), u64(buf), count))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 sys_write
|
||||||
|
fn sys_write(fd i64, buf &byte, count u64) (i64, Errno) {
|
||||||
|
return split_int_errno(sys_call3(1, u64(fd), u64(buf), count))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 sys_open
|
||||||
|
fn sys_open(filename &byte, flags i64, mode int) (i64, Errno) {
|
||||||
|
return split_int_errno(sys_call3(2, u64(filename), u64(flags), u64(mode)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3 sys_close
|
||||||
|
fn sys_close(fd i64) Errno {
|
||||||
|
return Errno(-i64(sys_call1(3, u64(fd))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9 sys_mmap
|
||||||
|
fn sys_mmap(addr &byte, len u64, prot MemProt, flags MapFlags, fildes u64, off u64) (&byte, Errno) {
|
||||||
|
rc := sys_call6(9, u64(addr), len, u64(prot), u64(flags), fildes, off)
|
||||||
|
a, e := split_int_errno(rc)
|
||||||
|
return &byte(a), e
|
||||||
|
}
|
||||||
|
|
||||||
|
// 11 sys_munmap
|
||||||
|
fn sys_munmap(addr voidptr, len u64) Errno {
|
||||||
|
return Errno(-sys_call2(11, u64(addr), len))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 22 sys_pipe
|
||||||
|
fn sys_pipe(filedes &int) Errno {
|
||||||
|
return Errno(sys_call1(22, u64(filedes)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 24 sys_sched_yield
|
||||||
|
fn sys_sched_yield() Errno {
|
||||||
|
return Errno(sys_call0(24))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 28 sys_madvise
|
||||||
|
fn sys_madvise(addr voidptr, len u64, advice int) Errno {
|
||||||
|
return Errno(sys_call3(28, u64(addr), len, u64(advice)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 39 sys_getpid
|
||||||
|
fn sys_getpid() int {
|
||||||
|
return int(sys_call0(39))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 57 sys_fork
|
||||||
|
fn sys_fork() int {
|
||||||
|
return int(sys_call0(57))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 58 sys_vfork
|
||||||
|
fn sys_vfork() int {
|
||||||
|
return int(sys_call0(58))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 33 sys_dup2
|
||||||
|
fn sys_dup2(oldfd int, newfd int) (i64, Errno) {
|
||||||
|
return split_int_errno(sys_call2(33, u64(oldfd), u64(newfd)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 59 sys_execve
|
||||||
|
fn sys_execve(filename &byte, argv []&byte, envp []&byte) int {
|
||||||
|
return int(sys_call3(59, u64(filename), argv.data, envp.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 60 sys_exit
|
||||||
|
fn sys_exit(ec int) {
|
||||||
|
sys_call1(60, u64(ec))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 102 sys_getuid
|
||||||
|
fn sys_getuid() int {
|
||||||
|
return int(sys_call0(102))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 247 sys_waitid
|
||||||
|
fn sys_waitid(which WiWhich, pid int, infop &int, options int, ru voidptr) Errno {
|
||||||
|
return Errno(sys_call5(247, u64(which), u64(pid), u64(infop), u64(options), u64(ru)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_call0(scn u64) u64 {
|
||||||
|
mut res := u64(0)
|
||||||
|
asm amd64 {
|
||||||
|
syscall
|
||||||
|
; =a (res)
|
||||||
|
; a (scn)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_call1(scn u64, arg1 u64) u64 {
|
||||||
|
mut res := u64(0)
|
||||||
|
asm amd64 {
|
||||||
|
syscall
|
||||||
|
; =a (res)
|
||||||
|
; a (scn)
|
||||||
|
D (arg1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_call2(scn u64, arg1 u64, arg2 u64) u64 {
|
||||||
|
mut res := u64(0)
|
||||||
|
asm amd64 {
|
||||||
|
syscall
|
||||||
|
; =a (res)
|
||||||
|
; a (scn)
|
||||||
|
D (arg1)
|
||||||
|
S (arg2)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_call3(scn u64, arg1 u64, arg2 u64, arg3 u64) u64 {
|
||||||
|
mut res := u64(0)
|
||||||
|
asm amd64 {
|
||||||
|
syscall
|
||||||
|
; =a (res)
|
||||||
|
; a (scn)
|
||||||
|
D (arg1)
|
||||||
|
S (arg2)
|
||||||
|
d (arg3)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_call4(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64) u64 {
|
||||||
|
mut res := u64(0)
|
||||||
|
asm amd64 {
|
||||||
|
mov r10, arg4
|
||||||
|
syscall
|
||||||
|
; =a (res)
|
||||||
|
; a (scn)
|
||||||
|
D (arg1)
|
||||||
|
S (arg2)
|
||||||
|
d (arg3)
|
||||||
|
r (arg4)
|
||||||
|
; r10
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_call5(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64) u64 {
|
||||||
|
mut res := u64(0)
|
||||||
|
asm amd64 {
|
||||||
|
mov r10, arg4
|
||||||
|
mov r8, arg5
|
||||||
|
syscall
|
||||||
|
; =a (res)
|
||||||
|
; a (scn)
|
||||||
|
D (arg1)
|
||||||
|
S (arg2)
|
||||||
|
d (arg3)
|
||||||
|
r (arg4)
|
||||||
|
r (arg5)
|
||||||
|
; r10
|
||||||
|
r8
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_call6(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64, arg6 u64) u64 {
|
||||||
|
mut res := u64(0)
|
||||||
|
asm amd64 {
|
||||||
|
mov r10, arg4
|
||||||
|
mov r8, arg5
|
||||||
|
mov r9, arg6
|
||||||
|
syscall
|
||||||
|
; =a (res)
|
||||||
|
; a (scn)
|
||||||
|
D (arg1)
|
||||||
|
S (arg2)
|
||||||
|
d (arg3)
|
||||||
|
r (arg4)
|
||||||
|
r (arg5)
|
||||||
|
r (arg6)
|
||||||
|
; r10
|
||||||
|
r8
|
||||||
|
r9
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
asm amd64 {
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
call main
|
||||||
|
mov rax, 60
|
||||||
|
xor rdi, rdi
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
fn mm_alloc(size u64) (&byte, Errno) {
|
||||||
|
// BEGIN CONSTS
|
||||||
|
// the constants need to be here, since the initialization of other constants,
|
||||||
|
// which happen before these ones would, require malloc
|
||||||
|
mem_prot := MemProt(int(MemProt.prot_read) | int(MemProt.prot_write))
|
||||||
|
map_flags := MapFlags(int(MapFlags.map_private) | int(MapFlags.map_anonymous))
|
||||||
|
// END CONSTS
|
||||||
|
|
||||||
|
a, e := sys_mmap(&byte(0), size + sizeof(u64), mem_prot, map_flags, -1, 0)
|
||||||
|
if e == .enoerror {
|
||||||
|
unsafe {
|
||||||
|
mut ap := &u64(a)
|
||||||
|
*ap = size
|
||||||
|
x2 := &byte(a + sizeof(u64))
|
||||||
|
return x2, e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &byte(0), e
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mm_free(addr &byte) Errno {
|
||||||
|
unsafe {
|
||||||
|
ap := &u64(addr - sizeof(u64))
|
||||||
|
size := *ap
|
||||||
|
return sys_munmap(addr - sizeof(u64), size + sizeof(u64))
|
||||||
|
}
|
||||||
|
}
|
|
@ -997,7 +997,11 @@ pub fn (s string) to_lower() string {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut b := malloc(s.len + 1)
|
mut b := malloc(s.len + 1)
|
||||||
for i in 0 .. s.len {
|
for i in 0 .. s.len {
|
||||||
b[i] = byte(C.tolower(s.str[i]))
|
if s.str[i] >= `A` && s.str[i] <= `Z` {
|
||||||
|
b[i] = s.str[i] + 32
|
||||||
|
} else {
|
||||||
|
b[i] = s.str[i]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
b[s.len] = 0
|
b[s.len] = 0
|
||||||
return tos(b, s.len)
|
return tos(b, s.len)
|
||||||
|
@ -1021,7 +1025,11 @@ pub fn (s string) to_upper() string {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut b := malloc(s.len + 1)
|
mut b := malloc(s.len + 1)
|
||||||
for i in 0 .. s.len {
|
for i in 0 .. s.len {
|
||||||
b[i] = byte(C.toupper(s.str[i]))
|
if s.str[i] >= `a` && s.str[i] <= `z` {
|
||||||
|
b[i] = s.str[i] - 32
|
||||||
|
} else {
|
||||||
|
b[i] = s.str[i]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
b[s.len] = 0
|
b[s.len] = 0
|
||||||
return tos(b, s.len)
|
return tos(b, s.len)
|
||||||
|
@ -1539,7 +1547,11 @@ pub fn (s &string) free() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.is_lit == -98761234 {
|
if s.is_lit == -98761234 {
|
||||||
C.printf(c'double string.free() detected\n')
|
$if freestanding {
|
||||||
|
bare_eprint(c'double string.free() detected\n', u64(unsafe { C.strlen(c'double string.free() detected\n') }))
|
||||||
|
} $else {
|
||||||
|
C.printf(c'double string.free() detected\n')
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.is_lit == 1 || s.len == 0 {
|
if s.is_lit == 1 || s.len == 0 {
|
||||||
|
|
12
vlib/os/os.v
12
vlib/os/os.v
|
@ -629,3 +629,15 @@ pub fn execute_or_panic(cmd string) Result {
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_atty returns 1 if the `fd` file descriptor is open and refers to a terminal
|
||||||
|
pub fn is_atty(fd int) int {
|
||||||
|
$if windows {
|
||||||
|
mut mode := u32(0)
|
||||||
|
osfh := voidptr(C._get_osfhandle(fd))
|
||||||
|
C.GetConsoleMode(osfh, voidptr(&mode))
|
||||||
|
return int(mode)
|
||||||
|
} $else {
|
||||||
|
return C.isatty(fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -125,8 +125,8 @@ fn supports_escape_sequences(fd int) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// 4 is enable_virtual_terminal_processing
|
// 4 is enable_virtual_terminal_processing
|
||||||
return (is_atty(fd) & 0x0004) > 0
|
return (os.is_atty(fd) & 0x0004) > 0
|
||||||
} $else {
|
} $else {
|
||||||
return is_atty(fd) > 0
|
return os.is_atty(fd) > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ fn C.ioctl(fd int, request u64, arg voidptr) int
|
||||||
|
|
||||||
// get_terminal_size returns a number of colums and rows of terminal window.
|
// get_terminal_size returns a number of colums and rows of terminal window.
|
||||||
pub fn get_terminal_size() (int, int) {
|
pub fn get_terminal_size() (int, int) {
|
||||||
if is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||||
return default_columns_size, default_rows_size
|
return default_columns_size, default_rows_size
|
||||||
}
|
}
|
||||||
w := C.winsize{}
|
w := C.winsize{}
|
||||||
|
@ -27,7 +27,7 @@ pub fn get_terminal_size() (int, int) {
|
||||||
|
|
||||||
// get_cursor_position returns a Coord containing the current cursor position
|
// get_cursor_position returns a Coord containing the current cursor position
|
||||||
pub fn get_cursor_position() Coord {
|
pub fn get_cursor_position() Coord {
|
||||||
if is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||||
return Coord{
|
return Coord{
|
||||||
x: 0
|
x: 0
|
||||||
y: 0
|
y: 0
|
||||||
|
@ -89,7 +89,7 @@ pub fn get_cursor_position() Coord {
|
||||||
|
|
||||||
// set_terminal_title change the terminal title
|
// set_terminal_title change the terminal title
|
||||||
pub fn set_terminal_title(title string) bool {
|
pub fn set_terminal_title(title string) bool {
|
||||||
if is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
print('\033]0')
|
print('\033]0')
|
||||||
|
|
|
@ -57,7 +57,7 @@ fn C.ScrollConsoleScreenBuffer(output C.HANDLE, scroll_rect &C.SMALL_RECT, clip_
|
||||||
|
|
||||||
// get_terminal_size returns a number of colums and rows of terminal window.
|
// get_terminal_size returns a number of colums and rows of terminal window.
|
||||||
pub fn get_terminal_size() (int, int) {
|
pub fn get_terminal_size() (int, int) {
|
||||||
if is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
if os.is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
||||||
info := C.CONSOLE_SCREEN_BUFFER_INFO{}
|
info := C.CONSOLE_SCREEN_BUFFER_INFO{}
|
||||||
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
||||||
columns := int(info.srWindow.Right - info.srWindow.Left + 1)
|
columns := int(info.srWindow.Right - info.srWindow.Left + 1)
|
||||||
|
@ -71,7 +71,7 @@ pub fn get_terminal_size() (int, int) {
|
||||||
// get_cursor_position returns a Coord containing the current cursor position
|
// get_cursor_position returns a Coord containing the current cursor position
|
||||||
pub fn get_cursor_position() Coord {
|
pub fn get_cursor_position() Coord {
|
||||||
mut res := Coord{}
|
mut res := Coord{}
|
||||||
if is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
if os.is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
||||||
info := C.CONSOLE_SCREEN_BUFFER_INFO{}
|
info := C.CONSOLE_SCREEN_BUFFER_INFO{}
|
||||||
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
||||||
res.x = info.dwCursorPosition.X
|
res.x = info.dwCursorPosition.X
|
||||||
|
|
|
@ -60,7 +60,7 @@ fn (mut ctx Context) termios_setup() ? {
|
||||||
// store the current title, so restore_terminal_state can get it back
|
// store the current title, so restore_terminal_state can get it back
|
||||||
save_title()
|
save_title()
|
||||||
|
|
||||||
if !ctx.cfg.skip_init_checks && !(is_atty(C.STDIN_FILENO) != 0 && is_atty(C.STDOUT_FILENO) != 0) {
|
if !ctx.cfg.skip_init_checks && !(os.is_atty(C.STDIN_FILENO) != 0 && os.is_atty(C.STDOUT_FILENO) != 0) {
|
||||||
return error('not running under a TTY')
|
return error('not running under a TTY')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3804,7 +3804,7 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
|
||||||
stmt.pos)
|
stmt.pos)
|
||||||
}
|
}
|
||||||
if c.pref.backend == .js {
|
if c.pref.backend == .js {
|
||||||
c.error('inline assembly is not supported in js backend', stmt.pos)
|
c.error('inline assembly is not supported in the js backend', stmt.pos)
|
||||||
}
|
}
|
||||||
if c.pref.backend == .c && c.pref.ccompiler_type == .msvc {
|
if c.pref.backend == .c && c.pref.ccompiler_type == .msvc {
|
||||||
c.error('msvc compiler does not support inline assembly', stmt.pos)
|
c.error('msvc compiler does not support inline assembly', stmt.pos)
|
||||||
|
@ -3857,16 +3857,7 @@ fn (mut c Checker) asm_stmt(mut stmt ast.AsmStmt) {
|
||||||
|
|
||||||
fn (mut c Checker) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt, aliases []string) {
|
fn (mut c Checker) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt, aliases []string) {
|
||||||
match mut arg {
|
match mut arg {
|
||||||
ast.AsmAlias {
|
ast.AsmAlias {}
|
||||||
name := arg.name
|
|
||||||
if name !in aliases && name !in stmt.local_labels && name !in c.file.global_labels {
|
|
||||||
mut possible := aliases.clone()
|
|
||||||
possible << stmt.local_labels
|
|
||||||
possible << c.file.global_labels
|
|
||||||
suggestion := util.new_suggestion(name, possible)
|
|
||||||
c.error(suggestion.say('alias or label `$arg.name` does not exist'), arg.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.AsmAddressing {
|
ast.AsmAddressing {
|
||||||
if arg.scale !in [-1, 1, 2, 4, 8] {
|
if arg.scale !in [-1, 1, 2, 4, 8] {
|
||||||
c.error('scale must be one of 1, 2, 4, or 8', arg.pos)
|
c.error('scale must be one of 1, 2, 4, or 8', arg.pos)
|
||||||
|
@ -5368,7 +5359,19 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
} else if !is_comptime_type_is_expr {
|
} else if !is_comptime_type_is_expr {
|
||||||
found_branch = true // If a branch wasn't skipped, the rest must be
|
found_branch = true // If a branch wasn't skipped, the rest must be
|
||||||
}
|
}
|
||||||
if !c.skip_flags || c.pref.output_cross_c {
|
if !c.skip_flags {
|
||||||
|
c.stmts(branch.stmts)
|
||||||
|
} else if c.pref.output_cross_c {
|
||||||
|
mut is_freestanding_block := false
|
||||||
|
if branch.cond is ast.Ident {
|
||||||
|
if branch.cond.name == 'freestanding' {
|
||||||
|
is_freestanding_block = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_freestanding_block {
|
||||||
|
branch.stmts = []
|
||||||
|
node.branches[i].stmts = []
|
||||||
|
}
|
||||||
c.stmts(branch.stmts)
|
c.stmts(branch.stmts)
|
||||||
} else if !is_comptime_type_is_expr {
|
} else if !is_comptime_type_is_expr {
|
||||||
node.branches[i].stmts = []
|
node.branches[i].stmts = []
|
||||||
|
@ -5603,7 +5606,7 @@ fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool {
|
||||||
'glibc' { return false } // TODO
|
'glibc' { return false } // TODO
|
||||||
'prealloc' { return !c.pref.prealloc }
|
'prealloc' { return !c.pref.prealloc }
|
||||||
'no_bounds_checking' { return cond.name !in c.pref.compile_defines_all }
|
'no_bounds_checking' { return cond.name !in c.pref.compile_defines_all }
|
||||||
'freestanding' { return !c.pref.is_bare }
|
'freestanding' { return !c.pref.is_bare || c.pref.output_cross_c }
|
||||||
else { return false }
|
else { return false }
|
||||||
}
|
}
|
||||||
} else if cond.name !in c.pref.compile_defines_all {
|
} else if cond.name !in c.pref.compile_defines_all {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
vlib/v/checker/tests/asm_alias_does_not_exist.vv:2:11: error: alias or label `a` does not exist
|
|
||||||
1 | asm amd64 {
|
|
||||||
2 | mov ebx, a
|
|
||||||
| ^
|
|
||||||
3 | }
|
|
|
@ -1,3 +0,0 @@
|
||||||
asm amd64 {
|
|
||||||
mov ebx, a
|
|
||||||
}
|
|
|
@ -392,7 +392,6 @@ pub fn (mut g Gen) init() {
|
||||||
} else {
|
} else {
|
||||||
g.cheaders.writeln(c_headers)
|
g.cheaders.writeln(c_headers)
|
||||||
}
|
}
|
||||||
g.definitions.writeln('void _STR_PRINT_ARG(const char*, char**, int*, int*, int, ...);')
|
|
||||||
g.definitions.writeln('string _STR(const char*, int, ...);')
|
g.definitions.writeln('string _STR(const char*, int, ...);')
|
||||||
g.definitions.writeln('string _STR_TMP(const char*, ...);')
|
g.definitions.writeln('string _STR_TMP(const char*, ...);')
|
||||||
}
|
}
|
||||||
|
@ -1893,7 +1892,7 @@ fn (mut g Gen) asm_arg(arg ast.AsmArg, stmt ast.AsmStmt) {
|
||||||
ast.AsmAlias {
|
ast.AsmAlias {
|
||||||
name := arg.name
|
name := arg.name
|
||||||
if name in stmt.local_labels || name in stmt.global_labels
|
if name in stmt.local_labels || name in stmt.global_labels
|
||||||
|| name in g.file.global_labels {
|
|| name in g.file.global_labels || stmt.is_top_level {
|
||||||
asm_formatted_name := if name in stmt.global_labels { '%l[$name]' } else { name }
|
asm_formatted_name := if name in stmt.global_labels { '%l[$name]' } else { name }
|
||||||
g.write(asm_formatted_name)
|
g.write(asm_formatted_name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -5466,7 +5465,9 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
||||||
g.type_definitions.writeln('} $name;')
|
g.type_definitions.writeln('} $name;')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.type_definitions.writeln('typedef pthread_t $name;')
|
if !g.pref.is_bare {
|
||||||
|
g.type_definitions.writeln('typedef pthread_t $name;')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.SumType {
|
ast.SumType {
|
||||||
|
|
|
@ -5,18 +5,18 @@ module c
|
||||||
// for each constant, during C code generation.
|
// for each constant, during C code generation.
|
||||||
const (
|
const (
|
||||||
// V_COMMIT_HASH is generated by cmd/tools/gen_vc.v .
|
// V_COMMIT_HASH is generated by cmd/tools/gen_vc.v .
|
||||||
c_commit_hash_default = '
|
c_commit_hash_default = '
|
||||||
#ifndef V_COMMIT_HASH
|
#ifndef V_COMMIT_HASH
|
||||||
#define V_COMMIT_HASH "@@@"
|
#define V_COMMIT_HASH "@@@"
|
||||||
#endif
|
#endif
|
||||||
'
|
'
|
||||||
// V_CURRENT_COMMIT_HASH is updated, when V is rebuilt inside a git repo.
|
// V_CURRENT_COMMIT_HASH is updated, when V is rebuilt inside a git repo.
|
||||||
c_current_commit_hash_default = '
|
c_current_commit_hash_default = '
|
||||||
#ifndef V_CURRENT_COMMIT_HASH
|
#ifndef V_CURRENT_COMMIT_HASH
|
||||||
#define V_CURRENT_COMMIT_HASH "@@@"
|
#define V_CURRENT_COMMIT_HASH "@@@"
|
||||||
#endif
|
#endif
|
||||||
'
|
'
|
||||||
c_concurrency_helpers = '
|
c_concurrency_helpers = '
|
||||||
typedef struct __shared_map __shared_map;
|
typedef struct __shared_map __shared_map;
|
||||||
struct __shared_map { map val; sync__RwMutex mtx; };
|
struct __shared_map { map val; sync__RwMutex mtx; };
|
||||||
static inline voidptr __dup_shared_map(voidptr src, int sz) {
|
static inline voidptr __dup_shared_map(voidptr src, int sz) {
|
||||||
|
@ -47,7 +47,136 @@ static inline void __sort_ptr(uintptr_t a[], bool b[], int l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
c_common_macros = '
|
c_str_fn_defs = '
|
||||||
|
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, guess);
|
||||||
|
// NB: (*memsize - *nbytes) === how much free space is left at the end of the current buffer refbufp
|
||||||
|
// *memsize === total length of the buffer refbufp
|
||||||
|
// *nbytes === already occupied bytes of buffer refbufp
|
||||||
|
// guess === how many bytes were taken during the current vsnprintf run
|
||||||
|
for(;;) {
|
||||||
|
int remaining_space = *memsize - *nbytes;
|
||||||
|
if (guess < remaining_space) {
|
||||||
|
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
||||||
|
if (guess < remaining_space) { // result did fit into buffer
|
||||||
|
*nbytes += guess;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// increase buffer (somewhat exponentially)
|
||||||
|
*memsize += guess + 3 * (*memsize) / 2;
|
||||||
|
#ifdef _VGCBOEHM
|
||||||
|
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
||||||
|
#else
|
||||||
|
*refbufp = (char*)realloc((void*)*refbufp, *memsize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
string _STR(const char *fmt, int nfmts, ...) {
|
||||||
|
va_list argptr;
|
||||||
|
int memsize = 128;
|
||||||
|
int nbytes = 0;
|
||||||
|
#ifdef _VGCBOEHM
|
||||||
|
char* buf = (char*)GC_MALLOC(memsize);
|
||||||
|
#else
|
||||||
|
char* buf = (char*)malloc(memsize);
|
||||||
|
#endif
|
||||||
|
va_start(argptr, nfmts);
|
||||||
|
for (int i=0; i<nfmts; ++i) {
|
||||||
|
int k = strlen(fmt);
|
||||||
|
bool is_fspec = false;
|
||||||
|
for (int j=0; j<k; ++j) {
|
||||||
|
if (fmt[j] == \'%\') {
|
||||||
|
j++;
|
||||||
|
if (fmt[j] != \'%\') {
|
||||||
|
is_fspec = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_fspec) {
|
||||||
|
char f = fmt[k-1];
|
||||||
|
char fup = f & 0xdf; // toupper
|
||||||
|
bool l = fmt[k-2] == \'l\';
|
||||||
|
bool ll = l && fmt[k-3] == \'l\';
|
||||||
|
if (f == \'u\' || fup == \'X\' || f == \'o\' || f == \'d\' || f == \'c\') { // int...
|
||||||
|
if (ll) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+16, va_arg(argptr, long long));
|
||||||
|
else if (l) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, long));
|
||||||
|
else _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+8, va_arg(argptr, int));
|
||||||
|
} else if (fup >= \'E\' && fup <= \'G\') { // floating point
|
||||||
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
||||||
|
} else if (f == \'p\') {
|
||||||
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+14, va_arg(argptr, void*));
|
||||||
|
} else if (f == \'C\') { // a C string
|
||||||
|
char* sptr = va_arg(argptr, char*);
|
||||||
|
char* fmt_no_c = (char*)v_malloc(k+4);
|
||||||
|
memcpy(fmt_no_c, fmt, k);
|
||||||
|
fmt_no_c[k-2]=\'C\';
|
||||||
|
fmt_no_c[k-1]=\'"\';
|
||||||
|
fmt_no_c[k]=\'%\';
|
||||||
|
fmt_no_c[k+1]=\'s\';
|
||||||
|
fmt_no_c[k+2]=\'"\';
|
||||||
|
fmt_no_c[k+3]=0;
|
||||||
|
_STR_PRINT_ARG(fmt_no_c, &buf, &nbytes, &memsize, k + 4 + 100, sptr);
|
||||||
|
v_free(fmt_no_c);
|
||||||
|
} else if (f == \'s\') { // v string
|
||||||
|
string s = va_arg(argptr, string);
|
||||||
|
if (fmt[k-4] == \'*\') { // %*.*s
|
||||||
|
int fwidth = va_arg(argptr, int);
|
||||||
|
if (fwidth < 0)
|
||||||
|
fwidth -= (s.len - utf8_str_visible_length(s));
|
||||||
|
else
|
||||||
|
fwidth += (s.len - utf8_str_visible_length(s));
|
||||||
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, fwidth, s.len, s.str);
|
||||||
|
} else { // %.*s
|
||||||
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//v_panic(tos3(\'Invaid format specifier\'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
||||||
|
}
|
||||||
|
fmt += k+1;
|
||||||
|
}
|
||||||
|
va_end(argptr);
|
||||||
|
buf[nbytes] = 0;
|
||||||
|
|
||||||
|
#ifdef DEBUG_ALLOC
|
||||||
|
//puts(\'_STR:\');
|
||||||
|
puts(buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _VAUTOFREE
|
||||||
|
//g_cur_str = (byteptr)buf;
|
||||||
|
#endif
|
||||||
|
return tos2((byteptr)buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
string _STR_TMP(const char *fmt, ...) {
|
||||||
|
va_list argptr;
|
||||||
|
va_start(argptr, fmt);
|
||||||
|
size_t len = vsnprintf(0, 0, fmt, argptr) + 1;
|
||||||
|
va_end(argptr);
|
||||||
|
va_start(argptr, fmt);
|
||||||
|
vsprintf((char *)g_str_buf, fmt, argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
|
||||||
|
#ifdef DEBUG_ALLOC
|
||||||
|
//puts(\'_STR_TMP:\');
|
||||||
|
//puts(g_str_buf);
|
||||||
|
#endif
|
||||||
|
string res = tos(g_str_buf, len);
|
||||||
|
res.is_lit = 1;
|
||||||
|
return res;
|
||||||
|
|
||||||
|
} // endof _STR_TMP
|
||||||
|
|
||||||
|
'
|
||||||
|
c_common_macros = '
|
||||||
#define EMPTY_VARG_INITIALIZATION 0
|
#define EMPTY_VARG_INITIALIZATION 0
|
||||||
#define EMPTY_STRUCT_DECLARATION
|
#define EMPTY_STRUCT_DECLARATION
|
||||||
#define EMPTY_STRUCT_INITIALIZATION 0
|
#define EMPTY_STRUCT_INITIALIZATION 0
|
||||||
|
@ -126,12 +255,6 @@ static inline void __sort_ptr(uintptr_t a[], bool b[], int l)
|
||||||
#define V64_PRINTFORMAT "0x%llx"
|
#define V64_PRINTFORMAT "0x%llx"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
'
|
|
||||||
c_headers = '
|
|
||||||
// c_headers
|
|
||||||
typedef int (*qsort_callback_func)(const void*, const void*);
|
|
||||||
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
#define VV_EXPORTED_SYMBOL extern __declspec(dllexport)
|
#define VV_EXPORTED_SYMBOL extern __declspec(dllexport)
|
||||||
|
@ -167,144 +290,8 @@ typedef int (*qsort_callback_func)(const void*, const void*);
|
||||||
#undef __has_include
|
#undef __has_include
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
'
|
||||||
#if defined __has_include
|
c_unsigned_comparison_functions = '
|
||||||
#if __has_include (<execinfo.h>)
|
|
||||||
#include <execinfo.h>
|
|
||||||
#else
|
|
||||||
// Most probably musl OR __ANDROID__ ...
|
|
||||||
int backtrace (void **__array, int __size) { return 0; }
|
|
||||||
char **backtrace_symbols (void *const *__array, int __size){ return 0; }
|
|
||||||
void backtrace_symbols_fd (void *const *__array, int __size, int __fd){}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#include "fns.h"
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdarg.h> // for va_list
|
|
||||||
#include <string.h> // memcpy
|
|
||||||
|
|
||||||
#if INTPTR_MAX == INT32_MAX
|
|
||||||
#define TARGET_IS_32BIT 1
|
|
||||||
#elif INTPTR_MAX == INT64_MAX
|
|
||||||
#define TARGET_IS_64BIT 1
|
|
||||||
#else
|
|
||||||
#error "The environment is not 32 or 64-bit."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
|
|
||||||
#define TARGET_ORDER_IS_BIG
|
|
||||||
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86)
|
|
||||||
#define TARGET_ORDER_IS_LITTLE
|
|
||||||
#else
|
|
||||||
#error "Unknown architecture endianness"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <locale.h> // tolower
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <unistd.h> // sleep
|
|
||||||
extern char **environ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__CYGWIN__) && !defined(_WIN32)
|
|
||||||
#error Cygwin is not supported, please use MinGW or Visual Studio.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h> // os__wait uses wait on nix
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h> // os__wait uses wait on nix
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __DragonFly__
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h> // os__wait uses wait on nix
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <sys/wait.h> // os__wait uses wait on nix
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __NetBSD__
|
|
||||||
#include <sys/wait.h> // os__wait uses wait on nix
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __sun
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h> // os__wait uses wait on nix
|
|
||||||
#endif
|
|
||||||
|
|
||||||
$c_common_macros
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define WINVER 0x0600
|
|
||||||
#ifdef _WIN32_WINNT
|
|
||||||
#undef _WIN32_WINNT
|
|
||||||
#endif
|
|
||||||
#define _WIN32_WINNT 0x0600
|
|
||||||
#ifndef WIN32_FULL
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#ifndef _UNICODE
|
|
||||||
#define _UNICODE
|
|
||||||
#endif
|
|
||||||
#ifndef UNICODE
|
|
||||||
#define UNICODE
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <io.h> // _waccess
|
|
||||||
#include <direct.h> // _wgetcwd
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// On MSVC these are the same (as long as /volatile:ms is passed)
|
|
||||||
#define _Atomic volatile
|
|
||||||
|
|
||||||
// MSVC cannot parse some things properly
|
|
||||||
#undef EMPTY_STRUCT_DECLARATION
|
|
||||||
#undef OPTION_CAST
|
|
||||||
|
|
||||||
#define EMPTY_STRUCT_DECLARATION int ____dummy_variable
|
|
||||||
#define OPTION_CAST(x)
|
|
||||||
#undef __NOINLINE
|
|
||||||
#undef __IRQHANDLER
|
|
||||||
#define __NOINLINE __declspec(noinline)
|
|
||||||
#define __IRQHANDLER __declspec(naked)
|
|
||||||
|
|
||||||
#include <dbghelp.h>
|
|
||||||
#pragma comment(lib, "Dbghelp")
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#ifndef PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
|
|
||||||
// musl does not have that
|
|
||||||
#define pthread_rwlockattr_setkind_np(a, b)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// g_live_info is used by live.info()
|
|
||||||
static void* g_live_info = NULL;
|
|
||||||
|
|
||||||
//============================== HELPER C MACROS =============================*/
|
|
||||||
//#define tos4(s, slen) ((string){.str=(s), .len=(slen)})
|
|
||||||
// `"" s` is used to enforce a string literal argument
|
|
||||||
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
|
||||||
// take the address of an rvalue
|
|
||||||
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
|
||||||
// copy something to the heap
|
|
||||||
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type)))
|
|
||||||
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
|
|
||||||
#define _IN_MAP(val, m) map_exists(m, val)
|
|
||||||
|
|
||||||
// unsigned/signed comparisons
|
// unsigned/signed comparisons
|
||||||
static inline bool _us32_gt(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a > b; }
|
static inline bool _us32_gt(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a > b; }
|
||||||
static inline bool _us32_ge(uint32_t a, int32_t b) { return a >= INT32_MAX || (int32_t)a >= b; }
|
static inline bool _us32_ge(uint32_t a, int32_t b) { return a >= INT32_MAX || (int32_t)a >= b; }
|
||||||
|
@ -318,32 +305,8 @@ static inline bool _us64_eq(uint64_t a, int64_t b) { return a <= INT64_MAX && (i
|
||||||
static inline bool _us64_ne(uint64_t a, int64_t b) { return a > INT64_MAX || (int64_t)a != b; }
|
static inline bool _us64_ne(uint64_t a, int64_t b) { return a > INT64_MAX || (int64_t)a != b; }
|
||||||
static inline bool _us64_le(uint64_t a, int64_t b) { return a <= INT64_MAX && (int64_t)a <= b; }
|
static inline bool _us64_le(uint64_t a, int64_t b) { return a <= INT64_MAX && (int64_t)a <= b; }
|
||||||
static inline bool _us64_lt(uint64_t a, int64_t b) { return a < INT64_MAX && (int64_t)a < b; }
|
static inline bool _us64_lt(uint64_t a, int64_t b) { return a < INT64_MAX && (int64_t)a < b; }
|
||||||
|
'
|
||||||
#if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__))
|
c_wyhash = '
|
||||||
#undef PRId64
|
|
||||||
#undef PRIi64
|
|
||||||
#undef PRIo64
|
|
||||||
#undef PRIu64
|
|
||||||
#undef PRIx64
|
|
||||||
#undef PRIX64
|
|
||||||
#define PRId64 "lld"
|
|
||||||
#define PRIi64 "lli"
|
|
||||||
#define PRIo64 "llo"
|
|
||||||
#define PRIu64 "llu"
|
|
||||||
#define PRIx64 "llx"
|
|
||||||
#define PRIX64 "llX"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//================================== GLOBALS =================================*/
|
|
||||||
//byte g_str_buf[1024];
|
|
||||||
byte* g_str_buf;
|
|
||||||
int load_so(byteptr);
|
|
||||||
void reload_so();
|
|
||||||
void _vinit(int ___argc, voidptr ___argv);
|
|
||||||
void _vcleanup();
|
|
||||||
#define sigaction_size sizeof(sigaction);
|
|
||||||
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
|
||||||
|
|
||||||
// ============== wyhash ==============
|
// ============== wyhash ==============
|
||||||
#ifndef wyhash_final_version_3
|
#ifndef wyhash_final_version_3
|
||||||
#define wyhash_final_version_3
|
#define wyhash_final_version_3
|
||||||
|
@ -363,7 +326,6 @@ void _vcleanup();
|
||||||
|
|
||||||
//includes
|
//includes
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
|
||||||
#if defined(_MSC_VER) && defined(_M_X64)
|
#if defined(_MSC_VER) && defined(_M_X64)
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#pragma intrinsic(_umul128)
|
#pragma intrinsic(_umul128)
|
||||||
|
@ -527,15 +489,215 @@ static inline void make_secret(uint64_t seed, uint64_t *secret){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
'
|
||||||
|
c_helper_macros = '//============================== HELPER C MACROS =============================*/
|
||||||
|
//#define tos4(s, slen) ((string){.str=(s), .len=(slen)})
|
||||||
|
// `"" s` is used to enforce a string literal argument
|
||||||
|
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
||||||
|
// take the address of an rvalue
|
||||||
|
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
||||||
|
// copy something to the heap
|
||||||
|
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type)))
|
||||||
|
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
|
||||||
|
#define _IN_MAP(val, m) map_exists(m, val)
|
||||||
|
'
|
||||||
|
c_headers =
|
||||||
|
c_helper_macros + c_unsigned_comparison_functions + c_common_macros + r'
|
||||||
|
// c_headers
|
||||||
|
typedef int (*qsort_callback_func)(const void*, const void*);
|
||||||
|
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
#define VV_EXPORTED_SYMBOL extern __declspec(dllexport)
|
||||||
|
#define VV_LOCAL_SYMBOL static
|
||||||
|
#else
|
||||||
|
// 4 < gcc < 5 is used by some older Ubuntu LTS and Centos versions,
|
||||||
|
// and does not support __has_attribute(visibility) ...
|
||||||
|
#ifndef __has_attribute
|
||||||
|
#define __has_attribute(x) 0 // Compatibility with non-clang compilers.
|
||||||
|
#endif
|
||||||
|
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || (defined(__clang__) && __has_attribute(visibility))
|
||||||
|
#ifdef ARM
|
||||||
|
#define VV_EXPORTED_SYMBOL extern __attribute__((externally_visible,visibility("default")))
|
||||||
|
#else
|
||||||
|
#define VV_EXPORTED_SYMBOL extern __attribute__((visibility("default")))
|
||||||
|
#endif
|
||||||
|
#define VV_LOCAL_SYMBOL __attribute__ ((visibility ("hidden")))
|
||||||
|
#else
|
||||||
|
#define VV_EXPORTED_SYMBOL extern
|
||||||
|
#define VV_LOCAL_SYMBOL static
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__TINYC__) && defined(__has_include)
|
||||||
|
// tcc does not support has_include properly yet, turn it off completely
|
||||||
|
#undef __has_include
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#if defined __has_include
|
||||||
|
#if __has_include (<execinfo.h>)
|
||||||
|
#include <execinfo.h>
|
||||||
|
#else
|
||||||
|
// Most probably musl OR __ANDROID__ ...
|
||||||
|
int backtrace (void **__array, int __size) { return 0; }
|
||||||
|
char **backtrace_symbols (void *const *__array, int __size){ return 0; }
|
||||||
|
void backtrace_symbols_fd (void *const *__array, int __size, int __fd){}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include "fns.h"
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h> // for va_list
|
||||||
|
|
||||||
|
//================================== GLOBALS =================================*/
|
||||||
|
//byte g_str_buf[1024];
|
||||||
|
byte* g_str_buf;
|
||||||
|
int load_so(byteptr);
|
||||||
|
void reload_so();
|
||||||
|
void _vinit(int ___argc, voidptr ___argv);
|
||||||
|
void _vcleanup();
|
||||||
|
#define sigaction_size sizeof(sigaction);
|
||||||
|
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
||||||
|
|
||||||
void v_free(voidptr ptr);
|
void v_free(voidptr ptr);
|
||||||
voidptr memdup(voidptr src, int sz);
|
voidptr memdup(voidptr src, int sz);
|
||||||
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
||||||
v_free(ptr);
|
v_free(ptr); // heloe
|
||||||
return memdup(src, sz);
|
return memdup(src, sz);
|
||||||
}
|
}
|
||||||
'
|
|
||||||
c_builtin_types = '
|
|
||||||
|
#if INTPTR_MAX == INT32_MAX
|
||||||
|
#define TARGET_IS_32BIT 1
|
||||||
|
#elif INTPTR_MAX == INT64_MAX
|
||||||
|
#define TARGET_IS_64BIT 1
|
||||||
|
#else
|
||||||
|
#error "The environment is not 32 or 64-bit."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
|
||||||
|
#define TARGET_ORDER_IS_BIG
|
||||||
|
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86)
|
||||||
|
#define TARGET_ORDER_IS_LITTLE
|
||||||
|
#else
|
||||||
|
#error "Unknown architecture endianness"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <locale.h> // tolower
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h> // sleep
|
||||||
|
extern char **environ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__) && !defined(_WIN32)
|
||||||
|
#error Cygwin is not supported, please use MinGW or Visual Studio.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h> // os__wait uses wait on nix
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h> // os__wait uses wait on nix
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __DragonFly__
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h> // os__wait uses wait on nix
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/wait.h> // os__wait uses wait on nix
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NetBSD__
|
||||||
|
#include <sys/wait.h> // os__wait uses wait on nix
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __sun
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h> // os__wait uses wait on nix
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WINVER 0x0600
|
||||||
|
#ifdef _WIN32_WINNT
|
||||||
|
#undef _WIN32_WINNT
|
||||||
|
#endif
|
||||||
|
#define _WIN32_WINNT 0x0600
|
||||||
|
#ifndef WIN32_FULL
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#ifndef _UNICODE
|
||||||
|
#define _UNICODE
|
||||||
|
#endif
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <io.h> // _waccess
|
||||||
|
#include <direct.h> // _wgetcwd
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// On MSVC these are the same (as long as /volatile:ms is passed)
|
||||||
|
#define _Atomic volatile
|
||||||
|
|
||||||
|
// MSVC cannot parse some things properly
|
||||||
|
#undef EMPTY_STRUCT_DECLARATION
|
||||||
|
#undef OPTION_CAST
|
||||||
|
|
||||||
|
#define EMPTY_STRUCT_DECLARATION int ____dummy_variable
|
||||||
|
#define OPTION_CAST(x)
|
||||||
|
#undef __NOINLINE
|
||||||
|
#undef __IRQHANDLER
|
||||||
|
#define __NOINLINE __declspec(noinline)
|
||||||
|
#define __IRQHANDLER __declspec(naked)
|
||||||
|
|
||||||
|
#include <dbghelp.h>
|
||||||
|
#pragma comment(lib, "Dbghelp")
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#ifndef PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
|
||||||
|
// musl does not have that
|
||||||
|
#define pthread_rwlockattr_setkind_np(a, b)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// g_live_info is used by live.info()
|
||||||
|
static void* g_live_info = NULL;
|
||||||
|
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__) || (defined(_WIN32) && defined(__TINYC__))
|
||||||
|
#undef PRId64
|
||||||
|
#undef PRIi64
|
||||||
|
#undef PRIo64
|
||||||
|
#undef PRIu64
|
||||||
|
#undef PRIx64
|
||||||
|
#undef PRIX64
|
||||||
|
#define PRId64 "lld"
|
||||||
|
#define PRIi64 "lli"
|
||||||
|
#define PRIo64 "llo"
|
||||||
|
#define PRIu64 "llu"
|
||||||
|
#define PRIx64 "llx"
|
||||||
|
#define PRIX64 "llX"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _VFREESTANDING
|
||||||
|
#undef _VFREESTANDING
|
||||||
|
#endif
|
||||||
|
' + c_wyhash
|
||||||
|
c_builtin_types = '
|
||||||
//================================== builtin types ================================*/
|
//================================== builtin types ================================*/
|
||||||
typedef int64_t i64;
|
typedef int64_t i64;
|
||||||
typedef int16_t i16;
|
typedef int16_t i16;
|
||||||
|
@ -569,12 +731,79 @@ typedef bool (*MapEqFn)(voidptr, voidptr);
|
||||||
typedef void (*MapCloneFn)(voidptr, voidptr);
|
typedef void (*MapCloneFn)(voidptr, voidptr);
|
||||||
typedef void (*MapFreeFn)(voidptr);
|
typedef void (*MapFreeFn)(voidptr);
|
||||||
'
|
'
|
||||||
bare_c_headers = '
|
bare_c_headers = c_helper_macros + c_unsigned_comparison_functions +
|
||||||
$c_common_macros
|
c_common_macros +
|
||||||
|
'
|
||||||
|
|
||||||
#ifndef exit
|
#ifndef exit
|
||||||
#define exit(rc) sys_exit(rc)
|
#define exit(rc) sys_exit(rc)
|
||||||
void sys_exit (int);
|
void sys_exit (int);
|
||||||
#endif
|
#endif
|
||||||
'
|
|
||||||
|
#define stdin 0
|
||||||
|
#define stdout 1
|
||||||
|
#define stderr 2
|
||||||
|
|
||||||
|
#define _VFREESTANDING
|
||||||
|
|
||||||
|
typedef long unsigned int size_t;
|
||||||
|
|
||||||
|
// Memory allocation related headers
|
||||||
|
// void *malloc(int size);
|
||||||
|
byte *calloc(int nitems, int size);
|
||||||
|
byte *realloc(byte *ptr, int size);
|
||||||
|
byte *memcpy(byte *dest, byte *src, int n);
|
||||||
|
byte *memset(byte *s, int c, int n);
|
||||||
|
byte *memmove(byte *dest, byte *src, int n);
|
||||||
|
|
||||||
|
// Backtrace headers
|
||||||
|
int backtrace(void **buffer, int size);
|
||||||
|
char **backtrace_symbols(void *const *buffer, int size);
|
||||||
|
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
|
||||||
|
|
||||||
|
// I/O related headers
|
||||||
|
typedef void FILE;
|
||||||
|
FILE *popen(const char *command, const char *type);
|
||||||
|
int pclose(FILE *stream);
|
||||||
|
int fgetc(FILE *stream);
|
||||||
|
char *fgets(char *s, int size, FILE *stream);
|
||||||
|
int getc(FILE *stream);
|
||||||
|
int getchar(void);
|
||||||
|
int ungetc(int c, FILE *stream);
|
||||||
|
|
||||||
|
|
||||||
|
// char manipulation headers
|
||||||
|
int toupper(int c);
|
||||||
|
int tolower(int c);
|
||||||
|
// int toupper_l(int c, locale_t locale);
|
||||||
|
// int tolower_l(int c, locale_t locale);
|
||||||
|
|
||||||
|
int isatty(int fd);
|
||||||
|
|
||||||
|
// varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky
|
||||||
|
typedef __builtin_va_list va_list;
|
||||||
|
#define va_start(a, b) __builtin_va_start(a, b)
|
||||||
|
#define va_end(a) __builtin_va_end(a)
|
||||||
|
#define va_arg(a, b) __builtin_va_arg(a, b)
|
||||||
|
#define va_copy(a, b) __builtin_va_copy(a, b)
|
||||||
|
|
||||||
|
//================================== GLOBALS =================================*/
|
||||||
|
//byte g_str_buf[1024];
|
||||||
|
byte* g_str_buf;
|
||||||
|
int load_so(byteptr);
|
||||||
|
void reload_so();
|
||||||
|
void _vinit(int ___argc, voidptr ___argv);
|
||||||
|
void _vcleanup();
|
||||||
|
#define sigaction_size sizeof(sigaction);
|
||||||
|
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
||||||
|
|
||||||
|
void v_free(voidptr ptr);
|
||||||
|
voidptr memdup(voidptr src, int sz);
|
||||||
|
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
||||||
|
v_free(ptr); // heloe
|
||||||
|
return memdup(src, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
' +
|
||||||
|
c_wyhash
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,136 +6,7 @@ import v.ast
|
||||||
import v.util
|
import v.util
|
||||||
|
|
||||||
fn (mut g Gen) write_str_fn_definitions() {
|
fn (mut g Gen) write_str_fn_definitions() {
|
||||||
// _STR function can't be defined in vlib
|
g.writeln(c_str_fn_defs)
|
||||||
g.writeln('
|
|
||||||
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, guess);
|
|
||||||
// NB: (*memsize - *nbytes) === how much free space is left at the end of the current buffer refbufp
|
|
||||||
// *memsize === total length of the buffer refbufp
|
|
||||||
// *nbytes === already occupied bytes of buffer refbufp
|
|
||||||
// guess === how many bytes were taken during the current vsnprintf run
|
|
||||||
for(;;) {
|
|
||||||
int remaining_space = *memsize - *nbytes;
|
|
||||||
if (guess < remaining_space) {
|
|
||||||
guess = vsnprintf(*refbufp + *nbytes, *memsize - *nbytes, fmt, args);
|
|
||||||
if (guess < remaining_space) { // result did fit into buffer
|
|
||||||
*nbytes += guess;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// increase buffer (somewhat exponentially)
|
|
||||||
*memsize += guess + 3 * (*memsize) / 2;
|
|
||||||
#ifdef _VGCBOEHM
|
|
||||||
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
|
||||||
#else
|
|
||||||
*refbufp = (char*)realloc((void*)*refbufp, *memsize);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
string _STR(const char *fmt, int nfmts, ...) {
|
|
||||||
va_list argptr;
|
|
||||||
int memsize = 128;
|
|
||||||
int nbytes = 0;
|
|
||||||
#ifdef _VGCBOEHM
|
|
||||||
char* buf = (char*)GC_MALLOC(memsize);
|
|
||||||
#else
|
|
||||||
char* buf = (char*)malloc(memsize);
|
|
||||||
#endif
|
|
||||||
va_start(argptr, nfmts);
|
|
||||||
for (int i=0; i<nfmts; ++i) {
|
|
||||||
int k = strlen(fmt);
|
|
||||||
bool is_fspec = false;
|
|
||||||
for (int j=0; j<k; ++j) {
|
|
||||||
if (fmt[j] == \'%\') {
|
|
||||||
j++;
|
|
||||||
if (fmt[j] != \'%\') {
|
|
||||||
is_fspec = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_fspec) {
|
|
||||||
char f = fmt[k-1];
|
|
||||||
char fup = f & 0xdf; // toupper
|
|
||||||
bool l = fmt[k-2] == \'l\';
|
|
||||||
bool ll = l && fmt[k-3] == \'l\';
|
|
||||||
if (f == \'u\' || fup == \'X\' || f == \'o\' || f == \'d\' || f == \'c\') { // int...
|
|
||||||
if (ll) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+16, va_arg(argptr, long long));
|
|
||||||
else if (l) _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, long));
|
|
||||||
else _STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+8, va_arg(argptr, int));
|
|
||||||
} else if (fup >= \'E\' && fup <= \'G\') { // floating point
|
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+10, va_arg(argptr, double));
|
|
||||||
} else if (f == \'p\') {
|
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+14, va_arg(argptr, void*));
|
|
||||||
} else if (f == \'C\') { // a C string
|
|
||||||
char* sptr = va_arg(argptr, char*);
|
|
||||||
char* fmt_no_c = (char*)v_malloc(k+4);
|
|
||||||
memcpy(fmt_no_c, fmt, k);
|
|
||||||
fmt_no_c[k-2]=\'C\';
|
|
||||||
fmt_no_c[k-1]=\'"\';
|
|
||||||
fmt_no_c[k]=\'%\';
|
|
||||||
fmt_no_c[k+1]=\'s\';
|
|
||||||
fmt_no_c[k+2]=\'"\';
|
|
||||||
fmt_no_c[k+3]=0;
|
|
||||||
_STR_PRINT_ARG(fmt_no_c, &buf, &nbytes, &memsize, k + 4 + 100, sptr);
|
|
||||||
v_free(fmt_no_c);
|
|
||||||
} else if (f == \'s\') { // v string
|
|
||||||
string s = va_arg(argptr, string);
|
|
||||||
if (fmt[k-4] == \'*\') { // %*.*s
|
|
||||||
int fwidth = va_arg(argptr, int);
|
|
||||||
if (fwidth < 0)
|
|
||||||
fwidth -= (s.len - utf8_str_visible_length(s));
|
|
||||||
else
|
|
||||||
fwidth += (s.len - utf8_str_visible_length(s));
|
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, fwidth, s.len, s.str);
|
|
||||||
} else { // %.*s
|
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k+s.len-4, s.len, s.str);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//v_panic(tos3(\'Invaid format specifier\'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_STR_PRINT_ARG(fmt, &buf, &nbytes, &memsize, k);
|
|
||||||
}
|
|
||||||
fmt += k+1;
|
|
||||||
}
|
|
||||||
va_end(argptr);
|
|
||||||
buf[nbytes] = 0;
|
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
|
||||||
//puts(\'_STR:\');
|
|
||||||
puts(buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if _VAUTOFREE
|
|
||||||
//g_cur_str = (byteptr)buf;
|
|
||||||
#endif
|
|
||||||
return tos2((byteptr)buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
string _STR_TMP(const char *fmt, ...) {
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, fmt);
|
|
||||||
size_t len = vsnprintf(0, 0, fmt, argptr) + 1;
|
|
||||||
va_end(argptr);
|
|
||||||
va_start(argptr, fmt);
|
|
||||||
vsprintf((char *)g_str_buf, fmt, argptr);
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
|
||||||
//puts(\'_STR_TMP:\');
|
|
||||||
//puts(g_str_buf);
|
|
||||||
#endif
|
|
||||||
string res = tos(g_str_buf, len);
|
|
||||||
res.is_lit = 1;
|
|
||||||
return res;
|
|
||||||
|
|
||||||
} // endof _STR_TMP
|
|
||||||
|
|
||||||
')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) string_literal(node ast.StringLiteral) {
|
fn (mut g Gen) string_literal(node ast.StringLiteral) {
|
||||||
|
|
|
@ -916,6 +916,9 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
|
||||||
|
|
||||||
mut args := []ast.AsmArg{}
|
mut args := []ast.AsmArg{}
|
||||||
args_loop: for {
|
args_loop: for {
|
||||||
|
if p.prev_tok.position().line_nr < p.tok.position().line_nr {
|
||||||
|
break
|
||||||
|
}
|
||||||
match p.tok.kind {
|
match p.tok.kind {
|
||||||
.name {
|
.name {
|
||||||
args << p.reg_or_alias()
|
args << p.reg_or_alias()
|
||||||
|
@ -976,6 +979,9 @@ fn (mut p Parser) asm_stmt(is_top_level bool) ast.AsmStmt {
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// if p.prev_tok.position().line_nr < p.tok.position().line_nr {
|
||||||
|
// break
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
mut comments := []ast.Comment{}
|
mut comments := []ast.Comment{}
|
||||||
for p.tok.kind == .comment {
|
for p.tok.kind == .comment {
|
||||||
|
|
|
@ -596,6 +596,9 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
|
||||||
res.path += '.v'
|
res.path += '.v'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !res.is_bare && res.bare_builtin_dir != '' {
|
||||||
|
eprintln('`-bare-builtin-dir` must be used with `-freestanding`')
|
||||||
|
}
|
||||||
if command == 'build-module' {
|
if command == 'build-module' {
|
||||||
res.build_mode = .build_module
|
res.build_mode = .build_module
|
||||||
res.path = args[command_pos + 1]
|
res.path = args[command_pos + 1]
|
||||||
|
|
|
@ -8,9 +8,6 @@ pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []s
|
||||||
files.sort()
|
files.sort()
|
||||||
mut all_v_files := []string{}
|
mut all_v_files := []string{}
|
||||||
for file in files {
|
for file in files {
|
||||||
if prefs.is_bare && os.join_path(dir, file).ends_with('/vlib/builtin/builtin_nix.c.v') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !file.ends_with('.v') && !file.ends_with('.vh') {
|
if !file.ends_with('.v') && !file.ends_with('.vh') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -123,22 +120,22 @@ pub fn (prefs &Preferences) should_compile_c(file string) bool {
|
||||||
// Probably something like `a.js.v`.
|
// Probably something like `a.js.v`.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if prefs.is_bare && file.ends_with('.freestanding.v') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if prefs.os == .all {
|
if prefs.os == .all {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !prefs.is_bare && file.ends_with('.freestanding.v') {
|
if prefs.backend != .x64 && file.ends_with('_x64.v') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (file.ends_with('_windows.c.v') || file.ends_with('_windows.v')) && prefs.os != .windows {
|
if prefs.os != .windows && (file.ends_with('_windows.c.v') || file.ends_with('_windows.v')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (file.ends_with('_linux.c.v') || file.ends_with('_linux.v')) && prefs.os != .linux {
|
if prefs.os != .linux && (file.ends_with('_linux.c.v') || file.ends_with('_linux.v')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (file.ends_with('_darwin.c.v') || file.ends_with('_darwin.v')) && prefs.os != .macos {
|
if prefs.os != .macos && (file.ends_with('_darwin.c.v') || file.ends_with('_darwin.v')) {
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (file.ends_with('_macos.c.v') || file.ends_with('_macos.v')) && prefs.os != .macos {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (file.ends_with('_ios.c.v') || file.ends_with('_ios.v')) && prefs.os != .ios {
|
if (file.ends_with('_ios.c.v') || file.ends_with('_ios.v')) && prefs.os != .ios {
|
||||||
|
@ -147,25 +144,28 @@ pub fn (prefs &Preferences) should_compile_c(file string) bool {
|
||||||
if file.ends_with('_nix.c.v') && prefs.os == .windows {
|
if file.ends_with('_nix.c.v') && prefs.os == .windows {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if file.ends_with('_android.c.v') && prefs.os != .android {
|
if prefs.os != .macos && (file.ends_with('_macos.c.v') || file.ends_with('_macos.v')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if file.ends_with('_freebsd.c.v') && prefs.os != .freebsd {
|
if prefs.os == .windows && file.ends_with('_nix.c.v') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if file.ends_with('_openbsd.c.v') && prefs.os != .openbsd {
|
if prefs.os != .android && file.ends_with('_android.c.v') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if file.ends_with('_netbsd.c.v') && prefs.os != .netbsd {
|
if prefs.os != .freebsd && file.ends_with('_freebsd.c.v') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if file.ends_with('_dragonfly.c.v') && prefs.os != .dragonfly {
|
if prefs.os != .openbsd && file.ends_with('_openbsd.c.v') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if file.ends_with('_solaris.c.v') && prefs.os != .solaris {
|
if prefs.os != .netbsd && file.ends_with('_netbsd.c.v') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if file.ends_with('_x64.v') && prefs.backend != .x64 {
|
if prefs.os != .dragonfly && file.ends_with('_dragonfly.c.v') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if prefs.os != .solaris && file.ends_with('_solaris.c.v') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
Loading…
Reference in New Issue