checker/gen: more generics fixes; ComptimeCall

pull/5018/head
Alexander Medvednikov 2020-05-25 05:32:33 +02:00
parent ec7863d174
commit 1ef8eacd6e
8 changed files with 171 additions and 45 deletions

View File

@ -15,10 +15,10 @@ pub type Expr = AnonFn | ArrayInit | AsCast | AssignExpr | Assoc | BoolLiteral |
PrefixExpr | RangeExpr | SelectorExpr | SizeOf | StringInterLiteral | StringLiteral | StructInit | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | StringInterLiteral | StringLiteral | StructInit |
Type | TypeOf Type | TypeOf
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl | pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ComptimeCall |
DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt | ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl |
GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | StructDecl | TypeDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | StructDecl |
UnsafeStmt TypeDecl | UnsafeStmt
pub type ScopeObject = ConstField | GlobalDecl | Var pub type ScopeObject = ConstField | GlobalDecl | Var
@ -731,7 +731,7 @@ pub struct OrExpr {
pub: pub:
stmts []Stmt stmts []Stmt
kind OrKind kind OrKind
pos token.Position pos token.Position
} }
pub struct Assoc { pub struct Assoc {
@ -772,6 +772,10 @@ pub mut:
return_type table.Type return_type table.Type
} }
pub struct ComptimeCall {
name string
}
pub struct None { pub struct None {
pub: pub:
foo int // todo foo int // todo
@ -888,7 +892,7 @@ pub fn (expr Expr) position() token.Position {
} }
pub fn (stmt Stmt) position() token.Position { pub fn (stmt Stmt) position() token.Position {
match mut stmt { match stmt {
AssertStmt { return it.pos } AssertStmt { return it.pos }
AssignStmt { return it.pos } AssignStmt { return it.pos }
/* /*

View File

@ -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 = former_expected_type
} }
c.expected_type = table.void_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 infix_expr.left_type = left_type
c.expected_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 infix_expr.right_type = right_type
right := c.table.get_type_symbol(right_type) right := c.table.get_type_symbol(right_type)
left := c.table.get_type_symbol(left_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) { fn (mut c Checker) assign_expr(mut assign_expr ast.AssignExpr) {
c.expected_type = table.void_type 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 c.expected_type = left_type
assign_expr.left_type = left_type assign_expr.left_type = left_type
// println('setting exp type to $c.expected_type $t.name') // 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 assign_expr.right_type = right_type
right := c.table.get_type_symbol(right_type) right := c.table.get_type_symbol(right_type)
left := c.table.get_type_symbol(left_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 { for i, exp_type in expected_types {
got_typ := got_types[i] got_typ := got_types[i]
/* is_generic := exp_type == table.t_type
ok := if exp_type == table.t_type { c.check_types(got_typ, c.cur_generic_type) } else { c.check_types(got_typ, 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) } 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) { if !ok { // !c.table.check(got_typ, exp_typ) {
got_typ_sym := c.table.get_type_symbol(got_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() 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', c.error('cannot use `$got_typ_sym.name` as type `$exp_typ_sym.name` in return argument',
pos) pos)
} }
@ -1643,6 +1651,14 @@ fn (mut c Checker) stmts(stmts []ast.Stmt) {
c.expected_type = table.void_type 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 { pub fn (mut c Checker) expr(node ast.Expr) table.Type {
match mut node { match mut node {
ast.AnonFn { ast.AnonFn {
@ -1870,12 +1886,12 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
typ: typ typ: typ
is_optional: is_optional is_optional: is_optional
} }
if typ == table.t_type { // if typ == table.t_type {
sym := c.table.get_type_symbol(c.cur_generic_type) // sym := c.table.get_type_symbol(c.cur_generic_type)
println('IDENT T unresolved $ident.name typ=$sym.name') // println('IDENT T unresolved $ident.name typ=$sym.name')
// Got a var with type T, return current generic type // Got a var with type T, return current generic type
// typ = c.cur_generic_type // typ = c.cur_generic_type
} // }
// } else { // } else {
it.typ = typ it.typ = typ
// unwrap optional (`println(x)`) // unwrap optional (`println(x)`)

View File

@ -359,6 +359,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
f.stmts(it.stmts) f.stmts(it.stmts)
f.writeln('}') f.writeln('}')
} }
ast.ComptimeCall {}
} }
} }
@ -873,6 +874,9 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
f.write(')') f.write(')')
f.or_expr(node.or_block) f.or_expr(node.or_block)
} else { } else {
if node.language == .c {
f.write('C.')
}
name := f.short_module(node.name) name := f.short_module(node.name)
f.mark_module_as_used(name) f.mark_module_as_used(name)
f.write('${name}') f.write('${name}')

View File

@ -1580,14 +1580,31 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
right_sym := g.table.get_type_symbol(node.right_type) 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 { if left_type == table.ustring_type_idx && node.op != .key_in && node.op != .not_in {
fn_name := match node.op { fn_name := match node.op {
.plus { 'ustring_add(' } .plus {
.eq { 'ustring_eq(' } 'ustring_add('
.ne { 'ustring_ne(' } }
.lt { 'ustring_lt(' } .eq {
.le { 'ustring_le(' } 'ustring_eq('
.gt { 'ustring_gt(' } }
.ge { 'ustring_ge(' } .ne {
else { '/*node error*/' } '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.write(fn_name)
g.expr(node.left) g.expr(node.left)
@ -1596,14 +1613,31 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
g.write(')') g.write(')')
} else if left_type == table.string_type_idx && node.op != .key_in && node.op != .not_in { } else if left_type == table.string_type_idx && node.op != .key_in && node.op != .not_in {
fn_name := match node.op { fn_name := match node.op {
.plus { 'string_add(' } .plus {
.eq { 'string_eq(' } 'string_add('
.ne { 'string_ne(' } }
.lt { 'string_lt(' } .eq {
.le { 'string_le(' } 'string_eq('
.gt { 'string_gt(' } }
.ge { 'string_ge(' } .ne {
else { '/*node error*/' } '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.write(fn_name)
g.expr(node.left) g.expr(node.left)

View File

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

View File

@ -22,7 +22,9 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
// loop thru each generic type and generate a function // loop thru each generic type and generate a function
for gen_type in g.table.fn_gen_types[it.name] { for gen_type in g.table.fn_gen_types[it.name] {
sym := g.table.get_type_symbol(gen_type) 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.cur_generic_type = gen_type
g.gen_fn_decl(it) g.gen_fn_decl(it)
} }

View File

@ -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() pos := p.tok.position()
p.next() p.next()
if p.tok.kind == .name && p.tok.lit == 'vweb' {
return p.vweb()
}
p.check(.key_if) p.check(.key_if)
is_not := p.tok.kind == .not is_not := p.tok.kind == .not
if is_not { if is_not {

View File

@ -25,15 +25,20 @@ fn test_generic_fn() {
assert plus<string>('a', 'b') == 'ab' assert plus<string>('a', 'b') == 'ab'
} }
/*
fn sum<T>(l []T) T { fn sum<T>(l []T) T {
mut r := T(0) mut r := T(0)
for e in l { for e in l {
r += e r += e
} }
return r return r
} }
fn test_foo() {
b := [1, 2, 3]
assert sum<int>(b) == 6
}
/*
fn map_f<T,U>(l []T, f fn(T)U) []U { fn map_f<T,U>(l []T, f fn(T)U) []U {
mut r := []U{} mut r := []U{}
for e in l { for e in l {