diff --git a/cesyms/cesyms.d b/cesyms/cesyms.d index 907bb4a2..74fa6fc9 100644 --- a/cesyms/cesyms.d +++ b/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 std.traits; + enum ListFmt { - Pascal, - JSON + Pas, + Json } void main(string[] args) @@ -62,47 +63,31 @@ void main(string[] args) else return; - // load and parse the file + // parses, visits and writes to stdout RollbackAllocator alloc; auto config = LexerConfig(fname, StringBehavior.source, WhitespaceBehavior.skip); auto scache = StringCache(StringCache.defaultBucketCount); - auto ast = parseModule(getTokensForParser(source, config, &scache), fname, - &alloc, &(SymbolListBuilder.astError)); - // visit each root member - SymbolListBuilder slb = construct!SymbolListBuilder; - foreach (Declaration decl; ast.declarations) + if (!asJson) { - slb.resetRoot; - slb.visit(decl); - } - - 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); + SymbolListBuilder!(ListFmt.Pas) slb = construct!(SymbolListBuilder!(ListFmt.Pas)); + auto ast = parseModule(getTokensForParser(source, config, &scache), fname, + &alloc, &(slb.astError)); + foreach (Declaration decl; ast.declarations) + slb.visit(decl); + write(slb.serialize); + slb.destruct; } else { - if (asJson) - write(slb.serializeJson); - else - write(slb.serializePascal); + 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; } - - slb.destruct; } // libdparse warnings includes some "'", which in Pascal are string delim @@ -133,14 +118,14 @@ string patchPasStringLitteral(string p) // Memory utils ---------------------------------------------------------------+ void* getMem(size_t size) nothrow { - import std.c.stdlib; - + import std.c.stdlib: malloc; auto result = malloc(size); assert(result, "Out of memory"); 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 memory = getMem(size); @@ -153,20 +138,8 @@ CT construct(CT, A...)(A a) if (is(CT == class) && !isAbstractClass!CT) 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) - if (is(T == class) || (isPointer!T && is(PointerTarget!T == struct))) + if (is(T == class) || (isPointer!T && is(PointerTarget!T == struct))) { if (!instance) return; @@ -175,7 +148,6 @@ void destruct(T)(ref T instance) } //---- -// Serializable Symbol --------------------------------------------------------+ enum SymbolType { _alias, @@ -193,167 +165,152 @@ enum SymbolType _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 ----------------------------------------------------+ -class SymbolListBuilder : ASTVisitor +class SymbolListBuilder(ListFmt Fmt): ASTVisitor { - Symbol* root; - Symbol* parent; - // for some reason (?) the .name of a (static Symbol* []) item was lost - __gshared static Symbol[] illFormed; - - size_t count; + static if (Fmt == ListFmt.Pas) + { + static Appender!string pasStream; + } + else + { + static JSONValue json; + static JSONValue* jarray; + } alias visit = ASTVisitor.visit; - this() + static this() { - root = construct!Symbol; - resetRoot; - } - - ~this() - { - root.destruct; + static if (Fmt == ListFmt.Pas) + { + pasStream.put("object TSymbolList\rsymbols = <"); + } + else + { + json = parseJSON("[]"); + jarray = &json; + } } static void astError(string fname, size_t line, size_t col, string msg, bool isErr) { - Symbol* newSym = construct!Symbol; - newSym.col = col; - newSym.line = line; - newSym.name = patchPasStringLitteral(msg); - newSym.type = isErr ? SymbolType._error : SymbolType._warning; - illFormed ~= *newSym; - } - - final void resetRoot() - { - 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 + SymbolType type = isErr ? SymbolType._error : SymbolType._warning; + 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", patchPasStringLitteral(msg))); + pasStream.put(format("symType = %s\r", type)); + pasStream.put("end"); + } 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". final void namedVisitorImpl(DT, SymbolType st, bool dig = true)(const(DT) dt) if (__traits(hasMember, DT, "name")) { - ++count; - 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) + static if (Fmt == ListFmt.Pas) { - auto previousParent = parent; - scope (exit) - parent = previousParent; - parent = newSymbol; - dt.accept(this); + 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(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. - 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++; - Symbol* result = construct!Symbol; - result.name = name.idup; - result.line = line; - result.col = col; - result.type = st; - parent.subs ~= result; + 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(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) @@ -376,7 +333,7 @@ class SymbolListBuilder : ASTVisitor { 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); } } @@ -388,12 +345,12 @@ class SymbolListBuilder : ASTVisitor 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) { - otherVisitorImpl(SymbolType._function, "~this", decl.line, decl.column); + otherVisitorImpl(decl, SymbolType._function, "~this", decl.line, decl.column); } final override void visit(const EnumDeclaration decl) @@ -429,7 +386,7 @@ class SymbolListBuilder : ASTVisitor modules ~= ident.text; 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].column); } @@ -466,12 +423,13 @@ class SymbolListBuilder : ASTVisitor 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) { - otherVisitorImpl(SymbolType._function, "static ~this", decl.line, decl.column); + + otherVisitorImpl(decl, SymbolType._function, "static ~this", decl.line, decl.column); } } //----