| 1 | module transformer |
| 2 | |
| 3 | import os |
| 4 | import v2.ast |
| 5 | import v2.parser |
| 6 | import v2.pref as vpref |
| 7 | import v2.token |
| 8 | import v2.types |
| 9 | |
| 10 | fn transform_fixed_array_slice_code_for_test(code string) []ast.File { |
| 11 | tmp_file := os.join_path(os.temp_dir(), 'v2_transformer_fixed_slice_${os.getpid()}.v') |
| 12 | os.write_file(tmp_file, code) or { panic('failed to write temp file') } |
| 13 | defer { |
| 14 | os.rm(tmp_file) or {} |
| 15 | } |
| 16 | prefs := &vpref.Preferences{ |
| 17 | backend: .cleanc |
| 18 | no_parallel: true |
| 19 | } |
| 20 | mut file_set := token.FileSet.new() |
| 21 | mut par := parser.Parser.new(prefs) |
| 22 | files := par.parse_files([tmp_file], mut file_set) |
| 23 | mut env := types.Environment.new() |
| 24 | mut checker := types.Checker.new(prefs, file_set, env) |
| 25 | checker.check_files(files) |
| 26 | mut transformer := Transformer.new_with_pref(env, prefs) |
| 27 | return transformer.transform_files(files) |
| 28 | } |
| 29 | |
| 30 | fn count_fixed_slice_call_in_expr(expr ast.Expr, name string) int { |
| 31 | match expr { |
| 32 | ast.ArrayInitExpr { |
| 33 | mut count := count_fixed_slice_call_in_expr(expr.typ, name) |
| 34 | for item in expr.exprs { |
| 35 | count += count_fixed_slice_call_in_expr(item, name) |
| 36 | } |
| 37 | count += count_fixed_slice_call_in_expr(expr.init, name) |
| 38 | count += count_fixed_slice_call_in_expr(expr.cap, name) |
| 39 | count += count_fixed_slice_call_in_expr(expr.len, name) |
| 40 | count += count_fixed_slice_call_in_expr(expr.update_expr, name) |
| 41 | return count |
| 42 | } |
| 43 | ast.CallExpr { |
| 44 | mut count := if expr.lhs is ast.Ident && expr.lhs.name == name { 1 } else { 0 } |
| 45 | count += count_fixed_slice_call_in_expr(expr.lhs, name) |
| 46 | for arg in expr.args { |
| 47 | count += count_fixed_slice_call_in_expr(arg, name) |
| 48 | } |
| 49 | return count |
| 50 | } |
| 51 | ast.CastExpr { |
| 52 | return count_fixed_slice_call_in_expr(expr.typ, name) + |
| 53 | count_fixed_slice_call_in_expr(expr.expr, name) |
| 54 | } |
| 55 | ast.IndexExpr { |
| 56 | return count_fixed_slice_call_in_expr(expr.lhs, name) + |
| 57 | count_fixed_slice_call_in_expr(expr.expr, name) |
| 58 | } |
| 59 | ast.InfixExpr { |
| 60 | return count_fixed_slice_call_in_expr(expr.lhs, name) + |
| 61 | count_fixed_slice_call_in_expr(expr.rhs, name) |
| 62 | } |
| 63 | ast.InitExpr { |
| 64 | mut count := count_fixed_slice_call_in_expr(expr.typ, name) |
| 65 | for field in expr.fields { |
| 66 | count += count_fixed_slice_call_in_expr(field.value, name) |
| 67 | } |
| 68 | return count |
| 69 | } |
| 70 | ast.KeywordOperator { |
| 71 | mut count := 0 |
| 72 | for value in expr.exprs { |
| 73 | count += count_fixed_slice_call_in_expr(value, name) |
| 74 | } |
| 75 | return count |
| 76 | } |
| 77 | ast.MapInitExpr { |
| 78 | mut count := count_fixed_slice_call_in_expr(expr.typ, name) |
| 79 | for key in expr.keys { |
| 80 | count += count_fixed_slice_call_in_expr(key, name) |
| 81 | } |
| 82 | for value in expr.vals { |
| 83 | count += count_fixed_slice_call_in_expr(value, name) |
| 84 | } |
| 85 | return count |
| 86 | } |
| 87 | ast.ModifierExpr { |
| 88 | return count_fixed_slice_call_in_expr(expr.expr, name) |
| 89 | } |
| 90 | ast.ParenExpr { |
| 91 | return count_fixed_slice_call_in_expr(expr.expr, name) |
| 92 | } |
| 93 | ast.PrefixExpr { |
| 94 | return count_fixed_slice_call_in_expr(expr.expr, name) |
| 95 | } |
| 96 | ast.RangeExpr { |
| 97 | return count_fixed_slice_call_in_expr(expr.start, name) + |
| 98 | count_fixed_slice_call_in_expr(expr.end, name) |
| 99 | } |
| 100 | ast.SelectorExpr { |
| 101 | return count_fixed_slice_call_in_expr(expr.lhs, name) |
| 102 | } |
| 103 | ast.Tuple { |
| 104 | mut count := 0 |
| 105 | for value in expr.exprs { |
| 106 | count += count_fixed_slice_call_in_expr(value, name) |
| 107 | } |
| 108 | return count |
| 109 | } |
| 110 | ast.UnsafeExpr { |
| 111 | return count_fixed_slice_call_in_stmts(expr.stmts, name) |
| 112 | } |
| 113 | else { |
| 114 | return 0 |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | fn count_fixed_slice_call_in_stmt(stmt ast.Stmt, name string) int { |
| 120 | match stmt { |
| 121 | ast.AssignStmt { |
| 122 | mut count := 0 |
| 123 | for lhs in stmt.lhs { |
| 124 | count += count_fixed_slice_call_in_expr(lhs, name) |
| 125 | } |
| 126 | for rhs in stmt.rhs { |
| 127 | count += count_fixed_slice_call_in_expr(rhs, name) |
| 128 | } |
| 129 | return count |
| 130 | } |
| 131 | ast.ExprStmt { |
| 132 | return count_fixed_slice_call_in_expr(stmt.expr, name) |
| 133 | } |
| 134 | else { |
| 135 | return 0 |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | fn count_fixed_slice_call_in_stmts(stmts []ast.Stmt, name string) int { |
| 141 | mut count := 0 |
| 142 | for stmt in stmts { |
| 143 | count += count_fixed_slice_call_in_stmt(stmt, name) |
| 144 | } |
| 145 | return count |
| 146 | } |
| 147 | |
| 148 | fn transformed_fixed_slice_fn(files []ast.File, name string) ?ast.FnDecl { |
| 149 | for file in files { |
| 150 | for stmt in file.stmts { |
| 151 | if stmt is ast.FnDecl && stmt.name == name { |
| 152 | return stmt |
| 153 | } |
| 154 | } |
| 155 | } |
| 156 | return none |
| 157 | } |
| 158 | |
| 159 | fn test_fixed_array_slice_bounds_are_materialized_once() { |
| 160 | files := transform_fixed_array_slice_code_for_test(' |
| 161 | fn next() int { |
| 162 | return 1 |
| 163 | } |
| 164 | |
| 165 | fn stop() int { |
| 166 | return 3 |
| 167 | } |
| 168 | |
| 169 | fn main() { |
| 170 | arr := [4]int{} |
| 171 | part := arr[next()..stop()] |
| 172 | _ = part |
| 173 | } |
| 174 | ') |
| 175 | main_decl := transformed_fixed_slice_fn(files, 'main') or { |
| 176 | assert false, 'missing transformed main' |
| 177 | return |
| 178 | } |
| 179 | |
| 180 | assert count_fixed_slice_call_in_stmts(main_decl.stmts, 'next') == 1 |
| 181 | assert count_fixed_slice_call_in_stmts(main_decl.stmts, 'stop') == 1 |
| 182 | assert count_fixed_slice_call_in_stmts(main_decl.stmts, 'new_array_from_c_array') == 1 |
| 183 | } |
| 184 | |