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
}
[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

View File

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

View File

@ -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

View File

@ -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')
}

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`.
// 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

View File

@ -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

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()
// }
ast.SizeOf {
return c.table.type_size(expr.typ)
s, _ := c.table.type_size(expr.typ)
return s
}
ast.FloatLiteral {
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 {
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 {

View File

@ -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

View File

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

View File

@ -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

View File

@ -15,6 +15,7 @@ const (
max_len = [0, 35, 60, 85, 93, 100]
)
[minify]
pub struct Fmt {
pub mut:
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)
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;')

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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
})

View File

@ -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

View File

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

View File

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

View File

@ -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

View File

@ -22,6 +22,7 @@ pub enum ErrorType {
trailing_space
}
[minify]
pub struct Error {
pub mut:
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)