Support Dart Language 14/280614/30
authorHwankyu Jhun <h.jhun@samsung.com>
Thu, 1 Sep 2022 07:14:15 +0000 (07:14 +0000)
committerHwanKyu Jhun <h.jhun@samsung.com>
Thu, 22 Sep 2022 06:34:38 +0000 (06:34 +0000)
TIDL supports Dart langauge for using RPC-Port.
After this patch is applied, tidlc generates the stub code for Dart language.

Change-Id: I5d94be9336c2092206ccab85ded8cb4776a91cb2
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
Makefile.dibs
README.md
idlc/gen/dart_gen_base.cc [new file with mode: 0644]
idlc/gen/dart_gen_base.h [new file with mode: 0644]
idlc/gen/dart_gen_base_cb.h [new file with mode: 0644]
idlc/gen/dart_stub_gen.cc [new file with mode: 0644]
idlc/gen/dart_stub_gen.h [new file with mode: 0644]
idlc/gen/dart_stub_gen_cb.h [new file with mode: 0644]
idlc/main.cc
idlc/options.cc
idlc/options.h

index 2f74b732214268376af299ef86f9a494c98cb475..392a8e411f56a46d415679ca31bc5f47f6e2dbc5 100644 (file)
@@ -32,6 +32,8 @@ SRC_FILES := \
        idlc/gen/cs_proxy_gen.cc \
        idlc/gen/cs_stub_gen.cc \
        idlc/gen/cs_group_gen.cc \
+       idlc/gen/dart_gen_base.cc \
+       idlc/gen/dart_stub_gen.cc \
        idlc/gen/generator.cc \
        idlc/gen/replace_all.cc \
        idlc/gen_cion/c_cion_body_gen_base.cc \
index 6f5c4902c1e28609e86eac683a335393738e40d5..8022514bbb07239891c202832585e8656d49f4f9 100755 (executable)
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ Help Options:
   --help-option               Additional options
 
 Additional Options:
