1
0
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:
Alexander Medvednikov 2019-12-19 23:52:45 +03:00
parent 76c800ffb6
commit d082b3f4b9
15 changed files with 839 additions and 492 deletions

View File

@ -17,7 +17,7 @@ pub:
// Private function, used by V (`nums := []int`) // Private function, used by V (`nums := []int`)
fn new_array(mylen, cap, elm_size int) array { 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{ arr := array{
len: mylen len: mylen
cap: cap cap: cap
@ -34,7 +34,7 @@ pub fn make(len, cap, elm_size int) array {
// Private function, used by V (`nums := [1, 2, 3]`) // Private function, used by V (`nums := [1, 2, 3]`)
fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array { 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{ arr := array{
len: len len: len
cap: cap 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 // Private function. Doubles array capacity if needed
fn (a mut array) ensure_cap(required int) { fn (a mut array) ensure_cap(required int) {
if required > a.cap { 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 { for required > cap {
cap *= 2 cap *= 2
} }
@ -204,7 +204,7 @@ fn (a array) right(n int) array {
// used internally for [2..4] // used internally for [2..4]
fn (a array) slice2(start, _end int, end_max bool) array { 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) return a.slice(start, end)
} }
@ -372,7 +372,7 @@ pub fn (b []byte) hex() string {
// TODO: implement for all types // TODO: implement for all types
pub fn copy(dst, src []byte) int { pub fn copy(dst, src []byte) int {
if dst.len > 0 && src.len > 0 { 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) C.memcpy(dst.data, src.left(min).data, dst.element_size * min)
return 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. // 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) // []int == []int (also for: i64, f32, f64, byte, string)
fn array_eq<T>(a1, a2 []T) bool { fn array_eq<T>(a1, a2 []T) bool {
if a1.len != a2.len { if a1.len != a2.len {
return false return false
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
__global g_m2_buf byteptr __global g_m2_buf byteptr
@ -11,12 +10,13 @@ fn init() {
$if windows { $if windows {
if is_atty(0) > 0 { if is_atty(0) > 0 {
C._setmode(C._fileno(C.stdin), C._O_U16TEXT) 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.stdin), C._O_U8TEXT)
} }
C._setmode(C._fileno(C.stdout), 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.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 return v == 0
} }
fn on_panic(f fn (int) int) { fn on_panic(f fn(int)int) {
// TODO // TODO
} }
pub fn print_backtrace_skipping_top_frames(skipframes int) { pub fn print_backtrace_skipping_top_frames(skipframes int) {
$if windows { $if windows {
$if msvc { $if msvc {
if print_backtrace_skipping_top_frames_msvc(skipframes) { return } if print_backtrace_skipping_top_frames_msvc(skipframes) {
return
}
} }
$if mingw { $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') 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: // 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_skipping_top_frames
// 1 frame for print_backtrace itself // 1 frame for print_backtrace itself
@ -58,7 +63,7 @@ pub fn print_backtrace(){
} }
// replaces panic when -debug arg is passed // 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('================ V panic ================')
println(' module: $mod') println(' module: $mod')
println(' function: ${fn_name}()') println(' function: ${fn_name}()')
@ -99,9 +104,8 @@ pub fn print(s string) {
} }
} }
__global total_m i64=0
__global total_m i64 = 0 __global nr_mallocs int=0
__global nr_mallocs int = 0
[unsafe_fn] [unsafe_fn]
pub fn malloc(n int) byteptr { pub fn malloc(n int) byteptr {
@ -120,7 +124,7 @@ pub fn malloc(n int) byteptr {
} }
return ptr return ptr
} }
/* /*
TODO TODO
#ifdef VPLAY #ifdef VPLAY
if n > 10000 { if n > 10000 {
@ -133,6 +137,7 @@ TODO
print_backtrace() print_backtrace()
#endif #endif
*/ */
} }
pub fn calloc(n int) byteptr { pub fn calloc(n int) byteptr {
@ -166,3 +171,4 @@ pub fn is_atty(fd int) int {
return C.isatty(fd) return C.isatty(fd)
} }
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
pub fn println(s string) { 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 { fn print_backtrace_skipping_top_frames_nix(xskipframes int) bool {
skipframes := xskipframes + 2 skipframes := xskipframes + 2
$if macos { return print_backtrace_skipping_top_frames_mac(skipframes) } $if macos {
$if linux { return print_backtrace_skipping_top_frames_linux(skipframes) } return print_backtrace_skipping_top_frames_mac(skipframes)
$if freebsd { return print_backtrace_skipping_top_frames_freebsd(skipframes) } }
$if linux {
return print_backtrace_skipping_top_frames_linux(skipframes)
}
$if freebsd {
return print_backtrace_skipping_top_frames_freebsd(skipframes)
}
return false 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 // so there is no need to have their twins in builtin_windows.v
fn print_backtrace_skipping_top_frames_mac(skipframes int) bool { fn print_backtrace_skipping_top_frames_mac(skipframes int) bool {
$if macos { $if macos {
buffer := [100]byteptr buffer := [100]byteptr
nr_ptrs := C.backtrace(*voidptr(buffer), 100) nr_ptrs := C.backtrace(*voidptr(buffer), 100)
C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs-skipframes, 1) C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs - skipframes, 1)
} }
return true return true
} }
fn print_backtrace_skipping_top_frames_freebsd(skipframes int) bool { fn print_backtrace_skipping_top_frames_freebsd(skipframes int) bool {
$if freebsd { $if freebsd {
buffer := [100]byteptr buffer := [100]byteptr
nr_ptrs := C.backtrace(*voidptr(buffer), 100) nr_ptrs := C.backtrace(*voidptr(buffer), 100)
C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs-skipframes, 1) C.backtrace_symbols_fd(*voidptr(&buffer[skipframes]), nr_ptrs - skipframes, 1)
} }
return true return true
} }
fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { 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" .') println('TODO: print_backtrace_skipping_top_frames_linux $skipframes with tcc fails tests with "stack smashing detected" .')
return false return false
} }
$if !android { // backtrace is not available on Android. $if !android {
// backtrace is not available on Android.
$if glibc { $if glibc {
buffer := [100]byteptr buffer := [100]byteptr
nr_ptrs := C.backtrace(*voidptr(buffer), 100) nr_ptrs := C.backtrace(*voidptr(buffer), 100)
nr_actual_frames := nr_ptrs-skipframes nr_actual_frames := nr_ptrs - skipframes
mut sframes := []string mut sframes := []string
csymbols := C.backtrace_symbols(*voidptr(&buffer[skipframes]), csymbols := C.backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
nr_actual_frames) for i in 0 .. nr_actual_frames {
for i in 0..nr_actual_frames { sframes << tos2(csymbols[i]) } sframes << tos2(csymbols[i])
}
for sframe in sframes { for sframe in sframes {
executable := sframe.all_before('(') executable := sframe.all_before('(')
addr := sframe.all_after('[').all_before(']') addr := sframe.all_after('[').all_before(']')
beforeaddr := sframe.all_before('[') beforeaddr := sframe.all_before('[')
cmd := 'addr2line -e $executable $addr' cmd := 'addr2line -e $executable $addr'
// taken from os, to avoid depending on the os module inside builtin.v // taken from os, to avoid depending on the os module inside builtin.v
f := C.popen(cmd.str, 'r') f := C.popen(cmd.str, 'r')
if isnil(f) { if isnil(f) {
println(sframe) continue println(sframe)
continue
} }
buf := [1000]byte buf := [1000]byte
mut output := '' mut output := ''
for C.fgets(voidptr(buf), 1000, f) != 0 { for C.fgets(voidptr(buf), 1000, f) != 0 {
output += tos(buf, vstrlen(buf)) output += tos(buf, vstrlen(buf))
} }
output = output.trim_space()+':' output = output.trim_space() + ':'
if 0 != C.pclose(f) { if 0 != C.pclose(f) {
println(sframe) continue println(sframe)
continue
} }
if output in ['??:0:','??:?:'] { output = '' } if output in ['??:0:', '??:?:'] {
println( '${output:-46s} | ${addr:14s} | $beforeaddr') 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 return true
}$else{ } $else {
C.printf('backtrace_symbols_fd is missing, so printing backtraces is not available.\n') 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') C.printf('Some libc implementations like musl simply do not provide it.\n')
} }
} }
return false return false
} }

View File

@ -1,166 +1,403 @@
module builtin module builtin
// <string.h> // <string.h>
fn C.memcpy(byteptr, byteptr, int) voidptr 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.realloc(a byteptr, b int) byteptr
fn C.qsort(voidptr, int, int, voidptr) 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 // stdio.h
fn C.popen(c byteptr, t byteptr) voidptr fn C.popen(c byteptr, t byteptr) voidptr
// <execinfo.h> // <execinfo.h>
fn backtrace(a voidptr, b int) int 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> // <libproc.h>
fn proc_pidpath(int, voidptr, int) int fn proc_pidpath(int, voidptr, int) int
fn C.realpath(byteptr, byteptr) &char fn C.realpath(byteptr, byteptr) &char
fn C.chmod(byteptr, int) int fn C.chmod(byteptr, int) int
fn C.printf(byteptr, ...byteptr) int fn C.printf(byteptr, ...byteptr) int
fn C.fputs(byteptr) int fn C.fputs(byteptr) int
fn C.fflush(byteptr) int fn C.fflush(byteptr) int
// TODO define args in these functions // TODO define args in these functions
fn C.fseek() int fn C.fseek() int
fn C.fopen() voidptr fn C.fopen() voidptr
fn C.fwrite() int fn C.fwrite() int
fn C.fclose() int fn C.fclose() int
fn C.pclose() int fn C.pclose() int
fn C.system() int fn C.system() int
fn C.setenv() int fn C.setenv() int
fn C.unsetenv() int fn C.unsetenv() int
fn C.access() int fn C.access() int
fn C.remove() int fn C.remove() int
fn C.rmdir() int fn C.rmdir() int
fn C.chdir() int fn C.chdir() int
fn C.fread() int fn C.fread() int
fn C.rewind() int fn C.rewind() int
fn C.stat() int fn C.stat() int
fn C.lstat() int fn C.lstat() int
fn C.rename() int fn C.rename() int
fn C.fgets() int fn C.fgets() int
fn C.memset() int fn C.memset() int
fn C.sigemptyset() int fn C.sigemptyset() int
fn C.getcwd() int fn C.getcwd() int
fn C.signal() int fn C.signal() int
fn C.mktime() int fn C.mktime() int
fn C.gettimeofday() int fn C.gettimeofday() int
fn C.sleep() int fn C.sleep() int
fn C.usleep() int fn C.usleep() int
fn C.opendir() voidptr fn C.opendir() voidptr
fn C.closedir() int fn C.closedir() int
fn C.mkdir() int fn C.mkdir() int
fn C.srand() int fn C.srand() int
fn C.atof() int fn C.atof() int
fn C.tolower() int fn C.tolower() int
fn C.toupper() int fn C.toupper() int
fn C.getchar() int fn C.getchar() int
fn C.strerror() charptr fn C.strerror() charptr
fn C.snprintf() int fn C.snprintf() int
fn C.fprintf(byteptr, ...byteptr) fn C.fprintf(byteptr, ...byteptr)
fn C.WIFEXITED() bool fn C.WIFEXITED() bool
fn C.WEXITSTATUS() int fn C.WEXITSTATUS() int
fn C.WIFSIGNALED() bool fn C.WIFSIGNALED() bool
fn C.WTERMSIG() int fn C.WTERMSIG() int
fn C.DEFAULT_LE() bool fn C.DEFAULT_LE() bool
fn C.DEFAULT_EQ() bool fn C.DEFAULT_EQ() bool
fn C.DEFAULT_GT() bool fn C.DEFAULT_GT() bool
fn C.DEFAULT_EQUAL() bool fn C.DEFAULT_EQUAL() bool
fn C.DEFAULT_NOT_EQUAL() bool fn C.DEFAULT_NOT_EQUAL() bool
fn C.DEFAULT_LT() bool fn C.DEFAULT_LT() bool
fn C.DEFAULT_GE() bool fn C.DEFAULT_GE() bool
fn C.isatty() int fn C.isatty() int
fn C.syscall() int fn C.syscall() int
fn C.sysctl() int fn C.sysctl() int
// Windows // Windows
fn C._setmode(int, int) int fn C._setmode(int, int) int
fn C._fileno(int) int fn C._fileno(int) int
fn C._get_osfhandle(fd int) C.intptr_t fn C._get_osfhandle(fd int) C.intptr_t
fn C.GetModuleFileNameW(hModule voidptr, lpFilename &u16, nSize u32) u32 fn C.GetModuleFileNameW(hModule voidptr, lpFilename &u16, nSize u32) u32
fn C.CreatePipe(hReadPipe &voidptr, hWritePipe &voidptr, lpPipeAttributes voidptr, nSize u32) bool fn C.CreatePipe(hReadPipe &voidptr, hWritePipe &voidptr, lpPipeAttributes voidptr, nSize u32) bool
fn C.SetHandleInformation(hObject voidptr, dwMask u32, dwFlags u32) bool fn C.SetHandleInformation(hObject voidptr, dwMask u32, dwFlags u32) bool
fn C.ExpandEnvironmentStringsW(lpSrc &u16, lpDst &u16, nSize u32) u32 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.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.ReadFile(hFile voidptr, lpBuffer voidptr, nNumberOfBytesToRead u32, lpNumberOfBytesRead voidptr, lpOverlapped voidptr) bool
fn C.GetFileAttributesW(lpFileName byteptr) u32 fn C.GetFileAttributesW(lpFileName byteptr) u32
fn C.RegQueryValueExW(hKey voidptr, lpValueName &u16, lpReserved &u32, lpType &u32, lpData byteptr, lpcbData &u32) int 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.RegOpenKeyExW(hKey voidptr, lpSubKey &u16, ulOptions u32, samDesired u32, phkResult voidptr) int
fn C.RegCloseKey() fn C.RegCloseKey()
fn C.RegQueryValueEx() voidptr fn C.RegQueryValueEx() voidptr
fn C.RemoveDirectory() int fn C.RemoveDirectory() int
fn C.GetStdHandle() voidptr fn C.GetStdHandle() voidptr
fn C.SetConsoleMode() fn C.SetConsoleMode()
fn C.GetConsoleMode() int fn C.GetConsoleMode() int
fn C._putws() fn C._putws()
fn C.wprintf() fn C.wprintf()
fn C.setbuf() fn C.setbuf()
fn C.SymCleanup() fn C.SymCleanup()
fn C.MultiByteToWideChar() int fn C.MultiByteToWideChar() int
fn C.wcslen() int fn C.wcslen() int
fn C.WideCharToMultiByte() int fn C.WideCharToMultiByte() int
fn C._wstat() fn C._wstat()
fn C._wrename() fn C._wrename()
fn C._wfopen() voidptr fn C._wfopen() voidptr
fn C._wpopen() voidptr fn C._wpopen() voidptr
fn C._pclose() int fn C._pclose() int
fn C._wsystem() int fn C._wsystem() int
fn C._wgetenv() voidptr fn C._wgetenv() voidptr
fn C._putenv() int fn C._putenv() int
fn C._waccess() int fn C._waccess() int
fn C._wremove() fn C._wremove()
fn C.ReadConsole() fn C.ReadConsole()
fn C.fgetws() voidptr fn C.fgetws() voidptr
fn C.GetModuleFileName() int fn C.GetModuleFileName() int
fn C._wchdir() fn C._wchdir()
fn C._wgetcwd() int fn C._wgetcwd() int
fn C._fullpath() int fn C._fullpath() int
fn C.GetCommandLine() voidptr fn C.GetCommandLine() voidptr
fn C.CommandLineToArgvW() &voidptr fn C.CommandLineToArgvW() &voidptr
fn C.LocalFree() fn C.LocalFree()
fn C.FindFirstFileW() voidptr fn C.FindFirstFileW() voidptr
fn C.FindFirstFile() voidptr fn C.FindFirstFile() voidptr
fn C.FindNextFile() voidptr fn C.FindNextFile() voidptr
fn C.FindClose() fn C.FindClose()
fn C.MAKELANGID() int fn C.MAKELANGID() int
fn C.FormatMessage() voidptr fn C.FormatMessage() voidptr
fn C.CloseHandle() fn C.CloseHandle()
fn C.GetExitCodeProcess() fn C.GetExitCodeProcess()
fn C.RegOpenKeyEx() voidptr fn C.RegOpenKeyEx() voidptr
fn C.GetTickCount() i64 fn C.GetTickCount() i64
fn C.Sleep() fn C.Sleep()
fn C.WSAStartup(u16, &voidptr) int fn C.WSAStartup(u16, &voidptr) int
fn C.WSAGetLastError() int fn C.WSAGetLastError() int
fn C.closesocket(int) int fn C.closesocket(int) int
fn C.vschannel_init(&C.TlsContext) 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.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.GetLastError() u32
fn C.CreateDirectory(byteptr, int) bool 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 fn C.ReleaseMutex(voidptr) bool

View File

@ -143,3 +143,4 @@ fn (a f64) gebit(b f64) bool {
fn (a f32) gebit(b f32) bool { fn (a f32) gebit(b f32) bool {
return C.DEFAULT_GE(a, b) return C.DEFAULT_GE(a, b)
} }

View File

@ -1,9 +1,7 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
/* /*
This is work in progress. This is work in progress.
A very early test version of the hashmap with a fixed size. 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. the performance gains are basically non-existent.
*/ */
struct hashmap { struct hashmap {
cap int cap int
keys []string keys []string
table []hashmapentry table []hashmapentry
elm_size int elm_size int
pub: pub:
nr_collisions int nr_collisions int
} }
struct hashmapentry { struct hashmapentry {
key string key string
val int val int
next &hashmapentry // linked list for collisions next &hashmapentry // linked list for collisions
} }
const ( const (
min_cap = 2 << 10 min_cap = 2<<10
max_cap = 2 << 20 max_cap = 2<<20
) )
fn new_hashmap(planned_nr_items int) hashmap { fn new_hashmap(planned_nr_items int) hashmap {
mut cap := planned_nr_items * 5 mut cap := planned_nr_items * 5
if cap < min_cap { if cap < min_cap {
cap = min_cap cap = min_cap
} }
if cap > max_cap { if cap > max_cap {
cap = max_cap cap = max_cap
} }
return hashmap{ return hashmap{
cap: cap cap: cap
elm_size: 4 elm_size: 4
table: make(cap, cap, sizeof(hashmapentry)) table: make(cap, cap, sizeof(hashmapentry))
} }
} }
fn (m mut hashmap) set(key string, val int) { 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 idx := hash % m.cap
if m.table[idx].key.len != 0 { 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++ m.nr_collisions++
//println('collision:' + m.table[idx].key) // println('collision:' + m.table[idx].key)
mut e := &m.table[idx] mut e := &m.table[idx]
for e.next != 0 { for e.next != 0 {
e = e.next e = e.next
} }
e.next = &hashmapentry{key, val, 0} e.next = &hashmapentry{
} else { key,val,0}
m.table[idx] = hashmapentry{key, val, 0}
} }
} else {
m.table[idx] = hashmapentry{
key,val,0}
}
}
fn (m mut hashmap) get(key string) int { fn (m mut hashmap) get(key string) int {
hash := int(b_fabs( key.hash() )) hash := int(b_fabs(key.hash()))
idx := hash % m.cap idx := hash % m.cap
mut e := &m.table[idx] mut e := &m.table[idx]
for e.next != 0 { // todo unsafe { for e.next != 0 {
// todo unsafe {
if e.key == key { if e.key == key {
return e.val return e.val
} }
e = e.next e = e.next
} }
return e.val 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 }
}

View File

@ -1,11 +1,10 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
pub fn ptr_str(ptr voidptr) string { 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) C.sprintf(charptr(buf), '%p', ptr)
return tos(buf, vstrlen(buf)) return tos(buf, vstrlen(buf))
} }
@ -19,7 +18,7 @@ pub fn (nn int) str() string {
return '0' return '0'
} }
max := 16 max := 16
mut buf := calloc(max+1) mut buf := calloc(max + 1)
mut len := 0 mut len := 0
mut is_neg := false mut is_neg := false
if n < 0 { if n < 0 {
@ -42,12 +41,20 @@ pub fn (nn int) str() string {
return tos(buf + max - len, len) return tos(buf + max - len, len)
} }
pub fn (n i8) str() string { return int(n).str() } pub fn (n i8) str() string {
pub fn (n i16) str() string { return int(n).str() } return int(n).str()
pub fn (n u16) 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 { pub fn (nn u32) str() string {
mut n := nn mut n := nn
if n == u32(0) { if n == u32(0) {
return '0' return '0'
} }
@ -84,6 +91,7 @@ pub fn (nn byte) str() string {
} }
*/ */
pub fn (nn i64) str() string { pub fn (nn i64) str() string {
mut n := nn mut n := nn
if n == i64(0) { if n == i64(0) {
@ -113,7 +121,7 @@ pub fn (nn i64) str() string {
} }
pub fn (nn u64) str() string { pub fn (nn u64) str() string {
mut n := nn mut n := nn
if n == u64(0) { if n == u64(0) {
return '0' return '0'
} }
@ -138,24 +146,16 @@ pub fn (b bool) str() string {
} }
pub fn (n int) hex() string { pub fn (n int) hex() string {
len := if n >= 0 { len := if n >= 0 { n.str().len + 3 } else { 11 }
n.str().len + 3
} else {
11
}
hex := malloc(len) // 0x + \n hex := malloc(len) // 0x + \n
count := int(C.sprintf(charptr(hex), '0x%x', n)) count := int(C.sprintf(charptr(hex), '0x%x', n))
return tos(hex, count) return tos(hex, count)
} }
pub fn (n i64) hex() string { pub fn (n i64) hex() string {
len := if n >= i64(0) { len := if n >= i64(0) { n.str().len + 3 } else { 19 }
n.str().len + 3
} else {
19
}
hex := malloc(len) 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) return tos(hex, count)
} }
@ -169,21 +169,21 @@ pub fn (a []byte) contains(val byte) bool {
} }
pub fn (c rune) str() string { 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) len := utf8_char_len(fst_byte)
mut str := string { mut str := string{
len: len len: len
str: malloc(len + 1) str: malloc(len + 1)
} }
for i := 0; i < len; i++ { 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` str[len] = `\0`
return str return str
} }
pub fn (c byte) str() string { pub fn (c byte) str() string {
mut str := string { mut str := string{
len: 1 len: 1
str: malloc(2) str: malloc(2)
} }

View File

@ -1,28 +1,27 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
import strings import strings
pub struct map { pub struct map {
element_size int element_size int
root &mapnode root &mapnode
pub: pub:
size int size int
} }
struct mapnode { struct mapnode {
left &mapnode left &mapnode
right &mapnode right &mapnode
is_empty bool // set by delete() is_empty bool // set by delete()
key string key string
val voidptr val voidptr
} }
fn new_map(cap, elm_size int) map { fn new_map(cap, elm_size int) map {
res := map { res := map{
element_size: elm_size element_size: elm_size
root: 0 root: 0
} }
@ -31,7 +30,7 @@ fn new_map(cap, elm_size int) map {
// `m := { 'one': 1, 'two': 2 }` // `m := { 'one': 1, 'two': 2 }`
fn new_map_init(cap, elm_size int, keys &string, vals voidptr) map { fn new_map_init(cap, elm_size int, keys &string, vals voidptr) map {
mut res := map { mut res := map{
element_size: elm_size element_size: elm_size
root: 0 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 { fn new_node(key string, val voidptr, element_size int) &mapnode {
new_e := &mapnode { new_e := &mapnode{
key: key key: key
val: malloc(element_size) val: malloc(element_size)
left: 0 left: 0
@ -65,7 +64,8 @@ fn (m mut map) insert(n mut mapnode, key string, val voidptr) {
if n.left == 0 { if n.left == 0 {
n.left = new_node(key, val, m.element_size) n.left = new_node(key, val, m.element_size)
m.size++ m.size++
} else { }
else {
m.insert(mut n.left, key, val) m.insert(mut n.left, key, val)
} }
return return
@ -73,12 +73,13 @@ fn (m mut map) insert(n mut mapnode, key string, val voidptr) {
if n.right == 0 { if n.right == 0 {
n.right = new_node(key, val, m.element_size) n.right = new_node(key, val, m.element_size)
m.size++ m.size++
} else { }
else {
m.insert(mut n.right, key, val) 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 { if n.key == key {
C.memcpy(out, n.val, element_size) C.memcpy(out, n.val, element_size)
return true return true
@ -86,35 +87,39 @@ fn (n & mapnode) find(key string, out voidptr, element_size int) bool{
else if n.key > key { else if n.key > key {
if n.left == 0 { if n.left == 0 {
return false return false
} else { }
else {
return n.left.find(key, out, element_size) return n.left.find(key, out, element_size)
} }
} }
else { else {
if n.right == 0 { if n.right == 0 {
return false return false
} else { }
else {
return n.right.find(key, out, element_size) return n.right.find(key, out, element_size)
} }
} }
} }
// same as `find`, but doesn't return a value. Used by `exists` // 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 { if n.key == key && !n.is_empty {
return true return true
} }
else if n.key > key { else if n.key > key {
if isnil(n.left) { if isnil(n.left) {
return false return false
} else { }
else {
return n.left.find2(key, element_size) return n.left.find2(key, element_size)
} }
} }
else { else {
if isnil(n.right) { if isnil(n.right) {
return false return false
} else { }
else {
return n.right.find2(key, element_size) 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 { fn preorder_keys(node &mapnode, keys mut []string, key_i int) int {
mut i := key_i mut i := key_i
if !node.is_empty { if !node.is_empty {
@ -181,7 +187,7 @@ pub fn (m &map) keys() []string {
} }
fn (m map) get(key string, out voidptr) bool { fn (m map) get(key string, out voidptr) bool {
//println('g') // println('g')
if m.root == 0 { if m.root == 0 {
return false return false
} }
@ -197,14 +203,16 @@ pub fn (n mut mapnode) delete(key string, element_size int) {
else if n.key > key { else if n.key > key {
if isnil(n.left) { if isnil(n.left) {
return return
} else { }
else {
n.left.delete(key, element_size) n.left.delete(key, element_size)
} }
} }
else { else {
if isnil(n.right) { if isnil(n.right) {
return return
} else { }
else {
n.right.delete(key, element_size) n.right.delete(key, element_size)
} }
} }
@ -223,10 +231,10 @@ fn (m map) exists(key string) bool {
pub fn (m map) print() { pub fn (m map) print() {
println('<<<<<<<<') println('<<<<<<<<')
//for i := 0; i < m.entries.len; i++ { // for i := 0; i < m.entries.len; i++ {
// entry := m.entries[i] // entry := m.entries[i]
// println('$entry.key => $entry.val') // println('$entry.key => $entry.val')
//} // }
/* /*
for i := 0; i < m.cap * m.element_size; i++ { for i := 0; i < m.cap * m.element_size; i++ {
b := m.table[i] b := m.table[i]
@ -235,6 +243,7 @@ pub fn (m map) print() {
println('') println('')
} }
*/ */
println('>>>>>>>>>>') println('>>>>>>>>>>')
} }
@ -266,9 +275,10 @@ pub fn (m map_string) str() string {
} }
mut sb := strings.new_builder(50) mut sb := strings.new_builder(50)
sb.writeln('{') sb.writeln('{')
for key, val in m { for key, val in m {
sb.writeln(' "$key" => "$val"') sb.writeln(' "$key" => "$val"')
} }
sb.writeln('}') sb.writeln('}')
return sb.str() return sb.str()
} }

View File

@ -1,9 +1,7 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
/* /*
struct Option2<T> { struct Option2<T> {
data T data T
@ -14,12 +12,13 @@ struct Option2<T> {
} }
*/ */
struct Option { struct Option {
data [300]byte data [300]byte
error string error string
ecode int ecode int
ok bool ok bool
is_none bool is_none bool
} }
// `fn foo() ?Foo { return foo }` => `fn foo() ?Foo { return opt_ok(foo); }` // `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 { if size >= 300 {
panic('option size too big: $size (max is 300), this is a temporary limit') panic('option size too big: $size (max is 300), this is a temporary limit')
} }
res := Option { res := Option{
ok: true ok: true
} }
C.memcpy(res.data, data, size) C.memcpy(res.data, data, size)
@ -36,21 +35,21 @@ fn opt_ok(data voidptr, size int) Option {
// used internally when returning `none` // used internally when returning `none`
fn opt_none() Option { fn opt_none() Option {
return Option{ is_none: true } return Option{
is_none: true
}
} }
pub fn error(s string) Option { pub fn error(s string) Option {
return Option { return Option{
error: s error: s
} }
} }
pub fn error_with_code(s string, code int) Option { pub fn error_with_code(s string, code int) Option {
return Option { return Option{
error: s error: s
ecode: code ecode: code
} }
} }

View File

@ -1,11 +1,9 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
import strconv import strconv
/* /*
NB: A V string should be/is immutable from the point of view of 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 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 { pub struct string {
//mut: // mut:
//hash_cache int // hash_cache int
pub: pub:
str byteptr // points to a C style 0 terminated string of bytes. 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 { pub struct ustring {
@ -70,7 +68,7 @@ pub fn tos(s byteptr, len int) string {
if s == 0 { if s == 0 {
panic('tos(): nil string') panic('tos(): nil string')
} }
return string { return string{
str: s str: s
len: len len: len
} }
@ -89,7 +87,7 @@ pub fn tos2(s byteptr) string {
if s == 0 { if s == 0 {
panic('tos2: nil string') panic('tos2: nil string')
} }
return string { return string{
str: s str: s
len: vstrlen(s) len: vstrlen(s)
} }
@ -100,14 +98,14 @@ pub fn tos3(s charptr) string {
if s == 0 { if s == 0 {
panic('tos3: nil string') panic('tos3: nil string')
} }
return string { return string{
str: byteptr(s) str: byteptr(s)
len: C.strlen(s) len: C.strlen(s)
} }
} }
pub fn (a string) clone() string { pub fn (a string) clone() string {
mut b := string { mut b := string{
len: a.len len: a.len
str: malloc(a.len + 1) 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 // cstring_to_vstring creates a copy of cstr and turns it into a v string
pub fn cstring_to_vstring(cstr byteptr) string { pub fn cstring_to_vstring(cstr byteptr) string {
slen := C.strlen(cstr) slen := C.strlen(cstr)
mut s := byteptr( memdup(cstr, slen+1) ) mut s := byteptr(memdup(cstr, slen + 1))
s[slen] = `\0` s[slen] = `\0`
return tos(s, slen) return tos(s, slen)
} }
pub fn (s string) replace_once(rep, with string) string { pub fn (s string) replace_once(rep, with string) string {
index := s.index(rep) or { return s } index := s.index(rep) or {
return s.substr(0,index) + with + s.substr(index + rep.len, s.len) return s
}
return s.substr(0, index) + with + s.substr(index + rep.len, s.len)
} }
pub fn (s string) replace(rep, with string) string { 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 // 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) 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 // Fill the new string
mut idx_pos := 0 mut idx_pos := 0
mut cur_idx := idxs[idx_pos] mut cur_idx := idxs[idx_pos]
@ -191,7 +191,7 @@ pub fn (s string) replace(rep, with string) string {
} }
struct RepIndex { struct RepIndex {
idx int idx int
val_idx int val_idx int
} }
@ -199,7 +199,6 @@ fn (a mut []RepIndex) sort() {
a.sort_with_compare(compare_rep_index) a.sort_with_compare(compare_rep_index)
} }
// TODO // TODO
/* /*
fn (a RepIndex) < (b RepIndex) bool { fn (a RepIndex) < (b RepIndex) bool {
@ -207,6 +206,7 @@ fn (a RepIndex) < (b RepIndex) bool {
} }
*/ */
fn compare_rep_index(a, b &RepIndex) int { fn compare_rep_index(a, b &RepIndex) int {
if a.idx < b.idx { if a.idx < b.idx {
return -1 return -1
@ -232,10 +232,10 @@ pub fn (s string) replace_each(vals []string) string {
mut new_len := s.len mut new_len := s.len
mut idxs := []RepIndex mut idxs := []RepIndex
mut idx := 0 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'] // vals: ['rep1, 'with1', 'rep2', 'with2']
rep := vals[rep_i] rep := vals[rep_i]
with := vals[rep_i+1] with := vals[rep_i + 1]
for { for {
idx = s.index_after(rep, idx) idx = s.index_after(rep, idx)
if idx == -1 { 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, // We need to remember both the position in the string,
// and which rep/with pair it refers to. // and which rep/with pair it refers to.
idxs << RepIndex{idx, rep_i} idxs << RepIndex{
idx,rep_i}
idx++ idx++
new_len += with.len - rep.len new_len += with.len - rep.len
} }
@ -253,7 +254,7 @@ pub fn (s string) replace_each(vals []string) string {
return s return s
} }
idxs.sort() 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 // Fill the new string
mut idx_pos := 0 mut idx_pos := 0
mut cur_idx := idxs[idx_pos] 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" // Reached the location of rep, replace it with "with"
if i == cur_idx.idx { if i == cur_idx.idx {
rep := vals[cur_idx.val_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++ { for j := 0; j < with.len; j++ {
b[b_i] = with[j] b[b_i] = with[j]
b_i++ b_i++
@ -290,7 +291,7 @@ pub fn (s string) bool() bool {
} }
pub fn (s string) int() int { 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 { pub fn (s string) i64() i64 {
@ -298,12 +299,12 @@ pub fn (s string) i64() i64 {
} }
pub fn (s string) f32() f32 { pub fn (s string) f32() f32 {
//return C.atof(charptr(s.str)) // return C.atof(charptr(s.str))
return f32(strconv.atof64(s)) return f32(strconv.atof64(s))
} }
pub fn (s string) f64() f64 { pub fn (s string) f64() f64 {
//return C.atof(charptr(s.str)) // return C.atof(charptr(s.str))
return strconv.atof64(s) return strconv.atof64(s)
} }
@ -317,7 +318,8 @@ pub fn (s string) u64() u64 {
// == // ==
fn (s string) eq(a string) bool { 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') panic('string.eq(): nil string')
} }
if s.len != a.len { 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. // TODO `fn (s string) + (a string)` ? To be consistent with operator overloading syntax.
fn (s string) add(a string) string { fn (s string) add(a string) string {
new_len := a.len + s.len new_len := a.len + s.len
mut res := string { mut res := string{
len: new_len len: new_len
str: malloc(new_len + 1) str: malloc(new_len + 1)
} }
@ -380,7 +382,7 @@ fn (s string) add(a string) string {
for j := 0; j < a.len; j++ { for j := 0; j < a.len; j++ {
res[s.len + j] = a[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 return res
} }
@ -412,7 +414,9 @@ pub fn (s string) split_nth(delim string, nth int) []string {
j++ j++
} }
was_last := nth > 0 && res.len == nth was_last := nth > 0 && res.len == nth
if was_last{break} if was_last {
break
}
last := i == s.len - 1 last := i == s.len - 1
if is_delim || last { if is_delim || last {
if !is_delim && last { if !is_delim && last {
@ -427,7 +431,7 @@ pub fn (s string) split_nth(delim string, nth int) []string {
} }
i++ i++
} }
if s.ends_with (delim) && (nth < 1 || res.len < nth) { if s.ends_with(delim) && (nth < 1 || res.len < nth) {
res << '' res << ''
} }
return res return res
@ -460,6 +464,7 @@ fn (s string) left(n int) string {
} }
return s.substr(0, n) return s.substr(0, n)
} }
// 'hello'.right(2) => 'llo' // 'hello'.right(2) => 'llo'
fn (s string) right(n int) string { fn (s string) right(n int) string {
if n >= s.len { 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)') panic('substr($start, $end) out of bounds (len=$s.len)')
} }
len := end - start len := end - start
mut res := string{
mut res := string {
len: len len: len
str: malloc(len + 1) 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[i] = s.str[start + i]
} }
res.str[len] = `\0` res.str[len] = `\0`
/*
/*
res := string { res := string {
str: s.str + start str: s.str + start
len: len len: len
} }
*/ */
return res return res
} }
@ -536,39 +540,40 @@ pub fn (s string) index(p string) ?int {
// KMP search // KMP search
fn (s string) index_kmp(p string) int { fn (s string) index_kmp(p string) int {
if p.len > s.len { if p.len > s.len {
return -1 return -1
} }
mut prefix := [0].repeat(p.len) mut prefix := [0].repeat(p.len)
mut j := 0 mut j := 0
for i := 1; i < p.len; i++ { for i := 1; i < p.len; i++ {
for p[j] != p[i] && j > 0 { for p[j] != p[i] && j > 0 {
j = prefix[j - 1] j = prefix[j - 1]
} }
if p[j] == p[i] { if p[j] == p[i] {
j++ j++
} }
prefix[i] = j prefix[i] = j
} }
j = 0 j = 0
for i := 0; i < s.len; i++ { for i := 0; i < s.len; i++ {
for p[j] != s[i] && j > 0 { for p[j] != s[i] && j > 0 {
j = prefix[j - 1] j = prefix[j - 1]
} }
if p[j] == s[i] { if p[j] == s[i] {
j++ j++
} }
if j == p.len { if j == p.len {
return i - p.len + 1 return i - p.len + 1
} }
} }
return -1 return -1
} }
pub fn (s string) index_any(chars string) int { pub fn (s string) index_any(chars string) int {
for c in chars { for c in chars {
index := s.index(c.str()) or { continue } index := s.index(c.str()) or {
continue
}
return index return index
} }
return -1 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 { 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 { if s[i] == c {
return i 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 { 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 { if s[i] == c {
return i return i
} }
@ -666,7 +671,9 @@ pub fn (s string) contains(p string) bool {
} }
pub fn (s string) starts_with(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 return idx == 0
} }
@ -699,29 +706,31 @@ pub fn (s string) to_upper() string {
pub fn (s string) capitalize() string { pub fn (s string) capitalize() string {
sl := s.to_lower() sl := s.to_lower()
cap := sl[0].str().to_upper() + sl.right(1) cap := sl[0].str().to_upper() + sl.right(1)
return cap return cap
} }
pub fn (s string) title() string { pub fn (s string) title() string {
words := s.split(' ') words := s.split(' ')
mut tit := []string mut tit := []string
for word in words { for word in words {
tit << word.capitalize() tit << word.capitalize()
} }
title := tit.join(' ') title := tit.join(' ')
return title return title
} }
// 'hey [man] how you doin' // 'hey [man] how you doin'
// find_between('[', ']') == 'man' // find_between('[', ']') == 'man'
pub fn (s string) find_between(start, end string) string { 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' // First get everything to the right of 'start'
val := s.right(start_pos + start.len) 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) return val.left(end_pos)
} }
@ -756,8 +765,9 @@ pub fn (a []string) to_c() voidptr {
} }
*/ */
pub fn (c byte) is_space() bool { 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 { pub fn (s string) trim_space() string {
@ -786,7 +796,7 @@ pub fn (s string) trim(cutset string) string {
return '' 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 { 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 { for pos >= -1 && s[pos] in cs_arr {
pos-- pos--
} }
return s.left(pos+1) return s.left(pos + 1)
} }
// fn print_cur_thread() { // fn print_cur_thread() {
@ -855,10 +865,11 @@ pub fn (s mut []string) sort_by_len() {
} }
pub fn (s string) ustring() ustring { pub fn (s string) ustring() ustring {
mut res := ustring { mut res := ustring{
s: s s: s
// runes will have at least s.len elements, save reallocations // runes will have at least s.len elements, save reallocations
// TODO use VLA for small strings? // TODO use VLA for small strings?
runes: new_array(0, s.len, sizeof(int)) runes: new_array(0, s.len, sizeof(int))
} }
for i := 0; i < s.len; i++ { 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 // 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. // right away. Uses global buffer for storing runes []int array.
__global g_ustring_runes []int __global g_ustring_runes []int
pub fn (s string) ustring_tmp() ustring { pub fn (s string) ustring_tmp() ustring {
if g_ustring_runes.len == 0 { if g_ustring_runes.len == 0 {
g_ustring_runes = new_array(0, 128, sizeof(int)) g_ustring_runes = new_array(0, 128, sizeof(int))
} }
mut res := ustring { mut res := ustring{
s: s s: s
} }
res.runes = g_ustring_runes res.runes = g_ustring_runes
@ -922,7 +934,7 @@ fn (u ustring) ge(a ustring) bool {
} }
fn (u ustring) add(a ustring) ustring { fn (u ustring) add(a ustring) ustring {
mut res := ustring { mut res := ustring{
s: u.s + a.s s: u.s + a.s
runes: new_array(0, u.s.len + a.s.len, sizeof(int)) 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 { if _start > _end || _start > u.len || _end > u.len || _start < 0 || _end < 0 {
panic('substr($_start, $_end) out of bounds (len=$u.len)') panic('substr($_start, $_end) out of bounds (len=$u.len)')
} }
end := if _end >= u.len { end := if _end >= u.len { u.s.len } else { u.runes[_end] }
u.s.len
}
else {
u.runes[_end]
}
return u.s.substr(u.runes[_start], 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' // all_before('23:34:45.234', '.') == '23:34:45'
pub fn (s string) all_before(dot string) string { 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) return s.left(pos)
} }
@ -1131,12 +1140,12 @@ pub fn (s string) reverse() string {
if s.len == 0 { if s.len == 0 {
return '' return ''
} }
mut res := string { mut res := string{
len: s.len len: s.len
str: malloc(s.len) str: malloc(s.len)
} }
for i := s.len - 1; i >= 0; i-- { for i := s.len - 1; i >= 0; i-- {
res[s.len-i-1] = s[i] res[s.len - i - 1] = s[i]
} }
return res return res
} }
@ -1158,9 +1167,8 @@ pub fn (c byte) is_white() bool {
return i == 10 || i == 32 || i == 9 || i == 13 || c == `\r` return i == 10 || i == 32 || i == 9 || i == 13 || c == `\r`
} }
pub fn (s string) hash() int { pub fn (s string) hash() int {
//mut h := s.hash_cache // mut h := s.hash_cache
mut h := 0 mut h := 0
if h == 0 && s.len > 0 { if h == 0 && s.len > 0 {
for c in s { for c in s {
@ -1185,11 +1193,12 @@ pub fn (s string) repeat(count int) string {
return s return s
} }
mut ret := malloc(s.len * count + 1) mut ret := malloc(s.len * count + 1)
for i in 0..count { for i in 0 .. count {
for j in 0..s.len { for j in 0 .. s.len {
ret[i*s.len + j] = s[j] ret[i * s.len + j] = s[j]
} }
} }
ret[s.len * count] = 0 ret[s.len * count] = 0
return string(ret) return string(ret)
} }

View File

@ -1,38 +1,46 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module builtin module builtin
pub fn utf8_char_len(b byte) int { 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 // Convert utf32 to utf8
// utf32 == Codepoint // utf32 == Codepoint
pub fn utf32_to_str(code u32) string { pub fn utf32_to_str(code u32) string {
icode := int(code) //Prevents doing casts everywhere icode := int(code) // Prevents doing casts everywhere
mut buffer := malloc(5) mut buffer := malloc(5)
if icode <= 127 /* 0x7F */ { if icode <= 127/* 0x7F */ {
buffer[0] = icode buffer[0] = icode
return tos(buffer, 1) return tos(buffer, 1)
} }
if (icode <= 2047 /* 0x7FF */) { if (icode <= 2047/* 0x7FF */) {
buffer[0] = 192 /*0xC0*/ | (icode >> 6) /* 110xxxxx */ buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */
buffer[1] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 2) return tos(buffer, 2)
} }
if (icode <= 65535 /* 0xFFFF */) { if (icode <= 65535/* 0xFFFF */) {
buffer[0] = 224 /*0xE0*/ | (icode >> 12) /* 1110xxxx */ buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */
buffer[1] = 128 /*0x80*/ | ((icode >> 6) & 63 /*0x3F*/) /* 10xxxxxx */
buffer[2] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */ buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 3) return tos(buffer, 3)
} }
if (icode <= 1114111 /* 0x10FFFF */) { if (icode <= 1114111/* 0x10FFFF */) {
buffer[0] = 240 /*0xF0*/ | (icode >> 18) /* 11110xxx */ 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[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
buffer[3] = 128 /*0x80*/ | (icode & 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 tos(buffer, 4)
} }
return '' return ''
@ -40,28 +48,37 @@ pub fn utf32_to_str(code u32) string {
// TODO copypasta // TODO copypasta
pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string { pub fn utf32_to_str_no_malloc(code u32, buf voidptr) string {
icode := int(code) //Prevents doing casts everywhere icode := int(code) // Prevents doing casts everywhere
mut buffer := byteptr(buf) mut buffer := byteptr(buf)
if icode <= 127 /* 0x7F */ { if icode <= 127/* 0x7F */ {
buffer[0] = icode buffer[0] = icode
return tos(buffer, 1) return tos(buffer, 1)
} }
if (icode <= 2047 /* 0x7FF */) { if (icode <= 2047/* 0x7FF */) {
buffer[0] = 192 /*0xC0*/ | (icode >> 6) /* 110xxxxx */ buffer[0] = 192/*0xC0*/ | (icode>>6)/* 110xxxxx */
buffer[1] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */
buffer[1] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 2) return tos(buffer, 2)
} }
if (icode <= 65535 /* 0xFFFF */) { if (icode <= 65535/* 0xFFFF */) {
buffer[0] = 224 /*0xE0*/ | (icode >> 12) /* 1110xxxx */ buffer[0] = 224/*0xE0*/ | (icode>>12)/* 1110xxxx */
buffer[1] = 128 /*0x80*/ | ((icode >> 6) & 63 /*0x3F*/) /* 10xxxxxx */
buffer[2] = 128 /*0x80*/ | (icode & 63 /*0x3F*/) /* 10xxxxxx */ buffer[1] = 128/*0x80*/ | ((icode>>6) & 63/*0x3F*/)/* 10xxxxxx */
buffer[2] = 128/*0x80*/ | (icode & 63/*0x3F*/)/* 10xxxxxx */
return tos(buffer, 3) return tos(buffer, 3)
} }
if (icode <= 1114111 /* 0x10FFFF */) { if (icode <= 1114111/* 0x10FFFF */) {
buffer[0] = 240 /*0xF0*/ | (icode >> 18) /* 11110xxx */ 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[1] = 128/*0x80*/ | ((icode>>12) & 63/*0x3F*/)/* 10xxxxxx */
buffer[3] = 128 /*0x80*/ | (icode & 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 tos(buffer, 4)
} }
return '' return ''
@ -79,12 +96,12 @@ pub fn (_rune string) utf32_code() int {
mut b := byte(int(_rune[0])) mut b := byte(int(_rune[0]))
// TODO should be // TODO should be
// res := int( rune[0] << rune.len) // res := int( rune[0] << rune.len)
b = b << _rune.len b = b<<_rune.len
mut res := int(b) mut res := int(b)
mut shift := 6 - _rune.len mut shift := 6 - _rune.len
for i := 1; i < _rune.len; i++ { for i := 1; i < _rune.len; i++ {
c := int(_rune[i]) c := int(_rune[i])
res = res << shift res = res<<shift
res |= c & 63 // 0x3f res |= c & 63 // 0x3f
shift = 6 shift = 6
} }
@ -92,8 +109,8 @@ pub fn (_rune string) utf32_code() int {
} }
const ( const (
CP_UTF8 = 65001 CP_UTF8 = 65001
) )
pub fn (_str string) to_wide() &u16 { pub fn (_str string) to_wide() &u16 {
$if windows { $if windows {
@ -110,72 +127,82 @@ pub fn (_str string) to_wide() &u16 {
} }
pub fn string_from_wide(_wstr &u16) string { pub fn string_from_wide(_wstr &u16) string {
$if windows { $if windows {
wstr_len := C.wcslen(_wstr) wstr_len := C.wcslen(_wstr)
return string_from_wide2(_wstr, wstr_len) return string_from_wide2(_wstr, wstr_len)
} $else { } $else {
return '' return ''
} }
} }
pub fn string_from_wide2(_wstr &u16, len int) string { pub fn string_from_wide2(_wstr &u16, len int) string {
$if windows { $if windows {
num_chars := C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, 0, 0, 0, 0) num_chars := C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, 0, 0, 0, 0)
mut str_to := malloc(num_chars + 1) mut str_to := malloc(num_chars + 1)
if !isnil(str_to) { if !isnil(str_to) {
C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, str_to, num_chars, 0, 0) C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, str_to, num_chars, 0, 0)
C.memset(str_to + num_chars, 0, 1) C.memset(str_to + num_chars, 0, 1)
} }
return tos2(str_to) return tos2(str_to)
} $else { } $else {
return '' return ''
} }
} }
// Calculate length to read from the first byte // Calculate length to read from the first byte
fn utf8_len(c byte) int { fn utf8_len(c byte) int {
mut b := 0 mut b := 0
mut x := c mut x := c
if ((x & 240) != 0) {
if ((x & 240) != 0) { //0xF0 // 0xF0
x >>= 4 x >>= 4
} else { }
b += 4 else {
} b += 4
if ((x & 12) != 0) { //0x0C }
x >>= 2 if ((x & 12) != 0) {
} else { // 0x0C
b += 2 x >>= 2
} }
if ((x & 2) == 0) { //0x02 else {
b++ b += 2
} }
return b if ((x & 2) == 0) {
// 0x02
b++
}
return b
} }
// Reads an utf8 character from standard input // Reads an utf8 character from standard input
pub fn utf8_getchar() int { pub fn utf8_getchar() int {
c := C.getchar() c := C.getchar()
len := utf8_len(~c) len := utf8_len(~c)
if c < 0 { if c < 0 {
return 0 return 0
} else if len == 0 { }
return c else if len == 0 {
} else if len == 1 { return c
return -1 }
} else { else if len == 1 {
mut uc := c & ((1 << (7 - len)) - 1) return -1
for i := 0; i + 1 < len; i++ { }
c2 := C.getchar() else {
if c2 != -1 && (c2 >> 6) == 2 { mut uc := c & ((1<<(7 - len)) - 1)
uc <<= 6 for i := 0; i + 1 < len; i++ {
uc |= (c2 & 63) c2 := C.getchar()
} else if c2 == -1 { if c2 != -1 && (c2>>6) == 2 {
return 0 uc <<= 6
} else { uc |= (c2 & 63)
return -1 }
} else if c2 == -1 {
} return 0
return uc }
} else {
return -1
}
}
return uc
}
} }

View File

@ -3,8 +3,6 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module compiler module compiler
import ( import (
strings strings
) )

View File

@ -1,7 +1,6 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module compiler module compiler
import strings import strings
@ -9,15 +8,16 @@ import strings
const ( const (
dot_ptr = '->' dot_ptr = '->'
) )
// returns the type of the new variable // returns the type of the new variable
fn (p mut Parser) gen_var_decl(name string, is_static bool) string { fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
p.is_var_decl = true p.is_var_decl = true
mut typ := p.bool_expression() mut typ := p.bool_expression()
//mut typ, expr := p.tmp_expr() // mut typ, expr := p.tmp_expr()
p.is_var_decl = false p.is_var_decl = false
if typ.starts_with('...') { typ = typ[3..] } if typ.starts_with('...') {
//p.gen('/*after expr*/') typ = typ[3..]
}
// p.gen('/*after expr*/')
// Option check ? or { // Option check ? or {
or_else := p.tok == .key_orelse or_else := p.tok == .key_orelse
if or_else { 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) gen_name := p.table.var_cgen_name(name)
mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ) mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ)
// `foo := C.Foo{}` => `Foo foo;` // `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 += '=' 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]!!` // a fixed_array initializer, like `v := [1.1, 2.2]!!`
// ... should translate to the following in C `f32 v[2] = {1.1, 2.2};` // ... should translate to the following in C `f32 v[2] = {1.1, 2.2};`
initializer := p.cgen.cur_line initializer := p.cgen.cur_line
if initializer.len > 0 { if initializer.len > 0 {
p.cgen.resetln(' = {' + initializer.all_after('{') ) p.cgen.resetln(' = {' + initializer.all_after('{'))
} else if initializer.len == 0 { }
else if initializer.len == 0 {
p.cgen.resetln(' = { 0 }') p.cgen.resetln(' = { 0 }')
} }
} }
if is_static { if is_static {
nt_gen = 'static $nt_gen' nt_gen = 'static $nt_gen'
} }
// Now that we know the type, prepend it // Now that we know the type, prepend it
// `[typ] [name] = bool_expression();` // `[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) p.cgen.set_placeholder(0, nt_gen)
return typ return typ
} }
fn (p mut Parser) gen_fn_decl(f Fn, typ, str_args string) { 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 { 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 { '' }
'__declspec(dllexport) '
} else if p.attr == 'inline' {
'static inline '
} else {
''
}
fn_name_cgen := p.table.fn_gen_name(f) 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) {') 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_name()
p.check_space(.assign) p.check_space(.assign)
is_indexer := p.peek() == .lsbr 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() pos := p.cgen.add_placeholder()
p.is_var_decl = true p.is_var_decl = true
typ := p.bool_expression() typ := p.bool_expression()
if typ == 'void' { 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 p.is_var_decl = false
if !is_indexer && !is_fn_call { if !is_indexer && !is_fn_call {
@ -82,10 +77,12 @@ fn (p mut Parser) gen_blank_identifier_assign() {
// handle or // handle or
if p.tok == .key_orelse { if p.tok == .key_orelse {
p.gen_handle_option_or_else(typ, '', pos) p.gen_handle_option_or_else(typ, '', pos)
} else { }
else {
if is_fn_call { if is_fn_call {
p.gen(';') p.gen(';')
} else { }
else {
p.cgen.resetln('{$typ _ = $p.cgen.cur_line;}') 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 or_tok_idx := p.token_idx
p.check(.key_orelse) p.check(.key_orelse)
p.check(.lcbr) p.check(.lcbr)
p.register_var(Var { p.register_var(Var{
name: 'err' name: 'err'
typ: 'string' typ: 'string'
is_mut: false is_mut: false
is_used: true is_used: true
}) })
p.register_var(Var { p.register_var(Var{
name: 'errcode' name: 'errcode'
typ: 'int' typ: 'int'
is_mut: false is_mut: false
is_used: true 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('$typ $name;')
} }
p.genln('if (!$tmp .ok) {') 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 // workaround for -g with default optional value
// when p.cgen.line_directives is true an extra // when p.cgen.line_directives is true an extra
// line is added so we need to account for that // line is added so we need to account for that
expr_line := if p.cgen.line_directives { expr_line := if p.cgen.line_directives { p.cgen.lines[p.cgen.lines.len - 3] } else { p.cgen.lines[p.cgen.lines.len - 2] }
p.cgen.lines[p.cgen.lines.len-3]
} else {
p.cgen.lines[p.cgen.lines.len-2]
}
last_expr := expr_line[last_ph..] last_expr := expr_line[last_ph..]
p.cgen.lines[p.cgen.lines.len-2] = '' p.cgen.lines[p.cgen.lines.len - 2] = ''
// same here // same here
if p.cgen.line_directives { 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('if ($tmp .ok) {')
p.genln('$name = *($typ*) $tmp . data;') p.genln('$name = *($typ*) $tmp . data;')
p.genln('} else {') p.genln('} else {')
p.genln('$name = $last_expr') p.genln('$name = $last_expr')
p.genln('}') p.genln('}')
} else if is_assign { }
else if is_assign {
p.genln('$name = *($typ*)${tmp}.data;') p.genln('$name = *($typ*)${tmp}.data;')
} }
if !p.returns && last_typ != typ && is_assign && p.prev_tok2 != .key_continue && p.prev_tok2 != .key_break { 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 { fn types_to_c(types []Type, table &Table) string {
mut sb := strings.new_builder(10) mut sb := strings.new_builder(10)
for t in types { 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_]) { if !(t.cat in [.union_, .struct_, .objc_interface, .interface_]) {
continue continue
} }
//if is_atomic { // if is_atomic {
//sb.write('_Atomic ') // sb.write('_Atomic ')
//} // }
if t.cat == .objc_interface { if t.cat == .objc_interface {
sb.writeln('@interface $t.name : $t.parent { @public') sb.writeln('@interface $t.name : $t.parent { @public')
} }
else { else {
kind := if t.cat == .union_ {'union'} else {'struct'} kind := if t.cat == .union_ { 'union' } else { 'struct' }
sb.writeln('$kind $t.name {') sb.writeln('$kind $t.name {')
if t.cat == .interface_ { if t.cat == .interface_ {
sb.writeln('\tvoid* _object;') sb.writeln('\tvoid* _object;')
@ -192,11 +187,10 @@ fn types_to_c(types []Type, table &Table) string {
} }
for field in t.fields { for field in t.fields {
sb.write('\t') sb.write('\t')
sb.writeln(table.cgen_name_type_pair(field.name, sb.writeln(table.cgen_name_type_pair(field.name, field.typ) + ';')
field.typ) + ';')
} }
sb.writeln('};\n') sb.writeln('};\n')
if t.cat == .objc_interface { if t.cat == .objc_interface {
sb.writeln('@end') 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 { if p.cgen.is_tmp {
index_expr = p.cgen.tmp_line[fn_ph..] index_expr = p.cgen.tmp_line[fn_ph..]
p.cgen.resetln(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..] index_expr = p.cgen.cur_line[fn_ph..]
p.cgen.resetln(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 { if cfg.is_map {
p.gen('$tmp') p.gen('$tmp')
def := type_default(typ) def := type_default(typ)
p.cgen.insert_before('$typ $tmp = $def; ' + p.cgen.insert_before('$typ $tmp = $def; ' + 'bool $tmp_ok = map_get(/*$p.file_name : $p.scanner.line_nr*/$index_expr, & $tmp);')
'bool $tmp_ok = map_get(/*$p.file_name : $p.scanner.line_nr*/$index_expr, & $tmp);')
} }
else if cfg.is_arr { else if cfg.is_arr {
if p.pref.translated && !p.builtin_mod { 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 { else if cfg.is_str && !p.builtin_mod {
if p.pref.is_bare { if p.pref.is_bare {
p.gen(index_expr) p.gen(index_expr)
} }
else if cfg.is_slice { else if cfg.is_slice {
p.gen('string_substr2($index_expr)') p.gen('string_substr2($index_expr)')
} else { }
else {
p.gen('string_at($index_expr)') 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}.str) $tmp = tos("", 0);')
p.cgen.insert_before('if (!$tmp_ok) $tmp = tos((byte *)"", 0);') p.cgen.insert_before('if (!$tmp_ok) $tmp = tos((byte *)"", 0);')
} }
} }
fn (table mut Table) fn_gen_name(f &Fn) string { 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(' ', '') name = name.replace(' ', '')
if f.name.len == 1 { if f.name.len == 1 {
match f.name[0] { match f.name[0] {
`+` { name = name.replace('+', 'op_plus') } `+` {
`-` { name = name.replace('-', 'op_minus') } name = name.replace('+', 'op_plus')
`*` { name = name.replace('*', 'op_mul') } }
`/` { name = name.replace('/', 'op_div') } `-` {
`%` { name = name.replace('%', 'op_mod') } name = name.replace('-', 'op_minus')
else {} }
} `*` {
name = name.replace('*', 'op_mul')
}
`/` {
name = name.replace('/', 'op_div')
}
`%` {
name = name.replace('%', 'op_mod')
}
else {
}}
} }
} }
if f.is_interface { if f.is_interface {
// iname := f.args[0].typ // Speaker // iname := f.args[0].typ // Speaker
// var := p.expr_var.name // var := p.expr_var.name
return '' return ''
} }
// Avoid name conflicts (with things like abs(), print() etc). // 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 // Obfuscate but skip certain names
// TODO ugly, fix // TODO ugly, fix
// NB: the order here is from faster to potentially slower checks // NB: the order here is from faster to potentially slower checks
if table.obfuscate && 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') {
!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] mut idx := table.obf_ids[name]
// No such function yet, register it // No such function yet, register it
if idx == 0 { if idx == 0 {
@ -316,10 +307,8 @@ fn (table mut Table) fn_gen_name(f &Fn) string {
return name return name
} }
fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string, fn (p mut Parser) gen_method_call(receiver &Var, receiver_type string, cgen_name string, ftyp string, method_ph int) {
cgen_name string, ftyp string, method_ph int) // mut cgen_name := p.table.fn_gen_name(f)
{
//mut cgen_name := p.table.fn_gen_name(f)
mut method_call := cgen_name + ' (' mut method_call := cgen_name + ' ('
// if receiver is key_mut or a ref (&), generate & for the first arg // if receiver is key_mut or a ref (&), generate & for the first arg
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) { 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 // array_int => int
cast = receiver_type.all_after('array_') cast = receiver_type.all_after('array_')
cast = '*($cast*) ' cast = '*($cast*) '
} else { }
else {
cast = '(voidptr) ' 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) { fn (p mut Parser) gen_array_at(typ_ string, is_arr0 bool, fn_ph int) {
mut typ := typ_ mut typ := typ_
//p.fgen('[') // p.fgen('[')
// array_int a; a[0] // array_int a; a[0]
// type is "array_int", need "int" // type is "array_int", need "int"
// typ = typ.replace('array_', '') // typ = typ.replace('array_', '')
// if is_arr0 { // if is_arr0 {
// typ = typ.right(6) // typ = typ.right(6)
// } // }
// array a; a.first() voidptr // array a; a.first() voidptr
// type is "array", need "void*" // 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) { fn (p mut Parser) gen_for_header(i, tmp, var_typ, val string) {
p.genln('for (int $i = 0; $i < ${tmp}.len; $i++) {') 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];') p.genln('$var_typ $val = (($var_typ *) $tmp . data)[$i];')
} }
fn (p mut Parser) gen_for_fixed_header(i, tmp, var_typ, val string) { 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++) {') 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];') p.genln('$var_typ $val = $tmp[$i];')
} }
fn (p mut Parser) gen_for_str_header(i, tmp, var_typ, val string) { fn (p mut Parser) gen_for_str_header(i, tmp, var_typ, val string) {
// TODO var_typ is always byte // 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 ++) {') p.genln(';\nfor (int $i = 0; $i < $tmp .len; $i ++) {')
if val == '_' { return } if val == '_' {
//p.genln('$var_typ $val = (($var_typ *) bytes_$tmp . data)[$i];') return
}
// p.genln('$var_typ $val = (($var_typ *) bytes_$tmp . data)[$i];')
p.genln('$var_typ $val = ${tmp}.str[$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) { 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++) {') p.genln(';\nfor (int $i = $tmp; $i < $range_end; $i++) {')
if val == '_' { return } if val == '_' {
return
}
p.genln('$var_type $val = $i;') 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];') p.genln('string $i = ((string*)keys_$tmp .data)[l];')
// TODO don't call map_get() for each key, fetch values while traversing // TODO don't call map_get() for each key, fetch values while traversing
// the tree (replace `map_keys()` above with `map_key_vals()`) // 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);') 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) { fn (p mut Parser) gen_for_varg_header(i, varg, var_typ, val string) {
p.genln('for (int $i = 0; $i < ${varg}->len; $i++) {') 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];') 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 { if nr_elems == 0 {
p.gen(' TCCSKIP(0) })') p.gen(' TCCSKIP(0) })')
} else { }
else {
p.gen(' })') p.gen(' })')
} }
// Need to do this in the second pass, otherwise it goes to the very top of the out.c file // Need to do this in the second pass, otherwise it goes to the very top of the out.c file
if !p.first_pass() { if !p.first_pass() {
p.cgen.set_placeholder(new_arr_ph, p.cgen.set_placeholder(new_arr_ph, '${new_arr}($nr_elems, $nr_elems, sizeof($typ), EMPTY_ARRAY_OF_ELEMS( $typ, $nr_elems ) { ')
'${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` // `a[0] = 7`
// curline right now: `a , 0 = 7` // curline right now: `a , 0 = 7`
mut val := p.cgen.cur_line[assign_pos..] 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_map {
if is_ptr { if is_ptr {
func = 'map_set(' func = 'map_set('
} else { }
else {
func = 'map_set(&' func = 'map_set(&'
} }
// CAO on map is a bit more complicated as it loads // 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) p.cgen.set_placeholder(fn_ph, func)
if is_cao { 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 })') p.gen(', & ($typ []) { $val })')
} }
// returns true in case of an early return // returns true in case of an early return
fn (p mut Parser) gen_struct_init(typ string, t Type) bool { 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: // 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 // TODO tm struct struct bug
if typ == 'tm' { if typ == 'tm' {
p.cgen.lines[p.cgen.lines.len-1] = '' p.cgen.lines[p.cgen.lines.len - 1] = ''
} }
p.next() p.next()
p.check(.lcbr) p.check(.lcbr)
@ -511,6 +513,7 @@ fn (p mut Parser) gen_struct_init(typ string, t Type) bool {
p.check(.rcbr) p.check(.rcbr)
return true return true
*/ */
} }
p.gen('($t.name*)memdup(&($t.name) {') 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) { fn (p mut Parser) cast(typ string) {
p.gen('(') p.gen('(')
defer { p.gen(')') } defer {
p.gen(')')
}
p.next() p.next()
pos := p.cgen.add_placeholder() pos := p.cgen.add_placeholder()
if p.tok == .rpar { 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') p.warn('casting `$typ` to `$expr_typ` is not needed')
} }
// `face := FT_Face(cobj)` => `FT_Face face = *((FT_Face*)cobj);` // `face := FT_Face(cobj)` => `FT_Face face = *((FT_Face*)cobj);`
casting_voidptr_to_value := expr_typ == 'void*' && typ != 'int' && casting_voidptr_to_value := expr_typ == 'void*' && typ != 'int' && typ != 'byteptr' && !typ.ends_with('*')
typ != 'byteptr' && !typ.ends_with('*')
p.expected_type = '' p.expected_type = ''
// `string(buffer)` => `tos2(buffer)` // `string(buffer)` => `tos2(buffer)`
// `string(buffer, len)` => `tos(buffer, len)` // `string(buffer, len)` => `tos(buffer, len)`
@ -561,7 +565,8 @@ fn (p mut Parser) cast(typ string) {
} }
p.gen(', ') p.gen(', ')
p.check_types(p.expression(), 'int') p.check_types(p.expression(), 'int')
} else { }
else {
if is_bytearr { if is_bytearr {
p.gen('.data') p.gen('.data')
} }
@ -617,30 +622,58 @@ fn type_default(typ string) string {
return '{0}' return '{0}'
} }
// Default values for other types are not needed because of mandatory initialization // Default values for other types are not needed because of mandatory initialization
match typ { match typ {
'bool'{ return '0'} 'bool' {
'string'{ return 'tos3("")'} return '0'
'i8'{ return '0'} }
'i16'{ return '0'} 'string' {
'i64'{ return '0'} return 'tos3("")'
'u16'{ return '0'} }
'u32'{ return '0'} 'i8' {
'u64'{ return '0'} return '0'
'byte'{ return '0'} }
'int'{ return '0'} 'i16' {
'rune'{ return '0'} return '0'
'f32'{ return '0.0'} }
'f64'{ return '0.0'} 'i64' {
'byteptr'{ return '0'} return '0'
'voidptr'{ return '0'} }
else {} 'u16' {
} return '0'
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 // TODO this results in
// error: expected a field designator, such as '.field = 4' // error: expected a field designator, such as '.field = 4'
//- Empty ee= (Empty) { . = {0} } ; // - Empty ee= (Empty) { . = {0} } ;
/* /*
return match typ { return match typ {
'bool'{ '0'} 'bool'{ '0'}
@ -661,20 +694,22 @@ else {}
else { '{0} '} else { '{0} '}
} }
*/ */
} }
fn (p mut Parser) gen_array_push(ph int, typ, expr_type, tmp, elm_type string) { fn (p mut Parser) gen_array_push(ph int, typ, expr_type, tmp, elm_type string) {
// Two arrays of the same type? // Two arrays of the same type?
push_array := typ == expr_type push_array := typ == expr_type
if push_array { if push_array {
p.cgen.set_placeholder(ph, '_PUSH_MANY(&' ) p.cgen.set_placeholder(ph, '_PUSH_MANY(&')
p.gen('), $tmp, $typ)') p.gen('), $tmp, $typ)')
} else { }
else {
p.check_types(expr_type, elm_type) p.check_types(expr_type, elm_type)
// Pass tmp var info to the _PUSH macro // Pass tmp var info to the _PUSH macro
// Prepend tmp initialisation and push call // Prepend tmp initialisation and push call
// Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`) // 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.cgen.set_placeholder(ph, push_call)
p.gen('), $tmp, $elm_type)') p.gen('), $tmp, $elm_type)')
} }

View File

@ -1,22 +1,21 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module compiler module compiler
import ( import (
strings strings
) )
fn (p mut Parser) get_type2() Type{ fn (p mut Parser) get_type2() Type {
mut mul := false mut mul := false
mut nr_muls := 0 mut nr_muls := 0
mut typ := '' mut typ := ''
cat := TypeCategory.struct_ cat := TypeCategory.struct_
// multiple returns // multiple returns
if p.tok == .lpar { if p.tok == .lpar {
//p.warn('`()` are no longer necessary in multiple returns' + // p.warn('`()` are no longer necessary in multiple returns' +
//'\nuse `fn foo() int, int {` instead of `fn foo() (int, int) {`') // '\nuse `fn foo() int, int {` instead of `fn foo() (int, int) {`')
// if p.inside_tuple {p.error('unexpected (')} // if p.inside_tuple {p.error('unexpected (')}
// p.inside_tuple = true // p.inside_tuple = true
p.check(.lpar) p.check(.lpar)
@ -32,7 +31,7 @@ fn (p mut Parser) get_type2() Type{
p.check(.rpar) p.check(.rpar)
// p.inside_tuple = false // p.inside_tuple = false
typ = p.register_multi_return_stuct(types) typ = p.register_multi_return_stuct(types)
return Type { return Type{
name: typ name: typ
mod: p.mod mod: p.mod
cat: cat cat: cat
@ -40,7 +39,10 @@ fn (p mut Parser) get_type2() Type{
} }
// fn type // fn type
if p.tok == .key_fn { if p.tok == .key_fn {
mut f := Fn{name: '_', mod: p.mod} mut f := Fn{
name: '_'
mod: p.mod
}
p.next() p.next()
line_nr := p.scanner.line_nr line_nr := p.scanner.line_nr
p.fn_args(mut f) p.fn_args(mut f)
@ -58,8 +60,9 @@ fn (p mut Parser) get_type2() Type{
f.typ = 'void' f.typ = 'void'
} }
// Register anon fn type // Register anon fn type
fn_typ := Type { fn_typ := Type{
name: f.typ_str()// 'fn (int, int) string' name: f.typ_str() // 'fn (int, int) string'
mod: p.mod mod: p.mod
func: f func: f
cat: .func 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 == .number || (p.tok == .name && !p.inside_const) {
if p.tok == .name { if p.tok == .name {
typ += '[${p.mod}__$p.lit]' typ += '[${p.mod}__$p.lit]'
}
} else { else {
typ += '[$p.lit]' typ += '[$p.lit]'
} }
p.next() p.next()
@ -99,10 +102,12 @@ fn (p mut Parser) get_type2() Type{
p.error('maps only support string keys for now') p.error('maps only support string keys for now')
} }
p.check(.rsbr) p.check(.rsbr)
val_type := p.get_type()// p.check_name() val_type := p.get_type() // p.check_name()
typ = 'map_$val_type' typ = 'map_$val_type'
p.register_map(typ) p.register_map(typ)
return Type{name: typ} return Type{
name: typ
}
} }
// ptr/ref // ptr/ref
mut warn := false mut warn := false
@ -123,7 +128,8 @@ fn (p mut Parser) get_type2() Type{
ti := p.cur_fn.dispatch_of.inst ti := p.cur_fn.dispatch_of.inst
if p.lit in ti.keys() { if p.lit in ti.keys() {
typ += ti[p.lit] typ += ti[p.lit]
} else { }
else {
typ += p.lit typ += p.lit
} }
// C.Struct import // C.Struct import
@ -153,8 +159,7 @@ fn (p mut Parser) get_type2() Type{
// "typ" not found? try "mod__typ" // "typ" not found? try "mod__typ"
if t.name == '' && !p.builtin_mod { if t.name == '' && !p.builtin_mod {
// && !p.first_pass() { // && !p.first_pass() {
if !typ.contains('array_') && p.mod != 'main' && !typ.contains('__') && if !typ.contains('array_') && p.mod != 'main' && !typ.contains('__') && !typ.starts_with('[') {
!typ.starts_with('[') {
typ = p.prepend_mod(typ) typ = p.prepend_mod(typ)
} }
t = p.table.find_type(typ) t = p.table.find_type(typ)
@ -164,7 +169,7 @@ fn (p mut Parser) get_type2() Type{
// for q in p.table.types { // for q in p.table.types {
// println(q.name) // 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 { if t_suggest.len > 0 {
t_suggest = '. did you mean: ($tc_suggest) `$t_suggest`' t_suggest = '. did you mean: ($tc_suggest) `$t_suggest`'
} }
@ -195,15 +200,14 @@ fn (p mut Parser) get_type2() Type{
typ = 'Option_$typ' typ = 'Option_$typ'
p.table.register_type_with_parent(typ, 'Option') p.table.register_type_with_parent(typ, 'Option')
} }
// Because the code uses * to see if it's a pointer // Because the code uses * to see if it's a pointer
if typ == 'byteptr' { if typ == 'byteptr' {
typ = 'byte*' typ = 'byte*'
} }
if typ == 'voidptr' { if typ == 'voidptr' {
//if !p.builtin_mod && p.mod != 'os' && p.mod != 'gx' && p.mod != 'gg' && !p.pref.translated { // 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') // p.error('voidptr can only be used in unsafe code')
//} // }
typ = 'void*' typ = 'void*'
} }
/* /*
@ -212,6 +216,10 @@ fn (p mut Parser) get_type2() Type{
p.error('2 __ in gettype(): typ="$typ"') p.error('2 __ in gettype(): typ="$typ"')
} }
*/ */
return Type{name: typ, cat: cat}
return Type{
name: typ
cat: cat
}
} }

View File

@ -250,9 +250,9 @@ fn (p &Parser) gen_fmt() {
if s == '' { if s == '' {
return return
} }
files := ['cgen.v', 'comptime.v', 'cc.v', 'if_match.v'] files := ['get_type.v']
//if !p.file_path.contains('table.v') {return} if !p.file_path.contains('vlib/builtin') {return}
if !(p.file_name in files) { return } //if !(p.file_name in files) { return }
path := os.tmpdir() + '/' + p.file_name path := os.tmpdir() + '/' + p.file_name
println('generating ${path}') println('generating ${path}')
mut out := os.create(path) or { mut out := os.create(path) or {