Support 'delegate' syntax 57/167257/8
authorJunghoon Park <jh9216.park@samsung.com>
Tue, 16 Jan 2018 11:02:40 +0000 (20:02 +0900)
committerJunghoon Park <jh9216.park@samsung.com>
Wed, 17 Jan 2018 05:36:11 +0000 (14:36 +0900)
Change-Id: Ia1daf2d2ee9a4b5a36442b4f2c326bd8e1b435af
Signed-off-by: Junghoon Park <jh9216.park@samsung.com>
idlc/code_block/cs_proxy_interop.cb
idlc/cs_gen/cs_gen_base.cc
idlc/cs_gen/cs_gen_base.h
idlc/cs_gen/cs_proxy_gen.cc
idlc/cs_gen/cs_stub_gen.cc
idlc/tidlc.ll
idlc/tidlc.yy

index c562f60..23fd141 100644 (file)
             [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
             internal delegate void RejectedEventCallback(string endPoint, string port_name, IntPtr data);
 
+            //typedef void (*rpc_port_proxy_received_event_cb) (const char* ep, const char* port_name, void* data);
+            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+            internal delegate void ReceivedEventCallback(string endPoint, string port_name, IntPtr data);
+
             //int rpc_port_proxy_create(rpc_port_proxy_h *h);
             [DllImport(Libraries.RpcPort, EntryPoint = "rpc_port_proxy_create")]
             internal static extern int Create(out IntPtr handle);
@@ -35,4 +39,8 @@
             //int rpc_port_proxy_add_rejected_event_cb(rpc_port_proxy_h h, rpc_port_proxy_rejected_event_cb cb, void* data);
             [DllImport(Libraries.RpcPort, EntryPoint = "rpc_port_proxy_add_rejected_event_cb")]
             internal static extern int AddRejectedEventCb(IntPtr handle, RejectedEventCallback cb, IntPtr data);
+
+            //int rpc_port_proxy_add_received_event_cb(rpc_port_proxy_h h, rpc_port_proxy_received_event_cb cb, void* data);
+            [DllImport(Libraries.RpcPort, EntryPoint = "rpc_port_proxy_add_received_event_cb")]
+            internal static extern int AddReceivedEventCb(IntPtr handle, ReceivedEventCallback cb, IntPtr data);
         }
index 6296b3c..3564f5e 100644 (file)
@@ -26,7 +26,7 @@ CsGeneratorBase::CsGeneratorBase(std::shared_ptr<Document> doc)
       {"char", "byte"}, {"int", "int"}, {"short", "short"},
       {"long", "long"}, {"string", "string"}, {"bool", "bool"},
       {"list", "List"}, {"float","float"}, {"double", "double"},
