aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ast
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/ast
parentc7f6891ca7dc623ed77840580cb9270c61d200ee (diff)
pkg/ast: support char constants
Frequently it's useful to do something like: int8['a':'z'] punctuation = ',', '-', ':'
Diffstat (limited to 'pkg/ast')
-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
6 files changed, 49 insertions, 18 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