mirror of https://gitlab.com/basile.b/dexed.git
cesyms, serializes directly during the visit
This commit is contained in:
parent
9fe1545de2
commit
50a2f499e6
320
cesyms/cesyms.d
320
cesyms/cesyms.d
|
@ -27,10 +27,11 @@ import std.getopt, std.json, std.conv;
|
||||||
import dparse.lexer, dparse.ast, dparse.parser, dparse.rollback_allocator;
|
import dparse.lexer, dparse.ast, dparse.parser, dparse.rollback_allocator;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
|
||||||
|
|
||||||
enum ListFmt
|
enum ListFmt
|
||||||
{
|
{
|
||||||
Pascal,
|
Pas,
|
||||||
JSON
|
Json
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(string[] args)
|
void main(string[] args)
|
||||||
|
@ -62,47 +63,31 @@ void main(string[] args)
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// load and parse the file
|
// parses, visits and writes to stdout
|
||||||
RollbackAllocator alloc;
|
RollbackAllocator alloc;
|
||||||
auto config = LexerConfig(fname, StringBehavior.source, WhitespaceBehavior.skip);
|
auto config = LexerConfig(fname, StringBehavior.source, WhitespaceBehavior.skip);
|
||||||
auto scache = StringCache(StringCache.defaultBucketCount);
|
auto scache = StringCache(StringCache.defaultBucketCount);
|
||||||
|
|
||||||
|
if (!asJson)
|
||||||
|
{
|
||||||
|
SymbolListBuilder!(ListFmt.Pas) slb = construct!(SymbolListBuilder!(ListFmt.Pas));
|
||||||
auto ast = parseModule(getTokensForParser(source, config, &scache), fname,
|
auto ast = parseModule(getTokensForParser(source, config, &scache), fname,
|
||||||
&alloc, &(SymbolListBuilder.astError));
|
&alloc, &(slb.astError));
|
||||||
|
|
||||||
// visit each root member
|
|
||||||
SymbolListBuilder slb = construct!SymbolListBuilder;
|
|
||||||
foreach (Declaration decl; ast.declarations)
|
foreach (Declaration decl; ast.declarations)
|
||||||
{
|
|
||||||
slb.resetRoot;
|
|
||||||
slb.visit(decl);
|
slb.visit(decl);
|
||||||
}
|
write(slb.serialize);
|
||||||
|
|
||||||
version (none)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (asJson)
|
|
||||||
write(slb.serializeJson);
|
|
||||||
else
|
|
||||||
write(slb.serializePascal);
|
|
||||||
}
|
|
||||||
|
|
||||||
slb.destruct;
|
slb.destruct;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SymbolListBuilder!(ListFmt.Json) slb = construct!(SymbolListBuilder!(ListFmt.Json));
|
||||||
|
auto ast = parseModule(getTokensForParser(source, config, &scache), fname,
|
||||||
|
&alloc, &(slb.astError));
|
||||||
|
foreach (Declaration decl; ast.declarations)
|
||||||
|
slb.visit(decl);
|
||||||
|
write(slb.serialize);
|
||||||
|
slb.destruct;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// libdparse warnings includes some "'", which in Pascal are string delim
|
// libdparse warnings includes some "'", which in Pascal are string delim
|
||||||
|
@ -133,14 +118,14 @@ string patchPasStringLitteral(string p)
|
||||||
// Memory utils ---------------------------------------------------------------+
|
// Memory utils ---------------------------------------------------------------+
|
||||||
void* getMem(size_t size) nothrow
|
void* getMem(size_t size) nothrow
|
||||||
{
|
{
|
||||||
import std.c.stdlib;
|
import std.c.stdlib: malloc;
|
||||||
|
|
||||||
auto result = malloc(size);
|
auto result = malloc(size);
|
||||||
assert(result, "Out of memory");
|
assert(result, "Out of memory");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CT construct(CT, A...)(A a) if (is(CT == class) && !isAbstractClass!CT)
|
CT construct(CT, A...)(A a)
|
||||||
|
if (is(CT == class) && !isAbstractClass!CT)
|
||||||
{
|
{
|
||||||
auto size = typeid(CT).init.length;
|
auto size = typeid(CT).init.length;
|
||||||
auto memory = getMem(size);
|
auto memory = getMem(size);
|
||||||
|
@ -153,18 +138,6 @@ CT construct(CT, A...)(A a) if (is(CT == class) && !isAbstractClass!CT)
|
||||||
return cast(CT) memory;
|
return cast(CT) memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
ST* construct(ST, A...)(A a) if (is(ST == struct) || is(ST == union))
|
|
||||||
{
|
|
||||||
import std.conv : emplace;
|
|
||||||
|
|
||||||
auto size = ST.sizeof;
|
|
||||||
auto memory = getMem(size)[0 .. size];
|
|
||||||
import core.memory : GC;
|
|
||||||
|
|
||||||
GC.addRange(memory.ptr, size, typeid(ST));
|
|
||||||
return emplace!(ST, A)(memory, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destruct(T)(ref T instance)
|
void destruct(T)(ref T instance)
|
||||||
if (is(T == class) || (isPointer!T && is(PointerTarget!T == struct)))
|
if (is(T == class) || (isPointer!T && is(PointerTarget!T == struct)))
|
||||||
{
|
{
|
||||||
|
@ -175,7 +148,6 @@ void destruct(T)(ref T instance)
|
||||||
}
|
}
|
||||||
//----
|
//----
|
||||||
|
|
||||||
// Serializable Symbol --------------------------------------------------------+
|
|
||||||
enum SymbolType
|
enum SymbolType
|
||||||
{
|
{
|
||||||
_alias,
|
_alias,
|
||||||
|
@ -193,167 +165,152 @@ enum SymbolType
|
||||||
_warning
|
_warning
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Symbol
|
|
||||||
{
|
|
||||||
size_t line;
|
|
||||||
size_t col;
|
|
||||||
string name;
|
|
||||||
SymbolType type;
|
|
||||||
Symbol*[] subs;
|
|
||||||
|
|
||||||
~this()
|
|
||||||
{
|
|
||||||
foreach_reverse (i; 0 .. subs.length)
|
|
||||||
subs[i].destruct;
|
|
||||||
}
|
|
||||||
|
|
||||||
void serialize(List)(auto ref List list)
|
|
||||||
{
|
|
||||||
static if (is(List == Appender!string))
|
|
||||||
serializePascal(list);
|
|
||||||
else static if (is(List == JSONValue))
|
|
||||||
serializeJson(list);
|
|
||||||
else
|
|
||||||
static assert(0, "serialization kind cannot be deduced from list");
|
|
||||||
}
|
|
||||||
|
|
||||||
void serializePascal(ref Appender!string lfmApp)
|
|
||||||
{
|
|
||||||
lfmApp.put("\ritem\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");
|
|
||||||
}
|
|
||||||
|
|
||||||
void serializeJson(ref JSONValue json)
|
|
||||||
{
|
|
||||||
auto vobj = parseJSON("{}");
|
|
||||||
vobj["line"] = JSONValue(line);
|
|
||||||
vobj["col"] = JSONValue(col);
|
|
||||||
vobj["name"] = JSONValue(name);
|
|
||||||
vobj["type"] = JSONValue(to!string(type));
|
|
||||||
if (subs.length)
|
|
||||||
{
|
|
||||||
auto vsubs = parseJSON("[]");
|
|
||||||
foreach (Symbol* sub; subs)
|
|
||||||
sub.serializeJson(vsubs);
|
|
||||||
vobj["items"] = vsubs;
|
|
||||||
}
|
|
||||||
json.array ~= vobj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//----
|
|
||||||
|
|
||||||
// AST visitor/Symbol list ----------------------------------------------------+
|
// AST visitor/Symbol list ----------------------------------------------------+
|
||||||
class SymbolListBuilder : ASTVisitor
|
class SymbolListBuilder(ListFmt Fmt): ASTVisitor
|
||||||
{
|
{
|
||||||
Symbol* root;
|
|
||||||
Symbol* parent;
|
|
||||||
|
|
||||||
// for some reason (?) the .name of a (static Symbol* []) item was lost
|
static if (Fmt == ListFmt.Pas)
|
||||||
__gshared static Symbol[] illFormed;
|
{
|
||||||
|
static Appender!string pasStream;
|
||||||
size_t count;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static JSONValue json;
|
||||||
|
static JSONValue* jarray;
|
||||||
|
}
|
||||||
|
|
||||||
alias visit = ASTVisitor.visit;
|
alias visit = ASTVisitor.visit;
|
||||||
|
|
||||||
this()
|
static this()
|
||||||
{
|
{
|
||||||
root = construct!Symbol;
|
static if (Fmt == ListFmt.Pas)
|
||||||
resetRoot;
|
{
|
||||||
|
pasStream.put("object TSymbolList\rsymbols = <");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
~this()
|
|
||||||
{
|
{
|
||||||
root.destruct;
|
json = parseJSON("[]");
|
||||||
|
jarray = &json;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void astError(string fname, size_t line, size_t col, string msg, bool isErr)
|
static void astError(string fname, size_t line, size_t col, string msg, bool isErr)
|
||||||
{
|
{
|
||||||
Symbol* newSym = construct!Symbol;
|
SymbolType type = isErr ? SymbolType._error : SymbolType._warning;
|
||||||
newSym.col = col;
|
static if (Fmt == ListFmt.Pas)
|
||||||
newSym.line = line;
|
|
||||||
newSym.name = patchPasStringLitteral(msg);
|
|
||||||
newSym.type = isErr ? SymbolType._error : SymbolType._warning;
|
|
||||||
illFormed ~= *newSym;
|
|
||||||
}
|
|
||||||
|
|
||||||
final void resetRoot()
|
|
||||||
{
|
{
|
||||||
parent = root;
|
pasStream.put("\ritem\r");
|
||||||
|
pasStream.put(format("line = %d\r", line));
|
||||||
|
pasStream.put(format("col = %d\r", col));
|
||||||
|
pasStream.put(format("name = '%s'\r", patchPasStringLitteral(msg)));
|
||||||
|
pasStream.put(format("symType = %s\r", type));
|
||||||
|
pasStream.put("end");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
final string serializePascal()
|
|
||||||
{
|
{
|
||||||
Appender!string lfmApp;
|
JSONValue item = parseJSON("{}");
|
||||||
lfmApp.reserve(count * 64);
|
item["line"] = JSONValue(line);
|
||||||
|
item["col"] = JSONValue(col);
|
||||||
lfmApp.put("object TSymbolList\rsymbols = <");
|
item["name"] = JSONValue(msg);
|
||||||
foreach (sym; illFormed)
|
item["type"] = JSONValue(to!string(type));
|
||||||
sym.serialize(lfmApp);
|
jarray.array ~= item;
|
||||||
foreach (sym; root.subs)
|
}
|
||||||
sym.serialize(lfmApp);
|
|
||||||
lfmApp.put(">\rend\r\n");
|
|
||||||
|
|
||||||
return lfmApp.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final string serializeJson()
|
final string serialize()
|
||||||
|
{
|
||||||
|
static if (Fmt == ListFmt.Pas)
|
||||||
|
{
|
||||||
|
pasStream.put(">\rend\r\n");
|
||||||
|
return pasStream.data;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
JSONValue result = parseJSON("{}");
|
JSONValue result = parseJSON("{}");
|
||||||
JSONValue vsubs = parseJSON("[]");
|
result["items"] = json;
|
||||||
foreach (sym; illFormed)
|
|
||||||
sym.serialize(vsubs);
|
|
||||||
foreach (sym; root.subs)
|
|
||||||
sym.serialize(vsubs);
|
|
||||||
result["items"] = vsubs;
|
|
||||||
version (assert)
|
version (assert)
|
||||||
return result.toPrettyString;
|
return result.toPrettyString;
|
||||||
// else: release mode
|
|
||||||
else
|
else
|
||||||
return result.toString;
|
return result.toString;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// visitor implementation if the declaration has a "name".
|
/// visitor implementation if the declaration has a "name".
|
||||||
final void namedVisitorImpl(DT, SymbolType st, bool dig = true)(const(DT) dt)
|
final void namedVisitorImpl(DT, SymbolType st, bool dig = true)(const(DT) dt)
|
||||||
if (__traits(hasMember, DT, "name"))
|
if (__traits(hasMember, DT, "name"))
|
||||||
{
|
{
|
||||||
++count;
|
static if (Fmt == ListFmt.Pas)
|
||||||
Symbol* newSymbol = construct!Symbol;
|
{
|
||||||
newSymbol.name = dt.name.text;
|
pasStream.put("\ritem\r");
|
||||||
newSymbol.line = dt.name.line;
|
pasStream.put(format("line = %d\r", dt.name.line));
|
||||||
newSymbol.col = dt.name.column;
|
pasStream.put(format("col = %d\r", dt.name.column));
|
||||||
newSymbol.type = st;
|
pasStream.put(format("name = '%s'\r", dt.name.text));
|
||||||
parent.subs ~= newSymbol;
|
pasStream.put(format("symType = %s\r", st));
|
||||||
static if (dig)
|
static if (dig)
|
||||||
{
|
{
|
||||||
auto previousParent = parent;
|
pasStream.put("subs = <");
|
||||||
scope (exit)
|
|
||||||
parent = previousParent;
|
|
||||||
parent = newSymbol;
|
|
||||||
dt.accept(this);
|
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(to!string(st));
|
||||||
|
static if (dig)
|
||||||
|
{
|
||||||
|
JSONValue subs = parseJSON("[]");
|
||||||
|
JSONValue* old = jarray;
|
||||||
|
jarray = &subs;
|
||||||
|
dt.accept(this);
|
||||||
|
item["items"] = subs;
|
||||||
|
jarray = old;
|
||||||
|
}
|
||||||
|
json.array ~= item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// visitor implementation for special cases.
|
/// visitor implementation for special cases.
|
||||||
final void otherVisitorImpl(SymbolType st, string name, size_t line, size_t col)
|
final void otherVisitorImpl(DT, bool dig = true)
|
||||||
|
(const(DT) dt, SymbolType st, string name, size_t line, size_t col)
|
||||||
{
|
{
|
||||||
count++;
|
static if (Fmt == ListFmt.Pas)
|
||||||
Symbol* result = construct!Symbol;
|
{
|
||||||
result.name = name.idup;
|
pasStream.put("\ritem\r");
|
||||||
result.line = line;
|
pasStream.put(format("line = %d\r", line));
|
||||||
result.col = col;
|
pasStream.put(format("col = %d\r", col));
|
||||||
result.type = st;
|
pasStream.put(format("name = '%s'\r", name));
|
||||||
parent.subs ~= result;
|
pasStream.put(format("symType = %s\r", st));
|
||||||
|
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(to!string(st));
|
||||||
|
static if (dig)
|
||||||
|
{
|
||||||
|
JSONValue subs = parseJSON("[]");
|
||||||
|
JSONValue* old = jarray;
|
||||||
|
jarray = &subs;
|
||||||
|
dt.accept(this);
|
||||||
|
item["items"] = subs;
|
||||||
|
jarray = old;
|
||||||
|
}
|
||||||
|
json.array ~= item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void visit(const AliasDeclaration decl)
|
final override void visit(const AliasDeclaration decl)
|
||||||
|
@ -376,7 +333,7 @@ class SymbolListBuilder : ASTVisitor
|
||||||
{
|
{
|
||||||
if (decl.identifiers.length)
|
if (decl.identifiers.length)
|
||||||
{
|
{
|
||||||
otherVisitorImpl(SymbolType._variable, decl.identifiers[0].text,
|
otherVisitorImpl(decl, SymbolType._variable, decl.identifiers[0].text,
|
||||||
decl.identifiers[0].line, decl.identifiers[0].column);
|
decl.identifiers[0].line, decl.identifiers[0].column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,12 +345,12 @@ class SymbolListBuilder : ASTVisitor
|
||||||
|
|
||||||
final override void visit(const Constructor decl)
|
final override void visit(const Constructor decl)
|
||||||
{
|
{
|
||||||
otherVisitorImpl(SymbolType._function, "this", decl.line, decl.column);
|
otherVisitorImpl(decl, SymbolType._function, "this", decl.line, decl.column);
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void visit(const Destructor decl)
|
final override void visit(const Destructor decl)
|
||||||
{
|
{
|
||||||
otherVisitorImpl(SymbolType._function, "~this", decl.line, decl.column);
|
otherVisitorImpl(decl, SymbolType._function, "~this", decl.line, decl.column);
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void visit(const EnumDeclaration decl)
|
final override void visit(const EnumDeclaration decl)
|
||||||
|
@ -429,7 +386,7 @@ class SymbolListBuilder : ASTVisitor
|
||||||
modules ~= ident.text;
|
modules ~= ident.text;
|
||||||
modules ~= ".";
|
modules ~= ".";
|
||||||
}
|
}
|
||||||
otherVisitorImpl(SymbolType._import, modules[0 .. $ - 1].join,
|
otherVisitorImpl(decl, SymbolType._import, modules[0 .. $ - 1].join,
|
||||||
si.identifierChain.identifiers[0].line,
|
si.identifierChain.identifiers[0].line,
|
||||||
si.identifierChain.identifiers[0].column);
|
si.identifierChain.identifiers[0].column);
|
||||||
}
|
}
|
||||||
|
@ -466,12 +423,13 @@ class SymbolListBuilder : ASTVisitor
|
||||||
|
|
||||||
final override void visit(const StaticConstructor decl)
|
final override void visit(const StaticConstructor decl)
|
||||||
{
|
{
|
||||||
otherVisitorImpl(SymbolType._function, "static this", decl.line, decl.column);
|
otherVisitorImpl(decl, SymbolType._function, "static this", decl.line, decl.column);
|
||||||
}
|
}
|
||||||
|
|
||||||
final override void visit(const StaticDestructor decl)
|
final override void visit(const StaticDestructor decl)
|
||||||
{
|
{
|
||||||
otherVisitorImpl(SymbolType._function, "static ~this", decl.line, decl.column);
|
|
||||||
|
otherVisitorImpl(decl, SymbolType._function, "static ~this", decl.line, decl.column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//----
|
//----
|
||||||
|
|
Loading…
Reference in New Issue