aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-04-29 10:56:48 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-04-29 12:04:22 +0200
commit1e85f7b9af8e29f06a22eb1ff325de2a40072738 (patch)
treefbbe16d0eb26f84ad22b82e0925420b1177798e2 /pkg
parentc7f6891ca7dc623ed77840580cb9270c61d200ee (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.go14
-rw-r--r--pkg/ast/clone.go6
-rw-r--r--pkg/ast/format.go18
-rw-r--r--pkg/ast/parser.go15
-rw-r--r--pkg/ast/scanner.go11
-rw-r--r--pkg/ast/testdata/all.txt3
-rw-r--r--pkg/compiler/compiler_test.go13
-rw-r--r--pkg/compiler/testdata/all.txt6
-rw-r--r--pkg/compiler/testdata/errors2.txt1
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