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 |
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 }
/*

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 = 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)`)

View File

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

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

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

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

View File

@ -25,15 +25,20 @@ fn test_generic_fn() {
assert plus<string>('a', 'b') == 'ab'
}
/*
fn sum<T>(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<int>(b) == 6
}
/*
fn map_f<T,U>(l []T, f fn(T)U) []U {
mut r := []U{}
for e in l {