From 25074446f281975780a61c4f7e938669054b46d3 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Fri, 12 Jun 2020 19:32:51 +0200 Subject: [PATCH] libdexed-d, return Pascal compatible strings, freed by ref counting --- dexed-d/src/common.d | 66 ++++++++++++++++++++++++++++++++++++++++++- dexed-d/src/symlist.d | 15 +++++----- dexed-d/src/todos.d | 10 +++---- src/u_dexed_d.pas | 4 +-- src/u_symlist.pas | 2 +- src/u_todolist.pas | 2 +- 6 files changed, 82 insertions(+), 17 deletions(-) diff --git a/dexed-d/src/common.d b/dexed-d/src/common.d index e685634f..64921b3e 100644 --- a/dexed-d/src/common.d +++ b/dexed-d/src/common.d @@ -7,7 +7,7 @@ import import dparse.lexer, dparse.ast, dparse.parser, dparse.rollback_allocator; import - iz.memory; + iz.memory, iz.containers; export extern(C) int d_rt_init(){ return rt_init(); } export extern(C) int d_rt_term(){ return rt_term(); } @@ -437,3 +437,67 @@ alias joinedFilesToFiles = (const char* a) => a[0 .. a.strlen] .filter!exists .filter!(b => b != "") .array; + +/** + * Translation of the FPC ref counted array type. + */ +struct FpcArray(T) +{ +private: + + size_t _refCount; + size_t _length; + T _data; + +public: + + /** + * Converts either and iz.containers.array or a D dynamic array to + * an array compatible with Freepascal built in arrays. + * + * The memory is allocated in the C heap and can be freed from + * the Pascal side, e.g on ref count decrement. + */ + static FpcArray!T* fromArray(A)(auto ref A array) nothrow @nogc + if (is(Unqual!A == T[]) || is(Unqual!A == iz.containers.Array!T)) + { + alias RT = FpcArray!T; + enum isChar = is(Unqual!T == char); + size_t len = size_t.sizeof * 2 + T.sizeof * array.length + ubyte(isChar); + void* mem = getMem(len); + // init refcount to -1 and length to izArray length + *cast(size_t*) (mem + 0 ) = -1; + *cast(size_t*) (mem + size_t.sizeof) = array.length; + // copy izArray data + mem[size_t.sizeof * 2 .. len - ubyte(isChar)] = array.ptr[0.. array.length * T.sizeof]; + // FreePascal specifies that strings are guaranteed to be zero terminated. + static if (isChar) + *cast(char*) (mem + len - 1) = '\0'; + auto result = cast(RT*) (mem + size_t.sizeof * 2); + return result; + } + + size_t length() const pure nothrow @nogc + { + return _length; + } + + size_t refCount() const pure nothrow @nogc + { + return _refCount; + } + + inout(T)* data() inout pure nothrow @nogc + { + return &_data; + } +} + +unittest +{ + enum test = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_è-(')àç_è"; + Array!char s = test; + auto fpcString = (FpcArray!char).fromArray(s); + assert(fpcString.length == test.length); + assert(fpcString.data[0..fpcString.length] == test); +} diff --git a/dexed-d/src/symlist.d b/dexed-d/src/symlist.d index bc64cda3..6e712e71 100644 --- a/dexed-d/src/symlist.d +++ b/dexed-d/src/symlist.d @@ -25,7 +25,7 @@ import * Returns: * The serialized symbols, as a C string. */ -export extern(C) const(char)* listSymbols(const(char)* src, bool deep) +export extern(C) FpcArray!char* listSymbols(const(char)* src, bool deep) { Appender!(AstErrors) errors; @@ -53,8 +53,7 @@ export extern(C) const(char)* listSymbols(const(char)* src, bool deep) } sl.visit(mod); - const(char)* result = sl.serialize(); - return result; + return sl.serialize(); } private: @@ -137,7 +136,7 @@ static assert (!MustAddGcRange!(SymbolListBuilder!(ListFmt.Pas))); destruct(fmtVisitor); static if (Fmt == ListFmt.Pas) { - destruct(pasStream); + //destruct(pasStream); } } @@ -171,12 +170,14 @@ static assert (!MustAddGcRange!(SymbolListBuilder!(ListFmt.Pas))); } } - const(char)* serialize() + FpcArray!char* serialize() { static if (Fmt == ListFmt.Pas) { - pasStream.put(">\rend\0"); - return cast(typeof(return))pasStream[].dup.ptr; + pasStream.put(">\rend"); + import std.stdio; + writeln(pasStream.length); + return (FpcArray!char).fromArray(pasStream); } else { diff --git a/dexed-d/src/todos.d b/dexed-d/src/todos.d index d516b277..9bdc6628 100644 --- a/dexed-d/src/todos.d +++ b/dexed-d/src/todos.d @@ -8,11 +8,11 @@ import import common; -export extern(C) const(char)* todoItems(const(char)* joinedFiles) +export extern(C) FpcArray!(char)* todoItems(const(char)* joinedFiles) { - scope Appender!string stream; + scope Appender!(char[]) stream; scope LexerConfig config = LexerConfig("", StringBehavior.source); - scope StringCache cache = StringCache(4096); + scope StringCache cache = StringCache(4096); stream.reserve(32); stream.put("object TTodoItems\ritems=<"); foreach (fname; joinedFilesToFiles(joinedFiles)) @@ -24,10 +24,10 @@ export extern(C) const(char)* todoItems(const(char)* joinedFiles) .each!(t => analyze(t, fname, stream)); } stream.put(">end"); - return stream.data.toStringz(); + return (FpcArray!char).fromArray(stream.data); } -private void analyze(const(Token) token, const(char)[] fname, ref Appender!string stream) +private void analyze(const(Token) token, const(char)[] fname, ref Appender!(char[]) stream) { string text = token.text.strip.patchPascalString; string identifier; diff --git a/src/u_dexed_d.pas b/src/u_dexed_d.pas index fe174c26..0c8b7c63 100644 --- a/src/u_dexed_d.pas +++ b/src/u_dexed_d.pas @@ -74,9 +74,9 @@ function listFilesImports(const files: PChar): PDStrings; cdecl; external libdex // Get the variables necessary to compute the Halstead metrics of the functions within a module. function halsteadMetrics(const src: PChar): PChar; cdecl; external libdexedd_name; // Get the list of declarations within a module. -function listSymbols(const src: PChar; deep: Boolean): PChar; cdecl; external libdexedd_name; +function listSymbols(const src: PChar; deep: Boolean): pointer; cdecl; external libdexedd_name; // Get the TODO items located in `files` (list of files joined with pathseparaotr and null terminated) -function todoItems(joinedFiles: PChar): PChar; cdecl; external libdexedd_name; +function todoItems(joinedFiles: PChar): pointer; cdecl; external libdexedd_name; (** * Gets the module name and the imports of the source code located in diff --git a/src/u_symlist.pas b/src/u_symlist.pas index 06e62914..bd596a5e 100644 --- a/src/u_symlist.pas +++ b/src/u_symlist.pas @@ -751,7 +751,7 @@ end; procedure TSymbolListWidget.threadedParsing; begin - fTreeDataFromThread := listSymbols(PChar(fSourcecodeForThread), fDeep); + fTreeDataFromThread := string(listSymbols(PChar(fSourcecodeForThread), fDeep)); end; procedure TSymbolListWidget.threadedParsingFinished(sender: TObject); diff --git a/src/u_todolist.pas b/src/u_todolist.pas index f8eb2c39..9094ec9c 100644 --- a/src/u_todolist.pas +++ b/src/u_todolist.pas @@ -472,7 +472,7 @@ end; procedure TTodoListWidget.threadedScanning; begin - fSerializedTodoItemFromThread := todoItems(PChar(fFileListForThread)); + fSerializedTodoItemFromThread := string(todoItems(PChar(fFileListForThread))); end; procedure TTodoListWidget.threadedScanningFinished(Sender : TObject);