new widget tool designed to replace the static explorer and based on libdparse

This commit is contained in:
Basile Burg 2015-02-25 07:55:22 +01:00
parent c98dd3c7bc
commit f28a83e8d8
3 changed files with 307 additions and 0 deletions

24
cesyms/cesyms.coedit Normal file
View File

@ -0,0 +1,24 @@
object CurrentProject: TCEProject
OptionsCollection = <
item
name = 'release'
outputOptions.inlining = True
outputOptions.boundsCheck = offAlways
outputOptions.optimizations = True
outputOptions.release = True
pathsOptions.outputFilename = '..\lazproj\cesyms'
preBuildProcess.options = []
preBuildProcess.showWindow = swoNone
postBuildProcess.options = []
postBuildProcess.showWindow = swoNone
runOptions.options = []
runOptions.showWindow = swoNone
end>
Sources.Strings = (
'cesyms.d'
)
ConfigurationIndex = 0
LibraryAliases.Strings = (
'libdparse'
)
end

270
cesyms/cesyms.d Normal file
View File

@ -0,0 +1,270 @@
module cesyms;
import std.stdio, std.path, std.file, std.array, std.string;
import std.d.lexer, std.d.ast, std.d.parser;
static import std.conv;
interface I{}
alias Int32 = int;
//alias long Int64;
enum E
{
e1,
e2,
e3,
}
enum {opt1,opt2}
class A
{
class AA
{
class AA1{}
class AA2{}
}
class BB
{
class BB1{}
class BB2{}
}
}
enum SymbolType
{
_alias, // X
_class, // X
_enum, // X
_function, // X
_interface, // X
_import, // X
_mixin,
_struct, // X
_template, // X
_union, // X
_variable // X
}
struct Symbol
{
int line;
int col;
string name;
SymbolType type;
Symbol * [] subs;
void serialize(ref Appender!string lfmApp)
{
lfmApp.put(" \r item\r");
lfmApp.put(format(" line = %d\r", line));
lfmApp.put(format(" col = %d\r", col));
lfmApp.put(format(" name = '%s'\r", name));
lfmApp.put(format(" symType = %s\r", type));
lfmApp.put(" subs = <");
if (subs.length) foreach(Symbol * sub; subs)
sub.serialize(lfmApp);
lfmApp.put(">\r");
lfmApp.put(" end\r");
}
}
void main(string[] args)
{
if (args.length < 2) return;
auto fname = args[1];
if (!fname.exists) return;
// load and parse the file
auto config = LexerConfig(fname, StringBehavior.source, WhitespaceBehavior.include);
auto source = cast(ubyte[]) read(fname, size_t.max);
auto scache = StringCache(StringCache.defaultBucketCount);
auto ast = parseModule(getTokensForParser(source, config, &scache), fname);
// visit each root member
auto slb = new SymbolListBuilder;
foreach(Declaration decl; ast.declarations)
{
slb.resetRoot;
slb.visit(decl);
}
// TODO-cfeature: Outputs the symbol tree in a format handlable by a Coedit widget
int level = -1;
void print(Symbol * s)
{
foreach(i; 0 .. level) write(".");
level++;
write(s.name, '\r');
foreach(ss; s.subs)
print(ss);
level--;
}
//print(&slb.root);
auto str = slb.serialize;
//std.file.write(r"C:\too.txt",cast(ubyte[])str);
write(str);
stdout.flush;
}
class SymbolListBuilder : ASTVisitor
{
Symbol root;
Symbol * parent;
size_t count;
alias visit = ASTVisitor.visit;
this(){resetRoot;}
void resetRoot(){parent = &root;}
string serialize()
{
Appender!string lfmApp;
lfmApp.reserve(count * 64);
lfmApp.put("object TSymbolList\r symbols = <");
foreach(Symbol * sym; root.subs) sym.serialize(lfmApp);
lfmApp.put(">\rend\r\n");
return lfmApp.data;
}
/// returns a new symbol if the declarator is based on a Token named "name".
Symbol * addDeclaration(DT)(DT adt)
{
static if
(
is(DT == const(AliasInitializer)) ||
is(DT == const(ClassDeclaration)) ||
is(DT == const(Declarator)) ||
is(DT == const(EnumDeclaration)) ||
is(DT == const(FunctionDeclaration)) ||
is(DT == const(InterfaceDeclaration)) ||
is(DT == const(StructDeclaration)) ||
is(DT == const(TemplateDeclaration)) ||
is(DT == const(UnionDeclaration))
)
{
count++;
auto result = new Symbol;
result.name = adt.name.text.idup;
result.line = adt.name.line;
result.col = adt.name.column;
parent.subs ~= result;
return result;
}
assert(0, "addDeclaration no implemented for " ~ DT.stringof);
}
/// visitor implementation if the declarator is based on a Token named "name".
void namedVisitorImpl(DT, SymbolType st, bool dig = true)(const(DT) dt)
{
auto newSymbol = addDeclaration(dt);
newSymbol.type = st;
//
static if (dig)
{
auto previousParent = parent;
scope(exit) parent = previousParent;
parent = newSymbol;
dt.accept(this);
}
}
final override void visit(const AliasDeclaration decl)
{
// old alias syntax not supported by this.
// why is initializers an array ?
if (decl.initializers.length == 1)
namedVisitorImpl!(AliasInitializer, SymbolType._alias)(decl.initializers[0]);
}
final override void visit(const ClassDeclaration decl)
{
namedVisitorImpl!(ClassDeclaration, SymbolType._class)(decl);
}
final override void visit(const EnumDeclaration decl)
{
// TODO-ctest: try to see if what dmd outputs as , "enum member" is handled.
namedVisitorImpl!(EnumDeclaration, SymbolType._class)(decl);
}
final override void visit(const FunctionDeclaration decl)
{
namedVisitorImpl!(FunctionDeclaration, SymbolType._function)(decl);
}
final override void visit(const InterfaceDeclaration decl)
{
namedVisitorImpl!(InterfaceDeclaration, SymbolType._interface)(decl);
}
final override void visit(const ImportDeclaration decl)
{
foreach(const(SingleImport) si; decl.singleImports)
{
if (!si.identifierChain.identifiers.length)
continue;
//
string[] modules;
foreach(ident; si.identifierChain.identifiers)
{
modules ~= ident.text;
modules ~= ".";
}
//
count++;
auto result = new Symbol;
result.name = modules[0..$-1].join;
result.line = si.identifierChain.identifiers[0].line;
result.col = si.identifierChain.identifiers[0].column;
result.type = SymbolType._import;
parent.subs ~= result;
}
}
final override void visit(const MixinDeclaration decl)
{
// TODO-cfeature: MixinDeclaration, just display the name of the mixed template.
// the template might be implemented in another module so their ùeùbrs cant be displayed.
}
final override void visit(const StructDeclaration decl)
{
namedVisitorImpl!(StructDeclaration, SymbolType._struct)(decl);
}
final override void visit(const TemplateDeclaration decl)
{
namedVisitorImpl!(TemplateDeclaration, SymbolType._function)(decl);
}
final override void visit(const UnionDeclaration decl)
{
namedVisitorImpl!(UnionDeclaration, SymbolType._function)(decl);
}
final override void visit(const VariableDeclaration decl)
{
foreach(elem; decl.declarators)
namedVisitorImpl!(Declarator, SymbolType._variable, false)(elem);
}
}

13
cesyms/readme.md Normal file
View File

@ -0,0 +1,13 @@
ceSyms
======
Tool designed to build a symbol tree for a particular D module.
It's written in D using Coedit. To build it, [libdparse](https://github.com/Hackerpilot/libdparse)
must be setup in the [libman](https://github.com/BBasile/Coedit/wiki#library-manager-widget)
as described in this [tutorial](https://github.com/BBasile/Coedit/wiki#lets-build-a-static-library).
This tool is mandatory to enable the new _Symbol list widget_.
If missing, the old _static explorer widget_ still does the same but it's from far less
efficient since it actually compiles while only the AST is needed.
The new tool does not take the module correctness in account.