Skip to content
This repository has been archived by the owner on Mar 1, 2022. It is now read-only.

Commit

Permalink
support void functions with ref parameter in RPC
Browse files Browse the repository at this point in the history
fixes tc_as_a_exe test with long seeks breaking stuff
  • Loading branch information
WebFreak001 committed Jun 22, 2021
1 parent d71c29b commit dc3c054
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 24 deletions.
61 changes: 49 additions & 12 deletions source/workspaced/api.d
Original file line number Diff line number Diff line change
Expand Up @@ -208,15 +208,19 @@ mixin template DefaultComponentWrapper(bool withDtor = true)
override Future!JSONValue run(string method, JSONValue[] args)
{
static foreach (member; __traits(derivedMembers, typeof(this)))
static if (member[0] != '_' && __traits(compiles, __traits(getMember,
typeof(this).init, member)) && __traits(getProtection, __traits(getMember, typeof(this).init,
member)) == "public" && __traits(compiles, isFunction!(__traits(getMember, typeof(this)
.init, member))) && isFunction!(__traits(getMember, typeof(this).init,
member)) && !hasUDA!(__traits(getMember, typeof(this).init, member),
ignoredFunc) && !__traits(isTemplate,
__traits(getMember, typeof(this).init, member)))
{
static if (member[0] != '_'
&& __traits(compiles, __traits(getMember, typeof(this).init, member))
&& __traits(getProtection, __traits(getMember, typeof(this).init, member)) == "public"
&& __traits(compiles, isFunction!(__traits(getMember, typeof(this) .init, member)))
&& isFunction!(__traits(getMember, typeof(this).init, member))
&& !hasUDA!(__traits(getMember, typeof(this).init, member), ignoredFunc)
&& !__traits(isTemplate, __traits(getMember, typeof(this).init, member)))
{
if (method == member)
return runMethod!member(args);
}
}
throw new Exception("Method " ~ method ~ " not found.");
}

Expand Down Expand Up @@ -247,33 +251,66 @@ mixin template DefaultComponentWrapper(bool withDtor = true)

static string generateOverloadCall(alias fun)()
{
string retarg;
string decl;
string call = "fun(";
string arg;
static foreach (i, T; Parameters!fun)
{
static if (is(T : const(char)[]))
call ~= "args[" ~ i.to!string ~ "].str, ";
arg = "args[" ~ i.to!string ~ "].str";
else
call ~= "args[" ~ i.to!string ~ "].fromJSON!(" ~ T.stringof ~ "), ";
arg = "args[" ~ i.to!string ~ "].fromJSON!(" ~ T.stringof ~ ")";

static if (isRefOrOutParam!(fun, i))
{
decl ~= "auto arg_" ~ i.stringof ~ " = " ~ arg ~ ";";
if (retarg.length)
assert(false, "only a single ref/out parameter is allowed");
retarg = "arg_" ~ i.stringof;
call ~= "arg_" ~ i.stringof ~ ", ";
}
else
{
call ~= arg ~ ", ";
}
}
call ~= ")";
static if (is(ReturnType!fun : Future!T, T))
{
assert(!retarg.length, "async functions may not use ref/out parameters");
static if (is(T == void))
string conv = "ret.finish(JSONValue(null));";
else
string conv = "ret.finish(v.value.toJSON);";
return "auto ret = new Future!JSONValue; auto v = " ~ call
return decl ~ "auto ret = new Future!JSONValue; auto v = " ~ call
~ "; v.onDone = { if (v.exception) ret.error(v.exception); else "
~ conv ~ " }; return ret;";
}
else static if (is(ReturnType!fun == void))
return call ~ "; return Future!JSONValue.fromResult(JSONValue(null));";
{
if (retarg.length)
return decl ~ call ~ "; return Future!JSONValue.fromResult(" ~ retarg ~ ".toJSON);";
else
return decl ~ call ~ "; return Future!JSONValue.fromResult(JSONValue(null));";
}
else
return "return Future!JSONValue.fromResult(" ~ call ~ ".toJSON);";
{
assert(!retarg.length, "functions with ref/out parameter may not return any value");
return decl ~ "return Future!JSONValue.fromResult(" ~ call ~ ".toJSON);";
}
}
}
}

bool isRefOrOutParam(alias fun, size_t i)()
{
static foreach (sc; __traits(getParameterStorageClasses, fun, i))
if (sc == "ref" || sc == "out")
return true;
return false;
}

