Mercurial > projects > dil
diff src/dil/ast/Visitor.d @ 806:bcb74c9b895c
Moved out files in the trunk folder to the root.
author | Aziz K?ksal <aziz.koeksal@gmail.com> |
---|---|
date | Sun, 09 Mar 2008 00:12:19 +0100 |
parents | trunk/src/dil/ast/Visitor.d@cf2ad5df025c |
children | aad6aeb5d12b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dil/ast/Visitor.d Sun Mar 09 00:12:19 2008 +0100 @@ -0,0 +1,155 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module dil.ast.Visitor; + +import dil.ast.Node; +import dil.ast.Declarations, + dil.ast.Expressions, + dil.ast.Statements, + dil.ast.Types, + dil.ast.Parameters; + +/// Generate visit methods. +/// +/// E.g.: +/// --- +/// Declaration visit(ClassDeclaration){return null;}; +/// Expression visit(CommaExpression){return null;}; +/// --- +char[] generateVisitMethods() +{ + char[] text; + foreach (className; g_classNames) + text ~= "returnType!(\""~className~"\") visit("~className~" node){return node;}\n"; + return text; +} +// pragma(msg, generateAbstractVisitMethods()); + +/// Gets the appropriate return type for the provided class. +template returnType(char[] className) +{ + static if (is(typeof(mixin(className)) : Declaration)) + alias Declaration returnType; + else + static if (is(typeof(mixin(className)) : Statement)) + alias Statement returnType; + else + static if (is(typeof(mixin(className)) : Expression)) + alias Expression returnType; + else + static if (is(typeof(mixin(className)) : TypeNode)) + alias TypeNode returnType; + else + alias Node returnType; +} + +/// Generate functions which do the second dispatch. +/// +/// E.g.: +/// --- +/// Expression visitCommaExpression(Visitor visitor, CommaExpression c) +/// { visitor.visit(c); /* Second dispatch. */ } +/// --- +/// The equivalent in the traditional visitor pattern would be: +/// --- +/// class CommaExpression : Expression +/// { +/// void accept(Visitor visitor) +/// { visitor.visit(this); } +/// } +/// --- +char[] generateDispatchFunctions() +{ + char[] text; + foreach (className; g_classNames) + text ~= "returnType!(\""~className~"\") visit"~className~"(Visitor visitor, "~className~" c)\n" + "{ return visitor.visit(c); }\n"; + return text; +} +// pragma(msg, generateDispatchFunctions()); + +/++ + Generates an array of function pointers. + + --- + [ + cast(void*)&visitCommaExpression, + // etc. + ] + --- ++/ +char[] generateVTable() +{ + char[] text = "["; + foreach (className; g_classNames) + text ~= "cast(void*)&visit"~className~",\n"; + return text[0..$-2]~"]"; // slice away last ",\n" +} +// pragma(msg, generateVTable()); + +/// Implements a variation of the visitor pattern. +/// +/// Inherited by classes that need to traverse a D syntax tree +/// and do computations, transformations and other things on it. +abstract class Visitor +{ + mixin(generateVisitMethods()); + + static + mixin(generateDispatchFunctions()); + + /// The table holding function pointers to the second dispatch functions. + static const void*[] dispatch_vtable = mixin(generateVTable()); + static assert(dispatch_vtable.length == g_classNames.length, "vtable length doesn't match number of classes"); + + /// Looks up the second dispatch function for n and returns that. + Node function(Visitor, Node) getDispatchFunction()(Node n) + { + return cast(Node function(Visitor, Node))dispatch_vtable[n.kind]; + } + + /// The main and first dispatch function. + Node dispatch(Node n) + { // Second dispatch is done in the called function. + return getDispatchFunction(n)(this, n); + } + +final: + Declaration visit(Declaration n) + { return visitD(n); } + Statement visit(Statement n) + { return visitS(n); } + Expression visit(Expression n) + { return visitE(n); } + TypeNode visit(TypeNode n) + { return visitT(n); } + Node visit(Node n) + { return visitN(n); } + + Declaration visitD(Declaration n) + { + return cast(Declaration)cast(void*)dispatch(n); + } + + Statement visitS(Statement n) + { + return cast(Statement)cast(void*)dispatch(n); + } + + Expression visitE(Expression n) + { + return cast(Expression)cast(void*)dispatch(n); + } + + TypeNode visitT(TypeNode n) + { + return cast(TypeNode)cast(void*)dispatch(n); + } + + Node visitN(Node n) + { + return dispatch(n); + } +}