From 1538ef47d1d4cc08e5f9c5894350bfa225866d40 Mon Sep 17 00:00:00 2001
From: Mike Buland <eichlan@xagasoft.com>
Date: Sun, 10 Feb 2013 21:53:22 +0000
Subject: Made the gats text parser much more robust.

---
 c++-libbu++/src/object.cpp | 27 ++++++++++++-------
 c++-libbu++/src/object.h   | 66 +++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 81 insertions(+), 12 deletions(-)

(limited to 'c++-libbu++/src')

diff --git a/c++-libbu++/src/object.cpp b/c++-libbu++/src/object.cpp
index db7b80b..faeca16 100644
--- a/c++-libbu++/src/object.cpp
+++ b/c++-libbu++/src/object.cpp
@@ -80,12 +80,12 @@ Gats::Object *Gats::Object::read( Bu::Stream &rIn )
     return pObj;
 }
 
-void Gats::Object::skipWs( Bu::String::const_iterator &i )
+void Gats::Object::skipWs( Gats::Object::StrPos &i )
 {
     for(; *i == ' ' || *i == '\t' || *i == '\r' || *i == '\n'; i++ ) { }
 }
 
-Bu::String Gats::Object::token( Bu::String::const_iterator &i )
+Bu::String Gats::Object::token( Gats::Object::StrPos &i )
 {
     Bu::String sRet;
     if( *i == '\"' )
@@ -111,7 +111,12 @@ Bu::String Gats::Object::token( Bu::String::const_iterator &i )
     return sRet;
 }
 
-Gats::Object *Gats::Object::strToGats( Bu::String::const_iterator &i )
+Bu::String::FormatProxy Gats::Object::posError( Gats::Object::StrPos &i, const Bu::String &msg )
+{
+    return msg.format( new Thrower(i) );
+}
+
+Gats::Object *Gats::Object::strToGats( Gats::Object::StrPos &i )
 {
     skipWs( i );
 
@@ -145,7 +150,8 @@ Gats::Object *Gats::Object::strToGats( Bu::String::const_iterator &i )
                             return pLst;
 
                         default:
-                            throw Bu::ExceptionBase("Invalid character found.");
+                            posError(i, "Expected ',' or ']' but found '%1'.").
+                                arg( *i );
                     }
                 }
             }
@@ -164,16 +170,18 @@ Gats::Object *Gats::Object::strToGats( Bu::String::const_iterator &i )
                         return pDict;
                     }
                     if( *i != '\"' )
-						throw Bu::ExceptionBase("Keys must be quoted strings.");
+                        posError(i, "Dictionary keys must be quoted strings.");
 					Bu::String sKey = token( i );
 					skipWs( i );
 					if( *i != ':' )
-						throw Bu::ExceptionBase("Keys and values must be "
+                        posError(i, "Dictionary keys and values must be "
 							"seperated with colons.");
+                    StrPos ih( i );
 					i++;
+                    skipWs( i );
 					Gats::Object *pObj = strToGats( i );
 					if( !pObj )
-						throw Bu::ExceptionBase("No value object found.");
+						posError(ih, "Dictionary key has no value.");
 					pDict->insert( sKey, pObj );
 					skipWs( i );
 					switch( *i )
@@ -187,7 +195,8 @@ Gats::Object *Gats::Object::strToGats( Bu::String::const_iterator &i )
 							return pDict;
 
 						default:
-							throw Bu::ExceptionBase("Invalid character found.");
+                            posError(i, "Expected ',' or '}' but found '%1'.")
+                                .arg( *i );
 					}
 				}
 			}
@@ -277,7 +286,7 @@ Gats::Object *Gats::Object::strToGats( Bu::String::const_iterator &i )
 
 Gats::Object *Gats::Object::strToGats( const Bu::String &sStr )
 {
-    Bu::String::const_iterator i = sStr.begin();
+    StrPos i( sStr.begin() );
 
     return strToGats( i );
 }
diff --git a/c++-libbu++/src/object.h b/c++-libbu++/src/object.h
index e4da8de..a876061 100644
--- a/c++-libbu++/src/object.h
+++ b/c++-libbu++/src/object.h
@@ -48,9 +48,69 @@ namespace Gats
         static Object *strToGats( const Bu::String &sStr );
 
     private:
-        static Object *strToGats( Bu::String::const_iterator &i );
-        static Bu::String token( Bu::String::const_iterator &i );
-        static void skipWs( Bu::String::const_iterator &i );
+        class StrPos
+        {
+        public:
+            StrPos( const Bu::String::const_iterator &i ) :
+                i( i ), iLine( 1 ), iChar( 1 )
+            { }
+            Bu::String::const_iterator i;
+            int iLine;
+            int iChar;
+
+            char operator*()
+            {
+                return *i;
+            }
+            StrPos &operator++(int)
+            {
+                i++;
+                if( i )
+                {
+                    if( *i == '\n' )
+                    {
+                        iLine++;
+                        iChar = 0;
+                    }
+                    else
+                        iChar++;
+                }
+                return *this;
+            }
+            operator bool()
+            {
+                return i;
+            }
+        };
+
+        class Thrower : public Bu::String::FormatProxyEndAction
+        {
+        public:
+            Thrower( Gats::Object::StrPos &i ) :
+                i( i )
+            {
+            }
+
+            virtual ~Thrower()
+            {
+            }
+
+            virtual void operator()( const Bu::String &sFinal )
+            {
+                throw Bu::ExceptionBase(
+                    (Bu::String("%1: %2: ").arg(i.iLine).arg(i.iChar).end() + sFinal)
+                    .getStr()
+                    );
+            }
+
+        private:
+            Gats::Object::StrPos &i;
+        };
+
+        static Bu::String::FormatProxy posError( Gats::Object::StrPos &i, const Bu::String &msg );
+        static Object *strToGats( Gats::Object::StrPos &i );
+        static Bu::String token( Gats::Object::StrPos &i );
+        static void skipWs( Gats::Object::StrPos &i );
     };
 
     const char *typeToStr( Type t );
-- 
cgit v1.2.3