v: virtual C consts with custom types (const C.MY_CONST u8)

This commit is contained in:
Alexander Medvednikov 2025-07-19 18:47:44 +03:00
parent 3725576729
commit 9ef51ee714
5 changed files with 58 additions and 16 deletions

View file

@ -398,12 +398,13 @@ pub fn (f &StructField) equals(o &StructField) bool {
// const field in const declaration group
pub struct ConstField {
pub:
mod string
name string
is_pub bool
is_markused bool // an explicit `@[markused]` tag; the const will NOT be removed by `-skip-unused`, no matter what
pos token.Pos
attrs []Attr // same value as `attrs` of the ConstDecl to which it belongs
mod string
name string
is_pub bool
is_markused bool // an explicit `@[markused]` tag; the const will NOT be removed by `-skip-unused`, no matter what
pos token.Pos
attrs []Attr // same value as `attrs` of the ConstDecl to which it belongs
is_virtual_c bool // `const C.MY_CONST u8`
pub mut:
expr Expr // the value expr of field; everything after `=`
typ Type // the type of the const field, it can be any type in V

View file

@ -4297,6 +4297,10 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
if node.name == 'C.NULL' {
return ast.voidptr_type
}
// TODO remove main. to avoid extra concats
if x := c.table.global_scope.find_const('main.' + node.name) {
return x.typ
}
return ast.int_type
}
if c.inside_sql {

View file

@ -968,9 +968,17 @@ pub fn (mut f Fmt) const_decl(node ast.ConstDecl) {
}
f.write('const ')
}
if field.is_virtual_c {
f.write('C.')
}
f.write('${name} ')
f.write('= ')
f.expr(field.expr)
if field.is_virtual_c {
// f.typ(field.typ)
f.write(f.table.type_to_str(field.typ))
} else {
f.write('= ')
f.expr(field.expr)
}
f.comments(field.end_comments, same_line: true)
if node.is_block && fidx < node.fields.len - 1 && node.fields.len > 1 {
// old style grouped consts, converted to the new style ungrouped const

View file

@ -2368,10 +2368,20 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
break
}
pos := p.tok.pos()
name := p.check_name()
mut name := p.check_name()
end_comments << p.eat_comments()
if !p.pref.translated && !p.is_translated && util.contains_capital(name) {
p.error_with_pos('const names cannot contain uppercase letters, use snake_case instead',
// Handle `const C.MY_CONST u16`
mut is_virtual_c_const := false
mut typ := ast.void_type
if name == 'C' && p.tok.kind == .dot {
p.next()
name += '.' + p.check_name()
typ = p.parse_type()
is_virtual_c_const = true
}
if !p.pref.translated && !p.is_translated && util.contains_capital(name)
&& !is_virtual_c_const {
p.error_with_pos('${name} const names cannot contain uppercase letters, use snake_case instead',
pos)
}
full_name := p.prepend_mod(name)
@ -2379,14 +2389,17 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
p.error_with_pos('const declaration do not support multiple assign yet', p.tok.pos())
}
// Allow for `const x := 123`, and for `const x = 123` too.
// Supporting `const x := 123` in addition to `const x = 123`, makes extracting local variables to constants much less annoying, while prototyping:
// Supporting `const x := 123` in addition to `const x = 123`, makes extracting local variables to constants
// much less annoying, while prototyping:
if p.tok.kind == .decl_assign {
p.check(.decl_assign)
} else {
p.check(.assign)
if !is_virtual_c_const {
p.check(.assign)
}
}
end_comments << p.eat_comments()
if p.tok.kind == .key_fn {
if p.tok.kind == .key_fn && !is_virtual_c_const {
p.error('const initializer fn literal is not a constant')
return ast.ConstDecl{}
}
@ -2394,11 +2407,14 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
p.unexpected(got: 'eof', expecting: 'an expression')
return ast.ConstDecl{}
}
expr := p.expr(0)
mut expr := ast.Expr{}
if !is_virtual_c_const {
expr = p.expr(0)
}
if is_block {
end_comments << p.eat_comments(same_line: true)
}
field := ast.ConstField{
mut field := ast.ConstField{
name: full_name
mod: p.mod
is_pub: is_pub
@ -2408,6 +2424,10 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
comments: comments
end_comments: end_comments
is_markused: is_markused
is_virtual_c: is_virtual_c_const
}
if is_virtual_c_const {
field.typ = typ
}
fields << field
p.table.global_scope.register(field)

View file

@ -0,0 +1,9 @@
const C.AF_INET u16
fn x(n u16) bool {
return true
}
fn test_const() {
assert x(C.AF_INET) == true
}