parser/cgen: interfaces (part 1)

pull/4553/head
Alexander Medvednikov 2020-04-22 20:20:49 +02:00
parent faed178cb1
commit d7ee4755c2
9 changed files with 365 additions and 289 deletions

View File

@ -157,6 +157,7 @@ pub struct InterfaceDecl {
pub: pub:
name string name string
field_names []string field_names []string
methods []FnDecl
} }
pub struct StructInitField { pub struct StructInitField {
@ -541,7 +542,6 @@ pub:
name string name string
is_pub bool is_pub bool
fields []EnumField fields []EnumField
// default_exprs []Expr
pos token.Position pos token.Position
} }
@ -739,22 +739,46 @@ pub fn expr_is_call(expr Expr) bool {
fn (expr Expr) position() token.Position { fn (expr Expr) position() token.Position {
// all uncommented have to be implemented // all uncommented have to be implemented
match var expr { match mut expr {
ArrayInit { return it.pos } ArrayInit {
AsCast { return it.pos } return it.pos
}
AsCast {
return it.pos
}
// ast.Ident { } // ast.Ident { }
AssignExpr { return it.pos } AssignExpr {
return it.pos
}
// ast.CastExpr { } // ast.CastExpr { }
Assoc { return it.pos } Assoc {
BoolLiteral { return it.pos } return it.pos
CallExpr { return it.pos } }
CharLiteral { return it.pos } BoolLiteral {
EnumVal { return it.pos } return it.pos
FloatLiteral { return it.pos } }
Ident { return it.pos } CallExpr {
IfExpr { return it.pos } return it.pos
}
CharLiteral {
return it.pos
}
EnumVal {
return it.pos
}
FloatLiteral {
return it.pos
}
Ident {
return it.pos
}
IfExpr {
return it.pos
}
// ast.IfGuardExpr { } // ast.IfGuardExpr { }
IndexExpr { return it.pos } IndexExpr {
return it.pos
}
InfixExpr { InfixExpr {
left_pos := it.left.position() left_pos := it.left.position()
right_pos := it.right.position() right_pos := it.right.position()
@ -767,20 +791,40 @@ fn (expr Expr) position() token.Position {
len: right_pos.pos - left_pos.pos + right_pos.len len: right_pos.pos - left_pos.pos + right_pos.len
} }
} }
IntegerLiteral { return it.pos } IntegerLiteral {
MapInit { return it.pos } return it.pos
MatchExpr { return it.pos } }
PostfixExpr { return it.pos } MapInit {
return it.pos
}
MatchExpr {
return it.pos
}
PostfixExpr {
return it.pos
}
// ast.None { } // ast.None { }
PrefixExpr { return it.pos } PrefixExpr {
return it.pos
}
// ast.ParExpr { } // ast.ParExpr { }
SelectorExpr { return it.pos } SelectorExpr {
return it.pos
}
// ast.SizeOf { } // ast.SizeOf { }
StringLiteral { return it.pos } StringLiteral {
StringInterLiteral { return it.pos } return it.pos
}
StringInterLiteral {
return it.pos
}
// ast.Type { } // ast.Type { }
StructInit { return it.pos } StructInit {
return it.pos
}
// ast.TypeOf { } // ast.TypeOf { }
else { return token.Position{} } else {
return token.Position{}
}
} }
} }

View File

@ -471,13 +471,13 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
//println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod') //println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos) c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
} }
no_args := method.args.len - 1 nr_args := if method.args.len == 0 { 0 } else {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 { 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)', 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) call_expr.pos)
} else if !method.is_variadic && call_expr.args.len > no_args { } else if !method.is_variadic && call_expr.args.len > nr_args {
c.error('too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $no_args)', c.error('!too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $nr_args)',
call_expr.pos) call_expr.pos)
return method.return_type return method.return_type
} }
@ -530,7 +530,7 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
return info.func.return_type return info.func.return_type
} }
} }
c.error('unknown method: ${left_type_sym.name}.$method_name', call_expr.pos) c.error('unknown method: `${left_type_sym.name}.$method_name`', call_expr.pos)
return table.void_type return table.void_type
} }

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/inout/unknown_method.v:7:12: error: unknown method: Test.sdd vlib/v/checker/tests/inout/unknown_method.v:7:12: error: unknown method: `Test.sdd`
5| fn main() { 5| fn main() {
6| t := Test{} 6| t := Test{}
7| println(t.sdd()) 7| println(t.sdd())

View File

@ -333,6 +333,14 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
// Imports are handled after the file is formatted, to automatically add necessary modules // Imports are handled after the file is formatted, to automatically add necessary modules
// f.imports(f.file.imports) // f.imports(f.file.imports)
} }
ast.InterfaceDecl {
f.writeln('interface $it.name {')
for method in it.methods {
f.write('\t')
f.writeln(method.str(f.table).after('fn '))
}
f.writeln('}\n')
}
ast.Module { ast.Module {
f.mod(it) f.mod(it)
} }

View File

@ -151,17 +151,11 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
} }
// //
g.finish() g.finish()
return g.hashes() + return g.hashes() + '\n// V typedefs:\n' + g.typedefs.str() + '\n// V typedefs2:\n' + g.typedefs2.str() +
'\n// V typedefs:\n' + g.typedefs.str() + '\n// V cheaders:\n' + g.cheaders.str() + '\n// V includes:\n' + g.includes.str() + '\n// V definitions:\n' +
'\n// V typedefs2:\n' + g.typedefs2.str() + g.definitions.str() + g.interface_table() + '\n// V gowrappers:\n' + g.gowrappers.str() + '\n// V stringliterals:\n' +
'\n// V cheaders:\n' + g.cheaders.str() + g.stringliterals.str() + '\n// V auto str functions:\n' + g.auto_str_funcs.str() + '\n// V out\n' +
'\n// V includes:\n' + g.includes.str() + g.out.str() + '\n// THE END.'
'\n// V definitions:\n' + g.definitions.str() +
'\n// V gowrappers:\n' + g.gowrappers.str() +
'\n// V stringliterals:\n' + g.stringliterals.str() +
'\n// V auto str functions:\n' + g.auto_str_funcs.str() +
'\n// V out\n' + g.out.str() +
'\n// THE END.'
} }
pub fn (g Gen) hashes() string { pub fn (g Gen) hashes() string {
@ -400,10 +394,10 @@ fn (mut g Gen) stmt(node ast.Stmt) {
match node { match node {
ast.InterfaceDecl { ast.InterfaceDecl {
g.writeln('//interface') g.writeln('//interface')
g.writeln('struct $it.name {') g.writeln('typedef struct {')
g.writeln('\tvoid* _object;') g.writeln('\tvoid* _object;')
g.writeln('\tint _interface_idx;') g.writeln('\tint _interface_idx;')
g.writeln('};') g.writeln('} $it.name;')
} }
ast.AssertStmt { ast.AssertStmt {
g.gen_assert_stmt(it) g.gen_assert_stmt(it)
@ -458,11 +452,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
cur_enum_expr = expr_str cur_enum_expr = expr_str
cur_enum_offset = 0 cur_enum_offset = 0
} }
cur_value := if cur_enum_offset > 0 { cur_value := if cur_enum_offset > 0 { '${cur_enum_expr}+${cur_enum_offset}' } else { cur_enum_expr }
'${cur_enum_expr}+${cur_enum_offset}'
} else {
cur_enum_expr
}
g.typedefs.writeln(', // ${cur_value}') g.typedefs.writeln(', // ${cur_value}')
cur_enum_offset++ cur_enum_offset++
} }
@ -2221,6 +2211,9 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
} }
// loop over types // loop over types
for t in typesa { for t in typesa {
if t.kind == .interface_ {
continue
}
// create list of deps // create list of deps
mut field_deps := []string mut field_deps := []string
match t.info { match t.info {
@ -2232,6 +2225,9 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
} }
table.Struct { table.Struct {
info := t.info as table.Struct info := t.info as table.Struct
// if info.is_interface {
// continue
// }
for field in info.fields { for field in info.fields {
dep := g.table.get_type_symbol(field.typ).name dep := g.table.get_type_symbol(field.typ).name
// skip if not in types list or already in deps // skip if not in types list or already in deps
@ -2849,12 +2845,12 @@ fn (mut g Gen) is_expr(node ast.InfixExpr) {
} }
fn styp_to_str_fn_name(styp string) string { fn styp_to_str_fn_name(styp string) string {
res := styp.replace('.', '__').replace('*','_ptr') + '_str' res := styp.replace('.', '__').replace('*', '_ptr') + '_str'
return res return res
} }
// already generated styp, reuse it // already generated styp, reuse it
fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp string, str_fn_name string) { fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp, str_fn_name string) {
already_generated_key := '${styp}:${str_fn_name}' already_generated_key := '${styp}:${str_fn_name}'
if sym.has_method('str') || already_generated_key in g.str_types { if sym.has_method('str') || already_generated_key in g.str_types {
return return
@ -2870,7 +2866,7 @@ fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp string, str_fn_name s
} }
} }
fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name string) { fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
mut convertor := '' mut convertor := ''
mut typename := '' mut typename := ''
if sym.parent_idx in table.integer_type_idxs { if sym.parent_idx in table.integer_type_idxs {
@ -2901,7 +2897,7 @@ fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name st
g.auto_str_funcs.writeln('}') g.auto_str_funcs.writeln('}')
} }
fn (mut g Gen) gen_str_for_enum(info table.Enum, styp string, str_fn_name string) { fn (mut g Gen) gen_str_for_enum(info table.Enum, styp, str_fn_name string) {
s := styp.replace('.', '__') s := styp.replace('.', '__')
g.definitions.writeln('string ${str_fn_name}($styp it); // auto') g.definitions.writeln('string ${str_fn_name}($styp it); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { /* gen_str_for_enum */') g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { /* gen_str_for_enum */')
@ -2914,27 +2910,29 @@ fn (mut g Gen) gen_str_for_enum(info table.Enum, styp string, str_fn_name string
g.auto_str_funcs.writeln('}') g.auto_str_funcs.writeln('}')
} }
fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name string) { fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
// TODO: short it if possible // TODO: short it if possible
// generates all definitions of substructs // generates all definitions of substructs
mut fnames2strfunc := map[string]string mut fnames2strfunc := {
'': ''
} // map[string]string // TODO vfmt bug
for i, field in info.fields { for i, field in info.fields {
sym := g.table.get_type_symbol(field.typ) sym := g.table.get_type_symbol(field.typ)
if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] { if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] {
field_styp := g.typ(field.typ) field_styp := g.typ(field.typ)
field_fn_name := styp_to_str_fn_name( field_styp ) field_fn_name := styp_to_str_fn_name(field_styp)
fnames2strfunc[ field_styp ] = field_fn_name fnames2strfunc[field_styp] = field_fn_name
g.gen_str_for_type(sym, field_styp, field_fn_name) g.gen_str_for_type(sym, field_styp, field_fn_name)
} }
} }
g.definitions.writeln('string ${str_fn_name}($styp x, int indent_count); // auto') g.definitions.writeln('string ${str_fn_name}($styp x, int indent_count); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp x, int indent_count) {') g.auto_str_funcs.writeln('string ${str_fn_name}($styp x, int indent_count) {')
mut clean_struct_v_type_name := styp.replace('__','.') mut clean_struct_v_type_name := styp.replace('__', '.')
if styp.ends_with('*') { if styp.ends_with('*') {
deref_typ := styp.replace('*', '') deref_typ := styp.replace('*', '')
g.auto_str_funcs.writeln('\t${deref_typ} *it = x;') g.auto_str_funcs.writeln('\t${deref_typ} *it = x;')
clean_struct_v_type_name = '&' + clean_struct_v_type_name.replace('*', '') clean_struct_v_type_name = '&' + clean_struct_v_type_name.replace('*', '')
}else{ } else {
deref_typ := styp deref_typ := styp
g.auto_str_funcs.writeln('\t${deref_typ} *it = &x;') g.auto_str_funcs.writeln('\t${deref_typ} *it = &x;')
} }
@ -2954,14 +2952,14 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
for i, field in info.fields { for i, field in info.fields {
sym := g.table.get_type_symbol(field.typ) sym := g.table.get_type_symbol(field.typ)
has_custom_str := sym.has_method('str') has_custom_str := sym.has_method('str')
second_str_param := if has_custom_str {''} else {', indent_count + 1'} second_str_param := if has_custom_str { '' } else { ', indent_count + 1' }
field_styp := g.typ(field.typ) field_styp := g.typ(field.typ)
field_styp_fn_name := if has_custom_str {'${field_styp}_str'} else {fnames2strfunc[ field_styp ]} field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] }
if sym.kind == .enum_ { if sym.kind == .enum_ {
g.auto_str_funcs.write('indents.len, indents.str, ') g.auto_str_funcs.write('indents.len, indents.str, ')
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).len, ') g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).len, ')
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).str ') g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).str ')
}else if sym.kind in [.struct_, .array, .array_fixed] { } else if sym.kind in [.struct_, .array, .array_fixed] {
g.auto_str_funcs.write('indents.len, indents.str, ') g.auto_str_funcs.write('indents.len, indents.str, ')
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).len, ') g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).len, ')
g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).str ') g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).str ')
@ -2983,11 +2981,11 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
g.auto_str_funcs.writeln('}') g.auto_str_funcs.writeln('}')
} }
fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name string) { fn (mut g Gen) gen_str_for_array(info table.Array, styp, str_fn_name string) {
sym := g.table.get_type_symbol(info.elem_type) sym := g.table.get_type_symbol(info.elem_type)
field_styp := g.typ(info.elem_type) field_styp := g.typ(info.elem_type)
if sym.kind == .struct_ && !sym.has_method('str') { if sym.kind == .struct_ && !sym.has_method('str') {
g.gen_str_for_type(sym, field_styp, styp_to_str_fn_name(field_styp) ) g.gen_str_for_type(sym, field_styp, styp_to_str_fn_name(field_styp))
} }
g.definitions.writeln('string ${str_fn_name}($styp a); // auto') g.definitions.writeln('string ${str_fn_name}($styp a); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) {') g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) {')
@ -3011,7 +3009,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
g.auto_str_funcs.writeln('}') g.auto_str_funcs.writeln('}')
} }
fn (mut g Gen) gen_str_for_map(info table.Map, styp string, str_fn_name string) { fn (mut g Gen) gen_str_for_map(info table.Map, styp, str_fn_name string) {
key_sym := g.table.get_type_symbol(info.key_type) key_sym := g.table.get_type_symbol(info.key_type)
key_styp := g.typ(info.key_type) key_styp := g.typ(info.key_type)
if key_sym.kind == .struct_ && !key_sym.has_method('str') { if key_sym.kind == .struct_ && !key_sym.has_method('str') {
@ -3068,3 +3066,60 @@ fn (g Gen) type_to_fmt(typ table.Type) string {
} }
return '%d' return '%d'
} }
// Generates interface table and interface indexes
fn (v &Gen) interface_table() string {
mut sb := strings.new_builder(100)
for _, t in v.table.types {
if t.kind != .interface_ {
continue
}
info := t.info as table.Interface
// interface_name is for example Speaker
interface_name := t.name
mut methods := ''
mut generated_casting_functions := ''
sb.writeln('// NR gen_types= $info.gen_types.len')
for i, gen_type in info.gen_types {
// ptr_ctype can be for example Cat OR Cat_ptr:
ptr_ctype := gen_type.replace('*', '_ptr')
// cctype is the Cleaned Concrete Type name, *without ptr*,
// i.e. cctype is always just Cat, not Cat_ptr:
cctype := gen_type.replace('*', '')
// Speaker_Cat_index = 0
interface_index_name := '_${interface_name}_${ptr_ctype}_index'
generated_casting_functions += '
${interface_name} I_${cctype}_to_${interface_name}(${cctype} x) {
return (${interface_name}){
._object = (void*) memdup(&x, sizeof(${cctype})),
._interface_idx = ${interface_index_name} };
}
'
methods += '{\n'
for j, method in t.methods {
// Cat_speak
methods += ' (void*) ${cctype}_${method.name}'
if j < t.methods.len - 1 {
methods += ', \n'
}
}
methods += '\n},\n\n'
sb.writeln('int ${interface_index_name} = $i;')
}
if info.gen_types.len > 0 {
// methods = '{TCCSKIP(0)}'
// }
sb.writeln('void* (* ${interface_name}_name_table[][$t.methods.len]) = ' + '{ \n $methods \n }; ')
} else {
// The line below is needed so that C compilation succeeds,
// even if no interface methods are called.
// See https://github.com/zenith391/vgtk3/issues/7
sb.writeln('void* (* ${interface_name}_name_table[][1]) = ' + '{ {NULL} }; ')
}
if generated_casting_functions.len > 0 {
sb.writeln('// Casting functions for interface "${interface_name}" :')
sb.writeln(generated_casting_functions)
}
}
return sb.str()
}

View File

@ -3,13 +3,11 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module gen module gen
import ( import v.ast
v.ast import v.table
v.table import v.util
v.util
)
fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
if it.is_c { if it.is_c {
// || it.no_body { // || it.no_body {
return return
@ -88,7 +86,6 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
g.writeln('\tint ___argc;') g.writeln('\tint ___argc;')
g.writeln('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);') g.writeln('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);')
} }
g.writeln('\t_vinit();') g.writeln('\t_vinit();')
if g.is_importing_os() { if g.is_importing_os() {
if g.autofree { if g.autofree {
@ -126,7 +123,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
g.fn_decl = 0 g.fn_decl = 0
} }
fn (g mut Gen) fn_args(args []table.Arg, is_variadic bool) { fn (mut g Gen) fn_args(args []table.Arg, is_variadic bool) {
no_names := args.len > 0 && args[0].name == 'arg_1' no_names := args.len > 0 && args[0].name == 'arg_1'
for i, arg in args { for i, arg in args {
arg_type_sym := g.table.get_type_symbol(arg.typ) arg_type_sym := g.table.get_type_symbol(arg.typ)
@ -175,7 +172,7 @@ fn (g mut Gen) fn_args(args []table.Arg, is_variadic bool) {
} }
} }
fn (g mut Gen) call_expr(node ast.CallExpr) { fn (mut g Gen) call_expr(node ast.CallExpr) {
gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0 gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0
tmp_opt := if gen_or { g.new_tmp_var() } else { '' } tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
if gen_or { if gen_or {
@ -192,21 +189,37 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
} }
} }
fn (g mut Gen) method_call(node ast.CallExpr) { fn (mut g Gen) method_call(node ast.CallExpr) {
// TODO: there are still due to unchecked exprs (opt/some fn arg) // TODO: there are still due to unchecked exprs (opt/some fn arg)
if node.left_type == 0 { if node.left_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs') verror('method receiver type is 0, this means there are some uchecked exprs')
} }
typ_sym := g.table.get_type_symbol(node.receiver_type) typ_sym := g.table.get_type_symbol(node.receiver_type)
// rec_sym := g.table.get_type_symbol(node.receiver_type)
mut receiver_name := typ_sym.name mut receiver_name := typ_sym.name
if typ_sym.kind == .interface_ {
g.writeln('// interface method call')
// `((void (*)())(Speaker_name_table[s._interface_idx][1]))(s._object);`
g.write('((void (*)())(${receiver_name}_name_table[')
g.expr(node.left)
g.write('._interface_idx][1]))(')
g.expr(node.left)
g.writeln('._object );')
return
}
// rec_sym := g.table.get_type_symbol(node.receiver_type)
if typ_sym.kind == .array && node.name == 'filter' { if typ_sym.kind == .array && node.name == 'filter' {
g.gen_filter(node) g.gen_filter(node)
return return
} }
// TODO performance, detect `array` method differently // TODO performance, detect `array` method differently
if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many',
'trim', 'first', 'last', 'clone', 'reverse', 'slice'] { 'trim'
'first'
'last'
'clone'
'reverse'
'slice'
] {
// && rec_sym.name == 'array' { // && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') { // && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone` // `array_byte_clone` => `array_clone`
@ -255,7 +268,7 @@ fn (g mut Gen) method_call(node ast.CallExpr) {
// } // }
} }
fn (g mut Gen) fn_call(node ast.CallExpr) { fn (mut g Gen) fn_call(node ast.CallExpr) {
// call struct field with fn type // call struct field with fn type
// TODO: test node.left instead // TODO: test node.left instead
// left & left_type will be `x` and `x type` in `x.fieldfn()` // left & left_type will be `x` and `x type` in `x.fieldfn()`
@ -264,8 +277,7 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
g.expr(node.left) g.expr(node.left)
if table.type_is_ptr(node.left_type) { if table.type_is_ptr(node.left_type) {
g.write('->') g.write('->')
} } else {
else {
g.write('.') g.write('.')
} }
} }
@ -322,15 +334,9 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
} else { } else {
expr := node.args[0].expr expr := node.args[0].expr
is_var := match expr { is_var := match expr {
ast.SelectorExpr { ast.SelectorExpr { true }
true ast.Ident { true }
} else { false }
ast.Ident {
true
}
else {
false
}
} }
if table.type_is_ptr(typ) && sym.kind != .struct_ { if table.type_is_ptr(typ) && sym.kind != .struct_ {
// ptr_str() for pointers // ptr_str() for pointers
@ -381,10 +387,10 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
} }
} }
fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) { fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len - is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len -
1], .variadic) 1], .variadic)
is_forwarding_varg := args.len > 0 && table.type_is(args[args.len-1].typ, .variadic) is_forwarding_varg := args.len > 0 && table.type_is(args[args.len - 1].typ, .variadic)
gen_vargs := is_variadic && !is_forwarding_varg gen_vargs := is_variadic && !is_forwarding_varg
mut arg_no := 0 mut arg_no := 0
for arg in args { for arg in args {
@ -427,7 +433,7 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
} }
[inline] [inline]
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs
expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs
if arg.is_mut && !arg_is_ptr { if arg.is_mut && !arg_is_ptr {
@ -454,7 +460,7 @@ fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
g.expr_with_cast(arg.expr, arg.typ, expected_type) g.expr_with_cast(arg.expr, arg.typ, expected_type)
} }
fn (g mut Gen) is_gui_app() bool { fn (mut g Gen) is_gui_app() bool {
$if windows { $if windows {
for cf in g.table.cflags { for cf in g.table.cflags {
if cf.value == 'gdi32' { if cf.value == 'gdi32' {

View File

@ -7,7 +7,7 @@ import v.ast
import v.table import v.table
import v.token import v.token
fn (var p Parser) struct_decl() ast.StructDecl { fn (mut p Parser) struct_decl() ast.StructDecl {
start_pos := p.tok.position() start_pos := p.tok.position()
is_pub := p.tok.kind == .key_pub is_pub := p.tok.kind == .key_pub
if is_pub { if is_pub {
@ -31,17 +31,17 @@ fn (var p Parser) struct_decl() ast.StructDecl {
p.error('`$p.tok.lit` lacks body') p.error('`$p.tok.lit` lacks body')
} }
end_pos := p.tok.position() end_pos := p.tok.position()
var name := p.check_name() mut name := p.check_name()
// println('struct decl $name') // println('struct decl $name')
var ast_fields := []ast.StructField mut ast_fields := []ast.StructField
var fields := []table.Field mut fields := []table.Field
var mut_pos := -1 mut mut_pos := -1
var pub_pos := -1 mut pub_pos := -1
var pub_mut_pos := -1 mut pub_mut_pos := -1
if !no_body { if !no_body {
p.check(.lcbr) p.check(.lcbr)
for p.tok.kind != .rcbr { for p.tok.kind != .rcbr {
var comment := ast.Comment{} mut comment := ast.Comment{}
if p.tok.kind == .comment { if p.tok.kind == .comment {
comment = p.comment() comment = p.comment()
} }
@ -72,8 +72,8 @@ fn (var p Parser) struct_decl() ast.StructDecl {
println('XXXX' + s.str()) println('XXXX' + s.str())
} }
*/ */
var default_expr := ast.Expr{} mut default_expr := ast.Expr{}
var has_default_expr := false mut has_default_expr := false
if p.tok.kind == .assign { if p.tok.kind == .assign {
// Default value // Default value
p.next() p.next()
@ -81,15 +81,13 @@ fn (var p Parser) struct_decl() ast.StructDecl {
// p.expr(0) // p.expr(0)
default_expr = p.expr(0) default_expr = p.expr(0)
match default_expr { match default_expr {
ast.EnumVal { ast.EnumVal { it.typ = typ }
it.typ = typ
}
// TODO: implement all types?? // TODO: implement all types??
else {} else {}
} }
has_default_expr = true has_default_expr = true
} }
var attr := ast.Attr{} mut attr := ast.Attr{}
if p.tok.kind == .lsbr { if p.tok.kind == .lsbr {
attr = p.attribute() attr = p.attribute()
} }
@ -132,7 +130,7 @@ fn (var p Parser) struct_decl() ast.StructDecl {
} }
mod: p.mod mod: p.mod
} }
var ret := 0 mut ret := 0
if p.builtin_mod && t.name in table.builtin_type_names { if p.builtin_mod && t.name in table.builtin_type_names {
// this allows overiding the builtins type // this allows overiding the builtins type
// with the real struct type info parsed from builtin // with the real struct type info parsed from builtin
@ -158,7 +156,7 @@ fn (var p Parser) struct_decl() ast.StructDecl {
} }
} }
fn (var p Parser) struct_init(short_syntax bool) ast.StructInit { fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
first_pos := p.tok.position() first_pos := p.tok.position()
typ := if short_syntax { table.void_type } else { p.parse_type() } typ := if short_syntax { table.void_type } else { p.parse_type() }
p.expr_mod = '' p.expr_mod = ''
@ -167,17 +165,17 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit {
if !short_syntax { if !short_syntax {
p.check(.lcbr) p.check(.lcbr)
} }
var fields := []ast.StructInitField mut fields := []ast.StructInitField
var i := 0 mut i := 0
is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr // `Vec{a,b,c} is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr // `Vec{a,b,c}
// p.warn(is_short_syntax.str()) // p.warn(is_short_syntax.str())
for p.tok.kind != .rcbr { for p.tok.kind != .rcbr {
p.check_comment() p.check_comment()
var field_name := '' mut field_name := ''
if is_short_syntax { if is_short_syntax {
expr := p.expr(0) expr := p.expr(0)
fields << ast.StructInitField{
// name will be set later in checker // name will be set later in checker
fields << ast.StructInitField{
expr: expr expr: expr
pos: expr.position() pos: expr.position()
} }
@ -221,28 +219,57 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit {
return node return node
} }
fn (var p Parser) interface_decl() ast.InterfaceDecl { fn (mut p Parser) interface_decl() ast.InterfaceDecl {
is_pub := p.tok.kind == .key_pub is_pub := p.tok.kind == .key_pub
if is_pub { if is_pub {
p.next() p.next()
} }
p.next() // `interface` p.next() // `interface`
interface_name := p.check_name() interface_name := p.check_name()
//println('interface decl $interface_name')
p.check(.lcbr) p.check(.lcbr)
var field_names := []string // Declare the type
t := table.TypeSymbol{
kind: .interface_
name: interface_name
info: table.Struct{
//is_interface: true
}
}
typ := p.table.register_type_symbol(t)
ts := p.table.get_type_symbol(typ) // TODO t vs ts
// Parse methods
mut methods := []ast.FnDecl
for p.tok.kind != .rcbr && p.tok.kind != .eof { for p.tok.kind != .rcbr && p.tok.kind != .eof {
line_nr := p.tok.line_nr line_nr := p.tok.line_nr
name := p.check_name() name := p.check_name()
field_names << name println(name)
p.fn_args() // field_names << name
if p.tok.kind == .name && p.tok.line_nr == line_nr { args2, _ := p.fn_args()
p.parse_type() mut args := [table.Arg{
name: 'x'
typ: typ
}]
args << args2
mut method := ast.FnDecl{
name: name
args: args
return_type: table.void_type
} }
if p.tok.kind == .name && p.tok.line_nr == line_nr {
method.return_type = p.parse_type()
}
methods << method
//println('register method $name')
ts.register_method(table.Fn{
name: name
args: args
return_type: method.return_type
})
} }
p.check(.rcbr) p.check(.rcbr)
return ast.InterfaceDecl{ return ast.InterfaceDecl{
name: interface_name name: interface_name
field_names: field_names methods: methods
} }
} }

View File

@ -16,7 +16,7 @@ import v.ast
pub type Type int pub type Type int
pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Alias | Enum | SumType | FnType pub type TypeInfo = Array | ArrayFixed | Map | Struct | Interface | MultiReturn | Alias | Enum | SumType | FnType
pub struct TypeSymbol { pub struct TypeSymbol {
pub: pub:
@ -160,10 +160,18 @@ pub const (
pub const ( pub const (
integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
u16_type_idx, u32_type_idx, u64_type_idx] u16_type_idx
u32_type_idx
u64_type_idx
]
float_type_idxs = [f32_type_idx, f64_type_idx] float_type_idxs = [f32_type_idx, f64_type_idx]
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx, number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
u16_type_idx, u32_type_idx, u64_type_idx, f32_type_idx, f64_type_idx] u16_type_idx
u32_type_idx
u64_type_idx
f32_type_idx
f64_type_idx
]
pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx] pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
string_type_idxs = [string_type_idx, ustring_type_idx] string_type_idxs = [string_type_idx, ustring_type_idx]
) )
@ -194,8 +202,10 @@ pub const (
pub const ( pub const (
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64',
'u16', 'u32', 'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed', 'u16'
'map', 'struct', 'mapnode', 'size_t'] 'u32', 'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array',
'array_fixed', 'map'
'struct', 'mapnode', 'size_t']
) )
pub struct MultiReturn { pub struct MultiReturn {
@ -242,6 +252,7 @@ pub enum Kind {
alias alias
enum_ enum_
function function
interface_
} }
pub fn (t &TypeSymbol) str() string { pub fn (t &TypeSymbol) str() string {
@ -251,60 +262,40 @@ pub fn (t &TypeSymbol) str() string {
[inline] [inline]
pub fn (t &TypeSymbol) enum_info() Enum { pub fn (t &TypeSymbol) enum_info() Enum {
match t.info { match t.info {
Enum { Enum { return it }
return it else { panic('TypeSymbol.enum_info(): no enum info for type: $t.name') }
}
else {
panic('TypeSymbol.enum_info(): no enum info for type: $t.name')
}
} }
} }
[inline] [inline]
pub fn (t &TypeSymbol) mr_info() MultiReturn { pub fn (t &TypeSymbol) mr_info() MultiReturn {
match t.info { match t.info {
MultiReturn { MultiReturn { return it }
return it else { panic('TypeSymbol.mr_info(): no multi return info for type: $t.name') }
}
else {
panic('TypeSymbol.mr_info(): no multi return info for type: $t.name')
}
} }
} }
[inline] [inline]
pub fn (t &TypeSymbol) array_info() Array { pub fn (t &TypeSymbol) array_info() Array {
match t.info { match t.info {
Array { Array { return it }
return it else { panic('TypeSymbol.array_info(): no array info for type: $t.name') }
}
else {
panic('TypeSymbol.array_info(): no array info for type: $t.name')
}
} }
} }
[inline] [inline]
pub fn (t &TypeSymbol) array_fixed_info() ArrayFixed { pub fn (t &TypeSymbol) array_fixed_info() ArrayFixed {
match t.info { match t.info {
ArrayFixed { ArrayFixed { return it }
return it else { panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name') }
}
else {
panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name')
}
} }
} }
[inline] [inline]
pub fn (t &TypeSymbol) map_info() Map { pub fn (t &TypeSymbol) map_info() Map {
match t.info { match t.info {
Map { Map { return it }
return it else { panic('TypeSymbol.map_info(): no map info for type: $t.name') }
}
else {
panic('TypeSymbol.map_info(): no map info for type: $t.name')
}
} }
} }
@ -313,7 +304,7 @@ pub fn (t TypeSymbol) str() string {
return t.name return t.name
} }
*/ */
pub fn (var t Table) register_builtin_type_symbols() { pub fn (mut t Table) register_builtin_type_symbols() {
// reserve index 0 so nothing can go there // reserve index 0 so nothing can go there
// save index check, 0 will mean not found // save index check, 0 will mean not found
t.register_type_symbol(TypeSymbol{ t.register_type_symbol(TypeSymbol{
@ -445,99 +436,40 @@ pub fn (t &TypeSymbol) is_number() bool {
pub fn (k Kind) str() string { pub fn (k Kind) str() string {
k_str := match k { k_str := match k {
.placeholder { .placeholder { 'placeholder' }
'placeholder' .void { 'void' }
} .voidptr { 'voidptr' }
.void { .charptr { 'charptr' }
'void' .byteptr { 'byteptr' }
} .struct_ { 'struct' }
.voidptr { .int { 'int' }
'voidptr' .i8 { 'i8' }
} .i16 { 'i16' }
.charptr { .i64 { 'i64' }
'charptr' .byte { 'byte' }
} .u16 { 'u16' }
.byteptr { .u32 { 'u32' }
'byteptr' .u64 { 'u64' }
} .f32 { 'f32' }
.struct_ { .f64 { 'f64' }
'struct' .string { 'string' }
} .char { 'char' }
.int { .bool { 'bool' }
'int' .none_ { 'none' }
} .array { 'array' }
.i8 { .array_fixed { 'array_fixed' }
'i8' .map { 'map' }
} .multi_return { 'multi_return' }
.i16 { .sum_type { 'sum_type' }
'i16' .alias { 'alias' }
} .enum_ { 'enum' }
.i64 { else { 'unknown' }
'i64'
}
.byte {
'byte'
}
.u16 {
'u16'
}
.u32 {
'u32'
}
.u64 {
'u64'
}
.f32 {
'f32'
}
.f64 {
'f64'
}
.string {
'string'
}
.ustring {
'ustring'
}
.char {
'char'
}
.bool {
'bool'
}
.none_ {
'none'
}
.array {
'array'
}
.array_fixed {
'array_fixed'
}
.map {
'map'
}
.multi_return {
'multi_return'
}
.sum_type {
'sum_type'
}
.alias {
'alias'
}
.enum_ {
'enum'
}
else {
'unknown'
}
} }
return k_str return k_str
} }
pub fn (kinds []Kind) str() string { pub fn (kinds []Kind) str() string {
var kinds_str := '' mut kinds_str := ''
for i, k in kinds { for i, k in kinds {
kinds_str += k.str() kinds_str += k.str()
if i < kinds.len - 1 { if i < kinds.len - 1 {
@ -554,6 +486,10 @@ pub mut:
is_union bool is_union bool
} }
pub struct Interface {
gen_types []string
}
pub struct Enum { pub struct Enum {
pub: pub:
vals []string vals []string
@ -604,7 +540,7 @@ pub:
pub fn (table &Table) type_to_str(t Type) string { pub fn (table &Table) type_to_str(t Type) string {
sym := table.get_type_symbol(t) sym := table.get_type_symbol(t)
if sym.kind == .multi_return { if sym.kind == .multi_return {
var res := '(' mut res := '('
mr_info := sym.info as MultiReturn mr_info := sym.info as MultiReturn
for i, typ in mr_info.types { for i, typ in mr_info.types {
res += table.type_to_str(typ) res += table.type_to_str(typ)
@ -615,7 +551,7 @@ pub fn (table &Table) type_to_str(t Type) string {
res += ')' res += ')'
return res return res
} }
var res := sym.name mut res := sym.name
if sym.kind == .array { if sym.kind == .array {
res = res.replace('array_', '[]') res = res.replace('array_', '[]')
} else if sym.kind == .map { } else if sym.kind == .map {

View File

@ -22,12 +22,40 @@ fn (d Dog) name() string {
return 'Dog' return 'Dog'
} }
fn test_todo() {} fn test_todo() {
if true {}
//
else{}
}
interface Speaker { interface Speaker {
name ()string name() string
speak() speak()
}
/*
fn perform_speak(s Speaker) {
s.speak()
assert true
/*
name := s.name()
assert name == 'Dog' || name == 'Cat'
println(s.name())
*/
}
fn test_perform_speak() {
dog := Dog{}
perform_speak(dog)
cat := Cat{}
perform_speak(cat)
// perform_speakers([dog, cat])
/*
f := Foo {
speaker: dog
} }
*/
}
/* /*
interface Speak2er { interface Speak2er {
@ -40,37 +68,8 @@ struct Foo {
speakers []Speaker speakers []Speaker
} }
fn perform_speak(s Speaker) {
if true {
// QTODO
return
}
s.speak()
assert true
name := s.name()
assert name == 'Dog' || name == 'Cat'
println(s.name())
}
fn perform_speakers(speakers []Speaker) {} fn perform_speakers(speakers []Speaker) {}
fn test_perform_speak() {
if true {
// QTODO
return
}
dog := Dog{}
perform_speak(dog)
cat := Cat{}
perform_speak(cat)
// perform_speakers([dog, cat])
/*
f := Foo {
speaker: dog
}
*/
}
interface Register { interface Register {
register()} register()}
@ -93,3 +92,4 @@ fn test_register() {
handle_reg(f) handle_reg(f)
} }
*/ */
*/