changeset 778:78be32e3e157

Implemented conditional compilation.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Wed, 20 Feb 2008 22:09:29 +0100
parents 9f61e8af55d5
children 8e6fed11bb68
files trunk/src/cmd/DDoc.d trunk/src/config.d trunk/src/dil/Compilation.d trunk/src/dil/Settings.d trunk/src/dil/SettingsLoader.d trunk/src/dil/semantic/Analysis.d trunk/src/dil/semantic/Pass1.d trunk/src/main.d
diffstat 8 files changed, 231 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/cmd/DDoc.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/cmd/DDoc.d	Wed Feb 20 22:09:29 2008 +0100
@@ -21,6 +21,7 @@
 import dil.semantic.Pass1;
 import dil.semantic.Symbol;
 import dil.semantic.Symbols;
+import dil.Compilation;
 import dil.Information;
 import dil.Converter;
 import dil.SourceText;
@@ -33,7 +34,8 @@
 import tango.io.FilePath;
 
 void execute(string[] filePaths, string destDir, string[] macroPaths,
-             bool incUndoc, bool verbose, InfoManager infoMan)
+             bool incUndoc, bool verbose, CompilationContext context,
+             InfoManager infoMan)
 {
   // Parse macro files.
   MacroTable mtable;
@@ -60,7 +62,7 @@
       continue;
 
     // Start semantic analysis.
-    auto pass1 = new SemanticPass1(mod);
+    auto pass1 = new SemanticPass1(mod, context);
     pass1.start();
 
     // Generate documentation.
@@ -771,8 +773,20 @@
   }
 
   D visit(DebugDeclaration d)
-  { return d; }
+  {
+    d.compiledDecls && visitD(d.compiledDecls);
+    return d;
+  }
 
   D visit(VersionDeclaration d)
-  { return d; }
+  {
+    d.compiledDecls && visitD(d.compiledDecls);
+    return d;
+  }
+
+  D visit(StaticIfDeclaration d)
+  {
+    d.ifDecls && visitD(d.ifDecls);
+    return d;
+  }
 }
--- a/trunk/src/config.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/config.d	Wed Feb 20 22:09:29 2008 +0100
@@ -3,6 +3,10 @@
 /// Relative paths are resolved from the directory of the executable.
 module config;
 
+/// Predefined version identifiers.
+var version_ids = ["X86", "linux", "LittleEndian"];
+// "X86_64", "Windows", "Win32", "Win64", "BigEndian"
+
 /// Path to the language file.
 var langfile = "lang_en.d";
 
--- a/trunk/src/dil/Compilation.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/dil/Compilation.d	Wed Feb 20 22:09:29 2008 +0100
@@ -9,11 +9,61 @@
 /// A group of settings relevant to the compilation process.
 class CompilationContext
 {
+  alias typeof(this) CC;
+  CC parent;
   string[] importPaths;
   uint debugLevel;
   uint versionLevel;
   bool[string] debugIds;
   bool[string] versionIds;
   bool releaseBuild;
-  uint structAlign;
+  uint structAlign = 4;
+
+  this(CC parent = null)
+  {
+    this.parent = parent;
+    if (parent)
+    {
+      this.importPaths = parent.importPaths;
+      this.debugLevel = parent.debugLevel;
+      this.versionLevel = parent.versionLevel;
+      this.releaseBuild = parent.releaseBuild;
+      this.structAlign = parent.structAlign;
+    }
+  }
+
+  void addDebugId(string id)
+  {
+    debugIds[id] = true;
+  }
+
+  void addVersionId(string id)
+  {
+    versionIds[id] = true;
+  }
+
+  bool findDebugId(string id)
+  {
+    auto pId = id in debugIds;
+    if (pId)
+      return true;
+    if (!isRoot())
+      return parent.findDebugId(id);
+    return false;
+  }
+
+  bool findVersionId(string id)
+  {
+    auto pId = id in versionIds;
+    if (pId)
+      return true;
+    if (!isRoot())
+      return parent.findVersionId(id);
+    return false;
+  }
+
+  bool isRoot()
+  {
+    return parent is null;
+  }
 }
--- a/trunk/src/dil/Settings.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/dil/Settings.d	Wed Feb 20 22:09:29 2008 +0100
@@ -5,9 +5,12 @@
 module dil.Settings;
 import common;
 
