diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index c8177544b8..42486816cb 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -157,7 +157,7 @@ pub fn (n i64) hex() string { hex := malloc(len) // QTODO //count := C.sprintf(charptr(hex), '0x%'C.PRIx64, n) - count := C.sprintf('%x', n) + count := C.sprintf(charptr(hex), '0x%x', n) return tos(hex, count) } @@ -165,7 +165,7 @@ pub fn (n u64) hex() string { len := if n >= u64(0) { n.str().len + 3 } else { 19 } hex := malloc(len) //count := C.sprintf(charptr(hex), '0x%'C.PRIx64, n) - count := C.sprintf('%x', n) + count := C.sprintf(charptr(hex), '0x%lx', n) return tos(hex, count) } diff --git a/vlib/builtin/int_test.v b/vlib/builtin/int_test.v index dd903d2f25..da0d3b6d86 100644 --- a/vlib/builtin/int_test.v +++ b/vlib/builtin/int_test.v @@ -108,3 +108,8 @@ fn test_int_alias() { assert i + 10 == 12 */ } + +fn test_hex() { + x := u64(10) + assert x.hex() == '0xa' +} diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 586708fb82..ba68decfa7 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -123,8 +123,8 @@ fn (n mut mapnode) split_child(child_index int, y mut mapnode) { } if !isnil(y.children) { z.children = &voidptr(malloc(children_bytes)) - for j := degree - 1; j >= 0; j-- { - z.children[j] = y.children[j + degree] + for jj := degree - 1; jj >= 0; jj-- { + z.children[jj] = y.children[jj + degree] } } if isnil(n.children) { diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index a7c1c733b4..a9f59e86d8 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -195,6 +195,17 @@ struct RepIndex { val_idx int } +fn compare_rep_index(a, b &RepIndex) int { + if a.idx < b.idx { + return -1 + } + if a.idx > b.idx { + return 1 + } + return 0 +} + + fn (a mut []RepIndex) sort() { a.sort_with_compare(compare_rep_index) } @@ -207,16 +218,6 @@ fn (a RepIndex) < (b RepIndex) bool { */ -fn compare_rep_index(a, b &RepIndex) int { - if a.idx < b.idx { - return -1 - } - if a.idx > b.idx { - return 1 - } - return 0 -} - pub fn (s string) replace_each(vals []string) string { if s.len == 0 || vals.len == 0 { return s @@ -244,7 +245,8 @@ pub fn (s string) replace_each(vals []string) string { // We need to remember both the position in the string, // and which rep/with pair it refers to. idxs << RepIndex{ - idx,rep_i} + idx:idx +val_idx:rep_i} idx++ new_len += with.len - rep.len } @@ -403,8 +405,8 @@ pub fn (s string) split(delim string) []string { } /* -split_nth - splits the string based on the passed `delim` substring. -It returns the first Nth parts. When N=0, return all the splits. +split_nth - splits the string based on the passed `delim` substring. +It returns the first Nth parts. When N=0, return all the splits. The last returned element has the remainder of the string, even if the remainder contains more `delim` substrings. */ @@ -447,7 +449,7 @@ pub fn (s string) split_nth(delim string, nth int) []string { res << s.right(start) break } - + res << val start = i + delim.len } diff --git a/vlib/time/time.v b/vlib/time/time.v index 2688ab4b5d..46119fd959 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -216,7 +216,8 @@ pub fn parse_iso(s string) Time { } mm := pos / 3 + 1 tmstr := malloc(s.len * 2) - count := int(C.sprintf(charptr(tmstr), '%s-%02d-%s %s'.str, fields[3].str, mm, fields[1].str, fields[4].str)) + count := C.sprintf(charptr(tmstr), '%s-%02d-%s %s'.str, fields[3].str, mm, + fields[1].str, fields[4].str) return parse(tos(tmstr, count)) } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 5f0a25222c..2bc33f9c6c 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -21,6 +21,10 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,table.Type) { pos: tok.position() } + if p.tok.kind == .key_orelse { + p.next() + p.parse_block() + } if f := p.table.find_fn(fn_name) { return node,f.return_type } @@ -45,6 +49,7 @@ pub fn (p mut Parser) call_args() []ast.Expr { } fn (p mut Parser) fn_decl() ast.FnDecl { + p.table.clear_vars() is_pub := p.tok.kind == .key_pub if is_pub { p.next() diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index f14d768a00..35d01ec2d8 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -32,6 +32,8 @@ mut: // vars []string table &table.Table return_type table.Type // current function's return type + // scope_level int + // var_idx int is_c bool // // prefix_parse_fns []PrefixParseFn @@ -118,6 +120,7 @@ pub fn (p mut Parser) read_first_token() { } pub fn (p mut Parser) parse_block() []ast.Stmt { + p.table.open_scope() p.check(.lcbr) mut stmts := []ast.Stmt if p.tok.kind != .rcbr { @@ -130,6 +133,7 @@ pub fn (p mut Parser) parse_block() []ast.Stmt { } } p.check(.rcbr) + p.table.close_scope() // println('nr exprs in block = $exprs.len') return stmts } @@ -405,7 +409,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { } // variable if var := p.table.find_var(p.tok.lit) { - println('#### IDENT: $var.name: $var.typ.name - $var.typ.idx') + // println('#### IDENT: $var.name: $var.typ.name - $var.typ.idx') typ = var.typ ident.kind = .variable ident.info = ast.IdentVar{ @@ -592,6 +596,10 @@ fn (p mut Parser) dot_expr(left ast.Expr, left_ti &table.Type) (ast.Expr,table.T if p.tok.kind == .lpar { p.next() args := p.call_args() + if p.tok.kind == .key_orelse { + p.next() + p.parse_block() + } mcall_expr := ast.MethodCallExpr{ expr: left name: field_name @@ -645,9 +653,12 @@ fn (p &Parser) is_addative() bool { fn (p mut Parser) for_statement() ast.Stmt { p.check(.key_for) + p.table.open_scope() + // defer { p.table.close_scope() } // Infinite loop if p.tok.kind == .lcbr { stmts := p.parse_block() + p.table.close_scope() return ast.ForStmt{ stmts: stmts pos: p.tok.position() @@ -685,6 +696,7 @@ fn (p mut Parser) for_statement() ast.Stmt { inc = p.stmt() } stmts := p.parse_block() + p.table.close_scope() return ast.ForCStmt{ stmts: stmts init: init @@ -693,8 +705,16 @@ fn (p mut Parser) for_statement() ast.Stmt { } } // `for i in vals`, `for i in start .. end` - else if p.peek_tok.kind == .key_in { + else if p.peek_tok.kind == .key_in || p.peek_tok.kind == .comma { var_name := p.check_name() + if p.tok.kind == .comma { + p.check(.comma) + val_name := p.check_name() + p.table.register_var(table.Var{ + name: val_name + typ: table.int_type + }) + } p.check(.key_in) start := p.tok.lit.int() p.expr(0) @@ -708,6 +728,7 @@ fn (p mut Parser) for_statement() ast.Stmt { }) stmts := p.parse_block() // println('nr stmts=$stmts.len') + p.table.close_scope() return ast.ForStmt{ stmts: stmts pos: p.tok.position() @@ -716,6 +737,7 @@ fn (p mut Parser) for_statement() ast.Stmt { // `for cond {` cond,_ := p.expr(0) stmts := p.parse_block() + p.table.close_scope() return ast.ForStmt{ cond: cond stmts: stmts @@ -735,7 +757,12 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) { mut else_stmts := []ast.Stmt if p.tok.kind == .key_else { p.check(.key_else) - else_stmts = p.parse_block() + if p.tok.kind == .key_if { + p.if_expr() + } + else { + else_stmts = p.parse_block() + } } mut ti := table.void_type // mut left := ast.Expr{} @@ -944,13 +971,18 @@ fn (p mut Parser) struct_decl() ast.StructDecl { // println('struct field $ti.name $field_name') } p.check(.rcbr) - p.table.register_type(table.Type{ - kind: .struct_ - name: name - info: table.Struct{ - fields: fields + if name != 'string' { + ret := p.table.register_type(table.Type{ + kind: .struct_ + name: name + info: table.Struct{ + fields: fields + } + }) + if ret == -1 { + p.error('cannot register type `$name`, another type with this name exists') } - }) + } return ast.StructDecl{ name: name is_pub: is_pub diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 24d450a87b..f274af39b8 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -8,15 +8,17 @@ module table pub struct Table { // struct_fields map[string][]string pub mut: - types []Type + types []Type // type_idxs Hashmap - type_idxs map[string]int - local_vars []Var + type_idxs map[string]int + local_vars []Var + scope_level int + var_idx int // fns Hashmap - fns map[string]Fn - consts map[string]Var - tmp_cnt int - imports []string + fns map[string]Fn + consts map[string]Var + tmp_cnt int + imports []string } pub struct Fn { @@ -28,12 +30,14 @@ pub: pub struct Var { pub: - name string - is_mut bool - is_const bool - is_global bool + name string + idx int + is_mut bool + is_const bool + is_global bool + scope_level int mut: - typ Type + typ Type } pub fn new_table() &Table { @@ -52,32 +56,21 @@ pub fn (t &Table) find_var_idx(name string) int { } pub fn (t &Table) find_var(name string) ?Var { - /* - for i in 0 .. p.var_idx { - if p.local_vars[i].name == name { - return p.local_vars[i] + for i in 0 .. t.var_idx { + if t.local_vars[i].name == name { + return t.local_vars[i] } } - */ - + /* // println(t.names) for var in t.local_vars { if var.name == name { return var } } - return none -} + */ -pub fn (t mut Table) clear_vars() { - // shared a := [1, 2, 3] - // p.var_idx = 0 - if t.local_vars.len > 0 { - // if p.pref.autofree { - // p.local_vars.free() - // } - t.local_vars = [] - } + return none } pub fn (t mut Table) register_const(v Var) { @@ -99,27 +92,76 @@ pub fn (t mut Table) register_global(name string, typ Type) { pub fn (t mut Table) register_var(v Var) { println('register_var: $v.name - $v.typ.name') - t.local_vars << v - /* mut new_var := { v | - idx:p.var_idx, - scope_level:p.cur_fn.scope_level + idx:t.var_idx, + scope_level:t.scope_level } + // t.local_vars << v + /* if v.line_nr == 0 { new_var.token_idx = p.cur_tok_index() new_var.line_nr = p.cur_tok().line_nr } + */ // Expand the array - if p.var_idx >= p.local_vars.len { - p.local_vars << new_var + if t.var_idx >= t.local_vars.len { + t.local_vars << new_var } else { - p.local_vars[p.var_idx] = new_var + t.local_vars[t.var_idx] = new_var + } + t.var_idx++ +} + +pub fn (t mut Table) open_scope() { + t.scope_level++ +} + +pub fn (t mut Table) close_scope() { + // println('close_scope level=$f.scope_level var_idx=$f.var_idx') + // Move back `var_idx` (pointer to the end of the array) till we reach + // the previous scope level. This effectivly deletes (closes) current + // scope. + mut i := t.var_idx - 1 + for ; i >= 0; i-- { + var := t.local_vars[i] + /* + if p.pref.autofree && (v.is_alloc || (v.is_arg && v.typ == 'string')) { + // && !p.pref.is_test { + p.free_var(v) + } + */ + + // if p.fileis('mem.v') { + // println(v.name + ' $v.is_arg scope=$v.scope_level cur=$p.cur_fn.scope_level')} + if var.scope_level != t.scope_level { + // && !v.is_arg { + break + } + } + /* + if p.cur_fn.defer_text.last() != '' { + p.genln(p.cur_fn.defer_text.last()) + // p.cur_fn.defer_text[f] = '' } - p.var_idx++ */ + t.scope_level-- + // p.cur_fn.defer_text = p.cur_fn.defer_text[..p.cur_fn.scope_level + 1] + t.var_idx = i + 1 + // println('close_scope new var_idx=$f.var_idx\n') +} + +pub fn (p mut Table) clear_vars() { + // shared a := [1, 2, 3] + p.var_idx = 0 + if p.local_vars.len > 0 { + // ///if p.pref.autofree { + // p.local_vars.free() + // ///} + p.local_vars = [] + } } pub fn (t &Table) find_fn(name string) ?Fn { @@ -240,7 +282,7 @@ pub fn (t mut Table) register_type(typ Type) int { if ex_type.kind == typ.kind { return existing_idx } - panic('cannot register type `$typ.name`, another type with this name exists') + return -1 } } }