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>
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 \
--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).
## 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]>**
- 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
**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
public string Name { get; set; } // Property for ‘Name’
};
```
+
**C**
```c
typedef struct Foo_s *rpc_port_Foo_h; // Handle for Foo
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**
…
};
```
+
**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
// 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
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**
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)
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
+ …
};
```
// 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’
// 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);
+}
+```
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/*
+ * 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_
#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"
}
break;
}
+ case tidl::Options::LANGUAGE_TYPE_DART:
+ {
+ tidl::DartStubGen stub(ps.GetDoc());
+ stub.EnableProxy(false);
+ stub.Run(options->GetOutput() + ".dart");
+ break;
+ }
default:
break;
}
break;
}
+ case tidl::Options::LANGUAGE_TYPE_DART:
+ {
+ break;
+ }
default:
break;
-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).
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;
}
LANGUAGE_TYPE_C,
LANGUAGE_TYPE_CPP,
LANGUAGE_TYPE_CSHARP,
- LANGUAGE_TYPE_JAVA
+ LANGUAGE_TYPE_JAVA,
+ LANGUAGE_TYPE_DART
};
Options();