all: interface arrays
parent
3d8853af2b
commit
2fc05b814c
|
@ -644,6 +644,9 @@ pub:
|
||||||
has_cap bool
|
has_cap bool
|
||||||
cap_expr Expr
|
cap_expr Expr
|
||||||
mut:
|
mut:
|
||||||
|
is_interface bool // array of interfaces e.g. `[]Animal` `[Dog{}, Cat{}]`
|
||||||
|
interface_types []table.Type // [Dog, Cat]
|
||||||
|
interface_type table.Type // Animal
|
||||||
elem_type table.Type
|
elem_type table.Type
|
||||||
typ table.Type
|
typ table.Type
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
||||||
c.error('struct name must begin with capital letter', pos)
|
c.error('struct name must begin with capital letter', pos)
|
||||||
}
|
}
|
||||||
for i, field in decl.fields {
|
for i, field in decl.fields {
|
||||||
for j in 0..i {
|
for j in 0 .. i {
|
||||||
if field.name == decl.fields[j].name {
|
if field.name == decl.fields[j].name {
|
||||||
c.error('field name `$field.name` duplicate', field.pos)
|
c.error('field name `$field.name` duplicate', field.pos)
|
||||||
}
|
}
|
||||||
|
@ -367,9 +367,8 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
||||||
return table.bool_type
|
return table.bool_type
|
||||||
}
|
}
|
||||||
.plus, .minus, .mul, .div {
|
.plus, .minus, .mul, .div {
|
||||||
if infix_expr.op == .div &&
|
if infix_expr.op == .div && (infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() ==
|
||||||
(infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == '0' ||
|
'0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) {
|
||||||
infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) {
|
|
||||||
c.error('division by zero', infix_expr.right.position())
|
c.error('division by zero', infix_expr.right.position())
|
||||||
}
|
}
|
||||||
if left.kind in [.array, .array_fixed, .map, .struct_] && !left.has_method(infix_expr.op.str()) {
|
if left.kind in [.array, .array_fixed, .map, .struct_] && !left.has_method(infix_expr.op.str()) {
|
||||||
|
@ -743,7 +742,8 @@ pub fn (mut c Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
|
||||||
if !found_in_args && call_expr.mod in ['builtin', 'main'] {
|
if !found_in_args && call_expr.mod in ['builtin', 'main'] {
|
||||||
scope := c.file.scope.innermost(call_expr.pos.pos)
|
scope := c.file.scope.innermost(call_expr.pos.pos)
|
||||||
if _ := scope.find_var(fn_name) {
|
if _ := scope.find_var(fn_name) {
|
||||||
c.error('ambiguous call to: `$fn_name`, may refer to fn `$fn_name` or variable `$fn_name`', call_expr.pos)
|
c.error('ambiguous call to: `$fn_name`, may refer to fn `$fn_name` or variable `$fn_name`',
|
||||||
|
call_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
call_expr.return_type = f.return_type
|
call_expr.return_type = f.return_type
|
||||||
|
@ -1117,27 +1117,49 @@ pub fn (mut c Checker) array_init(array_init mut ast.ArrayInit) table.Type {
|
||||||
}
|
}
|
||||||
// [1,2,3]
|
// [1,2,3]
|
||||||
if array_init.exprs.len > 0 && array_init.elem_type == table.void_type {
|
if array_init.exprs.len > 0 && array_init.elem_type == table.void_type {
|
||||||
expecting_interface_array := c.expected_type != 0 && c.table.get_type_symbol(c.table.value_type(c.expected_type)).kind ==
|
mut expected_value_type := table.void_type
|
||||||
.interface_
|
mut expecting_interface_array := false
|
||||||
|
cap := array_init.exprs.len
|
||||||
|
mut interface_types := []table.Type{cap: cap}
|
||||||
|
if c.expected_type != 0 {
|
||||||
|
expected_value_type = c.table.value_type(c.expected_type)
|
||||||
|
if c.table.get_type_symbol(expected_value_type).kind == .interface_ {
|
||||||
|
// Array of interfaces? (`[dog, cat]`) Save the interface type (`Animal`)
|
||||||
|
expecting_interface_array = true
|
||||||
|
array_init.interface_type = expected_value_type
|
||||||
|
array_init.is_interface = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// expecting_interface_array := c.expected_type != 0 &&
|
||||||
|
// c.table.get_type_symbol(c.table.value_type(c.expected_type)).kind == .interface_
|
||||||
|
//
|
||||||
// if expecting_interface_array {
|
// if expecting_interface_array {
|
||||||
// println('ex $c.expected_type')
|
// println('ex $c.expected_type')
|
||||||
// }
|
// }
|
||||||
for i, expr in array_init.exprs {
|
for i, expr in array_init.exprs {
|
||||||
typ := c.expr(expr)
|
typ := c.expr(expr)
|
||||||
|
if expecting_interface_array {
|
||||||
|
if i == 0 {
|
||||||
|
elem_type = expected_value_type
|
||||||
|
c.expected_type = elem_type
|
||||||
|
}
|
||||||
|
interface_types << typ
|
||||||
|
continue
|
||||||
|
}
|
||||||
// The first element's type
|
// The first element's type
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
elem_type = typ
|
elem_type = typ
|
||||||
c.expected_type = typ
|
c.expected_type = typ
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if expecting_interface_array {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !c.table.check(elem_type, typ) {
|
if !c.table.check(elem_type, typ) {
|
||||||
elem_type_sym := c.table.get_type_symbol(elem_type)
|
elem_type_sym := c.table.get_type_symbol(elem_type)
|
||||||
c.error('expected array element with type `$elem_type_sym.name`', array_init.pos)
|
c.error('expected array element with type `$elem_type_sym.name`', array_init.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if expecting_interface_array {
|
||||||
|
array_init.interface_types = interface_types
|
||||||
|
}
|
||||||
if array_init.is_fixed {
|
if array_init.is_fixed {
|
||||||
idx := c.table.find_or_register_array_fixed(elem_type, array_init.exprs.len, 1)
|
idx := c.table.find_or_register_array_fixed(elem_type, array_init.exprs.len, 1)
|
||||||
array_init.typ = table.new_type(idx)
|
array_init.typ = table.new_type(idx)
|
||||||
|
|
|
@ -996,7 +996,12 @@ fn (mut f Fmt) array_init(it ast.ArrayInit) {
|
||||||
if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type {
|
if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type {
|
||||||
// `x := []string`
|
// `x := []string`
|
||||||
f.write(f.type_to_str(it.typ))
|
f.write(f.type_to_str(it.typ))
|
||||||
f.write('{}')
|
f.write('{')
|
||||||
|
if it.has_cap {
|
||||||
|
f.write('cap: ')
|
||||||
|
f.expr(it.cap_expr)
|
||||||
|
}
|
||||||
|
f.write('}')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// `[1,2,3]`
|
// `[1,2,3]`
|
||||||
|
|
|
@ -450,7 +450,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
ast.Attr {
|
ast.Attr {
|
||||||
g.attr = it.name
|
g.attr = it.name
|
||||||
if it.name == 'inline' {
|
if it.name == 'inline' {
|
||||||
//g.writeln(it.name)
|
// g.writeln(it.name)
|
||||||
} else {
|
} else {
|
||||||
g.writeln('//[$it.name]')
|
g.writeln('//[$it.name]')
|
||||||
}
|
}
|
||||||
|
@ -517,14 +517,14 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
mut skip := false
|
mut skip := false
|
||||||
pos := g.out.buf.len
|
pos := g.out.buf.len
|
||||||
if g.pref.build_mode==.build_module {
|
if g.pref.build_mode == .build_module {
|
||||||
if !it.name.starts_with(g.module_built + '.'){
|
if !it.name.starts_with(g.module_built + '.') {
|
||||||
// Skip functions that don't have to be generated
|
// Skip functions that don't have to be generated
|
||||||
// for this module.
|
// for this module.
|
||||||
skip = true
|
skip = true
|
||||||
}
|
}
|
||||||
if g.is_builtin_mod && g.module_built == 'builtin' {
|
if g.is_builtin_mod && g.module_built == 'builtin' {
|
||||||
skip=false
|
skip = false
|
||||||
}
|
}
|
||||||
if !skip {
|
if !skip {
|
||||||
println('build module `$g.module_built` fn `$it.name`')
|
println('build module `$g.module_built` fn `$it.name`')
|
||||||
|
@ -606,7 +606,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
g.definitions.writeln('} $it.name;')
|
g.definitions.writeln('} $it.name;')
|
||||||
}
|
}
|
||||||
ast.Module {
|
ast.Module {
|
||||||
g.is_builtin_mod = it.name=='builtin'
|
g.is_builtin_mod = it.name == 'builtin'
|
||||||
}
|
}
|
||||||
ast.Return {
|
ast.Return {
|
||||||
g.write_defer_stmts_when_needed()
|
g.write_defer_stmts_when_needed()
|
||||||
|
@ -1176,7 +1176,7 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
g.write('.')
|
g.write('.')
|
||||||
}
|
}
|
||||||
if it.expr_type == 0 {
|
if it.expr_type == 0 {
|
||||||
verror('cgen: SelectorExpr typ=0 field=$it.field')
|
verror('cgen: SelectorExpr typ=0 field=$it.field $g.file.path $it.pos.line_nr')
|
||||||
}
|
}
|
||||||
g.write(c_name(it.field))
|
g.write(c_name(it.field))
|
||||||
}
|
}
|
||||||
|
@ -3361,7 +3361,17 @@ ${interface_name} I_${cctype}_to_${interface_name}(${cctype} x) {
|
||||||
|
|
||||||
fn (mut g Gen) array_init(it ast.ArrayInit) {
|
fn (mut g Gen) array_init(it ast.ArrayInit) {
|
||||||
type_sym := g.table.get_type_symbol(it.typ)
|
type_sym := g.table.get_type_symbol(it.typ)
|
||||||
if type_sym.kind != .array_fixed {
|
if type_sym.kind == .array_fixed {
|
||||||
|
g.write('{')
|
||||||
|
for i, expr in it.exprs {
|
||||||
|
g.expr(expr)
|
||||||
|
if i != it.exprs.len - 1 {
|
||||||
|
g.write(', ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.write('}')
|
||||||
|
return
|
||||||
|
}
|
||||||
// elem_sym := g.table.get_type_symbol(it.elem_type)
|
// elem_sym := g.table.get_type_symbol(it.elem_type)
|
||||||
elem_type_str := g.typ(it.elem_type)
|
elem_type_str := g.typ(it.elem_type)
|
||||||
if it.exprs.len == 0 {
|
if it.exprs.len == 0 {
|
||||||
|
@ -3379,24 +3389,22 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
|
||||||
g.write('0, ')
|
g.write('0, ')
|
||||||
}
|
}
|
||||||
g.write('sizeof($elem_type_str))')
|
g.write('sizeof($elem_type_str))')
|
||||||
} else {
|
return
|
||||||
|
}
|
||||||
len := it.exprs.len
|
len := it.exprs.len
|
||||||
g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), ')
|
g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), ')
|
||||||
g.write('($elem_type_str[$len]){\n\t\t')
|
g.write('($elem_type_str[$len]){\n\t\t')
|
||||||
for expr in it.exprs {
|
for i, expr in it.exprs {
|
||||||
|
if it.is_interface {
|
||||||
|
sym := g.table.get_type_symbol(it.interface_types[i])
|
||||||
|
isym := g.table.get_type_symbol(it.interface_type)
|
||||||
|
g.write('I_${sym.name}_to_${isym.name}(')
|
||||||
|
}
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
|
if it.is_interface {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
}
|
}
|
||||||
g.write('\n})')
|
g.write('\n})')
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.write('{')
|
|
||||||
for i, expr in it.exprs {
|
|
||||||
g.expr(expr)
|
|
||||||
if i != it.exprs.len - 1 {
|
|
||||||
g.write(', ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.write('}')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,9 +201,9 @@ pub fn (mut p Parser) close_scope() {
|
||||||
ast.Var {
|
ast.Var {
|
||||||
if !it.is_used && !it.name.starts_with('__') {
|
if !it.is_used && !it.name.starts_with('__') {
|
||||||
if p.pref.is_prod {
|
if p.pref.is_prod {
|
||||||
p.error_with_pos('Unused variable: $it.name', it.pos)
|
p.error_with_pos('unused variable: `$it.name`', it.pos)
|
||||||
} else {
|
} else {
|
||||||
p.warn_with_pos('Unused variable: $it.name', it.pos)
|
p.warn_with_pos('unused variable: `$it.name`', it.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1249,7 +1249,6 @@ fn (mut p Parser) assoc() ast.Assoc {
|
||||||
fields: fields
|
fields: fields
|
||||||
exprs: vals
|
exprs: vals
|
||||||
pos: pos
|
pos: pos
|
||||||
// typ: v.typ
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol {
|
||||||
return &t.types[idx]
|
return &t.types[idx]
|
||||||
}
|
}
|
||||||
// this should never happen
|
// this should never happen
|
||||||
panic('get_type_symbol: invalid type (typ=$typ idx=${idx}). This should never happen')
|
panic('get_type_symbol: invalid type (typ=$typ idx=${idx}). Compiler bug. This should never happen')
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
|
|
|
@ -46,7 +46,7 @@ fn test_perform_speak() {
|
||||||
perform_speak(dog)
|
perform_speak(dog)
|
||||||
cat := Cat{}
|
cat := Cat{}
|
||||||
perform_speak(cat)
|
perform_speak(cat)
|
||||||
//perform_speakers([dog, cat])
|
perform_speakers([dog, cat])
|
||||||
/*
|
/*
|
||||||
f := Foo {
|
f := Foo {
|
||||||
speaker: dog
|
speaker: dog
|
||||||
|
@ -62,6 +62,7 @@ interface Speak2er {
|
||||||
speak()
|
speak()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
speaker Speaker
|
speaker Speaker
|
||||||
speakers []Speaker
|
speakers []Speaker
|
||||||
|
|
Loading…
Reference in New Issue