diff --git a/0.3_roadmap.txt b/0.3_roadmap.txt index 28d8b58e4d..aaf72e5b68 100644 --- a/0.3_roadmap.txt +++ b/0.3_roadmap.txt @@ -17,4 +17,5 @@ - struct and interface embedding - vfmt: fix common errors automatically to save time (make vars mutable and vice versa, add missing imports etc) - method expressions with an explicit receiver as the first argument +- fix all remaining generics issues (`foo(5)` instead of `foo(5)` etc) diff --git a/examples/hot_reload/bounce.v b/examples/hot_reload/bounce.v index 98e2202fc2..b806b99c85 100644 --- a/examples/hot_reload/bounce.v +++ b/examples/hot_reload/bounce.v @@ -43,6 +43,7 @@ fn main() { create_window: true frame_fn: frame bg_color: gx.white + font_path: gg.system_font_path() }) // window.onkeydown(key_down) println('Starting the game loop...') @@ -56,6 +57,7 @@ fn main() { [live] fn frame (mut game Game) { game.gg.begin() + game.gg.draw_text_def(10, 5, 'Modify examples/hot_reload/bounce.v to get instant updates') game.gg.draw_rect(game.x, game.y, width, width, gx.blue) game.gg.draw_rect(window_width - width - game.x + 10, 200 - game.y + width, width, width, gx.rgb(228, 10, 55)) game.gg.draw_rect(game.x - 25, 250 - game.y, width, width, gx.rgb(28, 240, 55)) diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index c26e0a0c06..777fd9e766 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -607,6 +607,15 @@ pub fn (a []byte) index(v byte) int { return -1 } +pub fn (a []rune) index(v rune) int { + for i in 0..a.len { + if a[i] == v { + return i + } + } + return -1 +} + // []char.index returns the index of the first element equal to the given value, // or -1 if the value is not found in the array. // TODO is `char` type yet in the language? diff --git a/vlib/builtin/byte_test.v b/vlib/builtin/byte_test.v index 27357a44de..e108f2fba2 100644 --- a/vlib/builtin/byte_test.v +++ b/vlib/builtin/byte_test.v @@ -1,8 +1,19 @@ fn test_clone() { - a := [byte(0), 1, 2] + a := [byte(0), 1, 2] b := a.clone() assert b.len == 3 - assert b[0] == 0 - assert b[1] == 1 - assert b[2] == 2 -} + assert b[0] == 0 + assert b[1] == 1 + assert b[2] == 2 + println(b[1].str() ) + println(typeof(`A`)) + x := rune(`A`) + assert x.str() == 'A' + assert typeof(x) == 'rune' + // + y := `Z` + assert typeof(y) == 'rune' + assert y.str() == 'Z' + // assert b[1].str() == '1' TODO + +} diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 2f87762814..2d717f41f1 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -368,80 +368,21 @@ pub fn (nn byteptr) str() string { return u64(nn).hex() } -// ----- utilities functions ----- - -/* -pub fn (c rune) str() string { - fst_byte := int(c)>>8 * 3 & 0xff - len := utf8_char_len(fst_byte) - mut str := string{ - len: len - str: malloc(len + 1) - } - for i in 0..len { - str.str[i] = int(c)>>8 * (3 - i) & 0xff - } - str.str[len] = `\0` - return str -} -*/ - -pub fn (c byte) str() string { +pub fn (b byte) str() string { + // TODO + //return int(b).str_l(7) mut str := string{ str: malloc(2) len: 1 } unsafe { - str.str[0] = c + str.str[0] = b str.str[1] = `\0` } + //println(str) return str } -/* -type rune = int - -pub fn (r rune) str() string { - mut str := string{ - str: malloc(2) - len: 1 - } - unsafe { - str.str[0] = r - str.str[1] = `\0` - } - - return str -} -*/ - -pub fn (c byte) is_capital() bool { - return c >= `A` && c <= `Z` -} - -pub fn (b []byte) clone() []byte { - mut res := []byte{len: b.len} - //mut res := make([]byte, {repeat:b.len}) - for i in 0..b.len { - res[i] = b[i] - } - return res -} - -// TODO remove this once runes are implemented -pub fn (b []byte) bytestr() string { - return bytes2string(b) -} - -// TODO copy pasted from builder.v -fn bytes2string(b []byte) string { - mut copy := b.clone() - copy << `\0` - res := tos(copy.data, copy.len-1) - return res -} - - // TODO generic pub fn (a []byte) contains(val byte) bool { for aa in a { diff --git a/vlib/builtin/rune.v b/vlib/builtin/rune.v new file mode 100644 index 0000000000..a3272b232b --- /dev/null +++ b/vlib/builtin/rune.v @@ -0,0 +1,54 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. +module builtin + +type rune = int + +pub fn (c rune) str() string { + return utf32_to_str(u32(c)) + /* + unsafe { + fst_byte := int(c)>>8 * 3 & 0xff + len := utf8_char_len(byte(fst_byte)) + println('len=$len') + mut str := string{ + len: len + str: malloc(len + 1) + } + for i in 0..len { + str.str[i] = byte(int(c)>>8 * (3 - i) & 0xff) + } + str.str[len] = `\0` + println(str) + return str + } + */ +} + +// Define this on byte as well, so that we can do `s[0].is_capital()` +pub fn (c byte) is_capital() bool { + return c >= `A` && c <= `Z` +} + +pub fn (b []byte) clone() []byte { + mut res := []byte{len: b.len} + //mut res := make([]byte, {repeat:b.len}) + for i in 0..b.len { + res[i] = b[i] + } + return res +} + +// TODO remove this once runes are implemented +pub fn (b []byte) bytestr() string { + return bytes2string(b) +} + +// TODO copy pasted from builder.v +fn bytes2string(b []byte) string { + mut copy := b.clone() + copy << `\0` + res := tos(copy.data, copy.len-1) + return res +} + diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index 552a689b80..fcdd26aaa8 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -504,7 +504,7 @@ fn test_bytes_to_string() { } assert unsafe { buf.vstring() } == 'hello' assert unsafe { buf.vstring_with_len(2) } == 'he' - bytes := [`h`, `e`, `l`, `l`, `o`] + bytes := [byte(`h`), `e`, `l`, `l`, `o`] assert bytes.bytestr() == 'hello' } diff --git a/vlib/gg/text_rendering.v b/vlib/gg/text_rendering.v index 873d6ad47a..ca97aa16ea 100644 --- a/vlib/gg/text_rendering.v +++ b/vlib/gg/text_rendering.v @@ -163,3 +163,31 @@ pub fn (ctx &Context) text_size(s string) (int, int) { return int((buf[2] - buf[0]) / ctx.scale), int((buf[3] - buf[1]) / ctx.scale) } + +pub fn system_font_path() string { + env_font := os.getenv('VUI_FONT') + if env_font != '' && os.exists(env_font) { + return env_font + } + $if windows { + return 'C:\\Windows\\Fonts\\arial.ttf' + } + mut fonts := ['Ubuntu-R.ttf', 'Arial.ttf', 'LiberationSans-Regular.ttf', 'NotoSans-Regular.ttf', + 'FreeSans.ttf', 'DejaVuSans.ttf'] + $if macos { + return '/System/Library/Fonts/SFNS.ttf' + //fonts = ['SFNS.ttf', 'SFNSText.ttf'] + } + s := os.exec('fc-list') or { panic('failed to fetch system fonts') } + system_fonts := s.output.split('\n') + for line in system_fonts { + for font in fonts { + if line.contains(font) && line.contains(':') { + res := line.all_before(':') + println('Using font $res') + return res + } + } + } + panic('failed to init the font') +} diff --git a/vlib/os/file.v b/vlib/os/file.v index f6eaee91d3..28a5d23d52 100644 --- a/vlib/os/file.v +++ b/vlib/os/file.v @@ -72,7 +72,8 @@ pub fn (f &File) read_bytes(size int) []byte { // read_bytes_at reads an amount of bytes at the given position in the file pub fn (f &File) read_bytes_at(size, pos int) []byte { - mut arr := [`0`].repeat(size) + //mut arr := [`0`].repeat(size) + mut arr := []byte{ len:size } C.fseek(f.cfile, pos, C.SEEK_SET) nreadbytes := C.fread(arr.data, 1, size, f.cfile) C.fseek(f.cfile, 0, C.SEEK_SET) diff --git a/vlib/os/os.v b/vlib/os/os.v index 48fadc32e7..4dcb94cfc9 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -16,7 +16,7 @@ pub fn read_bytes(path string) ?[]byte { C.fseek(fp, 0, C.SEEK_END) fsize := C.ftell(fp) C.rewind(fp) - mut res := [`0`].repeat(fsize) + mut res := [byte(`0`)].repeat(fsize) nr_read_elements := C.fread(res.data, fsize, 1, fp) C.fclose(fp) return res[0..nr_read_elements * fsize] diff --git a/vlib/regex/regex.v b/vlib/regex/regex.v index bc5e886dd7..c8afb7f388 100644 --- a/vlib/regex/regex.v +++ b/vlib/regex/regex.v @@ -207,7 +207,7 @@ pub fn (re RE) get_parse_error_string(err int) string { // utf8_str convert and utf8 sequence to a printable string [inline] -fn utf8_str(ch u32) string { +fn utf8_str(ch rune) string { mut i := 4 mut res := "" for i > 0 { @@ -233,33 +233,33 @@ fn simple_log(txt string) { pub type FnValidator fn (byte) bool struct Token{ mut: - ist u32 = u32(0) + ist rune // char - ch u32 = u32(0) // char of the token if any - ch_len byte = byte(0) // char len + ch rune // char of the token if any + ch_len byte // char len // Quantifiers / branch - rep_min int = 0 // used also for jump next in the OR branch [no match] pc jump - rep_max int = 0 // used also for jump next in the OR branch [ match] pc jump - greedy bool = false // greedy quantifier flag + rep_min int // used also for jump next in the OR branch [no match] pc jump + rep_max int // used also for jump next in the OR branch [ match] pc jump + greedy bool // greedy quantifier flag // Char class cc_index int = -1 // counters for quantifier check (repetitions) - rep int = 0 + rep int // validator function pointer validator FnValidator // groups variables - group_rep int = 0 // repetition of the group + group_rep int // repetition of the group group_id int = -1 // id of the group goto_pc int = -1 // jump to this PC if is needed // OR flag for the token - next_is_or bool = false // true if the next token is an OR + next_is_or bool // true if the next token is an OR } [inline] @@ -380,7 +380,7 @@ Backslashes chars */ struct BslsStruct { - ch u32 // meta char + ch rune // meta char validator FnValidator // validator function pointer } @@ -466,8 +466,8 @@ const( struct CharClass { mut: cc_type int = cc_null // type of cc token - ch0 u32 = u32(0) // first char of the interval a-b a in this case - ch1 u32 = u32(0) // second char of the interval a-b b in this case + ch0 rune // first char of the interval a-b a in this case + ch1 rune // second char of the interval a-b b in this case validator FnValidator // validator function pointer } @@ -540,7 +540,7 @@ fn (re RE) get_char_class(pc int) string { return tos_clone( buf_ptr ) } -fn (re RE) check_char_class(pc int, ch u32) bool { +fn (re RE) check_char_class(pc int, ch rune) bool { mut cc_i := re.prog[pc].cc_index for cc_i >= 0 && cc_i < re.cc.len && re.cc[cc_i].cc_type != cc_end { if re.cc[cc_i].cc_type == cc_bsls { @@ -557,7 +557,7 @@ fn (re RE) check_char_class(pc int, ch u32) bool { } // parse_char_class return (index, str_len, cc_type) of a char class [abcm-p], char class start after the [ char -fn (mut re RE) parse_char_class(in_txt string, in_i int) (int, int, u32) { +fn (mut re RE) parse_char_class(in_txt string, in_i int) (int, int, rune) { mut status := CharClass_parse_state.start mut i := in_i @@ -915,7 +915,7 @@ fn (re RE) parse_groups(in_txt string, in_i int) (int, bool, string, int) { [deprecated] pub fn (mut re RE) compile(in_txt string) (int,int) { return re.impl_compile(in_txt) -} +} fn (mut re RE) impl_compile(in_txt string) (int,int) { mut i := 0 // input string index @@ -1493,14 +1493,14 @@ pub fn (mut re RE) match_base(in_txt byteptr, in_txt_len int ) (int,int) { mut first_match := -1 //index of the first match mut i := 0 // source string index - mut ch := u32(0) // examinated char + mut ch := rune(0) // examinated char mut char_len := 0 // utf8 examinated char len mut m_state := Match_state.start // start point for the matcher FSM mut pc := -1 // program counter mut state := StateObj{} // actual state - mut ist := u32(0) // actual instruction - mut l_ist := u32(0) // last matched instruction + mut ist := rune(0) // actual instruction + mut l_ist :=rune(0) // last matched instruction mut group_stack := [-1].repeat(re.group_max) mut group_data := [-1].repeat(re.group_max) @@ -2213,7 +2213,7 @@ pub fn new_regex() RE { [deprecated] pub fn new_regex_by_size(mult int) RE { return impl_new_regex_by_size(mult) -} +} fn impl_new_regex_by_size(mult int) RE { mut re := RE{} re.prog = [Token{}].repeat(max_code_len*mult) // max program length, default 256 istructions diff --git a/vlib/strconv/atof.v b/vlib/strconv/atof.v index 34619b6d9e..e3b28634a0 100644 --- a/vlib/strconv/atof.v +++ b/vlib/strconv/atof.v @@ -180,7 +180,7 @@ NOTE: #TOFIX need one char after the last char of the number fn parser(s string) (int,PrepNumber) { mut state := fsm_a mut digx := 0 - mut c := ` ` // initial value for kicking off the state machine + mut c := byte(` `) // initial value for kicking off the state machine mut result := parser_ok mut expneg := false mut expexp := 0 @@ -192,7 +192,8 @@ fn parser(s string) (int,PrepNumber) { // skip starting spaces fsm_a { if is_space(c) == true { - c = s[i++] + c = s[i] + i++ } else { state = fsm_b @@ -202,12 +203,13 @@ fn parser(s string) (int,PrepNumber) { fsm_b { state = fsm_c if c == c_plus { - c = s[i++] - //i++ + c = s[i] + i++ } else if c == c_minus { pn.negative = true - c = s[i++] + c = s[i] + i++ } else if is_digit(c) { } diff --git a/vlib/strconv/format.v b/vlib/strconv/format.v index 927b957d13..910c7ac435 100644 --- a/vlib/strconv/format.v +++ b/vlib/strconv/format.v @@ -203,7 +203,7 @@ pub fn f64_to_str_lnd(f f64, dec_digit int) string { */ pub struct BF_param { - pad_ch byte = ` ` // padding char + pad_ch byte = byte(` `) // padding char len0 int = -1 // default len for whole the number or string len1 int = 6 // number of decimal digits, if needed positive bool = true // mandatory: the sign of the number passed @@ -438,7 +438,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ mut len0 := -1 // forced length, if -1 free length mut len1 := -1 // decimal part for floats def_len1 := 6 // default value for len1 - mut pad_ch := ` ` // pad char + mut pad_ch := byte(` `) // pad char mut th_separator := false // thousands separator flag // prefix chars for Length field diff --git a/vlib/strings/builder.v b/vlib/strings/builder.v index c34543c1f2..57c683a816 100644 --- a/vlib/strings/builder.v +++ b/vlib/strings/builder.v @@ -52,7 +52,7 @@ pub fn (mut b Builder) go_back(n int) { fn bytes2string(b []byte) string { mut copy := b.clone() - copy << `\0` + copy << byte(`\0`) res := tos(copy.data, copy.len-1) return res } diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 978d5bfc01..dcae17c3fd 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -257,6 +257,11 @@ pub fn (mut c Checker) check_types(got, expected table.Type) bool { return false } if got.is_number() && expected.is_number() { + if got == table.rune_type && expected == table.byte_type { + return true + } else if expected == table.rune_type && got == table.byte_type { + return true + } if c.promote_num(expected, got) != expected { // println('could not promote ${c.table.get_type_symbol(got).name} to ${c.table.get_type_symbol(expected).name}') return false diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c97f29e3cd..40330893af 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1,6 +1,5 @@ // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. +// Use of this source code is governed by an MIT license that can be found in the LICENSE file. module checker import v.ast @@ -260,7 +259,7 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) { match node { ast.AliasTypeDecl { // TODO Replace `c.file.mod.name != 'time'` by `it.language != .v` once available - if c.file.mod.name != 'time' { + if c.file.mod.name != 'time' && c.file.mod.name != 'builtin' { c.check_valid_pascal_case(node.name, 'type alias', node.pos) } typ_sym := c.table.get_type_symbol(node.parent_type) @@ -513,8 +512,10 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type { .key_in, .not_in { match right.kind { .array { + elem_type := right.array_info().elem_type right_sym := c.table.get_type_symbol(c.table.mktyp(right.array_info().elem_type)) - if left_default.kind != right_sym.kind { + // if left_default.kind != right_sym.kind { + if !c.check_types(left_type, elem_type) { c.error('the data type on the left of `$infix_expr.op.str()` (`$left.name`) does not match the array item type (`$right_sym.source_name`)', infix_expr.pos) } @@ -2379,7 +2380,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { return c.chan_init(mut node) } ast.CharLiteral { - return table.byte_type + // return any_int, not rune, so that we can do "bytes << `A`" without a cast etc + // return table.any_int_type + return table.rune_type + // return table.byte_type } ast.Comment { return table.void_type @@ -3032,7 +3036,9 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type { mut last_expr := branch.stmts[branch.stmts.len - 1] as ast.ExprStmt c.expected_type = former_expected_type last_expr.typ = c.expr(last_expr.expr) - if last_expr.typ != node.typ { + // if last_expr.typ != node.typ { + // if !c.check_types(node.typ, last_expr.typ) { + if !c.check_types(last_expr.typ, node.typ) { if node.typ == table.void_type { // first branch of if expression node.is_expr = true diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 86202ae323..2791ec7169 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -259,16 +259,20 @@ pub const ( // t_type_idx = 23 any_flt_type_idx = 24 any_int_type_idx = 25 + sizet_type_idx = 26 + rune_type_idx = 27 ) pub const ( integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, - u16_type_idx, u32_type_idx, u64_type_idx, any_int_type_idx] + u16_type_idx, u32_type_idx, u64_type_idx, any_int_type_idx, rune_type_idx] signed_integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx] unsigned_integer_type_idxs = [byte_type_idx, u16_type_idx, u32_type_idx, u64_type_idx] float_type_idxs = [f32_type_idx, f64_type_idx, any_flt_type_idx] number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, - u16_type_idx, u32_type_idx, u64_type_idx, f32_type_idx, f64_type_idx, any_int_type_idx, any_flt_type_idx] + u16_type_idx, u32_type_idx, u64_type_idx, f32_type_idx, f64_type_idx, any_int_type_idx, any_flt_type_idx, + rune_type_idx, + ] pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx] string_type_idxs = [string_type_idx, ustring_type_idx] ) @@ -300,6 +304,7 @@ pub const ( // t_type = new_type(t_type_idx) any_flt_type = new_type(any_flt_type_idx) any_int_type = new_type(any_int_type_idx) + rune_type = new_type(rune_type_idx) ) pub const (