changeset 758:f4b9680c0e16

Revised module dil.SettingsLoader.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Thu, 14 Feb 2008 03:31:19 +0100
parents e4b60543c5e8
children 9c47f377ca0b
files trunk/src/config.d trunk/src/dil/SettingsLoader.d trunk/src/dil/semantic/Module.d trunk/src/dil/semantic/Pass1.d trunk/src/dil/semantic/Symbol.d trunk/src/dil/semantic/Symbols.d trunk/src/main.d
diffstat 7 files changed, 152 insertions(+), 132 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/config.d	Wed Feb 13 22:08:58 2008 +0100
+++ b/trunk/src/config.d	Thu Feb 14 03:31:19 2008 +0100
@@ -1,18 +1,25 @@
-// Relative paths are resolved from the directory of dil's executable.
+/// The configuration file of dil.
+///
+/// Relative paths are resolved from the directory of the executable.
+module config;
 
-// Path to the language file.
+/// Path to the language file.
 var langfile = "lang_en.d";
-// An array of import paths to look for modules.
-var import_paths = []; // E.g.: ["src/", "import/"]
-// DDoc macro file paths.
-var ddoc_files = []; // E.g.: ["src/mymacros.ddoc", "othermacros.ddoc"]
-/*
-  Customizing error messages.
-  0: file path to the source text.
-  1: line number.
-  2: column number.
-  3: error message.
-*/
+
+/// An array of import paths to look for modules.
+var import_paths = []; /// E.g.: ["src/", "import/"]
+
+/// DDoc macro file paths.
+var ddoc_files = []; /// E.g.: ["src/mymacros.ddoc", "othermacros.ddoc"]
+
+/// Customizable formats for error messages.
+///
+/// <ul>
+///   <li>0: file path to the source text.</li>
+///   <li>1: line number.</li>
+///   <li>2: column number.</li>
+///   <li>3: error message.</li>
+/// </ul>
 var lexer_error = "{0}({1},{2})L: {3}";
-var parser_error = "{0}({1},{2})P: {3}";
-var semantic_error = "{0}({1},{2})S: {3}";
+var parser_error = "{0}({1},{2})P: {3}"; /// ditto
+var semantic_error = "{0}({1},{2})S: {3}"; /// ditto
--- a/trunk/src/dil/SettingsLoader.d	Wed Feb 13 22:08:58 2008 +0100
+++ b/trunk/src/dil/SettingsLoader.d	Thu Feb 14 03:31:19 2008 +0100
@@ -8,125 +8,120 @@
 import dil.Messages;
 import dil.ast.Node, dil.ast.Declarations, dil.ast.Expressions;
 import dil.semantic.Module;
-import dil.File;
-import tango.io.FilePath;
+import dil.semantic.Pass1;
+import dil.semantic.Symbol;
+import dil.semantic.Symbols;
+import dil.Information;
 import common;
 
