X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Floader%2FInterpreter.cpp;h=a3d382ceba7618f9f1782bf718c1cf49293753be;hb=4bc70f5311dcbcca4e6b9e852bbcb19602f50eeb;hp=268fab9379954f35cad3e5abdaa99fa6578215ac;hpb=107b78b720db69ad402c09c0b1d9beb3b88a1952;p=l2e.git diff --git a/src/loader/Interpreter.cpp b/src/loader/Interpreter.cpp index 268fab9..a3d382c 100644 --- a/src/loader/Interpreter.cpp +++ b/src/loader/Interpreter.cpp @@ -8,77 +8,386 @@ #include "Interpreter.h" #include "ParsedSource.h" +#include "../battle/Hero.h" #include "../battle/Monster.h" +#include "../battle/PartyLayout.h" +#include "../battle/Resources.h" +#include "../common/Ikari.h" +#include "../common/Item.h" +#include "../common/Spell.h" +#include "../common/Stats.h" +#include "../common/TargetingMode.h" +#include "../graphics/ComplexAnimation.h" +#include "../graphics/Font.h" +#include "../graphics/Frame.h" +#include "../graphics/Gauge.h" +#include "../graphics/Menu.h" +#include "../graphics/SimpleAnimation.h" +#include "../graphics/Sprite.h" +#include +#include +#include + +using battle::Hero; using battle::Monster; -using std::map; +using battle::PartyLayout; +using common::Ikari; +using common::Item; +using common::Spell; +using common::Stats; +using common::TargetingMode; +using graphics::Animation; +using graphics::Color; +using graphics::Font; +using graphics::Frame; +using graphics::Gauge; +using graphics::ComplexAnimation; +using graphics::SimpleAnimation; +using graphics::Sprite; +using geometry::Vector; +using std::make_pair; using std::set; using std::string; +using std::vector; namespace loader { -void Interpreter::ReadSource() { - for (set::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) { - const Definition &dfn(source.GetDefinition(*i)); - if (dfn.HasLiteralValue()) { - ReadLiteral(dfn); +Interpreter::~Interpreter() { + for (vector::const_iterator i(postponedDefinitions.begin()), end(postponedDefinitions.end()); i != end; ++i) { + delete i->identifier; + } + for (std::map::const_iterator i(imageCache.begin()), end(imageCache.end()); i != end; ++i) { + SDL_FreeSurface(i->second); + } + // TODO: maybe need to reverse the array deletion check if most objects turn out to be arrays (of char) + for (std::map >::const_iterator i(values.begin()), end(values.end()); i != end; ++i) { + for (vector::const_iterator j(i->second.begin()), end(i->second.end()); j != end; ++j) { + delete[] reinterpret_cast(*j); + } + } +} + + +const Interpreter::ParsedDefinition &Interpreter::GetDefinition(const string &identifier) const { + return parsedDefinitions.at(identifier); +} + + +void *Interpreter::GetObject(int typeId, const std::string &name) { + std::map::const_iterator i(parsedDefinitions.find(name)); + if (i != parsedDefinitions.end()) { + const TypeDescription &requested(TypeDescription::Get(typeId)); + const TypeDescription &actual(TypeDescription::Get(i->second.type)); + if (requested.TypeId() == actual.TypeId()) { + return values[actual.TypeId()][i->second.id]; + } else if (actual.IsSubtypeOf(requested)) { + char *sub(reinterpret_cast(values[actual.TypeId()][i->second.id])); + std::ptrdiff_t offset(actual.SupertypeOffset(requested)); + return sub - offset; } else { - ReadObject(dfn); + throw Error("cannot cast " + actual.TypeName() + " to " + requested.TypeName()); } + } else { + throw Error("access to undefined object " + name); + } +} + + +void Interpreter::ReadSource() { + for (set::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) { + ReadDefinition(source.GetDefinition(*i)); + } +} + +void Interpreter::ReadDefinition(const Definition &dfn) { + if (parsedDefinitions.find(dfn.Identifier()) != parsedDefinitions.end()) { + return; + } + if (dfn.HasLiteralValue()) { + ReadLiteral(dfn); + } else { + ReadObject(dfn); } } void Interpreter::ReadLiteral(const Definition &dfn) { - switch (dfn.GetLiteral()->GetType()) { + const string &typeName(dfn.GetLiteral()->IsArray() ? "Array" : dfn.GetLiteral()->GetTypeName()); + int typeId(TypeDescription::GetTypeId(typeName)); + int id(values[typeId].size()); + const TypeDescription &td(TypeDescription::Get(typeId)); + int size( + (dfn.GetLiteral()->GetType() == Literal::PATH + || dfn.GetLiteral()->GetType() == Literal::STRING) + ? dfn.GetLiteral()->GetString().size() : td.Size()); + char *object(new char[size]); + if (dfn.GetLiteral()->GetType() == Literal::OBJECT) { + ReadObject(typeId, id, object, *dfn.GetLiteral()->GetProperties()); + } else { + ReadLiteral(typeId, id, object, *dfn.GetLiteral()); + } + values[typeId].push_back(object); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id))); +} + +void Interpreter::ReadLiteral(int typeId, int id, char *object, const Literal &literal) { + switch (literal.GetType()) { case Literal::ARRAY_VALUES: - throw Error("unhandled literal: array of values"); + throw Error("named value arrays are not supported, sorry"); break; case Literal::ARRAY_PROPS: - throw Error("unhandled literal: array of values"); + throw Error("named property list arrays are not supported, sorry"); break; case Literal::BOOLEAN: - throw Error("unhandled literal: array of values"); + new (object) bool(literal.GetBoolean()); break; case Literal::COLOR: - throw Error("unhandled literal: array of values"); + new (object) Color(literal.GetRed(), literal.GetGreen(), literal.GetBlue(), literal.GetAlpha()); break; case Literal::NUMBER: - throw Error("unhandled literal: array of values"); + new (object) int(literal.GetNumber()); + break; + case Literal::PATH: + std::memcpy(object, literal.GetString().c_str(), literal.GetString().size()); + object[literal.GetString().size()] = '\0'; break; case Literal::STRING: - throw Error("unhandled literal: array of values"); + std::memcpy(object, literal.GetString().c_str(), literal.GetString().size()); + object[literal.GetString().size()] = '\0'; break; case Literal::VECTOR: - throw Error("unhandled literal: array of values"); + new (object) Vector(literal.GetX(), literal.GetY()); break; case Literal::OBJECT: - throw Error("unhandled literal: array of values"); + throw Error("illogical branch: read literal object as non-object literal"); break; } } -void Interpreter::ReadObject(const Definition &dfn) { - if (dfn.TypeName() == "Monster") { - monsters.resize(monsters.size() + 1); - ReadMonster(monsters.back(), *dfn.GetProperties()); + +void *Interpreter::GetObject(int typeId, const Value &v) { + if (v.IsLiteral()) { + if (v.GetLiteral().IsObject()) { + int typeId(TypeDescription::GetTypeId(v.GetLiteral().GetTypeName())); + const TypeDescription &td(TypeDescription::Get(typeId)); + char *object(new char[td.Size()]); + td.Construct(object); + int id(values[typeId].size()); + values[typeId].push_back(object); + ReadObject(typeId, id, object, *v.GetLiteral().GetProperties()); + return object; + } else { + int typeId(0), id(0); + switch (v.GetLiteral().GetType()) { + case Literal::ARRAY_VALUES: + throw Error("cannot copy value arrays, sorry"); + break; + case Literal::ARRAY_PROPS: + throw Error("cannot copy property list arrays, sorry"); + break; + case Literal::BOOLEAN: + { + typeId = TypeDescription::GetTypeId("Boolean"); + id = values[typeId].size(); + const TypeDescription &td(TypeDescription::Get(typeId)); + char *object(new char[td.Size()]); + values[typeId].push_back(new (object) bool(v.GetLiteral().GetBoolean())); + } + break; + case Literal::COLOR: + { + typeId = TypeDescription::GetTypeId("Color"); + id = values[typeId].size(); + const TypeDescription &td(TypeDescription::Get(typeId)); + char *object(new char[td.Size()]); + values[typeId].push_back(new (object) Color(v.GetLiteral().GetRed(), v.GetLiteral().GetGreen(), v.GetLiteral().GetBlue(), v.GetLiteral().GetAlpha())); + } + break; + case Literal::NUMBER: + { + typeId = TypeDescription::GetTypeId("Number"); + id = values[typeId].size(); + const TypeDescription &td(TypeDescription::Get(typeId)); + char *object(new char[td.Size()]); + values[typeId].push_back(new (object) int(v.GetLiteral().GetNumber())); + } + break; + case Literal::PATH: + { + typeId = TypeDescription::GetTypeId("Path"); + id = values[typeId].size(); + char *str(new char[v.GetLiteral().GetString().size() + 1]); + std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size()); + str[v.GetLiteral().GetString().size()] = '\0'; + values[typeId].push_back(str); + } + break; + case Literal::STRING: + { + typeId = TypeDescription::GetTypeId("String"); + id = values[typeId].size(); + char *str(new char[v.GetLiteral().GetString().size() + 1]); + std::memcpy(str, v.GetLiteral().GetString().c_str(), v.GetLiteral().GetString().size()); + str[v.GetLiteral().GetString().size()] = '\0'; + values[typeId].push_back(str); + } + break; + case Literal::VECTOR: + { + typeId = TypeDescription::GetTypeId("Vector"); + id = values[typeId].size(); + const TypeDescription &td(TypeDescription::Get(typeId)); + char *object(new char[td.Size()]); + values[typeId].push_back(new (object) Vector(v.GetLiteral().GetX(), v.GetLiteral().GetY())); + } + break; + case Literal::OBJECT: + { + typeId = TypeDescription::GetTypeId(v.GetLiteral().GetTypeName()); + const TypeDescription &td(TypeDescription::Get(typeId)); + id = values[typeId].size(); + char *object(new char[td.Size()]); + td.Construct(object); + ReadObject(typeId, id, object, *v.GetLiteral().GetProperties()); + } + break; + } + return values[typeId][id]; + } } else { - throw Error("unhandled object: " + dfn.TypeName()); + ReadDefinition(source.GetDefinition(v.GetIdentifier())); + return GetObject(typeId, v.GetIdentifier()); } } -void Interpreter::ReadMonster(Monster &m, const PropertyList &props) { +void Interpreter::ReadObject(const Definition &dfn) { + int typeId(TypeDescription::GetTypeId(dfn.TypeName())); + const TypeDescription &td(TypeDescription::Get(typeId)); + int id(values[typeId].size()); + char *object(new char[td.Size()]); + td.Construct(object); + values[typeId].push_back(object); + ReadObject(typeId, id, object, *dfn.GetProperties()); + parsedDefinitions.insert(make_pair(dfn.Identifier(), ParsedDefinition(&dfn, typeId, id))); +} + + +void Interpreter::ReadObject(int typeId, int id, char *object, const PropertyList &props) { + const TypeDescription &td(TypeDescription::Get(typeId)); for (PropertyList::ConstIterator i(props.Begin()), end(props.End()); i != end; ++i) { - if (i->first == "name") { - if (i->second->IsLiteral()) { - m.SetName(i->second->GetLiteral().GetString().c_str()); + const FieldDescription &fd(td.GetField(i->first)); + const TypeDescription &fieldType(TypeDescription::Get(fd.TypeId())); + if (CanLink(*i->second)) { + char *dest(object + fd.Offset()); + if (fd.IsAggregate()) { + int arraySize(i->second->GetLiteral().ArraySize()); + char *aggregate(new char[fieldType.Size() * arraySize]); + char *iter(aggregate); + if (i->second->GetLiteral().GetType() == Literal::ARRAY_PROPS) { + const vector &list(i->second->GetLiteral().GetPropertyLists()); + for (vector::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) { + fieldType.Construct(iter); + ReadObject(fieldType.TypeId(), -1, iter, **j); + } + } else { + const vector &list(i->second->GetLiteral().GetValues()); + for (vector::const_iterator j(list.begin()), end(list.end()); j != end; ++j, iter += fieldType.Size()) { + fieldType.Construct(iter); + ReadLiteral(fieldType.TypeId(), -1, iter, (*j)->GetLiteral()); + } + } + if (fd.IsReferenced()) { + std::memcpy(dest, &aggregate, sizeof(char *)); + dest += sizeof(char *); + std::memcpy(dest, &arraySize, sizeof(int)); + } else { + throw Error("aggregate type fields must be referenced"); + } } else { - throw Error("identifier resolution not implemented"); + char *src(reinterpret_cast(GetObject(fd.TypeId(), *i->second))); + if (fd.TypeId() == TypeDescription::GetTypeId("Image")) { + src = reinterpret_cast(GetImage(src)); + } + if (fd.IsReferenced()) { + std::memcpy(dest, &src, sizeof(char *)); + } else { + std::memcpy(dest, src, fieldType.Size()); + } } } else { - throw Error("unknown monster property: " + i->first); + Postpone(typeId, id, fd.Offset(), i->second->GetIdentifier(), fd.TypeId(), !fd.IsReferenced()); } } + td.Load(object); +} + + +SDL_Surface *Interpreter::GetImage(const string &path) { + std::map::const_iterator result(imageCache.find(path)); + if (result != imageCache.end()) { + return result->second; + } else { + SDL_Surface *image(IMG_Load(path.c_str())); + imageCache.insert(make_pair(path, image)); + return image; + } +} + + +bool Interpreter::CanLink(const Value &v) const { + return v.IsLiteral() || source.IsDefined(v.GetIdentifier()); +} + +void Interpreter::Postpone(int type, int id, std::ptrdiff_t offset, const std::string &identifier, int linkedType, bool inlined) { + char *str(new char[identifier.size() + 1]); + std::memcpy(str, identifier.c_str(), identifier.size()); + str[identifier.size()] = '\0'; + postponedDefinitions.push_back(PostponedDefinition(type, id, offset, str, linkedType, inlined)); +} + + +void Interpreter::CreateTypeDescriptions() { + { + TypeDescription &td(TypeDescription::CreateOrGet("Boolean")); + td.SetDescription("Logical value which can be either true or false."); + td.SetSize(sizeof(bool)); + } + { + TypeDescription &td(TypeDescription::CreateOrGet("Color")); + td.SetDescription( + "A color in RGB format with an optional alpha channel.\n" + "Components range from 0 to 255.\n" + "Alpha defaults to 255 if omitted."); + td.SetSize(sizeof(Color)); + } + { + TypeDescription &td(TypeDescription::CreateOrGet("Image")); + td.SetDescription("Path to a PNG file with image data."); + td.SetSize(sizeof(SDL_Surface)); + } + { + TypeDescription &td(TypeDescription::CreateOrGet("Number")); + td.SetDescription("A signed integer."); + td.SetSize(sizeof(int)); + } + { + int stringId(TypeDescription::GetTypeId("String")); + TypeDescription &td(TypeDescription::CreateOrGet("Path")); + td.SetDescription("A path in the filesystem which is interpreted relative to the source file's location."); + td.SetSize(1); + td.AddSupertype(stringId, 0); + } + { + TypeDescription &td(TypeDescription::CreateOrGet("String")); + td.SetDescription("Some characters."); + td.SetSize(1); + } + { + TypeDescription &td(TypeDescription::CreateOrGet("Vector")); + td.SetDescription("A pair of numbers usually describing a 2D translation or offset."); + td.SetSize(sizeof(Vector)); + } } }