feature auto generate lexer parser
Some checks failed
build-crpc / build (Debug, host.toolchain.cmake) (push) Waiting to run
build-crpc / build (Debug, mingw-w64-x86_64.toolchain.cmake) (push) Waiting to run
build-crpc / build (Release, mingw-w64-x86_64.toolchain.cmake) (push) Has been cancelled
build-crpc / build (Release, host.toolchain.cmake) (push) Has been cancelled

This commit is contained in:
tqcq 2023-12-03 11:57:23 +08:00
parent c910b747ef
commit d908772e38
15 changed files with 605 additions and 2686 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,137 +0,0 @@
/*
Copyright (c) 2005-2013, Troy D. Hanson http://troydhanson.github.com/tpl/
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TPL_H
#define TPL_H
#include <stddef.h> /* size_t */
#include <stdarg.h> /* va_list */
#ifdef __INTEL_COMPILER
#include <tbb/tbbmalloc_proxy.h>
#endif /* Intel Compiler efficient memcpy etc */
#ifdef _MSC_VER
typedef unsigned int uint32_t;
#else
#include <inttypes.h> /* uint32_t */
#endif
#if defined __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#ifdef TPL_EXPORTS
#define TPL_API __declspec(dllexport)
#else /* */
#ifdef TPL_NOLIB
#define TPL_API
#else
#define TPL_API __declspec(dllimport)
#endif /* TPL_NOLIB */
#endif /* TPL_EXPORTS*/
#else
#define TPL_API
#endif
/* bit flags (external) */
#define TPL_FILE (1 << 0)
#define TPL_MEM (1 << 1)
#define TPL_PREALLOCD (1 << 2)
#define TPL_EXCESS_OK (1 << 3)
#define TPL_FD (1 << 4)
#define TPL_UFREE (1 << 5)
#define TPL_DATAPEEK (1 << 6)
#define TPL_FXLENS (1 << 7)
#define TPL_GETSIZE (1 << 8)
/* do not add flags here without renumbering the internal flags! */
/* flags for tpl_gather mode */
#define TPL_GATHER_BLOCKING 1
#define TPL_GATHER_NONBLOCKING 2
#define TPL_GATHER_MEM 3
/* Hooks for error logging, memory allocation functions and fatal */
typedef int (tpl_print_fcn)(const char *fmt, ...);
typedef void *(tpl_malloc_fcn)(size_t sz);
typedef void *(tpl_realloc_fcn)(void *ptr, size_t sz);
typedef void (tpl_free_fcn)(void *ptr);
typedef void (tpl_fatal_fcn)(const char *fmt, ...);
typedef struct tpl_hook_t {
tpl_print_fcn *oops;
tpl_malloc_fcn *malloc;
tpl_realloc_fcn *realloc;
tpl_free_fcn *free;
tpl_fatal_fcn *fatal;
size_t gather_max;
} tpl_hook_t;
typedef struct tpl_node {
int type;
void *addr;
void *data; /* r:tpl_root_data*. A:tpl_atyp*. ow:szof type */
int num; /* length of type if its a C array */
size_t ser_osz; /* serialization output size for subtree */
struct tpl_node *children; /* my children; linked-list */
struct tpl_node *next,*prev; /* my siblings (next child of my parent) */
struct tpl_node *parent; /* my parent */
} tpl_node;
/* used when un/packing 'B' type (binary buffers) */
typedef struct tpl_bin {
void *addr;
uint32_t sz;
} tpl_bin;
/* for async/piecemeal reading of tpl images */
typedef struct tpl_gather_t {
char *img;
int len;
} tpl_gather_t;
/* Callback used when tpl_gather has read a full tpl image */
typedef int (tpl_gather_cb)(void *img, size_t sz, void *data);
/* Prototypes */
TPL_API tpl_node *tpl_map(char *fmt,...); /* define tpl using format */
TPL_API void tpl_free(tpl_node *r); /* free a tpl map */
TPL_API int tpl_pack(tpl_node *r, int i); /* pack the n'th packable */
TPL_API int tpl_unpack(tpl_node *r, int i); /* unpack the n'th packable */
TPL_API int tpl_dump(tpl_node *r, int mode, ...); /* serialize to mem/file */
TPL_API int tpl_load(tpl_node *r, int mode, ...); /* set mem/file to unpack */
TPL_API int tpl_Alen(tpl_node *r, int i); /* array len of packable i */
TPL_API char* tpl_peek(int mode, ...); /* sneak peek at format string */
TPL_API int tpl_gather( int mode, ...); /* non-blocking image gather */
TPL_API int tpl_jot(int mode, ...); /* quick write a simple tpl */
TPL_API tpl_node *tpl_map_va(char *fmt, va_list ap);
#if defined __cplusplus
}
#endif
#endif /* TPL_H */

View File

