parser: parse func<T>() when T is a map or array type (#6765)

pull/6737/head
Nick Treleaven 2020-11-07 01:55:28 +00:00 committed by GitHub
parent 1d706674f2
commit 62cae1ba00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 3 deletions

View File

@ -1030,13 +1030,28 @@ pub fn (mut p Parser) name_expr() ast.Expr {
p.expr_mod = mod p.expr_mod = mod
} }
lit0_is_capital := p.tok.lit[0].is_capital() lit0_is_capital := p.tok.lit[0].is_capital()
// use heuristics to detect `func<T>()` from `var < expr`
is_generic_call := !lit0_is_capital && p.peek_tok.kind == .lt && (match p.peek_tok2.kind {
.name {
// maybe `f<int>`, `f<map[`
(p.peek_tok2.kind == .name &&
p.peek_tok3.kind == .gt) ||
(p.peek_tok2.lit == 'map' && p.peek_tok3.kind == .lsbr)
}
.lsbr {
// maybe `f<[]T>`, assume `var < []` is invalid
p.peek_tok3.kind == .rsbr
}
else {
false
}
})
// p.warn('name expr $p.tok.lit $p.peek_tok.str()') // p.warn('name expr $p.tok.lit $p.peek_tok.str()')
same_line := p.tok.line_nr == p.peek_tok.line_nr same_line := p.tok.line_nr == p.peek_tok.line_nr
// `(` must be on same line as name token otherwise it's a ParExpr // `(` must be on same line as name token otherwise it's a ParExpr
if !same_line && p.peek_tok.kind == .lpar { if !same_line && p.peek_tok.kind == .lpar {
node = p.parse_ident(language) node = p.parse_ident(language)
} else if p.peek_tok.kind == .lpar || } else if p.peek_tok.kind == .lpar || is_generic_call {
(p.peek_tok.kind == .lt && !lit0_is_capital && p.peek_tok2.kind == .name && p.peek_tok3.kind == .gt) {
// foo(), foo<int>() or type() cast // foo(), foo<int>() or type() cast
mut name := p.tok.lit mut name := p.tok.lit
if mod.len > 0 { if mod.len > 0 {

View File

@ -13,11 +13,17 @@ fn plus<T>(xxx T, b T) T {
return xxx + b return xxx + b
} }
fn test_generic_fn() { fn test_identity() {
assert simple<int>(1) == 1 assert simple<int>(1) == 1
assert simple<int>(1 + 0) == 1 assert simple<int>(1 + 0) == 1
assert simple<string>('g') == 'g' assert simple<string>('g') == 'g'
assert simple<string>('g') + 'h' == 'gh' assert simple<string>('g') + 'h' == 'gh'
assert simple<[]int>([1])[0] == 1
assert simple<map[string]string>({'a':'b'})['a'] == 'b'
}
fn test_plus() {
a := plus<int>(2, 3) a := plus<int>(2, 3)
println(a) println(a)
assert a == 5 assert a == 5