v/vlib/v/parser/lock.v

114 lines
2.4 KiB
V

module parser
import v.token
import v.ast
// parse `x` or `x.y.z` - no index, no struct literals (`{` starts lock block)
fn (mut p Parser) lockable() ast.Expr {
mut names := []string{}
mut positions := []token.Position{}
mut pos := p.tok.position()
for {
if p.tok.kind != .name {
p.error_with_pos('unexpected `$p.tok.lit` (field/variable name expected)',
p.tok.position())
}
names << p.tok.lit
positions << pos
p.next()
if p.tok.kind != .dot {
break
}
p.next()
pos.extend(p.tok.position())
}
mut expr := ast.Expr(ast.Ident{
language: ast.Language.v
pos: positions[0]
mod: p.mod
name: names[0]
is_mut: true
info: ast.IdentVar{}
scope: p.scope
})
for i := 1; i < names.len; i++ {
expr = ast.SelectorExpr{
expr: expr
field_name: names[i]
next_token: if i < names.len - 1 { token.Kind.dot } else { p.tok.kind }
is_mut: true
pos: positions[i]
scope: p.scope
}
}
return expr
}
// like `expr_list()` but only lockables are allowed, `{` starts lock block (not struct literal)
fn (mut p Parser) lockable_list() ([]ast.Expr, []ast.Comment) {
mut exprs := []ast.Expr{}
mut comments := []ast.Comment{}
for {
expr := p.lockable()
if expr is ast.Comment {
comments << expr
} else {
exprs << expr
if p.tok.kind != .comma {
break
}
p.next()
}
}
return exprs, comments
}
fn (mut p Parser) lock_expr() ast.LockExpr {
// TODO Handle aliasing sync
p.register_auto_import('sync')
p.open_scope()
mut pos := p.tok.position()
mut lockeds := []ast.Expr{}
mut comments := []ast.Comment{}
mut is_rlocked := []bool{}
for {
is_rlock := p.tok.kind == .key_rlock
if !is_rlock && p.tok.kind != .key_lock {
p.error_with_pos('unexpected `$p.tok`, expected `lock` or `rlock`', p.tok.position())
}
p.next()
if p.tok.kind == .lcbr {
break
}
if p.tok.kind == .name {
exprs, comms := p.lockable_list()
for e in exprs {
if !e.is_lockable() {
p.error_with_pos('`$e` cannot be locked - only `x` or `x.y` are supported',
e.position())
}
lockeds << e
is_rlocked << is_rlock
}
comments << comms
}
if p.tok.kind == .lcbr {
break
}
if p.tok.kind == .semicolon {
p.next()
}
}
stmts := p.parse_block_no_scope(false)
scope := p.scope
p.close_scope()
pos.update_last_line(p.prev_tok.line_nr)
return ast.LockExpr{
lockeds: lockeds
stmts: stmts
is_rlock: is_rlocked
pos: pos
scope: scope
}
}