diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index eba4183fc3..ccec340884 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -15,10 +15,10 @@ pub type Expr = AnonFn | ArrayInit | AsCast | AssignExpr | Assoc | BoolLiteral | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | StringInterLiteral | StringLiteral | StructInit | Type | TypeOf -pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl | - DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt | - GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | StructDecl | TypeDecl | - UnsafeStmt +pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ComptimeCall | + ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | + GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | StructDecl | + TypeDecl | UnsafeStmt pub type ScopeObject = ConstField | GlobalDecl | Var @@ -731,7 +731,7 @@ pub struct OrExpr { pub: stmts []Stmt kind OrKind - pos token.Position + pos token.Position } pub struct Assoc { @@ -772,6 +772,10 @@ pub mut: return_type table.Type } +pub struct ComptimeCall { + name string +} + pub struct None { pub: foo int // todo @@ -888,7 +892,7 @@ pub fn (expr Expr) position() token.Position { } pub fn (stmt Stmt) position() token.Position { - match mut stmt { + match stmt { AssertStmt { return it.pos } AssignStmt { return it.pos } /* diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index a3fecd554b..8c8960c950 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -395,10 +395,16 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type { c.expected_type = former_expected_type } c.expected_type = table.void_type - left_type := c.expr(infix_expr.left) + mut left_type := c.expr(infix_expr.left) + if false && left_type == table.t_type { + left_type = c.cur_generic_type + } infix_expr.left_type = left_type c.expected_type = left_type - right_type := c.expr(infix_expr.right) + mut right_type := c.expr(infix_expr.right) + if false && right_type == table.t_type { + right_type = c.cur_generic_type + } infix_expr.right_type = right_type right := c.table.get_type_symbol(right_type) left := c.table.get_type_symbol(left_type) @@ -613,11 +619,11 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) { fn (mut c Checker) assign_expr(mut assign_expr ast.AssignExpr) { c.expected_type = table.void_type - left_type := c.expr(assign_expr.left) + left_type := c.unwrap_generic(c.expr(assign_expr.left)) c.expected_type = left_type assign_expr.left_type = left_type // println('setting exp type to $c.expected_type $t.name') - right_type := c.expr(assign_expr.val) + right_type := c.unwrap_generic(c.expr(assign_expr.val)) assign_expr.right_type = right_type right := c.table.get_type_symbol(right_type) left := c.table.get_type_symbol(left_type) @@ -1162,15 +1168,17 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { } for i, exp_type in expected_types { got_typ := got_types[i] - /* - ok := if exp_type == table.t_type { c.check_types(got_typ, c.cur_generic_type) } else { c.check_types(got_typ, + is_generic := exp_type == table.t_type + ok := if is_generic { c.check_types(got_typ, c.cur_generic_type) || got_typ == exp_type } else { c.check_types(got_typ, exp_type) } - */ - ok := c.check_types(got_typ, exp_type) + // ok := c.check_types(got_typ, exp_type) if !ok { // !c.table.check(got_typ, exp_typ) { got_typ_sym := c.table.get_type_symbol(got_typ) - exp_typ_sym := c.table.get_type_symbol(exp_type) + mut exp_typ_sym := c.table.get_type_symbol(exp_type) pos := return_stmt.exprs[i].position() + if is_generic { + exp_typ_sym = c.table.get_type_symbol(c.cur_generic_type) + } c.error('cannot use `$got_typ_sym.name` as type `$exp_typ_sym.name` in return argument', pos) } @@ -1643,6 +1651,14 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) { c.expected_type = table.void_type } +pub fn (mut c Checker) unwrap_generic(typ table.Type) table.Type { + if typ == table.t_type { + return c.cur_generic_type + } + return typ +} + +// TODO node must be mut pub fn (mut c Checker) expr(node ast.Expr) table.Type { match mut node { ast.AnonFn { @@ -1870,12 +1886,12 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type { typ: typ is_optional: is_optional } - if typ == table.t_type { - sym := c.table.get_type_symbol(c.cur_generic_type) - println('IDENT T unresolved $ident.name typ=$sym.name') - // Got a var with type T, return current generic type - // typ = c.cur_generic_type - } + // if typ == table.t_type { + // sym := c.table.get_type_symbol(c.cur_generic_type) + // println('IDENT T unresolved $ident.name typ=$sym.name') + // Got a var with type T, return current generic type + // typ = c.cur_generic_type + // } // } else { it.typ = typ // unwrap optional (`println(x)`) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index e0666ff14b..b01c063c6e 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -359,6 +359,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) { f.stmts(it.stmts) f.writeln('}') } + ast.ComptimeCall {} } } @@ -873,6 +874,9 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) { f.write(')') f.or_expr(node.or_block) } else { + if node.language == .c { + f.write('C.') + } name := f.short_module(node.name) f.mark_module_as_used(name) f.write('${name}') diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 3bdc9e7bbd..386c617acb 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1580,14 +1580,31 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { right_sym := g.table.get_type_symbol(node.right_type) if left_type == table.ustring_type_idx && node.op != .key_in && node.op != .not_in { fn_name := match node.op { - .plus { 'ustring_add(' } - .eq { 'ustring_eq(' } - .ne { 'ustring_ne(' } - .lt { 'ustring_lt(' } - .le { 'ustring_le(' } - .gt { 'ustring_gt(' } - .ge { 'ustring_ge(' } - else { '/*node error*/' } + .plus { + 'ustring_add(' + } + .eq { + 'ustring_eq(' + } + .ne { + 'ustring_ne(' + } + .lt { + 'ustring_lt(' + } + .le { + 'ustring_le(' + } + .gt { + 'ustring_gt(' + } + .ge { + 'ustring_ge(' + } + else { + verror('op error for type `$left_sym.name`') + '/*node error*/' + } } g.write(fn_name) g.expr(node.left) @@ -1596,14 +1613,31 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.write(')') } else if left_type == table.string_type_idx && node.op != .key_in && node.op != .not_in { fn_name := match node.op { - .plus { 'string_add(' } - .eq { 'string_eq(' } - .ne { 'string_ne(' } - .lt { 'string_lt(' } - .le { 'string_le(' } - .gt { 'string_gt(' } - .ge { 'string_ge(' } - else { '/*node error*/' } + .plus { + 'string_add(' + } + .eq { + 'string_eq(' + } + .ne { + 'string_ne(' + } + .lt { + 'string_lt(' + } + .le { + 'string_le(' + } + .gt { + 'string_gt(' + } + .ge { + 'string_ge(' + } + else { + verror('op error for type `$left_sym.name`') + '/*node error*/' + } } g.write(fn_name) g.expr(node.left) diff --git a/vlib/v/gen/comptime.v b/vlib/v/gen/comptime.v new file mode 100644 index 0000000000..c7f43a23e1 --- /dev/null +++ b/vlib/v/gen/comptime.v @@ -0,0 +1,49 @@ +// 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 gen + +import vweb.tmpl +import os + +// $vweb.html() +fn (mut g Gen) vweb_html() { + // Compile vweb html template to V code, parse that V code and embed the resulting V functions + // that returns an html string + mut path := g.cur_fn.name + '.html' + println('html path=$path') + if g.pref.is_debug { + println('>>> compiling vweb HTML template "$path"') + } + if !os.exists(path) { + // Can't find the template file in current directory, + // try looking next to the vweb program, in case it's run with + // v path/to/vweb_app.v + // path = os.dir(g.scanner.file_path) + '/' + path + // if !os.exists(path) { + verror('vweb HTML template "$path" not found') + // } + } + v_code := tmpl.compile_template(path) + if g.pref.is_verbose { + println('\n\n') + println('>>> vweb template for ${path}:') + println(v_code) + println('>>> vweb template END') + println('\n\n') + } + // is_strings_imorted := p.import_table.known_import('strings') + // if !is_strings_imorted { + // p.register_import('strings', 0) // used by v_code + // } + // p.import_table.register_used_import('strings') + g.writeln('/////////////////// tmpl start') + // g.statements_from_text(v_code, false, path) + g.writeln('/////////////////// tmpl end') + receiver := g.cur_fn.args[0] + dot := '.' // if receiver.is_mut || receiver.ptr || receiver.typ.ends_with('*') { '->' } else { '.' } + g.writeln('vweb__Context_html(&$receiver.name /*!*/$dot vweb, tmpl_res)') +} + +fn fooo() { +} diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index b6f73c7389..d1c852d5c7 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -22,7 +22,9 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) { // loop thru each generic type and generate a function for gen_type in g.table.fn_gen_types[it.name] { sym := g.table.get_type_symbol(gen_type) - println('gen fn `$it.name` for type `$sym.name`') + if g.pref.is_verbose { + println('gen fn `$it.name` for type `$sym.name`') + } g.cur_generic_type = gen_type g.gen_fn_decl(it) } diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 9b0a49d77f..c67be6ac4b 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -53,9 +53,21 @@ fn (mut p Parser) hash() ast.HashStmt { } } -fn (mut p Parser) comp_if() ast.CompIf { +fn (mut p Parser) vweb() ast.ComptimeCall { + p.check(.name) // skip `vweb.html()` TODO + p.check(.dot) + p.check(.name) + p.check(.lpar) + p.check(.rpar) + return ast.ComptimeCall{} +} + +fn (mut p Parser) comp_if() ast.Stmt { pos := p.tok.position() p.next() + if p.tok.kind == .name && p.tok.lit == 'vweb' { + return p.vweb() + } p.check(.key_if) is_not := p.tok.kind == .not if is_not { diff --git a/vlib/v/tests/generic_test.v b/vlib/v/tests/generic_test.v index 9fbd3377e0..e8d1f3a366 100644 --- a/vlib/v/tests/generic_test.v +++ b/vlib/v/tests/generic_test.v @@ -25,15 +25,20 @@ fn test_generic_fn() { assert plus('a', 'b') == 'ab' } -/* fn sum(l []T) T { - mut r := T(0) - for e in l { - r += e - } - return r + mut r := T(0) + for e in l { + r += e + } + return r } +fn test_foo() { + b := [1, 2, 3] + assert sum(b) == 6 +} + +/* fn map_f(l []T, f fn(T)U) []U { mut r := []U{} for e in l {