+/// Global application settings.
 struct GlobalSettings
 {
 static:
+  /// Predefined version identifiers.
+  string[] versionIds;
   /// Path to the language file.
   string langFile = "lang_en.d";
   /// Language code of loaded messages catalogue.
--- a/trunk/src/dil/SettingsLoader.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/dil/SettingsLoader.d	Wed Feb 20 22:09:29 2008 +0100
@@ -12,6 +12,7 @@
 import dil.semantic.Symbol;
 import dil.semantic.Symbols;
 import dil.Information;
+import dil.Compilation;
 import common;
 
 import tango.io.FilePath;
@@ -77,9 +78,14 @@
     if (mod.hasErrors)
       return;
 
-    auto pass1 = new SemanticPass1(mod);
+    auto context = new CompilationContext;
+    auto pass1 = new SemanticPass1(mod, context);
     pass1.start();
 
+    if (auto array = getValue!(ArrayInitExpression)("version_ids"))
+      foreach (value; array.values)
+        if (auto str = castTo!(StringExpression)(value))
+          GlobalSettings.versionIds ~= str.getString();
     if (auto val = getValue!(StringExpression)("langfile"))
       GlobalSettings.langFile = val.getString();
     if (auto array = getValue!(ArrayInitExpression)("import_paths"))
@@ -109,7 +115,7 @@
     if (mod.hasErrors)
       return;
 
-    pass1 = new SemanticPass1(mod);
+    pass1 = new SemanticPass1(mod, context);
     pass1.start();
 
     if (auto array = getValue!(ArrayInitExpression)("messages"))
@@ -149,7 +155,8 @@
     if (mod.hasErrors)
       return null;
 
-    auto pass1 = new SemanticPass1(mod);
+    auto context = new CompilationContext;
+    auto pass1 = new SemanticPass1(mod, context);
     pass1.start();
 
     string[string] map;
--- a/trunk/src/dil/semantic/Analysis.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/dil/semantic/Analysis.d	Wed Feb 20 22:09:29 2008 +0100
@@ -8,6 +8,7 @@
 import dil.ast.Expressions;
 import dil.semantic.Scope;
 import dil.lexer.IdTable;
+import dil.Compilation;
 import common;
 
 /// Common semantics for pragma declarations and statements.
@@ -69,3 +70,37 @@
     // scop.error(e.begin, "expression must evaluate to a string");
   }
 }
+
+/// Returns true if the first branch (of a debug declaration/statement) or
+/// false if the else-branch should be compiled in.
+bool debugBranchChoice(Token* cond, CompilationContext context)
+{
+  if (cond)
+  {
+    if (cond.kind == TOK.Identifier)
+    {
+      if (context.findDebugId(cond.ident.str))
+        return true;
+    }
+    else if (cond.uint_ <= context.debugLevel)
+      return true;
+  }
+  else if (1 <= context.debugLevel)
+    return true;
+  return false;
+}
+
+/// Returns true if the first branch (of a version declaration/statement) or
+/// false if the else-branch should be compiled in.
+bool versionBranchChoice(Token* cond, CompilationContext context)
+{
+  assert(cond);
+  if (cond.kind == TOK.Identifier)
+  {
+    if (context.findVersionId(cond.ident.str))
+      return true;
+  }
+  else if (cond.uint_ >= context.versionLevel)
+    return true;
+  return false;
+}
--- a/trunk/src/dil/semantic/Pass1.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/dil/semantic/Pass1.d	Wed Feb 20 22:09:29 2008 +0100
@@ -18,6 +18,7 @@
        dil.semantic.Scope,
        dil.semantic.Module,
        dil.semantic.Analysis;
+import dil.Compilation;
 import dil.Location;
 import dil.Information;
 import dil.Messages;
@@ -25,32 +26,31 @@
 import dil.CompilerInfo;
 import common;
 
