mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: check incorrect names
This commit is contained in:
parent
3bd88a3cc2
commit
f44a40eee0
@ -213,7 +213,7 @@ 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, dw_flags u32) bool
|
||||||
|
|
||||||
|
|
||||||
fn C.ExpandEnvironmentStringsW(lpSrc &u16, lpDst &u16, nSize u32) u32
|
fn C.ExpandEnvironmentStringsW(lpSrc &u16, lpDst &u16, nSize u32) u32
|
||||||
@ -228,7 +228,7 @@ fn C.ReadFile(hFile voidptr, lpBuffer voidptr, nNumberOfBytesToRead u32, lpNumbe
|
|||||||
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, lp_reserved &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
|
||||||
|
@ -31,7 +31,6 @@ fn test_float_equal_operator() {
|
|||||||
assert a.gebit(1)
|
assert a.gebit(1)
|
||||||
assert -1 == 1 * -1
|
assert -1 == 1 * -1
|
||||||
assert -1.0 == 1.0 * -1.0
|
assert -1.0 == 1.0 * -1.0
|
||||||
|
|
||||||
a = f64(1)
|
a = f64(1)
|
||||||
a += 0.000001
|
a += 0.000001
|
||||||
a -= 0.000001
|
a -= 0.000001
|
||||||
@ -47,7 +46,6 @@ fn test_float_equal_operator() {
|
|||||||
assert a.gtbit(f32(1))
|
assert a.gtbit(f32(1))
|
||||||
assert a >= 1
|
assert a >= 1
|
||||||
assert a.gebit(1)
|
assert a.gebit(1)
|
||||||
|
|
||||||
f := 1.2
|
f := 1.2
|
||||||
ab := int(f)
|
ab := int(f)
|
||||||
assert ab == 1
|
assert ab == 1
|
||||||
@ -62,7 +60,6 @@ fn test_str_methods() {
|
|||||||
assert int(-1).str() == '-1'
|
assert int(-1).str() == '-1'
|
||||||
assert i64(1).str() == '1'
|
assert i64(1).str() == '1'
|
||||||
assert i64(-1).str() == '-1'
|
assert i64(-1).str() == '-1'
|
||||||
|
|
||||||
// assert byte(1).str() == '1'
|
// assert byte(1).str() == '1'
|
||||||
// assert byte(-1).str() == '255'
|
// assert byte(-1).str() == '255'
|
||||||
assert u16(1).str() == '1'
|
assert u16(1).str() == '1'
|
||||||
@ -131,17 +128,11 @@ fn test_cmp() {
|
|||||||
assert 1 ⩾ 0
|
assert 1 ⩾ 0
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
type MyInt int
|
||||||
type myint int
|
|
||||||
type mystring string
|
|
||||||
|
|
||||||
fn test_int_alias() {
|
fn test_int_alias() {
|
||||||
/*
|
i := MyInt(2)
|
||||||
i := myint(2)
|
|
||||||
s := mystring('hi')
|
|
||||||
ss := s + '!'
|
|
||||||
assert i + 10 == 12
|
assert i + 10 == 12
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_hex() {
|
fn test_hex() {
|
||||||
@ -194,49 +185,43 @@ fn test_int_decl() {
|
|||||||
|
|
||||||
fn test_int_to_hex() {
|
fn test_int_to_hex() {
|
||||||
// array hex
|
// array hex
|
||||||
st := [byte(`V`),`L`,`A`,`N`,`G`]
|
st := [byte(`V`), `L`, `A`, `N`, `G`]
|
||||||
assert st.hex() == "564c414e47"
|
assert st.hex() == '564c414e47'
|
||||||
assert st.hex().len == 10
|
assert st.hex().len == 10
|
||||||
|
|
||||||
st1 := [byte(0x41)].repeat(100)
|
st1 := [byte(0x41)].repeat(100)
|
||||||
assert st1.hex() == "41".repeat(100)
|
assert st1.hex() == '41'.repeat(100)
|
||||||
|
// --- int to hex tests
|
||||||
//--- int to hex tests
|
|
||||||
c0 := 12
|
c0 := 12
|
||||||
|
|
||||||
// 8Bit
|
// 8Bit
|
||||||
assert byte(0).hex() == "0"
|
assert byte(0).hex() == '0'
|
||||||
assert byte(c0).hex() == "c"
|
assert byte(c0).hex() == 'c'
|
||||||
assert i8(c0).hex() == "c"
|
assert i8(c0).hex() == 'c'
|
||||||
assert byte(127).hex() == "7f"
|
assert byte(127).hex() == '7f'
|
||||||
assert i8(127).hex() == "7f"
|
assert i8(127).hex() == '7f'
|
||||||
assert byte(255).hex() == "ff"
|
assert byte(255).hex() == 'ff'
|
||||||
assert byte(-1).hex() == "ff"
|
assert byte(-1).hex() == 'ff'
|
||||||
|
|
||||||
// 16bit
|
// 16bit
|
||||||
assert u16(0).hex() == "0"
|
assert u16(0).hex() == '0'
|
||||||
assert i16(c0).hex() == "c"
|
assert i16(c0).hex() == 'c'
|
||||||
assert u16(c0).hex() == "c"
|
assert u16(c0).hex() == 'c'
|
||||||
assert i16(32767).hex() == "7fff"
|
assert i16(32767).hex() == '7fff'
|
||||||
assert u16(32767).hex() == "7fff"
|
assert u16(32767).hex() == '7fff'
|
||||||
assert i16(-1).hex() == "ffff"
|
assert i16(-1).hex() == 'ffff'
|
||||||
assert u16(65535).hex() == "ffff"
|
assert u16(65535).hex() == 'ffff'
|
||||||
|
|
||||||
// 32bit
|
// 32bit
|
||||||
assert u32(0).hex() == "0"
|
assert u32(0).hex() == '0'
|
||||||
assert c0.hex() == "c"
|
assert c0.hex() == 'c'
|
||||||
assert u32(c0).hex() == "c"
|
assert u32(c0).hex() == 'c'
|
||||||
assert 2147483647.hex() == "7fffffff"
|
assert 2147483647.hex() == '7fffffff'
|
||||||
assert u32(2147483647).hex() == "7fffffff"
|
assert u32(2147483647).hex() == '7fffffff'
|
||||||
assert (-1).hex() == "ffffffff"
|
assert (-1).hex() == 'ffffffff'
|
||||||
assert u32(4294967295).hex() == "ffffffff"
|
assert u32(4294967295).hex() == 'ffffffff'
|
||||||
|
|
||||||
// 64 bit
|
// 64 bit
|
||||||
assert u64(0).hex() == "0"
|
assert u64(0).hex() == '0'
|
||||||
assert i64(c0).hex() == "c"
|
assert i64(c0).hex() == 'c'
|
||||||
assert u64(c0).hex() == "c"
|
assert u64(c0).hex() == 'c'
|
||||||
assert i64(9223372036854775807).hex() == "7fffffffffffffff"
|
assert i64(9223372036854775807).hex() == '7fffffffffffffff'
|
||||||
assert u64(9223372036854775807).hex() == "7fffffffffffffff"
|
assert u64(9223372036854775807).hex() == '7fffffffffffffff'
|
||||||
assert i64(-1).hex() == "ffffffffffffffff"
|
assert i64(-1).hex() == 'ffffffffffffffff'
|
||||||
assert u64(18446744073709551615).hex() == "ffffffffffffffff"
|
assert u64(18446744073709551615).hex() == 'ffffffffffffffff'
|
||||||
}
|
}
|
||||||
|
@ -766,3 +766,12 @@ fn test_string_literal_with_backslash(){
|
|||||||
Three'
|
Three'
|
||||||
assert b == 'OneTwoThree'
|
assert b == 'OneTwoThree'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
type MyString string
|
||||||
|
|
||||||
|
fn test_string_alias() {
|
||||||
|
s := MyString('hi')
|
||||||
|
ss := s + '!'
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -3,49 +3,62 @@ module clipboard
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
struct WndClassEx {
|
struct WndClassEx {
|
||||||
cbSize u32
|
cb_size u32
|
||||||
style u32
|
style u32
|
||||||
lpfnWndProc voidptr
|
lpfn_wnd_proc voidptr
|
||||||
cbClsExtra int
|
cb_cls_extra int
|
||||||
cbWndExtra int
|
cb_wnd_extra int
|
||||||
hInstance C.HINSTANCE
|
h_instance C.HINSTANCE
|
||||||
hIcon C.HICON
|
h_icon C.HICON
|
||||||
hCursor C.HCURSOR
|
h_cursor C.HCURSOR
|
||||||
hbrBackground C.HBRUSH
|
hbr_background C.HBRUSH
|
||||||
lpszMenuName &u16 // LPCWSTR
|
lpsz_menu_name &u16 // LPCWSTR
|
||||||
lpszClassName &u16
|
lpsz_class_name &u16
|
||||||
hIconSm &u16
|
h_icon_sm &u16
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.RegisterClassEx(class WndClassEx) int
|
fn C.RegisterClassEx(class WndClassEx) int
|
||||||
|
|
||||||
fn C.GetClipboardOwner() &C.HWND
|
fn C.GetClipboardOwner() &C.HWND
|
||||||
fn C.CreateWindowEx(dwExStyle i64, lpClassName &u16, lpWindowName &u16, dwStyle i64, x int, y int, nWidth int, nHeight int, hWndParent i64, hMenu voidptr, hInstance voidptr, lpParam voidptr) &C.HWND
|
|
||||||
//fn C.MultiByteToWideChar(CodePage u32, dwFlags u16, lpMultiByteStr byteptr, cbMultiByte int, lpWideCharStr u16, cchWideChar int) int
|
fn C.CreateWindowEx(dwExStyle i64, lpClassName, lpWindowName &u16, dwStyle i64, x, y, nWidth, nHeight int, hWndParent i64, hMenu, h_instance, lpParam voidptr) &C.HWND
|
||||||
|
|
||||||
|
// fn C.MultiByteToWideChar(CodePage u32, dw_flags u16, lpMultiByteStr byteptr, cbMultiByte int, lpWideCharStr u16, cchWideChar int) int
|
||||||
fn C.EmptyClipboard()
|
fn C.EmptyClipboard()
|
||||||
|
|
||||||
fn C.CloseClipboard()
|
fn C.CloseClipboard()
|
||||||
|
|
||||||
fn C.GlobalAlloc(uFlag u32, size i64) C.HGLOBAL
|
fn C.GlobalAlloc(uFlag u32, size i64) C.HGLOBAL
|
||||||
|
|
||||||
fn C.GlobalFree(buf C.HGLOBAL)
|
fn C.GlobalFree(buf C.HGLOBAL)
|
||||||
|
|
||||||
fn C.GlobalLock(buf C.HGLOBAL)
|
fn C.GlobalLock(buf C.HGLOBAL)
|
||||||
|
|
||||||
fn C.GlobalUnlock(buf C.HGLOBAL)
|
fn C.GlobalUnlock(buf C.HGLOBAL)
|
||||||
|
|
||||||
fn C.SetClipboardData(uFormat u32, data voidptr) C.HANDLE
|
fn C.SetClipboardData(uFormat u32, data voidptr) C.HANDLE
|
||||||
|
|
||||||
fn C.GetClipboardData(uFormat u32) C.HANDLE
|
fn C.GetClipboardData(uFormat u32) C.HANDLE
|
||||||
|
|
||||||
fn C.DefWindowProc(hwnd C.HWND, msg u32, wParam C.WPARAM, lParam C.LPARAM) C.LRESULT
|
fn C.DefWindowProc(hwnd C.HWND, msg u32, wParam C.WPARAM, lParam C.LPARAM) C.LRESULT
|
||||||
|
|
||||||
fn C.SetLastError(error i64)
|
fn C.SetLastError(error i64)
|
||||||
|
|
||||||
fn C.OpenClipboard(hwnd C.HWND) int
|
fn C.OpenClipboard(hwnd C.HWND) int
|
||||||
|
|
||||||
fn C.DestroyWindow(hwnd C.HWND)
|
fn C.DestroyWindow(hwnd C.HWND)
|
||||||
|
|
||||||
struct Clipboard {
|
struct Clipboard {
|
||||||
max_retries int
|
max_retries int
|
||||||
retry_delay int
|
retry_delay int
|
||||||
mut:
|
mut:
|
||||||
hwnd C.HWND
|
hwnd C.HWND
|
||||||
foo int // TODO remove
|
foo int // TODO remove
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (cb &Clipboard) get_clipboard_lock() bool {
|
fn (cb &Clipboard) get_clipboard_lock() bool {
|
||||||
mut retries := cb.max_retries
|
mut retries := cb.max_retries
|
||||||
mut last_error := u32(0)
|
mut last_error := u32(0)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
retries--
|
retries--
|
||||||
if retries < 0 {
|
if retries < 0 {
|
||||||
@ -57,7 +70,6 @@ fn (cb &Clipboard) get_clipboard_lock() bool {
|
|||||||
} else if last_error != u32(C.ERROR_ACCESS_DENIED) {
|
} else if last_error != u32(C.ERROR_ACCESS_DENIED) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
time.sleep(cb.retry_delay)
|
time.sleep(cb.retry_delay)
|
||||||
}
|
}
|
||||||
C.SetLastError(last_error)
|
C.SetLastError(last_error)
|
||||||
@ -65,24 +77,25 @@ fn (cb &Clipboard) get_clipboard_lock() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_clipboard() &Clipboard {
|
fn new_clipboard() &Clipboard {
|
||||||
mut cb := &Clipboard {
|
mut cb := &Clipboard{
|
||||||
max_retries: 5
|
max_retries: 5
|
||||||
retry_delay: 5
|
retry_delay: 5
|
||||||
}
|
}
|
||||||
class_name := "clipboard"
|
class_name := 'clipboard'
|
||||||
wndclass := WndClassEx {
|
wndclass := WndClassEx{
|
||||||
cbSize: sizeof(WndClassEx)
|
cb_size: sizeof(WndClassEx)
|
||||||
lpfnWndProc: voidptr(&C.DefWindowProc)
|
lpfn_wnd_proc: voidptr(&C.DefWindowProc)
|
||||||
lpszClassName: class_name.to_wide()
|
lpsz_class_name: class_name.to_wide()
|
||||||
lpszMenuName: 0
|
lpsz_menu_name: 0
|
||||||
hIconSm: 0
|
h_icon_sm: 0
|
||||||
}
|
}
|
||||||
if C.RegisterClassEx(&wndclass) == 0 && C.GetLastError() != u32(C.ERROR_CLASS_ALREADY_EXISTS) {
|
if C.RegisterClassEx(&wndclass) == 0 && C.GetLastError() != u32(C.ERROR_CLASS_ALREADY_EXISTS) {
|
||||||
println("Failed registering class.")
|
println('Failed registering class.')
|
||||||
}
|
}
|
||||||
hwnd := C.CreateWindowEx(0, wndclass.lpszClassName, wndclass.lpszClassName, 0, 0, 0, 0, 0, C.HWND_MESSAGE, C.NULL, C.NULL, C.NULL)
|
hwnd := C.CreateWindowEx(0, wndclass.lpsz_class_name, wndclass.lpsz_class_name, 0, 0, 0,
|
||||||
|
0, 0, C.HWND_MESSAGE, C.NULL, C.NULL, C.NULL)
|
||||||
if hwnd == C.NULL {
|
if hwnd == C.NULL {
|
||||||
println("Error creating window!")
|
println('Error creating window!')
|
||||||
}
|
}
|
||||||
cb.hwnd = hwnd
|
cb.hwnd = hwnd
|
||||||
return cb
|
return cb
|
||||||
@ -96,21 +109,24 @@ fn (cb &Clipboard) has_ownership() bool {
|
|||||||
return C.GetClipboardOwner() == cb.hwnd
|
return C.GetClipboardOwner() == cb.hwnd
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (cb mut Clipboard) clear() {
|
fn (mut cb Clipboard) clear() {
|
||||||
if !cb.get_clipboard_lock() {return}
|
if !cb.get_clipboard_lock() {
|
||||||
|
return
|
||||||
|
}
|
||||||
C.EmptyClipboard()
|
C.EmptyClipboard()
|
||||||
C.CloseClipboard()
|
C.CloseClipboard()
|
||||||
cb.foo = 0
|
cb.foo = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (cb mut Clipboard) free(){
|
fn (mut cb Clipboard) free() {
|
||||||
C.DestroyWindow(cb.hwnd)
|
C.DestroyWindow(cb.hwnd)
|
||||||
cb.foo = 0
|
cb.foo = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// the string.to_wide doesn't work with SetClipboardData, don't know why
|
// the string.to_wide doesn't work with SetClipboardData, don't know why
|
||||||
fn to_wide(text string) &C.HGLOBAL {
|
fn to_wide(text string) &C.HGLOBAL {
|
||||||
len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, C.NULL, 0)
|
len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len +
|
||||||
|
1, C.NULL, 0)
|
||||||
buf := C.GlobalAlloc(C.GMEM_MOVEABLE, sizeof(u16) * len_required)
|
buf := C.GlobalAlloc(C.GMEM_MOVEABLE, sizeof(u16) * len_required)
|
||||||
if buf != C.HGLOBAL(C.NULL) {
|
if buf != C.HGLOBAL(C.NULL) {
|
||||||
mut locked := &u16(C.GlobalLock(buf))
|
mut locked := &u16(C.GlobalLock(buf))
|
||||||
@ -121,7 +137,7 @@ fn to_wide(text string) &C.HGLOBAL {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (cb mut Clipboard) set_text(text string) bool {
|
fn (mut cb Clipboard) set_text(text string) bool {
|
||||||
cb.foo = 0
|
cb.foo = 0
|
||||||
buf := to_wide(text)
|
buf := to_wide(text)
|
||||||
if !cb.get_clipboard_lock() {
|
if !cb.get_clipboard_lock() {
|
||||||
@ -131,7 +147,7 @@ fn (cb mut Clipboard) set_text(text string) bool {
|
|||||||
// EmptyClipboard must be called to properly update clipboard ownership
|
// EmptyClipboard must be called to properly update clipboard ownership
|
||||||
C.EmptyClipboard()
|
C.EmptyClipboard()
|
||||||
if C.SetClipboardData(C.CF_UNICODETEXT, buf) == C.HANDLE(C.NULL) {
|
if C.SetClipboardData(C.CF_UNICODETEXT, buf) == C.HANDLE(C.NULL) {
|
||||||
println("SetClipboardData: Failed.")
|
println('SetClipboardData: Failed.')
|
||||||
C.CloseClipboard()
|
C.CloseClipboard()
|
||||||
C.GlobalFree(buf)
|
C.GlobalFree(buf)
|
||||||
return false
|
return false
|
||||||
@ -142,15 +158,15 @@ fn (cb mut Clipboard) set_text(text string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (cb mut Clipboard) get_text() string {
|
fn (mut cb Clipboard) get_text() string {
|
||||||
cb.foo = 0
|
cb.foo = 0
|
||||||
if !cb.get_clipboard_lock() {
|
if !cb.get_clipboard_lock() {
|
||||||
return ""
|
return ''
|
||||||
}
|
}
|
||||||
h_data := C.GetClipboardData(C.CF_UNICODETEXT)
|
h_data := C.GetClipboardData(C.CF_UNICODETEXT)
|
||||||
if h_data == C.HANDLE(C.NULL) {
|
if h_data == C.HANDLE(C.NULL) {
|
||||||
C.CloseClipboard()
|
C.CloseClipboard()
|
||||||
return ""
|
return ''
|
||||||
}
|
}
|
||||||
str := string_from_wide(&u16(C.GlobalLock(h_data)))
|
str := string_from_wide(&u16(C.GlobalLock(h_data)))
|
||||||
C.GlobalUnlock(h_data)
|
C.GlobalUnlock(h_data)
|
||||||
|
@ -164,27 +164,27 @@ fn utf8util_char_len(b byte) int {
|
|||||||
//
|
//
|
||||||
// up_low make the dirt job
|
// up_low make the dirt job
|
||||||
fn up_low(s string, upper_flag bool) string {
|
fn up_low(s string, upper_flag bool) string {
|
||||||
mut _index := 0
|
mut index := 0
|
||||||
mut str_res := malloc(s.len + 1)
|
mut str_res := malloc(s.len + 1)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ch_len := utf8util_char_len(s.str[_index])
|
ch_len := utf8util_char_len(s.str[index])
|
||||||
|
|
||||||
if ch_len == 1 {
|
if ch_len == 1 {
|
||||||
if upper_flag==true {
|
if upper_flag==true {
|
||||||
str_res[_index] = C.toupper(s.str[_index])
|
str_res[index] = C.toupper(s.str[index])
|
||||||
}else{
|
}else{
|
||||||
str_res[_index] = C.tolower(s.str[_index])
|
str_res[index] = C.tolower(s.str[index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ch_len > 1 && ch_len < 5{
|
else if ch_len > 1 && ch_len < 5{
|
||||||
mut lword := 0
|
mut lword := 0
|
||||||
|
|
||||||
for i:=0; i < ch_len ; i++ {
|
for i:=0; i < ch_len ; i++ {
|
||||||
lword = (lword << 8 ) | int( s.str[_index + i] )
|
lword = (lword << 8 ) | int( s.str[index + i] )
|
||||||
}
|
}
|
||||||
|
|
||||||
//C.printf(" #%d (%x) ", _index, lword)
|
//C.printf(" #%d (%x) ", index, lword)
|
||||||
|
|
||||||
mut res := 0
|
mut res := 0
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ fn up_low(s string, upper_flag bool) string {
|
|||||||
// char not in table, no need of conversion
|
// char not in table, no need of conversion
|
||||||
if ch_index == 0 {
|
if ch_index == 0 {
|
||||||
for i in 0..ch_len {
|
for i in 0..ch_len {
|
||||||
str_res[_index + i] = s.str[_index + i]
|
str_res[index + i] = s.str[index + i]
|
||||||
}
|
}
|
||||||
//C.printf("\n")
|
//C.printf("\n")
|
||||||
}else{
|
}else{
|
||||||
@ -227,13 +227,13 @@ fn up_low(s string, upper_flag bool) string {
|
|||||||
ch1 := byte( (tab_char >> 0) & 0x3f ) | 0x80 /*10xx xxxx*/
|
ch1 := byte( (tab_char >> 0) & 0x3f ) | 0x80 /*10xx xxxx*/
|
||||||
//C.printf("[%02x%02x] \n",ch0,ch1)
|
//C.printf("[%02x%02x] \n",ch0,ch1)
|
||||||
|
|
||||||
str_res[ _index + 0 ] = ch0
|
str_res[ index + 0 ] = ch0
|
||||||
str_res[ _index + 1 ] = ch1
|
str_res[ index + 1 ] = ch1
|
||||||
|
|
||||||
//****************************************************************
|
//****************************************************************
|
||||||
// BUG: doesn't compile, workaround use shitf to right of 0 bit
|
// BUG: doesn't compile, workaround use shitf to right of 0 bit
|
||||||
//****************************************************************
|
//****************************************************************
|
||||||
//str_res[_index + 1 ] = byte( tab_char & 0xbf ) /*1011 1111*/
|
//str_res[index + 1 ] = byte( tab_char & 0xbf ) /*1011 1111*/
|
||||||
|
|
||||||
}
|
}
|
||||||
else if ch_len == 3 {
|
else if ch_len == 3 {
|
||||||
@ -242,16 +242,16 @@ fn up_low(s string, upper_flag bool) string {
|
|||||||
ch2 := byte( (tab_char >> 0) & 0x3f ) | 0x80 /*10xx xxxx*/
|
ch2 := byte( (tab_char >> 0) & 0x3f ) | 0x80 /*10xx xxxx*/
|
||||||
//C.printf("[%02x%02x%02x] \n",ch0,ch1,ch2)
|
//C.printf("[%02x%02x%02x] \n",ch0,ch1,ch2)
|
||||||
|
|
||||||
str_res[_index + 0 ] = ch0
|
str_res[index + 0 ] = ch0
|
||||||
str_res[_index + 1 ] = ch1
|
str_res[index + 1 ] = ch1
|
||||||
str_res[_index + 2 ] = ch2
|
str_res[index + 2 ] = ch2
|
||||||
}
|
}
|
||||||
// TODO: write if needed
|
// TODO: write if needed
|
||||||
else if ch_len == 4 {
|
else if ch_len == 4 {
|
||||||
// place holder!!
|
// place holder!!
|
||||||
// at the present time simply copy the utf8 char
|
// at the present time simply copy the utf8 char
|
||||||
for i in 0..ch_len {
|
for i in 0..ch_len {
|
||||||
str_res[_index + i] = s.str[_index + i]
|
str_res[index + i] = s.str[index + i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,20 +260,20 @@ fn up_low(s string, upper_flag bool) string {
|
|||||||
// other cases, just copy the string
|
// other cases, just copy the string
|
||||||
else{
|
else{
|
||||||
for i in 0..ch_len {
|
for i in 0..ch_len {
|
||||||
str_res[_index + i] = s.str[_index + i]
|
str_res[index + i] = s.str[index + i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_index += ch_len
|
index += ch_len
|
||||||
|
|
||||||
// we are done, exit the loop
|
// we are done, exit the loop
|
||||||
if _index >= s.len {
|
if index >= s.len {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for c compatibility set the ending 0
|
// for c compatibility set the ending 0
|
||||||
str_res[_index]=0
|
str_res[index]=0
|
||||||
|
|
||||||
//C.printf("str_res: %s\n--------------\n",str_res)
|
//C.printf("str_res: %s\n--------------\n",str_res)
|
||||||
|
|
||||||
@ -1680,6 +1680,6 @@ unicode_punct=[
|
|||||||
0x1DA8A, // SIGNWRITING COLON 𝪊
|
0x1DA8A, // SIGNWRITING COLON 𝪊
|
||||||
0x1DA8B, // SIGNWRITING PARENTHESIS 𝪋
|
0x1DA8B, // SIGNWRITING PARENTHESIS 𝪋
|
||||||
0x1E95E, // ADLAM INITIAL EXCLAMATION MARK 𞥞
|
0x1E95E, // ADLAM INITIAL EXCLAMATION MARK 𞥞
|
||||||
0x1E95F, // ADLAM INITIAL QUESTION MARK
|
0x1E95F, // ADLAM INITIAL QUESTION MARK
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019-2020 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 freetype
|
module freetype
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -9,19 +8,17 @@ import gx
|
|||||||
import gg
|
import gg
|
||||||
import glm
|
import glm
|
||||||
import gl
|
import gl
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO
|
TODO
|
||||||
!!!!!!
|
!!!!!!
|
||||||
Use a font atlas
|
Use a font atlas
|
||||||
!!!!!!
|
!!!!!!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#flag windows -I @VROOT/thirdparty/freetype/include
|
#flag windows -I @VROOT/thirdparty/freetype/include
|
||||||
#flag windows -L @VROOT/thirdparty/freetype/win64
|
#flag windows -L @VROOT/thirdparty/freetype/win64
|
||||||
|
|
||||||
#flag solaris -I/opt/local/include/freetype2
|
#flag solaris -I/opt/local/include/freetype2
|
||||||
#flag solaris -L/opt/local/lib
|
#flag solaris -L/opt/local/lib
|
||||||
|
|
||||||
#flag darwin -I/usr/local/include/freetype2
|
#flag darwin -I/usr/local/include/freetype2
|
||||||
// MacPorts
|
// MacPorts
|
||||||
#flag darwin -I/opt/local/include/freetype2
|
#flag darwin -I/opt/local/include/freetype2
|
||||||
@ -29,49 +26,39 @@ Use a font atlas
|
|||||||
#flag freebsd -I/usr/local/include/freetype2
|
#flag freebsd -I/usr/local/include/freetype2
|
||||||
#flag freebsd -Wl -L/usr/local/lib
|
#flag freebsd -Wl -L/usr/local/lib
|
||||||
#flag -lfreetype
|
#flag -lfreetype
|
||||||
|
// #flag -I @VROOT/thirdparty/freetype
|
||||||
//#flag -I @VROOT/thirdparty/freetype
|
// #flag @VROOT/thirdparty/freetype/libfreetype.a
|
||||||
|
|
||||||
//#flag @VROOT/thirdparty/freetype/libfreetype.a
|
|
||||||
#flag darwin -lpng -lbz2 -lz
|
#flag darwin -lpng -lbz2 -lz
|
||||||
|
|
||||||
|
|
||||||
#flag linux -I/usr/include/freetype2
|
#flag linux -I/usr/include/freetype2
|
||||||
#flag linux -I.
|
#flag linux -I.
|
||||||
|
|
||||||
|
|
||||||
#include "ft2build.h"
|
#include "ft2build.h"
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
fn C.FT_Init_FreeType() voidptr
|
fn C.FT_Init_FreeType() voidptr
|
||||||
|
|
||||||
fn C.FT_New_Face() voidptr
|
fn C.FT_New_Face() voidptr
|
||||||
|
|
||||||
fn C.FT_Set_Pixel_Sizes()
|
fn C.FT_Set_Pixel_Sizes()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
default_font_size = 12
|
default_font_size = 12
|
||||||
)
|
)
|
||||||
|
|
||||||
struct Character {
|
struct Character {
|
||||||
code i64
|
code i64
|
||||||
|
texture_id u32
|
||||||
texture_id u32
|
size gg.Vec2
|
||||||
size gg.Vec2
|
|
||||||
|
|
||||||
horizontal_bearing_px gg.Vec2
|
horizontal_bearing_px gg.Vec2
|
||||||
horizontal_advance_px u32
|
horizontal_advance_px u32
|
||||||
|
|
||||||
vertical_bearing_px gg.Vec2
|
vertical_bearing_px gg.Vec2
|
||||||
vertical_advance_px u32
|
vertical_advance_px u32
|
||||||
}
|
}
|
||||||
|
|
||||||
[typedef]
|
[typedef]
|
||||||
struct C.FT_Library {}
|
struct C.FT_Library {
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FreeType {
|
pub struct FreeType {
|
||||||
shader gl.Shader
|
shader gl.Shader
|
||||||
// use_ortho bool
|
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
vao u32
|
vao u32
|
||||||
@ -89,8 +76,8 @@ mut:
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct C.Bitmap {
|
struct C.Bitmap {
|
||||||
width int
|
width int
|
||||||
rows int
|
rows int
|
||||||
buffer int
|
buffer int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,42 +99,43 @@ struct C.FT_Glyph_Metrics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct C.Glyph {
|
struct C.Glyph {
|
||||||
bitmap C.Bitmap
|
bitmap C.Bitmap
|
||||||
bitmap_left int
|
bitmap_left int
|
||||||
bitmap_top int
|
bitmap_top int
|
||||||
advance Advance
|
advance Advance
|
||||||
metrics C.FT_Glyph_Metrics
|
metrics C.FT_Glyph_Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
[typedef]
|
[typedef]
|
||||||
struct C.FT_FaceRec {
|
struct C.FT_FaceRec {
|
||||||
glyph &C.Glyph
|
glyph &C.Glyph
|
||||||
family_name charptr
|
family_name charptr
|
||||||
style_name charptr
|
style_name charptr
|
||||||
}
|
}
|
||||||
///type FT_Face &C.FT_FaceRec
|
|
||||||
|
|
||||||
|
// /type FT_Face &C.FT_FaceRec
|
||||||
fn C.FT_Load_Char(voidptr, i64, int) int
|
fn C.FT_Load_Char(voidptr, i64, int) int
|
||||||
|
|
||||||
fn ft_load_char(face &C.FT_FaceRec, code i64) Character {
|
fn ft_load_char(face &C.FT_FaceRec, code i64) Character {
|
||||||
//println('\nftload_char( code=$code)')
|
// println('\nftload_char( code=$code)')
|
||||||
//C.printf('face=%p\n', face)
|
// C.printf('face=%p\n', face)
|
||||||
//C.printf('cobj=%p\n', _face.cobj)
|
// C.printf('cobj=%p\n', _face.cobj)
|
||||||
ret := C.FT_Load_Char(face, code, C.FT_LOAD_RENDER|C.FT_LOAD_FORCE_AUTOHINT)
|
ret := C.FT_Load_Char(face, code, C.FT_LOAD_RENDER | C.FT_LOAD_FORCE_AUTOHINT)
|
||||||
//println('ret=$ret')
|
// println('ret=$ret')
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
println('freetype: failed to load glyph (utf32 code=$code, ' +
|
println('freetype: failed to load glyph (utf32 code=$code, ' + 'error code=$ret)')
|
||||||
'error code=$ret)')
|
return Character{
|
||||||
return Character{code: code}
|
code: code
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Generate texture
|
// Generate texture
|
||||||
mut texture := 0
|
mut texture := 0
|
||||||
C.glGenTextures(1, &texture)
|
C.glGenTextures(1, &texture)
|
||||||
C.glBindTexture(C.GL_TEXTURE_2D, texture)
|
C.glBindTexture(C.GL_TEXTURE_2D, texture)
|
||||||
fgwidth := (*face).glyph.bitmap.width
|
fgwidth := (*face).glyph.bitmap.width
|
||||||
fgrows := (*face).glyph.bitmap.rows
|
fgrows := (*face).glyph.bitmap.rows
|
||||||
C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RED, fgwidth, fgrows,
|
C.glTexImage2D(C.GL_TEXTURE_2D, 0, C.GL_RED, fgwidth, fgrows, 0, C.GL_RED, C.GL_UNSIGNED_BYTE,
|
||||||
0, C.GL_RED, C.GL_UNSIGNED_BYTE, (*face).glyph.bitmap.buffer)
|
(*face).glyph.bitmap.buffer)
|
||||||
// Set texture options
|
// Set texture options
|
||||||
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_S, C.GL_CLAMP_TO_EDGE)
|
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_S, C.GL_CLAMP_TO_EDGE)
|
||||||
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_T, C.GL_CLAMP_TO_EDGE)
|
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_T, C.GL_CLAMP_TO_EDGE)
|
||||||
@ -173,7 +161,9 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
|||||||
scale := cfg.scale
|
scale := cfg.scale
|
||||||
// Can only have text in ortho mode
|
// Can only have text in ortho mode
|
||||||
if !cfg.use_ortho {
|
if !cfg.use_ortho {
|
||||||
return &FreeType{face:0}
|
return &FreeType{
|
||||||
|
face: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
width := cfg.width * scale
|
width := cfg.width * scale
|
||||||
height := cfg.height * scale
|
height := cfg.height * scale
|
||||||
@ -193,7 +183,7 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
|||||||
C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA)
|
C.glBlendFunc(C.GL_SRC_ALPHA, C.GL_ONE_MINUS_SRC_ALPHA)
|
||||||
shader := gl.new_shader('text')
|
shader := gl.new_shader('text')
|
||||||
shader.use()
|
shader.use()
|
||||||
projection := glm.ortho(0, width, 0, height)// 0 at BOT
|
projection := glm.ortho(0, width, 0, height) // 0 at BOT
|
||||||
shader.set_mat4('projection', projection)
|
shader.set_mat4('projection', projection)
|
||||||
// FREETYPE
|
// FREETYPE
|
||||||
ft := C.FT_Library{}
|
ft := C.FT_Library{}
|
||||||
@ -215,9 +205,11 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
|||||||
eprintln('freetype: font "$font_path" does not exist')
|
eprintln('freetype: font "$font_path" does not exist')
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
face := &C.FT_FaceRec{glyph:0}
|
face := &C.FT_FaceRec{
|
||||||
|
glyph: 0
|
||||||
|
}
|
||||||
ret = int(C.FT_New_Face(ft, font_path.str, 0, &face))
|
ret = int(C.FT_New_Face(ft, font_path.str, 0, &face))
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
eprintln('freetype: failed to load font (error=$ret) from path: $font_path')
|
eprintln('freetype: failed to load font (error=$ret) from path: $font_path')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
@ -228,7 +220,7 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
|||||||
// Gen texture
|
// Gen texture
|
||||||
// Load first 128 characters of ASCII set
|
// Load first 128 characters of ASCII set
|
||||||
mut chars := []Character{}
|
mut chars := []Character{}
|
||||||
for c in 0..128 {
|
for c in 0 .. 128 {
|
||||||
ch := ft_load_char(face, i64(c))
|
ch := ft_load_char(face, i64(c))
|
||||||
// s := utf32_to_str(uint(0x043f))
|
// s := utf32_to_str(uint(0x043f))
|
||||||
// s := 'п'
|
// s := 'п'
|
||||||
@ -240,10 +232,10 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
|||||||
// # ch = gg__ft_load_char(f, 0xd0bf) ; // UTF 8
|
// # ch = gg__ft_load_char(f, 0xd0bf) ; // UTF 8
|
||||||
chars << ch
|
chars << ch
|
||||||
}
|
}
|
||||||
//ch := Character{}
|
// ch := Character{}
|
||||||
// Configure VAO
|
// Configure VAO
|
||||||
vao := gl.gen_vertex_array()
|
vao := gl.gen_vertex_array()
|
||||||
//println('new gg text context vao=$vao')
|
// println('new gg text context vao=$vao')
|
||||||
vbo := gl.gen_buffer()
|
vbo := gl.gen_buffer()
|
||||||
gl.bind_vao(vao)
|
gl.bind_vao(vao)
|
||||||
gl.bind_buffer(C.GL_ARRAY_BUFFER, vbo)
|
gl.bind_buffer(C.GL_ARRAY_BUFFER, vbo)
|
||||||
@ -253,7 +245,7 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
|||||||
// # glVertexAttribPointer(0, 4, GL_FLOAT,false, 4 * sizeof(GLf32), 0);
|
// # glVertexAttribPointer(0, 4, GL_FLOAT,false, 4 * sizeof(GLf32), 0);
|
||||||
// gl.bind_buffer(GL_ARRAY_BUFFER, uint(0))
|
// gl.bind_buffer(GL_ARRAY_BUFFER, uint(0))
|
||||||
// # glBindVertexArray(0);
|
// # glBindVertexArray(0);
|
||||||
ctx := &FreeType {
|
ctx := &FreeType{
|
||||||
shader: shader
|
shader: shader
|
||||||
width: width
|
width: width
|
||||||
height: height
|
height: height
|
||||||
@ -263,21 +255,21 @@ pub fn new_context(cfg gg.Cfg) &FreeType {
|
|||||||
chars: chars
|
chars: chars
|
||||||
face: face
|
face: face
|
||||||
}
|
}
|
||||||
//ctx.init_utf8_runes()
|
// ctx.init_utf8_runes()
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx mut FreeType) draw_text(_x, _y int, text string, cfg gx.TextCfg) {
|
pub fn (mut ctx FreeType) draw_text(_x, _y int, text string, cfg gx.TextCfg) {
|
||||||
//utext := text.ustring_tmp()
|
// utext := text.ustring_tmp()
|
||||||
utext := text.ustring()
|
utext := text.ustring()
|
||||||
ctx.private_draw_text(_x, _y, utext, cfg)
|
ctx.private_draw_text(_x, _y, utext, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (ctx mut FreeType) draw_text_fast(_x, _y int, text ustring, cfg gx.TextCfg) {
|
fn (mut ctx FreeType) draw_text_fast(_x, _y int, text ustring, cfg gx.TextCfg) {
|
||||||
ctx.private_draw_text(_x, _y, text, cfg)
|
ctx.private_draw_text(_x, _y, text, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) {
|
fn (mut ctx FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCfg) {
|
||||||
/*
|
/*
|
||||||
if utext.s.contains('on_seg') {
|
if utext.s.contains('on_seg') {
|
||||||
println('\nat(0)')
|
println('\nat(0)')
|
||||||
@ -295,14 +287,14 @@ fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
|
|||||||
yoffset := if ctx.scale > 1 { 5 } else { -1 } // 5 hidpi, -1 lowdpi
|
yoffset := if ctx.scale > 1 { 5 } else { -1 } // 5 hidpi, -1 lowdpi
|
||||||
// println('scale=$ctx.scale size=$cfg.size')
|
// println('scale=$ctx.scale size=$cfg.size')
|
||||||
if cfg.align == gx.ALIGN_RIGHT {
|
if cfg.align == gx.ALIGN_RIGHT {
|
||||||
//width := utext.len * 7
|
// width := utext.len * 7
|
||||||
width := wx
|
width := wx
|
||||||
x -= width + 10
|
x -= width + 10
|
||||||
}
|
}
|
||||||
x *= ctx.scale
|
x *= ctx.scale
|
||||||
y *= ctx.scale
|
y *= ctx.scale
|
||||||
y += yoffset
|
y += yoffset
|
||||||
y = f32(ctx.height) - y //invert y direction
|
y = f32(ctx.height) - y // invert y direction
|
||||||
color := cfg.color
|
color := cfg.color
|
||||||
// Activate corresponding render state
|
// Activate corresponding render state
|
||||||
ctx.shader.use()
|
ctx.shader.use()
|
||||||
@ -311,25 +303,24 @@ fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
|
|||||||
gl.bind_vao(ctx.vao)
|
gl.bind_vao(ctx.vao)
|
||||||
// Iterate through all characters
|
// Iterate through all characters
|
||||||
// utext := text.ustring()
|
// utext := text.ustring()
|
||||||
for i in 0..utext.len {
|
for i in 0 .. utext.len {
|
||||||
_rune := utext.at(i)
|
rune_ := utext.at(i)
|
||||||
// println('$i => $_rune')
|
// println('$i => $rune_')
|
||||||
mut ch := Character{}
|
mut ch := Character{}
|
||||||
mut found := false
|
mut found := false
|
||||||
if _rune.len == 1 {
|
if rune_.len == 1 {
|
||||||
idx := _rune[0]
|
idx := rune_[0]
|
||||||
if idx < 0 || idx >= ctx.chars.len {
|
if idx < 0 || idx >= ctx.chars.len {
|
||||||
println('BADE RUNE $_rune')
|
println('BADE RUNE $rune_')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
found = true
|
found = true
|
||||||
ch = ctx.chars[_rune[0]]
|
ch = ctx.chars[rune_[0]]
|
||||||
}
|
} else if rune_.len > 1 {
|
||||||
else if _rune.len > 1 {
|
|
||||||
// TODO O(1) use map
|
// TODO O(1) use map
|
||||||
for j in 0..ctx.utf_runes.len {
|
for j in 0 .. ctx.utf_runes.len {
|
||||||
rune_j := ctx.utf_runes[j]
|
rune_j := ctx.utf_runes[j]
|
||||||
if rune_j==_rune {
|
if rune_j == rune_ {
|
||||||
ch = ctx.utf_chars[j]
|
ch = ctx.utf_chars[j]
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
@ -337,31 +328,30 @@ fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// A new Unicode character. Load it and cache it.
|
// A new Unicode character. Load it and cache it.
|
||||||
if !found && _rune.len > 0 && _rune[0] > 32 {
|
if !found && rune_.len > 0 && rune_[0] > 32 {
|
||||||
//c := _rune[0]
|
// c := rune_[0]
|
||||||
//println('cant draw rune "$_rune" code=$c, loading')
|
// println('cant draw rune "$rune_" code=$c, loading')
|
||||||
//continue
|
// continue
|
||||||
ch = ft_load_char(ctx.face, _rune.utf32_code())
|
ch = ft_load_char(ctx.face, rune_.utf32_code())
|
||||||
//println('done loading')
|
// println('done loading')
|
||||||
ctx.utf_runes << _rune
|
ctx.utf_runes << rune_
|
||||||
ctx.utf_chars << ch
|
ctx.utf_chars << ch
|
||||||
//exit(1)
|
// exit(1)
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
xpos := x + f32(ch.horizontal_bearing_px.x) * 1
|
xpos := x + f32(ch.horizontal_bearing_px.x) * 1
|
||||||
ypos := y - f32(ch.size.y + wy - ch.horizontal_bearing_px.y) * 1
|
ypos := y - f32(ch.size.y + wy - ch.horizontal_bearing_px.y) * 1
|
||||||
//ypos := y - wy
|
// ypos := y - wy
|
||||||
w := f32(ch.size.x) * 1
|
w := f32(ch.size.x) * 1
|
||||||
h := f32(ch.size.y) * 1
|
h := f32(ch.size.y) * 1
|
||||||
// Update VBO for each character
|
// Update VBO for each character
|
||||||
vertices := [
|
vertices := [
|
||||||
xpos, ypos + h, 0.0, 0.0 ,
|
xpos, ypos + h, 0.0, 0.0,
|
||||||
xpos, ypos, 0.0, 1.0 ,
|
xpos, ypos, 0.0, 1.0,
|
||||||
xpos + w, ypos, 1.0, 1.0 ,
|
xpos + w, ypos, 1.0, 1.0,
|
||||||
xpos, ypos + h, 0.0, 0.0 ,
|
xpos, ypos + h, 0.0, 0.0,
|
||||||
xpos + w, ypos, 1.0, 1.0 ,
|
xpos + w, ypos, 1.0, 1.0,
|
||||||
xpos + w, ypos + h, 1.0, 0.0
|
xpos + w, ypos + h, 1.0, 0.0]
|
||||||
]
|
|
||||||
// Render glyph texture over quad
|
// Render glyph texture over quad
|
||||||
C.glBindTexture(C.GL_TEXTURE_2D, ch.texture_id)
|
C.glBindTexture(C.GL_TEXTURE_2D, ch.texture_id)
|
||||||
// Update content of VBO memory
|
// Update content of VBO memory
|
||||||
@ -372,9 +362,9 @@ fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
|
|||||||
gl.draw_arrays(C.GL_TRIANGLES, 0, 6)
|
gl.draw_arrays(C.GL_TRIANGLES, 0, 6)
|
||||||
x += f32(ch.horizontal_advance_px)
|
x += f32(ch.horizontal_advance_px)
|
||||||
// Stop drawing if the limit is reached
|
// Stop drawing if the limit is reached
|
||||||
if cfg.max_width > 0 {
|
if cfg.max_width > 0 {
|
||||||
if x >= cfg.max_width {
|
if x >= cfg.max_width {
|
||||||
//break
|
// break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,8 +372,8 @@ fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
|
|||||||
C.glBindTexture(C.GL_TEXTURE_2D, 0)
|
C.glBindTexture(C.GL_TEXTURE_2D, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx mut FreeType) draw_text_def(x, y int, text string) {
|
pub fn (mut ctx FreeType) draw_text_def(x, y int, text string) {
|
||||||
cfg := gx.TextCfg {
|
cfg := gx.TextCfg{
|
||||||
color: gx.Black
|
color: gx.Black
|
||||||
size: default_font_size
|
size: default_font_size
|
||||||
align: gx.align_left
|
align: gx.align_left
|
||||||
@ -391,50 +381,49 @@ pub fn (ctx mut FreeType) draw_text_def(x, y int, text string) {
|
|||||||
ctx.draw_text(x, y, text, cfg)
|
ctx.draw_text(x, y, text, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx mut FreeType) text_width(s string) int {
|
pub fn (mut ctx FreeType) text_width(s string) int {
|
||||||
x, _ := ctx.text_size(s)
|
x, _ := ctx.text_size(s)
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx mut FreeType) text_height(s string) int {
|
pub fn (mut ctx FreeType) text_height(s string) int {
|
||||||
_, y := ctx.text_size(s)
|
_, y := ctx.text_size(s)
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ctx mut FreeType) text_size(s string) (int, int) {
|
pub fn (mut ctx FreeType) text_size(s string) (int, int) {
|
||||||
//t := time.ticks()
|
// t := time.ticks()
|
||||||
utext := s.ustring()
|
utext := s.ustring()
|
||||||
mut x := u32(0)
|
mut x := u32(0)
|
||||||
mut maxy := u32(0)
|
mut maxy := u32(0)
|
||||||
mut _rune := ''
|
mut rune_ := ''
|
||||||
mut ch := Character{}
|
mut ch := Character{}
|
||||||
for i in 0..utext.len {
|
for i in 0 .. utext.len {
|
||||||
_rune = utext.at(i)
|
rune_ = utext.at(i)
|
||||||
ch = Character{}
|
ch = Character{}
|
||||||
mut found := false
|
mut found := false
|
||||||
if _rune.len == 1 {
|
if rune_.len == 1 {
|
||||||
idx := _rune[0]
|
idx := rune_[0]
|
||||||
if idx < 0 || idx >= ctx.chars.len {
|
if idx < 0 || idx >= ctx.chars.len {
|
||||||
println('BADE RUNE $_rune')
|
println('BADE RUNE $rune_')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
found = true
|
found = true
|
||||||
ch = ctx.chars[_rune[0]]
|
ch = ctx.chars[rune_[0]]
|
||||||
}
|
} else if rune_.len > 1 {
|
||||||
else if _rune.len > 1 {
|
|
||||||
// TODO O(1) use map
|
// TODO O(1) use map
|
||||||
for j in 0..ctx.utf_runes.len {
|
for j in 0 .. ctx.utf_runes.len {
|
||||||
rune_j := ctx.utf_runes[j]
|
rune_j := ctx.utf_runes[j]
|
||||||
if rune_j==_rune {
|
if rune_j == rune_ {
|
||||||
ch = ctx.utf_chars[j]
|
ch = ctx.utf_chars[j]
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found && _rune.len > 0 && _rune[0] > 32 {
|
if !found && rune_.len > 0 && rune_[0] > 32 {
|
||||||
ch = ft_load_char(ctx.face, _rune.utf32_code())
|
ch = ft_load_char(ctx.face, rune_.utf32_code())
|
||||||
ctx.utf_runes << _rune
|
ctx.utf_runes << rune_
|
||||||
ctx.utf_chars << ch
|
ctx.utf_chars << ch
|
||||||
}
|
}
|
||||||
x += ch.horizontal_advance_px
|
x += ch.horizontal_advance_px
|
||||||
@ -442,12 +431,12 @@ pub fn (ctx mut FreeType) text_size(s string) (int, int) {
|
|||||||
maxy = ch.vertical_advance_px
|
maxy = ch.vertical_advance_px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//println('text width "$s" = ${time.ticks() - t} ms')
|
// println('text width "$s" = ${time.ticks() - t} ms')
|
||||||
//scaled_x := x
|
// scaled_x := x
|
||||||
//scaled_y := maxy
|
// scaled_y := maxy
|
||||||
scaled_x := int(f64(x)/ctx.scale)
|
scaled_x := int(f64(x) / ctx.scale)
|
||||||
scaled_y := int(f64(maxy)/ctx.scale)
|
scaled_y := int(f64(maxy) / ctx.scale)
|
||||||
//println('text_size of "${s}" | x,y: $x,$maxy | scaled_x: ${scaled_x:3d} | scaled_y: ${scaled_y:3d} ')
|
// println('text_size of "${s}" | x,y: $x,$maxy | scaled_x: ${scaled_x:3d} | scaled_y: ${scaled_y:3d} ')
|
||||||
return scaled_x, scaled_y
|
return scaled_x, scaled_y
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +445,6 @@ pub fn (f FT_Face) str() string {
|
|||||||
return 'FT_Face{ style_name: ${ptr_str(f.style_name)} family_name: ${ptr_str(f.family_name)} }'
|
return 'FT_Face{ style_name: ${ptr_str(f.style_name)} family_name: ${ptr_str(f.family_name)} }'
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn (ac []Character) str() string {
|
pub fn (ac []Character) str() string {
|
||||||
mut res := []string{}
|
mut res := []string{}
|
||||||
for c in ac {
|
for c in ac {
|
||||||
|
@ -122,7 +122,7 @@ pub:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// type clickpub fn pub fn (window * GLFWwindow, button, action, mods int)
|
// type clickpub fn pub fn (window * GLFWwindow, button, action, mods int)
|
||||||
type clickpubfn fn (window voidptr, button, action, mods int)
|
type ClickPubFn fn (window voidptr, button, action, mods int)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO broken
|
* TODO broken
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
basic ftp module
|
basic ftp module
|
||||||
RFC-959
|
RFC-959
|
||||||
https://tools.ietf.org/html/rfc959
|
https://tools.ietf.org/html/rfc959
|
||||||
|
|
||||||
@ -15,29 +15,28 @@
|
|||||||
dtp.close()
|
dtp.close()
|
||||||
ftp.close()
|
ftp.close()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module ftp
|
module ftp
|
||||||
|
|
||||||
import net
|
import net
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Connected = 220
|
Connected = 220
|
||||||
SpecifyPassword = 331
|
SpecifyPassword = 331
|
||||||
LoggedIn = 230
|
LoggedIn = 230
|
||||||
LoginFirst = 503
|
LoginFirst = 503
|
||||||
Anonymous = 530
|
Anonymous = 530
|
||||||
OpenDataConnection = 150
|
OpenDataConnection = 150
|
||||||
CloseDataConnection = 226
|
CloseDataConnection = 226
|
||||||
CommandOk = 200
|
CommandOk = 200
|
||||||
denied = 550
|
denied = 550
|
||||||
PassiveMode = 227
|
PassiveMode = 227
|
||||||
complete = 226
|
complete = 226
|
||||||
)
|
)
|
||||||
|
|
||||||
struct DTP {
|
struct DTP {
|
||||||
mut:
|
mut:
|
||||||
sock net.Socket
|
sock net.Socket
|
||||||
ip string
|
ip string
|
||||||
port int
|
port int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,24 +44,27 @@ fn (dtp DTP) read() []byte {
|
|||||||
mut data := []byte{}
|
mut data := []byte{}
|
||||||
for {
|
for {
|
||||||
buf, len := dtp.sock.recv(1024)
|
buf, len := dtp.sock.recv(1024)
|
||||||
if len == 0 { break }
|
if len == 0 {
|
||||||
|
break
|
||||||
for i in 0..len {
|
}
|
||||||
|
for i in 0 .. len {
|
||||||
data << buf[i]
|
data << buf[i]
|
||||||
}
|
}
|
||||||
unsafe { free(buf) }
|
unsafe {
|
||||||
|
free(buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (dtp DTP) close() {
|
fn (dtp DTP) close() {
|
||||||
dtp.sock.close() or {}
|
dtp.sock.close() or {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FTP {
|
struct FTP {
|
||||||
mut:
|
mut:
|
||||||
sock net.Socket
|
sock net.Socket
|
||||||
buffer_size int
|
buffer_size int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,11 +89,9 @@ fn (ftp FTP) read() (int, string) {
|
|||||||
$if debug {
|
$if debug {
|
||||||
println('FTP.v <<< $data')
|
println('FTP.v <<< $data')
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.len < 5 {
|
if data.len < 5 {
|
||||||
return 0, ''
|
return 0, ''
|
||||||
}
|
}
|
||||||
|
|
||||||
code := data[..3].int()
|
code := data[..3].int()
|
||||||
if data[3] == `-` {
|
if data[3] == `-` {
|
||||||
for {
|
for {
|
||||||
@ -101,21 +101,18 @@ fn (ftp FTP) read() (int, string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return code, data
|
return code, data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ftp mut FTP) connect(ip string) bool {
|
pub fn (mut ftp FTP) connect(ip string) bool {
|
||||||
sock := net.dial(ip, 21) or {
|
sock := net.dial(ip, 21) or {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ftp.sock = sock
|
ftp.sock = sock
|
||||||
|
|
||||||
code, _ := ftp.read()
|
code, _ := ftp.read()
|
||||||
if code == Connected {
|
if code == Connected {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,36 +123,34 @@ pub fn (ftp FTP) login(user, passwd string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
mut code, data := ftp.read()
|
mut code, data := ftp.read()
|
||||||
if code == LoggedIn {
|
if code == LoggedIn {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if code != SpecifyPassword {
|
if code != SpecifyPassword {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
ftp.write('PASS $passwd') or {
|
ftp.write('PASS $passwd') or {
|
||||||
$if debug {
|
$if debug {
|
||||||
println('ERROR sending password')
|
println('ERROR sending password')
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
code, data = ftp.read()
|
code, data = ftp.read()
|
||||||
|
// TODO Replace `data` with `_`
|
||||||
|
_ := data
|
||||||
if code == LoggedIn {
|
if code == LoggedIn {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ftp FTP) close() {
|
pub fn (ftp FTP) close() {
|
||||||
send_quit := 'QUIT\r\n'
|
send_quit := 'QUIT\r\n'
|
||||||
ftp.sock.send_string(send_quit) or {}
|
ftp.sock.send_string(send_quit) or {
|
||||||
ftp.sock.close() or {}
|
}
|
||||||
|
ftp.sock.close() or {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ftp FTP) pwd() string {
|
pub fn (ftp FTP) pwd() string {
|
||||||
@ -171,7 +166,9 @@ pub fn (ftp FTP) pwd() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn (ftp FTP) cd(dir string) {
|
pub fn (ftp FTP) cd(dir string) {
|
||||||
ftp.write('CWD $dir') or { return }
|
ftp.write('CWD $dir') or {
|
||||||
|
return
|
||||||
|
}
|
||||||
mut code, mut data := ftp.read()
|
mut code, mut data := ftp.read()
|
||||||
match int(code) {
|
match int(code) {
|
||||||
denied {
|
denied {
|
||||||
@ -184,7 +181,6 @@ pub fn (ftp FTP) cd(dir string) {
|
|||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
|
|
||||||
$if debug {
|
$if debug {
|
||||||
println('CD $data')
|
println('CD $data')
|
||||||
}
|
}
|
||||||
@ -194,14 +190,11 @@ fn new_dtp(msg string) ?DTP {
|
|||||||
if !is_dtp_message_valid(msg) {
|
if !is_dtp_message_valid(msg) {
|
||||||
return error('Bad message')
|
return error('Bad message')
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, port := get_host_ip_from_dtp_message(msg)
|
ip, port := get_host_ip_from_dtp_message(msg)
|
||||||
|
|
||||||
sock := net.dial(ip, port) or {
|
sock := net.dial(ip, port) or {
|
||||||
return error('Cannot connect to the data channel')
|
return error('Cannot connect to the data channel')
|
||||||
}
|
}
|
||||||
|
dtp := DTP{
|
||||||
dtp := DTP {
|
|
||||||
sock: sock
|
sock: sock
|
||||||
ip: ip
|
ip: ip
|
||||||
port: port
|
port: port
|
||||||
@ -210,18 +203,17 @@ fn new_dtp(msg string) ?DTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (ftp FTP) pasv() ?DTP {
|
fn (ftp FTP) pasv() ?DTP {
|
||||||
ftp.write('PASV') or {}
|
ftp.write('PASV') or {
|
||||||
|
}
|
||||||
code, data := ftp.read()
|
code, data := ftp.read()
|
||||||
$if debug {
|
$if debug {
|
||||||
println('pass: $data')
|
println('pass: $data')
|
||||||
}
|
}
|
||||||
|
|
||||||
if code != PassiveMode {
|
if code != PassiveMode {
|
||||||
return error('pasive mode not allowed')
|
return error('pasive mode not allowed')
|
||||||
}
|
}
|
||||||
|
|
||||||
dtp := new_dtp(data) or {
|
dtp := new_dtp(data) or {
|
||||||
return error(err)
|
return error(err)
|
||||||
}
|
}
|
||||||
return dtp
|
return dtp
|
||||||
}
|
}
|
||||||
@ -230,8 +222,8 @@ pub fn (ftp FTP) dir() ?[]string {
|
|||||||
dtp := ftp.pasv() or {
|
dtp := ftp.pasv() or {
|
||||||
return error('cannot establish data connection')
|
return error('cannot establish data connection')
|
||||||
}
|
}
|
||||||
|
ftp.write('LIST') or {
|
||||||
ftp.write('LIST') or {}
|
}
|
||||||
code, _ := ftp.read()
|
code, _ := ftp.read()
|
||||||
if code == denied {
|
if code == denied {
|
||||||
return error('LIST denied')
|
return error('LIST denied')
|
||||||
@ -239,23 +231,20 @@ pub fn (ftp FTP) dir() ?[]string {
|
|||||||
if code != OpenDataConnection {
|
if code != OpenDataConnection {
|
||||||
return error('data channel empty')
|
return error('data channel empty')
|
||||||
}
|
}
|
||||||
|
|
||||||
list_dir := dtp.read()
|
list_dir := dtp.read()
|
||||||
result, _ := ftp.read()
|
result, _ := ftp.read()
|
||||||
if result != CloseDataConnection {
|
if result != CloseDataConnection {
|
||||||
println('LIST not ok')
|
println('LIST not ok')
|
||||||
}
|
}
|
||||||
dtp.close()
|
dtp.close()
|
||||||
|
|
||||||
mut dir := []string{}
|
mut dir := []string{}
|
||||||
sdir := string(byteptr(list_dir.data))
|
sdir := string(byteptr(list_dir.data))
|
||||||
for lfile in sdir.split('\n') {
|
for lfile in sdir.split('\n') {
|
||||||
if lfile.len >1 {
|
if lfile.len > 1 {
|
||||||
spl := lfile.split(' ')
|
spl := lfile.split(' ')
|
||||||
dir << spl[spl.len-1]
|
dir << spl[spl.len - 1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,21 +252,17 @@ pub fn (ftp FTP) get(file string) ?[]byte {
|
|||||||
dtp := ftp.pasv() or {
|
dtp := ftp.pasv() or {
|
||||||
return error('Cannot stablish data connection')
|
return error('Cannot stablish data connection')
|
||||||
}
|
}
|
||||||
|
ftp.write('RETR $file') or {
|
||||||
ftp.write('RETR $file') or {}
|
}
|
||||||
code, _ := ftp.read()
|
code, _ := ftp.read()
|
||||||
|
|
||||||
if code == denied {
|
if code == denied {
|
||||||
return error('Permission denied')
|
return error('Permission denied')
|
||||||
}
|
}
|
||||||
|
|
||||||
if code != OpenDataConnection {
|
if code != OpenDataConnection {
|
||||||
return error('Data connection not ready')
|
return error('Data connection not ready')
|
||||||
}
|
}
|
||||||
|
|
||||||
blob := dtp.read()
|
blob := dtp.read()
|
||||||
dtp.close()
|
dtp.close()
|
||||||
|
|
||||||
return blob
|
return blob
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +275,6 @@ fn is_dtp_message_valid(msg string) bool {
|
|||||||
fn get_host_ip_from_dtp_message(msg string) (string, int) {
|
fn get_host_ip_from_dtp_message(msg string) (string, int) {
|
||||||
mut par_start_idx := -1
|
mut par_start_idx := -1
|
||||||
mut par_end_idx := -1
|
mut par_end_idx := -1
|
||||||
|
|
||||||
for i, c in msg {
|
for i, c in msg {
|
||||||
if c == `(` {
|
if c == `(` {
|
||||||
par_start_idx = i + 1
|
par_start_idx = i + 1
|
||||||
@ -299,9 +283,7 @@ fn get_host_ip_from_dtp_message(msg string) (string, int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
data := msg[par_start_idx..par_end_idx].split(',')
|
data := msg[par_start_idx..par_end_idx].split(',')
|
||||||
|
|
||||||
ip := data[0..4].join('.')
|
ip := data[0..4].join('.')
|
||||||
port := data[4].int() * 256 + data[5].int()
|
port := data[4].int() * 256 + data[5].int()
|
||||||
|
|
||||||
return ip, port
|
return ip, port
|
||||||
}
|
}
|
||||||
|
@ -57,11 +57,11 @@ pub fn read_set_cookies(h map[string][]string) []&Cookie {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
name := keyval[0]
|
name := keyval[0]
|
||||||
_value := keyval[1]
|
raw_value := keyval[1]
|
||||||
if !is_cookie_name_valid(name) {
|
if !is_cookie_name_valid(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value := parse_cookie_value(_value, true) or {
|
value := parse_cookie_value(raw_value, true) or {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mut c := &Cookie{
|
mut c := &Cookie{
|
||||||
@ -75,14 +75,14 @@ pub fn read_set_cookies(h map[string][]string) []&Cookie {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mut attr := parts[i]
|
mut attr := parts[i]
|
||||||
mut _val := ''
|
mut raw_val := ''
|
||||||
if attr.contains('=') {
|
if attr.contains('=') {
|
||||||
pieces := attr.split('=')
|
pieces := attr.split('=')
|
||||||
attr = pieces[0]
|
attr = pieces[0]
|
||||||
_val = pieces[1]
|
raw_val = pieces[1]
|
||||||
}
|
}
|
||||||
lower_attr := attr.to_lower()
|
lower_attr := attr.to_lower()
|
||||||
val := parse_cookie_value(_val, false) or {
|
val := parse_cookie_value(raw_val, false) or {
|
||||||
c.unparsed << parts[i]
|
c.unparsed << parts[i]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -158,9 +158,9 @@ pub fn read_cookies(h map[string][]string, filter string) []&Cookie {
|
|||||||
mut part := ''
|
mut part := ''
|
||||||
for line.len > 0 {
|
for line.len > 0 {
|
||||||
if line.index_any(';') > 0 {
|
if line.index_any(';') > 0 {
|
||||||
_parts := line.split(';')
|
line_parts := line.split(';')
|
||||||
part = _parts[0]
|
part = line_parts[0]
|
||||||
line = _parts[1]
|
line = line_parts[1]
|
||||||
} else {
|
} else {
|
||||||
part = line
|
part = line
|
||||||
line = ''
|
line = ''
|
||||||
@ -172,9 +172,9 @@ pub fn read_cookies(h map[string][]string, filter string) []&Cookie {
|
|||||||
mut name := part
|
mut name := part
|
||||||
mut val := ''
|
mut val := ''
|
||||||
if part.contains('=') {
|
if part.contains('=') {
|
||||||
_parts := part.split('=')
|
val_parts := part.split('=')
|
||||||
name = _parts[0]
|
name = val_parts[0]
|
||||||
val = _parts[1]
|
val = val_parts[1]
|
||||||
}
|
}
|
||||||
if !is_cookie_name_valid(name) {
|
if !is_cookie_name_valid(name) {
|
||||||
continue
|
continue
|
||||||
@ -182,12 +182,9 @@ pub fn read_cookies(h map[string][]string, filter string) []&Cookie {
|
|||||||
if filter != '' && filter != name {
|
if filter != '' && filter != name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Circumvent the issue with assigning an `or` expression to an existing value
|
val = parse_cookie_value(val, true) or {
|
||||||
// TODO: Fix when fixed in compiler
|
|
||||||
_val := parse_cookie_value(val, true) or {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val = _val
|
|
||||||
cookies << &Cookie{name: name, value: val}
|
cookies << &Cookie{name: name, value: val}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module http
|
module http
|
||||||
|
|
||||||
type downloadfn fn(written int)type download_finished_fn fn()
|
type DownloadFn = fn (written int)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct DownloadStruct {
|
struct DownloadStruct {
|
||||||
mut:
|
mut:
|
||||||
stream voidptr
|
stream voidptr
|
||||||
written int
|
written int
|
||||||
cb downloadfn
|
cb DownloadFn
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
|
fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
|
||||||
@ -23,7 +24,7 @@ fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) {
|
pub fn download_file_with_progress(url, out string, cb DownloadFn, cb_finished fn()) {
|
||||||
/*
|
/*
|
||||||
curl := C.curl_easy_init()
|
curl := C.curl_easy_init()
|
||||||
if isnil(curl) {
|
if isnil(curl) {
|
||||||
@ -49,4 +50,3 @@ pub fn download_file_with_progress(url, out string, cb downloadfn, cb_finished f
|
|||||||
|
|
||||||
fn empty() {
|
fn empty() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import net.urllib
|
|||||||
import net.http.chunked
|
import net.http.chunked
|
||||||
|
|
||||||
const (
|
const (
|
||||||
max_redirects = 4
|
max_redirects = 4
|
||||||
content_type_default = 'text/plain'
|
content_type_default = 'text/plain'
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -20,7 +20,6 @@ pub mut:
|
|||||||
url string
|
url string
|
||||||
user_agent string
|
user_agent string
|
||||||
verbose bool
|
verbose bool
|
||||||
//mut:
|
|
||||||
user_ptr voidptr
|
user_ptr voidptr
|
||||||
ws_func voidptr
|
ws_func voidptr
|
||||||
}
|
}
|
||||||
@ -32,8 +31,8 @@ pub mut:
|
|||||||
params map[string]string
|
params map[string]string
|
||||||
headers map[string]string
|
headers map[string]string
|
||||||
cookies map[string]string
|
cookies map[string]string
|
||||||
user_agent string//='v' QTODO
|
user_agent string // ='v' QTODO
|
||||||
verbose bool=false
|
verbose bool = false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
@ -44,9 +43,9 @@ pub:
|
|||||||
status_code int
|
status_code int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_request(method, url_, data string) ?Request{
|
pub fn new_request(method, url_, data string) ?Request {
|
||||||
url := if method == 'GET' { url_ + '?' + data } else { url_ }
|
url := if method == 'GET' { url_ + '?' + data } else { url_ }
|
||||||
//println('new req() method=$method url="$url" dta="$data"')
|
// println('new req() method=$method url="$url" dta="$data"')
|
||||||
return Request{
|
return Request{
|
||||||
method: method.to_upper()
|
method: method.to_upper()
|
||||||
url: url
|
url: url
|
||||||
@ -147,7 +146,7 @@ pub fn url_encode_form_data(data map[string]string) string {
|
|||||||
return pieces.join('&')
|
return pieces.join('&')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_with_method(method string, url string, _config FetchConfig) ?Response {
|
fn fetch_with_method(method, url string, _config FetchConfig) ?Response {
|
||||||
mut config := _config
|
mut config := _config
|
||||||
config.method = method
|
config.method = method
|
||||||
return fetch(url, config)
|
return fetch(url, config)
|
||||||
@ -173,21 +172,21 @@ fn build_url_from_fetch(_url string, config FetchConfig) ?string {
|
|||||||
return url.str()
|
return url.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (req mut Request) free() {
|
fn (mut req Request) free() {
|
||||||
req.headers.free()
|
req.headers.free()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (resp mut Response) free() {
|
fn (mut resp Response) free() {
|
||||||
resp.headers.free()
|
resp.headers.free()
|
||||||
}
|
}
|
||||||
|
|
||||||
// add_header adds the key and value of an HTTP request header
|
// add_header adds the key and value of an HTTP request header
|
||||||
pub fn (req mut Request) add_header(key, val string) {
|
pub fn (mut req Request) add_header(key, val string) {
|
||||||
req.headers[key] = val
|
req.headers[key] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_headers(lines []string) map[string]string {
|
pub fn parse_headers(lines []string) map[string]string {
|
||||||
mut headers := map[string]string
|
mut headers := map[string]string{}
|
||||||
for i, line in lines {
|
for i, line in lines {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
continue
|
continue
|
||||||
@ -258,8 +257,7 @@ fn (req &Request) method_and_url_to_response(method string, url urllib.URL) ?Res
|
|||||||
return error(err)
|
return error(err)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
} else if scheme == 'http' {
|
||||||
else if scheme == 'http' {
|
|
||||||
// println('http_do( $nport, $method, $host_name, $path )')
|
// println('http_do( $nport, $method, $host_name, $path )')
|
||||||
res := req.http_do(nport, method, host_name, path) or {
|
res := req.http_do(nport, method, host_name, path) or {
|
||||||
return error(err)
|
return error(err)
|
||||||
@ -271,9 +269,9 @@ fn (req &Request) method_and_url_to_response(method string, url urllib.URL) ?Res
|
|||||||
|
|
||||||
fn parse_response(resp string) Response {
|
fn parse_response(resp string) Response {
|
||||||
// TODO: Header data type
|
// TODO: Header data type
|
||||||
mut headers := map[string]string
|
mut headers := map[string]string{}
|
||||||
// TODO: Cookie data type
|
// TODO: Cookie data type
|
||||||
mut cookies := map[string]string
|
mut cookies := map[string]string{}
|
||||||
first_header := resp.all_before('\n')
|
first_header := resp.all_before('\n')
|
||||||
mut status_code := 0
|
mut status_code := 0
|
||||||
if first_header.contains('HTTP/') {
|
if first_header.contains('HTTP/') {
|
||||||
@ -341,7 +339,8 @@ fn (req &Request) build_request_headers(method, host_name, path string) string {
|
|||||||
uheaders << '${key}: ${val}\r\n'
|
uheaders << '${key}: ${val}\r\n'
|
||||||
}
|
}
|
||||||
uheaders << req.build_request_cookies_header()
|
uheaders << req.build_request_cookies_header()
|
||||||
return '$method $path HTTP/1.1\r\n' + uheaders.join('') + 'Connection: close\r\n\r\n' + req.data
|
return '$method $path HTTP/1.1\r\n' + uheaders.join('') + 'Connection: close\r\n\r\n' +
|
||||||
|
req.data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (req &Request) build_request_cookies_header() string {
|
fn (req &Request) build_request_cookies_header() string {
|
||||||
@ -373,5 +372,3 @@ pub fn unescape(s string) string {
|
|||||||
pub fn escape(s string) string {
|
pub fn escape(s string) string {
|
||||||
panic('http.escape() was replaced with http.escape_url()')
|
panic('http.escape() was replaced with http.escape_url()')
|
||||||
}
|
}
|
||||||
|
|
||||||
type wsfn fn(s string, ptr voidptr)
|
|
||||||
|
@ -7,7 +7,7 @@ module net
|
|||||||
struct C.WSAData {
|
struct C.WSAData {
|
||||||
mut:
|
mut:
|
||||||
wVersion u16
|
wVersion u16
|
||||||
wHighVersion u16
|
wHighVersion u16
|
||||||
szDescription [257]byte
|
szDescription [257]byte
|
||||||
szSystemStatus [129]byte
|
szSystemStatus [129]byte
|
||||||
iMaxSockets u16
|
iMaxSockets u16
|
||||||
|
@ -6,7 +6,7 @@ pub struct Socket {
|
|||||||
pub:
|
pub:
|
||||||
sockfd int
|
sockfd int
|
||||||
family int
|
family int
|
||||||
_type int
|
typ int
|
||||||
proto int
|
proto int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,53 +39,39 @@ struct C.sockaddr_storage {
|
|||||||
|
|
||||||
fn C.socket() int
|
fn C.socket() int
|
||||||
|
|
||||||
|
|
||||||
fn C.setsockopt() int
|
fn C.setsockopt() int
|
||||||
|
|
||||||
|
|
||||||
fn C.htonl() int
|
fn C.htonl() int
|
||||||
|
|
||||||
|
|
||||||
fn C.htons() int
|
fn C.htons() int
|
||||||
|
|
||||||
|
|
||||||
fn C.bind() int
|
fn C.bind() int
|
||||||
|
|
||||||
|
|
||||||
fn C.listen() int
|
fn C.listen() int
|
||||||
|
|
||||||
|
|
||||||
fn C.accept() int
|
fn C.accept() int
|
||||||
|
|
||||||
|
|
||||||
fn C.getaddrinfo() int
|
fn C.getaddrinfo() int
|
||||||
|
|
||||||
|
|
||||||
fn C.connect() int
|
fn C.connect() int
|
||||||
|
|
||||||
|
|
||||||
fn C.send() int
|
fn C.send() int
|
||||||
|
|
||||||
|
|
||||||
fn C.recv() int
|
fn C.recv() int
|
||||||
|
|
||||||
|
|
||||||
fn C.read() int
|
fn C.read() int
|
||||||
|
|
||||||
|
|
||||||
fn C.shutdown() int
|
fn C.shutdown() int
|
||||||
|
|
||||||
|
|
||||||
fn C.close() int
|
fn C.close() int
|
||||||
|
|
||||||
|
|
||||||
fn C.ntohs() int
|
fn C.ntohs() int
|
||||||
|
|
||||||
|
|
||||||
fn C.getsockname() int
|
fn C.getsockname() int
|
||||||
|
|
||||||
// create socket
|
// create socket
|
||||||
pub fn new_socket(family int, _type int, proto int) ?Socket {
|
pub fn new_socket(family, typ, proto int) ?Socket {
|
||||||
sockfd := C.socket(family, _type, proto)
|
sockfd := C.socket(family, typ, proto)
|
||||||
one := 1
|
one := 1
|
||||||
// This is needed so that there are no problems with reusing the
|
// This is needed so that there are no problems with reusing the
|
||||||
// same port after the application exits.
|
// same port after the application exits.
|
||||||
@ -96,7 +82,7 @@ pub fn new_socket(family int, _type int, proto int) ?Socket {
|
|||||||
s := Socket{
|
s := Socket{
|
||||||
sockfd: sockfd
|
sockfd: sockfd
|
||||||
family: family
|
family: family
|
||||||
_type: _type
|
typ: typ
|
||||||
proto: proto
|
proto: proto
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
@ -107,7 +93,7 @@ pub fn socket_udp() ?Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set socket options
|
// set socket options
|
||||||
pub fn (s Socket) setsockopt(level int, optname int, optvalue &int) ?int {
|
pub fn (s Socket) setsockopt(level, optname int, optvalue &int) ?int {
|
||||||
res := C.setsockopt(s.sockfd, level, optname, optvalue, sizeof(&int))
|
res := C.setsockopt(s.sockfd, level, optname, optvalue, sizeof(&int))
|
||||||
if res < 0 {
|
if res < 0 {
|
||||||
return error('net.setsocketopt: failed with $res')
|
return error('net.setsocketopt: failed with $res')
|
||||||
@ -117,8 +103,7 @@ pub fn (s Socket) setsockopt(level int, optname int, optvalue &int) ?int {
|
|||||||
|
|
||||||
// bind socket to port
|
// bind socket to port
|
||||||
pub fn (s Socket) bind(port int) ?int {
|
pub fn (s Socket) bind(port int) ?int {
|
||||||
mut addr := C.sockaddr_in{
|
mut addr := C.sockaddr_in{}
|
||||||
}
|
|
||||||
addr.sin_family = s.family
|
addr.sin_family = s.family
|
||||||
addr.sin_port = C.htons(port)
|
addr.sin_port = C.htons(port)
|
||||||
addr.sin_addr.s_addr = C.htonl(C.INADDR_ANY)
|
addr.sin_addr.s_addr = C.htonl(C.INADDR_ANY)
|
||||||
@ -178,8 +163,7 @@ pub fn (s Socket) accept() ?Socket {
|
|||||||
$if debug {
|
$if debug {
|
||||||
println('accept()')
|
println('accept()')
|
||||||
}
|
}
|
||||||
addr := C.sockaddr_storage{
|
addr := C.sockaddr_storage{}
|
||||||
}
|
|
||||||
size := 128 // sizeof(sockaddr_storage)
|
size := 128 // sizeof(sockaddr_storage)
|
||||||
sockfd := C.accept(s.sockfd, &addr, &size)
|
sockfd := C.accept(s.sockfd, &addr, &size)
|
||||||
if sockfd < 0 {
|
if sockfd < 0 {
|
||||||
@ -188,7 +172,7 @@ pub fn (s Socket) accept() ?Socket {
|
|||||||
c := Socket{
|
c := Socket{
|
||||||
sockfd: sockfd
|
sockfd: sockfd
|
||||||
family: s.family
|
family: s.family
|
||||||
_type: s._type
|
typ: s.typ
|
||||||
proto: s.proto
|
proto: s.proto
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
@ -196,10 +180,9 @@ pub fn (s Socket) accept() ?Socket {
|
|||||||
|
|
||||||
// connect to given addrress and port
|
// connect to given addrress and port
|
||||||
pub fn (s Socket) connect(address string, port int) ?int {
|
pub fn (s Socket) connect(address string, port int) ?int {
|
||||||
mut hints := C.addrinfo{
|
mut hints := C.addrinfo{}
|
||||||
}
|
|
||||||
hints.ai_family = s.family
|
hints.ai_family = s.family
|
||||||
hints.ai_socktype = s._type
|
hints.ai_socktype = s.typ
|
||||||
hints.ai_flags = C.AI_PASSIVE
|
hints.ai_flags = C.AI_PASSIVE
|
||||||
hints.ai_protocol = s.proto
|
hints.ai_protocol = s.proto
|
||||||
hints.ai_addrlen = 0
|
hints.ai_addrlen = 0
|
||||||
@ -210,12 +193,12 @@ pub fn (s Socket) connect(address string, port int) ?int {
|
|||||||
sport := '$port'
|
sport := '$port'
|
||||||
info_res := C.getaddrinfo(address.str, sport.str, &hints, &info)
|
info_res := C.getaddrinfo(address.str, sport.str, &hints, &info)
|
||||||
if info_res != 0 {
|
if info_res != 0 {
|
||||||
error_message := os.get_error_msg(net.error_code())
|
error_message := os.get_error_msg(error_code())
|
||||||
return error('net.connect: getaddrinfo failed "$error_message"')
|
return error('net.connect: getaddrinfo failed "$error_message"')
|
||||||
}
|
}
|
||||||
res := C.connect(s.sockfd, info.ai_addr, info.ai_addrlen)
|
res := C.connect(s.sockfd, info.ai_addr, info.ai_addrlen)
|
||||||
if res < 0 {
|
if res < 0 {
|
||||||
error_message := os.get_error_msg(net.error_code())
|
error_message := os.get_error_msg(error_code())
|
||||||
return error('net.connect: connect failed "$error_message"')
|
return error('net.connect: connect failed "$error_message"')
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
@ -256,11 +239,13 @@ pub fn (s Socket) send_string(sdata string) ?int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// receive string data from socket. NB: you are responsible for freeing the returned byteptr
|
// receive string data from socket. NB: you are responsible for freeing the returned byteptr
|
||||||
pub fn (s Socket) recv(bufsize int) (byteptr,int) {
|
pub fn (s Socket) recv(bufsize int) (byteptr, int) {
|
||||||
mut buf := byteptr(0)
|
mut buf := byteptr(0)
|
||||||
unsafe { buf = malloc(bufsize) }
|
unsafe {
|
||||||
|
buf = malloc(bufsize)
|
||||||
|
}
|
||||||
res := C.recv(s.sockfd, buf, bufsize, 0)
|
res := C.recv(s.sockfd, buf, bufsize, 0)
|
||||||
return buf,res
|
return buf, res
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove cread/2 and crecv/2 when the Go net interface is done
|
// TODO: remove cread/2 and crecv/2 when the Go net interface is done
|
||||||
@ -300,10 +285,11 @@ pub fn (s Socket) close() ?int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
CRLF = '\r\n'
|
CRLF = '\r\n'
|
||||||
MAX_READ = 400
|
MAX_READ = 400
|
||||||
MSG_PEEK = 0x02
|
MSG_PEEK = 0x02
|
||||||
)
|
)
|
||||||
|
|
||||||
// write - write a string with CRLF after it over the socket s
|
// write - write a string with CRLF after it over the socket s
|
||||||
pub fn (s Socket) write(str string) ?int {
|
pub fn (s Socket) write(str string) ?int {
|
||||||
line := '$str$CRLF'
|
line := '$str$CRLF'
|
||||||
@ -329,7 +315,7 @@ pub fn (s Socket) read_line() string {
|
|||||||
}
|
}
|
||||||
buf[n] = `\0`
|
buf[n] = `\0`
|
||||||
mut eol_idx := -1
|
mut eol_idx := -1
|
||||||
for i in 0..n {
|
for i in 0 .. n {
|
||||||
if int(buf[i]) == `\n` {
|
if int(buf[i]) == `\n` {
|
||||||
eol_idx = i
|
eol_idx = i
|
||||||
// Ensure that tos_clone(buf) later,
|
// Ensure that tos_clone(buf) later,
|
||||||
@ -377,8 +363,7 @@ pub fn (s Socket) read_all() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s Socket) get_port() int {
|
pub fn (s Socket) get_port() int {
|
||||||
mut addr := C.sockaddr_in{
|
mut addr := C.sockaddr_in{}
|
||||||
}
|
|
||||||
size := 16 // sizeof(sockaddr_in)
|
size := 16 // sizeof(sockaddr_in)
|
||||||
C.getsockname(s.sockfd, &addr, &size)
|
C.getsockname(s.sockfd, &addr, &size)
|
||||||
return C.ntohs(addr.sin_port)
|
return C.ntohs(addr.sin_port)
|
||||||
|
10
vlib/os/os.v
10
vlib/os/os.v
@ -148,9 +148,9 @@ fn C.CopyFile(&u32, &u32, int) int
|
|||||||
// TODO implement actual cp for linux
|
// TODO implement actual cp for linux
|
||||||
pub fn cp(old, new string) ?bool {
|
pub fn cp(old, new string) ?bool {
|
||||||
$if windows {
|
$if windows {
|
||||||
_old := old.replace('/', '\\')
|
w_old := old.replace('/', '\\')
|
||||||
_new := new.replace('/', '\\')
|
w_new := new.replace('/', '\\')
|
||||||
C.CopyFile(_old.to_wide(), _new.to_wide(), false)
|
C.CopyFile(w_old.to_wide(), w_new.to_wide(), false)
|
||||||
result := C.GetLastError()
|
result := C.GetLastError()
|
||||||
if result == 0 {
|
if result == 0 {
|
||||||
return true
|
return true
|
||||||
@ -954,8 +954,8 @@ pub fn dir_exists(path string) bool {
|
|||||||
// is_dir returns a boolean indicating whether the given path is a directory.
|
// is_dir returns a boolean indicating whether the given path is a directory.
|
||||||
pub fn is_dir(path string) bool {
|
pub fn is_dir(path string) bool {
|
||||||
$if windows {
|
$if windows {
|
||||||
_path := path.replace('/', '\\')
|
w_path := path.replace('/', '\\')
|
||||||
attr := C.GetFileAttributesW(_path.to_wide())
|
attr := C.GetFileAttributesW(w_path.to_wide())
|
||||||
if attr == u32(C.INVALID_FILE_ATTRIBUTES) {
|
if attr == u32(C.INVALID_FILE_ATTRIBUTES) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -16,64 +16,64 @@ pub type HANDLE voidptr
|
|||||||
// win: FILETIME
|
// win: FILETIME
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
|
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
|
||||||
struct Filetime {
|
struct Filetime {
|
||||||
dwLowDateTime u32
|
dw_low_date_time u32
|
||||||
dwHighDateTime u32
|
dw_high_date_time u32
|
||||||
}
|
}
|
||||||
|
|
||||||
// win: WIN32_FIND_DATA
|
// win: WIN32_FIND_DATA
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-_win32_find_dataw
|
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-_win32_find_dataw
|
||||||
struct Win32finddata {
|
struct Win32finddata {
|
||||||
mut:
|
mut:
|
||||||
dwFileAttributes u32
|
dw_file_attributes u32
|
||||||
ftCreationTime Filetime
|
ft_creation_time Filetime
|
||||||
ftLastAccessTime Filetime
|
ft_last_access_time Filetime
|
||||||
ftLastWriteTime Filetime
|
ft_last_write_time Filetime
|
||||||
nFileSizeHigh u32
|
n_file_size_high u32
|
||||||
nFileSizeLow u32
|
n_file_size_low u32
|
||||||
dwReserved0 u32
|
dw_reserved0 u32
|
||||||
dwReserved1 u32
|
dw_reserved1 u32
|
||||||
cFileName [260]u16 // MAX_PATH = 260
|
c_file_name [260]u16 // MAX_PATH = 260
|
||||||
cAlternateFileName [14]u16 // 14
|
c_alternate_file_name [14]u16 // 14
|
||||||
dwFileType u32
|
dw_file_type u32
|
||||||
dwCreatorType u32
|
dw_creator_type u32
|
||||||
wFinderFlags u16
|
w_finder_flags u16
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProcessInformation {
|
struct ProcessInformation {
|
||||||
mut:
|
mut:
|
||||||
hProcess voidptr
|
h_process voidptr
|
||||||
hThread voidptr
|
h_thread voidptr
|
||||||
dwProcessId u32
|
dw_process_id u32
|
||||||
dwThreadId u32
|
dw_thread_id u32
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StartupInfo {
|
struct StartupInfo {
|
||||||
mut:
|
mut:
|
||||||
cb u32
|
cb u32
|
||||||
lpReserved &u16
|
lp_reserved &u16
|
||||||
lpDesktop &u16
|
lp_desktop &u16
|
||||||
lpTitle &u16
|
lp_title &u16
|
||||||
dwX u32
|
dw_x u32
|
||||||
dwY u32
|
dw_y u32
|
||||||
dwXSize u32
|
dw_x_size u32
|
||||||
dwYSize u32
|
dw_y_size u32
|
||||||
dwXCountChars u32
|
dw_x_count_chars u32
|
||||||
dwYCountChars u32
|
dw_y_count_chars u32
|
||||||
dwFillAttribute u32
|
dw_fill_attributes u32
|
||||||
dwFlags u32
|
dw_flags u32
|
||||||
wShowWindow u16
|
w_show_window u16
|
||||||
cbReserved2 u16
|
cb_reserved2 u16
|
||||||
lpReserved2 byteptr
|
lp_reserved2 byteptr
|
||||||
hStdInput voidptr
|
h_std_input voidptr
|
||||||
hStdOutput voidptr
|
h_std_output voidptr
|
||||||
hStdError voidptr
|
h_std_error voidptr
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SecurityAttributes {
|
struct SecurityAttributes {
|
||||||
mut:
|
mut:
|
||||||
nLength u32
|
n_length u32
|
||||||
lpSecurityDescriptor voidptr
|
lp_security_descriptor voidptr
|
||||||
bInheritHandle bool
|
b_inherit_handle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_os_args_wide(argc int, argv &byteptr) []string {
|
fn init_os_args_wide(argc int, argv &byteptr) []string {
|
||||||
@ -102,12 +102,12 @@ pub fn ls(path string) ?[]string {
|
|||||||
// NOTE:TODO: once we have a way to convert utf16 wide character to utf8
|
// NOTE:TODO: once we have a way to convert utf16 wide character to utf8
|
||||||
// we should use FindFirstFileW and FindNextFileW
|
// we should use FindFirstFileW and FindNextFileW
|
||||||
h_find_files := C.FindFirstFile(path_files.to_wide(), voidptr(&find_file_data))
|
h_find_files := C.FindFirstFile(path_files.to_wide(), voidptr(&find_file_data))
|
||||||
first_filename := string_from_wide(&u16(find_file_data.cFileName))
|
first_filename := string_from_wide(&u16(find_file_data.c_file_name))
|
||||||
if first_filename != '.' && first_filename != '..' {
|
if first_filename != '.' && first_filename != '..' {
|
||||||
dir_files << first_filename
|
dir_files << first_filename
|
||||||
}
|
}
|
||||||
for C.FindNextFile(h_find_files, voidptr(&find_file_data)) > 0 {
|
for C.FindNextFile(h_find_files, voidptr(&find_file_data)) > 0 {
|
||||||
filename := string_from_wide(&u16(find_file_data.cFileName))
|
filename := string_from_wide(&u16(find_file_data.c_file_name))
|
||||||
if filename != '.' && filename != '..' {
|
if filename != '.' && filename != '..' {
|
||||||
dir_files << filename.clone()
|
dir_files << filename.clone()
|
||||||
}
|
}
|
||||||
@ -186,12 +186,12 @@ pub fn mkdir(path string) ?bool {
|
|||||||
// get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor.
|
// get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor.
|
||||||
pub fn get_file_handle(path string) HANDLE {
|
pub fn get_file_handle(path string) HANDLE {
|
||||||
mode := 'rb'
|
mode := 'rb'
|
||||||
_fd := C._wfopen(path.to_wide(), mode.to_wide())
|
fd := C._wfopen(path.to_wide(), mode.to_wide())
|
||||||
if _fd == 0 {
|
if fd == 0 {
|
||||||
return HANDLE(INVALID_HANDLE_VALUE)
|
return HANDLE(INVALID_HANDLE_VALUE)
|
||||||
}
|
}
|
||||||
_handle := HANDLE(C._get_osfhandle(C._fileno(_fd))) // CreateFile? - hah, no -_-
|
handle := HANDLE(C._get_osfhandle(C._fileno(fd))) // CreateFile? - hah, no -_-
|
||||||
return _handle
|
return handle
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ref - https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea
|
// Ref - https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea
|
||||||
@ -205,8 +205,7 @@ pub fn get_module_filename(handle HANDLE) ?string {
|
|||||||
status := int(C.GetModuleFileNameW(handle, voidptr(&buf), sz))
|
status := int(C.GetModuleFileNameW(handle, voidptr(&buf), sz))
|
||||||
match status {
|
match status {
|
||||||
success {
|
success {
|
||||||
_filename := string_from_wide2(buf, sz)
|
return string_from_wide2(buf, sz)
|
||||||
return _filename
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Must handled with GetLastError and converted by FormatMessage
|
// Must handled with GetLastError and converted by FormatMessage
|
||||||
@ -261,11 +260,11 @@ pub fn get_error_msg(code int) string {
|
|||||||
if code < 0 { // skip negative
|
if code < 0 { // skip negative
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
_ptr_text := ptr_win_get_error_msg(u32(code))
|
ptr_text := ptr_win_get_error_msg(u32(code))
|
||||||
if _ptr_text == 0 { // compare with null
|
if ptr_text == 0 { // compare with null
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
return string_from_wide(_ptr_text)
|
return string_from_wide(ptr_text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// exec starts the specified command, waits for it to complete, and returns its output.
|
// exec starts the specified command, waits for it to complete, and returns its output.
|
||||||
@ -277,8 +276,8 @@ pub fn exec(cmd string) ?Result {
|
|||||||
mut child_stdout_read := &u32(0)
|
mut child_stdout_read := &u32(0)
|
||||||
mut child_stdout_write := &u32(0)
|
mut child_stdout_write := &u32(0)
|
||||||
mut sa := SecurityAttributes {}
|
mut sa := SecurityAttributes {}
|
||||||
sa.nLength = sizeof(C.SECURITY_ATTRIBUTES)
|
sa.n_length = sizeof(C.SECURITY_ATTRIBUTES)
|
||||||
sa.bInheritHandle = true
|
sa.b_inherit_handle = true
|
||||||
|
|
||||||
create_pipe_ok := C.CreatePipe(voidptr(&child_stdout_read),
|
create_pipe_ok := C.CreatePipe(voidptr(&child_stdout_read),
|
||||||
voidptr(&child_stdout_write), voidptr(&sa), 0)
|
voidptr(&child_stdout_write), voidptr(&sa), 0)
|
||||||
@ -294,14 +293,14 @@ pub fn exec(cmd string) ?Result {
|
|||||||
|
|
||||||
proc_info := ProcessInformation{}
|
proc_info := ProcessInformation{}
|
||||||
start_info := StartupInfo{
|
start_info := StartupInfo{
|
||||||
lpReserved: 0
|
lp_reserved: 0
|
||||||
lpDesktop: 0
|
lp_desktop: 0
|
||||||
lpTitle: 0
|
lp_title: 0
|
||||||
cb: sizeof(C.PROCESS_INFORMATION)
|
cb: sizeof(C.PROCESS_INFORMATION)
|
||||||
hStdInput: child_stdin
|
h_std_input: child_stdin
|
||||||
hStdOutput: child_stdout_write
|
h_std_output: child_stdout_write
|
||||||
hStdError: child_stdout_write
|
h_std_error: child_stdout_write
|
||||||
dwFlags: u32(C.STARTF_USESTDHANDLES)
|
dw_flags: u32(C.STARTF_USESTDHANDLES)
|
||||||
}
|
}
|
||||||
command_line := [32768]u16
|
command_line := [32768]u16
|
||||||
C.ExpandEnvironmentStringsW(cmd.to_wide(), voidptr(&command_line), 32768)
|
C.ExpandEnvironmentStringsW(cmd.to_wide(), voidptr(&command_line), 32768)
|
||||||
@ -325,10 +324,10 @@ pub fn exec(cmd string) ?Result {
|
|||||||
soutput := read_data.str().trim_space()
|
soutput := read_data.str().trim_space()
|
||||||
read_data.free()
|
read_data.free()
|
||||||
exit_code := u32(0)
|
exit_code := u32(0)
|
||||||
C.WaitForSingleObject(proc_info.hProcess, C.INFINITE)
|
C.WaitForSingleObject(proc_info.h_process, C.INFINITE)
|
||||||
C.GetExitCodeProcess(proc_info.hProcess, voidptr(&exit_code))
|
C.GetExitCodeProcess(proc_info.h_process, voidptr(&exit_code))
|
||||||
C.CloseHandle(proc_info.hProcess)
|
C.CloseHandle(proc_info.h_process)
|
||||||
C.CloseHandle(proc_info.hThread)
|
C.CloseHandle(proc_info.h_thread)
|
||||||
return Result {
|
return Result {
|
||||||
output: soutput
|
output: soutput
|
||||||
exit_code: int(exit_code)
|
exit_code: int(exit_code)
|
||||||
|
@ -151,15 +151,13 @@ fn process_in_thread(pool mut PoolProcessor, task_id int) {
|
|||||||
// return *(&T(pool.items[idx]))
|
// return *(&T(pool.items[idx]))
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// TODO: the below is a hack, remove it when v2 &string() casting works again
|
|
||||||
type mystring string
|
|
||||||
// get_string_item - called by the worker callback.
|
// get_string_item - called by the worker callback.
|
||||||
// It does not use generics so it does not mess up vfmt.
|
// It does not use generics so it does not mess up vfmt.
|
||||||
// TODO: remove the need for this when vfmt becomes smarter.
|
// TODO: remove the need for this when vfmt becomes smarter.
|
||||||
pub fn (pool &PoolProcessor) get_string_item(idx int) string {
|
pub fn (pool &PoolProcessor) get_string_item(idx int) string {
|
||||||
// return *(&string(pool.items[idx]))
|
// return *(&string(pool.items[idx]))
|
||||||
// TODO: the below is a hack, remove it when v2 casting works again
|
// TODO: the below is a hack, remove it when v2 casting works again
|
||||||
return &mystring( pool.items[idx] )
|
return &string( pool.items[idx] )
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_int_item - called by the worker callback.
|
// get_int_item - called by the worker callback.
|
||||||
|
@ -8,18 +8,18 @@ struct Coord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct SmallRect {
|
struct SmallRect {
|
||||||
Left i16
|
left i16
|
||||||
Top i16
|
top i16
|
||||||
Right i16
|
right i16
|
||||||
Bottom i16
|
bottom i16
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConsoleScreenBufferInfo {
|
struct ConsoleScreenBufferInfo {
|
||||||
dwSize Coord
|
dw_size Coord
|
||||||
dwCursorPosition Coord
|
dw_cursor_position Coord
|
||||||
wAttributes u16
|
w_attributes u16
|
||||||
srWindow SmallRect
|
sr_window SmallRect
|
||||||
dwMaximumWindowSize Coord
|
dw_maximum_window_size Coord
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.GetConsoleScreenBufferInfo(handle os.HANDLE, info &ConsoleScreenBufferInfo) bool
|
fn C.GetConsoleScreenBufferInfo(handle os.HANDLE, info &ConsoleScreenBufferInfo) bool
|
||||||
@ -28,13 +28,11 @@ fn C.GetConsoleScreenBufferInfo(handle os.HANDLE, info &ConsoleScreenBufferInfo)
|
|||||||
pub fn get_terminal_size() (int, int) {
|
pub fn get_terminal_size() (int, int) {
|
||||||
if is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
if is_atty(1) > 0 && os.getenv('TERM') != 'dumb' {
|
||||||
info := ConsoleScreenBufferInfo{}
|
info := ConsoleScreenBufferInfo{}
|
||||||
|
|
||||||
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) {
|
||||||
columns := int(info.srWindow.Right - info.srWindow.Left + 1)
|
columns := int(info.sr_window.right - info.sr_window.left + 1)
|
||||||
rows := int(info.srWindow.Bottom - info.srWindow.Top + 1)
|
rows := int(info.sr_window.bottom - info.sr_window.top + 1)
|
||||||
return columns, rows
|
return columns, rows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return default_columns_size, default_rows_size
|
return default_columns_size, default_rows_size
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@ pub:
|
|||||||
name string
|
name string
|
||||||
path string
|
path string
|
||||||
expr Expr
|
expr Expr
|
||||||
|
pos token.Position
|
||||||
is_skipped bool // module main can be skipped in single file programs
|
is_skipped bool // module main can be skipped in single file programs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,6 +296,7 @@ pub:
|
|||||||
name string
|
name string
|
||||||
expr Expr
|
expr Expr
|
||||||
has_expr bool
|
has_expr bool
|
||||||
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
typ table.Type
|
typ table.Type
|
||||||
}
|
}
|
||||||
|
@ -175,15 +175,44 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool {
|
|||||||
return has_main_fn
|
return has_main_fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Checker) check_valid_snake_case(name, identifier string, pos token.Position) {
|
||||||
|
if name[0] == `_` {
|
||||||
|
c.error('$identifier `$name` cannot start with `_`', pos)
|
||||||
|
}
|
||||||
|
if util.contains_capital(name) {
|
||||||
|
c.error('$identifier `$name` cannot contain uppercase letters, use snake_case instead',
|
||||||
|
pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stripped_name(name string) string {
|
||||||
|
idx := name.last_index('.') or {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
return name[(idx + 1)..]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut c Checker) check_valid_pascal_case(name, identifier string, pos token.Position) {
|
||||||
|
stripped_name := stripped_name(name)
|
||||||
|
if !stripped_name[0].is_capital() {
|
||||||
|
c.error('$identifier `$name` must begin with capital letter', pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
|
pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
|
||||||
match node {
|
match node {
|
||||||
ast.AliasTypeDecl {
|
ast.AliasTypeDecl {
|
||||||
|
// TODO Replace `c.file.mod.name != 'time'` by `it.is_c` once available
|
||||||
|
if c.file.mod.name != 'time' {
|
||||||
|
c.check_valid_pascal_case(it.name, 'type alias', it.pos)
|
||||||
|
}
|
||||||
typ_sym := c.table.get_type_symbol(it.parent_type)
|
typ_sym := c.table.get_type_symbol(it.parent_type)
|
||||||
if typ_sym.kind == .placeholder {
|
if typ_sym.kind == .placeholder {
|
||||||
c.error("type `$typ_sym.name` doesn't exist", it.pos)
|
c.error("type `$typ_sym.name` doesn't exist", it.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.FnTypeDecl {
|
ast.FnTypeDecl {
|
||||||
|
c.check_valid_pascal_case(it.name, 'fn type', it.pos)
|
||||||
typ_sym := c.table.get_type_symbol(it.typ)
|
typ_sym := c.table.get_type_symbol(it.typ)
|
||||||
fn_typ_info := typ_sym.info as table.FnType
|
fn_typ_info := typ_sym.info as table.FnType
|
||||||
fn_info := fn_typ_info.func
|
fn_info := fn_typ_info.func
|
||||||
@ -199,6 +228,7 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.SumTypeDecl {
|
ast.SumTypeDecl {
|
||||||
|
c.check_valid_pascal_case(it.name, 'sum type', it.pos)
|
||||||
for typ in it.sub_types {
|
for typ in it.sub_types {
|
||||||
typ_sym := c.table.get_type_symbol(typ)
|
typ_sym := c.table.get_type_symbol(typ)
|
||||||
if typ_sym.kind == .placeholder {
|
if typ_sym.kind == .placeholder {
|
||||||
@ -209,8 +239,21 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut c Checker) interface_decl(decl ast.InterfaceDecl) {
|
||||||
|
c.check_valid_pascal_case(decl.name, 'interface name', decl.pos)
|
||||||
|
for method in decl.methods {
|
||||||
|
c.check_valid_snake_case(method.name, 'method name', method.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
||||||
|
if !decl.is_c && !c.is_builtin_mod {
|
||||||
|
c.check_valid_pascal_case(decl.name, 'struct name', decl.pos)
|
||||||
|
}
|
||||||
for i, field in decl.fields {
|
for i, field in decl.fields {
|
||||||
|
if !decl.is_c {
|
||||||
|
c.check_valid_snake_case(field.name, 'field name', field.pos)
|
||||||
|
}
|
||||||
for j in 0 .. i {
|
for j in 0 .. i {
|
||||||
if field.name == decl.fields[j].name {
|
if field.name == decl.fields[j].name {
|
||||||
c.error('field name `$field.name` duplicate', field.pos)
|
c.error('field name `$field.name` duplicate', field.pos)
|
||||||
@ -1094,7 +1137,12 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
|
pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
|
||||||
|
c.check_valid_pascal_case(decl.name, 'enum name', decl.pos)
|
||||||
for i, field in decl.fields {
|
for i, field in decl.fields {
|
||||||
|
if util.contains_capital(field.name) {
|
||||||
|
c.error('field name `$field.name` cannot contain uppercase letters, use snake_case instead',
|
||||||
|
field.pos)
|
||||||
|
}
|
||||||
for j in 0 .. i {
|
for j in 0 .. i {
|
||||||
if field.name == decl.fields[j].name {
|
if field.name == decl.fields[j].name {
|
||||||
c.error('field name `$field.name` duplicate', field.pos)
|
c.error('field name `$field.name` duplicate', field.pos)
|
||||||
@ -1165,13 +1213,8 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
|||||||
val_type := assign_stmt.right_types[i]
|
val_type := assign_stmt.right_types[i]
|
||||||
// check variable name for beginning with capital letter 'Abc'
|
// check variable name for beginning with capital letter 'Abc'
|
||||||
is_decl := assign_stmt.op == .decl_assign
|
is_decl := assign_stmt.op == .decl_assign
|
||||||
if is_decl && util.contains_capital(ident.name) {
|
if is_decl && ident.name != '_' {
|
||||||
c.error('variable names cannot contain uppercase letters, use snake_case instead',
|
c.check_valid_snake_case(ident.name, 'variable name', ident.pos)
|
||||||
ident.pos)
|
|
||||||
} else if is_decl && ident.kind != .blank_ident {
|
|
||||||
if ident.name.starts_with('__') {
|
|
||||||
c.error('variable names cannot start with `__`', ident.pos)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if assign_stmt.op == .decl_assign {
|
if assign_stmt.op == .decl_assign {
|
||||||
c.var_decl_name = ident.name
|
c.var_decl_name = ident.name
|
||||||
@ -1385,6 +1428,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||||||
mut field_names := []string{}
|
mut field_names := []string{}
|
||||||
mut field_order := []int{}
|
mut field_order := []int{}
|
||||||
for i, field in it.fields {
|
for i, field in it.fields {
|
||||||
|
// TODO Check const name once the syntax is decided
|
||||||
if field.name in c.const_names {
|
if field.name in c.const_names {
|
||||||
c.error('field name `$field.name` duplicate', field.pos)
|
c.error('field name `$field.name` duplicate', field.pos)
|
||||||
}
|
}
|
||||||
@ -1433,6 +1477,9 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||||||
c.check_expr_opt_call(it.expr, etype, false)
|
c.check_expr_opt_call(it.expr, etype, false)
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
|
if !it.is_c && !c.is_builtin_mod {
|
||||||
|
c.check_valid_snake_case(it.name, 'function name', it.pos)
|
||||||
|
}
|
||||||
if it.is_method {
|
if it.is_method {
|
||||||
sym := c.table.get_type_symbol(it.receiver.typ)
|
sym := c.table.get_type_symbol(it.receiver.typ)
|
||||||
if sym.kind == .interface_ {
|
if sym.kind == .interface_ {
|
||||||
@ -1523,7 +1570,9 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||||||
c.stmts(it.stmts)
|
c.stmts(it.stmts)
|
||||||
c.in_for_count--
|
c.in_for_count--
|
||||||
}
|
}
|
||||||
// ast.GlobalDecl {}
|
ast.GlobalDecl {
|
||||||
|
c.check_valid_snake_case(it.name, 'global name', it.pos)
|
||||||
|
}
|
||||||
ast.GoStmt {
|
ast.GoStmt {
|
||||||
if !(it.call_expr is ast.CallExpr) {
|
if !(it.call_expr is ast.CallExpr) {
|
||||||
c.error('expression in `go` must be a function call', it.call_expr.position())
|
c.error('expression in `go` must be a function call', it.call_expr.position())
|
||||||
@ -1533,19 +1582,12 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||||||
// ast.HashStmt {}
|
// ast.HashStmt {}
|
||||||
ast.Import {}
|
ast.Import {}
|
||||||
ast.InterfaceDecl {
|
ast.InterfaceDecl {
|
||||||
name := it.name.after('.')
|
c.interface_decl(it)
|
||||||
if !name[0].is_capital() {
|
|
||||||
pos := token.Position{
|
|
||||||
line_nr: it.pos.line_nr
|
|
||||||
pos: it.pos.pos + 'interface'.len
|
|
||||||
len: name.len
|
|
||||||
}
|
|
||||||
c.error('interface name must begin with capital letter', pos)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast.Module {
|
ast.Module {
|
||||||
c.mod = it.name
|
c.mod = it.name
|
||||||
c.is_builtin_mod = it.name == 'builtin'
|
c.is_builtin_mod = it.name == 'builtin'
|
||||||
|
c.check_valid_snake_case(it.name, 'module name', it.pos)
|
||||||
}
|
}
|
||||||
ast.Return {
|
ast.Return {
|
||||||
c.returns = true
|
c.returns = true
|
||||||
@ -1865,7 +1907,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
|||||||
return table.void_type
|
return table.void_type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) concat_expr(concat_expr mut ast.ConcatExpr) table.Type {
|
pub fn (mut c Checker) concat_expr(mut concat_expr ast.ConcatExpr) table.Type {
|
||||||
mut mr_types := []table.Type{}
|
mut mr_types := []table.Type{}
|
||||||
for expr in concat_expr.vals {
|
for expr in concat_expr.vals {
|
||||||
mr_types << c.expr(expr)
|
mr_types << c.expr(expr)
|
||||||
|
@ -6,54 +6,59 @@ fn test_all() {
|
|||||||
vexe := os.getenv('VEXE')
|
vexe := os.getenv('VEXE')
|
||||||
vroot := os.dir(vexe)
|
vroot := os.dir(vexe)
|
||||||
os.chdir(vroot)
|
os.chdir(vroot)
|
||||||
dir := 'vlib/v/checker/tests'
|
classic_dir := 'vlib/v/checker/tests'
|
||||||
|
classic_tests := get_tests_in_dir(classic_dir)
|
||||||
|
global_dir := '$classic_dir/globals'
|
||||||
|
global_tests := get_tests_in_dir(global_dir)
|
||||||
|
// -prod so that warns are errors
|
||||||
|
total_errors += check_path(vexe, classic_dir, '-prod', '.out', classic_tests)
|
||||||
|
total_errors += check_path(vexe, global_dir, '--enable-globals', '.out', global_tests)
|
||||||
|
total_errors += check_path(vexe, classic_dir, '--enable-globals run', '.run.out', ['globals_error.vv'])
|
||||||
|
assert total_errors == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tests_in_dir(dir string) []string {
|
||||||
files := os.ls(dir) or {
|
files := os.ls(dir) or {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
mut tests := files.filter(it.ends_with('.vv'))
|
mut tests := files.filter(it.ends_with('.vv'))
|
||||||
if tests.len == 0 {
|
|
||||||
println('no compiler tests found')
|
|
||||||
assert false
|
|
||||||
}
|
|
||||||
tests.sort()
|
tests.sort()
|
||||||
for test in tests {
|
return tests
|
||||||
// -prod so that warns are errors
|
|
||||||
total_errors += check_path(vexe, dir, test, '-prod', '.out')
|
|
||||||
}
|
|
||||||
total_errors += check_path(vexe, dir, 'globals_error.vv', '--enable-globals run', '.run.out')
|
|
||||||
assert total_errors == 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_path(vexe, dir, test, voptions, result_extension string) int {
|
fn check_path(vexe, dir, voptions, result_extension string, tests []string) int {
|
||||||
path := os.join_path(dir, test).replace('\\', '/')
|
mut nb_fail := 0
|
||||||
program := path.replace('.vv', '.v')
|
for test in tests {
|
||||||
print(program + ' ')
|
path := os.join_path(dir, test).replace('\\', '/')
|
||||||
os.cp(path, program) or {
|
program := path.replace('.vv', '.v')
|
||||||
panic(err)
|
print(program + ' ')
|
||||||
|
os.cp(path, program) or {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
res := os.exec('$vexe $voptions $program') or {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
mut expected := os.read_file(program.replace('.v', '') + result_extension) or {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
expected = clean_line_endings(expected)
|
||||||
|
found := clean_line_endings(res.output)
|
||||||
|
if expected != found {
|
||||||
|
println(term.red('FAIL'))
|
||||||
|
println('============')
|
||||||
|
println('expected:')
|
||||||
|
println(expected)
|
||||||
|
println('============')
|
||||||
|
println('found:')
|
||||||
|
println(found)
|
||||||
|
println('============\n')
|
||||||
|
nb_fail += 1
|
||||||
|
} else {
|
||||||
|
println(term.green('OK'))
|
||||||
|
os.rm(program)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res := os.exec('$vexe $voptions $program') or {
|
return nb_fail
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
mut expected := os.read_file(program.replace('.v', '') + result_extension) or {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
expected = clean_line_endings(expected)
|
|
||||||
found := clean_line_endings(res.output)
|
|
||||||
if expected != found {
|
|
||||||
println(term.red('FAIL'))
|
|
||||||
println('============')
|
|
||||||
println('expected:')
|
|
||||||
println(expected)
|
|
||||||
println('============')
|
|
||||||
println('found:')
|
|
||||||
println(found)
|
|
||||||
println('============\n')
|
|
||||||
return 1
|
|
||||||
} else {
|
|
||||||
println(term.green('OK'))
|
|
||||||
os.rm(program)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_line_endings(s string) string {
|
fn clean_line_endings(s string) string {
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
vlib/v/checker/tests/decl_underscore.v:2:2: error: variable names cannot start with `__`
|
|
||||||
1 | fn main() {
|
|
||||||
2 | __abc := 1
|
|
||||||
| ~~~~~
|
|
||||||
3 | }
|
|
@ -1,3 +0,0 @@
|
|||||||
fn main() {
|
|
||||||
__abc := 1
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
vlib/v/checker/tests/enum_field_name_err.v:2:5: error: field name `Green` must be all lowercase
|
|
||||||
1 | enum Color {
|
|
||||||
2 | Green
|
|
||||||
| ~~~~~
|
|
||||||
3 | yellow
|
|
||||||
4 | }
|
|
@ -1,7 +0,0 @@
|
|||||||
enum Color {
|
|
||||||
Green
|
|
||||||
yellow
|
|
||||||
}
|
|
||||||
fn main(){
|
|
||||||
println('hello')
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
vlib/v/checker/tests/enum_name_err.v:1:6: error: enum name `color` must begin with capital letter
|
|
||||||
1 | enum color {
|
|
||||||
| ~~~~~
|
|
||||||
2 | green
|
|
||||||
3 | yellow
|
|
3
vlib/v/checker/tests/globals/incorrect_name_global.out
Normal file
3
vlib/v/checker/tests/globals/incorrect_name_global.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/globals/incorrect_name_global.v:1:1: error: global name `A` cannot contain uppercase letters, use snake_case instead
|
||||||
|
1 | __global A := 1
|
||||||
|
| ~~~~~~~~~~
|
1
vlib/v/checker/tests/globals/incorrect_name_global.vv
Normal file
1
vlib/v/checker/tests/globals/incorrect_name_global.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
__global A := 1
|
3
vlib/v/checker/tests/incorrect_name_alias_type.out
Normal file
3
vlib/v/checker/tests/incorrect_name_alias_type.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_alias_type.v:1:1: error: type alias `integer` must begin with capital letter
|
||||||
|
1 | type integer = int
|
||||||
|
| ~~~~~~~~~~~~
|
1
vlib/v/checker/tests/incorrect_name_alias_type.vv
Normal file
1
vlib/v/checker/tests/incorrect_name_alias_type.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
type integer = int
|
0
vlib/v/checker/tests/incorrect_name_const.out
Normal file
0
vlib/v/checker/tests/incorrect_name_const.out
Normal file
3
vlib/v/checker/tests/incorrect_name_const.vv
Normal file
3
vlib/v/checker/tests/incorrect_name_const.vv
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const (
|
||||||
|
_my_const = 0
|
||||||
|
)
|
5
vlib/v/checker/tests/incorrect_name_enum.out
Normal file
5
vlib/v/checker/tests/incorrect_name_enum.out
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_enum.v:1:1: error: enum name `color` must begin with capital letter
|
||||||
|
1 | enum color {
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
2 | green
|
||||||
|
3 | yellow
|
@ -2,6 +2,3 @@ enum color {
|
|||||||
green
|
green
|
||||||
yellow
|
yellow
|
||||||
}
|
}
|
||||||
fn main(){
|
|
||||||
println('hello')
|
|
||||||
}
|
|
6
vlib/v/checker/tests/incorrect_name_enum_field.out
Normal file
6
vlib/v/checker/tests/incorrect_name_enum_field.out
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_enum_field.v:2:5: error: field name `Green` cannot contain uppercase letters, use snake_case instead
|
||||||
|
1 | enum Color {
|
||||||
|
2 | Green
|
||||||
|
| ~~~~~
|
||||||
|
3 | red
|
||||||
|
4 | blue
|
5
vlib/v/checker/tests/incorrect_name_enum_field.vv
Normal file
5
vlib/v/checker/tests/incorrect_name_enum_field.vv
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
enum Color {
|
||||||
|
Green
|
||||||
|
red
|
||||||
|
blue
|
||||||
|
}
|
3
vlib/v/checker/tests/incorrect_name_fn_type.out
Normal file
3
vlib/v/checker/tests/incorrect_name_fn_type.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_fn_type.v:1:1: error: fn type `callback` must begin with capital letter
|
||||||
|
1 | type callback = fn ()
|
||||||
|
| ~~~~~~~~~~~~~
|
1
vlib/v/checker/tests/incorrect_name_fn_type.vv
Normal file
1
vlib/v/checker/tests/incorrect_name_fn_type.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
type callback = fn ()
|
3
vlib/v/checker/tests/incorrect_name_function.out
Normal file
3
vlib/v/checker/tests/incorrect_name_function.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_function.v:1:1: error: function name `_my_fn` cannot start with `_`
|
||||||
|
1 | fn _my_fn() {}
|
||||||
|
| ~~~~~~~~~~~
|
1
vlib/v/checker/tests/incorrect_name_function.vv
Normal file
1
vlib/v/checker/tests/incorrect_name_function.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
fn _my_fn() {}
|
3
vlib/v/checker/tests/incorrect_name_interface.out
Normal file
3
vlib/v/checker/tests/incorrect_name_interface.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_interface.v:1:1: error: interface name `_MyInterface` must begin with capital letter
|
||||||
|
1 | interface _MyInterface {}
|
||||||
|
| ~~~~~~~~~
|
1
vlib/v/checker/tests/incorrect_name_interface.vv
Normal file
1
vlib/v/checker/tests/incorrect_name_interface.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
interface _MyInterface {}
|
5
vlib/v/checker/tests/incorrect_name_interface_method.out
Normal file
5
vlib/v/checker/tests/incorrect_name_interface_method.out
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_interface_method.v:2:5: error: method name `_speak` cannot start with `_`
|
||||||
|
1 | interface MyInterface {
|
||||||
|
2 | _speak()
|
||||||
|
| ~~~~~~~~
|
||||||
|
3 | }
|
3
vlib/v/checker/tests/incorrect_name_interface_method.vv
Normal file
3
vlib/v/checker/tests/incorrect_name_interface_method.vv
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
interface MyInterface {
|
||||||
|
_speak()
|
||||||
|
}
|
3
vlib/v/checker/tests/incorrect_name_module.out
Normal file
3
vlib/v/checker/tests/incorrect_name_module.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_module.v:1:1: error: module name `_A` cannot start with `_`
|
||||||
|
1 | module _A
|
||||||
|
| ~~~~~~~~~
|
1
vlib/v/checker/tests/incorrect_name_module.vv
Normal file
1
vlib/v/checker/tests/incorrect_name_module.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
module _A
|
3
vlib/v/checker/tests/incorrect_name_struct.out
Normal file
3
vlib/v/checker/tests/incorrect_name_struct.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_struct.v:1:8: error: struct name `abc` must begin with capital letter
|
||||||
|
1 | struct abc {}
|
||||||
|
| ~~~
|
1
vlib/v/checker/tests/incorrect_name_struct.vv
Normal file
1
vlib/v/checker/tests/incorrect_name_struct.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
struct abc {}
|
5
vlib/v/checker/tests/incorrect_name_struct_field.out
Normal file
5
vlib/v/checker/tests/incorrect_name_struct_field.out
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_struct_field.v:2:5: error: field name `_a` cannot start with `_`
|
||||||
|
1 | struct Abc {
|
||||||
|
2 | _a int
|
||||||
|
| ~~~~~~
|
||||||
|
3 | }
|
3
vlib/v/checker/tests/incorrect_name_struct_field.vv
Normal file
3
vlib/v/checker/tests/incorrect_name_struct_field.vv
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
struct Abc {
|
||||||
|
_a int
|
||||||
|
}
|
3
vlib/v/checker/tests/incorrect_name_sum_type.out
Normal file
3
vlib/v/checker/tests/incorrect_name_sum_type.out
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_sum_type.v:1:1: error: sum type `integer` must begin with capital letter
|
||||||
|
1 | type integer = i8 | i16 | int | i64
|
||||||
|
| ~~~~~~~~~~~~
|
1
vlib/v/checker/tests/incorrect_name_sum_type.vv
Normal file
1
vlib/v/checker/tests/incorrect_name_sum_type.vv
Normal file
@ -0,0 +1 @@
|
|||||||
|
type integer = i8 | i16 | int | i64
|
6
vlib/v/checker/tests/incorrect_name_variable.out
Normal file
6
vlib/v/checker/tests/incorrect_name_variable.out
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
vlib/v/checker/tests/incorrect_name_variable.v:2:2: error: variable name `_abc` cannot start with `_`
|
||||||
|
1 | fn main() {
|
||||||
|
2 | _abc := 1
|
||||||
|
| ~~~~
|
||||||
|
3 | _ := _abc
|
||||||
|
4 | }
|
4
vlib/v/checker/tests/incorrect_name_variable.vv
Normal file
4
vlib/v/checker/tests/incorrect_name_variable.vv
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
fn main() {
|
||||||
|
_abc := 1
|
||||||
|
_ := _abc
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
vlib/v/checker/tests/struct_field_name_duplicate_err.v:3:4: error: field name `a` duplicate
|
vlib/v/checker/tests/struct_field_name_duplicate_err.v:3:2: error: field name `a` duplicate
|
||||||
1 | struct A {
|
1 | struct A {
|
||||||
2 | a int
|
2 | a int
|
||||||
3 | a string
|
3 | a string
|
||||||
| ~~~~~~
|
| ~~~~~~~~
|
||||||
4 | }
|
4 | }
|
||||||
5 | fn main(){}
|
|
@ -2,4 +2,3 @@ struct A {
|
|||||||
a int
|
a int
|
||||||
a string
|
a string
|
||||||
}
|
}
|
||||||
fn main(){}
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
vlib/v/checker/tests/struct_name.v:1:8: error: struct name `abc` must begin with capital letter
|
|
||||||
1 | struct abc {
|
|
||||||
| ~~~
|
|
||||||
2 |
|
|
||||||
3 | }
|
|
@ -1,5 +0,0 @@
|
|||||||
struct abc {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main(){}
|
|
@ -468,7 +468,7 @@ pub fn (mut g Gen) writeln(s string) {
|
|||||||
|
|
||||||
pub fn (mut g Gen) new_tmp_var() string {
|
pub fn (mut g Gen) new_tmp_var() string {
|
||||||
g.tmp_count++
|
g.tmp_count++
|
||||||
return 'tmp$g.tmp_count'
|
return '_t$g.tmp_count'
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) reset_tmp_count() {
|
pub fn (mut g Gen) reset_tmp_count() {
|
||||||
@ -1860,7 +1860,6 @@ fn (mut g Gen) concat_expr(node ast.ConcatExpr) {
|
|||||||
styp := g.typ(node.return_type)
|
styp := g.typ(node.return_type)
|
||||||
sym := g.table.get_type_symbol(node.return_type)
|
sym := g.table.get_type_symbol(node.return_type)
|
||||||
is_multi := sym.kind == .multi_return
|
is_multi := sym.kind == .multi_return
|
||||||
|
|
||||||
if !is_multi {
|
if !is_multi {
|
||||||
g.expr(node.vals[0])
|
g.expr(node.vals[0])
|
||||||
} else {
|
} else {
|
||||||
|
@ -294,10 +294,9 @@ fn (mut p Parser) check_js_name() string {
|
|||||||
p.next() // .name
|
p.next() // .name
|
||||||
p.next() // .dot
|
p.next() // .dot
|
||||||
}
|
}
|
||||||
// last .name
|
// last .name
|
||||||
name += p.tok.lit
|
name += p.tok.lit
|
||||||
p.next()
|
p.next()
|
||||||
|
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,8 +461,8 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
|||||||
}
|
}
|
||||||
} else if p.peek_tok.kind == .name {
|
} else if p.peek_tok.kind == .name {
|
||||||
p.error_with_pos('unexpected name `$p.peek_tok.lit`', p.peek_tok.position())
|
p.error_with_pos('unexpected name `$p.peek_tok.lit`', p.peek_tok.position())
|
||||||
} else if !p.inside_if_expr && !p.inside_match_body &&
|
} else if !p.inside_if_expr && !p.inside_match_body && !p.inside_or_expr && p.peek_tok.kind in
|
||||||
!p.inside_or_expr && p.peek_tok.kind in [.rcbr, .eof] {
|
[.rcbr, .eof] {
|
||||||
p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position())
|
p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position())
|
||||||
}
|
}
|
||||||
epos := p.tok.position()
|
epos := p.tok.position()
|
||||||
@ -528,7 +527,8 @@ pub fn (mut p Parser) stmt() ast.Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.key_const {
|
.key_const {
|
||||||
p.error_with_pos('const can only be defined at the top level (outside of functions)', p.tok.position())
|
p.error_with_pos('const can only be defined at the top level (outside of functions)',
|
||||||
|
p.tok.position())
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return p.parse_comma_separated()
|
return p.parse_comma_separated()
|
||||||
@ -680,7 +680,7 @@ fn (mut p Parser) parse_comma_separated() ast.Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ast.ExprStmt{
|
return ast.ExprStmt{
|
||||||
expr: ast.ConcatExpr {
|
expr: ast.ConcatExpr{
|
||||||
vals: collected
|
vals: collected
|
||||||
}
|
}
|
||||||
pos: p.tok.position()
|
pos: p.tok.position()
|
||||||
@ -706,7 +706,7 @@ pub fn (mut p Parser) parse_ident(is_c, is_js bool) ast.Ident {
|
|||||||
name: '_'
|
name: '_'
|
||||||
kind: .blank_ident
|
kind: .blank_ident
|
||||||
pos: pos
|
pos: pos
|
||||||
info: ast.IdentVar {
|
info: ast.IdentVar{
|
||||||
is_mut: false
|
is_mut: false
|
||||||
is_static: false
|
is_static: false
|
||||||
}
|
}
|
||||||
@ -862,7 +862,7 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
|||||||
} else if p.peek_tok.kind == .colon && p.prev_tok.kind != .str_dollar {
|
} else if p.peek_tok.kind == .colon && p.prev_tok.kind != .str_dollar {
|
||||||
// `foo(key:val, key2:val2)`
|
// `foo(key:val, key2:val2)`
|
||||||
return p.struct_init(true) // short_syntax:true
|
return p.struct_init(true) // short_syntax:true
|
||||||
// JS. function call with more than 1 dot
|
// JS. function call with more than 1 dot
|
||||||
} else if is_js && p.peek_tok.kind == .dot && p.peek_tok2.kind == .name {
|
} else if is_js && p.peek_tok.kind == .dot && p.peek_tok2.kind == .name {
|
||||||
node = p.call_expr(is_c, is_js, mod)
|
node = p.call_expr(is_c, is_js, mod)
|
||||||
} else {
|
} else {
|
||||||
@ -1105,8 +1105,9 @@ fn (mut p Parser) parse_number_literal() ast.Expr {
|
|||||||
fn (mut p Parser) module_decl() ast.Module {
|
fn (mut p Parser) module_decl() ast.Module {
|
||||||
mut name := 'main'
|
mut name := 'main'
|
||||||
is_skipped := p.tok.kind != .key_module
|
is_skipped := p.tok.kind != .key_module
|
||||||
|
mut module_pos := token.Position{}
|
||||||
if !is_skipped {
|
if !is_skipped {
|
||||||
module_pos := p.tok.position()
|
module_pos = p.tok.position()
|
||||||
p.next()
|
p.next()
|
||||||
mut pos := p.tok.position()
|
mut pos := p.tok.position()
|
||||||
name = p.check_name()
|
name = p.check_name()
|
||||||
@ -1121,6 +1122,7 @@ fn (mut p Parser) module_decl() ast.Module {
|
|||||||
p.error_with_pos('`module x` can only declare one module', pos)
|
p.error_with_pos('`module x` can only declare one module', pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
module_pos = module_pos.extend(pos)
|
||||||
}
|
}
|
||||||
full_mod := p.table.qualify_module(name, p.file_name)
|
full_mod := p.table.qualify_module(name, p.file_name)
|
||||||
p.mod = full_mod
|
p.mod = full_mod
|
||||||
@ -1128,6 +1130,7 @@ fn (mut p Parser) module_decl() ast.Module {
|
|||||||
return ast.Module{
|
return ast.Module{
|
||||||
name: full_mod
|
name: full_mod
|
||||||
is_skipped: is_skipped
|
is_skipped: is_skipped
|
||||||
|
pos: module_pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1252,7 +1255,9 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
|||||||
p.mod != 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
|
p.mod != 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
|
||||||
p.error('use `v --enable-globals ...` to enable globals')
|
p.error('use `v --enable-globals ...` to enable globals')
|
||||||
}
|
}
|
||||||
|
start_pos := p.tok.position()
|
||||||
p.next()
|
p.next()
|
||||||
|
pos := start_pos.extend(p.tok.position())
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
// println(name)
|
// println(name)
|
||||||
typ := p.parse_type()
|
typ := p.parse_type()
|
||||||
@ -1280,6 +1285,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
|||||||
glob := ast.GlobalDecl{
|
glob := ast.GlobalDecl{
|
||||||
name: name
|
name: name
|
||||||
typ: typ
|
typ: typ
|
||||||
|
pos: pos
|
||||||
has_expr: has_expr
|
has_expr: has_expr
|
||||||
expr: expr
|
expr: expr
|
||||||
}
|
}
|
||||||
@ -1296,9 +1302,6 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
|||||||
p.check(.key_enum)
|
p.check(.key_enum)
|
||||||
end_pos := p.tok.position()
|
end_pos := p.tok.position()
|
||||||
enum_name := p.check_name()
|
enum_name := p.check_name()
|
||||||
if enum_name.len > 0 && !enum_name[0].is_capital() {
|
|
||||||
p.error_with_pos('enum name `$enum_name` must begin with capital letter', end_pos)
|
|
||||||
}
|
|
||||||
name := p.prepend_mod(enum_name)
|
name := p.prepend_mod(enum_name)
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
mut vals := []string{}
|
mut vals := []string{}
|
||||||
@ -1307,9 +1310,6 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
|||||||
for p.tok.kind != .eof && p.tok.kind != .rcbr {
|
for p.tok.kind != .eof && p.tok.kind != .rcbr {
|
||||||
pos := p.tok.position()
|
pos := p.tok.position()
|
||||||
val := p.check_name()
|
val := p.check_name()
|
||||||
if !val.is_lower() {
|
|
||||||
p.error_with_pos('field name `$val` must be all lowercase', pos)
|
|
||||||
}
|
|
||||||
vals << val
|
vals << val
|
||||||
mut expr := ast.Expr{}
|
mut expr := ast.Expr{}
|
||||||
mut has_expr := false
|
mut has_expr := false
|
||||||
|
@ -95,8 +95,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||||||
is_field_mut = true
|
is_field_mut = true
|
||||||
is_field_global = true
|
is_field_global = true
|
||||||
}
|
}
|
||||||
|
field_start_pos := p.tok.position()
|
||||||
field_name := p.check_name()
|
field_name := p.check_name()
|
||||||
field_pos := p.tok.position()
|
field_pos := field_start_pos.extend(p.tok.position())
|
||||||
// p.warn('field $field_name')
|
// p.warn('field $field_name')
|
||||||
typ := p.parse_type()
|
typ := p.parse_type()
|
||||||
/*
|
/*
|
||||||
@ -288,6 +289,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
|||||||
// Parse methods
|
// Parse methods
|
||||||
mut methods := []ast.FnDecl{}
|
mut methods := []ast.FnDecl{}
|
||||||
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
for p.tok.kind != .rcbr && p.tok.kind != .eof {
|
||||||
|
method_start_pos := p.tok.position()
|
||||||
line_nr := p.tok.line_nr
|
line_nr := p.tok.line_nr
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
if util.contains_capital(name) {
|
if util.contains_capital(name) {
|
||||||
@ -307,6 +309,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
|||||||
file: p.file_name
|
file: p.file_name
|
||||||
return_type: table.void_type
|
return_type: table.void_type
|
||||||
is_pub: true
|
is_pub: true
|
||||||
|
pos: method_start_pos.extend(p.prev_tok.position())
|
||||||
}
|
}
|
||||||
if p.tok.kind.is_start_of_type() && p.tok.line_nr == line_nr {
|
if p.tok.kind.is_start_of_type() && p.tok.line_nr == line_nr {
|
||||||
method.return_type = p.parse_type()
|
method.return_type = p.parse_type()
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
// 1 line comment
|
// 1 line comment // 1 line comment
|
||||||
|
|
||||||
/* 1 line comment */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
multi line comment (1)
|
multi line comment (1)
|
||||||
multi line comment (2)
|
multi line comment (2)
|
||||||
multi line comment (3)
|
multi line comment (3)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
multi line comment (1)
|
multi line comment (1)
|
||||||
/*
|
/*
|
||||||
nested comment
|
nested comment
|
||||||
*/
|
*/
|
||||||
@ -20,44 +16,43 @@ multi line comment (3)
|
|||||||
/* /* nested comment */ */
|
/* /* nested comment */ */
|
||||||
multi line comment (2)
|
multi line comment (2)
|
||||||
*/
|
*/
|
||||||
|
type MyFn1 = fn (int) string
|
||||||
|
|
||||||
type myfn fn (int) string
|
type MyFn2 = fn (a int, b int) int
|
||||||
|
|
||||||
type myfn2 fn (a int, b int) int
|
type MyFn3 = fn (int, int)
|
||||||
|
|
||||||
type myfn3 fn (int, int)
|
|
||||||
|
|
||||||
fn myfn4(string)
|
fn myfn4(string)
|
||||||
|
|
||||||
fn foobar()
|
fn foobar()
|
||||||
|
|
||||||
fn slopediv(num u32, den u32) int
|
fn slopediv(num, den u32) int
|
||||||
|
|
||||||
type f1 fn ()
|
type F1 = fn ()
|
||||||
|
|
||||||
type f2 fn (voidptr)
|
type F2 = fn (voidptr)
|
||||||
|
|
||||||
type f3 fn (voidptr, voidptr)
|
type F3 = fn (voidptr, voidptr)
|
||||||
|
|
||||||
type f4 fn (voidptr) int
|
type F4 = fn (voidptr) int
|
||||||
|
|
||||||
type f5 fn (int, int) int
|
type F5 = fn (int, int) int
|
||||||
|
|
||||||
type f6 fn (int, int)
|
type F6 = fn (int, int)
|
||||||
|
|
||||||
fn C.atoi(byteptr) int
|
fn C.atoi(byteptr) int
|
||||||
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type actionf_v fn ()
|
type ActionfV = fn ()
|
||||||
|
|
||||||
type actionf_p1 fn (voidptr)
|
type ActionfP1 = fn (voidptr)
|
||||||
|
|
||||||
type actionf_p2 fn (voidptr, voidptr)
|
type ActionfP2 = fn (voidptr, voidptr)
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn modify_array(a mut []int) {
|
fn modify_array(mut a []int) {
|
||||||
a[0] = 10
|
a[0] = 10
|
||||||
for i in 0 .. a.len {
|
for i in 0 .. a.len {
|
||||||
a[i] = a[i] * 2
|
a[i] = a[i] * 2
|
||||||
@ -86,7 +81,7 @@ fn test_mut_array() {
|
|||||||
println(nums.clone())
|
println(nums.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mod_struct(user mut User) {
|
fn mod_struct(mut user User) {
|
||||||
user.age++
|
user.age++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +96,7 @@ fn test_mut_struct() {
|
|||||||
assert user.age == 19
|
assert user.age == 19
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mod_ptr(buf mut byteptr) {
|
fn mod_ptr(mut buf byteptr) {
|
||||||
buf[0] = 77
|
buf[0] = 77
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +106,6 @@ fn test_mut_ptr() {
|
|||||||
assert buf[0] == 77
|
assert buf[0] == 77
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn assert_in_bool_fn(v int) bool {
|
fn assert_in_bool_fn(v int) bool {
|
||||||
assert v < 3
|
assert v < 3
|
||||||
return true
|
return true
|
||||||
@ -121,7 +115,8 @@ fn test_assert_in_bool_fn() {
|
|||||||
assert_in_bool_fn(2)
|
assert_in_bool_fn(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MyFn fn (int) int
|
type MyFn = fn (int) int
|
||||||
|
|
||||||
fn test(n int) int {
|
fn test(n int) int {
|
||||||
return n + 1000
|
return n + 1000
|
||||||
}
|
}
|
||||||
@ -129,18 +124,21 @@ fn test(n int) int {
|
|||||||
struct MySt {
|
struct MySt {
|
||||||
f MyFn
|
f MyFn
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_fn_type_call() {
|
fn test_fn_type_call() {
|
||||||
mut arr := []MyFn{}
|
mut arr := []MyFn{}
|
||||||
arr << MyFn(test)
|
arr << MyFn(test)
|
||||||
// TODO: `arr[0](10)`
|
// TODO: `arr[0](10)`
|
||||||
// assert arr[0](10) == 1010
|
// assert arr[0](10) == 1010
|
||||||
x1 := arr[0]
|
x1 := arr[0]
|
||||||
x2 := x1(10)
|
x2 := x1(10)
|
||||||
assert x2 == 1010
|
assert x2 == 1010
|
||||||
|
st := MySt{
|
||||||
st := MySt{f:test}
|
f: test
|
||||||
assert st.f(10) == 1010
|
}
|
||||||
|
assert st.f(10) == 1010
|
||||||
st1 := &MySt{f:test}
|
st1 := &MySt{
|
||||||
assert st1.f(10) == 1010
|
f: test
|
||||||
|
}
|
||||||
|
assert st1.f(10) == 1010
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user