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

View File

@ -2520,12 +2520,16 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
if !node.is_type {
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
}
ast.IsRefType {
if !node.is_type {
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
}
ast.OffsetOf {
@ -4395,3 +4399,11 @@ fn semicolonize(main string, details string) string {
}
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`
12 | println("size of Abc: ${sizeof(Abc)}")
13 | println("size of Xyz: ${sizeof(Xyz)}")
14 | println("size of Test: ${sizeof(T)}")
| ^
12 | println('size of Abc: ${sizeof[Abc]()}')
13 | println('size of Xyz: ${sizeof[Xyz]()}')
14 | println('size of Test: ${sizeof[T]()}')
| ~~
15 | }

View File

@ -9,7 +9,7 @@ struct Xyz {
type Test = Abc | Xyz
fn main() {
println("size of Abc: ${sizeof(Abc)}")
println("size of Xyz: ${sizeof(Xyz)}")
println("size of Test: ${sizeof(T)}")
println('size of Abc: ${sizeof[Abc]()}')
println('size of Xyz: ${sizeof[Xyz]()}')
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`
12 | println("size of Abc: ${sizeof(Abc)}")
13 | println("size of Xyz: ${sizeof(Xyz)}")
14 | println("size of Test: ${sizeof(Zabc)}")
| ~~~~
12 | println('size of Abc: ${sizeof[Abc]()}')
13 | println('size of Xyz: ${sizeof[Xyz]()}')
14 | println('size of Test: ${sizeof[Zabc]()}')
| ~~~~~
15 | }

View File

@ -9,7 +9,7 @@ struct Xyz {
type Test = Abc | Xyz
fn main() {
println("size of Abc: ${sizeof(Abc)}")
println("size of Xyz: ${sizeof(Xyz)}")
println("size of Test: ${sizeof(Zabc)}")
println('size of Abc: ${sizeof[Abc]()}')
println('size of Xyz: ${sizeof[Xyz]()}')
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) {
f.write('sizeof(')
f.write('sizeof')
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))
} else {
f.expr(node.expr)
f.write(')')
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) {
f.write('isreftype(')
f.write('isreftype')
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))
} else {
f.expr(node.expr)
f.write(')')
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) {

View File

@ -236,57 +236,85 @@ pub fn (mut p Parser) check_expr(precedence int) !ast.Expr {
.key_sizeof, .key_isreftype {
is_reftype := p.tok.kind == .key_isreftype
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 {
is_known_var = false
is_type = false
}
if is_known_var || !is_type {
expr := p.expr(0)
if p.tok.kind == .lsbr {
// parse sizeof[T]() and isreftype[T]() without guessing:
p.check(.lsbr)
mut type_pos := p.tok.pos()
typ := p.parse_type()
type_pos = type_pos.extend(p.tok.pos())
p.check(.rsbr)
p.check(.lpar)
p.check(.rpar)
if is_reftype {
node = ast.IsRefType{
is_type: false
expr: expr
pos: pos
is_type: true
typ: typ
pos: type_pos
}
} else {
node = ast.SizeOf{
is_type: false
expr: expr
pos: pos
is_type: true
typ: typ
pos: type_pos
}
}
} else {
if p.tok.kind == .name {
p.register_used_import(p.tok.lit)
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 {
is_known_var = false
is_type = false
}
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{
is_type: true
typ: arg_type
pos: pos
if is_known_var || !is_type {
expr := p.expr(0)
if is_reftype {
node = ast.IsRefType{
is_type: false
expr: expr
pos: pos
}
} else {
node = ast.SizeOf{
is_type: false
expr: expr
pos: pos
}
}
} else {
node = ast.SizeOf{
is_type: true
typ: arg_type
pos: pos
if p.tok.kind == .name {
p.register_used_import(p.tok.lit)
}
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 {
spos := p.tok.pos()