asherkin@263: /* vim: set ts=4 sw=4 tw=99 et: asherkin@263: * asherkin@263: * Copyright (C) 2012 David Anderson asherkin@263: * asherkin@263: * This file is part of SourcePawn. asherkin@263: * asherkin@263: * SourcePawn is free software: you can redistribute it and/or modify it under asherkin@263: * the terms of the GNU General Public License as published by the Free asherkin@263: * Software Foundation, either version 3 of the License, or (at your option) asherkin@263: * any later version. asherkin@263: * asherkin@263: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY asherkin@263: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS asherkin@263: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. asherkin@263: * asherkin@263: * You should have received a copy of the GNU General Public License along with asherkin@263: * SourcePawn. If not, see http://www.gnu.org/licenses/. asherkin@263: */ asherkin@263: #include asherkin@263: #include "Types.h" asherkin@263: #include "Zone.h" asherkin@263: #include "Strings.h" asherkin@263: #include "Array.h" asherkin@263: #include "Structures.h" asherkin@263: #include "Heap-inl.h" asherkin@263: asherkin@263: using namespace ke; asherkin@263: asherkin@263: void asherkin@263: Type::init(Kind kind, Type *root) asherkin@263: { asherkin@263: this->kind_ = kind; asherkin@263: this->root_ = root ? root : this; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: Type::NewVoid(Zone *zone) asherkin@263: { asherkin@263: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(VOID); asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: Type::NewImportable(Zone *zone) asherkin@263: { asherkin@263: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(IMPORTABLE); asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: Type::NewString(Zone *zone) asherkin@263: { asherkin@263: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(STRING); asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: Type::NewUnchecked(Zone *zone) asherkin@263: { asherkin@263: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(UNCHECKED); asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: Type::NewType(Zone *zone) asherkin@263: { asherkin@263: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(TYPE); asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: Type::NewPrimitive(Zone *zone, PrimitiveType prim) asherkin@263: { asherkin@263: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(PRIMITIVE); asherkin@263: type->primitive_ = prim; asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: Type * asherkin@263: Type::NewQualified(Zone *zone, TypeQualifiers qual, Handle root) asherkin@263: { asherkin@263: Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(QUALTYPE, root); asherkin@263: type->quals_ = qual; asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: ArrayType * asherkin@263: ArrayType::New(Zone *zone, Handle contained, int elements) asherkin@263: { asherkin@263: if (contained->isArray() && asherkin@263: ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH) asherkin@263: { asherkin@263: zone->reportError(Message_MaximumArrayDepth); asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: Local type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(ARRAY); asherkin@263: type->contained_ = contained; asherkin@263: type->elements_ = elements; asherkin@263: if (!contained->isArray()) asherkin@263: type->levels_ = 1; asherkin@263: else asherkin@263: type->levels_ = ArrayType::cast(contained)->levels() + 1; asherkin@263: asherkin@263: type->newMap_ = ArrayMap::New(zone, type); asherkin@263: if (!type->newMap_) asherkin@263: return NULL; asherkin@263: asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: ArrayType * asherkin@263: ArrayType::NewExternal(Zone *zone, Handle contained) asherkin@263: { asherkin@263: Local type(zone, (ArrayType *)zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: assert(contained->isPrimitive()); asherkin@263: asherkin@263: type->init(EXTERNAL_ARRAY); asherkin@263: type->contained_ = contained; asherkin@263: type->elements_ = DYNAMIC_ARRAY_SIZE; asherkin@263: type->levels_ = 1; asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: ReferenceType * asherkin@263: ReferenceType::New(Zone *zone, Handle contained) asherkin@263: { asherkin@263: Local type(zone, (ReferenceType *)zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old)); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(REFERENCE); asherkin@263: type->contained_ = contained; asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: EnumType * asherkin@263: EnumType::New(Zone *zone, Handle name) asherkin@263: { asherkin@263: Local type(zone, (EnumType *)zone->allocate(MapKind_EnumType, sizeof(EnumType), Heap::Tenure_Old)); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(ENUM); asherkin@263: type->name_ = name; asherkin@263: type->fields_ = NULL; asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: StructType * asherkin@263: StructType::New(Zone *zone, Handle name, Handle fields) asherkin@263: { asherkin@263: Local type(zone, (StructType *)zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old)); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(STRUCT); asherkin@263: type->newMap_ = NULL; asherkin@263: type->fields_ = fields; asherkin@263: type->name_ = name; asherkin@263: asherkin@263: // Fill in field offsets. asherkin@263: StructureBufferBuilder builder; asherkin@263: Local fieldType(zone); asherkin@263: for (size_t i = 0; i < fields->length(); i++) { asherkin@263: Descriptor *desc = Descriptor::cast(fields->at(i)); asherkin@263: fieldType = desc->type(); asherkin@263: asherkin@263: unsigned offset; asherkin@263: if (!builder.add(fieldType, &offset)) asherkin@263: return NULL; asherkin@263: desc->setOffset(offset); asherkin@263: } asherkin@263: asherkin@263: Local map(zone, StructMap::New(zone, builder, type)); asherkin@263: if (!map) asherkin@263: return NULL; asherkin@263: asherkin@263: type->newMap_ = map; asherkin@263: asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: Descriptor * asherkin@263: StructType::lookupField(String *name, unsigned *index) asherkin@263: { asherkin@263: // :TODO: assert no GC asherkin@263: for (unsigned i = 0; i < fields_->length(); i++) { asherkin@263: Descriptor *desc = Descriptor::cast(fields_->at(i)); asherkin@263: if (desc->name() == name) { asherkin@263: if (index) asherkin@263: *index = i; asherkin@263: return desc; asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: return NULL; asherkin@263: } asherkin@263: asherkin@263: FunctionType * asherkin@263: FunctionType::New(Zone *zone, Handle name, TokenKind token) asherkin@263: { asherkin@263: Local type(zone, (FunctionType *)zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old)); asherkin@263: if (!type) asherkin@263: return NULL; asherkin@263: asherkin@263: type->init(FUNCTION); asherkin@263: type->parameters_ = NULL; asherkin@263: type->defaults_ = NULL; asherkin@263: type->returnType_ = NULL; asherkin@263: type->name_ = name; asherkin@263: type->token_ = token; asherkin@263: return type; asherkin@263: } asherkin@263: asherkin@263: static size_t asherkin@263: FormatVA(char *buffer, size_t maxlen, const char *text, va_list ap) asherkin@263: { asherkin@263: size_t len = vsnprintf(buffer, maxlen, text, ap); asherkin@263: if (len >= maxlen) { asherkin@263: buffer[maxlen - 1] = '\0'; asherkin@263: return maxlen - 1; asherkin@263: } asherkin@263: return len; asherkin@263: } asherkin@263: asherkin@263: static size_t asherkin@263: Format(char *buffer, size_t maxlen, const char *text, ...) asherkin@263: { asherkin@263: va_list ap; asherkin@263: va_start(ap, text); asherkin@263: size_t len = FormatVA(buffer, maxlen, text, ap); asherkin@263: va_end(ap); asherkin@263: return len; asherkin@263: } asherkin@263: asherkin@263: static size_t asherkin@263: FormatTypeName(Type *type, char *buffer, size_t maxlen) asherkin@263: { asherkin@263: if (type->isArray()) { asherkin@263: ArrayType *atype = ArrayType::cast(type); asherkin@263: Type *innermost = atype->innermost(); asherkin@263: asherkin@263: size_t len = FormatTypeName(innermost, buffer, maxlen); asherkin@263: for (;;) { asherkin@263: if (atype->isFixedLength()) asherkin@263: len += Format(buffer + len, maxlen - len, "[%d]", atype->fixedLength()); asherkin@263: else asherkin@263: len += Format(buffer + len, maxlen - len, "[]"); asherkin@263: if (!atype->contained()->isArray()) asherkin@263: break; asherkin@263: atype = ArrayType::cast(atype->contained()); asherkin@263: } asherkin@263: return len; asherkin@263: } asherkin@263: if (type->hasTypeQualifiers()) { asherkin@263: size_t len = 0; asherkin@263: if (type->quals() & TypeQual_Const) asherkin@263: len += Format(buffer, maxlen, "const "); asherkin@263: return len + FormatTypeName(type->unqualified(), buffer + len, maxlen - len); asherkin@263: } asherkin@263: if (type->isFunction()) asherkin@263: return Format(buffer, maxlen, "function"); asherkin@263: if (type->isVoid()) asherkin@263: return Format(buffer, maxlen, "void"); asherkin@263: if (type->isUnchecked()) asherkin@263: return Format(buffer, maxlen, "unchecked"); asherkin@263: if (type->isImportable()) asherkin@263: return Format(buffer, maxlen, "import"); asherkin@263: if (type->isEnum()) asherkin@263: return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars()); asherkin@263: if (type->isStruct()) asherkin@263: return Format(buffer, maxlen, "%s", StructType::cast(type)->name()->chars()); asherkin@263: if (type->isReference()) { asherkin@263: ReferenceType *ref = ReferenceType::cast(type); asherkin@263: size_t len = Format(buffer, maxlen, "&"); asherkin@263: return len + FormatTypeName(ref->contained(), buffer + len, maxlen - len); asherkin@263: } asherkin@263: switch (type->primitive()) { asherkin@263: case PrimitiveType_Bool: asherkin@263: return Format(buffer, maxlen, "bool"); asherkin@263: case PrimitiveType_Char: asherkin@263: return Format(buffer, maxlen, "char"); asherkin@263: case PrimitiveType_Int32: asherkin@263: return Format(buffer, maxlen, "int"); asherkin@263: case PrimitiveType_Float: asherkin@263: return Format(buffer, maxlen, "float"); asherkin@263: default: asherkin@263: return Format(buffer, maxlen, ""); asherkin@263: } asherkin@263: } asherkin@263: asherkin@263: const char * asherkin@263: ke::GetTypeName(Type *type, char *buffer, size_t maxlen) asherkin@263: { asherkin@263: FormatTypeName(type, buffer, maxlen); asherkin@263: return buffer; asherkin@263: }