/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "CBot/CBotDefParam.h" #include "CBot/CBotInstr/CBotInstrUtils.h" #include "CBot/CBotInstr/CBotParExpr.h" #include "CBot/CBotUtils.h" #include "CBot/CBotCStack.h" #include "CBot/CBotVar/CBotVarClass.h" #include namespace CBot { //////////////////////////////////////////////////////////////////////////////// CBotDefParam::CBotDefParam() { m_nIdent = 0; m_expr = nullptr; } //////////////////////////////////////////////////////////////////////////////// CBotDefParam::~CBotDefParam() { delete m_expr; } //////////////////////////////////////////////////////////////////////////////// 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 = nullptr; bool prevHasDefault = false; if (!IsOfType(p, ID_CLOSEPAR)) while (true) { CBotDefParam* param = new CBotDefParam(); if (list == nullptr) list = param; else list->AddNext(param); // added to the list param->m_typename = p->GetString(); CBotTypResult type = param->m_type = TypeParam(p, pStack); 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(CBotErrRedefVar, pp); break; } if (IsOfType(p, ID_ASS)) // default value assignment { CBotCStack* pStk = pStack->TokenStack(nullptr, true); if (nullptr != (param->m_expr = CBotParExpr::CompileLitExpr(p, pStk))) { CBotTypResult valueType = pStk->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); if (!TypesCompatibles(type, valueType)) pStack->SetError(CBotErrBadType1, p->GetPrev()); prevHasDefault = true; } else pStack->SetError(CBotErrNoExpression, p); pStack->DeleteNext(); } else if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev()); if (!pStack->IsOk()) break; if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody); CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable var->SetInit(CBotVar::InitType::IS_POINTER); // mark initialized param->m_nIdent = CBotVar::NextUniqNum(); var->SetUniqNum(param->m_nIdent); pStack->AddVar(var); // place on the stack if (IsOfType(p, ID_COMMA)) continue; if (IsOfType(p, ID_CLOSEPAR)) break; pStack->SetError(CBotErrClosePar, p->GetStart()); } pStack->SetError(CBotErrNoVar, p->GetStart()); } pStack->SetError(CBotErrNoType, p); delete list; return nullptr; } return list; } pStack->SetError(CBotErrOpenPar, p->GetStart()); return nullptr; } //////////////////////////////////////////////////////////////////////////////// bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj) { int i = 0; CBotDefParam* p = this; bool useDefault = false; CBotStack* pile = pj->AddStack(); while ( p != nullptr ) { pile = pile->AddStack(); if (pile->StackOver()) return pj->Return(pile); if (pile->GetState() == 1) // already done? { if (ppVars != nullptr && ppVars[i] != nullptr) ++i; p = p->m_next; continue; // next param } CBotVar* pVar = nullptr; if (useDefault || (ppVars == nullptr || ppVars[i] == nullptr)) { useDefault = true; // end of arguments found if (p->m_expr != nullptr) // has default expression ? { if (!p->m_expr->Execute(pile)) return false; // interupt here pVar = pile->GetVar(); } } else pVar = ppVars[i]; pile->SetState(1); // mark this param done // creates a local variable on the stack CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type); // serves to make the transformation of types: if ((useDefault && pVar != nullptr) || (ppVars != nullptr && pVar != nullptr)) { switch (p->m_type.GetType()) { case CBotTypByte: newvar->SetValByte(pVar->GetValByte()); newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypShort: newvar->SetValShort(pVar->GetValShort()); newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypChar: newvar->SetValChar(pVar->GetValChar()); newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypInt: newvar->SetValInt(pVar->GetValInt()); newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypLong: newvar->SetValLong(pVar->GetValLong()); newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypFloat: newvar->SetValFloat(pVar->GetValFloat()); newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypDouble: newvar->SetValDouble(pVar->GetValDouble()); newvar->SetInit(pVar->GetInit()); // copy nan break; case CBotTypString: newvar->SetValString(pVar->GetValString()); break; case CBotTypBoolean: newvar->SetValInt(pVar->GetValInt()); break; case CBotTypIntrinsic: (static_cast(newvar))->Copy(pVar, false); break; case CBotTypPointer: { newvar->SetPointer(pVar->GetPointer()); newvar->SetType(p->m_type); // keep pointer type } break; case CBotTypArrayPointer: { newvar->SetPointer(pVar->GetPointer()); } break; default: assert(0); } } newvar->SetUniqNum(p->m_nIdent); pj->AddVar(newvar); // add a variable p = p->m_next; if (!useDefault) i++; } return true; } //////////////////////////////////////////////////////////////////////////////// bool CBotDefParam::HasDefault() { return (m_expr != nullptr); } //////////////////////////////////////////////////////////////////////////////// void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) { CBotDefParam* p = this; CBotStack* pile = nullptr; if (bMain) pile = pj->RestoreStack(); while ( p != nullptr ) { if (bMain && pile != nullptr) { pile = pile->RestoreStack(); if (pile != nullptr && pile->GetState() == 0) { assert(p->m_expr != nullptr); p->m_expr->RestoreState(pile, true); return; } } // creates a local variable on the stack CBotVar* var = pj->FindVar(p->m_token.GetString()); if (var != nullptr) var->SetUniqNum(p->m_nIdent); p = p->m_next; } } //////////////////////////////////////////////////////////////////////////////// int CBotDefParam::GetType() { return m_type.GetType(); } //////////////////////////////////////////////////////////////////////////////// CBotTypResult CBotDefParam::GetTypResult() { return m_type; } //////////////////////////////////////////////////////////////////////////////// std::string CBotDefParam::GetParamString() { std::string param; param = m_typename; param += ' '; param += m_token.GetString(); return param; } } // namespace CBot