From bc3bdf59eaf8510adcebfac91583ae05d2073e37 Mon Sep 17 00:00:00 2001 From: Hwankyu Jhun Date: Thu, 1 Sep 2022 07:14:15 +0000 Subject: [PATCH] Support Dart Language 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 --- Makefile.dibs | 2 + README.md | 138 +++++++--- idlc/gen/dart_gen_base.cc | 603 ++++++++++++++++++++++++++++++++++++++++++++ idlc/gen/dart_gen_base.h | 80 ++++++ idlc/gen/dart_gen_base_cb.h | 299 ++++++++++++++++++++++ idlc/gen/dart_stub_gen.cc | 382 ++++++++++++++++++++++++++++ idlc/gen/dart_stub_gen.h | 56 ++++ idlc/gen/dart_stub_gen_cb.h | 240 ++++++++++++++++++ idlc/main.cc | 12 + idlc/options.cc | 4 +- idlc/options.h | 3 +- 11 files changed, 1775 insertions(+), 44 deletions(-) create mode 100644 idlc/gen/dart_gen_base.cc create mode 100644 idlc/gen/dart_gen_base.h create mode 100644 idlc/gen/dart_gen_base_cb.h create mode 100644 idlc/gen/dart_stub_gen.cc create mode 100644 idlc/gen/dart_stub_gen.h create mode 100644 idlc/gen/dart_stub_gen_cb.h diff --git a/Makefile.dibs b/Makefile.dibs index 2f74b73..392a8e4 100644 --- a/Makefile.dibs +++ b/Makefile.dibs @@ -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 \ diff --git a/README.md b/README.md index 6f5c490..8022514 100755 --- 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 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 CreateService(std::string sender) = 0; + virtual std::unique_ptr 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 disconnect() async { + await _port?.disconnect(); + _port = null; + } + + Future onCreate(); + Future onTerminate(); + Future onRun(Foo foo); +} + +class Runnable extends StubBase { + List services = []; + + 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 index 0000000..9e691d1 --- /dev/null +++ b/idlc/gen/dart_gen_base.cc @@ -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 +#include +#include +#include +#include +#include + +#include "idlc/gen/dart_gen_base_cb.h" + +namespace tidl { + +DartGeneratorBase::DartGeneratorBase(std::shared_ptr 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(*b); + for (const auto& e : st.GetElements()) { + auto& type = e->GetType(); + AddListSerializer(type); + } + } else { + auto& iface = static_cast(*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, "", 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).Out(stream); + stream << NLine(1); +} + +void DartGeneratorBase::GenVersion(std::ofstream& stream) { + ReplaceAll(CB_VERSION_DEF, "", 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 }, + { "", std::to_string(cnt++) } + }); + } + code += ";"; + + ReplaceAll(CB_DELEGATE_ID, "", 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(*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 }, + { "", std::to_string(cnt++) } + }); + } + code += ";"; + + ReplaceAll(CB_METHOD_ID, "", 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(*b); + GenMethodId(stream, iface); + } +} + +void DartGeneratorBase::GenCallbackBase(std::ofstream& stream) { + ReplaceAll(CB_CALLBACK_BASE, "", + 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(*i); + GenStructure(stream, st); + stream << std::endl; + } +} + +void DartGeneratorBase::GenListSerializer(std::ofstream& stream) { + if (list_serializer_.empty()) + return; + + ReplaceAll(CB_LIST_SERIALIZER, { + { "", GenListSerializerSerialize() }, + { "", 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, { + { "", "value" }, + { "", "parcel" } + }); + parcel_write += NLine(1); + } else if (type.GetMetaType()->ToString() == "list" || + type.GetMetaType()->ToString() == "array") { + parcel_write = ReplaceAll(CB_LIST_PARCEL_WRITE, { + { "", "value" }, + { "", "parcel" } + }); + parcel_write += NLine(1); + } else { + parcel_write = ReplaceAll(CB_BASE_PARCEL_WRITE, { + { "", "parcel" }, + { "", + ConvertTypeToParcelType(type.GetMetaType()->ToString()) }, + { "", "value" } + }); + parcel_write += NLine(1); + } + + code += ReplaceAll(CB_LIST_SERIALIZER_SERIALIZE, { + { "", iter.first }, + { "", ConvertTypeToString(*type.GetMetaType()) }, + { "", 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, { + { "", "value" }, + {" ", "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, { + { "", "value" }, + { "", "parcel" } + }); + } else { + parcel_read = "final " + ConvertTypeToString(*type.GetMetaType()) + " "; + parcel_read += ReplaceAll(CB_BASE_PARCEL_READ, { + { "", "parcel" }, + { "", + ConvertTypeToParcelType(type.GetMetaType()->ToString()) }, + { "", "value" } + }); + } + + code += ReplaceAll(CB_LIST_SERIALIZER_DESERIALIZE, { + { "", iter.first }, + { "", parcel_read } + }); + } + + return RemoveLine(code); +} + +void DartGeneratorBase::GenStructure(std::ofstream& stream, + const Structure& st) { + auto& elms = st.GetElements(); + ReplaceAll(CB_STRUCTURE_BASE, { + { "", GetClassName(st.GetID()) }, + { "", GenBaseElements(elms) }, + { "", GenBaseParcelWrite(elms) }, + { "", 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, { + { "", elm->GetID() }, + { "", "parcel" } + }); + code += NLine(1); + } else if (type.ToString() == "list" || type.ToString() == "array") { + code += ReplaceAll(CB_LIST_PARCEL_WRITE, { + { "", elm->GetID() }, + { "", "parcel" } + }); + code += NLine(1); + } else { + code += ReplaceAll(CB_BASE_PARCEL_WRITE, { + { "", "parcel" }, + { "", ConvertTypeToParcelType(type.ToString()) }, + { "", 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, { + { "", elm->GetID() }, + { "", "parcel" } + }); + code += NLine(1); + } else if (type.ToString() == "list" || type.ToString() == "array") { + code += ReplaceAll(CB_LIST_PARCEL_READ, { + { "", elm->GetID() }, + { "", "parcel" } + }); + code += NLine(1); + } else { + code += ReplaceAll(CB_BASE_PARCEL_READ, { + { "", "parcel" }, + { "", ConvertTypeToParcelType(type.ToString()) }, + { "", 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 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 }, + { "", arg } + }); + } + } else if (type.ToString() == "file") { + code = ReplaceAll(CB_FILE_SET_PRIVATE_SHARING, { + { "", port }, + { "", 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 index 0000000..a2241a1 --- /dev/null +++ b/idlc/gen/dart_gen_base.h @@ -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 +#include +#include +#include + +#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 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 type_map_; + std::map parcel_type_map_; + std::unordered_map 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 index 0000000..3dbc755 --- /dev/null +++ b/idlc/gen/dart_gen_base_cb.h @@ -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 { + +/** + * The TIDLC version. + */ +constexpr const char CB_ANNOTATION[] = +R"__dart_cb( +/// Generated by tidlc +)__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"; + +/** + * The log tag. + */ +constexpr const char CB_LOG_TAG[] = +R"__dart_cb(const String _logTag = '';)__dart_cb"; + +/** + * The TIDLC version. + */ +constexpr const char CB_VERSION_DEF[] = +R"__dart_cb(const String _tidlVersion = '';)__dart_cb"; + +/** + * The method IDs. + */ +constexpr const char CB_METHOD_ID[] = +R"__dart_cb( +enum _MethodId { + result(0), + callback(1), + + + const _MethodId(this.id); + final int id; +} +)__dart_cb"; + +/** + * The delegate IDs. + */ +constexpr const char CB_DELEGATE_ID[] = +R"__dart_cb( +enum _DelegateId { + + + const _DelegateId(this.id); + final int id; +} +)__dart_cb"; + +/** + * The name of the enumeration. + * The value of the enumeration. + */ +constexpr const char CB_ENUM[] = +R"__dart_cb(())__dart_cb"; + +/** + * 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'; + + + @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 _onReceivedEvent(Parcel parcel); +)__dart_cb"; + +/** + * The name of the structure. + * Elements of the structure. + * The implementation to write the data to the parcel. + * The implementation to read the data from the parcel. + */ +constexpr const char CB_STRUCTURE_BASE[] = +R"__dart_cb( +/// The [] class. +class extends Parcelable { + /// Constructor for this class. + (); + + /// Constructor for creating a [] class from the parcel. + .fromParcel(Parcel parcel) { + deserialize(parcel); + } + + + + @override + void serialize(Parcel parcel) { + + } + + @override + void deserialize(Parcel parcel) { + + } +} +)__dart_cb"; + +/** + * The variable name of the user defined type. + * The name of the parcel instance. + */ +constexpr const char CB_USER_DEFINED_PARCEL_WRITE[] = +R"__dart_cb(.serialize();)__dart_cb"; + +/** + * The name of the parcel instance. + * The variable name of the list type. + */ +constexpr const char CB_LIST_PARCEL_WRITE[] = +R"__dart_cb(ListSerializer().serialize(, );)__dart_cb"; + +/** + * The name of the parcel instance. + * The type of the parcel of the variable. + * The variable name of the base type. + */ +constexpr const char CB_BASE_PARCEL_WRITE[] = +R"__dart_cb(.write();)__dart_cb"; + +/** + * The variable name of the user defined type. + * The name of the parcel instance. + */ +constexpr const char CB_USER_DEFINED_PARCEL_READ[] = +R"__dart_cb(.deserialize();)__dart_cb"; + +/** + * The name of the parcel instance. + * The variable name of the list type. + */ +constexpr const char CB_LIST_PARCEL_READ[] = +R"__dart_cb(ListSerializer().deserialize(, );)__dart_cb"; + +/** + * The name of the parcel instance. + * The type of the parcel of the element. + * The variable name of the base type. + */ +constexpr const char CB_BASE_PARCEL_READ[] = +R"__dart_cb( = .read();)__dart_cb"; + +/** + * The rpc port handle. + * The argument. + */ +constexpr const char CB_FILE_SET_PRIVATE_SHARING[] = +R"__dart_cb(await .setPrivateSharing();)__dart_cb"; + +/** + * The rpc port handle. + * The argument. + */ +constexpr const char CB_LIST_FILE_SET_PRIVATE_SHARING[] = +R"__dart_cb(await .setPrivateSharingList();)__dart_cb"; + +/** + * The implementation to serialize the data to the parcel. + * 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) { + + default: + { + Log.error(_logTag, 'No such type'); + return; + } + } + } + + /// Deserializes the parameter from the parcel. + void deserialize(Parcel parcel, dynamic param) { + switch (param.runtimeType) { + + default: + { + Log.error(_logTag, 'No such type'); + return; + } + } + } +} +)__dart_cb"; + +/** + * The data type. + * The value type of the list element. + * The implementation to write the data to the parcel. + */ +constexpr const char CB_LIST_SERIALIZER_SERIALIZE[] = +R"__dart_cb( +case : + { + parcel.writeArrayCount(param.length as int); + param.forEach(( value) { + + }); + return; + } +)__dart_cb"; + +/** + * The data type. + * The implementation to read the data from the parcel. + */ +constexpr const char CB_LIST_SERIALIZER_DESERIALIZE[] = +R"__dart_cb( +case : + { + final int count = parcel.readArrayCount(); + for (int i = 0; i < count; ++i) { + + 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 index 0000000..550e2a4 --- /dev/null +++ b/idlc/gen/dart_stub_gen.cc @@ -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 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(*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, { + { "", name }, + { "", GenInterfaceCtor(iface) }, + { "", 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, { + { "", 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, { + { "", d->GetID() }, + { "", GenMethodHandlerParcelRead(*d) }, + { "", GenMethodHandlerInvoke(*d) }, + { "", 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, { + { "", p->GetID() }, + { "", "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, { + { "", p->GetID() }, + { "" , "parcel" } + }); + code += NLine(1); + } else { + code += "final " + ConvertTypeToString(type) + " "; + code += ReplaceAll(CB_BASE_PARCEL_READ, { + { "", "parcel" }, + { "", p->GetID() }, + { "", 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, { + { "", decl.GetID() }, + { "", 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, "", 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, { + { "", "result" }, + { "", "ret" } + }); + code += NLine(1); + } else if (type.ToString() == "list" || type.ToString() == "array") { + code += ReplaceAll(CB_LIST_PARCEL_WRITE, { + { "", "result" }, + { "", "ret" } + }); + code += NLine(1); + } else { + code += ReplaceAll(CB_BASE_PARCEL_WRITE, { + { "", "result" }, + { "", ConvertTypeToParcelType(type.ToString()) }, + { "" , "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, { + { "", "result" }, + { "", p->GetID() } + }); + code += NLine(1); + } else if (type.ToString() == "list" || type.ToString() == "array") { + code += ReplaceAll(CB_LIST_PARCEL_WRITE, { + { "", "result" }, + { "", p->GetID() } + }); + code += NLine(1); + } else { + code += ReplaceAll(CB_BASE_PARCEL_WRITE, { + { "", "result" }, + { "", ConvertTypeToParcelType(type.ToString()) }, + { "" , p->GetID() } + }); + code += NLine(1); + } + } + + return code; +} + +void DartStubGen::GenServiceBase(std::ofstream& stream, + const Interface& iface) { + ReplaceAll(CB_SERVICE_BASE, "", + 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, { + { "", ConvertTypeToString(d->GetType()) }, + { "", d->GetID() }, + { "", 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, { + { "", GetClassName(decl.GetID()) }, + { "", id }, + { "", GenDelegateParams(decl) }, + { "", 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, { + { "", p->GetID() }, + { "", "parcel" } + }); + code += NLine(1); + } else if (type.ToString() == "list" || type.ToString() == "array") { + code += ReplaceAll(CB_LIST_PARCEL_WRITE, { + { "", p->GetID() }, + { "", "parcel" } + }); + code += NLine(1); + } else { + code += ReplaceAll(CB_BASE_PARCEL_WRITE, { + { "", "parcel" }, + { "", ConvertTypeToParcelType(type.ToString()) }, + { "", 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 index 0000000..682881c --- /dev/null +++ b/idlc/gen/dart_stub_gen.h @@ -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 +#include + +#include "idlc/gen/dart_gen_base.h" + +namespace tidl { + +class DartStubGen : public DartGeneratorBase { + public: + explicit DartStubGen(std::shared_ptr 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 index 0000000..af7b8a3 --- /dev/null +++ b/idlc/gen/dart_stub_gen_cb.h @@ -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 { + +/** + * 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 disconnect() async { + await _port?.disconnect(); + _port = null; + } + + /// This abstract method will be called when the client is connected. + Future onCreate(); + + /// This abstract method will be called when the client is disconnected. + Future onTerminate(); + +} +)__dart_cb"; + +/** + * The return type of the method. + * The name of the method. + * The parameters of the method. + */ +constexpr const char CB_METHOD_DECL[] = +R"__dart_cb( +/// This abstract method will be called when the '' request is delivered. +Future<> on();)__dart_cb"; + +/** + * The name of the delegate. + * The ID of the delegate. + * Parameters of the delegate. + * The implementation to write arguments to the parcel. + */ +constexpr const char CB_DELEGATE_BASE[] = +R"__dart_cb( +/// The ' class to invoke the delegate method. +class extends CallbackBase { + /// Constructor for this class. + (this._port, this.service, {bool once = false}) + : super(_DelegateId..id, once); + + final Port? _port; + + /// The client service. + ServiceBase service; + bool _valid = true; + + /// Invokes the delegate method of the client. + Future invoke() 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); + + + + await _port?.send(parcel); + _valid = false; + } +} +)__dart_cb"; + +/** + * The name of the interface. + * The implementation of the constructor of the interface. + * The implementation of the method handlers of the interface. + */ +constexpr const char CB_INTERFACE_BASE[] = +R"__dart_cb( +/// Abstract class for creating [] class for RPC. +abstract class extends StubBase { + /// Constructor for this class. + () : super('') { + + } + + /// The indexable collection of [ServiceBase] class. + List services = []; + final Map _methodHandlers = {}; + + /// Listens to the requests for connections. + @override + Future 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 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 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; + } + } + } + + + + @override + Future 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"; + +/** + * The ID of the method. + * The name of the method. + */ +constexpr const char CB_METHOD_HANDLER_TABLE[] = +R"__dart_cb(_methodHandlers[_MethodId..id] = _onMethod;)__dart_cb"; + +/** + * The name of the method. + * The implementation to read the arguments from the parcel. + * The implementation to invoke the method handle. + * The implementation to write the result to the parcel. + * The implementation to release arguments. + */ +constexpr const char CB_METHOD_HANDLER_BASE[] = +R"__dart_cb( +Future _onMethod(ServiceBase service, Port port, + Parcel parcel) async { + Log.info(_logTag, ''); + + + +} +)__dart_cb"; + +/** + * The name of the method. + * The arguments of the method. + */ +constexpr const char CB_METHOD_HANDLER_INVOKE[] = +R"__dart_cb(service.on();)__dart_cb"; + +/** + * 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); + + +await port.send(result); +)__dart_cb"; + +} // namespace tidl + +#endif // IDLC_GEN_DART_STUB_GEN_CB_H_ diff --git a/idlc/main.cc b/idlc/main.cc index b6046f6..f7b592d 100644 --- a/idlc/main.cc +++ b/idlc/main.cc @@ -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 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 options, } break; } + case tidl::Options::LANGUAGE_TYPE_DART: + { + break; + } default: break; diff --git a/idlc/options.cc b/idlc/options.cc index ac146a7..d8a2361 100644 --- a/idlc/options.cc +++ b/idlc/options.cc @@ -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; } diff --git a/idlc/options.h b/idlc/options.h index 079a90f..40c00b6 100644 --- a/idlc/options.h +++ b/idlc/options.h @@ -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(); -- 2.7.4