diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 1f059fd2cb..5c5cd3943d 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -202,6 +202,7 @@ pub: pos token.Pos } +[minify] pub struct StringLiteral { pub: val string @@ -246,6 +247,7 @@ pub enum GenericKindField { } // `foo.bar` +[minify] pub struct SelectorExpr { pub: pos token.Pos @@ -287,11 +289,13 @@ pub: is_skipped bool // module main can be skipped in single file programs } +[minify] pub struct StructField { pub: pos token.Pos type_pos token.Pos comments []Comment + i int has_default_expr bool attrs []Attr is_pub bool @@ -333,6 +337,7 @@ pub mut: } // const declaration +[minify] pub struct ConstDecl { pub: is_pub bool @@ -344,6 +349,7 @@ pub mut: is_block bool // const() block } +[minify] pub struct StructDecl { pub: pos token.Pos @@ -380,6 +386,7 @@ pub: comments []Comment } +[minify] pub struct InterfaceDecl { pub: name string @@ -431,6 +438,7 @@ pub mut: // ...a // field1: 'hello' // }` +[minify] pub struct StructInit { pub: pos token.Pos @@ -484,6 +492,7 @@ pub mut: } // function or method declaration +[minify] pub struct FnDecl { pub: name string // 'math.bits.normalize' @@ -542,6 +551,7 @@ pub mut: } // break, continue +[minify] pub struct BranchStmt { pub: kind token.Kind @@ -550,6 +560,7 @@ pub: } // function or method call expr +[minify] pub struct CallExpr { pub: pos token.Pos @@ -589,6 +600,7 @@ pub struct AutofreeArgVar { } */ // function call argument: `f(callarg)` +[minify] pub struct CallArg { pub: is_mut bool @@ -612,6 +624,7 @@ pub mut: types []Type } +[minify] pub struct Var { pub: name string @@ -643,6 +656,7 @@ pub mut: // used for smartcasting only // struct fields change type in scopes +[minify] pub struct ScopeStructField { pub: struct_type Type // type of struct @@ -657,6 +671,7 @@ pub: // 12 <- the current casted type (typ) } +[minify] pub struct GlobalField { pub: name string @@ -682,6 +697,7 @@ pub mut: end_comments []Comment } +[minify] pub struct EmbeddedFile { pub: 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 // instead which points to the scope object +[minify] pub struct IdentVar { pub mut: typ Type @@ -771,6 +788,7 @@ pub enum IdentKind { } // A single identifier +[minify] pub struct Ident { pub: language Language @@ -816,6 +834,7 @@ pub fn (i &Ident) var_info() IdentVar { // left op right // See: token.Kind.is_infix +[minify] pub struct InfixExpr { pub: op token.Kind @@ -846,6 +865,7 @@ pub mut: } // See: token.Kind.is_prefix +[minify] pub struct PrefixExpr { pub: op token.Kind @@ -857,6 +877,7 @@ pub mut: is_option bool // IfGuard } +[minify] pub struct IndexExpr { pub: pos token.Pos @@ -874,6 +895,7 @@ pub mut: is_gated bool // #[] gated array } +[minify] pub struct IfExpr { pub: is_comptime bool @@ -921,6 +943,7 @@ pub mut: scope &Scope } +[minify] pub struct MatchExpr { pub: tok_kind token.Kind @@ -959,6 +982,7 @@ pub mut: expected_type Type // for debugging only } +[minify] pub struct SelectBranch { pub: pos token.Pos @@ -1000,6 +1024,7 @@ pub mut: scope &Scope } +[minify] pub struct ForInStmt { pub: key_var string @@ -1060,6 +1085,7 @@ pub: } */ // variable assign statement +[minify] pub struct AssignStmt { pub: 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 +[minify] pub struct EnumDecl { pub: name string @@ -1161,6 +1188,7 @@ pub: // TODO: handle this differently // v1 excludes non current os ifdefs so // the defer's never get added in the first place +[minify] pub struct DeferStmt { pub: stmts []Stmt @@ -1179,6 +1207,7 @@ pub mut: expr Expr } +[minify] pub struct GoExpr { pub: pos token.Pos @@ -1199,6 +1228,7 @@ pub: pos token.Pos } +[minify] pub struct ArrayInit { pub: pos token.Pos // `[]` in []Type{} position @@ -1242,6 +1272,7 @@ pub mut: elem_type Type } +[minify] pub struct MapInit { pub: pos token.Pos @@ -1257,6 +1288,7 @@ pub mut: } // s[10..20] +[minify] pub struct RangeExpr { pub: has_high bool @@ -1268,6 +1300,7 @@ pub mut: high Expr } +[minify] pub struct CastExpr { pub mut: arg Expr // `n` in `string(buf, n)` @@ -1279,6 +1312,7 @@ pub mut: pos token.Pos } +[minify] pub struct AsmStmt { pub: arch pref.Arch @@ -1296,6 +1330,7 @@ pub mut: local_labels []string // local to the assembly block } +[minify] pub struct AsmTemplate { pub mut: name string @@ -1460,6 +1495,7 @@ pub const ( } ) +[minify] pub struct AssertStmt { pub: pos token.Pos @@ -1511,6 +1547,7 @@ pub: */ // deprecated +[minify] pub struct Assoc { pub: var_name string @@ -1540,6 +1577,7 @@ pub mut: typ Type } +[minify] pub struct OffsetOf { pub: struct_type Type @@ -1555,6 +1593,7 @@ pub mut: expr Expr } +[minify] pub struct TypeOf { pub: pos token.Pos @@ -1563,6 +1602,7 @@ pub mut: expr_type Type } +[minify] pub struct DumpExpr { pub: pos token.Pos @@ -1598,6 +1638,7 @@ pub mut: val string } +[minify] pub struct ComptimeSelector { pub: has_parens bool // if $() is used, for vfmt @@ -1609,6 +1650,7 @@ pub mut: typ Type } +[minify] pub struct ComptimeCall { pub: pos token.Pos diff --git a/vlib/v/ast/attr.v b/vlib/v/ast/attr.v index deb16663fc..973d542bd0 100644 --- a/vlib/v/ast/attr.v +++ b/vlib/v/ast/attr.v @@ -14,6 +14,7 @@ pub enum AttrKind { } // e.g. `[unsafe]` +[minify] pub struct Attr { pub: name string // [name] diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 20d1951934..ad77fe4532 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -9,7 +9,7 @@ import v.cflag import v.token import v.util -[heap] +[heap; minify] pub struct Table { mut: 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) } +[minify] pub struct Fn { pub: is_variadic bool @@ -126,6 +127,7 @@ fn (f &Fn) method_equals(o &Fn) bool { && f.name == o.name } +[minify] pub struct Param { pub: pos token.Pos diff --git a/vlib/v/ast/type_size_test.v b/vlib/v/ast/type_size_test.v index 8e203aac4d..fb79f3b87f 100644 --- a/vlib/v/ast/type_size_test.v +++ b/vlib/v/ast/type_size_test.v @@ -41,14 +41,22 @@ fn test_type_size() ? { mut t := b.table - assert sizeof(T01) == t.type_size(t.type_idxs['main.T01'] ?) - assert sizeof(T02) == t.type_size(t.type_idxs['main.T02'] ?) - assert sizeof(T03) == t.type_size(t.type_idxs['main.T03'] ?) - assert sizeof(T04) == t.type_size(t.type_idxs['main.T04'] ?) - assert sizeof(T05) == t.type_size(t.type_idxs['main.T05'] ?) - assert sizeof(T06) == t.type_size(t.type_idxs['main.T06'] ?) - assert sizeof(T07) == t.type_size(t.type_idxs['main.T07'] ?) - assert sizeof(T08) == t.type_size(t.type_idxs['main.T08'] ?) + size01, _ := t.type_size(t.type_idxs['main.T01'] ?) + assert sizeof(T01) == size01 + size02, _ := t.type_size(t.type_idxs['main.T02'] ?) + assert sizeof(T02) == size02 + size03, _ := t.type_size(t.type_idxs['main.T03'] ?) + assert sizeof(T03) == size03 + size04, _ := t.type_size(t.type_idxs['main.T04'] ?) + 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') } diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 515f179e81..c8554716bb 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -80,6 +80,7 @@ pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language { // Each TypeSymbol is entered into `Table.types`. // See also: Table.sym. +[minify] pub struct TypeSymbol { pub: parent_idx int @@ -93,6 +94,8 @@ pub mut: is_pub bool language Language idx int + size int = -1 + align int = -1 } // max of 8 @@ -825,88 +828,100 @@ pub fn (t &TypeSymbol) is_builtin() bool { return t.mod == 'builtin' } -// type_size returns the size in bytes of `typ`, similarly to C's `sizeof()`. -pub fn (t &Table) type_size(typ Type) int { +// 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, int) { if typ.has_flag(.optional) { return t.type_size(ast.error_type_idx) } 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 { - .placeholder, .void, .none_ { - return 0 - } + .placeholder, .void, .none_, .generic_inst {} .voidptr, .byteptr, .charptr, .function, .usize, .isize, .any, .thread, .chan { - return t.pointer_size + size = t.pointer_size } .i8, .u8, .char, .bool { - return 1 + size = 1 + align = 1 } .i16, .u16 { - return 2 + size = 2 + align = 2 } .int, .u32, .rune, .f32, .enum_ { - return 4 + size = 4 + align = 4 } .i64, .u64, .int_literal, .f64, .float_literal { - return 8 + size = 8 + align = 8 } .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 { mut max_alignment := 0 mut total_size := 0 - types := if sym.info is Struct { + types := if mut sym.info is Struct { sym.info.fields.map(it.typ) } else { (sym.info as MultiReturn).types } for ftyp in types { - field_size := t.type_size(ftyp) - alignment := if field_size > t.pointer_size { t.pointer_size } else { field_size } + field_size, alignment := t.type_size(ftyp) if alignment > max_alignment { max_alignment = alignment } 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 { - match sym.info { + match mut sym.info { 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 { - 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 { - res += t.type_size(etyp) - 2 * t.pointer_size + esize, _ := t.type_size(etyp) + size += esize - 2 * t.pointer_size } - return res } else { // unreachable - return 0 } } } .array_fixed { 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: .map { - return if t.pointer_size == 8 { 120 } else { 80 } + size = if t.pointer_size == 8 { 120 } else { 80 } + align = t.pointer_size } .array { - return if t.pointer_size == 8 { 32 } else { 24 } - } - .generic_inst { - return 0 + size = if t.pointer_size == 8 { 32 } else { 24 } + align = t.pointer_size } } + sym.size = size + sym.align = align + return size, align } // 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 } +[minify] pub struct Struct { pub: attrs []Attr @@ -981,6 +997,7 @@ pub mut: is_typedef bool // C. [typedef] is_union bool is_heap bool + is_minify bool is_generic bool generic_types []Type concrete_types []Type @@ -994,6 +1011,7 @@ pub mut: concrete_types []Type // concrete types, e.g. } +[minify] pub struct Interface { pub mut: types []Type // all types that implement this interface @@ -1014,8 +1032,10 @@ pub: vals []string is_flag bool is_multi_allowed bool + uses_exprs bool } +[minify] pub struct Alias { pub: parent_type Type @@ -1038,6 +1058,7 @@ pub mut: elem_type Type } +[minify] pub struct ArrayFixed { pub: size int @@ -1063,6 +1084,7 @@ pub mut: value_type Type } +[minify] pub struct SumType { pub mut: fields []StructField @@ -1309,6 +1331,7 @@ fn (t Table) shorten_user_defined_typenames(originalname string, import_aliases return res } +[minify] pub struct FnSignatureOpts { skip_receiver bool type_only bool diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 0f0f683d6b..682394163c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -54,7 +54,7 @@ fn all_valid_comptime_idents() []string { return res } -[heap] +[heap; minify] pub struct Checker { pref &pref.Preferences // Preferences shared from V struct 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 && left_type != ast.int_literal_type_idx && right_type != ast.int_literal_type_idx { - ls := c.table.type_size(left_type) - rs := c.table.type_size(right_type) + ls, _ := c.table.type_size(left_type) + rs, _ := c.table.type_size(right_type) // prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32 // TODO u32 == i32, change < to <= 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 { 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 diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 62d78fa41e..78e67c6c47 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -127,7 +127,8 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp // return expr.val.i64() // } ast.SizeOf { - return c.table.type_size(expr.typ) + s, _ := c.table.type_size(expr.typ) + return s } ast.FloatLiteral { x := expr.val.f64() diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 576662eb3d..1419585215 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -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 { if attr.name == 'typedef' && node.language != .c { 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 { if node.typ == ast.void_type { // 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) } } + 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{} for i, mut field in node.fields { 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. break } - field_info = info.fields[i] + field_info = info_fields_sorted[i] field_name = field_info.name node.fields[i].name = field_name } else { diff --git a/vlib/v/doc/doc.v b/vlib/v/doc/doc.v index d9031e7a4b..3d914bc83c 100644 --- a/vlib/v/doc/doc.v +++ b/vlib/v/doc/doc.v @@ -92,6 +92,7 @@ pub fn (sk SymbolKind) str() string { } } +[minify] pub struct Doc { pub mut: prefs &pref.Preferences = new_vdoc_preferences() @@ -121,6 +122,7 @@ pub mut: platform Platform } +[minify] pub struct DocNode { pub mut: name string diff --git a/vlib/v/errors/errors.v b/vlib/v/errors/errors.v index 4194a5dc43..fea39f8430 100644 --- a/vlib/v/errors/errors.v +++ b/vlib/v/errors/errors.v @@ -10,6 +10,7 @@ pub enum Reporter { gen } +[minify] pub struct Error { pub: message string diff --git a/vlib/v/fmt/comments.v b/vlib/v/fmt/comments.v index 088cfa8b89..8e7871b6b8 100644 --- a/vlib/v/fmt/comments.v +++ b/vlib/v/fmt/comments.v @@ -16,7 +16,7 @@ pub enum CommentsLevel { // - level: either .keep (don't indent), or .indent (increment indentation) // - iembed: a /* ... */ block comment used inside expressions; // comments the whole line // - prev_line: the line number of the previous token to save linebreaks -[params] +[minify; params] pub struct CommentsOptions { has_nl bool = true inline bool diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index edc5f07bf3..8b28b89f0b 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -15,6 +15,7 @@ const ( max_len = [0, 35, 60, 85, 93, 100] ) +[minify] pub struct Fmt { pub mut: file ast.File diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 97b144f096..aad76ad199 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -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) if sym.info.is_union { @@ -4835,7 +4836,26 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) { type_name := g.typ(field.typ) field_name := c_name(field.name) 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 { g.type_definitions.writeln('\tEMPTY_STRUCT_DECLARATION;') diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index ef7b675bc6..84216bcbeb 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -492,7 +492,8 @@ fn (mut g Gen) gen_anon_fn(mut node ast.AnonFn) { g.indent-- ps := g.table.pointer_size 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)))') mut sb := strings.new_builder(512) diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 4d9d2018fe..374e7ea587 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -22,7 +22,7 @@ mut: // XXX WHY gen_exit fn (expr ast.Expr) } -[heap] +[heap; minify] pub struct Gen { out_name string pref &pref.Preferences // Preferences shared from V struct diff --git a/vlib/v/live/common.v b/vlib/v/live/common.v index 1da31a05da..61bc693617 100644 --- a/vlib/v/live/common.v +++ b/vlib/v/live/common.v @@ -8,6 +8,7 @@ pub type FNLinkLiveSymbols = fn (linkcb voidptr) pub type FNLiveReloadCB = fn (info &LiveReloadInfo) +[minify] pub struct LiveReloadInfo { pub: vexe string // full path to the v compiler diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index d07b67d9ac..b29209f2c2 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -14,6 +14,7 @@ import v.errors import os import hash.fnv1a +[minify] pub struct Parser { pref &pref.Preferences mut: @@ -3480,6 +3481,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { mut vals := []string{} // mut default_exprs := []ast.Expr{} mut fields := []ast.EnumField{} + mut uses_exprs := false for p.tok.kind != .eof && p.tok.kind != .rcbr { pos := p.tok.pos() val := p.check_name() @@ -3491,6 +3493,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { p.next() expr = p.expr(0) has_expr = true + uses_exprs = true } fields << ast.EnumField{ name: val @@ -3538,6 +3541,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { vals: vals is_flag: is_flag is_multi_allowed: is_multi_allowed + uses_exprs: uses_exprs } is_pub: is_pub }) diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 24985e747e..8e0dce3a66 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -103,6 +103,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl { mut end_comments := []ast.Comment{} if !no_body { p.check(.lcbr) + mut i := 0 for p.tok.kind != .rcbr { mut comments := []ast.Comment{} for p.tok.kind == .comment { @@ -267,6 +268,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl { pos: field_pos type_pos: type_pos comments: comments + i: i default_expr: default_expr has_default_expr: has_default_expr attrs: p.attrs @@ -283,6 +285,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl { pos: field_pos type_pos: type_pos comments: comments + i: i default_expr: default_expr has_default_expr: has_default_expr attrs: p.attrs @@ -292,12 +295,14 @@ fn (mut p Parser) struct_decl() ast.StructDecl { is_volatile: is_field_volatile } p.attrs = [] + i++ } p.top_level_statement_end() last_line = p.tok.line_nr p.check(.rcbr) } - t := ast.TypeSymbol{ + is_minify := attrs.contains('minify') + mut t := ast.TypeSymbol{ kind: .struct_ language: language name: name @@ -309,6 +314,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl { is_typedef: attrs.contains('typedef') is_union: is_union is_heap: attrs.contains('heap') + is_minify: is_minify is_generic: generic_types.len > 0 generic_types: generic_types attrs: attrs diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index b93e18a542..dba8b24d73 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -88,7 +88,7 @@ const ( 'cflags', 'path', 'arch'] ) -[heap] +[heap; minify] pub struct Preferences { pub mut: os OS // the OS to compile for diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 36733e8962..47ec367161 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -23,6 +23,7 @@ const ( backslash = `\\` ) +[minify] pub struct Scanner { pub mut: file_path string // '/path/to/file.v' diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index dda124058e..eb6b90584a 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -3,6 +3,7 @@ // that can be found in the LICENSE file. module token +[minify] pub struct Token { pub: kind Kind // the token number/enum; for quick comparisons diff --git a/vlib/v/vet/vet.v b/vlib/v/vet/vet.v index 98e8ddaec6..c6e197d9fb 100644 --- a/vlib/v/vet/vet.v +++ b/vlib/v/vet/vet.v @@ -22,6 +22,7 @@ pub enum ErrorType { trailing_space } +[minify] pub struct Error { pub mut: kind ErrorKind [required] diff --git a/x.v b/x.v new file mode 100644 index 0000000000..421ad69729 --- /dev/null +++ b/x.v @@ -0,0 +1,9 @@ +[minify] +struct Foo { + x u8 + i int + b u16 +} + +f := Foo{1, 2, 3} +println(f)