aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ast
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/ast')
-rw-r--r--pkg/ast/ast.go9
-rw-r--r--pkg/ast/clone.go2
-rw-r--r--pkg/ast/format.go15
-rw-r--r--pkg/ast/parser.go19
-rw-r--r--pkg/ast/scanner.go59
-rw-r--r--pkg/ast/testdata/all.txt7
6 files changed, 70 insertions, 41 deletions
diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go
index 13ff2b40e..f1f74e61b 100644
--- a/pkg/ast/ast.go
+++ b/pkg/ast/ast.go
@@ -163,6 +163,7 @@ func (n *Ident) Info() (Pos, string, string) {
type String struct {
Pos Pos
Value string
+ Fmt StrFmt
}
func (n *String) Info() (Pos, string, string) {
@@ -178,6 +179,13 @@ const (
IntFmtChar
)
+type StrFmt int
+
+const (
+ StrFmtRaw StrFmt = iota
+ StrFmtHex
+)
+
type Int struct {
Pos Pos
// Only one of Value, Ident, CExpr is filled.
@@ -198,6 +206,7 @@ type Type struct {
ValueFmt IntFmt
Ident string
String string
+ StringFmt StrFmt
HasString bool
// Parts after COLON (for ranges and bitfields).
Colon []*Type
diff --git a/pkg/ast/clone.go b/pkg/ast/clone.go
index a594e41f6..54bf8250c 100644
--- a/pkg/ast/clone.go
+++ b/pkg/ast/clone.go
@@ -134,6 +134,7 @@ func (n *String) Clone() Node {
return &String{
Pos: n.Pos,
Value: n.Value,
+ Fmt: n.Fmt,
}
}
@@ -154,6 +155,7 @@ func (n *Type) Clone() Node {
ValueFmt: n.ValueFmt,
Ident: n.Ident,
String: n.String,
+ StringFmt: n.StringFmt,
HasString: n.HasString,
Colon: cloneTypes(n.Colon),
Args: cloneTypes(n.Args),
diff --git a/pkg/ast/format.go b/pkg/ast/format.go
index c3d931706..a2ead06f2 100644
--- a/pkg/ast/format.go
+++ b/pkg/ast/format.go
@@ -50,6 +50,17 @@ func FormatInt(v uint64, format IntFmt) string {
}
}
+func FormatStr(v string, format StrFmt) string {
+ switch format {
+ case StrFmtRaw:
+ return fmt.Sprintf(`"%v"`, v)
+ case StrFmtHex:
+ return fmt.Sprintf("`%x`", v)
+ default:
+ panic(fmt.Sprintf("unknown str format %v", format))
+ }
+}
+
type serializer interface {
serialize(w io.Writer)
}
@@ -153,7 +164,7 @@ func (flags *IntFlags) serialize(w io.Writer) {
func (flags *StrFlags) serialize(w io.Writer) {
fmt.Fprintf(w, "%v = ", flags.Name.Name)
for i, v := range flags.Values {
- fmt.Fprintf(w, "%v\"%v\"", comma(i, ""), v.Value)
+ fmt.Fprintf(w, "%v%v", comma(i, ""), FormatStr(v.Value, v.Fmt))
}
fmt.Fprintf(w, "\n")
}
@@ -172,7 +183,7 @@ func fmtType(t *Type) string {
case t.Ident != "":
v = t.Ident
case t.HasString:
- v = fmt.Sprintf("\"%v\"", t.String)
+ v = FormatStr(t.String, t.StringFmt)
default:
v = FormatInt(t.Value, t.ValueFmt)
}
diff --git a/pkg/ast/parser.go b/pkg/ast/parser.go
index b8d22fd88..7b46f6611 100644
--- a/pkg/ast/parser.go
+++ b/pkg/ast/parser.go
@@ -314,7 +314,7 @@ func (p *parser) parseFlags(name *Ident) Node {
switch p.tok {
case tokInt, tokIdent:
return p.parseIntFlags(name)
- case tokString:
+ case tokString, tokStringHex:
return p.parseStrFlags(name)
default:
p.expect(tokInt, tokIdent, tokString)
@@ -417,9 +417,10 @@ func (p *parser) parseType() *Type {
case tokIdent:
allowColon = true
arg.Ident = p.lit
- case tokString:
+ case tokString, tokStringHex:
arg.String = p.lit
arg.HasString = true
+ arg.StringFmt = strTokToFmt(p.tok)
default:
p.expect(tokInt, tokIdent, tokString)
}
@@ -468,15 +469,27 @@ func (p *parser) parseIdent() *Ident {
}
func (p *parser) parseString() *String {
- p.expect(tokString)
+ p.expect(tokString, tokStringHex)
str := &String{
Pos: p.pos,
Value: p.lit,
+ Fmt: strTokToFmt(p.tok),
}
p.next()
return str
}
+func strTokToFmt(tok token) StrFmt {
+ switch tok {
+ case tokString:
+ return StrFmtRaw
+ case tokStringHex:
+ return StrFmtHex
+ default:
+ panic("bad string token")
+ }
+}
+
func (p *parser) parseInt() *Int {
i := &Int{
Pos: p.pos,
diff --git a/pkg/ast/scanner.go b/pkg/ast/scanner.go
index a9448b34f..3a6ba9d98 100644
--- a/pkg/ast/scanner.go
+++ b/pkg/ast/scanner.go
@@ -4,6 +4,7 @@
package ast
import (
+ "encoding/hex"
"fmt"
"os"
"strconv"
@@ -20,6 +21,7 @@ const (
tokDefine
tokResource
tokString
+ tokStringHex
tokCExpr
tokInt
@@ -51,18 +53,19 @@ var punctuation = [256]token{
}
var tok2str = [...]string{
- tokIllegal: "ILLEGAL",
- tokComment: "comment",
- tokIdent: "identifier",
- tokInclude: "include",
- tokIncdir: "incdir",
- tokDefine: "define",
- tokResource: "resource",
- tokString: "string",
- tokCExpr: "CEXPR",
- tokInt: "int",
- tokNewLine: "NEWLINE",
- tokEOF: "EOF",
+ tokIllegal: "ILLEGAL",
+ tokComment: "comment",
+ tokIdent: "identifier",
+ tokInclude: "include",
+ tokIncdir: "incdir",
+ tokDefine: "define",
+ tokResource: "resource",
+ tokString: "string",
+ tokStringHex: "hex string",
+ tokCExpr: "CEXPR",
+ tokInt: "int",
+ tokNewLine: "NEWLINE",
+ tokEOF: "EOF",
}
func init() {
@@ -132,12 +135,7 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) {
case s.ch == 0:
tok = tokEOF
s.next()
- case s.ch == '`':
- tok = tokCExpr
- lit = s.scanCExpr(pos)
case s.prev2 == tokDefine && s.prev1 == tokIdent:
- // Note: the old form for C expressions, not really lexable.
- // TODO(dvyukov): get rid of this eventually.
tok = tokCExpr
for ; s.ch != '\n'; s.next() {
}
@@ -150,6 +148,9 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) {
case s.ch == '"' || s.ch == '<':
tok = tokString
lit = s.scanStr(pos)
+ case s.ch == '`':
+ tok = tokStringHex
+ lit = s.scanStr(pos)
case s.ch >= '0' && s.ch <= '9' || s.ch == '-':
tok = tokInt
lit = s.scanInt(pos)
@@ -170,21 +171,9 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) {
return
}
-func (s *scanner) scanCExpr(pos Pos) string {
- for s.next(); s.ch != '`' && s.ch != '\n'; s.next() {
- }
- if s.ch == '\n' {
- s.Error(pos, "C expression is not terminated")
- return ""
- }
- lit := string(s.data[pos.Off+1 : s.off])
- s.next()
- return lit
-}
-
func (s *scanner) scanStr(pos Pos) string {
// TODO(dvyukov): get rid of <...> strings, that's only includes
- closing := byte('"')
+ closing := s.ch
if s.ch == '<' {
closing = '>'
}
@@ -196,7 +185,6 @@ func (s *scanner) scanStr(pos Pos) string {
}
lit := string(s.data[pos.Off+1 : s.off])
for i := 0; i < len(lit); i++ {
- //lit[i]
if lit[i] < 0x20 || lit[i] >= 0x80 {
pos1 := pos
pos1.Col += i + 1
@@ -206,7 +194,14 @@ func (s *scanner) scanStr(pos Pos) string {
}
}
s.next()
- return lit
+ if closing != '`' {
+ return lit
+ }
+ decoded, err := hex.DecodeString(lit)
+ if err != nil {
+ s.Error(pos, "bad hex string literal: %v", err)
+ }
+ return string(decoded)
}
func (s *scanner) scanInt(pos Pos) string {
diff --git a/pkg/ast/testdata/all.txt b/pkg/ast/testdata/all.txt
index 392796254..122fa514b 100644
--- a/pkg/ast/testdata/all.txt
+++ b/pkg/ast/testdata/all.txt
@@ -17,15 +17,14 @@ int_flags4 = 1, -2- ### bad integer "-2-"
str_flags0 = "foo", "bar"
str_flags1 = "non terminated ### string literal is not terminated
str_flags2 = "bad chars здесь" ### illegal character U+00D0 'Ð' in string literal
-str_flags3 = "string", not a string ### unexpected identifier, expecting string
-str_flags4 = "string", 42 ### unexpected int, expecting string
+str_flags3 = "string", not a string ### unexpected identifier, expecting string, hex string
+str_flags4 = "string", 42 ### unexpected int, expecting string, hex string
call(foo ,int32 , bar int32) ### unexpected ',', expecting int, identifier, string
call(foo int32:"bar") ### unexpected string, expecting int, identifier
call(a int32, b len[a:"bar"]) ### unexpected string, expecting int, identifier
-define FOO `bar`
-define FOO `bar ### C expression is not terminated
+define FOO bar
foo(x int32[1:2:3, opt])
foo2(x int32[1[2]:2]) ### unexpected ':', expecting ']'