src/Types.cpp
author David Anderson <dvander@alliedmods.net>
Mon Dec 24 02:56:02 2012 -0800 (2012-12-24)
changeset 235 43287eef2fff
parent 233 bbb498ccb4ac
child 236 072f1114ea5d
permissions -rw-r--r--
Move PrimitiveType_String to a dedicated string type.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2012 David Anderson
     4  *
     5  * This file is part of SourcePawn.
     6  *
     7  * SourcePawn is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * SourcePawn. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #include <string.h>
    20 #include "Types.h"
    21 #include "Zone.h"
    22 #include "Strings.h"
    23 #include "Structures.h"
    24 #include "Heap-inl.h"
    25 
    26 using namespace ke;
    27 
    28 Type *
    29 Type::NewVoid(Zone *zone)
    30 {
    31     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
    32     if (!type)
    33         return NULL;
    34 
    35     type->kind_ = VOID;
    36     return type;
    37 }
    38 
    39 Type *
    40 Type::NewString(Zone *zone)
    41 {
    42     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
    43     if (!type)
    44         return NULL;
    45 
    46     type->kind_ = STRING;
    47     return type;
    48 }
    49 
    50 Type *
    51 Type::NewUnchecked(Zone *zone)
    52 {
    53     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
    54     if (!type)
    55         return NULL;
    56 
    57     type->kind_ = UNCHECKED;
    58     return type;
    59 }
    60 
    61 Type *
    62 Type::NewPrimitive(Zone *zone, PrimitiveType prim)
    63 {
    64     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
    65     if (!type)
    66         return NULL;
    67 
    68     type->kind_ = PRIMITIVE;
    69     type->primitive_ = prim;
    70     return type;
    71 }
    72 
    73 ArrayType *
    74 ArrayType::New(Zone *zone, Handle<Type> contained, int elements)
    75 {
    76     if (contained->isArray() &&
    77         ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH)
    78     {
    79         zone->reportError(Message_MaximumArrayDepth);
    80         return NULL;
    81     }
    82 
    83     Local<ArrayType> type(zone, ArrayType::cast(zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)));
    84     if (!type)
    85         return NULL;
    86 
    87     type->kind_ = ARRAY;
    88     type->contained_ = contained;
    89     type->elements_ = elements;
    90     if (!contained->isArray())
    91         type->levels_ = 1;
    92     else
    93         type->levels_ = ArrayType::cast(contained)->levels() + 1;
    94     return type;
    95 }
    96 
    97 ArrayType *
    98 ArrayType::NewExternal(Zone *zone, Handle<Type> contained)
    99 {
   100     Local<ArrayType> type(zone, ArrayType::cast(zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)));
   101     if (!type)
   102         return NULL;
   103 
   104     assert(contained->isPrimitive());
   105 
   106     type->kind_ = EXTERNAL_ARRAY;
   107     type->contained_ = contained;
   108     type->elements_ = DYNAMIC_ARRAY_SIZE;
   109     type->levels_ = 1;
   110     return type;
   111 }
   112 
   113 ReferenceType *
   114 ReferenceType::New(Zone *zone, Handle<Type> contained)
   115 {
   116     Local<ReferenceType> type(zone, ReferenceType::cast(zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old)));
   117     if (!type)
   118         return NULL;
   119 
   120     type->kind_ = REFERENCE;
   121     type->const_ = false;
   122     type->contained_ = contained;
   123     return type;
   124 }
   125 
   126 EnumType *
   127 EnumType::New(Zone *zone, Handle<String> name)
   128 {
   129     Local<EnumType> type(zone, EnumType::cast(zone->allocate(MapKind_EnumType, sizeof(EnumType), Heap::Tenure_Old)));
   130     if (!type)
   131         return NULL;
   132 
   133     type->kind_ = ENUM;
   134     type->name_ = name;
   135     return type;
   136 }
   137 
   138 #if 0
   139 Type *
   140 Type::NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
   141                 Handle<FixedArray> defaults, bool variadic)
   142 {
   143     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   144     if (!type)
   145         return NULL;
   146 
   147     type->kind_ = NATIVE;
   148     type->contained_ = NULL;
   149     type->fields_ = NULL;
   150     type->newMap_ = NULL;
   151     type->returnType_ = returnType;
   152     type->parameters_ = parameters;
   153     type->defaults_ = defaults;
   154     type->variadicNative_ = variadic;
   155     return type;
   156 }
   157 #endif
   158 
   159 bool
   160 Type::Compare(Type *left, Type *right)
   161 {
   162     if (left == right)
   163         return true;
   164 
   165     if (left->kind() != right->kind())
   166         return false;
   167 
   168     switch (left->kind()) {
   169       case Type::PRIMITIVE:
   170         return left->primitive() == right->primitive();
   171 
   172       case Type::ARRAY:
   173       {
   174         ArrayType *aleft = ArrayType::cast(left);
   175         ArrayType *aright = ArrayType::cast(right);
   176         if (aleft->levels() != aright->levels())
   177             return false;
   178         if (aleft->isFixedLength() != aright->isFixedLength())
   179             return false;
   180         if (aleft->isFixedLength() && aleft->fixedLength() != aright->fixedLength())
   181             return false;
   182         return Compare(aleft->contained(), aright->contained());
   183       }
   184 
   185       case Type::FUNCTION:
   186       {
   187         FunctionType *fleft = FunctionType::cast(left);
   188         FunctionType *fright = FunctionType::cast(right);
   189         if (!Compare(fleft->returnType(), fright->returnType()))
   190             return false;
   191         if (fleft->parameters()->length() != fright->parameters()->length())
   192             return false;
   193         if (fleft->isNative() != fright->isNative())
   194             return false;
   195         if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic()))
   196             return false;
   197         for (unsigned i = 0; i < fleft->parameters()->length(); i++) {
   198             Type *leftparam = fleft->parameterAt(i);
   199             Type *rightparam = fright->parameterAt(i);
   200             if (!Compare(leftparam, rightparam))
   201                 return false;
   202         }
   203         return true;
   204       }
   205 
   206       case Type::ENUM:
   207         return false;
   208 
   209       case Type::VOID:
   210       	return true;
   211 
   212       default:
   213         assert(left->kind() == Type::REFERENCE);
   214         return Compare(ReferenceType::cast(left)->contained(), ReferenceType::cast(right)->contained());
   215     }
   216 }
   217 
   218 StructType *
   219 StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
   220 {
   221     Local<StructType> type(zone, StructType::cast(zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old)));
   222     if (!type)
   223         return NULL;
   224 
   225     type->kind_ = STRUCT;
   226     type->newMap_ = NULL;
   227     type->fields_ = fields;
   228     type->name_ = name;
   229 
   230     // Fill in field offsets.
   231     StructureBufferBuilder builder;
   232     Local<Type> fieldType(zone);
   233     for (size_t i = 0; i < fields->length(); i++) {
   234         Descriptor *desc = Descriptor::cast(fields->at(i));
   235         fieldType = desc->type();
   236 
   237         unsigned offset;
   238         if (!builder.add(fieldType, &offset))
   239             return NULL;
   240         desc->setOffset(offset);
   241     }
   242 
   243     Local<StructMap> map(zone, StructMap::New(zone, builder, type));
   244     if (!map)
   245         return NULL;
   246 
   247     type->newMap_ = map;
   248 
   249     return type;
   250 }
   251 
   252 Descriptor *
   253 StructType::lookupField(Handle<String> name, unsigned *index)
   254 {
   255     for (unsigned i = 0; i < fields_->length(); i++) {
   256         Descriptor *desc = Descriptor::cast(fields_->at(i));
   257         if (desc->name() == name) {
   258             if (index)
   259                 *index = i;
   260             return desc;
   261         }
   262     }
   263 
   264     return NULL;
   265 }
   266 
   267 FunctionType *
   268 FunctionType::New(Zone *zone, Handle<String> name, TokenKind token)
   269 {
   270     Local<FunctionType> type(zone, FunctionType::cast(zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old)));
   271     if (!type)
   272         return NULL;
   273 
   274     type->kind_ = FUNCTION;
   275     type->parameters_ = NULL;
   276     type->defaults_ = NULL;
   277     type->returnType_ = NULL;
   278     type->name_ = name;
   279     type->token_ = token;
   280     return type;
   281 }
   282 
   283 // :TODO: this leaks an interior pointer.
   284 const char *
   285 ke::GetTypeName(Type *type)
   286 {
   287     if (type->isArray())
   288         return "array";
   289     if (type->isFunction())
   290         return "function";
   291     if (type->isVoid())
   292         return "void";
   293     if (type->isEnum())
   294         return EnumType::cast(type)->name()->chars();
   295     if (type->isStruct())
   296         return StructType::cast(type)->name()->chars();
   297     if (type->isReference())
   298         type = ReferenceType::cast(type)->contained();
   299     switch (type->primitive()) {
   300       case PrimitiveType_Bool:
   301         return "bool";
   302       case PrimitiveType_Char:
   303         return "String";
   304       case PrimitiveType_Int32:
   305         return "int";
   306       case PrimitiveType_Float:
   307         return "Float";
   308       default:
   309         return "<unknown>";
   310     }
   311 }
   312