checker, gen: add support for a [minify] struct attribute (#14247)
							parent
							
								
									aed2d0caf2
								
							
						
					
					
						commit
						332e821518
					
				|  | @ -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 | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ pub enum AttrKind { | |||
| } | ||||
| 
 | ||||
| // e.g. `[unsafe]`
 | ||||
| [minify] | ||||
| pub struct Attr { | ||||
| pub: | ||||
| 	name    string // [name]
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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') | ||||
| } | ||||
|  |  | |||
|  | @ -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. <int, string>
 | ||||
| } | ||||
| 
 | ||||
| [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 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ pub enum Reporter { | |||
| 	gen | ||||
| } | ||||
| 
 | ||||
| [minify] | ||||
| pub struct Error { | ||||
| pub: | ||||
| 	message   string | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ const ( | |||
| 	max_len = [0, 35, 60, 85, 93, 100] | ||||
| ) | ||||
| 
 | ||||
| [minify] | ||||
| pub struct Fmt { | ||||
| pub mut: | ||||
| 	file               ast.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) | ||||
| 
 | ||||
| 				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;') | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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 | ||||
| 	}) | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ const ( | |||
| 		'cflags', 'path', 'arch'] | ||||
| ) | ||||
| 
 | ||||
| [heap] | ||||
| [heap; minify] | ||||
| pub struct Preferences { | ||||
| pub mut: | ||||
| 	os          OS // the OS to compile for
 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ const ( | |||
| 	backslash    = `\\` | ||||
| ) | ||||
| 
 | ||||
| [minify] | ||||
| pub struct Scanner { | ||||
| pub mut: | ||||
| 	file_path         string // '/path/to/file.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
 | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ pub enum ErrorType { | |||
| 	trailing_space | ||||
| } | ||||
| 
 | ||||
| [minify] | ||||
| pub struct Error { | ||||
| pub mut: | ||||
| 	kind ErrorKind [required] | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue