1
0
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:
Enzo Baldisserri 2020-05-16 16:12:23 +02:00 committed by GitHub
parent 3bd88a3cc2
commit f44a40eee0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 636 additions and 597 deletions

View File

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

View File

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

View File

@ -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 + '!'
}
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +0,0 @@
fn main() {
__abc := 1
}

View File

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

View File

@ -1,7 +0,0 @@
enum Color {
Green
yellow
}
fn main(){
println('hello')
}

View File

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

View 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
| ~~~~~~~~~~

View File

@ -0,0 +1 @@
__global A := 1

View 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
| ~~~~~~~~~~~~

View File

@ -0,0 +1 @@
type integer = int

View File

@ -0,0 +1,3 @@
const (
_my_const = 0
)

View 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

View File

@ -2,6 +2,3 @@ enum color {
green green
yellow yellow
} }
fn main(){
println('hello')
}

View 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

View File

@ -0,0 +1,5 @@
enum Color {
Green
red
blue
}

View 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 ()
| ~~~~~~~~~~~~~

View File

@ -0,0 +1 @@
type callback = fn ()

View 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() {}
| ~~~~~~~~~~~

View File

@ -0,0 +1 @@
fn _my_fn() {}

View 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 {}
| ~~~~~~~~~

View File

@ -0,0 +1 @@
interface _MyInterface {}

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

View File

@ -0,0 +1,3 @@
interface MyInterface {
_speak()
}

View 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
| ~~~~~~~~~

View File

@ -0,0 +1 @@
module _A

View 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 {}
| ~~~

View File

@ -0,0 +1 @@
struct abc {}

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

View File

@ -0,0 +1,3 @@
struct Abc {
_a int
}

View 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
| ~~~~~~~~~~~~

View File

@ -0,0 +1 @@
type integer = i8 | i16 | int | i64

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

View File

@ -0,0 +1,4 @@
fn main() {
_abc := 1
_ := _abc
}

View File

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

View File

@ -2,4 +2,3 @@ struct A {
a int a int
a string a string
} }
fn main(){}

View File

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

View File

@ -1,5 +0,0 @@
struct abc {
}
fn main(){}

View File

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

View File

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

View File

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

View File

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