From 0f0a91fc9ea0de46f97e7e6e20d767fb28fa9654 Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Sat, 15 Aug 2020 10:01:54 +0100 Subject: [PATCH] parser: support custom fixed size ArrayInit: `[3]int{init: -1}` (#6114) --- vlib/v/ast/ast.v | 2 +- vlib/v/fmt/fmt.v | 5 +++++ vlib/v/fmt/tests/array_newlines_keep.vv | 2 +- vlib/v/gen/cgen.v | 19 ++++++++++++++++--- vlib/v/parser/containers.v | 24 +++++++++++++++++++++--- vlib/v/tests/fixed_array_init_test.v | 17 +++++++++++++++-- vlib/v/tests/fixed_array_test.v | 6 ++++-- 7 files changed, 63 insertions(+), 12 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 4d30b7e5b2..1f66466c03 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -733,7 +733,7 @@ pub struct ArrayInit { pub: pos token.Position elem_type_pos token.Position - exprs []Expr + exprs []Expr // `[expr, expr]` or `[expr]Type{}` for fixed array is_fixed bool has_val bool // fixed size literal `[expr, expr]!!` mod string diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index f91d868e49..ad6dc0ffcf 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1734,6 +1734,11 @@ pub fn (mut f Fmt) array_init(it ast.ArrayInit) { // `[100]byte` if it.is_fixed { f.write(f.type_to_str(it.elem_type)) + if it.has_default { + f.write('{init: $it.default_expr}') + } else { + f.write('{}') + } } } diff --git a/vlib/v/fmt/tests/array_newlines_keep.vv b/vlib/v/fmt/tests/array_newlines_keep.vv index e60f6dda89..fbec39a89c 100644 --- a/vlib/v/fmt/tests/array_newlines_keep.vv +++ b/vlib/v/fmt/tests/array_newlines_keep.vv @@ -11,7 +11,7 @@ fn main() { ] x := []int{len: 10, cap: 100, init: 1} _ := expected_flags - buf := [100]byte + buf := [100]byte{} println(x) println(buf) } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 1f91206b7a..d4bd313b89 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1499,7 +1499,20 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { if !cloned { if is_decl { if is_fixed_array_init && !has_val { - g.write('{0}') + if val is ast.ArrayInit { + if val.has_default { + g.write('{$val.default_expr') + info := right_sym.info as table.ArrayFixed + for _ in 1 .. info.size { + g.write(', $val.default_expr') + } + g.write('}') + } else { + g.write('{0}') + } + } else { + g.write('{0}') + } } else { g.expr(val) } @@ -2152,8 +2165,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.write(')') } else if node.op in [.eq, .ne] && left_sym.kind == .array_fixed && right_sym.kind == .array_fixed { - af := left_sym.info as table.ArrayFixed - et := af.elem_type + info := left_sym.info as table.ArrayFixed + et := info.elem_type if !et.is_ptr() && !et.is_pointer() && !et.is_number() && et.idx() !in [table.bool_type_idx, table.char_type_idx] { verror('`==` on fixed array only supported with POD element types ATM') } diff --git a/vlib/v/parser/containers.v b/vlib/v/parser/containers.v index efdb970d90..bd50c99185 100644 --- a/vlib/v/parser/containers.v +++ b/vlib/v/parser/containers.v @@ -19,6 +19,8 @@ fn (mut p Parser) array_init() ast.ArrayInit { mut is_fixed := false mut has_val := false mut has_type := false + mut has_default := false + mut default_expr := ast.Expr{} if p.tok.kind == .rsbr { // []typ => `[]` and `typ` must be on the same line line_nr := p.tok.line_nr @@ -28,7 +30,7 @@ fn (mut p Parser) array_init() ast.ArrayInit { elem_type_pos = p.tok.position() elem_type = p.parse_type() sym := p.table.get_type_symbol(elem_type) - // this is set here becasue its a known type, others could be the + // this is set here because it's a known type, others could be the // result of expr so we do those in checker idx := p.table.find_or_register_array(elem_type, 1, sym.mod) array_type = table.new_type(idx) @@ -55,6 +57,24 @@ fn (mut p Parser) array_init() ast.ArrayInit { // [100]byte elem_type = p.parse_type() is_fixed = true + if p.tok.kind == .lcbr { + p.next() + if p.tok.kind != .rcbr { + pos := p.tok.position() + n := p.check_name() + if n != 'init' { + p.error_with_pos('expected `init:`, not `$n`', pos) + } + p.check(.colon) + has_default = true + default_expr = p.expr(0) + } + last_pos = p.tok.position() + p.check(.rcbr) + } + else { + // p.warn_with_pos('use e.g. `x := [1]Type{}` instead of `x := [1]Type`', last_pos) + } } else { if p.tok.kind == .not { last_pos = p.tok.position() @@ -73,10 +93,8 @@ fn (mut p Parser) array_init() ast.ArrayInit { } mut has_len := false mut has_cap := false - mut has_default := false mut len_expr := ast.Expr{} mut cap_expr := ast.Expr{} - mut default_expr := ast.Expr{} if p.tok.kind == .lcbr && exprs.len == 0 { // `[]int{ len: 10, cap: 100}` syntax p.next() diff --git a/vlib/v/tests/fixed_array_init_test.v b/vlib/v/tests/fixed_array_init_test.v index f7da1aeac5..4da5da1ea1 100644 --- a/vlib/v/tests/fixed_array_init_test.v +++ b/vlib/v/tests/fixed_array_init_test.v @@ -1,4 +1,4 @@ -fn test_fixed_array_init() { +fn test_fixed_array_lit_init() { a1 := ['1', '2', '3']!! assert typeof(a1) == '[3]string' assert '$a1' == "['1', '2', '3']" @@ -37,7 +37,20 @@ fn test_fixed_type_init() { assert a == [2]int assert a == [0,0]!! assert a == a - c := [3,3]!! + mut c := [3,3]!! assert a != c assert c == [3,3]!! + c = [2]int + assert a == c +} + +fn test_fixed_custom_init() { + a := [2]byte{init: 7} + assert a == [byte(7), 7]!! + + mut b := [3]int{} + assert b == [0,0,0]!! + // assign + b = [3]int{init:5} + assert b == [5,5,5]!! } diff --git a/vlib/v/tests/fixed_array_test.v b/vlib/v/tests/fixed_array_test.v index 93a1e1fa32..96809826d6 100644 --- a/vlib/v/tests/fixed_array_test.v +++ b/vlib/v/tests/fixed_array_test.v @@ -1,15 +1,17 @@ fn test_fixed_array_can_be_assigned() { x := 2.32 - mut v := [8]f64 + mut v := [8]f64{} assert v[1] == 0 v = [1.0, x, 3.0,4.0,5.0,6.0,7.0,8.0]!! assert v[1] == x - v = [8]f64 + v = [8]f64{} assert v[1] == 0 // test slicing for e in v[0..8] { assert e == 0 } + v = [8]f64{init: 3.0} + assert v[1] == 3.0 } fn test_fixed_array_can_be_used_in_declaration() {