changeset 7:b544c3a7c9ca

Some changes to exceptions and a few more debug commands. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Wed, 16 Jan 2008 12:48:07 +0000
parents dcb24afa0dce
children f63f4f41a2dc
files conf/input.mtt mde/exception.d mde/input/config.d mde/input/exception.d mde/input/input.d mde/mergetag/dataset.d mde/mergetag/doc/issues.txt mde/mergetag/exception.d mde/mergetag/read.d mde/text/exception.d mde/text/format.d mde/text/parse.d
diffstat 12 files changed, 128 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/conf/input.mtt	Thu Jan 10 18:33:24 2008 +0000
+++ b/conf/input.mtt	Wed Jan 16 12:48:07 2008 +0000
@@ -1,4 +1,4 @@
 {MT01}
-<uint[]|0=[1]>
+!<uint[]|0=[1]>
 {0}
 <uint[][uint]|0=[0x20000000 : [0x100, 3] ]>
--- a/mde/exception.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/exception.d	Wed Jan 16 12:48:07 2008 +0000
@@ -4,18 +4,18 @@
 /** Base class for all mde Exceptions.
  *
  * All packages should have their own base exception type extending this one, and for each package
- * level a CTOR taking a message should pass the message to the super prepended with "package: ".
- * The performance of this is unimportant since exceptions are only intended for recovering from
- * unexpected errors anyway. A CTOR not taking a message and calling the super without a parameter
- * should also be provided.
+ * level a CTOR taking a message should pass the message to the super. The const string symbol
+ * should be overriden as below so that it ends up as something like "mde.file" or
+ * "mde.pkg.file.Class" describing where the exception was thrown.
+ * A CTOR not taking a message and calling the super without a parameter may also be provided.
  */
 class mdeException : Exception {
-    const symbol = "mde";	/// Override in derived classes.
+    const symbol = "mde";	/// Override in derived classes to name the module where the error occured.
     this (char[] msg) {
         super(symbol ~ ": " ~ msg);
     }
-    this () {
-        super("");	// Exception doesn't have a this() CTOR
+    this () {			// No supplied error message.
+        super(symbol);
     }
 }
 
--- a/mde/input/config.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/input/config.d	Wed Jan 16 12:48:07 2008 +0000
@@ -81,6 +81,7 @@
     outQueue[uint] button;
     outQueue[uint] axis;	/// ditto
     outQueue[uint] mouse;	/// ditto
+    debug uint dnbc;		// debug num button configs
     
     char[] name;		/// Name for user to save this under.
     uint[] inheritants;		/// Other profiles to inherit.
@@ -124,7 +125,7 @@
             char tmp[128] = void;
             logger.info (logger.format (tmp, "Loaded {} config sections.", configs.length));
             foreach (id, cfg; configs) {
-                logger.trace ("Section "~format!(uint)(id)~": " ~ format!(uint[][uint])(cfg.button));
+                logger.trace ("Section "~format!(uint)(id)~": " ~ format!(uint[][uint])(cfg.button) ~ " (" ~ format!(uint)(cfg.dnbc) ~ ")");
             }
         }
     }
@@ -137,6 +138,7 @@
             if (id == QUEUE.BUTTON) {
                 button = cast(outQueue[uint]) parse!(uint[][uint]) (dt);
                 debug logger.trace ("Added button config: " ~ format!(uint[][uint])(button));
+                debug ++dnbc;
             }
             else if (id == QUEUE.AXIS) axis = cast(outQueue[uint]) parse!(uint[][uint]) (dt);
             else if (id == QUEUE.MOUSE) mouse = cast(outQueue[uint]) parse!(uint[][uint]) (dt);
@@ -150,5 +152,8 @@
     void writeAll (ItemDelg) {
         // FIXME
     }
+    debug void debugFunc () {
+        logger.trace ("After parse: " ~ format!(uint[][uint])(button) ~ " (" ~ format!(uint)(dnbc) ~ ")");
+    }
 //END File loading/saving code
 }
