mirror of https://gitlab.com/basile.b/dexed.git
fix, UB in symlist, GC freed some strings in the unmanaged symbol tree
This commit is contained in:
parent
0d7e34c1f1
commit
6d60a3118c
159
cesyms/cesyms.d
159
cesyms/cesyms.d
|
|
@ -12,7 +12,7 @@ Usage
|
|||
- `<filename>`: optional, the D module filename, if not set then the program
|
||||
reads the module from stdin.
|
||||
- see the source for more information about how to use the output.
|
||||
It's basically a tree of struct with 3 members: symbol type, name and location.
|
||||
It's basically a tree of struct with 3 members: symbol type, name and location
|
||||
|
||||
- Test in CE as a runnable module:
|
||||
click `Compile file and run ...` and type either `<CFF>` or `-j <CFF>` in the
|
||||
|
|
@ -48,21 +48,25 @@ void main(string[] args)
|
|||
{
|
||||
source = cast(ubyte[]) read(__FILE__, size_t.max);
|
||||
}
|
||||
else foreach(buff; stdin.byChunk(1024))
|
||||
else
|
||||
foreach (buff; stdin.byChunk(1024))
|
||||
source ~= buff;
|
||||
}
|
||||
else if (args.length == 2)
|
||||
{
|
||||
fname = args[$ - 1];
|
||||
if (!fname.exists) return;
|
||||
if (!fname.exists)
|
||||
return;
|
||||
source = cast(ubyte[]) read(fname, size_t.max);
|
||||
}
|
||||
else return;
|
||||
else
|
||||
return;
|
||||
|
||||
// load and parse the file
|
||||
auto config = LexerConfig(fname, StringBehavior.source, WhitespaceBehavior.skip);
|
||||
auto scache = StringCache(StringCache.defaultBucketCount);
|
||||
auto ast = parseModule(getTokensForParser(source, config, &scache), fname, null, &(SymbolListBuilder.astError));
|
||||
auto ast = parseModule(getTokensForParser(source, config, &scache), fname,
|
||||
null, &(SymbolListBuilder.astError));
|
||||
|
||||
// visit each root member
|
||||
SymbolListBuilder slb = construct!SymbolListBuilder;
|
||||
|
|
@ -77,7 +81,8 @@ void main(string[] args)
|
|||
int level = -1;
|
||||
void print(Symbol* s)
|
||||
{
|
||||
foreach(i; 0 .. level) write(".");
|
||||
foreach (i; 0 .. level)
|
||||
write(".");
|
||||
level++;
|
||||
write(s.name, '\r');
|
||||
foreach (ss; s.subs)
|
||||
|
|
@ -85,32 +90,41 @@ void main(string[] args)
|
|||
|
||||
level--;
|
||||
}
|
||||
|
||||
print(slb.root);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (asJson) write(slb.serializeJson);
|
||||
else write(slb.serializePascal);
|
||||
if (asJson)
|
||||
write(slb.serializeJson);
|
||||
else
|
||||
write(slb.serializePascal);
|
||||
}
|
||||
|
||||
slb.destruct;
|
||||
}
|
||||
|
||||
// libdparse warnings includes some "'", which in Pascal are string delim
|
||||
string patchPasStringLitteral(const ref string p)
|
||||
string patchPasStringLitteral(string p)
|
||||
{
|
||||
import std.range : empty, front, popFront;
|
||||
|
||||
string result;
|
||||
for (auto i = 0; i < p.length; i++)
|
||||
while (!p.empty)
|
||||
{
|
||||
auto curr = p[i];
|
||||
if (curr == 0)
|
||||
break;
|
||||
else if (curr == 13 || curr == 10)
|
||||
result ~= ' ';
|
||||
else if (curr == '\'')
|
||||
result ~= "'#39'";
|
||||
else
|
||||
dchar curr = p.front;
|
||||
switch (curr)
|
||||
{
|
||||
default:
|
||||
result ~= curr;
|
||||
break;
|
||||
case 10, 13:
|
||||
result ~= ' ';
|
||||
break;
|
||||
case '\'':
|
||||
result ~= "'#39'";
|
||||
}
|
||||
p.popFront;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -119,33 +133,42 @@ string patchPasStringLitteral(const ref string p)
|
|||
void* getMem(size_t size) nothrow
|
||||
{
|
||||
import std.c.stdlib;
|
||||
|
||||
auto result = malloc(size);
|
||||
assert(result, "Out of memory");
|
||||
return result;
|
||||
}
|
||||
|
||||
CT construct(CT, A...)(A a)
|
||||
if (is(CT == class))
|
||||
CT construct(CT, A...)(A a) if (is(CT == class) && !isAbstractClass!CT)
|
||||
{
|
||||
import std.conv : emplace;
|
||||
auto size = __traits(classInstanceSize, CT);
|
||||
auto memory = getMem(size)[0 .. size];
|
||||
return emplace!(CT, A)(memory, a);
|
||||
auto size = typeid(CT).init.length;
|
||||
auto memory = getMem(size);
|
||||
memory[0 .. size] = typeid(CT).init[];
|
||||
static if (__traits(hasMember, CT, "__ctor"))
|
||||
(cast(CT)(memory)).__ctor(a);
|
||||
import core.memory : GC;
|
||||
|
||||
GC.addRange(memory, size, typeid(CT));
|
||||
return cast(CT) memory;
|
||||
}
|
||||
|
||||
ST * construct(ST, A...)(A a)
|
||||
if(is(ST==struct))
|
||||
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 (!instance) return;
|
||||
if (!instance)
|
||||
return;
|
||||
destroy(instance);
|
||||
instance = null;
|
||||
}
|
||||
|
|
@ -189,7 +212,8 @@ struct Symbol
|
|||
serializePascal(list);
|
||||
else static if (is(List == JSONValue))
|
||||
serializeJson(list);
|
||||
else static assert(0, "serialization kind cannot be deduced from list");
|
||||
else
|
||||
static assert(0, "serialization kind cannot be deduced from list");
|
||||
}
|
||||
|
||||
void serializePascal(ref Appender!string lfmApp)
|
||||
|
|
@ -202,7 +226,8 @@ struct Symbol
|
|||
lfmApp.put(format("symType = %s\r", type));
|
||||
|
||||
lfmApp.put("subs = <");
|
||||
if (subs.length) foreach(Symbol * sub; subs)
|
||||
if (subs.length)
|
||||
foreach (Symbol* sub; subs)
|
||||
sub.serialize(lfmApp);
|
||||
lfmApp.put(">\r");
|
||||
lfmApp.put("end");
|
||||
|
|
@ -261,7 +286,10 @@ class SymbolListBuilder : ASTVisitor
|
|||
illFormed ~= *newSym;
|
||||
}
|
||||
|
||||
final void resetRoot(){parent = root;}
|
||||
final void resetRoot()
|
||||
{
|
||||
parent = root;
|
||||
}
|
||||
|
||||
final string serializePascal()
|
||||
{
|
||||
|
|
@ -269,8 +297,10 @@ class SymbolListBuilder : ASTVisitor
|
|||
lfmApp.reserve(count * 64);
|
||||
|
||||
lfmApp.put("object TSymbolList\rsymbols = <");
|
||||
foreach(sym; illFormed) sym.serialize(lfmApp);
|
||||
foreach(sym; root.subs) sym.serialize(lfmApp);
|
||||
foreach (sym; illFormed)
|
||||
sym.serialize(lfmApp);
|
||||
foreach (sym; root.subs)
|
||||
sym.serialize(lfmApp);
|
||||
lfmApp.put(">\rend\r\n");
|
||||
|
||||
return lfmApp.data;
|
||||
|
|
@ -280,40 +310,34 @@ class SymbolListBuilder : ASTVisitor
|
|||
{
|
||||
JSONValue result = parseJSON("{}");
|
||||
JSONValue vsubs = parseJSON("[]");
|
||||
foreach(sym; illFormed) sym.serialize(vsubs);
|
||||
foreach(sym; root.subs) sym.serialize(vsubs);
|
||||
foreach (sym; illFormed)
|
||||
sym.serialize(vsubs);
|
||||
foreach (sym; root.subs)
|
||||
sym.serialize(vsubs);
|
||||
result["items"] = vsubs;
|
||||
version(assert) return result.toPrettyString;
|
||||
version (assert)
|
||||
return result.toPrettyString;
|
||||
// else: release mode
|
||||
else return result.toString;
|
||||
else
|
||||
return result.toString;
|
||||
}
|
||||
|
||||
/// returns a new symbol if the declarator is based on a Token named "name".
|
||||
final Symbol * addDeclaration(DT)(DT adt)
|
||||
{
|
||||
static if (__traits(hasMember, DT, "name"))
|
||||
{
|
||||
count++;
|
||||
auto result = construct!Symbol;
|
||||
result.name = adt.name.text;
|
||||
result.line = adt.name.line;
|
||||
result.col = adt.name.column;
|
||||
parent.subs ~= result;
|
||||
return result;
|
||||
}
|
||||
else static assert(0, "addDeclaration no implemented for " ~ DT.stringof);
|
||||
}
|
||||
|
||||
/// visitor implementation if the declarator is based on a Token named "name".
|
||||
/// 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"))
|
||||
{
|
||||
auto newSymbol = addDeclaration(dt);
|
||||
++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)
|
||||
{
|
||||
auto previousParent = parent;
|
||||
scope(exit) parent = previousParent;
|
||||
scope (exit)
|
||||
parent = previousParent;
|
||||
parent = newSymbol;
|
||||
dt.accept(this);
|
||||
}
|
||||
|
|
@ -323,8 +347,8 @@ class SymbolListBuilder : ASTVisitor
|
|||
final void otherVisitorImpl(SymbolType st, string name, size_t line, size_t col)
|
||||
{
|
||||
count++;
|
||||
auto result = construct!Symbol;
|
||||
result.name = name;
|
||||
Symbol* result = construct!Symbol;
|
||||
result.name = name.idup;
|
||||
result.line = line;
|
||||
result.col = col;
|
||||
result.type = st;
|
||||
|
|
@ -333,8 +357,7 @@ class SymbolListBuilder : ASTVisitor
|
|||
|
||||
final override void visit(const AliasDeclaration decl)
|
||||
{
|
||||
// why is initializers an array ?
|
||||
if (decl.initializers.length > 0)
|
||||
if (decl.initializers.length)
|
||||
namedVisitorImpl!(AliasInitializer, SymbolType._alias)(decl.initializers[0]);
|
||||
}
|
||||
|
||||
|
|
@ -350,9 +373,11 @@ class SymbolListBuilder : ASTVisitor
|
|||
|
||||
final override void visit(const AutoDeclaration decl)
|
||||
{
|
||||
otherVisitorImpl(SymbolType._enum, decl.identifiers[0].text,
|
||||
if (decl.identifiers.length)
|
||||
{
|
||||
otherVisitorImpl(SymbolType._variable, decl.identifiers[0].text,
|
||||
decl.identifiers[0].line, decl.identifiers[0].column);
|
||||
decl.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
final override void visit(const ClassDeclaration decl)
|
||||
|
|
@ -396,18 +421,16 @@ class SymbolListBuilder : ASTVisitor
|
|||
{
|
||||
if (!si.identifierChain.identifiers.length)
|
||||
continue;
|
||||
//
|
||||
|
||||
string[] modules;
|
||||
foreach (ident; si.identifierChain.identifiers)
|
||||
{
|
||||
modules ~= ident.text;
|
||||
modules ~= ".";
|
||||
}
|
||||
//
|
||||
otherVisitorImpl(SymbolType._import, modules[0 .. $ - 1].join,
|
||||
si.identifierChain.identifiers[0].line,
|
||||
si.identifierChain.identifiers[0].column
|
||||
);
|
||||
si.identifierChain.identifiers[0].column);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -433,9 +456,10 @@ class SymbolListBuilder : ASTVisitor
|
|||
|
||||
final override void visit(const VariableDeclaration decl)
|
||||
{
|
||||
if (decl.declarators)
|
||||
foreach (elem; decl.declarators)
|
||||
namedVisitorImpl!(Declarator, SymbolType._variable, false)(elem);
|
||||
if (decl.autoDeclaration)
|
||||
else if (decl.autoDeclaration)
|
||||
visit(decl.autoDeclaration);
|
||||
}
|
||||
|
||||
|
|
@ -450,3 +474,4 @@ class SymbolListBuilder : ASTVisitor
|
|||
}
|
||||
}
|
||||
//----
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue