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:
name string
field_names []string
methods []FnDecl
}
pub struct StructInitField {
@ -541,7 +542,6 @@ pub:
name string
is_pub bool
fields []EnumField
// default_exprs []Expr
pos token.Position
}
@ -739,22 +739,46 @@ pub fn expr_is_call(expr Expr) bool {
fn (expr Expr) position() token.Position {
// all uncommented have to be implemented
match var expr {
ArrayInit { return it.pos }
AsCast { return it.pos }
match mut expr {
ArrayInit {
return it.pos
}
AsCast {
return it.pos
}
// ast.Ident { }
AssignExpr { return it.pos }
AssignExpr {
return it.pos
}
// ast.CastExpr { }
Assoc { return it.pos }
BoolLiteral { return it.pos }
CallExpr { return it.pos }
CharLiteral { return it.pos }
EnumVal { return it.pos }
FloatLiteral { return it.pos }
Ident { return it.pos }
IfExpr { return it.pos }
Assoc {
return it.pos
}
BoolLiteral {
return it.pos
}
CallExpr {
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 { }
IndexExpr { return it.pos }
IndexExpr {
return it.pos
}
InfixExpr {
left_pos := it.left.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
}
}
IntegerLiteral { return it.pos }
MapInit { return it.pos }
MatchExpr { return it.pos }
PostfixExpr { return it.pos }
IntegerLiteral {
return it.pos
}
MapInit {
return it.pos
}
MatchExpr {
return it.pos
}
PostfixExpr {
return it.pos
}
// ast.None { }
PrefixExpr { return it.pos }
PrefixExpr {
return it.pos
}
// ast.ParExpr { }
SelectorExpr { return it.pos }
SelectorExpr {
return it.pos
}
// ast.SizeOf { }
StringLiteral { return it.pos }
StringInterLiteral { return it.pos }
StringLiteral {
return it.pos
}
StringInterLiteral {
return it.pos
}
// ast.Type { }
StructInit { return it.pos }
StructInit {
return it.pos
}
// 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')
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 }
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)
} else if !method.is_variadic && call_expr.args.len > no_args {
c.error('too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $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 $nr_args)',
call_expr.pos)
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
}
}
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
}

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() {
6| t := Test{}
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
// 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 {
f.mod(it)
}

View File

@ -151,17 +151,11 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
}
//
g.finish()
return g.hashes() +
'\n// V typedefs:\n' + g.typedefs.str() +
'\n// V typedefs2:\n' + g.typedefs2.str() +
'\n// V cheaders:\n' + g.cheaders.str() +
'\n// V includes:\n' + g.includes.str() +
'\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.'
return g.hashes() + '\n// V typedefs:\n' + g.typedefs.str() + '\n// V typedefs2:\n' + g.typedefs2.str() +
'\n// V cheaders:\n' + g.cheaders.str() + '\n// V includes:\n' + g.includes.str() + '\n// V definitions:\n' +
g.definitions.str() + g.interface_table() + '\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 {
@ -400,10 +394,10 @@ fn (mut g Gen) stmt(node ast.Stmt) {
match node {
ast.InterfaceDecl {
g.writeln('//interface')
g.writeln('struct $it.name {')
g.writeln('typedef struct {')
g.writeln('\tvoid* _object;')
g.writeln('\tint _interface_idx;')
g.writeln('};')
g.writeln('} $it.name;')
}
ast.AssertStmt {
g.gen_assert_stmt(it)
@ -458,11 +452,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
cur_enum_expr = expr_str
cur_enum_offset = 0
}
cur_value := if cur_enum_offset > 0 {
'${cur_enum_expr}+${cur_enum_offset}'
} else {
cur_enum_expr
}
cur_value := if cur_enum_offset > 0 { '${cur_enum_expr}+${cur_enum_offset}' } else { cur_enum_expr }
g.typedefs.writeln(', // ${cur_value}')
cur_enum_offset++
}
@ -2221,6 +2211,9 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
}
// loop over types
for t in typesa {
if t.kind == .interface_ {
continue
}
// create list of deps
mut field_deps := []string
match t.info {
@ -2232,6 +2225,9 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
}
table.Struct {
info := t.info as table.Struct
// if info.is_interface {
// continue
// }
for field in info.fields {
dep := g.table.get_type_symbol(field.typ).name
// skip if not in types list or already in deps
@ -2297,15 +2293,15 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
} else if sym.kind in [.struct_, .map] && !sym.has_method('str') {
g.write('%.*s')
} else if node.expr_types[i] == table.i16_type {
g.write('%"PRId16"')
g.write('%"PRId16"')
} else if node.expr_types[i] == table.u16_type {
g.write('%"PRIu16"')
g.write('%"PRIu16"')
} else if node.expr_types[i] == table.u32_type {
g.write('%"PRIu32"')
g.write('%"PRIu32"')
} else if node.expr_types[i] == table.i64_type {
g.write('%"PRId64"')
g.write('%"PRId64"')
} else if node.expr_types[i] == table.u64_type {
g.write('%"PRIu64"')
g.write('%"PRIu64"')
} else {
g.write('%"PRId32"')
}
@ -2849,14 +2845,14 @@ fn (mut g Gen) is_expr(node ast.InfixExpr) {
}
fn styp_to_str_fn_name(styp string) string {
res := styp.replace('.', '__').replace('*','_ptr') + '_str'
res := styp.replace('.', '__').replace('*', '_ptr') + '_str'
return res
}
// 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}'
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
}
g.str_types << already_generated_key
@ -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 typename := ''
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('}')
}
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('.', '__')
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 */')
@ -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('}')
}
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
// generates all definitions of substructs
mut fnames2strfunc := map[string]string
mut fnames2strfunc := {
'': ''
} // map[string]string // TODO vfmt bug
for i, field in info.fields {
sym := g.table.get_type_symbol(field.typ)
if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] {
field_styp := g.typ(field.typ)
field_fn_name := styp_to_str_fn_name( field_styp )
fnames2strfunc[ field_styp ] = field_fn_name
field_fn_name := styp_to_str_fn_name(field_styp)
fnames2strfunc[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.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('*') {
deref_typ := styp.replace('*', '')
g.auto_str_funcs.writeln('\t${deref_typ} *it = x;')
clean_struct_v_type_name = '&' + clean_struct_v_type_name.replace('*', '')
}else{
} else {
deref_typ := styp
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 {
sym := g.table.get_type_symbol(field.typ)
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_fn_name := if has_custom_str {'${field_styp}_str'} else {fnames2strfunc[ field_styp ]}
if sym.kind == .enum_ {
field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] }
if sym.kind == .enum_ {
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} ).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('${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 ')
@ -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('}')
}
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)
field_styp := g.typ(info.elem_type)
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.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('}')
}
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_styp := g.typ(info.key_type)
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'
}
// 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.
module gen
import (
v.ast
v.table
v.util
)
import v.ast
import v.table
import 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 {
// || it.no_body {
return
@ -88,7 +86,6 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
g.writeln('\tint ___argc;')
g.writeln('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);')
}
g.writeln('\t_vinit();')
if g.is_importing_os() {
if g.autofree {
@ -126,11 +123,11 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
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'
for i, arg in args {
arg_type_sym := g.table.get_type_symbol(arg.typ)
mut arg_type_name := g.typ(arg.typ) // arg_type_sym.name.replace('.', '__')
mut arg_type_name := g.typ(arg.typ) // arg_type_sym.name.replace('.', '__')
is_varg := i == args.len - 1 && is_variadic
if is_varg {
varg_type_str := int(arg.typ).str()
@ -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
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
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)
if node.left_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs')
}
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
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' {
g.gen_filter(node)
return
}
// TODO performance, detect `array` method differently
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' && receiver_name.starts_with('array') {
// `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
// TODO: test node.left instead
// 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)
if table.type_is_ptr(node.left_type) {
g.write('->')
}
else {
} else {
g.write('.')
}
}
@ -322,15 +334,9 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
} else {
expr := node.args[0].expr
is_var := match expr {
ast.SelectorExpr {
true
}
ast.Ident {
true
}
else {
false
}
ast.SelectorExpr { true }
ast.Ident { true }
else { false }
}
if table.type_is_ptr(typ) && sym.kind != .struct_ {
// ptr_str() for pointers
@ -361,7 +367,7 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
}
g.expr(expr)
if sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
g.write(', 0') // trailing 0 is initial struct indent count
g.write(', 0') // trailing 0 is initial struct indent count
}
}
g.write('))')
@ -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 -
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
mut arg_no := 0
for arg in args {
@ -427,7 +433,7 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
}
[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
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 {
@ -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)
}
fn (g mut Gen) is_gui_app() bool {
fn (mut g Gen) is_gui_app() bool {
$if windows {
for cf in g.table.cflags {
if cf.value == 'gdi32' {

View File

@ -7,7 +7,7 @@ import v.ast
import v.table
import v.token
fn (var p Parser) struct_decl() ast.StructDecl {
fn (mut p Parser) struct_decl() ast.StructDecl {
start_pos := p.tok.position()
is_pub := p.tok.kind == .key_pub
if is_pub {
@ -22,8 +22,8 @@ fn (var p Parser) struct_decl() ast.StructDecl {
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
is_js := p.tok.lit == 'JS' && p.peek_tok.kind == .dot
if is_c {
p.next() // C || JS
p.next() // .
p.next() // C || JS
p.next() // .
}
is_typedef := p.attr == 'typedef'
no_body := p.peek_tok.kind != .lcbr
@ -31,17 +31,17 @@ fn (var p Parser) struct_decl() ast.StructDecl {
p.error('`$p.tok.lit` lacks body')
}
end_pos := p.tok.position()
var name := p.check_name()
mut name := p.check_name()
// println('struct decl $name')
var ast_fields := []ast.StructField
var fields := []table.Field
var mut_pos := -1
var pub_pos := -1
var pub_mut_pos := -1
mut ast_fields := []ast.StructField
mut fields := []table.Field
mut mut_pos := -1
mut pub_pos := -1
mut pub_mut_pos := -1
if !no_body {
p.check(.lcbr)
for p.tok.kind != .rcbr {
var comment := ast.Comment{}
mut comment := ast.Comment{}
if p.tok.kind == .comment {
comment = p.comment()
}
@ -72,8 +72,8 @@ fn (var p Parser) struct_decl() ast.StructDecl {
println('XXXX' + s.str())
}
*/
var default_expr := ast.Expr{}
var has_default_expr := false
mut default_expr := ast.Expr{}
mut has_default_expr := false
if p.tok.kind == .assign {
// Default value
p.next()
@ -81,15 +81,13 @@ fn (var p Parser) struct_decl() ast.StructDecl {
// p.expr(0)
default_expr = p.expr(0)
match default_expr {
ast.EnumVal {
it.typ = typ
}
ast.EnumVal { it.typ = typ }
// TODO: implement all types??
else {}
}
has_default_expr = true
}
var attr := ast.Attr{}
mut attr := ast.Attr{}
if p.tok.kind == .lsbr {
attr = p.attribute()
}
@ -132,7 +130,7 @@ fn (var p Parser) struct_decl() ast.StructDecl {
}
mod: p.mod
}
var ret := 0
mut ret := 0
if p.builtin_mod && t.name in table.builtin_type_names {
// this allows overiding the builtins type
// 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()
typ := if short_syntax { table.void_type } else { p.parse_type() }
p.expr_mod = ''
@ -167,17 +165,17 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit {
if !short_syntax {
p.check(.lcbr)
}
var fields := []ast.StructInitField
var i := 0
is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr // `Vec{a,b,c}
mut fields := []ast.StructInitField
mut i := 0
is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr // `Vec{a,b,c}
// p.warn(is_short_syntax.str())
for p.tok.kind != .rcbr {
p.check_comment()
var field_name := ''
mut field_name := ''
if is_short_syntax {
expr := p.expr(0)
// name will be set later in checker
fields << ast.StructInitField{
// name will be set later in checker
expr: expr
pos: expr.position()
}
@ -221,28 +219,57 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit {
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
if is_pub {
p.next()
}
p.next() // `interface`
p.next() // `interface`
interface_name := p.check_name()
//println('interface decl $interface_name')
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 {
line_nr := p.tok.line_nr
name := p.check_name()
field_names << name
p.fn_args()
if p.tok.kind == .name && p.tok.line_nr == line_nr {
p.parse_type()
println(name)
// field_names << name
args2, _ := p.fn_args()
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)
return ast.InterfaceDecl{
name: interface_name
field_names: field_names
methods: methods
}
}

View File

@ -16,7 +16,7 @@ import v.ast
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:
@ -160,10 +160,18 @@ pub const (
pub const (
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]
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]
string_type_idxs = [string_type_idx, ustring_type_idx]
)
@ -194,8 +202,10 @@ pub const (
pub const (
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',
'map', 'struct', 'mapnode', 'size_t']
'u16'
'u32', 'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array',
'array_fixed', 'map'
'struct', 'mapnode', 'size_t']
)
pub struct MultiReturn {
@ -242,6 +252,7 @@ pub enum Kind {
alias
enum_
function
interface_
}
pub fn (t &TypeSymbol) str() string {
@ -251,60 +262,40 @@ pub fn (t &TypeSymbol) str() string {
[inline]
pub fn (t &TypeSymbol) enum_info() Enum {
match t.info {
Enum {
return it
}
else {
panic('TypeSymbol.enum_info(): no enum info for type: $t.name')
}
Enum { return it }
else { panic('TypeSymbol.enum_info(): no enum info for type: $t.name') }
}
}
[inline]
pub fn (t &TypeSymbol) mr_info() MultiReturn {
match t.info {
MultiReturn {
return it
}
else {
panic('TypeSymbol.mr_info(): no multi return info for type: $t.name')
}
MultiReturn { return it }
else { panic('TypeSymbol.mr_info(): no multi return info for type: $t.name') }
}
}
[inline]
pub fn (t &TypeSymbol) array_info() Array {
match t.info {
Array {
return it
}
else {
panic('TypeSymbol.array_info(): no array info for type: $t.name')
}
Array { return it }
else { panic('TypeSymbol.array_info(): no array info for type: $t.name') }
}
}
[inline]
pub fn (t &TypeSymbol) array_fixed_info() ArrayFixed {
match t.info {
ArrayFixed {
return it
}
else {
panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name')
}
ArrayFixed { return it }
else { panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name') }
}
}
[inline]
pub fn (t &TypeSymbol) map_info() Map {
match t.info {
Map {
return it
}
else {
panic('TypeSymbol.map_info(): no map info for type: $t.name')
}
Map { return it }
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
}
*/
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
// save index check, 0 will mean not found
t.register_type_symbol(TypeSymbol{
@ -445,99 +436,40 @@ pub fn (t &TypeSymbol) is_number() bool {
pub fn (k Kind) str() string {
k_str := match k {
.placeholder {
'placeholder'
}
.void {
'void'
}
.voidptr {
'voidptr'
}
.charptr {
'charptr'
}
.byteptr {
'byteptr'
}
.struct_ {
'struct'
}
.int {
'int'
}
.i8 {
'i8'
}
.i16 {
'i16'
}
.i64 {
'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'
}
.placeholder { 'placeholder' }
.void { 'void' }
.voidptr { 'voidptr' }
.charptr { 'charptr' }
.byteptr { 'byteptr' }
.struct_ { 'struct' }
.int { 'int' }
.i8 { 'i8' }
.i16 { 'i16' }
.i64 { 'i64' }
.byte { 'byte' }
.u16 { 'u16' }
.u32 { 'u32' }
.u64 { 'u64' }
.f32 { 'f32' }
.f64 { 'f64' }
.string { 'string' }
.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
}
pub fn (kinds []Kind) str() string {
var kinds_str := ''
mut kinds_str := ''
for i, k in kinds {
kinds_str += k.str()
if i < kinds.len - 1 {
@ -554,6 +486,10 @@ pub mut:
is_union bool
}
pub struct Interface {
gen_types []string
}
pub struct Enum {
pub:
vals []string
@ -604,7 +540,7 @@ pub:
pub fn (table &Table) type_to_str(t Type) string {
sym := table.get_type_symbol(t)
if sym.kind == .multi_return {
var res := '('
mut res := '('
mr_info := sym.info as MultiReturn
for i, typ in mr_info.types {
res += table.type_to_str(typ)
@ -615,7 +551,7 @@ pub fn (table &Table) type_to_str(t Type) string {
res += ')'
return res
}
var res := sym.name
mut res := sym.name
if sym.kind == .array {
res = res.replace('array_', '[]')
} else if sym.kind == .map {

View File

@ -22,12 +22,40 @@ fn (d Dog) name() string {
return 'Dog'
}
fn test_todo() {}
fn test_todo() {
if true {}
//
else{}
}
interface Speaker {
name ()string
name() string
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 {
@ -40,37 +68,8 @@ struct Foo {
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 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 {
register()}
@ -93,3 +92,4 @@ fn test_register() {
handle_reg(f)
}
*/
*/