Last active
August 29, 2015 14:19
-
-
Save yutopp/75a4beaf9ae215a1e7ee to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright yutopp 2015 - . | |
// | |
// Distributed under the Boost Software License, Version 1.0. | |
// (See accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
// | |
module ast; | |
import std.traits, std.typetuple; | |
import std.stdio; | |
import std.algorithm; | |
template AstNodeIdEnum(class_names...) { | |
static if ( class_names.length > 0 ) { | |
enum AstNodeIdEnum = class_names[0] ~ ", " ~ AstNodeIdEnum!(class_names[1..$]); | |
} else { | |
enum AstNodeIdEnum = ""; | |
} | |
} | |
// define AstTag | |
mixin ("enum AstTag {" ~ AstNodeIdEnum!(__traits(allMembers, nodes)) ~ "}"); | |
// | |
mixin template ast_override_members(T) { | |
string name() const @property { | |
return T.stringof; | |
} | |
AstTag id() const { | |
return mixin ("AstTag." ~ T.stringof); | |
} | |
} | |
mixin template ast() { | |
alias self_type = typeof(this); | |
static if ( BaseClassesTuple!self_type.length > 1 ) { | |
override { mixin ast_override_members!self_type; } | |
} else { | |
mixin ast_override_members!self_type; | |
} | |
} | |
// | |
mixin template nodes() { | |
// base class | |
class AstBase { | |
mixin ast; | |
} | |
// | |
class Value : AstBase { | |
mixin ast; | |
} | |
// | |
class Expression : AstBase { | |
mixin ast; | |
} | |
// | |
class Statement : AstBase { | |
mixin ast; | |
} | |
} | |
mixin nodes; | |
// | |
mixin template visitor(R, bool prevent_missing = true) { | |
alias self_type = typeof(this); | |
alias visit_func_type = R function(self_type, AstBase); | |
R dispatch(T...)(AstBase node, T tx) { | |
return visitor_table_[node.id](this, node, tx); | |
} | |
static this() { | |
foreach( self_node; __traits(allMembers, nodes) ) { | |
auto self_tag = mixin ("AstTag." ~ self_node); | |
alias derived_order = TypeTuple!(mixin (self_node), BaseClassesTuple!(mixin (self_node))); | |
// emulate inheritance/dispatch | |
foreach( node_type; derived_order ) { | |
static if ( __traits(compiles, (cast(self_type)null).visit(cast(node_type)null)) ) { | |
// callable | |
visitor_table_[self_tag] = function R(self_type t, AstBase a) { | |
return t.visit(cast(node_type)a); | |
}; | |
break; | |
} else if ( __traits(isSame, node_type, Object) ) { | |
visitor_table_[self_tag] = &missing_node; | |
} | |
} | |
} | |
} | |
private: | |
static if ( prevent_missing ) { | |
static R missing_node(self_type t, AstBase a) { | |
assert(0); | |
} | |
} | |
static visit_func_type[AstTag.max+1] visitor_table_; | |
} | |
class HogeVisitor { | |
alias return_type = int; | |
mixin visitor!(return_type); | |
return_type visit(AstBase s) { | |
"astbase".writeln; | |
return 0; | |
} | |
return_type visit(Statement s) { | |
"statement".writeln; | |
return 0; | |
} | |
return_type visit(Value s) { | |
"value".writeln; | |
return 0; | |
} | |
} | |
void main() { | |
auto v = new HogeVisitor(); | |
v.dispatch(new Statement()); | |
v.dispatch(new Expression()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment