checker, gen: add support for a [minify] struct attribute (#14247)

master
spaceface 2022-05-02 00:59:17 +02:00 committed by GitHub
parent aed2d0caf2
commit 332e821518
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 249 additions and 49 deletions

View File

@ -202,6 +202,7 @@ pub:
pos token.Pos pos token.Pos
} }
[minify]
pub struct StringLiteral { pub struct StringLiteral {
pub: pub:
val string val string
@ -246,6 +247,7 @@ pub enum GenericKindField {
} }
// `foo.bar` // `foo.bar`
[minify]
pub struct SelectorExpr { pub struct SelectorExpr {
pub: pub:
pos token.Pos pos token.Pos
@ -287,11 +289,13 @@ pub:
is_skipped bool // module main can be skipped in single file programs is_skipped bool // module main can be skipped in single file programs
} }
[minify]
pub struct StructField { pub struct StructField {
pub: pub:
pos token.Pos pos token.Pos
type_pos token.Pos type_pos token.Pos
comments []Comment comments []Comment
i int
has_default_expr bool has_default_expr bool
attrs []Attr attrs []Attr
is_pub bool is_pub bool
@ -333,6 +337,7 @@ pub mut:
} }
// const declaration // const declaration
[minify]
pub struct ConstDecl { pub struct ConstDecl {
pub: pub:
is_pub bool is_pub bool
@ -344,6 +349,7 @@ pub mut:
is_block bool // const() block is_block bool // const() block
} }
[minify]
pub struct StructDecl { pub struct StructDecl {
pub: pub:
pos token.Pos pos token.Pos
@ -380,6 +386,7 @@ pub:
comments []Comment comments []Comment
} }
[minify]
pub struct InterfaceDecl { pub struct InterfaceDecl {
pub: pub:
name string name string
@ -431,6 +438,7 @@ pub mut:
// ...a // ...a
// field1: 'hello' // field1: 'hello'
// }` // }`
[minify]
pub struct StructInit { pub struct StructInit {
pub: pub:
pos token.Pos pos token.Pos
@ -484,6 +492,7 @@ pub mut:
} }
// function or method declaration // function or method declaration
[minify]
pub struct FnDecl { pub struct FnDecl {
pub: pub:
name string // 'math.bits.normalize' name string // 'math.bits.normalize'
@ -542,6 +551,7 @@ pub mut:
} }
// break, continue // break, continue
[minify]
pub struct BranchStmt { pub struct BranchStmt {
pub: pub:
kind token.Kind kind token.Kind
@ -550,6 +560,7 @@ pub:
} }
// function or method call expr // function or method call expr
[minify]
pub struct CallExpr { pub struct CallExpr {
pub: pub:
pos token.Pos pos token.Pos
@ -589,6 +600,7 @@ pub struct AutofreeArgVar {
} }
*/ */
// function call argument: `f(callarg)` // function call argument: `f(callarg)`
[minify]
pub struct CallArg { pub struct CallArg {
pub: pub:
is_mut bool is_mut bool
@ -612,6 +624,7 @@ pub mut:
types []Type types []Type
} }
[minify]
pub struct Var { pub struct Var {
pub: pub:
name string name string
@ -643,6 +656,7 @@ pub mut:
// used for smartcasting only // used for smartcasting only
// struct fields change type in scopes // struct fields change type in scopes
[minify]
pub struct ScopeStructField { pub struct ScopeStructField {
pub: pub:
struct_type Type // type of struct struct_type Type // type of struct
@ -657,6 +671,7 @@ pub:
// 12 <- the current casted type (typ) // 12 <- the current casted type (typ)
} }
[minify]
pub struct GlobalField { pub struct GlobalField {
pub: pub:
name string name string
@ -682,6 +697,7 @@ pub mut:
end_comments []Comment end_comments []Comment
} }
[minify]
pub struct EmbeddedFile { pub struct EmbeddedFile {
pub: pub:
rpath string // used in the source code, as an ID/key to the embed rpath string // used in the source code, as an ID/key to the embed
@ -749,6 +765,7 @@ pub mut:
// TODO: (joe) remove completely, use ident.obj // TODO: (joe) remove completely, use ident.obj
// instead which points to the scope object // instead which points to the scope object
[minify]
pub struct IdentVar { pub struct IdentVar {
pub mut: pub mut:
typ Type typ Type
@ -771,6 +788,7 @@ pub enum IdentKind {
} }
// A single identifier // A single identifier
[minify]
pub struct Ident { pub struct Ident {
pub: pub:
language Language language Language
@ -816,6 +834,7 @@ pub fn (i &Ident) var_info() IdentVar {
// left op right // left op right
// See: token.Kind.is_infix // See: token.Kind.is_infix
[minify]
pub struct InfixExpr { pub struct InfixExpr {
pub: pub:
op token.Kind op token.Kind
@ -846,6 +865,7 @@ pub mut:
} }
// See: token.Kind.is_prefix // See: token.Kind.is_prefix
[minify]
pub struct PrefixExpr { pub struct PrefixExpr {
pub: pub:
op token.Kind op token.Kind
@ -857,6 +877,7 @@ pub mut:
is_option bool // IfGuard is_option bool // IfGuard
} }
[minify]
pub struct IndexExpr { pub struct IndexExpr {
pub: pub:
pos token.Pos pos token.Pos
@ -874,6 +895,7 @@ pub mut:
is_gated bool // #[] gated array is_gated bool // #[] gated array
} }
[minify]
pub struct IfExpr { pub struct IfExpr {
pub: pub:
is_comptime bool is_comptime bool
@ -921,6 +943,7 @@ pub mut:
scope &Scope scope &Scope
} }
[minify]
pub struct MatchExpr { pub struct MatchExpr {
pub: pub:
tok_kind token.Kind tok_kind token.Kind
@ -959,6 +982,7 @@ pub mut:
expected_type Type // for debugging only expected_type Type // for debugging only
} }
[minify]
pub struct SelectBranch { pub struct SelectBranch {
pub: pub:
pos token.Pos pos token.Pos
@ -1000,6 +1024,7 @@ pub mut:
scope &Scope scope &Scope
} }
[minify]
pub struct ForInStmt { pub struct ForInStmt {
pub: pub:
key_var string key_var string
@ -1060,6 +1085,7 @@ pub:
} }
*/ */
// variable assign statement // variable assign statement
[minify]
pub struct AssignStmt { pub struct AssignStmt {
pub: pub:
op token.Kind // include: =,:=,+=,-=,*=,/= and so on; for a list of all the assign operators, see vlib/token/token.v op token.Kind // include: =,:=,+=,-=,*=,/= and so on; for a list of all the assign operators, see vlib/token/token.v
@ -1111,6 +1137,7 @@ pub mut:
} }
// enum declaration // enum declaration
[minify]
pub struct EnumDecl { pub struct EnumDecl {
pub: pub:
name string name string
@ -1161,6 +1188,7 @@ pub:
// TODO: handle this differently // TODO: handle this differently
// v1 excludes non current os ifdefs so // v1 excludes non current os ifdefs so
// the defer's never get added in the first place // the defer's never get added in the first place
[minify]
pub struct DeferStmt { pub struct DeferStmt {
pub: pub:
stmts []Stmt stmts []Stmt
@ -1179,6 +1207,7 @@ pub mut:
expr Expr expr Expr
} }
[minify]
pub struct GoExpr { pub struct GoExpr {
pub: pub:
pos token.Pos pos token.Pos
@ -1199,6 +1228,7 @@ pub:
pos token.Pos pos token.Pos
} }
[minify]
pub struct ArrayInit { pub struct ArrayInit {
pub: pub:
pos token.Pos // `[]` in []Type{} position pos token.Pos // `[]` in []Type{} position
@ -1242,6 +1272,7 @@ pub mut:
elem_type Type elem_type Type
} }
[minify]
pub struct MapInit { pub struct MapInit {
pub: pub:
pos token.Pos pos token.Pos
@ -1257,6 +1288,7 @@ pub mut:
} }
// s[10..20] // s[10..20]
[minify]
pub struct RangeExpr { pub struct RangeExpr {
pub: pub:
has_high bool has_high bool
@ -1268,6 +1300,7 @@ pub mut:
high Expr high Expr
} }
[minify]
pub struct CastExpr { pub struct CastExpr {
pub mut: pub mut:
arg Expr // `n` in `string(buf, n)` arg Expr // `n` in `string(buf, n)`
@ -1279,6 +1312,7 @@ pub mut:
pos token.Pos pos token.Pos
} }
[minify]
pub struct AsmStmt { pub struct AsmStmt {
pub: pub:
arch pref.Arch arch pref.Arch
@ -1296,6 +1330,7 @@ pub mut:
local_labels []string // local to the assembly block local_labels []string // local to the assembly block
} }
[minify]
pub struct AsmTemplate { pub struct AsmTemplate {
pub mut: pub mut:
name string name string
@ -1460,6 +1495,7 @@ pub const (
} }
) )
[minify]
pub struct AssertStmt { pub struct AssertStmt {
pub: pub:
pos token.Pos pos token.Pos
@ -1511,6 +1547,7 @@ pub:
*/ */
// deprecated // deprecated
[minify]
pub struct Assoc { pub struct Assoc {
pub: pub:
var_name string var_name string
@ -1540,6 +1577,7 @@ pub mut:
typ Type typ Type
} }
[minify]
pub struct OffsetOf { pub struct OffsetOf {
pub: pub:
struct_type Type struct_type Type
@ -1555,6 +1593,7 @@ pub mut:
expr Expr expr Expr
} }
[minify]
pub struct TypeOf { pub struct TypeOf {
pub: pub:
pos token.Pos pos token.Pos
@ -1563,6 +1602,7 @@ pub mut:
expr_type Type expr_type Type
} }
[minify]
pub struct DumpExpr { pub struct DumpExpr {
pub: pub:
pos token.Pos pos token.Pos
@ -1598,6 +1638,7 @@ pub mut:
val string val string
} }
[minify]
pub struct ComptimeSelector { pub struct ComptimeSelector {
pub: pub:
has_parens bool // if $() is used, for vfmt has_parens bool // if $() is used, for vfmt
@ -1609,6 +1650,7 @@ pub mut:
typ Type typ Type
} }
[minify]
pub struct ComptimeCall { pub struct ComptimeCall {
pub: pub:
pos token.Pos pos token.Pos

View File

@ -14,6 +14,7 @@ pub enum AttrKind {
} }
// e.g. `[unsafe]` // e.g. `[unsafe]`
[minify]
pub struct Attr { pub struct Attr {
pub: pub:
name string // [name] name string // [name]

View File

@ -9,7 +9,7 @@ import v.cflag
import v.token import v.token
import v.util import v.util
[heap] [heap; minify]
pub struct Table { pub struct Table {
mut: mut:
parsing_type string // name of the type to enable recursive type parsing parsing_type string // name of the type to enable recursive type parsing
@ -86,6 +86,7 @@ pub fn (t &Table) panic(message string) {
t.panic_handler(t, message) t.panic_handler(t, message)
} }
[minify]
pub struct Fn { pub struct Fn {
pub: pub:
is_variadic bool is_variadic bool
@ -126,6 +127,7 @@ fn (f &Fn) method_equals(o &Fn) bool {
&& f.name == o.name && f.name == o.name
} }
[minify]
pub struct Param { pub struct Param {
pub: pub:
pos token.Pos pos token.Pos

View File

@ -41,14 +41,22 @@ fn test_type_size() ? {
mut t := b.table mut t := b.table
assert sizeof(T01) == t.type_size(t.type_idxs['main.T01'] ?) size01, _ := t.type_size(t.type_idxs['main.T01'] ?)
assert sizeof(T02) == t.type_size(t.type_idxs['main.T02'] ?) assert sizeof(T01) == size01
assert sizeof(T03) == t.type_size(t.type_idxs['main.T03'] ?) size02, _ := t.type_size(t.type_idxs['main.T02'] ?)
assert sizeof(T04) == t.type_size(t.type_idxs['main.T04'] ?) assert sizeof(T02) == size02
assert sizeof(T05) == t.type_size(t.type_idxs['main.T05'] ?) size03, _ := t.type_size(t.type_idxs['main.T03'] ?)
assert sizeof(T06) == t.type_size(t.type_idxs['main.T06'] ?) assert sizeof(T03) == size03
assert sizeof(T07) == t.type_size(t.type_idxs['main.T07'] ?) size04, _ := t.type_size(t.type_idxs['main.T04'] ?)
assert sizeof(T08) == t.type_size(t.type_idxs['main.T08'] ?) assert sizeof(T04) == size04
size05, _ := t.type_size(t.type_idxs['main.T05'] ?)
assert sizeof(T05) == size05
size06, _ := t.type_size(t.type_idxs['main.T06'] ?)
assert sizeof(T06) == size06
size07, _ := t.type_size(t.type_idxs['main.T07'] ?)
assert sizeof(T07) == size07
size08, _ := t.type_size(t.type_idxs['main.T08'] ?)
assert sizeof(T08) == size08
println('done') println('done')
} }

View File

@ -80,6 +80,7 @@ pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language {
// Each TypeSymbol is entered into `Table.types`. // Each TypeSymbol is entered into `Table.types`.
// See also: Table.sym. // See also: Table.sym.
[minify]
pub struct TypeSymbol { pub struct TypeSymbol {
pub: pub:
parent_idx int parent_idx int
@ -93,6 +94,8 @@ pub mut:
is_pub bool is_pub bool
language Language language Language
idx int idx int
size int = -1
align int = -1
} }
// max of 8 // max of 8
@ -825,88 +828,100 @@ pub fn (t &TypeSymbol) is_builtin() bool {
return t.mod == 'builtin' return t.mod == 'builtin'
} }
// type_size returns the size in bytes of `typ`, similarly to C's `sizeof()`. // type_size returns the size and alignment (in bytes) of `typ`, similarly to C's `sizeof()` and `alignof()`.
pub fn (t &Table) type_size(typ Type) int { pub fn (t &Table) type_size(typ Type) (int, int) {
if typ.has_flag(.optional) { if typ.has_flag(.optional) {
return t.type_size(ast.error_type_idx) return t.type_size(ast.error_type_idx)
} }
if typ.nr_muls() > 0 { if typ.nr_muls() > 0 {
return t.pointer_size return t.pointer_size, t.pointer_size
} }
sym := t.sym(typ) mut sym := t.sym(typ)
if sym.size != -1 {
return sym.size, sym.align
}
mut size := 0
mut align := 0
match sym.kind { match sym.kind {
.placeholder, .void, .none_ { .placeholder, .void, .none_, .generic_inst {}
return 0
}
.voidptr, .byteptr, .charptr, .function, .usize, .isize, .any, .thread, .chan { .voidptr, .byteptr, .charptr, .function, .usize, .isize, .any, .thread, .chan {
return t.pointer_size size = t.pointer_size
} }
.i8, .u8, .char, .bool { .i8, .u8, .char, .bool {
return 1 size = 1
align = 1
} }
.i16, .u16 { .i16, .u16 {
return 2 size = 2
align = 2
} }
.int, .u32, .rune, .f32, .enum_ { .int, .u32, .rune, .f32, .enum_ {
return 4 size = 4
align = 4
} }
.i64, .u64, .int_literal, .f64, .float_literal { .i64, .u64, .int_literal, .f64, .float_literal {
return 8 size = 8
align = 8
} }
.alias { .alias {
return t.type_size((sym.info as Alias).parent_type) size, align = t.type_size((sym.info as Alias).parent_type)
} }
.struct_, .string, .multi_return { .struct_, .string, .multi_return {
mut max_alignment := 0 mut max_alignment := 0
mut total_size := 0 mut total_size := 0
types := if sym.info is Struct { types := if mut sym.info is Struct {
sym.info.fields.map(it.typ) sym.info.fields.map(it.typ)
} else { } else {
(sym.info as MultiReturn).types (sym.info as MultiReturn).types
} }
for ftyp in types { for ftyp in types {
field_size := t.type_size(ftyp) field_size, alignment := t.type_size(ftyp)
alignment := if field_size > t.pointer_size { t.pointer_size } else { field_size }
if alignment > max_alignment { if alignment > max_alignment {
max_alignment = alignment max_alignment = alignment
} }
total_size = round_up(total_size, alignment) + field_size total_size = round_up(total_size, alignment) + field_size
} }
return round_up(total_size, max_alignment) size = round_up(total_size, max_alignment)
align = max_alignment
} }
.sum_type, .interface_, .aggregate { .sum_type, .interface_, .aggregate {
match sym.info { match mut sym.info {
SumType, Aggregate { SumType, Aggregate {
return (sym.info.fields.len + 2) * t.pointer_size size = (sym.info.fields.len + 2) * t.pointer_size
align = t.pointer_size
} }
Interface { Interface {
mut res := (sym.info.fields.len + 2) * t.pointer_size size = (sym.info.fields.len + 2) * t.pointer_size
align = t.pointer_size
for etyp in sym.info.embeds { for etyp in sym.info.embeds {
res += t.type_size(etyp) - 2 * t.pointer_size esize, _ := t.type_size(etyp)
size += esize - 2 * t.pointer_size
} }
return res
} }
else { else {
// unreachable // unreachable
return 0
} }
} }
} }
.array_fixed { .array_fixed {
info := sym.info as ArrayFixed info := sym.info as ArrayFixed
return info.size * t.type_size(info.elem_type) elem_size, elem_align := t.type_size(info.elem_type)
size = info.size * elem_size
align = elem_align
} }
// TODO hardcoded: // TODO hardcoded:
.map { .map {
return if t.pointer_size == 8 { 120 } else { 80 } size = if t.pointer_size == 8 { 120 } else { 80 }
align = t.pointer_size
} }
.array { .array {
return if t.pointer_size == 8 { 32 } else { 24 } size = if t.pointer_size == 8 { 32 } else { 24 }
} align = t.pointer_size
.generic_inst {
return 0
} }
} }
sym.size = size
sym.align = align
return size, align
} }
// round_up rounds the number `n` up to the next multiple `multiple`. // round_up rounds the number `n` up to the next multiple `multiple`.
@ -972,6 +987,7 @@ pub fn (kinds []Kind) str() string {
return kinds_str return kinds_str
} }
[minify]
pub struct Struct { pub struct Struct {
pub: pub:
attrs []Attr attrs []Attr
@ -981,6 +997,7 @@ pub mut:
is_typedef bool // C. [typedef] is_typedef bool // C. [typedef]
is_union bool is_union bool
is_heap bool is_heap bool
is_minify bool
is_generic bool is_generic bool
generic_types []Type generic_types []Type
concrete_types []Type concrete_types []Type
@ -994,6 +1011,7 @@ pub mut:
concrete_types []Type // concrete types, e.g. <int, string> concrete_types []Type // concrete types, e.g. <int, string>
} }
[minify]
pub struct Interface { pub struct Interface {
pub mut: pub mut:
types []Type // all types that implement this interface types []Type // all types that implement this interface
@ -1014,8 +1032,10 @@ pub:
vals []string vals []string
is_flag bool is_flag bool
is_multi_allowed bool is_multi_allowed bool
uses_exprs bool
} }
[minify]
pub struct Alias { pub struct Alias {
pub: pub:
parent_type Type parent_type Type
@ -1038,6 +1058,7 @@ pub mut:
elem_type Type elem_type Type
} }
[minify]
pub struct ArrayFixed { pub struct ArrayFixed {
pub: pub:
size int size int
@ -1063,6 +1084,7 @@ pub mut:
value_type Type value_type Type
} }
[minify]
pub struct SumType { pub struct SumType {
pub mut: pub mut:
fields []StructField fields []StructField
@ -1309,6 +1331,7 @@ fn (t Table) shorten_user_defined_typenames(originalname string, import_aliases
return res return res
} }
[minify]
pub struct FnSignatureOpts { pub struct FnSignatureOpts {
skip_receiver bool skip_receiver bool
type_only bool type_only bool

View File

@ -54,7 +54,7 @@ fn all_valid_comptime_idents() []string {
return res return res
} }
[heap] [heap; minify]
pub struct Checker { pub struct Checker {
pref &pref.Preferences // Preferences shared from V struct pref &pref.Preferences // Preferences shared from V struct
pub mut: pub mut:
@ -644,8 +644,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
} else if is_left_type_signed != is_right_type_signed } else if is_left_type_signed != is_right_type_signed
&& left_type != ast.int_literal_type_idx && left_type != ast.int_literal_type_idx
&& right_type != ast.int_literal_type_idx { && right_type != ast.int_literal_type_idx {
ls := c.table.type_size(left_type) ls, _ := c.table.type_size(left_type)
rs := c.table.type_size(right_type) rs, _ := c.table.type_size(right_type)
// prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32 // prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32
// TODO u32 == i32, change < to <= // TODO u32 == i32, change < to <=
if (is_left_type_signed && ls < rs) || (is_right_type_signed && rs < ls) { if (is_left_type_signed && ls < rs) || (is_right_type_signed && rs < ls) {
@ -3720,6 +3720,16 @@ pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
if node.right.op == .amp { if node.right.op == .amp {
c.error('unexpected `&`, expecting expression', node.right.pos) c.error('unexpected `&`, expecting expression', node.right.pos)
} }
} else if mut node.right is ast.SelectorExpr {
right_sym := c.table.sym(right_type)
expr_sym := c.table.sym(node.right.expr_type)
if expr_sym.kind == .struct_ && (expr_sym.info as ast.Struct).is_minify
&& (node.right.typ == ast.bool_type_idx || (right_sym.kind == .enum_
&& !(right_sym.info as ast.Enum).is_flag
&& !(right_sym.info as ast.Enum).uses_exprs)) {
c.error('cannot take address of field in struct `${c.table.type_to_str(node.right.expr_type)}`, which is tagged as `[minify]`',
node.pos.extend(node.right.pos))
}
} }
} }
// TODO: testing ref/deref strategy // TODO: testing ref/deref strategy

View File

@ -127,7 +127,8 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp
// return expr.val.i64() // return expr.val.i64()
// } // }
ast.SizeOf { ast.SizeOf {
return c.table.type_size(expr.typ) s, _ := c.table.type_size(expr.typ)
return s
} }
ast.FloatLiteral { ast.FloatLiteral {
x := expr.val.f64() x := expr.val.f64()

View File

@ -25,6 +25,10 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
} }
} }
} }
if struct_sym.info.is_minify {
node.fields.sort_with_compare(minify_sort_fn)
struct_sym.info.fields.sort_with_compare(minify_sort_fn)
}
for attr in node.attrs { for attr in node.attrs {
if attr.name == 'typedef' && node.language != .c { if attr.name == 'typedef' && node.language != .c {
c.error('`typedef` attribute can only be used with C structs', node.pos) c.error('`typedef` attribute can only be used with C structs', node.pos)
@ -124,6 +128,62 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
} }
} }
fn minify_sort_fn(a &ast.StructField, b &ast.StructField) int {
if a.typ == b.typ {
return 0
}
// push all bool fields to the end of the struct
if a.typ == ast.bool_type_idx {
if b.typ == ast.bool_type_idx {
return 0
}
return 1
} else if b.typ == ast.bool_type_idx {
return -1
}
mut t := global_table
a_sym := t.sym(a.typ)
b_sym := t.sym(b.typ)
// push all non-flag enums to the end too, just before the bool fields
// TODO: support enums with custom field values as well
if a_sym.info is ast.Enum {
if !a_sym.info.is_flag && !a_sym.info.uses_exprs {
if b_sym.kind == .enum_ {
a_nr_vals := (a_sym.info as ast.Enum).vals.len
b_nr_vals := (b_sym.info as ast.Enum).vals.len
return if a_nr_vals > b_nr_vals {
-1
} else if a_nr_vals < b_nr_vals {
1
} else {
0
}
}
return 1
}
} else if b_sym.info is ast.Enum {
if !b_sym.info.is_flag && !b_sym.info.uses_exprs {
return -1
}
}
a_size, a_align := t.type_size(a.typ)
b_size, b_align := t.type_size(b.typ)
return if a_align > b_align {
-1
} else if a_align < b_align {
1
} else if a_size > b_size {
-1
} else if a_size < b_size {
1
} else {
0
}
}
pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type { pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
if node.typ == ast.void_type { if node.typ == ast.void_type {
// short syntax `foo(key:val, key2:val2)` // short syntax `foo(key:val, key2:val2)`
@ -267,6 +327,11 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
node.pos) node.pos)
} }
} }
mut info_fields_sorted := []ast.StructField{}
if node.is_short {
info_fields_sorted = info.fields.clone()
info_fields_sorted.sort(a.i < b.i)
}
mut inited_fields := []string{} mut inited_fields := []string{}
for i, mut field in node.fields { for i, mut field in node.fields {
mut field_info := ast.StructField{} mut field_info := ast.StructField{}
@ -277,7 +342,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
// We should just stop here. // We should just stop here.
break break
} }
field_info = info.fields[i] field_info = info_fields_sorted[i]
field_name = field_info.name field_name = field_info.name
node.fields[i].name = field_name node.fields[i].name = field_name
} else { } else {

View File

@ -92,6 +92,7 @@ pub fn (sk SymbolKind) str() string {
} }
} }
[minify]
pub struct Doc { pub struct Doc {
pub mut: pub mut:
prefs &pref.Preferences = new_vdoc_preferences() prefs &pref.Preferences = new_vdoc_preferences()
@ -121,6 +122,7 @@ pub mut:
platform Platform platform Platform
} }
[minify]
pub struct DocNode { pub struct DocNode {
pub mut: pub mut:
name string name string

View File

@ -10,6 +10,7 @@ pub enum Reporter {
gen gen
} }
[minify]
pub struct Error { pub struct Error {
pub: pub:
message string message string

View File

@ -16,7 +16,7 @@ pub enum CommentsLevel {
// - level: either .keep (don't indent), or .indent (increment indentation) // - level: either .keep (don't indent), or .indent (increment indentation)
// - iembed: a /* ... */ block comment used inside expressions; // comments the whole line // - iembed: a /* ... */ block comment used inside expressions; // comments the whole line
// - prev_line: the line number of the previous token to save linebreaks // - prev_line: the line number of the previous token to save linebreaks
[params] [minify; params]
pub struct CommentsOptions { pub struct CommentsOptions {
has_nl bool = true has_nl bool = true
inline bool inline bool

View File

@ -15,6 +15,7 @@ const (
max_len = [0, 35, 60, 85, 93, 100] max_len = [0, 35, 60, 85, 93, 100]
) )
[minify]
pub struct Fmt { pub struct Fmt {
pub mut: pub mut:
file ast.File file ast.File

View File

@ -4801,6 +4801,7 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
} }
} }
is_minify := sym.info.is_minify
g.type_definitions.writeln(pre_pragma) g.type_definitions.writeln(pre_pragma)
if sym.info.is_union { if sym.info.is_union {
@ -4835,7 +4836,26 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
type_name := g.typ(field.typ) type_name := g.typ(field.typ)
field_name := c_name(field.name) field_name := c_name(field.name)
volatile_prefix := if field.is_volatile { 'volatile ' } else { '' } volatile_prefix := if field.is_volatile { 'volatile ' } else { '' }
g.type_definitions.writeln('\t$volatile_prefix$type_name $field_name;') mut size_suffix := ''
if is_minify && !g.is_cc_msvc {
if field.typ == ast.bool_type_idx {
size_suffix = ' : 1'
} else {
field_sym := g.table.sym(field.typ)
if field_sym.info is ast.Enum {
if !field_sym.info.is_flag && !field_sym.info.uses_exprs {
mut bits_needed := 0
mut l := field_sym.info.vals.len
for l > 0 {
bits_needed++
l >>= 1
}
size_suffix = ' : $bits_needed'
}
}
}
}
g.type_definitions.writeln('\t$volatile_prefix$type_name $field_name$size_suffix;')
} }
} else { } else {
g.type_definitions.writeln('\tEMPTY_STRUCT_DECLARATION;') g.type_definitions.writeln('\tEMPTY_STRUCT_DECLARATION;')

View File

@ -492,7 +492,8 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) {
g.indent-- g.indent--
ps := g.table.pointer_size ps := g.table.pointer_size
is_big_cutoff := if g.pref.os == .windows || g.pref.arch == .arm32 { ps } else { ps * 2 } is_big_cutoff := if g.pref.os == .windows || g.pref.arch == .arm32 { ps } else { ps * 2 }
is_big := g.table.type_size(node.decl.return_type) > is_big_cutoff rt_size, _ := g.table.type_size(node.decl.return_type)
is_big := rt_size > is_big_cutoff
g.write('}, sizeof($ctx_struct)))') g.write('}, sizeof($ctx_struct)))')
mut sb := strings.new_builder(512) mut sb := strings.new_builder(512)

View File

@ -22,7 +22,7 @@ mut:
// XXX WHY gen_exit fn (expr ast.Expr) // XXX WHY gen_exit fn (expr ast.Expr)
} }
[heap] [heap; minify]
pub struct Gen { pub struct Gen {
out_name string out_name string
pref &pref.Preferences // Preferences shared from V struct pref &pref.Preferences // Preferences shared from V struct

View File

@ -8,6 +8,7 @@ pub type FNLinkLiveSymbols = fn (linkcb voidptr)
pub type FNLiveReloadCB = fn (info &LiveReloadInfo) pub type FNLiveReloadCB = fn (info &LiveReloadInfo)
[minify]
pub struct LiveReloadInfo { pub struct LiveReloadInfo {
pub: pub:
vexe string // full path to the v compiler vexe string // full path to the v compiler

View File

@ -14,6 +14,7 @@ import v.errors
import os import os
import hash.fnv1a import hash.fnv1a
[minify]
pub struct Parser { pub struct Parser {
pref &pref.Preferences pref &pref.Preferences
mut: mut:
@ -3480,6 +3481,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
mut vals := []string{} mut vals := []string{}
// mut default_exprs := []ast.Expr{} // mut default_exprs := []ast.Expr{}
mut fields := []ast.EnumField{} mut fields := []ast.EnumField{}
mut uses_exprs := false
for p.tok.kind != .eof && p.tok.kind != .rcbr { for p.tok.kind != .eof && p.tok.kind != .rcbr {
pos := p.tok.pos() pos := p.tok.pos()
val := p.check_name() val := p.check_name()
@ -3491,6 +3493,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
p.next() p.next()
expr = p.expr(0) expr = p.expr(0)
has_expr = true has_expr = true
uses_exprs = true
} }
fields << ast.EnumField{ fields << ast.EnumField{
name: val name: val
@ -3538,6 +3541,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
vals: vals vals: vals
is_flag: is_flag is_flag: is_flag
is_multi_allowed: is_multi_allowed is_multi_allowed: is_multi_allowed
uses_exprs: uses_exprs
} }
is_pub: is_pub is_pub: is_pub
}) })

View File

@ -103,6 +103,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
mut end_comments := []ast.Comment{} mut end_comments := []ast.Comment{}
if !no_body { if !no_body {
p.check(.lcbr) p.check(.lcbr)
mut i := 0
for p.tok.kind != .rcbr { for p.tok.kind != .rcbr {
mut comments := []ast.Comment{} mut comments := []ast.Comment{}
for p.tok.kind == .comment { for p.tok.kind == .comment {
@ -267,6 +268,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
pos: field_pos pos: field_pos
type_pos: type_pos type_pos: type_pos
comments: comments comments: comments
i: i
default_expr: default_expr default_expr: default_expr
has_default_expr: has_default_expr has_default_expr: has_default_expr
attrs: p.attrs attrs: p.attrs
@ -283,6 +285,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
pos: field_pos pos: field_pos
type_pos: type_pos type_pos: type_pos
comments: comments comments: comments
i: i
default_expr: default_expr default_expr: default_expr
has_default_expr: has_default_expr has_default_expr: has_default_expr
attrs: p.attrs attrs: p.attrs
@ -292,12 +295,14 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
is_volatile: is_field_volatile is_volatile: is_field_volatile
} }
p.attrs = [] p.attrs = []
i++
} }
p.top_level_statement_end() p.top_level_statement_end()
last_line = p.tok.line_nr last_line = p.tok.line_nr
p.check(.rcbr) p.check(.rcbr)
} }
t := ast.TypeSymbol{ is_minify := attrs.contains('minify')
mut t := ast.TypeSymbol{
kind: .struct_ kind: .struct_
language: language language: language
name: name name: name
@ -309,6 +314,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
is_typedef: attrs.contains('typedef') is_typedef: attrs.contains('typedef')
is_union: is_union is_union: is_union
is_heap: attrs.contains('heap') is_heap: attrs.contains('heap')
is_minify: is_minify
is_generic: generic_types.len > 0 is_generic: generic_types.len > 0
generic_types: generic_types generic_types: generic_types
attrs: attrs attrs: attrs

View File

@ -88,7 +88,7 @@ const (
'cflags', 'path', 'arch'] 'cflags', 'path', 'arch']
) )
[heap] [heap; minify]
pub struct Preferences { pub struct Preferences {
pub mut: pub mut:
os OS // the OS to compile for os OS // the OS to compile for

View File

@ -23,6 +23,7 @@ const (
backslash = `\\` backslash = `\\`
) )
[minify]
pub struct Scanner { pub struct Scanner {
pub mut: pub mut:
file_path string // '/path/to/file.v' file_path string // '/path/to/file.v'

View File

@ -3,6 +3,7 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module token module token
[minify]
pub struct Token { pub struct Token {
pub: pub:
kind Kind // the token number/enum; for quick comparisons kind Kind // the token number/enum; for quick comparisons

View File

@ -22,6 +22,7 @@ pub enum ErrorType {
trailing_space trailing_space
} }
[minify]
pub struct Error { pub struct Error {
pub mut: pub mut:
kind ErrorKind [required] kind ErrorKind [required]

9
x.v 100644
View File

@ -0,0 +1,9 @@
[minify]
struct Foo {
x u8
i int
b u16
}
f := Foo{1, 2, 3}
println(f)