changeset 206:d3c148ca429b

Major moving of files. all src now goes into src, all docs in docs.
author Anders Johnsen <skabet@gmail.com>
date Tue, 12 Aug 2008 18:14:56 +0200
parents 8387cbaa85ab
children e0551773a005
files ast/Decl.d ast/Expr.d ast/Stmt.d doc/candydoc/CANDYDOC.txt doc/candydoc/candy.ddoc doc/candydoc/explorer.js doc/candydoc/ie56hack.css doc/candydoc/img/bg.gif doc/candydoc/img/candydoc.gif doc/candydoc/img/outline/alias.gif doc/candydoc/img/outline/bg.gif doc/candydoc/img/outline/class.gif doc/candydoc/img/outline/enum.gif doc/candydoc/img/outline/func.gif doc/candydoc/img/outline/module.gif doc/candydoc/img/outline/package.gif doc/candydoc/img/outline/struct.gif doc/candydoc/img/outline/template.gif doc/candydoc/img/outline/var.gif doc/candydoc/img/package/bg.gif doc/candydoc/img/tree/shim.gif doc/candydoc/img/tree/tb.gif doc/candydoc/img/tree/tbr.gif doc/candydoc/img/tree/tbrm.gif doc/candydoc/img/tree/tbrp.gif doc/candydoc/img/tree/tr.gif doc/candydoc/img/tree/trm.gif doc/candydoc/img/tree/trp.gif doc/candydoc/modules.ddoc doc/candydoc/style.css doc/candydoc/tree.js doc/candydoc/util.js docs/candydoc/CANDYDOC.txt docs/candydoc/candy.ddoc docs/candydoc/explorer.js docs/candydoc/ie56hack.css docs/candydoc/img/bg.gif docs/candydoc/img/candydoc.gif docs/candydoc/img/outline/alias.gif docs/candydoc/img/outline/bg.gif docs/candydoc/img/outline/class.gif docs/candydoc/img/outline/enum.gif docs/candydoc/img/outline/func.gif docs/candydoc/img/outline/module.gif docs/candydoc/img/outline/package.gif docs/candydoc/img/outline/struct.gif docs/candydoc/img/outline/template.gif docs/candydoc/img/outline/var.gif docs/candydoc/img/package/bg.gif docs/candydoc/img/tree/shim.gif docs/candydoc/img/tree/tb.gif docs/candydoc/img/tree/tbr.gif docs/candydoc/img/tree/tbrm.gif docs/candydoc/img/tree/tbrp.gif docs/candydoc/img/tree/tr.gif docs/candydoc/img/tree/trm.gif docs/candydoc/img/tree/trp.gif docs/candydoc/modules.ddoc docs/candydoc/style.css docs/candydoc/tree.js docs/candydoc/util.js dsss.conf src/ast/Decl.d src/ast/Expr.d src/ast/Stmt.d src/basic/Message.d src/basic/Messages.d src/basic/SmallArray.d src/basic/SourceLocation.d src/basic/SourceManager.d src/lexer/Keyword.d src/lexer/Lexer.d src/lexer/Token.d src/parser/Action.d src/parser/Parser.d tests/code/array_1.d tests/code/basic_1.d tests/code/basic_2.d tests/code/basic_types_1.d tests/code/basic_types_2.d tests/code/bool_1.d tests/code/bool_2.d tests/code/cast_1.d tests/code/cast_2.d tests/code/func_1.d tests/code/if_1.d tests/code/if_2.d tests/code/if_3.d tests/code/if_4.d tests/code/math_1.d tests/code/math_2.d tests/code/math_3.d tests/code/sarray_1.d tests/code/sarray_2.d tests/code/scope_1.d tests/code/scope_2.d tests/code/scope_3.d tests/code/struct_1.d tests/code/struct_2.d tests/code/struct_3.d tests/code/struct_4.d tests/code/struct_5.d tests/code/switch_1.d tests/code/switch_2.d tests/code/switch_3.d tests/code/switch_4.d tests/code/switch_5.d tests/code/switch_6.d tests/code/while_1.d tests/code/while_2.d tests/lexer/Comments.d tests/lexer/Comments1.d tests/lexer/Comments1.d.orig tests/lexer/Comments2.d tests/lexer/Comments2.d.orig tests/parser/basic_type_char_1.d tests/parser/string_1.d tests/parser/struct_method_1.d tests/run.d tests/sema/deref_1.d tests/sema/deref_2.d
diffstat 121 files changed, 4845 insertions(+), 1505 deletions(-) [+]
line wrap: on
line diff
--- a/ast/Decl.d	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-module ast.Decl;
-
-import ast.Expr;
-
-/**
-  The base class for all Declarations. 
-  
-  Declarations comes in two forms:
-
-    $(OL
-    $(LI members, such as variables and functions.)
-    $(LI types, such as classes, structs.))
-
-  */
-class Decl
-{
-
-    /// Method for doing cast(FunctionDecl)
-    FunctionDecl asFunctionDecl() { return null;}
-
-    /// Returns true if it is a FunctionDecl
-    bool isFunctionDecl() { return false;}
-
-    /// Method for doing cast(VarDecl)
-    VarDecl asVarDecl() { return null;}
-
-    /// Returns true if it is a VarDecl
-    bool isVarDecl() { return false;}
-
-    /// Method for doing cast(StructDecl)
-    StructDecl asStructDecl() { return null;}
-
-    /// Returns true if it is a StructDecl
-    bool isStructDecl() { return false;}
-
-    /// Method for doing cast(ClassDecl)
-    ClassDecl asClassDecl() { return null;}
-
-    /// Returns true if it is a ClassDecl
-    bool isClassDecl() { return false;}
-
-    /// Method for doing cast(InterfaceDecl)
-    InterfaceDecl asInterfaceDecl() { return null;}
-
-    /// Returns true if it is a InterfaceDecl
-    bool isInterfaceDecl() { return false;}
-
-    /// Method for doing cast(TypedefDecl)
-    TypedefDecl asTypedefDecl() { return null;}
-
-    /// Returns true if it is a TypedefDecl
-    bool isTypedefDecl() { return false;}
-}
-
-/**
-  The FunctionDecl contains a set of VarDecls, being the parameters of the
-  method. It also contains a potentiel list of statements.
-  */
-class FunctionDecl : Decl
-{
-    /// Returns the parameters of the method.
-    VarDecl[] getParams() { return params;}
-    /// Return the parameter on a given index.
-    VarDecl getParam(int index) { return params[index];}
-    /// Returns the number of parameters.
-    int getNumberOfParamst() { return params.length;}
-    /**
-      Returns the number of required arguments, that should be given to
-      call this method.
-      */
-    int getMinimumNumberOfParams() 
-    { 
-        assert(0, "Unimplemented");
-        return 0;
-    }
-
-    override FunctionDecl asFunctionDecl() { return this;}
-    override bool isFunctionDecl() { return true;}
-
-private:
-    VarDecl[] params;
-}
-
-/**
-  The VarDecl contains as a minimum a Type. As an addition, i will also
-  in most cases contain an Identifier that it'll be reconized by and in
-  some cases it will also contain an expression that'll be it initializer.
-
-  Some cases to check:
-
-  $(UL
-      $(LI
-          If the VarDecl is a param in a FunctionDecl the initializer, if
-          present, should be a constant expression(Enum, Number, String 
-          or the like).
-        )
-    )
-  */
-class VarDecl : Decl
-{
-    /// Return true if the VarDecl has an identifier/name.
-    bool hasIdentifier() { return !(identifier is null);}
-    /// Return true if the VarDecl has en initializer.
-    bool hasInitializer() { return !(initializer is null);}
-
-    override VarDecl asVarDecl() { return this;}
-    override bool isVarDecl() { return true;}
-    
-private:
-    Identifier identifier;
-    Expr initializer;
-}
-
-class StructDecl : Decl
-{
-    override StructDecl asStructDecl() { return this;}
-    override bool isStructDecl() { return true;}
-}
-
-class ClassDecl : Decl
-{
-    override ClassDecl asClassDecl() { return this;}
-    override bool isClassDecl() { return true;}
-}
-
-class InterfaceDecl : Decl
-{
-    override InterfaceDecl asInterfaceDecl() { return this;}
-    override bool isInterfaceDecl() { return true;}
-}
-
-class TypedefDecl : Decl
-{
-    override TypedefDecl asTypedefDecl() { return this;}
-    override bool isTypedefDecl() { return true;}
-}
-
--- a/ast/Expr.d	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-module ast.Expr;
-
-/**
-  The base class for all Expressions.
-  */
-class Expr
-{
-    /// Get the type of the Expr
-    Object getType() 
-    {
-        assert(0, "Unimplemented");
-        return null;
-    }
-
-    /// Set the type of the Expr
-    void setType(Object type) 
-    {
-        assert(0, "Unimplemented");
-    }
-
-    /// Returns true if the Expr can be compile-time evaluated.
-    bool isConstantExpr() { return false; }
-
-    NumberLiteral asNumberLiteral() { return null; }
-    bool isNumberLiteral() { return false; }
-
-    StringLiteral asStringLiteral() { return null; }
-    bool isStringLiteral() { return false; }
-
-    ArrayLiteral asArrayLiteral() { return null; }
-    bool isArrayLiteral() { return false; }
-
-    Assign asAssign() { return null; }
-    bool isAssign() { return false; }
-
-    Binary asBinary() { return null; }
-    bool isBinary() { return false; }
-
-    Negate asNegate() { return null; }
-    bool isNegate() { return false; }
-
-    Deref asDeref() { return null; }
-    bool isDeref() { return false; }
-
-    AddressOf asAddressOf() { return null; }
-    bool isAddressOf() { return false; }
-
-    Index asIndex() { return null; }
-    bool isIndex() { return false; }
-
-    Identifier asIdentifier() { return null; }
-    bool isIdentifier() { return false; }
-
-    Member asMember() { return null; }
-    bool isMember() { return false; }
-
-private:
-/// FIXME: Add DType? here
-}
-
-/**
-  NumberLiteral
-  */
-/// FIXME: Should there be an IntegerLiteral and FloatLiteral instead?
-class NumberLiteral : Expr
-{
-    override bool isConstantExpr() { return true; }
-
-    override NumberLiteral asNumberLiteral() { return this; }
-    override bool isNumberLiteral() { return true; }
-}
-
-/**
-  StringLiteral
-  */
-class StringLiteral : Expr
-{
-    override bool isConstantExpr() { return true; }
-
-    override StringLiteral asStringLiteral() { return this; }
-    override bool isStringLiteral() { return true; }
-}
-
-/**
-  ArrayLiteral
-  */
-class ArrayLiteral : Expr
-{
-    /// Return the arguments for the ArrayLiteral
-    Expr[] getArguments() { return arguments; }
-
-    /// Return a given argument for the ArrayLiteral
-    Expr getArgument(int index) { return arguments[index]; }
-
-    /// Get the count of arguments for the ArrayLiteral
-    int getArgumentCount() { return arguments.length; }
-
-    override bool isConstantExpr() 
-    {
-        /**
-          If all the arguments to the ArrayLiteral is an constant Expr, then
-          this ArrayLiteral can be considered an constant Expr aswell.
-          */
-        // FIXME: consider if it should save the result
-        foreach (arg; arguments)
-            if (!arg.isConstantExpr())
-                return false;
-        return true; 
-    }
-
-    override ArrayLiteral asArrayLiteral() { return this; }
-    override bool isArrayLiteral() { return true; }
-
-private:
-    Expr[] arguments;
-}
-
-/**
-  The Assign expression contains two expression, a left and a right side, 
-  left being a lvalue, right being a rvalue. 
-
-  If the right side ain't the same type as the left type, the right side will
-  try to be promoted through an implicit cast. If this failes, an error must
-  be given.
-  */
-class Assign : Expr
-{
-    override Assign asAssign() { return this; }
-    override bool isAssign() { return true; }
-
-private:
-    Expr left, right;
-}
-
-/**
-  Binary
-  */
-class Binary : Expr
-{
-    override Binary asBinary() { return this; }
-    override bool isBinary() { return true; }
-
-private:
-    Expr left, right;
-}
-
-/**
-  Negate
-  */
-class Negate : Expr
-{
-    override Negate asNegate() { return this; }
-    override bool isNegate() { return true; }
-
-private:
-    Expr expr;
-}
-
-/**
-  Deref
-  */
-class Deref : Expr
-{
-    override Deref asDeref() { return this; }
-    override bool isDeref() { return true; }
-}
-
-/**
-  AddressOf
-  */
-class AddressOf : Expr
-{
-    override AddressOf asAddressOf() { return this; }
-    override bool isAddressOf() { return true; }
-}
-
-/**
-  Index
-  */
-class Index : Expr
-{
-    override Index asIndex() { return this; }
-    override bool isIndex() { return true; }
-}
-
-/**
-  Identifier
-  */
-class Identifier : Expr
-{
-    override Identifier asIdentifier() { return this; }
-    override bool isIdentifier() { return true; }
-}
-
-/**
-  Member
-  */
-class Member : Expr
-{
-    override Member asMember() { return this; }
-    override bool isMember() { return true; }
-}
-
--- a/ast/Stmt.d	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-module ast.Stmt;
-
-/**
-  The base class for all Statements.
-  */
-class Stmt
-{
-    bool isCompoundStmt() { return false; }
-    CompoundStmt asCompoundStmt() { return null; }
-
-    bool isDeclStmt() { return false; }
-    DeclStmt asDeclStmt() { return null; }
-
-    bool isExpStmt() { return false; }
-    ExpStmt asExpStmt() { return null; }
-
-    bool isReturnStmt() { return false; }
-    ReturnStmt asReturnStmt() { return null; }
-
-    bool isIfStmt() { return false; }
-    IfStmt asIfStmt() { return null; }
-
-    bool isWhileStmt() { return false; }
-    WhileStmt asWhileStmt() { return null; }
-
-    bool isForStmt() { return false; }
-    ForStmt asForStmt() { return null; }
-
-    bool isSwitchStmt() { return false; }
-    SwitchStmt asSwitchStmt() { return null; }
-
-    bool isForeachStmt() { return false; }
-    ForeachStmt asForeachStmt() { return null; }
-
-    bool isAssertStmt() { return false; }
-    AssertStmt asAssertStmt() { return null; }
-}
-
-/**
-  CompoundStmt
-  */
-class CompoundStmt : Stmt
-{
-    override bool isCompoundStmt() { return true; }
-    override CompoundStmt asCompoundStmt() { return this; }
-}
-
-/**
-  DeclStmt
-  */
-class DeclStmt : Stmt
-{
-    override bool isDeclStmt() { return true; }
-    override DeclStmt asDeclStmt() { return this; }
-}
-
-/**
-  ExpStmt
-  */
-class ExpStmt : Stmt
-{
-    override bool isExpStmt() { return true; }
-    override ExpStmt asExpStmt() { return this; }
-}
-
-/**
-  ReturnStmt
-  */
-class ReturnStmt : Stmt
-{
-    override bool isReturnStmt() { return true; }
-    override ReturnStmt asReturnStmt() { return this; }
-}
-
-/**
-  IfStmt
-  */
-class IfStmt : Stmt
-{
-    override bool isIfStmt() { return true; }
-    override IfStmt asIfStmt() { return this; }
-}
-
-/**
-  WhileStmt
-  */
-class WhileStmt : Stmt
-{
-    override bool isWhileStmt() { return true; }
-    override WhileStmt asWhileStmt() { return this; }
-}
-
-/**
-  ForStmt
-  */
-class ForStmt : Stmt
-{
-    override bool isForStmt() { return true; }
-    override ForStmt asForStmt() { return this; }
-}
-
-/**
-  SwitchStmt
-  */
-class SwitchStmt : Stmt
-{
-    override bool isSwitchStmt() { return true; }
-    override SwitchStmt asSwitchStmt() { return this; }
-}
-
-/**
-  ForeachStmt
-  */
-class ForeachStmt : Stmt
-{
-    override bool isForeachStmt() { return true; }
-    override ForeachStmt asForeachStmt() { return this; }
-}
-
-/**
-  AssertStmt
-  */
-class AssertStmt : Stmt
-{
-    override bool isAssertStmt() { return true; }
-    override AssertStmt asAssertStmt() { return this; }
-}
--- a/doc/candydoc/CANDYDOC.txt	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-
-CanDyDOC is fileset for creating advanced documentation of programs written
-in D programming language. CanDyDOC adds some eye-candy and advanced navigation
-features to .html documents that are generated by D compiler and known as DDOC.
-Produced result is AJAX web-application that is compatible with all mainstream
-web browsers.
-
-This is a fork of the original candydoc, distributed with DSSS. For more
-information on DSSS and DSSS' fork of candydoc, see
-http://www.dsource.org/projects/dsss/
-
-CanDyDOC includes following files:
-    - candy.ddoc
-        File with DDOC macro definitions. You haven't to touch it.
-
-    - modules.ddoc
-        You should enumerate all modules that would be avaible for navigation
-        here.
-
-    - style.css
-        Cascading style sheet file that defines look of produced documentation.
-        You can leave this file without changes or adjust fonts, colors, etc
-        here. See it for documentation.
-
-    - ie56hack.css
-        CSS file to force Internet Explorer 5/6 browser show documentation
-        as it looks like in standard-compliant browsers.
-
-    - tree.js
-        JavaScript implementing tree control that looks like native one.
-
-    - util.js
-        Common cross-browser routines.
-
-    - explorer.js
-        Heart of every documentation's page. Controls generation, behaviour and
-        navigation of a page.
-
-    - numerous of image files in 'img' folder.
-
-How to use:
-    1) Put 'candydoc' directory in place where documentation will be.
-    2) Modify modules.ddoc file: enumerate all modules that should be avaible
-       for navigation.
-    3) Modify style.css file if you want to change style of documentation. Or
-       leave it unmodified to apply defaul theme.
-    4) Run documentation compilation with candy.ddoc and modules.ddoc specified
-       on command line.
-    5) Enjoy a result :)
-
-Known bugs:
-    - Explorer window doesn't work on Safari browser.
-    - Scroll bar positions are not adjusted after explorer's tab change in Opera
-      browser. So it is posible to see nothing on some tab: solution is to
-      return to a previous tab, scroll it to top and then return back.
-    - Overlapping of some elements when too few horizontal place avaible.
--- a/doc/candydoc/candy.ddoc	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-DDOC =  
-<html><head>
-<meta http-equiv="content-type" content="text/html; charset=utf-8">
-<meta content="text/javascript" http-equiv="content-script-type">
-<title>$(TITLE)</title>
-<link rel="stylesheet" type="text/css" href="candydoc/style.css">
-<!--[if lt IE 7]><link rel="stylesheet" type="text/css" href="candydoc/ie56hack.css"><![endif]-->
-<script language="JavaScript" src="candydoc/util.js" type="text/javascript"></script>
-<script language="JavaScript" src="candydoc/tree.js" type="text/javascript"></script>
-<script language="JavaScript" src="candydoc/explorer.js" type="text/javascript"></script>
-</head><body>
-<div id="tabarea"></div><div id="explorerclient"></div>
-<div id="content"><script>explorer.initialize("$(TITLE)");</script>
-	<table class="content">
-		<tr><td id="docbody"><h1>$(TITLE)</h1>$(BODY)</td></tr>
-		<tr><td id="docfooter">
-			Page was generated with
-			<img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px">
-			on $(DATETIME)
-		</td></tr>
-	</table>
-</div>
-$(ADD_MODULES)
-</body></html>
-
-
-DDOC_DECL =
-<script>explorer.outline.writeEnabled = true;</script>
-$(DT <span class="decl">$0</span>)
-<script>explorer.outline.writeEnabled = false;</script>
-
-
-DDOC_PSYMBOL =
-<span class="currsymbol">$0</span>
-<script>explorer.outline.addDecl('$0');</script>
-
-
-DDOC_MEMBERS =
-<script>explorer.outline.incSymbolLevel();</script>
-$(DL $0)
-<script>explorer.outline.decSymbolLevel();</script>
-
-
-DDOC_PARAM_ID =
-<td nowrap valign="top" style="padding-right: 8px">$0</td>
-
-               
-DDOC_PARAM =<span class="funcparam">$0</span>
-ADD_MODULES =<script>$(MODULES)</script>
-MODULE =explorer.packageExplorer.addModule("$0");
-MODULE_FULL =explorer.packageExplorer.addModuleFull("$0");
--- a/doc/candydoc/explorer.js	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,319 +0,0 @@
-/* This file is a part of CanDyDOC fileset.
-   File is written by Victor Nakoryakov and placed into the public domain.
-
-   This file is javascript with classes that represents explorer window.
-   And things related to navigation. */
-   
-var explorer = new Explorer();
-
-///////////////////////////////////////////////////////////////////////////////
-// Current symbol marker class constructor
-///////////////////////////////////////////////////////////////////////////////
-function Marker()
-{
-    this.top    = document.createElement("div");
-    this.middle = document.createElement("div");
-    this.bottom = document.createElement("div");
-    this.container = document.createElement("div");
-    
-    this.setTo = function(term)
-    {
-        // find definition related to `term`
-        var def = term.nextSibling;
-        while (def && def.nodeName != "DD")
-            def = def.nextSibling;
-            
-        var defHeight = 0;
-        var childrenHeight = 0; // children of current declaration
-        if (def)
-        {
-            defHeight = def.offsetHeight;
-            var child = def.firstChild;
-            
-            // traverse until DL tag, until children definition
-            while (child && child.nodeName != "DL")
-                child = child.nextSibling;
-                
-            if (child)
-                childrenHeight = child.offsetHeight;
-        }
-        
-        this.top.style.height = term.offsetHeight;
-        this.middle.style.height = defHeight - childrenHeight;
-        this.bottom.style.height = childrenHeight;
-        
-        if (childrenHeight == 0)
-            this.bottom.style.display = "none";
-        else
-            this.bottom.style.display = "";
-        
-        this.container.style.left = getLeft(term) - 8;
-        this.container.style.top = getTop(term);
-        this.container.style.display = "";
-    }
-        
-    ///////////////////////////////////////////////////////////////////////////
-    this.container.style.position = "absolute";
-    this.container.style.display = "none";
-    
-    this.top.className = "markertop";
-    this.middle.className = "markermiddle";
-    this.bottom.className = "markerbottom";
-    
-    this.container.appendChild(this.top);
-    this.container.appendChild(this.middle);
-    this.container.appendChild(this.bottom);
-    
-    //document.body.appendChild( this.container );
-    
-    // Workaround bug in IE 5/6. We can not append anything to document body until
-    // full page load.
-    window.marker = this;
-    if (window.addEventListener)
-        window.addEventListener("load", new Function("document.body.appendChild( window.marker.container );"), false);
-    else if (window.attachEvent)
-        window.attachEvent("onload", new Function("document.body.appendChild( window.marker.container );"));
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Outline class constructor
-///////////////////////////////////////////////////////////////////////////////
-function Outline()
-{
-    this.tree           = new TreeView();
-    this.mountPoint     = null;    
-    this.writeEnabled   = false;
-    this.marker         = new Marker();        
-    this.classRegExp    = new RegExp;
-    this.structRegExp   = new RegExp;
-    this.enumRegExp     = new RegExp;
-    this.templateRegExp = new RegExp;
-    this.aliasRegExp    = new RegExp;
-    this.funcRegExp     = new RegExp;
-    
-    this.incSymbolLevel = function()
-    {
-        if (this.mountPoint == null)
-            this.mountPoint = this.tree.children[ 0 ];
-        else
-            this.mountPoint = this.mountPoint.lastChild();
-    }
-
-    this.decSymbolLevel = function()
-    {
-        // place icons near items according to extracted below type
-        for (var i = 0; i < this.mountPoint.children.length; ++i)
-        {
-            child = this.mountPoint.children[i];
-            var term = child.termRef;
-            
-            // find first span node
-            var n = term.firstChild;
-            while (n && n.nodeName != "SPAN")
-                n = n.nextSibling;
-            
-            if (!n) // shouldn't happen
-                continue;
-            
-            var iconSrc;
-            if (n.firstChild.nodeName == "#text")
-            {
-                var text = n.firstChild.data; // text before declaration
-                
-                if ( this.classRegExp.test(text) )
-                    iconSrc = "candydoc/img/outline/class.gif";
-                else if ( this.structRegExp.test(text) )
-                    iconSrc = "candydoc/img/outline/struct.gif";
-                else if ( this.enumRegExp.test(text) )
-                    iconSrc = "candydoc/img/outline/enum.gif";
-                else if ( this.templateRegExp.test(text) )
-                    iconSrc = "candydoc/img/outline/template.gif";
-                else if ( this.aliasRegExp.test(text) )
-                    iconSrc = "candydoc/img/outline/alias.gif";
-                else // function or variable? check whether '(' ')' exists on the right
-                {
-                    var np = n.firstChild;
-                    while (np && np.nodeName != "SCRIPT") // find our script "onDecl"
-                        np = np.nextSibling;
-                        
-                    if (np && np.nextSibling && np.nextSibling.nodeName == "#text" &&
-                        this.funcRegExp.test(np.nextSibling.data))
-                    {
-                        iconSrc = "candydoc/img/outline/func.gif";
-                    }
-                    else
-                        iconSrc = "candydoc/img/outline/var.gif";
-                }
-            }
-            else // enum member ?
-                iconSrc = "candydoc/img/outline/var.gif";
-                    
-            child.icon.src = iconSrc;
-            child.icon.width = 16;
-            child.icon.height = 16;
-        }
-        
-        this.mountPoint = this.mountPoint.parentNode;
-    }
-
-    this.addDecl = function(decl)
-    {
-        function getLastLeaf(elem)
-        {
-            if (elem.childNodes.length > 0)
-                return getLastLeaf(elem.lastChild);
-            else
-                return elem;
-        }
-
-        function getCurrentTerm()
-        {
-            var ret = getLastLeaf( document.getElementById("content") );
-            while (ret && ret.nodeName != "DT")
-                ret = ret.parentNode;
-            
-            return ret;
-        }
-        
-        if (this.writeEnabled)
-        {
-            var node = this.mountPoint.createChild(decl);
-            node.termRef = getCurrentTerm();
-            node.setOnclick( new Function("explorer.outline.mark(this.termRef);") );
-        }
-    }
-
-    this.mark = function(term)
-    {
-        this.marker.setTo(term);
-        window.scrollTo(0, getTop(term) - getWindowHeight() / 6);    
-    }
-        
-    
-    this.classRegExp.compile("(.*\b)?class(\b.*)?");
-    this.structRegExp.compile("(.*\b)?struct(\b.*)?");
-    this.enumRegExp.compile("(.*\b)?enum(\b.*)?");
-    this.templateRegExp.compile("(.*\b)?template(\b.*)?");
-    this.aliasRegExp.compile("(.*\b)?alias(\b.*)?");
-    this.funcRegExp.compile(/.*\(.*/);    
-}
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Package explorer class constructor
-///////////////////////////////////////////////////////////////////////////////
-function PackageExplorer()
-{
-    this.tree = new TreeView(true);    
-    
-    this.addModule2 = function(mod, full)
-    {
-        var moduleIco = "candydoc/img/outline/module.gif";
-        var packageIco = "candydoc/img/outline/package.gif";
-
-        var path = mod.split("\.");
-        var node = this.tree.branch(path[0]);
-        if ( !node )
-            node = this.tree.createBranch(path[0], (path.length == 1) ? moduleIco : packageIco);
-        
-        for (var i = 1; i < path.length; ++i)
-        {
-            var prev = node;
-            node = node.child(path[i]);
-            if (!node)
-                node = prev.createChild(path[i], (path.length == i + 1) ? moduleIco : packageIco);
-                
-            if (path.length == i + 1) {
-                if (full)
-                    node.setRef(mod + ".html");
-                else
-                    node.setRef(path[i] + ".html");
-            }
-        }
-    }
-    
-    this.addModuleFull = function(mod)
-    {
-        this.addModule2(mod, true);
-    }
-    
-    this.addModule = function(mod)
-    {
-        this.addModule2(mod, false);
-    }
-}
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Explorer class constructor
-///////////////////////////////////////////////////////////////////////////////
-function Explorer()
-{
-    this.outline         = new Outline();
-    this.packageExplorer = new PackageExplorer();
-    this.tabs            = new Array();
-    this.tabCount        = 0;
-    
-    this.initialize = function(moduleName)
-    {
-        this.tabArea = document.getElementById("tabarea");
-        this.clientArea = document.getElementById("explorerclient");
-        
-        // prevent text selection
-        this.tabArea.onmousedown = new Function("return false;");
-        this.tabArea.onclick = new Function("return true;");
-        this.tabArea.onselectstart = new Function("return false;");
-        this.clientArea.onmousedown = new Function("return false;");
-        this.clientArea.onclick = new Function("return true;");
-        this.clientArea.onselectstart = new Function("return false;");
-        
-        this.outline.tree.createBranch( moduleName, "candydoc/img/outline/module.gif" );
-        
-        // create tabs
-        this.createTab("Outline", this.outline.tree.domEntry);
-        this.createTab("Package", this.packageExplorer.tree.domEntry);
-    }
-    
-    this.createTab = function(name, domEntry)
-    {
-        var tab = new Object();
-        this.tabs[name] = tab;
-        this.tabCount++;
-        
-        tab.domEntry = domEntry;
-        tab.labelSpan = document.createElement("span");
-        
-        if (this.tabCount > 1)
-        {
-            tab.labelSpan.className = "inactivetab";
-            tab.domEntry.style.display = "none";
-        }
-        else
-        {
-            tab.labelSpan.className = "activetab";
-            tab.domEntry.style.display = "";
-        }
-        
-        tab.labelSpan.appendChild( document.createTextNode(name) );
-        tab.labelSpan.owner = this;
-        tab.labelSpan.onclick = new Function("this.owner.setSelection('" + name + "');");
-        
-        this.tabArea.appendChild( tab.labelSpan );
-        this.clientArea.appendChild( domEntry );
-    }
-    
-    this.setSelection = function(tabName)
-    {
-        for (name in this.tabs)
-        {
-            this.tabs[name].labelSpan.className = "inactivetab";
-            this.tabs[name].domEntry.style.display = "none";
-        }
-        
-        this.tabs[tabName].labelSpan.className = "activetab";
-        this.tabs[tabName].domEntry.style.display = "";
-    }
-}
--- a/doc/candydoc/ie56hack.css	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-/* This file is a part of CanDyDOC fileset.
-   File is written by Victor Nakoryakov and placed into the public domain.
-
-   This file is CSS to work around IE6 and earlier bugs. It's included just
-   in these browsers. */
-
-
-/* Some magic to emulate unsupported "position: fixed" style. */
-#tabarea
-{
-	_position: absolute;
-	_top: expression(eval(document.body.scrollTop+8));
-}
-
-/* ditto */
-#explorerclient 
-{
-	_position: absolute;
-	_top: expression(eval(document.body.scrollTop+24));
-	_height: expression(eval(document.body.clientHeight-48));
-}
Binary file doc/candydoc/img/bg.gif has changed
Binary file doc/candydoc/img/candydoc.gif has changed
Binary file doc/candydoc/img/outline/alias.gif has changed
Binary file doc/candydoc/img/outline/bg.gif has changed
Binary file doc/candydoc/img/outline/class.gif has changed
Binary file doc/candydoc/img/outline/enum.gif has changed
Binary file doc/candydoc/img/outline/func.gif has changed
Binary file doc/candydoc/img/outline/module.gif has changed
Binary file doc/candydoc/img/outline/package.gif has changed
Binary file doc/candydoc/img/outline/struct.gif has changed
Binary file doc/candydoc/img/outline/template.gif has changed
Binary file doc/candydoc/img/outline/var.gif has changed
Binary file doc/candydoc/img/package/bg.gif has changed
Binary file doc/candydoc/img/tree/shim.gif has changed
Binary file doc/candydoc/img/tree/tb.gif has changed
Binary file doc/candydoc/img/tree/tbr.gif has changed
Binary file doc/candydoc/img/tree/tbrm.gif has changed
Binary file doc/candydoc/img/tree/tbrp.gif has changed
Binary file doc/candydoc/img/tree/tr.gif has changed
Binary file doc/candydoc/img/tree/trm.gif has changed
Binary file doc/candydoc/img/tree/trp.gif has changed
--- a/doc/candydoc/modules.ddoc	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-MODULES =
-	$(MODULE_FULL ast.Decl)
-	$(MODULE_FULL ast.Expr)
--- a/doc/candydoc/style.css	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/* This file is a part of CanDyDOC fileset.
-   File is written by Victor Nakoryakov and placed into the public domain.
-
-   This file is main CSS file of CanDyDOC. You may adjust some part of
-   parameters to control how result documentation would looks like. See
-   further documentation for details. */
-
-
-
-/* This controls how background would looks like and
-   sets some document-scope defaults. */
-body 
-{
-	/* These parameters control default font. */
-	font-family: Verdana, Arial, Helvetica, sans-serif;
-	font-size: 10pt;
-	color: #666666;
-	
-	/* These control look of background. Note that you have to use
-       fixed background to keep documentation good-looking in
-       IE6 and earlier. Otherwise whole *explorer* will jerk while
-       scrolling. If you do not want to use background at all use
-       some invalid url, e.g. url(foo). */
-	background-color: #e6fcea;
-	background: url(img/bg.gif) fixed;
-	
-	/* Don't touch. Necessary for IE6 and earlier. */
-	height: 100%;	
-}
-
-
-
-/* Style applied to all tables. Actualy there are two: one table is
-   that contains contant and footer with CanDyDOC logo, and others
-   are that contains functions' parameters description. */
-table 
-{
-	font-family: Verdana, Arial, Helvetica, sans-serif;
-	font-size: 10pt;
-	color: #666666;
-	text-align: justify;
-}
-
-
-/* Style used for all hyperlinks. */
-a:link {  color: #009900; text-decoration: none }
-a:visited {  color: #009999; text-decoration: none }
-a:hover {  color: #0033cc; text-decoration: none }
-a:active {  color: #0033cc; text-decoration: none }
-
-/*
-table.matrix 
-{
-	border-left: double 3px #666666;
-	border-right: double 3px #666666;
-	margin-left: 3em;
-}
-*/
-
-/* Style appled to declarations. E.g. 'void foo(int a, float b);' */
-span.decl { font-size: 10pt; font-weight: bold; color: #000000; text-align: left }
-/* Style appled to current declaration's symbol. E.g. 'foo' in 'void foo(int a, float b);' */
-span.currsymbol { font-size: 12pt; color: #009900 }
-/* Style appled to function's parameters. E.g. 'a' and 'b' in 'void foo(int a, float b);' */
-span.funcparam  { font-style: italic; font-weight: normal; color: #331200 }
-
-/* Style for div that actualy contains documenation. */
-#content
-{
-	padding-right: 8px;
-	position: absolute;
-	left: 245px;
-	top: 8px;
-	text-align: justify;
-}
-
-/* Style for table that is inside div considered above. Contains documentaton
-   itself and footer with CanDyDOC logo. */
-table.content
-{
-	margin-bottom: 8px;
-	border-spacing: 0px;
-	border-collapse: collapse;
-	background-color: #ffffff;
-}
-
-/* Style for cell of above considered table that contains documentation itself. */
-#docbody
-{
-	padding: 8px 20px 8px 20px;
-	border: solid 1px #009900;
-}
-
-/* Style for cell that contains CanDyDOC logo. */
-#docfooter
-{
-	height: 16px;
-	background-color: #ddeedd;
-	padding: 0px 8px 0px 8px;
-	border: solid 1px #009900;
-}
-
-/* Style applied to currently active tab of explorer window. */
-span.activetab
-{
-	background-color: #0033cc;
-	border-top: solid 2px #009900;
-	color: #ffffff;
-	font-weight: bold;
-	padding-left: 4px;
-	padding-right: 4px;
-	padding-top: 1px;
-	margin-right: 1px;
-}
-
-/* Style applied to currently inactive tab of explorer window. */
-span.inactivetab
-{
-	background-color: #000066;
-	color: #cccccc;
-	font-weight: normal;
-	padding-left: 4px;
-	padding-right: 4px;
-	padding-top: 0px;
-	margin-right: 1px;
-}
-
-/* Style applied to div that contains tabs of explorer. Note that if
-   you want to change it's position you have to change position of
-   #explorerclient, #content and corresponding values in ie56hack.css */
-#tabarea
-{
-	position: fixed;
-	top: 8px;
-	width: 205px;
-	height: 16px;
-	cursor: default;
-}
-
-
-/* Style applied to div that contains tree in explorer. Note that if
-   you want to change it's position you have to change position of
-   #tabarea, #content and corresponding values in ie56hack.css */
-#explorerclient 
-{
-	position: fixed;
-	top: 24px;
-	bottom: 8px;
-	width: 205px;
-	overflow: auto;
-	background-color: #fcfffc;
-	border: solid 2px #0033cc;
-	padding: 4px;
-	cursor: default;
-	color: Black;
-}
-
-/* Following 3 styles control appearance of marker that appears
-   if you click some entity in outline window. */
-div.markertop	{ border-left: solid 2px #0033cc;}
-div.markermiddle{ border-left: dotted 2px #0033cc;}
-div.markerbottom{ border-left: dotted 2px #66cc66;}
-
-/* Style applied to preformated text used to show examples. */
-pre.d_code
-{
-	border: dotted 1px #9c9;
-	background-color: #eeffee;
-}
\ No newline at end of file
--- a/doc/candydoc/tree.js	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-/* This file is a part of CanDyDOC fileset.
-   File is written by Victor Nakoryakov and placed into the public domain.
-
-   This file is javascript with classes that represents native style tree control. */
-   
-var pmNone = 0;
-var pmPlus = 1;
-var pmMinus = 2;
-
-var hlNone = 0;
-var hlGrey = 1;
-var hlSelected = 2;
-
-function TreeView(hrefMode)
-{
-    this.domEntry = document.createElement("div");
-    this.children = new Array();
-    this.selection = null;
-    this.hrefMode = hrefMode;
-    
-    this.createBranch = function(text, iconSrc)
-    {
-        var root = new TreeNode(text, iconSrc, this.hrefMode);
-        root.owner = this;
-        this.children[ this.children.length ] = root;
-        this.domEntry.appendChild( root.domEntry );
-        return root;
-    }
-    
-    this.branch = function(text)
-    {
-        var ret = null;
-        for (var i = 0; i < this.children.length; ++i)
-            if (this.children[i].textElement.data == text)
-            {
-                ret = this.children[i];
-                break;
-            }
-            
-        return ret;
-    }
-    
-    this.domEntry.style.fontSize = "10px";
-    this.domEntry.style.cursor = "default";
-    this.domEntry.style.whiteSpace = "nowrap";
-}
-
-var idCounter = 0;
-function TreeNode(text, iconSrc, hrefMode)
-{
-    this.id             = idCounter++;
-    this.parentNode     = null;
-    this.children       = new Array();
-    this.domEntry       = document.createElement("div");
-    this.icon           = document.createElement("img");
-    this.textElement    = document.createTextNode(text);
-    this.textSpan       = document.createElement("span");
-    this.lineDiv        = document.createElement("div");
-    this.hierarchyImgs  = new Array();
-    this.onclick        = null;
-    
-    function createIcon()
-    {
-        var img = document.createElement("img");
-        img.style.verticalAlign = "middle";
-        img.style.position = "relative";
-        img.style.top = "-1px";
-        img.width = 16;
-        img.height = 16;
-        return img;
-    }
-    
-    function createHierarchyImage()
-    {
-        var img = createIcon();
-        img.pointsTop = false;
-        img.pointsBottom = false;
-        img.pointsRight = false;
-        img.pmState = pmNone;
-        return img;
-    }
-    
-    function genHierarchyImageSrc(hierarchyImg)
-    {
-        var name = "";
-        if (hierarchyImg.pointsTop)
-            name += "t";
-            
-        if (hierarchyImg.pointsBottom)
-            name += "b";
-            
-        if (hierarchyImg.pointsRight)
-            name += "r";
-            
-        if (hierarchyImg.pmState == pmPlus)
-            name += "p";
-        else if (hierarchyImg.pmState == pmMinus)
-            name += "m";
-        
-        if (name == "")
-            name = "shim";
-        
-        return "candydoc/img/tree/" + name + ".gif";
-    }
-    
-    function setSrc(icon, src)
-    {
-        icon.src = src;
-        // After src change width and height are reseted in IE.
-        // Bug workaround:
-        icon.width = 16;
-        icon.height = 16;
-    }
-    
-    this.createChild = function(text, iconSrc)
-    {
-        var child = new TreeNode(text, iconSrc, this.owner.hrefMode);
-        this.children[ this.children.length ] = child;
-        this.domEntry.appendChild( child.domEntry );
-        child.parentNode = this;
-        child.owner = this.owner;
-        
-        // insert hierarchy images according to deepness level
-        // of created child.
-        
-        if (this.children.length > 1)
-        {
-            // there were already added child before. So copy `level-1`
-            // hierarchy images from it.
-            
-            var prevAddedChild = this.children[ this.children.length - 2 ];
-            
-            for (var i = 0; i < prevAddedChild.hierarchyImgs.length - 1; ++i)
-            {
-                var prevAddedChildImg = prevAddedChild.hierarchyImgs[i];
-                var img = createHierarchyImage();
-                setSrc(img, prevAddedChildImg.src);
-                img.pointsTop = prevAddedChildImg.pointsTop;
-                img.pointsBottom = prevAddedChildImg.pointsBottom;
-                img.pointsRight = prevAddedChildImg.pointsRight;
-                img.pmState = prevAddedChildImg.pmState;
-                
-                child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
-                child.lineDiv.insertBefore(img, child.icon);
-            }
-            
-            // change last hierarchy image of prevAddedChild from |_ to |-
-            var lastHierarchyImg = prevAddedChild.hierarchyImgs[ prevAddedChild.hierarchyImgs.length - 1 ];
-            lastHierarchyImg.pointsBottom = true;
-            setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
-                        
-            // change hierarchy images of prevAddedChild's children on it's last
-            // level to |
-            prevAddedChild.addHierarchyTBLine(prevAddedChild.hierarchyImgs.length - 1);
-        }
-        else
-        {
-            // this is a first child. So copy `level-2`
-            // hierarchy images from parent, i.e. this.
-            
-            for (var i = 0; i < this.hierarchyImgs.length - 1; ++i)
-            {
-                var parentImg = this.hierarchyImgs[i];
-                var img = createHierarchyImage();
-                setSrc(img, parentImg.src);
-                img.pointsTop = parentImg.pointsTop;
-                img.pointsBottom = parentImg.pointsBottom;
-                img.pointsRight = parentImg.pointsRight;
-                img.pmState = parentImg.pmState;
-                
-                child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
-                child.lineDiv.insertBefore(img, child.icon);
-            }
-            
-            if (this.hierarchyImgs.length > 0) // we are not root
-            {
-                // change last hierarchy image of parent (i.e. this): add minus to it
-                var lastHierarchyImg = this.hierarchyImgs[ this.hierarchyImgs.length - 1];
-                lastHierarchyImg.pmState = pmMinus;
-                setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
-                lastHierarchyImg.owner = this;
-                lastHierarchyImg.onclick = new Function("e", "this.owner.processPMClick(e);");
-                
-                // make decision on image on `level-1`. It depends on parent's (ie this)
-                // image on same level.
-                var parentL1HierarchyImg = lastHierarchyImg;
-                var l1HierarchyImg = createHierarchyImage();
-                if (parentL1HierarchyImg.pointsBottom)
-                {
-                    l1HierarchyImg.pointsTop = true;
-                    l1HierarchyImg.pointsBottom = true;
-                }
-                setSrc(l1HierarchyImg, genHierarchyImageSrc(l1HierarchyImg));
-                child.hierarchyImgs[ child.hierarchyImgs.length ] = l1HierarchyImg;
-                child.lineDiv.insertBefore(l1HierarchyImg, child.icon);
-            }
-        }
-        
-        // in any case on last level our child will have icon |_
-        var img = createHierarchyImage();
-        img.pointsTop = true;
-        img.pointsRight = true;
-        setSrc(img, genHierarchyImageSrc(img));
-        
-        child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
-        child.lineDiv.insertBefore(img, child.icon);
-        
-        return child;
-    }
-    
-    this.lastChild = function()
-    {
-        return this.children[ this.children.length - 1 ];
-    }
-    
-    this.child = function(text)
-    {
-        var ret = null;
-        for (var i = 0; i < this.children.length; ++i)
-            if (this.children[i].textElement.data == text)
-            {
-                ret = this.children[i];
-                break;
-            }
-            
-        return ret;
-    }
-    
-    this.addHierarchyTBLine = function(level)
-    {
-        for (var i = 0; i < this.children.length; ++i)
-        {
-            var img = this.children[i].hierarchyImgs[level];
-            img.pointsTop = true;
-            img.pointsBottom = true;
-            setSrc(img, genHierarchyImageSrc(img));
-            this.children[i].addHierarchyTBLine(level);
-        }
-    }
-    
-    this.expand = function()
-    {
-        var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
-        
-        if (img.pmState == pmPlus)
-        {
-            img.pmState = pmMinus;
-            setSrc(img, genHierarchyImageSrc(img));
-            
-            for (var i = 0; i < this.children.length; ++i)
-                this.children[i].domEntry.style.display = "";
-        }
-    }
-    
-    this.collapse = function()
-    {
-        var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
-        
-        if (img.pmState == pmMinus)
-        {
-            img.pmState = pmPlus;
-            setSrc(img, genHierarchyImageSrc(img));
-            
-            for (var i = 0; i < this.children.length; ++i)
-                this.children[i].domEntry.style.display = "none";
-        }
-    }
-    
-    this.toggle = function()
-    {
-        var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
-        if (img.pmState == pmMinus)
-            this.collapse();
-        else
-            this.expand();
-    }
-    
-    this.select = function()
-    {
-        if (this.owner.selection != this)
-        {
-            if (this.owner.selection)
-                this.owner.selection.setHighlight(hlNone);
-                
-            this.owner.selection = this;
-            this.setHighlight(hlSelected);
-        }
-    }
-    
-    this.setHighlight = function(mode)
-    {
-        if (mode == hlNone)
-        {
-            this.textSpan.style.backgroundColor = "";
-            this.textSpan.style.color = "";
-            this.textSpan.style.border = "";
-        }
-        else if (mode == hlGrey)
-        {
-            this.textSpan.style.backgroundColor = "#aaaaaa";
-            this.textSpan.style.color = "";
-            this.textSpan.style.border = "";
-        }
-        else if (mode == hlSelected)
-        {
-            this.textSpan.style.backgroundColor = "3399cc";
-            this.textSpan.style.color = "white";
-            this.textSpan.style.border = "dotted 1px red";
-        }
-    }
-    
-    this.setOnclick = function(proc)
-    {
-        this.onclick = proc;
-    }
-    
-    this.setRef = function(url)
-    {
-        if (this.anchor)
-            this.anchor.href = url;
-    }
-    
-    this.processPMClick = function(e)
-    {
-        this.toggle();
-        
-        // prevent this line selection, stop bubbling
-        if (e)
-            e.stopPropagation(); // Mozilla way
-        if (window.event)
-            window.event.cancelBubble = true; // IE way
-    }
-    
-    this.processOnclick = function()
-    {
-        this.select();
-        if (this.onclick instanceof Function)
-            this.onclick();
-    }
-    
-    ///////////////////////////////////////////////////////////////////////////
-    if (iconSrc)
-        this.icon.src = iconSrc;
-    else
-    {
-        this.icon.width = 0;
-        this.icon.height = 0;
-    }
-    
-    this.icon.style.verticalAlign = "middle";
-    this.icon.style.position = "relative";
-    this.icon.style.top = "-1px";
-    this.icon.style.paddingRight = "2px";
-    
-    if (!hrefMode)
-    {
-        this.textSpan.appendChild( this.textElement );
-    }
-    else
-    {
-        this.anchor = document.createElement("a");
-        this.anchor.appendChild( this.textElement );
-        this.textSpan.appendChild( this.anchor );
-    }
-    
-    this.lineDiv.appendChild( this.icon );
-    this.lineDiv.appendChild( this.textSpan );
-    this.domEntry.appendChild( this.lineDiv );
-    
-    this.lineDiv.owner = this;
-    
-    if (!hrefMode)
-        this.lineDiv.onclick = new Function("this.owner.processOnclick();");
-}
--- a/doc/candydoc/util.js	Mon Aug 11 21:56:21 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/* This file is a part of CanDyDOC fileset.
-   File is written by Victor Nakoryakov and placed into the public domain.
-
-   This file is javascript with cross-browser utility functions. */
-
-function getLeft(elem)
-{
-    var ret = 0;
-	while (elem.offsetParent)
-	{
-		ret += elem.offsetLeft;
-		elem = elem.offsetParent;
-	}
-
-	return ret;
-}
-
-function getTop(elem)
-{
-    var ret = 0;
-	while (elem.offsetParent)
-	{
-		ret += elem.offsetTop;
-		elem = elem.offsetParent;
-	}
-
-	return ret;
-}
-
-function getWindowHeight()
-{
-    var ret = 0;
-    if (typeof(window.innerHeight) == "number")
-        ret = window.innerHeight;
-    else if (document.documentElement && document.documentElement.clientHeight)
-        ret = document.documentElement.clientHeight;
-    else if (document.body && document.body.clientHeight)
-        ret = document.body.clientHeight;
-    
-    return ret;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/CANDYDOC.txt	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,56 @@
+
+CanDyDOC is fileset for creating advanced documentation of programs written
+in D programming language. CanDyDOC adds some eye-candy and advanced navigation
+features to .html documents that are generated by D compiler and known as DDOC.
+Produced result is AJAX web-application that is compatible with all mainstream
+web browsers.
+
+This is a fork of the original candydoc, distributed with DSSS. For more
+information on DSSS and DSSS' fork of candydoc, see
+http://www.dsource.org/projects/dsss/
+
+CanDyDOC includes following files:
+    - candy.ddoc
+        File with DDOC macro definitions. You haven't to touch it.
+
+    - modules.ddoc
+        You should enumerate all modules that would be avaible for navigation
+        here.
+
+    - style.css
+        Cascading style sheet file that defines look of produced documentation.
+        You can leave this file without changes or adjust fonts, colors, etc
+        here. See it for documentation.
+
+    - ie56hack.css
+        CSS file to force Internet Explorer 5/6 browser show documentation
+        as it looks like in standard-compliant browsers.
+
+    - tree.js
+        JavaScript implementing tree control that looks like native one.
+
+    - util.js
+        Common cross-browser routines.
+
+    - explorer.js
+        Heart of every documentation's page. Controls generation, behaviour and
+        navigation of a page.
+
+    - numerous of image files in 'img' folder.
+
+How to use:
+    1) Put 'candydoc' directory in place where documentation will be.
+    2) Modify modules.ddoc file: enumerate all modules that should be avaible
+       for navigation.
+    3) Modify style.css file if you want to change style of documentation. Or
+       leave it unmodified to apply defaul theme.
+    4) Run documentation compilation with candy.ddoc and modules.ddoc specified
+       on command line.
+    5) Enjoy a result :)
+
+Known bugs:
+    - Explorer window doesn't work on Safari browser.
+    - Scroll bar positions are not adjusted after explorer's tab change in Opera
+      browser. So it is posible to see nothing on some tab: solution is to
+      return to a previous tab, scroll it to top and then return back.
+    - Overlapping of some elements when too few horizontal place avaible.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/candy.ddoc	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,51 @@
+DDOC =  
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<meta content="text/javascript" http-equiv="content-script-type">
+<title>$(TITLE)</title>
+<link rel="stylesheet" type="text/css" href="candydoc/style.css">
+<!--[if lt IE 7]><link rel="stylesheet" type="text/css" href="candydoc/ie56hack.css"><![endif]-->
+<script language="JavaScript" src="candydoc/util.js" type="text/javascript"></script>
+<script language="JavaScript" src="candydoc/tree.js" type="text/javascript"></script>
+<script language="JavaScript" src="candydoc/explorer.js" type="text/javascript"></script>
+</head><body>
+<div id="tabarea"></div><div id="explorerclient"></div>
+<div id="content"><script>explorer.initialize("$(TITLE)");</script>
+	<table class="content">
+		<tr><td id="docbody"><h1>$(TITLE)</h1>$(BODY)</td></tr>
+		<tr><td id="docfooter">
+			Page was generated with
+			<img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px">
+			on $(DATETIME)
+		</td></tr>
+	</table>
+</div>
+$(ADD_MODULES)
+</body></html>
+
+
+DDOC_DECL =
+<script>explorer.outline.writeEnabled = true;</script>
+$(DT <span class="decl">$0</span>)
+<script>explorer.outline.writeEnabled = false;</script>
+
+
+DDOC_PSYMBOL =
+<span class="currsymbol">$0</span>
+<script>explorer.outline.addDecl('$0');</script>
+
+
+DDOC_MEMBERS =
+<script>explorer.outline.incSymbolLevel();</script>
+$(DL $0)
+<script>explorer.outline.decSymbolLevel();</script>
+
+
+DDOC_PARAM_ID =
+<td nowrap valign="top" style="padding-right: 8px">$0</td>
+
+               
+DDOC_PARAM =<span class="funcparam">$0</span>
+ADD_MODULES =<script>$(MODULES)</script>
+MODULE =explorer.packageExplorer.addModule("$0");
+MODULE_FULL =explorer.packageExplorer.addModuleFull("$0");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/explorer.js	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,319 @@
+/* This file is a part of CanDyDOC fileset.
+   File is written by Victor Nakoryakov and placed into the public domain.
+
+   This file is javascript with classes that represents explorer window.
+   And things related to navigation. */
+   
+var explorer = new Explorer();
+
+///////////////////////////////////////////////////////////////////////////////
+// Current symbol marker class constructor
+///////////////////////////////////////////////////////////////////////////////
+function Marker()
+{
+    this.top    = document.createElement("div");
+    this.middle = document.createElement("div");
+    this.bottom = document.createElement("div");
+    this.container = document.createElement("div");
+    
+    this.setTo = function(term)
+    {
+        // find definition related to `term`
+        var def = term.nextSibling;
+        while (def && def.nodeName != "DD")
+            def = def.nextSibling;
+            
+        var defHeight = 0;
+        var childrenHeight = 0; // children of current declaration
+        if (def)
+        {
+            defHeight = def.offsetHeight;
+            var child = def.firstChild;
+            
+            // traverse until DL tag, until children definition
+            while (child && child.nodeName != "DL")
+                child = child.nextSibling;
+                
+            if (child)
+                childrenHeight = child.offsetHeight;
+        }
+        
+        this.top.style.height = term.offsetHeight;
+        this.middle.style.height = defHeight - childrenHeight;
+        this.bottom.style.height = childrenHeight;
+        
+        if (childrenHeight == 0)
+            this.bottom.style.display = "none";
+        else
+            this.bottom.style.display = "";
+        
+        this.container.style.left = getLeft(term) - 8;
+        this.container.style.top = getTop(term);
+        this.container.style.display = "";
+    }
+        
+    ///////////////////////////////////////////////////////////////////////////
+    this.container.style.position = "absolute";
+    this.container.style.display = "none";
+    
+    this.top.className = "markertop";
+    this.middle.className = "markermiddle";
+    this.bottom.className = "markerbottom";
+    
+    this.container.appendChild(this.top);
+    this.container.appendChild(this.middle);
+    this.container.appendChild(this.bottom);
+    
+    //document.body.appendChild( this.container );
+    
+    // Workaround bug in IE 5/6. We can not append anything to document body until
+    // full page load.
+    window.marker = this;
+    if (window.addEventListener)
+        window.addEventListener("load", new Function("document.body.appendChild( window.marker.container );"), false);
+    else if (window.attachEvent)
+        window.attachEvent("onload", new Function("document.body.appendChild( window.marker.container );"));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Outline class constructor
+///////////////////////////////////////////////////////////////////////////////
+function Outline()
+{
+    this.tree           = new TreeView();
+    this.mountPoint     = null;    
+    this.writeEnabled   = false;
+    this.marker         = new Marker();        
+    this.classRegExp    = new RegExp;
+    this.structRegExp   = new RegExp;
+    this.enumRegExp     = new RegExp;
+    this.templateRegExp = new RegExp;
+    this.aliasRegExp    = new RegExp;
+    this.funcRegExp     = new RegExp;
+    
+    this.incSymbolLevel = function()
+    {
+        if (this.mountPoint == null)
+            this.mountPoint = this.tree.children[ 0 ];
+        else
+            this.mountPoint = this.mountPoint.lastChild();
+    }
+
+    this.decSymbolLevel = function()
+    {
+        // place icons near items according to extracted below type
+        for (var i = 0; i < this.mountPoint.children.length; ++i)
+        {
+            child = this.mountPoint.children[i];
+            var term = child.termRef;
+            
+            // find first span node
+            var n = term.firstChild;
+            while (n && n.nodeName != "SPAN")
+                n = n.nextSibling;
+            
+            if (!n) // shouldn't happen
+                continue;
+            
+            var iconSrc;
+            if (n.firstChild.nodeName == "#text")
+            {
+                var text = n.firstChild.data; // text before declaration
+                
+                if ( this.classRegExp.test(text) )
+                    iconSrc = "candydoc/img/outline/class.gif";
+                else if ( this.structRegExp.test(text) )
+                    iconSrc = "candydoc/img/outline/struct.gif";
+                else if ( this.enumRegExp.test(text) )
+                    iconSrc = "candydoc/img/outline/enum.gif";
+                else if ( this.templateRegExp.test(text) )
+                    iconSrc = "candydoc/img/outline/template.gif";
+                else if ( this.aliasRegExp.test(text) )
+                    iconSrc = "candydoc/img/outline/alias.gif";
+                else // function or variable? check whether '(' ')' exists on the right
+                {
+                    var np = n.firstChild;
+                    while (np && np.nodeName != "SCRIPT") // find our script "onDecl"
+                        np = np.nextSibling;
+                        
+                    if (np && np.nextSibling && np.nextSibling.nodeName == "#text" &&
+                        this.funcRegExp.test(np.nextSibling.data))
+                    {
+                        iconSrc = "candydoc/img/outline/func.gif";
+                    }
+                    else
+                        iconSrc = "candydoc/img/outline/var.gif";
+                }
+            }
+            else // enum member ?
+                iconSrc = "candydoc/img/outline/var.gif";
+                    
+            child.icon.src = iconSrc;
+            child.icon.width = 16;
+            child.icon.height = 16;
+        }
+        
+        this.mountPoint = this.mountPoint.parentNode;
+    }
+
+    this.addDecl = function(decl)
+    {
+        function getLastLeaf(elem)
+        {
+            if (elem.childNodes.length > 0)
+                return getLastLeaf(elem.lastChild);
+            else
+                return elem;
+        }
+
+        function getCurrentTerm()
+        {
+            var ret = getLastLeaf( document.getElementById("content") );
+            while (ret && ret.nodeName != "DT")
+                ret = ret.parentNode;
+            
+            return ret;
+        }
+        
+        if (this.writeEnabled)
+        {
+            var node = this.mountPoint.createChild(decl);
+            node.termRef = getCurrentTerm();
+            node.setOnclick( new Function("explorer.outline.mark(this.termRef);") );
+        }
+    }
+
+    this.mark = function(term)
+    {
+        this.marker.setTo(term);
+        window.scrollTo(0, getTop(term) - getWindowHeight() / 6);    
+    }
+        
+    
+    this.classRegExp.compile("(.*\b)?class(\b.*)?");
+    this.structRegExp.compile("(.*\b)?struct(\b.*)?");
+    this.enumRegExp.compile("(.*\b)?enum(\b.*)?");
+    this.templateRegExp.compile("(.*\b)?template(\b.*)?");
+    this.aliasRegExp.compile("(.*\b)?alias(\b.*)?");
+    this.funcRegExp.compile(/.*\(.*/);    
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Package explorer class constructor
+///////////////////////////////////////////////////////////////////////////////
+function PackageExplorer()
+{
+    this.tree = new TreeView(true);    
+    
+    this.addModule2 = function(mod, full)
+    {
+        var moduleIco = "candydoc/img/outline/module.gif";
+        var packageIco = "candydoc/img/outline/package.gif";
+
+        var path = mod.split("\.");
+        var node = this.tree.branch(path[0]);
+        if ( !node )
+            node = this.tree.createBranch(path[0], (path.length == 1) ? moduleIco : packageIco);
+        
+        for (var i = 1; i < path.length; ++i)
+        {
+            var prev = node;
+            node = node.child(path[i]);
+            if (!node)
+                node = prev.createChild(path[i], (path.length == i + 1) ? moduleIco : packageIco);
+                
+            if (path.length == i + 1) {
+                if (full)
+                    node.setRef(mod + ".html");
+                else
+                    node.setRef(path[i] + ".html");
+            }
+        }
+    }
+    
+    this.addModuleFull = function(mod)
+    {
+        this.addModule2(mod, true);
+    }
+    
+    this.addModule = function(mod)
+    {
+        this.addModule2(mod, false);
+    }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Explorer class constructor
+///////////////////////////////////////////////////////////////////////////////
+function Explorer()
+{
+    this.outline         = new Outline();
+    this.packageExplorer = new PackageExplorer();
+    this.tabs            = new Array();
+    this.tabCount        = 0;
+    
+    this.initialize = function(moduleName)
+    {
+        this.tabArea = document.getElementById("tabarea");
+        this.clientArea = document.getElementById("explorerclient");
+        
+        // prevent text selection
+        this.tabArea.onmousedown = new Function("return false;");
+        this.tabArea.onclick = new Function("return true;");
+        this.tabArea.onselectstart = new Function("return false;");
+        this.clientArea.onmousedown = new Function("return false;");
+        this.clientArea.onclick = new Function("return true;");
+        this.clientArea.onselectstart = new Function("return false;");
+        
+        this.outline.tree.createBranch( moduleName, "candydoc/img/outline/module.gif" );
+        
+        // create tabs
+        this.createTab("Outline", this.outline.tree.domEntry);
+        this.createTab("Package", this.packageExplorer.tree.domEntry);
+    }
+    
+    this.createTab = function(name, domEntry)
+    {
+        var tab = new Object();
+        this.tabs[name] = tab;
+        this.tabCount++;
+        
+        tab.domEntry = domEntry;
+        tab.labelSpan = document.createElement("span");
+        
+        if (this.tabCount > 1)
+        {
+            tab.labelSpan.className = "inactivetab";
+            tab.domEntry.style.display = "none";
+        }
+        else
+        {
+            tab.labelSpan.className = "activetab";
+            tab.domEntry.style.display = "";
+        }
+        
+        tab.labelSpan.appendChild( document.createTextNode(name) );
+        tab.labelSpan.owner = this;
+        tab.labelSpan.onclick = new Function("this.owner.setSelection('" + name + "');");
+        
+        this.tabArea.appendChild( tab.labelSpan );
+        this.clientArea.appendChild( domEntry );
+    }
+    
+    this.setSelection = function(tabName)
+    {
+        for (name in this.tabs)
+        {
+            this.tabs[name].labelSpan.className = "inactivetab";
+            this.tabs[name].domEntry.style.display = "none";
+        }
+        
+        this.tabs[tabName].labelSpan.className = "activetab";
+        this.tabs[tabName].domEntry.style.display = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/ie56hack.css	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,21 @@
+/* This file is a part of CanDyDOC fileset.
+   File is written by Victor Nakoryakov and placed into the public domain.
+
+   This file is CSS to work around IE6 and earlier bugs. It's included just
+   in these browsers. */
+
+
+/* Some magic to emulate unsupported "position: fixed" style. */
+#tabarea
+{
+	_position: absolute;
+	_top: expression(eval(document.body.scrollTop+8));
+}
+
+/* ditto */
+#explorerclient 
+{
+	_position: absolute;
+	_top: expression(eval(document.body.scrollTop+24));
+	_height: expression(eval(document.body.clientHeight-48));
+}
Binary file docs/candydoc/img/bg.gif has changed
Binary file docs/candydoc/img/candydoc.gif has changed
Binary file docs/candydoc/img/outline/alias.gif has changed
Binary file docs/candydoc/img/outline/bg.gif has changed
Binary file docs/candydoc/img/outline/class.gif has changed
Binary file docs/candydoc/img/outline/enum.gif has changed
Binary file docs/candydoc/img/outline/func.gif has changed
Binary file docs/candydoc/img/outline/module.gif has changed
Binary file docs/candydoc/img/outline/package.gif has changed
Binary file docs/candydoc/img/outline/struct.gif has changed
Binary file docs/candydoc/img/outline/template.gif has changed
Binary file docs/candydoc/img/outline/var.gif has changed
Binary file docs/candydoc/img/package/bg.gif has changed
Binary file docs/candydoc/img/tree/shim.gif has changed
Binary file docs/candydoc/img/tree/tb.gif has changed
Binary file docs/candydoc/img/tree/tbr.gif has changed
Binary file docs/candydoc/img/tree/tbrm.gif has changed
Binary file docs/candydoc/img/tree/tbrp.gif has changed
Binary file docs/candydoc/img/tree/tr.gif has changed
Binary file docs/candydoc/img/tree/trm.gif has changed
Binary file docs/candydoc/img/tree/trp.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/modules.ddoc	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,14 @@
+MODULES =
+	$(MODULE_FULL parser.Action)
+	$(MODULE_FULL parser.Parser)
+	$(MODULE_FULL ast.Decl)
+	$(MODULE_FULL ast.Stmt)
+	$(MODULE_FULL ast.Expr)
+	$(MODULE_FULL lexer.Keyword)
+	$(MODULE_FULL lexer.Lexer)
+	$(MODULE_FULL lexer.Token)
+	$(MODULE_FULL basic.SmallArray)
+	$(MODULE_FULL basic.Message)
+	$(MODULE_FULL basic.SourceLocation)
+	$(MODULE_FULL basic.Messages)
+	$(MODULE_FULL basic.SourceManager)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/style.css	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,169 @@
+/* This file is a part of CanDyDOC fileset.
+   File is written by Victor Nakoryakov and placed into the public domain.
+
+   This file is main CSS file of CanDyDOC. You may adjust some part of
+   parameters to control how result documentation would looks like. See
+   further documentation for details. */
+
+
+
+/* This controls how background would looks like and
+   sets some document-scope defaults. */
+body 
+{
+	/* These parameters control default font. */
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 10pt;
+	color: #666666;
+	
+	/* These control look of background. Note that you have to use
+       fixed background to keep documentation good-looking in
+       IE6 and earlier. Otherwise whole *explorer* will jerk while
+       scrolling. If you do not want to use background at all use
+       some invalid url, e.g. url(foo). */
+	background-color: #e6fcea;
+	background: url(img/bg.gif) fixed;
+	
+	/* Don't touch. Necessary for IE6 and earlier. */
+	height: 100%;	
+}
+
+
+
+/* Style applied to all tables. Actualy there are two: one table is
+   that contains contant and footer with CanDyDOC logo, and others
+   are that contains functions' parameters description. */
+table 
+{
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 10pt;
+	color: #666666;
+	text-align: justify;
+}
+
+
+/* Style used for all hyperlinks. */
+a:link {  color: #009900; text-decoration: none }
+a:visited {  color: #009999; text-decoration: none }
+a:hover {  color: #0033cc; text-decoration: none }
+a:active {  color: #0033cc; text-decoration: none }
+
+/*
+table.matrix 
+{
+	border-left: double 3px #666666;
+	border-right: double 3px #666666;
+	margin-left: 3em;
+}
+*/
+
+/* Style appled to declarations. E.g. 'void foo(int a, float b);' */
+span.decl { font-size: 10pt; font-weight: bold; color: #000000; text-align: left }
+/* Style appled to current declaration's symbol. E.g. 'foo' in 'void foo(int a, float b);' */
+span.currsymbol { font-size: 12pt; color: #009900 }
+/* Style appled to function's parameters. E.g. 'a' and 'b' in 'void foo(int a, float b);' */
+span.funcparam  { font-style: italic; font-weight: normal; color: #331200 }
+
+/* Style for div that actualy contains documenation. */
+#content
+{
+	padding-right: 8px;
+	position: absolute;
+	left: 245px;
+	top: 8px;
+	text-align: justify;
+}
+
+/* Style for table that is inside div considered above. Contains documentaton
+   itself and footer with CanDyDOC logo. */
+table.content
+{
+	margin-bottom: 8px;
+	border-spacing: 0px;
+	border-collapse: collapse;
+	background-color: #ffffff;
+}
+
+/* Style for cell of above considered table that contains documentation itself. */
+#docbody
+{
+	padding: 8px 20px 8px 20px;
+	border: solid 1px #009900;
+}
+
+/* Style for cell that contains CanDyDOC logo. */
+#docfooter
+{
+	height: 16px;
+	background-color: #ddeedd;
+	padding: 0px 8px 0px 8px;
+	border: solid 1px #009900;
+}
+
+/* Style applied to currently active tab of explorer window. */
+span.activetab
+{
+	background-color: #0033cc;
+	border-top: solid 2px #009900;
+	color: #ffffff;
+	font-weight: bold;
+	padding-left: 4px;
+	padding-right: 4px;
+	padding-top: 1px;
+	margin-right: 1px;
+}
+
+/* Style applied to currently inactive tab of explorer window. */
+span.inactivetab
+{
+	background-color: #000066;
+	color: #cccccc;
+	font-weight: normal;
+	padding-left: 4px;
+	padding-right: 4px;
+	padding-top: 0px;
+	margin-right: 1px;
+}
+
+/* Style applied to div that contains tabs of explorer. Note that if
+   you want to change it's position you have to change position of
+   #explorerclient, #content and corresponding values in ie56hack.css */
+#tabarea
+{
+	position: fixed;
+	top: 8px;
+	width: 205px;
+	height: 16px;
+	cursor: default;
+}
+
+
+/* Style applied to div that contains tree in explorer. Note that if
+   you want to change it's position you have to change position of
+   #tabarea, #content and corresponding values in ie56hack.css */
+#explorerclient 
+{
+	position: fixed;
+	top: 24px;
+	bottom: 8px;
+	width: 205px;
+	overflow: auto;
+	background-color: #fcfffc;
+	border: solid 2px #0033cc;
+	padding: 4px;
+	cursor: default;
+	color: Black;
+}
+
+/* Following 3 styles control appearance of marker that appears
+   if you click some entity in outline window. */
+div.markertop	{ border-left: solid 2px #0033cc;}
+div.markermiddle{ border-left: dotted 2px #0033cc;}
+div.markerbottom{ border-left: dotted 2px #66cc66;}
+
+/* Style applied to preformated text used to show examples. */
+pre.d_code
+{
+	border: dotted 1px #9c9;
+	background-color: #eeffee;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/tree.js	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,374 @@
+/* This file is a part of CanDyDOC fileset.
+   File is written by Victor Nakoryakov and placed into the public domain.
+
+   This file is javascript with classes that represents native style tree control. */
+   
+var pmNone = 0;
+var pmPlus = 1;
+var pmMinus = 2;
+
+var hlNone = 0;
+var hlGrey = 1;
+var hlSelected = 2;
+
+function TreeView(hrefMode)
+{
+    this.domEntry = document.createElement("div");
+    this.children = new Array();
+    this.selection = null;
+    this.hrefMode = hrefMode;
+    
+    this.createBranch = function(text, iconSrc)
+    {
+        var root = new TreeNode(text, iconSrc, this.hrefMode);
+        root.owner = this;
+        this.children[ this.children.length ] = root;
+        this.domEntry.appendChild( root.domEntry );
+        return root;
+    }
+    
+    this.branch = function(text)
+    {
+        var ret = null;
+        for (var i = 0; i < this.children.length; ++i)
+            if (this.children[i].textElement.data == text)
+            {
+                ret = this.children[i];
+                break;
+            }
+            
+        return ret;
+    }
+    
+    this.domEntry.style.fontSize = "10px";
+    this.domEntry.style.cursor = "default";
+    this.domEntry.style.whiteSpace = "nowrap";
+}
+
+var idCounter = 0;
+function TreeNode(text, iconSrc, hrefMode)
+{
+    this.id             = idCounter++;
+    this.parentNode     = null;
+    this.children       = new Array();
+    this.domEntry       = document.createElement("div");
+    this.icon           = document.createElement("img");
+    this.textElement    = document.createTextNode(text);
+    this.textSpan       = document.createElement("span");
+    this.lineDiv        = document.createElement("div");
+    this.hierarchyImgs  = new Array();
+    this.onclick        = null;
+    
+    function createIcon()
+    {
+        var img = document.createElement("img");
+        img.style.verticalAlign = "middle";
+        img.style.position = "relative";
+        img.style.top = "-1px";
+        img.width = 16;
+        img.height = 16;
+        return img;
+    }
+    
+    function createHierarchyImage()
+    {
+        var img = createIcon();
+        img.pointsTop = false;
+        img.pointsBottom = false;
+        img.pointsRight = false;
+        img.pmState = pmNone;
+        return img;
+    }
+    
+    function genHierarchyImageSrc(hierarchyImg)
+    {
+        var name = "";
+        if (hierarchyImg.pointsTop)
+            name += "t";
+            
+        if (hierarchyImg.pointsBottom)
+            name += "b";
+            
+        if (hierarchyImg.pointsRight)
+            name += "r";
+            
+        if (hierarchyImg.pmState == pmPlus)
+            name += "p";
+        else if (hierarchyImg.pmState == pmMinus)
+            name += "m";
+        
+        if (name == "")
+            name = "shim";
+        
+        return "candydoc/img/tree/" + name + ".gif";
+    }
+    
+    function setSrc(icon, src)
+    {
+        icon.src = src;
+        // After src change width and height are reseted in IE.
+        // Bug workaround:
+        icon.width = 16;
+        icon.height = 16;
+    }
+    
+    this.createChild = function(text, iconSrc)
+    {
+        var child = new TreeNode(text, iconSrc, this.owner.hrefMode);
+        this.children[ this.children.length ] = child;
+        this.domEntry.appendChild( child.domEntry );
+        child.parentNode = this;
+        child.owner = this.owner;
+        
+        // insert hierarchy images according to deepness level
+        // of created child.
+        
+        if (this.children.length > 1)
+        {
+            // there were already added child before. So copy `level-1`
+            // hierarchy images from it.
+            
+            var prevAddedChild = this.children[ this.children.length - 2 ];
+            
+            for (var i = 0; i < prevAddedChild.hierarchyImgs.length - 1; ++i)
+            {
+                var prevAddedChildImg = prevAddedChild.hierarchyImgs[i];
+                var img = createHierarchyImage();
+                setSrc(img, prevAddedChildImg.src);
+                img.pointsTop = prevAddedChildImg.pointsTop;
+                img.pointsBottom = prevAddedChildImg.pointsBottom;
+                img.pointsRight = prevAddedChildImg.pointsRight;
+                img.pmState = prevAddedChildImg.pmState;
+                
+                child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
+                child.lineDiv.insertBefore(img, child.icon);
+            }
+            
+            // change last hierarchy image of prevAddedChild from |_ to |-
+            var lastHierarchyImg = prevAddedChild.hierarchyImgs[ prevAddedChild.hierarchyImgs.length - 1 ];
+            lastHierarchyImg.pointsBottom = true;
+            setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
+                        
+            // change hierarchy images of prevAddedChild's children on it's last
+            // level to |
+            prevAddedChild.addHierarchyTBLine(prevAddedChild.hierarchyImgs.length - 1);
+        }
+        else
+        {
+            // this is a first child. So copy `level-2`
+            // hierarchy images from parent, i.e. this.
+            
+            for (var i = 0; i < this.hierarchyImgs.length - 1; ++i)
+            {
+                var parentImg = this.hierarchyImgs[i];
+                var img = createHierarchyImage();
+                setSrc(img, parentImg.src);
+                img.pointsTop = parentImg.pointsTop;
+                img.pointsBottom = parentImg.pointsBottom;
+                img.pointsRight = parentImg.pointsRight;
+                img.pmState = parentImg.pmState;
+                
+                child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
+                child.lineDiv.insertBefore(img, child.icon);
+            }
+            
+            if (this.hierarchyImgs.length > 0) // we are not root
+            {
+                // change last hierarchy image of parent (i.e. this): add minus to it
+                var lastHierarchyImg = this.hierarchyImgs[ this.hierarchyImgs.length - 1];
+                lastHierarchyImg.pmState = pmMinus;
+                setSrc(lastHierarchyImg, genHierarchyImageSrc(lastHierarchyImg));
+                lastHierarchyImg.owner = this;
+                lastHierarchyImg.onclick = new Function("e", "this.owner.processPMClick(e);");
+                
+                // make decision on image on `level-1`. It depends on parent's (ie this)
+                // image on same level.
+                var parentL1HierarchyImg = lastHierarchyImg;
+                var l1HierarchyImg = createHierarchyImage();
+                if (parentL1HierarchyImg.pointsBottom)
+                {
+                    l1HierarchyImg.pointsTop = true;
+                    l1HierarchyImg.pointsBottom = true;
+                }
+                setSrc(l1HierarchyImg, genHierarchyImageSrc(l1HierarchyImg));
+                child.hierarchyImgs[ child.hierarchyImgs.length ] = l1HierarchyImg;
+                child.lineDiv.insertBefore(l1HierarchyImg, child.icon);
+            }
+        }
+        
+        // in any case on last level our child will have icon |_
+        var img = createHierarchyImage();
+        img.pointsTop = true;
+        img.pointsRight = true;
+        setSrc(img, genHierarchyImageSrc(img));
+        
+        child.hierarchyImgs[ child.hierarchyImgs.length ] = img;
+        child.lineDiv.insertBefore(img, child.icon);
+        
+        return child;
+    }
+    
+    this.lastChild = function()
+    {
+        return this.children[ this.children.length - 1 ];
+    }
+    
+    this.child = function(text)
+    {
+        var ret = null;
+        for (var i = 0; i < this.children.length; ++i)
+            if (this.children[i].textElement.data == text)
+            {
+                ret = this.children[i];
+                break;
+            }
+            
+        return ret;
+    }
+    
+    this.addHierarchyTBLine = function(level)
+    {
+        for (var i = 0; i < this.children.length; ++i)
+        {
+            var img = this.children[i].hierarchyImgs[level];
+            img.pointsTop = true;
+            img.pointsBottom = true;
+            setSrc(img, genHierarchyImageSrc(img));
+            this.children[i].addHierarchyTBLine(level);
+        }
+    }
+    
+    this.expand = function()
+    {
+        var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
+        
+        if (img.pmState == pmPlus)
+        {
+            img.pmState = pmMinus;
+            setSrc(img, genHierarchyImageSrc(img));
+            
+            for (var i = 0; i < this.children.length; ++i)
+                this.children[i].domEntry.style.display = "";
+        }
+    }
+    
+    this.collapse = function()
+    {
+        var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
+        
+        if (img.pmState == pmMinus)
+        {
+            img.pmState = pmPlus;
+            setSrc(img, genHierarchyImageSrc(img));
+            
+            for (var i = 0; i < this.children.length; ++i)
+                this.children[i].domEntry.style.display = "none";
+        }
+    }
+    
+    this.toggle = function()
+    {
+        var img = this.hierarchyImgs[ this.hierarchyImgs.length - 1 ];
+        if (img.pmState == pmMinus)
+            this.collapse();
+        else
+            this.expand();
+    }
+    
+    this.select = function()
+    {
+        if (this.owner.selection != this)
+        {
+            if (this.owner.selection)
+                this.owner.selection.setHighlight(hlNone);
+                
+            this.owner.selection = this;
+            this.setHighlight(hlSelected);
+        }
+    }
+    
+    this.setHighlight = function(mode)
+    {
+        if (mode == hlNone)
+        {
+            this.textSpan.style.backgroundColor = "";
+            this.textSpan.style.color = "";
+            this.textSpan.style.border = "";
+        }
+        else if (mode == hlGrey)
+        {
+            this.textSpan.style.backgroundColor = "#aaaaaa";
+            this.textSpan.style.color = "";
+            this.textSpan.style.border = "";
+        }
+        else if (mode == hlSelected)
+        {
+            this.textSpan.style.backgroundColor = "3399cc";
+            this.textSpan.style.color = "white";
+            this.textSpan.style.border = "dotted 1px red";
+        }
+    }
+    
+    this.setOnclick = function(proc)
+    {
+        this.onclick = proc;
+    }
+    
+    this.setRef = function(url)
+    {
+        if (this.anchor)
+            this.anchor.href = url;
+    }
+    
+    this.processPMClick = function(e)
+    {
+        this.toggle();
+        
+        // prevent this line selection, stop bubbling
+        if (e)
+            e.stopPropagation(); // Mozilla way
+        if (window.event)
+            window.event.cancelBubble = true; // IE way
+    }
+    
+    this.processOnclick = function()
+    {
+        this.select();
+        if (this.onclick instanceof Function)
+            this.onclick();
+    }
+    
+    ///////////////////////////////////////////////////////////////////////////
+    if (iconSrc)
+        this.icon.src = iconSrc;
+    else
+    {
+        this.icon.width = 0;
+        this.icon.height = 0;
+    }
+    
+    this.icon.style.verticalAlign = "middle";
+    this.icon.style.position = "relative";
+    this.icon.style.top = "-1px";
+    this.icon.style.paddingRight = "2px";
+    
+    if (!hrefMode)
+    {
+        this.textSpan.appendChild( this.textElement );
+    }
+    else
+    {
+        this.anchor = document.createElement("a");
+        this.anchor.appendChild( this.textElement );
+        this.textSpan.appendChild( this.anchor );
+    }
+    
+    this.lineDiv.appendChild( this.icon );
+    this.lineDiv.appendChild( this.textSpan );
+    this.domEntry.appendChild( this.lineDiv );
+    
+    this.lineDiv.owner = this;
+    
+    if (!hrefMode)
+        this.lineDiv.onclick = new Function("this.owner.processOnclick();");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/candydoc/util.js	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,41 @@
+/* This file is a part of CanDyDOC fileset.
+   File is written by Victor Nakoryakov and placed into the public domain.
+
+   This file is javascript with cross-browser utility functions. */
+
+function getLeft(elem)
+{
+    var ret = 0;
+	while (elem.offsetParent)
+	{
+		ret += elem.offsetLeft;
+		elem = elem.offsetParent;
+	}
+
+	return ret;
+}
+
+function getTop(elem)
+{
+    var ret = 0;
+	while (elem.offsetParent)
+	{
+		ret += elem.offsetTop;
+		elem = elem.offsetParent;
+	}
+
+	return ret;
+}
+
+function getWindowHeight()
+{
+    var ret = 0;
+    if (typeof(window.innerHeight) == "number")
+        ret = window.innerHeight;
+    else if (document.documentElement && document.documentElement.clientHeight)
+        ret = document.documentElement.clientHeight;
+    else if (document.body && document.body.clientHeight)
+        ret = document.body.clientHeight;
+    
+    return ret;
+}
--- a/dsss.conf	Mon Aug 11 21:56:21 2008 +0200
+++ b/dsss.conf	Tue Aug 12 18:14:56 2008 +0200
@@ -1,6 +1,4 @@
 
-[ast]
-buildflags = -version=Tango -candydoc -Dqdoc -I.
+[src]
+buildflags = -version=Tango -candydoc -Dqdocs -I./src
 
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ast/Decl.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,137 @@
+module ast.Decl;
+
+import ast.Expr;
+
+/**
+  The base class for all Declarations. 
+  
+  Declarations comes in two forms:
+
+    $(OL
+    $(LI members, such as variables and functions.)
+    $(LI types, such as classes, structs.))
+
+  */
+class Decl
+{
+
+    /// Method for doing cast(FunctionDecl)
+    FunctionDecl asFunctionDecl() { return null;}
+
+    /// Returns true if it is a FunctionDecl
+    bool isFunctionDecl() { return false;}
+
+    /// Method for doing cast(VarDecl)
+    VarDecl asVarDecl() { return null;}
+
+    /// Returns true if it is a VarDecl
+    bool isVarDecl() { return false;}
+
+    /// Method for doing cast(StructDecl)
+    StructDecl asStructDecl() { return null;}
+
+    /// Returns true if it is a StructDecl
+    bool isStructDecl() { return false;}
+
+    /// Method for doing cast(ClassDecl)
+    ClassDecl asClassDecl() { return null;}
+
+    /// Returns true if it is a ClassDecl
+    bool isClassDecl() { return false;}
+
+    /// Method for doing cast(InterfaceDecl)
+    InterfaceDecl asInterfaceDecl() { return null;}
+
+    /// Returns true if it is a InterfaceDecl
+    bool isInterfaceDecl() { return false;}
+
+    /// Method for doing cast(TypedefDecl)
+    TypedefDecl asTypedefDecl() { return null;}
+
+    /// Returns true if it is a TypedefDecl
+    bool isTypedefDecl() { return false;}
+}
+
+/**
+  The FunctionDecl contains a set of VarDecls, being the parameters of the
+  method. It also contains a potentiel list of statements.
+  */
+class FunctionDecl : Decl
+{
+    /// Returns the parameters of the method.
+    VarDecl[] getParams() { return params;}
+    /// Return the parameter on a given index.
+    VarDecl getParam(int index) { return params[index];}
+    /// Returns the number of parameters.
+    int getNumberOfParamst() { return params.length;}
+    /**
+      Returns the number of required arguments, that should be given to
+      call this method.
+      */
+    int getMinimumNumberOfParams() 
+    { 
+        assert(0, "Unimplemented");
+        return 0;
+    }
+
+    override FunctionDecl asFunctionDecl() { return this;}
+    override bool isFunctionDecl() { return true;}
+
+private:
+    VarDecl[] params;
+}
+
+/**
+  The VarDecl contains as a minimum a Type. As an addition, i will also
+  in most cases contain an Identifier that it'll be reconized by and in
+  some cases it will also contain an expression that'll be it initializer.
+
+  Some cases to check:
+
+  $(UL
+      $(LI
+          If the VarDecl is a param in a FunctionDecl the initializer, if
+          present, should be a constant expression(Enum, Number, String 
+          or the like).
+        )
+    )
+  */
+class VarDecl : Decl
+{
+    /// Return true if the VarDecl has an identifier/name.
+    bool hasIdentifier() { return !(identifier is null);}
+    /// Return true if the VarDecl has en initializer.
+    bool hasInitializer() { return !(initializer is null);}
+
+    override VarDecl asVarDecl() { return this;}
+    override bool isVarDecl() { return true;}
+    
+private:
+    Identifier identifier;
+    Expr initializer;
+}
+
+class StructDecl : Decl
+{
+    override StructDecl asStructDecl() { return this;}
+    override bool isStructDecl() { return true;}
+}
+
+class ClassDecl : Decl
+{
+    override ClassDecl asClassDecl() { return this;}
+    override bool isClassDecl() { return true;}
+}
+
+class InterfaceDecl : Decl
+{
+    override InterfaceDecl asInterfaceDecl() { return this;}
+    override bool isInterfaceDecl() { return true;}
+}
+
+class TypedefDecl : Decl
+{
+    override TypedefDecl asTypedefDecl() { return this;}
+    override bool isTypedefDecl() { return true;}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ast/Expr.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,203 @@
+module ast.Expr;
+
+/**
+  The base class for all Expressions.
+  */
+class Expr
+{
+    /// Get the type of the Expr
+    Object getType() 
+    {
+        assert(0, "Unimplemented");
+        return null;
+    }
+
+    /// Set the type of the Expr
+    void setType(Object type) 
+    {
+        assert(0, "Unimplemented");
+    }
+
+    /// Returns true if the Expr can be compile-time evaluated.
+    bool isConstantExpr() { return false; }
+
+    NumberLiteral asNumberLiteral() { return null; }
+    bool isNumberLiteral() { return false; }
+
+    StringLiteral asStringLiteral() { return null; }
+    bool isStringLiteral() { return false; }
+
+    ArrayLiteral asArrayLiteral() { return null; }
+    bool isArrayLiteral() { return false; }
+
+    Assign asAssign() { return null; }
+    bool isAssign() { return false; }
+
+    Binary asBinary() { return null; }
+    bool isBinary() { return false; }
+
+    Negate asNegate() { return null; }
+    bool isNegate() { return false; }
+
+    Deref asDeref() { return null; }
+    bool isDeref() { return false; }
+
+    AddressOf asAddressOf() { return null; }
+    bool isAddressOf() { return false; }
+
+    Index asIndex() { return null; }
+    bool isIndex() { return false; }
+
+    Identifier asIdentifier() { return null; }
+    bool isIdentifier() { return false; }
+
+    Member asMember() { return null; }
+    bool isMember() { return false; }
+
+private:
+/// FIXME: Add DType? here
+}
+
+/**
+  NumberLiteral
+  */
+/// FIXME: Should there be an IntegerLiteral and FloatLiteral instead?
+class NumberLiteral : Expr
+{
+    override bool isConstantExpr() { return true; }
+
+    override NumberLiteral asNumberLiteral() { return this; }
+    override bool isNumberLiteral() { return true; }
+}
+
+/**
+  StringLiteral
+  */
+class StringLiteral : Expr
+{
+    override bool isConstantExpr() { return true; }
+
+    override StringLiteral asStringLiteral() { return this; }
+    override bool isStringLiteral() { return true; }
+}
+
+/**
+  ArrayLiteral
+  */
+class ArrayLiteral : Expr
+{
+    /// Return the arguments for the ArrayLiteral
+    Expr[] getArguments() { return arguments; }
+
+    /// Return a given argument for the ArrayLiteral
+    Expr getArgument(int index) { return arguments[index]; }
+
+    /// Get the count of arguments for the ArrayLiteral
+    int getArgumentCount() { return arguments.length; }
+
+    override bool isConstantExpr() 
+    {
+        /**
+          If all the arguments to the ArrayLiteral is an constant Expr, then
+          this ArrayLiteral can be considered an constant Expr aswell.
+          */
+        // FIXME: consider if it should save the result
+        foreach (arg; arguments)
+            if (!arg.isConstantExpr())
+                return false;
+        return true; 
+    }
+
+    override ArrayLiteral asArrayLiteral() { return this; }
+    override bool isArrayLiteral() { return true; }
+
+private:
+    Expr[] arguments;
+}
+
+/**
+  The Assign expression contains two expression, a left and a right side, 
+  left being a lvalue, right being a rvalue. 
+
+  If the right side ain't the same type as the left type, the right side will
+  try to be promoted through an implicit cast. If this failes, an error must
+  be given.
+  */
+class Assign : Expr
+{
+    override Assign asAssign() { return this; }
+    override bool isAssign() { return true; }
+
+private:
+    Expr left, right;
+}
+
+/**
+  Binary
+  */
+class Binary : Expr
+{
+    override Binary asBinary() { return this; }
+    override bool isBinary() { return true; }
+
+private:
+    Expr left, right;
+}
+
+/**
+  Negate
+  */
+class Negate : Expr
+{
+    override Negate asNegate() { return this; }
+    override bool isNegate() { return true; }
+
+private:
+    Expr expr;
+}
+
+/**
+  Deref
+  */
+class Deref : Expr
+{
+    override Deref asDeref() { return this; }
+    override bool isDeref() { return true; }
+}
+
+/**
+  AddressOf
+  */
+class AddressOf : Expr
+{
+    override AddressOf asAddressOf() { return this; }
+    override bool isAddressOf() { return true; }
+}
+
+/**
+  Index
+  */
+class Index : Expr
+{
+    override Index asIndex() { return this; }
+    override bool isIndex() { return true; }
+}
+
+/**
+  Identifier
+  */
+class Identifier : Expr
+{
+    override Identifier asIdentifier() { return this; }
+    override bool isIdentifier() { return true; }
+}
+
+/**
+  Member
+  */
+class Member : Expr
+{
+    override Member asMember() { return this; }
+    override bool isMember() { return true; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ast/Stmt.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,127 @@
+module ast.Stmt;
+
+/**
+  The base class for all Statements.
+  */
+class Stmt
+{
+    bool isCompoundStmt() { return false; }
+    CompoundStmt asCompoundStmt() { return null; }
+
+    bool isDeclStmt() { return false; }
+    DeclStmt asDeclStmt() { return null; }
+
+    bool isExpStmt() { return false; }
+    ExpStmt asExpStmt() { return null; }
+
+    bool isReturnStmt() { return false; }
+    ReturnStmt asReturnStmt() { return null; }
+
+    bool isIfStmt() { return false; }
+    IfStmt asIfStmt() { return null; }
+
+    bool isWhileStmt() { return false; }
+    WhileStmt asWhileStmt() { return null; }
+
+    bool isForStmt() { return false; }
+    ForStmt asForStmt() { return null; }
+
+    bool isSwitchStmt() { return false; }
+    SwitchStmt asSwitchStmt() { return null; }
+
+    bool isForeachStmt() { return false; }
+    ForeachStmt asForeachStmt() { return null; }
+
+    bool isAssertStmt() { return false; }
+    AssertStmt asAssertStmt() { return null; }
+}
+
+/**
+  CompoundStmt
+  */
+class CompoundStmt : Stmt
+{
+    override bool isCompoundStmt() { return true; }
+    override CompoundStmt asCompoundStmt() { return this; }
+}
+
+/**
+  DeclStmt
+  */
+class DeclStmt : Stmt
+{
+    override bool isDeclStmt() { return true; }
+    override DeclStmt asDeclStmt() { return this; }
+}
+
+/**
+  ExpStmt
+  */
+class ExpStmt : Stmt
+{
+    override bool isExpStmt() { return true; }
+    override ExpStmt asExpStmt() { return this; }
+}
+
+/**
+  ReturnStmt
+  */
+class ReturnStmt : Stmt
+{
+    override bool isReturnStmt() { return true; }
+    override ReturnStmt asReturnStmt() { return this; }
+}
+
+/**
+  IfStmt
+  */
+class IfStmt : Stmt
+{
+    override bool isIfStmt() { return true; }
+    override IfStmt asIfStmt() { return this; }
+}
+
+/**
+  WhileStmt
+  */
+class WhileStmt : Stmt
+{
+    override bool isWhileStmt() { return true; }
+    override WhileStmt asWhileStmt() { return this; }
+}
+
+/**
+  ForStmt
+  */
+class ForStmt : Stmt
+{
+    override bool isForStmt() { return true; }
+    override ForStmt asForStmt() { return this; }
+}
+
+/**
+  SwitchStmt
+  */
+class SwitchStmt : Stmt
+{
+    override bool isSwitchStmt() { return true; }
+    override SwitchStmt asSwitchStmt() { return this; }
+}
+
+/**
+  ForeachStmt
+  */
+class ForeachStmt : Stmt
+{
+    override bool isForeachStmt() { return true; }
+    override ForeachStmt asForeachStmt() { return this; }
+}
+
+/**
+  AssertStmt
+  */
+class AssertStmt : Stmt
+{
+    override bool isAssertStmt() { return true; }
+    override AssertStmt asAssertStmt() { return this; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/basic/Message.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,163 @@
+module basic.Message;
+
+import tango.core.Exception,
+       Array = tango.core.Array,
+       tango.io.Stdout,
+       tango.text.Util;
+
+import tango.stdc.stdlib;
+
+import llvm.type;
+
+import lexer.Token,
+       lexer.Lexer;
+
+import basic.SourceLocation,
+       basic.SourceManager;
+
+public import basic.Messages;
+
+enum ExitLevel
+{
+    Normal = 1,
+    Lexer = 2,
+    Parser = 3,
+    Semantic = 3,
+}
+
+class MessageHandler
+{
+public:
+
+    this(SourceManager src_mgr)
+    {
+        this.src_mgr = src_mgr;
+    }
+
+    Message report(uint opcode, SLoc location)
+    {
+        Message m = new Message(opcode, location, src_mgr, this);
+        messages ~= m;
+        return m;
+    }
+
+    void checkErrors(ExitLevel exitlevel = ExitLevel.Normal)
+    {
+        if(messages.length == 0)
+            return;
+
+        if(warnings)
+            checkWarnings;
+        foreach(m ; messages)
+            if(m.type == MessageType.Error)
+            {
+                Stdout(m).newline;
+            }
+
+        exit(exitlevel);
+    }
+
+    void checkWarnings()
+    {
+        foreach(m ; messages)
+            if(m.type == MessageType.Warning)
+            {
+                Stdout(m).newline;
+            }
+    }
+
+    void showWarnings(bool value)
+    {
+        warnings = value;
+    }
+
+private:
+    Message[] messages;
+    SourceManager src_mgr;
+    bool warnings;
+}
+
+class Message
+{
+
+    this(int opcode, SLoc location, SourceManager src_mgr, MessageHandler msg_handler)
+    {
+        this.src_mgr = src_mgr;
+        this.location = location;
+        args ~= Messages[opcode].message;
+        this.type = Messages[opcode].type;
+        this.msg_handler = msg_handler;
+    }
+
+    char[] toString()
+    {
+        char[256] tmp = void;
+        char[] msg = layout(tmp, args);
+
+        Lexer l = new Lexer(location, src_mgr, new MessageHandler(src_mgr));
+
+        Token t = l.next;
+        
+        if (src_mgr.getRawData(location).length > 0)
+            msg = src_mgr.getLocationAsString(location) ~ ": " ~ msg;
+        else
+            msg = msg.dup;
+
+
+        char[] line = src_mgr.getLine(location);
+        char[] marks = line.dup;
+        marks[] = ' ';
+        size_t p = src_mgr.getColumn(location);
+        marks[p .. p + t.length] = '^';
+
+        msg ~= "\n    ";
+        msg ~= line;
+        msg ~= "\n    ";
+        msg ~= marks;
+
+        return msg;
+    }
+
+    Message arg(char[] s)
+    {
+        if (args.length == 11)
+            throw new Exception("Sorry, errors only support up to 10 args");
+        args ~= s;
+        return this;
+    }
+
+    Message arg(char[][] s)
+    {
+        char[] res = s[0 .. $ - 1].join(", ");
+        if (s.length > 1)
+            res ~= " and ";
+        res ~= s[$ - 1];
+        return arg(res);
+    }
+
+    Message arg(char c)
+    {
+        return arg([c]);
+    }
+
+    Message fatal(ExitLevel exitlevel = ExitLevel.Normal)
+    {
+        msg_handler.checkErrors(exitlevel);
+        return this;
+    }
+
+    /*
+    Message loc(SLoc loc)
+    {
+        location = loc;
+        return this;
+    }
+    */
+
+    MessageType type;
+private:
+    char[][] args;
+    SLoc location;
+    SourceManager src_mgr;
+    MessageHandler msg_handler;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/basic/Messages.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,74 @@
+module basic.Messages;
+
+enum : uint
+{
+    // Lex
+    InvalidSymbol,
+    InvalidIlligaleType,
+    UnexpectedEOFBlock,
+    OnlyOneDotFloating,
+    OnlyOneEFloating,
+
+    // Parse
+    UnexpectedTokMulti,
+    UnexpectedTokSingle,
+    UnexpectedTok,
+    CaseValueMustBeInt,
+    UnexpectedBeginStmt,
+    UnexpectedTokType,
+    ExpectedIdAfterDot,
+    ExpectedExp,
+    ExpectedCastType,
+    InvalidDeclType,
+    InvalidType,
+    //   - imports/module
+    ExpectedIdAfterPackage,
+    RenameMustBeSingleIdent,
+
+
+    // Imports
+    CannotFindModule,
+}
+
+enum MessageType
+{
+    Warning,
+    Error,
+}
+
+MessageEntry[uint] Messages;
+
+struct MessageEntry
+{
+    MessageType type;
+    char[] message;
+}
+    
+private alias MessageType.Error Err;
+private alias MessageType.Warning War;
+private alias MessageEntry E;
+static this()
+{
+    Messages = [
+        UnexpectedEOFBlock  : E(Err, "Unexpected end of file. Unclosed comment block"),
+        InvalidSymbol       : E(Err, "Read invalid symbol: '%0'"),
+        OnlyOneDotFloating  : E(Err, "Only one '.' is allowed in an floating number"),
+        OnlyOneEFloating    : E(Err, "Only one E is allowed in an floating number"),
+
+        UnexpectedTokMulti  : E(Err, "Unexpected token, got %0 expected one of %1"),
+        UnexpectedTokSingle : E(Err, "Unexpected token, got %0 expected %1"),
+        UnexpectedTok       : E(Err, "Unexpected token %0"),
+        CaseValueMustBeInt  : E(Err, "Cases can only be integer literals"),
+        UnexpectedBeginStmt : E(Err, "Unexpected begining of statement."),
+        UnexpectedTokType   : E(Err, "Unexpected token in Type parsing. Got %0"),
+        ExpectedIdAfterDot  : E(Err, "Expected identifier after '.'"),
+        ExpectedExp         : E(Err, "Expected expression"),
+        ExpectedCastType    : E(Err, "Expected cast type"),
+        InvalidDeclType     : E(Err, "Invalid declaration type"),
+        InvalidType         : E(Err, "Invalid type"),
+        ExpectedIdAfterPackage : E(Err, "Identifier expected following package"),
+
+        CannotFindModule    : E(Err, "Cannot find module '%0'")
+    ];
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/basic/SmallArray.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,106 @@
+module basic.SmallArray;
+
+/**
+  This struct acts like a normal dynamic array, with one difference.
+  A size is given, which is how many elements are preallocated on the stack.
+
+  Example:
+  --------
+  SmallArray!(float, 4) array;
+  array ~= 1.0;
+  array ~= 2.0;
+  array ~= 3.0;
+  float[] three_floats = array[0 .. 3];
+  // The slice gives a reference to the stack, remember to .dup
+  array ~= 4.0;
+  // not using the heap yet, but after the next line all values will have been
+  // copied to the heap.
+  array ~= 5.0;
+  --------
+
+  Compared to a normal dynamic array there is 8 bytes overhead (on 32 bit cpus)
+  and ofcourse size * T.sizeof bytes for the stack allocated array.
+ */
+struct SmallArray(T, ubyte size = 8)
+{
+    T[] opSlice(size_t low, size_t high)
+    {
+        assert(high <= len && low <= high, "Array index out of range");
+        return ptr[low .. high];
+    }
+
+    T[] opSlice()
+    {
+        return ptr[0 .. len];
+    }
+    alias opSlice unsafe;
+
+    T[] safe()
+    {
+        if (len <= size)
+            return static_array[0 .. len].dup;
+        return array[0 .. len];
+    }
+
+    T[] opSliceAssign(T val, size_t low, size_t high)
+    {
+        assert(high <= len && low <= high, "Array index out of range");
+        return ptr[low .. high] = val;
+    }
+
+    T[] opSliceAssign(T val)
+    {
+        return ptr[0 .. len] = val;
+    }
+
+    T opIndex(size_t index)
+    {
+        assert(index < len, "Array index out of range");
+        return ptr[index];
+    }
+
+    T opIndexAssign(T val, size_t index)
+    {
+        assert(index < len, "Array index out of range");
+        return ptr[index] = val;
+    }
+
+    void opCatAssign(T val)
+    {
+        if (len < size)
+            static_array[len] = val;
+        else if (len == size)
+        {
+            T[] tmp = static_array[].dup;
+            array = tmp;
+            array ~= val;
+        }
+        else
+            array ~= val;
+
+        ++len;
+        if (len <= size)
+            ptr = static_array.ptr;
+        else
+            ptr = array.ptr;
+    }
+
+    size_t length() { return len; }
+
+    static SmallArray opCall()
+    {
+        SmallArray array;
+        array.ptr = array.static_array.ptr;
+        return array;
+    }
+
+private:
+    T* ptr;
+    size_t len;
+    union
+    {
+        T[] array;
+        T[size] static_array;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/basic/SourceLocation.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,145 @@
+module basic.SourceLocation;
+
+/// Shorter alias for SourceLocation
+public alias SourceLocation SLoc;
+
+/// SourceLocation points to a place in some buffer
+struct SourceLocation
+{
+    /// Returns true, if the location is from a real file
+    bool isReal() { return (val & 0x80_00_00_00) == 0; }
+    /// Returns true, if the location is not from a real file
+    bool isVirtual() { return (val & 0x80_00_00_00) != 0; }
+
+    /// Check if this location is invalid or not
+    bool isValid() { return val != uint.max; }
+    /// ditto
+    bool isInvalid() { return val == uint.max; }
+
+    /**
+      Extracts the file id.
+
+      Warning: In release mode this may return junk, if the loc is not from a
+      file
+     **/
+    uint fileID() {
+        assert(isValid, "Location is invalid");
+        assert(isReal, "You can only extract fileID from a real location");
+        // Here we can rely on two facts, first that the high bit is zero
+        // since its a real position, second that FileOffset is saved in the
+        // high end, so all we need is some shifting
+        return val >> Bits.FileOffset;
+    }
+
+    /**
+      Extracts the offset into the "file". (actually in to the referenced
+      chunk)
+
+      Warning: In release mode this may return junk, if the loc is not from a
+      file
+     **/
+    uint fileOffset() {
+        assert(isValid, "Location is invalid");
+        assert(isReal, "You can only extract fileOffset from real locations");
+        // FileOffset is stored in the lower bits, so all that is needed is a
+        // binary and with all ones in the lower bits.
+        return val & (1 << Bits.FileOffset) - 1;
+    }
+
+    /// Get a new location, placed n bytes after the given location
+    SourceLocation opAdd(int n)
+    {
+        SourceLocation res = *this;
+        res.val += n;
+        return res;
+    }
+
+    /// Get a new location, placed n bytes before the given location
+    SourceLocation opSub(int n)
+    {
+        SourceLocation res = *this;
+        res.val -= n;
+        return res;
+    }
+
+    /// Creates a SourceLocation from a File ID
+    static SourceLocation fromFileID(uint fileID)
+    {
+        assert(fileID < Bits.MaxFileID, "To large fileID");
+        SourceLocation res;
+        res.val = fileID << Bits.FileOffset;
+        return res;
+    }
+
+    /**
+      Used for invalid/unknown locations. (also the default value, but this is
+      more explicit)
+     **/
+    static const SourceLocation Invalid = {val: uint.max};
+
+private:
+    /**
+      A SourceLocation consists of 1 bit, indicating real or virtual, meaning
+      if the location points to a file(real), a string mixin or has been
+      affected by #line(virtual). That information is saved in the most
+      significant bit.
+      The rest depends on which type we are dealing with.
+      Real:
+           13 bits for a file identifier
+           18 bits for offset into that "file" (one file may be split)
+      Virtual:
+           Unknown for now. Likely skewed toward more ids and some meta data
+      An invalid location is uint.max, this might happen by accident but its
+      unlikely.
+     **/
+    uint val = uint.max;
+
+    /**
+      This enum contains some constants that are useful for manipulating
+      SourceLocation's, like the size of various “members” of val.
+     **/
+    static enum Bits {
+        /// Number of bits used for the offset into file buffers
+        FileOffset = 18,
+        /// Number of bits used to identify which file buffer this is from
+        FileID = 31 - FileOffset,
+
+        /// Indicates how much can be indexed within one block(2^FileOffset)
+        MaxFileOffset = 1 << FileOffset,
+        MaxFileID = 1 << FileID,
+    }
+}
+
+/// A simple pair used to describe a range in a buffer and not just a point.
+struct SourceRange
+{
+    SourceLocation begin, end;
+
+    static SourceRange opCall(SourceLocation loc)
+    {
+        return SourceRange(loc, loc + 1);
+    }
+
+    static SourceRange opCall(SourceLocation begin, SourceLocation end)
+    {
+        SourceRange res;
+        res.begin = begin;
+        res.end = end;
+        return res;
+    }
+
+    bool isValid() { return begin.isValid && end.isValid; }
+    bool isInvalid() { return begin.isInvalid || end.isInvalid; }
+
+    bool isReal() { return begin.isReal && end.isReal; }
+
+    /// Get a new range spanning both ranges
+    SourceRange opAdd(SourceRange that)
+    {
+        assert(this.isValid && that.isValid, "Invalid range");
+        return SourceRange(
+                this.begin.val < that.begin.val? this.begin : that.begin,
+                this.end.val > that.end.val? this.end : that.end);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/basic/SourceManager.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,284 @@
+module basic.SourceManager;
+
+import tango.core.Memory : GC;
+import tango.io.UnicodeFile;
+import tango.io.Stdout;
+import tango.text.convert.Layout;
+
+public import basic.SourceLocation;
+
+private alias char[] string;
+
+/**
+  SourceManager is used to handle input files, by loading them in in chunks
+  that can be referenced elsewhere.
+
+  It will also help extract the line/col of locations and convert between
+  real and virtual locations
+ **/
+class SourceManager
+{
+    this()
+    {
+        layout = new Layout!(char);
+    }
+
+    /**
+      Will load in the file belonging to the filename
+
+        filename = The file to load. Theres some assumptions about this file.
+            1. The file has a BOM or is valid utf-8
+            2. The file is not empty, unreadable, a folder etc.
+     **/
+    SourceLocation addFile(string filename)
+    {
+        scope file = new UnicodeFile!(char)(filename, Encoding.UTF_8);
+        auto file_data = file.read();
+        return createCheckpoints(file_data, filename);
+    }
+
+    /**
+      Returns a string slice containing the part of the file after loc (a
+      pointer might be better, it allows negative indexing)
+     **/
+    string getRawData(SourceLocation loc)
+    {
+        CP cp = checkpoints[loc.fileID];
+        auto length = cp.data_end - cp.data.ptr;
+        return cp.data.ptr[loc.fileOffset .. length];
+    }
+
+    /**
+      Extracts the line number of the given location
+      O("file size") if cache isn't built, O(log "lines in file") else
+     **/
+    uint getLineNumber(SourceLocation loc)
+    {
+        assert(loc.isValid, "Location is invalid");
+        assert(loc.isReal, "Virtual locations not supported yet");
+        assert(loc.fileID < checkpoints.length, "Non-existent location");
+
+        CP* cp = &checkpoints[loc.fileID];
+        auto cache = &linecache[cp.meta_index];
+        if (!cache.isCached)
+            cache.build(cp.data_start[0 .. cp.data_end - cp.data_start]);
+        return cache.lineOf(getFileOffset(loc));
+    }
+
+    /**
+      Extracts the full byte offset into a file, at which a location
+      is pointing.
+     **/
+    uint getFileOffset(SourceLocation loc)
+    {
+        return loc.fileOffset
+            + checkpoints[loc.fileID].part * loc.Bits.MaxFileOffset;
+    }
+
+    /**
+      Extracts a string containing the entire line loc appears in.
+     **/
+    string getLine(SourceLocation loc)
+    {
+        // The line is extracted by getting two pointers to the exact location
+        // and decreasing one until the nearest newline while the other ptr is
+        // increased to the nearest newline.
+        CP* cp = &checkpoints[loc.fileID];
+        char* ptr = cp.data.ptr + loc.fileOffset;
+        char* ptr_lo = ptr;
+        while (cp.inRange(ptr_lo) && *ptr_lo != '\n' && *ptr_lo != '\r')
+            --ptr_lo;
+        while (cp.inRange(ptr) && *ptr != '\n' && *ptr != '\r')
+            ++ptr;
+        return ptr_lo[1 .. ptr - ptr_lo];
+    }
+
+    /**
+      Gets the column of where the loc appears.
+     **/
+    int getColumn(SourceLocation loc)
+    {
+        // Use same approach as getLine
+
+        CP* cp = &checkpoints[loc.fileID];
+        char* ptr = cp.data.ptr + loc.fileOffset;
+        char* ptr_lo = ptr;
+        while (cp.inRange(ptr_lo) && *ptr_lo != '\n' && *ptr_lo != '\r')
+            --ptr_lo;
+        return cast(int)ptr - cast(int)ptr_lo - 1;
+    }
+
+    /**
+      Get the original source text of a SourceRange
+     **/
+    string getText(SourceRange loc)
+    {
+        assert(loc.isValid, "Range is invalid");
+        assert(loc.isReal, "Virtual locations not supported yet");
+        auto begin  = getFileOffset(loc.begin);
+        auto end    = getFileOffset(loc.end);
+        return checkpoints[loc.begin.fileID].data_start[begin .. end];
+    }
+
+    /**
+      Get the original source text
+     **/
+    string getText(SourceLocation loc, size_t length)
+    {
+        return getText(SourceRange(loc, loc + length));
+    }
+
+    /**
+      Convert a location into a string. Something like "file(line)"
+     **/
+    string getLocationAsString(SourceLocation loc)
+    {
+        assert(loc.isValid, "Location is invalid");
+        return layout.convert("{}({})",
+            checkpoints[loc.fileID].filename,
+            getLineNumber(loc));
+    }
+    string getLocationAsString(SourceRange loc)
+    {
+        return layout.convert("{}({}:{})",
+            checkpoints[loc.begin.fileID].filename,
+            getFileOffset(loc.begin),
+            getFileOffset(loc.end));
+    }
+
+    /**
+      Get the file name of a loc.
+     **/
+    string getFile(SourceLocation loc)
+    {
+        return checkpoints[loc.fileID].filename;
+    }
+
+private:
+    synchronized
+        SourceLocation createCheckpoints(string data, string source_file)
+    {
+        // The line-cache is added, but not built,
+        // getLineNumber makes sure it is called when needed.
+        linecache ~= FileLineCache();
+        uint meta_index = linecache.length - 1;
+
+        // SourceLocation's can only index relatively short buffers, therefore
+        // the file is split into several checkpoints.
+        uint checkpoint_counter = 0;
+        char* data_start = data.ptr;
+        char* data_end = data.ptr + data.length;
+        while (data.length > 0)
+        {
+            uint to_take = min(data.length, SourceLocation.Bits.MaxFileOffset);
+            checkpoints ~=
+                CP(source_file,
+                        data_start,
+                        data_end,
+                        data[0 .. to_take],
+                        checkpoint_counter++,
+                        meta_index);
+            data = data[to_take .. $];
+        }
+        checkpoint_counter = checkpoints.length - checkpoint_counter;
+        return SourceLocation.fromFileID(checkpoint_counter);
+    }
+
+    /// Contains the read/generated data.
+    CP[] checkpoints;
+    /// Cache used to speed up finding of line-starts.
+    FileLineCache[] linecache;
+    /// Used for formatting locations as strings.
+    Layout!(char) layout;
+
+    // These really should be magically available everywhere and templated.
+    int min(int a, int b) { return a < b? a : b; }
+    int max(int a, int b) { return a >= b? a : b; }
+
+    // A Check Point is used to store a file in multiple parts, to overcome
+    // the limitation of SourceLocation only having a rather limited amount of
+    // bits to index any one file.
+    struct CP
+    {
+        // read-only
+        char[] filename;
+        // ditto
+        char* data_start;
+        char* data_end;
+        // ditto
+        char[] data;
+        // ditto
+        uint part = 0;
+        // ditto
+        uint meta_index = 0;
+
+        bool inRange(char* p)
+        {
+            return p >= data_start && p < data_end;
+        }
+    }
+
+    struct FileLineCache
+    {
+        /// Contains the offset of the i'th line on index i
+        uint[] line_starts;
+
+        /// Indicates weather the cache has been built or not
+        bool isCached = false;
+
+        /**
+          This method does a binary search to find the line that contains the
+          given offset.
+         **/
+        uint lineOf(uint offset)
+        {
+            size_t  beg = 0,
+                    end = line_starts.length,
+                    mid = end >> 1;
+
+            while( beg < end )
+            {
+                if( line_starts[mid] <= offset )
+                    beg = mid + 1;
+                else
+                    end = mid;
+                mid = beg + ( end - beg ) / 2;
+            }
+            return mid;
+        }
+
+        /**
+          Builds the cache data - always make sure this has been called before
+          calling lineOf.
+         **/
+        void build(char[] data)
+        {
+            // j starts at 1, because we need an additional place in the array
+            // to indicate that line 1 starts at index 0.
+            size_t j = 1;
+            char* it = data.ptr, end = data.ptr + data.length;
+            for (; it != end; ++it)
+                if (*it == '\n')
+                    ++j;
+            // Allocate without initialization. Saves a bit of time
+            line_starts.length = j;
+            line_starts[0] = 0;
+
+            // Go over the data again, writing the line starts in our new array
+            j = 1;
+            for (size_t i = 0; i < data.length; i++)
+            {
+                if (data[i] == '\n')
+                    line_starts[j++] = i;
+                else if (data[i] == '\r')
+                {
+                    line_starts[j++] = i;
+                    i += cast(size_t)(data[i+1] == '\n');
+                }
+            }
+
+            isCached = true;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lexer/Keyword.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,53 @@
+module lexer.Keyword;
+
+import lexer.Token;
+
+/**
+  A list of keywords in an associative array that link a string
+  representation of the keyword to a Tok
+  */
+Tok[char[]] keywords;
+
+static this ()
+{
+    keywords =
+    [
+        // types
+        "byte"[]    : Tok.Byte,
+        "ubyte"     : Tok.Ubyte,
+        "short"     : Tok.Short,
+        "ushort"    : Tok.Ushort,
+        "int"       : Tok.Int,
+        "uint"      : Tok.Uint,
+        "long"      : Tok.Long,
+        "ulong"     : Tok.Ulong,
+
+        "char"      : Tok.Char,
+        "wchar"     : Tok.Wchar,
+        "dchar"     : Tok.Dchar,
+
+        "bool"      : Tok.Bool,
+
+        "float"     : Tok.Float,
+        "double"    : Tok.Double,
+
+        "void"      : Tok.Void,
+
+        // type related
+        "struct"    : Tok.Struct,
+
+        // control flow
+        "if"        : Tok.If,
+        "else"      : Tok.Else,
+        "while"     : Tok.While,
+        "switch"    : Tok.Switch,
+        "case"      : Tok.Case,
+        "default"   : Tok.Default,
+        "return"    : Tok.Return,
+        "cast"      : Tok.Cast,
+
+        // modules
+        "module"    : Tok.Module,
+        "import"    : Tok.Import
+    ];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lexer/Lexer.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,447 @@
+module lexer.Lexer;
+
+import basic.Message,
+       basic.SourceManager;
+
+import lexer.Token,
+       lexer.Keyword;
+
+import tango.io.Stdout;
+
+/**
+  The Lexer class will supply you with methods to tokenize a D file. Supply the
+  Lexer with a DataSource and you can 'peek' and 'next' Tokens from the file. 
+
+  For more info about Tokens, look up the lexer.Token module.
+*/  
+class Lexer
+{
+public:
+
+    /**
+      Create a new Lexer.
+    */
+    this(SourceLocation start, SourceManager src_mgr, MessageHandler messages)
+    {
+        this.messages = messages;
+        sm = src_mgr;
+        start_loc = start;
+        position = 0;
+        source = sm.getRawData(start_loc);
+
+
+        charTable.length = 256;
+        foreach (c; "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")
+            charTable[c] = CharType.Letter;
+
+        foreach (c; "0123456789")
+            charTable[c] = CharType.Number;
+
+        foreach (c; "(){}[];:.,=!<>+-*/%\"`")
+            charTable[c] = CharType.Symbol;
+
+        foreach (c; " \n")
+            charTable[c] = CharType.Whitespace;
+
+        foreach (c; "'\\")
+            charTable[c] = CharType.Other;
+
+        symbolFunctions.length = 256;
+
+        symbolFunctions['('] = &openParentheses;
+        symbolFunctions[')'] = &closeParentheses;
+        symbolFunctions['{'] = &openBrace;
+        symbolFunctions['}'] = &closeBrace;
+        symbolFunctions['['] = &openBracket;
+        symbolFunctions[']'] = &closeBracket;
+        symbolFunctions[';'] = &seperator;
+        symbolFunctions[':'] = &colon;
+        symbolFunctions['.'] = &dot;
+        symbolFunctions[','] = &comma;
+        symbolFunctions['='] = &eq;
+        symbolFunctions['!'] = &ne;
+        symbolFunctions['<'] = &le;
+        symbolFunctions['>'] = &ge;
+        symbolFunctions['+'] = &plus;
+        symbolFunctions['-'] = &minus;
+        symbolFunctions['*'] = &star;
+        symbolFunctions['/'] = &slash;
+        symbolFunctions['%'] = &percent;
+        symbolFunctions['"'] = &string;
+        symbolFunctions['`'] = &string;
+    }
+
+    /**
+      Get the next token from the source. This method will move the
+      internal position forward to the next Token.
+
+      return: A Token - Token.type is TokType.EOF if there is
+        no more tokens in the file.
+      */
+    Token next()
+    {
+        switch (getNextChar)
+        {
+            case CharType.EOF:
+                SLoc loc;
+                return Token(Tok.EOF, loc, 0); 
+
+            case CharType.Whitespace:
+                position += 1;
+                return this.next;
+
+            case CharType.Symbol:
+                return lexSymbol;
+
+            case CharType.Letter:
+                return lexLetter;
+
+            case CharType.Number:
+                return lexNumber;
+            case CharType.Other:
+                messages.report(UnexpectedTok, Loc(position)).fatal(ExitLevel.Lexer);
+        }
+    }
+
+    /**
+      Get the next token from the source. This method will NOT move the
+      internal position forward, and thereby having no side-effects.
+
+      return: A Token - Token.type is TokType.EOF if there is
+        no more tokens in the file.
+      */
+    Token peek(int skip = 0)
+    {
+        int oldPosition = this.position;
+        while (skip-- > 0)
+            this.next;
+        Token t = this.next;
+        this.position = oldPosition;
+        return t;
+    }
+
+private:
+    Token eq()
+    {
+        if(source[position] == '=')
+            return Token(Tok.Eq, Loc(position++ - 1), 2);
+        return Token(Tok.Assign, Loc(position - 1), 1);
+    }
+    Token openBrace() 
+    {
+        return Token(Tok.OpenBrace, Loc(position - 1), 1);
+    }
+    Token closeBrace() 
+    {
+        return Token(Tok.CloseBrace, Loc(position - 1), 1);
+    }
+    Token openParentheses() 
+    {
+        return Token(Tok.OpenParentheses, Loc(position - 1), 1);
+    }
+    Token closeParentheses()
+    {
+        return Token(Tok.CloseParentheses, Loc(position - 1), 1);
+    }
+    Token openBracket() 
+    {
+        return Token(Tok.OpenBracket, Loc(position - 1), 1);
+    }
+    Token closeBracket()
+    {
+        return Token(Tok.CloseBracket, Loc(position - 1), 1);
+    }
+    Token seperator()
+    {
+        return Token(Tok.Seperator, Loc(position - 1), 1);
+    }
+    Token colon()
+    {
+        return Token(Tok.Colon, Loc(position - 1), 1);
+    }
+    Token dot() 
+    {
+        int pos = 0;
+        while(getNextChar(0) == CharType.Number || 
+              this.source[position + pos + 1] == '_')
+        {
+            if(getNextChar(0) == CharType.Number)
+            {
+                position--;
+                return lexNumber();
+            }
+            pos++;
+        }
+        return Token(Tok.Dot, Loc(position - 1), 1);
+    }
+    Token comma() 
+    {
+        return Token(Tok.Comma, Loc(position - 1), 1);
+    }
+    Token ne() 
+    {
+        if(source[position] == '=')
+            return Token(Tok.Ne, Loc(position++ - 1), 2);
+        return Token(Tok.Not, Loc(position - 1), 1);
+    }
+    Token le()
+    {
+        if(source[position] == '=')
+            return Token(Tok.Le, Loc(position++ - 1), 2);
+        return Token(Tok.Lt, Loc(position - 1), 1);
+    }
+    Token ge() 
+    {
+        if(source[position] == '=')
+            return Token(Tok.Ge, Loc(position++ - 1), 2);
+        return Token(Tok.Gt, Loc(position - 1), 1);
+    }
+    Token plus() 
+    {
+        return Token(Tok.Plus, Loc(position - 1), 1);
+    }
+    Token minus() 
+    {
+        return Token(Tok.Minus, Loc(position - 1), 1);
+    }
+    Token star() 
+    {
+        return Token(Tok.Star, Loc(position - 1), 1);
+    }
+    Token slash()
+    {
+        switch(source[position])
+        {
+            case '/':
+                while(getNextChar != CharType.EOF)
+                {
+                    if(source[position++] == '\n')
+                        return this.next;
+                }
+                return Token(Tok.EOF, Loc(position), 0);
+
+            case '*':
+                position += 2;
+                while(getNextChar != CharType.EOF)
+                {
+                    ++position;
+                    if(source[position-2] == '*')
+                        if(source[position-1] == '/')
+                        {
+                            return this.next;
+                        }
+                }
+                messages.report(UnexpectedEOFBlock,Loc(position));
+
+            case '+':
+                position += 2;
+                int nesting = 1;
+                while(getNextChar != CharType.EOF)
+                {
+                    ++position;
+                    if(source[position-2] == '+')
+                        if(source[position-1] == '/')
+                        {
+                            position++;
+                            nesting--;
+                        }
+
+                    if(source[position-2] == '/')
+                        if(source[position-1] == '+')
+                        {
+                            nesting++;
+                            position++;
+                        }
+
+                    if(nesting == 0)
+                        return this.next;
+                }
+                messages.report(UnexpectedEOFBlock,Loc(position));
+
+            default:
+                return Token(Tok.Slash, Loc(position - 1), 1);
+        }
+    }
+
+    Token percent() 
+    {
+        return Token(Tok.Percent, Loc(position - 1), 1);
+    }
+
+    Token string()
+    {
+        --position;
+        int start = position;
+        if(getNextChar() == CharType.Letter)
+            position++;
+        char end = '`';
+        switch(source[position])
+        {
+            case '"':
+                if(position > 0)
+                    if(source[position-1] == 'r')
+                    {
+                        end = '"';
+                        goto string_wys;
+                    }
+                ++position;
+                while(getNextChar != CharType.EOF)
+                {
+                    ++position;
+                    if (source[position-1] == '"' )
+                        return Token(Tok.String, Loc(start), position - start);
+                    else if (source[position-1] == '\\')
+                        position++;
+                }
+                break;
+                case '`':
+string_wys:     
+                ++position;
+                while(getNextChar != CharType.EOF)
+                {
+                    ++position;
+                    if (source[position-1] == end )
+                        return Token(Tok.String, Loc(start), position - start);
+                }
+                break;
+        }
+        messages.report(UnexpectedEOFBlock, Loc(position)).fatal(ExitLevel.Lexer);
+    }
+    
+    Token lexNumber ()
+    {
+        bool sign = false;
+        bool dot = false;
+        bool e = false;
+
+        int i = 0;
+
+        bool end = false;
+        while(!end)
+        {
+            switch(getNextChar(i))
+            {
+                case CharType.Number:
+                    break;
+                case CharType.Symbol:
+                    if(this.source[position+i] == '.')
+                    {
+                        if(dot)
+                            messages.report(OnlyOneDotFloating, Loc(position + i));
+                        dot = true;
+                        break;
+                    }
+                    end = true;
+                    continue;
+                case CharType.Letter:
+                    if(this.source[position+i] == '_')
+                        break;
+                    if (this.source[position+i] == 'e' || 
+                        this.source[position+i] == 'E')
+                    {
+                        if (e)
+                            messages.report(OnlyOneEFloating, Loc(position + i));
+                        e = true;
+                        break;
+                    }
+                    end = true;
+                    continue;
+
+                default:
+                    end = true;
+                    continue;
+            }
+            i++;
+        }
+
+        position += i;
+
+        return Token(Tok.Integer, Loc(position - i), i);
+    }
+
+    Token lexSymbol ()
+    {
+        Token t = symbolFunctions[source[position++]]();
+
+        return t;
+    }
+
+    Token lexLetter ()
+    {
+        int i = 0;
+        bool hasNumber = false;
+        if (source[position+1] == '"' ||
+            source[position+1] == '`')
+        {
+            ++position;
+            return string;
+        }
+        while (getNextChar(++i) == CharType.Letter || 
+                getNextChar(i) == CharType.Number)
+        {
+            if (getNextChar(i) == CharType.Number)
+            {
+                hasNumber = true;
+            }
+        }
+
+        Token t = Token(Tok.Identifier, Loc(), i);
+
+        if (!hasNumber)
+        {
+            char[] str = source[position .. position + i];
+            if(str in keywords)
+                t.type = keywords[str];
+        }
+
+        position += i;
+
+        return t;
+    }
+
+    CharType getNextChar(int offset = 0)
+    {
+        if (position + offset >= this.source.length)
+            return CharType.EOF;
+
+        char current = source[position + offset];
+
+        CharType c = charTable[current];
+
+        if(c == CharType.INVALID)
+            messages.report(InvalidSymbol, Loc())
+                .arg(Integer.toString(cast(int)current))
+                .fatal(ExitLevel.Lexer);
+
+        return c;
+
+    }
+
+    private final SourceLocation Loc(int pos = -1)
+    {
+        if (pos < 0)
+            return start_loc + position;
+        return start_loc + pos;
+    }
+
+    SourceManager sm;
+    SourceLocation start_loc;
+    int position;
+    char[] source;
+    MessageHandler messages;
+    CharType[] charTable;
+    Token delegate()[] symbolFunctions;
+}
+
+enum CharType : ubyte
+{
+    INVALID,
+    Letter,
+    Number,
+    Symbol,
+    Whitespace,
+    Other,
+
+    EOF
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lexer/Token.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,202 @@
+module lexer.Token;
+
+public 
+import basic.SourceLocation;
+
+import Integer = tango.text.convert.Integer;
+
+/** 
+  The Token struct will be used through the Lexer, Parser and other
+  modules as a location into source.
+
+  The Token should always be optimized for size to limit unnecessary
+  memory usage.
+  */
+struct Token
+{
+    Tok type;
+    SLoc location;
+    uint length;
+
+    /**
+      Create a new token with a Tok type, Location in source and a 
+      length of how many chars the Token span in the source
+      */
+    static Token opCall (Tok type, SLoc location, uint length)
+    {
+        Token t;
+        t.type = type;
+        t.location = location;
+        t.length = length;
+        return t;
+    }
+
+    /**
+      Get the type of the Token as a string
+      */
+    char[] getType ()
+    {
+        return typeToString[this.type];
+    }
+
+    /**
+      A human readable dump of a Token
+      */
+    char[] toString ()
+    {
+        return this.getType()~": Len: "~Integer.toString(this.length);
+    }
+
+    /// Get the range of this token
+    SourceRange asRange() { return SourceRange(location, location + length); }
+
+    /**
+      Returns true if the type of this token is a basic type (int, float, ...).
+      Void is included, although a void in it self is not really a type.
+     */
+    bool isBasicType()
+    {
+        return type >= Tok.Byte && type <= Tok.Void;
+    }
+
+    /**
+      Returns true for all the various assignments (=, +=, *= ...)
+     */
+    bool isAssignment()
+    {
+        return type == Tok.Assign;
+    }
+
+    /**
+      Just a shortcut to avoid `token.type == Tok.Identifier`.
+     */
+    bool isIdentifier()
+    {
+        return type == Tok.Identifier;
+    }
+}
+
+/**
+  Tok is short for TokenType. This enum list is to supply the Token 
+  with a type. 
+  
+  This enum is used to switch over "many" places.
+  */
+enum Tok : ushort
+{
+    /* Non-code related tokens */
+    EOF,
+
+    /* Basic types */
+    Identifier,
+    Integer,
+
+    /* Basic operators */
+    Assign,
+    Plus, Minus,
+    Star, Slash, Percent,
+    Comma,
+
+    /* Symbols */
+    OpenParentheses,
+    CloseParentheses,
+    OpenBrace,
+    CloseBrace,
+    OpenBracket,
+    CloseBracket,
+    Seperator,
+    Colon,
+    Dot,
+
+    /* Comparator operators */
+    Eq, Ne,
+    Lt, Gt,
+    Le, Ge,
+
+    Not,
+
+    /* Keywords */
+    Byte, Ubyte,
+    Short, Ushort,
+    Int, Uint,
+    Long, Ulong,
+
+    Char, Wchar, Dchar,
+
+    Float, Double,
+
+    Bool,
+
+    Void,
+
+    Struct,
+
+    If, Else,
+    While,
+    Switch, Case, Default,
+    Return, Cast,
+
+    String,
+
+    Module, Import,
+
+}
+
+/**
+  An associative array to supply a Tok to String function.
+
+  Keep always this list updated when adding a new Tok.
+  */
+public char[][Tok] typeToString;
+
+static this()
+{
+    typeToString =
+    [
+        Tok.EOF:"EOF"[],
+        Tok.Identifier:"Identifier",
+        Tok.Byte:"Byte",
+        Tok.Short:"Short",
+        Tok.Int:"Int",
+        Tok.Long:"Long",
+        Tok.Char:"Char",
+        Tok.Wchar:"Wchar",
+        Tok.Dchar:"Dchar",
+        Tok.Bool:"Bool",
+        Tok.Void:"Void",
+        Tok.Eq:"Eq",
+        Tok.Ne:"Ne",
+        Tok.Lt:"Lt",
+        Tok.Le:"Le",
+        Tok.Gt:"Gt",
+        Tok.Ge:"Ge",
+        Tok.OpenParentheses:"OpenParentheses",
+        Tok.CloseParentheses:"CloseParentheses",
+        Tok.OpenBrace:"OpenBrace",
+        Tok.CloseBrace:"CloseBrace",
+        Tok.OpenBracket:"OpenBracket",
+        Tok.CloseBracket:"CloseBracket",
+        Tok.Dot:"Dot",
+        Tok.Assign:"Assign",
+        Tok.Plus:"Plus",
+        Tok.Minus:"Minus",
+        Tok.Star:"Star",
+        Tok.Slash:"Slash",
+        Tok.Percent:"Percent",
+        Tok.Integer:"Integer",
+        Tok.If:"If",
+        Tok.While:"While",
+        Tok.Switch:"Switch",
+        Tok.Case:"Case",
+        Tok.Default:"Default",
+        Tok.Comma:"Comma",
+        Tok.Return:"Return",
+        Tok.Struct:"Struct",
+        Tok.Colon:"Colon",
+        Tok.Seperator:"Seperator",
+        Tok.Cast:"Cast",
+        Tok.Module:"Module",
+        Tok.Import:"Import",
+        Tok.String:"String"
+    ];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/parser/Action.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,362 @@
+module parser.Action;
+
+import lexer.Token;
+
+/**
+  Used to indicate what type of operator is used in a given binary expression
+  (and unary expressions?)
+ */
+public enum Operator
+{
+    Assign,
+
+    Eq, Ne,
+
+    Lt, Le,
+    Gt, Ge,
+
+    Add, Sub,
+    Mul, Div, Mod,
+}
+
+
+class Id
+{
+    public static Id opCall(Token tok)
+    {
+        auto id = new Id();
+        id.tok = tok;
+        return id;
+    }
+    Token tok;
+}
+
+class PointerId : Id
+{
+    public static PointerId opCall(Id id)
+    {
+        auto p = new PointerId();
+        p.id = id;
+        return p;
+    }
+
+    Id id;
+}
+
+class ArrayId : Id
+{
+    public static ArrayId opCall(Id id, Object number)
+    {
+        auto a = new ArrayId();
+        a.id = id;
+        a.number = number;
+        return a;
+    }
+
+    Id id;
+    Object number;
+}
+
+/**
+  Represents a fully qualified name, with some packages and a final identifier.
+  The identifier should always be set, but packages may have length 0.
+ **/
+struct ModuleName
+{
+    Id id;
+    Id[] packages;
+
+    /// Get the full ranged spanned by packages and identifier
+    SourceRange asRange()
+    {
+        SourceRange r = id.tok.asRange();
+        foreach (identifier; packages)
+            r = r + identifier.tok.asRange();
+        return r;
+    }
+}
+
+/**
+  All methods are optional.
+
+Warning: Interface is not stable yet. Use the `override` keyword in all classes
+            inheriting from this to get warning if the interface changes.
+ */
+abstract class Action
+{
+    /**
+      A few aliases to indicate what methods should be dealing with the same
+      types.
+
+      Not typesafe, and not using typedef because users would need a lot of
+      casts (and base type would be void*, so no possibility to synchronize,
+      print etc.)
+     */
+    alias Object ExprT;
+    alias Object StmtT; /// ditto
+    alias Object DeclT; /// ditto
+    alias Object ModuleT; /// ditto
+
+    // -- Modules --
+
+    ModuleT actOnModule(ref Token _module, char[] name)
+    {
+        return null;
+    }
+
+    /**
+      This action is called when a file does not start with a module
+      declaration - in which case there is no Token available.
+
+      Instead a SLoc to the start of the file is given.
+     */
+    ModuleT actOnImplicitModule(SourceLocation fileStart, char[] name)
+    {
+        return null;
+    }
+
+    void actOnModuleDecl(ModuleT m, DeclT d)
+    {
+    }
+
+    // -- Declarations --
+
+    /**
+      Called for an import statement, that may be renamed. Id name is null,
+      there is no rename.
+
+      If there are selective imports, its handled in add 
+     */
+    DeclT actOnImport(ref Token _import, ref ModuleName target, Id* name)
+    {
+        return null;
+    }
+
+    /**
+     */
+    void addSelectiveImport(DeclT _import, ref Id target, Id* name)
+    {
+    }
+
+    /**
+      Either we should have one case that handles a lot of things, or we should
+      have a lot of separate cases.
+      As an example, this method could handle the params in `int f(int, int)`
+      as well as handling `int x` at both top-level, in classes and in methods.
+      
+      The other solution is an addParamToFunc or similar.
+     */
+    DeclT actOnDeclarator(ref Id type, ref Id name, ExprT init)
+    {
+        return null;
+    }
+
+    /**
+      Add a struct member to a struct.
+     */
+    void actOnStructMember(DeclT st_decl, DeclT m_decl) //ref Id type, ref Id name, ExprT init)
+    {
+        return null;
+    }
+
+    /**
+      Add an initialization expression to a previously created decl.
+
+      Used for default values on function params and for values to local
+      variables.
+     */
+    void addInitToDeclarator(DeclT decl, ExprT exp)
+    {
+    }
+
+    /**
+      Called at the start of a function, doesn't get a lot of info - that is
+      added later on, through addFuncArg and actOnEndOfFunction.
+     */
+    DeclT actOnStartOfFunctionDef(ref Id type, ref Id name)
+    {
+        return null;
+    }
+
+    /**
+      Add a new parameter to the function func.
+     */
+    void addFuncArg(DeclT func, Id type, Id name)
+    {
+    }
+
+    /**
+      Finish off the function, by giving it the body (a single statement, so
+      you probably want some sort of compound statement)
+     */
+    DeclT actOnEndOfFunction(DeclT func, StmtT stmts)
+    {
+        return func;
+    }
+
+    // -- Statements --
+
+    /**
+      Called after parsing a function/while/for/whatever body.
+
+      Note that stmts is to be considered temporary, it might point into the
+      stack and needs to be copied before saving.
+     */
+    StmtT actOnCompoundStmt(ref Token left, ref Token right, StmtT[] stmts)
+    {
+        return null;
+    }
+
+    /**
+      An expression was used as a statement - this includes assignments,
+      function calls.
+
+      Additionally the D spec dictates that expressions with no effect are not
+      legal as statements, but the parser can't test for this so it has to be
+      done in the later stages.
+     */
+    StmtT actOnExprStmt(ExprT exp)
+    {
+        return null;
+    }
+
+    /**
+      Called after parsing return statements.
+
+      loc is the return token.
+     */
+    StmtT actOnReturnStmt(ref Token loc, ExprT exp)
+    {
+        return null;
+    }
+
+    /**
+     */
+    StmtT actOnIfStmt(ref Token ifTok, ExprT cond, StmtT thenBody,
+                      ref Token elseTok, StmtT elseBody)
+    {
+        return null;
+    }
+
+    /**
+     */
+    StmtT actOnWhileStmt(ref Token whileTok, ExprT cond, StmtT whileBody)
+    {
+        return null;
+    }
+
+    /**
+     */
+    StmtT actOnDeclStmt(DeclT decl)
+    {
+        return null;
+    }
+
+    StmtT actOnStartOfSwitchStmt()
+    {
+        return null;
+    }
+
+    void actOnCaseStmt()
+    {
+    }
+
+    void actOnDefaultStmt()
+    {
+    }
+
+    StmtT actOnFinishSwitchStmt(StmtT sw)
+    {
+        return sw;
+    }
+
+    // -- Expressions --
+
+    /**
+      A single numerical constant -- this can be absolutely any kind of number.
+      Integers, floats, hex, octal, binary, imaginary and so on.
+     */
+    ExprT actOnNumericConstant(Token op)
+    {
+        return null;
+    }
+
+    /**
+      This is called when identifiers are used in expressions.
+     */
+    ExprT actOnIdentifierExp(Id id)
+    {
+        return null;
+    }
+
+    /**
+      This is called when strings are used in expression
+     */
+    ExprT actOnStringExp(Token t)
+    {
+        return null;
+    }
+
+    /**
+      Unary operator.
+     */
+    ExprT actOnUnaryOp(Token op, ExprT operand)
+    {
+        return null;
+    }
+
+    /**
+      Binary operator.
+     */
+    ExprT actOnBinaryOp(SLoc op_loc, Operator op, ExprT l, ExprT r)
+    {
+        return null;
+    }
+
+    /**
+      Called when using the 'dot' operator.
+      The left hand side can be any expression, but its only possible to look
+      up an identifier.
+     */
+    ExprT actOnMemberReference(ExprT lhs, SourceLocation op, Id member)
+    {
+        return null;
+    }
+
+    /**
+      Called when function calls are encountered.
+
+      Note that args is temporary and might point into the stack. Remember to
+      copy before saving a reference to it.
+     */
+    ExprT actOnCallExpr(ExprT func, ref Token left_paren, ExprT[] args,
+                        ref Token right_paren)
+    {
+        return null;
+    }
+
+    /**
+      Called when function calls are encountered.
+     */
+    ExprT actOnIndexEpr(ExprT array, ref Token left_bracket, ExprT index,
+                        ref Token right_bracket)
+    {
+        return null;
+    }
+
+    /**
+      Cast expression.
+     */
+    ExprT actOnCastExpr(ref Token _cast, Id type, ExprT exp)
+    {
+        return null;
+    }
+}
+
+/**
+  Doesn't do anything at all - can be used for benchmarking the parser.
+ */
+class NullAction : Action
+{
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/parser/Parser.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,731 @@
+module parser.Parser;
+
+import lexer.Lexer,
+       lexer.Token;
+
+import parser.Action;
+
+import basic.Message;
+
+import basic.SmallArray,
+       basic.SourceManager;
+
+import tango.io.Stdout,
+       Integer = tango.text.convert.Integer;
+
+class Parser
+{
+    Action action;
+    MessageHandler messages;
+    alias Object Exp;
+    alias Object Stmt;
+    alias Object Decl;
+    alias Object Module;
+
+    this(MessageHandler messages)
+    {
+        this.messages = messages;
+    }
+
+    Module parse(SourceManager sm, Lexer lexer, Action act)
+    {
+        this.sm = sm;
+        this.lexer = lexer;
+        this.action = act;
+
+        Module m;
+        if (lexer.peek.type == Tok.Module)
+        {
+            Token _module = lexer.next;
+            ModuleName name = parseModuleName();
+            m = action.actOnModule(_module, sm.getText(name.asRange()));
+            require(Tok.Seperator);
+        }
+        else
+        {
+            SLoc loc = lexer.peek.location;
+            m = action.actOnImplicitModule(loc, sm.getFile(loc));
+        }
+
+        while (lexer.peek.type != Tok.EOF)
+            foreach (d; parseDeclDef())
+                action.actOnModuleDecl(m, d);
+
+        return m;
+    }
+
+private:
+    Decl[] parseDeclDef()
+    {
+        Token t = lexer.peek;
+        if (t.type == Tok.Import)
+            return parseImports();
+        else
+            return [parseDecl()];
+    }
+
+    Decl parseDecl()
+    {
+        Token t = lexer.peek;
+
+        if (t.isBasicType || t.isIdentifier)
+        {
+            Id type;
+            Id iden;
+            int len = peekParseType;
+            if(lexer.peek(len).type == Tok.Identifier && len != 0)
+            {
+                type = parseType;
+parseDeclAfterInvalidType:
+                iden = Id(require(Tok.Identifier));
+                Token next = lexer.peek();
+                if (next.type == Tok.Seperator)
+                {
+                    Token sep = lexer.next();
+                    return action.actOnDeclarator(type, iden, null);
+                }
+                else if (next.type == Tok.Assign)
+                {
+                    Token assign = lexer.next();
+                    Exp exp = parseExpression();
+                    require(Tok.Seperator);
+                    return action.actOnDeclarator(type, iden, exp);
+                }
+                else if (next.type == Tok.OpenParentheses)
+                    return parseFunc(type, iden);
+                else
+                    messages.report(UnexpectedTok, next.location).arg(next.getType);
+            }
+            t = lexer.peek(len);
+            messages.report(InvalidDeclType, t.location)
+                .arg(sm.getText(t.asRange));
+            while(len--)
+                lexer.next;
+            while(lexer.peek.type != Tok.Identifier)
+                lexer.next;
+            type = Id(lexer.peek);
+            goto parseDeclAfterInvalidType;
+        }
+        else if (t.type == Tok.Struct)
+        {
+            Id type = Id(lexer.next);
+            Id iden = Id(require(Tok.Identifier));
+            
+            return parseStruct(type, iden);
+        }
+        messages.report(UnexpectedTok, t.location)
+            .arg(t.getType)
+            .arg(Tok.Identifier)
+            .fatal(ExitLevel.Parser);
+    }
+
+    /**
+      Parse a series of imports belonging to a single import token.
+     */
+    Decl[] parseImports()
+    {
+        Token _import = require(Tok.Import);
+        SmallArray!(Decl) res;
+        void addToRes(Decl d) { res ~= d; }
+
+        bool done = false;
+        while (!done && !on_a(Tok.Seperator))
+        {
+            ModuleName mod = parseModuleName();
+            Token tok = lexer.peek;
+            switch (tok.type)
+            {
+                case Tok.Comma:
+                    // import A, B.C;
+                    // parse another module-name
+                    lexer.next();
+                    res ~= action.actOnImport(_import, mod, null);
+                    break;
+                case Tok.Assign:
+                    // import B = A.A;
+                    //        ^- must be a single identifier
+                    // renamed import
+                    if (mod.packages.length != 0)
+                    {
+                        SLoc loc = mod.packages[0].tok.location;
+                        messages.report(RenameMustBeSingleIdent, loc);
+                    }
+                    //if (isStatic)
+                    //    error("Static imports cannot be renamed");
+                    lexer.next();
+                    Id name = mod.id;
+                    mod = parseModuleName();
+                    // create from mod and rename to `name`
+                    res ~= action.actOnImport(_import, mod, &name);
+                    break;
+                case Tok.Colon:
+                    // import A : a;
+                    // selective imports, potentially import A : print = a
+                    lexer.next();
+                    Decl d = action.actOnImport(_import, mod, null);
+                    // do-while on a comma:
+                    //   add explicit symbol
+                    do
+                    {
+                        Id sym = parseIdentifier();
+                        Id dummy;
+                        Id* name = null;
+                        if (skip(Tok.Assign))
+                        {
+                            dummy = sym;
+                            name = &dummy;
+                            sym = parseIdentifier();
+                        }
+                        action.addSelectiveImport(d, sym, name);
+
+                    } while (skip(Tok.Comma));
+                    require(Tok.Seperator);
+                    res ~= d;
+                    return res.safe();
+                case Tok.Seperator:
+                    done = true;
+                    break;
+                default:
+                    goto Lerror;
+            }
+            res ~= action.actOnImport(_import, mod, null);
+        }
+
+        require(Tok.Seperator);
+        return res.safe();
+Lerror:
+        while (!on_a (Tok.Seperator))
+            lexer.next();
+        return res.safe();
+    }
+
+    /**
+      Parse struct
+     */
+    Decl parseStruct(Id type, Id iden)
+    {
+        auto decl = action.actOnDeclarator(type, iden, null);
+
+        require(Tok.OpenBrace);
+
+        while(lexer.peek.isBasicType || lexer.peek.isIdentifier)
+        {
+            auto m_decl = parseDecl();
+            action.actOnStructMember(decl, m_decl); 
+/*            Id var_type = Id(lexer.next);
+            Id var_iden = Id(require(Tok.Identifier));
+            Token next = lexer.peek();
+            if (next.type == Tok.Seperator)
+            {
+                Token sep = lexer.next();
+                action.actOnStructMember(decl, var_type, var_iden, null);
+                continue;
+            }
+            else if (next.type == Tok.Assign)
+            {
+                Token assign = lexer.next();
+                Exp exp = parseExpression();
+                require(Tok.Seperator);
+                action.actOnStructMember(decl, var_type, var_iden, exp);
+                continue;
+            }
+            messages.report(UnexpectedTok, next.location).arg(next.getType);*/
+        }
+
+        require(Tok.CloseBrace);
+        
+        return decl;
+    }
+
+    /**
+      Parse statements.
+
+      This is the place to attack!
+     */
+    Stmt parseStatement()
+    {
+        Token t = lexer.peek;
+
+        switch(t.type)
+        {
+            case Tok.Return:
+                Token ret = lexer.next;
+                Exp exp;
+                if (lexer.peek.type != Tok.Seperator)
+                    exp = parseExpression();
+                require(Tok.Seperator);
+                return action.actOnReturnStmt(ret, exp);
+
+            /*
+               if (cond)
+                single statement | compound statement
+               [else
+                single statement | compound statement]
+             */
+            case Tok.If:
+                Token _if = lexer.next();
+
+                require(Tok.OpenParentheses);
+                Exp cond = parseExpression();
+                require(Tok.CloseParentheses);
+
+                Stmt thenB = parseSingleOrCompoundStatement();
+
+                // if there is no else part we use the if as token, to have
+                // something than can be passed along
+                Token _else = _if;
+                Stmt elseB;
+                if (lexer.peek.type == Tok.Else)
+                {
+                    _else = lexer.next;
+                    elseB = parseSingleOrCompoundStatement();
+                }
+
+                return action.actOnIfStmt(_if, cond, thenB, _else, elseB);
+
+            /*
+               while (cond)
+                single statement | compound statement
+             */
+            case Tok.While:
+                Token _while = lexer.next;
+                require(Tok.OpenParentheses);
+                Exp cond = parseExpression();
+                require(Tok.CloseParentheses);
+                Stmt bodyStmt = parseSingleOrCompoundStatement();
+                return action.actOnWhileStmt(_while, cond, bodyStmt);
+
+            /*
+               One of four things:
+               A declaration of a function/variable `type id ...`
+               A direct assignment `id = exp;`
+               An indirect assignment `id.id = exp`
+               Some sort of free standing expression
+
+               The assignments should be handled as binary expressions?
+             */
+            case Tok.Identifier:
+                Token iden = lexer.peek;
+                Token n = lexer.peek(1);
+                // Must be an decl, if we start with a basic type, or two
+                // identifiers in a row
+                if (iden.isBasicType() || iden.isIdentifier())
+                {
+                    if ( n.type == Tok.Star || n.type == Tok.OpenBracket)
+                    {
+                        int len = peekParseType;
+                        if(lexer.peek(len).type == Tok.Identifier && len != 0)
+                            return action.actOnDeclStmt(parseVarDecl());
+
+                        Exp exp = parseExpression();
+                        require(Tok.Seperator);
+                        return action.actOnExprStmt(exp);
+                    }
+                        
+                    if (n.isIdentifier())
+                        return action.actOnDeclStmt(parseVarDecl());
+
+                    // Expression: a.b, a = b, a(b) etc.
+                    Exp exp = parseExpression();
+                    require(Tok.Seperator);
+                    return action.actOnExprStmt(exp);
+                }
+
+            case Tok.Switch:
+                messages.report(UnexpectedTok, lexer.peek.location).arg(lexer.next.getType);
+                return null;
+
+            default:
+                if (t.isBasicType())
+                    goto case Tok.Identifier;
+                if (t.type == Tok.Star)
+                {
+                    auto exp = parseExpression();
+                    require(Tok.Seperator);
+                    return action.actOnExprStmt(exp);
+                }
+                messages.report(UnexpectedBeginStmt, lexer.peek.location).arg(lexer.next.getType);
+                return null;
+        }
+        messages.report(UnexpectedTok, t.location);
+        return null;
+    }
+
+    Decl parseVarDecl()
+    {
+        // manually hardcoded to only support "type id [= exp];"
+        // as that is the only thing the codegen understands
+        Id type = parseType;
+        Id id = Id(lexer.next);
+        Exp init;
+        if (skip(Tok.Assign))
+            init = parseExpression();
+        require(Tok.Seperator);
+        Decl d = action.actOnDeclarator(type, id, init);
+        return d;
+    }
+
+    /**
+      Parses a function/method given the already parsed return type and name
+     */
+    Decl parseFunc(ref Id type, ref Id name)
+    {
+        Decl func = action.actOnStartOfFunctionDef(type, name);
+        parseFuncArgs(func);
+
+        if(lexer.peek.type == Tok.Seperator)
+        {
+            lexer.next;
+            return func;
+        }
+        Stmt stmt = parseCompoundStatement();
+
+        return action.actOnEndOfFunction(func, stmt);
+    }
+
+    /**
+      Parse the function arguments, assumes current token is (.
+
+      Both the intitial paren and the ending paren is consumed.
+     */
+    void parseFuncArgs(Decl func)
+    {
+        require(Tok.OpenParentheses); // Remove the "(" token.
+
+        while(lexer.peek.type != Tok.CloseParentheses)
+        {
+            auto t = parseType();
+            Id i;
+            if(lexer.peek.type == Tok.Identifier)
+                i = parseIdentifier();
+            action.addFuncArg(func, t, i);
+
+            if(lexer.peek.type == Tok.Comma)
+                lexer.next;
+        }
+
+        require(Tok.CloseParentheses); // Remove the ")"
+    }
+
+    /**
+      Parse either a block, or a single statement as allowed after if, while
+      and for.
+     */
+    Stmt parseSingleOrCompoundStatement()
+    {
+        if (lexer.peek.type == Tok.OpenBrace)
+            return parseCompoundStatement();
+        return parseStatement();
+    }
+
+    /**
+      Parses a function-body or similar, expects an opening brace to be the
+      current token.
+      
+      Will consume both the starting { and ending }
+     */
+    Stmt parseCompoundStatement()
+    {
+        Token lbrace = require(Tok.OpenBrace);
+        SmallArray!(Stmt, 32) stmts; // Try to use the stack only
+        while (lexer.peek.type != Tok.CloseBrace)
+            stmts ~= parseStatement();
+        Token rbrace = require(Tok.CloseBrace);
+        return action.actOnCompoundStmt(lbrace, rbrace, stmts.unsafe());
+    }
+
+    Id parseIdentifier()
+    {
+        Token tok = lexer.next;
+
+        if (tok.type is Tok.Identifier)
+            return Id(tok);
+
+        messages.report(UnexpectedTokSingle, tok.location)
+            .arg(tok.getType)
+            .arg(Tok.Identifier);
+    }
+
+    ModuleName parseModuleName()
+    {
+        auto id = parseIdentifier();
+        ModuleName mod;
+        while (skip(Tok.Dot))
+        {
+            mod.packages ~= id;
+            if (lexer.peek.type != Tok.Identifier) {
+                messages.report(ExpectedIdAfterPackage, lexer.peek.location);
+                goto Lerror;
+            }
+            id = parseIdentifier();
+        }
+        mod.id = id;
+        return mod;
+Lerror:
+        while (!skip(Tok.Seperator))
+            lexer.next();
+        return mod;
+    }
+
+
+    /**
+      Parse a type - this includes pointer and array(at some point) types.
+     */
+    Id parseType()
+    {
+        Token type = lexer.next;
+
+        Id currentType;
+
+        if ( !(type.isBasicType || type.type == Tok.Identifier) )
+            messages.report(InvalidType, type.location);
+
+        currentType = Id(type);
+        type = lexer.peek;
+
+        while(type.type == Tok.Star || type.type == Tok.OpenBracket)
+        {
+            if(type.type == Tok.Star)
+            {
+                currentType = PointerId(currentType);
+                lexer.next;
+            }
+            else
+            {
+                lexer.next;
+                if(lexer.peek.type == Tok.Integer)
+                    currentType = ArrayId(currentType, action.actOnNumericConstant(require(Tok.Integer)));
+                require(Tok.CloseBracket);
+                
+            }
+            type = lexer.peek;
+        }
+
+        return currentType;
+    }
+
+    int peekParseType()
+    {
+        int i;
+        Token type = lexer.peek(i);
+
+        Id currentType;
+
+        if ( !(type.isBasicType || type.type == Tok.Identifier) )
+            return 0;
+
+        currentType = Id(type);
+        type = lexer.peek(++i);
+
+        while(type.type == Tok.Star || type.type == Tok.OpenBracket)
+        {
+            if(type.type == Tok.Star)
+            {
+                i++;
+            }
+            else
+            {
+                if(lexer.peek(i++).type != Tok.OpenBracket)
+                    return 0;
+                if(lexer.peek(i).type == Tok.Integer)
+                {
+                    i++;
+                    if(lexer.peek(i++).type != Tok.CloseBracket)    
+                        return 0;
+                }
+                else
+                    if(lexer.peek(i++).type != Tok.CloseBracket)
+                        return 0;
+                
+            }
+            type = lexer.peek(i);
+        }
+
+        return i;
+    }
+
+private:
+    // -- Expression parsing -- //
+    Exp parsePostfixExp(Exp target)
+    {
+        switch(lexer.peek.type)
+        {
+            case Tok.Dot:
+                switch(lexer.peek(1).type)
+                {
+                    case Tok.Identifier:
+                        Token op = lexer.next;
+                        Id member = Id(lexer.next);
+                        Exp exp = action.actOnMemberReference(target, op.location, member);
+                        return parsePostfixExp(exp);
+                    default:
+                        Token t = lexer.peek(1);
+                        messages.report(ExpectedIdAfterDot, t.location);
+                }
+            case Tok.OpenBracket:
+                Token open = lexer.next;
+                Exp index = parseExpression();
+                Token close = require(Tok.CloseBracket);
+                return action.actOnIndexEpr(target, open, index, close);
+            default:
+                return target;
+        }
+    }
+
+    Exp parseExpression(int p = 0)
+    {
+        auto exp = P();
+        Token next = lexer.peek();
+        BinOp* op = null;
+        while ((op = binary(next.type)) != null && op.prec >= p)
+        {
+            lexer.next();
+            int q = op.leftAssoc? 1 + op.prec : op.prec;
+            auto exp2 = parseExpression(q);
+            exp = action.actOnBinaryOp(next.location, op.operator, exp, exp2);
+            next = lexer.peek();
+        }
+
+        return exp;
+    }
+
+    Exp P()
+    {
+        Token next = lexer.next();
+        if (auto op = unary(next.type))
+            return action.actOnUnaryOp(next, parseExpression(op.prec));
+        else if (next.type == Tok.OpenParentheses)
+        {
+            auto e = parseExpression(0);
+            require(Tok.CloseParentheses);
+            return e;
+        }
+        else if (next.type == Tok.Identifier)
+        {
+            Exp value = action.actOnIdentifierExp(Id(next));
+            Exp iden = parsePostfixExp(value);
+            switch(lexer.peek.type)
+            {
+                case Tok.OpenParentheses:
+                    Token lp = lexer.next;
+                    SmallArray!(Exp, 8) args;
+                    while(lexer.peek.type != Tok.CloseParentheses)
+                    {
+                        if(lexer.peek.type == Tok.Comma)
+                            lexer.next;
+                        args ~= parseExpression();
+                    }
+
+                    Token rp = lexer.next();
+                    return action.actOnCallExpr(iden, lp, args.unsafe(), rp);
+
+                default:
+                    return iden;
+            }
+        }
+        else if (next.type == Tok.Cast)
+            return parseCast(next);
+        else if (next.type == Tok.Integer)
+            return action.actOnNumericConstant(next);
+        else if (next.type == Tok.String)
+            return action.actOnStringExp(next);
+
+        messages.report(ExpectedExp, next.location)
+            .fatal(ExitLevel.Parser);
+        return null;
+    }
+
+    Exp parseCast(ref Token _cast)
+    {
+        require(Tok.OpenParentheses);
+        auto next = lexer.next;
+        if(!next.isBasicType && !next.isIdentifier)
+            messages.report(ExpectedCastType, next.location);
+        
+        require(Tok.CloseParentheses);
+        auto exp = P();
+        return action.actOnCastExpr(_cast, Id(next), exp);
+    }
+
+    struct UnOp
+    {
+        Tok tokenType;
+        int prec;
+    }
+
+    static const UnOp[] _unary =
+    [
+        {Tok.Minus, 4},
+        {Tok.Star, 4}
+    ];
+    UnOp* unary(Tok t)
+    {
+        foreach (ref op; _unary)
+            if (op.tokenType == t)
+                return &op;
+        return null;
+    }
+
+    struct BinOp
+    {
+        Tok tokenType;
+        int prec;
+        bool leftAssoc;
+        Operator operator;
+    }
+
+    static const BinOp[] _binary =
+    [
+        {Tok.Assign,    1, false, Operator.Assign},
+
+        {Tok.Eq,        2, true, Operator.Eq},
+        {Tok.Ne,        2, true, Operator.Ne},
+
+        {Tok.Lt,        2, true, Operator.Lt},
+        {Tok.Le,        2, true, Operator.Le},
+        {Tok.Gt,        2, true, Operator.Gt},
+        {Tok.Ge,        2, true, Operator.Ge},
+
+        {Tok.Plus,      3, true, Operator.Add},
+        {Tok.Minus,     3, true, Operator.Sub},
+
+        {Tok.Star,      5, true, Operator.Mul},
+        {Tok.Slash,     5, true, Operator.Div},
+        {Tok.Percent,   5, true, Operator.Mod}
+    ];
+    BinOp* binary(Tok t)
+    {
+        foreach (ref op; _binary)
+            if (op.tokenType == t)
+                return &op;
+        return null;
+    }
+
+private:
+
+    Token require(Tok t)
+    {
+        if (lexer.peek().type != t)
+            messages.report(UnexpectedTokSingle, lexer.peek.location)
+                .arg(lexer.peek.getType)
+                .arg(t);
+        return lexer.next();
+    }
+
+    bool skip(Tok t)
+    {
+        if (lexer.peek().type != t)
+            return false;
+        lexer.next();
+        return true;
+    }
+
+    bool on_a(Tok t)
+    {
+        return lexer.peek.type == t;
+    }
+
+    Lexer lexer;
+    SourceManager sm;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/array_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,21 @@
+struct Array
+{
+    int[] data;
+    int length;
+}
+
+void insert(Array a, int v)
+{
+    a.length = a.length + 1;
+    a.data[a.length - 1] = v;
+}
+
+int main()
+{
+    Array a;
+    a.length = 0;
+
+    insert(a, 5);
+    
+    return a.data[0];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/basic_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,19 @@
+
+int x = 4;
+
+int main()
+{
+    long var1 = 1;
+    short var2 = 2;
+    nice(var1, var2);
+    return var2;
+}
+
+int nice(long s, short t)
+{
+    byte x = 5 + t;
+    t = 5 + 1 * 5 * s + t;
+    return 2 * (t + -1) - x;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/basic_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,8 @@
+//fail
+int main()
+{
+    int x = y;
+    int y = 1;
+    return y;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/basic_types_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,8 @@
+int main()
+{
+    // test some basic type conversions
+    byte a = 2;
+    short b = 3 * a;
+    int c = b + a;
+    long d = c * a / b;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/basic_types_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,21 @@
+int main()
+{
+    byte a = 2;
+    short b = 3 * a;
+    int c = b + a;
+    long d = c * a / b;
+
+    d = itol(2);
+    d = itol(a);
+    d = itol(b);
+    d = itol(c);
+
+    c = stoi(a);
+    c = stoi(b);
+
+    return 3;
+}
+
+long itol(int x) { return x; }
+int stoi(short x) { return x; }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/bool_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,6 @@
+int main()
+{
+    bool b = 1 < 2;
+    return b;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/bool_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,5 @@
+int main()
+{
+    return 42 == 42;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/cast_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,12 @@
+
+int main()
+{
+    byte y = 44;
+
+    int b = cast(int)y * 66;
+
+    if(b == 2904)
+        return 0;
+    else
+        return 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/cast_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,14 @@
+
+
+
+int main()
+{
+    byte y = 44;
+
+    int b = y * cast(byte)66;
+
+    if(b == 88)
+        return 0;
+    else
+        return 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/func_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,20 @@
+
+
+int main()
+{
+    testStruct t;
+    t.x = 5;
+
+    return t.x;
+}
+
+testStruct m(testStruct t)
+{
+    t.x = t.x - 5;
+    return t;
+}
+
+struct testStruct
+{
+    int x;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/if_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,19 @@
+
+int x = 4;
+
+int main()
+{
+    long var1 = 1;
+    short var2 = 2;
+    return nice(var1, var2);
+}
+
+int nice(long s, short t)
+{
+    byte x = 5 + t;
+    if (x)
+        t = 5 + 1 * 5 * s + t;
+    return 2 * (t + -1) - x;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/if_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,20 @@
+
+int x = 4;
+
+int main()
+{
+    long var1 = 1;
+    short var2 = 2;
+    return nice(var1, var2);
+}
+
+int nice(long s, short t)
+{
+    byte x = 5 + t;
+    if (x)
+        if (s)
+            t = 5 + 1 * 5 * s + t;
+    return 2 * (t + -1) - x;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/if_3.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,11 @@
+int main()
+{
+    int x = 0;
+    int y = 1;
+    if (x)
+        return 1;
+    else if (y == 2)
+        return 1;
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/if_4.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,13 @@
+int main()
+{
+    int x = 0;
+    int y = 1;
+    if (x)
+        return 1;
+    else if (y == 2)
+        return 1;
+    else
+        y = 0;
+    return y;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/math_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,6 @@
+int main()
+{
+    int x = 2;
+    int y = 3;
+    return 2 * (x + y);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/math_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,6 @@
+int main()
+{
+    int x = 1 + 2 * 3 + 4 + 5;
+    int y = x - x;
+    return y + x - 15;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/math_3.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,6 @@
+//fail
+int main()
+{
+    int x = x;
+    return x;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/sarray_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,7 @@
+int main()
+{
+    int[10] a;
+    a[0] = 1;
+    a[1] = a[0];
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/sarray_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,8 @@
+//fail
+int main()
+{
+    int[10] a;
+    // static array assignment is illegal - we fail for other reasons though
+    int[10] b = a;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/scope_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,7 @@
+//fail
+int main()
+{
+    int x = y;
+    int y = 1;
+    return x;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/scope_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,11 @@
+//fail
+int main()
+{
+    int x = 10;
+    while (x > 0)
+    {
+        int y = 1;
+        x = x -y;
+    }
+    return y;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/scope_3.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,9 @@
+int y = 0;
+
+int main()
+{
+    return x + y;
+}
+
+int x = 0;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/struct_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,9 @@
+
+struct S
+{
+}
+
+void main()
+{
+    S s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/struct_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,13 @@
+
+struct S
+{
+    int a;
+    int b;
+}
+
+void main()
+{
+    S s;
+    s.a = 2;
+    s.b = s.a;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/struct_3.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,11 @@
+
+struct S
+{
+    int a;
+}
+
+void main()
+{
+    S s;
+    S s2 = s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/struct_4.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,18 @@
+
+struct A
+{
+    int a;
+}
+
+struct B
+{
+    int b;
+    A a;
+}
+
+void main()
+{
+    B b;
+    b.a.a = 1;
+    b.b = 2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/struct_5.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,17 @@
+// Test forward references in struct members
+struct B
+{
+    int b;
+    A a;
+}
+
+struct A
+{
+    int a;
+}
+
+void main()
+{
+    B b;
+    b.b = 2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/switch_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,8 @@
+
+void main(int x)
+{
+    switch (x)
+    {
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/switch_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,9 @@
+
+void main(int x)
+{
+    switch (x)
+    {
+        case 1:
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/switch_3.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,15 @@
+
+void main(int x)
+{
+    switch (x)
+    {
+        case 1, 2:
+            x = 2;
+            return;
+        case 3, 4:
+            x = 1;
+            return;
+        default:
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/switch_4.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,16 @@
+
+int main(int x)
+{
+    switch (x)
+    {
+        case 1, 2:
+            x = 2;
+            return x;
+        case 3, 4:
+            x = 1;
+            return x;
+        default:
+            return 0;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/switch_5.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,12 @@
+//fail
+int main(int x)
+{
+    switch (x)
+    {
+        default:
+            return 0;
+        default:
+            return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/switch_6.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,12 @@
+//fail
+int main(int x)
+{
+    switch (x)
+    {
+        case 1, 2:
+            return 0;
+        case 2, 3:
+            return 1;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/while_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,8 @@
+int main()
+{
+    int x = 10;
+    while (x > 0)
+        x = x - 1;
+    return x;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/code/while_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,14 @@
+int main()
+{
+    int x = 10;
+    int res = 0;
+    while (x > 0)
+    {
+        res = res + x;
+        x = x - 1;
+    }
+    if (res == 55)
+        return 0;
+    return 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/lexer/Comments.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,33 @@
+/*
+
+
+   /++
+   +++++
+
+
+   /++++
+
+   */
+
+int i = 0;
+ /// lalalala
+
+/****
+  */
+
+/+
+
+/+
+
++/
+
+/+
+
++/
+
++/
+
+/+ /+/
+fdsafasdf
++/ +/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/lexer/Comments1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,17 @@
+/*
+
+
+*/
+
+/*/
+
+*/
+
+/+
+
++/
+
+
+/+/
+
++/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/lexer/Comments1.d.orig	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,17 @@
+/*
+
+
+*/
+
+/*
+
+*/
+
+/+
+
++/
+
+
+/+/
+
++/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/lexer/Comments2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,4 @@
+//fail
+
+/+ 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/lexer/Comments2.d.orig	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,3 @@
+//fail
+/+ 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/parser/basic_type_char_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,10 @@
+
+
+int main()
+{
+    char c;
+    wchar w;
+    dchar d;
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/parser/string_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,27 @@
+
+int main()
+{
+    /* All examples taken from D's Language site */
+
+    char[4]     s1  = "food";
+
+    char[5]     s2  = r"hello";
+    char[15]    s3  = r"c:\root\foo.exe";
+    char[4]     s4  = r"ab\n";
+
+    char[5]     s5  = `hello`;
+    char[15]    s6  = `c:\root\foo.exe`;
+    char[4]     s7  = `ab\n`;
+    char[4]     s9  = `abn\`;
+
+    char[5]     s10 = "hello";
+    char[15]    s11 = "c:\\root\\foo.exe";
+    char[3]     s12 = "ab\n";
+    char[3]     s13 = "ab
+";
+
+    char[1]     s14 = x"0A";
+    char[6]     s15 = x"00 FBCD 32FD 0A";
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/parser/struct_method_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,17 @@
+module struct_method_1;
+
+struct A
+{
+    int x;
+    int foo(int i)
+    {
+        return i;
+    }
+}
+
+int main()
+{
+    A a;
+    a.x = 6;
+    return a.foo(a.x);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/run.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,200 @@
+module run.d;
+
+import tango.io.Stdout,
+       tango.core.Array,
+       tango.io.FilePath,
+       tango.io.GrowBuffer,
+       tango.io.UnicodeFile,
+       tango.io.stream.BufferStream,
+       tango.text.Util,
+       tango.io.protocol.Reader,
+       tango.io.protocol.Writer,
+       tango.text.Unicode,
+       tango.sys.Process;
+
+
+enum 
+{
+    SuccessSuccess,
+    SuccessFailure,
+    FailureSuccess,
+    FailureFailure,
+}
+
+char[] prog = "./Dang";
+
+void main(char[][] args)
+{
+    auto cPath = FilePath("tests");
+
+    ubyte success_success, success_failure, failure_failure, failure_success;
+
+    foreach( path ; cPath.toList((FilePath path, bool isFolder){return isFolder;}))
+    {
+        Stdout(path.name)(":").newline;
+        auto paths = path.toList(
+                (FilePath path, bool isFolder)
+                {
+                    if(path.ext == "d" && path.name[0] != '.')
+                        return true;
+                    return false;
+                });
+        sort(paths, (FilePath a, FilePath b) { return a.name < b.name; });
+        foreach (p ; paths)
+        {
+            auto test = new Test(p);    
+            ubyte result = test.run();
+
+            switch(result)
+            {
+                case SuccessSuccess:
+                    success_success++;
+                    break;
+                case SuccessFailure:
+                    success_failure++;
+                    break;
+                case FailureFailure:
+                    failure_failure++;
+                    break;
+                case FailureSuccess:
+                    failure_success++;
+                    break;
+            }
+
+        }
+    }
+
+    Stdout().newline.newline()
+        ("Result:").newline()
+        ("  - Success/Success:   ")(success_success).newline()
+        ("  - Success/Failure:   ")(success_failure).newline()
+        ("  - Failure/Failure:  ")(failure_failure).newline()
+        ("  - Failure/Success:  ")(failure_success).newline;
+}
+
+class Test
+{
+    enum TestValue
+    {
+        Success = 0,
+        Lexer = 2,
+        Parser = 3,
+        Gen = 4,
+
+        Fail = 100
+    }
+
+    FilePath target;
+
+    TestValue[int] testValues;
+    
+    public this(FilePath target)
+    {
+        this.target = target;
+    }
+
+    public ubyte run()
+    {
+        auto process = new Process(prog,"--gen-llvm",target.path~target.file);
+
+        auto file = new UnicodeFile!(char)(target.path~target.file, Encoding.UTF_8);
+
+        TestValue mode;
+
+        char[] data = file.read;
+        char[][] commands = split(splitLines(data)[0], " ");
+        if(commands[0] == "//fail")
+        {
+            mode = TestValue.Fail;
+            if(commands.length > 1)
+            {
+                try
+                {
+                    int i = Integer.toInt(commands[1]);
+                    if(i in testValues)
+                        mode = testValues[i];
+                }
+                catch{}
+            }
+        }
+/*        if(data.length > 6 && data[0..6] == "//fail")
+        {
+            char[] str = data.splitLines()[0][6..$];
+
+            switch(toLower(trim(str)))
+            {
+                case "fail":
+                case "failure":
+                    mode = 1;
+                    break;
+                default:
+                    mode = 0;
+            }
+        }
+*/
+        Stdout.format("  {,-25}", target.file);
+
+        process.execute;
+        auto result = process.wait;
+
+        /*
+        if(result.status == 0)
+        {
+            auto llvm_process = new Process("llvm-as");
+            llvm_process.execute;
+            llvm_process.stdin.copy(process.stdout);
+            llvm_process.stdin.close();
+            result = llvm_process.wait;
+        }
+        */
+
+        return resultOf(result.status, mode);
+    }
+
+    private int resultOf(int status, TestValue mode)
+    {
+        char[] good(char[] s)
+        {
+            version (Posix)
+                return "\033[1;32m" ~ s ~ "\033[m";
+            else
+                return s;
+        }
+
+        char[] bad(char[] s)
+        {
+            version (Posix)
+                return "\033[1;31m" ~ s ~ "\033[m";
+            else
+                return s;
+        }
+
+        if(status == 0)
+        {
+            if(mode == TestValue.Success)
+            {
+                Stdout(good("SUCCESS")).newline;
+                return SuccessSuccess;
+            }
+            if(mode == TestValue.Fail)
+            {
+                Stdout(bad("SUCCESS - Unexpected")).newline;
+                return FailureSuccess;
+            }
+        }
+        else
+        {
+            if(mode == TestValue.Fail)
+            {
+                Stdout(good("FAILURE")).newline;
+                return FailureFailure;
+            }
+            if(mode == TestValue.Success)
+            {
+                Stdout(bad("FAILURE - Unexpected")).newline;
+                return SuccessFailure;
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/sema/deref_1.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,7 @@
+//fail
+int main()
+{
+    int a = 2;
+    int b = *a;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/sema/deref_2.d	Tue Aug 12 18:14:56 2008 +0200
@@ -0,0 +1,10 @@
+int main()
+{
+    int *a;
+    int *b;
+    a = b;
+    *a = 1;
+
+    return *a == *b;
+}
+