dexed/dastworx/src/symlist.d

361 lines
10 KiB
D

module symlist;
import
std.stdio, std.array, std.traits, std.conv, std.json, std.format,
std.algorithm;
import
iz.memory;
import
dparse.lexer, dparse.ast, dparse.parser;
import
common;
/**
* Serializes the symbols in the standard output
*/
void listSymbols(const(Module) mod, AstErrors errors, bool deep = true)
{
mixin(logCall);
alias SL = SymbolListBuilder!(ListFmt.Pas);
SL.addAstErrors(errors);
SL sl = construct!(SL)(deep);
sl.visit(mod);
sl.serialize.writeln;
}
private:
enum ListFmt
{
Pas,
Json
}
enum SymbolType
{
_alias,
_class,
_enum,
_error,
_function,
_interface,
_import,
_mixin, // (template decl)
_struct,
_template,
_union,
_unittest,
_variable,
_warning
}
string makeSymbolTypeArray()
{
string result = "string[SymbolType.max + 1] symbolTypeStrings = [";
foreach(st; EnumMembers!SymbolType)
result ~= `"` ~ to!string(st) ~ `",`;
result ~= "];";
return result;
}
mixin(makeSymbolTypeArray);
class SymbolListBuilder(ListFmt Fmt): ASTVisitor
{
private immutable bool _deep;
static if (Fmt == ListFmt.Pas)
{
static Appender!string pasStream;
}
else
{
static JSONValue json;
static JSONValue* jarray;
}
static uint utc;
this(bool deep)
{
_deep = deep;
}
alias visit = ASTVisitor.visit;
static this()
{
static if (Fmt == ListFmt.Pas)
{
pasStream.put("object TSymbolList\rsymbols=<");
}
else
{
json = parseJSON("[]");
jarray = &json;
}
}
static void addAstErrors(AstErrors errors)
{
foreach(error; errors)
{
string type = (error.type == ErrorType.error) ?
symbolTypeStrings[SymbolType._error] :
symbolTypeStrings[SymbolType._warning];
static if (Fmt == ListFmt.Pas)
{
pasStream.put("\ritem\r");
pasStream.put(format("line=%d\r", error.line));
pasStream.put(format("col=%d\r", error.column));
pasStream.put(format("name='%s'\r", patchPascalString!100(error.message)));
pasStream.put(format("symType=%s\r", type));
pasStream.put("end");
}
else
{
JSONValue item = parseJSON("{}");
item["line"] = JSONValue(error.line);
item["col"] = JSONValue(error.column);
item["name"] = JSONValue(error.message);
item["type"] = JSONValue(type);
jarray.array ~= item;
}
}
}
final string serialize()
{
static if (Fmt == ListFmt.Pas)
{
pasStream.put(">\rend");
return pasStream.data;
}
else
{
JSONValue result = parseJSON("{}");
result["items"] = json;
version (assert)
return result.toPrettyString;
else
return result.toString;
}
}
/// visitor implementation if the declaration has a "name".
final void namedVisitorImpl(DT, SymbolType st, bool dig = true)(const(DT) dt)
if (__traits(hasMember, DT, "name"))
{
static if (Fmt == ListFmt.Pas)
{
pasStream.put("\ritem\r");
pasStream.put(format("line=%d\r", dt.name.line));
pasStream.put(format("col=%d\r", dt.name.column));
pasStream.put(format("name='%s'\r", dt.name.text));
pasStream.put("symType=" ~ symbolTypeStrings[st] ~ "\r");
static if (dig) if (_deep)
{
pasStream.put("subs = <");
dt.accept(this);
pasStream.put(">\r");
}
pasStream.put("end");
}
else
{
JSONValue item = parseJSON("{}");
item["line"] = JSONValue(dt.name.line);
item["col"] = JSONValue(dt.name.column);
item["name"] = JSONValue(dt.name.text);
item["type"] = JSONValue(symbolTypeStrings[st]);
static if (dig) if (_deep)
{
JSONValue subs = parseJSON("[]");
const JSONValue* old = jarray;
jarray = &subs;
dt.accept(this);
item["items"] = subs;
jarray = old;
}
json.array ~= item;
}
}
/// visitor implementation for special cases.
final void otherVisitorImpl(DT, bool dig = true)
(const(DT) dt, SymbolType st, string name, size_t line, size_t col)
{
static if (Fmt == ListFmt.Pas)
{
pasStream.put("\ritem\r");
pasStream.put(format("line=%d\r", line));
pasStream.put(format("col=%d\r", col));
pasStream.put(format("name='%s'\r", name));
pasStream.put("symType=" ~ symbolTypeStrings[st] ~ "\r");
static if (dig)
{
pasStream.put("subs = <");
dt.accept(this);
pasStream.put(">\r");
}
pasStream.put("end");
}
else
{
JSONValue item = parseJSON("{}");
item["line"] = JSONValue(line);
item["col"] = JSONValue(col);
item["name"] = JSONValue(name);
item["type"] = JSONValue(symbolTypeStrings[st]);
static if (dig)
{
JSONValue subs = parseJSON("[]");
const JSONValue* old = jarray;
jarray = &subs;
dt.accept(this);
item["items"] = subs;
jarray = old;
}
json.array ~= item;
}
}
final override void visit(const AliasDeclaration decl)
{
if (decl.initializers.length)
namedVisitorImpl!(AliasInitializer, SymbolType._alias)(decl.initializers[0]);
}
final override void visit(const AnonymousEnumMember decl)
{
namedVisitorImpl!(AnonymousEnumMember, SymbolType._enum)(decl);
}
final override void visit(const AnonymousEnumDeclaration decl)
{
decl.accept(this);
}
final override void visit(const AutoDeclarationPart decl)
{
otherVisitorImpl(decl, SymbolType._variable, decl.identifier.text,
decl.identifier.line, decl.identifier.column);
}
final override void visit(const ClassDeclaration decl)
{
namedVisitorImpl!(ClassDeclaration, SymbolType._class)(decl);
}
final override void visit(const Constructor decl)
{
otherVisitorImpl(decl, SymbolType._function, "ctor", decl.line, decl.column);
}
final override void visit(const Destructor decl)
{
otherVisitorImpl(decl, SymbolType._function, "dtor", decl.line, decl.column);
}
final override void visit(const EnumDeclaration decl)
{
namedVisitorImpl!(EnumDeclaration, SymbolType._enum)(decl);
}
final override void visit(const EponymousTemplateDeclaration decl)
{
namedVisitorImpl!(EponymousTemplateDeclaration, SymbolType._template)(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;
otherVisitorImpl(decl, SymbolType._import,
si.identifierChain.identifiers.map!(a => a.text).join("."),
si.identifierChain.identifiers[0].line,
si.identifierChain.identifiers[0].column);
}
if (decl.importBindings) with (decl.importBindings.singleImport)
otherVisitorImpl(decl, SymbolType._import,
identifierChain.identifiers.map!(a => a.text).join("."),
identifierChain.identifiers[0].line,
identifierChain.identifiers[0].column);
}
final override void visit(const MixinTemplateDeclaration decl)
{
namedVisitorImpl!(TemplateDeclaration, SymbolType._mixin)(decl.templateDeclaration);
}
final override void visit(const Postblit pb)
{
otherVisitorImpl(pb, SymbolType._function, "postblit", pb.line, pb.column);
pb.accept(this);
}
final override void visit(const StructDeclaration decl)
{
namedVisitorImpl!(StructDeclaration, SymbolType._struct)(decl);
}
final override void visit(const TemplateDeclaration decl)
{
namedVisitorImpl!(TemplateDeclaration, SymbolType._template)(decl);
}
final override void visit(const UnionDeclaration decl)
{
namedVisitorImpl!(UnionDeclaration, SymbolType._union)(decl);
}
final override void visit(const Unittest decl)
{
otherVisitorImpl(decl, SymbolType._unittest, format("test%.4d",utc++),
decl.line, decl.column);
}
final override void visit(const VariableDeclaration decl)
{
if (decl.declarators)
foreach (elem; decl.declarators)
namedVisitorImpl!(Declarator, SymbolType._variable, false)(elem);
else if (decl.autoDeclaration)
visit(decl.autoDeclaration);
}
final override void visit(const StaticConstructor decl)
{
otherVisitorImpl(decl, SymbolType._function, "static ctor", decl.line, decl.column);
}
final override void visit(const StaticDestructor decl)
{
otherVisitorImpl(decl, SymbolType._function, "static dtor", decl.line, decl.column);
}
final override void visit(const SharedStaticConstructor decl)
{
otherVisitorImpl(decl, SymbolType._function, "shared static ctor", decl.line, decl.column);
}
final override void visit(const SharedStaticDestructor decl)
{
otherVisitorImpl(decl, SymbolType._function, "shared static dtor", decl.line, decl.column);
}
}