diff --git a/vlib/math/floor.v b/vlib/math/floor.v index 4e930fa572..6654fe9183 100644 --- a/vlib/math/floor.v +++ b/vlib/math/floor.v @@ -21,6 +21,31 @@ pub fn floor(x f64) f64 { return d } +// floorf returns the greatest integer value less than or equal to x. +// +// special cases are: +// floor(±0) = ±0 +// floor(±inf) = ±inf +// floor(nan) = nan +pub fn floorf(x f32) f32 { + // TODO + return f32(floor(f64(x))) + /* + if x == 0 || is_nan(x) || is_inf(x, 0) { + return x + } + if x < 0 { + mut d, fract := modf(-x) + if fract != 0.0 { + d = d + 1 + } + return -d + } + d, _ := modf(x) + return d + */ +} + // ceil returns the least integer value greater than or equal to x. // // special cases are: diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index bd533c3357..5d4f04ddac 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -416,6 +416,9 @@ pub: pre_comments []Comment end_comments []Comment embeds []Embed + + is_implements bool + implements_type Type pub mut: fields []StructField } diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index f8733fc099..f4850568a5 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -328,6 +328,13 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { node.pos) } } + // Handle `implements` if it's present + if node.is_implements { + // XTODO2 + // cgen error if I use `println(sym)` without handling the option with `or{}` + struct_type := c.table.find_type_idx(node.name) // or { panic(err) } + c.type_implements(struct_type, node.implements_type, node.pos) + } } fn minify_sort_fn(a &ast.StructField, b &ast.StructField) int { diff --git a/vlib/v/checker/tests/implements_keyword.out b/vlib/v/checker/tests/implements_keyword.out new file mode 100644 index 0000000000..6b75ddc745 --- /dev/null +++ b/vlib/v/checker/tests/implements_keyword.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/implements_keyword.vv:5:1: error: `CustomError` doesn't implement method `print_error` of interface `MyError` + 3 | } + 4 | + 5 | struct CustomError implements MyError { + | ~~~~~~~~~~~~~~~~~~ + 6 | } + 7 | diff --git a/vlib/v/checker/tests/implements_keyword.vv b/vlib/v/checker/tests/implements_keyword.vv new file mode 100644 index 0000000000..4b2bf45146 --- /dev/null +++ b/vlib/v/checker/tests/implements_keyword.vv @@ -0,0 +1,9 @@ +interface MyError { + print_error() +} + +struct CustomError implements MyError { +} + +fn (e CustomError) print_error2() { +} diff --git a/vlib/v/fmt/struct.v b/vlib/v/fmt/struct.v index 0c90a219f5..2febda9e12 100644 --- a/vlib/v/fmt/struct.v +++ b/vlib/v/fmt/struct.v @@ -31,6 +31,10 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) { mut attr_align := new_field_align(use_threshold: true) mut comment_align := new_field_align(use_threshold: true) mut field_types := []string{cap: node.fields.len} + if node.is_implements { + f.write(' implements ') + f.write(f.table.type_to_str_using_aliases(node.implements_type, f.mod2alias)) + } // Calculate the alignments first f.calculate_alignment(node.fields, mut type_align, mut comment_align, mut default_expr_align, mut attr_align, mut field_types) diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 889fc16d10..4325c9eb36 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -53,7 +53,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { } generic_types, _ := p.parse_generic_types() mut pre_comments := p.eat_comments() - no_body := p.tok.kind != .lcbr + no_body := p.tok.kind != .lcbr && p.tok.kind != .key_implements if language == .v && no_body { p.error('`${p.tok.lit}` lacks body') return ast.StructDecl{} @@ -93,9 +93,16 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { mut is_field_mut := false mut is_field_pub := false mut is_field_global := false + mut is_implements := false + mut implements_type := ast.void_type mut last_line := p.prev_tok.pos().line_nr + 1 mut end_comments := []ast.Comment{} if !no_body { + if p.tok.kind == .key_implements { + p.next() + implements_type = p.parse_type() + is_implements = true + } p.check(.lcbr) pre_comments << p.eat_comments() mut i := 0 @@ -371,22 +378,24 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { } p.expr_mod = '' return ast.StructDecl{ - name: name - is_pub: is_pub - fields: ast_fields - pos: start_pos.extend_with_last_line(name_pos, last_line) - mut_pos: mut_pos - pub_pos: pub_pos - pub_mut_pos: pub_mut_pos - global_pos: global_pos - module_pos: module_pos - language: language - is_union: is_union - attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes - pre_comments: pre_comments - end_comments: end_comments - generic_types: generic_types - embeds: embeds + name: name + is_pub: is_pub + fields: ast_fields + pos: start_pos.extend_with_last_line(name_pos, last_line) + mut_pos: mut_pos + pub_pos: pub_pos + pub_mut_pos: pub_mut_pos + global_pos: global_pos + module_pos: module_pos + language: language + is_union: is_union + attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes + pre_comments: pre_comments + end_comments: end_comments + generic_types: generic_types + embeds: embeds + is_implements: is_implements + implements_type: implements_type } } diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index 33e1f968a8..66e74ab049 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -463,3 +463,23 @@ fn print_displayable(ds ...Displayable) { fn test_variadic_interface() { print_displayable(Text('test'), Text('hehe')) } + +interface MyError { + print_error() +} + +struct CustomError implements MyError { +} + +fn (e CustomError) print_error() { +} + +fn handle_implements(e MyError) { + // e.print_error() +} + +fn test_implements() { + // e := CustomError{} + // handle_implements(e) + println('implements ok') +} diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 8b8d22f537..82dda6d8da 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -138,6 +138,7 @@ pub enum Kind { key_volatile key_unsafe key_spawn + key_implements keyword_end _end_ } @@ -338,6 +339,7 @@ fn build_token_str() []string { s[Kind.key_offsetof] = '__offsetof' s[Kind.key_is] = 'is' s[Kind.key_spawn] = 'spawn' + s[Kind.key_implements] = 'implements' // The following kinds are not for tokens returned by the V scanner. // They are used just for organisation/ease of checking: s[Kind.keyword_beg] = 'keyword_beg' @@ -659,6 +661,7 @@ pub fn kind_to_string(k Kind) string { .key_volatile { 'key_volatile' } .key_unsafe { 'key_unsafe' } .key_spawn { 'key_spawn' } + .key_implements { 'key_implements' } .keyword_end { 'keyword_end' } ._end_ { '_end_' } .key_nil { 'key_nil' } @@ -784,6 +787,7 @@ pub fn kind_from_string(s string) !Kind { 'key_volatile' { .key_volatile } 'key_unsafe' { .key_unsafe } 'key_spawn' { .key_spawn } + 'key_implements' { .key_implements } 'keyword_end' { .keyword_end } '_end_' { ._end_ } else { error('unknown') }