Implement c++ stub generator (interface part) 33/170933/9
authorJunghoon Park <jh9216.park@samsung.com>
Fri, 23 Feb 2018 08:27:39 +0000 (17:27 +0900)
committerJunghoon Park <jh9216.park@samsung.com>
Tue, 27 Feb 2018 06:41:36 +0000 (15:41 +0900)
Change-Id: I1af1ef89b82a9e91581f29eabcb9fc91fc3d7c17
Signed-off-by: Junghoon Park <jh9216.park@samsung.com>
idlc/cpp_gen/cpp_gen_base.cc
idlc/cpp_gen/cpp_stub_body_gen.cc
idlc/cpp_gen/cpp_stub_body_gen.h
idlc/cpp_gen/cpp_stub_header_gen.cc
idlc/cpp_gen/cpp_stub_header_gen.h

index 68f8813..8cb9ae9 100644 (file)
@@ -544,8 +544,7 @@ std::string CppGeneratorBase::ConvertTypeToDeserializer(
     if (make_new_type) {
       ret += n + " ";
       if (IsDelegateType(type.ToString())) {
-        ret += id + "(port, std::weak_ptr<ServiceBase>(b));\n"
-            + "CallbackBase.";
+        ret += id + "(port, std::weak_ptr<ServiceBase>(b));\n";
       } else {
         ret += id + ";\n";
       }
@@ -595,7 +594,8 @@ void CppGeneratorBase::GenBodyCallbacks(std::ofstream& stream,
 void CppGeneratorBase::GenBodyCallback(std::ofstream& stream,
     const Interface& iface, const Declaration& decl, bool is_proxy) {
   if (!is_proxy) {
-    const char method[] = "void $$::$$::Invoke()";
+    const char method[] = "void $$::$$::Invoke(";
+
 
     GenTemplate(method, stream,
       [&]()->std::string {
@@ -608,8 +608,31 @@ void CppGeneratorBase::GenBodyCallback(std::ofstream& stream,
     GenParameters(stream, decl.GetParameters());
     stream << ") ";
     GenBrace(stream, 0, [&]() {
-      //TODO
+      const char* pre =
+          "if (port_ == nullptr)\n" \
+          "    throw NotConnectedSocketException();\n" \
+          "if (service_.lock().get() == nullptr)\n" \
+          "    throw NotConnectedSocketException();\n" \
+          "\n" \
+          "rpc_port_parcel_h p;\n" \
+          "rpc_port_parcel_create(&p);\n" \
+          "rpc_port_parcel_write_int32(p, static_cast<int>(MethodId::Callback));\n" \
+          "p << *this;\n";
+
+      const char* mid =
+          "// Send\n" \
+          "rpc_port_parcel_send(p, port_);\n" \
+          "rpc_port_parcel_destroy(p);\n";
+
+      stream << AddIndent(TAB_SIZE, pre);
+      std::string m;
+      for (auto& i : decl.GetParameters().GetParams()) {
+        auto& pt = i->GetParameterType();
+        m += ConvertTypeToSerializer(pt.GetBaseType(), i->GetID(), "p");
+      }
 
+      stream << AddIndent(TAB_SIZE, m) << NLine(1);
+      stream << AddIndent(TAB_SIZE, mid);
     }, false);
   } else {
     const char cb[] = "void $$::$$::OnReceivedEvent(rpc_port_parcel_h parcel) ";
@@ -737,7 +760,7 @@ void CppGeneratorBase::GenHeaderCallback(std::ofstream& stream,
     }
     stream << Tab(2) << "rpc_port_parcel_h port_;" << NLine(1);
     if (!is_proxy)
-      stream << Tab(2) << "weak_ptr<ServiceBase> service_;" << NLine(1);
+      stream << Tab(2) << "std::weak_ptr<ServiceBase> service_;" << NLine(1);
   }, false, false);
   stream << ";" << NLine(2);
 }
index 78399c6..cf2fd2b 100644 (file)
@@ -42,16 +42,240 @@ void CppStubBodyGen::GenNamespace(std::ofstream& stream) {
   stream << "namespace rpc_port ";
   GenBrace(stream, 0, [&]() {
     stream <<  NLine(1);
-    GenPrototype(stream);
     GenStructuresForBody(stream);
-    GenSerializer(stream);
-    GenDeSerializer(stream);
-    GenListSerializer(stream);
     stream << "namespace stub ";
     GenBrace(stream, 0, [&]() {
-//      GenInterfaces(stream);
+      GenPrototype(stream);
+      GenSerializer(stream);
+      GenDeSerializer(stream);
+      GenListSerializer(stream);
+      GenInterfaces(stream);
     }, false);
   }, false);
 }
 
+void CppStubBodyGen::GenInterfaces(std::ofstream& stream) {
+  for (auto& i : GetDocument().GetBlocks()) {
+    if (i->GetType() != Block::TYPE_INTERFACE)
+      continue;
+    Interface& iface = static_cast<Interface&>(*i);
+    GenInterface(stream, iface);
+  }
+}
+
+void CppStubBodyGen::GenInterface(std::ofstream& stream,
+                                    const Interface& iface) {
+  GenServiceBase(stream, iface);
+  GenBodyCallbacks(stream, iface, false);
+  GenDefaultMethods(stream, iface);
+  GenReceivedEvent(stream, iface);
+}
+
+void CppStubBodyGen::GenServiceBase(std::ofstream& stream,
+                                    const Interface& iface) {
+  const char cb[] =
+      "$$::ServiceBase::ServiceBase(std::string sender, std::string instance)\n" \
+      "    : sender_(std::move(sender)), instance_(std::move(instance)) {}\n" \
+      "\n";
+
+  GenTemplate(cb, stream,
+    [&]()->std::string {
+      return iface.GetID();
+    }
+  );
+  stream << NLine(1);
+}
+
+void CppStubBodyGen::GenDefaultMethods(std::ofstream& stream,
+                                       const Interface& iface) {
+  const char cb[] =
+R"__cpp_cb(
+$$::$$() {
+  rpc_port_stub_create(&stub_, "$$");
+  rpc_port_stub_add_connected_event_cb(stub_, OnConnectedCB, this);
+  rpc_port_stub_add_disconnected_event_cb(stub_, OnDisconnectedCB, this);
+  rpc_port_stub_add_received_event_cb(stub_, OnReceivedCB, this);
+}
+
+$$::~$$() {
+  if (stub_) {
+    rpc_port_stub_destroy(stub_);
+  }
+}
+
+void $$::Listen(
+    std::shared_ptr<$$::ServiceBase::Factory> service_factory) {
+  service_factory_ = std::move(service_factory);
+  rpc_port_stub_listen(stub_);
+}
+
+void $$::OnConnectedCB(const char* sender, const char* instance, void *data) {
+  $$* stub = static_cast<$$*>(data);
+  auto s = stub->service_factory_->CreateService(sender, instance);
+  s->OnCreate();
+  stub->services_.emplace_back(std::move(s));
+}
+
+void $$::OnDisconnectedCB(const char* sender, const char* instance, void *data) {
+  $$* stub = static_cast<$$*>(data);
+
+  for (auto& i : stub->services_) {
+    if (i->GetInstance() == instance) {
+      i->OnTerminate();
+      stub->services_.remove(i);
+      return;
+    }
+  }
+}
+)__cpp_cb";
+
+  GenTemplate(cb, stream,
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); },
+    [&]()->std::string { return iface.GetID(); }
+  );
+  stream << NLine(1);
+}
+
+void CppStubBodyGen::GenReceivedEvent(std::ofstream& stream,
+                                      const Interface& iface) {
+  const char method_front[] =
+    "int $$::OnReceivedCB(const char* sender, const char* instance, rpc_port_h port, void *data)\n" \
+    "{\n" \
+    "  auto* cxt = static_cast<$$*>(data);"
+    "  rpc_port_parcel_h p;\n" \
+    "  rpc_port_parcel_h result;\n" \
+    "  int cmd;\n" \
+    "  int ret = rpc_port_parcel_create_from_port(&p, port);\n" \
+    "\n" \
+    "  if (ret != 0)\n" \
+    "    return ret;\n" \
+    "\n" \
+    "  rpc_port_parcel_create(&result);\n" \
+    "  rpc_port_parcel_read_int32(p, &cmd);\n" \
+    "  std::shared_ptr<ServiceBase> b;\n" \
+    "\n" \
+    "  for (auto& i : cxt->services_) {\n" \
+    "    if (i->GetInstance() == instance) {\n" \
+    "      b = i;\n" \
+    "      break;\n" \
+    "    }\n" \
+    "  }\n" \
+    "\n" \
+    "  if (b.get() == nullptr)\n" \
+    "    return -1;\n" \
+    "\n"
+    "  switch (cmd) {\n";
+
+  const char method_back[] =
+    "    default:\n" \
+    "      return -1;\n" \
+    "  }\n" \
+    "\n" \
+    "  rpc_port_parcel_destroy(p);\n" \
+    "  rpc_port_parcel_destroy(result);\n" \
+    "\n" \
+    "  return 0;\n" \
+    "}\n";
+
+  GenTemplate(method_front, stream,
+    [&]()->std::string {
+      return iface.GetID();
+    },
+    [&]()->std::string {
+      return iface.GetID();
+    }
+  );
+  for (auto& i : iface.GetDeclarations().GetDecls()) {
+    if (i->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+    stream << Tab(2) << "case static_cast<int>(MethodId::" << i->GetID() << "): ";
+    GenBrace(stream, TAB_SIZE * 2, [&]() {
+      GenInvocation(stream, *i);
+      stream << Tab(3) << "break;" << NLine(1);
+    }, false);
+    stream << NLine(1);
+  }
+  stream << method_back << NLine(1);
+}
+
+void CppStubBodyGen::GenInvocation(std::ofstream& stream, const Declaration& decl) {
+  int cnt = 1;
+
+  // Deserialize
+  for (auto& i : decl.GetParameters().GetParams()) {
+    if (i->GetParameterType().GetDirection() == ParameterType::Direction::OUT) {
+      cnt++;
+      continue;
+    }
+
+    std::string v = "param" + std::to_string(cnt);
+    std::string c = ConvertTypeToDeserializer(
+        i->GetParameterType().GetBaseType(), v, "p");
+    stream << AddIndent(TAB_SIZE * 3, c);
+    cnt++;
+  }
+
+  // Invoke
+  cnt = 1;
+  std::string m;
+  bool hasRet = false;
+
+  if (decl.GetType().ToString() != "void") {
+    m += "auto retVal = ";
+    hasRet = true;
+  }
+
+  m += "b->" + decl.GetID() + "(";
+  for (auto& i : decl.GetParameters().GetParams()) {
+    if (cnt != 1) {
+      m += ", ";
+    }
+
+    std::string v = "param" + std::to_string(cnt);
+    auto& pt = i->GetParameterType();
+    if (pt.GetDirection() == ParameterType::Direction::OUT ||
+        pt.GetDirection() == ParameterType::Direction::REF) {
+      m += ConvertTypeToString(pt.GetBaseType()) + "& ";
+    }
+    m += v;
+    cnt++;
+  }
+
+  m += ");\n";
+  stream << AddIndent(TAB_SIZE * 3, m);
+
+  // Serialize
+  if (decl.GetMethodType() == Declaration::MethodType::ASYNC)
+    return;
+
+  cnt = 0;
+  m = "rpc_port_parcel_write_int32(result, static_cast<int>(MethodId::Result));\n";
+  for (auto& i : decl.GetParameters().GetParams()) {
+    auto& pt = i->GetParameterType();
+    cnt++;
+    if (pt.GetDirection() == ParameterType::Direction::IN)
+      continue;
+    m += ConvertTypeToSerializer(pt.GetBaseType(),
+                                "param" + std::to_string(cnt), "result");
+  }
+
+  if (hasRet) {
+    m += ConvertTypeToSerializer(decl.GetType(), "retVal", "result");
+  }
+
+  m += "rpc_port_parcel_send(result, port);\n";
+  stream << AddIndent(TAB_SIZE * 3, m);
+}
+
 }  // namespace tidl
index 47a4944..76e2083 100644 (file)
@@ -34,6 +34,12 @@ class CppStubBodyGen : public CppGeneratorBase {
 
  private:
   void GenNamespace(std::ofstream& stream);
+  void GenInterfaces(std::ofstream& stream);
+  void GenInterface(std::ofstream& stream, const Interface& iface);
+  void GenServiceBase(std::ofstream& stream, const Interface& iface);
+  void GenDefaultMethods(std::ofstream& stream, const Interface& iface);
+  void GenReceivedEvent(std::ofstream& stream, const Interface& iface);
+  void GenInvocation(std::ofstream& stream, const Declaration& decl);
 };
 
 }  // namespace tidl
index 8a36891..17f8e31 100644 (file)
@@ -28,6 +28,7 @@ void CppStubHeaderGen::OnInitGen(std::ofstream& stream) {
          << "#include <rpc-port-parcel.h>" << NLine(1)
          << "#include <rpc-port.h>" << NLine(1)
          <<  NLine(1)
+         << "#include <memory>" << NLine(1)
          << "#include <string>" << NLine(1)
          << "#include <vector>" << NLine(1)
          << "#include <list>" << NLine(2);
@@ -44,8 +45,134 @@ void CppStubHeaderGen::GenNamespace(std::ofstream& stream) {
     GenStructuresForHeader(stream);
     stream << "namespace stub ";
     GenBrace(stream, 0, [&]() {
-//      GenInterfaces(stream);
+      GenExceptions(stream);
+      GenInterfaces(stream);
     }, false);
   }, false);
 }