-/++
-  The first pass is the declaration pass.
-
-  The basic task of this class is to traverse the parse tree,
-  find all kinds of declarations and add them
-  to the symbol tables of their respective scopes.
-+/
+/// The first pass is the declaration pass.
+///
+/// The basic task of this class is to traverse the parse tree,
+/// find all kinds of declarations and add them
+/// to the symbol tables of their respective scopes.
 class SemanticPass1 : Visitor
 {
   Scope scop; /// The current scope.
   Module modul; /// The module to be semantically checked.
+  CompilationContext context;
 
   // Attributes:
   LinkageType linkageType;
   Protection protection;
   StorageClass storageClass;
-  uint alignSize = DEFAULT_ALIGN_SIZE;
+  uint alignSize;
 
-  /++
-    Construct a SemanticPass1 object.
-    Params:
-      modul = the module to be processed.
-  +/
-  this(Module modul)
+  /// Construct a SemanticPass1 object.
+  /// Params:
+  ///   modul = the module to be processed.
+  this(Module modul, CompilationContext context)
   {
     this.modul = modul;
+    this.context = new CompilationContext(context);
+    this.alignSize = context.structAlign;
   }
 
   /// Start semantic analysis.
@@ -352,14 +352,40 @@
   {
     if (d.isSpecification)
     {
-
+      if (d.spec.kind == TOK.Identifier)
+        context.addDebugId(d.spec.ident.str);
+      else
+        context.debugLevel = d.spec.uint_;
     }
-    return null;
+    else
+    {
+      if (debugBranchChoice(d.cond, context))
+        d.compiledDecls = d.decls;
+      else
+        d.compiledDecls = d.elseDecls;
+      d.compiledDecls && visitD(d.compiledDecls);
+    }
+    return d;
   }
 
   D visit(VersionDeclaration d)
   {
-    return null;
+    if (d.isSpecification)
+    {
+      if (d.spec.kind == TOK.Identifier)
+        context.addVersionId(d.spec.ident.str);
+      else
+        context.versionLevel = d.spec.uint_;
+    }
+    else
+    {
+      if (versionBranchChoice(d.cond, context))
+        d.compiledDecls = d.decls;
+      else
+        d.compiledDecls = d.elseDecls;
+      d.compiledDecls && visitD(d.compiledDecls);
+    }
+    return d;
   }
 
   D visit(TemplateDeclaration d)
--- a/trunk/src/main.d	Wed Feb 20 01:24:19 2008 +0100
+++ b/trunk/src/main.d	Wed Feb 20 22:09:29 2008 +0100
@@ -24,6 +24,7 @@
 import dil.CompilerInfo;
 import dil.Information;
 import dil.SourceText;
+import dil.Compilation;
 
 import cmd.Generate;
 import cmd.Statistics;
@@ -55,8 +56,16 @@
     if (args.length < 2)
       return printHelp("compile");
 
+    string[] filePaths;
+    auto context = newCompilationContext();
+    foreach (arg; args[2..$])
+    {
+      if (parseDebugOrVersion(arg, context))
+      {}
+      else
+        filePaths ~= arg;
+    }
     infoMan = new InfoManager();
-    auto filePaths = args[2..$];
     foreach (filePath; filePaths)
     {
       auto mod = new Module(filePath, infoMan);
@@ -66,7 +75,7 @@
         continue;
 
       // Start semantic analysis.
-      auto pass1 = new SemanticPass1(mod);
+      auto pass1 = new SemanticPass1(mod, context);
       pass1.start();
 
       void printSymbolTable(ScopeSymbol scopeSym, char[] indent)
@@ -98,9 +107,12 @@
     bool incUndoc;
     bool verbose;
     // Parse arguments.
+    auto context = newCompilationContext();
     foreach (arg; args[3..$])
     {
-      if (arg == "-i")
+      if (parseDebugOrVersion(arg, context))
+      {}
+      else if (arg == "-i")
         incUndoc = true;
       else if (arg == "-v")
         verbose = true;
@@ -112,7 +124,7 @@
 
     infoMan = new InfoManager();
     // Execute command.
-    cmd.DDoc.execute(filePaths, destination, macroPaths, incUndoc, verbose, infoMan);
+    cmd.DDoc.execute(filePaths, destination, macroPaths, incUndoc, verbose, context, infoMan);
     infoMan.hasInfo && printErrors(infoMan);
     break;
   case "gen", "generate":
@@ -323,6 +335,49 @@
   return false;
 }
 
+/// Creates the global compilation context.
+CompilationContext newCompilationContext()
+{
+  auto cc = new CompilationContext;
+  cc.importPaths = GlobalSettings.importPaths;
+  cc.addVersionId("dil");
+  cc.addVersionId("all");
+version(D2)
+  cc.addVersionId("D_Version2");
+  foreach (versionId; GlobalSettings.versionIds)
+    if (!Lexer.isReservedIdentifier(versionId))
+      cc.versionIds[versionId] = true;
+  return cc;
+}
+
+bool parseDebugOrVersion(string arg, CompilationContext context)
+{
+  if (strbeg(arg, "-debug"))
+  {
+    if (arg.length > 7)
+    {
+      auto val = arg[7..$];
+      if (isdigit(val[0]))
+        context.debugLevel = Integer.toInt(val);
+      else if (!Lexer.isReservedIdentifier(val))
+        context.addDebugId(val);
+    }
+    else
+      context.debugLevel = 1;
+  }
+  else if (arg.length > 9 && strbeg(arg, "-version="))
+  {
+    auto val = arg[9..$];
+    if (isdigit(val[0]))
+      context.versionLevel = Integer.toInt(val);
+    else if (!Lexer.isReservedIdentifier(val))
+      context.addVersionId(val);
+  }
+  else
+    return false;
+  return true;
+}
+
 void printErrors(InfoManager infoMan)
 {
   foreach (info; infoMan.info)
@@ -354,7 +409,7 @@
   switch (command)
   {
   case "c", "compile":
-    msg = "Compile D source files.
+    msg = `Compile D source files.
 Usage:
   dil compile file.d [file2.d, ...] [Options]
 
@@ -362,9 +417,14 @@
   Errors are printed to standard error output.
 
 Options:
+  -debug           : include debug code
+  -debug=level     : include debug(l) code where l <= level
+  -debug=ident     : include debug(ident) code
+  -version=level   : include version(l) code where l >= level
+  -version=ident   : include version(ident) code
 
 Example:
-  dil c src/main.d";
+  dil c src/main.d`;
     break;
   case "ddoc", "d":
     msg = `Generate documentation from DDoc comments in D source files.
@@ -379,7 +439,7 @@
   -v               : verbose output
 
 Example:
-  dil d doc/ src/main.d mymacros.ddoc -i`;
+  dil d doc/ src/main.d src/macros_dil.ddoc -i`;
     break;
   case "gen", "generate":
 //     msg = GetMsg(MID.HelpGenerate);