diff trunk/src/dil/Information.d @ 422:ad7977fe315a

Added support for column numbers in error messages. Moved class Location to module Information. In class Lexer: Renamed p_newl to beginLine. Added member errorLoc. Renamed fileName to filePath. Tidied up the code and reordered some methods. Renamed set_p_newl() to setLineBegin(). All other modifications are pretty much self-explanatory.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sun, 30 Sep 2007 15:20:35 +0200
parents 33b566df6af4
children bb3cb00feeb2
line wrap: on
line diff
--- a/trunk/src/dil/Information.d	Sat Sep 29 14:26:14 2007 +0200
+++ b/trunk/src/dil/Information.d	Sun Sep 30 15:20:35 2007 +0200
@@ -17,14 +17,16 @@
 {
   MID id;
   InfoType type;
-  uint loc;
+  Location location;
+  uint column;
   string message;
 
-  this(InfoType type, MID id, uint loc, string message)
+  this(InfoType type, MID id, Location location, string message)
   {
+    assert(location !is null);
     this.id = id;
     this.type = type;
-    this.loc = loc;
+    this.location = location;
     this.message = message;
   }
 
@@ -32,4 +34,104 @@
   {
     return this.message;
   }
+
+  size_t loc()
+  {
+    return location.lineNum;
+  }
+
+  size_t col()
+  {
+    if (column == 0)
+      column = location.calculateColumn();
+    return column;
+  }
+
+  string filePath()
+  {
+    return location.filePath;
+  }
 }
+
+final class Location
+{
+  char[] filePath;
+  size_t lineNum;
+  char* lineBegin, to; // Used to calculate column.
+
+  this(char[] filePath, size_t lineNum)
+  {
+    set(filePath, lineNum);
+  }
+
+  this(char[] filePath, size_t lineNum, char* lineBegin, char* to)
+  {
+    set(filePath, lineNum, lineBegin, to);
+  }
+
+  Location clone()
+  {
+    return new Location(filePath, lineNum, lineBegin, to);
+  }
+
+  void set(char[] filePath, size_t lineNum)
+  {
+    set(filePath, lineNum, null, null);
+  }
+
+  void set(char[] filePath, size_t lineNum, char* lineBegin, char* to)
+  {
+    this.filePath  = filePath;
+    set(lineNum, lineBegin, to);
+  }
+
+  void set(size_t lineNum, char* lineBegin, char* to)
+  {
+    assert(lineBegin <= to);
+    this.lineNum   = lineNum;
+    this.lineBegin = lineBegin;
+    this.to        = to;
+  }
+
+  void setFilePath(char[] filePath)
+  {
+    this.filePath = filePath;
+  }
+
+  /+
+    This is a primitive method to count the number of characters in a string.
+    Unicode compound characters and other special characters are not
+    taken into account.
+  +/
+  uint calculateColumn()
+  {
+    uint col;
+    auto p = lineBegin;
+    for (; p <= to; ++p)
+    {
+      assert(delegate ()
+        {
+          const char[3] LS = \u2028;
+          const char[3] PS = \u2029;
+          // Check that there is no newline between p and to.
+          // But 'to' may point to a newline.
+          if (p != to && (*p == '\n' || *p == '\r'))
+            return false;
+          if (to-p >= 2)
+          {
+            if (*p == LS[0] && p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2]))
+              return false;
+          }
+          return true;
+        }() == true
+      );
+
+      // Skip this byte if it is a trail byte of a UTF-8 sequence.
+      if (*p & 0x80 && !(*p & 0x40))
+        continue; // *p == 0b10xx_xxxx
+      // Only count ASCII characters and the first byte of a UTF-8 sequence.
+      ++col;
+    }
+    return col;
+  }
+}