| 1 | module parser |
| 2 | |
| 3 | import v.ast |
| 4 | import v.util |
| 5 | import v.token |
| 6 | |
| 7 | // peek token `type Fn = fn () int` |
| 8 | fn (p &Parser) is_fn_type_decl() bool { |
| 9 | mut n := 1 |
| 10 | mut tok := p.tok |
| 11 | mut prev_tok := p.tok |
| 12 | cur_ln := p.tok.line_nr |
| 13 | for { |
| 14 | tok = p.scanner.peek_token(n) |
| 15 | if tok.kind == .eof { |
| 16 | break |
| 17 | } |
| 18 | if tok.kind in [.lpar, .rpar] { |
| 19 | n++ |
| 20 | prev_tok = tok |
| 21 | continue |
| 22 | } |
| 23 | if tok.kind == .pipe { |
| 24 | if tok.pos - prev_tok.pos > prev_tok.len { |
| 25 | return false |
| 26 | } |
| 27 | } |
| 28 | if tok.line_nr > cur_ln { |
| 29 | break |
| 30 | } |
| 31 | prev_tok = tok |
| 32 | n++ |
| 33 | } |
| 34 | return true |
| 35 | } |
| 36 | |
| 37 | fn (p &Parser) has_prev_newline() bool { |
| 38 | mut tok := p.tok |
| 39 | mut prev_tok := p.prev_tok |
| 40 | mut idx := -1 |
| 41 | |
| 42 | for { |
| 43 | if tok.line_nr - prev_tok.line_nr - prev_tok.lit.count('\n') > 1 { |
| 44 | return true |
| 45 | } |
| 46 | if prev_tok.kind == .comment { |
| 47 | idx-- |
| 48 | tok = prev_tok |
| 49 | prev_tok = p.peek_token(idx) |
| 50 | continue |
| 51 | } |
| 52 | break |
| 53 | } |
| 54 | return false |
| 55 | } |
| 56 | |
| 57 | fn (p &Parser) has_prev_line_comment_or_label() bool { |
| 58 | return p.prev_tok.kind == .colon || (p.prev_tok.kind == .comment |
| 59 | && p.tok.line_nr - p.prev_tok.line_nr == 1 |
| 60 | && p.prev_tok.line_nr - p.peek_token(-2).line_nr > 0) |
| 61 | } |
| 62 | |
| 63 | fn (p &Parser) is_array_type() bool { |
| 64 | mut i := 1 |
| 65 | mut tok := p.tok |
| 66 | line_nr := p.tok.line_nr |
| 67 | mut sbr_level := if p.tok.kind == .lsbr { 1 } else { 0 } |
| 68 | |
| 69 | for { |
| 70 | tok = p.peek_token(i) |
| 71 | if tok.line_nr != line_nr { |
| 72 | return false |
| 73 | } |
| 74 | if sbr_level == 0 |
| 75 | && tok.kind in [.name, .amp, .lpar, .question, .key_atomic, .key_fn, .key_shared, .key_struct] { |
| 76 | return true |
| 77 | } |
| 78 | if tok.kind == .lsbr { |
| 79 | sbr_level++ |
| 80 | } else if tok.kind == .rsbr { |
| 81 | sbr_level-- |
| 82 | } |
| 83 | if sbr_level == 0 && tok.kind in [.eof, .colon, .dot] { |
| 84 | break |
| 85 | } |
| 86 | i++ |
| 87 | } |
| 88 | return false |
| 89 | } |
| 90 | |
| 91 | fn (mut p Parser) is_following_concrete_types() bool { |
| 92 | if !(p.tok.kind == .lsbr && p.tok.is_next_to(p.prev_tok)) { |
| 93 | return false |
| 94 | } |
| 95 | mut i := 1 |
| 96 | for { |
| 97 | cur_tok := p.peek_token(i) |
| 98 | if cur_tok.kind == .eof { |
| 99 | return false |
| 100 | } else if cur_tok.kind == .rsbr { |
| 101 | break |
| 102 | } else if cur_tok.kind == .name { |
| 103 | if p.peek_token(i + 1).kind == .dot { |
| 104 | if p.is_typename(cur_tok) { |
| 105 | return false |
| 106 | } |
| 107 | i++ |
| 108 | } else if !(p.is_typename(cur_tok) && !(cur_tok.lit.len == 1 |
| 109 | && !cur_tok.lit[0].is_capital())) { |
| 110 | return false |
| 111 | } |
| 112 | } else if cur_tok.kind != .comma { |
| 113 | return false |
| 114 | } |
| 115 | i++ |
| 116 | } |
| 117 | return true |
| 118 | } |
| 119 | |
| 120 | @[direct_array_access] |
| 121 | fn (p &Parser) is_anon_struct_generic_arg(next_kind token.Kind) bool { |
| 122 | mut i := 2 |
| 123 | mut nested_sbr_count := 0 |
| 124 | mut nested_cbr_count := 0 |
| 125 | for { |
| 126 | cur_tok := p.peek_token(i) |
| 127 | if cur_tok.kind == .eof { |
| 128 | return false |
| 129 | } |
| 130 | if cur_tok.kind == .lsbr { |
| 131 | nested_sbr_count++ |
| 132 | } else if cur_tok.kind == .rsbr { |
| 133 | if nested_cbr_count == 0 && nested_sbr_count == 0 { |
| 134 | return p.peek_token(i + 1).kind == next_kind |
| 135 | } |
| 136 | if nested_sbr_count == 0 { |
| 137 | return false |
| 138 | } |
| 139 | nested_sbr_count-- |
| 140 | } else if cur_tok.kind == .lcbr { |
| 141 | nested_cbr_count++ |
| 142 | } else if cur_tok.kind == .rcbr { |
| 143 | if nested_cbr_count == 0 { |
| 144 | return false |
| 145 | } |
| 146 | nested_cbr_count-- |
| 147 | } |
| 148 | i++ |
| 149 | } |
| 150 | return false |
| 151 | } |
| 152 | |
| 153 | @[direct_array_access] |
| 154 | fn (p &Parser) is_generic_struct_init() bool { |
| 155 | lit0_is_capital := p.tok.kind != .eof && p.tok.lit.len > 0 && p.tok.lit[0].is_capital() |
| 156 | if !lit0_is_capital || p.peek_tok.kind != .lsbr { |
| 157 | return false |
| 158 | } |
| 159 | if p.peek_token(2).kind == .key_struct { |
| 160 | return p.is_anon_struct_generic_arg(.lcbr) |
| 161 | } |
| 162 | mut i := 2 |
| 163 | mut nested_sbr_count := 0 |
| 164 | for { |
| 165 | cur_tok := p.peek_token(i) |
| 166 | if cur_tok.kind == .eof |
| 167 | || cur_tok.kind !in [.amp, .dot, .comma, .name, .lpar, .rpar, .lsbr, .rsbr, .key_fn] { |
| 168 | break |
| 169 | } |
| 170 | if cur_tok.kind == .lsbr { |
| 171 | nested_sbr_count++ |
| 172 | } else if cur_tok.kind == .rsbr { |
| 173 | if nested_sbr_count > 0 { |
| 174 | nested_sbr_count-- |
| 175 | } else { |
| 176 | if p.peek_token(i + 1).kind == .lcbr { |
| 177 | return true |
| 178 | } |
| 179 | break |
| 180 | } |
| 181 | } |
| 182 | i++ |
| 183 | } |
| 184 | return false |
| 185 | } |
| 186 | |
| 187 | @[direct_array_access; inline] |
| 188 | fn (p &Parser) is_typename(t token.Token) bool { |
| 189 | return t.kind == .name && (t.lit[0].is_capital() || p.table.known_type(t.lit)) |
| 190 | } |
| 191 | |
| 192 | // heuristics to detect `func[T]()` from `var [ expr` |
| 193 | // 1. `f[[]` is generic(e.g. `f[[]int]`) because `var [ []` is invalid |
| 194 | // 2. `f[map[` is generic(e.g. `f[map[string]string]) |
| 195 | // 3. `f[foo]` is generic because `v1 [ foo ] v2` is invalid syntax |
| 196 | // 4. `f[foo[bar` is generic when bar is not generic T (f[foo[T](), in contrast, is not generic!) |
| 197 | // 5. `f[Foo,` is generic when Foo is typename. |
| 198 | // otherwise it is not generic because it may be multi-value (e.g. `return f [ foo, 0`). |
| 199 | // 6. `f[mod.Foo]` is same as case 3 |
| 200 | // 7. `f[mod.Foo,` is same as case 5 |
| 201 | // 8. if there is a &, ignore the & and see if it is a type |
| 202 | // 9. otherwise, it's not generic |
| 203 | // see also test_generic_detection in vlib/v/tests/generics_test.v |
| 204 | @[direct_array_access] |
| 205 | fn (p &Parser) is_generic_call() bool { |
| 206 | lit0_is_capital := p.tok.kind != .eof && p.tok.lit.len > 0 && p.tok.lit[0].is_capital() |
| 207 | if lit0_is_capital || p.peek_tok.kind != .lsbr { |
| 208 | return false |
| 209 | } |
| 210 | mut tok2 := p.peek_token(2) |
| 211 | mut tok3 := p.peek_token(3) |
| 212 | mut tok4 := p.peek_token(4) |
| 213 | mut tok5 := p.peek_token(5) |
| 214 | mut kind2, mut kind3, mut kind4, mut kind5 := tok2.kind, tok3.kind, tok4.kind, tok5.kind |
| 215 | if kind2 == .amp { // if there is a & in front, shift everything left |
| 216 | tok2 = tok3 |
| 217 | kind2 = kind3 |
| 218 | tok3 = tok4 |
| 219 | kind3 = kind4 |
| 220 | tok4 = tok5 |
| 221 | kind4 = kind5 |
| 222 | tok5 = p.peek_token(6) |
| 223 | kind5 = tok5.kind |
| 224 | } |
| 225 | if (kind2 == .question || kind2 in [.key_shared, .key_atomic]) && kind3 == .key_fn { |
| 226 | tok2 = tok3 |
| 227 | kind2 = kind3 |
| 228 | tok3 = tok4 |
| 229 | kind3 = kind4 |
| 230 | tok4 = tok5 |
| 231 | kind4 = kind5 |
| 232 | tok5 = p.peek_token(6) |
| 233 | kind5 = tok5.kind |
| 234 | } |
| 235 | |
| 236 | if kind2 == .lsbr { |
| 237 | // case 1 (array or fixed array type) |
| 238 | return tok3.kind == .rsbr || (tok4.kind == .rsbr && p.is_typename(tok5)) |
| 239 | } |
| 240 | if kind2 == .key_struct { |
| 241 | return p.is_anon_struct_generic_arg(.lpar) |
| 242 | } |
| 243 | if kind2 == .key_fn { |
| 244 | mut i := 3 |
| 245 | mut nested_sbr_count := 0 |
| 246 | for { |
| 247 | cur_tok := p.peek_token(i) |
| 248 | if cur_tok.kind == .eof |
| 249 | || cur_tok.kind !in [.amp, .dot, .comma, .ellipsis, .name, .number, .lpar, .rpar, .lsbr, .rsbr, .question, .not, .key_fn, .key_mut, .key_shared, .key_atomic] { |
| 250 | break |
| 251 | } |
| 252 | if cur_tok.kind == .lsbr { |
| 253 | nested_sbr_count++ |
| 254 | } else if cur_tok.kind == .rsbr { |
| 255 | if nested_sbr_count > 0 { |
| 256 | nested_sbr_count-- |
| 257 | } else { |
| 258 | return p.peek_token(i + 1).kind == .lpar |
| 259 | } |
| 260 | } |
| 261 | i++ |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | if kind2 == .name { |
| 266 | if kind3 == .lsbr && tok2.lit == 'map' { |
| 267 | // case 2 |
| 268 | return true |
| 269 | } |
| 270 | if p.peek_tok.kind == .lsbr { |
| 271 | mut i := 3 |
| 272 | mut nested_sbr_count := 0 |
| 273 | for { |
| 274 | cur_tok := p.peek_token(i) |
| 275 | if cur_tok.kind == .eof |
| 276 | || cur_tok.kind !in [.amp, .dot, .comma, .name, .lpar, .rpar, .lsbr, .rsbr, .key_fn] { |
| 277 | break |
| 278 | } |
| 279 | if cur_tok.kind == .lsbr { |
| 280 | nested_sbr_count++ |
| 281 | } |
| 282 | if cur_tok.kind == .rsbr { |
| 283 | if nested_sbr_count > 0 { |
| 284 | nested_sbr_count-- |
| 285 | } else { |
| 286 | prev_tok := p.peek_token(i - 1) |
| 287 | // `funcs[i]()` is not generic call |
| 288 | if !(p.is_typename(prev_tok) || prev_tok.kind == .rsbr) { |
| 289 | return false |
| 290 | } |
| 291 | if p.peek_token(i + 1).kind == .lpar { |
| 292 | return true |
| 293 | } |
| 294 | break |
| 295 | } |
| 296 | } |
| 297 | i++ |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | return false |
| 302 | } |
| 303 | |
| 304 | const valid_tokens_inside_types = [token.Kind.lsbr, .rsbr, .name, .dot, .comma, .key_fn] |
| 305 | |
| 306 | fn (mut p Parser) is_generic_cast() bool { |
| 307 | if !ast.type_can_start_with_token(&p.tok) { |
| 308 | return false |
| 309 | } |
| 310 | mut i := 0 |
| 311 | mut level := 0 |
| 312 | mut lt_count := 0 |
| 313 | for { |
| 314 | i++ |
| 315 | tok := p.peek_token(i) |
| 316 | |
| 317 | if tok.kind == .lsbr { |
| 318 | lt_count++ |
| 319 | level++ |
| 320 | } else if tok.kind == .rsbr { |
| 321 | level-- |
| 322 | } |
| 323 | if lt_count > 0 && level == 0 { |
| 324 | break |
| 325 | } |
| 326 | |
| 327 | if i > 20 || tok.kind !in valid_tokens_inside_types { |
| 328 | return false |
| 329 | } |
| 330 | } |
| 331 | next_tok := p.peek_token(i + 1) |
| 332 | // `next_tok` is the token following the closing `]` of the generic type: MyType[int]{ |
| 333 | // ^ |
| 334 | // if `next_tok` is a left paren, then the full expression looks something like |
| 335 | // `Foo[string](` or `Foo[mod.Type](`, which are valid type casts - return true |
| 336 | if next_tok.kind == .lpar { |
| 337 | return true |
| 338 | } |
| 339 | // any other token is not a valid generic cast, however |
| 340 | return false |
| 341 | } |
| 342 | |
| 343 | // is_generic_name returns true if the current token is a generic name. |
| 344 | @[inline] |
| 345 | fn (p &Parser) is_generic_name() bool { |
| 346 | return p.tok.kind == .name && util.is_generic_type_name(p.tok.lit) |
| 347 | } |
| 348 | |