cesyms, serializes directly during the visit

This commit is contained in:
Basile Burg 2016-04-12 19:02:10 +02:00
parent 9fe1545de2
commit 50a2f499e6
1 changed files with 152 additions and 194 deletions

View File

@ -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);
auto ast = parseModule(getTokensForParser(source, config, &scache), fname,
&alloc, &(SymbolListBuilder.astError));
// visit each root member if (!asJson)
SymbolListBuilder slb = construct!SymbolListBuilder;
foreach (Declaration decl; ast.declarations)
{ {
slb.resetRoot; SymbolListBuilder!(ListFmt.Pas) slb = construct!(SymbolListBuilder!(ListFmt.Pas));
slb.visit(decl); auto ast = parseModule(getTokensForParser(source, config, &scache), fname,
} &alloc, &(slb.astError));
foreach (Declaration decl; ast.declarations)
version (none) slb.visit(decl);
{ write(slb.serialize);
int level = -1; slb.destruct;
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 else
{ {
if (asJson) SymbolListBuilder!(ListFmt.Json) slb = construct!(SymbolListBuilder!(ListFmt.Json));
write(slb.serializeJson); auto ast = parseModule(getTokensForParser(source, config, &scache), fname,
else &alloc, &(slb.astError));
write(slb.serializePascal); foreach (Declaration decl; ast.declarations)
slb.visit(decl);
write(slb.serialize);
slb.destruct;
} }
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,20 +138,8 @@ 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)))
{ {
if (!instance) if (!instance)
return; return;
@ -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 = <");
}
~this() else
{ {
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); pasStream.put("\ritem\r");
newSym.type = isErr ? SymbolType._error : SymbolType._warning; pasStream.put(format("line = %d\r", line));
illFormed ~= *newSym; pasStream.put(format("col = %d\r", col));
} pasStream.put(format("name = '%s'\r", patchPasStringLitteral(msg)));
pasStream.put(format("symType = %s\r", type));
final void resetRoot() pasStream.put("end");
{ }
parent = root;
}
final string serializePascal()
{
Appender!string lfmApp;
lfmApp.reserve(count * 64);
lfmApp.put("object TSymbolList\rsymbols = <");
foreach (sym; illFormed)
sym.serialize(lfmApp);
foreach (sym; root.subs)
sym.serialize(lfmApp);
lfmApp.put(">\rend\r\n");
return lfmApp.data;
}
final string serializeJson()
{
JSONValue result = parseJSON("{}");
JSONValue vsubs = parseJSON("[]");
foreach (sym; illFormed)
sym.serialize(vsubs);
foreach (sym; root.subs)
sym.serialize(vsubs);
result["items"] = vsubs;
version (assert)
return result.toPrettyString;
// else: release mode
else else
return result.toString; {
JSONValue item = parseJSON("{}");
item["line"] = JSONValue(line);
item["col"] = JSONValue(col);
item["name"] = JSONValue(msg);
item["type"] = JSONValue(to!string(type));
jarray.array ~= item;
}
}
final string serialize()
{
static if (Fmt == ListFmt.Pas)
{
pasStream.put(">\rend\r\n");
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". /// 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;
newSymbol.line = dt.name.line;
newSymbol.col = dt.name.column;
newSymbol.type = st;
parent.subs ~= newSymbol;
static if (dig)
{ {
auto previousParent = parent; pasStream.put("\ritem\r");
scope (exit) pasStream.put(format("line = %d\r", dt.name.line));
parent = previousParent; pasStream.put(format("col = %d\r", dt.name.column));
parent = newSymbol; pasStream.put(format("name = '%s'\r", dt.name.text));
dt.accept(this); 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(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);
} }
} }
//---- //----