1 /*
2  * This file is part of the Colobot: Gold Edition source code
3  * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4  * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see http://gnu.org/licenses
18  */
19 
20 #include "CBot/CBotInstr/CBotCase.h"
21 
22 #include "CBot/CBotInstr/CBotTwoOpExpr.h"
23 
24 #include "CBot/CBotStack.h"
25 #include "CBot/CBotCStack.h"
26 
27 namespace CBot
28 {
29 
30 ////////////////////////////////////////////////////////////////////////////////
CBotCase()31 CBotCase::CBotCase()
32 {
33     m_instr = nullptr;
34 }
35 
36 ////////////////////////////////////////////////////////////////////////////////
~CBotCase()37 CBotCase::~CBotCase()
38 {
39     delete m_instr;
40 }
41 
Compile(CBotToken * & p,CBotCStack * pStack,std::unordered_map<long,CBotInstr * > & labels)42 CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map<long, CBotInstr*>& labels)
43 {
44     CBotToken*  pp = p;                         // preserves at the ^ token (starting position)
45 
46     if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return nullptr;     // should never happen
47     pStack->SetStartError(pp->GetStart());
48 
49     long labelValue = 0;
50 
51     if (pp->GetType() == ID_CASE)
52     {
53         CBotInstr* i = nullptr;
54         if (nullptr != (i = CBotTwoOpExpr::Compile(p, pStack, nullptr, true)))
55         {
56             if (pStack->GetType() <= CBotTypLong)
57             {
58                 CBotStack* pile = CBotStack::AllocateStack();
59                 while ( !i->Execute(pile) );
60                 labelValue = pile->GetVar()->GetValLong();
61                 pile->Delete();
62 
63                 if (labels.count(labelValue) > 0)
64                 {
65                     pStack->SetError(CBotErrRedefCase, p->GetStart());
66                 }
67             }
68             else
69                 pStack->SetError(CBotErrBadNum, p->GetStart());
70             delete i;
71         }
72         else
73             pStack->SetError(CBotErrBadNum, p->GetStart());
74     }
75 
76     if (pStack->IsOk() && IsOfType(p, ID_DOTS))
77     {
78         CBotCase* newCase = new CBotCase();
79         newCase->SetToken(pp);
80         if (pp->GetType() == ID_CASE)
81             labels[labelValue] = newCase;
82         return newCase;
83     }
84 
85     pStack->SetError(CBotErrNoDoubleDots, p->GetStart());
86     return nullptr;
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
Execute(CBotStack * & pj)90 bool CBotCase::Execute(CBotStack* &pj)
91 {
92     if (m_instr == nullptr) return true;
93     CBotStack* pile = pj->AddStack(this, CBotStack::BlockVisibilityType::BLOCK);
94 
95     int state = pile->GetState();
96     CBotInstr* p = m_instr;
97     while (state-- > 0) p = p->GetNext();
98 
99     while (p != nullptr)
100     {
101         if (!p->Execute(pile)) return false;
102         pile->IncState();
103         p = p->GetNext();
104     }
105 
106     pile->Delete();
107     return pj->IsOk();
108 }
109 
110 ////////////////////////////////////////////////////////////////////////////////
RestoreState(CBotStack * & pj,bool bMain)111 void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
112 {
113     if (!bMain) return;
114 
115     CBotStack* pile = pj->RestoreStack(this);
116     if (pile == nullptr) return;
117 
118     CBotInstr* p = m_instr;
119 
120     int state = pile->GetState();
121     while (p != nullptr && state-- > 0)
122     {
123         p->RestoreState(pile, bMain);
124         p = p->GetNext();
125     }
126 
127     if (p != nullptr) p->RestoreState(pile, bMain);
128 }
129 
GetDebugLinks()130 std::map<std::string, CBotInstr*> CBotCase::GetDebugLinks()
131 {
132     auto links = CBotInstr::GetDebugLinks();
133     links["m_instr"] = m_instr;
134     return links;
135 }
136 
137 } // namespace CBot
138