--- a/mde/input/exception.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/input/exception.d	Wed Jan 16 12:48:07 2008 +0000
@@ -3,14 +3,26 @@
 import mde.exception;
 
 /// Base Input exception class.
-class InputException : mdeException {
-    const override symbol = super.symbol ~ ".input.input.Input";
+class inputException : mdeException {
+    const override symbol = super.symbol ~ ".input";
     this (char[] msg) {
         super(msg);
     }
     this () {}
 }
 
-class ConfigLoadException : InputException {
+class InputClassException : inputException {
+    const override symbol = super.symbol ~ ".input.Input";
+    this (char[] msg) {
+        super(msg);
+    }
     this () {}
 }
+
+class ConfigLoadException : inputException {
+    const override symbol = super.symbol ~ ".config.Config";
+    this (char[] msg) {
+        super(msg);
+    }
+    this () {}
+}
--- a/mde/input/input.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/input/input.d	Wed Jan 16 12:48:07 2008 +0000
@@ -205,7 +205,7 @@
         }
         uint next () {			// Get the next element. Throws an exception if there isn't another.
             if (p >= _q.length)
-                throw new InputException ("Input: Invalid configuration: incomplete config stack");
+                throw new InputClassException ("Input: Invalid configuration: incomplete config stack");
             uint ret = _q[p];
             ++p;
             return ret;
@@ -238,19 +238,19 @@
     {
         ES_B_Func* func = (s.next() in es_b_fcts);
         if (func != null) (*func)(b,s);
-        else throw new InputException ("Input: Invalid configuration: bad event function code");
+        else throw new InputClassException ("Input: Invalid configuration: bad event function code");
     }
     void aEventOut (short x, readOutQueue s)
     {
         ES_A_Func* func = (s.next() in es_a_fcts);
         if (func != null) (*func)(x,s);
-        else throw new InputException ("Input: Invalid configuration: bad event function code");
+        else throw new InputClassException ("Input: Invalid configuration: bad event function code");
     }
     void mEventOut (short x, short y, readOutQueue s)
     {
         ES_M_Func* func = (s.next() in es_m_fcts);
         if (func != null) (*func)(x,y,s);
-        else throw new InputException ("Input: Invalid configuration: bad event function code");
+        else throw new InputClassException ("Input: Invalid configuration: bad event function code");
     }
     
     // The remaining functions are the stream functions, for adjusting and outputting an event.
--- a/mde/mergetag/dataset.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/mergetag/dataset.d	Wed Jan 16 12:48:07 2008 +0000
@@ -8,7 +8,6 @@
 import mde.text.util;
 import mde.text.parse : parse;
 import mde.text.format : format;
-import mde.text.exception : TextParseException;
 
 // tango imports
 import Util = tango.text.Util;
@@ -111,6 +110,7 @@
      * calling addTag. */
     void addTag (char[],ID,char[]);
     void writeAll (ItemDelg);	/// TBD
+    debug void debugFunc ();		/// Run in debug builds after parseSection.
 }
 
 /**
@@ -253,6 +253,7 @@
     void writeAll (ItemDelg itemdlg) {
         foreach (id, dt; _charA) itemdlg ("char[]", id, format!(char[])(dt));
     }
+    debug void debugFunc () {}
     
     /* These make no attempt to check Arg is valid.
      * But if the symbol doesn't exist the complier will throw an error anyway, e.g.:
--- a/mde/mergetag/doc/issues.txt	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/mergetag/doc/issues.txt	Wed Jan 16 12:48:07 2008 +0000
@@ -2,6 +2,7 @@
 
 Overall:
 	Threading support?
+	Use string IDs instead of integers? Could actually be faster due to no conversion being necessary.
 
 read.d:
 	Allow only partially loading a file.
--- a/mde/mergetag/exception.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/mergetag/exception.d	Wed Jan 16 12:48:07 2008 +0000
@@ -9,8 +9,9 @@
 
 /// Base MergeTag exception class.
 class MTException : mdeException {
+    const override symbol = super.symbol ~ ".mergetag";
     this (char[] msg) {
-        super("MergeTag: " ~ msg);
+        super(msg);
     }
     this () {}
 }
--- a/mde/mergetag/read.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/mergetag/read.d	Wed Jan 16 12:48:07 2008 +0000
@@ -9,6 +9,7 @@
 // package imports
 public import mde.mergetag.dataset;
 public import mde.mergetag.exception;
+import mde.text.exception : textParseException;
 
 // tango imports
 import tango.io.UnicodeFile;
@@ -79,6 +80,7 @@
     static Logger logger;
     
     // Non-static symbols:
+    final char[] ErrFile;		// added after ErrInFile to do the same without the "in " bit.
     final char[] ErrInFile;		// something like "in \"path/file.mtt\""
     
     final char[] fbuf;			// file is read into this
@@ -149,8 +151,9 @@
             throwMTErr ("Error reading file: " ~ e.msg, new MTFileIOException);
         }
         // Remember the file name so that we can report errors (somewhat) informatively:
-        ErrInFile = " in \"" ~ path.path ~ path.file ~ '"';
-        
+        ErrFile = path.path ~ path.file;
+        ErrInFile = " in \"" ~ ErrFile ~ '"';
+                
         // Version checking & matching header section tag:
         if (fbuf.length < 6 || fbuf[0] != '{' || fbuf[1] != 'M' || fbuf[2] != 'T' || fbuf[5] != '}')
             throwMTErr("Not a valid MergeTag text file" ~ ErrInFile, new MTFileFormatException);
@@ -220,6 +223,15 @@
         read (hs);
     }
     public void read (View!(ID) secSet = new ArrayBag!(ID)) {	/** ditto */
+        /* Look for a section; return it if it exists otherwise create a new section:
+        *     use dataSecCreator if it exists or just create a DefaultData if not.
+        */
+        DataSection getOrCreateSec (ID id) {
+            DataSection* i = id in dataset.sec;
+            if (i) return *i;
+            return (dataset.sec[id] = (dataSecCreator !is null) ? dataSecCreator(id) : new DefaultData);
+        }
+        
         if (allRead || fatal) return;			// never do anything in either case
         if (secSet.size) {
             if (secTable.length) {
@@ -228,6 +240,7 @@
                     if (psmd && !psmd.read) {			// may not exist
                         DataSection ds = getOrCreateSec (id);
                         parseSection (psmd.pos, &ds);
+                        debug ds.debugFunc ();
                         psmd.read = true;
                     }
                 }
@@ -239,6 +252,7 @@
                         if (secSet.contains(id)) {
                             DataSection ds = getOrCreateSec (id);
                             pos = parseSection (pos, &ds);
+                            debug ds.debugFunc ();
                             secTable[id].read = true;
                         }
                     } catch (MTStringIDException) {	// don't do any of the stuff above
@@ -252,6 +266,7 @@
                     if (!smd.read) {
                         DataSection ds = getOrCreateSec (id);
                         parseSection (smd.pos, &ds);
+                        debug ds.debugFunc ();
                         smd.read = true;
                     }
                 }
@@ -261,6 +276,7 @@
                         ID id = fbufReadSecMarker (pos);
                         DataSection ds = getOrCreateSec (id);
                         pos = parseSection (pos, &ds);
+                        debug ds.debugFunc ();
                     } catch (MTStringIDException) {
                         pos = parseSection (pos, null);	// just skip the section
                     }
