1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

parser: support an unambiguous sizeof[T]() and isreftype[T]() (part 1) (#16684)

This commit is contained in:
Delyan Angelov 2022-12-15 19:21:52 +02:00 committed by GitHub
parent e5e73ebbfa
commit 0a11955284
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 128 additions and 66 deletions

View File

@ -6468,4 +6468,4 @@ Assignment Operators
+= -= *= /= %= += -= *= /= %=
&= |= ^= &= |= ^=
>>= <<= >>>= >>= <<= >>>=
``` ```

View File

@ -1591,19 +1591,21 @@ pub mut:
pub struct SizeOf { pub struct SizeOf {
pub: pub:
is_type bool guessed_type bool // a legacy `sizeof( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `sizeof[ Type ]()`
pos token.Pos is_type bool
pos token.Pos
pub mut: pub mut:
expr Expr // checker uses this to set typ expr Expr // checker uses this to set typ, when !is_type
typ Type typ Type
} }
pub struct IsRefType { pub struct IsRefType {
pub: pub:
is_type bool guessed_type bool // a legacy `isreftype( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `isreftype[ Type ]()`
pos token.Pos is_type bool
pos token.Pos
pub mut: pub mut:
expr Expr // checker uses this to set typ expr Expr // checker uses this to set typ, when !is_type
typ Type typ Type
} }
@ -1629,7 +1631,7 @@ pub:
is_type bool is_type bool
pos token.Pos pos token.Pos
pub mut: pub mut:
expr Expr // checker uses this to set typ expr Expr // checker uses this to set typ, when !is_type
typ Type typ Type
} }

View File

@ -2520,12 +2520,16 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
if !node.is_type { if !node.is_type {
node.typ = c.expr(node.expr) node.typ = c.expr(node.expr)
} }
// c.deprecate_old_isreftype_and_sizeof_of_a_guessed_type(node.guessed_type,
// node.typ, node.pos, 'sizeof')
return ast.u32_type return ast.u32_type
} }
ast.IsRefType { ast.IsRefType {
if !node.is_type { if !node.is_type {
node.typ = c.expr(node.expr) node.typ = c.expr(node.expr)
} }
// c.deprecate_old_isreftype_and_sizeof_of_a_guessed_type(node.guessed_type,
// node.typ, node.pos, 'isreftype')
return ast.bool_type return ast.bool_type
} }
ast.OffsetOf { ast.OffsetOf {
@ -4395,3 +4399,11 @@ fn semicolonize(main string, details string) string {
} }
return '${main}; ${details}' return '${main}; ${details}'
} }
fn (mut c Checker) deprecate_old_isreftype_and_sizeof_of_a_guessed_type(is_guessed_type bool, typ ast.Type, pos token.Pos, label string) {
if is_guessed_type {
styp := c.table.type_to_str(typ)
c.note('`${label}(${styp})` is deprecated. Use `v fmt -w .` to convert it to `${label}[${styp}]()` instead.',
pos)
}
}

View File

@ -1,6 +1,6 @@
vlib/v/checker/tests/unknown_sizeof_type_err_a.vv:14:34: cgen error: unknown type `T` vlib/v/checker/tests/unknown_sizeof_type_err_a.vv:14:34: cgen error: unknown type `T`
12 | println("size of Abc: ${sizeof(Abc)}") 12 | println('size of Abc: ${sizeof[Abc]()}')
13 | println("size of Xyz: ${sizeof(Xyz)}") 13 | println('size of Xyz: ${sizeof[Xyz]()}')
14 | println("size of Test: ${sizeof(T)}") 14 | println('size of Test: ${sizeof[T]()}')
| ^ | ~~
15 | } 15 | }

View File

@ -9,7 +9,7 @@ struct Xyz {
type Test = Abc | Xyz type Test = Abc | Xyz
fn main() { fn main() {
println("size of Abc: ${sizeof(Abc)}") println('size of Abc: ${sizeof[Abc]()}')
println("size of Xyz: ${sizeof(Xyz)}") println('size of Xyz: ${sizeof[Xyz]()}')
println("size of Test: ${sizeof(T)}") println('size of Test: ${sizeof[T]()}')
} }

View File

@ -1,6 +1,6 @@
vlib/v/checker/tests/unknown_sizeof_type_err_b.vv:14:34: cgen error: unknown type `Zabc` vlib/v/checker/tests/unknown_sizeof_type_err_b.vv:14:34: cgen error: unknown type `Zabc`
12 | println("size of Abc: ${sizeof(Abc)}") 12 | println('size of Abc: ${sizeof[Abc]()}')
13 | println("size of Xyz: ${sizeof(Xyz)}") 13 | println('size of Xyz: ${sizeof[Xyz]()}')
14 | println("size of Test: ${sizeof(Zabc)}") 14 | println('size of Test: ${sizeof[Zabc]()}')
| ~~~~ | ~~~~~
15 | } 15 | }

View File

