diff options
Diffstat (limited to 'vendor/modernc.org/gc/v3/value.go')
-rw-r--r-- | vendor/modernc.org/gc/v3/value.go | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/vendor/modernc.org/gc/v3/value.go b/vendor/modernc.org/gc/v3/value.go new file mode 100644 index 0000000..c2cefd2 --- /dev/null +++ b/vendor/modernc.org/gc/v3/value.go @@ -0,0 +1,716 @@ +// Copyright 2022 The Gc Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gc // modernc.org/gc/v3 + +import ( + "go/constant" + "math" +) + +var ( + _ Expression = (*BasicLitNode)(nil) + _ Expression = (*BinaryExpressionNode)(nil) + _ Expression = (*CompositeLitNode)(nil) + _ Expression = (*ConversionNode)(nil) + _ Expression = (*FunctionLitNode)(nil) + _ Expression = (*KeyedElementNode)(nil) + _ Expression = (*LiteralValueNode)(nil) + _ Expression = (*MethodExprNode)(nil) + _ Expression = (*OperandNameNode)(nil) + _ Expression = (*OperandNode)(nil) + _ Expression = (*OperandQualifiedNameNode)(nil) + _ Expression = (*ParenthesizedExpressionNode)(nil) + _ Expression = (*PrimaryExprNode)(nil) + _ Expression = (*UnaryExprNode)(nil) + _ Expression = (*ValueExpression)(nil) + + falseVal = constant.MakeBool(false) + trueVal = constant.MakeBool(true) + unknown = constant.MakeUnknown() +) + +func known(v constant.Value) bool { return v != nil && v.Kind() != constant.Unknown } + +type valueCache struct { + v constant.Value +} + +func (n *valueCache) Value() constant.Value { + if n.v != nil { + return n.v + } + + return unknown +} + +func (n *valueCache) setValue(v constant.Value) constant.Value { + n.v = v + return v +} + +type valuer interface { + Value() constant.Value +} + +type Expression interface { + Node + checkExpr(c *ctx) Expression + clone() Expression + typer + valuer +} + +type ValueExpression struct { + Node + typeCache + valueCache +} + +func (n *ValueExpression) checkExpr(c *ctx) Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *ValueExpression) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *BasicLitNode) Type() Type { + switch n.Ch() { + case CHAR: + return n.ctx.int32 + case INT: + return n.ctx.untypedInt + case FLOAT: + return n.ctx.untypedFloat + case STRING: + return n.ctx.untypedString + default: + panic(todo("%v: %T %s %v", n.Position(), n, n.Source(false), n.Ch())) + } +} + +func (n *BasicLitNode) Value() constant.Value { + return constant.MakeFromLiteral(n.Src(), n.Ch(), 0) +} + +func (n *BasicLitNode) checkExpr(c *ctx) Expression { + n.ctx = c + if !known(n.Value()) { + c.err(n, "invalid literal: %s", n.Source(false)) + } + return n +} + +func (n *BasicLitNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandNameNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandNameNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandNameNode) checkExpr(c *ctx) Expression { + in, named := n.LexicalScope().lookup(n.Name) + switch x := named.n.(type) { + case *ConstSpecNode: + switch in.kind { + case UniverseScope: + switch n.Name.Src() { + case "iota": + if c.iota < 0 { + panic(todo("%v: %T %s", n.Position(), x, n.Source(false))) + } + + r := &ValueExpression{Node: x} + r.t = c.untypedInt + r.v = constant.MakeInt64(c.iota) + return r + default: + panic(todo("%v: %T %s", n.Position(), x, n.Source(false))) + } + default: + return x.Expression + } + default: + panic(todo("%v: %T %s", n.Position(), x, n.Source(false))) + } +} + +func (n *OperandNameNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *ParenthesizedExpressionNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *ParenthesizedExpressionNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *ParenthesizedExpressionNode) checkExpr(c *ctx) Expression { + return n.Expression.checkExpr(c) +} + +func (n *ParenthesizedExpressionNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *LiteralValueNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *LiteralValueNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *LiteralValueNode) checkExpr(c *ctx) Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *LiteralValueNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *KeyedElementNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *KeyedElementNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *KeyedElementNode) checkExpr(c *ctx) Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *KeyedElementNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *CompositeLitNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *CompositeLitNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *CompositeLitNode) checkExpr(c *ctx) Expression { + if n == nil { + return nil + } + + if !n.enter(c, n) { + return n + } + + t := n.setType(c.checkType(n.LiteralType)) + n.LiteralValue.check(c, t) + return n +} + +func (n *CompositeLitNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *LiteralValueNode) check(c *ctx, t Type) { + if n == nil { + return + } + + switch t.Kind() { + case Array: + n.checkArray(c, t.(*ArrayTypeNode)) + default: + panic(todo("%v: %T %s %v", n.Position(), n, n.Source(false), t.Kind())) + } +} + +func (n *LiteralValueNode) checkArray(c *ctx, t *ArrayTypeNode) { + panic(todo("%v: %T %s %s", n.Position(), n, t, n.Source(false))) +} + +func (n *FunctionLitNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *FunctionLitNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *FunctionLitNode) checkExpr(c *ctx) Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *FunctionLitNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandNode) checkExpr(c *ctx) Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandQualifiedNameNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandQualifiedNameNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandQualifiedNameNode) checkExpr(c *ctx) Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *OperandQualifiedNameNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *ConversionNode) Type() Type { + return n.TypeNode +} + +func (n *ConversionNode) checkExpr(c *ctx) Expression { + t := n.TypeNode.check(c) + n.Expression = n.Expression.checkExpr(c) + v := n.Expression.Value() + n.v = c.convertValue(n.Expression, v, t) + return n +} + +func (n *ConversionNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *MethodExprNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *MethodExprNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *MethodExprNode) checkExpr(c *ctx) Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *MethodExprNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *PrimaryExprNode) Type() Type { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *PrimaryExprNode) Value() constant.Value { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *PrimaryExprNode) checkExpr(c *ctx) Expression { + switch x := n.PrimaryExpr.(type) { + case *OperandNameNode: + _, named := x.LexicalScope().lookup(x.Name) + switch y := named.n.(type) { + case *TypeDefNode: + switch z := n.Postfix.(type) { + case *ArgumentsNode: + cnv := &ConversionNode{ + TypeNode: &TypeNameNode{ + Name: x.Name, + lexicalScoper: x.lexicalScoper, + }, + LPAREN: z.LPAREN, + Expression: z.Expression, + RPAREN: z.RPAREN, + } + return cnv.checkExpr(c) + default: + panic(todo("%v: %T %s", n.Position(), z, n.Source(false))) + } + default: + panic(todo("%v: %T %s", n.Position(), y, n.Source(false))) + } + default: + panic(todo("%v: %T %s", n.Position(), x, n.Source(false))) + } + + n.PrimaryExpr = n.PrimaryExpr.checkExpr(c) + switch x := n.Postfix.(type) { + default: + panic(todo("%v: %T %s", n.Position(), x, n.Source(false))) + } +} + +func (n *PrimaryExprNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *BinaryExpressionNode) checkExpr(c *ctx) (r Expression) { + if n == nil { + return nil + } + + if n.typeCache.Type() != Invalid { + return n + } + + n.LHS = n.LHS.checkExpr(c) + n.RHS = n.RHS.checkExpr(c) + lv := n.LHS.Value() + lt := n.LHS.Type() + rv := n.RHS.Value() + rt := n.RHS.Type() + + defer func() { + if known(lv) && known(rv) && r != nil && !known(r.Value()) { + c.err(n.Op, "operation value not determined: %v %s %v", lv, n.Op.Src(), rv) + } + }() + + switch n.Op.Ch() { + case SHL, SHR: + var u uint64 + var uOk bool + n.t = lt + // The right operand in a shift expression must have integer type or be an + // untyped constant representable by a value of type uint. + switch { + case isIntegerType(rt): + // ok + case known(rv): + if isAnyArithmeticType(rt) { + rv = c.convertValue(n.RHS, rv, c.cfg.uint) + if known(rv) { + u, uOk = constant.Uint64Val(rv) + } + break + } + + c.err(n.Op, "TODO %v", n.Op.Src()) + return n + default: + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) + return n + } + + // If the left operand of a non-constant shift expression is an untyped + // constant, it is first implicitly converted to the type it would assume if + // the shift expression were replaced by its left operand alone. + switch { + case known(lv) && !known(rv): + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) + // c.err(n.Op, "TODO %v", n.Op.Ch.str()) + // return n + case known(lv) && known(rv): + if !uOk { + panic(todo("")) + } + + n.t = lt + n.v = constant.Shift(lv, n.Op.Ch(), uint(u)) + default: + trc("", known(lv), known(rv), u, uOk) + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) + // n.t = lt + // n.v = constant.BinaryOp(lv, n.Op.Ch(), rv) + } + case ADD, SUB, MUL, QUO, REM: + if !isAnyArithmeticType(lt) || !isAnyArithmeticType(rt) { + c.err(n.Op, "TODO %v %v", lt, rt) + break + } + + // For other binary operators, the operand types must be identical unless the + // operation involves shifts or untyped constants. + // + // Except for shift operations, if one operand is an untyped constant and the + // other operand is not, the constant is implicitly converted to the type of + // the other operand. + switch { + case isAnyUntypedType(lt) && isAnyUntypedType(rt): + n.v = constant.BinaryOp(lv, n.Op.Ch(), rv) + switch n.v.Kind() { + case constant.Int: + n.t = c.untypedInt + case constant.Float: + n.t = c.untypedFloat + default: + c.err(n.Op, "TODO %v %v %q %v %v -> %v %v", lv, lt, n.Op.Src(), rv, rt, n.v, n.v.Kind()) + } + case isAnyUntypedType(lt) && !isAnyUntypedType(rt): + c.err(n.Op, "TODO %v %v %q %v %v", lv, lt, n.Op.Src(), rv, rt) + case !isAnyUntypedType(lt) && isAnyUntypedType(rt): + c.err(n.Op, "TODO %v %v %q %v %v", lv, lt, n.Op.Src(), rv, rt) + default: // case !isAnyUntypedType(lt) && !isAnyUntypedType(rt): + c.err(n.Op, "TODO %v %v %q %v %v", lv, lt, n.Op.Src(), rv, rt) + } + default: + c.err(n.Op, "TODO %v %v %q %v %v", lv, lt, n.Op.Src(), rv, rt) + } + return n +} + +func (n *BinaryExpressionNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (n *UnaryExprNode) checkExpr(c *ctx) Expression { + if n == nil { + return nil + } + + if n.typeCache.Type() != Invalid { + return n + } + + n.UnaryExpr = n.UnaryExpr.checkExpr(c) + v := n.UnaryExpr.Value() + t := n.UnaryExpr.Type() + switch n.Op.Ch() { + default: + trc("", v, t) + panic(todo("%v: %T %s", n.Op.Position(), n, n.Source(false))) + } +} + +func (n *UnaryExprNode) clone() Expression { + panic(todo("%v: %T %s", n.Position(), n, n.Source(false))) +} + +func (c *ctx) convertValue(n Node, v constant.Value, to Type) (r constant.Value) { + if !known(v) { + return unknown + } + + switch to.Kind() { + case + Complex128, + Complex64, + Function, + Interface, + Map, + Pointer, + Slice, + String, + Struct, + Tuple, + UnsafePointer, + UntypedBool, + UntypedComplex, + UntypedFloat, + UntypedInt, + UntypedNil, + UntypedRune, + UntypedString: + + c.err(n, "TODO %v -> %v", v, to) + case Int: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + i64, ok := constant.Int64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + switch c.cfg.goarch { + case "386", "arm": + if i64 < math.MinInt32 || i64 > math.MaxInt32 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + } + return w + case Int8: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + i64, ok := constant.Int64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + if i64 < math.MinInt8 || i64 > math.MaxInt8 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Int16: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + i64, ok := constant.Int64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + if i64 < math.MinInt16 || i64 > math.MaxInt16 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Int32: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + i64, ok := constant.Int64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + if i64 < math.MinInt32 || i64 > math.MaxInt32 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Int64: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + if _, ok := constant.Int64Val(w); !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Uint, Uintptr: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + u64, ok := constant.Uint64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + switch c.cfg.goarch { + case "386", "arm": + if u64 > math.MaxUint32 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + } + return w + case Uint8: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + u64, ok := constant.Uint64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + if u64 > math.MaxUint8 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Uint16: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + u64, ok := constant.Uint64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + if u64 > math.MaxUint16 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Uint32: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + u64, ok := constant.Uint64Val(w) + if !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + if u64 > math.MaxUint32 { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Uint64: + w := constant.ToInt(v) + if !known(w) { + c.err(n, "cannot convert %s to %s", v, to) + return unknown + } + + if _, ok := constant.Uint64Val(w); !ok { + c.err(n, "value %s overflows %s", v, to) + return unknown + } + + return w + case Float32, Float64: + return constant.ToFloat(v) + case Bool: + if v.Kind() == constant.Bool { + return v + } + } + return unknown +} |