@ -1,7 +1,19 @@
cmake_minimum_required(VERSION 3.10)
project(crpc)
find_package(antlr4-runtime CONFIG REQUIRED)
find_program(Java_JAVA_EXECUTABLE NAMES java)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(ANTLR4_GIT_REPOSITORY https://code.uocat.com/3party/antlr4.git)
set(ANTLR4_TAG 4.13.1)
include( ExternalAntlr4Cpp )
# find_package(antlr4-runtime CONFIG REQUIRED)
set(ANTLR4CPP_JAR_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/3party/anltr/antlr-4.13.1-complete.jar)
set(ANTLR4CPP_GENERATED_SRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/src/grammar)
antlr4cpp_process_grammar(proto
tqcq
${CMAKE_CURRENT_SOURCE_DIR}/src/grammar/ProtoLexer.g4
${CMAKE_CURRENT_SOURCE_DIR}/src/grammar/ProtoParser.g4
)
set(CMAKE_CXX_STANDARD 17)
@ -21,10 +33,15 @@ add_executable(crpc
src/plugins/c/rpcs/crpc_client.cpp
src/plugins/c/rpcs/crpc.cpp
src/plugins/c/c_service_plugin.cpp
${antlr4cpp_src_files_tqcq}
)
target_link_libraries(crpc PRIVATE antlr4_static)
target_include_directories(crpc PRIVATE /opt/dev/vcpkg/installed/arm64-osx/include/antlr4-runtime)
target_include_directories(crpc PRIVATE src/grammar/ src/)
target_include_directories(crpc PRIVATE
${antlr4cpp_include_dirs_tqcq}
)
target_link_libraries(crpc PRIVATE
antlr4_static
)
FILE(GLOB_RECURSE TEST_SRC_LIST ${CMAKE_CURRENT_BINARY_DIR}/grammar/*.c)
add_executable(test ${TEST_SRC_LIST}
@ -35,4 +52,6 @@ target_include_directories(test PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/3party/tpl
)
add_dependencies(crpc antlr4cpp_generation_tqcq)
INSTALL(TARGETS crpc DESTINATION bin)

View File

@ -0,0 +1,222 @@
cmake_minimum_required(VERSION 3.7)
if(POLICY CMP0114)
cmake_policy(SET CMP0114 NEW)
endif()
include(ExternalProject)
set(ANTLR4_ROOT ${CMAKE_CURRENT_BINARY_DIR}/antlr4_runtime/src/antlr4_runtime)
set(ANTLR4_INCLUDE_DIRS ${ANTLR4_ROOT}/runtime/Cpp/runtime/src)
set(ANTLR4_GIT_REPOSITORY https://github.com/antlr/antlr4.git)
if(NOT DEFINED ANTLR4_TAG)
# Set to branch name to keep library updated at the cost of needing to rebuild after 'clean'
# Set to commit hash to keep the build stable and does not need to rebuild after 'clean'
set(ANTLR4_TAG master)
endif()
# Ensure that the include dir already exists at configure time (to avoid cmake erroring
# on non-existent include dirs)
file(MAKE_DIRECTORY "${ANTLR4_INCLUDE_DIRS}")
if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*")
set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/runtime/$(Configuration))
elseif(${CMAKE_GENERATOR} MATCHES "Xcode.*")
set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/runtime/$(CONFIGURATION))
else()
set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/runtime)
endif()
if(MSVC)
set(ANTLR4_STATIC_LIBRARIES
${ANTLR4_OUTPUT_DIR}/antlr4-runtime-static.lib)
set(ANTLR4_SHARED_LIBRARIES
${ANTLR4_OUTPUT_DIR}/antlr4-runtime.lib)
set(ANTLR4_RUNTIME_LIBRARIES
${ANTLR4_OUTPUT_DIR}/antlr4-runtime.dll)
else()
set(ANTLR4_STATIC_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.a)
if(MINGW)
set(ANTLR4_SHARED_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a)
set(ANTLR4_RUNTIME_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll)
elseif(CYGWIN)
set(ANTLR4_SHARED_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a)
set(ANTLR4_RUNTIME_LIBRARIES
${ANTLR4_OUTPUT_DIR}/cygantlr4-runtime-4.13.1.dll)
elseif(APPLE)
set(ANTLR4_RUNTIME_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dylib)
else()
set(ANTLR4_RUNTIME_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.so)
endif()
endif()
if(${CMAKE_GENERATOR} MATCHES ".* Makefiles")
# This avoids
# 'warning: jobserver unavailable: using -j1. Add '+' to parent make rule.'
set(ANTLR4_BUILD_COMMAND $(MAKE))
elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio.*")
set(ANTLR4_BUILD_COMMAND
${CMAKE_COMMAND}
--build .
--config $(Configuration)
--target)
elseif(${CMAKE_GENERATOR} MATCHES "Xcode.*")
set(ANTLR4_BUILD_COMMAND
${CMAKE_COMMAND}
--build .
--config $(CONFIGURATION)
--target)
else()
set(ANTLR4_BUILD_COMMAND
${CMAKE_COMMAND}
--build .
--target)
endif()
if(NOT DEFINED ANTLR4_WITH_STATIC_CRT)
set(ANTLR4_WITH_STATIC_CRT ON)
endif()
if(ANTLR4_ZIP_REPOSITORY)
ExternalProject_Add(
antlr4_runtime
PREFIX antlr4_runtime
URL ${ANTLR4_ZIP_REPOSITORY}
DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}
BUILD_COMMAND ""
BUILD_IN_SOURCE 1
SOURCE_DIR ${ANTLR4_ROOT}
SOURCE_SUBDIR runtime/Cpp
CMAKE_CACHE_ARGS
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DWITH_STATIC_CRT:BOOL=${ANTLR4_WITH_STATIC_CRT}
-DDISABLE_WARNINGS:BOOL=ON
# -DCMAKE_CXX_STANDARD:STRING=17 # if desired, compile the runtime with a different C++ standard
# -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} # alternatively, compile the runtime with the same C++ standard as the outer project
INSTALL_COMMAND ""
EXCLUDE_FROM_ALL 1)
else()
ExternalProject_Add(
antlr4_runtime
PREFIX antlr4_runtime
GIT_REPOSITORY ${ANTLR4_GIT_REPOSITORY}
GIT_TAG ${ANTLR4_TAG}
GIT_SHALLOW 1
DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}
BUILD_COMMAND ""
BUILD_IN_SOURCE 1
SOURCE_DIR ${ANTLR4_ROOT}
SOURCE_SUBDIR runtime/Cpp
CMAKE_CACHE_ARGS
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DWITH_STATIC_CRT:BOOL=${ANTLR4_WITH_STATIC_CRT}
-DDISABLE_WARNINGS:BOOL=ON
# -DCMAKE_CXX_STANDARD:STRING=17 # if desired, compile the runtime with a different C++ standard
# -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} # alternatively, compile the runtime with the same C++ standard as the outer project
INSTALL_COMMAND ""
EXCLUDE_FROM_ALL 1)
endif()
# Separate build step as rarely people want both
set(ANTLR4_BUILD_DIR ${ANTLR4_ROOT})
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0")
# CMake 3.14 builds in above's SOURCE_SUBDIR when BUILD_IN_SOURCE is true
set(ANTLR4_BUILD_DIR ${ANTLR4_ROOT}/runtime/Cpp)
endif()
ExternalProject_Add_Step(
antlr4_runtime
build_static
COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_static
# Depend on target instead of step (a custom command)
# to avoid running dependent steps concurrently
DEPENDS antlr4_runtime
BYPRODUCTS ${ANTLR4_STATIC_LIBRARIES}
EXCLUDE_FROM_MAIN 1
WORKING_DIRECTORY ${ANTLR4_BUILD_DIR})
ExternalProject_Add_StepTargets(antlr4_runtime build_static)
add_library(antlr4_static STATIC IMPORTED)
add_dependencies(antlr4_static antlr4_runtime-build_static)
set_target_properties(antlr4_static PROPERTIES
IMPORTED_LOCATION ${ANTLR4_STATIC_LIBRARIES})
target_include_directories(antlr4_static
INTERFACE
${ANTLR4_INCLUDE_DIRS}
)
ExternalProject_Add_Step(
antlr4_runtime
build_shared
COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_shared
# Depend on target instead of step (a custom command)
# to avoid running dependent steps concurrently
DEPENDS antlr4_runtime
BYPRODUCTS ${ANTLR4_SHARED_LIBRARIES} ${ANTLR4_RUNTIME_LIBRARIES}
EXCLUDE_FROM_MAIN 1
WORKING_DIRECTORY ${ANTLR4_BUILD_DIR})
ExternalProject_Add_StepTargets(antlr4_runtime build_shared)
add_library(antlr4_shared SHARED IMPORTED)
add_dependencies(antlr4_shared antlr4_runtime-build_shared)
set_target_properties(antlr4_shared PROPERTIES
IMPORTED_LOCATION ${ANTLR4_RUNTIME_LIBRARIES})
target_include_directories(antlr4_shared
INTERFACE
${ANTLR4_INCLUDE_DIRS}
)
if(ANTLR4_SHARED_LIBRARIES)
set_target_properties(antlr4_shared PROPERTIES
IMPORTED_IMPLIB ${ANTLR4_SHARED_LIBRARIES})
endif()
macro(antlr4cpp_process_grammar
antlr4cpp_project
antlr4cpp_project_namespace
antlr4cpp_grammar_lexer
antlr4cpp_grammar_parser)
if(EXISTS "${ANTLR4CPP_JAR_LOCATION}")
message(STATUS "Found antlr tool: ${ANTLR4CPP_JAR_LOCATION}")
else()
message(FATAL_ERROR "Unable to find antlr tool. ANTLR4CPP_JAR_LOCATION:${ANTLR4CPP_JAR_LOCATION}")
endif()
message(STATUS "GENERATED_SRC_DIR: ${ANTLR4CPP_GENERATED_SRC_DIR}")
add_custom_target("antlr4cpp_generation_${antlr4cpp_project_namespace}"
COMMAND
${CMAKE_COMMAND} -E make_directory "${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}"
COMMAND
"${Java_JAVA_EXECUTABLE}" -jar "${ANTLR4CPP_JAR_LOCATION}" -Werror -Dlanguage=Cpp -listener -visitor -o "${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}" -package ${antlr4cpp_project_namespace} "${antlr4cpp_grammar_lexer}" "${antlr4cpp_grammar_parser}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
DEPENDS "${antlr4cpp_grammar_lexer}" "${antlr4cpp_grammar_parser}"
COMMENT "Generating ${antlr4cpp_project_namespace} with antlr4cpp"
)
# message(STATUS "Generate Command: ${Java_JAVA_EXECUTABLE} -jar ${ANTLR4CPP_JAR_LOCATION} -Werror -Dlanguage=Cpp -listener -visitor -o ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace} -package ${antlr4cpp_project_namespace} ${antlr4cpp_grammar_lexer} ${antlr4cpp_grammar_parser}")
# Find all the input files
FILE(GLOB generated_files ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}/*.cpp)
# export generated cpp files into list
foreach(generated_file ${generated_files})
list(APPEND antlr4cpp_src_files_${antlr4cpp_project_namespace} ${generated_file})
set_source_files_properties(
${generated_file}
PROPERTIES
COMPILE_FLAGS -Wno-overloaded-virtual
)
endforeach(generated_file)
message(STATUS "Antlr4Cpp ${antlr4cpp_project_namespace} Generated: ${generated_files}")
# export generated include directory
set(antlr4cpp_include_dirs_${antlr4cpp_project_namespace} ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace})
message(STATUS "Antlr4Cpp ${antlr4cpp_project_namespace} include: ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}")
endmacro()

View File

@ -13,6 +13,8 @@
#include <map>
#include <unistd.h>
using namespace tqcq;
class Listener : public ProtoParserBaseListener {
public:
void enterMessageStatement(ProtoParser::MessageStatementContext *context) override
@ -117,7 +119,8 @@ main(int argc, char *argv[])
tqcq::CServiceServerPlugin service_server_plugin(output_dir);
service_server_plugin.Generate(listener.services);
// tqcq::CServiceClientPlugin service_client_plugin("./gen/");
tqcq::CServiceClientPlugin service_client_plugin(output_dir);
service_client_plugin.Generate(listener.services);
return 0;
}

View File

@ -5,6 +5,10 @@
#include "c_service_client_plugin.h"
#include <utility>
#include <string>
#include <sstream>
#include <fstream>
#include "plugins/c/rpcs/crpc_client.h"
namespace tqcq {
CServiceClientPlugin::CServiceClientPlugin(std::string generate_path, std::string generate_prefix)
@ -14,84 +18,216 @@ CServiceClientPlugin::CServiceClientPlugin(std::string generate_path, std::strin
std::string
CServiceClientPlugin::GenerateHeaderFileName(std::string service_id)
{
return std::string();
std::stringstream ss;
ss << service_id << "_Client.h";
return ss.str();
}
std::string
CServiceClientPlugin::GenerateSourceFileName(std::string service_id)
{
return std::string();
}
void
CServiceClientPlugin::GenerateHeader(Service::Ptr service)
{
CServicePlugin::GenerateHeader(service);
}
void
CServiceClientPlugin::GenerateSource(Service::Ptr service)
{
CServicePlugin::GenerateSource(service);
std::stringstream ss;
ss << service_id << "_Client.c";
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderIncludeFiles(Service::Ptr service)
{
return std::string();
}
std::stringstream ss;
ss << "#include <stdint.h>" << std::endl;
ss << "#include <string.h>" << std::endl;
ss << "#include <stdlib.h>" << std::endl;
std::set<std::string> message_set;
for (const auto &rpc : service->rpcs()) {
auto crpc = CRPCClient::Create(rpc);
message_set.insert(crpc->request_id());
message_set.insert(crpc->response_id());
}
for (const auto &message_id : message_set) { ss << "#include \"" << message_id << ".h\"" << std::endl; }
ss << std::endl;
std::string
CServiceClientPlugin::GenerateHeaderStructStart(Service::Ptr service)
{
return std::string();
}
std::string
CServiceClientPlugin::GenerateHeaderStructItems(Service::Ptr service)
{
return std::string();
}
std::string
CServiceClientPlugin::GenerateHeaderStructEnd(Service::Ptr service)
{
return std::string();
ss << "#ifdef __cplusplus" << std::endl;
ss << "extern \"C\" {" << std::endl;
ss << "#endif" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderStructAPIStart(Service::Ptr service)
{
return std::string();
std::stringstream ss;
for (const auto &rpc : service->rpcs()) {
auto crpc = CRPCClient::Create(rpc);
ss << crpc->GenerateAsyncCallback(service->id()) << std::endl;
}
ss << std::endl;
ss << "typedef struct _" << service->id() << "_Client " << service->id() << "_Client;" << std::endl;
ss << std::endl;
//
// ss << "typedef struct "
// << "{" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderStructAPIItems(Service::Ptr service)
{
return std::string();
std::stringstream ss;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderStructAPIEnd(Service::Ptr service)
{
return std::string();
std::stringstream ss;
// ss << "} " << service->id() << "_Client_API"
// << ";" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderStructStart(Service::Ptr service)
{
std::stringstream ss;
ss << "struct _" << service->id() << "_Client {" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderStructItems(Service::Ptr service)
{
std::stringstream ss;
for (const auto &rpc : service->rpcs()) {
auto crpc = CRPCClient::Create(rpc);
ss << crpc->GenerateStructDeclareCodeBlock(service->id());
}
ss << std::endl;
for (const auto &rpc : service->rpcs()) {
auto crpc = CRPCClient::Create(rpc);
ss << crpc->GenerateStructAPIDeclareAsyncCodeBlock(service->id());
}
ss << std::endl;
ss << " void* impl;" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderStructEnd(Service::Ptr service)
{
std::stringstream ss;
ss << "}; " << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateHeaderFunctionDeclaration(Service::Ptr service)
{
return std::string();
std::stringstream ss;
ss << "int32_t " << service->id() << "_Client_Init(" << service->id() << "_Client* client);" << std::endl;
ss << "int32_t " << service->id() << "_Client_Connect(" << service->id() << "_Client* client, const char* format, ...);" << std::endl;
// ss << "int32_t " << service->id() << "_Client_Send(" << service->id() << "_Client* client, const char* msg, int32_t msg_len);" << std::endl;
ss << "void " << service->id() << "_Client_Destroy(" << service->id() << "_Client* client);" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateSourceIncludeFiles(Service::Ptr service)
{
return std::string();
std::stringstream ss;
ss << "#include <assert.h>" << std::endl;
ss << "#include <stdint.h>" << std::endl;
ss << "#include <stdarg.h>" << std::endl;
ss << "#include <stdio.h>" << std::endl;
ss << "#include <crpc/service.h>" << std::endl;
ss << "#include \"" << GenerateHeaderFileName(service->id()) << "\"" << std::endl;
std::set<std::string> message_set;
for (const auto &rpc : service->rpcs()) {
auto crpc = CRPCClient::Create(rpc);
message_set.insert(crpc->request_id());
message_set.insert(crpc->response_id());
}
for (const auto &message_id : message_set) { ss << "#include \"" << message_id << ".h\"" << std::endl; }
return ss.str();
}
std::string
CServiceClientPlugin::GenerateSourceFunctionDefinition(Service::Ptr service)
{
std::stringstream ss;
for (const auto &rpc : service->rpcs()) {
auto crpc = CRPCClient::Create(rpc);
ss << crpc->GenerateStructAPIWrapper(service->id());
ss << std::endl;
}
ss << std::endl;
ss << GenerateSourceInitFunctionDefinition(service) << std::endl;
ss << GenerateSourceConnectFunctionDefinition(service) << std::endl;
ss << GenerateSourceDestroyFunctionDefinition(service) << std::endl;
ss << GenerateSourceSendFunctionDefinition(service) << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateSourceInitFunctionDefinition(Service::Ptr service)
{
std::stringstream ss;
ss << "int32_t " << service->id() << "_Client_Init(" << service->id() << "_Client* client, " << service->id()
<< "_Client_API* api)" << std::endl;
ss << "{" << std::endl;
ss << " assert(client != NULL);" << std::endl;
ss << " client->impl = Service_New();" << std::endl;
ss << " if (api) {" << std::endl;
ss << " memcpy(&client->api, api, sizeof(" << service->id() << "_Client_API));" << std::endl;
ss << " } else {" << std::endl;
ss << " memset(&client->api, 0, sizeof(" << service->id() << "_Client_API));" << std::endl;
ss << " }" << std::endl;
ss << " if (client->impl == NULL) { return -1; }" << std::endl;
ss << " return 0;" << std::endl;
ss << "}" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateSourceDestroyFunctionDefinition(Service::Ptr service)
{
std::stringstream ss;
ss << "void " << service->id() << "_Client_Destroy(" << service->id() << "_Client* client)" << std::endl;
ss << "{" << std::endl;
ss << " if (client == NULL) { return; }" << std::endl;
ss << " if (client->impl != NULL) { Service_Free(client->impl); }" << std::endl;
ss << "}" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateSourceSendFunctionDefinition(Service::Ptr service)
{
std::stringstream ss;
ss << "int32_t " << service->id() << "_Client_Send(" << service->id() << "_Client* client, const char* msg, int32_t msg_len)" << std::endl;
ss << "{" << std::endl;
ss << " assert(client != NULL);" << std::endl;
ss << " assert(client->impl != NULL);" << std::endl;
ss << " assert(msg != NULL || msg_len == 0);" << std::endl;
ss << " assert(msg_len > 0);" << std::endl;
ss << std::endl;
ss << " return Service_Send(client->impl, msg, msg_len);" << std::endl;
ss << "}" << std::endl;
return ss.str();
}
std::string
CServiceClientPlugin::GenerateSourceConnectFunctionDefinition(Service::Ptr service)
{
return std::string();
}
}// namespace tqcq

View File

@ -16,18 +16,26 @@ public:
protected:
std::string GenerateHeaderFileName(std::string service_id) override;
std::string GenerateSourceFileName(std::string service_id) override;
void GenerateHeader(Service::Ptr service) override;
void GenerateSource(Service::Ptr service) override;
std::string GenerateHeaderIncludeFiles(Service::Ptr service) override;
std::string GenerateHeaderStructStart(Service::Ptr service) override;
std::string GenerateHeaderStructItems(Service::Ptr service) override;
std::string GenerateHeaderStructEnd(Service::Ptr service) override;
std::string GenerateHeaderStructAPIStart(Service::Ptr service) override;
std::string GenerateHeaderStructAPIItems(Service::Ptr service) override;
std::string GenerateHeaderStructAPIEnd(Service::Ptr service) override;
std::string GenerateHeaderStructStart(Service::Ptr service) override;
std::string GenerateHeaderStructItems(Service::Ptr service) override;
std::string GenerateHeaderStructEnd(Service::Ptr service) override;
std::string GenerateHeaderFunctionDeclaration(Service::Ptr service) override;
std::string GenerateSourceIncludeFiles(Service::Ptr service) override;
std::string GenerateSourceFunctionDefinition(Service::Ptr service) override;
std::string GenerateSourceInitFunctionDefinition(Service::Ptr service);
std::string GenerateSourceConnectFunctionDefinition(Service::Ptr service);
std::string GenerateSourceDestroyFunctionDefinition(Service::Ptr service);
std::string GenerateSourceSendFunctionDefinition(Service::Ptr service);
};
}// namespace tqcq

View File

@ -5,6 +5,7 @@
#include "c_service_plugin.h"
#include <sstream>
#include <fstream>
#include <iostream>
namespace tqcq {
@ -32,6 +33,7 @@ CServicePlugin::GenerateHeader(Service::Ptr service)
ss << GenerateHeaderIncludeFiles(service);
ss << std::endl;
ss << GenerateHeaderStructAPIStart(service);
ss << GenerateHeaderStructAPIItems(service);
ss << GenerateHeaderStructAPIEnd(service);
@ -46,7 +48,9 @@ CServicePlugin::GenerateHeader(Service::Ptr service)
ss << std::endl;
ss << GenerateHeaderGuardEnd(service);
std::ofstream ofs(generate_path() + "/" + GenerateHeaderFileName(service->id()));
std::filesystem::path path(generate_path());
std::filesystem::path filename(GenerateHeaderFileName(service->id()));
std::ofstream ofs(path / filename);
ofs << ss.str();
}
@ -58,8 +62,12 @@ CServicePlugin::GenerateSource(Service::Ptr service)
ss << std::endl;
ss << GenerateSourceFunctionDefinition(service);
std::ofstream ofs(generate_path() + "/" + GenerateSourceFileName(service->id()));
std::filesystem::path path(generate_path());
std::filesystem::path filename(GenerateSourceFileName(service->id()));
std::ofstream ofs(path / filename);
ofs << ss.str();
std::cout << ss.str() << std::endl;
std::cout << path / filename << std::endl;
}
std::string
@ -76,6 +84,10 @@ std::string
CServicePlugin::GenerateHeaderGuardEnd(Service::Ptr service)
{
std::stringstream ss;
ss << "#ifdef __cplusplus" << std::endl;
ss << "}" << std::endl;
ss << "#endif // __cplusplus" << std::endl;
auto guard_macro = GenerateGuardMacro(service->id(), generate_prefix());
ss << "#endif // " << guard_macro << std::endl;
return ss.str();

View File

@ -20,8 +20,8 @@ protected:
virtual std::string GenerateHeaderFileName(std::string service_id) = 0;
virtual std::string GenerateSourceFileName(std::string service_id) = 0;
virtual void GenerateHeader(Service::Ptr service) override;
virtual void GenerateSource(Service::Ptr service) override;
void GenerateHeader(Service::Ptr service) override;
void GenerateSource(Service::Ptr service) override;
virtual std::string GenerateHeaderGuardStart(Service::Ptr service);
virtual std::string GenerateHeaderIncludeFiles(Service::Ptr service) = 0;

View File

@ -58,7 +58,7 @@ std::string
CServiceServerPlugin::GenerateHeaderStructAPIEnd(Service::Ptr service)
{
std::stringstream ss;
ss << "} " << service->id() << "_API"
ss << "} " << service->id() << "_Server_API"
<< ";" << std::endl;
return ss.str();
}
@ -93,7 +93,7 @@ CServiceServerPlugin::GenerateHeaderStructItems(Service::Ptr service)
{
std::stringstream ss;
ss << " void* impl;" << std::endl;
ss << " DeviceService_API api;" << std::endl;
ss << " DeviceService_Server_API api;" << std::endl;
return ss.str();
}
@ -111,10 +111,11 @@ CServiceServerPlugin::GenerateHeaderFunctionDeclaration(Service::Ptr service)
{
std::stringstream ss;
ss << "int32_t " << service->id() << "_Server_Init(" << service->id() << "_Server* server, " << service->id()
<< "_API* api);" << std::endl;
<< "_Server_API* api);" << std::endl;
ss << "int32_t " << service->id() << "_Server_Bind(" << service->id() << "_Server* server, const char* format, ...);"
<< std::endl;
ss << "int32_t " << service->id() << "_Server_Listen(" << service->id() << "_Server* server);" << std::endl;
ss << "int32_t " << service->id() << "_Server_Send(" << service->id() << "_Server* server, const char* msg, int32_t msg_len);" << std::endl;
ss << "void " << service->id() << "_Server_Destroy(" << service->id() << "_Server* server);" << std::endl;
return ss.str();
}
@ -124,6 +125,7 @@ CServiceServerPlugin::GenerateSourceIncludeFiles(Service::Ptr service)
{
std::stringstream ss;
ss << "#include <assert.h>" << std::endl;
ss << "#include <stdint.h>" << std::endl;
ss << "#include <stdarg.h>" << std::endl;
ss << "#include <stdio.h>" << std::endl;
ss << "#include <crpc/service.h>" << std::endl;
@ -155,6 +157,7 @@ CServiceServerPlugin::GenerateSourceFunctionDefinition(Service::Ptr service)
ss << GenerateSourceBindFunctionDefinition(service) << std::endl;
ss << GenerateSourceListenFunctionDefinition(service) << std::endl;
ss << GenerateSourceDestroyFunctionDefinition(service) << std::endl;
ss << GenerateSourceSendFunctionDefinition(service) << std::endl;
return ss.str();
}
@ -163,14 +166,14 @@ CServiceServerPlugin::GenerateSourceInitFunctionDefinition(Service::Ptr service)
{
std::stringstream ss;
ss << "int32_t " << service->id() << "_Server_Init(" << service->id() << "_Server* server, " << service->id()
<< "_API* api)" << std::endl;
<< "_Server_API* api)" << std::endl;
ss << "{" << std::endl;
ss << " assert(server != NULL);" << std::endl;
ss << " server->impl = Service_New();" << std::endl;
ss << " if (api) {" << std::endl;
ss << " memcpy(&server->api, api, sizeof(" << service->id() << "_API));" << std::endl;
ss << " memcpy(&server->api, api, sizeof(" << service->id() << "_Server_API));" << std::endl;
ss << " } else {" << std::endl;
ss << " memset(&server->api, 0, sizeof(" << service->id() << "_API));" << std::endl;
ss << " memset(&server->api, 0, sizeof(" << service->id() << "_Server_API));" << std::endl;
ss << " }" << std::endl;
ss << " if (server->impl == NULL) { return -1; }" << std::endl;
ss << " return 0;" << std::endl;
@ -226,4 +229,20 @@ CServiceServerPlugin::GenerateSourceDestroyFunctionDefinition(Service::Ptr servi
return ss.str();
}
std::string
CServiceServerPlugin::GenerateSourceSendFunctionDefinition(Service::Ptr service)
{
std::stringstream ss;
ss << "int32_t " << service->id() << "_Server_Send(" << service->id() << "_Server* server, const char* msg, int32_t msg_len)" << std::endl;
ss << "{" << std::endl;
ss << " assert(server != NULL);" << std::endl;
ss << " assert(server->impl != NULL);" << std::endl;
ss << " assert(msg != NULL || msg_len == 0);" << std::endl;
ss << " assert(msg_len > 0);" << std::endl;
ss << std::endl;
ss << " return Service_Send(server->impl, msg, msg_len);" << std::endl;
ss << "}" << std::endl;
return ss.str();
}
}// namespace tqcq

View File

@ -36,6 +36,7 @@ protected:
std::string GenerateSourceBindFunctionDefinition(Service::Ptr service);
std::string GenerateSourceListenFunctionDefinition(Service::Ptr service);
std::string GenerateSourceDestroyFunctionDefinition(Service::Ptr service);
std::string GenerateSourceSendFunctionDefinition(Service::Ptr service);
};
}// namespace tqcq

View File

@ -4,4 +4,102 @@
#include "crpc_client.h"
namespace tqcq {}// namespace tqcq
namespace tqcq {
CRPCClient::Ptr
CRPCClient::Create(RPC::Ptr rpc)
{
return std::make_shared<CRPCClient>(rpc);
}
CRPCClient::CRPCClient(RPC::Ptr rpc) : CRPC(std::move(rpc)) {}
std::string
CRPCClient::GenerateStructAPIWrapper(std::string service_id) const
{
std::stringstream ss;
ss << "int32_t " << id() << "_Wrapper(" << service_id << "_Client *client, char *msg, int32_t msg_len)"
<< std::endl;
ss << "{" << std::endl;
ss << " assert(client != NULL);" << std::endl;
ss << " assert(msg != NULL || msg_len == 0);" << std::endl;
ss << " if (client->api." << id() << " == NULL) { return 0; }" << std::endl;
ss << std::endl;
ss << " int32_t status = 0;" << std::endl;
ss << " " << request_id() << " request;" << std::endl;
ss << " " << response_id() << " response;" << std::endl;
ss << std::endl;
ss << " do {" << std::endl;
ss << " " << request_id() << "_Init(&request);" << std::endl;
ss << " status = " << request_id() << "_Deserialize(&request, msg, msg_len);" << std::endl;
ss << " if (status != 0) {" << std::endl;
ss << " " << request_id() << "_Destroy(&request);" << std::endl;
ss << " break;" << std::endl;
ss << " }" << std::endl;
ss << std::endl;
ss << " " << response_id() << "_Init(&response);" << std::endl;
ss << " " << response_id() << "_set_code(&response, 200);" << std::endl;
ss << " " << response_id() << "_set_msg_string(&response, \"OK\");" << std::endl;
ss << " status = client->api." << id() << "(&request, &response);" << std::endl;
ss << " if (status != 0) {" << std::endl;
ss << " printf(\"" << id() << " failed: %d\\n\", status);" << std::endl;
ss << " " << response_id() << "_set_code(&response, 500);" << std::endl;
ss << " " << response_id() << "_set_msg_string(&response, \"Internal Client Error\");" << std::endl;
ss << " }" << std::endl;
ss << std::endl;
ss << " char* response_msg = NULL;" << std::endl;
ss << " int32_t response_msg_len = 0;" << std::endl;
ss << " status = " << response_id() << "_Serialize(&response, &response_msg, &response_msg_len);"
<< std::endl;
ss << " if (status < 0) {" << std::endl;
ss << " printf(\"" << id() << " failed: %d\\n\", status);" << std::endl;
ss << " " << response_id() << "_set_code(&response, 500);" << std::endl;
ss << " " << response_id() << "_set_msg_string(&response, \"Internal Client Error\");" << std::endl;
ss << " }" << std::endl;
ss << std::endl;
ss << " int32_t send_result = DeviceService_Client_Send(client, response_msg, response_msg_len);"
<< std::endl;
ss << " if (send_result < 0) {" << std::endl;
ss << " printf(\"" << id() << " failed: %d\\n\", status);" << std::endl;
ss << " break;" << std::endl;
ss << " }" << std::endl;
ss << " status = 0;" << std::endl;
ss << " } while (0);" << std::endl;
ss << " " << response_id() << "_Destroy(&response);" << std::endl;
ss << " " << request_id() << "_Destroy(&request);" << std::endl;
ss << " return status;" << std::endl;
ss << "}" << std::endl;
return ss.str();
}
std::string
CRPCClient::GenerateStructDeclareCodeBlock(std::string service_id) const
{
std::stringstream ss;
ss << " int32_t (*" << id() << ")("<< service_id << "_Client* client, const " << request_id() << " *request, " << response_id() << " **response);" << std::endl;
return ss.str();
}
std::string
CRPCClient::GenerateStructAPIDeclareCodeBlock(std::string service_id) const
{
return "";
}
std::string
CRPCClient::GenerateStructAPIDeclareAsyncCodeBlock(std::string service_id) const
{
std::stringstream ss;
ss << " int32_t (*" << id() << "_Async)(" << service_id << "_Client *client, const " << request_id() << " *request, " << service_id << "_" << id() << "_Callback callback);" << std::endl;
return ss.str();
}
std::string
CRPCClient::GenerateAsyncCallback(std::string service_id) const
{
std::stringstream ss;
ss << "typedef void (*" << service_id << "_" << id() << "_Callback)(const " << request_id() << " *request, const " << response_id() << " *response);";
return ss.str();
}
}// namespace tqcq

View File

@ -11,8 +11,17 @@ namespace tqcq {
class CRPCClient : public CRPC {
public:
CRPCClient() = default;
using Ptr = std::shared_ptr<CRPCClient>;
static Ptr Create(RPC::Ptr rpc);
CRPCClient(RPC::Ptr rpc);
~CRPCClient() override = default;
std::string GenerateStructAPIWrapper(std::string service_id) const override;
std::string GenerateStructDeclareCodeBlock(std::string service_id) const override;
std::string GenerateStructAPIDeclareCodeBlock(std::string service_id) const override;
std::string GenerateStructAPIDeclareAsyncCodeBlock(std::string service_id) const ;
std::string GenerateAsyncCallback(std::string service_id) const;
};
}// namespace tqcq

View File

@ -32,7 +32,8 @@ std::string
CRPCServer::GenerateStructAPIWrapper(std::string service_id) const
{
std::stringstream ss;
ss << "int32_t " << id() << "_Wrapper(" << service_id << "_Server *server, char *msg, int32_t msg_len)" << std::endl;
ss << "int32_t " << id() << "_Wrapper(" << service_id << "_Server *server, char *msg, int32_t msg_len)"
<< std::endl;
ss << "{" << std::endl;
ss << " assert(server != NULL);" << std::endl;
ss << " assert(msg != NULL || msg_len == 0);" << std::endl;
@ -61,6 +62,23 @@ CRPCServer::GenerateStructAPIWrapper(std::string service_id) const
ss << " " << response_id() << "_set_msg_string(&response, \"Internal Server Error\");" << std::endl;
ss << " }" << std::endl;
ss << std::endl;
ss << " char* response_msg = NULL;" << std::endl;
ss << " int32_t response_msg_len = 0;" << std::endl;
ss << " status = " << response_id() << "_Serialize(&response, &response_msg, &response_msg_len);"
<< std::endl;
ss << " if (status < 0) {" << std::endl;
ss << " printf(\"" << id() << " failed: %d\\n\", status);" << std::endl;
ss << " " << response_id() << "_set_code(&response, 500);" << std::endl;
ss << " " << response_id() << "_set_msg_string(&response, \"Internal Server Error\");" << std::endl;
ss << " }" << std::endl;
ss << std::endl;
ss << " int32_t send_result = DeviceService_Server_Send(server, response_msg, response_msg_len);"
<< std::endl;
ss << " if (send_result < 0) {" << std::endl;
ss << " printf(\"" << id() << " failed: %d\\n\", status);" << std::endl;
ss << " break;" << std::endl;
ss << " }" << std::endl;
ss << " status = 0;" << std::endl;
ss << " } while (0);" << std::endl;
ss << " " << response_id() << "_Destroy(&response);" << std::endl;
ss << " " << request_id() << "_Destroy(&request);" << std::endl;