-void loadSettings()
-{
-  scope execPath = new FilePath(GetExecutableFilePath());
-  execPath = new FilePath(execPath.folder());
+import tango.io.FilePath;
 
-  // Load config.d
-  auto filePath = resolvePath(execPath, "config.d");
-  auto modul = new Module(filePath);
-  modul.parse();
+struct SettingsLoader
+{
+  InfoManager infoMan;
+  Module mod; /// Current module.
 
-  if (modul.hasErrors)
-    throw new Exception("There are errors in " ~ filePath ~ ".");
-
-  foreach (decl; modul.root.children)
+  static SettingsLoader opCall(InfoManager infoMan)
   {
-    auto v = decl.Is!(VariablesDeclaration);
-    if (v is null)
-      continue;
+    SettingsLoader sl;
+    sl.infoMan = infoMan;
+    return sl;
+  }
 
-    auto variableName = v.names[0].str;
-    auto e = v.inits[0];
-    if (!e)
-      throw new Exception(variableName ~ " variable has no value set.");
+  void error(Token* token, char[] formatMsg, ...)
+  {
+    auto location = token.getErrorLocation();
+    auto msg = Format(_arguments, _argptr, formatMsg);
+    infoMan ~= new SemanticError(location, msg);
+  }
 
-    switch (variableName)
-    {
-    case "langfile":
-      if (auto val = e.Is!(StringExpression))
-        GlobalSettings.langFile = val.getString();
-      break;
-    case "import_paths":
-      if (auto array = e.Is!(ArrayInitExpression))
-      {
-        foreach (value; array.values)
-          if (auto str = value.Is!(StringExpression))
-            GlobalSettings.importPaths ~= str.getString();
-      }
-      else
-        throw new Exception("import_paths variable is set to "~e.classinfo.name~" instead of an ArrayInitializer.");
-      break;
-    case "ddoc_files":
-      if (auto array = e.Is!(ArrayInitExpression))
-      {
-        foreach (value; array.values)
-          if (auto str = value.Is!(StringExpression))
-            GlobalSettings.ddocFilePaths ~= resolvePath(execPath, str.getString());
-      }
-      else
-        throw new Exception("import_paths variable is set to "~e.classinfo.name~" instead of an ArrayInitializer.");
-      break;
-    case "lexer_error":
-      if (auto val = e.Is!(StringExpression))
-        GlobalSettings.lexerErrorFormat = val.getString();
-      break;
-    case "parser_error":
-      if (auto val = e.Is!(StringExpression))
-        GlobalSettings.parserErrorFormat = val.getString();
-      break;
-    case "semantic_error":
-      if (auto val = e.Is!(StringExpression))
-        GlobalSettings.semanticErrorFormat = val.getString();
-      break;
-    default:
-    }
+  T getValue(T)(char[] name)
+  {
+    auto var = mod.lookup(name);
+    if (!var) // Returning T.init instead of null, because dmd gives an error.
+      return error(mod.firstToken, "variable '{}' is not defined", name), T.init;
+    auto t = var.node.begin;
+    if (!var.isVariable)
+      return error(t, "'{}' is not a variable declaration", name), T.init;
+    auto value = var.to!(Variable).value;
+    if (!value)
+      return error(t, "'{}' variable has no value set", name), T.init;
+    T val = value.Is!(T); // Try casting to T.
+    if (!val)
+      error(value.begin, "the value of '{}' is not of type {}", name, typeof(T).stringof);
+    return val;
+  }
+
+  T castTo(T)(Node n)
+  {
+    char[] type;
+    is(T == StringExpression) && (type = "char[]");
+    if (!n.Is!(T))
+      error(n.begin, "expression is not of type {}", type);
+    return n.Is!(T);
   }
 
-  // Load language file.
-  filePath = resolvePath(execPath, GlobalSettings.langFile);
-  modul = new Module(filePath);
-  modul.parse();
-
-  if (modul.hasErrors)
-    throw new Exception("There are errors in "~filePath~".");
-
-  char[][] messages;
-  foreach (decl; modul.root.children)
+  void load()
   {
-    auto v = decl.Is!(VariablesDeclaration);
-    if (v is null)
-      continue;
+    scope execPath = new FilePath(GetExecutableFilePath());
+    execPath = new FilePath(execPath.folder());
+
+    // Load config.d
+    auto filePath = resolvePath(execPath, "config.d");
+    mod = new Module(filePath, infoMan);
+    mod.parse();
+
+    if (mod.hasErrors)
+      return;
+
+    auto pass1 = new SemanticPass1(mod);
+    pass1.start();
+
+    if (auto val = getValue!(StringExpression)("langfile"))
+      GlobalSettings.langFile = val.getString();
 
-    auto variableName = v.names[0].str;
-    auto e = v.inits[0];
-    if (!e)
-      throw new Exception(variableName~" variable in "~filePath~" has no value set.");
+    if (auto array = getValue!(ArrayInitExpression)("import_paths"))
+      foreach (value; array.values)
+        if (auto str = castTo!(StringExpression)(value))
+          GlobalSettings.importPaths ~= str.getString();
+    if (auto array = getValue!(ArrayInitExpression)("ddoc_files"))
+      foreach (value; array.values)
+        if (auto str = castTo!(StringExpression)(value))
+          GlobalSettings.ddocFilePaths ~= resolvePath(execPath, str.getString());
+    if (auto val = getValue!(StringExpression)("lexer_error"))
+      GlobalSettings.lexerErrorFormat = val.getString();
+    if (auto val = getValue!(StringExpression)("parser_error"))
+      GlobalSettings.parserErrorFormat = val.getString();
+    if (auto val = getValue!(StringExpression)("semantic_error"))
+      GlobalSettings.semanticErrorFormat = val.getString();
 
-    switch (variableName)
+    // Load language file.
+    filePath = resolvePath(execPath, GlobalSettings.langFile);
+    mod = new Module(filePath);
+    mod.parse();
+
+    if (mod.hasErrors)
+      return;
+
+    pass1 = new SemanticPass1(mod);
+    pass1.start();
+
+    if (auto array = getValue!(ArrayInitExpression)("messages"))
     {
-    case "messages":
-      if (auto array = e.Is!(ArrayInitExpression))
-      {
-        foreach (value; array.values)
-        {
-          if (auto str = value.Is!(StringExpression))
-            messages ~= str.getString();
-        }
-      }
-      else
-        throw new Exception("messages variable is set to "~e.classinfo.name~" instead of an ArrayInitializer.");
-      break;
-    case "lang_code":
-      if (auto str = e.Is!(StringExpression))
-          GlobalSettings.langCode = str.getString();
-      break;
-    default:
+      char[][] messages;
+      foreach (value; array.values)
+        if (auto str = castTo!(StringExpression)(value))
+          messages ~= str.getString();
+      if (messages.length != MID.max+1)
+        error(mod.firstToken,
+              "messages table in {} must exactly have {} entries, but not {}.",
+              filePath, MID.max+1, messages.length);
+      GlobalSettings.messages = messages;
+      dil.Messages.SetMessages(messages);
     }
+    if (auto val = getValue!(StringExpression)("lang_code"))
+      GlobalSettings.langCode = val.getString();
   }
-  if (messages.length != MID.max+1)
-    throw new Exception(
-      Format(
-        "messages table in {0} must exactly have {1} entries, but {2} were found.",
-        filePath, MID.max+1, messages.length)
-      );
-  GlobalSettings.messages = messages;
-  dil.Messages.SetMessages(messages);
 }
 
 string resolvePath(FilePath execPath, string filePath)
@@ -139,9 +134,7 @@
 version(Windows)
 {
 private extern(Windows) uint GetModuleFileNameA(void*, char*, uint);
-/++
-  Get the fully qualified path to this executable.
-+/
+/// Get the fully qualified path to this executable.
 char[] GetExecutableFilePath()
 {
   alias GetModuleFileNameA GetModuleFileName;
@@ -171,9 +164,7 @@
 else version(linux)
 {
 private extern(C) size_t readlink(char* path, char* buf, size_t bufsize);
-/++
-  Get the fully qualified path to this executable.
-+/
+/// Get the fully qualified path to this executable.
 char[] GetExecutableFilePath()
 {
   char[] buffer = new char[256];
--- a/trunk/src/dil/semantic/Module.d	Wed Feb 13 22:08:58 2008 +0100
+++ b/trunk/src/dil/semantic/Module.d	Thu Feb 14 03:31:19 2008 +0100
@@ -88,6 +88,11 @@
     }
   }
 
+  Token* firstToken()
+  {
+    return parser.lexer.firstToken();
+  }
+
   /// Returns true if there are errors in the source file.
   bool hasErrors()
   {
--- a/trunk/src/dil/semantic/Pass1.d	Wed Feb 13 22:08:58 2008 +0100
+++ b/trunk/src/dil/semantic/Pass1.d	Thu Feb 14 03:31:19 2008 +0100
@@ -324,9 +324,10 @@
       return error(vd.begin, MSG.InterfaceCantHaveVariables), vd;
 
     // Insert variable symbols in this declaration into the symbol table.
-    foreach (name; vd.names)
+    foreach (i, name; vd.names)
     {
       auto variable = new Variable(name, protection, storageClass, linkageType, vd);
+      variable.value = vd.inits[i];
       vd.variables ~= variable;
       insert(variable, name);
     }
--- a/trunk/src/dil/semantic/Symbol.d	Wed Feb 13 22:08:58 2008 +0100
+++ b/trunk/src/dil/semantic/Symbol.d	Thu Feb 14 03:31:19 2008 +0100
@@ -84,6 +84,12 @@
   mixin(isX!("OverloadSet"));
 //   mixin(isX!("Type"));
 
+  Class to(Class)()
+  {
+    assert(mixin(`this.sid == mixin("SYM." ~ typeof(Class).stringof)`));
+    return cast(Class)cast(void*)this;
+  }
+
   /// Returns: the fully qualified name of this symbol.
   /// E.g.: dil.semantic.Symbol.Symbol.getFQN
   char[] getFQN()
--- a/trunk/src/dil/semantic/Symbols.d	Wed Feb 13 22:08:58 2008 +0100
+++ b/trunk/src/dil/semantic/Symbols.d	Thu Feb 14 03:31:19 2008 +0100
@@ -9,7 +9,7 @@
 import dil.semantic.SymbolTable;
 import dil.semantic.Types;
 import dil.ast.Node;
-import dil.lexer.Identifier;
+import dil.lexer.IdTable;
 import dil.Enums;
 import common;
 
@@ -30,6 +30,13 @@
     return symbolTable.lookup(name);
   }
 
+  /// Look up name in the table.
+  Symbol lookup(string name)
+  {
+    auto id = IdTable.lookup(name);
+    return id ? symbolTable.lookup(id) : null;
+  }
+
   /// Insert a symbol into the table.
   void insert(Symbol s, Identifier* name)
   {
--- a/trunk/src/main.d	Wed Feb 13 22:08:58 2008 +0100
+++ b/trunk/src/main.d	Thu Feb 14 03:31:19 2008 +0100
@@ -41,7 +41,10 @@
 
 void main(char[][] args)
 {
-  dil.SettingsLoader.loadSettings();
+  auto infoMan = new InfoManager();
+  SettingsLoader(infoMan).load();
+  if (infoMan.info.length)
+    return printErrors(infoMan);
 
   if (args.length <= 1)
     return Stdout(helpMain()).newline;
@@ -53,7 +56,7 @@
     if (args.length < 2)
       return printHelp("compile");
 
-    auto infoMan = new InfoManager();
+    infoMan = new InfoManager();
     auto filePaths = args[2..$];
     foreach (filePath; filePaths)
     {
@@ -108,7 +111,7 @@
         filePaths ~= arg;
     }
 
-    auto infoMan = new InfoManager();
+    infoMan = new InfoManager();
     // Execute command.
     cmd.DDoc.execute(filePaths, destination, macroPaths, incUndoc, verbose, infoMan);
     if (infoMan.info.length)
@@ -220,7 +223,7 @@
     if (!sourceText)
       sourceText = new SourceText(filePath, true);
 
-    auto infoMan = new InfoManager();
+    infoMan = new InfoManager();
     auto lx = new Lexer(sourceText, infoMan);
     lx.scanAll();
     auto token = lx.firstToken();
@@ -243,7 +246,7 @@
     if (args[2] != "German")
       return Stdout.formatln("Error: unrecognized target language \"{}\"", args[2]);
 
-    auto infoMan = new InfoManager();
+    infoMan = new InfoManager();
     auto filePath = args[3];
     auto mod = new Module(filePath, infoMan);
     // Parse the file.