Index: .poseidon
==================================================================
--- .poseidon
+++ .poseidon
@@ -44,13 +44,14 @@
build.bat
build.sh
+ builddoc.bat
readme.txt
ADDED builddoc.bat
Index: builddoc.bat
==================================================================
--- builddoc.bat
+++ builddoc.bat
@@ -0,0 +1,6 @@
+@setlocal ENABLEDELAYEDEXPANSION
+@set ARGS=
+@for %%I in (main.d polemy\*.d tricks\*.d) do @set ARGS=!ARGS! %%I
+@if not exist bin mkdir bin
+@echo dmd -o- -Dddoc doc\candydoc\candy.ddoc doc\candydoc\modules.ddoc %ARGS%
+@dmd -o- -Dddoc doc\candydoc\candy.ddoc doc\candydoc\modules.ddoc %ARGS%
ADDED doc/candydoc/CANDYDOC.txt
Index: doc/candydoc/CANDYDOC.txt
==================================================================
--- doc/candydoc/CANDYDOC.txt
+++ doc/candydoc/CANDYDOC.txt
@@ -0,0 +1,55 @@
+
+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 version 0.80. For latest release see
+http://trac.dsource.org/projects/helix/
+
+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.
ADDED doc/candydoc/candy.ddoc
Index: doc/candydoc/candy.ddoc
==================================================================
--- doc/candydoc/candy.ddoc
+++ doc/candydoc/candy.ddoc
@@ -0,0 +1,50 @@
+DDOC =
+
+
+
+$(TITLE)
+
+
+
+
+
+
+
+
+$(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");
ADDED doc/candydoc/explorer.js
Index: doc/candydoc/explorer.js
==================================================================
--- doc/candydoc/explorer.js
+++ doc/candydoc/explorer.js
@@ -0,0 +1,310 @@
+/* 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.addModule = function(mod)
+ {
+ 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);
+ // modified by k.inaba : link for toplevel module
+ if (path.length == 1)
+ node.setRef(path[0] + ".html");
+ }
+
+ 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)
+ node.setRef(path[i] + ".html");
+ }
+ }
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 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 = "";
+ }
+}
ADDED doc/candydoc/ie56hack.css
Index: doc/candydoc/ie56hack.css
==================================================================
--- doc/candydoc/ie56hack.css
+++ doc/candydoc/ie56hack.css
@@ -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));
+}
ADDED doc/candydoc/img/bg.gif
Index: doc/candydoc/img/bg.gif
==================================================================
--- doc/candydoc/img/bg.gif
+++ doc/candydoc/img/bg.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/candydoc.gif
Index: doc/candydoc/img/candydoc.gif
==================================================================
--- doc/candydoc/img/candydoc.gif
+++ doc/candydoc/img/candydoc.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/alias.gif
Index: doc/candydoc/img/outline/alias.gif
==================================================================
--- doc/candydoc/img/outline/alias.gif
+++ doc/candydoc/img/outline/alias.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/bg.gif
Index: doc/candydoc/img/outline/bg.gif
==================================================================
--- doc/candydoc/img/outline/bg.gif
+++ doc/candydoc/img/outline/bg.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/class.gif
Index: doc/candydoc/img/outline/class.gif
==================================================================
--- doc/candydoc/img/outline/class.gif
+++ doc/candydoc/img/outline/class.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/enum.gif
Index: doc/candydoc/img/outline/enum.gif
==================================================================
--- doc/candydoc/img/outline/enum.gif
+++ doc/candydoc/img/outline/enum.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/func.gif
Index: doc/candydoc/img/outline/func.gif
==================================================================
--- doc/candydoc/img/outline/func.gif
+++ doc/candydoc/img/outline/func.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/module.gif
Index: doc/candydoc/img/outline/module.gif
==================================================================
--- doc/candydoc/img/outline/module.gif
+++ doc/candydoc/img/outline/module.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/package.gif
Index: doc/candydoc/img/outline/package.gif
==================================================================
--- doc/candydoc/img/outline/package.gif
+++ doc/candydoc/img/outline/package.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/struct.gif
Index: doc/candydoc/img/outline/struct.gif
==================================================================
--- doc/candydoc/img/outline/struct.gif
+++ doc/candydoc/img/outline/struct.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/template.gif
Index: doc/candydoc/img/outline/template.gif
==================================================================
--- doc/candydoc/img/outline/template.gif
+++ doc/candydoc/img/outline/template.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/outline/var.gif
Index: doc/candydoc/img/outline/var.gif
==================================================================
--- doc/candydoc/img/outline/var.gif
+++ doc/candydoc/img/outline/var.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/package/bg.gif
Index: doc/candydoc/img/package/bg.gif
==================================================================
--- doc/candydoc/img/package/bg.gif
+++ doc/candydoc/img/package/bg.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/shim.gif
Index: doc/candydoc/img/tree/shim.gif
==================================================================
--- doc/candydoc/img/tree/shim.gif
+++ doc/candydoc/img/tree/shim.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/tb.gif
Index: doc/candydoc/img/tree/tb.gif
==================================================================
--- doc/candydoc/img/tree/tb.gif
+++ doc/candydoc/img/tree/tb.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/tbr.gif
Index: doc/candydoc/img/tree/tbr.gif
==================================================================
--- doc/candydoc/img/tree/tbr.gif
+++ doc/candydoc/img/tree/tbr.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/tbrm.gif
Index: doc/candydoc/img/tree/tbrm.gif
==================================================================
--- doc/candydoc/img/tree/tbrm.gif
+++ doc/candydoc/img/tree/tbrm.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/tbrp.gif
Index: doc/candydoc/img/tree/tbrp.gif
==================================================================
--- doc/candydoc/img/tree/tbrp.gif
+++ doc/candydoc/img/tree/tbrp.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/tr.gif
Index: doc/candydoc/img/tree/tr.gif
==================================================================
--- doc/candydoc/img/tree/tr.gif
+++ doc/candydoc/img/tree/tr.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/trm.gif
Index: doc/candydoc/img/tree/trm.gif
==================================================================
--- doc/candydoc/img/tree/trm.gif
+++ doc/candydoc/img/tree/trm.gif
cannot compute difference between binary files
ADDED doc/candydoc/img/tree/trp.gif
Index: doc/candydoc/img/tree/trp.gif
==================================================================
--- doc/candydoc/img/tree/trp.gif
+++ doc/candydoc/img/tree/trp.gif
cannot compute difference between binary files
ADDED doc/candydoc/modules.ddoc
Index: doc/candydoc/modules.ddoc
==================================================================
--- doc/candydoc/modules.ddoc
+++ doc/candydoc/modules.ddoc
@@ -0,0 +1,10 @@
+MODULES =
+ $(MODULE main)
+ $(MODULE tricks.tricks)
+ $(MODULE tricks.test)
+ $(MODULE polemy._common)
+ $(MODULE polemy.lex)
+ $(MODULE polemy.parse)
+ $(MODULE polemy.ast)
+ $(MODULE polemy.eval)
+ $(MODULE polemy.value)
ADDED doc/candydoc/style.css
Index: doc/candydoc/style.css
==================================================================
--- doc/candydoc/style.css
+++ doc/candydoc/style.css
@@ -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;
+}
ADDED doc/candydoc/tree.js
Index: doc/candydoc/tree.js
==================================================================
--- doc/candydoc/tree.js
+++ doc/candydoc/tree.js
@@ -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();");
+}
ADDED doc/candydoc/util.js
Index: doc/candydoc/util.js
==================================================================
--- doc/candydoc/util.js
+++ doc/candydoc/util.js
@@ -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;
+}
Index: main.d
==================================================================
--- main.d
+++ main.d
@@ -11,10 +11,11 @@
import polemy.lex;
import polemy.parse;
import polemy.ast;
import polemy.eval;
+/// Tenuki Read-Eval-Print-Loop
class REPL
{
Table ctx;
string buf;
Value lastVal;
@@ -57,10 +58,12 @@
version(unittest) {
bool success = false;
static ~this(){ if(!success){writeln("(press enter to exit)"); readln();} }
}
+/// Entry point. If args.length==1, invoke REPL.
+/// Otherwise interpret the argument as a filename.
void main( string[] args )
{
version(unittest) success=true;
if( args.length <= 1 )
Index: polemy/ast.d
==================================================================
--- polemy/ast.d
+++ polemy/ast.d
@@ -6,62 +6,70 @@
*/
module polemy.ast;
import polemy._common;
import polemy.lex;
+///
abstract class AST
{
immutable LexPosition pos;
mixin SimpleConstructor;
}
+///
class StrLiteral : AST
{
string data;
mixin SimpleClass;
}
+///
class IntLiteral : AST
{
BigInt data;
mixin SimpleClass;
this(immutable LexPosition pos, long n) {super(pos); data = n;}
this(immutable LexPosition pos, BigInt n) {super(pos); data = n;}
this(immutable LexPosition pos, string n) {super(pos); data = BigInt(n);}
}
+///
class VarExpression : AST
{
string var;
mixin SimpleClass;
}
+///
class LayeredExpression : AST
{
string lay;
AST expr;
mixin SimpleClass;
}
+///
class LetExpression : AST
{
string var;
string layer;
AST init;
AST expr;
mixin SimpleClass;
}
+///
class FuncallExpression : AST
{
AST fun;
AST[] args;
this(immutable LexPosition pos, AST fun, AST[] args...)
{ super(pos); this.fun=fun; this.args=args.dup; }
mixin SimpleClass;
}
+///
class FunLiteral : AST
{
string[] params;
AST funbody;
mixin SimpleClass;
@@ -70,16 +78,17 @@
/// Handy Generator for AST nodes. To use this, mixin EasyAst;
/*mixin*/
template EasyAST()
{
+ ///
template genEast(T)
{ T genEast(P...)(P ps) { return new T(LexPosition.dummy, ps); } }
- alias genEast!StrLiteral strl;
- alias genEast!IntLiteral intl;
- auto fun(string[] xs, AST ps) { return genEast!FunLiteral(xs,ps); } // to help type inference of D
- alias genEast!VarExpression var;
- alias genEast!LayeredExpression lay;
- alias genEast!LetExpression let;
- alias genEast!FuncallExpression call;
+ alias genEast!StrLiteral strl; ///
+ alias genEast!IntLiteral intl; ///
+ auto fun(string[] xs, AST ps) { return genEast!FunLiteral(xs,ps); } ///
+ alias genEast!VarExpression var; ///
+ alias genEast!LayeredExpression lay; ///
+ alias genEast!LetExpression let; ///
+ alias genEast!FuncallExpression call; ///
}
Index: polemy/eval.d
==================================================================
--- polemy/eval.d
+++ polemy/eval.d
@@ -10,11 +10,12 @@
import polemy.ast;
import polemy.parse;
import polemy.value;
import std.typecons;
import std.stdio;
-
+
+///
Table createGlobalContext()
{
auto ctx = new Table;
// [TODO] autogenerate these typechecks
ctx.set("+", "@v", new FunValue(delegate Value(immutable LexPosition pos, Layer lay, Value[] args){
@@ -88,21 +89,29 @@
Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn)
{
return eval( polemy.parse.parseString(str, fn_ln_cn) );
}
+/// Entry point of this module
+
Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filename, T ln_cn)
{
return eval( polemy.parse.parseFile(filename, ln_cn) );
}
+/// Entry point of this module
+
Tuple!(Value,"val",Table,"ctx") eval(AST e)
{
Table ctx = createGlobalContext();
return typeof(return)(eval(e, ctx, false, "@v"), ctx);
}
+/// Entry point of this module
+/// If splitCtx = true, then inner variable declaration do not overwrite ctx.
+/// lay is the layer ID for evaluation (standard value semantics uses "@v").
+
Value eval(AST _e, Table ctx, bool splitCtx, Layer lay)
{
if( auto e = cast(StrLiteral)_e )
{
return new StrValue(e.data);
Index: polemy/lex.d
==================================================================
--- polemy/lex.d
+++ polemy/lex.d
@@ -7,25 +7,25 @@
module polemy.lex;
import polemy._common;
import std.file : readText;
import std.ctype : isspace, isalnum;
-/// Exception from this module
-
/*mixin*/
template ExceptionWithPosition()
{
const LexPosition pos;
this( const LexPosition pos, string msg, string file=null, size_t line=0, Throwable next=null )
{ super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos = pos; }
}
+///
class UnexpectedEOF : Exception
{
mixin ExceptionWithPosition;
}
+///
class LexException : Exception
{
mixin ExceptionWithPosition;
};
@@ -95,16 +95,19 @@
assert( !__traits(compiles, t.quoted=true) );
}
/// Named Construtors for Lexer
-auto lexerFromFile(T...)( string filename, T rest )
+Lexer lexerFromFile(T...)( string filename, T rest )
{
return lexerFromString( std.file.readText(filename), filename, rest );
}
-auto lexerFromString(CharSeq)( CharSeq str, string filename="", int lineno=1, int column=1 )
+/// Named Construtors for Lexer
+
+LexerT!(PositionedReader!CharSeq) /* ddoc doesn't recognize auto return... bugzilla:2581 */
+lexerFromString(CharSeq)( CharSeq str, string filename="", int lineno=1, int column=1 )
{
return new LexerT!(PositionedReader!CharSeq)(
PositionedReader!CharSeq(str, filename, lineno, column)
);
}
Index: polemy/parse.d
==================================================================
--- polemy/parse.d
+++ polemy/parse.d
@@ -1,48 +1,49 @@
-/**
- * Authors: k.inaba
- * License: NYSL 0.9982 http://www.kmonos.net/nysl/
- *
- * Parser for Polemy programming language
- */
-module polemy.parse;
-import polemy._common;
-import polemy.lex;
-import polemy.ast;
+/**
+ * Authors: k.inaba
+ * License: NYSL 0.9982 http://www.kmonos.net/nysl/
+ *
+ * Parser for Polemy programming language
+ */
+module polemy.parse;
+import polemy._common;
+import polemy.lex;
+import polemy.ast;
-/// Exception from this module
-
-class ParseException : Exception
-{
+///
+class ParseException : Exception
+{
mixin ExceptionWithPosition;
-}
+}
+
+/// Entry points of this module
+
+AST parseString(S, T...)(S str, T fn_ln_cn)
+ { return parserFromString(str, fn_ln_cn).parse(); }
/// Entry points of this module
-auto parseString(S, T...)(S str, T fn_ln_cn)
- { return parserFromString(str, fn_ln_cn).parse(); }
-
-auto parseFile(S, T...)(S filename, T ln_cn)
+AST parseFile(S, T...)(S filename, T ln_cn)
{ return parserFromFile(filename, ln_cn).parse(); }
-/// Named Constructor of Parser
+// Named Constructors of Parser
-private auto parserFromLexer(Lexer)(Lexer lex)
- { return new Parser!Lexer(lex); }
-
-private auto parserFromString(T...)(T params)
- { return parserFromLexer(polemy.lex.lexerFromString(params)); }
-
-private auto parserFromFile(T...)(T params)
+private auto parserFromLexer(Lexer)(Lexer lex)
+ { return new Parser!Lexer(lex); }
+
+private auto parserFromString(T...)(T params)
+ { return parserFromLexer(polemy.lex.lexerFromString(params)); }
+
+private auto parserFromFile(T...)(T params)
{ return parserFromLexer(polemy.lex.lexerFromFile(params)); }
-/// Parser
-
+// Parser
+
private class Parser(Lexer)
- if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) )
+ if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) )
{
- AST parse()
+ AST parse()
{
auto e = Body();
if( !lex.empty )
throw genex!ParseException(currentPosition(), "parsing ended but some tokens left");
return e;
@@ -92,134 +93,134 @@
if( tryEat(";") && !lex.empty && (lex.front.quoted || (lex.front.str!="}" && lex.front.str!=")")) )
return new LetExpression(pos, "_", "", e, Body());
else
return e;
}
- }
-
- // [TODO] make customizable from program
- static immutable string[][] operator_perferences = [
- ["||"],
- ["&&"],
- ["!="],
- ["=="],
- ["<","<=",">",">="],
- ["|"],
- ["^"],
- ["&"],
- ["<<", ">>"],
+ }
+
+ // [TODO] make customizable from program
+ static immutable string[][] operator_perferences = [
+ ["||"],
+ ["&&"],
+ ["!="],
+ ["=="],
+ ["<","<=",">",">="],
+ ["|"],
+ ["^"],
+ ["&"],
+ ["<<", ">>"],
["+","-"],
["~"],
["*","/","%"],
["^^"]
- ];
-
- AST E(int level)
- {
- if( operator_perferences.length <= level )
- return Funcall();
- else
- {
- auto ops = operator_perferences[level];
- auto e = E(level+1);
- seq:
- while( !lex.empty )
- {
- auto pos = lex.front.pos;
- foreach(op; ops)
- if( tryEat(op) )
- {
- e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, E(level+1));
- continue seq;
- }
- break;
- }
- return e;
- }
- }
-
- AST Funcall()
- {
+ ];
+
+ AST E(int level)
+ {
+ if( operator_perferences.length <= level )
+ return Funcall();
+ else
+ {
+ auto ops = operator_perferences[level];
+ auto e = E(level+1);
+ seq:
+ while( !lex.empty )
+ {
+ auto pos = lex.front.pos;
+ foreach(op; ops)
+ if( tryEat(op) )
+ {
+ e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, E(level+1));
+ continue seq;
+ }
+ break;
+ }
+ return e;
+ }
+ }
+
+ AST Funcall()
+ {
auto e = BaseExpression();
- while( tryEat("(") )
+ while( tryEat("(") )
{
auto pos = currentPosition();
- AST[] args;
- while( !tryEat(")") ) {
+ AST[] args;
+ while( !tryEat(")") ) {
if( lex.empty )
- throw genex!UnexpectedEOF(pos,"Closing ')' for arguments not found");
+ throw genex!UnexpectedEOF(pos,"Closing ')' for arguments not found");
args ~= E(0);
- if( !tryEat(",") ) {
- eat(")", "after function parameters");
- break;
- }
- }
- e = new FuncallExpression(e.pos, e, args);
- }
- return e;
- }
-
- AST BaseExpression()
- {
+ if( !tryEat(",") ) {
+ eat(")", "after function parameters");
+ break;
+ }
+ }
+ e = new FuncallExpression(e.pos, e, args);
+ }
+ return e;
+ }
+
+ AST BaseExpression()
+ {
if( lex.empty )
throw genex!UnexpectedEOF(currentPosition(), "Reached EOF when tried to parse an expression");
- auto pos = lex.front.pos;
- if( lex.front.quoted )
- {
- scope(exit) lex.popFront;
- return new StrLiteral(pos, lex.front.str);
- }
- if( isNumber(lex.front.str) )
- {
- scope(exit) lex.popFront;
- return new IntLiteral(pos, BigInt(cast(string)lex.front.str));
- }
+ auto pos = lex.front.pos;
+ if( lex.front.quoted )
+ {
+ scope(exit) lex.popFront;
+ return new StrLiteral(pos, lex.front.str);
+ }
+ if( isNumber(lex.front.str) )
+ {
+ scope(exit) lex.popFront;
+ return new IntLiteral(pos, BigInt(cast(string)lex.front.str));
+ }
if( tryEat("@") )
{
auto lay = "@"~eatId("for layer ID");
eat("(", "for layered execution");
auto e = Body();
eat(")", "after "~lay~"(...");
return new LayeredExpression(pos, lay, e);
}
- if( tryEat("(") )
- {
- auto e = Body();
- eat(")", "after parenthesized expression");
- return e;
- }
- if( tryEat("if") )
- {
- eat("(", "after if");
- auto cond = E(0);
- eat(")", "after if condition");
- auto thenPos = lex.front.pos;
- eat("{", "after if condition");
- auto th = Body();
- eat("}", "after if-then body");
- auto el = doNothingExpression();
- auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos);
- if( tryEat("else") ) {
- eat("{", "after else");
- el = Body();
- eat("}", "after else body");
- }
- return new FuncallExpression(pos,
- new VarExpression(pos, "if"),
- cond,
- new FunLiteral(thenPos, [], th),
- new FunLiteral(elsePos, [], el)
- );
- }
- if( tryEat("fun") || tryEat("\u03BB") )
- {
- eat("(", "after fun");
+ if( tryEat("(") )
+ {
+ auto e = Body();
+ eat(")", "after parenthesized expression");
+ return e;
+ }
+ if( tryEat("if") )
+ {
+ eat("(", "after if");
+ auto cond = E(0);
+ eat(")", "after if condition");
+ auto thenPos = lex.front.pos;
+ eat("{", "after if condition");
+ auto th = Body();
+ eat("}", "after if-then body");
+ auto el = doNothingExpression();
+ auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos);
+ if( tryEat("else") ) {
+ eat("{", "after else");
+ el = Body();
+ eat("}", "after else body");
+ }
+ return new FuncallExpression(pos,
+ new VarExpression(pos, "if"),
+ cond,
+ new FunLiteral(thenPos, [], th),
+ new FunLiteral(elsePos, [], el)
+ );
+ }
+ if( tryEat("fun") || tryEat("\u03BB") )
+ {
+ eat("(", "after fun");
return parseLambdaAfterOpenParen(pos);
- }
- scope(exit) lex.popFront;
- return new VarExpression(pos, lex.front.str);
+ }
+ scope(exit) lex.popFront;
+ return new VarExpression(pos, lex.front.str);
}
AST parseLambdaAfterOpenParen(immutable LexPosition pos)
{
string[] params;
@@ -233,34 +234,34 @@
}
eat("{", "after function parameters");
auto funbody = Body();
eat("}", "after function body");
return new FunLiteral(pos, params, funbody);
- }
-
-private:
+ }
+
+private:
Lexer lex;
this(Lexer lex) { this.lex = lex; }
-
- void eat(string kwd, lazy string msg)
- {
+
+ void eat(string kwd, lazy string msg)
+ {
if( !tryEat(kwd) )
if( lex.empty )
throw genex!UnexpectedEOF(
currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg));
else
throw genex!ParseException(
currentPosition(), sprintf!"%s is expected for %s but not found"(kwd,msg));
- }
-
- bool tryEat(string kwd)
- {
- if( lex.empty || lex.front.quoted || lex.front.str!=kwd )
- return false;
- lex.popFront;
- return true;
- }
+ }
+
+ bool tryEat(string kwd)
+ {
+ if( lex.empty || lex.front.quoted || lex.front.str!=kwd )
+ return false;
+ lex.popFront;
+ return true;
+ }
string eatId(lazy string msg, bool allowQuoted=false)
{
if( lex.empty )
throw genex!UnexpectedEOF(currentPosition(), "identifier is expected but not found "~msg);
@@ -267,14 +268,14 @@
if( !allowQuoted && lex.front.quoted )
throw genex!ParseException(currentPosition(), "identifier is expected but not found "~msg);
scope(exit) lex.popFront;
return lex.front.str;
}
-
- bool isNumber(string s)
- {
- return find!(`a<'0'||'9'> "~e.toString()); }
@@ -53,12 +53,10 @@
assert_throw!AssertError( assert_throw!Error(nothing()) );
assert_nothrow ( assert_throw!Error(assertError()) );
assert_throw!AssertError( assert_throw!AssertError(error()) );
}
-/// Unittest helpers asserting two values are in some relation ==, !=, <, <=, >, >=
-
template assertOp(string op)
{
void assertOp(A, B, string fn=__FILE__, size_t ln=__LINE__)(A a, B b, string msg="")
{
try
@@ -67,16 +65,16 @@
{ onAssertErrorMsg(fn, ln, msg.length ? msg : "exception ["~e.toString()~"]"); }
onAssertErrorMsg(fn, ln, msg.length ? msg : to!string(a)~" !"~op~" "~to!string(b));
}
}
-alias assertOp!(`==`) assert_eq;
-alias assertOp!(`!=`) assert_ne;
-alias assertOp!(`<`) assert_lt;
-alias assertOp!(`<=`) assert_le;
-alias assertOp!(`>`) assert_gt;
-alias assertOp!(`>=`) assert_ge;
+alias assertOp!(`==`) assert_eq; /// asserts two operands are ==
+alias assertOp!(`!=`) assert_ne; /// asserts two operands are !=
+alias assertOp!(`<`) assert_lt; /// asserts two operands are <
+alias assertOp!(`<=`) assert_le; /// asserts two operands are <=
+alias assertOp!(`>`) assert_gt; /// asserts two operands are >
+alias assertOp!(`>=`) assert_ge; /// asserts two operands are >=
unittest
{
assert_nothrow( assert_eq(1, 1) );
assert_nothrow( assert_ne(1, 0) );
Index: tricks/tricks.d
==================================================================
--- tricks/tricks.d
+++ tricks/tricks.d
@@ -26,11 +26,11 @@
assert_throw!Error( sprintf!"%s%s"(1) );
}
/// Create an exception with automatically completed filename and lineno information
-auto genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params)
+ExceptionType genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params)
{
static if( T.length > 0 && is(T[$-1] : Throwable) )
return new ExceptionType(params[0..$-1], fn, ln, params[$-1]);
else
return new ExceptionType(params, fn, ln);
@@ -46,10 +46,11 @@
/// Mixing-in the bean constructor for a class
/*mixin*/
template SimpleConstructor()
{
+ /// member-by-member constructor
static if( is(typeof(super) == Object) || super.tupleof.length==0 )
this( typeof(this.tupleof) params )
{
static if(this.tupleof.length>0)
this.tupleof = params;
@@ -91,23 +92,20 @@
// shiyo- desu. Don't use in this way.
// Tamp tries to call new Tomp(real) (because it only sees Tomp's members),
// but it fails because Tomp takes (int,string,real).
assert( !__traits(compiles, {
- class Tamp : Tomp
- {
- mixin SimpleConstructor;
- }
+ class Tamp : Tomp { mixin SimpleConstructor; }
}) );
}
/// Mixing-in the MOST-DERIVED-member-wise comparator for a class
/*mixin*/
template SimpleCompare()
{
- override bool opEquals(Object rhs_) const
+ override bool opEquals(Object rhs_) const /// member-by-member equality
{
if( auto rhs = cast(typeof(this))rhs_ )
{
foreach(i,_; this.tupleof)
if( this.tupleof[i] != rhs.tupleof[i] )
@@ -115,19 +113,19 @@
return true;
}
assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
}
- override hash_t toHash() const
+ override hash_t toHash() const /// member-by-member hash
{
hash_t h = 0;
foreach(mem; this.tupleof)
h += typeid(mem).getHash(&mem);
return h;
}
- override int opCmp(Object rhs_) const
+ override int opCmp(Object rhs_) const /// member-by-member compare
{
if( auto rhs = cast(typeof(this))rhs_ )
{
foreach(i,_; this.tupleof)
if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i]))
@@ -168,11 +166,12 @@
/// Mixing-in a simple toString method
/*mixin*/
template SimpleToString()
-{
+{
+ /// member-by-member toString
override string toString()
{
string str = sprintf!"%s("(typeof(this).stringof);
foreach(i,mem; this.tupleof)
{