diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-07-09 20:47:07 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-07-09 20:47:07 +0200 |
| commit | 710eefe85a976c438da255499fbefd1a6c989ef6 (patch) | |
| tree | 3467ac95a3c574bdf41105e012df2e4c540ed859 /pkg/ast | |
| parent | f25e57704183544b0d540ef0035acfa6fb9071d7 (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.go | 15 | ||||
| -rw-r--r-- | pkg/ast/clone.go | 6 | ||||
| -rw-r--r-- | pkg/ast/format.go | 34 | ||||
| -rw-r--r-- | pkg/ast/parser.go | 17 | ||||
| -rw-r--r-- | pkg/ast/scanner.go | 29 | ||||
| -rw-r--r-- | pkg/ast/testdata/all.txt | 1 |
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 |
