CBotVar* CBotCStack::CopyVar(CBotToken& Token) { CBotVar* pVar = FindVar( Token ); if ( pVar == NULL) return NULL; CBotVar* pCopy = CBotVar::Create( "", pVar->GetType() ); pCopy->Copy(pVar); return pCopy; }
bool CBotExprRetVar::Execute(CBotStack* &pj) { CBotStack* pile = pj->AddStack(); CBotStack* pile1 = pile; CBotVar* pVar; if (pile1->GetState() == 0) { pVar = pj->GetVar(); pVar->Update(pj->GetUserPtr()); if (pVar->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypNullPointer) { pile1->SetError(CBotErrNull, &m_token); return pj->Return(pile1); } if ( !m_next3->ExecuteVar(pVar, pile, &m_token, true, false) ) return false; if (pVar) pile1->SetCopyVar(pVar); else return pj->Return(pile1); pile1->IncState(); } pVar = pile1->GetVar(); if (pVar == nullptr) { return pj->Return(pile1); } if (pVar->IsUndefined()) { pile1->SetError(CBotErrNotInit, &m_token); return pj->Return(pile1); } return pj->Return(pile1); }
CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack) { CBotCStack* pStk = pStack->TokenStack(); pStk->SetStartError(p->GetStart()); // is it a variable name? if (p->GetType() == TokenTypVar) { CBotLeftExpr* inst = new CBotLeftExpr(); // creates the object inst->SetToken(p); CBotVar* var; if (nullptr != (var = pStk->FindVar(p))) // seek if known variable { inst->m_nIdent = var->GetUniqNum(); if (inst->m_nIdent > 0 && inst->m_nIdent < 9000) { if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly)) { pStk->SetError(CBotErrPrivate, p); goto err; } // this is an element of the current class // adds the equivalent of this. before CBotToken pthis("this"); inst->SetToken(&pthis); inst->m_nIdent = -2; // indent for this CBotFieldExpr* i = new CBotFieldExpr(); // new element i->SetToken(p); // keeps the name of the token inst->AddNext3(i); // add after var = pStk->FindVar(pthis); var = var->GetItem(p->GetString()); i->SetUniqNum(var->GetUniqNum()); } p = p->GetNext(); // next token while (true) { if (var->GetType() == CBotTypArrayPointer) { if (IsOfType( p, ID_OPBRK )) { CBotIndexExpr* i = new CBotIndexExpr(); i->m_expr = CBotExpression::Compile(p, pStk); inst->AddNext3(i); // add to the chain var = (static_cast<CBotVarArray*>(var))->GetItem(0,true); // gets the component [0] if (i->m_expr == nullptr) { pStk->SetError(CBotErrBadIndex, p->GetStart()); goto err; } if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) { pStk->SetError(CBotErrCloseIndex, p->GetStart()); goto err; } continue; } } if (var->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypPointer) // for classes { if (IsOfType(p, ID_DOT)) { CBotToken* pp = p; CBotFieldExpr* i = new CBotFieldExpr(); // new element i->SetToken(pp); // keeps the name of the token inst->AddNext3(i); // adds after if (p->GetType() == TokenTypVar) // must be a name { CBotVar* preVar = var; var = var->GetItem(p->GetString()); // get item correspondent if (var != nullptr) { if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, CBotVar::ProtectionLevel::ReadOnly)) { pStk->SetError(CBotErrPrivate, pp); goto err; } i->SetUniqNum(var->GetUniqNum()); p = p->GetNext(); // skips the name continue; } pStk->SetError(CBotErrUndefItem, p); } pStk->SetError(CBotErrUndefClass, p->GetStart()); goto err; } } break; } if (pStk->IsOk()) return static_cast<CBotLeftExpr*> (pStack->Return(inst, pStk)); } pStk->SetError(CBotErrUndefVar, p); err: delete inst; return static_cast<CBotLeftExpr*> ( pStack->Return(nullptr, pStk)); } return static_cast<CBotLeftExpr*> ( pStack->Return(nullptr, pStk)); }
CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bMethodsOnly) { if (p->GetType() == ID_DOT) { CBotVar* var = pStack->GetVar(); if (var == nullptr) return nullptr; CBotCStack* pStk = pStack->TokenStack(); CBotInstr* inst = new CBotExprRetVar(); while (true) { pStk->SetStartError(p->GetStart()); if (var->GetType() == CBotTypArrayPointer) { if (bMethodsOnly) goto err; if (IsOfType( p, ID_OPBRK )) { CBotIndexExpr* i = new CBotIndexExpr(); i->m_expr = CBotExpression::Compile(p, pStk); inst->AddNext3(i); var = var->GetItem(0,true); if (i->m_expr == nullptr || pStk->GetType() != CBotTypInt) { pStk->SetError(CBotErrBadIndex, p->GetStart()); goto err; } if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK )) { pStk->SetError(CBotErrCloseIndex, p->GetStart()); goto err; } continue; } } if (var->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypPointer) { if (IsOfType(p, ID_DOT)) { CBotToken* pp = p; if (p->GetType() == TokenTypVar) { if (p->GetNext()->GetType() == ID_OPENPAR) { CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var, bMethodsOnly); if (!pStk->IsOk()) goto err; inst->AddNext3(i); return pStack->Return(inst, pStk); } else if (bMethodsOnly) { p = p->GetPrev(); goto err; } else { CBotFieldExpr* i = new CBotFieldExpr(); i->SetToken(pp); inst->AddNext3(i); CBotVar* preVar = var; var = var->GetItem(p->GetString()); if (var != nullptr) { i->SetUniqNum(var->GetUniqNum()); if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var)) { pStk->SetError(CBotErrPrivate, pp); goto err; } } } if (var != nullptr) { p = p->GetNext(); continue; } pStk->SetError(CBotErrUndefItem, p); goto err; } pStk->SetError(CBotErrUndefClass, p); goto err; } } break; } pStk->SetCopyVar(var); if (pStk->IsOk()) return pStack->Return(inst, pStk); pStk->SetError(CBotErrUndefVar, p); err: delete inst; return pStack->Return(nullptr, pStk); } return nullptr; }
CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type) { CBotCStack* pStk = pStack->TokenStack(p); CBotDefArray* inst = new CBotDefArray(); CBotToken* vartoken = p; inst->SetToken(vartoken); // determinse the expression is valid for the item on the left side if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) { if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable? { pStk->SetError(CBotErrRedefVar, vartoken); goto error; } CBotInstr* i; while (IsOfType(p, ID_OPBRK)) { pStk->SetStartError(p->GetStart()); if (p->GetType() != ID_CLBRK) { i = CBotExpression::Compile(p, pStk); // expression for the value if (i == nullptr || pStk->GetType() != CBotTypInt) // must be a number { pStk->SetError(CBotErrBadIndex, p->GetStart()); goto error; } } else i = new CBotEmpty(); // if no special formula inst->AddNext3b(i); // construct a list type = CBotTypResult(CBotTypArrayPointer, type); if (IsOfType(p, ID_CLBRK)) continue; pStk->SetError(CBotErrCloseIndex, p->GetStart()); goto error; } CBotVar* var = CBotVar::Create(*vartoken, type); // create an instance inst->m_typevar = type; var->SetUniqNum( (static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); // place it on the stack if (IsOfType(p, ID_ASS)) // with an assignment { pStk->SetStartError(p->GetStart()); if ( IsOfType(p, ID_SEP) ) { pStk->SetError(CBotErrNoExpression, p->GetPrev()); goto error; } if ( nullptr == (inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem())) ) { if (pStk->IsOk()) { inst->m_listass = CBotTwoOpExpr::Compile(p, pStk); if (inst->m_listass == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } } } if (pStk->IsOk()) while (true) // mark initialized { var = var->GetItem(0, true); if (var == nullptr) break; if (var->GetType() == CBotTypArrayPointer) continue; if (var->GetType() <= CBotTypString) var->SetInit(CBotVar::InitType::DEF); break; } } if (pStk->IsOk()) return pStack->Return(inst, pStk); } error: delete inst; return pStack->Return(nullptr, pStk); }
CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic) { TypeOrError.SetType(TX_UNDEFCALL); // no routine of the name CBotFunction* pt; if ( nIdent ) { if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next ) { if ( pt->m_nFuncIdent == nIdent ) { TypeOrError = pt->m_retTyp; return pt; } } // search the list of public functions for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) { if ( pt->m_nFuncIdent == nIdent ) { TypeOrError = pt->m_retTyp; return pt; } } } if ( name == NULL ) return NULL; int delta = 99999; // seeks the lowest signature CBotFunction* pFunc = NULL; // the best function found if ( this != NULL ) { for ( pt = this ; pt != NULL ; pt = pt->m_next ) { if ( pt->m_token.GetString() == name ) { int i = 0; int alpha = 0; // signature of parameters // parameters are compatible? CBotDefParam* pv = pt->m_Param; // expected list of parameters CBotVar* pw = ppVars[i++]; // provided list parameter while ( pv != NULL && pw != NULL) { if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult())) { if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; break; } int d = pv->GetType() - pw->GetType(2); alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! pv = pv->GetNext(); pw = ppVars[i++]; } if ( pw != NULL ) { if ( pFunc != NULL ) continue; if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); continue; // too many parameters } if ( pv != NULL ) { if ( pFunc != NULL ) continue; if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); continue; // not enough parameters } if (alpha == 0) // perfect signature { nIdent = pt->m_nFuncIdent; TypeOrError = pt->m_retTyp; return pt; } if ( alpha < delta ) // a better signature? { pFunc = pt; delta = alpha; } } } } if ( bPublic ) { for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic ) { if ( pt->m_token.GetString() == name ) { int i = 0; int alpha = 0; // signature of parameters // parameters sont-ils compatibles ? CBotDefParam* pv = pt->m_Param; // list of expected parameters CBotVar* pw = ppVars[i++]; // list of provided parameters while ( pv != NULL && pw != NULL) { if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult())) { if ( pFunc == NULL ) TypeOrError = TX_BADPARAM; break; } int d = pv->GetType() - pw->GetType(2); alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! pv = pv->GetNext(); pw = ppVars[i++]; } if ( pw != NULL ) { if ( pFunc != NULL ) continue; if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM); if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM); continue; // to many parameters } if ( pv != NULL ) { if ( pFunc != NULL ) continue; if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM); if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM); continue; // not enough parameters } if (alpha == 0) // perfect signature { nIdent = pt->m_nFuncIdent; TypeOrError = pt->m_retTyp; return pt; } if ( alpha < delta ) // a better signature? { pFunc = pt; delta = alpha; } } } } if ( pFunc != NULL ) { nIdent = pFunc->m_nFuncIdent; TypeOrError = pFunc->m_retTyp; return pFunc; } return NULL; }