@ -9,7 +9,7 @@ struct Xyz {
type Test = Abc | Xyz type Test = Abc | Xyz
fn main() { fn main() {
println("size of Abc: ${sizeof(Abc)}") println('size of Abc: ${sizeof[Abc]()}')
println("size of Xyz: ${sizeof(Xyz)}") println('size of Xyz: ${sizeof[Xyz]()}')
println("size of Test: ${sizeof(Zabc)}") println('size of Test: ${sizeof[Zabc]()}')
} }

View File

@ -2572,23 +2572,43 @@ pub fn (mut f Fmt) selector_expr(node ast.SelectorExpr) {
} }
pub fn (mut f Fmt) size_of(node ast.SizeOf) { pub fn (mut f Fmt) size_of(node ast.SizeOf) {
f.write('sizeof(') f.write('sizeof')
if node.is_type { if node.is_type {
// keep the old form for now
f.write('(')
f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias))
} else { f.write(')')
f.expr(node.expr) return
}
if node.is_type {
f.write('[')
f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias))
f.write(']()')
} else {
f.write('(')
f.expr(node.expr)
f.write(')')
} }
f.write(')')
} }
pub fn (mut f Fmt) is_ref_type(node ast.IsRefType) { pub fn (mut f Fmt) is_ref_type(node ast.IsRefType) {
f.write('isreftype(') f.write('isreftype')
if node.is_type { if node.is_type {
// keep the old form for now
f.write('(')
f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias)) f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias))
} else { f.write(')')
f.expr(node.expr) return
}
if node.is_type {
f.write('[')
f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias))
f.write(']()')
} else {
f.write('(')
f.expr(node.expr)
f.write(')')
} }
f.write(')')
} }
pub fn (mut f Fmt) sql_expr(node ast.SqlExpr) { pub fn (mut f Fmt) sql_expr(node ast.SqlExpr) {

View File

@ -236,57 +236,85 @@ pub fn (mut p Parser) check_expr(precedence int) !ast.Expr {
.key_sizeof, .key_isreftype { .key_sizeof, .key_isreftype {
is_reftype := p.tok.kind == .key_isreftype is_reftype := p.tok.kind == .key_isreftype
p.next() // sizeof p.next() // sizeof
p.check(.lpar)
pos := p.tok.pos()
mut is_known_var := p.mark_var_as_used(p.tok.lit)
|| p.table.global_scope.known_const(p.mod + '.' + p.tok.lit)
//|| p.table.known_fn(p.mod + '.' + p.tok.lit)
// assume `mod.` prefix leads to a type
mut is_type := p.known_import(p.tok.lit) || p.tok.kind.is_start_of_type()
|| (p.tok.lit.len > 0 && p.tok.lit[0].is_capital())
if p.tok.lit in ['c', 'r'] && p.peek_tok.kind == .string { if p.tok.kind == .lsbr {
is_known_var = false // parse sizeof[T]() and isreftype[T]() without guessing:
is_type = false p.check(.lsbr)
} mut type_pos := p.tok.pos()
if is_known_var || !is_type { typ := p.parse_type()
expr := p.expr(0) type_pos = type_pos.extend(p.tok.pos())
p.check(.rsbr)
p.check(.lpar)
p.check(.rpar)
if is_reftype { if is_reftype {
node = ast.IsRefType{ node = ast.IsRefType{
is_type: false is_type: true
expr: expr typ: typ
pos: pos pos: type_pos
} }
} else { } else {
node = ast.SizeOf{ node = ast.SizeOf{
is_type: false is_type: true
expr: expr typ: typ
pos: pos pos: type_pos
} }
} }
} else { } else {
if p.tok.kind == .name { p.check(.lpar)
p.register_used_import(p.tok.lit) pos := p.tok.pos()
mut is_known_var := p.mark_var_as_used(p.tok.lit)
|| p.table.global_scope.known_const(p.mod + '.' + p.tok.lit)
//|| p.table.known_fn(p.mod + '.' + p.tok.lit)
// assume `mod.` prefix leads to a type
mut is_type := p.known_import(p.tok.lit)
|| p.tok.kind.is_start_of_type()
|| (p.tok.lit.len > 0 && p.tok.lit[0].is_capital())
if p.tok.lit in ['c', 'r'] && p.peek_tok.kind == .string {
is_known_var = false
is_type = false
} }
save_expr_mod := p.expr_mod if is_known_var || !is_type {
p.expr_mod = '' expr := p.expr(0)
arg_type := p.parse_type() if is_reftype {
p.expr_mod = save_expr_mod node = ast.IsRefType{
if is_reftype { is_type: false
node = ast.IsRefType{ expr: expr
is_type: true pos: pos
typ: arg_type }
pos: pos } else {
node = ast.SizeOf{
is_type: false
expr: expr
pos: pos
}
} }
} else { } else {
node = ast.SizeOf{ if p.tok.kind == .name {
is_type: true p.register_used_import(p.tok.lit)
typ: arg_type }
pos: pos save_expr_mod := p.expr_mod
p.expr_mod = ''
arg_type := p.parse_type()
p.expr_mod = save_expr_mod
if is_reftype {
node = ast.IsRefType{
guessed_type: true
is_type: true
typ: arg_type
pos: pos
}
} else {
node = ast.SizeOf{
guessed_type: true
is_type: true
typ: arg_type
pos: pos
}
} }
} }
p.check(.rpar)
} }
p.check(.rpar)
} }
.key_dump { .key_dump {
spos := p.tok.pos() spos := p.tok.pos()