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/CBotExprLitChar.h"
21
22 #include "CBot/CBotStack.h"
23 #include "CBot/CBotCStack.h"
24
25 #include "CBot/CBotVar/CBotVar.h"
26
27 namespace CBot
28 {
29
CBotExprLitChar()30 CBotExprLitChar::CBotExprLitChar()
31 {
32 }
33
~CBotExprLitChar()34 CBotExprLitChar::~CBotExprLitChar()
35 {
36 }
37
Compile(CBotToken * & p,CBotCStack * pStack)38 CBotInstr* CBotExprLitChar::Compile(CBotToken* &p, CBotCStack* pStack)
39 {
40 CBotCStack* pStk = pStack->TokenStack();
41
42 const auto& s = p->GetString();
43
44 auto it = s.cbegin();
45 if (++it != s.cend())
46 {
47 if (*it != '\'') // not empty quotes ?
48 {
49 uint32_t valchar = 0;
50 int pos = p->GetStart() + 1;
51
52 if (*it != '\\') valchar = *(it++); // not escape sequence ?
53 else if (++it != s.cend())
54 {
55 pStk->SetStartError(pos++);
56 unsigned char c = *(it++);
57 if (c == '\"' || c == '\'' || c == '\\') valchar = c;
58 else if (c == 'a') valchar = '\a'; // alert bell
59 else if (c == 'b') valchar = '\b'; // backspace
60 else if (c == 'f') valchar = '\f'; // form feed
61 else if (c == 'n') valchar = '\n'; // new line
62 else if (c == 'r') valchar = '\r'; // carriage return
63 else if (c == 't') valchar = '\t'; // horizontal tab
64 else if (c == 'v') valchar = '\v'; // vertical tab
65 else if (c == 'u' || c == 'U') // unicode escape
66 {
67 if (it != s.cend())
68 {
69 std::string hex = "";
70 size_t maxlen = (c == 'u') ? 4 : 8;
71
72 for (size_t i = 0; i < maxlen; i++)
73 {
74 if (!CharInList(*it, "0123456789ABCDEFabcdef")) break;
75 ++pos;
76 hex += *it;
77 if (++it == s.cend()) break;
78 }
79
80 if (maxlen == hex.length()) // unicode character
81 {
82 try
83 {
84 valchar = std::stoi(hex, nullptr, 16);
85 if (0x10FFFF < valchar || (0xD7FF < valchar && valchar < 0xE000))
86 pStk->SetError(CBotErrUnicodeName, pos + 1);
87 }
88 catch (const std::out_of_range& e)
89 {
90 pStk->SetError(CBotErrHexRange, pos + 1);
91 }
92 }
93 else
94 pStk->SetError(CBotErrHexDigits, pos + 1);
95 }
96 else
97 pStk->SetError(CBotErrHexDigits, pos + 1);
98 }
99 else
100 pStk->SetError(CBotErrBadEscape, pos + 1);
101 }
102
103 if (it == s.cend() || *it != '\'')
104 pStk->SetError(CBotErrEndQuote, p);
105
106 if (pStk->IsOk())
107 {
108 CBotExprLitChar* inst = new CBotExprLitChar();
109 inst->m_valchar = valchar;
110 inst->SetToken(p);
111 p = p->GetNext();
112
113 CBotVar* var = CBotVar::Create("", CBotTypChar);
114 pStk->SetVar(var);
115
116 return pStack->Return(inst, pStk);
117 }
118 }
119 pStk->SetError(CBotErrCharEmpty, p);
120 }
121
122 pStk->SetError(CBotErrEndQuote, p);
123 return pStack->Return(nullptr, pStk);
124 }
125
Execute(CBotStack * & pj)126 bool CBotExprLitChar::Execute(CBotStack* &pj)
127 {
128 CBotStack* pile = pj->AddStack(this);
129
130 if (pile->IfStep()) return false;
131
132 CBotVar* var = CBotVar::Create("", CBotTypChar);
133
134 var->SetValChar(m_valchar);
135
136 pile->SetVar(var);
137
138 return pj->Return(pile);
139 }
140
RestoreState(CBotStack * & pj,bool bMain)141 void CBotExprLitChar::RestoreState(CBotStack* &pj, bool bMain)
142 {
143 if (bMain) pj->RestoreStack(this);
144 }
145
GetDebugData()146 std::string CBotExprLitChar::GetDebugData()
147 {
148 return m_token.GetString();
149 }
150
151 } // namespace CBot
152