tc_const.mx raw

   1  package main
   2  
   3  func (c *Checker) checkConstGroup(decls []*ConstDecl) {
   4  	var prevType Expr
   5  	var prevValues Expr
   6  	for i, d := range decls {
   7  		typ := d.Type
   8  		vals := d.Values
   9  		if vals == nil {
  10  			typ = prevType
  11  			vals = prevValues
  12  		} else {
  13  			prevType = typ
  14  			prevValues = vals
  15  		}
  16  		c.checkConstDeclAt(d, typ, vals, int64(i))
  17  	}
  18  }
  19  
  20  func (c *Checker) checkConstDeclAt(d *ConstDecl, typExpr Expr, valExpr Expr, iotaVal int64) {
  21  	var typ Type
  22  	if typExpr != nil {
  23  		typ = c.resolveTypeExpr(typExpr)
  24  	}
  25  
  26  	var vals []ConstVal
  27  	if valExpr != nil {
  28  		vals = c.evalConstExprList(valExpr, iotaVal)
  29  	}
  30  
  31  	for i, name := range d.NameList {
  32  		if name.Value == "_" {
  33  			continue
  34  		}
  35  		obj, ok := c.pkg.scope.Lookup(name.Value).(*TCConst)
  36  		if !ok {
  37  			continue
  38  		}
  39  		var cv ConstVal
  40  		if i < len(vals) {
  41  			cv = vals[i]
  42  		}
  43  		obj.val = cv
  44  		if c.pkg.path == "strconv" {
  45  			cvStr := "nil"
  46  			if cv != nil {
  47  				cvStr = cv.String()
  48  			}
  49  			writeStr(2, "  TC-CONST-SET name=" | name.Value | " val=" | cvStr | " pkg=" | c.pkg.path | "\n")
  50  		}
  51  		if typ != nil {
  52  			obj.typ = typ
  53  		} else if cv != nil {
  54  			obj.typ = untypedTypeOfCV(cv)
  55  		}
  56  		if c.info != nil {
  57  			c.info.Defs[name] = obj
  58  		}
  59  	}
  60  }
  61  
  62  func (c *Checker) evalConstExprList(e Expr, iotaVal int64) []ConstVal {
  63  	if l, ok := e.(*ListExpr); ok {
  64  		var out []ConstVal
  65  		for _, el := range l.ElemList {
  66  			v := c.evalConst(el, iotaVal)
  67  			out = append(out, v)
  68  		}
  69  		return out
  70  	}
  71  	v := c.evalConst(e, iotaVal)
  72  	return []ConstVal{v}
  73  }
  74  
  75  func (c *Checker) evalConst(e Expr, iotaVal int64) ConstVal {
  76  	if e == nil {
  77  		return nil
  78  	}
  79  	switch e := e.(type) {
  80  	case *BasicLit:
  81  		return evalBasicLitLocal(e)
  82  	case *Name:
  83  		if e.Value == "iota" {
  84  			return constInt{iotaVal}
  85  		}
  86  		_, obj := c.lookup(e.Value, c.pkg.scope)
  87  		if obj == nil {
  88  			writeStr(2, "  CONST-LOOKUP-FAIL name=" | e.Value | " pkg=" | c.pkg.path | "\n")
  89  			return nil
  90  		}
  91  		if k, ok := obj.(*TCConst); ok {
  92  			if k.val == nil {
  93  				writeStr(2, "  CONST-REF-NIL name=" | e.Value | " pkg=" | c.pkg.path | "\n")
  94  			}
  95  			return k.val
  96  		}
  97  		return nil
  98  	case *Operation:
  99  		return c.evalConstOp(e, iotaVal)
 100  	case *ParenExpr:
 101  		return c.evalConst(e.X, iotaVal)
 102  	case *CallExpr:
 103  		if id, ok := e.Fun.(*Name); ok && id.Value == "len" && len(e.ArgList) == 1 {
 104  			if lit, ok := e.ArgList[0].(*BasicLit); ok && lit.Kind == StringLit {
 105  				lv := evalBasicLitLocal(lit)
 106  				if cs, ok := lv.(constStr); ok {
 107  					return constInt{int64(len(cs.s))}
 108  				}
 109  			}
 110  		}
 111  		if sel, ok := e.Fun.(*SelectorExpr); ok {
 112  			if pkg, ok := sel.X.(*Name); ok && pkg.Value == "unsafe" {
 113  				switch sel.Sel.Value {
 114  				case "Sizeof", "Alignof", "Offsetof":
 115  					return constInt{8}
 116  				}
 117  			}
 118  		}
 119  		if len(e.ArgList) != 1 {
 120  			return nil
 121  		}
 122  		inner := c.evalConst(e.ArgList[0], iotaVal)
 123  		if inner == nil {
 124  			return nil
 125  		}
 126  		targetType := c.resolveTypeExpr(e.Fun)
 127  		if targetType == nil {
 128  			funName := "?"
 129  			if id, ok2 := e.Fun.(*Name); ok2 {
 130  				funName = id.Value
 131  			}
 132  			writeStr(2, "  CONST-CONV-FAIL fun=" | funName | " pkg=" | c.pkg.path | "\n")
 133  			return nil
 134  		}
 135  		return convertConstLocal(inner, targetType)
 136  	}
 137  	return nil
 138  }
 139  
 140  func evalBasicLitLocal(e *BasicLit) ConstVal {
 141  	switch e.Kind {
 142  	case IntLit:
 143  		n := parseIntLocal(e.Value)
 144  		return constInt{n}
 145  	case FloatLit:
 146  		f := parseFloatLocal(e.Value)
 147  		return constFloat{v: f, lit: e.Value}
 148  	case StringLit:
 149  		s := interpStringLocal(e.Value)
 150  		return constStr{s}
 151  	case RuneLit:
 152  		s := interpStringLocal(e.Value)
 153  		if len(s) > 0 {
 154  			return constInt{int64(decodeFirstRune(s))}
 155  		}
 156  		return constInt{0}
 157  	}
 158  	return nil
 159  }
 160  
 161  func parseIntLocal(s string) int64 {
 162  	if len(s) == 0 {
 163  		return 0
 164  	}
 165  	neg := false
 166  	i := 0
 167  	if s[0] == '-' {
 168  		neg = true
 169  		i = 1
 170  	} else if s[0] == '+' {
 171  		i = 1
 172  	}
 173  	base := int64(10)
 174  	if i < len(s)-1 && s[i] == '0' {
 175  		c := s[i+1]
 176  		if c == 'x' || c == 'X' {
 177  			base = 16
 178  			i += 2
 179  		} else if c == 'o' || c == 'O' {
 180  			base = 8
 181  			i += 2
 182  		} else if c == 'b' || c == 'B' {
 183  			base = 2
 184  			i += 2
 185  		} else if c >= '0' && c <= '7' {
 186  			base = 8
 187  			i += 1
 188  		}
 189  	}
 190  	var n int64
 191  	for ; i < len(s); i++ {
 192  		ch := s[i]
 193  		if ch == '_' {
 194  			continue
 195  		}
 196  		var d int64
 197  		if ch >= '0' && ch <= '9' {
 198  			d = int64(ch - '0')
 199  		} else if ch >= 'a' && ch <= 'f' {
 200  			d = int64(ch-'a') + 10
 201  		} else if ch >= 'A' && ch <= 'F' {
 202  			d = int64(ch-'A') + 10
 203  		} else {
 204  			break
 205  		}
 206  		n = n*base + d
 207  	}
 208  	if neg {
 209  		return -n
 210  	}
 211  	return n
 212  }
 213  
 214  func parseFloatLocal(s string) float64 {
 215  	if len(s) == 0 {
 216  		return 0.0
 217  	}
 218  	neg := false
 219  	i := 0
 220  	if s[0] == '-' {
 221  		neg = true
 222  		i = 1
 223  	} else if s[0] == '+' {
 224  		i = 1
 225  	}
 226  	var intPart float64
 227  	for ; i < len(s); i++ {
 228  		ch := s[i]
 229  		if ch == '_' {
 230  			continue
 231  		}
 232  		if ch < '0' || ch > '9' {
 233  			break
 234  		}
 235  		intPart = intPart*10.0 + float64(ch-'0')
 236  	}
 237  	var fracPart float64
 238  	if i < len(s) && s[i] == '.' {
 239  		i++
 240  		divisor := 10.0
 241  		for ; i < len(s); i++ {
 242  			ch := s[i]
 243  			if ch == '_' {
 244  				continue
 245  			}
 246  			if ch < '0' || ch > '9' {
 247  				break
 248  			}
 249  			fracPart = fracPart + float64(ch-'0')/divisor
 250  			divisor = divisor * 10.0
 251  		}
 252  	}
 253  	result := intPart + fracPart
 254  	if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
 255  		i++
 256  		expNeg := false
 257  		if i < len(s) && s[i] == '-' {
 258  			expNeg = true
 259  			i++
 260  		} else if i < len(s) && s[i] == '+' {
 261  			i++
 262  		}
 263  		var exp int
 264  		for ; i < len(s); i++ {
 265  			ch := s[i]
 266  			if ch < '0' || ch > '9' {
 267  				break
 268  			}
 269  			exp = exp*10 + int(ch-'0')
 270  		}
 271  		mul := 1.0
 272  		for j := 0; j < exp; j++ {
 273  			mul = mul * 10.0
 274  		}
 275  		if expNeg {
 276  			result = result / mul
 277  		} else {
 278  			result = result * mul
 279  		}
 280  	}
 281  	if neg {
 282  		return -result
 283  	}
 284  	return result
 285  }
 286  
 287  func interpStringLocal(s string) string {
 288  	if len(s) < 2 {
 289  		return s
 290  	}
 291  	if s[0] == '`' {
 292  		return s[1 : len(s)-1]
 293  	}
 294  	quote := s[0]
 295  	if quote != '"' && quote != '\'' {
 296  		return s
 297  	}
 298  	s = s[1 : len(s)-1]
 299  	hasEsc := false
 300  	for i := 0; i < len(s); i++ {
 301  		if s[i] == '\\' {
 302  			hasEsc = true
 303  			break
 304  		}
 305  	}
 306  	if !hasEsc {
 307  		return s
 308  	}
 309  	var buf []byte
 310  	for i := 0; i < len(s); i++ {
 311  		if s[i] != '\\' {
 312  			buf = append(buf, s[i])
 313  			continue
 314  		}
 315  		i++
 316  		if i >= len(s) {
 317  			break
 318  		}
 319  		switch s[i] {
 320  		case 'n':
 321  			buf = append(buf, '\n')
 322  		case 't':
 323  			buf = append(buf, '\t')
 324  		case 'r':
 325  			buf = append(buf, '\r')
 326  		case '\\':
 327  			buf = append(buf, '\\')
 328  		case '\'':
 329  			buf = append(buf, '\'')
 330  		case '"':
 331  			buf = append(buf, '"')
 332  		case '0':
 333  			buf = append(buf, 0)
 334  		case 'a':
 335  			buf = append(buf, '\a')
 336  		case 'b':
 337  			buf = append(buf, '\b')
 338  		case 'f':
 339  			buf = append(buf, '\f')
 340  		case 'v':
 341  			buf = append(buf, '\v')
 342  		case 'x':
 343  			if i+2 < len(s) {
 344  				h := hexDigit(s[i+1])*16 + hexDigit(s[i+2])
 345  				buf = append(buf, byte(h))
 346  				i += 2
 347  			}
 348  		case 'u':
 349  			if i+4 < len(s) {
 350  				r := rune(hexDigit(s[i+1]))*4096 + rune(hexDigit(s[i+2]))*256 + rune(hexDigit(s[i+3]))*16 + rune(hexDigit(s[i+4]))
 351  				buf = appendRuneUTF8(buf, r)
 352  				i += 4
 353  			}
 354  		case 'U':
 355  			if i+8 < len(s) {
 356  				var r rune
 357  				for j := 1; j <= 8; j++ {
 358  					r = r*16 + rune(hexDigit(s[i+j]))
 359  				}
 360  				buf = appendRuneUTF8(buf, r)
 361  				i += 8
 362  			}
 363  		default:
 364  			if s[i] >= '0' && s[i] <= '7' {
 365  				v := int(s[i] - '0')
 366  				if i+1 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' {
 367  					v = v*8 + int(s[i+1]-'0')
 368  					i++
 369  					if i+1 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' {
 370  						v = v*8 + int(s[i+1]-'0')
 371  						i++
 372  					}
 373  				}
 374  				buf = append(buf, byte(v))
 375  			} else {
 376  				buf = append(buf, s[i])
 377  			}
 378  		}
 379  	}
 380  	return string(buf)
 381  }
 382  
 383  func hexDigit(c byte) int {
 384  	if c >= '0' && c <= '9' {
 385  		return int(c - '0')
 386  	}
 387  	if c >= 'a' && c <= 'f' {
 388  		return int(c-'a') + 10
 389  	}
 390  	if c >= 'A' && c <= 'F' {
 391  		return int(c-'A') + 10
 392  	}
 393  	return 0
 394  }
 395  
 396  func appendRuneUTF8(buf []byte, r rune) []byte {
 397  	if r < 0x80 {
 398  		return append(buf, byte(r))
 399  	}
 400  	if r < 0x800 {
 401  		buf = append(buf, byte(0xC0|(r>>6)))
 402  		return append(buf, byte(0x80|(r&0x3F)))
 403  	}
 404  	if r < 0x10000 {
 405  		buf = append(buf, byte(0xE0|(r>>12)))
 406  		buf = append(buf, byte(0x80|((r>>6)&0x3F)))
 407  		return append(buf, byte(0x80|(r&0x3F)))
 408  	}
 409  	buf = append(buf, byte(0xF0|(r>>18)))
 410  	buf = append(buf, byte(0x80|((r>>12)&0x3F)))
 411  	buf = append(buf, byte(0x80|((r>>6)&0x3F)))
 412  	return append(buf, byte(0x80|(r&0x3F)))
 413  }
 414  
 415  func (c *Checker) evalConstOp(e *Operation, iotaVal int64) ConstVal {
 416  	if e.Y == nil {
 417  		x := c.evalConst(e.X, iotaVal)
 418  		if x == nil {
 419  			writeStr(2, "  CONSTOP-UNARY-NIL-X pkg=" | c.pkg.path | "\n")
 420  			return nil
 421  		}
 422  		r := evalUnaryLocal(e.Op, x)
 423  		if r == nil {
 424  			writeStr(2, "  CONSTOP-UNARY-NIL-R pkg=" | c.pkg.path | " x=" | x.String() | "\n")
 425  		}
 426  		return r
 427  	}
 428  	x := c.evalConst(e.X, iotaVal)
 429  	y := c.evalConst(e.Y, iotaVal)
 430  	if x == nil || y == nil {
 431  		return nil
 432  	}
 433  	return evalBinaryLocal(e.Op, x, y)
 434  }
 435  
 436  func evalUnaryLocal(op Operator, x ConstVal) ConstVal {
 437  	switch op {
 438  	case Add:
 439  		return x
 440  	case Sub:
 441  		if ci, ok := x.(constInt); ok {
 442  			return constInt{-ci.v}
 443  		}
 444  		if cf, ok := x.(constFloat); ok {
 445  			neg := ""
 446  			if cf.lit != "" {
 447  				neg = "-" + cf.lit
 448  			}
 449  			return constFloat{v: -cf.v, lit: neg}
 450  		}
 451  	case Xor:
 452  		if ci, ok := x.(constInt); ok {
 453  			return constInt{^ci.v}
 454  		}
 455  	case Not:
 456  		if cb, ok := x.(constBool); ok {
 457  			return constBool{!cb.v}
 458  		}
 459  	}
 460  	return nil
 461  }
 462  
 463  func evalBinaryLocal(op Operator, x ConstVal, y ConstVal) ConstVal {
 464  	switch op {
 465  	case Add:
 466  		if xi, ok := x.(constInt); ok {
 467  			return constInt{xi.v + cvInt(y)}
 468  		}
 469  		if xf, ok := x.(constFloat); ok {
 470  			return constFloat{v: xf.v + cvFloat(y)}
 471  		}
 472  		if xs, ok := x.(constStr); ok {
 473  			return constStr{xs.s + cvStr(y)}
 474  		}
 475  	case Sub:
 476  		if xi, ok := x.(constInt); ok {
 477  			return constInt{xi.v - cvInt(y)}
 478  		}
 479  		if xf, ok := x.(constFloat); ok {
 480  			return constFloat{v: xf.v - cvFloat(y)}
 481  		}
 482  	case Mul:
 483  		if xi, ok := x.(constInt); ok {
 484  			return constInt{xi.v * cvInt(y)}
 485  		}
 486  		if xf, ok := x.(constFloat); ok {
 487  			return constFloat{v: xf.v * cvFloat(y)}
 488  		}
 489  	case Div:
 490  		if xi, ok := x.(constInt); ok {
 491  			d := cvInt(y)
 492  			if d == 0 {
 493  				return constInt{0}
 494  			}
 495  			return constInt{xi.v / d}
 496  		}
 497  		if xf, ok := x.(constFloat); ok {
 498  			d := cvFloat(y)
 499  			if d == 0.0 {
 500  				return constFloat{v: 0.0}
 501  			}
 502  			return constFloat{v: xf.v / d}
 503  		}
 504  	case Rem:
 505  		if xi, ok := x.(constInt); ok {
 506  			d := cvInt(y)
 507  			if d == 0 {
 508  				return constInt{0}
 509  			}
 510  			return constInt{xi.v % d}
 511  		}
 512  	case And:
 513  		if xi, ok := x.(constInt); ok {
 514  			return constInt{xi.v & cvInt(y)}
 515  		}
 516  	case Or:
 517  		if xi, ok := x.(constInt); ok {
 518  			return constInt{xi.v | cvInt(y)}
 519  		}
 520  		if xs, ok := x.(constStr); ok {
 521  			return constStr{xs.s + cvStr(y)}
 522  		}
 523  	case Xor:
 524  		if xi, ok := x.(constInt); ok {
 525  			return constInt{xi.v ^ cvInt(y)}
 526  		}
 527  	case Shl:
 528  		if xi, ok := x.(constInt); ok {
 529  			shift := uint(cvInt(y))
 530  			return constInt{xi.v << shift}
 531  		}
 532  	case Shr:
 533  		if xi, ok := x.(constInt); ok {
 534  			shift := uint(cvInt(y))
 535  			return constInt{xi.v >> shift}
 536  		}
 537  	case AndNot:
 538  		if xi, ok := x.(constInt); ok {
 539  			return constInt{xi.v &^ cvInt(y)}
 540  		}
 541  	case Eql:
 542  		return constBool{constEqual(x, y)}
 543  	case Neq:
 544  		return constBool{!constEqual(x, y)}
 545  	case Lss:
 546  		return constBool{constLess(x, y)}
 547  	case Leq:
 548  		return constBool{constLess(x, y) || constEqual(x, y)}
 549  	case Gtr:
 550  		return constBool{constLess(y, x)}
 551  	case Geq:
 552  		return constBool{constLess(y, x) || constEqual(x, y)}
 553  	}
 554  	return nil
 555  }
 556  
 557  func constEqual(x ConstVal, y ConstVal) bool {
 558  	if xi, ok := x.(constInt); ok {
 559  		return xi.v == cvInt(y)
 560  	}
 561  	if xf, ok := x.(constFloat); ok {
 562  		return xf.v == cvFloat(y)
 563  	}
 564  	if xs, ok := x.(constStr); ok {
 565  		return xs.s == cvStr(y)
 566  	}
 567  	if xb, ok := x.(constBool); ok {
 568  		if yb, ok := y.(constBool); ok {
 569  			return xb.v == yb.v
 570  		}
 571  	}
 572  	return false
 573  }
 574  
 575  func constLess(x ConstVal, y ConstVal) bool {
 576  	if xi, ok := x.(constInt); ok {
 577  		return xi.v < cvInt(y)
 578  	}
 579  	if xf, ok := x.(constFloat); ok {
 580  		return xf.v < cvFloat(y)
 581  	}
 582  	if xs, ok := x.(constStr); ok {
 583  		return xs.s < cvStr(y)
 584  	}
 585  	return false
 586  }
 587  
 588  func convertConstLocal(v ConstVal, target Type) ConstVal {
 589  	b, ok := safeUnderlying(target).(*Basic)
 590  	if !ok {
 591  		return v
 592  	}
 593  	switch {
 594  	case b.info&IsInteger != 0:
 595  		iv := cvInt(v)
 596  		return constInt{iv}
 597  	case b.info&IsFloat != 0:
 598  		fv := cvFloat(v)
 599  		return constFloat{v: fv}
 600  	case b.info&IsString != 0:
 601  		if cvKind(v) == 3 {
 602  			n := cvInt(v)
 603  			return constStr{runeToStr(rune(n))}
 604  		}
 605  		return v
 606  	}
 607  	return v
 608  }
 609  
 610  func untypedTypeOfCV(v ConstVal) Type {
 611  	switch cvKind(v) {
 612  	case 1:
 613  		return Typ[UntypedBool]
 614  	case 3:
 615  		return Typ[UntypedInt]
 616  	case 4:
 617  		return Typ[UntypedFloat]
 618  	case 2:
 619  		return Typ[UntypedString]
 620  	}
 621  	return nil
 622  }
 623  
 624  func cvKind(val ConstVal) int {
 625  	switch val.(type) {
 626  	case constBool:
 627  		return 1
 628  	case constStr:
 629  		return 2
 630  	case constInt:
 631  		return 3
 632  	case constFloat:
 633  		return 4
 634  	case constNil:
 635  		return 0
 636  	}
 637  	return 0
 638  }
 639  
 640  func constInt64CV(v ConstVal) (int64, bool) {
 641  	if v == nil || cvKind(v) != 3 {
 642  		return 0, false
 643  	}
 644  	if ci, ok := v.(constInt); ok {
 645  		return ci.v, true
 646  	}
 647  	return 0, false
 648  }
 649  
 650  func (c *Checker) IsConstExpr(e Expr) bool {
 651  	return c.evalConst(e, 0) != nil
 652  }
 653  
 654  func (c *Checker) evalArrayLen(e Expr) int64 {
 655  	v := c.evalConst(e, 0)
 656  	if v == nil {
 657  		return 0
 658  	}
 659  	n, _ := constInt64CV(v)
 660  	return n
 661  }
 662  
 663  func cvInt(v ConstVal) int64 {
 664  	if ci, ok := v.(constInt); ok {
 665  		return ci.v
 666  	}
 667  	if cf, ok := v.(constFloat); ok {
 668  		return int64(cf.v)
 669  	}
 670  	return 0
 671  }
 672  
 673  func cvFloat(v ConstVal) float64 {
 674  	if cf, ok := v.(constFloat); ok {
 675  		return cf.v
 676  	}
 677  	if ci, ok := v.(constInt); ok {
 678  		return float64(ci.v)
 679  	}
 680  	return 0
 681  }
 682  
 683  func cvStr(v ConstVal) string {
 684  	if cs, ok := v.(constStr); ok {
 685  		return cs.s
 686  	}
 687  	return ""
 688  }
 689  
 690  func decodeFirstRune(s string) int32 {
 691  	b := s[0]
 692  	if b < 0x80 {
 693  		return int32(b)
 694  	}
 695  	if b < 0xC0 {
 696  		return int32(b)
 697  	}
 698  	if b < 0xE0 && len(s) >= 2 {
 699  		return int32(b&0x1F)<<6 | int32(s[1]&0x3F)
 700  	}
 701  	if b < 0xF0 && len(s) >= 3 {
 702  		return int32(b&0x0F)<<12 | int32(s[1]&0x3F)<<6 | int32(s[2]&0x3F)
 703  	}
 704  	if len(s) >= 4 {
 705  		return int32(b&0x07)<<18 | int32(s[1]&0x3F)<<12 | int32(s[2]&0x3F)<<6 | int32(s[3]&0x3F)
 706  	}
 707  	return int32(b)
 708  }
 709  
 710  func runeToStr(r rune) string {
 711  	if r < 0 || r > 0x10FFFF {
 712  		r = 0xFFFD
 713  	}
 714  	var buf [4]byte
 715  	if r <= 0x7F {
 716  		buf[0] = byte(r)
 717  		return string(buf[:1])
 718  	}
 719  	if r <= 0x7FF {
 720  		buf[0] = byte(0xC0 | (r >> 6))
 721  		buf[1] = byte(0x80 | (r & 0x3F))
 722  		return string(buf[:2])
 723  	}
 724  	if r <= 0xFFFF {
 725  		buf[0] = byte(0xE0 | (r >> 12))
 726  		buf[1] = byte(0x80 | ((r >> 6) & 0x3F))
 727  		buf[2] = byte(0x80 | (r & 0x3F))
 728  		return string(buf[:3])
 729  	}
 730  	buf[0] = byte(0xF0 | (r >> 18))
 731  	buf[1] = byte(0x80 | ((r >> 12) & 0x3F))
 732  	buf[2] = byte(0x80 | ((r >> 6) & 0x3F))
 733  	buf[3] = byte(0x80 | (r & 0x3F))
 734  	return string(buf[:4])
 735  }
 736