-  -l, --language=LANGUAGE     Select generating language (C, C++, C#).
+  -l, --language=LANGUAGE     Select generating language (C, C++, C#, Dart).
   -i, --input=INPUT           A tidl interface file.
   -o, --output=OUTPUT         The generated interface file.
   -n, --namespace             Add the prefix in the funtion name as output file name (C language only).
@@ -137,18 +137,18 @@ struct Student  {
 ## TIDL Type System
  - Built-in type (‘in’ direction case)
 
-       | TIDL type   |Size  |C# type |C++ type  |C type|
-       |------------|------|--------|----------|------|
-       | void   |0|void |void  |void|void|
-       | char|1|byte|char|char|
-       | short|2|short|short int|short int|
-       | int|4|int |int  |int|
-       | long|8|long|long long|long long|
-       | float|4|float|float|float|
-       | double|8|double|double|double|
-       | bundle|variable|Bundle|Bundle|bundle *|
-       | string|variable|string|std::string|const char *|
-       | bool|1|bool|bool|bool|
+       | TIDL type | Size     | C# type | C++ type    | C type       | Dart Type     |
+       |-----------|----------|---------|-------------|--------------|---------------|
+       | void      | 0        | void    | void        | void         | void          |
+       | char      | 1        | byte    | char        | char         | int           |
+       | short     | 2        | short   | short int   | short int    | int           |
+       | int       | 4        | int     | int         | int          | int           |
+       | long      | 8        | long    | long long   | long long    | int           |
+       | float     | 4        | float   | float       | float        | Not supported |
+       | double    | 8        | double  | double      | double       | double        |
+       | bundle    | variable | Bundle  | Bundle      | bundle *     | Bundle        |
+       | string    | variable | string  | std::string | const char * | String        |
+       | bool      | 1        | bool    | bool        | bool         | bool          |
 
  - Container type
         - **list< [type] >**  Or  **array<[type]>**
@@ -156,10 +156,10 @@ struct Student  {
                - Similar to c++ std::list / std::vector
                - Can be nested
 
-       | TIDL type  | C# type| C++ type |C type |
-       |--|--|--|--|
-       | list<>  | LinkedList<> |std::list<> |Handle (pointer)|
-       | array<> | List<>|std::vector<> |Handle (pointer)|
+       | TIDL type  | C# type      | C++ type      | C type           | Dart type |
+       |------------|--------------|---------------|------------------|-----------|
+       | list<>     | LinkedList<> | std::list<>   | Handle (pointer) | List<>    |
+       | array<>    | List<>       | std::vector<> | Handle (pointer) | List<>    |
 
   - User-defined type
        - Name defined by ‘struct’ syntax
@@ -170,22 +170,23 @@ struct Student  {
 **TIDL**
 ```csharp
 struct Foo {
-       int Age;
-       string Name;
+  int Age;
+  string Name;
 }
 ```
 
 **C++**
 ```cpp
 class Foo final { // Copyable and movable class
-       Foo(); // Constructor
-       Foo(int age, std::string name); // Constructor
-       int GetAge() const; // Getter for property ‘Age’
-       void SetAge(int age); // Setter for property ‘Age’
-       const std::string& GetName() const; // Getter for property ‘Name’
-       void SetName(std::string name); // Setter for property ‘Name’
+  Foo(); // Constructor
+  Foo(int age, std::string name); // Constructor
+  int GetAge() const; // Getter for property ‘Age’
+  void SetAge(int age); // Setter for property ‘Age’
+  const std::string& GetName() const; // Getter for property ‘Name’
+  void SetName(std::string name); // Setter for property ‘Name’
 };
 ```
+
 **C#**
 ```csharp
 public selaed class Foo  { // Class for Foo
@@ -193,6 +194,7 @@ public selaed class Foo  { // Class for Foo
        public  string Name { get; set; } // Property for ‘Name’
 };
 ```
+
 **C**
 ```c
 typedef struct Foo_s *rpc_port_Foo_h; // Handle for Foo
@@ -225,6 +227,16 @@ int rpc_port_stub_get_Foo_Age(rpc_port_stub_Foo_h h, int* Age); // Getter for pr
 int rpc_port_stub_get_Foo_Name(rpc_port_stub_Foo_h h, char** Name); // Getter for property ‘Name’
 ```
 
+**Dart**
+```dart
+class Foo {
+  int age;
+  String name;
+
+  Foo(this.age, this.name);
+}
+```
+
 ### Proxy Interface
 
 **TIDL**
@@ -264,15 +276,16 @@ public class Runnable : IDisposable  {
        …
 };
 ```
+
 **C**
 ```c
 // Previous version
 typedef struct Runnable_s* rpc_port_proxy_Runnable_h; // Handle for ‘Runnable’
 
 typedef struct {
-       void (*connected)(rpc_port_proxy_Runnable_h h, void* user_data); // Connected event callback
-       void (*disconnected)(rpc_port_proxy_Runnable_h h, void* user_data); // Disconnected event callback
-       void (*rejected)(rpc_port_proxy_Runnable_h h, void* user_data); // Rejected event callback
+  void (*connected)(rpc_port_proxy_Runnable_h h, void* user_data); // Connected event callback
+  void (*disconnected)(rpc_port_proxy_Runnable_h h, void* user_data); // Disconnected event callback
+  void (*rejected)(rpc_port_proxy_Runnable_h h, void* user_data); // Rejected event callback
 } rpc_port_proxy_Runnable_callback_s;
 
 //  Function for creating Runnable proxy handle
@@ -303,9 +316,9 @@ typedef void (*rpc_port_proxy_Runnable_rejected_cb)(rpc_port_proxy_Runnable_h h,
 
 // The structure type containing the set of callback functions for handling proxy events
 typedef struct {
-       rpc_port_proxy_Runnable_connected_cb connected;
-       rpc_port_proxy_Runnable_disconnected_cb disconnected;
-       rpc_port_proxy_Runnable_rejected_cb rejected;
+  rpc_port_proxy_Runnable_connected_cb connected;
+  rpc_port_proxy_Runnable_disconnected_cb disconnected;
+  rpc_port_proxy_Runnable_rejected_cb rejected;
 } rpc_port_proxy_Runnable_callback_s;
 
 //  Function for creating Runnable proxy handle
@@ -324,6 +337,19 @@ int rpc_port_proxy_Runnable_invoke_Run(rpc_port_proxy_Runnable_h h, rpc_port_Foo
 int rpc_port_proxy_Runnable_disconnect(rpc_port_proxy_Runnable_h h);
 ```
 
+**Dart**
+```dart
+class Runnable extends ProxyBase {
+  Runnable(String appid) : super(appid, 'Runnable');
+
+  void onConnected();
+  void onDisconnected;
+  void onRejected();
+
+  Future<int> Run(Foo foo) async;
+}
+```
+
 ### Stub Interface
 
 **TIDL**
@@ -338,12 +364,12 @@ interface Runnable {
 class Runnable  {
        class ServiceBase { // Abstract class for RPC service
                class Factory { // Factory class to make real service object
-                       virtual std::unique_ptr<ServiceBase> CreateService(std::string sender) = 0;
+                   virtual std::unique_ptr<ServiceBase> CreateService(std::string sender) = 0;
                };
 
-               virtual  void OnCreate() = 0; // Called when service object is created
-               virtual  void OnTerminate() = 0; // Called when service object is terminated
-               virtual  int Run(Foo foo) = 0; // Method to implement
+               virtual void OnCreate() = 0; // Called when service object is created
+               virtual void OnTerminate() = 0; // Called when service object is terminated
+               virtual int Run(Foo foo) = 0; // Method to implement
 
         ...
                void Disconnect(); // Method for disconnecting from the RPC service (Since TIDLC version 1.6.1)
@@ -362,12 +388,12 @@ public sealed class Runnable : IDisposable {
                public abstract void OnCreate(); // Called when service object is created
                public abstract void OnTerminate(); // Called when service object is terminated
                public abstract int Run(Foo foo); // Method to implement
-               
+        …
                public void Disconnect(); // Method for disconnecting from the RPC service (Since TIDLC version 1.6.1)
        };
        public Runnable(); // Constructor
-       public  void Listen(Type serviceType); // Method for listening
-       
+       public void Listen(Type serviceType); // Method for listening
+    …
 };
 ```
 
@@ -426,9 +452,9 @@ typedef void (*rpc_port_stub_Runnable_Run_cb)(rpc-port_stub_Runnable_context_h c
 
 // The structure type containing the set of callback functions for handling stub events
 typedef struct {
-       rpc_port_stub_Runnable_create_cb create;
-       rpc_port_stub_Runnable_terminate_cb terminate;
-       rpc_port_stub_Runnable_Run_cb Run;
+  rpc_port_stub_Runnable_create_cb create;
+  rpc_port_stub_Runnable_terminate_cb terminate;
+  rpc_port_stub_Runnable_Run_cb Run;
 } rpc_port_stub_Runnable_callback_s;
 
 // Initialize interface ‘Runnable’
@@ -439,4 +465,32 @@ int rpc_port_stub_Runnable_unregister(void);
 
 // Gets the number of connected clients
 int rpc_port_stub_Runnable_get_client_number(unsigned int *client_number);
-```
\ No newline at end of file
+```
+
+**Dart**
+```dart
+abstract class ServiceBase {
+  final String sender;
+  final String instance;
+  Port? _port;
+
+  ServiceBase(this.sender, this.instance);
+
+  Future<void> disconnect() async {
+    await _port?.disconnect();
+    _port = null;
+  }
+
+  Future<void> onCreate();
+  Future<void> onTerminate();
+  Future<int> onRun(Foo foo);
+}
+
+class Runnable extends StubBase {
+  List<ServiceBase> services = <ServiceBase>[];
+
+  Runnable() : super('Runnable');
+
+  ServiceBase createInstance(String sender, String instance);
+}
+```
diff --git a/idlc/gen/dart_gen_base.cc b/idlc/gen/dart_gen_base.cc
new file mode 100644 (file)
index 0000000..9e691d1
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idlc/gen/dart_gen_base.h"
+
+#include <algorithm>
+#include <ctime>
+#include <sstream>
+#include <stack>
+#include <utility>
+#include <vector>
+
+#include "idlc/gen/dart_gen_base_cb.h"
+
+namespace tidl {
+
+DartGeneratorBase::DartGeneratorBase(std::shared_ptr<Document> doc)
+    : Generator(doc) {
+  type_map_ = {
+      {"char", "int"},
+      {"int", "int"},
+      {"short", "int"},
+      {"long", "int"},
+      {"string", "String"},
+      {"bool", "bool"},
+      {"list", "List"},
+      {"array", "List"},
+      {"double", "double"},
+      {"bundle", "Bundle"},
+      {"void", "void"},
+      {"file", "String"}
+  };
+
+  parcel_type_map_ = {
+    {"char", "Byte"},
+    {"int", "Int32"},
+    {"short", "Int16"},
+    {"long", "Int64"},
+    {"string", "String"},
+    {"bool", "Bool"},
+    {"double", "Double"},
+    {"bundle", "Bundle"},
+    {"file", "String"}
+  };
+
+  for (auto& b : GetDocument().GetBlocks()) {
+    if (b->GetType() == Block::TYPE_STRUCTURE) {
+      auto& st = static_cast<const Structure&>(*b);
+      for (const auto& e : st.GetElements()) {
+        auto& type = e->GetType();
+        AddListSerializer(type);
+      }
+    } else {
+      auto& iface = static_cast<const Interface&>(*b);
+      for (const auto& d : iface.GetDeclarations()) {
+        for (const auto& p : d->GetParameters())
+          AddListSerializer(p->GetParameterType().GetBaseType());
+
+        if (d->GetMethodType() == Declaration::MethodType::SYNC)
+          AddListSerializer(d->GetType());
+      }
+    }
+  }
+}
+
+void DartGeneratorBase::AddListSerializer(const BaseType& type) {
+  if (type.ToString() != "list" && type.ToString() != "array")
+    return;
+
+  std::string type_name = ConvertTypeToString(type);
+  AddListSerializer(*type.GetMetaType());
+
+  if (list_serializer_.find(type_name) != list_serializer_.end())
+    return;
+
+  list_serializer_[std::move(type_name)] = &type;
+}
+
+void DartGeneratorBase::GenAnnotation(std::ofstream& stream) {
+  ReplaceAll(CB_ANNOTATION, "<VERSION>", FULLVER)
+      .Transform([&](std::string str) {
+          return RemoveLine(str);
+      })
+      .Out(stream);
+}
+
+void DartGeneratorBase::GenImport(std::ofstream& stream) {
+  stream << CB_IMPORT << std::endl;
+}
+
+void DartGeneratorBase::GenLogTag(std::ofstream& stream,
+    const std::string& log_tag) {
+  ReplaceAll(CB_LOG_TAG, "<LOG_TAG>", log_tag).Out(stream);
+  stream << NLine(1);
+}
+
+void DartGeneratorBase::GenVersion(std::ofstream& stream) {
+  ReplaceAll(CB_VERSION_DEF, "<VERSION>", FULLVER).Out(stream);
+  stream << NLine(1);
+}
+
+void DartGeneratorBase::GenDelegateId(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code;
+  int cnt = 1;
+  for (const auto& i : iface.GetDeclarations()) {
+    if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+      continue;
+
+    if (cnt != 1)
+      code += "," + NLine(1);
+
+    std::string name = i->GetID();
+    name[0] = ::tolower(name[0]);
+    code += ReplaceAll(CB_ENUM, {
+          { "<NAME>", name },
+          { "<VALUE>", std::to_string(cnt++) }
+        });
+  }
+  code += ";";
+
+  ReplaceAll(CB_DELEGATE_ID, "<DELEGATE_IDS>", code)
+      .Transform([&](std::string str) { return SmartIndent(str); })
+      .Out(stream);
+}
+
+void DartGeneratorBase::GenDelegateId(std::ofstream& stream) {
+  for (auto& b : GetDocument().GetBlocks()) {
+    if (b->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<const Interface&>(*b);
+    GenDelegateId(stream, iface);
+  }
+}
+
+void DartGeneratorBase::GenMethodId(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code;
+  int cnt = 2;
+  for (const auto& i : iface.GetDeclarations()) {
+    if (i->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    if (cnt != 2)
+      code += "," + NLine(1);
+
+    std::string name = i->GetID();
+    name[0] = ::tolower(name[0]);
+    code += ReplaceAll(CB_ENUM, {
+          { "<NAME>", name },
+          { "<VALUE>", std::to_string(cnt++) }
+        });
+  }
+  code += ";";
+
+  ReplaceAll(CB_METHOD_ID, "<METHOD_IDS>", code)
+      .Transform([&](std::string str) { return SmartIndent(str); })
+      .Out(stream);
+}
+
+void DartGeneratorBase::GenMethodId(std::ofstream& stream) {
+  for (auto& b : GetDocument().GetBlocks()) {
+    if (b->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<const Interface&>(*b);
+    GenMethodId(stream, iface);
+  }
+}
+
+void DartGeneratorBase::GenCallbackBase(std::ofstream& stream) {
+  ReplaceAll(CB_CALLBACK_BASE, "<ON_RECEIVED_EVENT>",
+      IsProxy() ? CB_CALLBACK_BASE_ON_RECEIVED_EVENT : "")
+      .Transform([&](std::string str) {
+        return SmartIndent(std::move(str));
+      })
+      .Out(stream);
+}
+
+void DartGeneratorBase::GenStructures(std::ofstream& stream) {
+  GenListSerializer(stream);
+
+  for (auto& i : GetDocument().GetBlocks()) {
+    if (i->GetType() != Block::TYPE_STRUCTURE)
+      continue;
+
+    Structure& st = static_cast<Structure&>(*i);
+    GenStructure(stream, st);
+    stream << std::endl;
+  }
+}
+
+void DartGeneratorBase::GenListSerializer(std::ofstream& stream) {
+  if (list_serializer_.empty())
+    return;
+
+  ReplaceAll(CB_LIST_SERIALIZER, {
+    { "<SERIALIZE>", GenListSerializerSerialize() },
+    { "<DESERIALIZE>", GenListSerializerDeserialize() }
+  })
+  .Transform([&](std::string str) {
+    return SmartIndent(str);
+  })
+  .Out(stream);
+}
+
+std::string DartGeneratorBase::GenListSerializerSerialize() {
+  std::string code;
+  for (const auto& iter : list_serializer_) {
+    std::string parcel_write;
+    auto& type = *(iter.second);
+    if (type.GetMetaType()->IsUserDefinedType()) {
+      parcel_write = ReplaceAll(CB_USER_DEFINED_PARCEL_WRITE, {
+            { "<NAME>", "value" },
+            { "<PARCEL>", "parcel" }
+          });
+      parcel_write += NLine(1);
+    } else if (type.GetMetaType()->ToString() == "list" ||
+               type.GetMetaType()->ToString() == "array") {
+      parcel_write = ReplaceAll(CB_LIST_PARCEL_WRITE, {
+            { "<NAME>", "value" },
+            { "<PARCEL>", "parcel" }
+          });
+      parcel_write += NLine(1);
+    } else {
+      parcel_write = ReplaceAll(CB_BASE_PARCEL_WRITE, {
+            { "<PARCEL>", "parcel" },
+            { "<PARCEL_TYPE>",
+              ConvertTypeToParcelType(type.GetMetaType()->ToString()) },
+            { "<NAME>", "value" }
+          });
+      parcel_write += NLine(1);
+    }
+
+    code += ReplaceAll(CB_LIST_SERIALIZER_SERIALIZE, {
+          { "<TYPE>", iter.first },
+          { "<VALUE_TYPE>", ConvertTypeToString(*type.GetMetaType()) },
+          { "<PARCEL_WRITE>", parcel_write }
+        });
+  }
+
+  return RemoveLine(code);
+}
+
+std::string DartGeneratorBase::GenListSerializerDeserialize() {
+  std::string code;
+  for (const auto& iter : list_serializer_) {
+    std::string parcel_read;
+    auto& type = *(iter.second);
+    if (type.GetMetaType()->IsUserDefinedType()) {
+      parcel_read = "final " + ConvertTypeToString(*type.GetMetaType()) +
+          " value = " + ConvertTypeToString(*type.GetMetaType()) + "();";
+      parcel_read += NLine(1);
+      parcel_read += ReplaceAll(CB_USER_DEFINED_PARCEL_READ, {
+           { "<NAME>", "value" },
+           {" <PARCEL>", "parcel" }
+          });
+    } else if (type.GetMetaType()->ToString() == "list" ||
+               type.GetMetaType()->ToString() == "array") {
+      parcel_read = "final " + ConvertTypeToString(*type.GetMetaType()) +
+          " value = [];";
+      parcel_read += NLine(1);
+      parcel_read += ReplaceAll(CB_LIST_PARCEL_READ, {
+            { "<NAME>", "value" },
+            { "<PARCEL>", "parcel" }
+          });
+    } else {
+      parcel_read = "final " + ConvertTypeToString(*type.GetMetaType()) + " ";
+      parcel_read += ReplaceAll(CB_BASE_PARCEL_READ, {
+            { "<PARCEL>", "parcel" },
+            { "<PARCEL_TYPE>",
+              ConvertTypeToParcelType(type.GetMetaType()->ToString()) },
+            { "<NAME>", "value" }
+          });
+    }
+
+    code += ReplaceAll(CB_LIST_SERIALIZER_DESERIALIZE, {
+          { "<TYPE>", iter.first },
+          { "<PARCEL_READ>", parcel_read }
+        });
+  }
+
+  return RemoveLine(code);
+}
+
+void DartGeneratorBase::GenStructure(std::ofstream& stream,
+    const Structure& st) {
+  auto& elms = st.GetElements();
+  ReplaceAll(CB_STRUCTURE_BASE, {
+      { "<NAME>", GetClassName(st.GetID()) },
+      { "<ELEMENTS>", GenBaseElements(elms) },
+      { "<PARCEL_WRITE>", GenBaseParcelWrite(elms) },
+      { "<PARCEL_READ>", GenBaseParcelRead(elms) }
+  })
+  .Transform([&](std::string str) {
+    return SmartIndent(str);
+  })
+  .Out(stream);
+}
+
+std::string DartGeneratorBase::GenBaseElements(const Elements& elms) {
+  std::string code;
+  for (const auto& elm : elms) {
+    if (!code.empty())
+      code += NLine(1);
+
+    auto& type = elm->GetType();
+    auto param_type = ConvertTypeToString(type);
+    code += "/// The " + elm->GetID();
+    code += NLine(1);
+    code += "late " + param_type + " " + elm->GetID() + ";";
+    code += NLine(1);
+  }
+
+  return code;
+}
+
+std::string DartGeneratorBase::GenBaseParcelWrite(const Elements& elms) {
+  std::string code;
+  for (const auto& elm : elms) {
+    auto& type = elm->GetType();
+    if (type.IsUserDefinedType()) {
+      code += ReplaceAll(CB_USER_DEFINED_PARCEL_WRITE, {
+            { "<NAME>", elm->GetID() },
+            { "<PARCEL>", "parcel" }
+          });
+      code += NLine(1);
+    } else if (type.ToString() == "list" || type.ToString() == "array") {
+      code += ReplaceAll(CB_LIST_PARCEL_WRITE, {
+            { "<NAME>", elm->GetID() },
+            { "<PARCEL>", "parcel" }
+          });
+      code += NLine(1);
+    } else {
+      code += ReplaceAll(CB_BASE_PARCEL_WRITE, {
+            { "<PARCEL>", "parcel" },
+            { "<PARCEL_TYPE>", ConvertTypeToParcelType(type.ToString()) },
+            { "<NAME>", elm->GetID() }
+          });
+      code += NLine(1);
+    }
+
+    auto private_sharing_code = GetPrivateSharingString(
+        type, "port", elm->GetID());
+    if (!private_sharing_code.empty())
+      code += private_sharing_code + NLine(1);
+  }
+
+  return code;
+}
+
+std::string DartGeneratorBase::GenBaseParcelRead(const Elements& elms) {
+  std::string code;
+  for (const auto& elm : elms) {
+    auto& type = elm->GetType();
+    if (type.IsUserDefinedType()) {
+      code += ReplaceAll(CB_USER_DEFINED_PARCEL_READ, {
+            { "<NAME>", elm->GetID() },
+            { "<PARCEL>", "parcel" }
+          });
+      code += NLine(1);
+    } else if (type.ToString() == "list" || type.ToString() == "array") {
+      code += ReplaceAll(CB_LIST_PARCEL_READ, {
+            { "<NAME>", elm->GetID() },
+            { "<PARCEL>", "parcel" }
+          });
+      code += NLine(1);
+    } else {
+      code += ReplaceAll(CB_BASE_PARCEL_READ, {
+            { "<PARCEL>", "parcel" },
+            { "<PARCEL_TYPE>", ConvertTypeToParcelType(type.ToString()) },
+            { "<NAME>", elm->GetID() }
+          });
+      code += NLine(1);
+    }
+  }
+
+  return code;
+}
+
+std::string DartGeneratorBase::ConvertTypeToString(const BaseType& type) {
+  if (type.IsUserDefinedType())
+    return type.ToString();
+
+  if (type.GetMetaType() != nullptr)
+    return type_map_[type.ToString()] + "<" +
+        ConvertTypeToString(*(type.GetMetaType())) + ">";
+
+  return type_map_[type.ToString()];
+}
+
+std::string DartGeneratorBase::ConvertTypeToParcelType(const std::string& key) {
+  return parcel_type_map_[key];
+}
+
+std::string DartGeneratorBase::Tab(int cnt) {
+  std::string t;
+  for (int i = 0; i < cnt; i++)
+    t += "  ";
+
+  return t;
+}
+
+std::string DartGeneratorBase::NLine(int cnt) {
+  std::string t;
+  for (int i = 0; i < cnt; i++)
+    t += "\n";
+
+  return t;
+}
+
+std::string DartGeneratorBase::RemoveSpaces(const std::string& str) {
+  // for annotation
+  if (str.compare(0, 3, "/**") == 0 ||
+      str.compare(0, 2, " *") == 0 ||
+      str.compare(0, 3, " */") == 0)
+    return str;
+
+  std::size_t found = str.find_first_not_of(' ');
+  if (found == std::string::npos)
+      return "";
+
+  return str.substr(found, str.size() - found);
+}
+
+std::string DartGeneratorBase::Trim(const std::string& str) {
+  // for annotation
+  if (str.compare(0, 3, "/**") == 0 ||
+      str.compare(0, 2, " *") == 0 ||
+      str.compare(0, 3, " */") == 0)
+    return str;
+
+  std::size_t first = str.find_first_not_of(" \t\r\n");
+  if (first == std::string::npos)
+    return str;
+
+  std::size_t last = str.find_last_not_of(" \t\r\n");
+  return str.substr(first, (last - first + 1));
+}
+
+std::string DartGeneratorBase::RemoveLine(std::string lines,
+    unsigned int line_num) {
+  std::stringstream ss(lines);
+  std::string result;
+  std::string line;
+  unsigned int line_count = 0;
+
+  while (std::getline(ss, line, '\n')) {
+    line_count++;
+    if (line_num == line_count)
+      continue;
+
+    result += Trim(line);
+    result += NLine(1);
+  }
+
+  return result;
+}
+
+std::string DartGeneratorBase::SmartIndent(std::string lines) {
+  std::stringstream stream(lines);
+  std::string next_line;
+  std::string line;
+  std::string tab;
+  std::string line_back;
+  std::string code;
+  unsigned int line_count = 0;
+  int tab_size = 0;
+  std::stack<int> prev_tab_size;
+  bool tab_once = false;
+  bool continuous = false;
+  bool enum_block = false;
+
+  while (std::getline(stream, next_line, '\n')) {
+    next_line = RemoveSpaces(std::move(next_line));
+    line_count++;
+    if (line_count == 1) {
+      line = Trim(next_line);
+      continue;
+    }
+
+    tab.clear();
+    // Checks whether the brace is end or not.
+    if (line.find("}") != std::string::npos &&
+        line.find("{") == std::string::npos)
+      tab_size--;
+
+    // Set tab
+    if (line.length() > 0)
+      tab += std::move(Tab(tab_size));
+
+    // Set tab for if statement or for loop or while loop
+    if (tab_once) {
+      tab += Tab(1);
+      tab_once = false;
+    }
+
+    if (continuous) {
+      tab += Tab(2);
+      continuous = false;
+    }
+
+    if (line.front() == ':')
+      tab += Tab(2);
+
+    // Checks whether switch case is end or not.
+    line_back = line.back();
+    if (!prev_tab_size.empty() && prev_tab_size.top() == (tab_size - 1) &&
+        line_back == "}") {
+      prev_tab_size.pop();
+      tab_size--;
+      enum_block = false;
+    }
+
+    if (line.empty() || std::all_of(line.begin(), line.end(), isspace)) {
+      std::string new_line = std::move(Trim(next_line));
+      if (new_line.empty() || new_line.find('}') != std::string::npos ||
+          std::all_of(new_line.begin(), new_line.end(), isspace)) {
+        line = std::move(new_line);
+        continue;
+      }
+
+      code += tab + line + NLine(1);
+    } else {
+      if (line.compare(0, 2, " *") != 0)
+        code += tab;
+
+      code += line + NLine(1);
+    }
+
+    // Checks whether the brace is starting or not
+    if (line_back == "{" ) {
+      tab_size++;
+      if (line.find("enum ") != std::string::npos)
+        enum_block = true;
+    }
+
+    if (line_back != "{") {
+      // Checks whether if statement or for loop or while loop without braces is starting or not.
+      if (line.find("if (") != std::string::npos ||
+          line.find("for (") != std::string::npos ||
+          line.find("while (") != std::string::npos)
+        tab_once = true;
+
+      /// Checks whether switch case is starting or not.
+      if ((line.find("case ") != std::string::npos && line_back == ":") ||
+          line.find("default:") != std::string::npos) {
+        tab_size++;
+
+        prev_tab_size.push(tab_size - 1);
+      }
+
+      if (!enum_block && line_back == ",")
+        continuous = true;
+    }
+
+    line = std::move(Trim(next_line));
+  }
+
+  code += line + NLine(1);
+  return code;
+}
+
+std::string DartGeneratorBase::GetClassName(std::string name) {
+  name[0] = ::toupper(name[0]);
+  return name;
+}
+
+std::string DartGeneratorBase::GetPrivateSharingString(const BaseType& type,
+    const std::string& port, const std::string& arg) {
+  std::string code;
+  if (type.ToString() == "list" || type.ToString() == "array") {
+    if (type.GetMetaType()->ToString() == "file") {
+      code = ReplaceAll(CB_LIST_FILE_SET_PRIVATE_SHARING, {
+            { "<PORT>", port },
+            { "<ARG>", arg }
+          });
+    }
+  } else if (type.ToString() == "file") {
+    code = ReplaceAll(CB_FILE_SET_PRIVATE_SHARING, {
+          { "<PORT>", port },
+          { "<ARG>", arg }
+        });
+  }
+
+  return code;
+}
+
+}  // namespace tidl
diff --git a/idlc/gen/dart_gen_base.h b/idlc/gen/dart_gen_base.h
new file mode 100644 (file)
index 0000000..a2241a1
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_DART_GEN_BASE_H_
+#define IDLC_GEN_DART_GEN_BASE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "idlc/ast/structure.h"
+#include "idlc/ast/type.h"
+#include "idlc/gen/generator.h"
+
+namespace tidl {
+
+class DartGeneratorBase : public Generator {
+ public:
+  explicit DartGeneratorBase(std::shared_ptr<Document> doc);
+  virtual ~DartGeneratorBase() = default;
+
+  void GenAnnotation(std::ofstream& stream);
+  void GenImport(std::ofstream& stream);
+  void GenLogTag(std::ofstream& stream, const std::string& log_tag);
+  void GenVersion(std::ofstream& stream);
+  void GenDelegateId(std::ofstream& stream);
+  void GenMethodId(std::ofstream& stream);
+  void GenCallbackBase(std::ofstream& stream);
+  void GenStructures(std::ofstream& stream);
+
+  std::string ConvertTypeToParcelType(const std::string& key);
+  std::string ConvertTypeToString(const BaseType& type);
+  std::string GetClassName(std::string name);
+  std::string NLine(int cnt);
+  std::string RemoveLine(std::string lines, unsigned int line_num = 1);
+  std::string RemoveSpaces(const std::string& str);
+  std::string SmartIndent(std::string lines);
+  std::string Tab(int cnt);
+  std::string Trim(const std::string& str);
+  std::string GetPrivateSharingString(const BaseType& type,
+      const std::string& port, const std::string& arg);
+
+ private:
+  void AddListSerializer(const BaseType& type);
+  void GenListSerializer(std::ofstream& stream);
+  std::string GenListSerializerSerialize();
+  std::string GenListSerializerDeserialize();
+  void GenStructure(std::ofstream& stream, const Structure& st);
+  std::string GenBaseElements(const Elements& elms);
+  std::string GenBaseParcelWrite(const Elements& elms);
+  std::string GenBaseParcelRead(const Elements& elms);
+  void GenDelegateId(std::ofstream& stream, const Interface& iface);
+  void GenMethodId(std::ofstream& stream, const Interface& iface);
+
+ protected:
+  const int TAB_SIZE = 2;
+
+ private:
+  std::map<std::string, std::string> type_map_;
+  std::map<std::string, std::string> parcel_type_map_;
+  std::unordered_map<std::string, const BaseType*> list_serializer_;
+};
+
+}  // namespace tidl
+
+#endif  // IDLC_GEN_DART_GEN_BASE_H_
diff --git a/idlc/gen/dart_gen_base_cb.h b/idlc/gen/dart_gen_base_cb.h
new file mode 100644 (file)
index 0000000..3dbc755
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_DART_GEN_BASE_CB_H_
+#define IDLC_GEN_DART_GEN_BASE_CB_H_
+
+namespace tidl {
+
+/**
+ * <VERSION> The TIDLC version.
+ */
+constexpr const char CB_ANNOTATION[] =
+R"__dart_cb(
+/// Generated by tidlc <VERSION>
+)__dart_cb";
+
+constexpr const char CB_IMPORT[] =
+R"__dart_cb(
+import 'package:tizen_log/tizen_log.dart';
+import 'package:tizen_rpc_port/tizen_rpc_port.dart';
+)__dart_cb";
+
+/**
+ * <LOG_TAG> The log tag.
+ */
+constexpr const char CB_LOG_TAG[] =
+R"__dart_cb(const String _logTag = '<LOG_TAG>';)__dart_cb";
+
+/**
+ * <VERSION> The TIDLC version.
+ */
+constexpr const char CB_VERSION_DEF[] =
+R"__dart_cb(const String _tidlVersion = '<VERSION>';)__dart_cb";
+
+/**
+ * <METHOD_IDS> The method IDs.
+ */
+constexpr const char CB_METHOD_ID[] =
+R"__dart_cb(
+enum _MethodId {
+  result(0),
+  callback(1),
+  <METHOD_IDS>
+
+  const _MethodId(this.id);
+  final int id;
+}
+)__dart_cb";
+
+/**
+ * <DELEGATE_IDS> The delegate IDs.
+ */
+constexpr const char CB_DELEGATE_ID[] =
+R"__dart_cb(
+enum _DelegateId {
+  <DELEGATE_IDS>
+
+  const _DelegateId(this.id);
+  final int id;
+}
+)__dart_cb";
+
+/**
+ * <NAME> The name of the enumeration.
+ * <VALUE> The value of the enumeration.
+ */
+constexpr const char CB_ENUM[] =
+R"__dart_cb(<NAME>(<VALUE>))__dart_cb";
+
+/**
+ * <ON_RECEIVED_EVENT> The definition for _onReceivedEvent method for proxy.
+ */
+constexpr const char CB_CALLBACK_BASE[] =
+R"__dart_cb(
+/// Abstract class for creating a [CallbackBase] class for RPC.
+abstract class CallbackBase extends Parcelable {
+  /// Constructor for this class.
+  CallbackBase(this._id, this._once) {
+    _seqId = _seqNum++;
+  }
+
+  /// Creating a [CallbackBase] class from the parcel.
+  CallbackBase.fromParcel(Parcel parcel) {
+    deserialize(parcel);
+  }
+
+  int _id = 0;
+  bool _once = false;
+  int _seqId = 0;
+  static int _seqNum = 0;
+
+  /// Gets the tag.
+  String get tag => '$_id::$_seqId';
+  <ON_RECEIVED_EVENT>
+
+  @override
+  void serialize(Parcel parcel) {
+    parcel.writeInt32(_id);
+    parcel.writeInt32(_seqId);
+    parcel.writeBool(_once);
+  }
+
+  @override
+  void deserialize(Parcel parcel) {
+    _id = parcel.readInt32();
+    _seqId = parcel.readInt32();
+    _once = parcel.readBool();
+  }
+}
+)__dart_cb";
+
+constexpr const char CB_CALLBACK_BASE_ON_RECEIVED_EVENT[] =
+R"__dart_cb(
+Future<void> _onReceivedEvent(Parcel parcel);
+)__dart_cb";
+
+/**
+ * <NAME> The name of the structure.
+ * <ELEMENTS> Elements of the structure.
+ * <PARCEL_WRITE> The implementation to write the data to the parcel.
+ * <PARCEL_READ> The implementation to read the data from the parcel.
+ */
+constexpr const char CB_STRUCTURE_BASE[] =
+R"__dart_cb(
+/// The [<NAME>] class.
+class <NAME> extends Parcelable {
+  /// Constructor for this class.
+  <NAME>();
+
+  /// Constructor for creating a [<NAME>] class from the parcel.
+  <NAME>.fromParcel(Parcel parcel) {
+    deserialize(parcel);
+  }
+
+  <ELEMENTS>
+
+  @override
+  void serialize(Parcel parcel) {
+    <PARCEL_WRITE>
+  }
+
+  @override
+  void deserialize(Parcel parcel) {
+    <PARCEL_READ>
+  }
+}
+)__dart_cb";
+
+/**
+ * <NAME> The variable name of the user defined type.
+ * <PARCEL> The name of the parcel instance.
+ */
+constexpr const char CB_USER_DEFINED_PARCEL_WRITE[] =
+R"__dart_cb(<NAME>.serialize(<PARCEL>);)__dart_cb";
+
+/**
+ * <PARCEL> The name of the parcel instance.
+ * <NAME> The variable name of the list type.
+ */
+constexpr const char CB_LIST_PARCEL_WRITE[] =
+R"__dart_cb(ListSerializer().serialize(<PARCEL>, <NAME>);)__dart_cb";
+
+/**
+ * <PARCEL> The name of the parcel instance.
+ * <PARCEL_TYPE> The type of the parcel of the variable.
+ * <NAME> The variable name of the base type.
+ */
+constexpr const char CB_BASE_PARCEL_WRITE[] =
+R"__dart_cb(<PARCEL>.write<PARCEL_TYPE>(<NAME>);)__dart_cb";
+
+/**
+ * <NAME> The variable name of the user defined type.
+ * <PARCEL> The name of the parcel instance.
+ */
+constexpr const char CB_USER_DEFINED_PARCEL_READ[] =
+R"__dart_cb(<NAME>.deserialize(<PARCEL>);)__dart_cb";
+
+/**
+ * <PARCEL> The name of the parcel instance.
+ * <NAME> The variable name of the list type.
+ */
+constexpr const char CB_LIST_PARCEL_READ[] =
+R"__dart_cb(ListSerializer().deserialize(<PARCEL>, <NAME>);)__dart_cb";
+
+/**
+ * <PARCEL> The name of the parcel instance.
+ * <PARCEL_TYPE> The type of the parcel of the element.
+ * <NAME> The variable name of the base type.
+ */
+constexpr const char CB_BASE_PARCEL_READ[] =
+R"__dart_cb(<NAME> = <PARCEL>.read<PARCEL_TYPE>();)__dart_cb";
+
+/**
+ * <PORT> The rpc port handle.
+ * <ARG> The argument.
+ */
+constexpr const char CB_FILE_SET_PRIVATE_SHARING[] =
+R"__dart_cb(await <PORT>.setPrivateSharing(<ARG>);)__dart_cb";
+
+/**
+ * <PORT> The rpc port handle.
+ * <ARG> The argument.
+ */
+constexpr const char CB_LIST_FILE_SET_PRIVATE_SHARING[] =
+R"__dart_cb(await <PORT>.setPrivateSharingList(<ARG>);)__dart_cb";
+
+/**
+ * <SERIALIZE> The implementation to serialize the data to the parcel.
+ * <DESERIALIZE> The implementation to deserialize the data from the parcel.
+ */
+constexpr const char CB_LIST_SERIALIZER[] =
+R"__dart_cb(
+/// The [ListSerializer] class for serializing a list to the parcel.
+class ListSerializer {
+  /// Gets the instance of the [ListSerializer].
+  factory ListSerializer() {
+    return _instance;
+  }
+
+  ListSerializer._internal();
+
+  static final ListSerializer _instance = ListSerializer._internal();
+
+  /// Serailizes the parameter to the parcel.
+  void serialize(Parcel parcel, dynamic param) {
+    switch (param.runtimeType) {
+      <SERIALIZE>
+      default:
+        {
+          Log.error(_logTag, 'No such type');
+          return;
+        }
+    }
+  }
+
+  /// Deserializes the parameter from the parcel.
+  void deserialize(Parcel parcel, dynamic param) {
+    switch (param.runtimeType) {
+      <DESERIALIZE>
+      default:
+        {
+          Log.error(_logTag, 'No such type');
+          return;
+        }
+    }
+  }
+}
+)__dart_cb";
+
+/**
+ * <TYPE> The data type.
+ * <VALUE_TYPE> The value type of the list element.
+ * <PARCEL_WRITE> The implementation to write the data to the parcel.
+ */
+constexpr const char CB_LIST_SERIALIZER_SERIALIZE[] =
+R"__dart_cb(
+case <TYPE>:
+  {
+    parcel.writeArrayCount(param.length as int);
+    param.forEach((<VALUE_TYPE> value) {
+      <PARCEL_WRITE>
+    });
+    return;
+  }
+)__dart_cb";
+
+/**
+ * <TYPE> The data type.
+ * <PARCEL_READ> The implementation to read the data from the parcel.
+ */
+constexpr const char CB_LIST_SERIALIZER_DESERIALIZE[] =
+R"__dart_cb(
+case <TYPE>:
+  {
+    final int count = parcel.readArrayCount();
+    for (int i = 0; i < count; ++i) {
+      <PARCEL_READ>
+      param.add(value);
+    }
+    return;
+  }
+)__dart_cb";
+
+}  // namespace tidl
+
+#endif  // IDLC_GEN_DART_GEN_BASE_CB_H_
diff --git a/idlc/gen/dart_stub_gen.cc b/idlc/gen/dart_stub_gen.cc
new file mode 100644 (file)
index 0000000..550e2a4
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idlc/gen/dart_stub_gen.h"
+
+#include "idlc/gen/dart_gen_base_cb.h"
+#include "idlc/gen/dart_stub_gen_cb.h"
+
+namespace tidl {
+
+DartStubGen::DartStubGen(std::shared_ptr<Document> doc)
+    : DartGeneratorBase(doc) {}
+
+void DartStubGen::OnInitGen(std::ofstream& stream) {
+  GenAnnotation(stream);
+  GenImport(stream);
+  GenLogTag(stream, "RPC_PORT_STUB");
+  GenVersion(stream);
+  GenDelegateId(stream);
+  GenMethodId(stream);
+  GenCallbackBase(stream);
+  GenStructures(stream);
+  GenInterfaces(stream);
+}
+
+void DartStubGen::OnFiniGen(std::ofstream& stream) {}
+
+void DartStubGen::GenInterfaces(std::ofstream& stream) {
+  for (auto& i : GetDocument().GetBlocks()) {
+    if (i->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<const Interface&>(*i);
+    GenInterface(stream, iface);
+  }
+}
+
+void DartStubGen::GenInterface(std::ofstream& stream, const Interface& iface) {
+  GenServiceBase(stream, iface);
+
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      GenDelegateBase(stream, *d);
+  }
+
+  GenInterfaceBase(stream, iface);
+}
+
+void DartStubGen::GenInterfaceBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string name = iface.GetID();
+  name[0] = ::toupper(name[0]);
+  ReplaceAll(CB_INTERFACE_BASE, {
+        { "<INTERFACE_NAME>", name },
+        { "<CTOR>", GenInterfaceCtor(iface) },
+        { "<METHOD_HANDLERS>", GenInterfaceMethodHandlers(iface) }
+      })
+      .Transform([&](std::string str) {
+        return SmartIndent(std::move(str));
+      })
+      .Out(stream);
+}
+
+std::string DartStubGen::GenInterfaceCtor(const Interface& iface) {
+  std::string method_handler_table;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    std::string name = d->GetID();
+    name[0] = ::tolower(name[0]);
+    method_handler_table += ReplaceAll(CB_METHOD_HANDLER_TABLE, {
+          { "<METHOD_ID>", name },
+          { "<METHOD_NAME>", d->GetID() }
+        });
+    method_handler_table += NLine(1);
+  }
+
+  std::string attributes;
+  for (const auto& i : iface.GetAttributes()) {
+    if (i->GetKey() == "privilege") {
+      attributes += "addPrivilege('" +  i->GetValue() + "');";
+      attributes += NLine(1);
+    } else if (i->GetKey() == "trusted" && i->GetValue() == "true") {
+      attributes += "setTrusted(true);";
+      attributes += NLine(1);
+    }
+  }
+
+  std::string code = std::move(method_handler_table);
+  code += NLine(1);
+  code += std::move(attributes);
+  return code;
+}
+
+std::string DartStubGen::GenInterfaceMethodHandlers(const Interface& iface) {
+  std::string code;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    code += ReplaceAll(CB_METHOD_HANDLER_BASE, {
+          { "<METHOD_NAME>", d->GetID() },
+          { "<METHOD_HANDLER_PARCEL_READ>", GenMethodHandlerParcelRead(*d) },
+          { "<METHOD_HANDLER_INVOKE>", GenMethodHandlerInvoke(*d) },
+          { "<METHOD_HANDLER_PARCEL_WRITE>", GenMethodHandlerParcelWrite(*d) },
+        });
+  }
+
+  return RemoveLine(code);
+}
+
+std::string DartStubGen::GenMethodHandlerParcelRead(const Declaration& decl) {
+  std::string code;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    if (param_type.GetDirection() != ParameterType::Direction::IN)
+      continue;
+
+    auto& type = param_type.GetBaseType();
+    if (type.IsUserDefinedType()) {
+      code += "final " + ConvertTypeToString(type) + " " + p->GetID() +
+          " = " + ConvertTypeToString(type);
+      code += IsDelegateType(type) ? "(service._port, service);" : "();";
+      code += NLine(1);
+      code += ReplaceAll(CB_USER_DEFINED_PARCEL_READ, {
+            { "<NAME>", p->GetID() },
+            { "<PARCEL>", "parcel" }
+          });
+      code += NLine(1);
+    } else if (type.ToString() == "list" || type.ToString() == "array") {
+      code += "final " + ConvertTypeToString(type) + " " + p->GetID() +
+          " = [];";
+      code += NLine(1);
+      code += ReplaceAll(CB_LIST_PARCEL_READ, {
+            { "<NAME>", p->GetID() },
+            { "<PARCEL>" , "parcel" }
+          });
+      code += NLine(1);
+    } else {
+      code += "final " + ConvertTypeToString(type) + " ";
+      code += ReplaceAll(CB_BASE_PARCEL_READ, {
+            { "<PARCEL>", "parcel" },
+            { "<NAME>", p->GetID() },
+            { "<PARCEL_TYPE>", ConvertTypeToParcelType(type.ToString()) }
+          });
+      code += NLine(1);
+    }
+  }
+
+  return code;
+}
+
+std::string DartStubGen::GenMethodHandlerInvoke(const Declaration& decl) {
+  std::string args;
+  std::string code;
+  for (const auto& p : decl.GetParameters()) {
+    if (!args.empty())
+      args += ", ";
+
+    args += p->GetID();
+    auto& param_type = p->GetParameterType();
+    if (param_type.GetDirection() != ParameterType::Direction::OUT)
+      continue;
+
+    auto& type = param_type.GetBaseType();
+    if (type.IsUserDefinedType()) {
+      code += "final " + ConvertTypeToString(type) + " " + p->GetID() +
+          " = " + ConvertTypeToString(type) + "();";
+      code += NLine(1);
+    } else if (type.ToString() == "list" || type.ToString() == "array") {
+      code += "final " + ConvertTypeToString(type) + " " + p->GetID() +
+          " = [];";
+      code += NLine(1);
+    } else {
+      code += "final " + ConvertTypeToString(type) + " " + p->GetID() + ";";
+      code += NLine(1);
+    }
+  }
+
+  if (decl.GetMethodType() == Declaration::MethodType::SYNC)
+    code += "final " + ConvertTypeToString(decl.GetType()) + " ret = await ";
+
+  code += ReplaceAll(CB_METHOD_HANDLER_INVOKE, {
+        { "<METHOD_NAME>", decl.GetID() },
+        { "<ARGS>", args }
+      });
+  return code;
+}
+
+std::string DartStubGen::GenMethodHandlerParcelWrite(const Declaration& decl) {
+  if (decl.GetMethodType() == Declaration::MethodType::ASYNC)
+    return {};
+
+  std::string code = std::move(GenMethodHandlerResultParcelWrite(decl));
+  code += std::move(GenMethodHandlerOutParamParcelWrite(decl));
+  code = ReplaceAll(CB_METHOD_HANDLER_PARCEL_WRITE, "<PARCEL_WRITE>", code);
+  return code;
+}
+
+std::string DartStubGen::GenMethodHandlerResultParcelWrite(
+    const Declaration& decl) {
+  std::string code;
+  auto& type = decl.GetType();
+  if (type.IsUserDefinedType()) {
+    code += ReplaceAll(CB_USER_DEFINED_PARCEL_WRITE, {
+          { "<PARCEL>", "result" },
+          { "<NAME>", "ret" }
+        });
+    code += NLine(1);
+  } else if (type.ToString() == "list" || type.ToString() == "array") {
+    code += ReplaceAll(CB_LIST_PARCEL_WRITE, {
+          { "<PARCEL>", "result" },
+          { "<NAME>", "ret" }
+        });
+    code += NLine(1);
+  } else {
+    code += ReplaceAll(CB_BASE_PARCEL_WRITE, {
+          { "<PARCEL>", "result" },
+          { "<PARCEL_TYPE>", ConvertTypeToParcelType(type.ToString()) },
+          { "<NAME>" , "ret" }
+        });
+    code += NLine(1);
+  }
+
+  return code;
+}
+
+std::string DartStubGen::GenMethodHandlerOutParamParcelWrite(
+    const Declaration& decl) {
+  std::string code;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    if (param_type.GetDirection() != ParameterType::Direction::OUT)
+      continue;
+
+    auto& type = param_type.GetBaseType();
+    if (type.IsUserDefinedType()) {
+      code += ReplaceAll(CB_USER_DEFINED_PARCEL_WRITE, {
+            { "<PARCEL>", "result" },
+            { "<NAME>", p->GetID() }
+          });
+      code += NLine(1);
+    } else if (type.ToString() == "list" || type.ToString() == "array") {
+      code += ReplaceAll(CB_LIST_PARCEL_WRITE, {
+            { "<PARCEL>", "result" },
+            { "<NAME>", p->GetID() }
+          });
+      code += NLine(1);
+    } else {
+      code += ReplaceAll(CB_BASE_PARCEL_WRITE, {
+            { "<PARCEL>", "result" },
+            { "<PARCEL_TYPE>", ConvertTypeToParcelType(type.ToString()) },
+            { "<NAME>" , p->GetID() }
+          });
+      code += NLine(1);
+    }
+  }
+
+  return code;
+}
+
+void DartStubGen::GenServiceBase(std::ofstream& stream,
+    const Interface& iface) {
+  ReplaceAll(CB_SERVICE_BASE, "<METHOD_DECLS>",
+      GenServiceBaseMethodDecls(iface))
+      .Transform([&](std::string str) {
+        return SmartIndent(std::move(RemoveLine(std::move(str))));
+      })
+      .Out(stream);
+}
+
+std::string DartStubGen::GenServiceBaseMethodDecls(const Interface& iface) {
+  std::string code;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    code += ReplaceAll(CB_METHOD_DECL, {
+          { "<RETURN_TYPE>", ConvertTypeToString(d->GetType()) },
+          { "<METHOD_NAME>", d->GetID() },
+          { "<METHOD_PARAMS>", GenMethodParams(*d) }
+        });
+    code += NLine(1);
+  }
+
+  return code;
+}
+
+std::string DartStubGen::GenMethodParams(const Declaration& decl) {
+  std::string params;
+  for (const auto& p : decl.GetParameters()) {
+    if (!params.empty())
+      params += ", ";
+
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    params += ConvertTypeToString(type) + " " + p->GetID();
+  }
+
+  return params;
+}
+
+void DartStubGen::GenDelegateBase(std::ofstream& stream,
+    const Declaration& decl) {
+  std::string id = decl.GetID();
+  id[0] = ::tolower(id[0]);
+  ReplaceAll(CB_DELEGATE_BASE, {
+        { "<DELEGATE_NAME>", GetClassName(decl.GetID()) },
+        { "<DELEGATE_ID>", id },
+        { "<DELEGATE_PARAMS>", GenDelegateParams(decl) },
+        { "<DELEGATE_PARCEL_WRITE>", GenDelegateParcelWrite(decl) }
+      })
+      .Transform([&](std::string str) {
+        return SmartIndent(str);
+      })
+      .Out(stream);
+}
+
+std::string DartStubGen::GenDelegateParams(const Declaration& decl) {
+  std::string params;
+  for (const auto& p : decl.GetParameters()) {
+    if (!params.empty())
+      params += ", ";
+
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    params += ConvertTypeToString(type) + " " + p->GetID();
+  }
+
+  return params;
+}
+
+std::string DartStubGen::GenDelegateParcelWrite(const Declaration& decl) {
+  std::string code;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    if (type.IsUserDefinedType()) {
+      code += ReplaceAll(CB_USER_DEFINED_PARCEL_WRITE, {
+            { "<NAME>", p->GetID() },
+            { "<PARCEL>", "parcel" }
+          });
+      code += NLine(1);
+    } else if (type.ToString() == "list" || type.ToString() == "array") {
+      code += ReplaceAll(CB_LIST_PARCEL_WRITE, {
+            { "<NAME>", p->GetID() },
+            { "<PARCEL>", "parcel" }
+          });
+      code += NLine(1);
+    } else {
+      code += ReplaceAll(CB_BASE_PARCEL_WRITE, {
+            { "<PARCEL>", "parcel" },
+            { "<PARCEL_TYPE>", ConvertTypeToParcelType(type.ToString()) },
+            { "<NAME>", p->GetID() }
+          });
+      code += NLine(1);
+    }
+
+    auto private_sharing_code = GetPrivateSharingString(
+        type, "_port?", p->GetID());
+    if (!private_sharing_code.empty())
+      code += private_sharing_code + NLine(1);
+  }
+
+  return code;
+}
+
+}  // namespace tidl
diff --git a/idlc/gen/dart_stub_gen.h b/idlc/gen/dart_stub_gen.h
new file mode 100644 (file)
index 0000000..682881c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_DART_STUB_GEN_H_
+#define IDLC_GEN_DART_STUB_GEN_H_
+
+#include <memory>
+#include <string>
+
+#include "idlc/gen/dart_gen_base.h"
+
+namespace tidl {
+
+class DartStubGen : public DartGeneratorBase {
+ public:
+  explicit DartStubGen(std::shared_ptr<Document> doc);
+  virtual ~DartStubGen() = default;
+
+  void OnInitGen(std::ofstream& stream) override;
+  void OnFiniGen(std::ofstream& stream) override;
+
+ private:
+  void GenInterfaces(std::ofstream& stream);
+  void GenInterface(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceBase(std::ofstream& stream, const Interface& iface);
+  std::string GenInterfaceCtor(const Interface& iface);
+  std::string GenInterfaceMethodHandlers(const Interface& iface);
+  std::string GenMethodHandlerParcelRead(const Declaration& decl);
+  std::string GenMethodHandlerInvoke(const Declaration& decl);
+  std::string GenMethodHandlerParcelWrite(const Declaration& decl);
+  std::string GenMethodHandlerResultParcelWrite(const Declaration& decl);
+  std::string GenMethodHandlerOutParamParcelWrite(const Declaration& decl);
+  void GenServiceBase(std::ofstream& stream, const Interface& iface);
+  std::string GenServiceBaseMethodDecls(const Interface& iface);
+  std::string GenMethodParams(const Declaration& decl);
+  void GenDelegateBase(std::ofstream& stream, const Declaration& decl);
+  std::string GenDelegateParams(const Declaration& decl);
+  std::string GenDelegateParcelWrite(const Declaration& decl);
+};
+
+}  // namespace tidl
+
+#endif  // IDLC_GEN_DART_STUB_GEN_H_
diff --git a/idlc/gen/dart_stub_gen_cb.h b/idlc/gen/dart_stub_gen_cb.h
new file mode 100644 (file)
index 0000000..af7b8a3
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_DART_STUB_GEN_CB_H_
+#define IDLC_GEN_DART_STUB_GEN_CB_H_
+
+namespace tidl {
+
+/**
+ * <METHOD_DECLS> The declarations of methods.
+ */
+constexpr const char CB_SERVICE_BASE[] =
+R"__dart_cb(
+/// Abstract class for creating a service base class for RPC.
+abstract class ServiceBase {
+  /// Constructor for this class.
+  ServiceBase(this.sender, this.instance);
+
+  /// The client application ID.
+  final String sender;
+
+  /// The client instance ID.
+  final String instance;
+
+  /// The delegate port of the client.
+  Port? _port;
+
+  /// Disconnects from the client application.
+  Future<void> disconnect() async {
+    await _port?.disconnect();
+    _port = null;
+  }
+
+  /// This abstract method will be called when the client is connected.
+  Future<void> onCreate();
+
+  /// This abstract method will be called when the client is disconnected.
+  Future<void> onTerminate();
+  <METHOD_DECLS>
+}
+)__dart_cb";
+
+/**
+ * <RETURN_TYPE> The return type of the method.
+ * <METHOD_NAME> The name of the method.
+ * <METHOD_PARAMS> The parameters of the method.
+ */
+constexpr const char CB_METHOD_DECL[] =
+R"__dart_cb(
+/// This abstract method will be called when the '<METHOD_NAME>' request is delivered.
+Future<<RETURN_TYPE>> on<METHOD_NAME>(<METHOD_PARAMS>);)__dart_cb";
+
+/**
+ * <DELEGATE_NAME> The name of the delegate.
+ * <DELEGATE_ID> The ID of the delegate.
+ * <DELEGATE_PARAMS> Parameters of the delegate.
+ * <DELEGATE_PARCEL_WRITE> The implementation to write arguments to the parcel.
+ */
+constexpr const char CB_DELEGATE_BASE[] =
+R"__dart_cb(
+/// The '<DELEGATE_NAME> class to invoke the delegate method.
+class <DELEGATE_NAME> extends CallbackBase {
+  /// Constructor for this class.
+  <DELEGATE_NAME>(this._port, this.service, {bool once = false})
+      : super(_DelegateId.<DELEGATE_ID>.id, once);
+
+  final Port? _port;
+
+  /// The client service.
+  ServiceBase service;
+  bool _valid = true;
+
+  /// Invokes the delegate method of the client.
+  Future<void> invoke(<DELEGATE_PARAMS>) async {
+    if (_port == null) {
+      Log.error(_logTag, 'port is null');
+      throw Exception('NotConnectedSocketException');
+    }
+
+    if (_once && !_valid) {
+      Log.error(_logTag, 'invalid');
+      throw Exception('InvalidCallbackException');
+    }
+
+    final Parcel parcel = Parcel();
+    parcel.writeInt32(_MethodId.callback.id);
+    serialize(parcel);
+
+    <DELEGATE_PARCEL_WRITE>
+
+    await _port?.send(parcel);
+    _valid = false;
+  }
+}
+)__dart_cb";
+
+/**
+ * <INTERFACE_NAME> The name of the interface.
+ * <CTOR> The implementation of the constructor of the interface.
+ * <METHOD_HANDLERS> The implementation of the method handlers of the interface.
+ */
+constexpr const char CB_INTERFACE_BASE[] =
+R"__dart_cb(
+/// Abstract class for creating [<INTERFACE_NAME>] class for RPC.
+abstract class <INTERFACE_NAME> extends StubBase {
+  /// Constructor for this class.
+  <INTERFACE_NAME>() : super('<INTERFACE_NAME>') {
+    <CTOR>
+  }
+
+  /// The indexable collection of [ServiceBase] class.
+  List<ServiceBase> services = <ServiceBase>[];
+  final Map<int, dynamic> _methodHandlers = <int, dynamic>{};
+
+  /// Listens to the requests for connections.
+  @override
+  Future<void> listen() async {
+    Log.warn(_logTag, 'listen. portName: $portName');
+    return await super.listen();
+  }
+
+  /// Abstract method for creating an instance of the client.
+  ServiceBase createInstance(String sender, String instance);
+
+  @override
+  Future<void> onConnectedEvent(String sender, String instance) async {
+    Log.info(_logTag, 'sender: $sender, instance: $instance');
+    final ServiceBase service = createInstance(sender, instance);
+    service._port = getPort(instance, PortType.callback);
+    await service.onCreate();
+    services.add(service);
+  }
+
+  @override
+  Future<void> onDisconnectedEvent(String sender, String instance) async {
+    Log.info(_logTag, 'sender: $sender, instance: $instance');
+    for (final ServiceBase service in services) {
+      if (service.instance == instance) {
+        await service.onTerminate();
+        services.remove(service);
+        break;
+      }
+    }
+  }
+
+  <METHOD_HANDLERS>
+
+  @override
+  Future<void> onReceivedEvent(String sender, String instance,
+      Parcel parcel) async {
+    Log.info(_logTag, 'sender: $sender, instance: $instance');
+    ServiceBase? service;
+    for (final ServiceBase s in services) {
+      if (s.instance == instance) {
+        service = s;
+        break;
+      }
+    }
+
+    if (service == null) {
+      Log.error(_logTag, 'service is null');
+      return;
+    }
+
+    final Port port = getPort(instance, PortType.main);
+    final int cmd = parcel.readInt32();
+    if (_methodHandlers.containsKey(cmd)) {
+      await _methodHandlers[cmd](service, port, parcel);
+    } else {
+      Log.error(_logTag, 'Unknown cmd: $cmd');
+    }
+  }
+}
+)__dart_cb";
+
+/**
+ * <METHOD_ID> The ID of the method.
+ * <METHOD_NAME> The name of the method.
+ */
+constexpr const char CB_METHOD_HANDLER_TABLE[] =
+R"__dart_cb(_methodHandlers[_MethodId.<METHOD_ID>.id] = _on<METHOD_NAME>Method;)__dart_cb";
+
+/**
+ * <METHOD_NAME> The name of the method.
+ * <METHOD_HANDLER_PARCEL_READ> The implementation to read the arguments from the parcel.
+ * <METHOD_HANDLER_INVOKE> The implementation to invoke the method handle.
+ * <METHOD_HANDLER_PARCEL_WRITE> The implementation to write the result to the parcel.
+ * <METHOD_HANDLER_ARGS_FREE> The implementation to release arguments.
+ */
+constexpr const char CB_METHOD_HANDLER_BASE[] =
+R"__dart_cb(
+Future<void> _on<METHOD_NAME>Method(ServiceBase service, Port port,
+    Parcel parcel) async {
+  Log.info(_logTag, '<METHOD_NAME>');
+  <METHOD_HANDLER_PARCEL_READ>
+  <METHOD_HANDLER_INVOKE>
+  <METHOD_HANDLER_PARCEL_WRITE>
+}
+)__dart_cb";
+
+/**
+ * <METHOD_NAME> The name of the method.
+ * <ARGS> The arguments of the method.
+ */
+constexpr const char CB_METHOD_HANDLER_INVOKE[] =
+R"__dart_cb(service.on<METHOD_NAME>(<ARGS>);)__dart_cb";
+
+/**
+ * <PARCEL_WRITE> The implementation to write the result to the parcel.
+ */
+constexpr const char CB_METHOD_HANDLER_PARCEL_WRITE[] =
+R"__dart_cb(
+final Parcel result = Parcel();
+final ParcelHeader header = parcel.header;
+final ParcelHeader resultHeader = result.header;
+resultHeader.tag = _tidlVersion;
+resultHeader.sequenceNumber = header.sequenceNumber;
+
+result.writeInt32(_MethodId.result.id);
+<PARCEL_WRITE>
+
+await port.send(result);
+)__dart_cb";
+
+}  // namespace tidl
+
+#endif  // IDLC_GEN_DART_STUB_GEN_CB_H_
index b6046f68223acb0a8a56d67ba55c5511574e09f7..f7b592da2134473aa116a9290664442df6d96657 100644 (file)
@@ -36,6 +36,7 @@
 #include "idlc/gen/cpp_stub_body_gen.h"
 #include "idlc/gen/cpp_group_header_gen.h"
 #include "idlc/gen/cpp_group_body_gen.h"
