aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ast
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-07-09 20:47:07 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-07-09 20:47:07 +0200
commit710eefe85a976c438da255499fbefd1a6c989ef6 (patch)
tree3467ac95a3c574bdf41105e012df2e4c540ed859 /pkg/ast
parentf25e57704183544b0d540ef0035acfa6fb9071d7 (diff)
pkg/compiler: support negative integers
Currently we have to use 0xffffffffffffffff to represent -1, and we can't express e.g. -20:20 int range. Support negative consts to fix both problems.
Diffstat (limited to 'pkg/ast')
-rw-r--r--pkg/ast/ast.go15
-rw-r--r--pkg/ast/clone.go6
-rw-r--r--pkg/ast/format.go34
-rw-r--r--pkg/ast/parser.go17
-rw-r--r--pkg/ast/scanner.go29
-rw-r--r--pkg/ast/testdata/all.txt1
6 files changed, 55 insertions, 47 deletions
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go
index 610d22f30..1e1e97221 100644
--- a/pkg/ast/ast.go
+++ b/pkg/ast/ast.go
@@ -169,19 +169,20 @@ func (n *String) Info() (Pos, string, string) {
return n.Pos, tok2str[tokString], ""
}
-type intFmt int
+type IntFmt int
const (
- intFmtDec intFmt = iota
- intFmtHex
- intFmtChar
+ IntFmtDec IntFmt = iota
+ IntFmtNeg
+ IntFmtHex
+ IntFmtChar
)
type Int struct {
Pos Pos
// Only one of Value, Ident, CExpr is filled.
Value uint64
- valueFmt intFmt
+ ValueFmt IntFmt
Ident string
CExpr string
}
@@ -194,7 +195,7 @@ type Type struct {
Pos Pos
// Only one of Value, Ident, String is filled.
Value uint64
- valueFmt intFmt
+ ValueFmt IntFmt
Ident string
String string
HasString bool
@@ -202,7 +203,7 @@ type Type struct {
HasColon bool
Pos2 Pos
Value2 uint64
- value2Fmt intFmt
+ Value2Fmt IntFmt
Ident2 string
Args []*Type
}
diff --git a/pkg/ast/clone.go b/pkg/ast/clone.go
index 9ccc3ea76..072425115 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,
- valueFmt: n.valueFmt,
+ 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,
- valueFmt: n.valueFmt,
+ ValueFmt: n.ValueFmt,
Ident: n.Ident,
String: n.String,
HasString: n.HasString,
HasColon: n.HasColon,
Pos2: n.Pos2,
Value2: n.Value2,
- value2Fmt: n.value2Fmt,
+ Value2Fmt: n.Value2Fmt,
Ident2: n.Ident2,
Args: args,
}
diff --git a/pkg/ast/format.go b/pkg/ast/format.go
index 5022d5da1..13cd26e2c 100644
--- a/pkg/ast/format.go
+++ b/pkg/ast/format.go
@@ -35,6 +35,21 @@ func SerializeNode(n Node) string {
return buf.String()
}
+func FormatInt(v uint64, format IntFmt) string {
+ switch format {
+ case IntFmtDec:
+ return fmt.Sprint(v)
+ case IntFmtNeg:
+ return fmt.Sprint(int64(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))
+ }
+}
+
type serializer interface {
serialize(w io.Writer)
}
@@ -159,14 +174,14 @@ func fmtType(t *Type) string {
case t.HasString:
v = fmt.Sprintf("\"%v\"", t.String)
default:
- v = fmtIntValue(t.Value, t.valueFmt)
+ v = FormatInt(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.value2Fmt))
+ v += fmt.Sprintf(":%v", FormatInt(t.Value2, t.Value2Fmt))
}
}
v += fmtTypeList(t.Args)
@@ -206,20 +221,7 @@ func fmtInt(i *Int) string {
case i.CExpr != "":
return fmt.Sprintf("%v", i.CExpr)
default:
- return fmtIntValue(i.Value, i.valueFmt)
- }
-}
-
-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 FormatInt(i.Value, i.ValueFmt)
}
}
diff --git a/pkg/ast/parser.go b/pkg/ast/parser.go
index e4c5d8742..d43011796 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.valueFmt = 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.value2Fmt = 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.valueFmt = p.parseIntValue()
+ i.Value, i.ValueFmt = p.parseIntValue()
case tokIdent:
i.Ident = p.lit
default:
@@ -489,16 +489,19 @@ func (p *parser) parseInt() *Int {
return i
}
-func (p *parser) parseIntValue() (uint64, intFmt) {
+func (p *parser) parseIntValue() (uint64, IntFmt) {
if p.lit[0] == '\'' {
- return uint64(p.lit[1]), intFmtChar
+ return uint64(p.lit[1]), IntFmtChar
}
if v, err := strconv.ParseUint(p.lit, 10, 64); err == nil {
- return v, intFmtDec
+ return v, IntFmtDec
+ }
+ if v, err := strconv.ParseInt(p.lit, 10, 64); err == nil {
+ return uint64(v), IntFmtNeg
}
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, intFmtHex
+ 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 67e7f50bd..af9ac562f 100644
--- a/pkg/ast/scanner.go
+++ b/pkg/ast/scanner.go
@@ -150,7 +150,7 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) {
case s.ch == '"' || s.ch == '<':
tok = tokString
lit = s.scanStr(pos)
- case s.ch >= '0' && s.ch <= '9':
+ case s.ch >= '0' && s.ch <= '9' || s.ch == '-':
tok = tokInt
lit = s.scanInt(pos)
case s.ch == '\'':
@@ -211,25 +211,26 @@ func (s *scanner) scanStr(pos Pos) string {
func (s *scanner) scanInt(pos Pos) string {
for s.ch >= '0' && s.ch <= '9' ||
s.ch >= 'a' && s.ch <= 'f' ||
- s.ch >= 'A' && s.ch <= 'F' || s.ch == 'x' {
+ s.ch >= 'A' && s.ch <= 'F' ||
+ s.ch == 'x' || s.ch == '-' {
s.next()
}
lit := string(s.data[pos.Off:s.off])
- bad := false
- if _, err := strconv.ParseUint(lit, 10, 64); err != nil {
- if len(lit) > 2 && lit[0] == '0' && lit[1] == 'x' {
- if _, err := strconv.ParseUint(lit[2:], 16, 64); err != nil {
- bad = true
- }
- } else {
- bad = true
+ if _, err := strconv.ParseUint(lit, 10, 64); err == nil {
+ return lit
+ }
+ if len(lit) > 1 && lit[0] == '-' {
+ if _, err := strconv.ParseInt(lit, 10, 64); err == nil {
+ return lit
}
}
- if bad {
- s.Error(pos, fmt.Sprintf("bad integer %q", lit))
- lit = "0"
+ if len(lit) > 2 && lit[0] == '0' && lit[1] == 'x' {
+ if _, err := strconv.ParseUint(lit[2:], 16, 64); err == nil {
+ return lit
+ }
}
- return lit
+ s.Error(pos, fmt.Sprintf("bad integer %q", lit))
+ return "0"
}
func (s *scanner) scanChar(pos Pos) string {
diff --git a/pkg/ast/testdata/all.txt b/pkg/ast/testdata/all.txt
index 6c818eca6..6e4e72d2c 100644
--- a/pkg/ast/testdata/all.txt
+++ b/pkg/ast/testdata/all.txt
@@ -12,6 +12,7 @@ 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
+int_flags4 = 1, -2- ### bad integer "-2-"
str_flags0 = "foo", "bar"
str_flags1 = "non terminated ### string literal is not terminated