Exemplo n.º 1
0
/*  NFunctionSignature::calculateSignature() */
std::string NMethodCall::calculateSignature(AsmGenerator& context)
{
    std::string sig = "(";
    for (ExpressionList::const_iterator i = this->arguments.begin(); i != this->arguments.end(); i++)
    {
        if (i != this->arguments.begin())
        {
            sig = sig + ",";
        }
        IType* type = (*i)->getExpressionType(context);
        sig = sig + type->getName();
    }
    sig = sig + ")";
    return sig;
}
AsmBlock* NStructureResolutionOperator::compile(AsmGenerator& context)
{
    AsmBlock* block = new AsmBlock();

    // Add file and line information.
    *block << this->getFileAndLineState();

    // Use our reference function to generate the location.
    AsmBlock* expr = this->reference(context);

    IType* fieldType = this->m_structType->getStructFieldType(this->rhs.name);

    // return the value of the field
    *block <<   *expr;
    *block <<   *(fieldType->loadFromRef(context, 'A', 'A'));
    delete expr;

    return block;
}
Exemplo n.º 3
0
RetT callFromC(IFunction *func, RuntimeEnv* env)
{
    TypeSystem* ts = TypeSystem::instance();
    IType *retT = CType2ScriptType<RetT>::get(ts);
    vector<IType*> argT = {};
    IType *ftype = ts->getFunc(retT, argT);

    int retSize = retT->getSize();
    int retArgSize = retSize;
    env->pushValue(RetT());

    env->pushFrame(retArgSize);
    func->call(env);
    env->popFrame(retSize);

    RetT r;
    env->popValue(r);
    return r;
}
Exemplo n.º 4
0
void Loader::onRaises( const location& loc, const std::string& name )
{
	IType* type = resolveType( loc, name );
	if( getError() )
		return;

	if( !type )
	{
		PUSH_ERROR( loc, "error loading exception type '" << name << "'" );
	}
	else if( type->getKind() != TK_EXCEPTION )
	{
		PUSH_ERROR( loc, "attempt to raise non-exception type '" << type->getFullName() << "'" );
	}
	else
	{
		CATCH_ERRORS( loc, _methodBuilder->defineException( static_cast<IException*>( type ) ) );
	}
}
Exemplo n.º 5
0
void Loader::onAnnotation( const location& loc, const std::string& name, bool hasData )
{
	std::string componentName;
	componentName.reserve( name.size() + 10 );
	componentName.append( name );
	componentName.append( "Annotation" );

	IType* type = resolveType( loc, componentName );
	if( !type )
	{
		PUSH_ERROR( loc, "error loading annotation type '" << componentName << "'" );
		return;
	}

	if( type->getKind() != TK_COMPONENT )
	{
		PUSH_ERROR( loc, "annotation type '" << componentName << "' is not a component" );
		return;
	}

	try
	{
		RefPtr<IAnnotation> annotation;
		if( hasData )
		{
			RefPtr<IObject> object( type->getReflector()->newInstance() );
			annotation = getAnnotationFrom( object.get() );
		}
		else
		{
			annotation = getDefaultAnnotationInstance( type );
		}

		if( _annotations.empty() )
			_annotations.push_back( AnnotationRecord() );
		_annotations.back().annotations.push_back( annotation.get() );
	}
	catch( Exception& e )
	{
		pushError( loc, e.getMessage() );
	}
}
Exemplo n.º 6
0
AsmBlock* NUnaryOperator::compile(AsmGenerator& context)
{
	AsmBlock* block = new AsmBlock();

	// Add file and line information.
	*block << this->getFileAndLineState();

	// When an expression is evaluated, the result goes into the A register.
	AsmBlock* rhs = this->rhs.compile(context);

	// get type
	IType* rhsType = this->rhs.getExpressionType(context);

	if (!rhsType->isBasicType())
	{
		throw new CompilerException(this->line, this->file,
					    "Invalid operand to unary operation. (have '"
					    + rhsType->getName() + "')");
	}

	// Move the value into A
	*block <<   *rhs;
	delete rhs;

	// Now do the appropriate operation.
	AsmBlock* compiledOp;
	switch (this->op)
	{
		case ADD:
			/* TODO integer promotion */
			compiledOp = rhsType->plus(context, 'A');
			break;

			/* unary negative:  "A = -A" */
		case SUBTRACT:
			// A = 0 - A
			compiledOp = rhsType->minus(context, 'A');
			break;

			/* unary bitwise negate:  "A = ~A" */
		case BITWISE_NEGATE:
			compiledOp = rhsType->bnot(context, 'A');
			break;
			/* boolean negate: A = !A  */
		case NEGATE:
			compiledOp = rhsType->lnot(context, 'A');
			break;

		default:
			throw new CompilerException(this->line, this->file, "Unknown unary operations requested.");
	}
	*block << *compiledOp;

	return block;
}
Exemplo n.º 7
0
IArray* TypeManager::getArrayOf( IType* elementType )
{
	if( !elementType )
		CORAL_THROW( IllegalArgumentException, "null element type" );

	const std::string& elementTypeName = elementType->getName();

	std::string arrayName;
	arrayName.reserve( elementTypeName.length() + 2 );
	arrayName.append( elementTypeName );
	arrayName.append( "[]" );

	Namespace* ns = static_cast<Namespace*>( elementType->getNamespace() );

	// try to locate an existing array of this type
	IType* existingArrayType = ns->getType( arrayName );
	if( existingArrayType )
	{
		assert( existingArrayType->getKind() == TK_ARRAY );
		return static_cast<IArray*>( existingArrayType );
	}

	// otherwise, try to create it
	TypeKind kind = elementType->getKind();
	if( kind == TK_ARRAY )
		CORAL_THROW( IllegalArgumentException, "arrays of arrays are illegal" );

	if( !isData( kind ) )
		CORAL_THROW( IllegalArgumentException, "arrays of " << kind << "s are illegal" );

	RefPtr<ArrayType> arrayType = new ArrayType;
	arrayType->setType( TK_ARRAY, elementType->getName() + "[]", ns );
	arrayType->setElementType( elementType );

	ns->addType( arrayType.get() );

	return arrayType.get();
}
void our_trie_iterator(KTrie<IEntityFactory_CE *> *pTrie, const char *name, IEntityFactory_CE *& obj, void *data)
{
	SourceHook::List<CEntity *> *cent_list = (SourceHook::List<CEntity *> *)data;
	int count = 0;
	SourceHook::List<CEntity *>::iterator _iter;
	CEntity *pInfo;
	for(_iter=cent_list->begin(); _iter!=cent_list->end(); _iter++)
	{
		pInfo = (*_iter);

		if(strcmp(name, pInfo->GetClassname()) == 0)
		{
			count++;
			continue;
		}
		IType *pType = GetType(pInfo->BaseEntity());
		IBaseType *pBase = pType->GetBaseType();

		do 
		{
			const char *classname = GetTypeName(pBase->GetTypeInfo());
			if(strcmp(classname, name) == 0)
			{
				count++;
			}
		} while (pBase->GetNumBaseClasses() && (pBase = pBase->GetBaseClass(0)));
		pType->Destroy();
	}

	if(strlen(name) < 7)
		META_CONPRINTF("%s:\t\t\t\t%d\n",name,count);
	else if(strlen(name) < 15)
		META_CONPRINTF("%s:\t\t\t%d\n",name,count);
	else if(strlen(name) < 23)
		META_CONPRINTF("%s:\t\t%d\n",name,count);
	else
		META_CONPRINTF("%s:\t%d\n",name,count);
}
Exemplo n.º 9
0
AsmBlock* NIdentifier::compile(AsmGenerator& context)
{
	AsmBlock* block = new AsmBlock();

	// Add file and line information.
	*block << this->getFileAndLineState();

	// Get the position and type of the variable.
	TypePosition result = context.m_CurrentFrame->getPositionOfVariable(this->name);
	IType* type = context.m_CurrentFrame->getTypeOfVariable(this->name);

	if (!result.isFound())
		throw new CompilerException(this->line, this->file, "The variable '" + this->name + "' was not found in the scope.");

	if (result.isFunction())
		throw new CompilerException(this->line, this->file, "Can not get value representation of function '" + this->name + "'; did you want a reference instead?");

	// Load the value of the variable into register A.
	*block << result.pushAddress('I');
	*block << *(type->loadFromRef(context, 'I', 'A'));
	//*block <<	"	SET A, [I]" << std::endl;

	return block;
}
Exemplo n.º 10
0
IComponent* ComponentBase::getOrCreateInternalComponent(
	const char* componentName, const char* interfaceName, const char* facetName )
{
	std::string fullTypeName( componentName );

	// get the component if it already exists
	ITypeManager* tm = getSystem()->getTypes();
	IType* type = tm->findType( fullTypeName );
	if( type )
	{
		assert( type->getKind() == TK_COMPONENT );
		return static_cast<IComponent*>( type );
	}

	// otherwise, create the component
	IType* itfType = getType( interfaceName );
	assert( itfType->getKind() == TK_INTERFACE );

	size_t lastDotPos = fullTypeName.rfind( '.' );
	assert( lastDotPos != std::string::npos ); // componentName must be specified with a namespace

	std::string namespaceName( fullTypeName.substr( 0, lastDotPos ) );
	std::string localTypeName( fullTypeName.substr( lastDotPos + 1 ) );

	INamespace* ns = tm->findNamespace( namespaceName );
	assert( ns ); // the namespace should have been created before

	RefPtr<ITypeBuilder> tb = ns->defineType( localTypeName, TK_COMPONENT );
	tb->definePort( facetName, static_cast<IInterface*>( itfType ), true );

	try
	{
		tm->getTransaction()->commit();
	}
	catch( std::exception& )
	{
		tm->getTransaction()->rollback();
		throw;
	}

	type = tb->createType();
	assert( type && type->getKind() == TK_COMPONENT );

	// set the component with a basic reflector
	type->setReflector( BasicReflector::create( type ) );

	return static_cast<IComponent*>( type );
}
Exemplo n.º 11
0
AsmBlock* NPostIncDec::compile(AsmGenerator& context)
{
	AsmBlock* block = new AsmBlock();

	// We have to compile and reference, but the reference function allready compiles
	// and evaluates, thus we use the reference not the value.
	AsmBlock* reference = this->expr.reference(context);
	*block <<   *reference;
	delete reference;

	// get type
	IType* exprType = this->expr.getExpressionType(context);

	// Type checking
	if ((!exprType->isPointer()) && (!exprType->isBasicType()))
	{
		throw new CompilerException(this->line, this->file,
					    "Invalid operand to post increase/decrease operation. (have '"
					    + exprType->getName() + "')");
	}

	*block <<	"	SET B, A" << std::endl;
	// return old value in A
	*block << *(exprType->loadFromRef(context, 'B', 'A'));

	// increment/decrement
	switch (this->op)
	{
		case INCREMENT:
			*block << *(exprType->inc(context, 'B'));
			break;

		case DECREMENT:
			*block << *(exprType->dec(context, 'B'));
			break;

		default:
			throw new CompilerException(this->line, this->file, "Unknown Post-Increase-Decrease operation requested.");
	}

	return block;
}
Exemplo n.º 12
0
AsmBlock* NAssignment::compile(AsmGenerator& context)
{
    AsmBlock* block = new AsmBlock();

    // Add file and line information.
    *block << this->getFileAndLineState();

    // When an assignment expression is referenced, the memory
    // address of the target goes into A.
    AsmBlock* las = this->lhs.reference(context);
    *block << *las;

    // get lhs type
    IType* lhsType = this->lhs.getExpressionType(context);

    // push memory address
    *block <<   "   SET PUSH, A" << std::endl;
    delete las;

    // handle regular assignment as special case
    if (this->op == ASSIGN_EQUAL)
    {
        // When an expression is evaluated, the result goes into the A register.
        AsmBlock* rhs = this->rhs.compile(context);
        *block <<   *rhs;
        delete rhs;

        // get rhs type
        IType* rhsType = this->rhs.getExpressionType(context);

        // cast to rhs to lhs type
        if (rhsType->implicitCastable(context, lhsType))
        {
            *block << *(rhsType->implicitCast(context, lhsType, 'A'));
        }
        else
        {
            throw new CompilerException(this->line, this->file,
                                        "Unable to implicitly cast '" + rhsType->getName()
                                        + "' to '" + lhsType->getName() + "'");
        }

        // Pop the address of lhs into B
        if (context.isAssemblerDebug())
        {
            // Put the value into B and clear the
            // stack positions as we do so.
            *block <<   "   SET B, PEEK" << std::endl;
            *block <<   "   SET PEEK, 0" << std::endl;
            *block <<   "   ADD SP, 1" << std::endl;
        }
        else
        {
            // Not debugging, put the values into B.
            *block <<   "   SET B, POP" << std::endl;
        }

        // save the value A to [B]
        *block << *(lhsType->saveToRef(context, 'A', 'B'));
    }
    else
    {
        // When an expression is evaluated, the result goes into the A register.
        AsmBlock* rhs = this->rhs.compile(context);
        *block <<   *rhs;
        delete rhs;

        // get rhs type
        IType* rhsType = this->rhs.getExpressionType(context);

        // Check if both types are of a basic type
        bool isPointerOp = false;
        if (lhsType->isPointer() && rhsType->isBasicType())
        {
            // pointer op: p += i, or p -= i
            isPointerOp = true;
            if (this->op != ASSIGN_ADD && this->op != ASSIGN_SUBTRACT)
            {
                throw new CompilerException(this->line, this->file,
                                            "Invalid operands to assign operation. (have '"
                                            + lhsType->getName() + "' and '" + rhsType->getName() + "')");
            }
        }
        else if ((!rhsType->isBasicType()) || (!lhsType->isBasicType()))
        {
            throw new CompilerException(this->line, this->file,
                                        "Invalid operands to assign operation. (have '"
                                        + lhsType->getName() + "' and '" + rhsType->getName() + "')");
        }

        if (!isPointerOp)
        {
            // cast to rhs to lhs type
            if (rhsType->implicitCastable(context, lhsType))
            {
                *block << *(rhsType->implicitCast(context, lhsType, 'A'));
            }
            else
            {
                throw new CompilerException(this->line, this->file,
                                            "Unable to implicitly cast '" + rhsType->getName()
                                            + "' to '" + lhsType->getName() + "'");
            }
        }

        // move rhs over to register B
        *block <<   "   SET B, A" << std::endl;

        // get referenced value and put it in A
        *block <<   "   SET A, PEEK" << std::endl;
        *block << *(lhsType->loadFromRef(context, 'A', 'A'));

        // Now do the appropriate operation.
        // TODO a lot of assignment operations are missing !!
        // TODO type specific ops
        switch (this->op)
        {
            case ASSIGN_ADD:
                *block << *(lhsType->add(context, 'A', 'B'));
                break;

            case ASSIGN_SUBTRACT:
                *block << *(lhsType->sub(context, 'A', 'B'));
                break;

            case ASSIGN_MULTIPLY:
                *block << *(lhsType->mul(context, 'A', 'B'));
                break;

            case ASSIGN_DIVIDE:
                *block << *(lhsType->div(context, 'A', 'B'));
                break;

            case ASSIGN_MOD:
                *block << *(lhsType->mod(context, 'A', 'B'));
                break;

            case ASSIGN_BAND:
                *block << *(lhsType->band(context, 'A', 'B'));
                break;

            case ASSIGN_BOR:
                *block << *(lhsType->bor(context, 'A', 'B'));
                break;

            case ASSIGN_BXOR:
                *block << *(lhsType->bxor(context, 'A', 'B'));
                break;

            case ASSIGN_SHL:
                *block << *(lhsType->shl(context, 'A', 'B'));
                break;

            case ASSIGN_SHR:
                *block << *(lhsType->shr(context, 'A', 'B'));
                break;

            default:
                throw new CompilerException(this->line, this->file, "Unknown assignment operation requested.");
        }

        // Pop reference from stack
        // If debugging, clear the value as we POP them.
        if (context.isAssemblerDebug())
        {
            // Put the value into B and clear the
            // stack position as we do so.
            *block <<   "   SET B, PEEK" << std::endl;
            *block <<   "   SET PEEK, 0" << std::endl;
            *block <<   "   ADD SP, 1" << std::endl;
        }
        else
        {
            // Not debugging, put the values into B.
            *block <<   "   SET B, POP" << std::endl;
        }

        // Move the value into the target address.
        *block << *(lhsType->saveToRef(context, 'A', 'B'));
    }
    return block;
}
Exemplo n.º 13
0
AsmBlock* TGenericBasicType::compileBinaryOperator(NBinaryOperator* binopNode, AsmGenerator& context)
{
	AsmBlock* block = new AsmBlock();

	// get types
	IType* lhsType = binopNode->lhs.getExpressionType(context);
	IType* rhsType = binopNode->rhs.getExpressionType(context);

	// If debugging, clear the values as we POP them.
	if (context.isAssemblerDebug())
	{
		// Put the values into A and B and clear the
		// stack positions as we do so.
		*block <<   *(rhsType->popStackCleanReturn(context, 'B'));
		*block <<   *(lhsType->popStackCleanReturn(context, 'A'));
	}
	else
	{
		// Not debugging, put the values into A and B.
		*block <<   *(rhsType->popStackReturn(context, 'B'));
		*block <<   *(lhsType->popStackReturn(context, 'A'));
	}

	// get promoted type and cast values to result type
	IType* commonType = TGenericBasicType::promoteTypes(lhsType, rhsType);
	if (lhsType != commonType)
	{
		// cast lhsType
		if (lhsType->implicitCastable(context, commonType))
		{
			*block << *(lhsType->implicitCast(context, commonType, 'A'));
		}
		else
		{
			throw new CompilerException(binopNode->line, binopNode->file,
						    "Unable to implicitly cast '" + lhsType->getName()
						    + "' to '" + commonType->getName() + "'");
		}
	}
	else if (rhsType != commonType)
	{
		// cast rhsType
		if (rhsType->implicitCastable(context, commonType))
		{
			*block << *(rhsType->implicitCast(context, commonType, 'B'));
		}
		else
		{
			throw new CompilerException(binopNode->line, binopNode->file,
						    "Unable to implicitly cast '" + rhsType->getName()
						    + "' to '" + commonType->getName() + "'");
		}
	}

	// Now do the appropriate operation.
	switch (binopNode->op)
	{
		case ADD:
			*block << *(commonType->add(context, 'A', 'B'));
			break;

		case SUBTRACT:
			*block << *(commonType->sub(context, 'A', 'B'));
			break;

		case STAR:
			*block << *(commonType->mul(context, 'A', 'B'));
			break;

		case SLASH:
			*block << *(commonType->div(context, 'A', 'B'));
			break;

		case PERCENT:
			*block << *(commonType->mod(context, 'A', 'B'));
			break;

		case BOOLEAN_AND:
			*block << *(commonType->land(context, 'A', 'B'));
			break;

		case BOOLEAN_OR:
			*block << *(commonType->lor(context, 'A', 'B'));
			break;

		case BINARY_AND:
			*block << *(commonType->band(context, 'A', 'B'));
			break;

		case BINARY_OR:
			*block << *(commonType->bor(context, 'A', 'B'));
			break;

		case BINARY_XOR:
			*block << *(commonType->bxor(context, 'A', 'B'));
			break;

		case BINARY_LEFT_SHIFT:
			*block << *(commonType->shl(context, 'A', 'B'));
			break;

		case BINARY_RIGHT_SHIFT:
			*block << *(commonType->shr(context, 'A', 'B'));
			break;

		case COMPARE_EQUAL:
			*block << *(commonType->eq(context, 'A', 'B'));
			break;

		case COMPARE_NOT_EQUAL:
			*block << *(commonType->neq(context, 'A', 'B'));
			break;

		case COMPARE_LESS_THAN:
			*block << *(commonType->lt(context, 'A', 'B'));
			break;

		case COMPARE_LESS_THAN_EQUAL:
			*block << *(commonType->le(context, 'A', 'B'));
			break;

		case COMPARE_GREATER_THAN:
			*block << *(commonType->gt(context, 'A', 'B'));
			break;

		case COMPARE_GREATER_THAN_EQUAL:
			*block << *(commonType->ge(context, 'A', 'B'));
			break;

		default:
			throw new CompilerException(binopNode->line, binopNode->file, "Unknown binary operations requested.");
	}

	return block;
}
Exemplo n.º 14
0
AsmBlock* NMethodCall::compile(AsmGenerator& context)
{
    AsmBlock* block = new AsmBlock();

    // Add file and line information.
    *block << this->getFileAndLineState();

    // Get the function declaration.
    bool isDirect = true;
    NFunctionSignature* funcsig = (NFunctionDeclaration*)context.getFunction(this->id.name);

    // FIXME: get rid of the use of NType for function signatures!!
    if (funcsig == NULL)
    {
        // Try and get a variable with matching signature then.
        TypePosition varpos = context.m_CurrentFrame->getPositionOfVariable(this->id.name);

        if (!varpos.isFound())
            throw new CompilerException(this->line, this->file, "Neither a function nor a function pointer was found by the name '" + this->id.name + "'.");

        NType* vartype = (NType*)context.m_CurrentFrame->getTypeOfVariable(this->id.name);

        if (vartype->cType != "expression-identifier-type-function")
            throw new CompilerException(this->line, this->file, "Unable to call variable '" + this->id.name + "' as it is not a function pointer.");

        funcsig = (NFunctionSignature*)((NFunctionPointerType*)vartype);
        isDirect = false;
    }



    // check if the called function matches the signature size of this
    // method call
    if (this->arguments.size() != funcsig->arguments.size())
    {
        throw new CompilerException(this->line, this->file,
                                    "Unable to find function\n"
                                    "with singature:                 "
                                    + this->id.name + this->calculateSignature(context)
                                    + "\n"
                                    + "Candidates are:               "
                                    + this->id.name + funcsig->getSignature());
    }

    // Get the stack table of this method.
    StackFrame* frame = context.generateStackFrameIncomplete(funcsig);

    // Get a random label for our jump-back point.
    std::string jmpback = context.getRandomLabel("callback");

    // Evaluate each of the argument expressions in reverse
    // TODO make it depend on the typePosition somehow
    //  this here has to be exactly reverse to the order in the
    //  parameter stack frame and thus the TypePosition
    for (int i = this->arguments.size() - 1; i >= 0; --i)
    {
        // Compile the expression.
        AsmBlock* inst = this->arguments[i]->compile(context);
        *block << *inst;
        delete inst;

        IType* instType = this->arguments[i]->getExpressionType(context);

        // check types and cast implicitly
        IType* parameterType = funcsig->arguments[i]->type;
        if (instType->implicitCastable(context, parameterType))
        {
            // do cast
            *block << *(instType->implicitCast(context, parameterType, 'A'));
        }
        else
        {
            throw new CompilerException(this->line, this->file,
                                        "Unable to find function\n"
                                        "with singature:                 "
                                        + this->id.name + this->calculateSignature(context)
                                        + "\n"
                                        + "Candidates are:               "
                                        + this->id.name + funcsig->getSignature());
        }

        // Push the result onto the stack.
        *block << *(parameterType->pushStack(context, 'A'));
    }

    // Initialize the stack for this method.
    if (isDirect)
    {
        *block <<  "    SET X, cfunc_" << this->id.name << std::endl;
        *block <<  "    ADD X, 2" << std::endl;
    }
    else
    {
        TypePosition varpos = context.m_CurrentFrame->getPositionOfVariable(this->id.name);
        *block <<  varpos.pushAddress('X');
        *block <<  "    SET X, [X]" << std::endl;
        *block <<  "    ADD X, 2" << std::endl;
    }

    *block <<  "    SET X, [X]" << std::endl;
    *block <<  "    SET Z, " << jmpback << std::endl;
    *block <<  "    JSR _stack_caller_init_overlap" << std::endl;

    // Then call the actual method and insert the return label.
    if (isDirect)
    {
        *block <<  "    SET PC, cfunc_" << this->id.name << std::endl;
    }
    else
    {
        // we are referencing the previous stack frame here
        // => parameter previousStackFrame=true
        TypePosition varpos = context.m_CurrentFrame->getPositionOfVariable(this->id.name, true);
        *block <<  varpos.pushAddress('X');
        *block <<  "    SET X, [X]" << std::endl;
        *block <<  "    SET PC, X" << std::endl;

        // TODO: In debug mode, there should be additional checks here to see if
        //   the value that is going to be jumped to is 0 (NULL) so that it can
        //   be reported back without doing weird stuff (like restarting the
        //   program!)
    }

    *block <<  ":" << jmpback << std::endl;

    // Clean up frame.
    context.finishStackFrame(frame);

    return block;
}
CEntity *CEntityManager::CBaseEntityPostConstructor(CBaseEntity *pEntity, const char * szClassname )
{
	IServerNetworkable *pNetworkable = pEntity->GetNetworkable();
	Assert(pNetworkable);

	edict_t *pEdict = pNetworkable->GetEdict();

	if(strcmp(szClassname,"player") == 0 && engine->IndexOfEdict(pEdict) == 0)
	{
		return NULL;
	}

	IEntityFactory_CE **value = NULL;
	bool m_bShouldAddToCache = false;
	value = pCacheTrie.retrieve(szClassname);

	if(!value)
	{
		m_bShouldAddToCache = true;
		value = pFactoryTrie.retrieve(szClassname);
	}

	if (!value)
	{
		/* Attempt to do an RTTI lookup for C++ class links */
		IType *pType = GetType(pEntity);
		IBaseType *pBase = pType->GetBaseType();

		do 
		{
			const char *classname = GetTypeName(pBase->GetTypeInfo());
			value = pFactoryTrie.retrieve(classname);

			if (value)
			{
				break;
			}

		} while (pBase->GetNumBaseClasses() && (pBase = pBase->GetBaseClass(0)));

		pType->Destroy();
	}

	if (!value)
	{
		/* No specific handler for this entity */
		value = pFactoryTrie.retrieve("baseentity");
		assert(value);
	}

	IEntityFactory_CE *pFactory = *value;
	assert(pFactory);

	if(m_bShouldAddToCache)
	{
		pCacheTrie.insert(szClassname, pFactory);
	}

	CEntity *cent = pFactory->Create(pEdict, pEntity);

	char vtable[20];
	_snprintf(vtable, sizeof(vtable), "%x", (unsigned int) *(void **)pEntity);

	cent->ClearAllFlags();
	cent->InitProps();
	
	if (!pHookedTrie.retrieve(vtable))
	{
		cent->InitHooks();
		pHookedTrie.insert(vtable, true);
	}
	
	cent->InitDataMap();

	return cent;
}