-      {"bundle", "Bundle"}
+      {"bundle", "Bundle"}, {"void", "void"}
   };
 
   parcel_type_map_ = {
@@ -269,6 +269,8 @@ std::string CsGeneratorBase::ConvertTypeToDeserializer(
       ret = n + " ";
 
     ret += id + " = new " + n +"();\n";
+    if (IsDelegateType(type.ToString()))
+      ret += "CallbackBase.";
     ret += "Deserialize(" + parcel + ", " + id +");\n";
     return ret;
   }
@@ -295,6 +297,8 @@ std::string CsGeneratorBase::ConvertTypeToSerializer(
 
   if (type.IsUserDefinedType() ||
       type.GetMetaType() != nullptr) {
+    if (IsDelegateType(type.ToString()))
+      return "CallbackBase.Serialize(" + parcel + ", " + id + ");\n";
     return "Serialize(" + parcel + ", " + id + ");\n";
   }
 
@@ -349,8 +353,26 @@ void CsGeneratorBase::GenWriteBundle(std::ofstream& stream, const std::string& i
 void CsGeneratorBase::GenMethodId(std::ofstream& stream, const Interface& iface) {
   stream << Tab(3) << "private enum MethodId : int" << NLine(1);
   GenBrace(stream, TAB_SIZE * 3, [&]() {
+    int cnt = 2;
+    stream << Tab(4) << "Result = 0," << NLine(1);
+    stream << Tab(4) << "Callback = 1," << NLine(1);
+    for (auto& i : iface.GetDeclarations().GetDecls()) {
+      if (i->GetMethodType() == Declaration::MethodType::DELEGATE)
+        continue;
+      stream << Tab(4)
+             << i->GetID() << " = " << cnt++ << "," << NLine(1);
+    }
+  });
+  stream << NLine(1);
+}
+
+void CsGeneratorBase::GenDelegateId(std::ofstream& stream, const Interface& iface) {
+  stream << Tab(3) << "private enum DelegateId : int" << NLine(1);
+  GenBrace(stream, TAB_SIZE * 3, [&]() {
     int cnt = 1;
     for (auto& i : iface.GetDeclarations().GetDecls()) {
+        if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+          continue;
         stream << Tab(4)
                << i->GetID() << " = " << cnt++ << "," << NLine(1);
     }
@@ -389,4 +411,164 @@ void CsGeneratorBase::GenParameters(std::ofstream& stream, const Parameters& ps)
   }
 }
 
+void CsGeneratorBase::GenCallbacks(std::ofstream& stream,
+                                   const Interface& iface) {
+  const char block[] =
+      "public abstract class CallbackBase\n" \
+      "{\n" \
+      "    internal int Id;\n" \
+      "    internal int SeqId;\n" \
+      "    private static int _seqNum = 0;\n" \
+      "\n" \
+      "    public CallbackBase(int delegateId)\n" \
+      "    {\n" \
+      "        Id = delegateId;\n" \
+      "        SeqId = _seqNum++;\n" \
+      "    }\n" \
+      "\n" \
+      "    internal abstract void OnReceivedEvent(IntPtr port);\n" \
+      "\n" \
+      "    internal static void Serialize(IntPtr h, CallbackBase param)\n" \
+      "    {\n" \
+      "        Interop.LibRPCPort.Parcel.WriteInt32(h, (int)param.Id);\n" \
+      "        Interop.LibRPCPort.Parcel.WriteInt32(h, (int)param.SeqId);\n" \
+      "    }\n" \
+      "\n" \
+      "    internal static void Deserialize(IntPtr h, CallbackBase param)\n" \
+      "    {\n" \
+      "        Interop.LibRPCPort.Parcel.ReadInt32(h, out var id);\n" \
+      "        param.Id = id;\n" \
+      "        Interop.LibRPCPort.Parcel.ReadInt32(h, out var seqId);\n" \
+      "        param.SeqId = seqId;\n" \
+      "    }\n" \
+      "}\n";
+  stream << AddIndent(TAB_SIZE * 3, block) << NLine(1);
+
+  for (auto& i : iface.GetDeclarations().GetDecls()) {
+    if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+          continue;
+    GenCallback(stream, *i);
+  }
+}
+
+void CsGeneratorBase::GenCallback(std::ofstream& stream,
+                                  const Declaration& decl) {
+  stream << Tab(3) << "public sealed class " << decl.GetID()
+         << " : CallbackBase" << NLine(1);
+  GenBrace(stream, TAB_SIZE * 3, [&]() {
+    const char ctor[] =
+      "public $$() : base((int)DelegateId.$$)\n" \
+      "{\n" \
+      "}\n" \
+      "\n" \
+      "internal $$(IntPtr port) : base((int)DelegateId.$$)\n" \
+      "{\n" \
+      "    _port = port;\n" \
+      "}\n";
+
+    GenTemplate(AddIndent(TAB_SIZE * 4, ctor), stream,
+      [&]()->std::string {
+        return decl.GetID();
+      },
+      [&]()->std::string {
+        return decl.GetID();
+      },
+      [&]()->std::string {
+        return decl.GetID();
+      },
+      [&]()->std::string {
+        return decl.GetID();
+      }
+    );
+    stream << NLine(1);
+
+    stream << Tab(4) << "private IntPtr _port = IntPtr.Zero;" << NLine(1);
+    stream << Tab(4) << "public delegate void Callback(";
+    GenParameters(stream, decl.GetParameters());
+    stream << ");" << NLine(1);
+    stream << Tab(4) << "public event Callback Received;" << NLine(2);
+
+    GenReceivedEvent(stream, decl);
+    GenInvokeMethod(stream, decl);
+  });
+  stream << NLine(1);
+}
+
+void CsGeneratorBase::GenReceivedEvent(std::ofstream& stream,
+                                       const Declaration& decl) {
+  stream << Tab(4) << "internal override void OnReceivedEvent(IntPtr parcel)"
+         << NLine(1);
+  GenBrace(stream, TAB_SIZE * 4, [&]() {
+    int cnt = 1;
+    for (auto& i : decl.GetParameters().GetParams()) {
+      std::string v = "param" + std::to_string(cnt);
+      std::string c = ConvertTypeToDeserializer(
+          i->GetParameterType().GetBaseType(), v, "parcel");
+      stream << AddIndent(TAB_SIZE * 5, c);
+      cnt++;
+    }
+
+    cnt = 1;
+    stream << Tab(5) << "Received?.Invoke(";
+    for (int i = 0; i < decl.GetParameters().GetParams().size(); i++) {
+      if (cnt != 1) {
+        stream << ", ";
+      }
+      std::string v = "param" + std::to_string(cnt);
+        stream << v;
+      cnt++;
+    }
+    stream << ");" << NLine(1);
+  });
+  stream << NLine(1);
+}
+
+void CsGeneratorBase::GenInvokeMethod(std::ofstream& stream,
+                                      const Declaration& decl) {
+  const char* pre =
+      "if (_port == IntPtr.Zero)\n" \
+      "    throw new InvalidOperationException(\"Not connected!\");\n" \
+      "\n" \
+      "Interop.LibRPCPort.Parcel.Create(out IntPtr p);\n" \
+      "Interop.LibRPCPort.Parcel.WriteInt32(p, (int)MethodId.Callback);\n" \
+      "Serialize(p, this);\n";
+
+  const char* mid =
+      "// Send\n" \
+      "Interop.LibRPCPort.Parcel.Send(p, _port);\n" \
+      "Interop.LibRPCPort.Parcel.Destroy(p);\n";
+
+  stream << Tab(4) << "public void Invoke(";
+  GenParameters(stream, decl.GetParameters());
+  stream << ")" << NLine(1);
+  GenBrace(stream, TAB_SIZE * 4, [&]() {
+    stream << AddIndent(TAB_SIZE * 5, 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 * 5, m) << NLine(1);
+    stream << AddIndent(TAB_SIZE * 5, mid);
+  });
+}
+
+bool CsGeneratorBase::IsDelegateType(const std::string type_name) {
+  for (auto& i : GetDocument().GetBlocks()) {
+    if (i->GetType() != Block::TYPE_INTERFACE)
+      continue;
+    Interface& iface = static_cast<Interface&>(*i);
+
+    for (auto& j : iface.GetDeclarations().GetDecls()) {
+      if (j->GetMethodType() == Declaration::MethodType::DELEGATE) {
+        if (j->GetID() == type_name)
+          return true;
+      }
+    }
+  }
+
+  return false;
+}
+
 }  // namespace tidl
index 0c30a4a..d5865a2 100644 (file)
@@ -39,9 +39,11 @@ class CsGeneratorBase : public Generator {
   void GenListSerializer(std::ofstream& stream);
   void GenListSerializer(std::ofstream& stream, const BaseType& type);
   void GenMethodId(std::ofstream& stream, const Interface& iface);
+  void GenDelegateId(std::ofstream& stream, const Interface& iface);
   void GenDeclaration(std::ofstream& stream,
                       const Declaration& decl, bool semicol = true);
   void GenParameters(std::ofstream& stream, const Parameters& ps);
+  void GenCallbacks(std::ofstream& stream, const Interface& iface);
 
   std::string ConvertTypeToString(const BaseType& type);
   std::string ConvertTypeToDeserializer(const BaseType& type,
@@ -50,6 +52,7 @@ class CsGeneratorBase : public Generator {
   std::string ConvertTypeToSerializer(const BaseType& type,
                                       std::string id, std::string parcel);
   std::string ConvertTypeToParcelType(const std::string& key);
+  bool IsDelegateType(const std::string type_name);
   std::string Tab(int cnt);
   std::string NLine(int cnt);
 
@@ -59,6 +62,9 @@ class CsGeneratorBase : public Generator {
  private:
   void GenWriteBundle(std::ofstream& stream, const std::string& id);
   void AddSerializerList(const BaseType& type);
+  void GenCallback(std::ofstream& stream, const Declaration& decl);
+  void GenReceivedEvent(std::ofstream& stream, const Declaration& decl);
+  void GenInvokeMethod(std::ofstream& stream, const Declaration& decl);
 
  private:
   std::map<std::string, std::string> type_map_;
index 4edfbfb..4e03844 100644 (file)
@@ -71,7 +71,12 @@ void CsProxyGen::GenInterface(std::ofstream& stream, const Interface& iface) {
       "private IntPtr _proxy;\n" \
       "private IntPtr _port;\n" \
       "private bool _online = false;\n" \
-      "private string _appId;\n";
+      "private string _appId;\n" \
+      "private List<CallbackBase> _delegateList = new List<CallbackBase>();\n" \
+      "private Interop.LibRPCPort.Proxy.ConnectedEventCallback _connectedEventCallback;\n" \
+      "private Interop.LibRPCPort.Proxy.DisconnectedEventCallback _disconnectedEventCallback;\n" \
+      "private Interop.LibRPCPort.Proxy.RejectedEventCallback _rejectedEventCallback;\n" \
+      "private Interop.LibRPCPort.Proxy.ReceivedEventCallback _receivedEventCallback;\n";
 
   const char* eventMethods =
       "private void OnConnectedEvent(string endPoint, string port_name, IntPtr port, IntPtr data)\n" \
@@ -89,12 +94,42 @@ void CsProxyGen::GenInterface(std::ofstream& stream, const Interface& iface) {
       "private void OnRejectedEvent(string endPoint, string port_name, IntPtr data)\n" \
       "{\n" \
       "    Rejected?.Invoke(this, null);\n" \
+      "}\n" \
+      "\n" \
+      "private void OnReceivedEvent(string endPoint, string port_name, IntPtr data)\n" \
+      "{\n" \
+      "    if (Interop.LibRPCPort.Parcel.CreateFromPort(out IntPtr parcel_received, _port) != 0)\n" \
+      "        return;\n" \
+      "\n" \
+      "    Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int cmd);\n" \
+      "    if (cmd != (int)MethodId.Callback)\n" \
+      "    {\n" \
+      "        Interop.LibRPCPort.Parcel.Destroy(parcel_received);\n" \
+      "        //TODO\n" \
+      "        return;\n" \
+      "    }\n" \
+      "\n" \
+      "    Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int id);\n" \
+      "    Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int seqId);\n" \
+      "\n" \
+      "    foreach (var i in _delegateList)\n" \
+      "    {\n" \
+      "        if ((int)i.Id == id && i.SeqId == seqId)\n" \
+      "        {\n" \
+      "            i.OnReceivedEvent(parcel_received);\n" \
+      "            break;\n" \
+      "        }\n" \
+      "    }\n" \
+      "\n" \
+      "    Interop.LibRPCPort.Parcel.Destroy(parcel_received);\n" \
       "}\n";
 
   stream << Tab(2) << "public class " << iface.GetID()
          << " : IDisposable" << NLine(1);
   GenBrace(stream, TAB_SIZE * 2, [&]() {
     stream << AddIndent(TAB_SIZE * 3, prop) << NLine(1);
+    GenCallbacks(stream, iface);
+    GenDelegateId(stream, iface);
     GenMethodId(stream, iface);
     stream << AddIndent(TAB_SIZE * 3, eventMethods) << NLine(1);
     GenSerializer(stream);
@@ -122,9 +157,14 @@ void CsProxyGen::GenConnectMethod(std::ofstream& stream, const Interface& iface)
     "public void Connect()\n" \
     "{\n" \
     "    Interop.LibRPCPort.Proxy.Create(out _proxy);\n" \
-    "    Interop.LibRPCPort.Proxy.AddConnectedEventCb(_proxy, OnConnectedEvent, IntPtr.Zero);\n" \
-    "    Interop.LibRPCPort.Proxy.AddDisconnectedEventCb(_proxy, OnDisconnectedEvent, IntPtr.Zero);\n" \
-    "    Interop.LibRPCPort.Proxy.AddRejectedEventCb(_proxy, OnRejectedEvent, IntPtr.Zero);\n" \
+    "    _connectedEventCallback = new Interop.LibRPCPort.Proxy.ConnectedEventCallback(OnConnectedEvent);\n" \
+    "    _disconnectedEventCallback = new Interop.LibRPCPort.Proxy.DisconnectedEventCallback(OnDisconnectedEvent);\n" \
+    "    _rejectedEventCallback = new Interop.LibRPCPort.Proxy.RejectedEventCallback(OnRejectedEvent);\n" \
+    "    _receivedEventCallback = new Interop.LibRPCPort.Proxy.ReceivedEventCallback(OnReceivedEvent);\n" \
+    "    Interop.LibRPCPort.Proxy.AddConnectedEventCb(_proxy, _connectedEventCallback, IntPtr.Zero);\n" \
+    "    Interop.LibRPCPort.Proxy.AddDisconnectedEventCb(_proxy, _disconnectedEventCallback, IntPtr.Zero);\n" \
+    "    Interop.LibRPCPort.Proxy.AddRejectedEventCb(_proxy, _rejectedEventCallback, IntPtr.Zero);\n" \
+    "    Interop.LibRPCPort.Proxy.AddReceivedEventCb(_proxy, _receivedEventCallback, IntPtr.Zero);\n" \
     "    if (Interop.LibRPCPort.Proxy.Connect(_proxy, _appId, \"$$\") != 0)\n" \
     "        throw new InvalidOperationException(\"Connection failed\");\n" \
     "}";
@@ -178,6 +218,8 @@ void CsProxyGen::GenInvocation(std::ofstream& stream, const Declaration& decl) {
     if (pt.GetDirection() == ParameterType::Direction::OUT)
       continue;
     m += ConvertTypeToSerializer(pt.GetBaseType(), i->GetID(), "p");
+    if (IsDelegateType(pt.GetBaseType().ToString()))
+      m += "_delegateList.Add(" + i->GetID() + ");\n";
   }
 
   stream << AddIndent(TAB_SIZE * 4, m) << NLine(1);
@@ -191,6 +233,15 @@ void CsProxyGen::GenInvocation(std::ofstream& stream, const Declaration& decl) {
   stream << Tab(4)
          << "Interop.LibRPCPort.Parcel.CreateFromPort(out IntPtr parcel_received, _port);"
          << NLine(1);
+  stream << Tab(4)
+         << "Interop.LibRPCPort.Parcel.ReadInt32(parcel_received, out int cmd);"
+         << NLine(1);
+  stream << Tab(4)
+         << "if (cmd != (int)MethodId.Result)" << NLine(1);
+  GenBrace(stream, TAB_SIZE * 4, [&]() {
+    //TODO
+  });
+  stream << NLine(1);
 
   for (auto& i : decl.GetParameters().GetParams()) {
     if (i->GetParameterType().GetDirection() == ParameterType::Direction::IN) {
index 64a6ced..63ef05a 100644 (file)
@@ -65,14 +65,20 @@ void CsStubGen::GenInterfaces(std::ofstream& stream) {
 void CsStubGen::GenInterface(std::ofstream& stream, const Interface& iface) {
   stream << Tab(2) << "public sealed class " << iface.GetID() << NLine(1);
   GenBrace(stream, TAB_SIZE * 2, [&]() {
-    GenServiceBase(stream, iface);
-    stream << Tab(3)
-           << "private IntPtr _stub;" << NLine(2);
+    stream << Tab(3) << "private IntPtr _stub;" << NLine(1);
     stream << Tab(3)
            << "private List<ServiceBase> _services = new List<ServiceBase>();"
+           << NLine(1);
+    stream << Tab(3) << "private Type _serviceType;" << NLine(1);
+    stream << Tab(3) << "private Interop.LibRPCPort.Stub.ConnectedEventCallback _connectedEventCallback;"
+           << NLine(1);
+    stream << Tab(3) << "private Interop.LibRPCPort.Stub.DisconnectedEventCallback _disconnectedEventCallback;"
+           << NLine(1);
+    stream << Tab(3) << "private Interop.LibRPCPort.Stub.ReceivedEventCallback _receivedEventCallback;"
            << NLine(2);
-    stream << Tab(3)
-           << "private Type _serviceType;" << NLine(2);
+    GenServiceBase(stream, iface);
+    GenCallbacks(stream, iface);
+    GenDelegateId(stream, iface);
     GenMethodId(stream, iface);
     GenSerializer(stream);
     GenListSerializer(stream);
@@ -108,6 +114,8 @@ void CsStubGen::GenServiceBase(std::ofstream& stream, const Interface& iface) {
 void CsStubGen::GenDeclarations(std::ofstream& stream,
                                 const Declarations& decls) {
   for (auto& i : decls.GetDecls()) {
+    if (i->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
     stream << Tab(4) << "public abstract ";
     GenDeclaration(stream, *i);
     stream << NLine(1);
@@ -218,7 +226,7 @@ void CsStubGen::GenInvocation(std::ofstream& stream, const Declaration& decl) {
     return;
 
   cnt = 0;
-  m = "";
+  m = "Interop.LibRPCPort.Parcel.WriteInt32(result, (int)MethodId.Result);\n";
   for (auto& i : decl.GetParameters().GetParams()) {
     auto& pt = i->GetParameterType();
     cnt++;
@@ -268,9 +276,12 @@ void CsStubGen::GenCtor(std::ofstream& stream, const Interface& iface) {
       "public $$()\n" \
       "{\n" \
       "    Interop.LibRPCPort.Stub.Create(out _stub, \"$$\");\n" \
-      "    Interop.LibRPCPort.Stub.AddReceivedEventCb(_stub, OnReceivedEvent, IntPtr.Zero);\n" \
-      "    Interop.LibRPCPort.Stub.AddConnectedEventCb(_stub, OnConnectedEvent, IntPtr.Zero);\n" \
-      "    Interop.LibRPCPort.Stub.AddDisconnectedEventCb(_stub, OnDisconnectedEvent, IntPtr.Zero);\n";
+      "    _connectedEventCallback = new Interop.LibRPCPort.Stub.ConnectedEventCallback(OnConnectedEvent);\n" \
+      "    _disconnectedEventCallback = new Interop.LibRPCPort.Stub.DisconnectedEventCallback(OnDisconnectedEvent);\n" \
+      "    _receivedEventCallback = new Interop.LibRPCPort.Stub.ReceivedEventCallback(OnReceivedEvent);\n" \
+      "    Interop.LibRPCPort.Stub.AddReceivedEventCb(_stub, _receivedEventCallback, IntPtr.Zero);\n" \
+      "    Interop.LibRPCPort.Stub.AddConnectedEventCb(_stub, _connectedEventCallback, IntPtr.Zero);\n" \
+      "    Interop.LibRPCPort.Stub.AddDisconnectedEventCb(_stub, _disconnectedEventCallback, IntPtr.Zero);\n";
 
   GenTemplate(AddIndent(TAB_SIZE * 3, ctor), stream,
     [&]()->std::string {
index d9b235f..fb309a4 100644 (file)
 "out"                   { return yy::parser::token::T_OUT; }
 "ref"                   { return yy::parser::token::T_REF; }
 "async"                 { return yy::parser::token::T_ASYNC; }
+"delegate"              { return yy::parser::token::T_DELEGATE; }
 "<"                     { return yy::parser::token::T_META_OPEN; }
 ">"                     { return yy::parser::token::T_META_CLOSE; }
 "list"                  {
                           return yy::parser::token::T_SB_CLOSE;
                         }
 "="                     { return yy::parser::token::T_EQUAL; }
-"delegate"              { return yy::parser::token::T_DELEGATE; }
+
 
 %%
 
index bc313f7..cb859a4 100644 (file)
@@ -283,7 +283,7 @@ declaration: base_type T_ID T_LEFT parameter_list T_RIGHT T_SEMICOLON {
     delete $1;
     delete $2;
   }
- | T_VOID T_ID T_LEFT parameter_list T_RIGHT T_DELEGATE T_SEMICOLON {
 | T_VOID T_ID T_LEFT parameter_list T_RIGHT T_DELEGATE T_SEMICOLON {
     $$ = new tidl::Declaration($2->ToString(),
         new tidl::BaseType("void", $1->GetComments()), $4,
         $1->GetComments(), @1.begin.line,