/* 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; }
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; }
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 ) ) ); } }
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() ); } }
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; }
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); }
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; }
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 ); }
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; }
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; }
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; }
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; }