1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

vfmt: add missing imports automatically

This commit is contained in:
Alexander Medvednikov 2020-04-12 17:45:04 +02:00
parent d55f4ab097
commit 0db0c642c3
6 changed files with 278 additions and 188 deletions

View File

@ -12,6 +12,14 @@ struct C.cJSON {
valuestring byteptr
}
pub fn decode() voidptr {
}
pub fn encode() voidptr {
}
fn jsdecode_int(root &C.cJSON) int {
if isnil(root) {
return 0

View File

@ -251,11 +251,14 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
}
pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
if call_expr.name == 'panic' {
c.returns = true
}
c.stmts(call_expr.or_block.stmts)
if call_expr.is_method {
return c.call_method(call_expr)
}
return c.call_fn(call_expr)
}
pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
left_type := c.expr(call_expr.left)
call_expr.left_type = left_type
left_type_sym := c.table.get_type_symbol(left_type)
@ -289,8 +292,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
}
if method := c.table.type_find_method(left_type_sym, method_name) {
no_args := method.args.len - 1
min_required_args := method.args.len - if method.is_variadic && method.args.len >
1 { 2 } else { 1 }
min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
if call_expr.args.len < min_required_args {
c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)',
call_expr.pos)
@ -335,12 +337,22 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
}
c.error('unknown method: ${left_type_sym.name}.$method_name', call_expr.pos)
return table.void_type
} else {
}
pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
if call_expr.name == 'panic' {
c.returns = true
}
fn_name := call_expr.name
// TODO: impl typeof properly (probably not going to be a fn call)
if fn_name == 'typeof' {
// TODO: impl typeof properly (probably not going to be a fn call)
return table.string_type
}
//if c.fileis('json_test.v') {
//println(fn_name)
//}
if fn_name == 'json.encode' {
}
// look for function in format `mod.fn` or `fn` (main/builtin)
mut f := table.Fn{}
mut found := false
@ -430,7 +442,6 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
}
return f.return_type
}
}
pub fn (c mut Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) {
match x {
@ -1564,3 +1575,7 @@ fn (c mut Checker) warn_or_error(s string, pos token.Position, warn bool) {
exit(1)
}
}
fn (p Checker) fileis(s string) bool {
return p.file.path.contains(s)
}

View File

@ -16,6 +16,7 @@ const (
struct Fmt {
out strings.Builder
out_imports strings.Builder
table &table.Table
mut:
indent int
@ -26,21 +27,35 @@ mut:
file ast.File
did_imports bool
is_assign bool
auto_imports []string // automatically inserted imports that the user forgot to specify
import_pos int // position of the imports in the resulting string for later autoimports insertion
}
pub fn fmt(file ast.File, table &table.Table) string {
mut f := Fmt{
out: strings.new_builder(1000)
out_imports: strings.new_builder(200)
table: table
indent: 0
file: file
}
f.cur_mod = 'main'
for i, stmt in file.stmts {
// TODO `if stmt is ast.Import`
match stmt {
ast.Import {
// Just remember the position of the imports for now
f.import_pos = f.out.len
// f.imports(f.file.imports)
}
else {}
}
f.stmt(stmt)
}
// for comment in file.comments { println('$comment.line_nr $comment.text') }
return f.out.str().trim_space() + '\n'
f.imports(f.file.imports) // now that we have all autoimports, handle them
res := f.out.str().trim_space() + '\n'
return res[..f.import_pos] + f.out_imports.str() + res[f.import_pos..]
}
/*
@ -86,17 +101,19 @@ fn (f mut Fmt) imports(imports []ast.Import) {
return
}
f.did_imports = true
// f.import_pos = f.out.len
if imports.len == 1 {
imp_stmt_str := f.imp_stmt_str(imports[0])
f.writeln('import ${imp_stmt_str}\n')
f.out_imports.writeln('import ${imp_stmt_str}\n')
} else if imports.len > 1 {
f.writeln('import (')
f.indent++
f.out_imports.writeln('import (')
// f.indent++
for imp in imports {
f.writeln(f.imp_stmt_str(imp))
f.out_imports.write('\t')
f.out_imports.writeln(f.imp_stmt_str(imp))
}
f.indent--
f.writeln(')\n')
// f.indent--
f.out_imports.writeln(')\n')
}
}
@ -306,7 +323,8 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
f.writeln('#$it.val')
}
ast.Import {
f.imports(f.file.imports)
// Imports are handled after the file is formatted, to automatically add necessary modules
// f.imports(f.file.imports)
}
ast.Module {
f.mod(it)
@ -482,19 +500,7 @@ fn (f mut Fmt) expr(node ast.Expr) {
f.write(')')
}
ast.CallExpr {
if it.is_method {
f.expr(it.left)
f.write('.' + it.name + '(')
f.call_args(it.args)
f.write(')')
f.or_expr(it.or_block)
} else {
name := short_module(it.name)
f.write('${name}(')
f.call_args(it.args)
f.write(')')
f.or_expr(it.or_block)
}
f.call_expr(it)
}
ast.CharLiteral {
f.write('`$it.val`')
@ -801,3 +807,40 @@ fn (f mut Fmt) if_expr(it ast.IfExpr) {
f.write('}')
f.single_line_if = false
}
fn (f mut Fmt) call_expr(node ast.CallExpr) {
if node.is_method {
match node.left {
ast.Ident {
// `time.now()` without `time imported` is processed as a method call with `time` being
// a `node.left` expression. Import `time` automatically.
// TODO fetch all available modules
if it.name in ['time', 'os', 'strings', 'math', 'json'] {
if !(it.name in f.auto_imports) {
f.auto_imports << it.name
f.file.imports << ast.Import{
mod: it.name
alias: it.name
}
}
println(it.name + '!!')
for imp in f.file.imports {
println(imp.mod)
}
}
}
else {}
}
f.expr(node.left)
f.write('.' + node.name + '(')
f.call_args(node.args)
f.write(')')
f.or_expr(node.or_block)
} else {
name := short_module(node.name)
f.write('${name}(')
f.call_args(node.args)
f.write(')')
f.or_expr(node.or_block)
}
}

View File

@ -338,6 +338,13 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// println('cgen.stmt()')
// g.writeln('//// stmt start')
match node {
ast.InterfaceDecl {
g.writeln('//interface')
g.writeln('struct $it.name {')
g.writeln('\tvoid* _object;')
g.writeln('\tint _interface_idx;')
g.writeln('};')
}
ast.AssertStmt {
g.gen_assert_stmt(it)
}
@ -2339,6 +2346,7 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
field_deps << dep
}
}
// table.Interface {}
else {}
}
// add type and dependant types to graph

View File

@ -482,7 +482,16 @@ fn (p mut Parser) attribute() ast.Attr {
if p.tok.kind == .key_if {
p.next()
}
name := p.check_name()
mut name := p.check_name()
if p.tok.kind == .colon {
p.next()
if p.tok.kind == .name {
name += p.check_name()
} else if p.tok.kind == .string {
name += p.tok.lit
p.next()
}
}
p.check(.rsbr)
p.attr = name
return ast.Attr{
@ -1577,6 +1586,10 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
}
has_default_expr = true
}
mut attr := ast.Attr{}
if p.tok.kind == .lsbr {
attr = p.attribute()
}
if p.tok.kind == .comment {
comment = p.comment()
}
@ -1587,6 +1600,7 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
comment: comment
default_expr: default_expr
has_default_expr: has_default_expr
attr: attr.name
}
fields << table.Field{
name: field_name

View File

@ -24,14 +24,16 @@ fn (d Dog) name() string {
fn test_todo() {}
/*
interface Speaker {
name ()string
speak()}
speak()
}
/*
interface Speak2er {
name ()string
speak()}
speak()
}
struct Foo {
speaker Speaker