]> git.localhorst.tv Git - l2e.git/blob - src/loader/Interpreter.cpp
switched to static type IDs
[l2e.git] / src / loader / Interpreter.cpp
1 /*
2  * Interpreter.cpp
3  *
4  *  Created on: Aug 26, 2012
5  *      Author: holy
6  */
7
8 #include "Interpreter.h"
9
10 #include "ParsedSource.h"
11 #include "../battle/Hero.h"
12 #include "../battle/Monster.h"
13 #include "../battle/PartyLayout.h"
14 #include "../battle/Resources.h"
15 #include "../common/Ikari.h"
16 #include "../common/Item.h"
17 #include "../common/Script.h"
18 #include "../common/Spell.h"
19 #include "../common/Stats.h"
20 #include "../common/TargetingMode.h"
21 #include "../graphics/ComplexAnimation.h"
22 #include "../graphics/Font.h"
23 #include "../graphics/Frame.h"
24 #include "../graphics/Gauge.h"
25 #include "../graphics/Menu.h"
26 #include "../graphics/SimpleAnimation.h"
27 #include "../graphics/Sprite.h"
28
29 #include <algorithm>
30 #include <cstring>
31 #include <SDL_image.h>
32
33 using battle::Hero;
34 using battle::Monster;
35 using battle::PartyLayout;
36 using common::Ikari;
37 using common::Item;
38 using common::Script;
39 using common::Spell;
40 using common::Stats;
41 using common::TargetingMode;
42 using graphics::Animation;
43 using graphics::Color;
44 using graphics::Font;
45 using graphics::Frame;
46 using graphics::Gauge;
47 using graphics::ComplexAnimation;
48 using graphics::SimpleAnimation;
49 using graphics::Sprite;
50 using geometry::Vector;
51 using std::make_pair;
52 using std::set;
53 using std::string;
54 using std::vector;
55
56 namespace loader {
57
58 Interpreter::~Interpreter() {
59         for (std::map<string, SDL_Surface *>::const_iterator i(imageCache.begin()), end(imageCache.end()); i != end; ++i) {
60                 SDL_FreeSurface(i->second);
61         }
62 }
63
64
65 const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &identifier) {
66         std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(identifier));
67         if (i != parsedDefinitions.end()) {
68                 return i->second;
69         } else if (source.IsDefined(identifier)) {
70                 ReadDefinition(source.GetDefinition(identifier));
71                 return parsedDefinitions.at(identifier);
72         } else {
73                 throw Error("access to undefined object " + identifier);
74         }
75 }
76
77
78 void *Interpreter::GetObject(int typeId, const std::string &name) {
79         std::map<string, ParsedDefinition>::const_iterator i(parsedDefinitions.find(name));
80         if (i != parsedDefinitions.end()) {
81                 const TypeDescription &requested(TypeDescription::Get(typeId));
82                 const TypeDescription &actual(TypeDescription::Get(i->second.type));
83                 if (requested.TypeId() == actual.TypeId()) {
84                         return values[actual.TypeId()][i->second.id];
85                 } else if (actual.IsSubtypeOf(requested)) {
86                         char *sub(reinterpret_cast<char *>(values[actual.TypeId()][i->second.id]));
87                         std::ptrdiff_t offset(actual.SupertypeOffset(requested));
88                         return sub - offset;
89                 } else {
90                         throw Error("cannot cast " + actual.TypeName() + " to " + requested.TypeName());
91                 }
92         } else {
93                 throw Error("access to undefined object " + name);
94         }
95 }
96
97
98 void Interpreter::ReadSource() {
99         for (set<string>::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) {
100                 ReadDefinition(source.GetDefinition(*i));
101         }
102 }
103
104 void Interpreter::ReadDefinition(const Definition &dfn) {
105         if (parsedDefinitions.find(dfn.Identifier()) != parsedDefinitions.end()) {
106                 return;
107         }
108         if (dfn.HasLiteralValue()) {
109                 ReadLiteral(dfn);
110         } else {
111                 ReadObject(dfn);
112         }
113 }
114
115 void Interpreter::ReadLiteral(const Definition &dfn) {
116         const string &typeName(dfn.GetLiteral()->IsArray() ? "Array" : dfn.GetLiteral()->GetTypeName());
117         int typeId(TypeDescription::GetTypeId(typeName));
118         int id(values[typeId].size());
119         const TypeDescription &td(TypeDescription::Get(typeId));
120         int size(
121                         (dfn.GetLiteral()->GetType() == Literal::PATH
122                                         || dfn.GetLiteral()->GetType() == Literal::STRING)
123                         ? dfn.GetLiteral()->GetString().size() : td.Size());
124         char *object(alloc.Alloc(size));
125         values[typeId].push_back(object);
126         parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
127         if (dfn.GetLiteral()->GetType() == Literal::OBJECT) {
128                 ReadObject(typeId, id, object, *dfn.GetLiteral()->GetProperties());
129         } else {
130                 ReadLiteral(typeId, id, object, *dfn.GetLiteral());
131         }
132 }
133
134 void Interpreter::ReadLiteral(int typeId, int id, char *object, const Literal &literal) {
135         switch (literal.GetType()) {
136                 case Literal::ARRAY_VALUES:
137                         throw Error("named value arrays are not supported, sorry");
138                         break;
139                 case Literal::ARRAY_PROPS:
140                         throw Error("named property list arrays are not supported, sorry");
141                         break;
142                 case Literal::BOOLEAN:
143                         new (object) bool(literal.GetBoolean());
144                         break;
145                 case Literal::COLOR:
146                         new (object) Color(literal.GetRed(), literal.GetGreen(), literal.GetBlue(), literal.GetAlpha());
147                         break;
148                 case Literal::NUMBER:
149                         new (object) int(literal.GetNumber());
150                         break;
151                 case Literal::PATH:
152                         std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
153                         object[literal.GetString().size()] = '\0';
154                         break;
155                 case Literal::SCRIPT:
156                         new (object) Script;
157                         ReadScript(literal.GetScript(), reinterpret_cast<Script *>(object));
158                         break;
159                 case Literal::STRING:
160                         std::memcpy(object, literal.GetString().c_str(), literal.GetString().size());
161                         object[literal.GetString().size()] = '\0';
162                         break;
163                 case Literal::VECTOR:
164                         new (object) Vector<int>(literal.GetX(), literal.GetY());
165                         break;
166                 case Literal::OBJECT:
167                         throw Error("illogical branch: read literal object as non-object literal");
168         }
169 }
170
171
172 void *Interpreter::GetObject(int typeId, const Value &v) {
173         if (v.IsLiteral()) {
174                 if (v.GetLiteral().IsObject()) {
175                         int typeId(TypeDescription::GetTypeId(v.GetLiteral().GetTypeName()));
176                         const TypeDescription &td(TypeDescription::Get(typeId));
177                         char *object(alloc.Alloc(td.Size()));
178                         td.Construct(object);
179                         int id(values[typeId].size());
180                         values[typeId].push_back(object);
181                         ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
182                         return object;
183                 } else {
184                         int typeId(0), id(0);
185                         switch (v.GetLiteral().GetType()) {
186                                 case Literal::ARRAY_VALUES:
187                                         throw Error("cannot copy value arrays, sorry");
188                                         break;
189                                 case Literal::ARRAY_PROPS:
190                                         throw Error("cannot copy property list arrays, sorry");
191                                         break;
192                                 case Literal::BOOLEAN:
193                                         {
194                                                 typeId = TypeDescription::GetTypeId("Boolean");
195                                                 id = values[typeId].size();
196                                                 const TypeDescription &td(TypeDescription::Get(typeId));
197                                                 char *object(alloc.Alloc(td.Size()));
198                                                 values[typeId].push_back(new (object) bool(v.GetLiteral().GetBoolean()));
199                                         }
200                                         break;
201                                 case Literal::COLOR:
202                                         {
203                                                 typeId = TypeDescription::GetTypeId("Color");
204                                                 id = values[typeId].size();
205                                                 const TypeDescription &td(TypeDescription::Get(typeId));
206                                                 char *object(alloc.Alloc(td.Size()));
207                                                 values[typeId].push_back(new (object) Color(v.GetLiteral().GetRed(), v.GetLiteral().GetGreen(), v.GetLiteral().GetBlue(), v.GetLiteral().GetAlpha()));
208                                         }
209                                         break;
210                                 case Literal::NUMBER:
211                                         {
212                                                 typeId = TypeDescription::GetTypeId("Number");
213                                                 id = values[typeId].size();
214                                                 const TypeDescription &td(TypeDescription::Get(typeId));
215                                                 char *object(alloc.Alloc(td.Size()));
216                                                 values[typeId].push_back(new (object) int(v.GetLiteral().GetNumber()));
217                                         }
218                                         break;
219                                 case Literal::PATH:
220                                         {
221                                                 typeId = TypeDescription::GetTypeId("Path");
222                                                 id = values[typeId].size();
223                                                 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
224                                                 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
225                                                 str[v.GetLiteral().GetString().size()] = '\0';
226                                                 values[typeId].push_back(str);
227                                         }
228                                         break;
229                                 case Literal::SCRIPT:
230                                         {
231                                                 typeId = TypeDescription::GetTypeId("Script");
232                                                 char *script(ReadScript(v.GetLiteral().GetScript()));
233                                                 id = values[typeId].size();
234                                                 values[typeId].push_back(script);
235                                         }
236                                         break;
237                                 case Literal::STRING:
238                                         {
239                                                 typeId = TypeDescription::GetTypeId("String");
240                                                 id = values[typeId].size();
241                                                 char *str(alloc.Alloc(v.GetLiteral().GetString().size() + 1));
242                                                 std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size());
243                                                 str[v.GetLiteral().GetString().size()] = '\0';
244                                                 values[typeId].push_back(str);
245                                         }
246                                         break;
247                                 case Literal::VECTOR:
248                                         {
249                                                 typeId = TypeDescription::GetTypeId("Vector");
250                                                 id = values[typeId].size();
251                                                 const TypeDescription &td(TypeDescription::Get(typeId));
252                                                 char *object(alloc.Alloc(td.Size()));
253                                                 values[typeId].push_back(new (object) Vector<int>(v.GetLiteral().GetX(), v.GetLiteral().GetY()));
254                                         }
255                                         break;
256                                 case Literal::OBJECT:
257                                         {
258                                                 typeId = TypeDescription::GetTypeId(v.GetLiteral().GetTypeName());
259                                                 const TypeDescription &td(TypeDescription::Get(typeId));
260                                                 id = values[typeId].size();
261                                                 char *object(alloc.Alloc(td.Size()));
262                                                 td.Construct(object);
263                                                 ReadObject(typeId, id, object, *v.GetLiteral().GetProperties());
264                                         }
265                                         break;
266                         }
267                         return values[typeId][id];
268                 }
269         } else {
270                 ReadDefinition(source.GetDefinition(v.GetIdentifier()));
271                 return GetObject(typeId, v.GetIdentifier());
272         }
273 }
274
275
276 void Interpreter::ReadObject(const Definition &dfn) {
277         int typeId(TypeDescription::GetTypeId(dfn.TypeName()));
278         const TypeDescription &td(TypeDescription::Get(typeId));
279         int id(values[typeId].size());
280         char *object(alloc.Alloc(td.Size()));
281         td.Construct(object);
282         values[typeId].push_back(object);
283         parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id)));
284         ReadObject(typeId, id, object, *dfn.GetProperties());
285 }
286
287
288 void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyList &props) {
289         const TypeDescription &td(TypeDescription::Get(typeId));
290         for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) {
291                 const FieldDescription &fd(td.GetField(i->first));
292                 const TypeDescription &fieldType(TypeDescription::Get(fd.TypeId()));
293                 if (CanLink(*i->second)) {
294                         char *dest(object + fd.Offset());
295                         if (fd.IsAggregate()) {
296                                 int arraySize(i->second->GetLiteral().ArraySize());
297                                 char *aggregate(alloc.Alloc(fieldType.Size() * arraySize));
298                                 char *iter(aggregate);
299                                 if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) {
300                                         const vector<PropertyList *> &list(i->second->GetLiteral().GetPropertyLists());
301                                         for (vector<PropertyList *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
302                                                 fieldType.Construct(iter);
303                                                 ReadObject(fieldType.TypeId(), -1, iter, **j);
304                                         }
305                                 } else {
306                                         const vector<Value *> &list(i->second->GetLiteral().GetValues());
307                                         for (vector<Value *>::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) {
308                                                 fieldType.Construct(iter);
309                                                 ReadLiteral(fieldType.TypeId(), -1, iter, (*j)->GetLiteral());
310                                         }
311                                 }
312                                 if (fd.IsReferenced()) {
313                                         std::memcpy(dest, &aggregate, sizeof(char *));
314                                         dest += sizeof(char *);
315                                         std::memcpy(dest, &arraySize, sizeof(int));
316                                 } else {
317                                         throw Error("aggregate type fields must be referenced");
318                                 }
319                         } else if (i->second->IsLiteral() && !fd.IsReferenced()) {
320                                 // inline literals
321                                 if (i->second->GetLiteral().IsObject()) {
322                                         ReadObject(fd.TypeId(), -1, dest, *i->second->GetLiteral().GetProperties());
323                                 } else {
324                                         ReadLiteral(fd.TypeId(), -1, dest, i->second->GetLiteral());
325                                 }
326                         } else {
327                                 char *src(reinterpret_cast<char *>(GetObject(fd.TypeId(), *i->second)));
328                                 if (fd.TypeId() == TypeDescription::GetTypeId("Image")) {
329                                         src = reinterpret_cast<char *>(GetImage(src));
330                                 }
331                                 if (fd.IsReferenced()) {
332                                         std::memcpy(dest, &src, sizeof(char *));
333                                 } else {
334                                         std::memcpy(dest, src, fieldType.Size());
335                                 }
336                         }
337                 } else {
338                         Postpone(typeId, id, fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced());
339                 }
340         }
341         td.Load(object);
342 }
343
344
345 void Interpreter::ReadScript(const std::vector<ScriptToken *> &s, Script *script) {
346         std::map<string, int> labels;
347         int size(0);
348         for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
349                 if ((*i)->GetType() == ScriptToken::LABEL) {
350                         if (labels.count((*i)->Label())) {
351                                 throw Error("duplicate label " + (*i)->Label());
352                         } else {
353                                 labels[(*i)->Label()] = size;
354                         }
355                 } else if ((*i)->GetType() != ScriptToken::COMMAND) {
356                         throw Error("unexpected script token");
357                 }
358                 ++size;
359                 const string &cmd((*i)->CommandName());
360                 if (cmd == "move") {
361                         ++i;
362                         if (i == end) {
363                                 throw Error("unexpected script end after move");
364                         }
365                         const string &reg((*i)->RegisterName());
366                         switch (reg[0]) {
367                                 case 'a':
368                                         size += sizeof(void *);
369                                         break;
370                                 case 'i':
371                                         size += sizeof(int);
372                                         break;
373                                 case 'v':
374                                         size += sizeof(Vector<int>);
375                                         break;
376                                 default:
377                                         throw Error("unknown register " + reg);
378                         }
379                         ++i;
380                         if (i == end) {
381                                 throw Error("unexpected script end after move");
382                         }
383                 } else if (cmd == "add") {
384                         ++i;
385                         if (i == end) {
386                                 throw Error("unexpected script end after add");
387                         }
388                         const string &reg((*i)->RegisterName());
389                         switch (reg[0]) {
390                                 case 'i':
391                                         size += sizeof(int);
392                                         break;
393                                 case 'v':
394                                         size += sizeof(Vector<int>);
395                                         break;
396                                 default:
397                                         throw Error("expected register after add " + reg);
398                         }
399                         ++i;
400                         if (i == end) {
401                                 throw Error("unexpected script end after add");
402                         }
403                 } else if (cmd == "mod") {
404                         ++i;
405                         if (i == end) {
406                                 throw Error("unexpected script end after mod");
407                         }
408                         size += sizeof(int);
409                         ++i;
410                         if (i == end) {
411                                 throw Error("unexpected script end after mod");
412                         }
413                 } else if (cmd == "rand") {
414                         ++i;
415                         if (i == end) {
416                                 throw Error("unexpected script end after rand");
417                         }
418                         size += sizeof(int);
419                         ++i;
420                         if (i == end) {
421                                 throw Error("unexpected script end after rand");
422                         }
423                 } else if (cmd == "cmp") {
424                         ++i;
425                         if (i == end) {
426                                 throw Error("unexpected script end after cmp");
427                         }
428                         size += sizeof(int);
429                         ++i;
430                         if (i == end) {
431                                 throw Error("unexpected script end after cmp");
432                         }
433                 } else if (cmd == "jmp") {
434                         size += sizeof(int);
435                         ++i;
436                         if (i == end) {
437                                 throw Error("unexpected script end after cmp");
438                         }
439                 } else if (cmd == "jeq") {
440                         size += sizeof(int);
441                         ++i;
442                         if (i == end) {
443                                 throw Error("unexpected script end after cmp");
444                         }
445                 } else if (cmd == "jne") {
446                         size += sizeof(int);
447                         ++i;
448                         if (i == end) {
449                                 throw Error("unexpected script end after cmp");
450                         }
451                 } else if (cmd == "jl") {
452                         size += sizeof(int);
453                         ++i;
454                         if (i == end) {
455                                 throw Error("unexpected script end after cmp");
456                         }
457                 } else if (cmd == "jle") {
458                         size += sizeof(int);
459                         ++i;
460                         if (i == end) {
461                                 throw Error("unexpected script end after cmp");
462                         }
463                 } else if (cmd == "jg") {
464                         size += sizeof(int);
465                         ++i;
466                         if (i == end) {
467                                 throw Error("unexpected script end after cmp");
468                         }
469                 } else if (cmd == "jge") {
470                         size += sizeof(int);
471                         ++i;
472                         if (i == end) {
473                                 throw Error("unexpected script end after cmp");
474                         }
475                 } else if (cmd == "sysc") {
476
477                 } else {
478                         throw Error("unknown command " + cmd);
479                 }
480         }
481
482         unsigned char *text(reinterpret_cast<unsigned char *>(alloc.Alloc(size)));
483         int cursor(0);
484         for (vector<ScriptToken *>::const_iterator i(s.begin()), end(s.end()); i != end; ++i) {
485                 if ((*i)->GetType() == ScriptToken::LABEL) {
486                         continue;
487                 }
488                 if ((*i)->GetType() != ScriptToken::COMMAND) {
489                         throw Error("unexpected script token");
490                 }
491                 const string &cmd((*i)->CommandName());
492                 if (cmd == "move") {
493                         ++i;
494                         const string &reg((*i)->RegisterName());
495                         ++i;
496                         if (reg == "a0") {
497                                 text[cursor] = Script::CODE_MOVE_A0;
498                                 ++cursor;
499                                 ReadScriptAddress(**i, text + cursor);
500                                 cursor += sizeof(void *);
501                         } else if (reg == "a1") {
502                                 text[cursor] = Script::CODE_MOVE_A1;
503                                 ++cursor;
504                                 ReadScriptAddress(**i, text + cursor);
505                                 cursor += sizeof(void *);
506                         } else if (reg == "i0") {
507                                 text[cursor] = Script::CODE_MOVE_I0;
508                                 ++cursor;
509                                 ReadScriptInteger(**i, text + cursor);
510                                 cursor += sizeof(int);
511                         } else if (reg == "i1") {
512                                 text[cursor] = Script::CODE_MOVE_I1;
513                                 ++cursor;
514                                 ReadScriptInteger(**i, text + cursor);
515                                 cursor += sizeof(int);
516                         } else if (reg == "v0") {
517                                 text[cursor] = Script::CODE_MOVE_V0;
518                                 ++cursor;
519                                 ReadScriptVector(**i, text + cursor);
520                                 cursor += sizeof(Vector<int>);
521                         } else if (reg == "v1") {
522                                 text[cursor] = Script::CODE_MOVE_V1;
523                                 ++cursor;
524                                 ReadScriptVector(**i, text + cursor);
525                                 cursor += sizeof(Vector<int>);
526                         } else {
527                                 throw Error("unknown register " + reg);
528                         }
529                 } else if (cmd == "add") {
530                         ++i;
531                         const string &reg((*i)->RegisterName());
532                         ++i;
533                         if (reg == "i0") {
534                                 text[cursor] = Script::CODE_ADD_I0;
535                                 ++cursor;
536                                 ReadScriptInteger(**i, text + cursor);
537                                 cursor += sizeof(int);
538                         } else if (reg == "i1") {
539                                 text[cursor] = Script::CODE_ADD_I1;
540                                 ++cursor;
541                                 ReadScriptInteger(**i, text + cursor);
542                                 cursor += sizeof(int);
543                         } else if (reg == "v0") {
544                                 text[cursor] = Script::CODE_ADD_V0;
545                                 ++cursor;
546                                 ReadScriptVector(**i, text + cursor);
547                                 cursor += sizeof(Vector<int>);
548                         } else if (reg == "v1") {
549                                 text[cursor] = Script::CODE_ADD_V1;
550                                 ++cursor;
551                                 ReadScriptVector(**i, text + cursor);
552                                 cursor += sizeof(Vector<int>);
553                         } else {
554                                 throw Error("unexpected register " + reg);
555                         }
556                 } else if (cmd == "mod") {
557                         ++i;
558                         const string &reg((*i)->RegisterName());
559                         ++i;
560                         if (reg == "i0") {
561                                 text[cursor] = Script::CODE_MOD_I0;
562                                 ++cursor;
563                                 ReadScriptInteger(**i, text + cursor);
564                                 cursor += sizeof(int);
565                         } else if (reg == "i1") {
566                                 text[cursor] = Script::CODE_MOD_I1;
567                                 ++cursor;
568                                 ReadScriptInteger(**i, text + cursor);
569                                 cursor += sizeof(int);
570                         } else {
571                                 throw Error("unexpected register " + reg);
572                         }
573                 } else if (cmd == "rand") {
574                         ++i;
575                         const string &reg((*i)->RegisterName());
576                         if (reg == "i0") {
577                                 text[cursor] = Script::CODE_RAND_I0;
578                                 ++cursor;
579                         } else if (reg == "i1") {
580                                 text[cursor] = Script::CODE_RAND_I1;
581                                 ++cursor;
582                         } else {
583                                 throw Error("unexpected register " + reg);
584                         }
585                 } else if (cmd == "cmp") {
586                         ++i;
587                         const string &reg((*i)->RegisterName());
588                         ++i;
589                         if (reg == "i0") {
590                                 if ((*i)->GetType() == ScriptToken::REGISTER && (*i)->RegisterName() == "i1") {
591                                         text[cursor] = Script::CODE_CMP_I0_I1;
592                                         ++cursor;
593                                 } else {
594                                         text[cursor] = Script::CODE_CMP_I0;
595                                         ++cursor;
596                                         ReadScriptInteger(**i, text + cursor);
597                                         cursor += sizeof(int);
598                                 }
599                         } else if (reg == "i1") {
600                                 text[cursor] = Script::CODE_CMP_I1;
601                                 ++cursor;
602                                 ReadScriptInteger(**i, text + cursor);
603                                 cursor += sizeof(int);
604                         } else {
605                                 throw Error("cannot use " + reg + " as lhs for comparison");
606                         }
607                 } else if (cmd == "jmp") {
608                         text[cursor] = Script::CODE_JUMP;
609                         ++cursor;
610                         ++i;
611                         if (!labels.count((*i)->Identifier())) {
612                                 throw Error("use of undefined label " + (*i)->Identifier());
613                         }
614                         *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
615                         cursor += sizeof(int);
616                 } else if (cmd == "jeq") {
617                         text[cursor] = Script::CODE_JUMP_EQUAL;
618                         ++cursor;
619                         ++i;
620                         if (!labels.count((*i)->Identifier())) {
621                                 throw Error("use of undefined label " + (*i)->Identifier());
622                         }
623                         *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
624                         cursor += sizeof(int);
625                 } else if (cmd == "jne") {
626                         text[cursor] = Script::CODE_JUMP_NOT_EQUAL;
627                         ++cursor;
628                         ++i;
629                         if (!labels.count((*i)->Identifier())) {
630                                 throw Error("use of undefined label " + (*i)->Identifier());
631                         }
632                         *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
633                         cursor += sizeof(int);
634                 } else if (cmd == "jl") {
635                         text[cursor] = Script::CODE_JUMP_LESS;
636                         ++cursor;
637                         ++i;
638                         if (!labels.count((*i)->Identifier())) {
639                                 throw Error("use of undefined label " + (*i)->Identifier());
640                         }
641                         *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
642                         cursor += sizeof(int);
643                 } else if (cmd == "jle") {
644                         text[cursor] = Script::CODE_JUMP_LESS_EQUAL;
645                         ++cursor;
646                         ++i;
647                         if (!labels.count((*i)->Identifier())) {
648                                 throw Error("use of undefined label " + (*i)->Identifier());
649                         }
650                         *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
651                         cursor += sizeof(int);
652                 } else if (cmd == "jg") {
653                         text[cursor] = Script::CODE_JUMP_GREATER;
654                         ++cursor;
655                         ++i;
656                         if (!labels.count((*i)->Identifier())) {
657                                 throw Error("use of undefined label " + (*i)->Identifier());
658                         }
659                         *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
660                         cursor += sizeof(int);
661                 } else if (cmd == "jge") {
662                         text[cursor] = Script::CODE_JUMP_GREATER_EQUAL;
663                         ++cursor;
664                         ++i;
665                         if (!labels.count((*i)->Identifier())) {
666                                 throw Error("use of undefined label " + (*i)->Identifier());
667                         }
668                         *reinterpret_cast<int *>(text + cursor) = labels[(*i)->Identifier()];
669                         cursor += sizeof(int);
670                 } else if (cmd == "sysc") {
671                         text[cursor] = Script::CODE_SYSCALL;
672                         ++cursor;
673                 } else {
674                         throw Error("unknown command " + cmd);
675                 }
676         }
677
678         script->text = text;
679         script->textlen = size;
680 }
681
682 char *Interpreter::ReadScript(const vector<ScriptToken *> &s) {
683         char *mem(alloc.Alloc(sizeof(Script)));
684         new (mem) Script;
685         Script *script(reinterpret_cast<Script *>(mem));
686         ReadScript(s, script);
687         return mem;
688 }
689
690 void Interpreter::ReadScriptAddress(const ScriptToken &t, unsigned char *dest) {
691         if (t.GetType() != ScriptToken::IDENTIFIER) {
692                 throw Error("expected identifier for address");
693         }
694         if (source.IsDefined(t.Identifier())) {
695                 const ParsedDefinition &def(GetDefinition(t.Identifier()));
696                 void *addr(GetObject(def.type, t.Identifier()));
697                 *reinterpret_cast<void **>(dest) = addr;
698         } else {
699                 throw Error("postponing values in scripts not implemented");
700         }
701 }
702
703 void Interpreter::ReadScriptInteger(const ScriptToken &t, unsigned char *dest) {
704         if (t.GetType() == ScriptToken::IDENTIFIER) {
705                 if (source.IsDefined(t.Identifier())) {
706                         void *num(GetObject(TypeDescription::GetTypeId("Number"), t.Identifier()));
707                         *reinterpret_cast<int *>(dest) = *reinterpret_cast<int *>(num);
708                 } else {
709                         throw Error("postponing values in scripts not implemented");
710                 }
711         } else if (t.GetType() == ScriptToken::LITERAL) {
712                 *reinterpret_cast<int *>(dest) = t.GetLiteral()->GetNumber();
713         } else {
714                 throw Error("expected identifier or integer literal");
715         }
716 }
717
718 void Interpreter::ReadScriptVector(const ScriptToken &t, unsigned char *dest) {
719         if (t.GetType() == ScriptToken::IDENTIFIER) {
720                 if (source.IsDefined(t.Identifier())) {
721                         void *vec(GetObject(TypeDescription::GetTypeId("Vector"), t.Identifier()));
722                         *reinterpret_cast<Vector<int> *>(dest) = *reinterpret_cast<Vector<int> *>(vec);
723                 } else {
724                         throw Error("postponing values in scripts not implemented");
725                 }
726         } else if (t.GetType() == ScriptToken::LITERAL) {
727                 *reinterpret_cast<Vector<int> *>(dest) = Vector<int>(t.GetLiteral()->GetX(), t.GetLiteral()->GetY());
728         } else {
729                 throw Error("expected identifier or vector literal");
730         }
731 }
732
733
734 SDL_Surface *Interpreter::GetImage(const string &path) {
735         std::map<string, SDL_Surface *>::const_iterator result(imageCache.find(path));
736         if (result != imageCache.end()) {
737                 return result->second;
738         } else {
739                 SDL_Surface *image(IMG_Load(path.c_str()));
740                 imageCache.insert(make_pair(path, image));
741                 return image;
742         }
743 }
744
745
746 bool Interpreter::CanLink(const Value &v) const {
747         return v.IsLiteral() || source.IsDefined(v.GetIdentifier());
748 }
749
750 void Interpreter::Postpone(int type, int id, std::ptrdiff_t offset, const std::string &identifier, int linkedType, bool inlined) {
751         char *str(alloc.Alloc(identifier.size() + 1));
752         std::memcpy(str, identifier.c_str(), identifier.size());
753         str[identifier.size()] = '\0';
754         postponedDefinitions.push_back(PostponedDefinition(type, id, offset, str, linkedType, inlined));
755 }
756
757
758 void Interpreter::CreateTypeDescriptions() {
759         {
760                 TypeDescription &td(TypeDescription::Create(BOOLEAN_ID, "Boolean"));
761                 td.SetDescription("Logical value which can be either true or false.");
762                 td.SetSize(sizeof(bool));
763         }
764         {
765                 TypeDescription &td(TypeDescription::Create(COLOR_ID, "Color"));
766                 td.SetDescription(
767                                 "A color in RGB format with an optional alpha channel.\n"
768                                 "Components range from 0 to 255.\n"
769                                 "Alpha defaults to 255 if omitted.");
770                 td.SetSize(sizeof(Color));
771         }
772         {
773                 TypeDescription &td(TypeDescription::Create(IMAGE_ID, "Image"));
774                 td.SetDescription("Path to a PNG file with image data.");
775                 td.SetSize(sizeof(SDL_Surface));
776         }
777         {
778                 TypeDescription &td(TypeDescription::Create(NUMBER_ID, "Number"));
779                 td.SetDescription("A signed integer.");
780                 td.SetSize(sizeof(int));
781         }
782         {;
783                 TypeDescription &td(TypeDescription::Create(PATH_ID, "Path"));
784                 td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location.");
785                 td.SetSize(1);
786                 td.AddSupertype(STRING_ID, 0);
787         }
788         {
789                 TypeDescription &td(TypeDescription::Create(SCRIPT_ID, "Script"));
790                 td.SetDescription("Collection of commands that define a behaviour.");
791                 td.SetSize(sizeof(Script));
792         }
793         {
794                 TypeDescription &td(TypeDescription::Create(STRING_ID, "String"));
795                 td.SetDescription("Some characters.");
796                 td.SetSize(1);
797         }
798         {
799                 TypeDescription &td(TypeDescription::Create(VECTOR_ID, "Vector"));
800                 td.SetDescription("A pair of numbers usually describing a 2D translation or offset.");
801                 td.SetSize(sizeof(Vector<int>));
802         }
803 }
804
805 }