aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/compiler
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-07-07 20:07:30 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-07-08 22:52:24 +0200
commit306ca0571c5d906ce76df97bd1ea54f4e0e50240 (patch)
treea579718e096c53dc5386f4af2fbabb3318eaf1ed /pkg/compiler
parent93213ec0d3c4522c8844a51b718eb56ce62f395b (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.go12
-rw-r--r--pkg/compiler/compiler.go2
-rw-r--r--pkg/compiler/gen.go6
-rw-r--r--pkg/compiler/testdata/all.txt13
-rw-r--r--pkg/compiler/testdata/errors.txt12
-rw-r--r--pkg/compiler/types.go104
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 {