func val(lit string) exact.Value { if len(lit) == 0 { return exact.MakeUnknown() } switch lit { case "?": return exact.MakeUnknown() case "true": return exact.MakeBool(true) case "false": return exact.MakeBool(false) } tok := token.INT switch first, last := lit[0], lit[len(lit)-1]; { case first == '"' || first == '`': tok = token.STRING lit = strings.Replace(lit, "_", " ", -1) case first == '\'': tok = token.CHAR case last == 'i': tok = token.IMAG default: if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") { tok = token.FLOAT } } return exact.MakeFromLiteral(lit, tok) }
func val(lit string) exact.Value { if len(lit) == 0 { return exact.MakeUnknown() } switch lit { case "?": return exact.MakeUnknown() case "nil": return nil case "true": return exact.MakeBool(true) case "false": return exact.MakeBool(false) } tok := token.FLOAT switch first, last := lit[0], lit[len(lit)-1]; { case first == '"' || first == '`': tok = token.STRING lit = strings.Replace(lit, "_", " ", -1) case first == '\'': tok = token.CHAR case last == 'i': tok = token.IMAG } return exact.MakeFromLiteral(lit, tok) }
func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { assert(obj.typ == nil) if obj.visited { obj.typ = Typ[Invalid] return } obj.visited = true // use the correct value of iota assert(check.iota == nil) check.iota = obj.val defer func() { check.iota = nil }() // provide valid constant value under all circumstances obj.val = exact.MakeUnknown() // determine type, if any if typ != nil { t := check.typ(typ) if !isConstType(t) { check.errorf(typ.Pos(), "invalid constant type %s", t) obj.typ = Typ[Invalid] return } obj.typ = t } // check initialization var x operand if init != nil { check.expr(&x, init) } check.initConst(obj, &x) }
func (check *checker) initConst(lhs *Const, x *operand) { lhs.val = exact.MakeUnknown() if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { if lhs.typ == nil { lhs.typ = Typ[Invalid] } return // nothing else to check } // If the lhs doesn't have a type yet, use the type of x. if lhs.typ == nil { lhs.typ = x.typ } if !check.assignment(x, lhs.typ) { if x.mode != invalid { check.errorf(x.pos(), "cannot define constant %s (type %s) as %s", lhs.Name(), lhs.typ, x) } return } // rhs must be a constant if x.mode != constant { check.errorf(x.pos(), "%s is not constant", x) return } assert(isConstType(x.typ)) lhs.val = x.val }
func (c *compiler) VisitExpr(expr ast.Expr) Value { c.setDebugLine(expr.Pos()) // Before all else, check if we've got a constant expression. // go/types performs constant folding, and we store the value // alongside the expression's type. if constval := c.typeinfo.Values[expr]; constval != nil { return c.NewConstValue(constval, c.typeinfo.Types[expr]) } // nil-literals are parsed to Ident-nodes for some reason, // treat them like constant values here. // TODO nil literals should be represented more appropriately. if identval, valid := expr.(*ast.Ident); valid && identval.Name == "nil" { return c.NewConstValue(exact.MakeUnknown(), c.typeinfo.Types[expr]) } switch x := expr.(type) { case *ast.BinaryExpr: return c.VisitBinaryExpr(x) case *ast.FuncLit: return c.VisitFuncLit(x) case *ast.CompositeLit: return c.VisitCompositeLit(x) case *ast.UnaryExpr: return c.VisitUnaryExpr(x) case *ast.CallExpr: return c.VisitCallExpr(x) case *ast.IndexExpr: return c.VisitIndexExpr(x) case *ast.SelectorExpr: return c.VisitSelectorExpr(x) case *ast.StarExpr: return c.VisitStarExpr(x) case *ast.ParenExpr: return c.VisitExpr(x.X) case *ast.TypeAssertExpr: return c.VisitTypeAssertExpr(x) case *ast.SliceExpr: return c.VisitSliceExpr(x) case *ast.Ident: return c.Resolve(x) } panic(fmt.Sprintf("Unhandled Expr node: %s", reflect.TypeOf(expr))) }