Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Filter implementation #109

Merged
merged 8 commits into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/main/native/jni_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const char CLS_JBOOL[] = "org/bblfsh/client/v2/JBool";
const char CLS_JUINT[] = "org/bblfsh/client/v2/JUint";
const char CLS_JARR[] = "org/bblfsh/client/v2/JArray";
const char CLS_JOBJ[] = "org/bblfsh/client/v2/JObject";
const char CLS_ITER[] = "org/bblfsh/client/v2/libuast/Libuast$UastIterExt";
const char CLS_JITER[] = "org/bblfsh/client/v2/libuast/Libuast$UastIter";

// Method signatures
const char METHOD_JNODE_KEY_AT[] = "(I)Ljava/lang/String;";
Expand All @@ -54,6 +56,9 @@ const char METHOD_RE_INIT[] = "(Ljava/lang/String;)V";
const char METHOD_RE_INIT_CAUSE[] =
"(Ljava/lang/String;Ljava/lang/Throwable;)V";

const char METHOD_ITER_INIT[] = "(Lorg/bblfsh/client/v2/NodeExt;IJJ)V";
const char METHOD_JITER_INIT[] = "(Lorg/bblfsh/client/v2/JNode;IJJ)V";

// Field signatures
const char FIELD_ITER_NODE[] = "Ljava/lang/Object;";

Expand Down
4 changes: 4 additions & 0 deletions src/main/native/jni_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ extern const char CLS_JBOOL[];
extern const char CLS_JUINT[];
extern const char CLS_JARR[];
extern const char CLS_JOBJ[];
extern const char CLS_ITER[];
extern const char CLS_JITER[];

// Method signatures
extern const char METHOD_JNODE_KEY_AT[];
Expand All @@ -29,6 +31,8 @@ extern const char METHOD_JARR_ADD[];
extern const char METHOD_OBJ_TO_STR[];
extern const char METHOD_RE_INIT[];
extern const char METHOD_RE_INIT_CAUSE[];
extern const char METHOD_ITER_INIT[];
extern const char METHOD_JITER_INIT[];

// Field signatures
extern const char FIELD_ITER_NODE[];
Expand Down
6 changes: 3 additions & 3 deletions src/main/native/org_bblfsh_client_v2_Context.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/main/native/org_bblfsh_client_v2_ContextExt.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/main/native/org_bblfsh_client_v2_NodeExt.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

