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@256: #include "Array.h" dvander@148: #include "Structures.h" dvander@11: #include "Heap-inl.h" dvander@0: dvander@59: using namespace ke; dvander@0: dvander@238: void dvander@240: Type::init(Kind kind, Type *root) dvander@238: { dvander@238: this->kind_ = kind; dvander@240: this->root_ = root ? root : this; dvander@238: } dvander@238: 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@238: type->init(VOID); dvander@71: return type; dvander@71: } dvander@71: dvander@71: Type * dvander@256: Type::NewImportable(Zone *zone) dvander@256: { dvander@256: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@256: if (!type) dvander@256: return NULL; dvander@256: dvander@256: type->init(IMPORTABLE); dvander@256: return type; dvander@256: } dvander@256: dvander@256: Type * dvander@235: Type::NewString(Zone *zone) dvander@235: { dvander@235: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@235: if (!type) dvander@235: return NULL; dvander@235: dvander@238: type->init(STRING); dvander@235: return type; dvander@235: } dvander@235: dvander@235: 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@238: type->init(UNCHECKED); dvander@167: return type; dvander@167: } dvander@167: dvander@167: Type * dvander@261: Type::NewType(Zone *zone) dvander@261: { dvander@261: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@261: if (!type) dvander@261: return NULL; dvander@261: dvander@261: type->init(TYPE); dvander@261: return type; dvander@261: } dvander@261: dvander@261: 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@238: type->init(PRIMITIVE); dvander@233: type->primitive_ = prim; dvander@12: return type; dvander@12: } dvander@12: dvander@240: Type * dvander@240: Type::NewQualified(Zone *zone, TypeQualifiers qual, Handle root) dvander@240: { dvander@240: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); dvander@240: if (!type) dvander@240: return NULL; dvander@240: dvander@240: type->init(QUALTYPE, root); dvander@240: type->quals_ = qual; dvander@240: return type; dvander@240: } dvander@240: 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@239: Local type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)); dvander@41: if (!type) dvander@11: return NULL; dvander@11: dvander@238: type->init(ARRAY); 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@256: dvander@256: type->newMap_ = ArrayMap::New(zone, type); dvander@256: if (!type->newMap_) dvander@256: return NULL; dvander@256: dvander@0: return type; dvander@0: } dvander@14: dvander@209: ArrayType * dvander@209: ArrayType::NewExternal(Zone *zone, Handle contained) dvander@188: { dvander@239: Local type(zone, (ArrayType *)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@238: type->init(EXTERNAL_ARRAY); 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@222: ReferenceType * dvander@222: ReferenceType::New(Zone *zone, Handle contained) dvander@14: { dvander@239: Local type(zone, (ReferenceType *)zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old)); dvander@41: if (!type) dvander@14: return NULL; dvander@14: dvander@238: type->init(REFERENCE); dvander@222: type->contained_ = contained; dvander@14: return type; dvander@14: } dvander@14: dvander@233: EnumType * dvander@233: EnumType::New(Zone *zone, Handle name) dvander@145: { dvander@239: Local type(zone, (EnumType *)zone->allocate(MapKind_EnumType, sizeof(EnumType), Heap::Tenure_Old)); dvander@145: if (!type) dvander@145: return NULL; dvander@145: dvander@238: type->init(ENUM); dvander@145: type->name_ = name; dvander@261: type->fields_ = NULL; dvander@146: return type; dvander@146: } dvander@146: dvander@195: StructType * dvander@195: StructType::New(Zone *zone, Handle name, Handle fields) dvander@148: { dvander@239: Local type(zone, (StructType *)zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old)); dvander@195: if (!type) dvander@195: return NULL; dvander@195: dvander@238: type->init(STRUCT); dvander@195: type->newMap_ = NULL; dvander@195: type->fields_ = fields; dvander@233: type->name_ = name; 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@258: StructType::lookupField(String *name, unsigned *index) dvander@195: { dvander@258: // :TODO: assert no GC 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@233: FunctionType::New(Zone *zone, Handle name, TokenKind token) dvander@195: { dvander@239: Local type(zone, (FunctionType *)zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old)); dvander@195: if (!type) dvander@195: return NULL; dvander@195: dvander@238: type->init(FUNCTION); dvander@195: type->parameters_ = NULL; dvander@195: type->defaults_ = NULL; dvander@195: type->returnType_ = NULL; dvander@233: type->name_ = name; dvander@195: type->token_ = token; dvander@195: return type; dvander@195: } dvander@195: dvander@241: static size_t dvander@241: FormatVA(char *buffer, size_t maxlen, const char *text, va_list ap) dvander@241: { dvander@241: size_t len = vsnprintf(buffer, maxlen, text, ap); dvander@241: if (len >= maxlen) { dvander@241: buffer[maxlen - 1] = '\0'; dvander@241: return maxlen - 1; dvander@241: } dvander@241: return len; dvander@241: } dvander@241: dvander@241: static size_t dvander@241: Format(char *buffer, size_t maxlen, const char *text, ...) dvander@195: { dvander@241: va_list ap; dvander@241: va_start(ap, text); dvander@241: size_t len = FormatVA(buffer, maxlen, text, ap); dvander@241: va_end(ap); dvander@241: return len; dvander@241: } dvander@241: dvander@241: static size_t dvander@241: FormatTypeName(Type *type, char *buffer, size_t maxlen) dvander@241: { dvander@241: if (type->isArray()) { dvander@241: ArrayType *atype = ArrayType::cast(type); dvander@241: Type *innermost = atype->innermost(); dvander@241: dvander@241: size_t len = FormatTypeName(innermost, buffer, maxlen); dvander@241: for (;;) { dvander@241: if (atype->isFixedLength()) dvander@241: len += Format(buffer + len, maxlen - len, "[%d]", atype->fixedLength()); dvander@241: else dvander@241: len += Format(buffer + len, maxlen - len, "[]"); dvander@241: if (!atype->contained()->isArray()) dvander@241: break; dvander@241: atype = ArrayType::cast(atype->contained()); dvander@241: } dvander@241: return len; dvander@241: } dvander@241: if (type->hasTypeQualifiers()) { dvander@241: size_t len = 0; dvander@241: if (type->quals() & TypeQual_Const) dvander@241: len += Format(buffer, maxlen, "const "); dvander@241: return len + FormatTypeName(type->unqualified(), buffer + len, maxlen - len); dvander@241: } dvander@195: if (type->isFunction()) dvander@241: return Format(buffer, maxlen, "function"); dvander@195: if (type->isVoid()) dvander@241: return Format(buffer, maxlen, "void"); dvander@241: if (type->isUnchecked()) dvander@241: return Format(buffer, maxlen, "unchecked"); dvander@256: if (type->isImportable()) dvander@256: return Format(buffer, maxlen, "import"); dvander@233: if (type->isEnum()) dvander@241: return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars()); dvander@233: if (type->isStruct()) dvander@241: return Format(buffer, maxlen, "%s", StructType::cast(type)->name()->chars()); dvander@241: if (type->isReference()) { dvander@241: ReferenceType *ref = ReferenceType::cast(type); dvander@241: size_t len = Format(buffer, maxlen, "&"); dvander@241: return len + FormatTypeName(ref->contained(), buffer + len, maxlen - len); dvander@241: } dvander@195: switch (type->primitive()) { dvander@195: case PrimitiveType_Bool: dvander@241: return Format(buffer, maxlen, "bool"); dvander@195: case PrimitiveType_Char: dvander@241: return Format(buffer, maxlen, "char"); dvander@195: case PrimitiveType_Int32: dvander@241: return Format(buffer, maxlen, "int"); dvander@195: case PrimitiveType_Float: dvander@241: return Format(buffer, maxlen, "float"); dvander@195: default: dvander@241: return Format(buffer, maxlen, ""); dvander@195: } dvander@195: } dvander@241: dvander@241: const char * dvander@241: ke::GetTypeName(Type *type, char *buffer, size_t maxlen) dvander@241: { dvander@241: FormatTypeName(type, buffer, maxlen); dvander@241: return buffer; dvander@241: }