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/CBotDefString.h"
21 
22 #include "CBot/CBotInstr/CBotLeftExprVar.h"
23 #include "CBot/CBotInstr/CBotDefArray.h"
24 #include "CBot/CBotInstr/CBotTwoOpExpr.h"
25 
26 #include "CBot/CBotStack.h"
27 #include "CBot/CBotCStack.h"
28 
29 #include "CBot/CBotVar/CBotVar.h"
30 
31 namespace CBot
32 {
33 
34 ////////////////////////////////////////////////////////////////////////////////
CBotDefString()35 CBotDefString::CBotDefString()
36 {
37     m_var    = nullptr;
38     m_expr   = nullptr;
39 }
40 
41 ////////////////////////////////////////////////////////////////////////////////
~CBotDefString()42 CBotDefString::~CBotDefString()
43 {
44     delete m_var;
45     delete m_expr;
46 }
47 
48 ////////////////////////////////////////////////////////////////////////////////
Compile(CBotToken * & p,CBotCStack * pStack,bool cont,bool noskip)49 CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
50 {
51     CBotToken*    pp = cont ? nullptr : p;
52 
53     if (!cont && !IsOfType(p, ID_STRING)) return nullptr;
54 
55     CBotDefString*    inst = static_cast<CBotDefString*>(CompileArray(p, pStack, CBotTypString));
56     if (inst != nullptr || !pStack->IsOk()) return inst;
57 
58     CBotCStack* pStk = pStack->TokenStack(pp);
59 
60     inst = new CBotDefString();
61 
62     inst->m_expr = nullptr;
63 
64     CBotToken*    vartoken = p;
65     CBotVar*    var = nullptr;
66     inst->SetToken(vartoken);
67 
68     if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
69     {
70         (static_cast<CBotLeftExprVar*>(inst->m_var))->m_typevar = CBotTypString;
71         if (pStk->CheckVarLocal(vartoken))
72         {
73             pStk->SetStartError(vartoken->GetStart());
74             pStk->SetError(CBotErrRedefVar, vartoken->GetEnd());
75             goto error;
76         }
77 
78         if (IsOfType(p,  ID_OPBRK))
79         {
80             delete inst;    // type is not CBotDefString
81             p = vartoken;   // returns the variable name
82 
83             // compiles an array declaration
84 
85             CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypString);
86 
87             inst = static_cast<CBotDefString*>(inst2);
88             goto suite;     // no assignment, variable already created
89         }
90 
91         if (IsOfType(p,  ID_ASS))
92         {
93             pStk->SetStartError(p->GetStart());
94             if ( IsOfType(p, ID_SEP) )
95             {
96                 pStk->SetError(CBotErrNoExpression, p->GetStart());
97                 goto error;
98             }
99             if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
100             {
101                 goto error;
102             }
103 /*            if (!pStk->GetTypResult().Eq(CBotTypString))            // type compatible ?
104             {
105                 pStk->SetError(CBotErrBadType1, p->GetStart());
106                 goto error;
107             }*/
108         }
109 
110         var = CBotVar::Create(*vartoken, CBotTypString);
111         var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF);
112         var->SetUniqNum(
113             (static_cast<CBotLeftExprVar*>(inst->m_var))->m_nIdent = CBotVar::NextUniqNum());
114         pStack->AddVar(var);
115 suite:
116         if (pStk->IsOk() && IsOfType(p,  ID_COMMA))
117         {
118             if (nullptr != ( inst->m_next2b = CBotDefString::Compile(p, pStk, true, noskip)))
119             {
120                 return pStack->Return(inst, pStk);
121             }
122         }
123 
124         if (noskip || IsOfType(p,  ID_SEP))
125         {
126             return pStack->Return(inst, pStk);
127         }
128 
129         pStk->SetError(CBotErrNoTerminator, p->GetStart());
130     }
131 
132 error:
133     delete inst;
134     return pStack->Return(nullptr, pStk);
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
Execute(CBotStack * & pj)138 bool CBotDefString::Execute(CBotStack* &pj)
139 {
140     CBotStack*    pile = pj->AddStack(this);
141 
142     if ( pile->GetState()==0)
143     {
144         if (m_expr && !m_expr->Execute(pile)) return false;
145         m_var->Execute(pile);
146 
147         if (!pile->SetState(1)) return false;
148     }
149 
150     if (pile->IfStep()) return false;
151 
152     if ( m_next2b &&
153          !m_next2b->Execute(pile)) return false;
154 
155     return pj->Return(pile);
156 }
157 
158 ////////////////////////////////////////////////////////////////////////////////
RestoreState(CBotStack * & pj,bool bMain)159 void CBotDefString::RestoreState(CBotStack* &pj, bool bMain)
160 {
161     CBotStack*    pile = pj;
162 
163     if (bMain)
164     {
165         pile = pj->RestoreStack(this);
166         if (pile == nullptr) return;
167 
168         if ( pile->GetState()==0)
169         {
170             if (m_expr) m_expr->RestoreState(pile, bMain);
171             return;
172         }
173     }
174 
175     m_var->RestoreState(pile, bMain);
176 
177     if (m_next2b)
178          m_next2b->RestoreState(pile, bMain);
179 }
180 
GetDebugLinks()181 std::map<std::string, CBotInstr*> CBotDefString::GetDebugLinks()
182 {
183     auto links = CBotInstr::GetDebugLinks();
184     links["m_var"] = m_var;
185     links["m_expr"] = m_expr;
186     return links;
187 }
188 
189 } // namespace CBot
190