+#include "idlc/gen/dart_stub_gen.h"
 #include "idlc/gen_cion/c_cion_proxy_header_gen.h"
 #include "idlc/gen_cion/c_cion_proxy_body_gen.h"
 #include "idlc/gen_cion/c_cion_stub_header_gen.h"
@@ -251,6 +252,13 @@ void GenerateStubCodes(std::shared_ptr<tidl::Options> options,
       }
       break;
     }
+    case tidl::Options::LANGUAGE_TYPE_DART:
+    {
+      tidl::DartStubGen stub(ps.GetDoc());
+      stub.EnableProxy(false);
+      stub.Run(options->GetOutput() + ".dart");
+      break;
+    }
 
     default:
       break;
@@ -436,6 +444,10 @@ void GenerateProxyCodes(std::shared_ptr<tidl::Options> options,
       }
       break;
     }
+    case tidl::Options::LANGUAGE_TYPE_DART:
+    {
+      break;
+    }
 
     default:
       break;
index ac146a7fa00c3a4efeb6e8f388e42064f9110195..d8a2361a652a5a50d154afe63af78d2f34e57d62 100644 (file)
@@ -32,7 +32,7 @@ Help Options:
   -h, --help                  Show help options
 
 Additional Options:
-  -l, --language=LANGUAGE     Select generating language (C, C++, C#, Java(CION & AITT only)).
+  -l, --language=LANGUAGE     Select generating language (C, C++, C#, Java(CION & AITT only), Dart).
   -i, --input=INPUT           A tidl interface file.
   -o, --output=OUTPUT         The generated interface file.
   -n, --namespace             Add the prefix in the funtion name as output file name (C language only).
@@ -72,6 +72,8 @@ Options::LanguageType ConvertStr2LanguageType(std::string str_type) {
     return Options::LANGUAGE_TYPE_CSHARP;
   else if (str_type == "c")
     return Options::LANGUAGE_TYPE_C;
+  else if (str_type == "dart")
+    return Options::LANGUAGE_TYPE_DART;
 
   return Options::LANGUAGE_TYPE_UNKNOWN;
 }
index 079a90fd9ac28e5a7008d4e470e21dfb372ab57f..40c00b6872e5af412c9ba879c7a5eb150ea78ac3 100644 (file)
@@ -36,7 +36,8 @@ class Options {
     LANGUAGE_TYPE_C,
     LANGUAGE_TYPE_CPP,
     LANGUAGE_TYPE_CSHARP,
-    LANGUAGE_TYPE_JAVA
+    LANGUAGE_TYPE_JAVA,
+    LANGUAGE_TYPE_DART
   };
 
   Options();