tc_const.mx raw
1 package types
2
3 import (
4 "git.smesh.lol/moxie/pkg/mxutil"
5 "git.smesh.lol/moxie/pkg/syntax"
6 "git.smesh.lol/moxie/pkg/token"
7 )
8
9 func (c *Checker) checkConstGroup(decls []*syntax.ConstDecl) {
10 var prevType syntax.Expr
11 var prevValues syntax.Expr
12 for i, d := range decls {
13 typ := d.Type
14 vals := d.Values
15 if vals == nil {
16 typ = prevType
17 vals = prevValues
18 } else {
19 prevType = typ
20 prevValues = vals
21 }
22 c.checkConstDeclAt(d, typ, vals, int64(i))
23 }
24 }
25
26 func (c *Checker) checkConstDeclAt(d *syntax.ConstDecl, typExpr syntax.Expr, valExpr syntax.Expr, iotaVal int64) {
27 var typ Type
28 if typExpr != nil {
29 typ = c.resolveTypeExpr(typExpr)
30 }
31
32 var vals []ConstVal
33 if valExpr != nil {
34 vals = c.evalConstExprList(valExpr, iotaVal)
35 }
36
37 // When no explicit type and the value is a type conversion (CallExpr
38 // with a type name as Fun), infer the type from the conversion target.
39 // e.g. const EOF = errors.Const("EOF") -> type is errors.Const
40 var inferredTypes []Type
41 if typ == nil && valExpr != nil {
42 inferredTypes = c.inferConstTypeList(valExpr)
43 }
44
45 for i, name := range d.NameList {
46 if name.Value == "_" {
47 continue
48 }
49 obj, ok := c.pkg.Scope.Lookup(name.Value).(*TCConst)
50 if !ok {
51 continue
52 }
53 var cv ConstVal
54 if i < len(vals) {
55 cv = vals[i]
56 }
57 obj.Val = cv
58 if typ != nil {
59 obj.Typ = typ
60 } else if i < len(inferredTypes) && inferredTypes[i] != nil {
61 obj.Typ = inferredTypes[i]
62 } else if cv != nil {
63 obj.Typ = UntypedTypeOfCV(cv)
64 }
65 if c.info != nil {
66 c.info.Defs[name] = obj
67 }
68 }
69 }
70
71 func (c *Checker) inferConstTypeList(e syntax.Expr) (ts []Type) {
72 if l, ok := e.(*syntax.ListExpr); ok {
73 var out []Type
74 for _, el := range l.ElemList {
75 push(out, c.inferConstType(el))
76 }
77 return out
78 }
79 return []Type{c.inferConstType(e)}
80 }
81
82 func (c *Checker) inferConstType(e syntax.Expr) (t Type) {
83 if e == nil {
84 return nil
85 }
86 ce, ok := e.(*syntax.CallExpr)
87 if !ok {
88 return nil
89 }
90 if len(ce.ArgList) != 1 {
91 return nil
92 }
93 return c.resolveTypeExpr(ce.Fun)
94 }
95
96 func (c *Checker) evalConstExprList(e syntax.Expr, iotaVal int64) (cs []ConstVal) {
97 if l, ok := e.(*syntax.ListExpr); ok {
98 var out []ConstVal
99 for _, el := range l.ElemList {
100 cv := c.evalConst(el, iotaVal)
101 push(out, cv)
102 }
103 return out
104 }
105 v := c.evalConst(e, iotaVal)
106 return []ConstVal{v}
107 }
108
109 func (c *Checker) evalConst(e syntax.Expr, iotaVal int64) (cv ConstVal) {
110 if e == nil {
111 return nil
112 }
113 switch ex := e.(type) {
114 case *syntax.BasicLit:
115 return EvalBasicLitLocal(ex)
116 case *syntax.Name:
117 if ex.Value == "iota" {
118 return &ConstInt{V:iotaVal}
119 }
120 var obj Object
121 if c.localScope != nil {
122 _, obj = c.localScope.LookupParent(ex.Value)
123 }
124 if obj == nil {
125 _, obj = c.lookup(ex.Value, c.pkg.Scope)
126 }
127 if obj == nil {
128 mxutil.WriteStr(2, " CONST-LOOKUP-FAIL name=" | ex.Value | " pkg=" | c.pkg.Path | "\n")
129 return nil
130 }
131 if k, matched := obj.(*TCConst); matched {
132 if k.Val == nil {
133 mxutil.WriteStr(2, " CONST-REF-NIL name=" | ex.Value | " pkg=" | c.pkg.Path | "\n")
134 }
135 return k.Val
136 }
137 return nil
138 case *syntax.SelectorExpr:
139 if pkgName, matched := ex.X.(*syntax.Name); matched {
140 if _, imp := c.lookupType(pkgName.Value); imp != nil {
141 if pn, ok2 := imp.(*PkgName); ok2 && pn.Imported != nil {
142 if obj := pn.Imported.Scope.Lookup(ex.Sel.Value); obj != nil {
143 if k, ok3 := obj.(*TCConst); ok3 {
144 return k.Val
145 }
146 }
147 }
148 }
149 }
150 return nil
151 case *syntax.Operation:
152 return c.evalConstOp(ex, iotaVal)
153 case *syntax.ParenExpr:
154 return c.evalConst(ex.X, iotaVal)
155 case *syntax.CallExpr:
156 if id, matched := ex.Fun.(*syntax.Name); matched && id.Value == "len" && len(ex.ArgList) == 1 {
157 if lit, matched2 := ex.ArgList[0].(*syntax.BasicLit); matched2 && lit.Kind == token.StringLit {
158 lv := EvalBasicLitLocal(lit)
159 if cs2, matched3 := lv.(*ConstStr); matched3 {
160 return &ConstInt{V:int64(len(cs2.S))}
161 }
162 }
163 lenArg := c.evalConst(ex.ArgList[0], iotaVal)
164 if cs2, matched2 := lenArg.(*ConstStr); matched2 {
165 return &ConstInt{V:int64(len(cs2.S))}
166 }
167 }
168 if sel, matched := ex.Fun.(*syntax.SelectorExpr); matched {
169 if pkg, matched2 := sel.X.(*syntax.Name); matched2 && pkg.Value == "unsafe" {
170 switch sel.Sel.Value {
171 case "Sizeof", "Alignof", "Offsetof":
172 return &ConstInt{V:8}
173 }
174 }
175 }
176 if len(ex.ArgList) != 1 {
177 return nil
178 }
179 arg := c.evalConst(ex.ArgList[0], iotaVal)
180 if arg == nil {
181 return nil
182 }
183 targetType := c.resolveTypeExpr(ex.Fun)
184 if targetType == nil {
185 funName := "?"
186 if id, ok2 := ex.Fun.(*syntax.Name); ok2 {
187 funName = id.Value
188 }
189 mxutil.WriteStr(2, " CONST-CONV-FAIL fun=" | funName | " pkg=" | c.pkg.Path | "\n")
190 return nil
191 }
192 return ConvertConstLocal(arg, targetType)
193 }
194 return nil
195 }
196
197 func EvalBasicLitLocal(e *syntax.BasicLit) (c ConstVal) {
198 switch e.Kind {
199 case token.IntLit:
200 n := ParseIntLocal(e.Value)
201 return &ConstInt{V:n}
202 case token.FloatLit:
203 f := parseFloatLocal(e.Value)
204 return &ConstFloat{V:f, Lit:e.Value}
205 case token.StringLit:
206 s := interpStringLocal(e.Value)
207 return &ConstStr{S:s}
208 case token.RuneLit:
209 s := interpStringLocal(e.Value)
210 if len(s) > 0 {
211 return &ConstInt{V:int64(decodeFirstRune(s))}
212 }
213 return &ConstInt{V:0}
214 }
215 return nil
216 }
217
218 func ParseIntLocal(s string) (n int64) {
219 if len(s) == 0 {
220 return 0
221 }
222 neg := false
223 i := 0
224 if s[0] == '-' {
225 neg = true
226 i = 1
227 } else if s[0] == '+' {
228 i = 1
229 }
230 base := int64(10)
231 if i < len(s)-1 && s[i] == '0' {
232 c := s[i+1]
233 if c == 'x' || c == 'X' {
234 base = 16
235 i += 2
236 } else if c == 'o' || c == 'O' {
237 base = 8
238 i += 2
239 } else if c == 'b' || c == 'B' {
240 base = 2
241 i += 2
242 } else if c >= '0' && c <= '7' {
243 base = 8
244 i += 1
245 }
246 }
247 for ; i < len(s); i++ {
248 ch := s[i]
249 if ch == '_' {
250 continue
251 }
252 var d int64
253 if ch >= '0' && ch <= '9' {
254 d = int64(ch - '0')
255 } else if ch >= 'a' && ch <= 'f' {
256 d = int64(ch-'a') + 10
257 } else if ch >= 'A' && ch <= 'F' {
258 d = int64(ch-'A') + 10
259 } else {
260 break
261 }
262 n = n*base + d
263 }
264 if neg {
265 return -n
266 }
267 return n
268 }
269
270 func parseFloatLocal(s string) (f float64) {
271 if len(s) == 0 {
272 return 0.0
273 }
274 neg := false
275 i := 0
276 if s[0] == '-' {
277 neg = true
278 i = 1
279 } else if s[0] == '+' {
280 i = 1
281 }
282 var intPart float64
283 for ; i < len(s); i++ {
284 ch := s[i]
285 if ch == '_' {
286 continue
287 }
288 if ch < '0' || ch > '9' {
289 break
290 }
291 intPart = intPart*10.0 + float64(ch-'0')
292 }
293 var fracPart float64
294 if i < len(s) && s[i] == '.' {
295 i++
296 divisor := 10.0
297 for ; i < len(s); i++ {
298 ch := s[i]
299 if ch == '_' {
300 continue
301 }
302 if ch < '0' || ch > '9' {
303 break
304 }
305 fracPart = fracPart + float64(ch-'0')/divisor
306 divisor = divisor * 10.0
307 }
308 }
309 result := intPart + fracPart
310 if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
311 i++
312 expNeg := false
313 if i < len(s) && s[i] == '-' {
314 expNeg = true
315 i++
316 } else if i < len(s) && s[i] == '+' {
317 i++
318 }
319 var exp int32
320 for ; i < len(s); i++ {
321 ch := s[i]
322 if ch < '0' || ch > '9' {
323 break
324 }
325 exp = exp*10 + int32(ch-'0')
326 }
327 mul := 1.0
328 for j := 0; j < exp; j++ {
329 mul = mul * 10.0
330 }
331 if expNeg {
332 result = result / mul
333 } else {
334 result = result * mul
335 }
336 }
337 if neg {
338 return -result
339 }
340 return result
341 }
342
343 func interpStringLocal(s string) (sv string) {
344 if len(s) < 2 {
345 return s
346 }
347 if s[0] == '`' {
348 return s[1 : len(s)-1]
349 }
350 quote := s[0]
351 if quote != '"' && quote != '\'' {
352 return s
353 }
354 s = s[1 : len(s)-1]
355 hasEsc := false
356 for i := 0; i < len(s); i++ {
357 if s[i] == '\\' {
358 hasEsc = true
359 break
360 }
361 }
362 if !hasEsc {
363 return s
364 }
365 var buf []byte
366 for i := 0; i < len(s); i++ {
367 if s[i] != '\\' {
368 push(buf, s[i])
369 continue
370 }
371 i++
372 if i >= len(s) {
373 break
374 }
375 switch s[i] {
376 case 'n':
377 push(buf, '\n')
378 case 't':
379 push(buf, '\t')
380 case 'r':
381 push(buf, '\r')
382 case '\\':
383 push(buf, '\\')
384 case '\'':
385 push(buf, '\'')
386 case '"':
387 push(buf, '"')
388 case '0':
389 push(buf, 0)
390 case 'a':
391 push(buf, '\a')
392 case 'b':
393 push(buf, '\b')
394 case 'f':
395 push(buf, '\f')
396 case 'v':
397 push(buf, '\v')
398 case 'x':
399 if i+2 < len(s) {
400 h := hexDigit(s[i+1])*16 + hexDigit(s[i+2])
401 push(buf, byte(h))
402 i += 2
403 }
404 case 'u':
405 if i+4 < len(s) {
406 r := rune(hexDigit(s[i+1]))*4096 + rune(hexDigit(s[i+2]))*256 + rune(hexDigit(s[i+3]))*16 + rune(hexDigit(s[i+4]))
407 buf = appendRuneUTF8(buf, r)
408 i += 4
409 }
410 case 'U':
411 if i+8 < len(s) {
412 var r rune
413 for j := 1; j <= 8; j++ {
414 r = r*16 + rune(hexDigit(s[i+j]))
415 }
416 buf = appendRuneUTF8(buf, r)
417 i += 8
418 }
419 default:
420 if s[i] >= '0' && s[i] <= '7' {
421 v := int32(s[i] - '0')
422 if i+1 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' {
423 v = v*8 + int32(s[i+1]-'0')
424 i++
425 if i+1 < len(s) && s[i+1] >= '0' && s[i+1] <= '7' {
426 v = v*8 + int32(s[i+1]-'0')
427 i++
428 }
429 }
430 push(buf, byte(v))
431 } else {
432 push(buf, s[i])
433 }
434 }
435 }
436 return string(buf)
437 }
438
439 func hexDigit(c byte) (n int32) {
440 if c >= '0' && c <= '9' {
441 return int32(c - '0')
442 }
443 if c >= 'a' && c <= 'f' {
444 return int32(c-'a') + 10
445 }
446 if c >= 'A' && c <= 'F' {
447 return int32(c-'A') + 10
448 }
449 return 0
450 }
451
452 func appendRuneUTF8(buf []byte, r rune) (buf2 []byte) {
453 if r < 0x80 {
454 push(buf, byte(r))
455 return buf
456 }
457 if r < 0x800 {
458 push(buf, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F)))
459 return buf
460 }
461 if r < 0x10000 {
462 push(buf, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
463 return buf
464 }
465 push(buf, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
466 return buf
467 }
468
469 func (c *Checker) evalConstOp(e *syntax.Operation, iotaVal int64) (cv ConstVal) {
470 if e.Y == nil {
471 xu := c.evalConst(e.X, iotaVal)
472 if xu == nil {
473 mxutil.WriteStr(2, " CONSTOP-UNARY-NIL-X pkg=" | c.pkg.Path | "\n")
474 return nil
475 }
476 r := EvalUnaryLocal(e.Op, xu)
477 if r == nil {
478 mxutil.WriteStr(2, " CONSTOP-UNARY-NIL-R pkg=" | c.pkg.Path | " x=" | xu.String() | "\n")
479 }
480 // ^x on a typed operand must be masked to the operand's width: the
481 // arbitrary-precision result (-x-1) is only correct for untyped
482 // constants. Without this, uint64(^someUint32Const) sign-extends
483 // the stored negative value to 0xffffffffXXXXXXXX.
484 if r != nil && e.Op == token.Xor {
485 if b := c.constExprBasic(e.X); b != nil {
486 r = MaskConstToBasic(r, b)
487 }
488 }
489 return r
490 }
491 x := c.evalConst(e.X, iotaVal)
492 y := c.evalConst(e.Y, iotaVal)
493 if x == nil || y == nil {
494 return nil
495 }
496 return EvalBinaryLocal(e.Op, x, y)
497 }
498
499 func EvalUnaryLocal(op token.Operator, x ConstVal) (c ConstVal) {
500 switch op {
501 case token.Add:
502 return x
503 case token.Sub:
504 if ci, ok := x.(*ConstInt); ok {
505 return &ConstInt{V:-ci.V}
506 }
507 if cf, ok := x.(*ConstFloat); ok {
508 neg := ""
509 if cf.Lit != "" {
510 neg = "-" | cf.Lit
511 }
512 return &ConstFloat{V:-cf.V, Lit:neg}
513 }
514 case token.Xor:
515 if ci, ok := x.(*ConstInt); ok {
516 return &ConstInt{V:^ci.V}
517 }
518 case token.Not:
519 if cb, ok := x.(*ConstBool); ok {
520 return &ConstBool{V:!cb.V}
521 }
522 }
523 return nil
524 }
525
526 func EvalBinaryLocal(op token.Operator, x ConstVal, y ConstVal) (c ConstVal) {
527 switch op {
528 case token.Add:
529 if xi, ok := x.(*ConstInt); ok {
530 return &ConstInt{V:xi.V + cvInt(y)}
531 }
532 if xf, ok := x.(*ConstFloat); ok {
533 return &ConstFloat{V:xf.V + cvFloat(y)}
534 }
535 if xs, ok := x.(*ConstStr); ok {
536 return &ConstStr{S:xs.S | cvStr(y)}
537 }
538 case token.Sub:
539 if xi, ok := x.(*ConstInt); ok {
540 return &ConstInt{V:xi.V - cvInt(y)}
541 }
542 if xf, ok := x.(*ConstFloat); ok {
543 return &ConstFloat{V:xf.V - cvFloat(y)}
544 }
545 case token.Mul:
546 if xi, ok := x.(*ConstInt); ok {
547 return &ConstInt{V:xi.V * cvInt(y)}
548 }
549 if xf, ok := x.(*ConstFloat); ok {
550 return &ConstFloat{V:xf.V * cvFloat(y)}
551 }
552 case token.Div:
553 if xi, ok := x.(*ConstInt); ok {
554 d := cvInt(y)
555 if d == 0 {
556 return &ConstInt{V:0}
557 }
558 return &ConstInt{V:xi.V / d}
559 }
560 if xf, ok := x.(*ConstFloat); ok {
561 d := cvFloat(y)
562 if d == 0.0 {
563 return &ConstFloat{V:0.0}
564 }
565 return &ConstFloat{V:xf.V / d}
566 }
567 case token.Rem:
568 if xi, ok := x.(*ConstInt); ok {
569 d := cvInt(y)
570 if d == 0 {
571 return &ConstInt{V:0}
572 }
573 return &ConstInt{V:xi.V % d}
574 }
575 case token.And:
576 if xi, ok := x.(*ConstInt); ok {
577 return &ConstInt{V:xi.V & cvInt(y)}
578 }
579 case token.Or:
580 if xi, ok := x.(*ConstInt); ok {
581 return &ConstInt{V:xi.V | cvInt(y)}
582 }
583 if xs, ok := x.(*ConstStr); ok {
584 return &ConstStr{S:xs.S | cvStr(y)}
585 }
586 case token.Xor:
587 if xi, ok := x.(*ConstInt); ok {
588 return &ConstInt{V:xi.V ^ cvInt(y)}
589 }
590 case token.Shl:
591 if xi, ok := x.(*ConstInt); ok {
592 shift := uint32(cvInt(y))
593 return &ConstInt{V:xi.V << shift}
594 }
595 case token.Shr:
596 if xi, ok := x.(*ConstInt); ok {
597 shift := uint32(cvInt(y))
598 return &ConstInt{V:xi.V >> shift}
599 }
600 case token.AndNot:
601 if xi, ok := x.(*ConstInt); ok {
602 return &ConstInt{V:xi.V &^ cvInt(y)}
603 }
604 case token.Eql:
605 return &ConstBool{V:constEqual(x, y)}
606 case token.Neq:
607 return &ConstBool{V:!constEqual(x, y)}
608 case token.Lss:
609 return &ConstBool{V:constLess(x, y)}
610 case token.Leq:
611 return &ConstBool{V:constLess(x, y) || constEqual(x, y)}
612 case token.Gtr:
613 return &ConstBool{V:constLess(y, x)}
614 case token.Geq:
615 return &ConstBool{V:constLess(y, x) || constEqual(x, y)}
616 case token.OrOr:
617 xb, xok := x.(*ConstBool)
618 yb, yok := y.(*ConstBool)
619 if xok && yok {
620 return &ConstBool{V:xb.V || yb.V}
621 }
622 case token.AndAnd:
623 xb, xok := x.(*ConstBool)
624 yb, yok := y.(*ConstBool)
625 if xok && yok {
626 return &ConstBool{V:xb.V && yb.V}
627 }
628 }
629 return nil
630 }
631
632 func constEqual(x ConstVal, y ConstVal) (eq bool) {
633 if xi, matched := x.(*ConstInt); matched {
634 return xi.V == cvInt(y)
635 }
636 if xf, matched := x.(*ConstFloat); matched {
637 return xf.V == cvFloat(y)
638 }
639 if xs, matched := x.(*ConstStr); matched {
640 return xs.S == cvStr(y)
641 }
642 if xb, matched := x.(*ConstBool); matched {
643 if yb, matched2 := y.(*ConstBool); matched2 {
644 return xb.V == yb.V
645 }
646 }
647 return false
648 }
649
650 func constLess(x ConstVal, y ConstVal) (lt bool) {
651 if xi, matched := x.(*ConstInt); matched {
652 return xi.V < cvInt(y)
653 }
654 if xf, matched := x.(*ConstFloat); matched {
655 return xf.V < cvFloat(y)
656 }
657 if xs, matched := x.(*ConstStr); matched {
658 return xs.S < cvStr(y)
659 }
660 return false
661 }
662
663 func ConvertConstLocal(v ConstVal, target Type) (c ConstVal) {
664 b, isBasic := SafeUnderlying(target).(*Basic)
665 if !isBasic {
666 return v
667 }
668 switch {
669 case b.Info&IsInteger != 0:
670 iv := cvInt(v)
671 return MaskConstToBasic(&ConstInt{V:iv}, b)
672 case b.Info&IsFloat != 0:
673 fv := cvFloat(v)
674 if cf, matched := v.(*ConstFloat); matched {
675 return &ConstFloat{V:fv, Lit:cf.Lit}
676 }
677 return &ConstFloat{V:fv}
678 case b.Info&IsString != 0:
679 if cvKind(v) == 3 {
680 n := cvInt(v)
681 return &ConstStr{S:runeToStr(rune(n))}
682 }
683 return v
684 }
685 return v
686 }
687
688 // MaskConstToBasic truncates a ConstInt to the width and signedness of the
689 // given sized basic integer type. Untyped and non-integer types pass
690 // through unchanged.
691 func MaskConstToBasic(v ConstVal, b *Basic) (c ConstVal) {
692 ci, ok := v.(*ConstInt)
693 if !ok || b == nil || b.Info&IsInteger == 0 || b.Info&IsUntyped != 0 {
694 return v
695 }
696 n := ci.V
697 switch b.Kind {
698 case Int8:
699 n = int64(int8(n))
700 case Int16:
701 n = int64(int16(n))
702 case Int32:
703 n = int64(int32(n))
704 case Uint8:
705 n = int64(uint8(n))
706 case Uint16:
707 n = int64(uint16(n))
708 case Uint32:
709 n = int64(uint32(n))
710 case Int64, Uint64:
711 // 64-bit: int64 bit pattern is already exact.
712 default:
713 return v
714 }
715 return &ConstInt{V:n}
716 }
717
718 // constExprBasic resolves the basic type of a constant expression, used to
719 // apply width masking to typed constant operations. Returns nil when the
720 // type cannot be determined (untyped literals and untracked forms).
721 func (c *Checker) constExprBasic(e syntax.Expr) (b *Basic) {
722 switch ex := e.(type) {
723 case *syntax.Name:
724 var obj Object
725 if c.localScope != nil {
726 _, obj = c.localScope.LookupParent(ex.Value)
727 }
728 if obj == nil {
729 _, obj = c.lookup(ex.Value, c.pkg.Scope)
730 }
731 if k, matched := obj.(*TCConst); matched && k.Typ != nil {
732 if bb, matched2 := SafeUnderlying(k.Typ).(*Basic); matched2 {
733 return bb
734 }
735 }
736 case *syntax.SelectorExpr:
737 if pkgName, matched := ex.X.(*syntax.Name); matched {
738 if _, imp := c.lookupType(pkgName.Value); imp != nil {
739 if pn, matched2 := imp.(*PkgName); matched2 && pn.Imported != nil {
740 if obj := pn.Imported.Scope.Lookup(ex.Sel.Value); obj != nil {
741 if k, matched3 := obj.(*TCConst); matched3 && k.Typ != nil {
742 if bb, matched4 := SafeUnderlying(k.Typ).(*Basic); matched4 {
743 return bb
744 }
745 }
746 }
747 }
748 }
749 }
750 case *syntax.ParenExpr:
751 return c.constExprBasic(ex.X)
752 case *syntax.CallExpr:
753 if t := c.resolveTypeExpr(ex.Fun); t != nil {
754 if bb, matched := SafeUnderlying(t).(*Basic); matched {
755 return bb
756 }
757 }
758 case *syntax.Operation:
759 if bb := c.constExprBasic(ex.X); bb != nil && bb.Info&IsUntyped == 0 {
760 return bb
761 }
762 if ex.Y != nil {
763 return c.constExprBasic(ex.Y)
764 }
765 }
766 return nil
767 }
768
769 func UntypedTypeOfCV(v ConstVal) (t Type) {
770 switch cvKind(v) {
771 case 1:
772 return Typ[UntypedBool]
773 case 3:
774 return Typ[UntypedInt]
775 case 4:
776 return Typ[UntypedFloat]
777 case 2:
778 return Typ[UntypedString]
779 }
780 return nil
781 }
782
783 func cvKind(val ConstVal) (n int32) {
784 switch val.(type) {
785 case *ConstBool:
786 return 1
787 case *ConstStr:
788 return 2
789 case *ConstInt:
790 return 3
791 case *ConstFloat:
792 return 4
793 case *ConstNil:
794 return 0
795 }
796 return 0
797 }
798
799 func constInt64CV(v ConstVal) (n int64, valid bool) {
800 if v == nil || cvKind(v) != 3 {
801 return 0, false
802 }
803 if ci, matched := v.(*ConstInt); matched {
804 return ci.V, true
805 }
806 return 0, false
807 }
808
809 func (c *Checker) IsConstExpr(e syntax.Expr) (ok bool) {
810 return c.evalConst(e, 0) != nil
811 }
812
813 func (c *Checker) evalArrayLen(e syntax.Expr) (n int64) {
814 v := c.evalConst(e, 0)
815 if v == nil {
816 return 0
817 }
818 n, _ = constInt64CV(v)
819 return n
820 }
821
822 func cvInt(v ConstVal) (n int64) {
823 if ci, ok := v.(*ConstInt); ok {
824 return ci.V
825 }
826 if cf, ok := v.(*ConstFloat); ok {
827 return int64(cf.V)
828 }
829 return 0
830 }
831
832 func cvFloat(v ConstVal) (f float64) {
833 if cf, ok := v.(*ConstFloat); ok {
834 return cf.V
835 }
836 if ci, ok := v.(*ConstInt); ok {
837 return float64(ci.V)
838 }
839 return 0
840 }
841
842 func cvStr(v ConstVal) (s string) {
843 if cs, ok := v.(*ConstStr); ok {
844 return cs.S
845 }
846 return ""
847 }
848
849 func decodeFirstRune(s string) (n int32) {
850 b := s[0]
851 if b < 0x80 {
852 return int32(b)
853 }
854 if b < 0xC0 {
855 return int32(b)
856 }
857 if b < 0xE0 && len(s) >= 2 {
858 return int32(b&0x1F)<<6 | int32(s[1]&0x3F)
859 }
860 if b < 0xF0 && len(s) >= 3 {
861 return int32(b&0x0F)<<12 | int32(s[1]&0x3F)<<6 | int32(s[2]&0x3F)
862 }
863 if len(s) >= 4 {
864 return int32(b&0x07)<<18 | int32(s[1]&0x3F)<<12 | int32(s[2]&0x3F)<<6 | int32(s[3]&0x3F)
865 }
866 return int32(b)
867 }
868
869 func runeToStr(r rune) (s string) {
870 if r < 0 || r > 0x10FFFF {
871 r = 0xFFFD
872 }
873 var out []byte
874 if r <= 0x7F {
875 push(out, byte(r))
876 } else if r <= 0x7FF {
877 push(out, byte(0xC0|(r>>6)), byte(0x80|(r&0x3F)))
878 } else if r <= 0xFFFF {
879 push(out, byte(0xE0|(r>>12)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
880 } else {
881 push(out, byte(0xF0|(r>>18)), byte(0x80|((r>>12)&0x3F)), byte(0x80|((r>>6)&0x3F)), byte(0x80|(r&0x3F)))
882 }
883 return string(out)
884 }
885