parser: parse `map{key_expr: val_expr}` (#8608)

pull/8615/head
Nick Treleaven 2021-02-06 21:13:24 +00:00 committed by GitHub
parent db0fc8fbc9
commit f5f65f929f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 67 additions and 14 deletions

View File

@ -128,13 +128,17 @@ fn test_map() {
}
fn test_map_init() {
m := {
'one': 1
one := 'one'
three := 'three'
m := map{
one: 1
'two': 2
three: 1 + 2
}
assert m['one'] == 1
assert m['two'] == 2
assert m['three'] == 0
assert m['three'] == 3
assert m['unknown'] == 0
}
fn test_string_map() {

View File

@ -5335,16 +5335,20 @@ pub fn (mut c Checker) check_dup_keys(node &ast.MapInit, i int) {
key_i := node.keys[i]
if key_i is ast.StringLiteral {
for j in 0 .. i {
key_j := node.keys[j] as ast.StringLiteral
if key_i.val == key_j.val {
c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
key_j := node.keys[j]
if key_j is ast.StringLiteral {
if key_i.val == key_j.val {
c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
}
}
}
} else if key_i is ast.IntegerLiteral {
for j in 0 .. i {
key_j := node.keys[j] as ast.IntegerLiteral
if key_i.val == key_j.val {
c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
key_j := node.keys[j]
if key_j is ast.IntegerLiteral {
if key_i.val == key_j.val {
c.error('duplicate key "$key_i.val" in map literal', key_i.pos)
}
}
}
}

View File

@ -152,6 +152,7 @@ fn (mut p Parser) array_init() ast.ArrayInit {
}
}
// parse tokens between braces
fn (mut p Parser) map_init() ast.MapInit {
first_pos := p.prev_tok.position()
mut keys := []ast.Expr{}

View File

@ -128,7 +128,13 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
p.next()
array_decompose = true
}
mut e := p.expr(0)
mut e := ast.Expr{}
if p.tok.kind == .name && p.peek_tok.kind == .colon {
// `foo(key:val, key2:val2)`
e = p.struct_init(true) // short_syntax:true
} else {
e = p.expr(0)
}
if array_decompose {
e = ast.ArrayDecompose{
expr: e

View File

@ -1314,6 +1314,16 @@ pub fn (mut p Parser) name_expr() ast.Expr {
&& (!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital))
&& !p.inside_match_case && (!p.inside_if || p.inside_select)
&& (!p.inside_for || p.inside_select) { // && (p.tok.lit[0].is_capital() || p.builtin_mod) {
// map.v has struct literal: map{field: expr}
if p.peek_tok.kind == .lcbr && !(p.builtin_mod && p.file_base == 'map.v')
&& p.tok.lit == 'map' {
// map{key_expr: val_expr}
p.check(.name)
p.check(.lcbr)
map_init := p.map_init()
p.check(.rcbr)
return map_init
}
return p.struct_init(false) // short_syntax: false
} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
// T.name
@ -1351,11 +1361,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
pos: p.tok.position()
mod: mod
}
} else if p.peek_tok.kind == .colon && p.prev_tok.kind != .str_dollar {
// `foo(key:val, key2:val2)`
return p.struct_init(true) // short_syntax:true
// JS. function call with more than 1 dot
} else if language == .js && p.peek_tok.kind == .dot && p.peek_tok2.kind == .name {
// JS. function call with more than 1 dot
node = p.call_expr(language, mod)
} else {
node = p.parse_ident(language)

View File

@ -240,6 +240,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
// Map `{"age": 20}` or `{ x | foo:bar, a:10 }`
p.next()
if p.tok.kind in [.chartoken, .number, .string] {
// TODO deprecate
node = p.map_init()
} else {
// it should be a struct

View File

@ -0,0 +1,30 @@
const (
alpha = 'a'
beta = 'b'
m = map{
alpha : 'Alpha'
beta : 'Beta'
}
)
fn test_const_keys() {
assert m[alpha] == 'Alpha'
assert m[beta] == 'Beta'
}
enum Enum {
a b
}
const (
m2 = map{
Enum.a.str() : 'first'
Enum.b.str() : 'second'
}
)
fn test_method_call() {
assert m2.keys() == ['a', 'b']
assert m2[Enum.a.str()] == 'first'
assert m2[Enum.b.str()] == 'second'
}