bool matchesOverload(alias fun)(JSONValue[] args)
{
if (args.length > Parameters!fun.length)
Expand Down
52 changes: 40 additions & 12 deletions test/tc_as_a_exe/source/app.d
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,53 @@ void main()
auto backend = pipeProcess(["../../workspace-d"], Redirect.stdout | Redirect.stdin);

//auto instance = backend.addInstance(dir);
backend.stdin.writeRequest(1, `{"cmd": "new", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
assert(backend.stdout.readResponse(1).type == JSONType.true_);
backend.stdin.writeRequest(10, `{"cmd": "new", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
assert(backend.stdout.readResponse(10).type == JSONType.true_);

//backend.register!FSWorkspaceComponent;
backend.stdin.writeRequest(2,
backend.stdin.writeRequest(20,
`{"cmd": "load", "component": "fsworkspace", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
assert(backend.stdout.readResponse(2).type == JSONType.true_);
assert(backend.stdout.readResponse(20).type == JSONType.true_);

//backend.register!DscannerComponent;
backend.stdin.writeRequest(21,
`{"cmd": "load", "component": "dscanner", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
assert(backend.stdout.readResponse(21).type == JSONType.true_);

//auto fsworkspace = backend.get!FSWorkspaceComponent(dir);
//assert(instance.importPaths == [getcwd]);
backend.stdin.writeRequest(3, `{"cmd": "import-paths", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
response = backend.stdout.readResponse(3);
backend.stdin.writeRequest(30, `{"cmd": "import-paths", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
response = backend.stdout.readResponse(30);
assert(response.type == JSONType.array);
assert(response.array.length == 1);
assert(response.array[0].type == JSONType.string);
assert(response.array[0].str == getcwd);

//fsworkspace.addImports(["source"]);
backend.stdin.writeRequest(4,
backend.stdin.writeRequest(40,
`{"cmd": "call", "component": "fsworkspace", "method": "addImports", "params": [["source"]], "cwd": ` ~ JSONValue(
dir).toString ~ `}`);
backend.stdout.readResponse(4);
backend.stdout.readResponse(40);

//dscanner.resolveRanges(code, ref issues);
backend.stdin.writeRequest(41,
`{"cmd": "call", "component": "dscanner", "method": "resolveRanges", "params": ["cool code", [{"file": "something.d", "line": 1, "column": 4, "type": "custom.type", "description": "custom description", "key": "custom.key"}]], "cwd": ` ~ JSONValue(
dir).toString ~ `}`);
response = backend.stdout.readResponse(41);
assert(response.type == JSONType.array);
assert(response.array.length == 1);
assert(response.array[0].type == JSONType.object);
assert(response.array[0].object["file"].str == "something.d");
assert(response.array[0].object["line"].integer == 1);
assert(response.array[0].object["column"].integer == 4);
assert(response.array[0].object["type"].str == "custom.type");
assert(response.array[0].object["description"].str == "custom description");
assert(response.array[0].object["key"].str == "custom.key");
assert(response.array[0].object["range"].type == JSONType.array);

//assert(instance.importPaths == [getcwd, "source"]);
backend.stdin.writeRequest(5, `{"cmd": "import-paths", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
response = backend.stdout.readResponse(5);
backend.stdin.writeRequest(50, `{"cmd": "import-paths", "cwd": ` ~ JSONValue(dir).toString ~ `}`);
response = backend.stdout.readResponse(50);
assert(response.type == JSONType.array);
assert(response.array.length == 2);
assert(response.array[0].type == JSONType.string);
Expand All @@ -74,6 +95,9 @@ void writeRequest(File stdin, int id, string data)

JSONValue readResponse(File stdout, int expectedId = 0x7F000001)
{
import std.algorithm;

ubyte[512] skipBuf;
ubyte[4] intBuf;
uint length;
int reqId;
Expand All @@ -85,9 +109,13 @@ JSONValue readResponse(File stdout, int expectedId = 0x7F000001)
reqId = intBuf.bigEndianToNative!uint;
if (expectedId != 0x7F000001 && expectedId != reqId)
{
writefln("%s << <skipped>", reqId);
writefln("%s << <skipped %d bytes>", reqId, length);
if (length > 4)
stdout.seek(length - 4);
{
length -= 4;
while (length > 0)
length -= stdout.rawRead(skipBuf[0 .. min($, length)]).length;
}
}
else
break;
Expand Down

0 comments on commit dc3c054

Please sign in to comment.