110 changes: 93 additions & 17 deletions src/main/native/org_bblfsh_client_v2_libuast_Libuast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class ContextExt {
NodeHandle toHandle(jobject obj) {
if (!obj) return 0;

JNIEnv *env = getJNIEnv();
JNIEnv *env = getJNIEnv(); // TODO: refactor to JNI util LongField()
jclass cls = env->FindClass(CLS_NODE);
checkJvmException("failed to find class " + std::string(CLS_NODE));

Expand Down Expand Up @@ -153,6 +153,18 @@ class ContextExt {
return iter;
}

// Filter queries an external UAST.
// Borrows the reference.
uast::Iterator<NodeHandle> *Filter(jobject node, std::string query) {
if (!assertNotContext(node)) return nullptr;

NodeHandle unode = toHandle(node);
if (unode == 0) unode = ctx->RootNode();

auto it = ctx->Filter(unode, query);
return it;
}

// Encode serializes the external UAST.
// Borrows the reference.
jobject Encode(jobject node, UastFormat format) {
Expand All @@ -163,6 +175,30 @@ class ContextExt {
}
};

// creates new UastIterExt from the given context
jobject filterUastIterExt(ContextExt *ctx, jstring jquery, JNIEnv *env) {
const char *q = env->GetStringUTFChars(jquery, 0);
std::string query = std::string(q);
env->ReleaseStringUTFChars(jquery, q);

auto node = ctx->RootNode();
uast::Iterator<NodeHandle> *it = nullptr;
try {
it = ctx->Filter(node, query);
} catch (const std::exception &e) {
ThrowByName(env, CLS_RE, e.what());
return nullptr;
}

// new UastIterExt()
jobject iter = NewJavaObject(env, CLS_ITER, METHOD_ITER_INIT, 0, 0, it, ctx);
if (env->ExceptionCheck() || !iter) {
delete (it);
checkJvmException("failed create new UastIterExt class");
}
return iter;
}

// ================================================
// UAST Node interface (called from libuast)
// ================================================
Expand All @@ -174,7 +210,6 @@ class Node : public uast::Node<Node *> {
jobject obj; // Node owns a (global) reference
NodeKind kind;

jobject keys;
std::string *str;

// kindOf returns a kind of a JVM object.
Expand Down Expand Up @@ -208,26 +243,22 @@ class Node : public uast::Node<Node *> {

// Node creates a new node associated with a given JVM object and sets the
// kind. Creates a new global reference.
Node(Interface *i, NodeKind k, jobject v) : keys(nullptr), str(nullptr) {
Node(Interface *i, NodeKind k, jobject v) : str(nullptr) {
iface = i;
obj = getJNIEnv()->NewGlobalRef(v);
kind = k;
}

// Node creates a new node associated with a given JVM object and
// automatically determines the kind. Creates a new global reference.
Node(Interface *i, jobject v) : keys(nullptr), str(nullptr) {
Node(Interface *i, jobject v) : str(nullptr) {
iface = i;
obj = getJNIEnv()->NewGlobalRef(v);
kind = kindOf(v);
}

~Node() {
JNIEnv *env = getJNIEnv();
if (keys) {
env->DeleteGlobalRef(keys);
keys = nullptr;
}
if (obj) {
env->DeleteGlobalRef(obj);
}
Expand Down Expand Up @@ -503,7 +534,7 @@ class Context {
}

// Iterate returns iterator over an external UAST tree.
// Borrows the reference.
// Creates a new reference.
uast::Iterator<Node *> *Iterate(jobject jnode, TreeOrder order) {
if (!assertNotContext(jnode)) return nullptr;

Expand All @@ -512,6 +543,18 @@ class Context {
return iter;
}

// Filter queries UAST.
// Creates a new reference.
uast::Iterator<Node *> *Filter(jobject node, std::string query) {
if (!assertNotContext(node)) return nullptr;

Node *unode = toNode(node);
if (unode == nullptr) unode = ctx->RootNode();

auto it = ctx->Filter(unode, query);
return it;
}

// Encode serializes UAST.
// Creates a new reference.
jobject Encode(jobject jnode, UastFormat format) {
Expand Down Expand Up @@ -602,10 +645,10 @@ Java_org_bblfsh_client_v2_libuast_Libuast_00024UastIter_nativeInit(
JNIEXPORT void JNICALL
Java_org_bblfsh_client_v2_libuast_Libuast_00024UastIter_nativeDispose(
JNIEnv *env, jobject self) {
// this.ctx - delete Context as iterator owns it
// this.ctx - delete as iterator owns it for both .iterate()/.filter() cases
auto ctx = getHandle<Context>(env, self, "ctx");
setHandle<Context>(env, self, 0, "ctx");
delete (ctx);
setHandle<Context>(env, self, 0, "ctx");

// this.iter
auto iter = getHandle<uast::Iterator<Node *>>(env, self, "iter");
Expand Down Expand Up @@ -697,16 +740,37 @@ Java_org_bblfsh_client_v2_libuast_Libuast_00024UastIterExt_nativeNext(
return ctx->lookup(node);
}

// TODO(#83): implement
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_filter(
JNIEnv *, jobject, jobject, jstring) {
return nullptr;
}

// ==========================================
// v2.Context()
// ==========================================

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_filter(
JNIEnv *env, jobject self, jstring jquery, jobject jnode) {
Context *ctx = getHandle<Context>(env, self, nativeContext);

const char *q = env->GetStringUTFChars(jquery, 0);
std::string query = std::string(q);
env->ReleaseStringUTFChars(jquery, q);

uast::Iterator<Node *> *it = nullptr;
try {
// global ref will be deleted by Interface destructor on ctx deletion
it = ctx->Filter(env->NewGlobalRef(jnode), query);
} catch (const std::exception &e) {
ThrowByName(env, CLS_RE, e.what());
return nullptr;
}

// new UastIter()
jobject iter =
NewJavaObject(env, CLS_JITER, METHOD_JITER_INIT, 0, 0, it, ctx);
if (env->ExceptionCheck() || !iter) {
delete (it);
checkJvmException("failed create new UastIter class");
}
return iter;
}

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_encode(
JNIEnv *env, jobject self, jobject jnode) {
UastFormat fmt = UAST_BINARY; // TODO(#107): make it argument
Expand Down Expand Up @@ -738,6 +802,12 @@ Java_org_bblfsh_client_v2_ContextExt_root(JNIEnv *env, jobject self) {
return p->RootNode();
}

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_ContextExt_filter(
JNIEnv *env, jobject self, jstring jquery) {
ContextExt *ctx = getHandle<ContextExt>(env, self, nativeContext);
return filterUastIterExt(ctx, jquery, env);
}

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_ContextExt_encode(
JNIEnv *env, jobject self, jobject node) {
UastFormat fmt = UAST_BINARY; // TODO(#107): make it argument
Expand Down Expand Up @@ -765,6 +835,12 @@ JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_NodeExt_load(JNIEnv *env,
return node;
}

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_NodeExt_filter(
JNIEnv *env, jobject self, jstring jquery) {
auto *ctx = getHandle<ContextExt>(env, self, "ctx");
return filterUastIterExt(ctx, jquery, env);
}

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_8) != JNI_OK) {
Expand Down
8 changes: 0 additions & 8 deletions src/main/native/org_bblfsh_client_v2_libuast_Libuast.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions src/main/scala/org/bblfsh/client/v2/BblfshClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,6 @@ object BblfshClient {
maxMsgSize: Int = DEFAULT_MAX_MSG_SIZE
): BblfshClient = new BblfshClient(host, port, maxMsgSize)

def filter(node: NodeExt, query: String): List[NodeExt] = Libuast.synchronized {
libuast.filter(node, query)
}

/**
* Decodes bytes from wired format of bblfsh protocol.v2.
* Requires a buffer in Direct mode.
Expand Down Expand Up @@ -166,13 +162,17 @@ object BblfshClient {
Libuast.UastIter(node, treeOrder)
}

// Enables API: resp.uast.decode().load().filter("//query")
// TODO(83): implement XPath query
// implicit class NodeExtMethods(val node: NodeExt) {
// def filter(query: String): List[NodeExt] = {
// BblfshClient.filter(node, query)
// }
// }
/** Factory method for iterator over an native node, filtered by XPath query */
def filter(node: NodeExt, query: String): Libuast.UastIterExt = Libuast.synchronized {
node.filter(query)
}

/** Factory method for iterator over an managed node, filtered by XPath query */
def filter(node: JNode, query: String): Libuast.UastIter = Libuast.synchronized {
val ctx = Context()
ctx.filter(query, node)
// do not dispose the context, iterator steals it
}

}

6 changes: 4 additions & 2 deletions src/main/scala/org/bblfsh/client/v2/ContextExt.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.bblfsh.client.v2

import java.nio.ByteBuffer

import org.bblfsh.client.v2.libuast.Libuast.{UastIter, UastIterExt}

/**
* Represents Go-side constructed tree, result of Libuast.decode()
*
Expand All @@ -10,7 +12,7 @@ import java.nio.ByteBuffer
case class ContextExt(nativeContext: Long) {
// @native def load(): JNode // TODO(bzz): clarify when it's needed VS just .root().load()
@native def root(): NodeExt
@native def filter()
@native def filter(query: String): UastIterExt
@native def encode(n: NodeExt): ByteBuffer

@native def dispose()
Expand All @@ -27,7 +29,7 @@ case class ContextExt(nativeContext: Long) {
*/
case class Context(nativeContext: Long) {
@native def root(): JNode
@native def filter()
@native def filter(query: String, node: JNode): UastIter
@native def encode(n: JNode): ByteBuffer

@native def dispose()
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/org/bblfsh/client/v2/NodeExt.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package org.bblfsh.client.v2
import java.io.Serializable
import java.nio.ByteBuffer

import org.bblfsh.client.v2.libuast.Libuast.UastIterExt

import scala.collection.mutable


/**
* UAST representation for the nodes originated from the Go side.
* This is equivalent of pyuast.NodeExt API.
Expand All @@ -14,6 +17,7 @@ import scala.collection.mutable
*/
case class NodeExt(ctx: Long, handle: Long) {
@native def load(): JNode
@native def filter(query: String): UastIterExt
}


Expand Down
Loading