diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-04-29 10:56:48 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-04-29 12:04:22 +0200 |
| commit | 1e85f7b9af8e29f06a22eb1ff325de2a40072738 (patch) | |
| tree | fbbe16d0eb26f84ad22b82e0925420b1177798e2 /pkg | |
| parent | c7f6891ca7dc623ed77840580cb9270c61d200ee (diff) | |
pkg/ast: support char constants
Frequently it's useful to do something like:
int8['a':'z']
punctuation = ',', '-', ':'
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/ast/ast.go | 14 | ||||
| -rw-r--r-- | pkg/ast/clone.go | 6 | ||||
| -rw-r--r-- | pkg/ast/format.go | 18 | ||||
| -rw-r--r-- | pkg/ast/parser.go | 15 | ||||
| -rw-r--r-- | pkg/ast/scanner.go | 11 | ||||
| -rw-r--r-- | pkg/ast/testdata/all.txt | 3 | ||||
| -rw-r--r-- | pkg/compiler/compiler_test.go | 13 | ||||
| -rw-r--r-- | pkg/compiler/testdata/all.txt | 6 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors2.txt | 1 |
9 files changed, 65 insertions, 22 deletions
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go index 723d6d9c4..610d22f30 100644 --- a/pkg/ast/ast.go +++ b/pkg/ast/ast.go @@ -169,11 +169,19 @@ func (n *String) Info() (Pos, string, string) { return n.Pos, tok2str[tokString], "" } +type intFmt int + +const ( + intFmtDec intFmt = iota + intFmtHex + intFmtChar +) + type Int struct { Pos Pos // Only one of Value, Ident, CExpr is filled. Value uint64 - ValueHex bool // says if value was in hex (for formatting) + valueFmt intFmt Ident string CExpr string } @@ -186,7 +194,7 @@ type Type struct { Pos Pos // Only one of Value, Ident, String is filled. Value uint64 - ValueHex bool + valueFmt intFmt Ident string String string HasString bool @@ -194,7 +202,7 @@ type Type struct { HasColon bool Pos2 Pos Value2 uint64 - Value2Hex bool + value2Fmt intFmt Ident2 string Args []*Type } diff --git a/pkg/ast/clone.go b/pkg/ast/clone.go index 4c938b807..9ccc3ea76 100644 --- a/pkg/ast/clone.go +++ b/pkg/ast/clone.go @@ -165,7 +165,7 @@ func (n *Int) Clone() Node { return &Int{ Pos: n.Pos, Value: n.Value, - ValueHex: n.ValueHex, + valueFmt: n.valueFmt, Ident: n.Ident, CExpr: n.CExpr, } @@ -179,14 +179,14 @@ func (n *Type) Clone() Node { return &Type{ Pos: n.Pos, Value: n.Value, - ValueHex: n.ValueHex, + valueFmt: n.valueFmt, Ident: n.Ident, String: n.String, HasString: n.HasString, HasColon: n.HasColon, Pos2: n.Pos2, Value2: n.Value2, - Value2Hex: n.Value2Hex, + value2Fmt: n.value2Fmt, Ident2: n.Ident2, Args: args, } diff --git a/pkg/ast/format.go b/pkg/ast/format.go index cf7edf975..5022d5da1 100644 --- a/pkg/ast/format.go +++ b/pkg/ast/format.go @@ -159,14 +159,14 @@ func fmtType(t *Type) string { case t.HasString: v = fmt.Sprintf("\"%v\"", t.String) default: - v = fmtIntValue(t.Value, t.ValueHex) + v = fmtIntValue(t.Value, t.valueFmt) } if t.HasColon { switch { case t.Ident2 != "": v += fmt.Sprintf(":%v", t.Ident2) default: - v += fmt.Sprintf(":%v", fmtIntValue(t.Value2, t.Value2Hex)) + v += fmt.Sprintf(":%v", fmtIntValue(t.Value2, t.value2Fmt)) } } v += fmtTypeList(t.Args) @@ -206,15 +206,21 @@ func fmtInt(i *Int) string { case i.CExpr != "": return fmt.Sprintf("%v", i.CExpr) default: - return fmtIntValue(i.Value, i.ValueHex) + return fmtIntValue(i.Value, i.valueFmt) } } -func fmtIntValue(v uint64, hex bool) string { - if hex { +func fmtIntValue(v uint64, format intFmt) string { + switch format { + case intFmtDec: + return fmt.Sprint(v) + case intFmtHex: return fmt.Sprintf("0x%x", v) + case intFmtChar: + return fmt.Sprintf("'%c'", v) + default: + panic(fmt.Sprintf("unknown int format %v", format)) } - return fmt.Sprint(v) } func comma(i int, or string) string { diff --git a/pkg/ast/parser.go b/pkg/ast/parser.go index fb3327223..e4c5d8742 100644 --- a/pkg/ast/parser.go +++ b/pkg/ast/parser.go @@ -413,7 +413,7 @@ func (p *parser) parseType() *Type { switch p.tok { case tokInt: allowColon = true - arg.Value, arg.ValueHex = p.parseIntValue() + arg.Value, arg.valueFmt = p.parseIntValue() case tokIdent: allowColon = true arg.Ident = p.lit @@ -429,7 +429,7 @@ func (p *parser) parseType() *Type { arg.Pos2 = p.pos switch p.tok { case tokInt: - arg.Value2, arg.Value2Hex = p.parseIntValue() + arg.Value2, arg.value2Fmt = p.parseIntValue() case tokIdent: arg.Ident2 = p.lit default: @@ -479,7 +479,7 @@ func (p *parser) parseInt() *Int { } switch p.tok { case tokInt: - i.Value, i.ValueHex = p.parseIntValue() + i.Value, i.valueFmt = p.parseIntValue() case tokIdent: i.Ident = p.lit default: @@ -489,13 +489,16 @@ func (p *parser) parseInt() *Int { return i } -func (p *parser) parseIntValue() (uint64, bool) { +func (p *parser) parseIntValue() (uint64, intFmt) { + if p.lit[0] == '\'' { + return uint64(p.lit[1]), intFmtChar + } if v, err := strconv.ParseUint(p.lit, 10, 64); err == nil { - return v, false + return v, intFmtDec } if len(p.lit) > 2 && p.lit[0] == '0' && p.lit[1] == 'x' { if v, err := strconv.ParseUint(p.lit[2:], 16, 64); err == nil { - return v, true + return v, intFmtHex } } panic(fmt.Sprintf("scanner returned bad integer %q", p.lit)) diff --git a/pkg/ast/scanner.go b/pkg/ast/scanner.go index 5ad5e5808..343c3b9ab 100644 --- a/pkg/ast/scanner.go +++ b/pkg/ast/scanner.go @@ -200,6 +200,17 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) { s.Error(pos, fmt.Sprintf("bad integer %q", lit)) lit = "0" } + case s.ch == '\'': + tok = tokInt + lit = "0" + s.next() + s.next() + if s.ch != '\'' { + s.Error(pos, "char literal is not terminated") + return + } + s.next() + lit = string(s.data[pos.Off : pos.Off+3]) case s.ch == '_' || s.ch >= 'a' && s.ch <= 'z' || s.ch >= 'A' && s.ch <= 'Z': tok = tokIdent for s.ch == '_' || s.ch == '$' || diff --git a/pkg/ast/testdata/all.txt b/pkg/ast/testdata/all.txt index 7e1db7309..6c818eca6 100644 --- a/pkg/ast/testdata/all.txt +++ b/pkg/ast/testdata/all.txt @@ -9,6 +9,9 @@ int_flags0 = 0, 0x1, 0xab int_flags1 = 123ab0x ### bad integer "123ab0x" int_flags1 == 0, 1 ### unexpected '=', expecting int, identifier, string int_flags = 0, "foo" ### unexpected string, expecting int, identifier +int_flags2 = ' ### char literal is not terminated +int_flags3 = 'a ### char literal is not terminated +int_flags3 = 'a, 1 ### char literal is not terminated str_flags0 = "foo", "bar" str_flags1 = "non terminated ### string literal is not terminated diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go index a5cc6a86a..c52d4d39d 100644 --- a/pkg/compiler/compiler_test.go +++ b/pkg/compiler/compiler_test.go @@ -5,6 +5,7 @@ package compiler import ( "bytes" + "flag" "fmt" "io/ioutil" "path/filepath" @@ -15,6 +16,8 @@ import ( "github.com/google/syzkaller/sys/targets" ) +var flagUpdate = flag.Bool("update", false, "reformat all.txt") + func TestCompileAll(t *testing.T) { for os, arches := range targets.List { os, arches := os, arches @@ -63,7 +66,8 @@ func TestNoErrors(t *testing.T) { eh := func(pos ast.Pos, msg string) { t.Logf("%v: %v", pos, msg) } - data, err := ioutil.ReadFile(filepath.Join("testdata", name)) + fileName := filepath.Join("testdata", name) + data, err := ioutil.ReadFile(fileName) if err != nil { t.Fatal(err) } @@ -71,6 +75,13 @@ func TestNoErrors(t *testing.T) { if astDesc == nil { t.Fatalf("parsing failed") } + formatted := ast.Format(astDesc) + if !bytes.Equal(data, formatted) { + if *flagUpdate { + ioutil.WriteFile(fileName, formatted, 0644) + } + t.Fatalf("description is not formatted") + } constInfo := ExtractConsts(astDesc, target, eh) if constInfo == nil { t.Fatalf("const extraction failed") diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index 081bb1aab..d451f5a60 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -6,6 +6,7 @@ foo$1(a int8[C1:C2]) foo$2(a ptr[out, array[int32]]) foo$3(a union_arg) foo$4() r0 +foo$5(a int8['a':'z']) resource r0[intptr] @@ -139,8 +140,8 @@ type templ_struct1[C] { } union_with_templ_struct [ - f1 templ_struct0[C1, type0] - f2 templ_struct0[C2, struct0] + f1 templ_struct0[C1, type0] + f2 templ_struct0[C2, struct0] ] [varlen] struct0 { @@ -183,7 +184,6 @@ foo$templ4(a ptr[in, templ_struct1[3]]) foo$templ5(a ptr[in, templ_struct1[3]]) foo$templ6(a ptr[in, templ_struct4]) - # Structs. s0 { diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index 86148a563..69fa46e62 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -183,5 +183,6 @@ foo$505(a proc[20, 0]) ### proc per-process values must not be 0 foo$506(a ptr[in, array[int32, 0]]) ### arrays of size 0 are not supported foo$507(a ptr[in, array[int32, 0:0]]) ### arrays of size 0 are not supported foo$508(a ptr[in, string["foo", 3]]) ### string value "foo\x00" exceeds buffer length 3 +foo$509(a int8['b':'a']) ### bad int range [98:97] type type500 proc[C1, 8, int8] ### values starting from 1 with step 8 overflow base type for 32 procs |
