about summary refs log tree commit diff
path: root/vendor/modernc.org/gc/v3/value.go
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-08-16 19:50:26 +0200
committerEmile <git@emile.space>2024-08-16 19:50:26 +0200
commit1a57267a17c2fc17fb6e104846fabc3e363c326c (patch)
tree1e574e3a80622086dc3c81ff9cba65ef7049b1a9 /vendor/modernc.org/gc/v3/value.go
initial commit
Diffstat (limited to 'vendor/modernc.org/gc/v3/value.go')
-rw-r--r--vendor/modernc.org/gc/v3/value.go716
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
+}