diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-07-07 20:07:30 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-07-08 22:52:24 +0200 |
| commit | 306ca0571c5d906ce76df97bd1ea54f4e0e50240 (patch) | |
| tree | a579718e096c53dc5386f4af2fbabb3318eaf1ed /pkg/compiler | |
| parent | 93213ec0d3c4522c8844a51b718eb56ce62f395b (diff) | |
prog, pkg/compiler: support fmt type
fmt type allows to convert intergers and resources
to string representation.
Diffstat (limited to 'pkg/compiler')
| -rw-r--r-- | pkg/compiler/check.go | 12 | ||||
| -rw-r--r-- | pkg/compiler/compiler.go | 2 | ||||
| -rw-r--r-- | pkg/compiler/gen.go | 6 | ||||
| -rw-r--r-- | pkg/compiler/testdata/all.txt | 13 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors.txt | 12 | ||||
| -rw-r--r-- | pkg/compiler/types.go | 104 |
6 files changed, 128 insertions, 21 deletions
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 19e196adb..a07bcd479 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -309,7 +309,7 @@ func (comp *compiler) checkLenType(t *ast.Type, name string, fields []*ast.Field if argDesc.Type == typeArgLenTarget { comp.checkLenTarget(t, name, arg.Ident, fields, parents) } else if argDesc.Type == typeArgType { - comp.checkLenType(arg, name, fields, parents, checked, false) + comp.checkLenType(arg, name, fields, parents, checked, argDesc.IsArg) } } } @@ -417,7 +417,7 @@ func (comp *compiler) collectUsedType(structs, flags, strflags map[string]bool, _, args, _ := comp.getArgsBase(t, "", prog.DirIn, isArg) for i, arg := range args { if desc.Args[i].Type == typeArgType { - comp.collectUsedType(structs, flags, strflags, arg, false) + comp.collectUsedType(structs, flags, strflags, arg, desc.Args[i].IsArg) } } } @@ -524,7 +524,7 @@ func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg bool, _, args, _ := comp.getArgsBase(t, "", dir, isArg) for i, arg := range args { if desc.Args[i].Type == typeArgType { - comp.checkTypeCtors(arg, dir, false, ctors, checked) + comp.checkTypeCtors(arg, dir, desc.Args[i].IsArg, ctors, checked) } } } @@ -722,7 +722,11 @@ func (comp *compiler) checkType(ctx checkCtx, t *ast.Type, flags checkFlags) { err0 := comp.errors for i, arg := range args { if desc.Args[i].Type == typeArgType { - comp.checkType(ctx, arg, 0) + var innerFlags checkFlags + if desc.Args[i].IsArg { + innerFlags |= checkIsArg + } + comp.checkType(ctx, arg, innerFlags) } else { comp.checkTypeArg(t, arg, desc.Args[i]) } diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index b44a698ca..e66da802b 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -311,7 +311,7 @@ func (comp *compiler) foreachSubType(t *ast.Type, isArg bool, cb(t, desc, args, base) for i, arg := range args { if desc.Args[i].Type == typeArgType { - comp.foreachSubType(arg, false, cb) + comp.foreachSubType(arg, desc.Args[i].IsArg, cb) } } } diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index 5bf239e79..0e13db460 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -396,9 +396,13 @@ func genCommon(name, field string, size uint64, dir prog.Dir, opt bool) prog.Typ } func genIntCommon(com prog.TypeCommon, bitLen uint64, bigEndian bool) prog.IntTypeCommon { + bf := prog.FormatNative + if bigEndian { + bf = prog.FormatBigEndian + } return prog.IntTypeCommon{ TypeCommon: com, - BigEndian: bigEndian, + ArgFormat: bf, BitfieldLen: bitLen, } } diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index a5a097de3..573fb6412 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -213,3 +213,16 @@ u0 [ ] foo$u0(a ptr[in, u0]) + +# fmt + +foo$fmt0(a ptr[in, fmt[dec, int32[1:10]]]) +foo$fmt1(a ptr[in, fmt[hex, flags[int_flags]]]) +foo$fmt2(a ptr[in, fmt[oct, len[b]]], b ptr[in, array[int8]]) +foo$fmt3(a ptr[in, fmt[dec, proc[10, 20]]]) +foo$fmt4(a ptr[in, fmt[dec, r0]]) +foo$fmt5(a ptr[in, struct$fmt0]) + +struct$fmt0 { + f0 fmt[dec, int8] +} diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt index 750916a83..cbfebbfd7 100644 --- a/pkg/compiler/testdata/errors.txt +++ b/pkg/compiler/testdata/errors.txt @@ -318,3 +318,15 @@ foo$203(a type0[42]) ### type type0 is not a template foo$204(a ptr[in, templ_struct0[42, int8]]) foo$205(a ptr[in, templ_struct0[int8, int8]]) foo$207(a ptr[in, templ_struct2[1]]) + +# fmt + +foo$fmt0(a fmt) ### wrong number of arguments for type fmt, expect format, value +foo$fmt1(a fmt[dec, int8]) ### fmt can't be syscall argument +foo$fmt2(a ptr[in, fmt[dec, ptr[in, int8]]]) ### bad fmt value ptr, expect an integer +foo$fmt3(a ptr[in, fmt[foo, int8]]) ### unexpected value foo for format argument of fmt type, expect [dec hex oct] +foo$fmt4(a ptr[in, fmt[dec, int8:3]]) ### unexpected ':', only struct fields can be bitfields + +struct$fmt0 { + f0 fmt[dec, int8:3] ### unexpected ':', only struct fields can be bitfields +} diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index c41ce4bdf..156b1505a 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -46,8 +46,9 @@ type typeArg struct { } type namedArg struct { - Name string - Type *typeArg + Name string + Type *typeArg + IsArg bool // does not need base type } const ( @@ -67,7 +68,7 @@ var typeInt = &typeDesc{ AllowColon: true, ResourceBase: true, OptArgs: 1, - Args: []namedArg{{"range", typeArgRange}}, + Args: []namedArg{{Name: "range", Type: typeArgRange}}, Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { typeArgBase.Type.Check(comp, t) }, @@ -91,7 +92,7 @@ var typePtr = &typeDesc{ Names: []string{"ptr", "ptr64"}, CanBeArgRet: canBeArg, CanBeTypedef: true, - Args: []namedArg{{"direction", typeArgDir}, {"type", typeArgType}}, + Args: []namedArg{{Name: "direction", Type: typeArgDir}, {Name: "type", Type: typeArgType}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { base.ArgDir = prog.DirIn // pointers are always in base.TypeSize = comp.ptrSize @@ -127,7 +128,7 @@ var typeArray = &typeDesc{ CanBeTypedef: true, CantBeOpt: true, OptArgs: 1, - Args: []namedArg{{"type", typeArgType}, {"size", typeArgRange}}, + Args: []namedArg{{Name: "type", Type: typeArgType}, {Name: "size", Type: typeArgRange}}, CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { if len(args) > 1 && args[1].Value == 0 && args[1].Value2 == 0 { comp.error(args[1].Pos, "arrays of size 0 are not supported") @@ -187,7 +188,7 @@ var typeLen = &typeDesc{ CanBeArgRet: canBeArg, CantBeOpt: true, NeedBase: true, - Args: []namedArg{{"len target", typeArgLenTarget}}, + Args: []namedArg{{Name: "len target", Type: typeArgLenTarget}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { var bitSize uint64 switch t.Ident { @@ -213,7 +214,7 @@ var typeConst = &typeDesc{ CanBeTypedef: true, CantBeOpt: true, NeedBase: true, - Args: []namedArg{{"value", typeArgInt}}, + Args: []namedArg{{Name: "value", Type: typeArgInt}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { return &prog.ConstType{ IntTypeCommon: base, @@ -232,7 +233,7 @@ var typeFlags = &typeDesc{ CanBeTypedef: true, CantBeOpt: true, NeedBase: true, - Args: []namedArg{{"flags", typeArgFlags}}, + Args: []namedArg{{Name: "flags", Type: typeArgFlags}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { name := args[0].Ident base.TypeName = name @@ -289,7 +290,7 @@ var typeVMA = &typeDesc{ Names: []string{"vma"}, CanBeArgRet: canBeArg, OptArgs: 1, - Args: []namedArg{{"size range", typeArgRange}}, + Args: []namedArg{{Name: "size range", Type: typeArgRange}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { begin, end := uint64(0), uint64(0) if len(args) > 0 { @@ -309,7 +310,11 @@ var typeCsum = &typeDesc{ NeedBase: true, CantBeOpt: true, OptArgs: 1, - Args: []namedArg{{"csum target", typeArgLenTarget}, {"kind", typeArgCsumType}, {"proto", typeArgInt}}, + Args: []namedArg{ + {Name: "csum target", Type: typeArgLenTarget}, + {Name: "kind", Type: typeArgCsumType}, + {Name: "proto", Type: typeArgInt}, + }, Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { if len(args) > 2 && genCsumKind(args[1]) != prog.CsumPseudo { comp.error(args[2].Pos, "only pseudo csum can have proto") @@ -350,7 +355,10 @@ var typeProc = &typeDesc{ CanBeArgRet: canBeArg, CanBeTypedef: true, NeedBase: true, - Args: []namedArg{{"range start", typeArgInt}, {"per-proc values", typeArgInt}}, + Args: []namedArg{ + {Name: "range start", Type: typeArgInt}, + {Name: "per-proc values", Type: typeArgInt}, + }, CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { start := args[0].Value perProc := args[1].Value @@ -381,7 +389,7 @@ var typeProc = &typeDesc{ var typeText = &typeDesc{ Names: []string{"text"}, CantBeOpt: true, - Args: []namedArg{{"kind", typeArgTextType}}, + Args: []namedArg{{Name: "kind", Type: typeArgTextType}}, Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { return true }, @@ -420,7 +428,7 @@ func genTextType(t *ast.Type) prog.TextKind { var typeBuffer = &typeDesc{ Names: []string{"buffer"}, CanBeArgRet: canBeArg, - Args: []namedArg{{"direction", typeArgDir}}, + Args: []namedArg{{Name: "direction", Type: typeArgDir}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { base.TypeSize = comp.ptrSize common := genCommon("", "", 0, genDir(args[0]), false) @@ -444,7 +452,10 @@ var typeString = &typeDesc{ Names: []string{"string", stringnoz}, CanBeTypedef: true, OptArgs: 2, - Args: []namedArg{{"literal or flags", typeArgStringFlags}, {"size", typeArgInt}}, + Args: []namedArg{ + {Name: "literal or flags", Type: typeArgStringFlags}, + {Name: "size", Type: typeArgInt}, + }, Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { if t.Ident == stringnoz && len(args) > 1 { comp.error(args[0].Pos, "fixed-size string can't be non-zero-terminated") @@ -570,6 +581,66 @@ var typeArgStringFlags = &typeArg{ }, } +var typeFmt = &typeDesc{ + Names: []string{"fmt"}, + CanBeTypedef: true, + CantBeOpt: true, + Args: []namedArg{ + {Name: "format", Type: typeFmtFormat}, + {Name: "value", Type: typeArgType, IsArg: true}, + }, + Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { + desc, _, _ := comp.getArgsBase(args[1], "", base.TypeCommon.ArgDir, true) + switch desc { + case typeResource, typeInt, typeLen, typeFlags, typeProc: + default: + comp.error(t.Pos, "bad fmt value %v, expect an integer", args[1].Ident) + return + } + }, + Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { + var format prog.BinaryFormat + var size uint64 + switch args[0].Ident { + case "dec": + format = prog.FormatStrDec + size = 20 + case "hex": + format = prog.FormatStrHex + size = 18 + case "oct": + format = prog.FormatStrOct + size = 23 + } + typ := comp.genType(args[1], "", base.TypeCommon.ArgDir, true) + switch t := typ.(type) { + case *prog.ResourceType: + t.ArgFormat = format + t.TypeSize = size + case *prog.IntType: + t.ArgFormat = format + t.TypeSize = size + case *prog.LenType: + t.ArgFormat = format + t.TypeSize = size + case *prog.FlagsType: + t.ArgFormat = format + t.TypeSize = size + case *prog.ProcType: + t.ArgFormat = format + t.TypeSize = size + default: + panic(fmt.Sprintf("unexpected type: %#v", typ)) + } + return typ + }, +} + +var typeFmtFormat = &typeArg{ + Names: []string{"dec", "hex", "oct"}, + Kind: kindIdent, +} + // typeArgType is used as placeholder for any type (e.g. ptr target type). var typeArgType = &typeArg{} @@ -588,9 +659,11 @@ func init() { baseType = r.Base r = comp.resources[r.Base.Ident] } - base.TypeSize = comp.genType(baseType, "", prog.DirIn, false).Size() + baseProgType := comp.genType(baseType, "", prog.DirIn, false) + base.TypeSize = baseProgType.Size() return &prog.ResourceType{ TypeCommon: base.TypeCommon, + ArgFormat: baseProgType.Format(), } } } @@ -778,6 +851,7 @@ func init() { typeText, typeBuffer, typeString, + typeFmt, } for _, desc := range builtins { for _, name := range desc.Names { |
