 e1221e69a8
			
		
	
	e1221e69a8
	
	
	
		
			
			Note: now vndr >= v0.10 is required (https://github.com/containerd/cgroups/issues/139) Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
		
			
				
	
	
		
			818 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			818 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package dbus
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"reflect"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"unicode/utf8"
 | |
| )
 | |
| 
 | |
| type varParser struct {
 | |
| 	tokens []varToken
 | |
| 	i      int
 | |
| }
 | |
| 
 | |
| func (p *varParser) backup() {
 | |
| 	p.i--
 | |
| }
 | |
| 
 | |
| func (p *varParser) next() varToken {
 | |
| 	if p.i < len(p.tokens) {
 | |
| 		t := p.tokens[p.i]
 | |
| 		p.i++
 | |
| 		return t
 | |
| 	}
 | |
| 	return varToken{typ: tokEOF}
 | |
| }
 | |
| 
 | |
| type varNode interface {
 | |
| 	Infer() (Signature, error)
 | |
| 	String() string
 | |
| 	Sigs() sigSet
 | |
| 	Value(Signature) (interface{}, error)
 | |
| }
 | |
| 
 | |
| func varMakeNode(p *varParser) (varNode, error) {
 | |
| 	var sig Signature
 | |
| 
 | |
| 	for {
 | |
| 		t := p.next()
 | |
| 		switch t.typ {
 | |
| 		case tokEOF:
 | |
| 			return nil, io.ErrUnexpectedEOF
 | |
| 		case tokError:
 | |
| 			return nil, errors.New(t.val)
 | |
| 		case tokNumber:
 | |
| 			return varMakeNumNode(t, sig)
 | |
| 		case tokString:
 | |
| 			return varMakeStringNode(t, sig)
 | |
| 		case tokBool:
 | |
| 			if sig.str != "" && sig.str != "b" {
 | |
| 				return nil, varTypeError{t.val, sig}
 | |
| 			}
 | |
| 			b, err := strconv.ParseBool(t.val)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			return boolNode(b), nil
 | |
| 		case tokArrayStart:
 | |
| 			return varMakeArrayNode(p, sig)
 | |
| 		case tokVariantStart:
 | |
| 			return varMakeVariantNode(p, sig)
 | |
| 		case tokDictStart:
 | |
| 			return varMakeDictNode(p, sig)
 | |
| 		case tokType:
 | |
| 			if sig.str != "" {
 | |
| 				return nil, errors.New("unexpected type annotation")
 | |
| 			}
 | |
| 			if t.val[0] == '@' {
 | |
| 				sig.str = t.val[1:]
 | |
| 			} else {
 | |
| 				sig.str = varTypeMap[t.val]
 | |
| 			}
 | |
| 		case tokByteString:
 | |
| 			if sig.str != "" && sig.str != "ay" {
 | |
| 				return nil, varTypeError{t.val, sig}
 | |
| 			}
 | |
| 			b, err := varParseByteString(t.val)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			return byteStringNode(b), nil
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("unexpected %q", t.val)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type varTypeError struct {
 | |
| 	val string
 | |
| 	sig Signature
 | |
| }
 | |
| 
 | |
| func (e varTypeError) Error() string {
 | |
| 	return fmt.Sprintf("dbus: can't parse %q as type %q", e.val, e.sig.str)
 | |
| }
 | |
| 
 | |
| type sigSet map[Signature]bool
 | |
| 
 | |
| func (s sigSet) Empty() bool {
 | |
| 	return len(s) == 0
 | |
| }
 | |
| 
 | |
| func (s sigSet) Intersect(s2 sigSet) sigSet {
 | |
| 	r := make(sigSet)
 | |
| 	for k := range s {
 | |
| 		if s2[k] {
 | |
| 			r[k] = true
 | |
| 		}
 | |
| 	}
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| func (s sigSet) Single() (Signature, bool) {
 | |
| 	if len(s) == 1 {
 | |
| 		for k := range s {
 | |
| 			return k, true
 | |
| 		}
 | |
| 	}
 | |
| 	return Signature{}, false
 | |
| }
 | |
| 
 | |
| func (s sigSet) ToArray() sigSet {
 | |
| 	r := make(sigSet, len(s))
 | |
| 	for k := range s {
 | |
| 		r[Signature{"a" + k.str}] = true
 | |
| 	}
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| type numNode struct {
 | |
| 	sig Signature
 | |
| 	str string
 | |
| 	val interface{}
 | |
| }
 | |
| 
 | |
| var numSigSet = sigSet{
 | |
| 	Signature{"y"}: true,
 | |
| 	Signature{"n"}: true,
 | |
| 	Signature{"q"}: true,
 | |
| 	Signature{"i"}: true,
 | |
| 	Signature{"u"}: true,
 | |
| 	Signature{"x"}: true,
 | |
| 	Signature{"t"}: true,
 | |
| 	Signature{"d"}: true,
 | |
| }
 | |
| 
 | |
| func (n numNode) Infer() (Signature, error) {
 | |
| 	if strings.ContainsAny(n.str, ".e") {
 | |
| 		return Signature{"d"}, nil
 | |
| 	}
 | |
| 	return Signature{"i"}, nil
 | |
| }
 | |
| 
 | |
| func (n numNode) String() string {
 | |
| 	return n.str
 | |
| }
 | |
| 
 | |
| func (n numNode) Sigs() sigSet {
 | |
| 	if n.sig.str != "" {
 | |
| 		return sigSet{n.sig: true}
 | |
| 	}
 | |
| 	if strings.ContainsAny(n.str, ".e") {
 | |
| 		return sigSet{Signature{"d"}: true}
 | |
| 	}
 | |
| 	return numSigSet
 | |
| }
 | |
| 
 | |
| func (n numNode) Value(sig Signature) (interface{}, error) {
 | |
| 	if n.sig.str != "" && n.sig != sig {
 | |
| 		return nil, varTypeError{n.str, sig}
 | |
| 	}
 | |
| 	if n.val != nil {
 | |
| 		return n.val, nil
 | |
| 	}
 | |
| 	return varNumAs(n.str, sig)
 | |
| }
 | |
| 
 | |
| func varMakeNumNode(tok varToken, sig Signature) (varNode, error) {
 | |
| 	if sig.str == "" {
 | |
| 		return numNode{str: tok.val}, nil
 | |
| 	}
 | |
| 	num, err := varNumAs(tok.val, sig)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return numNode{sig: sig, val: num}, nil
 | |
| }
 | |
| 
 | |
| func varNumAs(s string, sig Signature) (interface{}, error) {
 | |
| 	isUnsigned := false
 | |
| 	size := 32
 | |
| 	switch sig.str {
 | |
| 	case "n":
 | |
| 		size = 16
 | |
| 	case "i":
 | |
| 	case "x":
 | |
| 		size = 64
 | |
| 	case "y":
 | |
| 		size = 8
 | |
| 		isUnsigned = true
 | |
| 	case "q":
 | |
| 		size = 16
 | |
| 		isUnsigned = true
 | |
| 	case "u":
 | |
| 		isUnsigned = true
 | |
| 	case "t":
 | |
| 		size = 64
 | |
| 		isUnsigned = true
 | |
| 	case "d":
 | |
| 		d, err := strconv.ParseFloat(s, 64)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		return d, nil
 | |
| 	default:
 | |
| 		return nil, varTypeError{s, sig}
 | |
| 	}
 | |
| 	base := 10
 | |
| 	if strings.HasPrefix(s, "0x") {
 | |
| 		base = 16
 | |
| 		s = s[2:]
 | |
| 	}
 | |
| 	if strings.HasPrefix(s, "0") && len(s) != 1 {
 | |
| 		base = 8
 | |
| 		s = s[1:]
 | |
| 	}
 | |
| 	if isUnsigned {
 | |
| 		i, err := strconv.ParseUint(s, base, size)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		var v interface{} = i
 | |
| 		switch sig.str {
 | |
| 		case "y":
 | |
| 			v = byte(i)
 | |
| 		case "q":
 | |
| 			v = uint16(i)
 | |
| 		case "u":
 | |
| 			v = uint32(i)
 | |
| 		}
 | |
| 		return v, nil
 | |
| 	}
 | |
| 	i, err := strconv.ParseInt(s, base, size)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	var v interface{} = i
 | |
| 	switch sig.str {
 | |
| 	case "n":
 | |
| 		v = int16(i)
 | |
| 	case "i":
 | |
| 		v = int32(i)
 | |
| 	}
 | |
| 	return v, nil
 | |
| }
 | |
| 
 | |
| type stringNode struct {
 | |
| 	sig Signature
 | |
| 	str string      // parsed
 | |
| 	val interface{} // has correct type
 | |
| }
 | |
| 
 | |
| var stringSigSet = sigSet{
 | |
| 	Signature{"s"}: true,
 | |
| 	Signature{"g"}: true,
 | |
| 	Signature{"o"}: true,
 | |
| }
 | |
| 
 | |
| func (n stringNode) Infer() (Signature, error) {
 | |
| 	return Signature{"s"}, nil
 | |
| }
 | |
| 
 | |
| func (n stringNode) String() string {
 | |
| 	return n.str
 | |
| }
 | |
| 
 | |
| func (n stringNode) Sigs() sigSet {
 | |
| 	if n.sig.str != "" {
 | |
| 		return sigSet{n.sig: true}
 | |
| 	}
 | |
| 	return stringSigSet
 | |
| }
 | |
| 
 | |
| func (n stringNode) Value(sig Signature) (interface{}, error) {
 | |
| 	if n.sig.str != "" && n.sig != sig {
 | |
| 		return nil, varTypeError{n.str, sig}
 | |
| 	}
 | |
| 	if n.val != nil {
 | |
| 		return n.val, nil
 | |
| 	}
 | |
| 	switch {
 | |
| 	case sig.str == "g":
 | |
| 		return Signature{n.str}, nil
 | |
| 	case sig.str == "o":
 | |
| 		return ObjectPath(n.str), nil
 | |
| 	case sig.str == "s":
 | |
| 		return n.str, nil
 | |
| 	default:
 | |
| 		return nil, varTypeError{n.str, sig}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func varMakeStringNode(tok varToken, sig Signature) (varNode, error) {
 | |
| 	if sig.str != "" && sig.str != "s" && sig.str != "g" && sig.str != "o" {
 | |
| 		return nil, fmt.Errorf("invalid type %q for string", sig.str)
 | |
| 	}
 | |
| 	s, err := varParseString(tok.val)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	n := stringNode{str: s}
 | |
| 	if sig.str == "" {
 | |
| 		return stringNode{str: s}, nil
 | |
| 	}
 | |
| 	n.sig = sig
 | |
| 	switch sig.str {
 | |
| 	case "o":
 | |
| 		n.val = ObjectPath(s)
 | |
| 	case "g":
 | |
| 		n.val = Signature{s}
 | |
| 	case "s":
 | |
| 		n.val = s
 | |
| 	}
 | |
| 	return n, nil
 | |
| }
 | |
| 
 | |
| func varParseString(s string) (string, error) {
 | |
| 	// quotes are guaranteed to be there
 | |
| 	s = s[1 : len(s)-1]
 | |
| 	buf := new(bytes.Buffer)
 | |
| 	for len(s) != 0 {
 | |
| 		r, size := utf8.DecodeRuneInString(s)
 | |
| 		if r == utf8.RuneError && size == 1 {
 | |
| 			return "", errors.New("invalid UTF-8")
 | |
| 		}
 | |
| 		s = s[size:]
 | |
| 		if r != '\\' {
 | |
| 			buf.WriteRune(r)
 | |
| 			continue
 | |
| 		}
 | |
| 		r, size = utf8.DecodeRuneInString(s)
 | |
| 		if r == utf8.RuneError && size == 1 {
 | |
| 			return "", errors.New("invalid UTF-8")
 | |
| 		}
 | |
| 		s = s[size:]
 | |
| 		switch r {
 | |
| 		case 'a':
 | |
| 			buf.WriteRune(0x7)
 | |
| 		case 'b':
 | |
| 			buf.WriteRune(0x8)
 | |
| 		case 'f':
 | |
| 			buf.WriteRune(0xc)
 | |
| 		case 'n':
 | |
| 			buf.WriteRune('\n')
 | |
| 		case 'r':
 | |
| 			buf.WriteRune('\r')
 | |
| 		case 't':
 | |
| 			buf.WriteRune('\t')
 | |
| 		case '\n':
 | |
| 		case 'u':
 | |
| 			if len(s) < 4 {
 | |
| 				return "", errors.New("short unicode escape")
 | |
| 			}
 | |
| 			r, err := strconv.ParseUint(s[:4], 16, 32)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 			buf.WriteRune(rune(r))
 | |
| 			s = s[4:]
 | |
| 		case 'U':
 | |
| 			if len(s) < 8 {
 | |
| 				return "", errors.New("short unicode escape")
 | |
| 			}
 | |
| 			r, err := strconv.ParseUint(s[:8], 16, 32)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 			buf.WriteRune(rune(r))
 | |
| 			s = s[8:]
 | |
| 		default:
 | |
| 			buf.WriteRune(r)
 | |
| 		}
 | |
| 	}
 | |
| 	return buf.String(), nil
 | |
| }
 | |
| 
 | |
| var boolSigSet = sigSet{Signature{"b"}: true}
 | |
| 
 | |
| type boolNode bool
 | |
| 
 | |
| func (boolNode) Infer() (Signature, error) {
 | |
| 	return Signature{"b"}, nil
 | |
| }
 | |
| 
 | |
| func (b boolNode) String() string {
 | |
| 	if b {
 | |
| 		return "true"
 | |
| 	}
 | |
| 	return "false"
 | |
| }
 | |
| 
 | |
| func (boolNode) Sigs() sigSet {
 | |
| 	return boolSigSet
 | |
| }
 | |
| 
 | |
| func (b boolNode) Value(sig Signature) (interface{}, error) {
 | |
| 	if sig.str != "b" {
 | |
| 		return nil, varTypeError{b.String(), sig}
 | |
| 	}
 | |
| 	return bool(b), nil
 | |
| }
 | |
| 
 | |
| type arrayNode struct {
 | |
| 	set      sigSet
 | |
| 	children []varNode
 | |
| 	val      interface{}
 | |
| }
 | |
| 
 | |
| func (n arrayNode) Infer() (Signature, error) {
 | |
| 	for _, v := range n.children {
 | |
| 		csig, err := varInfer(v)
 | |
| 		if err != nil {
 | |
| 			continue
 | |
| 		}
 | |
| 		return Signature{"a" + csig.str}, nil
 | |
| 	}
 | |
| 	return Signature{}, fmt.Errorf("can't infer type for %q", n.String())
 | |
| }
 | |
| 
 | |
| func (n arrayNode) String() string {
 | |
| 	s := "["
 | |
| 	for i, v := range n.children {
 | |
| 		s += v.String()
 | |
| 		if i != len(n.children)-1 {
 | |
| 			s += ", "
 | |
| 		}
 | |
| 	}
 | |
| 	return s + "]"
 | |
| }
 | |
| 
 | |
| func (n arrayNode) Sigs() sigSet {
 | |
| 	return n.set
 | |
| }
 | |
| 
 | |
| func (n arrayNode) Value(sig Signature) (interface{}, error) {
 | |
| 	if n.set.Empty() {
 | |
| 		// no type information whatsoever, so this must be an empty slice
 | |
| 		return reflect.MakeSlice(typeFor(sig.str), 0, 0).Interface(), nil
 | |
| 	}
 | |
| 	if !n.set[sig] {
 | |
| 		return nil, varTypeError{n.String(), sig}
 | |
| 	}
 | |
| 	s := reflect.MakeSlice(typeFor(sig.str), len(n.children), len(n.children))
 | |
| 	for i, v := range n.children {
 | |
| 		rv, err := v.Value(Signature{sig.str[1:]})
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		s.Index(i).Set(reflect.ValueOf(rv))
 | |
| 	}
 | |
| 	return s.Interface(), nil
 | |
| }
 | |
| 
 | |
| func varMakeArrayNode(p *varParser, sig Signature) (varNode, error) {
 | |
| 	var n arrayNode
 | |
| 	if sig.str != "" {
 | |
| 		n.set = sigSet{sig: true}
 | |
| 	}
 | |
| 	if t := p.next(); t.typ == tokArrayEnd {
 | |
| 		return n, nil
 | |
| 	} else {
 | |
| 		p.backup()
 | |
| 	}
 | |
| Loop:
 | |
| 	for {
 | |
| 		t := p.next()
 | |
| 		switch t.typ {
 | |
| 		case tokEOF:
 | |
| 			return nil, io.ErrUnexpectedEOF
 | |
| 		case tokError:
 | |
| 			return nil, errors.New(t.val)
 | |
| 		}
 | |
| 		p.backup()
 | |
| 		cn, err := varMakeNode(p)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if cset := cn.Sigs(); !cset.Empty() {
 | |
| 			if n.set.Empty() {
 | |
| 				n.set = cset.ToArray()
 | |
| 			} else {
 | |
| 				nset := cset.ToArray().Intersect(n.set)
 | |
| 				if nset.Empty() {
 | |
| 					return nil, fmt.Errorf("can't parse %q with given type information", cn.String())
 | |
| 				}
 | |
| 				n.set = nset
 | |
| 			}
 | |
| 		}
 | |
| 		n.children = append(n.children, cn)
 | |
| 		switch t := p.next(); t.typ {
 | |
| 		case tokEOF:
 | |
| 			return nil, io.ErrUnexpectedEOF
 | |
| 		case tokError:
 | |
| 			return nil, errors.New(t.val)
 | |
| 		case tokArrayEnd:
 | |
| 			break Loop
 | |
| 		case tokComma:
 | |
| 			continue
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("unexpected %q", t.val)
 | |
| 		}
 | |
| 	}
 | |
| 	return n, nil
 | |
| }
 | |
| 
 | |
| type variantNode struct {
 | |
| 	n varNode
 | |
| }
 | |
| 
 | |
| var variantSet = sigSet{
 | |
| 	Signature{"v"}: true,
 | |
| }
 | |
| 
 | |
| func (variantNode) Infer() (Signature, error) {
 | |
| 	return Signature{"v"}, nil
 | |
| }
 | |
| 
 | |
| func (n variantNode) String() string {
 | |
| 	return "<" + n.n.String() + ">"
 | |
| }
 | |
| 
 | |
| func (variantNode) Sigs() sigSet {
 | |
| 	return variantSet
 | |
| }
 | |
| 
 | |
| func (n variantNode) Value(sig Signature) (interface{}, error) {
 | |
| 	if sig.str != "v" {
 | |
| 		return nil, varTypeError{n.String(), sig}
 | |
| 	}
 | |
| 	sig, err := varInfer(n.n)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	v, err := n.n.Value(sig)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return MakeVariant(v), nil
 | |
| }
 | |
| 
 | |
| func varMakeVariantNode(p *varParser, sig Signature) (varNode, error) {
 | |
| 	n, err := varMakeNode(p)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if t := p.next(); t.typ != tokVariantEnd {
 | |
| 		return nil, fmt.Errorf("unexpected %q", t.val)
 | |
| 	}
 | |
| 	vn := variantNode{n}
 | |
| 	if sig.str != "" && sig.str != "v" {
 | |
| 		return nil, varTypeError{vn.String(), sig}
 | |
| 	}
 | |
| 	return variantNode{n}, nil
 | |
| }
 | |
| 
 | |
| type dictEntry struct {
 | |
| 	key, val varNode
 | |
| }
 | |
| 
 | |
| type dictNode struct {
 | |
| 	kset, vset sigSet
 | |
| 	children   []dictEntry
 | |
| 	val        interface{}
 | |
| }
 | |
| 
 | |
| func (n dictNode) Infer() (Signature, error) {
 | |
| 	for _, v := range n.children {
 | |
| 		ksig, err := varInfer(v.key)
 | |
| 		if err != nil {
 | |
| 			continue
 | |
| 		}
 | |
| 		vsig, err := varInfer(v.val)
 | |
| 		if err != nil {
 | |
| 			continue
 | |
| 		}
 | |
| 		return Signature{"a{" + ksig.str + vsig.str + "}"}, nil
 | |
| 	}
 | |
| 	return Signature{}, fmt.Errorf("can't infer type for %q", n.String())
 | |
| }
 | |
| 
 | |
| func (n dictNode) String() string {
 | |
| 	s := "{"
 | |
| 	for i, v := range n.children {
 | |
| 		s += v.key.String() + ": " + v.val.String()
 | |
| 		if i != len(n.children)-1 {
 | |
| 			s += ", "
 | |
| 		}
 | |
| 	}
 | |
| 	return s + "}"
 | |
| }
 | |
| 
 | |
| func (n dictNode) Sigs() sigSet {
 | |
| 	r := sigSet{}
 | |
| 	for k := range n.kset {
 | |
| 		for v := range n.vset {
 | |
| 			sig := "a{" + k.str + v.str + "}"
 | |
| 			r[Signature{sig}] = true
 | |
| 		}
 | |
| 	}
 | |
| 	return r
 | |
| }
 | |
| 
 | |
| func (n dictNode) Value(sig Signature) (interface{}, error) {
 | |
| 	set := n.Sigs()
 | |
| 	if set.Empty() {
 | |
| 		// no type information -> empty dict
 | |
| 		return reflect.MakeMap(typeFor(sig.str)).Interface(), nil
 | |
| 	}
 | |
| 	if !set[sig] {
 | |
| 		return nil, varTypeError{n.String(), sig}
 | |
| 	}
 | |
| 	m := reflect.MakeMap(typeFor(sig.str))
 | |
| 	ksig := Signature{sig.str[2:3]}
 | |
| 	vsig := Signature{sig.str[3 : len(sig.str)-1]}
 | |
| 	for _, v := range n.children {
 | |
| 		kv, err := v.key.Value(ksig)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		vv, err := v.val.Value(vsig)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		m.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv))
 | |
| 	}
 | |
| 	return m.Interface(), nil
 | |
| }
 | |
| 
 | |
| func varMakeDictNode(p *varParser, sig Signature) (varNode, error) {
 | |
| 	var n dictNode
 | |
| 
 | |
| 	if sig.str != "" {
 | |
| 		if len(sig.str) < 5 {
 | |
| 			return nil, fmt.Errorf("invalid signature %q for dict type", sig)
 | |
| 		}
 | |
| 		ksig := Signature{string(sig.str[2])}
 | |
| 		vsig := Signature{sig.str[3 : len(sig.str)-1]}
 | |
| 		n.kset = sigSet{ksig: true}
 | |
| 		n.vset = sigSet{vsig: true}
 | |
| 	}
 | |
| 	if t := p.next(); t.typ == tokDictEnd {
 | |
| 		return n, nil
 | |
| 	} else {
 | |
| 		p.backup()
 | |
| 	}
 | |
| Loop:
 | |
| 	for {
 | |
| 		t := p.next()
 | |
| 		switch t.typ {
 | |
| 		case tokEOF:
 | |
| 			return nil, io.ErrUnexpectedEOF
 | |
| 		case tokError:
 | |
| 			return nil, errors.New(t.val)
 | |
| 		}
 | |
| 		p.backup()
 | |
| 		kn, err := varMakeNode(p)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if kset := kn.Sigs(); !kset.Empty() {
 | |
| 			if n.kset.Empty() {
 | |
| 				n.kset = kset
 | |
| 			} else {
 | |
| 				n.kset = kset.Intersect(n.kset)
 | |
| 				if n.kset.Empty() {
 | |
| 					return nil, fmt.Errorf("can't parse %q with given type information", kn.String())
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		t = p.next()
 | |
| 		switch t.typ {
 | |
| 		case tokEOF:
 | |
| 			return nil, io.ErrUnexpectedEOF
 | |
| 		case tokError:
 | |
| 			return nil, errors.New(t.val)
 | |
| 		case tokColon:
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("unexpected %q", t.val)
 | |
| 		}
 | |
| 		t = p.next()
 | |
| 		switch t.typ {
 | |
| 		case tokEOF:
 | |
| 			return nil, io.ErrUnexpectedEOF
 | |
| 		case tokError:
 | |
| 			return nil, errors.New(t.val)
 | |
| 		}
 | |
| 		p.backup()
 | |
| 		vn, err := varMakeNode(p)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if vset := vn.Sigs(); !vset.Empty() {
 | |
| 			if n.vset.Empty() {
 | |
| 				n.vset = vset
 | |
| 			} else {
 | |
| 				n.vset = n.vset.Intersect(vset)
 | |
| 				if n.vset.Empty() {
 | |
| 					return nil, fmt.Errorf("can't parse %q with given type information", vn.String())
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		n.children = append(n.children, dictEntry{kn, vn})
 | |
| 		t = p.next()
 | |
| 		switch t.typ {
 | |
| 		case tokEOF:
 | |
| 			return nil, io.ErrUnexpectedEOF
 | |
| 		case tokError:
 | |
| 			return nil, errors.New(t.val)
 | |
| 		case tokDictEnd:
 | |
| 			break Loop
 | |
| 		case tokComma:
 | |
| 			continue
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("unexpected %q", t.val)
 | |
| 		}
 | |
| 	}
 | |
| 	return n, nil
 | |
| }
 | |
| 
 | |
| type byteStringNode []byte
 | |
| 
 | |
| var byteStringSet = sigSet{
 | |
| 	Signature{"ay"}: true,
 | |
| }
 | |
| 
 | |
| func (byteStringNode) Infer() (Signature, error) {
 | |
| 	return Signature{"ay"}, nil
 | |
| }
 | |
| 
 | |
| func (b byteStringNode) String() string {
 | |
| 	return string(b)
 | |
| }
 | |
| 
 | |
| func (b byteStringNode) Sigs() sigSet {
 | |
| 	return byteStringSet
 | |
| }
 | |
| 
 | |
| func (b byteStringNode) Value(sig Signature) (interface{}, error) {
 | |
| 	if sig.str != "ay" {
 | |
| 		return nil, varTypeError{b.String(), sig}
 | |
| 	}
 | |
| 	return []byte(b), nil
 | |
| }
 | |
| 
 | |
| func varParseByteString(s string) ([]byte, error) {
 | |
| 	// quotes and b at start are guaranteed to be there
 | |
| 	b := make([]byte, 0, 1)
 | |
| 	s = s[2 : len(s)-1]
 | |
| 	for len(s) != 0 {
 | |
| 		c := s[0]
 | |
| 		s = s[1:]
 | |
| 		if c != '\\' {
 | |
| 			b = append(b, c)
 | |
| 			continue
 | |
| 		}
 | |
| 		c = s[0]
 | |
| 		s = s[1:]
 | |
| 		switch c {
 | |
| 		case 'a':
 | |
| 			b = append(b, 0x7)
 | |
| 		case 'b':
 | |
| 			b = append(b, 0x8)
 | |
| 		case 'f':
 | |
| 			b = append(b, 0xc)
 | |
| 		case 'n':
 | |
| 			b = append(b, '\n')
 | |
| 		case 'r':
 | |
| 			b = append(b, '\r')
 | |
| 		case 't':
 | |
| 			b = append(b, '\t')
 | |
| 		case 'x':
 | |
| 			if len(s) < 2 {
 | |
| 				return nil, errors.New("short escape")
 | |
| 			}
 | |
| 			n, err := strconv.ParseUint(s[:2], 16, 8)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			b = append(b, byte(n))
 | |
| 			s = s[2:]
 | |
| 		case '0':
 | |
| 			if len(s) < 3 {
 | |
| 				return nil, errors.New("short escape")
 | |
| 			}
 | |
| 			n, err := strconv.ParseUint(s[:3], 8, 8)
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			b = append(b, byte(n))
 | |
| 			s = s[3:]
 | |
| 		default:
 | |
| 			b = append(b, c)
 | |
| 		}
 | |
| 	}
 | |
| 	return append(b, 0), nil
 | |
| }
 | |
| 
 | |
| func varInfer(n varNode) (Signature, error) {
 | |
| 	if sig, ok := n.Sigs().Single(); ok {
 | |
| 		return sig, nil
 | |
| 	}
 | |
| 	return n.Infer()
 | |
| }
 |