mirror of https://gitlab.com/basile.b/dexed.git
more for #39
- simplified API - renamed token to handle to avoid confusion - scan in a thread - notification
This commit is contained in:
parent
d0da5ebb4e
commit
2a9fb832bc
|
@ -1,7 +1,7 @@
|
|||
module ast;
|
||||
|
||||
import std.d.lexer, std.d.parser, std.d.ast;
|
||||
import std.json, std.array, std.conv;
|
||||
import std.json, std.array, std.conv, std.parallelism;
|
||||
import iz.enumset, iz.memory;
|
||||
|
||||
import common;
|
||||
|
@ -294,7 +294,7 @@ private
|
|||
}
|
||||
|
||||
|
||||
struct Ast
|
||||
class Ast
|
||||
{
|
||||
|
||||
private:
|
||||
|
@ -304,6 +304,8 @@ private:
|
|||
LexerConfig config;
|
||||
StringCache strcache;
|
||||
Module mod;
|
||||
AstNotification notif;
|
||||
void* notifparam;
|
||||
bool scanned;
|
||||
|
||||
CachedInfos cachedInfos;
|
||||
|
@ -325,49 +327,55 @@ private:
|
|||
{
|
||||
cachedInfos = 0;
|
||||
modName = modName.init;
|
||||
jsonErrors = jsonErrors.init;
|
||||
pasErrors = pasErrors.init;
|
||||
todosPas = todosPas.init;
|
||||
todosJson = todosJson.init;
|
||||
symsPas = symsPas.init;
|
||||
symsJson = symsJson.init;
|
||||
errors = errors.init;
|
||||
}
|
||||
|
||||
final void scan()
|
||||
final void taskScan()
|
||||
{
|
||||
resetCachedInfo;
|
||||
scanned = false;
|
||||
scope(success) scanned = true;
|
||||
|
||||
config = LexerConfig(fname, StringBehavior.source, WhitespaceBehavior.skip);
|
||||
mod = parseModule(getTokensForParser(src, config, &strcache), fname, null, &parserError);
|
||||
if (notif) notif(notifparam);
|
||||
scanned = true;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
this(string filename)
|
||||
{
|
||||
fname = filename;
|
||||
strcache = StringCache(StringCache.defaultBucketCount);
|
||||
rescanFile();
|
||||
}
|
||||
|
||||
this(ubyte[] buffer)
|
||||
this()
|
||||
{
|
||||
strcache = StringCache(StringCache.defaultBucketCount);
|
||||
rescanBuffer(buffer);
|
||||
}
|
||||
|
||||
final void rescanFile()
|
||||
final void scanFile(string filename)
|
||||
{
|
||||
resetCachedInfo;
|
||||
fname = filename;
|
||||
import std.file;
|
||||
src = cast(ubyte[]) read(fname, size_t.max);
|
||||
scan;
|
||||
try src = cast(ubyte[]) read(fname, size_t.max);
|
||||
catch(Exception e){}
|
||||
scanned = false;
|
||||
task(&taskScan).executeInNewThread;
|
||||
}
|
||||
|
||||
final void rescanBuffer(ubyte[] buffer)
|
||||
final void scanBuffer(ubyte[] buffer)
|
||||
{
|
||||
resetCachedInfo;
|
||||
src = buffer.dup;
|
||||
scan;
|
||||
scanned = false;
|
||||
task(&taskScan).executeInNewThread;
|
||||
}
|
||||
|
||||
@property AstNotification notification(){return notif;}
|
||||
@property void notification(AstNotification value){notif = value;}
|
||||
|
||||
@property void* notificationParameter(){return notifparam;}
|
||||
@property void notificationParameter(void* value){notifparam = value;}
|
||||
|
||||
final string moduleName()
|
||||
{
|
||||
string result;
|
||||
|
@ -423,3 +431,4 @@ public:
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -3,17 +3,19 @@ module cedast;
|
|||
import core.runtime, common, ast;
|
||||
import iz.memory;
|
||||
|
||||
__gshared Ast*[] modules;
|
||||
__gshared Ast[] modules;
|
||||
|
||||
|
||||
extern(C) export
|
||||
AstToken scanFile(char* filename)
|
||||
AstHandle newAst(void* param, AstNotification clbck)
|
||||
{
|
||||
AstToken result;
|
||||
AstHandle result;
|
||||
try
|
||||
{
|
||||
import std.string: fromStringz;
|
||||
import std.algorithm: countUntil;
|
||||
Ast* ast = construct!Ast(filename.fromStringz.idup);
|
||||
Ast ast = construct!Ast;
|
||||
ast.notification = clbck;
|
||||
ast.notificationParameter = param;
|
||||
result = countUntil(modules, null);
|
||||
if (result == -1)
|
||||
{
|
||||
|
@ -28,115 +30,92 @@ AstToken scanFile(char* filename)
|
|||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
if (result != 0) unleash(result);
|
||||
result = invalidAstToken;
|
||||
if (result != 0) deleteAst(result);
|
||||
result = invalidAstHandle;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
AstToken scanBuffer(ubyte* buffer, size_t len)
|
||||
void deleteAst(AstHandle hdl)
|
||||
{
|
||||
AstToken result;
|
||||
try
|
||||
{
|
||||
import std.algorithm: countUntil;
|
||||
Ast* ast = construct!Ast(buffer[0 .. len]);
|
||||
result = countUntil(modules, null);
|
||||
if (result == -1)
|
||||
{
|
||||
modules ~= ast;
|
||||
result = modules.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
modules[result] = ast;
|
||||
++result;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
if (result != 0) unleash(result);
|
||||
result = invalidAstToken;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (hdl < 1 || hdl > modules.length)
|
||||
return;
|
||||
if (modules[hdl - 1] is null)
|
||||
return;
|
||||
|
||||
extern(C) export
|
||||
void rescanFile(AstToken tok)
|
||||
{
|
||||
if (tok < 1 || tok > modules.length)
|
||||
return;
|
||||
modules[tok - 1].rescanFile;
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
void rescanBuffer(AstToken tok, ubyte* buffer, size_t len)
|
||||
{
|
||||
if (tok < 1 || tok > modules.length)
|
||||
return;
|
||||
modules[tok - 1].rescanBuffer(buffer[0 .. len]);
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
void unleash(AstToken tok)
|
||||
{
|
||||
mixin(logcall);
|
||||
if (tok < 1 || tok > modules.length)
|
||||
return;
|
||||
if (modules[tok - 1] == null)
|
||||
return;
|
||||
destruct(modules[tok - 1]);
|
||||
modules[tok - 1] = null;
|
||||
if (tok == modules.length)
|
||||
destruct(modules[hdl - 1]);
|
||||
modules[hdl - 1] = null;
|
||||
if (hdl == modules.length)
|
||||
modules.length -= 1;
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
immutable(char*) moduleName(AstToken tok)
|
||||
void scanFile(AstHandle hdl, char* filename)
|
||||
{
|
||||
if (tok < 1 || tok > modules.length)
|
||||
return null;
|
||||
Ast* mod = modules[tok - 1];
|
||||
if (mod == null)
|
||||
return null;
|
||||
import std.string: toStringz;
|
||||
return toStringz(mod.moduleName);
|
||||
if (hdl < 1 || hdl > modules.length)
|
||||
return;
|
||||
if (modules[hdl - 1] is null)
|
||||
return;
|
||||
|
||||
import std.string: fromStringz;
|
||||
modules[hdl - 1].scanFile(fromStringz(filename).idup);
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
ubyte* symbolList(AstToken tok, ref size_t len, SerializationFormat fmt)
|
||||
void scanBuffer(AstHandle hdl, ubyte* buffer, size_t len)
|
||||
{
|
||||
if (tok < 1 || tok > modules.length)
|
||||
if (hdl < 1 || hdl > modules.length)
|
||||
return;
|
||||
if (modules[hdl - 1] is null)
|
||||
return;
|
||||
|
||||
modules[hdl - 1].scanBuffer(buffer[0 .. len]);
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
immutable(char*) moduleName(AstHandle hdl)
|
||||
{
|
||||
if (hdl < 1 || hdl > modules.length)
|
||||
return null;
|
||||
Ast* mod = modules[tok - 1];
|
||||
if (mod == null)
|
||||
if (modules[hdl - 1] is null)
|
||||
return null;
|
||||
|
||||
import std.string: toStringz;
|
||||
return toStringz(modules[hdl - 1].moduleName);
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
ubyte* symbolList(AstHandle hdl, ref size_t len, SerializationFormat fmt)
|
||||
{
|
||||
if (hdl < 1 || hdl > modules.length)
|
||||
return null;
|
||||
if (modules[hdl - 1] is null)
|
||||
return null;
|
||||
|
||||
ubyte[] result;
|
||||
if (fmt == SerializationFormat.json)
|
||||
result = mod.symbolListJson;
|
||||
result = modules[hdl - 1].symbolListJson;
|
||||
else
|
||||
result = mod.symbolListPas;
|
||||
result = modules[hdl - 1].symbolListPas;
|
||||
|
||||
len = result.length;
|
||||
return result.ptr;
|
||||
}
|
||||
|
||||
extern(C) export
|
||||
ubyte* todoList(AstToken tok, ref size_t len, SerializationFormat fmt)
|
||||
ubyte* todoList(AstHandle hdl, ref size_t len, SerializationFormat fmt)
|
||||
{
|
||||
if (tok < 1 || tok > modules.length)
|
||||
if (hdl < 1 || hdl > modules.length)
|
||||
return null;
|
||||
Ast* mod = modules[tok - 1];
|
||||
if (mod == null)
|
||||
if (modules[hdl - 1] is null)
|
||||
return null;
|
||||
|
||||
ubyte[] result;
|
||||
if (fmt == SerializationFormat.json)
|
||||
result = mod.todoListJson;
|
||||
result = modules[hdl - 1].todoListJson;
|
||||
else
|
||||
result = mod.todoListPas;
|
||||
result = modules[hdl - 1].todoListPas;
|
||||
|
||||
len = result.length;
|
||||
return result.ptr;
|
||||
|
@ -177,4 +156,3 @@ version(Windows)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
module common;
|
||||
|
||||
alias AstToken = ptrdiff_t;
|
||||
alias AstHandle = ptrdiff_t;
|
||||
|
||||
__gshared immutable AstToken invalidAstToken = 0;
|
||||
alias AstNotification = extern(C) void function(void* param);
|
||||
|
||||
__gshared immutable AstHandle invalidAstHandle = 0;
|
||||
|
||||
enum SerializationFormat : byte
|
||||
{
|
||||
|
|
|
@ -1,41 +1,52 @@
|
|||
program cedast_loader;
|
||||
|
||||
{$MODE OBJFPC}
|
||||
|
||||
uses dynlibs, classes, sysutils;
|
||||
|
||||
type
|
||||
|
||||
TAstToken = NativeInt;
|
||||
TAstHandle = NativeInt;
|
||||
|
||||
TAstNotification = procedure(param: pointer); cdecl;
|
||||
|
||||
{$Z1}
|
||||
|
||||
TSerializationFormat = (json, pas);
|
||||
|
||||
TScanFile = function(filename: PChar): TAstToken; cdecl;
|
||||
TScanBuffer = function(buffer: PByte; len: NativeUint): TAstToken; cdecl;
|
||||
TRescanFile = procedure(tok: TAstToken); cdecl;
|
||||
TRescanBuffer = procedure(tok: TAstToken; buffer: PByte; len: NativeUint); cdecl;
|
||||
TUnleash = procedure(tok: TAstToken); cdecl;
|
||||
TNewAst = function(param: Pointer; clbck: TAstNotification): TAstHandle; cdecl;
|
||||
TDeleteAst = procedure(tok: TAstHandle); cdecl;
|
||||
|
||||
TModuleName = function(tok: TAstToken): PChar; cdecl;
|
||||
TSymbolList = function(tok: TAstToken; var len: NativeUint ; fmt: TSerializationFormat): PByte; cdecl;
|
||||
TScanFile = procedure(tok: TAstHandle; filename: PChar); cdecl;
|
||||
TScanBuffer = procedure(tok: TAstHandle; buffer: PByte; len: NativeUint); cdecl;
|
||||
|
||||
|
||||
TModuleName = function(tok: TAstHandle): PChar; cdecl;
|
||||
TSymbolList = function(tok: TAstHandle; var len: NativeUint ; fmt: TSerializationFormat): PByte; cdecl;
|
||||
|
||||
|
||||
|
||||
var
|
||||
dast: TLibHandle;
|
||||
scanfile: TScanFile;
|
||||
scanbuffer: TScanBuffer;
|
||||
rescanfile: TRescanFile;
|
||||
rescanbuffer: TRescanBuffer;
|
||||
unleash: TUnleash;
|
||||
newAst: TNewAst;
|
||||
deleteast: TDeleteAst;
|
||||
scanFile: TScanFile;
|
||||
scanBuffer: TScanBuffer;
|
||||
moduleName: TModuleName;
|
||||
symlist: TSymbolList;
|
||||
tok: TAstToken;
|
||||
symbolList: TSymbolList;
|
||||
hdl: TAstHandle;
|
||||
len: NativeUint = 0;
|
||||
ptr: PByte;
|
||||
done: boolean;
|
||||
|
||||
const
|
||||
testModule = 'module a.b.c.d.e.f.g.h; import std.stdio; uint a; struct F{long c;}';
|
||||
|
||||
procedure notif(param: Pointer); cdecl;
|
||||
begin
|
||||
done := true;
|
||||
end;
|
||||
|
||||
|
||||
begin
|
||||
|
||||
|
@ -43,39 +54,44 @@ begin
|
|||
if dast = NilHandle then
|
||||
writeln('dast invalid handle')
|
||||
else begin
|
||||
scanfile := TScanFile(GetProcAddress(dast, 'scanFile'));
|
||||
|
||||
newAst := TNewAst(GetProcAddress(dast, 'newAst'));
|
||||
if newAst = nil then writeln('invalid newAst proc ptr')
|
||||
else hdl := newAst(nil, @notif);
|
||||
|
||||
scanFile := TScanFile(GetProcAddress(dast, 'scanFile'));
|
||||
if scanFile = nil then writeln('invalid scanfile proc ptr')
|
||||
else tok := scanfile(PChar('exception in call so ticket value is 0'));
|
||||
else begin
|
||||
done := false;
|
||||
scanFile(hdl, PChar('exception in call'));
|
||||
while not done do sleep(20);
|
||||
end;
|
||||
|
||||
rescanfile := TRescanFile(GetProcAddress(dast, 'rescanFile'));
|
||||
if rescanfile = nil then writeln('invalid rescanFile proc ptr')
|
||||
else rescanfile(tok);
|
||||
|
||||
scanbuffer := TScanBuffer(GetProcAddress(dast, 'scanBuffer'));
|
||||
if scanbuffer = nil then writeln('invalid scanBuffer proc ptr')
|
||||
else tok := scanbuffer(@testModule[1], length(testModule));
|
||||
|
||||
rescanbuffer := TRescanBuffer(GetProcAddress(dast, 'rescanBuffer'));
|
||||
if rescanbuffer = nil then writeln('invalid rescanBuffer proc ptr')
|
||||
else rescanbuffer(tok, @testmodule[1], length(testModule));
|
||||
scanBuffer := TScanBuffer(GetProcAddress(dast, 'scanBuffer'));
|
||||
if scanBuffer = nil then writeln('invalid scanBuffer proc ptr')
|
||||
else begin
|
||||
done := false;
|
||||
scanBuffer(hdl, @testModule[1], length(testModule));
|
||||
while not done do sleep(20);
|
||||
end;
|
||||
|
||||
moduleName := TModuleName(GetProcAddress(dast, 'moduleName'));
|
||||
if moduleName = nil then writeln('invalid moduleName proc ptr')
|
||||
else if tok <> 0 then writeln(moduleName(tok));
|
||||
else if hdl <> 0 then writeln(moduleName(hdl));
|
||||
|
||||
symlist := TSymbolList(GetProcAddress(dast, 'symbolList'));
|
||||
if symlist = nil then writeln('invalid symbolList proc ptr')
|
||||
else if tok <> 0 then with TMemoryStream.Create do try
|
||||
ptr := symlist(tok, len, TSerializationFormat.json);
|
||||
symbolList := TSymbolList(GetProcAddress(dast, 'symbolList'));
|
||||
if symbolList = nil then writeln('invalid symbolList proc ptr')
|
||||
else if hdl <> 0 then with TMemoryStream.Create do try
|
||||
ptr := symbolList(hdl, len, TSerializationFormat.json);
|
||||
write(ptr^, len);
|
||||
SaveToFile('testsymlist.txt');
|
||||
finally
|
||||
free;
|
||||
end;
|
||||
|
||||
unleash := TUnleash(GetProcAddress(dast, 'unleash'));
|
||||
if unleash = nil then writeln('invalid unleash proc ptr')
|
||||
else unleash(tok);
|
||||
deleteAst := TDeleteAst(GetProcAddress(dast, 'deleteAst'));
|
||||
if deleteAst = nil then writeln('invalid deleteAst proc ptr')
|
||||
else deleteAst(hdl);
|
||||
|
||||
end;
|
||||
|
||||
|
|
Loading…
Reference in New Issue