all: change the way import symbols work & support consts (#7182)
parent
f30faf2627
commit
78a6795319
|
@ -233,16 +233,10 @@ pub mut:
|
||||||
syms []ImportSymbol
|
syms []ImportSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ImportSymbolKind {
|
|
||||||
fn_
|
|
||||||
type_
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ImportSymbol {
|
pub struct ImportSymbol {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
name string
|
name string
|
||||||
kind ImportSymbolKind
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AnonFn {
|
pub struct AnonFn {
|
||||||
|
@ -406,16 +400,17 @@ pub mut:
|
||||||
|
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub:
|
pub:
|
||||||
path string
|
path string
|
||||||
mod Module
|
mod Module
|
||||||
global_scope &Scope
|
global_scope &Scope
|
||||||
pub mut:
|
pub mut:
|
||||||
scope &Scope
|
scope &Scope
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
imports []Import
|
imports []Import
|
||||||
errors []errors.Error
|
imported_symbols map[string]string // 'Type' => 'module.Type'
|
||||||
warnings []errors.Warning
|
errors []errors.Error
|
||||||
generic_fns []&FnDecl
|
warnings []errors.Warning
|
||||||
|
generic_fns []&FnDecl
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IdentFn {
|
pub struct IdentFn {
|
||||||
|
|
|
@ -89,23 +89,11 @@ pub fn (mut c Checker) check_basic(got table.Type, expected table.Type) bool {
|
||||||
if got_idx == table.array_type_idx || exp_idx == table.array_type_idx {
|
if got_idx == table.array_type_idx || exp_idx == table.array_type_idx {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if got_type_sym.kind == .array && exp_type_sym.kind == .array {
|
// TODO
|
||||||
// TODO
|
// accept [] when an expected type is an array
|
||||||
// accept [] when an expected type is an array
|
if got_type_sym.kind == .array &&
|
||||||
if got_type_sym.name == 'array_void' {
|
exp_type_sym.kind == .array && got_type_sym.name == 'array_void' {
|
||||||
return true
|
return true
|
||||||
}
|
|
||||||
// if elem_type is an alias, check it
|
|
||||||
// TODO: think about recursion, how many levels of alias can there be?
|
|
||||||
got_info := got_type_sym.info as table.Array
|
|
||||||
exp_info := exp_type_sym.info as table.Array
|
|
||||||
got_elem_sym := c.table.get_type_symbol(got_info.elem_type)
|
|
||||||
exp_elem_sym := c.table.get_type_symbol(exp_info.elem_type)
|
|
||||||
if (got_elem_sym.kind == .alias ||
|
|
||||||
exp_elem_sym.kind == .alias) &&
|
|
||||||
c.check_basic(got_info.elem_type, exp_info.elem_type) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// type alias
|
// type alias
|
||||||
if (got_type_sym.kind == .alias &&
|
if (got_type_sym.kind == .alias &&
|
||||||
|
|
|
@ -2753,20 +2753,28 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
||||||
fn (mut c Checker) import_stmt(imp ast.Import) {
|
fn (mut c Checker) import_stmt(imp ast.Import) {
|
||||||
for sym in imp.syms {
|
for sym in imp.syms {
|
||||||
name := '${imp.mod}.$sym.name'
|
name := '${imp.mod}.$sym.name'
|
||||||
if sym.kind == .fn_ {
|
if sym.name[0].is_capital() {
|
||||||
c.table.find_fn(name) or {
|
|
||||||
c.error('module `$imp.mod` has no public fn named `${sym.name}()`', sym.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sym.kind == .type_ {
|
|
||||||
if type_sym := c.table.find_type(name) {
|
if type_sym := c.table.find_type(name) {
|
||||||
if type_sym.kind == .placeholder || !type_sym.is_public {
|
if type_sym.kind != .placeholder {
|
||||||
c.error('module `$imp.mod` has no public type `$sym.name{}`', sym.pos)
|
if !type_sym.is_public {
|
||||||
|
c.error('module `$imp.mod` type `$sym.name` is private', sym.pos)
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
c.error('module `$imp.mod` has no public type `$sym.name{}`', sym.pos)
|
|
||||||
}
|
}
|
||||||
|
c.error('module `$imp.mod` has no type `$sym.name`', sym.pos)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
if func := c.table.find_fn(name) {
|
||||||
|
if !func.is_pub {
|
||||||
|
c.error('module `$imp.mod` function `${sym.name}()` is private', sym.pos)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _ := c.file.global_scope.find_const(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.error('module `$imp.mod` has no constant or function `$sym.name`', sym.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3308,9 +3316,13 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prepend mod to look for fn call or const
|
|
||||||
mut name := ident.name
|
mut name := ident.name
|
||||||
if !name.contains('.') && ident.mod != 'builtin' {
|
// check for imported symbol
|
||||||
|
if name in c.file.imported_symbols {
|
||||||
|
name = c.file.imported_symbols[name]
|
||||||
|
}
|
||||||
|
// prepend mod to look for fn call or const
|
||||||
|
else if !name.contains('.') && ident.mod != 'builtin' {
|
||||||
name = '${ident.mod}.$ident.name'
|
name = '${ident.mod}.$ident.name'
|
||||||
}
|
}
|
||||||
if obj := c.file.global_scope.find(name) {
|
if obj := c.file.global_scope.find(name) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/import_symbol_fn_err.vv:1:17: error: module `crypto` has no public fn named `userper()`
|
vlib/v/checker/tests/import_symbol_fn_err.vv:1:17: error: module `crypto` has no constant or function `userper`
|
||||||
1 | import crypto { userper }
|
1 | import crypto { userper }
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
vlib/v/checker/tests/import_symbol_fn_private_err.vv:1:20: error: module `time` function `since()` is private
|
||||||
|
1 | import time { now, since }
|
||||||
|
| ~~~~~
|
||||||
|
2 | fn main() {
|
||||||
|
3 | since(now())
|
||||||
|
vlib/v/checker/tests/import_symbol_fn_private_err.vv:3:3: error: function `time.since` is private. curmod=main fmod=time
|
||||||
|
1 | import time { now, since }
|
||||||
|
2 | fn main() {
|
||||||
|
3 | since(now())
|
||||||
|
| ~~~~~~~~~~~~
|
||||||
|
4 | }
|
|
@ -0,0 +1,4 @@
|
||||||
|
import time { now, since }
|
||||||
|
fn main() {
|
||||||
|
since(now())
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
vlib/v/checker/tests/import_symbol_type_err.vv:1:17: error: module `crypto` has no public type `Coin{}`
|
vlib/v/checker/tests/import_symbol_type_err.vv:1:17: error: module `crypto` has no type `Coin`
|
||||||
1 | import crypto { Coin }
|
1 | import crypto { Coin }
|
||||||
| ~~~~
|
| ~~~~
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | println(Coin{})
|
3 | println(Coin{})
|
||||||
vlib/v/checker/tests/import_symbol_type_err.vv:3:11: error: unknown struct: Coin
|
vlib/v/checker/tests/import_symbol_type_err.vv:3:11: error: unknown struct: crypto.Coin
|
||||||
1 | import crypto { Coin }
|
1 | import crypto { Coin }
|
||||||
2 | fn main() {
|
2 | fn main() {
|
||||||
3 | println(Coin{})
|
3 | println(Coin{})
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
vlib/v/checker/tests/import_symbol_type_private_err.vv:1:13: error: module `io` type `ReaderWriterImpl` is private
|
||||||
|
1 | import io { ReaderWriterImpl }
|
||||||
|
| ~~~~~~~~~~~~~~~~
|
||||||
|
2 | fn main() {
|
||||||
|
3 | _ := ReaderWriterImpl{}
|
||||||
|
vlib/v/checker/tests/import_symbol_type_private_err.vv:3:8: error: type `io.ReaderWriterImpl` is private
|
||||||
|
1 | import io { ReaderWriterImpl }
|
||||||
|
2 | fn main() {
|
||||||
|
3 | _ := ReaderWriterImpl{}
|
||||||
|
| ~~~~~~~~~~~~~~~~~~
|
||||||
|
4 | }
|
|
@ -0,0 +1,4 @@
|
||||||
|
import io { ReaderWriterImpl }
|
||||||
|
fn main() {
|
||||||
|
_ := ReaderWriterImpl{}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/modules/overload_return_type/main.v:14:8: error: cannot assign to `two`: expected `Point`, not `int`
|
vlib/v/checker/tests/modules/overload_return_type/main.v:14:8: error: cannot assign to `two`: expected `point.Point`, not `int`
|
||||||
12 | y: 1
|
12 | y: 1
|
||||||
13 | }
|
13 | }
|
||||||
14 | two = one + two
|
14 | two = one + two
|
||||||
|
|
|
@ -1273,6 +1273,9 @@ pub fn (mut f Fmt) short_module(name string) string {
|
||||||
if !name.contains('.') {
|
if !name.contains('.') {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
if name in f.mod2alias {
|
||||||
|
return f.mod2alias[name]
|
||||||
|
}
|
||||||
if name.ends_with('>') {
|
if name.ends_with('>') {
|
||||||
x := name.trim_suffix('>').split('<')
|
x := name.trim_suffix('>').split('<')
|
||||||
if x.len == 2 {
|
if x.len == 2 {
|
||||||
|
@ -1692,7 +1695,7 @@ pub fn (mut f Fmt) array_init(it ast.ArrayInit) {
|
||||||
f.write('}')
|
f.write('}')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.write(f.table.type_to_str(it.typ))
|
f.write(f.table.type_to_str_using_aliases(it.typ, f.mod2alias))
|
||||||
f.write('{')
|
f.write('{')
|
||||||
// TODO copypasta
|
// TODO copypasta
|
||||||
if it.has_len {
|
if it.has_len {
|
||||||
|
|
|
@ -82,17 +82,13 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
||||||
p.next()
|
p.next()
|
||||||
or_kind = .propagate
|
or_kind = .propagate
|
||||||
}
|
}
|
||||||
mut fn_mod := p.mod
|
if fn_name in p.imported_symbols {
|
||||||
if registered := p.table.find_fn(fn_name) {
|
fn_name = p.imported_symbols[fn_name]
|
||||||
if registered.is_placeholder {
|
|
||||||
fn_mod = registered.mod
|
|
||||||
fn_name = registered.name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ast.CallExpr{
|
return ast.CallExpr{
|
||||||
name: fn_name
|
name: fn_name
|
||||||
args: args
|
args: args
|
||||||
mod: fn_mod
|
mod: p.mod
|
||||||
pos: pos
|
pos: pos
|
||||||
language: language
|
language: language
|
||||||
generic_type: generic_type
|
generic_type: generic_type
|
||||||
|
|
|
@ -217,6 +217,8 @@ pub fn (mut p Parser) parse_any_type(language table.Language, is_ptr bool, check
|
||||||
}
|
}
|
||||||
} else if p.expr_mod != '' && !p.in_generic_params { // p.expr_mod is from the struct and not from the generic parameter
|
} else if p.expr_mod != '' && !p.in_generic_params { // p.expr_mod is from the struct and not from the generic parameter
|
||||||
name = p.expr_mod + '.' + name
|
name = p.expr_mod + '.' + name
|
||||||
|
} else if name in p.imported_symbols {
|
||||||
|
name = p.imported_symbols[name]
|
||||||
} else if p.mod != 'builtin' && name.len > 1 && name !in p.table.type_idxs {
|
} else if p.mod != 'builtin' && name.len > 1 && name !in p.table.type_idxs {
|
||||||
// `Foo` in module `mod` means `mod.Foo`
|
// `Foo` in module `mod` means `mod.Foo`
|
||||||
name = p.mod + '.' + name
|
name = p.mod + '.' + name
|
||||||
|
|
|
@ -46,6 +46,7 @@ mut:
|
||||||
imports map[string]string // alias => mod_name
|
imports map[string]string // alias => mod_name
|
||||||
ast_imports []ast.Import // mod_names
|
ast_imports []ast.Import // mod_names
|
||||||
used_imports []string // alias
|
used_imports []string // alias
|
||||||
|
imported_symbols map[string]string
|
||||||
is_amp bool // for generating the right code for `&Foo{}`
|
is_amp bool // for generating the right code for `&Foo{}`
|
||||||
returns bool
|
returns bool
|
||||||
inside_match bool // to separate `match A { }` from `Struct{}`
|
inside_match bool // to separate `match A { }` from `Struct{}`
|
||||||
|
@ -218,6 +219,7 @@ pub fn (mut p Parser) parse() ast.File {
|
||||||
path: p.file_name
|
path: p.file_name
|
||||||
mod: module_decl
|
mod: module_decl
|
||||||
imports: p.ast_imports
|
imports: p.ast_imports
|
||||||
|
imported_symbols: p.imported_symbols
|
||||||
stmts: stmts
|
stmts: stmts
|
||||||
scope: p.scope
|
scope: p.scope
|
||||||
global_scope: p.global_scope
|
global_scope: p.global_scope
|
||||||
|
@ -1681,44 +1683,11 @@ fn (mut p Parser) import_syms(mut parent ast.Import) {
|
||||||
for p.tok.kind == .name {
|
for p.tok.kind == .name {
|
||||||
pos := p.tok.position()
|
pos := p.tok.position()
|
||||||
alias := p.check_name()
|
alias := p.check_name()
|
||||||
name := '${parent.mod}.$alias'
|
p.imported_symbols[alias] = parent.mod + '.' + alias
|
||||||
if alias[0].is_capital() {
|
// so we can work with this in fmt+checker
|
||||||
idx := p.table.add_placeholder_type(name, .v)
|
parent.syms << ast.ImportSymbol{
|
||||||
typ := table.new_type(idx)
|
pos: pos
|
||||||
prepend_mod_name := p.prepend_mod(alias)
|
name: alias
|
||||||
p.table.register_type_symbol(table.TypeSymbol{
|
|
||||||
kind: .alias
|
|
||||||
name: prepend_mod_name
|
|
||||||
cname: util.no_dots(prepend_mod_name)
|
|
||||||
mod: p.mod
|
|
||||||
parent_idx: idx
|
|
||||||
info: table.Alias{
|
|
||||||
parent_type: typ
|
|
||||||
language: table.Language.v
|
|
||||||
is_import: true
|
|
||||||
}
|
|
||||||
is_public: false
|
|
||||||
})
|
|
||||||
// so we can work with the fully declared type in fmt+checker
|
|
||||||
parent.syms << ast.ImportSymbol{
|
|
||||||
pos: pos
|
|
||||||
name: alias
|
|
||||||
kind: .type_
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !p.table.known_fn(name) {
|
|
||||||
p.table.fns[alias] = table.Fn{
|
|
||||||
is_placeholder: true
|
|
||||||
mod: parent.mod
|
|
||||||
name: name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// so we can work with this in fmt+checker
|
|
||||||
parent.syms << ast.ImportSymbol{
|
|
||||||
pos: pos
|
|
||||||
name: alias
|
|
||||||
kind: .fn_
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if p.tok.kind == .comma { // go again if more than one
|
if p.tok.kind == .comma { // go again if more than one
|
||||||
p.next()
|
p.next()
|
||||||
|
|
|
@ -387,6 +387,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
pre_comments := p.eat_comments()
|
pre_comments := p.eat_comments()
|
||||||
// Declare the type
|
// Declare the type
|
||||||
reg_idx := p.table.register_type_symbol(
|
reg_idx := p.table.register_type_symbol(
|
||||||
|
is_public: is_pub
|
||||||
kind: .interface_
|
kind: .interface_
|
||||||
name: interface_name
|
name: interface_name
|
||||||
cname: util.no_dots(interface_name)
|
cname: util.no_dots(interface_name)
|
||||||
|
|
|
@ -842,6 +842,11 @@ pub:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (table &Table) type_to_str(t Type) string {
|
pub fn (table &Table) type_to_str(t Type) string {
|
||||||
|
return table.type_to_str_using_aliases(t, map[string]string{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// import_aliases is a map of imported symbol aliases 'module.Type' => 'Type'
|
||||||
|
pub fn (table &Table) type_to_str_using_aliases(t Type, import_aliases map[string]string) string {
|
||||||
sym := table.get_type_symbol(t)
|
sym := table.get_type_symbol(t)
|
||||||
mut res := sym.name
|
mut res := sym.name
|
||||||
match sym.kind {
|
match sym.kind {
|
||||||
|
@ -854,12 +859,12 @@ pub fn (table &Table) type_to_str(t Type) string {
|
||||||
return 'array'
|
return 'array'
|
||||||
}
|
}
|
||||||
info := sym.info as Array
|
info := sym.info as Array
|
||||||
elem_str := table.type_to_str(info.elem_type)
|
elem_str := table.type_to_str_using_aliases(info.elem_type, import_aliases)
|
||||||
res = '[]$elem_str'
|
res = '[]$elem_str'
|
||||||
}
|
}
|
||||||
.array_fixed {
|
.array_fixed {
|
||||||
info := sym.info as ArrayFixed
|
info := sym.info as ArrayFixed
|
||||||
elem_str := table.type_to_str(info.elem_type)
|
elem_str := table.type_to_str_using_aliases(info.elem_type, import_aliases)
|
||||||
res = '[$info.size]$elem_str'
|
res = '[$info.size]$elem_str'
|
||||||
}
|
}
|
||||||
.chan {
|
.chan {
|
||||||
|
@ -872,7 +877,7 @@ pub fn (table &Table) type_to_str(t Type) string {
|
||||||
mut_str = 'mut '
|
mut_str = 'mut '
|
||||||
elem_type = elem_type.set_nr_muls(elem_type.nr_muls() - 1)
|
elem_type = elem_type.set_nr_muls(elem_type.nr_muls() - 1)
|
||||||
}
|
}
|
||||||
elem_str := table.type_to_str(elem_type)
|
elem_str := table.type_to_str_using_aliases(elem_type, import_aliases)
|
||||||
res = 'chan $mut_str$elem_str'
|
res = 'chan $mut_str$elem_str'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -887,8 +892,8 @@ pub fn (table &Table) type_to_str(t Type) string {
|
||||||
return 'map'
|
return 'map'
|
||||||
}
|
}
|
||||||
info := sym.info as Map
|
info := sym.info as Map
|
||||||
key_str := table.type_to_str(info.key_type)
|
key_str := table.type_to_str_using_aliases(info.key_type, import_aliases)
|
||||||
val_str := table.type_to_str(info.value_type)
|
val_str := table.type_to_str_using_aliases(info.value_type, import_aliases)
|
||||||
res = 'map[$key_str]$val_str'
|
res = 'map[$key_str]$val_str'
|
||||||
}
|
}
|
||||||
.multi_return {
|
.multi_return {
|
||||||
|
@ -898,7 +903,7 @@ pub fn (table &Table) type_to_str(t Type) string {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
res += ', '
|
res += ', '
|
||||||
}
|
}
|
||||||
res += table.type_to_str(typ)
|
res += table.type_to_str_using_aliases(typ, import_aliases)
|
||||||
}
|
}
|
||||||
res += ')'
|
res += ')'
|
||||||
}
|
}
|
||||||
|
@ -917,6 +922,9 @@ pub fn (table &Table) type_to_str(t Type) string {
|
||||||
if res.starts_with(table.cmod_prefix) {
|
if res.starts_with(table.cmod_prefix) {
|
||||||
res = res.replace_once(table.cmod_prefix, '')
|
res = res.replace_once(table.cmod_prefix, '')
|
||||||
}
|
}
|
||||||
|
if res in import_aliases {
|
||||||
|
res = import_aliases[res]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nr_muls := t.nr_muls()
|
nr_muls := t.nr_muls()
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import shapes { Point, Line }
|
import geometry { Point, Line, point_str, module_name }
|
||||||
|
|
||||||
// test that Point & Line work correctly
|
fn test_imported_symbols_types() {
|
||||||
// with struct init & array's
|
// struct init
|
||||||
fn test_imported_symbols() {
|
p0 := Point{x: 10 y: 20}
|
||||||
p0 := Point {x: 10 y: 10}
|
p1 := Point{x: 40 y: 60}
|
||||||
p1 := Point {x: 50 y: 10}
|
// array init
|
||||||
|
l0 := Line {
|
||||||
_ := Line {
|
|
||||||
ps: [p0, p1]
|
ps: [p0, p1]
|
||||||
}
|
}
|
||||||
|
assert l0.ps[0].y == 20
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_imported_symbols_functions() {
|
||||||
|
p0 := Point{x: 20 y: 40}
|
||||||
|
// method
|
||||||
|
assert p0.str() == '20 40'
|
||||||
|
// function
|
||||||
|
assert point_str(p0) == '20 40'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_imported_symbols_constants() {
|
||||||
|
assert module_name == 'geometry'
|
||||||
}
|
}
|
|
@ -1,9 +1,18 @@
|
||||||
module point
|
module geometry
|
||||||
|
|
||||||
|
const(
|
||||||
|
module_name = 'geometry'
|
||||||
|
)
|
||||||
|
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
pub mut:
|
pub mut:
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Line {
|
||||||
|
pub mut:
|
||||||
|
ps []Point
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Point) +(b Point) Point {
|
pub fn (a Point) +(b Point) Point {
|
||||||
|
@ -15,4 +24,8 @@ pub fn (a Point) +(b Point) Point {
|
||||||
|
|
||||||
pub fn (a Point) str() string {
|
pub fn (a Point) str() string {
|
||||||
return '${a.x} ${a.y}'
|
return '${a.x} ${a.y}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn point_str(a Point) string {
|
||||||
|
return a.str()
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import point { Point }
|
import geometry { Point }
|
||||||
|
|
||||||
fn test_operator_overloading() {
|
fn test_operator_overloading() {
|
||||||
one := Point {x:1, y:2}
|
one := Point {x:1, y:2}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
module shapes
|
|
||||||
|
|
||||||
pub struct Point {
|
|
||||||
pub mut:
|
|
||||||
x int
|
|
||||||
y int
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Line {
|
|
||||||
pub mut:
|
|
||||||
ps []Point
|
|
||||||
}
|
|
Loading…
Reference in New Issue