+
+void CppStubHeaderGen::GenExceptions(std::ofstream& stream) {
+  const char cb[] =
+R"__cpp_cb(
+class Exception {};
+class NotConnectedSocketException : public Exception {};
+class InvalidProtocolException : public Exception {};
+)__cpp_cb";
+  stream << cb << NLine(1);
+}
+
+void CppStubHeaderGen::GenInterfaces(std::ofstream& stream) {
+  for (auto& i : GetDocument().GetBlocks()) {
+    if (i->GetType() != Block::TYPE_INTERFACE)
+      continue;
+    Interface& iface = static_cast<Interface&>(*i);
+    GenInterface(stream, iface);
+  }
+}
+
+void CppStubHeaderGen::GenInterface(std::ofstream& stream,
+                                    const Interface& iface) {
+  stream << NLine(1) << "class " << iface.GetID() << " final ";
+  GenBrace(stream, 0, [&]() {
+    GenPublic(stream, iface);
+    GenPrivate(stream, iface);
+  }, false, false);
+  stream << ";" << NLine(1);
+}
+
+void CppStubHeaderGen::GenPublic(std::ofstream& stream,
+                                 const Interface& iface) {
+  stream << " public:" << NLine(1);
+  stream << "  class ServiceBase;" << NLine(1);
+  GenHeaderCallbacks(stream, iface, false);
+  GenServiceBase(stream, iface);
+  GenPublicMethods(stream, iface);
+}
+
+void CppStubHeaderGen::GenPrivate(std::ofstream& stream,
+                                 const Interface& iface) {
+  stream << " private:" << NLine(1);
+  GenMethodId(stream, iface);
+  GenDelegateId(stream, iface);
+
+  const char cb[] =
+      "static void OnConnectedCB(const char* sender, const char* instance, void* data);\n" \
+      "static void OnDisconnectedCB(const char* sender, const char* instance, void* data);\n" \
+      "static int OnReceivedCB(const char* sender, const char* instance, rpc_port_h port, void* data);\n" \
+      "\n" \
+      "rpc_port_stub_h stub_;\n" \
+      "std::shared_ptr<ServiceBase::Factory> service_factory_;\n" \
+      "std::list<std::shared_ptr<ServiceBase>> services_;\n";
+
+  stream << AddIndent(TAB_SIZE, cb);
+}
+
+void CppStubHeaderGen::GenServiceBase(std::ofstream& stream,
+                                      const Interface& iface) {
+  const char cb1[] = R"__cpp_cb(  class ServiceBase {
+   public:
+    class Factory {
+     public:
+      virtual std::unique_ptr<ServiceBase> CreateService(std::string sender, std::string instance) = 0;
+    };
+
+    virtual ~ServiceBase() = default;
+
+    const std::string& GetSender() const {
+      return sender_;
+    }
+
+    const std::string& GetInstance() const {
+      return instance_;
+    }
+
+    virtual void OnCreate() = 0;
+    virtual void OnTerminate() = 0;
+)__cpp_cb";
+
+  const char cb2[] = R"__cpp_cb(
+   protected:
+    ServiceBase(std::string sender, std::string instance);
+
+   private:
+    std::string sender_;
+    std::string instance_;
+  };)__cpp_cb";
+
+  stream << cb1;
+  auto& decls = iface.GetDeclarations();
+
+  for (auto& i : decls.GetDecls()) {
+    if (i->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+    stream << Tab(2) << "virtual " << ConvertTypeToString(i->GetType())
+           << " " << i->GetID() << "(";
+    GenParameters(stream, i->GetParameters());
+    stream << ") = 0;" << NLine(1);
+  }
+
+  stream << cb2 << NLine(2);
+}
+
+void CppStubHeaderGen::GenPublicMethods(std::ofstream& stream,
+                                        const Interface& iface) {
+  const char cb[] =
+      "$$();\n" \
+      "~$$();\n" \
+      "void Listen(std::shared_ptr<ServiceBase::Factory> service_factory);\n" \
+      "const std::list<std::shared_ptr<ServiceBase>>& GetServices() const {\n" \
+      "  return services_;\n" \
+      "}\n";
+
+  GenTemplate(AddIndent(TAB_SIZE, cb), stream,
+    [&]()->std::string {
+      return iface.GetID();
+    },
+    [&]()->std::string {
+      return iface.GetID();
+    }
+  );
+  stream << NLine(1);
+}
+
 }  // namespace tidl
index 5dd1326..52bebfe 100644 (file)
@@ -33,7 +33,14 @@ class CppStubHeaderGen : public CppGeneratorBase {
   void OnFiniGen(std::ofstream& stream) override;
 
  private:
+  void GenExceptions(std::ofstream& stream);
   void GenNamespace(std::ofstream& stream);
+  void GenInterfaces(std::ofstream& stream);
+  void GenInterface(std::ofstream& stream, const Interface& iface);
+  void GenPublic(std::ofstream& stream, const Interface& iface);
+  void GenPrivate(std::ofstream& stream, const Interface& iface);
+  void GenServiceBase(std::ofstream& stream, const Interface& iface);
+  void GenPublicMethods(std::ofstream& stream, const Interface& iface);
 };
 
 }  // namespace tidl