vfmt: add missing imports automatically
parent
d55f4ab097
commit
0db0c642c3
|
@ -12,6 +12,14 @@ struct C.cJSON {
|
||||||
valuestring byteptr
|
valuestring byteptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decode() voidptr {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode() voidptr {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
fn jsdecode_int(root &C.cJSON) int {
|
fn jsdecode_int(root &C.cJSON) int {
|
||||||
if isnil(root) {
|
if isnil(root) {
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -251,185 +251,196 @@ 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 {
|
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)
|
c.stmts(call_expr.or_block.stmts)
|
||||||
if call_expr.is_method {
|
if call_expr.is_method {
|
||||||
left_type := c.expr(call_expr.left)
|
return c.call_method(call_expr)
|
||||||
call_expr.left_type = left_type
|
}
|
||||||
left_type_sym := c.table.get_type_symbol(left_type)
|
return c.call_fn(call_expr)
|
||||||
method_name := call_expr.name
|
}
|
||||||
// TODO: remove this for actual methods, use only for compiler magic
|
|
||||||
if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse',
|
pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
|
||||||
'map', 'slice'] {
|
left_type := c.expr(call_expr.left)
|
||||||
if method_name in ['filter', 'map'] {
|
call_expr.left_type = left_type
|
||||||
array_info := left_type_sym.info as table.Array
|
left_type_sym := c.table.get_type_symbol(left_type)
|
||||||
mut scope := c.file.scope.innermost(call_expr.pos.pos)
|
method_name := call_expr.name
|
||||||
scope.update_var_type('it', array_info.elem_type)
|
// TODO: remove this for actual methods, use only for compiler magic
|
||||||
}
|
if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse',
|
||||||
for i, arg in call_expr.args {
|
'map', 'slice'] {
|
||||||
c.expr(arg.expr)
|
if method_name in ['filter', 'map'] {
|
||||||
}
|
array_info := left_type_sym.info as table.Array
|
||||||
// need to return `array_xxx` instead of `array`
|
mut scope := c.file.scope.innermost(call_expr.pos.pos)
|
||||||
call_expr.return_type = left_type
|
scope.update_var_type('it', array_info.elem_type)
|
||||||
if method_name == 'clone' {
|
|
||||||
// in ['clone', 'str'] {
|
|
||||||
call_expr.receiver_type = table.type_to_ptr(left_type)
|
|
||||||
// call_expr.return_type = call_expr.receiver_type
|
|
||||||
} else {
|
|
||||||
call_expr.receiver_type = left_type
|
|
||||||
}
|
|
||||||
return left_type
|
|
||||||
} else if left_type_sym.kind == .array && method_name in ['first', 'last'] {
|
|
||||||
info := left_type_sym.info as table.Array
|
|
||||||
call_expr.return_type = info.elem_type
|
|
||||||
call_expr.receiver_type = left_type
|
|
||||||
return info.elem_type
|
|
||||||
}
|
}
|
||||||
if method := c.table.type_find_method(left_type_sym, method_name) {
|
for i, arg in call_expr.args {
|
||||||
no_args := method.args.len - 1
|
c.expr(arg.expr)
|
||||||
min_required_args := method.args.len - if method.is_variadic && method.args.len >
|
}
|
||||||
1 { 2 } else { 1 }
|
// need to return `array_xxx` instead of `array`
|
||||||
if call_expr.args.len < min_required_args {
|
call_expr.return_type = left_type
|
||||||
c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)',
|
if method_name == 'clone' {
|
||||||
call_expr.pos)
|
// in ['clone', 'str'] {
|
||||||
} else if !method.is_variadic && call_expr.args.len > no_args {
|
call_expr.receiver_type = table.type_to_ptr(left_type)
|
||||||
c.error('too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $no_args)',
|
// call_expr.return_type = call_expr.receiver_type
|
||||||
call_expr.pos)
|
} else {
|
||||||
return method.return_type
|
call_expr.receiver_type = left_type
|
||||||
}
|
}
|
||||||
// if method_name == 'clone' {
|
return left_type
|
||||||
// println('CLONE nr args=$method.args.len')
|
} else if left_type_sym.kind == .array && method_name in ['first', 'last'] {
|
||||||
// }
|
info := left_type_sym.info as table.Array
|
||||||
// call_expr.args << method.args[0].typ
|
call_expr.return_type = info.elem_type
|
||||||
// call_expr.exp_arg_types << method.args[0].typ
|
call_expr.receiver_type = left_type
|
||||||
for i, arg in call_expr.args {
|
return info.elem_type
|
||||||
c.expected_type = if method.is_variadic && i >= method.args.len - 1 {
|
}
|
||||||
method.args[method.args.len - 1].typ
|
if method := c.table.type_find_method(left_type_sym, method_name) {
|
||||||
} else {
|
no_args := method.args.len - 1
|
||||||
method.args[i + 1].typ
|
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 {
|
||||||
call_expr.args[i].typ = c.expr(arg.expr)
|
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)
|
||||||
// TODO: typ optimize.. this node can get processed more than once
|
} else if !method.is_variadic && call_expr.args.len > no_args {
|
||||||
if call_expr.expected_arg_types.len == 0 {
|
c.error('too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $no_args)',
|
||||||
for i in 1 .. method.args.len {
|
call_expr.pos)
|
||||||
call_expr.expected_arg_types << method.args[i].typ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
call_expr.receiver_type = method.args[0].typ
|
|
||||||
call_expr.return_type = method.return_type
|
|
||||||
return method.return_type
|
return method.return_type
|
||||||
}
|
}
|
||||||
// TODO: str methods
|
// if method_name == 'clone' {
|
||||||
if left_type_sym.kind == .map && method_name == 'str' {
|
// println('CLONE nr args=$method.args.len')
|
||||||
call_expr.receiver_type = table.new_type(c.table.type_idxs['map_string'])
|
// }
|
||||||
call_expr.return_type = table.string_type
|
// call_expr.args << method.args[0].typ
|
||||||
return table.string_type
|
// call_expr.exp_arg_types << method.args[0].typ
|
||||||
}
|
for i, arg in call_expr.args {
|
||||||
if left_type_sym.kind == .array && method_name == 'str' {
|
c.expected_type = if method.is_variadic && i >= method.args.len - 1 {
|
||||||
call_expr.receiver_type = left_type
|
method.args[method.args.len - 1].typ
|
||||||
call_expr.return_type = table.string_type
|
} else {
|
||||||
return table.string_type
|
method.args[i + 1].typ
|
||||||
}
|
|
||||||
c.error('unknown method: ${left_type_sym.name}.$method_name', call_expr.pos)
|
|
||||||
return table.void_type
|
|
||||||
} else {
|
|
||||||
fn_name := call_expr.name
|
|
||||||
// TODO: impl typeof properly (probably not going to be a fn call)
|
|
||||||
if fn_name == 'typeof' {
|
|
||||||
return table.string_type
|
|
||||||
}
|
|
||||||
// look for function in format `mod.fn` or `fn` (main/builtin)
|
|
||||||
mut f := table.Fn{}
|
|
||||||
mut found := false
|
|
||||||
// try prefix with current module as it would have never gotten prefixed
|
|
||||||
if !fn_name.contains('.') && !(call_expr.mod in ['builtin', 'main']) {
|
|
||||||
name_prefixed := '${call_expr.mod}.$fn_name'
|
|
||||||
if f1 := c.table.find_fn(name_prefixed) {
|
|
||||||
call_expr.name = name_prefixed
|
|
||||||
found = true
|
|
||||||
f = f1
|
|
||||||
}
|
}
|
||||||
}
|
call_expr.args[i].typ = c.expr(arg.expr)
|
||||||
// already prefixed (mod.fn) or C/builtin/main
|
|
||||||
if !found {
|
|
||||||
if f1 := c.table.find_fn(fn_name) {
|
|
||||||
found = true
|
|
||||||
f = f1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check for arg (var) of fn type
|
|
||||||
if !found {
|
|
||||||
scope := c.file.scope.innermost(call_expr.pos.pos)
|
|
||||||
if var := scope.find_var(fn_name) {
|
|
||||||
if var.typ != 0 {
|
|
||||||
vts := c.table.get_type_symbol(var.typ)
|
|
||||||
if vts.kind == .function {
|
|
||||||
info := vts.info as table.FnType
|
|
||||||
f = info.func
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
c.error('unknown fn: $fn_name', call_expr.pos)
|
|
||||||
return table.void_type
|
|
||||||
}
|
|
||||||
call_expr.return_type = f.return_type
|
|
||||||
if f.is_c || call_expr.is_c {
|
|
||||||
for arg in call_expr.args {
|
|
||||||
c.expr(arg.expr)
|
|
||||||
}
|
|
||||||
return f.return_type
|
|
||||||
}
|
|
||||||
min_required_args := if f.is_variadic { f.args.len - 1 } else { f.args.len }
|
|
||||||
if call_expr.args.len < min_required_args {
|
|
||||||
c.error('too few arguments in call to `$fn_name` ($call_expr.args.len instead of $min_required_args)',
|
|
||||||
call_expr.pos)
|
|
||||||
} else if !f.is_variadic && call_expr.args.len > f.args.len {
|
|
||||||
c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)',
|
|
||||||
call_expr.pos)
|
|
||||||
return f.return_type
|
|
||||||
}
|
|
||||||
// println can print anything
|
|
||||||
if fn_name == 'println' || fn_name == 'print' {
|
|
||||||
c.expected_type = table.string_type
|
|
||||||
call_expr.args[0].typ = c.expr(call_expr.args[0].expr)
|
|
||||||
return f.return_type
|
|
||||||
}
|
}
|
||||||
// TODO: typ optimize.. this node can get processed more than once
|
// TODO: typ optimize.. this node can get processed more than once
|
||||||
if call_expr.expected_arg_types.len == 0 {
|
if call_expr.expected_arg_types.len == 0 {
|
||||||
for arg in f.args {
|
for i in 1 .. method.args.len {
|
||||||
call_expr.expected_arg_types << arg.typ
|
call_expr.expected_arg_types << method.args[i].typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, call_arg in call_expr.args {
|
call_expr.receiver_type = method.args[0].typ
|
||||||
arg := if f.is_variadic && i >= f.args.len - 1 { f.args[f.args.len - 1] } else { f.args[i] }
|
call_expr.return_type = method.return_type
|
||||||
c.expected_type = arg.typ
|
return method.return_type
|
||||||
typ := c.expr(call_arg.expr)
|
}
|
||||||
call_expr.args[i].typ = typ
|
// TODO: str methods
|
||||||
typ_sym := c.table.get_type_symbol(typ)
|
if left_type_sym.kind == .map && method_name == 'str' {
|
||||||
arg_typ_sym := c.table.get_type_symbol(arg.typ)
|
call_expr.receiver_type = table.new_type(c.table.type_idxs['map_string'])
|
||||||
if !c.table.check(typ, arg.typ) {
|
call_expr.return_type = table.string_type
|
||||||
// str method, allow type with str method if fn arg is string
|
return table.string_type
|
||||||
if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
}
|
||||||
continue
|
if left_type_sym.kind == .array && method_name == 'str' {
|
||||||
|
call_expr.receiver_type = left_type
|
||||||
|
call_expr.return_type = table.string_type
|
||||||
|
return table.string_type
|
||||||
|
}
|
||||||
|
c.error('unknown method: ${left_type_sym.name}.$method_name', call_expr.pos)
|
||||||
|
return table.void_type
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
// try prefix with current module as it would have never gotten prefixed
|
||||||
|
if !fn_name.contains('.') && !(call_expr.mod in ['builtin', 'main']) {
|
||||||
|
name_prefixed := '${call_expr.mod}.$fn_name'
|
||||||
|
if f1 := c.table.find_fn(name_prefixed) {
|
||||||
|
call_expr.name = name_prefixed
|
||||||
|
found = true
|
||||||
|
f = f1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// already prefixed (mod.fn) or C/builtin/main
|
||||||
|
if !found {
|
||||||
|
if f1 := c.table.find_fn(fn_name) {
|
||||||
|
found = true
|
||||||
|
f = f1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for arg (var) of fn type
|
||||||
|
if !found {
|
||||||
|
scope := c.file.scope.innermost(call_expr.pos.pos)
|
||||||
|
if var := scope.find_var(fn_name) {
|
||||||
|
if var.typ != 0 {
|
||||||
|
vts := c.table.get_type_symbol(var.typ)
|
||||||
|
if vts.kind == .function {
|
||||||
|
info := vts.info as table.FnType
|
||||||
|
f = info.func
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
if typ_sym.kind == .void && arg_typ_sym.kind == .string {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if typ_sym.kind == .array_fixed {
|
|
||||||
}
|
|
||||||
// println('fixed')
|
|
||||||
c.error('cannot use type `$typ_sym.str()` as type `$arg_typ_sym.str()` in argument ${i+1} to `$fn_name`',
|
|
||||||
call_expr.pos)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
c.error('unknown fn: $fn_name', call_expr.pos)
|
||||||
|
return table.void_type
|
||||||
|
}
|
||||||
|
call_expr.return_type = f.return_type
|
||||||
|
if f.is_c || call_expr.is_c {
|
||||||
|
for arg in call_expr.args {
|
||||||
|
c.expr(arg.expr)
|
||||||
|
}
|
||||||
return f.return_type
|
return f.return_type
|
||||||
}
|
}
|
||||||
|
min_required_args := if f.is_variadic { f.args.len - 1 } else { f.args.len }
|
||||||
|
if call_expr.args.len < min_required_args {
|
||||||
|
c.error('too few arguments in call to `$fn_name` ($call_expr.args.len instead of $min_required_args)',
|
||||||
|
call_expr.pos)
|
||||||
|
} else if !f.is_variadic && call_expr.args.len > f.args.len {
|
||||||
|
c.error('too many arguments in call to `$fn_name` ($call_expr.args.len instead of $f.args.len)',
|
||||||
|
call_expr.pos)
|
||||||
|
return f.return_type
|
||||||
|
}
|
||||||
|
// println can print anything
|
||||||
|
if fn_name == 'println' || fn_name == 'print' {
|
||||||
|
c.expected_type = table.string_type
|
||||||
|
call_expr.args[0].typ = c.expr(call_expr.args[0].expr)
|
||||||
|
return f.return_type
|
||||||
|
}
|
||||||
|
// TODO: typ optimize.. this node can get processed more than once
|
||||||
|
if call_expr.expected_arg_types.len == 0 {
|
||||||
|
for arg in f.args {
|
||||||
|
call_expr.expected_arg_types << arg.typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, call_arg in call_expr.args {
|
||||||
|
arg := if f.is_variadic && i >= f.args.len - 1 { f.args[f.args.len - 1] } else { f.args[i] }
|
||||||
|
c.expected_type = arg.typ
|
||||||
|
typ := c.expr(call_arg.expr)
|
||||||
|
call_expr.args[i].typ = typ
|
||||||
|
typ_sym := c.table.get_type_symbol(typ)
|
||||||
|
arg_typ_sym := c.table.get_type_symbol(arg.typ)
|
||||||
|
if !c.table.check(typ, arg.typ) {
|
||||||
|
// str method, allow type with str method if fn arg is string
|
||||||
|
if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if typ_sym.kind == .void && arg_typ_sym.kind == .string {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if typ_sym.kind == .array_fixed {
|
||||||
|
}
|
||||||
|
// println('fixed')
|
||||||
|
c.error('cannot use type `$typ_sym.str()` as type `$arg_typ_sym.str()` in argument ${i+1} to `$fn_name`',
|
||||||
|
call_expr.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f.return_type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c mut Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) {
|
pub fn (c mut Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) {
|
||||||
|
@ -1564,3 +1575,7 @@ fn (c mut Checker) warn_or_error(s string, pos token.Position, warn bool) {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (p Checker) fileis(s string) bool {
|
||||||
|
return p.file.path.contains(s)
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ const (
|
||||||
|
|
||||||
struct Fmt {
|
struct Fmt {
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
|
out_imports strings.Builder
|
||||||
table &table.Table
|
table &table.Table
|
||||||
mut:
|
mut:
|
||||||
indent int
|
indent int
|
||||||
|
@ -26,21 +27,35 @@ mut:
|
||||||
file ast.File
|
file ast.File
|
||||||
did_imports bool
|
did_imports bool
|
||||||
is_assign 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 {
|
pub fn fmt(file ast.File, table &table.Table) string {
|
||||||
mut f := Fmt{
|
mut f := Fmt{
|
||||||
out: strings.new_builder(1000)
|
out: strings.new_builder(1000)
|
||||||
|
out_imports: strings.new_builder(200)
|
||||||
table: table
|
table: table
|
||||||
indent: 0
|
indent: 0
|
||||||
file: file
|
file: file
|
||||||
}
|
}
|
||||||
f.cur_mod = 'main'
|
f.cur_mod = 'main'
|
||||||
for i, stmt in file.stmts {
|
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)
|
f.stmt(stmt)
|
||||||
}
|
}
|
||||||
// for comment in file.comments { println('$comment.line_nr $comment.text') }
|
// 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
|
return
|
||||||
}
|
}
|
||||||
f.did_imports = true
|
f.did_imports = true
|
||||||
|
// f.import_pos = f.out.len
|
||||||
if imports.len == 1 {
|
if imports.len == 1 {
|
||||||
imp_stmt_str := f.imp_stmt_str(imports[0])
|
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 {
|
} else if imports.len > 1 {
|
||||||
f.writeln('import (')
|
f.out_imports.writeln('import (')
|
||||||
f.indent++
|
// f.indent++
|
||||||
for imp in imports {
|
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.indent--
|
||||||
f.writeln(')\n')
|
f.out_imports.writeln(')\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +323,8 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
|
||||||
f.writeln('#$it.val')
|
f.writeln('#$it.val')
|
||||||
}
|
}
|
||||||
ast.Import {
|
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 {
|
ast.Module {
|
||||||
f.mod(it)
|
f.mod(it)
|
||||||
|
@ -482,19 +500,7 @@ fn (f mut Fmt) expr(node ast.Expr) {
|
||||||
f.write(')')
|
f.write(')')
|
||||||
}
|
}
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
if it.is_method {
|
f.call_expr(it)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast.CharLiteral {
|
ast.CharLiteral {
|
||||||
f.write('`$it.val`')
|
f.write('`$it.val`')
|
||||||
|
@ -801,3 +807,40 @@ fn (f mut Fmt) if_expr(it ast.IfExpr) {
|
||||||
f.write('}')
|
f.write('}')
|
||||||
f.single_line_if = false
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -338,6 +338,13 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||||
// println('cgen.stmt()')
|
// println('cgen.stmt()')
|
||||||
// g.writeln('//// stmt start')
|
// g.writeln('//// stmt start')
|
||||||
match node {
|
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 {
|
ast.AssertStmt {
|
||||||
g.gen_assert_stmt(it)
|
g.gen_assert_stmt(it)
|
||||||
}
|
}
|
||||||
|
@ -2339,6 +2346,7 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
|
||||||
field_deps << dep
|
field_deps << dep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// table.Interface {}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
// add type and dependant types to graph
|
// add type and dependant types to graph
|
||||||
|
|
|
@ -482,7 +482,16 @@ fn (p mut Parser) attribute() ast.Attr {
|
||||||
if p.tok.kind == .key_if {
|
if p.tok.kind == .key_if {
|
||||||
p.next()
|
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.check(.rsbr)
|
||||||
p.attr = name
|
p.attr = name
|
||||||
return ast.Attr{
|
return ast.Attr{
|
||||||
|
@ -1577,6 +1586,10 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||||
}
|
}
|
||||||
has_default_expr = true
|
has_default_expr = true
|
||||||
}
|
}
|
||||||
|
mut attr := ast.Attr{}
|
||||||
|
if p.tok.kind == .lsbr {
|
||||||
|
attr = p.attribute()
|
||||||
|
}
|
||||||
if p.tok.kind == .comment {
|
if p.tok.kind == .comment {
|
||||||
comment = p.comment()
|
comment = p.comment()
|
||||||
}
|
}
|
||||||
|
@ -1587,6 +1600,7 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||||
comment: comment
|
comment: comment
|
||||||
default_expr: default_expr
|
default_expr: default_expr
|
||||||
has_default_expr: has_default_expr
|
has_default_expr: has_default_expr
|
||||||
|
attr: attr.name
|
||||||
}
|
}
|
||||||
fields << table.Field{
|
fields << table.Field{
|
||||||
name: field_name
|
name: field_name
|
||||||
|
|
|
@ -24,14 +24,16 @@ fn (d Dog) name() string {
|
||||||
|
|
||||||
fn test_todo() {}
|
fn test_todo() {}
|
||||||
|
|
||||||
/*
|
|
||||||
interface Speaker {
|
interface Speaker {
|
||||||
name ()string
|
name ()string
|
||||||
speak()}
|
speak()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
interface Speak2er {
|
interface Speak2er {
|
||||||
name ()string
|
name ()string
|
||||||
speak()}
|
speak()
|
||||||
|
}
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
speaker Speaker
|
speaker Speaker
|
||||||
|
|
Loading…
Reference in New Issue