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