src/Types.cpp
author David Anderson <dvander@alliedmods.net>
Sun Nov 18 15:50:41 2012 -0800 (2012-11-18)
changeset 217 c22e983b3b6e
parent 212 443d24cfdf2d
child 222 0cde1379b29f
permissions -rw-r--r--
Get preinc working again.
     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::NewUnchecked(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_ = UNCHECKED;
    47     return type;
    48 }
    49 
    50 Type *
    51 Type::NewPrimitive(Zone *zone, PrimitiveType prim)
    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_ = PRIMITIVE;
    58     type->name_ = NULL;
    59      type->primitive_ = prim;
    60     return type;
    61 }
    62 
    63 ArrayType *
    64 ArrayType::New(Zone *zone, Handle<Type> contained, int elements)
    65 {
    66     if (contained->isArray() &&
    67         ArrayType::cast(contained)->levels() == MAX_ARRAY_DEPTH)
    68     {
    69         zone->reportError(Message_MaximumArrayDepth);
    70         return NULL;
    71     }
    72 
    73     Local<ArrayType> type(zone, ArrayType::cast(zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)));
    74     if (!type)
    75         return NULL;
    76 
    77     type->kind_ = ARRAY;
    78     type->name_ = NULL;
    79     type->contained_ = contained;
    80     type->elements_ = elements;
    81     if (!contained->isArray())
    82         type->levels_ = 1;
    83     else
    84         type->levels_ = ArrayType::cast(contained)->levels() + 1;
    85     return type;
    86 }
    87 
    88 ArrayType *
    89 ArrayType::NewExternal(Zone *zone, Handle<Type> contained)
    90 {
    91     Local<ArrayType> type(zone, ArrayType::cast(zone->allocate(MapKind_ArrayType, sizeof(ArrayType), Heap::Tenure_Old)));
    92     if (!type)
    93         return NULL;
    94 
    95     assert(contained->isPrimitive());
    96 
    97     type->kind_ = EXTERNAL_ARRAY;
    98     type->name_ = NULL;
    99     type->contained_ = contained;
   100     type->elements_ = DYNAMIC_ARRAY_SIZE;
   101     type->levels_ = 1;
   102     return type;
   103 }
   104 
   105 Type *
   106 Type::NewReference(Zone *zone, Handle<Type> contained, bool isConst)
   107 {
   108     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   109     if (!type)
   110         return NULL;
   111 
   112     type->kind_ = REFERENCE;
   113     type->name_ = NULL;
   114     type->const_ = isConst;
   115     return type;
   116 }
   117 
   118 Type *
   119 Type::NewEnum(Zone *zone, Handle<String> name)
   120 {
   121     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   122     if (!type)
   123         return NULL;
   124 
   125     type->kind_ = ENUM;
   126     type->name_ = name;
   127     return type;
   128 }
   129 
   130 #if 0
   131 Type *
   132 Type::NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
   133                 Handle<FixedArray> defaults, bool variadic)
   134 {
   135     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   136     if (!type)
   137         return NULL;
   138 
   139     type->kind_ = NATIVE;
   140     type->name_ = NULL;
   141     type->contained_ = NULL;
   142     type->fields_ = NULL;
   143     type->newMap_ = NULL;
   144     type->returnType_ = returnType;
   145     type->parameters_ = parameters;
   146     type->defaults_ = defaults;
   147     type->variadicNative_ = variadic;
   148     return type;
   149 }
   150 #endif
   151 
   152 bool
   153 Type::Compare(Type *left, Type *right)
   154 {
   155     if (left == right)
   156         return true;
   157 
   158     if (left->kind() != right->kind())
   159         return false;
   160 
   161     switch (left->kind()) {
   162       case Type::PRIMITIVE:
   163         return left->primitive() == right->primitive();
   164 
   165       case Type::ARRAY:
   166       {
   167         ArrayType *aleft = ArrayType::cast(left);
   168         ArrayType *aright = ArrayType::cast(right);
   169         if (aleft->levels() != aright->levels())
   170             return false;
   171         if (aleft->isFixedLength() != aright->isFixedLength())
   172             return false;
   173         if (aleft->isFixedLength() && aleft->fixedLength() != aright->fixedLength())
   174             return false;
   175         return Compare(aleft->contained(), aright->contained());
   176       }
   177 
   178       case Type::FUNCTION:
   179       {
   180         FunctionType *fleft = FunctionType::cast(left);
   181         FunctionType *fright = FunctionType::cast(right);
   182         if (!Compare(fleft->returnType(), fright->returnType()))
   183             return false;
   184         if (fleft->parameters()->length() != fright->parameters()->length())
   185             return false;
   186         if (fleft->isNative() != fright->isNative())
   187             return false;
   188         if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic()))
   189             return false;
   190         for (unsigned i = 0; i < fleft->parameters()->length(); i++) {
   191             Type *leftparam = fleft->parameterAt(i);
   192             Type *rightparam = fright->parameterAt(i);
   193             if (!Compare(leftparam, rightparam))
   194                 return false;
   195         }
   196         return true;
   197       }
   198 
   199       case Type::ENUM:
   200         return false;
   201 
   202       case Type::VOID:
   203       	return true;
   204 
   205       default:
   206         assert(left->kind() == Type::REFERENCE);
   207         return Compare(left->contained_ref(), right->contained_ref());
   208     }
   209 }
   210 
   211 StructType *
   212 StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
   213 {
   214     Local<StructType> type(zone, StructType::cast(zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old)));
   215     if (!type)
   216         return NULL;
   217 
   218     type->kind_ = STRUCT;
   219     type->name_ = name;
   220     type->newMap_ = NULL;
   221     type->fields_ = fields;
   222 
   223     // Fill in field offsets.
   224     StructureBufferBuilder builder;
   225     Local<Type> fieldType(zone);
   226     for (size_t i = 0; i < fields->length(); i++) {
   227         Descriptor *desc = Descriptor::cast(fields->at(i));
   228         fieldType = desc->type();
   229 
   230         unsigned offset;
   231         if (!builder.add(fieldType, &offset))
   232             return NULL;
   233         desc->setOffset(offset);
   234     }
   235 
   236     Local<StructMap> map(zone, StructMap::New(zone, builder, type));
   237     if (!map)
   238         return NULL;
   239 
   240     type->newMap_ = map;
   241 
   242     return type;
   243 }
   244 
   245 Descriptor *
   246 StructType::lookupField(Handle<String> name, unsigned *index)
   247 {
   248     for (unsigned i = 0; i < fields_->length(); i++) {
   249         Descriptor *desc = Descriptor::cast(fields_->at(i));
   250         if (desc->name() == name) {
   251             if (index)
   252                 *index = i;
   253             return desc;
   254         }
   255     }
   256 
   257     return NULL;
   258 }
   259 
   260 FunctionType *
   261 FunctionType::New(Zone *zone, TokenKind token)
   262 {
   263     Local<FunctionType> type(zone, FunctionType::cast(zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old)));
   264     if (!type)
   265         return NULL;
   266 
   267     type->kind_ = FUNCTION;
   268     type->name_ = NULL;
   269     type->parameters_ = NULL;
   270     type->defaults_ = NULL;
   271     type->returnType_ = NULL;
   272     type->token_ = token;
   273     return type;
   274 }
   275 
   276 // :TODO: this leaks an interior pointer.
   277 const char *
   278 ke::GetTypeName(Type *type)
   279 {
   280     if (type->isArray())
   281         return "array";
   282     if (type->isFunction())
   283         return "function";
   284     if (type->isVoid())
   285         return "void";
   286     if (type->isEnum() || type->isStruct())
   287         return type->name()->chars();
   288     if (type->isReference())
   289         type = type->contained_ref();
   290     switch (type->primitive()) {
   291       case PrimitiveType_Bool:
   292         return "bool";
   293       case PrimitiveType_Char:
   294         return "String";
   295       case PrimitiveType_Int32:
   296         return "int";
   297       case PrimitiveType_Float:
   298         return "Float";
   299       default:
   300         return "<unknown>";
   301     }
   302 }
   303