# HG changeset patch # User Anders Johnsen # Date 1218557696 -7200 # Node ID d3c148ca429b86498eba8f68f7b8fa1445b1d895 # Parent 8387cbaa85ab243972100d05871972f34bea7556 Major moving of files. all src now goes into src, all docs in docs. diff -r 8387cbaa85ab -r d3c148ca429b ast/Decl.d --- 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;} -} - diff -r 8387cbaa85ab -r d3c148ca429b ast/Expr.d --- 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; } -} - diff -r 8387cbaa85ab -r d3c148ca429b ast/Stmt.d --- 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; } -} diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/CANDYDOC.txt --- 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. diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/candy.ddoc --- 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 = - - - -$(TITLE) - - - - - - -
-
- - - -

$(TITLE)

$(BODY)
- Page was generated with - - on $(DATETIME) -
-
-$(ADD_MODULES) - - - -DDOC_DECL = - -$(DT $0) - - - -DDOC_PSYMBOL = -$0 - - - -DDOC_MEMBERS = - -$(DL $0) - - - -DDOC_PARAM_ID = -$0 - - -DDOC_PARAM =$0 -ADD_MODULES = -MODULE =explorer.packageExplorer.addModule("$0"); -MODULE_FULL =explorer.packageExplorer.addModuleFull("$0"); diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/explorer.js --- 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 = ""; - } -} diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/ie56hack.css --- 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)); -} diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/bg.gif Binary file doc/candydoc/img/bg.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/candydoc.gif Binary file doc/candydoc/img/candydoc.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/alias.gif Binary file doc/candydoc/img/outline/alias.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/bg.gif Binary file doc/candydoc/img/outline/bg.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/class.gif Binary file doc/candydoc/img/outline/class.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/enum.gif Binary file doc/candydoc/img/outline/enum.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/func.gif Binary file doc/candydoc/img/outline/func.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/module.gif Binary file doc/candydoc/img/outline/module.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/package.gif Binary file doc/candydoc/img/outline/package.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/struct.gif Binary file doc/candydoc/img/outline/struct.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/template.gif Binary file doc/candydoc/img/outline/template.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/outline/var.gif Binary file doc/candydoc/img/outline/var.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/package/bg.gif Binary file doc/candydoc/img/package/bg.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/shim.gif Binary file doc/candydoc/img/tree/shim.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/tb.gif Binary file doc/candydoc/img/tree/tb.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/tbr.gif Binary file doc/candydoc/img/tree/tbr.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/tbrm.gif Binary file doc/candydoc/img/tree/tbrm.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/tbrp.gif Binary file doc/candydoc/img/tree/tbrp.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/tr.gif Binary file doc/candydoc/img/tree/tr.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/trm.gif Binary file doc/candydoc/img/tree/trm.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/img/tree/trp.gif Binary file doc/candydoc/img/tree/trp.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/modules.ddoc --- 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) diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/style.css --- 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 diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/tree.js --- 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();"); -} diff -r 8387cbaa85ab -r d3c148ca429b doc/candydoc/util.js --- 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; -} diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/CANDYDOC.txt --- /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. diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/candy.ddoc --- /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 = + + + +$(TITLE) + + + + + + +
+
+ + + +

$(TITLE)

