diff --git a/aegisub/libaegisub/common/cajun/elements.cpp b/aegisub/libaegisub/common/cajun/elements.cpp index c3f9b97ce..94635a139 100644 --- a/aegisub/libaegisub/common/cajun/elements.cpp +++ b/aegisub/libaegisub/common/cajun/elements.cpp @@ -14,32 +14,40 @@ Author: Terry Caton #include #endif +namespace { + using namespace json; + + class CastVisitorBase : public Visitor, public ConstVisitor { + void Visit(Array&) { } + void Visit(Object&) { } + void Visit(Number&) { } + void Visit(String&) { } + void Visit(Boolean&) { } + void Visit(Null&) { is_null = true; } + void Visit(Array const&) { } + void Visit(Object const&) { } + void Visit(Number const&) { } + void Visit(String const&) { } + void Visit(Boolean const&) { } + void Visit(Null const&) { is_null = true; } + public: + bool is_null; + CastVisitorBase() : is_null(false) { } + }; + + template + struct CastVisitor : public CastVisitorBase { + T *element; + CastVisitor() : element(0) { } + void Visit(T& ele) { element = &ele; } + }; +} + namespace json { ///////////////////////// // UnknownElement members -class CastVisitor : public ConstVisitor -{ - virtual void Visit(const Array&) { } - virtual void Visit(const Object&) { } - virtual void Visit(const Number&) { } - virtual void Visit(const String&) { } - virtual void Visit(const Boolean&) { } - virtual void Visit(const Null&) { } -}; - -template -class CastVisitor_T : public CastVisitor -{ -public: - const ElementTypeT *element; - CastVisitor_T() : element(0) { } - - // we don't know what this is, but it overrides one of the base's no-op functions - void Visit(const ElementTypeT& element) { this->element = &element; } -}; - class UnknownElement::Imp { public: @@ -57,15 +65,15 @@ template class UnknownElement::Imp_T : public UnknownElement::Imp { public: - Imp_T(const ElementTypeT& element) : m_Element(element) {} - virtual Imp* Clone() const { return new Imp_T(*this); } + Imp_T(const ElementTypeT& element) : m_Element(element) { } + Imp* Clone() const { return new Imp_T(*this); } - virtual void Accept(ConstVisitor& visitor) const { visitor.Visit(m_Element); } - virtual void Accept(Visitor& visitor) { visitor.Visit(m_Element); } + void Accept(ConstVisitor& visitor) const { visitor.Visit(m_Element); } + void Accept(Visitor& visitor) { visitor.Visit(m_Element); } - virtual bool Compare(const Imp& imp) const + bool Compare(const Imp& imp) const { - CastVisitor_T castVisitor; + CastVisitor castVisitor; imp.Accept(castVisitor); return castVisitor.element && m_Element == *castVisitor.element; } @@ -88,31 +96,30 @@ UnknownElement::UnknownElement(const Null& null) : m_pImp( new Imp UnknownElement::~UnknownElement() { delete m_pImp; } -UnknownElement::operator const Object& () const { return CastTo(); } -UnknownElement::operator const Array& () const { return CastTo(); } -UnknownElement::operator const Number& () const { return CastTo(); } -UnknownElement::operator const Boolean& () const { return CastTo(); } -UnknownElement::operator const String& () const { return CastTo(); } -UnknownElement::operator const Null& () const { return CastTo(); } +UnknownElement::operator Object const&() const { return CastTo(); } +UnknownElement::operator Array const&() const { return CastTo(); } +UnknownElement::operator Number const&() const { return CastTo(); } +UnknownElement::operator Boolean const&() const { return CastTo(); } +UnknownElement::operator String const&() const { return CastTo(); } +UnknownElement::operator Null const&() const { return CastTo(); } -UnknownElement::operator Object& () { return ConvertTo(); } -UnknownElement::operator Array& () { return ConvertTo(); } -UnknownElement::operator Number& () { return ConvertTo(); } -UnknownElement::operator Boolean& () { return ConvertTo(); } -UnknownElement::operator String& () { return ConvertTo(); } -UnknownElement::operator Null& () { return ConvertTo(); } +UnknownElement::operator Object&() { return CastTo(); } +UnknownElement::operator Array&() { return CastTo(); } +UnknownElement::operator Number&() { return CastTo(); } +UnknownElement::operator Boolean&() { return CastTo(); } +UnknownElement::operator String&() { return CastTo(); } +UnknownElement::operator Null&() { return CastTo(); } -UnknownElement& UnknownElement::operator = (const UnknownElement& unknown) +UnknownElement& UnknownElement::operator =(const UnknownElement& unknown) { delete m_pImp; m_pImp = unknown.m_pImp->Clone(); return *this; } -UnknownElement& UnknownElement::operator[] (const std::string& key) +UnknownElement& UnknownElement::operator[](const std::string& key) { - // the people want an object. make us one if we aren't already - return ConvertTo()[key]; + return CastTo()[key]; } const UnknownElement& UnknownElement::operator[] (const std::string& key) const @@ -125,23 +132,14 @@ const UnknownElement& UnknownElement::operator[] (const std::string& key) const return it->second; } -UnknownElement& UnknownElement::operator[] (size_t index) -{ - // the people want an array. make us one if we aren't already - return ConvertTo()[index]; -} - -const UnknownElement& UnknownElement::operator[] (size_t index) const -{ - // throws if we aren't an array - return CastTo()[index]; -} +UnknownElement& UnknownElement::operator[](size_t index) { return CastTo()[index]; } +UnknownElement const& UnknownElement::operator[](size_t index) const { return CastTo()[index]; } template -const ElementTypeT& UnknownElement::CastTo() const +ElementTypeT const& UnknownElement::CastTo() const { - CastVisitor_T castVisitor; + CastVisitor castVisitor; m_pImp->Accept(castVisitor); if (!castVisitor.element) throw Exception("Bad cast"); @@ -149,17 +147,21 @@ const ElementTypeT& UnknownElement::CastTo() const } template -ElementTypeT& UnknownElement::ConvertTo() +ElementTypeT& UnknownElement::CastTo() { - CastVisitor_T castVisitor; + CastVisitor castVisitor; Accept(castVisitor); - if (!castVisitor.element) - { - // we're not the right type. fix it & try again + + // If this element is uninitialized, implicitly convert it to the desired type + if (castVisitor.is_null) { *this = ElementTypeT(); + return *this; } - return *this; + // Otherwise throw an exception + if (!castVisitor.element) + throw Exception("Bad cast"); + return *castVisitor.element; } void UnknownElement::Accept(ConstVisitor& visitor) const { m_pImp->Accept(visitor); } diff --git a/aegisub/libaegisub/common/cajun/reader.cpp b/aegisub/libaegisub/common/cajun/reader.cpp index baf263c36..d45b99099 100644 --- a/aegisub/libaegisub/common/cajun/reader.cpp +++ b/aegisub/libaegisub/common/cajun/reader.cpp @@ -123,7 +123,7 @@ void Reader::Read_i(ElementTypeT& element, std::istream& istr) reader.Scan(tokens, inputStream); TokenStream tokenStream(tokens); - reader.Parse(element, tokenStream); + element = reader.Parse(tokenStream); if (!tokenStream.EOS()) { @@ -304,131 +304,79 @@ void Reader::MatchNumber(std::string& sNumber, InputStream& inputStream) } -void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStream) +UnknownElement Reader::Parse(Reader::TokenStream& tokenStream) { - if (tokenStream.EOS()) { + if (tokenStream.EOS()) throw ParseException("Unexpected end of token stream", Location(), Location()); // nowhere to point to - } - const Token& token = tokenStream.Peek(); + Token const& token = tokenStream.Peek(); switch (token.nType) { - case Token::TOKEN_OBJECT_BEGIN: - { - // implicit non-const cast will perform conversion for us (if necessary) - Object& object = element; - Parse(object, tokenStream); - break; - } - - case Token::TOKEN_ARRAY_BEGIN: - { - Array& array = element; - Parse(array, tokenStream); - break; - } - - case Token::TOKEN_STRING: - { - String& string = element; - Parse(string, tokenStream); - break; - } - - case Token::TOKEN_NUMBER: - { - Number& number = element; - Parse(number, tokenStream); - break; - } - - case Token::TOKEN_BOOLEAN: - { - Boolean& boolean = element; - Parse(boolean, tokenStream); - break; - } - - case Token::TOKEN_NULL: - { - Null& null = element; - Parse(null, tokenStream); - break; - } - + case Token::TOKEN_OBJECT_BEGIN: return ParseObject(tokenStream); + case Token::TOKEN_ARRAY_BEGIN: return ParseArray(tokenStream); + case Token::TOKEN_STRING: return ParseString(tokenStream); + case Token::TOKEN_NUMBER: return ParseNumber(tokenStream); + case Token::TOKEN_BOOLEAN: return ParseBoolean(tokenStream); + case Token::TOKEN_NULL: return ParseNull(tokenStream); default: - { throw ParseException("Unexpected token: " + token.sValue, token.locBegin, token.locEnd); - } } } - -void Reader::Parse(Object& object, Reader::TokenStream& tokenStream) +Object Reader::ParseObject(Reader::TokenStream& tokenStream) { MatchExpectedToken(Token::TOKEN_OBJECT_BEGIN, tokenStream); - bool bContinue = (tokenStream.EOS() == false && - tokenStream.Peek().nType != Token::TOKEN_OBJECT_END); - while (bContinue) + Object object; + + while (!tokenStream.EOS() && tokenStream.Peek().nType != Token::TOKEN_OBJECT_END) { // first the member name. save the token in case we have to throw an exception const Token& tokenName = tokenStream.Peek(); std::string const& name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream); if (object.count(name)) - { throw ParseException("Duplicate object member token: " + name, tokenName.locBegin, tokenName.locEnd); - } // ...then the key/value separator... MatchExpectedToken(Token::TOKEN_MEMBER_ASSIGN, tokenStream); // ...then the value itself (can be anything). - UnknownElement value; - Parse(value, tokenStream); + object[name] = Parse(tokenStream); - object[name] = value; - - bContinue = (tokenStream.EOS() == false && - tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT); - if (bContinue) + if (!tokenStream.EOS() && tokenStream.Peek().nType != Token::TOKEN_OBJECT_END) MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream); } MatchExpectedToken(Token::TOKEN_OBJECT_END, tokenStream); + + return object; } - -void Reader::Parse(Array& array, Reader::TokenStream& tokenStream) +Array Reader::ParseArray(Reader::TokenStream& tokenStream) { MatchExpectedToken(Token::TOKEN_ARRAY_BEGIN, tokenStream); - bool bContinue = (tokenStream.EOS() == false && - tokenStream.Peek().nType != Token::TOKEN_ARRAY_END); - while (bContinue) - { - // ...what's next? could be anything - array.push_back(UnknownElement()); - UnknownElement& element = array.back(); - Parse(element, tokenStream); + Array array; - bContinue = (tokenStream.EOS() == false && - tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT); - if (bContinue) + while (!tokenStream.EOS() && tokenStream.Peek().nType != Token::TOKEN_ARRAY_END) + { + array.push_back(Parse(tokenStream)); + + if (!tokenStream.EOS() && tokenStream.Peek().nType != Token::TOKEN_ARRAY_END) MatchExpectedToken(Token::TOKEN_NEXT_ELEMENT, tokenStream); } MatchExpectedToken(Token::TOKEN_ARRAY_END, tokenStream); + + return array; } - -void Reader::Parse(String& string, Reader::TokenStream& tokenStream) +String Reader::ParseString(Reader::TokenStream& tokenStream) { - string = MatchExpectedToken(Token::TOKEN_STRING, tokenStream); + return MatchExpectedToken(Token::TOKEN_STRING, tokenStream); } - -void Reader::Parse(Number& number, Reader::TokenStream& tokenStream) +Number Reader::ParseNumber(Reader::TokenStream& tokenStream) { const Token& currentToken = tokenStream.Peek(); // might need this later for throwing exception const std::string& sValue = MatchExpectedToken(Token::TOKEN_NUMBER, tokenStream); @@ -438,25 +386,21 @@ void Reader::Parse(Number& number, Reader::TokenStream& tokenStream) iStr >> dValue; // did we consume all characters in the token? - if (iStr.eof() == false) - { + if (!iStr.eof()) throw ParseException("Unexpected character in NUMBER token: " + iStr.peek(), currentToken.locBegin, currentToken.locEnd); - } - number = dValue; + return dValue; } - -void Reader::Parse(Boolean& boolean, Reader::TokenStream& tokenStream) +Boolean Reader::ParseBoolean(Reader::TokenStream& tokenStream) { - const std::string& sValue = MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream); - boolean = (sValue == "true"); + return MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream) == "true"; } - -void Reader::Parse(Null&, Reader::TokenStream& tokenStream) +Null Reader::ParseNull(Reader::TokenStream& tokenStream) { MatchExpectedToken(Token::TOKEN_NULL, tokenStream); + return Null(); } diff --git a/aegisub/libaegisub/common/hotkey.cpp b/aegisub/libaegisub/common/hotkey.cpp index a7802d698..305d3b8d1 100644 --- a/aegisub/libaegisub/common/hotkey.cpp +++ b/aegisub/libaegisub/common/hotkey.cpp @@ -69,7 +69,7 @@ Hotkey::Hotkey(const std::string &file, const std::string &default_config) LOG_D("hotkey/init") << "Generating hotkeys."; json::UnknownElement hotkey_root = agi::json_util::file(config_file, default_config); - json::Object object = hotkey_root; + json::Object const& object = hotkey_root; for (json::Object::const_iterator index(object.begin()); index != object.end(); ++index) BuildHotkey(index->first, index->second); diff --git a/aegisub/libaegisub/common/log.cpp b/aegisub/libaegisub/common/log.cpp index ac3002791..5558cddea 100644 --- a/aegisub/libaegisub/common/log.cpp +++ b/aegisub/libaegisub/common/log.cpp @@ -93,6 +93,8 @@ LogSink::~LogSink() { array.push_back(entry); } + root["timeval"] = json::Object(); + json::Array timeval_open; timeval_open.push_back(time_start.tv_sec); timeval_open.push_back(time_start.tv_usec); diff --git a/aegisub/libaegisub/include/libaegisub/cajun/elements.h b/aegisub/libaegisub/include/libaegisub/cajun/elements.h index 7fcd0e90a..7dda1a4a1 100644 --- a/aegisub/libaegisub/include/libaegisub/cajun/elements.h +++ b/aegisub/libaegisub/include/libaegisub/cajun/elements.h @@ -79,24 +79,24 @@ public: UnknownElement& operator = (const UnknownElement& unknown); // implicit cast to actual element type. throws on failure - operator const Object& () const; - operator const Array& () const; - operator const Number& () const; - operator const Boolean& () const; - operator const String& () const; - operator const Null& () const; - - // implicit cast to actual element type. *converts* on failure, and always returns success - operator Object& (); - operator Array& (); - operator Number& (); - operator Boolean& (); - operator String& (); - operator Null& (); + operator Object const&() const; + operator Array const&() const; + operator Number const&() const; + operator Boolean const&() const; + operator String const&() const; + operator Null const&() const; + operator Object&(); + operator Array&(); + operator Number&(); + operator Boolean&(); + operator String&(); + operator Null&(); // provides quick access to children when real element type is object - UnknownElement& operator[] (const char *key) { return operator[](std::string(key)); } - const UnknownElement& operator[] (const char *key) const { return operator[](std::string(key)); } + template + UnknownElement& operator[] (const char (&key)[N]) { return operator[](std::string(key)); } + template + const UnknownElement& operator[] (const char (&key)[N]) const { return operator[](std::string(key)); } UnknownElement& operator[] (const std::string& key); const UnknownElement& operator[] (const std::string& key) const; @@ -109,7 +109,8 @@ public: void Accept(Visitor& visitor); // tests equality. first checks type, then value if possible - bool operator == (const UnknownElement& element) const; + bool operator ==(const UnknownElement& element) const; + bool operator !=(const UnknownElement& element) const { return !(*this == element); } private: class Imp; @@ -118,10 +119,10 @@ private: class Imp_T; template - const ElementTypeT& CastTo() const; + ElementTypeT const& CastTo() const; template - ElementTypeT& ConvertTo(); + ElementTypeT& CastTo(); Imp* m_pImp; }; diff --git a/aegisub/libaegisub/include/libaegisub/cajun/reader.h b/aegisub/libaegisub/include/libaegisub/cajun/reader.h index b129098d1..af329b61b 100644 --- a/aegisub/libaegisub/include/libaegisub/cajun/reader.h +++ b/aegisub/libaegisub/include/libaegisub/cajun/reader.h @@ -110,13 +110,13 @@ private: void MatchExpectedString(const std::string& sExpected, InputStream& inputStream); // parsing token sequence into element structure - void Parse(UnknownElement& element, TokenStream& tokenStream); - void Parse(Object& object, TokenStream& tokenStream); - void Parse(Array& array, TokenStream& tokenStream); - void Parse(String& string, TokenStream& tokenStream); - void Parse(Number& number, TokenStream& tokenStream); - void Parse(Boolean& boolean, TokenStream& tokenStream); - void Parse(Null& null, TokenStream& tokenStream); + UnknownElement Parse(TokenStream& tokenStream); + Object ParseObject(TokenStream& tokenStream); + Array ParseArray(TokenStream& tokenStream); + String ParseString(TokenStream& tokenStream); + Number ParseNumber(TokenStream& tokenStream); + Boolean ParseBoolean(TokenStream& tokenStream); + Null ParseNull(TokenStream& tokenStream); const std::string& MatchExpectedToken(Token::Type nExpected, TokenStream& tokenStream); };