src/Types.cpp
author David Anderson <dvander@alliedmods.net>
Thu Dec 20 00:59:38 2012 -0800 (2012-12-20)
changeset 222 0cde1379b29f
parent 212 443d24cfdf2d
child 233 bbb498ccb4ac
permissions -rw-r--r--
Re-added support for reference arguments.
     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 ReferenceType *
   106 ReferenceType::New(Zone *zone, Handle<Type> contained)
   107 {
   108     Local<ReferenceType> type(zone, ReferenceType::cast(zone->allocate(MapKind_ReferenceType, sizeof(ReferenceType), Heap::Tenure_Old)));
   109     if (!type)
   110         return NULL;
   111 
   112     type->kind_ = REFERENCE;
   113     type->name_ = NULL;
   114     type->const_ = false;
   115     type->contained_ = contained;
   116     return type;
   117 }
   118 
   119 Type *
   120 Type::NewEnum(Zone *zone, Handle<String> name)
   121 {
   122     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   123     if (!type)
   124         return NULL;
   125 
   126     type->kind_ = ENUM;
   127     type->name_ = name;
   128     return type;
   129 }
   130 
   131 #if 0
   132 Type *
   133 Type::NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters,
   134                 Handle<FixedArray> defaults, bool variadic)
   135 {
   136     Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
   137     if (!type)
   138         return NULL;
   139 
   140     type->kind_ = NATIVE;
   141     type->name_ = NULL;
   142     type->contained_ = NULL;
   143     type->fields_ = NULL;
   144     type->newMap_ = NULL;
   145     type->returnType_ = returnType;
   146     type->parameters_ = parameters;
   147     type->defaults_ = defaults;
   148     type->variadicNative_ = variadic;
   149     return type;
   150 }
   151 #endif
   152 
   153 bool
   154 Type::Compare(Type *left, Type *right)
   155 {
   156     if (left == right)
   157         return true;
   158 
   159     if (left->kind() != right->kind())
   160         return false;
   161 
   162     switch (left->kind()) {
   163       case Type::PRIMITIVE:
   164         return left->primitive() == right->primitive();
   165 
   166       case Type::ARRAY:
   167       {
   168         ArrayType *aleft = ArrayType::cast(left);
   169         ArrayType *aright = ArrayType::cast(right);
   170         if (aleft->levels() != aright->levels())
   171             return false;
   172         if (aleft->isFixedLength() != aright->isFixedLength())
   173             return false;
   174         if (aleft->isFixedLength() && aleft->fixedLength() != aright->fixedLength())
   175             return false;
   176         return Compare(aleft->contained(), aright->contained());
   177       }
   178 
   179       case Type::FUNCTION:
   180       {
   181         FunctionType *fleft = FunctionType::cast(left);
   182         FunctionType *fright = FunctionType::cast(right);
   183         if (!Compare(fleft->returnType(), fright->returnType()))
   184             return false;
   185         if (fleft->parameters()->length() != fright->parameters()->length())
   186             return false;
   187         if (fleft->isNative() != fright->isNative())
   188             return false;
   189         if (fleft->isNative() && (fleft->isNativeVariadic() != fright->isNativeVariadic()))
   190             return false;
   191         for (unsigned i = 0; i < fleft->parameters()->length(); i++) {
   192             Type *leftparam = fleft->parameterAt(i);
   193             Type *rightparam = fright->parameterAt(i);
   194             if (!Compare(leftparam, rightparam))
   195                 return false;
   196         }
   197         return true;
   198       }
   199 
   200       case Type::ENUM:
   201         return false;
   202 
   203       case Type::VOID:
   204       	return true;
   205 
   206       default:
   207         assert(left->kind() == Type::REFERENCE);
   208         return Compare(ReferenceType::cast(left)->contained(), ReferenceType::cast(right)->contained());
   209     }
   210 }
   211 
   212 StructType *
   213 StructType::New(Zone *zone, Handle<String> name, Handle<FixedArray> fields)
   214 {
   215     Local<StructType> type(zone, StructType::cast(zone->allocate(MapKind_StructType, sizeof(StructType), Heap::Tenure_Old)));
   216     if (!type)
   217         return NULL;
   218 
   219     type->kind_ = STRUCT;
   220     type->name_ = name;
   221     type->newMap_ = NULL;
   222     type->fields_ = fields;
   223 
   224     // Fill in field offsets.
   225     StructureBufferBuilder builder;
   226     Local<Type> fieldType(zone);
   227     for (size_t i = 0; i < fields->length(); i++) {
   228         Descriptor *desc = Descriptor::cast(fields->at(i));
   229         fieldType = desc->type();
   230 
   231         unsigned offset;
   232         if (!builder.add(fieldType, &offset))
   233             return NULL;
   234         desc->setOffset(offset);
   235     }
   236 
   237     Local<StructMap> map(zone, StructMap::New(zone, builder, type));
   238     if (!map)
   239         return NULL;
   240 
   241     type->newMap_ = map;
   242 
   243     return type;
   244 }
   245 
   246 Descriptor *
   247 StructType::lookupField(Handle<String> name, unsigned *index)
   248 {
   249     for (unsigned i = 0; i < fields_->length(); i++) {
   250         Descriptor *desc = Descriptor::cast(fields_->at(i));
   251         if (desc->name() == name) {
   252             if (index)
   253                 *index = i;
   254             return desc;
   255         }
   256     }
   257 
   258     return NULL;
   259 }
   260 
   261 FunctionType *
   262 FunctionType::New(Zone *zone, TokenKind token)
   263 {
   264     Local<FunctionType> type(zone, FunctionType::cast(zone->allocate(MapKind_FunctionType, sizeof(FunctionType), Heap::Tenure_Old)));
   265     if (!type)
   266         return NULL;
   267 
   268     type->kind_ = FUNCTION;
   269     type->name_ = NULL;
   270     type->parameters_ = NULL;
   271     type->defaults_ = NULL;
   272     type->returnType_ = NULL;
   273     type->token_ = token;
   274     return type;
   275 }
   276 
   277 // :TODO: this leaks an interior pointer.
   278 const char *
   279 ke::GetTypeName(Type *type)
   280 {
   281     if (type->isArray())
   282         return "array";
   283     if (type->isFunction())
   284         return "function";
   285     if (type->isVoid())
   286         return "void";
   287     if (type->isEnum() || type->isStruct())
   288         return type->name()->chars();
   289     if (type->isReference())
   290         type = ReferenceType::cast(type)->contained();
   291     switch (type->primitive()) {
   292       case PrimitiveType_Bool:
   293         return "bool";
   294       case PrimitiveType_Char:
   295         return "String";
   296       case PrimitiveType_Int32:
   297         return "int";
   298       case PrimitiveType_Float:
   299         return "Float";
   300       default:
   301         return "<unknown>";
   302     }
   303 }
   304