dvander@143: /* vim: set ts=4 sw=4 tw=99 et: dvander@143: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@143: * This file is part of SourcePawn. dvander@0: * dvander@143: * SourcePawn is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@143: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@143: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@0: */ danderson@92: #include dvander@0: #include "Types.h" dvander@11: #include "Zone.h" dvander@54: #include "Strings.h" dvander@148: #include "Structures.h" dvander@11: #include "Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@11: Type * dvander@71: Type::NewVoid(Zone *zone) dvander@71: { dvander@71: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@71: if (!type) dvander@71: return NULL; dvander@71: dvander@71: type->kind_ = VOID; dvander@71: return type; dvander@71: } dvander@71: dvander@71: Type * dvander@167: Type::NewUnchecked(Zone *zone) dvander@167: { dvander@167: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@167: if (!type) dvander@167: return NULL; dvander@167: dvander@167: type->kind_ = UNCHECKED; dvander@167: return type; dvander@167: } dvander@167: dvander@167: Type * dvander@12: Type::NewPrimitive(Zone *zone, PrimitiveType prim) dvander@12: { dvander@41: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@41: if (!type) dvander@12: return NULL; dvander@12: dvander@13: type->kind_ = PRIMITIVE; dvander@145: type->name_ = NULL; dvander@209: type->primitive_ = prim; dvander@12: return type; dvander@12: } dvander@12: dvander@209: ArrayType * dvander@209: ArrayType::New(Zone *zone, Handle contained, int elements) dvander@4: { dvander@212: if (contained->isArray() && dvander@212: ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH) dvander@212: { dvander@212: zone->reportError(Message_MaximumArrayDepth); dvander@212: return NULL; dvander@212: } dvander@212: dvander@209: Local type(zone, ArrayType::cast(zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old))); dvander@41: if (!type) dvander@11: return NULL; dvander@11: dvander@14: type->kind_ = ARRAY; dvander@145: type->name_ = NULL; dvander@13: type->contained_ = contained; dvander@13: type->elements_ = elements; dvander@145: if (!contained->isArray()) dvander@13: type->levels_ = 1; dvander@13: else dvander@209: type->levels_ = ArrayType::cast(contained)->levels() + 1; dvander@0: return type; dvander@0: } dvander@14: dvander@209: ArrayType * dvander@209: ArrayType::NewExternal(Zone *zone, Handle contained) dvander@188: { dvander@209: Local type(zone, ArrayType::cast(zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old))); dvander@188: if (!type) dvander@188: return NULL; dvander@188: dvander@188: assert(contained->isPrimitive()); dvander@188: dvander@188: type->kind_ = EXTERNAL_ARRAY; dvander@188: type->name_ = NULL; dvander@188: type->contained_ = contained; dvander@188: type->elements_ = DYNAMIC_ARRAY_SIZE; dvander@188: type->levels_ = 1; dvander@188: return type; dvander@188: } dvander@188: dvander@188: Type * dvander@67: Type::NewReference(Zone *zone, Handle contained, bool isConst) dvander@14: { dvander@41: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@41: if (!type) dvander@14: return NULL; dvander@14: dvander@14: type->kind_ = REFERENCE; dvander@145: type->name_ = NULL; dvander@67: type->const_ = isConst; dvander@14: return type; dvander@14: } dvander@14: dvander@14: Type * dvander@145: Type::NewEnum(Zone *zone, Handle name) dvander@145: { dvander@145: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@145: if (!type) dvander@145: return NULL; dvander@145: dvander@145: type->kind_ = ENUM; dvander@145: type->name_ = name; dvander@146: return type; dvander@146: } dvander@146: dvander@195: #if 0 dvander@145: Type * dvander@168: Type::NewNative(Zone *zone, Handle returnType, Handle parameters, dvander@168: Handle defaults, bool variadic) dvander@68: { dvander@68: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@68: if (!type) dvander@68: return NULL; dvander@68: dvander@68: type->kind_ = NATIVE; dvander@145: type->name_ = NULL; dvander@68: type->contained_ = NULL; dvander@146: type->fields_ = NULL; dvander@147: type->newMap_ = NULL; dvander@68: type->returnType_ = returnType; dvander@68: type->parameters_ = parameters; dvander@168: type->defaults_ = defaults; dvander@68: type->variadicNative_ = variadic; dvander@68: return type; dvander@68: } dvander@195: #endif dvander@68: dvander@63: bool dvander@63: Type::Compare(Type *left, Type *right) dvander@63: { dvander@145: if (left == right) dvander@145: return true; dvander@145: dvander@63: if (left->kind() != right->kind()) dvander@63: return false; dvander@63: dvander@63: switch (left->kind()) { dvander@63: case Type::PRIMITIVE: dvander@145: return left->primitive() == right->primitive(); dvander@63: dvander@63: case Type::ARRAY: dvander@63: { dvander@209: ArrayType *aleft = ArrayType::cast(left); dvander@209: ArrayType *aright = ArrayType::cast(right); dvander@209: if (aleft->levels() != aright->levels()) dvander@184: return false; dvander@209: if (aleft->isFixedLength() != aright->isFixedLength()) dvander@209: return false; dvander@209: if (aleft->isFixedLength() && aleft->fixedLength() != aright->fixedLength()) dvander@209: return false; dvander@209: return Compare(aleft->contained(), aright->contained()); dvander@63: } dvander@63: dvander@63: case Type::FUNCTION: dvander@63: { dvander@195: FunctionType *fleft = FunctionType::cast(left); dvander@195: FunctionType *fright = FunctionType::cast(right); dvander@195: if (!Compare(fleft->returnType(), fright->returnType())) dvander@63: return false; dvander@195: if (fleft->parameters()->length() != fright->parameters()->length()) dvander@69: return false; dvander@195: if (fleft->isNative() != fright->isNative()) dvander@195: return false; dvander@195: if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic())) dvander@69: return false; dvander@195: for (unsigned i = 0; i < fleft->parameters()->length(); i++) { dvander@195: Type *leftparam = fleft->parameterAt(i); dvander@195: Type *rightparam = fright->parameterAt(i); dvander@63: if (!Compare(leftparam, rightparam)) dvander@63: return false; dvander@63: } dvander@63: return true; dvander@63: } dvander@63: dvander@145: case Type::ENUM: dvander@145: return false; dvander@145: dvander@124: case Type::VOID: dvander@124: return true; dvander@124: dvander@63: default: dvander@63: assert(left->kind() == Type::REFERENCE); dvander@209: return Compare(left->contained_ref(), right->contained_ref()); dvander@63: } dvander@63: } dvander@148: dvander@195: StructType * dvander@195: StructType::New(Zone *zone, Handle name, Handle fields) dvander@148: { dvander@195: Local type(zone, StructType::cast(zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old))); dvander@195: if (!type) dvander@195: return NULL; dvander@195: dvander@195: type->kind_ = STRUCT; dvander@195: type->name_ = name; dvander@195: type->newMap_ = NULL; dvander@195: type->fields_ = fields; dvander@195: dvander@195: // Fill in field offsets. dvander@195: StructureBufferBuilder builder; dvander@195: Local fieldType(zone); dvander@195: for (size_t i = 0; i < fields->length(); i++) { dvander@195: Descriptor *desc = Descriptor::cast(fields->at(i)); dvander@195: fieldType = desc->type(); dvander@148: dvander@195: unsigned offset; dvander@195: if (!builder.add(fieldType, &offset)) dvander@195: return NULL; dvander@195: desc->setOffset(offset); dvander@195: } dvander@195: dvander@195: Local map(zone, StructMap::New(zone, builder, type)); dvander@195: if (!map) dvander@195: return NULL; dvander@195: dvander@195: type->newMap_ = map; dvander@195: dvander@195: return type; dvander@195: } dvander@195: dvander@195: Descriptor * dvander@195: StructType::lookupField(Handle name, unsigned *index) dvander@195: { dvander@148: for (unsigned i = 0; i < fields_->length(); i++) { dvander@148: Descriptor *desc = Descriptor::cast(fields_->at(i)); dvander@148: if (desc->name() == name) { dvander@195: if (index) dvander@195: *index = i; dvander@148: return desc; dvander@148: } dvander@148: } dvander@148: dvander@148: return NULL; dvander@148: } dvander@148: dvander@195: FunctionType * dvander@195: FunctionType::New(Zone *zone, TokenKind token) dvander@195: { dvander@195: Local type(zone, FunctionType::cast(zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old))); dvander@195: if (!type) dvander@195: return NULL; dvander@195: dvander@195: type->kind_ = FUNCTION; dvander@195: type->name_ = NULL; dvander@195: type->parameters_ = NULL; dvander@195: type->defaults_ = NULL; dvander@195: type->returnType_ = NULL; dvander@195: type->token_ = token; dvander@195: return type; dvander@195: } dvander@195: dvander@195: // :TODO: this leaks an interior pointer. dvander@195: const char * dvander@195: ke::GetTypeName(Type *type) dvander@195: { dvander@195: if (type->isArray()) dvander@195: return "array"; dvander@195: if (type->isFunction()) dvander@195: return "function"; dvander@195: if (type->isVoid()) dvander@195: return "void"; dvander@195: if (type->isEnum() || type->isStruct()) dvander@195: return type->name()->chars(); dvander@195: if (type->isReference()) dvander@209: type = type->contained_ref(); dvander@195: switch (type->primitive()) { dvander@195: case PrimitiveType_Bool: dvander@195: return "bool"; dvander@195: case PrimitiveType_Char: dvander@195: return "String"; dvander@195: case PrimitiveType_Int32: dvander@195: return "int"; dvander@195: case PrimitiveType_Float: dvander@195: return "Float"; dvander@195: default: dvander@195: return ""; dvander@195: } dvander@195: } dvander@195: