代码拉取完成,页面将自动刷新
// Copyright 2017 The CC 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 cc
// [0]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
import (
"bytes"
"fmt"
"github.com/cznic/ir"
)
var (
_ Type = (*ArrayType)(nil)
_ Type = (*EnumType)(nil)
_ Type = (*FunctionType)(nil)
_ Type = (*NamedType)(nil)
_ Type = (*PointerType)(nil)
_ Type = (*StructType)(nil)
_ Type = (*TaggedStructType)(nil)
_ Type = (*TaggedUnionType)(nil)
_ Type = (*TaggedEnumType)(nil)
_ Type = (*UnionType)(nil)
_ Type = TypeKind(0)
_ fieldFinder = (*StructType)(nil)
_ fieldFinder = (*UnionType)(nil)
)
type fieldFinder interface {
findField(int) *FieldProperties
}
// Type represents a C type.
type Type interface {
Equal(Type) bool
IsArithmeticType() bool
IsCompatible(Type) bool // [0]6.2.7
IsIntegerType() bool
IsPointerType() bool
IsScalarType() bool
IsUnsigned() bool
IsVoidPointerType() bool
Kind() TypeKind
String() string
assign(ctx *context, n Node, op Operand) Operand
}
// TypeKind represents a particular type kind.
type TypeKind int
// TypeKind values.
const (
_ TypeKind = iota
Bool
Char
Int
Long
LongLong
SChar
Short
UChar
UInt
ULong
ULongLong
UShort
Float
Double
LongDouble
FloatComplex
DoubleComplex
LongDoubleComplex
Array
Enum
EnumTag
Function
Ptr
Struct
StructTag
TypedefName
Union
UnionTag
Void
maxTypeKind
)
// IsUnsigned implements Type.
func (t TypeKind) IsUnsigned() bool { return t.IsIntegerType() && !isSigned[t] }
// Kind implements Type.
func (t TypeKind) Kind() TypeKind { return t }
// assign implements Type.
func (t TypeKind) assign(ctx *context, n Node, op Operand) Operand {
// [0]6.5.16.1
switch {
// One of the following shall hold:
case
// the left operand has qualified or unqualified arithmetic
// type and the right has arithmetic type;
t.IsArithmeticType() && op.Type.IsArithmeticType():
return op.ConvertTo(ctx.model, t)
default:
panic(fmt.Sprintf("%v: %v <- %v", ctx.position(n), t, op))
}
}
// IsPointerType implements Type.
func (t TypeKind) IsPointerType() bool {
if t.IsArithmeticType() {
return false
}
switch t {
case Void:
return false
default:
panic(t)
}
}
// IsIntegerType implements Type.
func (t TypeKind) IsIntegerType() bool {
switch t {
case
Bool,
Char,
Int,
Long,
LongLong,
SChar,
Short,
UChar,
UInt,
ULong,
ULongLong,
UShort:
return true
case
Double,
DoubleComplex,
Float,
FloatComplex,
LongDouble,
LongDoubleComplex,
Void:
return false
default:
panic(t)
}
}
// IsScalarType implements Type.
func (t TypeKind) IsScalarType() bool {
switch t {
case
Char,
Double,
DoubleComplex,
Float,
FloatComplex,
Int,
Long,
LongDouble,
LongDoubleComplex,
LongLong,
SChar,
Short,
UChar,
UInt,
ULong,
ULongLong,
UShort:
return true
case Void:
return false
default:
panic(t)
}
}
// IsVoidPointerType implements Type.
func (t TypeKind) IsVoidPointerType() bool {
if t != Ptr {
return false
}
panic(t)
}
// IsArithmeticType implements Type.
func (t TypeKind) IsArithmeticType() bool { return isArithmeticType[t] }
// IsCompatible implements Type.
func (t TypeKind) IsCompatible(u Type) bool {
for {
switch x := u.(type) {
case *PointerType:
switch t {
case
Char,
Int:
return false
default:
panic(fmt.Errorf("%v %v", t, x))
}
case *NamedType:
u = x.Type
case *EnumType:
u = x.Enums[0].Operand.Type
case TypeKind:
if t.IsIntegerType() && u.IsIntegerType() {
return intConvRank[t] == intConvRank[x] && isSigned[t] == isSigned[x]
}
switch x {
case
Double,
DoubleComplex,
Float,
FloatComplex,
LongDouble,
LongDoubleComplex:
return t == x
case Void:
return t == x
default:
panic(fmt.Errorf("%v", x))
}
default:
panic(fmt.Errorf("%v %T", t, x))
}
}
}
// Equal implements Type.
func (t TypeKind) Equal(u Type) bool {
switch x := u.(type) {
case
*ArrayType,
*EnumType,
*FunctionType,
*PointerType,
*StructType,
*TaggedEnumType,
*TaggedStructType,
*TaggedUnionType,
*UnionType:
if t.IsScalarType() || t == Void {
return false
}
panic(t)
case *NamedType:
return t.Equal(x.Type)
case TypeKind:
switch x {
case
Bool,
Char,
Double,
DoubleComplex,
Float,
FloatComplex,
Int,
Long,
LongDouble,
LongDoubleComplex,
LongLong,
SChar,
Short,
UChar,
UInt,
ULong,
ULongLong,
UShort,
Void:
return t == x
default:
panic(x)
}
default:
panic(fmt.Errorf("%T", x))
}
}
func (t TypeKind) String() string {
switch t {
case Bool:
return "bool"
case Char:
return "char"
case Int:
return "int"
case Long:
return "long"
case LongLong:
return "long long"
case SChar:
return "signed char"
case Short:
return "short"
case UChar:
return "unsigned char"
case UInt:
return "unsigned"
case ULong:
return "unsigned long"
case ULongLong:
return "unsigned long long"
case UShort:
return "unsigned short"
case Float:
return "float"
case Double:
return "double"
case LongDouble:
return "long double"
case FloatComplex:
return "float complex"
case DoubleComplex:
return "double complex"
case LongDoubleComplex:
return "long double complex"
case Array:
return "array"
case Enum:
return "enum"
case EnumTag:
return "enum tag"
case Function:
return "function"
case Ptr:
return "ptr"
case Struct:
return "struct"
case StructTag:
return "struct tag"
case TypedefName:
return "typedef name"
case Union:
return "union"
case Void:
return "void"
default:
return fmt.Sprintf("TypeKind(%v)", int(t))
}
}
// ArrayType type represents an array type.
type ArrayType struct {
Item Type
Size Operand
TypeQualifiers []*TypeQualifier // Eg. double a[restrict 3][5], see 6.7.5.3-21.
}
// IsUnsigned implements Type.
func (t *ArrayType) IsUnsigned() bool { panic("TODO") }
// IsVoidPointerType implements Type.
func (t *ArrayType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *ArrayType) IsArithmeticType() bool { return false }
// IsCompatible implements Type.
func (t *ArrayType) IsCompatible(u Type) bool {
// [0]6.7.5.2
//
// 6. For two array types to be compatible, both shall have compatible
// element types, and if both size specifiers are present, and are
// integer constant expressions, then both size specifiers shall have
// the same constant value. If the two array types are used in a
// context which requires them to be compatible, it is undefined
// behavior if the two size specifiers evaluate to unequal values.
switch x := u.(type) {
case *ArrayType:
if !t.Item.IsCompatible(x.Item) {
return false
}
if t.Size.Type != nil && x.Size.Type != nil {
return t.Size.Value.(*ir.Int64Value).Value == x.Size.Value.(*ir.Int64Value).Value
}
return true
case *NamedType:
return x.IsCompatible(t)
case *PointerType:
return t.Size.Type == nil && t.Item.IsCompatible(x.Item)
case TypeKind:
if x.IsArithmeticType() {
return false
}
panic(fmt.Errorf("%T\n%v\n%v", x, t, u))
default:
panic(fmt.Errorf("%T\n%v\n%v", x, t, u))
}
}
// Equal implements Type.
func (t *ArrayType) Equal(u Type) bool {
if t == u {
return true
}
switch x := u.(type) {
case *ArrayType:
if !t.Item.Equal(x.Item) {
return false
}
switch {
case t.Size.Type != nil && x.Size.Type != nil:
return x.Size.Type != nil && t.Size.Value.(*ir.Int64Value).Value == x.Size.Value.(*ir.Int64Value).Value
case t.Size.Type == nil && x.Size.Type == nil:
return true
default:
panic(fmt.Errorf("%v, %v", t, u))
}
case *NamedType:
return x.Type.Equal(t)
case
*FunctionType,
*PointerType,
*StructType,
*TaggedStructType:
return false
case TypeKind:
if x.IsScalarType() || x == Void {
return false
}
panic(x)
default:
panic(fmt.Errorf("%T %v", x, x))
}
}
// Kind implements Type.
func (t *ArrayType) Kind() TypeKind { return Array }
// assign implements Type.
func (t *ArrayType) assign(ctx *context, n Node, op Operand) Operand {
switch {
case t.Size.Value == nil:
return (&PointerType{Item: t.Item}).assign(ctx, n, op)
default:
panic("TODO")
}
}
// IsPointerType implements Type.
func (t *ArrayType) IsPointerType() bool { return false }
// IsIntegerType implements Type.
func (t *ArrayType) IsIntegerType() bool { return false }
// IsScalarType implements Type.
func (t *ArrayType) IsScalarType() bool { return false }
func (t *ArrayType) String() string {
switch {
case t.Size.Type != nil && t.Size.Value != nil:
return fmt.Sprintf("array of %v %v", t.Size.Value, t.Item)
default:
return fmt.Sprintf("array of %v", t.Item)
}
}
// EnumType represents an enum type.
type EnumType struct {
Tag int
Enums []*EnumerationConstant
Min int64
Max uint64
}
func (t *EnumType) find(nm int) *EnumerationConstant {
for _, v := range t.Enums {
if v.Token.Val == nm {
return v
}
}
return nil
}
// IsUnsigned implements Type.
func (t *EnumType) IsUnsigned() bool { return t.Enums[0].Operand.Type.IsUnsigned() }
// IsVoidPointerType implements Type.
func (t *EnumType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *EnumType) IsArithmeticType() bool { return true }
// IsCompatible implements Type.
func (t *EnumType) IsCompatible(u Type) bool {
switch x := underlyingType(u, true).(type) {
case *EnumType:
if len(t.Enums) != len(x.Enums) {
return false
}
for i, v := range t.Enums {
if !v.equal(x.Enums[i]) {
return false
}
}
return true
default:
return false
}
}
// Equal implements Type.
func (t *EnumType) Equal(u Type) bool {
if t == u {
return true
}
switch x := UnderlyingType(u).(type) {
case *EnumType:
if t.Tag != x.Tag || len(t.Enums) != len(x.Enums) {
return false
}
for i, v := range t.Enums {
w := x.Enums[i]
if !v.Operand.Type.Equal(w.Operand.Type) || v.Operand.Value.(*ir.Int64Value).Value != w.Operand.Value.(*ir.Int64Value).Value {
return false
}
}
return true
case TypeKind:
if x.IsScalarType() {
return false
}
panic(fmt.Errorf("%v %T %v", t, x, x))
default:
panic(fmt.Errorf("%v %T %v", t, x, x))
}
}
// Kind implements Type.
func (t *EnumType) Kind() TypeKind { return Enum }
// assign implements Type.
func (t *EnumType) assign(ctx *context, n Node, op Operand) Operand {
return op.ConvertTo(ctx.model, t)
}
// IsPointerType implements Type.
func (t *EnumType) IsPointerType() bool { return false }
// IsIntegerType implements Type.
func (t *EnumType) IsIntegerType() bool { return true }
// IsScalarType implements Type.
func (t *EnumType) IsScalarType() bool { return true }
func (t *EnumType) String() string {
return fmt.Sprintf("%s enumeration %s", t.Enums[0].Operand.Type.String(), dict.S(t.Tag))
}
// Field represents a struct/union field.
type Field struct {
Bits int
Declarator *Declarator
Name int
PackedType Type // Bits != 0: underlaying struct field type
Type Type
Anonymous bool
}
func (f Field) equal(g Field) bool {
return f.Name == g.Name && f.Type.Equal(g.Type) && f.Bits == g.Bits
}
func (f Field) isCompatiblel(g Field) bool {
return f.Name == g.Name && f.Type.IsCompatible(g.Type) && f.Bits == g.Bits
}
func (f Field) String() string { return fmt.Sprintf("%s %v", dict.S(f.Name), f.Type) }
// FunctionType represents a function type.
type FunctionType struct {
Params []Type
Result Type
Variadic bool
params []int
}
// IsUnsigned implements Type.
func (t *FunctionType) IsUnsigned() bool { panic("TODO") }
// IsVoidPointerType implements Type.
func (t *FunctionType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *FunctionType) IsArithmeticType() bool { return false }
// IsCompatible implements Type.
func (t *FunctionType) IsCompatible(u Type) bool {
switch x := u.(type) {
case *FunctionType:
if t.Variadic != x.Variadic || !t.Result.IsCompatible(x.Result) {
return false
}
if len(t.Params) != len(x.Params) {
switch {
case len(t.Params) == 1 && len(x.Params) == 0 && t.Params[0].Kind() == Void:
return true
case len(t.Params) == 0 && len(x.Params) == 1 && x.Params[0].Kind() == Void:
return true
}
return false
}
for i, t := range t.Params {
if !t.IsCompatible(x.Params[i]) {
return false
}
}
return true
case *NamedType:
return x.Type.IsCompatible(t)
case *PointerType:
return x.Item.IsCompatible(t)
default:
panic(fmt.Errorf("%T", x))
}
}
// Equal implements Type.
func (t *FunctionType) Equal(u Type) bool {
if t == u {
return true
}
switch x := u.(type) {
case *FunctionType:
if len(t.Params) != len(x.Params) || t.Variadic != x.Variadic || !t.Result.Equal(x.Result) {
return false
}
for i, t := range t.Params {
if !t.Equal(x.Params[i]) {
return false
}
}
return true
case
*NamedType,
*PointerType,
*StructType:
return false
case TypeKind:
switch x {
case
Char,
Int,
Void:
return false
default:
panic(x)
}
default:
panic(fmt.Errorf("%T", x))
}
}
// Kind implements Type.
func (t *FunctionType) Kind() TypeKind { return Function }
// assign implements Type.
func (t *FunctionType) assign(ctx *context, n Node, op Operand) Operand {
switch x := UnderlyingType(op.Type).(type) {
case *PointerType:
switch y := UnderlyingType(x.Item).(type) {
case *FunctionType:
if !t.Equal(y) {
panic(fmt.Errorf("%v: %v != %v", ctx.position(n), t, y))
}
return op
default:
panic(fmt.Errorf("%v: %T", ctx.position(n), y))
}
default:
panic(fmt.Errorf("%v: %T", ctx.position(n), x))
}
}
// IsPointerType implements Type.
func (t *FunctionType) IsPointerType() bool { return false }
// IsIntegerType implements Type.
func (t *FunctionType) IsIntegerType() bool { return false }
// IsScalarType implements Type.
func (t *FunctionType) IsScalarType() bool { return false }
func (t *FunctionType) String() string {
var buf bytes.Buffer
buf.WriteString("function (")
switch {
case len(t.Params) == 1 && t.Params[0].Kind() == Void:
// nop
default:
for i, v := range t.Params {
if i != 0 {
buf.WriteString(", ")
}
buf.WriteString(v.String())
}
}
fmt.Fprintf(&buf, ") returning %v", t.Result)
return buf.String()
}
// NamedType represents a type described by a typedef name.
type NamedType struct {
Name int
Type Type // The type Name refers to.
}
// IsUnsigned implements Type.
func (t *NamedType) IsUnsigned() bool { return t.Type.IsUnsigned() }
// IsVoidPointerType implements Type.
func (t *NamedType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *NamedType) IsArithmeticType() bool { return t.Type.IsArithmeticType() }
// IsCompatible implements Type.
func (t *NamedType) IsCompatible(u Type) (r bool) {
return UnderlyingType(t.Type).IsCompatible(UnderlyingType(u))
}
// Equal implements Type.
func (t *NamedType) Equal(u Type) bool {
if t == u {
return true
}
switch x := u.(type) {
case *ArrayType:
return x.Equal(t.Type)
case *EnumType:
return x.Equal(t.Type)
case *NamedType:
return t.Name == x.Name && t.Type.Equal(x.Type)
case
*FunctionType,
*PointerType:
return x.Equal(t.Type)
case *StructType:
return t.Type.Equal(x)
case *TaggedEnumType:
v := x.getType()
return v != x && t.Type.Equal(v)
case *TaggedStructType:
v := x.getType()
return v != x && t.Type.Equal(v)
case *TaggedUnionType:
v := x.getType()
return v != x && t.Type.Equal(v)
case TypeKind:
switch x {
case
Char,
Double,
Float,
Int,
Long,
LongDouble,
LongLong,
SChar,
Short,
UChar,
UInt,
ULong,
ULongLong,
UShort,
Void:
return x.Equal(t.Type)
default:
panic(x)
}
case *UnionType:
return t.Type.Equal(x)
default:
panic(fmt.Errorf("%T: %v, %v", x, t.Type, u))
}
}
// Kind implements Type.
func (t *NamedType) Kind() TypeKind { return t.Type.Kind() }
// assign implements Type.
func (t *NamedType) assign(ctx *context, n Node, op Operand) Operand { return t.Type.assign(ctx, n, op) }
// IsPointerType implements Type.
func (t *NamedType) IsPointerType() bool { return t.Type.IsPointerType() }
// IsIntegerType implements Type.
func (t *NamedType) IsIntegerType() bool { return t.Type.IsIntegerType() }
// IsScalarType implements Type.
func (t *NamedType) IsScalarType() bool { return t.Type.IsScalarType() }
func (t *NamedType) String() string { return string(dict.S(t.Name)) }
// PointerType represents a pointer type.
type PointerType struct {
Item Type
}
// IsUnsigned implements Type.
func (t *PointerType) IsUnsigned() bool { return true }
// IsVoidPointerType implements Type.
func (t *PointerType) IsVoidPointerType() bool { return UnderlyingType(t.Item) == Void }
// IsArithmeticType implements Type.
func (t *PointerType) IsArithmeticType() bool { return false }
// IsCompatible implements Type.
func (t *PointerType) IsCompatible(u Type) bool {
if t.Equal(u) {
return true
}
var ai Type
switch x := UnderlyingType(t.Item).(type) {
case *ArrayType:
ai = x.Item
}
switch x := UnderlyingType(u).(type) {
case *ArrayType:
return t.Item.IsCompatible(x.Item)
case *NamedType:
return t.IsCompatible(x.Type)
case *FunctionType:
return x.IsCompatible(t)
case *PointerType:
// [0]6.3.2.3
//
// 1. A pointer to void may be converted to or from a pointer to any
// incomplete or object type. A pointer to any incomplete or object
// type may be converted to a pointer to void and back again; the
// result shall compare equal to the original pointer.
return t.Item == Void || x.Item == Void ||
ai != nil && ai.IsCompatible(x.Item) ||
underlyingType(t.Item, true).IsCompatible(underlyingType(x.Item, true)) ||
Unsigned(t.Item) == Unsigned(x.Item)
case *StructType:
return false
case TypeKind:
if u.IsArithmeticType() {
return false
}
panic(fmt.Errorf("%T\n%v\n%v", x, t, u))
default:
panic(fmt.Errorf("%T\n%v\n%v", x, t, u))
}
}
func Unsigned(t Type) TypeKind {
switch k := underlyingType(t, false).Kind(); k {
case Char, SChar:
return UChar
case Short:
return UShort
case Int:
return UInt
case Long:
return ULong
case LongLong:
return ULongLong
default:
return k
}
}
// Equal implements Type.
func (t *PointerType) Equal(u Type) bool {
if t == u {
return true
}
switch x := u.(type) {
case
*ArrayType,
*FunctionType,
*StructType,
*TaggedStructType,
*UnionType:
return false
case *NamedType:
return t.Equal(x.Type)
case *PointerType:
return t.Item.Equal(x.Item)
case TypeKind:
switch x {
case
Char,
Double,
Float,
Int,
Long,
LongLong,
Short,
UChar,
UInt,
ULong,
ULongLong,
UShort,
Void:
return false
default:
panic(x)
}
default:
panic(fmt.Errorf("%T", x))
}
}
// Kind implements Type.
func (t *PointerType) Kind() TypeKind { return Ptr }
// assign implements Type.
func (t *PointerType) assign(ctx *context, n Node, op Operand) (r Operand) {
u := UnderlyingType(t.Item)
var v Type
if op.Type.IsPointerType() {
v = UnderlyingType(UnderlyingType(op.Type).(*PointerType).Item)
}
// [0]6.5.16.1
switch {
// One of the following shall hold:
case ctx.tweaks.EnablePointerCompatibility && op.Type.IsPointerType():
return op.ConvertTo(ctx.model, t)
case
// both operands are pointers to qualified or unqualified
// versions of compatible types, and the type pointed to by the
// left has all the qualifiers of the type pointed to by the
// right;
op.Type.IsPointerType() && t.IsCompatible(op.Type),
u.IsIntegerType() && v != nil && v.IsIntegerType() && ctx.model.Sizeof(u) == ctx.model.Sizeof(v) && u.IsUnsigned() == v.IsUnsigned():
return op.ConvertTo(ctx.model, t)
case
// one operand is a pointer to an object or incomplete type and
// the other is a pointer to a qualified or unqualified version
// of void, and the type pointed to by the left has all the
// qualifiers of the type pointed to by the right;
t.IsPointerType() && op.Type.IsVoidPointerType():
panic("TODO")
case
// the left operand is a pointer and the right is a null
// pointer constant;
op.isNullPtrConst():
return Operand{Type: t, Value: Null}
default:
panic(fmt.Errorf("%v: lhs type %v <- operand %v, op.IsPointerType %v op.IsCompatible %v", ctx.position(n), t, op, op.Type.IsPointerType(), t.IsCompatible(op.Type)))
}
}
// IsPointerType implements Type.
func (t *PointerType) IsPointerType() bool { return true }
// IsIntegerType implements Type.
func (t *PointerType) IsIntegerType() bool { return false }
// IsScalarType implements Type.
func (t *PointerType) IsScalarType() bool { return true }
func (t *PointerType) String() string { return fmt.Sprintf("pointer to %v", t.Item) }
type structBase struct {
Fields []Field
Tag int
scope *Scope
layout []FieldProperties
}
func (s *structBase) findField(nm int) *FieldProperties {
fps := s.layout
if x, ok := s.scope.Idents[nm].(*Declarator); ok {
r := fps[x.Field]
return &r
}
for _, v := range fps {
if v.Declarator != nil {
continue
}
x, ok := v.Type.(fieldFinder)
if !ok {
continue
}
if fp := x.findField(nm); fp != nil {
r := *fp
r.Offset += v.Offset
return &r
}
}
return nil
}
// StructType represents a struct type.
type StructType struct{ structBase }
// IsUnsigned implements Type.
func (t *StructType) IsUnsigned() bool { panic("TODO") }
// Field returns the properties of field nm or nil if the field does not exist.
func (t *StructType) Field(nm int) *FieldProperties {
return t.findField(nm)
}
// IsVoidPointerType implements Type.
func (t *StructType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *StructType) IsArithmeticType() bool { return false }
// IsCompatible implements Type.
func (t *StructType) IsCompatible(u Type) bool {
if t.Equal(u) {
return true
}
// [0]6.2.7.1
//
// Moreover, two structure, union, or enumerated types declared in
// separate translation units are compatible if their tags and members
// satisfy the following requirements: If one is declared with a tag,
// the other shall be declared with the same tag. If both are complete
// types, then the following additional requirements apply: there shall
// be a one-to-one correspondence between their members such that each
// pair of corresponding members are declared with compatible types,
// and such that if one member of a corresponding pair is declared with
// a name, the other member is declared with the same name. For two
// structures, corresponding members shall be declared in the same
// order. For two structures or unions, corresponding bit-fields shall
// have the same widths.
switch x := UnderlyingType(u).(type) {
case *StructType:
//TODO if len(t.Fields) != len(x.Fields) || t.Tag != x.Tag { // Fails in _sqlite/src/test_fs.c
if len(t.Fields) != len(x.Fields) {
return false
}
for i, v := range t.Fields {
if !v.isCompatiblel(x.Fields[i]) {
return false
}
}
return true
default:
return false
}
}
// Equal implements Type.
func (t *StructType) Equal(u Type) bool {
if t == u {
return true
}
switch x := u.(type) {
case *NamedType:
return t.Equal(x.Type)
case
*ArrayType,
*FunctionType,
*PointerType:
return false
case *StructType:
if len(t.Fields) != len(x.Fields) || t.Tag != x.Tag {
return false
}
for i, v := range t.Fields {
if !v.equal(x.Fields[i]) {
return false
}
}
return true
case *TaggedStructType:
v := x.getType()
if v == u {
return false
}
return t.Equal(v)
case TypeKind:
switch x {
case
Char,
Int,
Long,
UChar,
UInt,
UShort,
Void:
return false
default:
panic(x)
}
default:
panic(fmt.Errorf("%T", x))
}
}
// Kind implements Type.
func (t *StructType) Kind() TypeKind { return Struct }
// assign implements Type.
func (t *StructType) assign(ctx *context, n Node, op Operand) Operand {
switch x := op.Type.(type) {
case *StructType:
if !t.IsCompatible(x) {
panic("TODO")
}
return Operand{Type: t}
case *NamedType:
if !t.IsCompatible(x.Type) {
panic("TODO")
}
return Operand{Type: t}
default:
panic(fmt.Errorf("%v: %T %v", ctx.position(n), x, x))
}
}
// IsPointerType implements Type.
func (t *StructType) IsPointerType() bool { return false }
// IsIntegerType implements Type.
func (t *StructType) IsIntegerType() bool { return false }
// IsScalarType implements Type.
func (t *StructType) IsScalarType() bool { return false }
func (t *StructType) String() string {
var buf bytes.Buffer
buf.WriteString("struct{")
for i, v := range t.Fields {
if i != 0 {
buf.WriteString("; ")
}
fmt.Fprintf(&buf, "%s %s", dict.S(v.Name), v.Type)
if v.Bits != 0 {
fmt.Fprintf(&buf, ".%d", v.Bits)
}
}
buf.WriteByte('}')
return buf.String()
}
// TaggedEnumType represents an enum type described by a tag name.
type TaggedEnumType struct {
Tag int
Type Type
scope *Scope
}
// IsUnsigned implements Type.
func (t *TaggedEnumType) IsUnsigned() bool { return t.Type.IsUnsigned() }
// Equal implements Type.
func (t *TaggedEnumType) Equal(u Type) bool {
switch x := UnderlyingType(u).(type) {
case *EnumType:
switch y := t.getType(); {
case y == t:
panic("TODO")
default:
return y.Equal(u)
}
case *TaggedEnumType:
if t.Tag == x.Tag {
return true
}
panic("TODO")
case TypeKind:
if x.IsScalarType() {
return false
}
panic(fmt.Errorf("%v", x))
default:
panic(fmt.Errorf("%T", x))
}
}
// IsArithmeticType implements Type.
func (t *TaggedEnumType) IsArithmeticType() bool { return true }
// IsCompatible implements Type.
func (t *TaggedEnumType) IsCompatible(u Type) bool {
switch x := t.getType(); {
case x == t:
panic("TODO")
default:
return underlyingType(x, true).IsCompatible(underlyingType(u, true))
}
}
// IsIntegerType implements Type.
func (t *TaggedEnumType) IsIntegerType() bool { return true }
// IsPointerType implements Type.
func (t *TaggedEnumType) IsPointerType() bool { return false }
// IsScalarType implements Type.
func (t *TaggedEnumType) IsScalarType() bool { return true }
// IsVoidPointerType implements Type.
func (t *TaggedEnumType) IsVoidPointerType() bool { panic("TODO") }
// Kind implements Type.
func (t *TaggedEnumType) Kind() TypeKind { return Int }
func (t *TaggedEnumType) String() string { return fmt.Sprintf("enum %s", dict.S(t.Tag)) }
// assign implements Type.
func (t *TaggedEnumType) assign(ctx *context, n Node, op Operand) Operand {
switch x := UnderlyingType(op.Type).(type) {
case *EnumType:
//TODO use IsCompatible
op.Type = t
return op
case TypeKind:
if x.IsIntegerType() {
op.Type = t
return op
}
panic(x)
default:
panic(fmt.Errorf("%T", x))
}
}
func (t *TaggedEnumType) getType() Type {
if t.Type != nil {
return t.Type
}
s := t.scope.lookupEnumTag(t.Tag)
if s == nil {
return t
}
t.Type = s.typ
return t.Type
}
// TaggedStructType represents a struct type described by a tag name.
type TaggedStructType struct {
Tag int
Type Type
scope *Scope
}
// IsUnsigned implements Type.
func (t *TaggedStructType) IsUnsigned() bool { panic("TODO") }
// IsVoidPointerType implements Type.
func (t *TaggedStructType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *TaggedStructType) IsArithmeticType() bool { return false }
// IsCompatible implements Type.
func (t *TaggedStructType) IsCompatible(u Type) bool {
if t == u {
return true
}
if x, ok := u.(*TaggedStructType); ok && t.Tag == x.Tag {
return true
}
a := UnderlyingType(t)
b := UnderlyingType(u)
return UnderlyingType(a).IsCompatible(UnderlyingType(b))
}
// Equal implements Type.
func (t *TaggedStructType) Equal(u Type) bool {
if t == u {
return true
}
if x, ok := u.(*TaggedStructType); ok && t.Tag == x.Tag {
return true
}
switch x := t.getType().(type) {
case *StructType:
return x.Equal(u)
case *TaggedStructType:
if x == t {
switch y := u.(type) {
case *NamedType:
return t.Equal(y.Type)
case *StructType:
return false
case *TaggedStructType:
return t.Tag == y.Tag
case TypeKind:
switch y {
case Void:
return false
default:
panic(y)
}
default:
panic(fmt.Errorf("%T", y))
}
}
panic("TODO")
default:
panic(fmt.Errorf("%T", x))
}
}
func (t *TaggedStructType) getType() Type {
if t.Type != nil {
return t.Type
}
s := t.scope.lookupStructTag(t.Tag)
if s == nil {
return t
}
t.Type = s.typ
return t.Type
}
// Kind implements Type.
func (t *TaggedStructType) Kind() TypeKind { return Struct }
// assign implements Type.
func (t *TaggedStructType) assign(ctx *context, n Node, op Operand) Operand {
switch x := op.Type.(type) {
case *NamedType:
op.Type = x.Type
return t.assign(ctx, n, op)
case *TaggedStructType:
t2 := t.getType()
u2 := x.getType()
if t2 != t && u2 != x {
// [0]6.5.16.1
//
// the left operand has a qualified or unqualified
// version of a structure or union type compatible with
// the type of the right;
if t2.Equal(u2) {
return op
}
panic("TODO")
}
panic("TODO")
case *StructType:
t2 := t.getType()
if t2.Equal(x) {
return op
}
panic(fmt.Errorf("%v: %T %v, %T %v", ctx.position(n), t2, t2, x, x))
default:
panic(fmt.Errorf("%T", x))
}
}
// IsPointerType implements Type.
func (t *TaggedStructType) IsPointerType() bool { return false }
// IsIntegerType implements Type.
func (t *TaggedStructType) IsIntegerType() bool { return false }
// IsScalarType implements Type.
func (t *TaggedStructType) IsScalarType() bool { return false }
func (t *TaggedStructType) String() string { return fmt.Sprintf("struct %s", dict.S(t.Tag)) }
// UnionType represents a union type.
type UnionType struct{ structBase }
// Field returns the properties of field nm or nil if the field does not exist.
func (t *UnionType) Field(nm int) *FieldProperties {
return t.findField(nm)
}
// IsUnsigned implements Type.
func (t *UnionType) IsUnsigned() bool { panic("TODO") }
// TaggedUnionType represents a struct type described by a tag name.
type TaggedUnionType struct {
Tag int
Type Type
scope *Scope
}
// IsUnsigned implements Type.
func (t *TaggedUnionType) IsUnsigned() bool { panic("TODO") }
// IsVoidPointerType implements Type.
func (t *TaggedUnionType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *TaggedUnionType) IsArithmeticType() bool { return false }
// IsCompatible implements Type.
func (t *TaggedUnionType) IsCompatible(u Type) bool { return t.Equal(u) }
// Equal implements Type.
func (t *TaggedUnionType) Equal(u Type) bool {
if t == u {
return true
}
if x, ok := u.(*TaggedUnionType); ok && t.Tag == x.Tag {
return true
}
switch x := t.getType().(type) {
case *UnionType:
return x.Equal(u)
default:
panic(fmt.Errorf("%T", x))
}
}
func (t *TaggedUnionType) getType() Type {
if t.Type != nil {
return t.Type
}
s := t.scope.lookupStructTag(t.Tag)
if s == nil {
return t
}
t.Type = s.typ
return t.Type
}
// Kind implements Type.
func (t *TaggedUnionType) Kind() TypeKind { return Union }
// assign implements Type.
func (t *TaggedUnionType) assign(ctx *context, n Node, op Operand) Operand {
switch x := op.Type.(type) {
case *TaggedUnionType:
t2 := t.getType()
u2 := x.getType()
if t2 != t && u2 != x {
// [0]6.5.16.1
//
// the left operand has a qualified or unqualified
// version of a structure or union type compatible with
// the type of the right;
if t2.Equal(u2) {
return op
}
panic("TODO")
}
panic("TODO")
default:
panic(fmt.Errorf("%T", x))
}
}
// IsPointerType implements Type.
func (t *TaggedUnionType) IsPointerType() bool { return false }
// IsIntegerType implements Type.
func (t *TaggedUnionType) IsIntegerType() bool { return false }
// IsScalarType implements Type.
func (t *TaggedUnionType) IsScalarType() bool { return false }
func (t *TaggedUnionType) String() string { return fmt.Sprintf("union %s", dict.S(t.Tag)) }
// IsVoidPointerType implements Type.
func (t *UnionType) IsVoidPointerType() bool { panic("TODO") }
// IsArithmeticType implements Type.
func (t *UnionType) IsArithmeticType() bool { return false }
// IsCompatible implements Type.
func (t *UnionType) IsCompatible(u Type) bool {
if t.Equal(u) {
return true
}
switch x := UnderlyingType(u).(type) {
case TypeKind:
if x.IsScalarType() {
return false
}
panic(fmt.Errorf("%v %T %v", t, x, x))
default:
panic(fmt.Errorf("%v %T %v", t, x, x))
}
}
// Equal implements Type.
func (t *UnionType) Equal(u Type) bool {
if t == u {
return true
}
switch x := u.(type) {
case *NamedType:
return t.Equal(x.Type)
case *PointerType:
return false
case *TaggedUnionType:
v := x.Type
if v == x {
panic(x)
}
return t.Equal(v)
case TypeKind:
switch x {
case
Char,
Int,
UInt,
ULongLong,
Void:
return false
default:
panic(x)
}
case *UnionType:
if len(t.Fields) != len(x.Fields) || t.Tag != x.Tag {
return false
}
for i, v := range t.Fields {
if !v.equal(x.Fields[i]) {
return false
}
}
return true
default:
panic(x)
}
}
// Kind implements Type.
func (t *UnionType) Kind() TypeKind { return Union }
// assign implements Type.
func (t *UnionType) assign(ctx *context, n Node, op Operand) Operand {
switch x := op.Type.(type) {
case *NamedType:
if !t.IsCompatible(x.Type) {
panic("TODO")
}
return Operand{Type: t}
case *UnionType:
if !t.IsCompatible(x) {
panic("TODO")
}
return Operand{Type: t}
default:
panic(fmt.Errorf("%v: %T %v", ctx.position(n), x, x))
}
}
// IsPointerType implements Type.
func (t *UnionType) IsPointerType() bool { return false }
// IsIntegerType implements Type.
func (t *UnionType) IsIntegerType() bool { return false }
// IsScalarType implements Type.
func (t *UnionType) IsScalarType() bool { return false }
func (t *UnionType) String() string {
var buf bytes.Buffer
buf.WriteString("union{")
for i, v := range t.Fields {
if i != 0 {
buf.WriteString("; ")
}
fmt.Fprintf(&buf, "%s %s", dict.S(v.Name), v.Type)
if v.Bits != 0 {
fmt.Fprintf(&buf, ".%d", v.Bits)
}
}
buf.WriteByte('}')
return buf.String()
}
// AdjustedParameterType returns the type of an expression when used as an
// argument of a function, see [0]6.9.1-10.
func AdjustedParameterType(t Type) Type {
u := t
for {
switch x := u.(type) {
case *ArrayType:
return &PointerType{t}
case *NamedType:
if isVaList(x) {
return x
}
u = x.Type
case
*EnumType,
*PointerType,
*StructType,
*TaggedEnumType,
*TaggedStructType,
*TaggedUnionType,
*UnionType:
return t
case TypeKind:
switch x {
case
Char,
Double,
DoubleComplex,
LongDouble,
Float,
FloatComplex,
Int,
Long,
LongDoubleComplex,
LongLong,
SChar,
Short,
UChar,
UInt,
ULong,
ULongLong,
UShort:
return t
default:
panic(x)
}
default:
panic(fmt.Errorf("%T", x))
}
}
}
// UnderlyingType returns the concrete type of t, if posible.
func UnderlyingType(t Type) Type { return underlyingType(t, false) }
func underlyingType(t Type, enums bool) Type {
for {
switch x := t.(type) {
case
*ArrayType,
*FunctionType,
*PointerType,
*StructType,
*UnionType:
return x
case *EnumType:
if enums {
return x
}
return x.Enums[0].Operand.Type
case *NamedType:
if x.Type == nil {
return x
}
t = x.Type
case *TaggedEnumType:
if x.Type == nil {
return x
}
t = x.Type
case *TaggedStructType:
if x.Type == nil {
return x
}
t = x.Type
case *TaggedUnionType:
if x.Type == nil {
return x
}
t = x.Type
case TypeKind:
switch x {
case
Bool,
Char,
Double,
DoubleComplex,
Float,
FloatComplex,
Int,
Long,
LongDouble,
LongDoubleComplex,
LongLong,
Ptr,
SChar,
Short,
UChar,
UInt,
ULong,
ULongLong,
UShort,
Void:
return x
default:
panic(fmt.Errorf("%v", x))
}
default:
panic(fmt.Errorf("%T", x))
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。