run vfmt on vlib/builtin

pull/3153/head
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`)
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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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

View File

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

View File

@ -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 }
}

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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
}
}

View File

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

View File

@ -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)')
}

View File

@ -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
}
}

View File

@ -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 {