diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-01-23 11:05:51 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-01-23 11:05:51 +0100 |
| commit | 14d1e424b6a582d021c73c88e1f0c5f0962ecc9d (patch) | |
| tree | 0fdc71b6e0de2576ae330f145a51f9c016ad81a2 /pkg | |
| parent | de3e24c4b6cd0136618ce74eb025a15d4834c082 (diff) | |
pkg/compiler: allow use of empty strings
This comes up in several contexts in netfilter.
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/ast/ast.go | 9 | ||||
| -rw-r--r-- | pkg/ast/clone.go | 1 | ||||
| -rw-r--r-- | pkg/ast/format.go | 2 | ||||
| -rw-r--r-- | pkg/ast/parser.go | 1 | ||||
| -rw-r--r-- | pkg/ast/scanner.go | 6 | ||||
| -rw-r--r-- | pkg/ast/testdata/all.txt | 4 | ||||
| -rw-r--r-- | pkg/compiler/check.go | 2 | ||||
| -rw-r--r-- | pkg/compiler/testdata/all.txt | 11 | ||||
| -rw-r--r-- | pkg/compiler/types.go | 24 |
9 files changed, 36 insertions, 24 deletions
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go index 08703ba33..f7d5b8b32 100644 --- a/pkg/ast/ast.go +++ b/pkg/ast/ast.go @@ -185,10 +185,11 @@ func (n *Int) Info() (Pos, string, string) { type Type struct { Pos Pos // Only one of Value, Ident, String is filled. - Value uint64 - ValueHex bool - Ident string - String string + Value uint64 + ValueHex bool + Ident string + String string + HasString bool // Part after COLON (for ranges and bitfields). HasColon bool Pos2 Pos diff --git a/pkg/ast/clone.go b/pkg/ast/clone.go index b915c1f33..b754b7650 100644 --- a/pkg/ast/clone.go +++ b/pkg/ast/clone.go @@ -182,6 +182,7 @@ func (n *Type) Clone() Node { ValueHex: n.ValueHex, Ident: n.Ident, String: n.String, + HasString: n.HasString, HasColon: n.HasColon, Pos2: n.Pos2, Value2: n.Value2, diff --git a/pkg/ast/format.go b/pkg/ast/format.go index c1dd3a624..a7e0f568f 100644 --- a/pkg/ast/format.go +++ b/pkg/ast/format.go @@ -152,7 +152,7 @@ func fmtType(t *Type) string { switch { case t.Ident != "": v = t.Ident - case t.String != "": + case t.HasString: v = fmt.Sprintf("\"%v\"", t.String) default: v = fmtIntValue(t.Value, t.ValueHex) diff --git a/pkg/ast/parser.go b/pkg/ast/parser.go index bd5650ad5..a7cfdbf02 100644 --- a/pkg/ast/parser.go +++ b/pkg/ast/parser.go @@ -419,6 +419,7 @@ func (p *parser) parseType() *Type { arg.Ident = p.lit case tokString: arg.String = p.lit + arg.HasString = true default: p.expect(tokInt, tokIdent, tokString) } diff --git a/pkg/ast/scanner.go b/pkg/ast/scanner.go index bd2171506..5ad5e5808 100644 --- a/pkg/ast/scanner.go +++ b/pkg/ast/scanner.go @@ -177,12 +177,6 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) { break } } - if lit == "" { - // Currently unsupported because with the current Type representation - // it would not be possible to understand if it is an empty string - // or a 0 integer. - s.Error(pos, "empty string literals are not supported") - } s.next() case s.ch >= '0' && s.ch <= '9': tok = tokInt diff --git a/pkg/ast/testdata/all.txt b/pkg/ast/testdata/all.txt index d4452b34f..ede11a88a 100644 --- a/pkg/ast/testdata/all.txt +++ b/pkg/ast/testdata/all.txt @@ -25,10 +25,10 @@ define FOO `bar ### C expression is not terminated foo(x int32[1:2:3, opt]) ### unexpected ':', expecting ']' s0 { - f0 string[""] ### empty string literals are not supported + f0 string[""] } -sf0 = "", "1" ### empty string literals are not supported +sf0 = "", "1" include <linux/foo.h> include "linux/foo.h" diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 5d741effc..eb2a13e19 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -802,7 +802,7 @@ func checkTypeKind(t *ast.Type, kind int) (unexpected string, expect string, ok switch { case kind == kindAny: ok = true - case t.String != "": + case t.HasString: ok = kind == kindString if !ok { unexpected = fmt.Sprintf("string %q", t.String) diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index 088e119ef..88e45dba4 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -9,12 +9,19 @@ strings { f1 string f2 string["foo"] f3 string["foo", 10] - f4 string[string_flags, 10] + f4 string[string_flags1, 10] f5 stringnoz f6 stringnoz["foo"] + f7 string[""] + f8 string["", 10] + f9 stringnoz[""] + f11 stringnoz[string_flags1] + f12 string[string_flags2] + f13 stringnoz[string_flags2] } [packed] -string_flags = "foo", "barbaz" +string_flags1 = "foo", "barbaz" +string_flags2 = "" # Proc type. diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index abfbc86fc..847849f2e 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -463,6 +463,9 @@ var typeString = &typeDesc{ } }, Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { + return comp.stringSize(t, args) == varlenString + }, + ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { return comp.stringSize(t, args) == 0 }, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { @@ -472,6 +475,9 @@ var typeString = &typeDesc{ } vals := comp.genStrings(t, args) base.TypeSize = comp.stringSize(t, args) + if base.TypeSize == varlenString { + base.TypeSize = 0 + } return &prog.BufferType{ TypeCommon: base.TypeCommon, Kind: prog.BufferString, @@ -485,7 +491,7 @@ var typeString = &typeDesc{ func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string { var vals []string if len(args) > 0 { - if args[0].String != "" { + if args[0].HasString { vals = append(vals, args[0].String) } else { vals = genStrArray(comp.strFlags[args[0].Ident].Values) @@ -508,24 +514,26 @@ func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string { return vals } -// stringSize returns static string size, or 0 if it is variable length. +const varlenString = ^uint64(0) + +// stringSize returns static string size, or varlenString if it is variable length. func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 { switch len(args) { case 0: - return 0 // a random string + return varlenString // a random string case 1: var z uint64 if t.Ident == "string" { z = 1 } - if args[0].String != "" { + if args[0].HasString { return uint64(len(args[0].String)) + z // string constant } - var size uint64 + size := varlenString for _, s := range comp.strFlags[args[0].Ident].Values { s1 := uint64(len(s.Value)) + z - if size != 0 && size != s1 { - return 0 // strings of different lengths + if size != varlenString && size != s1 { + return varlenString // strings of different lengths } size = s1 } @@ -539,7 +547,7 @@ func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 { var typeArgStringFlags = &typeArg{ Check: func(comp *compiler, t *ast.Type) { - if t.String == "" && t.Ident == "" { + if !t.HasString && t.Ident == "" { comp.error(t.Pos, "unexpected int %v, string arg must be a string literal or string flags", t.Value) return } |
