bool CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar) { CBotStack* pile1 = pj->AddStack(); CBotVar* pVar2; CBotInstr* p = m_expr; int n = 0; for (; p != nullptr ; n++, p = p->GetNext3b()) { if (pile1->GetState() > n) continue; pVar2 = pVar->GetItem(n, true); if (pVar2 == nullptr) { pj->SetError(CBotErrOutArray, p->GetToken()); return false; } CBotTypResult type = pVar2->GetTypResult(); if (!p->Execute(pile1, pVar2)) return false; // evaluate expression if (type.Eq(CBotTypPointer)) pVar2->SetType(type); // keep pointer type pile1->IncState(); } return pj->Return(pile1); }
CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; if (!IsOfType(p, ID_RETURN)) return NULL; // should never happen CBotReturn* inst = new CBotReturn(); // creates the object inst->SetToken( pp ); CBotTypResult type = pStack->GetRetType(); if ( type.GetType() == 0 ) // returned void ? { if ( IsOfType( p, ID_SEP ) ) return inst; pStack->SetError( TX_BADTYPE, pp ); return NULL; } inst->m_Instr = CBotExpression::Compile(p, pStack); if ( pStack->IsOk() ) { CBotTypResult retType = pStack->GetTypResult(2); if (TypeCompatible(retType, type, ID_ASS)) { if ( IsOfType( p, ID_SEP ) ) return inst; pStack->SetError(TX_ENDOF, p->GetStart()); } pStack->SetError(TX_BADTYPE, p->GetStart()); } delete inst; return NULL; // no object, the error is on the stack }
CBotVarClass::CBotVarClass( const CBotToken* name, const CBotTypResult& type) { /* // int nIdent = 0; InitCBotVarClass( name, type ) //, nIdent ); } CBotVarClass::CBotVarClass( const CBotToken* name, CBotTypResult& type) //, int &nIdent ) { InitCBotVarClass( name, type ); //, nIdent ); } void CBotVarClass::InitCBotVarClass( const CBotToken* name, CBotTypResult& type ) //, int &nIdent ) {*/ if ( !type.Eq(CBotTypClass) && !type.Eq(CBotTypIntrinsic) && // by convenience there accepts these types !type.Eq(CBotTypPointer) && !type.Eq(CBotTypArrayPointer) && !type.Eq(CBotTypArrayBody)) ASM_TRAP(); m_token = new CBotToken(name); m_next = NULL; m_pMyThis = NULL; m_pUserPtr = OBJECTCREATED;//NULL; m_InitExpr = NULL; m_LimExpr = NULL; m_pVar = NULL; m_type = type; if ( type.Eq(CBotTypArrayPointer) ) m_type.SetType( CBotTypArrayBody ); else if ( !type.Eq(CBotTypArrayBody) ) m_type.SetType( CBotTypClass ); // officel type for this object m_pClass = NULL; m_pParent = NULL; m_binit = false; m_bStatic = false; m_mPrivate = 0; m_bConstructor = false; m_CptUse = 0; m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum(); // se place tout seul dans la liste // TODO stands alone in the list (stands only in a list) if (m_ExClass) m_ExClass->m_ExPrev = this; m_ExNext = m_ExClass; m_ExPrev = NULL; m_ExClass = this; CBotClass* pClass = type.GetClass(); CBotClass* pClass2 = pClass->GetParent(); if ( pClass2 != NULL ) { // also creates an instance of the parent class m_pParent = new CBotVarClass(name, CBotTypResult(type.GetType(),pClass2) ); //, nIdent); } SetClass( pClass ); //, nIdent ); }
// compiles a list of parameters CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack) { // mainly not pStack->TokenStack here // declared variables must remain visible thereafter pStack->SetStartError(p->GetStart()); if (IsOfType(p, ID_OPENPAR)) { CBotDefParam* list = NULL; while (!IsOfType(p, ID_CLOSEPAR)) { CBotDefParam* param = new CBotDefParam(); if (list == NULL) list = param; else list->AddNext(param); // added to the list // CBotClass* pClass = NULL;//= CBotClass::Find(p); param->m_typename = p->GetString(); CBotTypResult type = param->m_type = TypeParam(p, pStack); // if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object if (param->m_type.GetType() > 0) { CBotToken* pp = p; param->m_token = *p; if (pStack->IsOk() && IsOfType(p, TokenTypVar) ) { // variable already declared? if (pStack->CheckVarLocal(pp)) { pStack->SetError(TX_REDEFVAR, pp); break; } if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable // if ( pClass ) var->SetClass(pClass); var->SetInit(2); // mark initialized param->m_nIdent = CBotVar::NextUniqNum(); var->SetUniqNum(param->m_nIdent); pStack->AddVar(var); // place on the stack if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR) continue; } pStack->SetError(TX_CLOSEPAR, p->GetStart()); } pStack->SetError(TX_NOTYP, p); delete list; return NULL; } return list; } pStack->SetError(TX_OPENPAR, p->GetStart()); return NULL; }
CBotTypResult CBotVar::GetTypResult(GetTypeMode mode) { CBotTypResult r = m_type; if ( mode == GetTypeMode::CLASS_AS_POINTER && m_type.Eq(CBotTypClass) ) r.SetType(CBotTypPointer); if ( mode == GetTypeMode::CLASS_AS_INTRINSIC && m_type.Eq(CBotTypClass) ) r.SetType(CBotTypIntrinsic); return r; }
CBotTypResult CBotVar::GetTypResult(int mode) { CBotTypResult r = m_type; if ( mode == 1 && m_type.Eq(CBotTypClass) ) r.SetType(CBotTypPointer); if ( mode == 2 && m_type.Eq(CBotTypClass) ) r.SetType(CBotTypIntrinsic); return r; }
CBotVarArray::CBotVarArray(const CBotToken& name, CBotTypResult& type) : CBotVar(name) { if ( !type.Eq(CBotTypArrayPointer) && !type.Eq(CBotTypArrayBody)) assert(0); m_next = nullptr; m_pMyThis = nullptr; m_pUserPtr = nullptr; m_type = type; m_type.SetType(CBotTypArrayPointer); m_binit = CBotVar::InitType::UNDEF; m_pInstance = nullptr; // the list of the array elements }
CBotTypResult CBotClass::CompileMethode(const char* name, CBotVar* pThis, CBotVar** ppParams, CBotCStack* pStack, long& nIdent) { nIdent = 0; // forget the previous one if necessary // find the methods declared by AddFunction CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent); if ( r.GetType() >= 0) return r; // find the methods declared by user r = m_pMethod->CompileCall(name, ppParams, nIdent); if ( r.Eq(TX_UNDEFCALL) && m_pParent != NULL ) return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent); return r; }
bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2) { int t1 = type1.GetType(); int t2 = type2.GetType(); if (t1 == CBotTypIntrinsic) t1 = CBotTypClass; if (t2 == CBotTypIntrinsic) t2 = CBotTypClass; int max = (t1 > t2) ? t1 : t2; if (max == 99) return false; // result is void? if (max >= CBotTypBoolean) { if (t2 != t1) return false; if (max == CBotTypArrayPointer) return TypesCompatibles(type1.GetTypElem(), type2.GetTypElem()); if (max == CBotTypClass || max == CBotTypPointer) return type1.GetClass() == type2.GetClass() ; return true ; } return true; }
bool CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate) { CBotToken token(name, CBotString()); CBotClass* pClass = type.GetClass(); CBotVar* pVar = CBotVar::Create( name, type ); /// pVar->SetUniqNum(CBotVar::NextUniqNum()); pVar->SetPrivate( mPrivate ); if ( pClass != NULL ) { // pVar->SetClass(pClass); if ( type.Eq(CBotTypClass) ) { // adds a new statement for the object initialization pVar->m_InitExpr = new CBotNew() ; CBotToken nom( pClass->GetName() ); pVar->m_InitExpr->SetToken(&nom); } } return AddItem( pVar ); }
CBotTypResult cSpace(CBotVar* &var, void* user) { CBotTypResult ret; if ( var == 0 ) return CBotTypResult( CBotTypIntrinsic, "point" ); ret = cPoint(var, user); if ( !ret.Eq(0) ) return ret; if ( var == 0 ) return CBotTypIntrinsic; if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum ); var = var->GivNext(); if ( var == 0 ) return CBotTypIntrinsic; if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum ); var = var->GivNext(); if ( var == 0 ) return CBotTypIntrinsic; if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum ); var = var->GivNext(); if ( var != 0 ) return CBotErrOverParam; return CBotTypResult( CBotTypIntrinsic, "point" ); }
bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op) { int t1 = type1.GetType(); int t2 = type2.GetType(); int max = (t1 > t2) ? t1 : t2; if (max == 99) return false; // result is void? // special case for strin concatenation if (op == ID_ADD && max >= CBotTypString) return true; if (op == ID_ASSADD && max >= CBotTypString) return true; if (op == ID_ASS && t1 == CBotTypString) return true; if (max >= CBotTypBoolean) { if ( (op == ID_EQ || op == ID_NE) && (t1 == CBotTypPointer && t2 == CBotTypNullPointer)) return true; if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && (t2 == CBotTypPointer && t1 == CBotTypNullPointer)) return true; if ( (op == ID_EQ || op == ID_NE) && (t1 == CBotTypArrayPointer && t2 == CBotTypNullPointer)) return true; if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) && (t2 == CBotTypArrayPointer && t1 == CBotTypNullPointer)) return true; if (t2 != t1) return false; if (t1 == CBotTypArrayPointer) return type1.Compare(type2); if (t1 == CBotTypPointer || t1 == CBotTypClass || t1 == CBotTypIntrinsic ) { CBotClass* c1 = type1.GetClass(); CBotClass* c2 = type2.GetClass(); return c1->IsChildOf(c2) || c2->IsChildOf(c1); // accept the case in reverse // the transaction will be denied at runtime if the pointer is not // compatible } return true; } type1.SetType(max); type2.SetType(max); return true; }
bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype) { CBotTypResult res; // first looks by the identifier res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype ); if (res.GetType() >= 0) return res.GetType(); res = m_prog->GetFunctions()->DoCall(nIdent, NULL, ppVar, this, token ); if (res.GetType() >= 0) return res.GetType(); // if not found (recompile?) seeks by name nIdent = 0; res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype ); if (res.GetType() >= 0) return res.GetType(); res = m_prog->GetFunctions()->DoCall(nIdent, token->GetString(), ppVar, this, token ); if (res.GetType() >= 0) return res.GetType(); SetError(TX_NOCALL, token); return true; }
CBotVarPointer::CBotVarPointer(const CBotToken& name, CBotTypResult& type) { if ( !type.Eq(CBotTypPointer) && !type.Eq(CBotTypNullPointer) && !type.Eq(CBotTypClass) && // for convenience accepts Class and Intrinsic !type.Eq(CBotTypIntrinsic) ) assert(0); m_token = new CBotToken(name); m_next = nullptr; m_pMyThis = nullptr; m_pUserPtr = nullptr; m_type = type; if ( !type.Eq(CBotTypNullPointer) ) m_type.SetType(CBotTypPointer); // anyway, this is a pointer m_binit = CBotVar::InitType::UNDEF; m_pClass = nullptr; m_pVarClass = nullptr; // will be defined by a SetPointer() SetClass(type.GetClass()); }
CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack) { CBotToken* pp = p; if (!IsOfType(p, ID_NEW)) return nullptr; // verifies that the token is a class name if (p->GetType() != TokenTypVar) { pStack->SetError(CBotErrBadNew, p); return nullptr; } CBotClass* pClass = CBotClass::Find(p); if (pClass == nullptr) { pStack->SetError(CBotErrBadNew, p); return nullptr; } CBotNew* inst = new CBotNew(); inst->SetToken(pp); inst->m_vartoken = *p; p = p->GetNext(); // creates the object on the stack // with a pointer to the object CBotVar* pVar = CBotVar::Create("", pClass); // do the call of the creator CBotCStack* pStk = pStack->TokenStack(); { // check if there are parameters CBotVar* ppVars[1000]; inst->m_parameters = CompileParams(p, pStk, ppVars); if (!pStk->IsOk()) goto error; // constructor exist? CBotTypResult r = pClass->CompileMethode(pClass->GetName(), pVar, ppVars, pStk, inst->m_nMethodeIdent); delete pStk->TokenStack(); // release extra stack int typ = r.GetType(); // if there is no constructor, and no parameters either, it's ok if (typ == CBotErrUndefCall && inst->m_parameters == nullptr) typ = 0; pVar->SetInit(CBotVar::InitType::DEF); // mark the instance as init if (typ>20) { pStk->SetError(static_cast<CBotError>(typ), inst->m_vartoken.GetEnd()); goto error; } // if the constructor does not exist, but there are parameters if (typ<0 && inst->m_parameters != nullptr) { pStk->SetError(CBotErrNoConstruct, &inst->m_vartoken); goto error; } // makes pointer to the object on the stack pStk->SetVar(pVar); pp = p; // chained method ? if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true))) { inst->m_exprRetVar->SetToken(pp); delete pStk->TokenStack(); } if (pStack->IsOk()) return pStack->Return(inst, pStk); } error: delete inst; return pStack->Return(nullptr, pStk); }
CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) { // seeks the corresponding classes if ( pClass == NULL ) { pStack->SetStartError(p->GetStart()); pClass = CBotClass::Find(p); if ( pClass == NULL ) { // not found? is bizare pStack->SetError(TX_NOCLASS, p); return NULL; } p = p->GetNext(); } bool bIntrinsic = pClass->IsIntrinsic(); CBotTypResult type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer, pClass ); CBotClassInst* inst = static_cast<CBotClassInst*>(CompileArray(p, pStack, type)); if ( inst != NULL || !pStack->IsOk() ) return inst; CBotCStack* pStk = pStack->TokenStack(); inst = new CBotClassInst(); /// \TODO Need to be revised and fixed after adding unit tests CBotToken token(pClass->GetName(), CBotString(), p->GetStart(), p->GetEnd()); inst->SetToken(&token); CBotToken* vartoken = p; if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) ) { (static_cast<CBotLeftExprVar*>(inst->m_var))->m_typevar = type; if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable { pStk->SetStartError(vartoken->GetStart()); pStk->SetError(TX_REDEFVAR, vartoken->GetEnd()); goto error; } if (IsOfType(p, ID_OPBRK)) // with any clues? { delete inst; // is not type CBotInt p = vartoken; // returns to the variable name // compiles declaration an array inst = static_cast<CBotClassInst*>(CBotInstArray::Compile( p, pStk, type )); if (!pStk->IsOk() ) { pStk->SetError(TX_CLBRK, p->GetStart()); goto error; } goto suite; // no assignment, variable already created } CBotVar* var; var = CBotVar::Create(vartoken->GetString(), type); // creates the instance // var->SetClass(pClass); var->SetUniqNum( (static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); // its attribute a unique number pStack->AddVar(var); // placed on the stack // look if there are parameters inst->m_hasParams = (p->GetType() == ID_OPENPAR); CBotVar* ppVars[1000]; inst->m_Parameters = CompileParams(p, pStk, ppVars); if ( !pStk->IsOk() ) goto error; // if there are parameters, is the equivalent to the stament "new" // CPoint A ( 0, 0 ) is equivalent to // CPoint A = new CPoint( 0, 0 ) // if ( NULL != inst->m_Parameters ) if ( inst->m_hasParams ) { // the constructor is there? // CBotString noname; CBotTypResult r = pClass->CompileMethode(pClass->GetName(), var, ppVars, pStk, inst->m_nMethodeIdent); delete pStk->TokenStack(); // releases the supplement stack int typ = r.GetType(); if (typ == TX_UNDEFCALL) { // si le constructeur n'existe pas if (inst->m_Parameters != NULL) // with parameters { pStk->SetError(TX_NOCONST, vartoken); goto error; } typ = 0; } if (typ>20) { pStk->SetError(typ, vartoken->GetEnd()); goto error; } } if (IsOfType(p, ID_ASS)) // with a assignment? { if (inst->m_hasParams) { pStk->SetError(TX_ENDOF, p->GetStart()); goto error; } if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) ) { goto error; } CBotClass* result = pStk->GetClass(); if ( !pStk->GetTypResult(1).Eq(CBotTypNullPointer) && ( !pStk->GetTypResult(1).Eq(CBotTypPointer) || ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ? { pStk->SetError(TX_BADTYPE, p->GetStart()); goto error; } // if ( !bIntrinsic ) var->SetPointer(pStk->GetVar()->GetPointer()); if ( !bIntrinsic ) { // does not use the result on the stack, to impose the class CBotVar* pvar = CBotVar::Create("", pClass); var->SetPointer( pvar ); // variable already declared instance pointer delete pvar; // removes the second pointer } var->SetInit(true); // marks the pointer as init } else if (inst->m_hasParams) { // creates the object on the "job" (\TODO "tas") // with a pointer to the object if ( !bIntrinsic ) { CBotVar* pvar = CBotVar::Create("", pClass); var->SetPointer( pvar ); // variable already declared instance pointer delete pvar; // removes the second pointer } var->SetInit(2); // marks the pointer as init } suite: if (IsOfType(p, ID_COMMA)) // several chained definitions { if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compiles the following { return pStack->Return(inst, pStk); } } if (IsOfType(p, ID_SEP)) // complete instruction { return pStack->Return(inst, pStk); } pStk->SetError(TX_ENDOF, p->GetStart()); } error: delete inst; return pStack->Return(NULL, pStk); }