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()
 | 
						|
}
 |