@@ -281,6 +297,28 @@
     slightly faster, but a tiny difference isn't worth the extra effort/risk of using char*'s.
     */
     private uint parseSection (uint pos, DataSection* dsec) {
+        /* Searches fbuf starting from start to find one of <=>| and stops at its index.
+    
+        If quotable then be quote-aware for single and double quotes.
+        Note: there's no length restriction for the content of the quote since it could be a single
+        non-ascii UTF-8 char which would look like several chars.
+        */
+        void fbufLocateDataTagChar (inout uint pos, bool quotable) {
+            for (; pos < fbuf.length; ++pos) {
+                if ((fbuf[pos] >= '<' && fbuf[pos] <= '>') || fbuf[pos] == '|') return;
+                else if (quotable) {
+                    char c = fbuf[pos];
+                    if (c == '\'' || c == '"') {
+                        ++pos;
+                        while (fbuf[pos] != c) {
+                            if (fbuf[pos] == '\\') ++pos;	// escape seq.
+                            fbufIncrement(pos);
+                        } 
+                    }
+                }
+            }
+        }
+        
         bool comment = false;				// preceding char was !
         for (; pos < fbuf.length; ++pos) {
             if (Util.isSpace(fbuf[pos])) continue;	// whitespace
@@ -315,8 +353,9 @@
                     try {
                         dsec.addTag (type, tagID, data);
                     }
-                    catch (TextParseException) {
-                        logger.warn("Above error occured" ~ ErrInFile);	// following a parse error
+                    catch (textParseException e) {
+                        logger.warn ("While reading " ~ ErrFile ~ ":");	// following a parse error
+                        logger.warn (e.msg);
                     }
                     catch (MTUnknownTypeException e) {
                         logger.warn ("Unsupported type \"" ~ type ~ "\" " ~ ErrInFile /*~ ":"*/);
@@ -354,15 +393,6 @@
         return pos;
     }
     
-    /* Look for a section; return it if it exists otherwise create a new section:
-     *     use dataSecCreator if it exists or just create a DefaultData if not.
-     */
-    DataSection getOrCreateSec (ID id) {
-        DataSection* i = id in dataset.sec;
-        if (i) return *i;
-        return (dataset.sec[id] = (dataSecCreator != null) ? dataSecCreator(id) : new DefaultData);
-    }
-    
     /* Parses fbuf for a section marker. Already knows fbuf[pos] == '{'.
     */
     private ID fbufReadSecMarker (inout uint pos) {
@@ -399,27 +429,6 @@
         }
     }
     
-    /* Searches fbuf starting from start to find one of <=>| and stops at its index.
-    
-    If quotable then be quote-aware for single and double quotes.
-    Note: there's no length restriction for the content of the quote since it could be a single
-    non-ascii UTF-8 char which would look like several chars.
-    */
-    private void fbufLocateDataTagChar (inout uint pos, bool quotable) {
-        for (; pos < fbuf.length; ++pos) {
-            if ((fbuf[pos] >= '<' && fbuf[pos] <= '>') || fbuf[pos] == '|') return;
-            else if (quotable) {
-                char c = fbuf[pos];
-                if (c == '\'' || c == '"') {
-                    ++pos;
-                    while (fbuf[pos] != c) {
-                        if (fbuf[pos] == '\\') ++pos;	// escape seq.
-                        fbufIncrement(pos);
-                    } 
-                }
-            }
-        }
-    }
     /* Increments pos and checks it hasn't hit fbuf.length . */
     private void fbufIncrement(inout uint pos) {
         ++pos;
--- a/mde/text/exception.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/text/exception.d	Wed Jan 16 12:48:07 2008 +0000
@@ -8,20 +8,29 @@
 public import mde.exception;
 
 /// Base Text exception class.
-class TextException : mdeException {
+class textException : mdeException {
+    const override symbol = super.symbol ~ ".text";
     this (char[] msg) {
-        super("Text: " ~ msg);
+        super(msg);
     }
     this () {}
 }
 
 /** Thrown by the parse module on any error.
  */
-class TextParseException : TextException {
+class textParseException : textException {
+    const override symbol = super.symbol ~ ".parse";
+    this (char[] msg) {
+        super(msg);
+    }
     this () {}
 }
 /** Thrown by the format module on any error.
 */
-class TextFormatException : TextException {
-this () {}
+class textFormatException : textException {
+    const override symbol = super.symbol ~ ".format";
+    this (char[] msg) {
+        super(msg);
+    }
+    this () {}
 }
--- a/mde/text/format.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/text/format.d	Wed Jan 16 12:48:07 2008 +0000
@@ -29,12 +29,13 @@
 import cFloat = tango.text.convert.Float;
 import Utf = tango.text.convert.Utf;
 import Util = tango.text.Util;
+/+
 import tango.util.log.Log : Log, Logger;
 
 private Logger logger;
 static this () {
     logger = Log.getLogger ("mde.text.format");
-}
+}+/
 
 //BEGIN Convert templates
 /* Idea: could extend format with a second parameter, containing flags for things like base to output.
@@ -134,11 +135,11 @@
 const char[] WIDE_CHAR_ERROR = "Error: unicode non-ascii character cannot be converted to a single UTF-8 char";
 char[] format(T : dchar) (T val) {
     if (val <= 127u) return format (cast(char) val);	// this char can be converted
-    throwException (WIDE_CHAR_ERROR);
+    throw new textFormatException (WIDE_CHAR_ERROR);
 }
 char[] format(T : wchar) (T val) {
     if (val <= 127u) return format (cast(char) val);	// this char can be converted
-    throwException (WIDE_CHAR_ERROR);
+    throw new textFormatException (WIDE_CHAR_ERROR);
 }
 char[] format(T : char) (T val) {
     // Note: if (val > 127) "is invalid UTF-8 single char"
@@ -192,7 +193,7 @@
     return formatLong (val);
 }
 char[] format(T : ulong) (T val) {
-    if (val > cast(ulong) long.max) throwException ("No handling available for ulong where value > long.max");
+    if (val > cast(ulong) long.max) throw new textFormatException ("No handling available for ulong where value > long.max");
     return formatLong (val);
 }
 unittest {
@@ -236,7 +237,7 @@
 //BEGIN Utility funcs
 private char[] formatLong (long val) {
     try return cInt.toString (val, cInt.Style.Signed, cInt.Flags.Throw);
-    catch (Exception e) throwException (e.msg);
+    catch (Exception e) throw new textFormatException (e.msg);
 }
 private bool isEscapableChar (char c) {
     return ((c <= '\r' && c >= '\a') || c == '\"' || c == '\'' || c == '\\');
@@ -259,11 +260,6 @@
     return escCharsRev[c];
 }
 
-private void throwException (char[] msg) {
-    logger.warn (msg);			// only small errors are trapped here
-    throw new TextFormatException ();
-}
-
 unittest {
     // all utility functions should be well-enough used not to need testing
 }
--- a/mde/text/parse.d	Thu Jan 10 18:33:24 2008 +0000
+++ b/mde/text/parse.d	Wed Jan 16 12:48:07 2008 +0000
@@ -20,7 +20,7 @@
  *
  * There are also a few utility functions defined; the public ones have their own documentation.
  *
- * On errors, a warning is logged and an TextParseException is thrown. No other exceptions should
+ * On errors, a textParseException is thrown with a suitable message. No other exceptions should
  * be thrown and none thrown from functions used outside this module.
  *************************************************************************************************/
 module mde.text.parse;
@@ -33,11 +33,13 @@
 import cInt = tango.text.convert.Integer;
 import cFloat = tango.text.convert.Float;
 import Util = tango.text.Util;
-import tango.util.log.Log : Log, Logger;
+debug {
+    import tango.util.log.Log : Log, Logger;
 
-private Logger logger;
+    private Logger logger;
+}
 static this () {
-    logger = Log.getLogger ("mde.text.parse");
+    debug logger = Log.getLogger ("mde.text.parse");
 }
 
 //BEGIN parse templates
@@ -46,7 +48,7 @@
 T[S] parse(T : T[S], S) (char[] src) {
     src = Util.trim(src);
     if (src.length < 2 || src[0] != '[' || src[$-1] != ']')
-        throwException (AA_ERR ~ "not [ ... ]");	// bad braces.
+        throw new textParseException (AA_ERR ~ "not [ ... ]");	// bad braces.
     
     T[S] ret;
     foreach (char[] pair; split (src[1..$-1])) {
@@ -58,20 +60,20 @@
                 ++i;
                 while (i < pair.length && pair[i] != c) {
                     if (pair[i] == '\\') {
-                        if (i+2 >= pair.length) throwException (AA_ERR ~ "unfinished escape sequence within string/char");
+                        if (i+2 >= pair.length) throw new textParseException (AA_ERR ~ "unfinished escape sequence within string/char");
                         ++i;	// escape seq.
                     }
                     ++i;
                 }
                 if (i == pair.length) {
                     debug logger.warn ("Pair is: " ~ pair);
-                    throwException (AA_ERR ~ "encountered [ ... KEY] (missing :DATA)");
+                    throw new textParseException (AA_ERR ~ "encountered [ ... KEY] (missing :DATA)");
                 }
             }
             ++i;
         }
         if (i == pair.length) {
-            throwException (AA_ERR ~ "encountered [ ... KEY:] (missing DATA)");
+            throw new textParseException (AA_ERR ~ "encountered [ ... KEY:] (missing DATA)");
         }
         ret[parse!(S) (pair[0..i])] = parse!(T) (pair[i+1..$]);
     }
@@ -94,7 +96,7 @@
 T[] parse(T : T[]) (char[] src) {
     src = Util.trim(src);
     if (src.length >= 2 && src[0] == '[' && src[$-1] == ']') return toArray!(T[]) (src);
-    throwException ("Invalid array: not [x, ..., z]");
+    throw new textParseException ("Invalid array: not [x, ..., z]");
 }
 T parse(T : char[]) (char[] src) {
     src = Util.trim(src);
@@ -114,21 +116,21 @@
             // process a block of escaped characters
             while (t < src.length && src[t] == '\\') {
                 t++;
-                if (t == src.length) throwException ("Invalid string: ends \\\" !");	// next char is "
+                if (t == src.length) throw new textParseException ("Invalid string: ends \\\" !");	// next char is "
                 ret[i++] = replaceEscapedChar (src[t++]);	// throws if it's invalid
             }
         }
         return ret[0..i];
     }
     else if (src.length >= 2 && src[0] == '[' && src[$-1] == ']') return toArray!(T) (src);
-    throwException ("Invalid string: not quoted (\"*\") or char array (['a',...,'c'])");
+    throw new textParseException ("Invalid string: not quoted (\"*\") or char array (['a',...,'c'])");
 }
 T parse(T : ubyte[]) (char[] src) {
     src = Util.trim(src);
     // Standard case:
     if (src.length >= 2 && src[0] == '[' && src[$-1] == ']') return toArray!(T) (src);
     // Special case: sequence of hex digits, each pair of which is a ubyte
-    if (src.length % 2 == 1) throwException ("Invalid binary: odd number of chars");
+    if (src.length % 2 == 1) throw new textParseException ("Invalid binary: odd number of chars");
     T ret;
     ret.length = src.length / 2;	// exact
     for (uint i, pos; pos + 1 < src.length; ++i) {
@@ -152,16 +154,16 @@
 T parse(T : char) (char[] src) {
     src = Util.trim(src);
     if (src.length < 3 || src[0] != '\'' || src[$-1] != '\'')
-        throwException ("Invalid char: not quoted ('c')");
+        throw new textParseException ("Invalid char: not quoted ('c')");
     if (src[1] != '\\' && src.length == 3) return src[1];	// Either non escaped
     if (src.length == 4) return replaceEscapedChar (src[2]);	// Or escaped
     
     // Report various errors; warnings for likely and difficult to tell cases:
     /+ This was caused by a bug. Shouldn't occur now normally.
-    if (src[1] == '\\' && src.length == 3) throwException (`Warning: \' in char! There's currently no support for this during tokenising. Thus your input's probably been garbled!`);	// next char is ' +/
+    if (src[1] == '\\' && src.length == 3) throw new textParseException (`Warning: \' in char! There's currently no support for this during tokenising. Thus your input's probably been garbled!`);	// next char is ' +/
     // Warn in case it's a multibyte UTF-8 character:
-    if (src[1] & 0xC0u) throwException ("Invalid char: too long (non-ASCII UTF-8 characters cannot be read as a single character)");
-    throwException ("Invalid char: too long");
+    if (src[1] & 0xC0u) throw new textParseException ("Invalid char: too long (non-ASCII UTF-8 characters cannot be read as a single character)");
+    throw new textParseException ("Invalid char: too long");
 }
 // unittest covered above
 
@@ -173,7 +175,7 @@
     while (src.length > pos && src[pos] == '0') ++pos;	// strip leading zeros
     if (src.length == pos && pos > 0) return false;
     if (src.length == pos + 1 && src[pos] == '1') return true;
-    throwException ("Invalid bool: not true or false and doesn't evaluate to 0 or 1");
+    throw new textParseException ("Invalid bool: not true or false and doesn't evaluate to 0 or 1");
 }
 unittest {
     assert (parse!(bool[]) (`[true,false,01,00]`) == cast(bool[]) [1,0,1,0]);
@@ -236,20 +238,20 @@
     uint radix, ate, ate2;
     
     ate = cInt.trim (src, sign, radix);
-    if (ate == src.length) throwException ("Invalid integer: no digits");
+    if (ate == src.length) throw new textParseException ("Invalid integer: no digits");
     ulong val = cInt.convert (src[ate..$], radix, &ate2);
     ate += ate2;
     
     while (ate < src.length) {
         if (src[ate] == ' ' || src[ate] == '\t') ++ate;
-        else throwException ("Invalid integer");
+        else throw new textParseException ("Invalid integer");
     }
     
-    if (val > TInt.max) throwException (INT_OUT_OF_RANGE);
+    if (val > TInt.max) throw new textParseException (INT_OUT_OF_RANGE);
     if (sign) {
         long sval = cast(long) -val;
         if (sval > TInt.min) return cast(TInt) sval;
-        else throwException (INT_OUT_OF_RANGE);
+        else throw new textParseException (INT_OUT_OF_RANGE);
     }
     return cast(TInt) val;
 }
@@ -259,7 +261,7 @@
  * when it does. */
 TFloat toTFloat(TFloat) (char[] src) {
     src = postTrim (src);
-    if (src == "") throwException ("Invalid float: no digits");
+    if (src == "") throw new textParseException ("Invalid float: no digits");
     uint ate;
 
     TFloat x = cFloat.parse (src, &ate);
@@ -292,7 +294,7 @@
         else if (c == '[') ++depth;
         else if (c == ']') {
             if (depth) --depth;
-            else throwException ("Invalid array literal: closes before end of data item.");
+            else throw new textParseException ("Invalid array literal: closes before end of data item.");
         }
         else if (c == ',' && depth == 0) {		// only if not an embedded array
             if (ret.length <= k) ret.length = ret.length * 2;
@@ -327,7 +329,7 @@
     char* r = c in escChars;
     if (r != null) return *r;
     
-    throwException ("Invalid escape sequence: \\"~c);	// we didn't return, so something failed
+    throw new textParseException ("Invalid escape sequence: \\"~c);	// we didn't return, so something failed
 }
 
 // Reads one hex char: [0-9A-Fa-f]. Otherwise throws an exception. Doesn't check src.length.
@@ -336,7 +338,7 @@
     if (src[pos] >= '0' && src[pos] <= '9') x = src[pos] - '0';
     else if (src[pos] >= 'A' && src[pos] <= 'F') x = src[pos] - 'A' + 10;
     else if (src[pos] >= 'a' && src[pos] <= 'f') x = src[pos] - 'a' + 10;
-    else throwException ("Invalid hex digit.");
+    else throw new textParseException ("Invalid hex digit.");
     ++pos;
     return x;
 }
@@ -354,11 +356,6 @@
     return ret[0..i];
 }
 
-private void throwException (char[] msg) {
-    logger.warn (msg);			// only small errors are trapped here
-    throw new TextParseException ();
-}
-
 unittest {
     // all utility functions should be well-enough used not to need testing
 }