mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
run vfmt on vlib/builtin
This commit is contained in:
parent
76c800ffb6
commit
d082b3f4b9
@ -17,7 +17,7 @@ pub:
|
||||
|
||||
// Private function, used by V (`nums := []int`)
|
||||
fn new_array(mylen, cap, elm_size int) array {
|
||||
cap_ := if cap == 0 {1}else {cap}
|
||||
cap_ := if cap == 0 { 1 } else { cap }
|
||||
arr := array{
|
||||
len: mylen
|
||||
cap: cap
|
||||
@ -34,7 +34,7 @@ pub fn make(len, cap, elm_size int) array {
|
||||
|
||||
// Private function, used by V (`nums := [1, 2, 3]`)
|
||||
fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array {
|
||||
cap_ := if cap == 0 {1}else {cap}
|
||||
cap_ := if cap == 0 { 1 } else { cap }
|
||||
arr := array{
|
||||
len: len
|
||||
cap: cap
|
||||
@ -60,7 +60,7 @@ fn new_array_from_c_array_no_alloc(len, cap, elm_size int, c_array voidptr) arra
|
||||
// Private function. Doubles array capacity if needed
|
||||
fn (a mut array) ensure_cap(required int) {
|
||||
if required > a.cap {
|
||||
mut cap := if a.cap == 0 {2}else {a.cap * 2}
|
||||
mut cap := if a.cap == 0 { 2 } else { a.cap * 2 }
|
||||
for required > cap {
|
||||
cap *= 2
|
||||
}
|
||||
@ -204,7 +204,7 @@ fn (a array) right(n int) array {
|
||||
|
||||
// used internally for [2..4]
|
||||
fn (a array) slice2(start, _end int, end_max bool) array {
|
||||
end := if end_max {a.len}else {_end}
|
||||
end := if end_max { a.len } else { _end }
|
||||
return a.slice(start, end)
|
||||
}
|
||||
|
||||
@ -372,7 +372,7 @@ pub fn (b []byte) hex() string {
|
||||
// TODO: implement for all types
|
||||
pub fn copy(dst, src []byte) int {
|
||||
if dst.len > 0 && src.len > 0 {
|
||||
min := if dst.len < src.len {dst.len}else {src.len}
|
||||
min := if dst.len < src.len { dst.len } else { src.len }
|
||||
C.memcpy(dst.data, src.left(min).data, dst.element_size * min)
|
||||
return min
|
||||
}
|
||||
@ -454,7 +454,6 @@ pub fn (a []int) reduce(iter fn(accum, curr int)int, accum_start int) int {
|
||||
// array_eq<T> checks if two arrays contain all the same elements in the same order.
|
||||
// []int == []int (also for: i64, f32, f64, byte, string)
|
||||
fn array_eq<T>(a1, a2 []T) bool {
|
||||
|
||||
if a1.len != a2.len {
|
||||
return false
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
__global g_m2_buf byteptr
|
||||
@ -11,12 +10,13 @@ fn init() {
|
||||
$if windows {
|
||||
if is_atty(0) > 0 {
|
||||
C._setmode(C._fileno(C.stdin), C._O_U16TEXT)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
C._setmode(C._fileno(C.stdin), C._O_U8TEXT)
|
||||
}
|
||||
C._setmode(C._fileno(C.stdout), C._O_U8TEXT)
|
||||
C.SetConsoleMode(C.GetStdHandle(C.STD_OUTPUT_HANDLE), C.ENABLE_PROCESSED_OUTPUT | 0x0004) // ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
C.setbuf(C.stdout,0)
|
||||
C.setbuf(C.stdout, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,26 +29,31 @@ pub fn isnil(v voidptr) bool {
|
||||
return v == 0
|
||||
}
|
||||
|
||||
fn on_panic(f fn (int) int) {
|
||||
fn on_panic(f fn(int)int) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
pub fn print_backtrace_skipping_top_frames(skipframes int) {
|
||||
$if windows {
|
||||
$if msvc {
|
||||
if print_backtrace_skipping_top_frames_msvc(skipframes) { return }
|
||||
if print_backtrace_skipping_top_frames_msvc(skipframes) {
|
||||
return
|
||||
}
|
||||
}
|
||||
$if mingw {
|
||||
if print_backtrace_skipping_top_frames_mingw(skipframes) { return }
|
||||
if print_backtrace_skipping_top_frames_mingw(skipframes) {
|
||||
return
|
||||
}
|
||||
}
|
||||
} $else {
|
||||
if print_backtrace_skipping_top_frames_nix(skipframes) {
|
||||
return
|
||||
}
|
||||
}$else{
|
||||
if print_backtrace_skipping_top_frames_nix(skipframes) { return }
|
||||
}
|
||||
println('print_backtrace_skipping_top_frames is not implemented on this platform for now...\n')
|
||||
}
|
||||
|
||||
|
||||
pub fn print_backtrace(){
|
||||
pub fn print_backtrace() {
|
||||
// at the time of backtrace_symbols_fd call, the C stack would look something like this:
|
||||
// 1 frame for print_backtrace_skipping_top_frames
|
||||
// 1 frame for print_backtrace itself
|
||||
@ -58,7 +63,7 @@ pub fn print_backtrace(){
|
||||
}
|
||||
|
||||
// replaces panic when -debug arg is passed
|
||||
fn panic_debug(line_no int, file, mod, fn_name, s string) {
|
||||
fn panic_debug(line_no int, file, mod, fn_name, s string) {
|
||||
println('================ V panic ================')
|
||||
println(' module: $mod')
|
||||
println(' function: ${fn_name}()')
|
||||
@ -99,9 +104,8 @@ pub fn print(s string) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__global total_m i64 = 0
|
||||
__global nr_mallocs int = 0
|
||||
__global total_m i64=0
|
||||
__global nr_mallocs int=0
|
||||
|
||||
[unsafe_fn]
|
||||
pub fn malloc(n int) byteptr {
|
||||
@ -120,7 +124,7 @@ pub fn malloc(n int) byteptr {
|
||||
}
|
||||
return ptr
|
||||
}
|
||||
/*
|
||||
/*
|
||||
TODO
|
||||
#ifdef VPLAY
|
||||
if n > 10000 {
|
||||
@ -133,6 +137,7 @@ TODO
|
||||
print_backtrace()
|
||||
#endif
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
pub fn calloc(n int) byteptr {
|
||||
@ -166,3 +171,4 @@ pub fn is_atty(fd int) int {
|
||||
return C.isatty(fd)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
pub fn println(s string) {
|
||||
@ -20,9 +19,15 @@ fn print_backtrace_skipping_top_frames_mingw(skipframes int) bool {
|
||||
|
||||
fn print_backtrace_skipping_top_frames_nix(xskipframes int) bool {
|
||||
skipframes := xskipframes + 2
|
||||
$if macos { return print_backtrace_skipping_top_frames_mac(skipframes) }
|
||||
$if linux { return print_backtrace_skipping_top_frames_linux(skipframes) }
|
||||
$if freebsd { return print_backtrace_skipping_top_frames_freebsd(skipframes) }
|
||||
$if macos {
|
||||
return print_backtrace_skipping_top_frames_mac(skipframes)
|
||||
}
|
||||
$if linux {
|
||||
return print_backtrace_skipping_top_frames_linux(skipframes)
|
||||
}
|
||||
$if freebsd {
|
||||
return print_backtrace_skipping_top_frames_freebsd(skipframes)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -30,20 +35,20 @@ fn print_backtrace_skipping_top_frames_nix(xskipframes int) bool {
|
||||
// so there is no need to have their twins in builtin_windows.v
|
||||
fn print_backtrace_skipping_top_frames_mac(skipframes int) bool {
|
||||
$if macos {
|
||||
buffer := [100]byteptr
|
||||
nr_ptrs := C.backtrace(*voidptr(buffer), 100)
|
||||
C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs-skipframes, 1)
|
||||
buffer := [100]byteptr
|
||||
nr_ptrs := C.backtrace(*voidptr(buffer), 100)
|
||||
C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs - skipframes, 1)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn print_backtrace_skipping_top_frames_freebsd(skipframes int) bool {
|
||||
$if freebsd {
|
||||
buffer := [100]byteptr
|
||||
nr_ptrs := C.backtrace(*voidptr(buffer), 100)
|
||||
C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs-skipframes, 1)
|
||||
}
|
||||
return true
|
||||
buffer := [100]byteptr
|
||||
nr_ptrs := C.backtrace(*voidptr(buffer), 100)
|
||||
C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs - skipframes, 1)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
|
||||
@ -51,44 +56,50 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
|
||||
println('TODO: print_backtrace_skipping_top_frames_linux $skipframes with tcc fails tests with "stack smashing detected" .')
|
||||
return false
|
||||
}
|
||||
$if !android { // backtrace is not available on Android.
|
||||
$if !android {
|
||||
// backtrace is not available on Android.
|
||||
$if glibc {
|
||||
buffer := [100]byteptr
|
||||
nr_ptrs := C.backtrace(*voidptr(buffer), 100)
|
||||
nr_actual_frames := nr_ptrs-skipframes
|
||||
nr_actual_frames := nr_ptrs - skipframes
|
||||
mut sframes := []string
|
||||
csymbols := C.backtrace_symbols(*voidptr(&buffer[skipframes]),
|
||||
nr_actual_frames)
|
||||
for i in 0..nr_actual_frames { sframes << tos2(csymbols[i]) }
|
||||
csymbols := C.backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
|
||||
for i in 0 .. nr_actual_frames {
|
||||
sframes << tos2(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(cmd.str, 'r')
|
||||
if isnil(f) {
|
||||
println(sframe) continue
|
||||
println(sframe)
|
||||
continue
|
||||
}
|
||||
buf := [1000]byte
|
||||
mut output := ''
|
||||
for C.fgets(voidptr(buf), 1000, f) != 0 {
|
||||
output += tos(buf, vstrlen(buf))
|
||||
}
|
||||
output = output.trim_space()+':'
|
||||
output = output.trim_space() + ':'
|
||||
if 0 != C.pclose(f) {
|
||||
println(sframe) continue
|
||||
println(sframe)
|
||||
continue
|
||||
}
|
||||
if output in ['??:0:','??:?:'] { output = '' }
|
||||
println( '${output:-46s} | ${addr:14s} | $beforeaddr')
|
||||
if output in ['??:0:', '??:?:'] {
|
||||
output = ''
|
||||
}
|
||||
println('${output:-46s} | ${addr:14s} | $beforeaddr')
|
||||
}
|
||||
//C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_actual_frames, 1)
|
||||
// C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_actual_frames, 1)
|
||||
return true
|
||||
}$else{
|
||||
} $else {
|
||||
C.printf('backtrace_symbols_fd is missing, so printing backtraces is not available.\n')
|
||||
C.printf('Some libc implementations like musl simply do not provide it.\n')
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -1,166 +1,403 @@
|
||||
module builtin
|
||||
|
||||
|
||||
// <string.h>
|
||||
fn C.memcpy(byteptr, byteptr, int) voidptr
|
||||
fn C.memmove(byteptr, byteptr, int) voidptr
|
||||
|
||||
//fn C.malloc(int) byteptr
|
||||
|
||||
fn C.memmove(byteptr, byteptr, int) voidptr
|
||||
// fn C.malloc(int) byteptr
|
||||
fn C.realloc(a byteptr, b int) byteptr
|
||||
|
||||
|
||||
fn C.qsort(voidptr, int, int, voidptr)
|
||||
|
||||
fn C.sprintf(a ...voidptr) byteptr
|
||||
fn C.strlen(s byteptr) int
|
||||
fn C.isdigit(s byteptr) bool
|
||||
|
||||
fn C.sprintf(a ...voidptr) byteptr
|
||||
|
||||
|
||||
fn C.strlen(s byteptr) int
|
||||
|
||||
|
||||
fn C.isdigit(s byteptr) bool
|
||||
// stdio.h
|
||||
fn C.popen(c byteptr, t byteptr) voidptr
|
||||
|
||||
// <execinfo.h>
|
||||
fn backtrace(a voidptr, b int) int
|
||||
fn backtrace_symbols(voidptr, int) &byteptr
|
||||
fn backtrace_symbols_fd(voidptr, int, int)
|
||||
|
||||
|
||||
fn backtrace_symbols(voidptr, int) &byteptr
|
||||
|
||||
|
||||
fn backtrace_symbols_fd(voidptr, int, int)
|
||||
// <libproc.h>
|
||||
fn proc_pidpath(int, voidptr, int) int
|
||||
|
||||
|
||||
fn C.realpath(byteptr, byteptr) &char
|
||||
|
||||
|
||||
|
||||
|
||||
fn C.chmod(byteptr, int) int
|
||||
|
||||
|
||||
fn C.printf(byteptr, ...byteptr) int
|
||||
|
||||
|
||||
fn C.fputs(byteptr) int
|
||||
|
||||
|
||||
fn C.fflush(byteptr) int
|
||||
// TODO define args in these functions
|
||||
fn C.fseek() int
|
||||
|
||||
|
||||
fn C.fopen() voidptr
|
||||
|
||||
|
||||
fn C.fwrite() int
|
||||
|
||||
|
||||
fn C.fclose() int
|
||||
|
||||
|
||||
fn C.pclose() int
|
||||
|
||||
|
||||
fn C.system() int
|
||||
|
||||
|
||||
fn C.setenv() int
|
||||
|
||||
|
||||
fn C.unsetenv() int
|
||||
|
||||
|
||||
fn C.access() int
|
||||
|
||||
|
||||
fn C.remove() int
|
||||
|
||||
|
||||
fn C.rmdir() int
|
||||
|
||||
|
||||
fn C.chdir() int
|
||||
|
||||
|
||||
fn C.fread() int
|
||||
|
||||
|
||||
fn C.rewind() int
|
||||
|
||||
|
||||
fn C.stat() int
|
||||
|
||||
|
||||
fn C.lstat() int
|
||||
|
||||
|
||||
fn C.rename() int
|
||||
|
||||
|
||||
fn C.fgets() int
|
||||
|
||||
|
||||
fn C.memset() int
|
||||
|
||||
|
||||
fn C.sigemptyset() int
|
||||
|
||||
|
||||
fn C.getcwd() int
|
||||
|
||||
|
||||
fn C.signal() int
|
||||
|
||||
|
||||
fn C.mktime() int
|
||||
|
||||
|
||||
fn C.gettimeofday() int
|
||||
|
||||
|
||||
fn C.sleep() int
|
||||
|
||||
|
||||
fn C.usleep() int
|
||||
|
||||
|
||||
fn C.opendir() voidptr
|
||||
|
||||
|
||||
fn C.closedir() int
|
||||
|
||||
|
||||
fn C.mkdir() int
|
||||
|
||||
|
||||
fn C.srand() int
|
||||
|
||||
|
||||
fn C.atof() int
|
||||
|
||||
|
||||
fn C.tolower() int
|
||||
|
||||
|
||||
fn C.toupper() int
|
||||
|
||||
|
||||
fn C.getchar() int
|
||||
|
||||
|
||||
fn C.strerror() charptr
|
||||
|
||||
|
||||
fn C.snprintf() int
|
||||
|
||||
|
||||
fn C.fprintf(byteptr, ...byteptr)
|
||||
|
||||
|
||||
fn C.WIFEXITED() bool
|
||||
|
||||
|
||||
fn C.WEXITSTATUS() int
|
||||
|
||||
|
||||
fn C.WIFSIGNALED() bool
|
||||
|
||||
|
||||
fn C.WTERMSIG() int
|
||||
|
||||
|
||||
fn C.DEFAULT_LE() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_EQ() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_GT() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_EQUAL() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_NOT_EQUAL() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_LT() bool
|
||||
|
||||
|
||||
fn C.DEFAULT_GE() bool
|
||||
|
||||
|
||||
fn C.isatty() int
|
||||
|
||||
|
||||
fn C.syscall() int
|
||||
|
||||
|
||||
fn C.sysctl() int
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Windows
|
||||
fn C._setmode(int, int) int
|
||||
|
||||
|
||||
fn C._fileno(int) int
|
||||
|
||||
|
||||
fn C._get_osfhandle(fd int) C.intptr_t
|
||||
|
||||
|
||||
fn C.GetModuleFileNameW(hModule voidptr, lpFilename &u16, nSize u32) u32
|
||||
|
||||
|
||||
fn C.CreatePipe(hReadPipe &voidptr, hWritePipe &voidptr, lpPipeAttributes voidptr, nSize u32) bool
|
||||
|
||||
|
||||
fn C.SetHandleInformation(hObject voidptr, dwMask u32, dwFlags u32) bool
|
||||
|
||||
|
||||
fn C.ExpandEnvironmentStringsW(lpSrc &u16, lpDst &u16, nSize u32) u32
|
||||
|
||||
|
||||
fn C.CreateProcessW(lpApplicationName &u16, lpCommandLine &u16, lpProcessAttributes voidptr, lpThreadAttributes voidptr, bInheritHandles bool, dwCreationFlags u32, lpEnvironment voidptr, lpCurrentDirectory &u16, lpStartupInfo voidptr, lpProcessInformation voidptr) bool
|
||||
|
||||
|
||||
fn C.ReadFile(hFile voidptr, lpBuffer voidptr, nNumberOfBytesToRead u32, lpNumberOfBytesRead voidptr, lpOverlapped voidptr) bool
|
||||
|
||||
|
||||
fn C.GetFileAttributesW(lpFileName byteptr) u32
|
||||
|
||||
|
||||
fn C.RegQueryValueExW(hKey voidptr, lpValueName &u16, lpReserved &u32, lpType &u32, lpData byteptr, lpcbData &u32) int
|
||||
|
||||
|
||||
fn C.RegOpenKeyExW(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) int
|
||||
|
||||
|
||||
fn C.RegCloseKey()
|
||||
|
||||
|
||||
fn C.RegQueryValueEx() voidptr
|
||||
|
||||
|
||||
fn C.RemoveDirectory() int
|
||||
|
||||
|
||||
fn C.GetStdHandle() voidptr
|
||||
|
||||
|
||||
fn C.SetConsoleMode()
|
||||
|
||||
|
||||
fn C.GetConsoleMode() int
|
||||
|
||||
|
||||
fn C._putws()
|
||||
|
||||
|
||||
fn C.wprintf()
|
||||
|
||||
|
||||
fn C.setbuf()
|
||||
|
||||
|
||||
fn C.SymCleanup()
|
||||
|
||||
|
||||
fn C.MultiByteToWideChar() int
|
||||
|
||||
|
||||
fn C.wcslen() int
|
||||
|
||||
|
||||
fn C.WideCharToMultiByte() int
|
||||
|
||||
|
||||
fn C._wstat()
|
||||
|
||||
|
||||
fn C._wrename()
|
||||
|
||||
|
||||
fn C._wfopen() voidptr
|
||||
|
||||
|
||||
fn C._wpopen() voidptr
|
||||
|
||||
|
||||
fn C._pclose() int
|
||||
|
||||
|
||||
fn C._wsystem() int
|
||||
|
||||
|
||||
fn C._wgetenv() voidptr
|
||||
|
||||
|
||||
fn C._putenv() int
|
||||
|
||||
|
||||
fn C._waccess() int
|
||||
|
||||
|
||||
fn C._wremove()
|
||||
|
||||
|
||||
fn C.ReadConsole()
|
||||
|
||||
|
||||
fn C.fgetws() voidptr
|
||||
|
||||
|
||||
fn C.GetModuleFileName() int
|
||||
|
||||
|
||||
fn C._wchdir()
|
||||
|
||||
|
||||
fn C._wgetcwd() int
|
||||
|
||||
|
||||
fn C._fullpath() int
|
||||
|
||||
|
||||
fn C.GetCommandLine() voidptr
|
||||
|
||||
|
||||
fn C.CommandLineToArgvW() &voidptr
|
||||
|
||||
|
||||
fn C.LocalFree()
|
||||
|
||||
|
||||
fn C.FindFirstFileW() voidptr
|
||||
|
||||
|
||||
fn C.FindFirstFile() voidptr
|
||||
|
||||
|
||||
fn C.FindNextFile() voidptr
|
||||
|
||||
|
||||
fn C.FindClose()
|
||||
|
||||
|
||||
fn C.MAKELANGID() int
|
||||
|
||||
|
||||
fn C.FormatMessage() voidptr
|
||||
|
||||
|
||||
fn C.CloseHandle()
|
||||
|
||||
|
||||
fn C.GetExitCodeProcess()
|
||||
|
||||
|
||||
fn C.RegOpenKeyEx() voidptr
|
||||
|
||||
|
||||
fn C.GetTickCount() i64
|
||||
|
||||
|
||||
fn C.Sleep()
|
||||
|
||||
|
||||
fn C.WSAStartup(u16, &voidptr) int
|
||||
|
||||
|
||||
fn C.WSAGetLastError() int
|
||||
|
||||
|
||||
fn C.closesocket(int) int
|
||||
|
||||
|
||||
fn C.vschannel_init(&C.TlsContext)
|
||||
fn C.request(&C.TlsContext,int, &u16, byteptr, &byteptr)
|
||||
|
||||
|
||||
fn C.request(&C.TlsContext, int, &u16, byteptr, &byteptr)
|
||||
|
||||
|
||||
fn C.vschannel_cleanup(&C.TlsContext)
|
||||
fn C.URLDownloadToFile(int, &u16,&u16, int, int)
|
||||
|
||||
|
||||
fn C.URLDownloadToFile(int, &u16, &u16, int, int)
|
||||
|
||||
|
||||
fn C.GetLastError() u32
|
||||
|
||||
|
||||
fn C.CreateDirectory(byteptr, int) bool
|
||||
fn C.BCryptGenRandom(int,voidptr,int,int) int
|
||||
fn C.CreateMutex(int,bool,byteptr) voidptr
|
||||
fn C.WaitForSingleObject(voidptr,int) int
|
||||
|
||||
|
||||
fn C.BCryptGenRandom(int, voidptr, int, int) int
|
||||
|
||||
|
||||
fn C.CreateMutex(int, bool, byteptr) voidptr
|
||||
|
||||
|
||||
fn C.WaitForSingleObject(voidptr, int) int
|
||||
|
||||
|
||||
fn C.ReleaseMutex(voidptr) bool
|
||||
|
||||
|
@ -143,3 +143,4 @@ fn (a f64) gebit(b f64) bool {
|
||||
fn (a f32) gebit(b f32) bool {
|
||||
return C.DEFAULT_GE(a, b)
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
/*
|
||||
This is work in progress.
|
||||
A very early test version of the hashmap with a fixed size.
|
||||
@ -14,69 +12,78 @@ module builtin
|
||||
the performance gains are basically non-existent.
|
||||
*/
|
||||
|
||||
|
||||
struct hashmap {
|
||||
cap int
|
||||
keys []string
|
||||
table []hashmapentry
|
||||
elm_size int
|
||||
cap int
|
||||
keys []string
|
||||
table []hashmapentry
|
||||
elm_size int
|
||||
pub:
|
||||
nr_collisions int
|
||||
}
|
||||
|
||||
struct hashmapentry {
|
||||
key string
|
||||
val int
|
||||
next &hashmapentry // linked list for collisions
|
||||
key string
|
||||
val int
|
||||
next &hashmapentry // linked list for collisions
|
||||
}
|
||||
|
||||
const (
|
||||
min_cap = 2 << 10
|
||||
max_cap = 2 << 20
|
||||
min_cap = 2<<10
|
||||
max_cap = 2<<20
|
||||
)
|
||||
|
||||
fn new_hashmap(planned_nr_items int) hashmap {
|
||||
mut cap := planned_nr_items * 5
|
||||
if cap < min_cap {
|
||||
cap = min_cap
|
||||
}
|
||||
}
|
||||
if cap > max_cap {
|
||||
cap = max_cap
|
||||
}
|
||||
}
|
||||
return hashmap{
|
||||
cap: cap
|
||||
elm_size: 4
|
||||
table: make(cap, cap, sizeof(hashmapentry))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (m mut hashmap) set(key string, val int) {
|
||||
mut hash := int(b_fabs( key.hash() ))
|
||||
mut hash := int(b_fabs(key.hash()))
|
||||
idx := hash % m.cap
|
||||
if m.table[idx].key.len != 0 {
|
||||
//println('\nset() idx=$idx key="$key" hash="$hash" val=$val')
|
||||
// println('\nset() idx=$idx key="$key" hash="$hash" val=$val')
|
||||
m.nr_collisions++
|
||||
//println('collision:' + m.table[idx].key)
|
||||
// println('collision:' + m.table[idx].key)
|
||||
mut e := &m.table[idx]
|
||||
for e.next != 0 {
|
||||
e = e.next
|
||||
}
|
||||
e.next = &hashmapentry{key, val, 0}
|
||||
} else {
|
||||
m.table[idx] = hashmapentry{key, val, 0}
|
||||
}
|
||||
e.next = &hashmapentry{
|
||||
key,val,0}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m.table[idx] = hashmapentry{
|
||||
key,val,0}
|
||||
}
|
||||
}
|
||||
|
||||
fn (m mut hashmap) get(key string) int {
|
||||
hash := int(b_fabs( key.hash() ))
|
||||
hash := int(b_fabs(key.hash()))
|
||||
idx := hash % m.cap
|
||||
mut e := &m.table[idx]
|
||||
for e.next != 0 { // todo unsafe {
|
||||
for e.next != 0 {
|
||||
// todo unsafe {
|
||||
if e.key == key {
|
||||
return e.val
|
||||
}
|
||||
}
|
||||
e = e.next
|
||||
}
|
||||
}
|
||||
return e.val
|
||||
}
|
||||
|
||||
[inline] fn b_fabs(v int) f64 { return if v < 0 { -v } else { v } }
|
||||
[inline]
|
||||
fn b_fabs(v int) f64 {
|
||||
return if v < 0 { -v } else { v }
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
pub fn ptr_str(ptr voidptr) string {
|
||||
buf := malloc(sizeof(double) * 5 + 1)// TODO
|
||||
buf := malloc(sizeof(double) * 5 + 1) // TODO
|
||||
C.sprintf(charptr(buf), '%p', ptr)
|
||||
return tos(buf, vstrlen(buf))
|
||||
}
|
||||
@ -19,7 +18,7 @@ pub fn (nn int) str() string {
|
||||
return '0'
|
||||
}
|
||||
max := 16
|
||||
mut buf := calloc(max+1)
|
||||
mut buf := calloc(max + 1)
|
||||
mut len := 0
|
||||
mut is_neg := false
|
||||
if n < 0 {
|
||||
@ -42,12 +41,20 @@ pub fn (nn int) str() string {
|
||||
return tos(buf + max - len, len)
|
||||
}
|
||||
|
||||
pub fn (n i8) str() string { return int(n).str() }
|
||||
pub fn (n i16) str() string { return int(n).str() }
|
||||
pub fn (n u16) str() string { return int(n).str() }
|
||||
pub fn (n i8) str() string {
|
||||
return int(n).str()
|
||||
}
|
||||
|
||||
pub fn (n i16) str() string {
|
||||
return int(n).str()
|
||||
}
|
||||
|
||||
pub fn (n u16) str() string {
|
||||
return int(n).str()
|
||||
}
|
||||
|
||||
pub fn (nn u32) str() string {
|
||||
mut n := nn
|
||||
mut n := nn
|
||||
if n == u32(0) {
|
||||
return '0'
|
||||
}
|
||||
@ -84,6 +91,7 @@ pub fn (nn byte) str() string {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
pub fn (nn i64) str() string {
|
||||
mut n := nn
|
||||
if n == i64(0) {
|
||||
@ -113,7 +121,7 @@ pub fn (nn i64) str() string {
|
||||
}
|
||||
|
||||
pub fn (nn u64) str() string {
|
||||
mut n := nn
|
||||
mut n := nn
|
||||
if n == u64(0) {
|
||||
return '0'
|
||||
}
|
||||
@ -138,24 +146,16 @@ pub fn (b bool) str() string {
|
||||
}
|
||||
|
||||
pub fn (n int) hex() string {
|
||||
len := if n >= 0 {
|
||||
n.str().len + 3
|
||||
} else {
|
||||
11
|
||||
}
|
||||
len := if n >= 0 { n.str().len + 3 } else { 11 }
|
||||
hex := malloc(len) // 0x + \n
|
||||
count := int(C.sprintf(charptr(hex), '0x%x', n))
|
||||
return tos(hex, count)
|
||||
}
|
||||
|
||||
pub fn (n i64) hex() string {
|
||||
len := if n >= i64(0) {
|
||||
n.str().len + 3
|
||||
} else {
|
||||
19
|
||||
}
|
||||
len := if n >= i64(0) { n.str().len + 3 } else { 19 }
|
||||
hex := malloc(len)
|
||||
count := int(C.sprintf(charptr(hex), '0x%' C.PRIx64, n))
|
||||
count := int(C.sprintf(charptr(hex), '0x%'C.PRIx64, n))
|
||||
return tos(hex, count)
|
||||
}
|
||||
|
||||
@ -169,21 +169,21 @@ pub fn (a []byte) contains(val byte) bool {
|
||||
}
|
||||
|
||||
pub fn (c rune) str() string {
|
||||
fst_byte := int(c) >> 8 * 3 & 0xff
|
||||
fst_byte := int(c)>>8 * 3 & 0xff
|
||||
len := utf8_char_len(fst_byte)
|
||||
mut str := string {
|
||||
mut str := string{
|
||||
len: len
|
||||
str: malloc(len + 1)
|
||||
}
|
||||
for i := 0; i < len; i++ {
|
||||
str.str[i] = int(c) >> 8 * (3 - i) & 0xff
|
||||
str.str[i] = int(c)>>8 * (3 - i) & 0xff
|
||||
}
|
||||
str[len] = `\0`
|
||||
return str
|
||||
}
|
||||
|
||||
pub fn (c byte) str() string {
|
||||
mut str := string {
|
||||
mut str := string{
|
||||
len: 1
|
||||
str: malloc(2)
|
||||
}
|
||||
|
@ -1,28 +1,27 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
import strings
|
||||
|
||||
pub struct map {
|
||||
element_size int
|
||||
root &mapnode
|
||||
root &mapnode
|
||||
pub:
|
||||
size int
|
||||
size int
|
||||
}
|
||||
|
||||
struct mapnode {
|
||||
left &mapnode
|
||||
right &mapnode
|
||||
left &mapnode
|
||||
right &mapnode
|
||||
is_empty bool // set by delete()
|
||||
key string
|
||||
val voidptr
|
||||
key string
|
||||
val voidptr
|
||||
}
|
||||
|
||||
fn new_map(cap, elm_size int) map {
|
||||
res := map {
|
||||
res := map{
|
||||
element_size: elm_size
|
||||
root: 0
|
||||
}
|
||||
@ -31,7 +30,7 @@ fn new_map(cap, elm_size int) map {
|
||||
|
||||
// `m := { 'one': 1, 'two': 2 }`
|
||||
fn new_map_init(cap, elm_size int, keys &string, vals voidptr) map {
|
||||
mut res := map {
|
||||
mut res := map{
|
||||
element_size: elm_size
|
||||
root: 0
|
||||
}
|
||||
@ -42,7 +41,7 @@ fn new_map_init(cap, elm_size int, keys &string, vals voidptr) map {
|
||||
}
|
||||
|
||||
fn new_node(key string, val voidptr, element_size int) &mapnode {
|
||||
new_e := &mapnode {
|
||||
new_e := &mapnode{
|
||||
key: key
|
||||
val: malloc(element_size)
|
||||
left: 0
|
||||
@ -65,7 +64,8 @@ fn (m mut map) insert(n mut mapnode, key string, val voidptr) {
|
||||
if n.left == 0 {
|
||||
n.left = new_node(key, val, m.element_size)
|
||||
m.size++
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
m.insert(mut n.left, key, val)
|
||||
}
|
||||
return
|
||||
@ -73,12 +73,13 @@ fn (m mut map) insert(n mut mapnode, key string, val voidptr) {
|
||||
if n.right == 0 {
|
||||
n.right = new_node(key, val, m.element_size)
|
||||
m.size++
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
m.insert(mut n.right, key, val)
|
||||
}
|
||||
}
|
||||
|
||||
fn (n & mapnode) find(key string, out voidptr, element_size int) bool{
|
||||
fn (n &mapnode) find(key string, out voidptr, element_size int) bool {
|
||||
if n.key == key {
|
||||
C.memcpy(out, n.val, element_size)
|
||||
return true
|
||||
@ -86,35 +87,39 @@ fn (n & mapnode) find(key string, out voidptr, element_size int) bool{
|
||||
else if n.key > key {
|
||||
if n.left == 0 {
|
||||
return false
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return n.left.find(key, out, element_size)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if n.right == 0 {
|
||||
return false
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return n.right.find(key, out, element_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// same as `find`, but doesn't return a value. Used by `exists`
|
||||
fn (n & mapnode) find2(key string, element_size int) bool{
|
||||
fn (n &mapnode) find2(key string, element_size int) bool {
|
||||
if n.key == key && !n.is_empty {
|
||||
return true
|
||||
}
|
||||
else if n.key > key {
|
||||
if isnil(n.left) {
|
||||
return false
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return n.left.find2(key, element_size)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if isnil(n.right) {
|
||||
return false
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return n.right.find2(key, element_size)
|
||||
}
|
||||
}
|
||||
@ -156,6 +161,7 @@ fn (m map) bs(query string, start, end int, out voidptr) {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
fn preorder_keys(node &mapnode, keys mut []string, key_i int) int {
|
||||
mut i := key_i
|
||||
if !node.is_empty {
|
||||
@ -181,7 +187,7 @@ pub fn (m &map) keys() []string {
|
||||
}
|
||||
|
||||
fn (m map) get(key string, out voidptr) bool {
|
||||
//println('g')
|
||||
// println('g')
|
||||
if m.root == 0 {
|
||||
return false
|
||||
}
|
||||
@ -197,14 +203,16 @@ pub fn (n mut mapnode) delete(key string, element_size int) {
|
||||
else if n.key > key {
|
||||
if isnil(n.left) {
|
||||
return
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
n.left.delete(key, element_size)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if isnil(n.right) {
|
||||
return
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
n.right.delete(key, element_size)
|
||||
}
|
||||
}
|
||||
@ -223,10 +231,10 @@ fn (m map) exists(key string) bool {
|
||||
|
||||
pub fn (m map) print() {
|
||||
println('<<<<<<<<')
|
||||
//for i := 0; i < m.entries.len; i++ {
|
||||
// entry := m.entries[i]
|
||||
// println('$entry.key => $entry.val')
|
||||
//}
|
||||
// for i := 0; i < m.entries.len; i++ {
|
||||
// entry := m.entries[i]
|
||||
// println('$entry.key => $entry.val')
|
||||
// }
|
||||
/*
|
||||
for i := 0; i < m.cap * m.element_size; i++ {
|
||||
b := m.table[i]
|
||||
@ -235,6 +243,7 @@ pub fn (m map) print() {
|
||||
println('')
|
||||
}
|
||||
*/
|
||||
|
||||
println('>>>>>>>>>>')
|
||||
}
|
||||
|
||||
@ -266,9 +275,10 @@ pub fn (m map_string) str() string {
|
||||
}
|
||||
mut sb := strings.new_builder(50)
|
||||
sb.writeln('{')
|
||||
for key, val in m {
|
||||
for key, val in m {
|
||||
sb.writeln(' "$key" => "$val"')
|
||||
}
|
||||
sb.writeln('}')
|
||||
return sb.str()
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
/*
|
||||
struct Option2<T> {
|
||||
data T
|
||||
@ -14,12 +12,13 @@ struct Option2<T> {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
struct Option {
|
||||
data [300]byte
|
||||
error string
|
||||
ecode int
|
||||
ok bool
|
||||
is_none bool
|
||||
data [300]byte
|
||||
error string
|
||||
ecode int
|
||||
ok bool
|
||||
is_none bool
|
||||
}
|
||||
|
||||
// `fn foo() ?Foo { return foo }` => `fn foo() ?Foo { return opt_ok(foo); }`
|
||||
@ -27,7 +26,7 @@ fn opt_ok(data voidptr, size int) Option {
|
||||
if size >= 300 {
|
||||
panic('option size too big: $size (max is 300), this is a temporary limit')
|
||||
}
|
||||
res := Option {
|
||||
res := Option{
|
||||
ok: true
|
||||
}
|
||||
C.memcpy(res.data, data, size)
|
||||
@ -36,21 +35,21 @@ fn opt_ok(data voidptr, size int) Option {
|
||||
|
||||
// used internally when returning `none`
|
||||
fn opt_none() Option {
|
||||
return Option{ is_none: true }
|
||||
return Option{
|
||||
is_none: true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error(s string) Option {
|
||||
return Option {
|
||||
return Option{
|
||||
error: s
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_with_code(s string, code int) Option {
|
||||
return Option {
|
||||
return Option{
|
||||
error: s
|
||||
ecode: code
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
import strconv
|
||||
|
||||
/*
|
||||
NB: A V string should be/is immutable from the point of view of
|
||||
V user programs after it is first created. A V string is
|
||||
@ -45,11 +43,11 @@ NB: A V string should be/is immutable from the point of view of
|
||||
|
||||
|
||||
pub struct string {
|
||||
//mut:
|
||||
//hash_cache int
|
||||
// mut:
|
||||
// hash_cache int
|
||||
pub:
|
||||
str byteptr // points to a C style 0 terminated string of bytes.
|
||||
len int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str).
|
||||
len int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str).
|
||||
}
|
||||
|
||||
pub struct ustring {
|
||||
@ -70,7 +68,7 @@ pub fn tos(s byteptr, len int) string {
|
||||
if s == 0 {
|
||||
panic('tos(): nil string')
|
||||
}
|
||||
return string {
|
||||
return string{
|
||||
str: s
|
||||
len: len
|
||||
}
|
||||
@ -89,7 +87,7 @@ pub fn tos2(s byteptr) string {
|
||||
if s == 0 {
|
||||
panic('tos2: nil string')
|
||||
}
|
||||
return string {
|
||||
return string{
|
||||
str: s
|
||||
len: vstrlen(s)
|
||||
}
|
||||
@ -100,14 +98,14 @@ pub fn tos3(s charptr) string {
|
||||
if s == 0 {
|
||||
panic('tos3: nil string')
|
||||
}
|
||||
return string {
|
||||
return string{
|
||||
str: byteptr(s)
|
||||
len: C.strlen(s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (a string) clone() string {
|
||||
mut b := string {
|
||||
mut b := string{
|
||||
len: a.len
|
||||
str: malloc(a.len + 1)
|
||||
}
|
||||
@ -128,14 +126,16 @@ pub fn (s string) cstr() byteptr {
|
||||
// cstring_to_vstring creates a copy of cstr and turns it into a v string
|
||||
pub fn cstring_to_vstring(cstr byteptr) string {
|
||||
slen := C.strlen(cstr)
|
||||
mut s := byteptr( memdup(cstr, slen+1) )
|
||||
mut s := byteptr(memdup(cstr, slen + 1))
|
||||
s[slen] = `\0`
|
||||
return tos(s, slen)
|
||||
}
|
||||
|
||||
pub fn (s string) replace_once(rep, with string) string {
|
||||
index := s.index(rep) or { return s }
|
||||
return s.substr(0,index) + with + s.substr(index + rep.len, s.len)
|
||||
index := s.index(rep) or {
|
||||
return s
|
||||
}
|
||||
return s.substr(0, index) + with + s.substr(index + rep.len, s.len)
|
||||
}
|
||||
|
||||
pub fn (s string) replace(rep, with string) string {
|
||||
@ -160,7 +160,7 @@ pub fn (s string) replace(rep, with string) string {
|
||||
}
|
||||
// Now we know the number of replacements we need to do and we can calc the len of the new string
|
||||
new_len := s.len + idxs.len * (with.len - rep.len)
|
||||
mut b := malloc(new_len + 1)// add a newline just in case
|
||||
mut b := malloc(new_len + 1) // add a newline just in case
|
||||
// Fill the new string
|
||||
mut idx_pos := 0
|
||||
mut cur_idx := idxs[idx_pos]
|
||||
@ -191,7 +191,7 @@ pub fn (s string) replace(rep, with string) string {
|
||||
}
|
||||
|
||||
struct RepIndex {
|
||||
idx int
|
||||
idx int
|
||||
val_idx int
|
||||
}
|
||||
|
||||
@ -199,7 +199,6 @@ fn (a mut []RepIndex) sort() {
|
||||
a.sort_with_compare(compare_rep_index)
|
||||
}
|
||||
|
||||
|
||||
// TODO
|
||||
/*
|
||||
fn (a RepIndex) < (b RepIndex) bool {
|
||||
@ -207,6 +206,7 @@ fn (a RepIndex) < (b RepIndex) bool {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
fn compare_rep_index(a, b &RepIndex) int {
|
||||
if a.idx < b.idx {
|
||||
return -1
|
||||
@ -232,10 +232,10 @@ pub fn (s string) replace_each(vals []string) string {
|
||||
mut new_len := s.len
|
||||
mut idxs := []RepIndex
|
||||
mut idx := 0
|
||||
for rep_i := 0; rep_i < vals.len; rep_i+=2 {
|
||||
for rep_i := 0; rep_i < vals.len; rep_i += 2 {
|
||||
// vals: ['rep1, 'with1', 'rep2', 'with2']
|
||||
rep := vals[rep_i]
|
||||
with := vals[rep_i+1]
|
||||
with := vals[rep_i + 1]
|
||||
for {
|
||||
idx = s.index_after(rep, idx)
|
||||
if idx == -1 {
|
||||
@ -243,7 +243,8 @@ pub fn (s string) replace_each(vals []string) string {
|
||||
}
|
||||
// We need to remember both the position in the string,
|
||||
// and which rep/with pair it refers to.
|
||||
idxs << RepIndex{idx, rep_i}
|
||||
idxs << RepIndex{
|
||||
idx,rep_i}
|
||||
idx++
|
||||
new_len += with.len - rep.len
|
||||
}
|
||||
@ -253,7 +254,7 @@ pub fn (s string) replace_each(vals []string) string {
|
||||
return s
|
||||
}
|
||||
idxs.sort()
|
||||
mut b := malloc(new_len + 1)// add a \0 just in case
|
||||
mut b := malloc(new_len + 1) // add a \0 just in case
|
||||
// Fill the new string
|
||||
mut idx_pos := 0
|
||||
mut cur_idx := idxs[idx_pos]
|
||||
@ -262,7 +263,7 @@ pub fn (s string) replace_each(vals []string) string {
|
||||
// Reached the location of rep, replace it with "with"
|
||||
if i == cur_idx.idx {
|
||||
rep := vals[cur_idx.val_idx]
|
||||
with := vals[cur_idx.val_idx+1]
|
||||
with := vals[cur_idx.val_idx + 1]
|
||||
for j := 0; j < with.len; j++ {
|
||||
b[b_i] = with[j]
|
||||
b_i++
|
||||
@ -290,7 +291,7 @@ pub fn (s string) bool() bool {
|
||||
}
|
||||
|
||||
pub fn (s string) int() int {
|
||||
return int(strconv.common_parse_int(s,0,32, false, false))
|
||||
return int(strconv.common_parse_int(s, 0, 32, false, false))
|
||||
}
|
||||
|
||||
pub fn (s string) i64() i64 {
|
||||
@ -298,12 +299,12 @@ pub fn (s string) i64() i64 {
|
||||
}
|
||||
|
||||
pub fn (s string) f32() f32 {
|
||||
//return C.atof(charptr(s.str))
|
||||
// return C.atof(charptr(s.str))
|
||||
return f32(strconv.atof64(s))
|
||||
}
|
||||
|
||||
pub fn (s string) f64() f64 {
|
||||
//return C.atof(charptr(s.str))
|
||||
// return C.atof(charptr(s.str))
|
||||
return strconv.atof64(s)
|
||||
}
|
||||
|
||||
@ -317,7 +318,8 @@ pub fn (s string) u64() u64 {
|
||||
|
||||
// ==
|
||||
fn (s string) eq(a string) bool {
|
||||
if isnil(s.str) { // should never happen
|
||||
if isnil(s.str) {
|
||||
// should never happen
|
||||
panic('string.eq(): nil string')
|
||||
}
|
||||
if s.len != a.len {
|
||||
@ -370,7 +372,7 @@ fn (s string) ge(a string) bool {
|
||||
// TODO `fn (s string) + (a string)` ? To be consistent with operator overloading syntax.
|
||||
fn (s string) add(a string) string {
|
||||
new_len := a.len + s.len
|
||||
mut res := string {
|
||||
mut res := string{
|
||||
len: new_len
|
||||
str: malloc(new_len + 1)
|
||||
}
|
||||
@ -380,7 +382,7 @@ fn (s string) add(a string) string {
|
||||
for j := 0; j < a.len; j++ {
|
||||
res[s.len + j] = a[j]
|
||||
}
|
||||
res[new_len] = `\0`// V strings are not null terminated, but just in case
|
||||
res[new_len] = `\0` // V strings are not null terminated, but just in case
|
||||
return res
|
||||
}
|
||||
|
||||
@ -412,7 +414,9 @@ pub fn (s string) split_nth(delim string, nth int) []string {
|
||||
j++
|
||||
}
|
||||
was_last := nth > 0 && res.len == nth
|
||||
if was_last{break}
|
||||
if was_last {
|
||||
break
|
||||
}
|
||||
last := i == s.len - 1
|
||||
if is_delim || last {
|
||||
if !is_delim && last {
|
||||
@ -427,7 +431,7 @@ pub fn (s string) split_nth(delim string, nth int) []string {
|
||||
}
|
||||
i++
|
||||
}
|
||||
if s.ends_with (delim) && (nth < 1 || res.len < nth) {
|
||||
if s.ends_with(delim) && (nth < 1 || res.len < nth) {
|
||||
res << ''
|
||||
}
|
||||
return res
|
||||
@ -460,6 +464,7 @@ fn (s string) left(n int) string {
|
||||
}
|
||||
return s.substr(0, n)
|
||||
}
|
||||
|
||||
// 'hello'.right(2) => 'llo'
|
||||
fn (s string) right(n int) string {
|
||||
if n >= s.len {
|
||||
@ -479,8 +484,7 @@ fn (s string) substr(start, end int) string {
|
||||
panic('substr($start, $end) out of bounds (len=$s.len)')
|
||||
}
|
||||
len := end - start
|
||||
|
||||
mut res := string {
|
||||
mut res := string{
|
||||
len: len
|
||||
str: malloc(len + 1)
|
||||
}
|
||||
@ -488,13 +492,13 @@ fn (s string) substr(start, end int) string {
|
||||
res.str[i] = s.str[start + i]
|
||||
}
|
||||
res.str[len] = `\0`
|
||||
|
||||
/*
|
||||
/*
|
||||
res := string {
|
||||
str: s.str + start
|
||||
len: len
|
||||
}
|
||||
*/
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@ -536,39 +540,40 @@ pub fn (s string) index(p string) ?int {
|
||||
|
||||
// KMP search
|
||||
fn (s string) index_kmp(p string) int {
|
||||
if p.len > s.len {
|
||||
return -1
|
||||
}
|
||||
mut prefix := [0].repeat(p.len)
|
||||
mut j := 0
|
||||
for i := 1; i < p.len; i++ {
|
||||
for p[j] != p[i] && j > 0 {
|
||||
j = prefix[j - 1]
|
||||
}
|
||||
if p[j] == p[i] {
|
||||
j++
|
||||
}
|
||||
prefix[i] = j
|
||||
}
|
||||
j = 0
|
||||
for i := 0; i < s.len; i++ {
|
||||
for p[j] != s[i] && j > 0 {
|
||||
j = prefix[j - 1]
|
||||
}
|
||||
if p[j] == s[i] {
|
||||
j++
|
||||
}
|
||||
if j == p.len {
|
||||
return i - p.len + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
if p.len > s.len {
|
||||
return -1
|
||||
}
|
||||
mut prefix := [0].repeat(p.len)
|
||||
mut j := 0
|
||||
for i := 1; i < p.len; i++ {
|
||||
for p[j] != p[i] && j > 0 {
|
||||
j = prefix[j - 1]
|
||||
}
|
||||
if p[j] == p[i] {
|
||||
j++
|
||||
}
|
||||
prefix[i] = j
|
||||
}
|
||||
j = 0
|
||||
for i := 0; i < s.len; i++ {
|
||||
for p[j] != s[i] && j > 0 {
|
||||
j = prefix[j - 1]
|
||||
}
|
||||
if p[j] == s[i] {
|
||||
j++
|
||||
}
|
||||
if j == p.len {
|
||||
return i - p.len + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
|
||||
pub fn (s string) index_any(chars string) int {
|
||||
for c in chars {
|
||||
index := s.index(c.str()) or { continue }
|
||||
index := s.index(c.str()) or {
|
||||
continue
|
||||
}
|
||||
return index
|
||||
}
|
||||
return -1
|
||||
@ -620,7 +625,7 @@ pub fn (s string) index_after(p string, start int) int {
|
||||
}
|
||||
|
||||
pub fn (s string) index_byte(c byte) int {
|
||||
for i:=0; i<s.len; i++ {
|
||||
for i := 0; i < s.len; i++ {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
@ -629,7 +634,7 @@ pub fn (s string) index_byte(c byte) int {
|
||||
}
|
||||
|
||||
pub fn (s string) last_index_byte(c byte) int {
|
||||
for i:=s.len-1; i>=0; i-- {
|
||||
for i := s.len - 1; i >= 0; i-- {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
@ -666,7 +671,9 @@ pub fn (s string) contains(p string) bool {
|
||||
}
|
||||
|
||||
pub fn (s string) starts_with(p string) bool {
|
||||
idx := s.index(p) or { return false }
|
||||
idx := s.index(p) or {
|
||||
return false
|
||||
}
|
||||
return idx == 0
|
||||
}
|
||||
|
||||
@ -699,29 +706,31 @@ pub fn (s string) to_upper() string {
|
||||
|
||||
pub fn (s string) capitalize() string {
|
||||
sl := s.to_lower()
|
||||
cap := sl[0].str().to_upper() + sl.right(1)
|
||||
cap := sl[0].str().to_upper() + sl.right(1)
|
||||
return cap
|
||||
}
|
||||
|
||||
pub fn (s string) title() string {
|
||||
words := s.split(' ')
|
||||
mut tit := []string
|
||||
|
||||
words := s.split(' ')
|
||||
mut tit := []string
|
||||
for word in words {
|
||||
tit << word.capitalize()
|
||||
}
|
||||
title := tit.join(' ')
|
||||
|
||||
return title
|
||||
}
|
||||
|
||||
// 'hey [man] how you doin'
|
||||
// find_between('[', ']') == 'man'
|
||||
pub fn (s string) find_between(start, end string) string {
|
||||
start_pos := s.index(start) or { return '' }
|
||||
start_pos := s.index(start) or {
|
||||
return ''
|
||||
}
|
||||
// First get everything to the right of 'start'
|
||||
val := s.right(start_pos + start.len)
|
||||
end_pos := val.index(end) or { return val }
|
||||
end_pos := val.index(end) or {
|
||||
return val
|
||||
}
|
||||
return val.left(end_pos)
|
||||
}
|
||||
|
||||
@ -756,8 +765,9 @@ pub fn (a []string) to_c() voidptr {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
pub fn (c byte) is_space() bool {
|
||||
return c in [` `,`\n`,`\t`,`\v`,`\f`,`\r`]
|
||||
return c in [` `, `\n`, `\t`, `\v`, `\f`, `\r`]
|
||||
}
|
||||
|
||||
pub fn (s string) trim_space() string {
|
||||
@ -786,7 +796,7 @@ pub fn (s string) trim(cutset string) string {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
return s.substr(pos_left, pos_right+1)
|
||||
return s.substr(pos_left, pos_right + 1)
|
||||
}
|
||||
|
||||
pub fn (s string) trim_left(cutset string) string {
|
||||
@ -810,7 +820,7 @@ pub fn (s string) trim_right(cutset string) string {
|
||||
for pos >= -1 && s[pos] in cs_arr {
|
||||
pos--
|
||||
}
|
||||
return s.left(pos+1)
|
||||
return s.left(pos + 1)
|
||||
}
|
||||
|
||||
// fn print_cur_thread() {
|
||||
@ -855,10 +865,11 @@ pub fn (s mut []string) sort_by_len() {
|
||||
}
|
||||
|
||||
pub fn (s string) ustring() ustring {
|
||||
mut res := ustring {
|
||||
mut res := ustring{
|
||||
s: s
|
||||
// runes will have at least s.len elements, save reallocations
|
||||
// TODO use VLA for small strings?
|
||||
|
||||
runes: new_array(0, s.len, sizeof(int))
|
||||
}
|
||||
for i := 0; i < s.len; i++ {
|
||||
@ -874,11 +885,12 @@ pub fn (s string) ustring() ustring {
|
||||
// It's called from functions like draw_text() where we know that the string is going to be freed
|
||||
// right away. Uses global buffer for storing runes []int array.
|
||||
__global g_ustring_runes []int
|
||||
|
||||
pub fn (s string) ustring_tmp() ustring {
|
||||
if g_ustring_runes.len == 0 {
|
||||
g_ustring_runes = new_array(0, 128, sizeof(int))
|
||||
}
|
||||
mut res := ustring {
|
||||
mut res := ustring{
|
||||
s: s
|
||||
}
|
||||
res.runes = g_ustring_runes
|
||||
@ -922,7 +934,7 @@ fn (u ustring) ge(a ustring) bool {
|
||||
}
|
||||
|
||||
fn (u ustring) add(a ustring) ustring {
|
||||
mut res := ustring {
|
||||
mut res := ustring{
|
||||
s: u.s + a.s
|
||||
runes: new_array(0, u.s.len + a.s.len, sizeof(int))
|
||||
}
|
||||
@ -996,12 +1008,7 @@ pub fn (u ustring) substr(_start, _end int) string {
|
||||
if _start > _end || _start > u.len || _end > u.len || _start < 0 || _end < 0 {
|
||||
panic('substr($_start, $_end) out of bounds (len=$u.len)')
|
||||
}
|
||||
end := if _end >= u.len {
|
||||
u.s.len
|
||||
}
|
||||
else {
|
||||
u.runes[_end]
|
||||
}
|
||||
end := if _end >= u.len { u.s.len } else { u.runes[_end] }
|
||||
return u.s.substr(u.runes[_start], end)
|
||||
}
|
||||
|
||||
@ -1068,7 +1075,9 @@ fn (arr []string) free() {
|
||||
|
||||
// all_before('23:34:45.234', '.') == '23:34:45'
|
||||
pub fn (s string) all_before(dot string) string {
|
||||
pos := s.index(dot) or { return s }
|
||||
pos := s.index(dot) or {
|
||||
return s
|
||||
}
|
||||
return s.left(pos)
|
||||
}
|
||||
|
||||
@ -1131,12 +1140,12 @@ pub fn (s string) reverse() string {
|
||||
if s.len == 0 {
|
||||
return ''
|
||||
}
|
||||
mut res := string {
|
||||
mut res := string{
|
||||
len: s.len
|
||||
str: malloc(s.len)
|
||||
}
|
||||
for i := s.len - 1; i >= 0; i-- {
|
||||
res[s.len-i-1] = s[i]
|
||||
res[s.len - i - 1] = s[i]
|
||||
}
|
||||
return res
|
||||
}
|
||||
@ -1158,9 +1167,8 @@ pub fn (c byte) is_white() bool {
|
||||
return i == 10 || i == 32 || i == 9 || i == 13 || c == `\r`
|
||||
}
|
||||
|
||||
|
||||
pub fn (s string) hash() int {
|
||||
//mut h := s.hash_cache
|
||||
// mut h := s.hash_cache
|
||||
mut h := 0
|
||||
if h == 0 && s.len > 0 {
|
||||
for c in s {
|
||||
@ -1185,11 +1193,12 @@ pub fn (s string) repeat(count int) string {
|
||||
return s
|
||||
}
|
||||
mut ret := malloc(s.len * count + 1)
|
||||
for i in 0..count {
|
||||
for j in 0..s.len {
|
||||
ret[i*s.len + j] = s[j]
|
||||
for i in 0 .. count {
|
||||
for j in 0 .. s.len {
|
||||
ret[i * s.len + j] = s[j]
|
||||
}
|
||||
}
|
||||
ret[s.len * count] = 0
|
||||
return string(ret)
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,46 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module builtin
|
||||
|
||||
pub fn utf8_char_len(b byte) int {
|
||||
return (( 0xe5000000 >> (( b >> 3 ) & 0x1e )) & 3 ) + 1
|
||||
return ((0xe5000000>>((b>>3) & 0x1e)) & 3) + 1
|
||||
}
|
||||
|
||||
// Convert utf32 to utf8
|
||||
// utf32 == Codepoint
|
||||
pub fn utf32_to_str(code u32) string {
|
||||
icode := int(code) //Prevents doing casts everywhere
|
||||
mut buffer := malloc(5)
|
||||
if icode <= 127 /* 0x7F */ {
|
||||
icode := int(code) // Prevents doing casts everywhere
|
||||
mut buffer := malloc(5)
|
||||
if icode <= 127/* 0x7F */ {
|
||||
buffer[0] = icode
|
||||
return tos(buffer, 1)
|
||||
}
|
||||
if (icode <= 2047 /* 0x7FF */) {
|
||||
buffer[0] = 192 /*0xC0*/ | (icode >> 6) /* 110xxxxx */
|
||||
buffer[1] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
if (icode <= 2047/* 0x7FF */) {
|
||||
buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */
|
||||
|
||||
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
return tos(buffer, 2)
|
||||
}
|
||||
if (icode <= 65535 /* 0xFFFF */) {
|
||||
buffer[0] = 224 /*0xE0*/ | (icode >> 12) /* 1110xxxx */
|
||||
buffer[1] = 128 /*0x80*/ | ((icode >> 6) & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
buffer[2] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
if (icode <= 65535/* 0xFFFF */) {
|
||||
buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */
|
||||
|
||||
buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
return tos(buffer, 3)
|
||||
}
|
||||
if (icode <= 1114111 /* 0x10FFFF */) {
|
||||
buffer[0] = 240 /*0xF0*/ | (icode >> 18) /* 11110xxx */
|
||||
buffer[1] = 128 /*0x80*/ | ((icode >> 12) & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
buffer[2] = 128 /*0x80*/ | ((icode >> 6) & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
buffer[3] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
if (icode <= 1114111/* 0x10FFFF */) {
|
||||
buffer[0] = 240/*0xF0*/ | (icode>>18)/* 11110xxx */
|
||||
|
||||
buffer[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
buffer[2] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
buffer[3] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
return tos(buffer, 4)
|
||||
}
|
||||
return ''
|
||||
@ -40,28 +48,37 @@ pub fn utf32_to_str(code u32) string {
|
||||
|
||||
// TODO copypasta
|
||||
pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
|
||||
icode := int(code) //Prevents doing casts everywhere
|
||||
mut buffer := byteptr(buf)
|
||||
if icode <= 127 /* 0x7F */ {
|
||||
icode := int(code) // Prevents doing casts everywhere
|
||||
mut buffer := byteptr(buf)
|
||||
if icode <= 127/* 0x7F */ {
|
||||
buffer[0] = icode
|
||||
return tos(buffer, 1)
|
||||
}
|
||||
if (icode <= 2047 /* 0x7FF */) {
|
||||
buffer[0] = 192 /*0xC0*/ | (icode >> 6) /* 110xxxxx */
|
||||
buffer[1] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
if (icode <= 2047/* 0x7FF */) {
|
||||
buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */
|
||||
|
||||
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
return tos(buffer, 2)
|
||||
}
|
||||
if (icode <= 65535 /* 0xFFFF */) {
|
||||
buffer[0] = 224 /*0xE0*/ | (icode >> 12) /* 1110xxxx */
|
||||
buffer[1] = 128 /*0x80*/ | ((icode >> 6) & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
buffer[2] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
if (icode <= 65535/* 0xFFFF */) {
|
||||
buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */
|
||||
|
||||
buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
return tos(buffer, 3)
|
||||
}
|
||||
if (icode <= 1114111 /* 0x10FFFF */) {
|
||||
buffer[0] = 240 /*0xF0*/ | (icode >> 18) /* 11110xxx */
|
||||
buffer[1] = 128 /*0x80*/ | ((icode >> 12) & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
buffer[2] = 128 /*0x80*/ | ((icode >> 6) & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
buffer[3] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
|
||||
if (icode <= 1114111/* 0x10FFFF */) {
|
||||
buffer[0] = 240/*0xF0*/ | (icode>>18)/* 11110xxx */
|
||||
|
||||
buffer[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
buffer[2] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
buffer[3] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
|
||||
|
||||
return tos(buffer, 4)
|
||||
}
|
||||
return ''
|
||||
@ -79,12 +96,12 @@ pub fn (_rune string) utf32_code() int {
|
||||
mut b := byte(int(_rune[0]))
|
||||
// TODO should be
|
||||
// res := int( rune[0] << rune.len)
|
||||
b = b << _rune.len
|
||||
b = b<<_rune.len
|
||||
mut res := int(b)
|
||||
mut shift := 6 - _rune.len
|
||||
for i := 1; i < _rune.len; i++ {
|
||||
c := int(_rune[i])
|
||||
res = res << shift
|
||||
res = res<<shift
|
||||
res |= c & 63 // 0x3f
|
||||
shift = 6
|
||||
}
|
||||
@ -92,8 +109,8 @@ pub fn (_rune string) utf32_code() int {
|
||||
}
|
||||
|
||||
const (
|
||||
CP_UTF8 = 65001
|
||||
)
|
||||
CP_UTF8 = 65001
|
||||
)
|
||||
|
||||
pub fn (_str string) to_wide() &u16 {
|
||||
$if windows {
|
||||
@ -110,72 +127,82 @@ pub fn (_str string) to_wide() &u16 {
|
||||
}
|
||||
|
||||
pub fn string_from_wide(_wstr &u16) string {
|
||||
$if windows {
|
||||
wstr_len := C.wcslen(_wstr)
|
||||
return string_from_wide2(_wstr, wstr_len)
|
||||
} $else {
|
||||
return ''
|
||||
}
|
||||
$if windows {
|
||||
wstr_len := C.wcslen(_wstr)
|
||||
return string_from_wide2(_wstr, wstr_len)
|
||||
} $else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_from_wide2(_wstr &u16, len int) string {
|
||||
$if windows {
|
||||
num_chars := C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, 0, 0, 0, 0)
|
||||
mut str_to := malloc(num_chars + 1)
|
||||
if !isnil(str_to) {
|
||||
C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, str_to, num_chars, 0, 0)
|
||||
C.memset(str_to + num_chars, 0, 1)
|
||||
}
|
||||
return tos2(str_to)
|
||||
} $else {
|
||||
return ''
|
||||
}
|
||||
$if windows {
|
||||
num_chars := C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, 0, 0, 0, 0)
|
||||
mut str_to := malloc(num_chars + 1)
|
||||
if !isnil(str_to) {
|
||||
C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, str_to, num_chars, 0, 0)
|
||||
C.memset(str_to + num_chars, 0, 1)
|
||||
}
|
||||
return tos2(str_to)
|
||||
} $else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate length to read from the first byte
|
||||
fn utf8_len(c byte) int {
|
||||
mut b := 0
|
||||
mut x := c
|
||||
|
||||
if ((x & 240) != 0) { //0xF0
|
||||
x >>= 4
|
||||
} else {
|
||||
b += 4
|
||||
}
|
||||
if ((x & 12) != 0) { //0x0C
|
||||
x >>= 2
|
||||
} else {
|
||||
b += 2
|
||||
}
|
||||
if ((x & 2) == 0) { //0x02
|
||||
b++
|
||||
}
|
||||
return b
|
||||
mut b := 0
|
||||
mut x := c
|
||||
if ((x & 240) != 0) {
|
||||
// 0xF0
|
||||
x >>= 4
|
||||
}
|
||||
else {
|
||||
b += 4
|
||||
}
|
||||
if ((x & 12) != 0) {
|
||||
// 0x0C
|
||||
x >>= 2
|
||||
}
|
||||
else {
|
||||
b += 2
|
||||
}
|
||||
if ((x & 2) == 0) {
|
||||
// 0x02
|
||||
b++
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Reads an utf8 character from standard input
|
||||
pub fn utf8_getchar() int {
|
||||
c := C.getchar()
|
||||
len := utf8_len(~c)
|
||||
if c < 0 {
|
||||
return 0
|
||||
} else if len == 0 {
|
||||
return c
|
||||
} else if len == 1 {
|
||||
return -1
|
||||
} else {
|
||||
mut uc := c & ((1 << (7 - len)) - 1)
|
||||
for i := 0; i + 1 < len; i++ {
|
||||
c2 := C.getchar()
|
||||
if c2 != -1 && (c2 >> 6) == 2 {
|
||||
uc <<= 6
|
||||
uc |= (c2 & 63)
|
||||
} else if c2 == -1 {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return uc
|
||||
}
|
||||
c := C.getchar()
|
||||
len := utf8_len(~c)
|
||||
if c < 0 {
|
||||
return 0
|
||||
}
|
||||
else if len == 0 {
|
||||
return c
|
||||
}
|
||||
else if len == 1 {
|
||||
return -1
|
||||
}
|
||||
else {
|
||||
mut uc := c & ((1<<(7 - len)) - 1)
|
||||
for i := 0; i + 1 < len; i++ {
|
||||
c2 := C.getchar()
|
||||
if c2 != -1 && (c2>>6) == 2 {
|
||||
uc <<= 6
|
||||
uc |= (c2 & 63)
|
||||
}
|
||||
else if c2 == -1 {
|
||||
return 0
|
||||
}
|
||||
else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return uc
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
// that can be found in the LICENSE file.
|
||||
module compiler
|
||||
|
||||
|
||||
|
||||
import (
|
||||
strings
|
||||
)
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module compiler
|
||||
|
||||
import strings
|
||||
@ -9,15 +8,16 @@ import strings
|
||||
const (
|
||||
dot_ptr = '->'
|
||||
)
|
||||
|
||||
// returns the type of the new variable
|
||||
fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
|
||||
p.is_var_decl = true
|
||||
mut typ := p.bool_expression()
|
||||
//mut typ, expr := p.tmp_expr()
|
||||
// mut typ, expr := p.tmp_expr()
|
||||
p.is_var_decl = false
|
||||
if typ.starts_with('...') { typ = typ[3..] }
|
||||
//p.gen('/*after expr*/')
|
||||
if typ.starts_with('...') {
|
||||
typ = typ[3..]
|
||||
}
|
||||
// p.gen('/*after expr*/')
|
||||
// Option check ? or {
|
||||
or_else := p.tok == .key_orelse
|
||||
if or_else {
|
||||
@ -26,39 +26,34 @@ fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
|
||||
gen_name := p.table.var_cgen_name(name)
|
||||
mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ)
|
||||
// `foo := C.Foo{}` => `Foo foo;`
|
||||
if !p.is_empty_c_struct_init && !typ.starts_with('['){
|
||||
if !p.is_empty_c_struct_init && !typ.starts_with('[') {
|
||||
nt_gen += '='
|
||||
} else if typ.starts_with('[') && typ[ typ.len-1 ] != `*` {
|
||||
}
|
||||
else if typ.starts_with('[') && typ[typ.len - 1] != `*` {
|
||||
// a fixed_array initializer, like `v := [1.1, 2.2]!!`
|
||||
// ... should translate to the following in C `f32 v[2] = {1.1, 2.2};`
|
||||
initializer := p.cgen.cur_line
|
||||
if initializer.len > 0 {
|
||||
p.cgen.resetln(' = {' + initializer.all_after('{') )
|
||||
} else if initializer.len == 0 {
|
||||
p.cgen.resetln(' = {' + initializer.all_after('{'))
|
||||
}
|
||||
else if initializer.len == 0 {
|
||||
p.cgen.resetln(' = { 0 }')
|
||||
}
|
||||
}
|
||||
|
||||
if is_static {
|
||||
nt_gen = 'static $nt_gen'
|
||||
}
|
||||
// Now that we know the type, prepend it
|
||||
// `[typ] [name] = bool_expression();`
|
||||
//p.cgen.prepend_to_statement(nt_gen)
|
||||
// p.cgen.prepend_to_statement(nt_gen)
|
||||
p.cgen.set_placeholder(0, nt_gen)
|
||||
return typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_fn_decl(f Fn, typ, str_args string) {
|
||||
dll_export_linkage := if p.pref.ccompiler == 'msvc' && p.attr == 'live' && p.pref.is_so {
|
||||
'__declspec(dllexport) '
|
||||
} else if p.attr == 'inline' {
|
||||
'static inline '
|
||||
} else {
|
||||
''
|
||||
}
|
||||
dll_export_linkage := if p.pref.ccompiler == 'msvc' && p.attr == 'live' && p.pref.is_so { '__declspec(dllexport) ' } else if p.attr == 'inline' { 'static inline ' } else { '' }
|
||||
fn_name_cgen := p.table.fn_gen_name(f)
|
||||
//str_args := f.str_args(p.table)
|
||||
// str_args := f.str_args(p.table)
|
||||
p.genln('$dll_export_linkage$typ $fn_name_cgen ($str_args) {')
|
||||
}
|
||||
|
||||
@ -68,12 +63,12 @@ fn (p mut Parser) gen_blank_identifier_assign() {
|
||||
p.check_name()
|
||||
p.check_space(.assign)
|
||||
is_indexer := p.peek() == .lsbr
|
||||
is_fn_call, next_expr := p.is_expr_fn_call(p.token_idx)
|
||||
is_fn_call,next_expr := p.is_expr_fn_call(p.token_idx)
|
||||
pos := p.cgen.add_placeholder()
|
||||
p.is_var_decl = true
|
||||
typ := p.bool_expression()
|
||||
if typ == 'void' {
|
||||
p.error_with_token_index('${next_expr}() $err_used_as_value', p.token_idx-2)
|
||||
p.error_with_token_index('${next_expr}() $err_used_as_value', p.token_idx - 2)
|
||||
}
|
||||
p.is_var_decl = false
|
||||
if !is_indexer && !is_fn_call {
|
||||
@ -82,10 +77,12 @@ fn (p mut Parser) gen_blank_identifier_assign() {
|
||||
// handle or
|
||||
if p.tok == .key_orelse {
|
||||
p.gen_handle_option_or_else(typ, '', pos)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if is_fn_call {
|
||||
p.gen(';')
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
p.cgen.resetln('{$typ _ = $p.cgen.cur_line;}')
|
||||
}
|
||||
}
|
||||
@ -104,19 +101,20 @@ fn (p mut Parser) gen_handle_option_or_else(_typ, name string, fn_call_ph int) s
|
||||
or_tok_idx := p.token_idx
|
||||
p.check(.key_orelse)
|
||||
p.check(.lcbr)
|
||||
p.register_var(Var {
|
||||
p.register_var(Var{
|
||||
name: 'err'
|
||||
typ: 'string'
|
||||
is_mut: false
|
||||
is_used: true
|
||||
})
|
||||
p.register_var(Var {
|
||||
p.register_var(Var{
|
||||
name: 'errcode'
|
||||
typ: 'int'
|
||||
is_mut: false
|
||||
is_used: true
|
||||
})
|
||||
if is_assign && !name.contains('.') { // don't initialize struct fields
|
||||
if is_assign && !name.contains('.') {
|
||||
// don't initialize struct fields
|
||||
p.genln('$typ $name;')
|
||||
}
|
||||
p.genln('if (!$tmp .ok) {')
|
||||
@ -128,23 +126,20 @@ fn (p mut Parser) gen_handle_option_or_else(_typ, name string, fn_call_ph int) s
|
||||
// workaround for -g with default optional value
|
||||
// when p.cgen.line_directives is true an extra
|
||||
// line is added so we need to account for that
|
||||
expr_line := if p.cgen.line_directives {
|
||||
p.cgen.lines[p.cgen.lines.len-3]
|
||||
} else {
|
||||
p.cgen.lines[p.cgen.lines.len-2]
|
||||
}
|
||||
expr_line := if p.cgen.line_directives { p.cgen.lines[p.cgen.lines.len - 3] } else { p.cgen.lines[p.cgen.lines.len - 2] }
|
||||
last_expr := expr_line[last_ph..]
|
||||
p.cgen.lines[p.cgen.lines.len-2] = ''
|
||||
p.cgen.lines[p.cgen.lines.len - 2] = ''
|
||||
// same here
|
||||
if p.cgen.line_directives {
|
||||
p.cgen.lines[p.cgen.lines.len-3] = ''
|
||||
p.cgen.lines[p.cgen.lines.len - 3] = ''
|
||||
}
|
||||
p.genln('if ($tmp .ok) {')
|
||||
p.genln('$name = *($typ*) $tmp . data;')
|
||||
p.genln('} else {')
|
||||
p.genln('$name = $last_expr')
|
||||
p.genln('}')
|
||||
} else if is_assign {
|
||||
}
|
||||
else if is_assign {
|
||||
p.genln('$name = *($typ*)${tmp}.data;')
|
||||
}
|
||||
if !p.returns && last_typ != typ && is_assign && p.prev_tok2 != .key_continue && p.prev_tok2 != .key_break {
|
||||
@ -172,18 +167,18 @@ fn (p mut Parser) gen_handle_question_suffix(f Fn, ph int) string {
|
||||
fn types_to_c(types []Type, table &Table) string {
|
||||
mut sb := strings.new_builder(10)
|
||||
for t in types {
|
||||
//if t.cat != .union_ && t.cat != .struct_ && t.cat != .objc_interface {
|
||||
// if t.cat != .union_ && t.cat != .struct_ && t.cat != .objc_interface {
|
||||
if !(t.cat in [.union_, .struct_, .objc_interface, .interface_]) {
|
||||
continue
|
||||
}
|
||||
//if is_atomic {
|
||||
//sb.write('_Atomic ')
|
||||
//}
|
||||
// if is_atomic {
|
||||
// sb.write('_Atomic ')
|
||||
// }
|
||||
if t.cat == .objc_interface {
|
||||
sb.writeln('@interface $t.name : $t.parent { @public')
|
||||
}
|
||||
else {
|
||||
kind := if t.cat == .union_ {'union'} else {'struct'}
|
||||
kind := if t.cat == .union_ { 'union' } else { 'struct' }
|
||||
sb.writeln('$kind $t.name {')
|
||||
if t.cat == .interface_ {
|
||||
sb.writeln('\tvoid* _object;')
|
||||
@ -192,11 +187,10 @@ fn types_to_c(types []Type, table &Table) string {
|
||||
}
|
||||
for field in t.fields {
|
||||
sb.write('\t')
|
||||
sb.writeln(table.cgen_name_type_pair(field.name,
|
||||
field.typ) + ';')
|
||||
sb.writeln(table.cgen_name_type_pair(field.name, field.typ) + ';')
|
||||
}
|
||||
sb.writeln('};\n')
|
||||
if t.cat == .objc_interface {
|
||||
if t.cat == .objc_interface {
|
||||
sb.writeln('@end')
|
||||
}
|
||||
}
|
||||
@ -211,7 +205,8 @@ fn (p mut Parser) index_get(typ string, fn_ph int, cfg IndexConfig) {
|
||||
if p.cgen.is_tmp {
|
||||
index_expr = p.cgen.tmp_line[fn_ph..]
|
||||
p.cgen.resetln(p.cgen.tmp_line[..fn_ph])
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
index_expr = p.cgen.cur_line[fn_ph..]
|
||||
p.cgen.resetln(p.cgen.cur_line[..fn_ph])
|
||||
}
|
||||
@ -221,8 +216,7 @@ fn (p mut Parser) index_get(typ string, fn_ph int, cfg IndexConfig) {
|
||||
if cfg.is_map {
|
||||
p.gen('$tmp')
|
||||
def := type_default(typ)
|
||||
p.cgen.insert_before('$typ $tmp = $def; ' +
|
||||
'bool $tmp_ok = map_get(/*$p.file_name : $p.scanner.line_nr*/$index_expr, & $tmp);')
|
||||
p.cgen.insert_before('$typ $tmp = $def; ' + 'bool $tmp_ok = map_get(/*$p.file_name : $p.scanner.line_nr*/$index_expr, & $tmp);')
|
||||
}
|
||||
else if cfg.is_arr {
|
||||
if p.pref.translated && !p.builtin_mod {
|
||||
@ -239,12 +233,13 @@ fn (p mut Parser) index_get(typ string, fn_ph int, cfg IndexConfig) {
|
||||
}
|
||||
}
|
||||
else if cfg.is_str && !p.builtin_mod {
|
||||
if p.pref.is_bare {
|
||||
if p.pref.is_bare {
|
||||
p.gen(index_expr)
|
||||
}
|
||||
else if cfg.is_slice {
|
||||
p.gen('string_substr2($index_expr)')
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
p.gen('string_at($index_expr)')
|
||||
}
|
||||
}
|
||||
@ -255,7 +250,6 @@ fn (p mut Parser) index_get(typ string, fn_ph int, cfg IndexConfig) {
|
||||
// p.cgen.insert_before('if (!${tmp}.str) $tmp = tos("", 0);')
|
||||
p.cgen.insert_before('if (!$tmp_ok) $tmp = tos((byte *)"", 0);')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn (table mut Table) fn_gen_name(f &Fn) string {
|
||||
@ -265,18 +259,28 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
|
||||
name = name.replace(' ', '')
|
||||
if f.name.len == 1 {
|
||||
match f.name[0] {
|
||||
`+` { name = name.replace('+', 'op_plus') }
|
||||
`-` { name = name.replace('-', 'op_minus') }
|
||||
`*` { name = name.replace('*', 'op_mul') }
|
||||
`/` { name = name.replace('/', 'op_div') }
|
||||
`%` { name = name.replace('%', 'op_mod') }
|
||||
else {}
|
||||
}
|
||||
`+` {
|
||||
name = name.replace('+', 'op_plus')
|
||||
}
|
||||
`-` {
|
||||
name = name.replace('-', 'op_minus')
|
||||
}
|
||||
`*` {
|
||||
name = name.replace('*', 'op_mul')
|
||||
}
|
||||
`/` {
|
||||
name = name.replace('/', 'op_div')
|
||||
}
|
||||
`%` {
|
||||
name = name.replace('%', 'op_mod')
|
||||
}
|
||||
else {
|
||||
}}
|
||||
}
|
||||
}
|
||||
if f.is_interface {
|
||||
// iname := f.args[0].typ // Speaker
|
||||
// var := p.expr_var.name
|
||||
// iname := f.args[0].typ // Speaker
|
||||
// var := p.expr_var.name
|
||||
return ''
|
||||
}
|
||||
// Avoid name conflicts (with things like abs(), print() etc).
|
||||
@ -288,20 +292,7 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
|
||||
// Obfuscate but skip certain names
|
||||
// TODO ugly, fix
|
||||
// NB: the order here is from faster to potentially slower checks
|
||||
if table.obfuscate &&
|
||||
!f.is_c &&
|
||||
f.name != 'main' && f.name != 'WinMain' && f.name != 'main__main' &&
|
||||
f.name != 'gg__vec2' &&
|
||||
f.name != 'build_token_str' &&
|
||||
f.name != 'build_keys' &&
|
||||
f.mod != 'builtin' &&
|
||||
f.mod != 'darwin' &&
|
||||
f.mod != 'os' &&
|
||||
f.mod != 'json' &&
|
||||
!f.name.ends_with('_init') &&
|
||||
!f.name.contains('window_proc') &&
|
||||
!name.ends_with('_str') &&
|
||||
!name.contains('contains') {
|
||||
if table.obfuscate && !f.is_c && f.name != 'main' && f.name != 'WinMain' && f.name != 'main__main' && f.name != 'gg__vec2' && f.name != 'build_token_str' && f.name != 'build_keys' && f.mod != 'builtin' && f.mod != 'darwin' && f.mod != 'os' && f.mod != 'json' && !f.name.ends_with('_init') && !f.name.contains('window_proc') && !name.ends_with('_str') && !name.contains('contains') {
|
||||
mut idx := table.obf_ids[name]
|
||||
// No such function yet, register it
|
||||
if idx == 0 {
|
||||
@ -316,10 +307,8 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
|
||||
return name
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string,
|
||||
cgen_name string, ftyp string, method_ph int)
|
||||
{
|
||||
//mut cgen_name := p.table.fn_gen_name(f)
|
||||
fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string, cgen_name string, ftyp string, method_ph int) {
|
||||
// mut cgen_name := p.table.fn_gen_name(f)
|
||||
mut method_call := cgen_name + ' ('
|
||||
// if receiver is key_mut or a ref (&), generate & for the first arg
|
||||
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) {
|
||||
@ -337,7 +326,8 @@ fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string,
|
||||
// array_int => int
|
||||
cast = receiver_type.all_after('array_')
|
||||
cast = '*($cast*) '
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
cast = '(voidptr) '
|
||||
}
|
||||
}
|
||||
@ -346,12 +336,12 @@ fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string,
|
||||
|
||||
fn (p mut Parser) gen_array_at(typ_ string, is_arr0 bool, fn_ph int) {
|
||||
mut typ := typ_
|
||||
//p.fgen('[')
|
||||
// p.fgen('[')
|
||||
// array_int a; a[0]
|
||||
// type is "array_int", need "int"
|
||||
// typ = typ.replace('array_', '')
|
||||
// if is_arr0 {
|
||||
// typ = typ.right(6)
|
||||
// typ = typ.right(6)
|
||||
// }
|
||||
// array a; a.first() voidptr
|
||||
// type is "array", need "void*"
|
||||
@ -372,28 +362,36 @@ fn (p mut Parser) gen_array_at(typ_ string, is_arr0 bool, fn_ph int) {
|
||||
|
||||
fn (p mut Parser) gen_for_header(i, tmp, var_typ, val string) {
|
||||
p.genln('for (int $i = 0; $i < ${tmp}.len; $i++) {')
|
||||
if val == '_' { return }
|
||||
if val == '_' {
|
||||
return
|
||||
}
|
||||
p.genln('$var_typ $val = (($var_typ *) $tmp . data)[$i];')
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_for_fixed_header(i, tmp, var_typ, val string) {
|
||||
p.genln('for (int $i = 0; $i < sizeof(${tmp}) / sizeof($tmp [0]); $i++) {')
|
||||
if val == '_' { return }
|
||||
if val == '_' {
|
||||
return
|
||||
}
|
||||
p.genln('$var_typ $val = $tmp[$i];')
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_for_str_header(i, tmp, var_typ, val string) {
|
||||
// TODO var_typ is always byte
|
||||
//p.genln('array_byte bytes_$tmp = string_bytes( $tmp );')
|
||||
// p.genln('array_byte bytes_$tmp = string_bytes( $tmp );')
|
||||
p.genln(';\nfor (int $i = 0; $i < $tmp .len; $i ++) {')
|
||||
if val == '_' { return }
|
||||
//p.genln('$var_typ $val = (($var_typ *) bytes_$tmp . data)[$i];')
|
||||
if val == '_' {
|
||||
return
|
||||
}
|
||||
// p.genln('$var_typ $val = (($var_typ *) bytes_$tmp . data)[$i];')
|
||||
p.genln('$var_typ $val = ${tmp}.str[$i];')
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_for_range_header(i, range_end, tmp, var_type, val string) {
|
||||
p.genln(';\nfor (int $i = $tmp; $i < $range_end; $i++) {')
|
||||
if val == '_' { return }
|
||||
if val == '_' {
|
||||
return
|
||||
}
|
||||
p.genln('$var_type $val = $i;')
|
||||
}
|
||||
|
||||
@ -404,13 +402,17 @@ fn (p mut Parser) gen_for_map_header(i, tmp, var_typ, val, typ string) {
|
||||
p.genln('string $i = ((string*)keys_$tmp .data)[l];')
|
||||
// TODO don't call map_get() for each key, fetch values while traversing
|
||||
// the tree (replace `map_keys()` above with `map_key_vals()`)
|
||||
if val == '_' { return }
|
||||
if val == '_' {
|
||||
return
|
||||
}
|
||||
p.genln('$var_typ $val = $def; map_get($tmp, $i, & $val);')
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_for_varg_header(i, varg, var_typ, val string) {
|
||||
p.genln('for (int $i = 0; $i < ${varg}->len; $i++) {')
|
||||
if val == '_' { return }
|
||||
if val == '_' {
|
||||
return
|
||||
}
|
||||
p.genln('$var_typ $val = (($var_typ *) $varg->args)[$i];')
|
||||
}
|
||||
|
||||
@ -421,17 +423,17 @@ fn (p mut Parser) gen_array_init(typ string, no_alloc bool, new_arr_ph int, nr_e
|
||||
}
|
||||
if nr_elems == 0 {
|
||||
p.gen(' TCCSKIP(0) })')
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
p.gen(' })')
|
||||
}
|
||||
// Need to do this in the second pass, otherwise it goes to the very top of the out.c file
|
||||
if !p.first_pass() {
|
||||
p.cgen.set_placeholder(new_arr_ph,
|
||||
'${new_arr}($nr_elems, $nr_elems, sizeof($typ), EMPTY_ARRAY_OF_ELEMS( $typ, $nr_elems ) { ')
|
||||
p.cgen.set_placeholder(new_arr_ph, '${new_arr}($nr_elems, $nr_elems, sizeof($typ), EMPTY_ARRAY_OF_ELEMS( $typ, $nr_elems ) { ')
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_array_set(typ string, is_ptr, is_map bool,fn_ph, assign_pos int, is_cao bool) {
|
||||
fn (p mut Parser) gen_array_set(typ string, is_ptr, is_map bool, fn_ph, assign_pos int, is_cao bool) {
|
||||
// `a[0] = 7`
|
||||
// curline right now: `a , 0 = 7`
|
||||
mut val := p.cgen.cur_line[assign_pos..]
|
||||
@ -441,7 +443,8 @@ fn (p mut Parser) gen_array_set(typ string, is_ptr, is_map bool,fn_ph, assign_po
|
||||
if is_map {
|
||||
if is_ptr {
|
||||
func = 'map_set('
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
func = 'map_set(&'
|
||||
}
|
||||
// CAO on map is a bit more complicated as it loads
|
||||
@ -463,12 +466,11 @@ fn (p mut Parser) gen_array_set(typ string, is_ptr, is_map bool,fn_ph, assign_po
|
||||
}
|
||||
p.cgen.set_placeholder(fn_ph, func)
|
||||
if is_cao {
|
||||
val = cao_tmp + val.all_before('=') + val.all_after('=')
|
||||
val = cao_tmp + val.all_before('=') + val.all_after('=')
|
||||
}
|
||||
p.gen(', & ($typ []) { $val })')
|
||||
}
|
||||
|
||||
|
||||
// returns true in case of an early return
|
||||
fn (p mut Parser) gen_struct_init(typ string, t Type) bool {
|
||||
// TODO hack. If it's a C type, we may need to add "struct" before declaration:
|
||||
@ -480,7 +482,7 @@ fn (p mut Parser) gen_struct_init(typ string, t Type) bool {
|
||||
}
|
||||
// TODO tm struct struct bug
|
||||
if typ == 'tm' {
|
||||
p.cgen.lines[p.cgen.lines.len-1] = ''
|
||||
p.cgen.lines[p.cgen.lines.len - 1] = ''
|
||||
}
|
||||
p.next()
|
||||
p.check(.lcbr)
|
||||
@ -511,6 +513,7 @@ fn (p mut Parser) gen_struct_init(typ string, t Type) bool {
|
||||
p.check(.rcbr)
|
||||
return true
|
||||
*/
|
||||
|
||||
}
|
||||
p.gen('($t.name*)memdup(&($t.name) {')
|
||||
}
|
||||
@ -527,7 +530,9 @@ fn (p mut Parser) gen_empty_map(typ string) {
|
||||
|
||||
fn (p mut Parser) cast(typ string) {
|
||||
p.gen('(')
|
||||
defer { p.gen(')') }
|
||||
defer {
|
||||
p.gen(')')
|
||||
}
|
||||
p.next()
|
||||
pos := p.cgen.add_placeholder()
|
||||
if p.tok == .rpar {
|
||||
@ -543,8 +548,7 @@ fn (p mut Parser) cast(typ string) {
|
||||
p.warn('casting `$typ` to `$expr_typ` is not needed')
|
||||
}
|
||||
// `face := FT_Face(cobj)` => `FT_Face face = *((FT_Face*)cobj);`
|
||||
casting_voidptr_to_value := expr_typ == 'void*' && typ != 'int' &&
|
||||
typ != 'byteptr' && !typ.ends_with('*')
|
||||
casting_voidptr_to_value := expr_typ == 'void*' && typ != 'int' && typ != 'byteptr' && !typ.ends_with('*')
|
||||
p.expected_type = ''
|
||||
// `string(buffer)` => `tos2(buffer)`
|
||||
// `string(buffer, len)` => `tos(buffer, len)`
|
||||
@ -561,7 +565,8 @@ fn (p mut Parser) cast(typ string) {
|
||||
}
|
||||
p.gen(', ')
|
||||
p.check_types(p.expression(), 'int')
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if is_bytearr {
|
||||
p.gen('.data')
|
||||
}
|
||||
@ -617,30 +622,58 @@ fn type_default(typ string) string {
|
||||
return '{0}'
|
||||
}
|
||||
// Default values for other types are not needed because of mandatory initialization
|
||||
match typ {
|
||||
'bool'{ return '0'}
|
||||
'string'{ return 'tos3("")'}
|
||||
'i8'{ return '0'}
|
||||
'i16'{ return '0'}
|
||||
'i64'{ return '0'}
|
||||
'u16'{ return '0'}
|
||||
'u32'{ return '0'}
|
||||
'u64'{ return '0'}
|
||||
'byte'{ return '0'}
|
||||
'int'{ return '0'}
|
||||
'rune'{ return '0'}
|
||||
'f32'{ return '0.0'}
|
||||
'f64'{ return '0.0'}
|
||||
'byteptr'{ return '0'}
|
||||
'voidptr'{ return '0'}
|
||||
else {}
|
||||
}
|
||||
return '{0}'
|
||||
|
||||
|
||||
match typ {
|
||||
'bool' {
|
||||
return '0'
|
||||
}
|
||||
'string' {
|
||||
return 'tos3("")'
|
||||
}
|
||||
'i8' {
|
||||
return '0'
|
||||
}
|
||||
'i16' {
|
||||
return '0'
|
||||
}
|
||||
'i64' {
|
||||
return '0'
|
||||
}
|
||||
'u16' {
|
||||
return '0'
|
||||
}
|
||||
'u32' {
|
||||
return '0'
|
||||
}
|
||||
'u64' {
|
||||
return '0'
|
||||
}
|
||||
'byte' {
|
||||
return '0'
|
||||
}
|
||||
'int' {
|
||||
return '0'
|
||||
}
|
||||
'rune' {
|
||||
return '0'
|
||||
}
|
||||
'f32' {
|
||||
return '0.0'
|
||||
}
|
||||
'f64' {
|
||||
return '0.0'
|
||||
}
|
||||
'byteptr' {
|
||||
return '0'
|
||||
}
|
||||
'voidptr' {
|
||||
return '0'
|
||||
}
|
||||
else {
|
||||
}}
|
||||
return '{0}'
|
||||
// TODO this results in
|
||||
// error: expected a field designator, such as '.field = 4'
|
||||
//- Empty ee= (Empty) { . = {0} } ;
|
||||
// - Empty ee= (Empty) { . = {0} } ;
|
||||
/*
|
||||
return match typ {
|
||||
'bool'{ '0'}
|
||||
@ -661,20 +694,22 @@ else {}
|
||||
else { '{0} '}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
fn (p mut Parser) gen_array_push(ph int, typ, expr_type, tmp, elm_type string) {
|
||||
// Two arrays of the same type?
|
||||
push_array := typ == expr_type
|
||||
if push_array {
|
||||
p.cgen.set_placeholder(ph, '_PUSH_MANY(&' )
|
||||
p.cgen.set_placeholder(ph, '_PUSH_MANY(&')
|
||||
p.gen('), $tmp, $typ)')
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
p.check_types(expr_type, elm_type)
|
||||
// Pass tmp var info to the _PUSH macro
|
||||
// Prepend tmp initialisation and push call
|
||||
// Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`)
|
||||
push_call := if typ.contains('*'){'_PUSH('} else { '_PUSH(&'}
|
||||
push_call := if typ.contains('*') { '_PUSH(' } else { '_PUSH(&' }
|
||||
p.cgen.set_placeholder(ph, push_call)
|
||||
p.gen('), $tmp, $elm_type)')
|
||||
}
|
||||
|
@ -1,22 +1,21 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module compiler
|
||||
|
||||
import (
|
||||
strings
|
||||
)
|
||||
|
||||
fn (p mut Parser) get_type2() Type{
|
||||
fn (p mut Parser) get_type2() Type {
|
||||
mut mul := false
|
||||
mut nr_muls := 0
|
||||
mut typ := ''
|
||||
cat := TypeCategory.struct_
|
||||
// multiple returns
|
||||
if p.tok == .lpar {
|
||||
//p.warn('`()` are no longer necessary in multiple returns' +
|
||||
//'\nuse `fn foo() int, int {` instead of `fn foo() (int, int) {`')
|
||||
// p.warn('`()` are no longer necessary in multiple returns' +
|
||||
// '\nuse `fn foo() int, int {` instead of `fn foo() (int, int) {`')
|
||||
// if p.inside_tuple {p.error('unexpected (')}
|
||||
// p.inside_tuple = true
|
||||
p.check(.lpar)
|
||||
@ -32,7 +31,7 @@ fn (p mut Parser) get_type2() Type{
|
||||
p.check(.rpar)
|
||||
// p.inside_tuple = false
|
||||
typ = p.register_multi_return_stuct(types)
|
||||
return Type {
|
||||
return Type{
|
||||
name: typ
|
||||
mod: p.mod
|
||||
cat: cat
|
||||
@ -40,7 +39,10 @@ fn (p mut Parser) get_type2() Type{
|
||||
}
|
||||
// fn type
|
||||
if p.tok == .key_fn {
|
||||
mut f := Fn{name: '_', mod: p.mod}
|
||||
mut f := Fn{
|
||||
name: '_'
|
||||
mod: p.mod
|
||||
}
|
||||
p.next()
|
||||
line_nr := p.scanner.line_nr
|
||||
p.fn_args(mut f)
|
||||
@ -58,8 +60,9 @@ fn (p mut Parser) get_type2() Type{
|
||||
f.typ = 'void'
|
||||
}
|
||||
// Register anon fn type
|
||||
fn_typ := Type {
|
||||
name: f.typ_str()// 'fn (int, int) string'
|
||||
fn_typ := Type{
|
||||
name: f.typ_str() // 'fn (int, int) string'
|
||||
|
||||
mod: p.mod
|
||||
func: f
|
||||
cat: .func
|
||||
@ -79,8 +82,8 @@ fn (p mut Parser) get_type2() Type{
|
||||
if p.tok == .number || (p.tok == .name && !p.inside_const) {
|
||||
if p.tok == .name {
|
||||
typ += '[${p.mod}__$p.lit]'
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
typ += '[$p.lit]'
|
||||
}
|
||||
p.next()
|
||||
@ -99,10 +102,12 @@ fn (p mut Parser) get_type2() Type{
|
||||
p.error('maps only support string keys for now')
|
||||
}
|
||||
p.check(.rsbr)
|
||||
val_type := p.get_type()// p.check_name()
|
||||
val_type := p.get_type() // p.check_name()
|
||||
typ = 'map_$val_type'
|
||||
p.register_map(typ)
|
||||
return Type{name: typ}
|
||||
return Type{
|
||||
name: typ
|
||||
}
|
||||
}
|
||||
// ptr/ref
|
||||
mut warn := false
|
||||
@ -123,7 +128,8 @@ fn (p mut Parser) get_type2() Type{
|
||||
ti := p.cur_fn.dispatch_of.inst
|
||||
if p.lit in ti.keys() {
|
||||
typ += ti[p.lit]
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
typ += p.lit
|
||||
}
|
||||
// C.Struct import
|
||||
@ -153,8 +159,7 @@ fn (p mut Parser) get_type2() Type{
|
||||
// "typ" not found? try "mod__typ"
|
||||
if t.name == '' && !p.builtin_mod {
|
||||
// && !p.first_pass() {
|
||||
if !typ.contains('array_') && p.mod != 'main' && !typ.contains('__') &&
|
||||
!typ.starts_with('[') {
|
||||
if !typ.contains('array_') && p.mod != 'main' && !typ.contains('__') && !typ.starts_with('[') {
|
||||
typ = p.prepend_mod(typ)
|
||||
}
|
||||
t = p.table.find_type(typ)
|
||||
@ -164,7 +169,7 @@ fn (p mut Parser) get_type2() Type{
|
||||
// for q in p.table.types {
|
||||
// println(q.name)
|
||||
// }
|
||||
mut t_suggest, tc_suggest := p.table.find_misspelled_type(typ, p, 0.50)
|
||||
mut t_suggest,tc_suggest := p.table.find_misspelled_type(typ, p, 0.50)
|
||||
if t_suggest.len > 0 {
|
||||
t_suggest = '. did you mean: ($tc_suggest) `$t_suggest`'
|
||||
}
|
||||
@ -195,15 +200,14 @@ fn (p mut Parser) get_type2() Type{
|
||||
typ = 'Option_$typ'
|
||||
p.table.register_type_with_parent(typ, 'Option')
|
||||
}
|
||||
|
||||
// Because the code uses * to see if it's a pointer
|
||||
if typ == 'byteptr' {
|
||||
typ = 'byte*'
|
||||
}
|
||||
if typ == 'voidptr' {
|
||||
//if !p.builtin_mod && p.mod != 'os' && p.mod != 'gx' && p.mod != 'gg' && !p.pref.translated {
|
||||
//p.error('voidptr can only be used in unsafe code')
|
||||
//}
|
||||
// if !p.builtin_mod && p.mod != 'os' && p.mod != 'gx' && p.mod != 'gg' && !p.pref.translated {
|
||||
// p.error('voidptr can only be used in unsafe code')
|
||||
// }
|
||||
typ = 'void*'
|
||||
}
|
||||
/*
|
||||
@ -212,6 +216,10 @@ fn (p mut Parser) get_type2() Type{
|
||||
p.error('2 __ in gettype(): typ="$typ"')
|
||||
}
|
||||
*/
|
||||
return Type{name: typ, cat: cat}
|
||||
|
||||
return Type{
|
||||
name: typ
|
||||
cat: cat
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,9 +250,9 @@ fn (p &Parser) gen_fmt() {
|
||||
if s == '' {
|
||||
return
|
||||
}
|
||||
files := ['cgen.v', 'comptime.v', 'cc.v', 'if_match.v']
|
||||
//if !p.file_path.contains('table.v') {return}
|
||||
if !(p.file_name in files) { return }
|
||||
files := ['get_type.v']
|
||||
if !p.file_path.contains('vlib/builtin') {return}
|
||||
//if !(p.file_name in files) { return }
|
||||
path := os.tmpdir() + '/' + p.file_name
|
||||
println('generating ${path}')
|
||||
mut out := os.create(path) or {
|
||||
|
Loading…
Reference in New Issue
Block a user