$(BODY)
+ Page was generated with + + on $(DATETIME) +
+
+$(ADD_MODULES) + + + +DDOC_DECL = + +$(DT $0) + + + +DDOC_PSYMBOL = +$0 + + + +DDOC_MEMBERS = + +$(DL $0) + + + +DDOC_PARAM_ID = +$0 + + +DDOC_PARAM =$0 +ADD_MODULES = +MODULE =explorer.packageExplorer.addModule("$0"); +MODULE_FULL =explorer.packageExplorer.addModuleFull("$0"); diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/explorer.js --- /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 = ""; + } +} diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/ie56hack.css --- /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)); +} diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/bg.gif Binary file docs/candydoc/img/bg.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/candydoc.gif Binary file docs/candydoc/img/candydoc.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/alias.gif Binary file docs/candydoc/img/outline/alias.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/bg.gif Binary file docs/candydoc/img/outline/bg.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/class.gif Binary file docs/candydoc/img/outline/class.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/enum.gif Binary file docs/candydoc/img/outline/enum.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/func.gif Binary file docs/candydoc/img/outline/func.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/module.gif Binary file docs/candydoc/img/outline/module.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/package.gif Binary file docs/candydoc/img/outline/package.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/struct.gif Binary file docs/candydoc/img/outline/struct.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/template.gif Binary file docs/candydoc/img/outline/template.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/outline/var.gif Binary file docs/candydoc/img/outline/var.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/package/bg.gif Binary file docs/candydoc/img/package/bg.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/shim.gif Binary file docs/candydoc/img/tree/shim.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/tb.gif Binary file docs/candydoc/img/tree/tb.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/tbr.gif Binary file docs/candydoc/img/tree/tbr.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/tbrm.gif Binary file docs/candydoc/img/tree/tbrm.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/tbrp.gif Binary file docs/candydoc/img/tree/tbrp.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/tr.gif Binary file docs/candydoc/img/tree/tr.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/trm.gif Binary file docs/candydoc/img/tree/trm.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/img/tree/trp.gif Binary file docs/candydoc/img/tree/trp.gif has changed diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/modules.ddoc --- /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) diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/style.css --- /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 diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/tree.js --- /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();"); +} diff -r 8387cbaa85ab -r d3c148ca429b docs/candydoc/util.js --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b dsss.conf --- 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 - - diff -r 8387cbaa85ab -r d3c148ca429b src/ast/Decl.d --- /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;} +} + diff -r 8387cbaa85ab -r d3c148ca429b src/ast/Expr.d --- /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; } +} + diff -r 8387cbaa85ab -r d3c148ca429b src/ast/Stmt.d --- /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; } +} diff -r 8387cbaa85ab -r d3c148ca429b src/basic/Message.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b src/basic/Messages.d --- /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'") + ]; +} + diff -r 8387cbaa85ab -r d3c148ca429b src/basic/SmallArray.d --- /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; + } +} + diff -r 8387cbaa85ab -r d3c148ca429b src/basic/SourceLocation.d --- /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); + } +} + diff -r 8387cbaa85ab -r d3c148ca429b src/basic/SourceManager.d --- /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; + } + } +} + diff -r 8387cbaa85ab -r d3c148ca429b src/lexer/Keyword.d --- /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 + ]; +} diff -r 8387cbaa85ab -r d3c148ca429b src/lexer/Lexer.d --- /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[':'] = : + symbolFunctions['.'] = ˙ + symbolFunctions[','] = , + symbolFunctions['='] = &eq; + symbolFunctions['!'] = ≠ + symbolFunctions['<'] = ≤ + symbolFunctions['>'] = ≥ + symbolFunctions['+'] = + + symbolFunctions['-'] = − + symbolFunctions['*'] = ☆ + 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 +} + diff -r 8387cbaa85ab -r d3c148ca429b src/lexer/Token.d --- /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" + ]; +} diff -r 8387cbaa85ab -r d3c148ca429b src/parser/Action.d --- /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 +{ +} + diff -r 8387cbaa85ab -r d3c148ca429b src/parser/Parser.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/array_1.d --- /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]; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/basic_1.d --- /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; +} + + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/basic_2.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/basic_types_1.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/basic_types_2.d --- /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; } + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/bool_1.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/bool_2.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/cast_1.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/cast_2.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/func_1.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/if_1.d --- /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; +} + + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/if_2.d --- /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; +} + + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/if_3.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/if_4.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/math_1.d --- /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); +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/math_2.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/math_3.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/sarray_1.d --- /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]; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/sarray_2.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/scope_1.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/scope_2.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/scope_3.d --- /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; + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/struct_1.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/struct_2.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/struct_3.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/struct_4.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/struct_5.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/code/switch_1.d --- /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) + { + } +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/switch_2.d --- /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: + } +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/switch_3.d --- /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: + } +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/switch_4.d --- /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; + } +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/switch_5.d --- /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; + } +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/switch_6.d --- /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; + } +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/while_1.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/code/while_2.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/lexer/Comments.d --- /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 ++/ +/ + diff -r 8387cbaa85ab -r d3c148ca429b tests/lexer/Comments1.d --- /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 @@ +/* + + +*/ + +/*/ + +*/ + +/+ + ++/ + + +/+/ + ++/ diff -r 8387cbaa85ab -r d3c148ca429b tests/lexer/Comments1.d.orig --- /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 @@ +/* + + +*/ + +/* + +*/ + +/+ + ++/ + + +/+/ + ++/ diff -r 8387cbaa85ab -r d3c148ca429b tests/lexer/Comments2.d --- /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 + +/+ + diff -r 8387cbaa85ab -r d3c148ca429b tests/lexer/Comments2.d.orig --- /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 +/+ + diff -r 8387cbaa85ab -r d3c148ca429b tests/parser/basic_type_char_1.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/parser/string_1.d --- /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; +} diff -r 8387cbaa85ab -r d3c148ca429b tests/parser/struct_method_1.d --- /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); +} diff -r 8387cbaa85ab -r d3c148ca429b tests/run.d --- /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; + } + } + } +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/sema/deref_1.d --- /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; +} + diff -r 8387cbaa85ab -r d3c148ca429b tests/sema/deref_2.d --- /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; +} +