diff --git a/.travis.yml b/.travis.yml index 568485564d..677a3c5a40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -177,9 +177,6 @@ windows1809_vs2017: &windows1809_vs2017 else eval "export GENERATOR='Visual Studio 15 2017'" fi - - JAVA_HOME=$(find "/c/Program Files/Android/jdk/" -name "*openjdk*" | sort | head -n 1) - - export JAVA_HOME - - export PATH="${PATH}:${JAVA_HOME}/bin" # Windows targets in Travis are still very much in beta and Python is not yet # available and installation of Python through Chocolaty does not work well. # The real fix is to wait until Python and pip are both available on the @@ -187,7 +184,6 @@ windows1809_vs2017: &windows1809_vs2017 # the extracted folder to the path. install: - choco install innoextract - - choco install maven --ignore-dependencies - choco install winflexbison3 - wget -q https://dl.bintray.com/conan/installers/conan-win-64_1_34_0.exe - innoextract conan-win-64_1_34_0.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index c4c2f77911..41ae750526 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,14 +49,7 @@ string(REPLACE " " "-" PROJECT_NAME_DASHED "${PROJECT_NAME_FULL}") string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_CAPS) string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_SMALL) -# By default the Java-based components get built, but make it possible to disable that: if only the -# core library is required, there's no need to build them, and that in turn eliminates the Maven and -# JDK dependency. option(BUILD_IDLC "Build IDL preprocessor" ON) -if(BUILD_IDLC STREQUAL "AUTO") - find_package(Maven 3.0 QUIET) - set(BUILD_IDLC ${Maven_FOUND}) -endif() set(CMAKE_C_STANDARD 99) if(CMAKE_SYSTEM_NAME STREQUAL "VxWorks") diff --git a/README.md b/README.md index 00d405db0c..50bdeca99d 100644 --- a/README.md +++ b/README.md @@ -25,19 +25,11 @@ In order to build Cyclone DDS you need a Linux, Mac or Windows 10 machine (or, w * [OpenSSL](https://www.openssl.org/), preferably version 1.1 or later if you want to use TLS over TCP. You can explicitly disable it by setting ``ENABLE_SSL=NO``, which is very useful for reducing the footprint or when the FindOpenSSL CMake script gives you trouble; - * Java JDK, version 8 or later, e.g., [OpenJDK](https://jdk.java.net/); - * [Apache Maven](https://maven.apache.org/download.cgi), version 3.5 or later. - -On Ubuntu ``apt install maven default-jdk`` should do the trick for getting Java and Maven -installed, and the rest should already be there. On Windows, installing chocolatey and ``choco -install git cmake openjdk maven`` should get you a long way. On macOS, ``brew install maven cmake`` -and downloading and installing the JDK is easiest. - -The only Java-based component is the IDL preprocessor. The run-time -libraries are pure C code, so there is no need to have Java available on "target" -machines. If desired, it is possible to do a build without Java or Maven installed by -defining ``BUILD_IDLC=NO``, but that effectively only gets you the core library. For the -current [ROS 2 RMW layer](https://github.com/ros2/rmw_cyclonedds), that is sufficient. + * [Bison](https://www.gnu.org/software/bison/) parser generator. + +On Ubuntu ``apt install bison`` should do the trick for getting Bison installed, and the rest should +already be there. On Windows, installing chocolatey and ``choco install winflexbison3`` should get +you a long way. On macOS, ``brew install bison`` is easiest. To obtain Eclipse Cyclone DDS, do diff --git a/cmake/Modules/FindMaven.cmake b/cmake/Modules/FindMaven.cmake deleted file mode 100644 index 02d2dbd356..0000000000 --- a/cmake/Modules/FindMaven.cmake +++ /dev/null @@ -1,83 +0,0 @@ -# -# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License v. 2.0 which is available at -# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -# v. 1.0 which is available at -# http://www.eclipse.org/org/documents/edl-v10.php. -# -# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause -# -if(DEFINED ENV{M2}) - list(APPEND _mvn_hints "$ENV{M2}") -endif() - -if(DEFINED ENV{M2_HOME}) - list(APPEND _mvn_hints "$ENV{M2_HOME}/bin") -endif() - -# Chocolatey installs packages under C:\ProgramData\chocolatey. -if(NOT "$ENV{ProgramData}" STREQUAL "") - if(IS_DIRECTORY "$ENV{ProgramData}/chocolatey/bin") - list(APPEND _mvn_paths "$ENV{ProgramData}/chocolatey/bin") - endif() - if(IS_DIRECTORY "$ENV{ProgramData}/chocolatey/bin") - list(APPEND _dirs "$ENV{ProgramData}/chocolatey/lib/maven") - endif() -endif() - -# Maven documentation mentions intalling maven under C:\Program Files on -# Windows and under /opt on *NIX platforms. -if(WIN32) - foreach(_env "ProgramFiles" "ProgramFiles(x86)") - if(ENV{${_env}} AND IS_DIRECTORY "$ENV{${_env}}") - list(APPEND _dirs "$ENV{${_env}}") - endif() - endforeach() -else() - list(APPEND _dirs "/opt") -endif() - -foreach(_dir ${_dirs}) - file(GLOB _mvn_dirs "${_dir}/apache-maven-*") - foreach(_mvn_dir ${_mvn_dirs}) - if((IS_DIRECTORY "${_mvn_dir}") AND (IS_DIRECTORY "${_mvn_dir}/bin")) - list(APPEND _mvn_paths "${_mvn_dir}/bin") - endif() - endforeach() -endforeach() - -if(WIN32) - set(_mvn_names "mvn.cmd" "mvn.exe") -else() - set(_mvn_names "mvn") -endif() - -find_program(Maven_EXECUTABLE - NAMES ${_mvn_names} - HINTS ${_mvn_hints} - PATHS ${_mvn_paths}) - -if(Maven_EXECUTABLE) - execute_process(COMMAND ${Maven_EXECUTABLE} -version - RESULT_VARIABLE res - OUTPUT_VARIABLE var - ERROR_VARIABLE var - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_STRIP_TRAILING_WHITESPACE) - if(NOT res) - if(var MATCHES "Apache Maven ([0-9]+)\\.([0-9]+)\\.([0-9]+)") - set(Maven_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") - endif() - endif() -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Maven - FOUND_VAR Maven_FOUND - VERSION_VAR Maven_VERSION - REQUIRED_VARS Maven_EXECUTABLE Maven_VERSION) - -mark_as_advanced(Maven_FOUND Maven_EXECUTABLE Maven_VERSION) - diff --git a/cmake/Modules/ListJoin.cmake b/cmake/Modules/ListJoin.cmake deleted file mode 100644 index cc2f336aae..0000000000 --- a/cmake/Modules/ListJoin.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright(c) 2019 Jeroen Koekkoek -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License v. 2.0 which is available at -# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -# v. 1.0 which is available at -# http://www.eclipse.org/org/documents/edl-v10.php. -# -# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause -# - -if(__LIST_JOIN__) - return() -endif() -set(__LIST_JOIN__ TRUE) - -# list(JOIN ...) was added in CMake 3.12 (3.7 is currently required) -function(LIST_JOIN _list _glue _var) - set(_str "") - list(LENGTH ${_list} _len) - - if(_len GREATER 0) - set(_cnt 0) - math(EXPR _max ${_len}-1) - list(GET ${_list} 0 _str) - if(_len GREATER 1) - foreach(_cnt RANGE 1 ${_max}) - list(GET ${_list} ${_cnt} _elm) - set(_str "${_str}${_glue}${_elm}") - endforeach() - endif() - endif() - - set(${_var} "${_str}" PARENT_SCOPE) -endfunction() - diff --git a/cmake/Modules/Packaging/PackageConfig.cmake.in b/cmake/Modules/Packaging/PackageConfig.cmake.in index 31d8f9b7f2..17e5d89a78 100644 --- a/cmake/Modules/Packaging/PackageConfig.cmake.in +++ b/cmake/Modules/Packaging/PackageConfig.cmake.in @@ -16,7 +16,7 @@ option("@PROJECT_NAME@_IDLC_ALWAYS" "Should we include idlc even if the user did set("@PROJECT_NAME@_idlc_FOUND" FALSE) if ("idlc" IN_LIST "@PROJECT_NAME@_FIND_COMPONENTS" OR "@PROJECT_NAME@_IDLC_ALWAYS") - include("${CMAKE_CURRENT_LIST_DIR}/idlc/IdlcGenerate.cmake" OPTIONAL RESULT_VARIABLE _IdlcGenerate) + include("${CMAKE_CURRENT_LIST_DIR}/idlc/Generate.cmake" OPTIONAL RESULT_VARIABLE _IdlcGenerate) if(NOT _IdlcGenerate STREQUAL "NOTFOUND") set("@PROJECT_NAME@_idlc_FOUND" TRUE) endif() diff --git a/docs/dev/debugging.md b/docs/dev/debugging.md index a4ef6a5758..c1b0bf160a 100644 --- a/docs/dev/debugging.md +++ b/docs/dev/debugging.md @@ -44,7 +44,7 @@ $ add-apt-repository ppa:ubuntu-toolchain-r/test $ echo "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main" >> /etc/apt/sources.list.d/llvm-toolchain-6.0.list $ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - $ apt-get update -$ apt-get install gcc-8 g++-8 clang-6.0 oracle-java8-set-default maven +$ apt-get install gcc-8 g++-8 clang-6.0 bison ``` 4. Switch to the *travis* user. diff --git a/examples/helloworld/CMakeLists.export b/examples/helloworld/CMakeLists.export index 9ac2859035..c7107dcd4c 100644 --- a/examples/helloworld/CMakeLists.export +++ b/examples/helloworld/CMakeLists.export @@ -9,7 +9,7 @@ find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_D # that will supply a library target related the the given idl file. # In short, it takes the idl file, generates the source files with # the proper data types and compiles them into a library. -idlc_generate(HelloWorldData_lib "HelloWorldData.idl") +idlc_generate(TARGET HelloWorldData_lib FILES "HelloWorldData.idl") # Both executables have only one related source file. add_executable(HelloworldPublisher publisher.c) diff --git a/examples/helloworld/CMakeLists.txt b/examples/helloworld/CMakeLists.txt index b34e174ee3..186860228f 100644 --- a/examples/helloworld/CMakeLists.txt +++ b/examples/helloworld/CMakeLists.txt @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -idlc_generate(HelloWorldData_lib "HelloWorldData.idl") +idlc_generate(TARGET HelloWorldData_lib FILES "HelloWorldData.idl") add_executable(HelloworldPublisher publisher.c) add_executable(HelloworldSubscriber subscriber.c) diff --git a/examples/roundtrip/CMakeLists.export b/examples/roundtrip/CMakeLists.export index 11be9e6332..9d795c3d9c 100644 --- a/examples/roundtrip/CMakeLists.export +++ b/examples/roundtrip/CMakeLists.export @@ -20,7 +20,7 @@ find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_D # that will supply a library target related the the given idl file. # In short, it takes the idl file, generates the source files with # the proper data types and compiles them into a library. -idlc_generate(RoundTrip_lib RoundTrip.idl) +idlc_generate(TARGET RoundTrip_lib FILES RoundTrip.idl) # Both executables have only one related source file. add_executable(RoundtripPing ping.c) diff --git a/examples/roundtrip/CMakeLists.txt b/examples/roundtrip/CMakeLists.txt index 9afe648fb0..8ae656ea6d 100644 --- a/examples/roundtrip/CMakeLists.txt +++ b/examples/roundtrip/CMakeLists.txt @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -idlc_generate(RoundTrip_lib RoundTrip.idl) +idlc_generate(TARGET RoundTrip_lib FILES RoundTrip.idl) add_executable(RoundtripPing ping.c) add_executable(RoundtripPong pong.c) diff --git a/examples/throughput/CMakeLists.txt b/examples/throughput/CMakeLists.txt index 1c917fc95d..c3689e29ba 100644 --- a/examples/throughput/CMakeLists.txt +++ b/examples/throughput/CMakeLists.txt @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -idlc_generate(Throughput_lib Throughput.idl) +idlc_generate(TARGET Throughput_lib FILES Throughput.idl) add_executable(ThroughputPublisher publisher.c) add_executable(ThroughputSubscriber subscriber.c) diff --git a/scripts/docker/Dockerfile b/scripts/docker/Dockerfile index c933f06cd7..6a49b7da4f 100644 --- a/scripts/docker/Dockerfile +++ b/scripts/docker/Dockerfile @@ -13,7 +13,6 @@ FROM ubuntu:bionic # Dependencies required to build cyclonedds RUN apt update && apt install -y \ cmake \ - default-jdk \ - maven \ + bison \ g++ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 656db83aa6..f788c2c3ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,14 +82,8 @@ endif() configure_file(features.h.in "${CMAKE_CURRENT_BINARY_DIR}/core/include/dds/features.h") +add_subdirectory(tools) add_subdirectory(ddsrt) - -# some of the tests in the core rely on preprocessing IDL, so idlc has to -# come first -if(BUILD_IDLC) - add_subdirectory(idlc) -endif() +add_subdirectory(idl) add_subdirectory(security) add_subdirectory(core) -add_subdirectory(tools) -add_subdirectory(ddsts) diff --git a/src/core/ddsc/CMakeLists.txt b/src/core/ddsc/CMakeLists.txt index 234daa32e5..f94e07f1cc 100644 --- a/src/core/ddsc/CMakeLists.txt +++ b/src/core/ddsc/CMakeLists.txt @@ -53,6 +53,7 @@ PREPEND(hdrs_public_ddsc "$ #include "dds/export.h" #include "dds/ddsc/dds_public_alloc.h" +#include "dds/ddsc/dds_opcodes.h" #if defined (__cplusplus) extern "C" { @@ -66,13 +67,6 @@ typedef struct dds_topic_descriptor } dds_topic_descriptor_t; -/* Topic descriptor flag values */ - -#define DDS_TOPIC_NO_OPTIMIZE 0x0001 -#define DDS_TOPIC_FIXED_KEY 0x0002 -#define DDS_TOPIC_CONTAINS_UNION 0x0004 -#define DDS_TOPIC_DISABLE_TYPECHECK 0x0008 - /* Masks for read condition, read, take: there is only one mask here, which combines the sample, view and instance states. @@ -119,120 +113,6 @@ typedef enum dds_entity_kind typedef uint64_t dds_instance_handle_t; typedef uint32_t dds_domainid_t; - -/* Topic encoding instruction types */ - -enum dds_stream_opcode { - /* return from subroutine, exits top-level - [RTS, 0, 0, 0] */ - DDS_OP_RTS = 0x00 << 24, - /* data field - [ADR, nBY, 0, k] [offset] - [ADR, STR, 0, k] [offset] - [ADR, BST, 0, k] [offset] [bound] - [ADR, SEQ, nBY, 0] [offset] - [ADR, SEQ, STR, 0] [offset] - [ADR, SEQ, BST, 0] [offset] [bound] - [ADR, SEQ, s, 0] [offset] [elem-size] [next-insn, elem-insn] - where s = {SEQ,ARR,UNI,STU} - [ADR, ARR, nBY, k] [offset] [alen] - [ADR, ARR, STR, 0] [offset] [alen] - [ADR, ARR, BST, 0] [offset] [alen] [0] [bound] - [ADR, ARR, s, 0] [offset] [alen] [next-insn, elem-insn] [elem-size] - where s = {SEQ,ARR,UNI,STU} - [ADR, UNI, d, z] [offset] [alen] [next-insn, cases] - where - d = discriminant type of {1BY,2BY,4BY} - z = default present/not present (DDS_OP_FLAG_DEF) - offset = discriminant offset - followed by alen case labels: in JEQ format - note: [ADR, STU, ...] is illegal - where - s = subtype - k = key/not key (DDS_OP_FLAG_KEY) - [offset] = field offset from start of element in memory - [elem-size] = element size in memory - [bound] = string bound + 1 - [alen] = array length, number of cases - [next-insn] = (unsigned 16 bits) offset to instruction for next field, from start of insn - [elem-insn] = (unsigned 16 bits) offset to first instruction for element, from start of insn - [cases] = (unsigned 16 bits) offset to first case label, from start of insn - */ - DDS_OP_ADR = 0x01 << 24, - /* jump-to-subroutine (apparently not used at the moment) - [JSR, 0, e] - where - e = (signed 16 bits) offset to first instruction in subroutine, from start of insn - instruction sequence must end in RTS, execution resumes at instruction - following JSR */ - DDS_OP_JSR = 0x02 << 24, - /* union case - [JEQ, nBY, 0] [disc] [offset] - [JEQ, STR, 0] [disc] [offset] - [JEQ, s, e] [disc] [offset] - where - s = subtype other than {nBY,STR} - e = (unsigned 16 bits) offset to first instruction for case, from start of insn - instruction sequence must end in RTS, at which point executes continues - at the next field's instruction as specified by the union */ - DDS_OP_JEQ = 0x03 << 24 -}; - -enum dds_stream_typecode { - DDS_OP_VAL_1BY = 0x01, /* one byte simple type (char, octet, boolean) */ - DDS_OP_VAL_2BY = 0x02, /* two byte simple type ((unsigned) short) */ - DDS_OP_VAL_4BY = 0x03, /* four byte simple type ((unsigned) long, enums, float) */ - DDS_OP_VAL_8BY = 0x04, /* eight byte simple type ((unsigned) long long, double) */ - DDS_OP_VAL_STR = 0x05, /* string */ - DDS_OP_VAL_BST = 0x06, /* bounded string */ - DDS_OP_VAL_SEQ = 0x07, /* sequence */ - DDS_OP_VAL_ARR = 0x08, /* array */ - DDS_OP_VAL_UNI = 0x09, /* union */ - DDS_OP_VAL_STU = 0x0a /* struct */ -}; - -/* primary type code for DDS_OP_ADR, DDS_OP_JEQ */ -enum dds_stream_typecode_primary { - DDS_OP_TYPE_1BY = DDS_OP_VAL_1BY << 16, - DDS_OP_TYPE_2BY = DDS_OP_VAL_2BY << 16, - DDS_OP_TYPE_4BY = DDS_OP_VAL_4BY << 16, - DDS_OP_TYPE_8BY = DDS_OP_VAL_8BY << 16, - DDS_OP_TYPE_STR = DDS_OP_VAL_STR << 16, - DDS_OP_TYPE_BST = DDS_OP_VAL_BST << 16, - DDS_OP_TYPE_SEQ = DDS_OP_VAL_SEQ << 16, - DDS_OP_TYPE_ARR = DDS_OP_VAL_ARR << 16, - DDS_OP_TYPE_UNI = DDS_OP_VAL_UNI << 16, - DDS_OP_TYPE_STU = DDS_OP_VAL_STU << 16 -}; -#define DDS_OP_TYPE_BOO DDS_OP_TYPE_1BY - -/* sub-type code: - - encodes element type for DDS_OP_TYPE_{SEQ,ARR}, - - discriminant type for DDS_OP_TYPE_UNI */ -enum dds_stream_typecode_subtype { - DDS_OP_SUBTYPE_1BY = DDS_OP_VAL_1BY << 8, - DDS_OP_SUBTYPE_2BY = DDS_OP_VAL_2BY << 8, - DDS_OP_SUBTYPE_4BY = DDS_OP_VAL_4BY << 8, - DDS_OP_SUBTYPE_8BY = DDS_OP_VAL_8BY << 8, - DDS_OP_SUBTYPE_STR = DDS_OP_VAL_STR << 8, - DDS_OP_SUBTYPE_BST = DDS_OP_VAL_BST << 8, - DDS_OP_SUBTYPE_SEQ = DDS_OP_VAL_SEQ << 8, - DDS_OP_SUBTYPE_ARR = DDS_OP_VAL_ARR << 8, - DDS_OP_SUBTYPE_UNI = DDS_OP_VAL_UNI << 8, - DDS_OP_SUBTYPE_STU = DDS_OP_VAL_STU << 8 -}; -#define DDS_OP_SUBTYPE_BOO DDS_OP_SUBTYPE_1BY - -#define DDS_OP_FLAG_KEY 0x01 /* key field: applicable to {1,2,4,8}BY, STR, BST, ARR-of-{1,2,4,8}BY */ -#define DDS_OP_FLAG_DEF 0x02 /* union has a default case (for DDS_OP_ADR | DDS_OP_TYPE_UNI) */ - -/* For a union: (1) the discriminator may be a key field; (2) there may be a default value; - and (3) the discriminator can be an integral type (or enumerated - here treated as equivalent). - What it can't be is a floating-point type. So DEF and FP need never be set at the same time. - There are only a few flag bits, so saving one is not such a bad idea. */ -#define DDS_OP_FLAG_FP 0x02 /* floating-point: applicable to {4,8}BY and arrays, sequences of them */ -#define DDS_OP_FLAG_SGN 0x04 /* signed: applicable to {1,2,4,8}BY and arrays, sequences of them */ - /** * Description : Enable or disable write batching. Overrides default configuration * setting for write batching (Internal/WriteBatch). diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt index 4c978ff07d..53319b11d2 100644 --- a/src/core/ddsc/tests/CMakeLists.txt +++ b/src/core/ddsc/tests/CMakeLists.txt @@ -11,13 +11,13 @@ # include(CUnit) -idlc_generate(RoundTrip RoundTrip.idl) -idlc_generate(Space Space.idl) -idlc_generate(TypesArrayKey TypesArrayKey.idl) -idlc_generate(WriteTypes WriteTypes.idl) -idlc_generate(InstanceHandleTypes InstanceHandleTypes.idl) -idlc_generate(RWData RWData.idl) -idlc_generate(CreateWriter CreateWriter.idl) +idlc_generate(TARGET RoundTrip FILES RoundTrip.idl) +idlc_generate(TARGET Space FILES Space.idl) +idlc_generate(TARGET TypesArrayKey FILES TypesArrayKey.idl) +idlc_generate(TARGET WriteTypes FILES WriteTypes.idl) +idlc_generate(TARGET InstanceHandleTypes FILES InstanceHandleTypes.idl) +idlc_generate(TARGET RWData FILES RWData.idl) +idlc_generate(TARGET CreateWriter FILES CreateWriter.idl) set(ddsc_test_sources "basic.c" diff --git a/src/core/xtests/cdrtest/CMakeLists.txt b/src/core/xtests/cdrtest/CMakeLists.txt index 2021e0b46b..40678a5311 100644 --- a/src/core/xtests/cdrtest/CMakeLists.txt +++ b/src/core/xtests/cdrtest/CMakeLists.txt @@ -32,7 +32,7 @@ add_compile_options("-I$ENV{OSPL_HOME}/src/api/dcps/sac/code") # that will supply a library target related the the given idl file. # In short, it takes the idl file, generates the source files with # the proper data types and compiles them into a library. -idlc_generate(xxx_lib "xxx.idl") +idlc_generate(TARGET xxx_lib FILES "xxx.idl") # Both executables have only one related source file. add_executable(xxx xxx-cyc.c) diff --git a/src/core/xtests/initsampledeliv/CMakeLists.txt b/src/core/xtests/initsampledeliv/CMakeLists.txt index e4804fa4c0..e7843944d8 100644 --- a/src/core/xtests/initsampledeliv/CMakeLists.txt +++ b/src/core/xtests/initsampledeliv/CMakeLists.txt @@ -11,7 +11,7 @@ # cmake_minimum_required(VERSION 3.5) -idlc_generate(InitSampleDeliv_lib InitSampleDelivData.idl) +idlc_generate(TARGET InitSampleDeliv_lib FILES InitSampleDelivData.idl) add_executable(InitSampleDelivPub publisher.c) add_executable(InitSampleDelivSub subscriber.c) diff --git a/src/core/xtests/rhc_torture/CMakeLists.txt b/src/core/xtests/rhc_torture/CMakeLists.txt index 4aa3a5f852..931cc8ef03 100644 --- a/src/core/xtests/rhc_torture/CMakeLists.txt +++ b/src/core/xtests/rhc_torture/CMakeLists.txt @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -idlc_generate(RhcTypes RhcTypes.idl) +idlc_generate(TARGET RhcTypes FILES RhcTypes.idl) add_executable(rhc_torture rhc_torture.c) diff --git a/src/ddsrt/include/dds/ddsrt/retcode.h b/src/ddsrt/include/dds/ddsrt/retcode.h index abfc1be865..66f2a3636f 100644 --- a/src/ddsrt/include/dds/ddsrt/retcode.h +++ b/src/ddsrt/include/dds/ddsrt/retcode.h @@ -77,8 +77,6 @@ typedef int32_t dds_return_t; #define DDS_RETCODE_OUT_OF_RANGE DDS_XRETCODE(9) /** Not found */ #define DDS_RETCODE_NOT_FOUND DDS_XRETCODE(10) -/** Syntax error */ -#define DDS_RETCODE_BAD_SYNTAX DDS_XRETCODE(11) /** * @} */ diff --git a/src/ddsrt/src/getopt.c b/src/ddsrt/src/getopt.c index 0d2c807fa5..e3473fabfd 100644 --- a/src/ddsrt/src/getopt.c +++ b/src/ddsrt/src/getopt.c @@ -1,6 +1,6 @@ #include #include -#include +#include "getopt.h" /* ::[[ @(#) getopt.c 1.5 89/03/11 05:40:23 ]]:: */ #ifndef LINT diff --git a/src/ddsts/CMakeLists.txt b/src/ddsts/CMakeLists.txt deleted file mode 100644 index 7412f4811b..0000000000 --- a/src/ddsts/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# -# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License v. 2.0 which is available at -# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -# v. 1.0 which is available at -# http://www.eclipse.org/org/documents/edl-v10.php. -# -# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause -# - -include(GenerateExportHeader) - -add_library(ddsts SHARED src/typetree.c src/type_walk.c) - -target_include_directories( - ddsts - PUBLIC - "$" - "$") - -generate_export_header(ddsts EXPORT_FILE_NAME include/dds/ddsts/export.h) - -target_link_libraries(ddsts PUBLIC ddsc) diff --git a/src/ddsts/include/dds/ddsts/type_walk.h b/src/ddsts/include/dds/ddsts/type_walk.h deleted file mode 100644 index a46500c14b..0000000000 --- a/src/ddsts/include/dds/ddsts/type_walk.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -#ifndef DDSTS_TYPE_WALK_H -#define DDSTS_TYPE_WALK_H - -#include "dds/ddsrt/retcode.h" -#include "dds/ddsts/export.h" - -typedef dds_return_t (*ddsts_walk_call_func_t)(ddsts_call_path_t *path, void *context); - -DDSTS_EXPORT dds_return_t -ddsts_walk(ddsts_call_path_t *path, ddsts_flags_t visit, ddsts_flags_t call, ddsts_walk_call_func_t func, void *context); - -#endif /* DDSTS_TYPE_WALK_H */ diff --git a/src/ddsts/include/dds/ddsts/typetree.h b/src/ddsts/include/dds/ddsts/typetree.h deleted file mode 100644 index 122a4cdf42..0000000000 --- a/src/ddsts/include/dds/ddsts/typetree.h +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#ifndef DDSTS_TYPETREE_H -#define DDSTS_TYPETREE_H - -#include -#include - -#include "dds/ddsts/export.h" -#include "dds/ddsrt/retcode.h" - -#define DDSTS_TYPE(X) (1ULL<<(X)) -#define DDSTS_NOTYPE (0ULL) - -#define DDSTS_BASIC_TYPES ((1ULL<<(16+1))-1ULL) -#define DDSTS_UNSIGNED DDSTS_TYPE(0) -#define DDSTS_INT8 DDSTS_TYPE(1) -#define DDSTS_INT16 DDSTS_TYPE(2) -#define DDSTS_INT32 DDSTS_TYPE(3) -#define DDSTS_INT64 DDSTS_TYPE(4) -#define DDSTS_FLOAT DDSTS_TYPE(5) -#define DDSTS_DOUBLE DDSTS_TYPE(6) -#define DDSTS_LONGDOUBLE DDSTS_TYPE(7) -#define DDSTS_CHAR DDSTS_TYPE(8) -#define DDSTS_OCTET DDSTS_TYPE(9) -#define DDSTS_BOOLEAN DDSTS_TYPE(10) -#define DDSTS_ENUM DDSTS_TYPE(11) - -#define DDSTS_WIDE DDSTS_TYPE(12) -#define DDSTS_FIXED_PT_CONST DDSTS_TYPE(13) -#define DDSTS_ANY DDSTS_TYPE(14) - -#define DDSTS_SEQUENCE DDSTS_TYPE(17) -#define DDSTS_ARRAY DDSTS_TYPE(18) -#define DDSTS_STRING DDSTS_TYPE(19) -#define DDSTS_FIXED_PT DDSTS_TYPE(20) -#define DDSTS_MAP DDSTS_TYPE(21) - -#define DDSTS_MODULE DDSTS_TYPE(22) -#define DDSTS_FORWARD_STRUCT DDSTS_TYPE(23) -#define DDSTS_STRUCT DDSTS_TYPE(24) -#define DDSTS_DECLARATION DDSTS_TYPE(25) -#define DDSTS_FORWARD_UNION DDSTS_TYPE(26) -#define DDSTS_UNION DDSTS_TYPE(27) -#define DDSTS_UNION_CASE DDSTS_TYPE(28) -#define DDSTS_DEFINITIONS (DDSTS_MODULE | DDSTS_FORWARD_STRUCT | DDSTS_STRUCT | DDSTS_FORWARD_UNION | DDSTS_UNION) - -#define DDSTS_TYPES ((1ULL<<(29+1))-1ULL) -#define DDSTS_TYPE_OF(O) ((O)->type.flags & DDSTS_TYPES) -#define DDSTS_TYPE_OF_IGNORE_SIGN(O) ((O)->type.flags & DDSTS_TYPES & ~DDSTS_UNSIGNED) -#define DDSTS_IS_TYPE(O,T) ((DDSTS_TYPE_OF(O) & (T)) != 0) -#define DDSTS_IS_DEFINITION(O) ((DDSTS_DEFINITIONS & (O)->type.flags) != 0) - -#define DDSTS_UNBOUND (1ULL<<30) -#define DDSTS_IS_UNBOUND(O) (((O)->type.flags & DDSTS_UNBOUND) != 0) - -#define DDSTS_REFERENCE_1 (1ULL<<31) -#define DDSTS_REFERENCE_2 (1ULL<<32) - -typedef char *ddsts_identifier_t; - -/** - * Literals - * - * Literals are values, either stated or calculated with an expression, that - * appear in the IDL declaration. The literals only appear as members of - * IDL elements, such as the constant definition and the case labels. - */ - -typedef uint64_t ddsts_flags_t; - -typedef struct { - ddsts_flags_t flags; /* flags defining the kind of the literal */ - union { - bool bln; - char chr; - unsigned long wchr; - char *str; - unsigned long long ullng; - signed long long llng; - long double ldbl; - } value; -} ddsts_literal_t; - -DDSTS_EXPORT void ddsts_free_literal(ddsts_literal_t *literal); - - -/** - * Type specification - * - * The union ddsts_type_t is used to contain all possible type specifications, - * where the struct ddsts_typespec_t serves as a basis for these type specifications. - */ - -typedef union ddsts_type ddsts_type_t; - -/** - * @brief Frees a type with all its parts - * - * @param[in] type A pointer to a type. Pointer may be NULL. - * - * @returns A dds_return_t indicating success or failure. Returns failure - * when the type is part of another type. - */ -DDSTS_EXPORT dds_return_t -ddsts_free_type(ddsts_type_t *type); - -typedef struct ddsts_typespec ddsts_typespec_t; -struct ddsts_typespec { - ddsts_flags_t flags; /* flags defining the kind of the type */ - ddsts_identifier_t name; - ddsts_type_t *parent; /* pointer to the parent type, implying ownership */ - ddsts_type_t *next; /* pointer to the next sibling */ - void (*free_func)(ddsts_type_t*); -}; - -typedef struct { - ddsts_type_t *first; /* pointer to the first element */ - ddsts_type_t **ref_end; /* pointer to the pointer where a next element can be appended */ -} ddsts_type_list_t; - -/* Base type specification (base_type_spec) */ -typedef struct { - ddsts_typespec_t typespec; -} ddsts_base_type_t; - -/** - * @brief Creates a ddsts_base_type_t struct and sets it with flags - * - * @param[in] flags One of DDSTS_SHORT to and including DDSTS_ANY. - * @param[out] result Pointer to the created ddsts_base_type_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_base_type(ddsts_flags_t flags, ddsts_type_t **result); - -/* Sequence type (sequence_type) */ -typedef struct { - ddsts_typespec_t typespec; - ddsts_type_t *element_type; - unsigned long long max; -} ddsts_sequence_t; - -/** - * @brief Creates a ddsts_sequence_t struct with a given element type. - * - * @param[in] element_type A non-NULL pointer to the element type. If - * function returns success and the element type - * is not owned yet, it will be is owned by the - * created ddsts_sequence_t struct. - * @param[in] max A positive number representing the maximum size - * of the sequence or 0 for representing an unbound - * sequence. - * @param[out] result Pointer to the created ddsts_sequence_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_sequence(ddsts_type_t *element_type, unsigned long long max, ddsts_type_t **result); - -/* Array type */ -typedef struct { - ddsts_typespec_t typespec; - ddsts_type_t *element_type; - unsigned long long size; -} ddsts_array_t; - -/** - * @brief Creates a ddsts_array_t struct with a given element type. - * - * @param[in] element_type A possibly NULL pointer to the element type. If - * the pointer was non-NULL, not yet owned, and the - * function returns, it will be owned by the created - * ddsts_array_t struct. - * @param[in] size A positive number representing the size of the - * array. - * @param[out] result Pointer to the created ddsts_array_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_array(ddsts_type_t *element_type, unsigned long long size, ddsts_type_t **result); - -/** - * @brief Sets the element type of a ddsts_array_t. - * - * @param[in,out] array A non-NULL pointer to an ddsts_array_t struct - * with a NULL element type. - * @param[in] element_type A non-NULL pointer to the element type. If the - * function returns success and the element type - * is not owned yet, it will be owned by the created - * ddsts_array_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_array_set_element_type(ddsts_type_t *array, ddsts_type_t *element_type); - -/* (Wide) string type (string_type, wide_string_type) */ -typedef struct { - ddsts_typespec_t typespec; - unsigned long long max; -} ddsts_string_t; - -/** - * @brief Creates a ddsts_string_t struct. - * - * @param[in] flags One of DDSTS_STRING or DDSTS_WIDE_STRING. - * @param[in] max A positive number representing the maximum size - * of the string or 0 for representing an unbound - * string. - * @param[out] result Pointer to the created ddsts_string_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_string(ddsts_flags_t flags, unsigned long long max, ddsts_type_t **result); - -/* Fixed point type (fixed_pt_type) */ -typedef struct { - ddsts_typespec_t typespec; - unsigned long long digits; - unsigned long long fraction_digits; -} ddsts_fixed_pt_t; - -/** - * @brief Creates a ddsts_fixed_pt_t struct. - * - * @param[in] digits A positive number representing the maximum - * number of digits. - * @param[in] fraction_digits A positive number representing the number of - * fraction digits. - * @param[out] result Pointer to the created ddsts_fixed_pt_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_fixed_pt(unsigned long long digits, unsigned long long fraction_digits, ddsts_type_t **result); - -/* Map type (map_type) */ -typedef struct { - ddsts_typespec_t typespec; - ddsts_type_t *key_type; - ddsts_type_t *value_type; - unsigned long long max; -} ddsts_map_t; - -/** - * @brief Creates a ddsts_map_t struct with a given element type. - * - * @param[in] key_type A non-NULL pointer to the key type. If the function - * returns success and the key type was not owned yet, - * it will be owned by the created ddsts_map_t struct. - * @param[in] value_type A non-NULL pointer to the key type. If the function - * returns success and the value type was not owned yet, - * it will be owned by the created ddsts_map_t struct. - * @param[in] max A positive number representing the maximum size - * of the map or 0 for representing an unbound - * map. - * @param[out] result Pointer to the created ddsts_map_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_map(ddsts_type_t *key_type, ddsts_type_t *value_type, unsigned long long max, ddsts_type_t **result); - -/* Module declaration (module_dcl) - */ -typedef struct ddsts_module ddsts_module_t; -struct ddsts_module { - ddsts_typespec_t type; - ddsts_type_list_t members; - ddsts_module_t *previous; /* to previous open of this module, if present */ -}; - -/** - * @brief Creates a ddsts_module_t with no members. - * - * @param[in] name A non-NULL pointer to a string. If the function - * returns success, the string should be considered as - * owned by the created ddsts_module_t struct. - * @param[out] result Pointer to the created ddsts_module_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_module(ddsts_identifier_t name, ddsts_type_t **result); - -/** - * @brief Adds a member at the end of the members of a ddsts_module_t struct. - * - * @param[in,out] module A non-NULL pointer to a ddsts_module_t struct. - * @param[in] member A non-NULL pointer to a member type that is not owned - * yet. If the function returns success, the member type - * will be owned by the module. - * In case the member type is a module and the module - * is reopened the 'previous' struct member is set to - * point to the previous opening of the module. - * In case the member type is a struct, the 'definition' - * struct member of matching previous forward declaration - * are set to this struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_module_add_member(ddsts_type_t *module, ddsts_type_t *member); - -/* Forward declaration */ -typedef struct { - ddsts_typespec_t type; - ddsts_type_t *definition; /* reference to the actual definition */ -} ddsts_forward_t; - -/* Struct forward declaration (struct_forward_dcl) - * ddsts_forward_t (no extra members) - */ - -/** - * @brief Creates a ddsts_forward_t struct for a struct forward declaration. - * - * @param[in] name A non-NULL pointer to a string. If the function - * returns success, the string should be considered as - * owned by the created ddsts_forward_t struct. - * @param[out] result Pointer to the created ddsts_forward_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_struct_forward_dcl(ddsts_identifier_t name, ddsts_type_t **result); - -/* Struct declaration (struct_def) - */ -typedef struct ddsts_struct_key ddsts_struct_key_t; -typedef struct { - ddsts_typespec_t type; - ddsts_type_t *super; /* used for extended struct type definition */ - ddsts_type_list_t members; - ddsts_struct_key_t *keys; -} ddsts_struct_t; - -struct ddsts_struct_key { - ddsts_type_t *member; - ddsts_struct_key_t *next; -}; - -/** - * @brief Creates a ddsts_struct_t with no members. - * - * @param[in] name A non-NULL pointer to a string. If the function - * returns success, the string should be considered as - * owned by the created ddsts_struct_t struct. - * @param[out] result Pointer to the created ddsts_struct_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_struct(ddsts_identifier_t name, ddsts_type_t **result); - -/** - * @brief Adds a member at the end of the members of a ddsts_struct_t struct. - * - * @param[in,out] struct_def A non-NULL pointer to a ddsts_struct_t struct. - * @param[in] member A non-NULL pointer to a member type that is not - * owned yet. If the function returns success, the - * member type will be owned by the struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_struct_add_member(ddsts_type_t *struct_def, ddsts_type_t *member); - -/** - * @brief Adds a key at the end of the keys of a ddsts_struct_t struct. - * - * @param[in,out] struct_def A non-NULL pointer to a ddsts_struct_t struct. - * @param[in] member A non-NULL pointer to a member type that - * belongs to the struct. - * - * @returns A dds_return_t indicating success or failure. On success a - * struct ddsts_struct_key_t pointing to the member will be added to the - * keys of struct_def. DDS_RETCODE_ERROR is returned when the member is - * already included as a key. - */ -DDSTS_EXPORT dds_return_t -ddsts_struct_add_key(ddsts_type_t *struct_def, ddsts_type_t *member); - -/* Declaration - */ -typedef struct { - ddsts_typespec_t type; - ddsts_type_t *decl_type; -} ddsts_declaration_t; - -/** - * @brief Creates a ddsts_declaration_t struct. - * - * @param[in] name A non-NULL pointer to a string. If the function - * returns success, the string should be considered as - * owned by the created ddsts_declaration_t struct. - * @param[in] decl_type A possibly NULL pointer to the type of the declaration. - * If the pointer was non-NULL, not yet owned, and the - * function returns, it will be owned by the created - * ddsts_declaration_t struct. - * @param[out] result Pointer to the created ddsts_declaration_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_declaration(ddsts_identifier_t name, ddsts_type_t *decl_type, ddsts_type_t **result); - -/** - * @brief Sets the declaration type of a ddsts_declaration_t. - * - * @param[in,out] declaration A non-NULL pointer to an ddsts_declaration_t - * struct with a NULL element type. - * @param[in] type A non-NULL pointer to the declaration type. If - * the function returns success and the element - * type is not owned yet, it will be owned by the - * created ddsts_declaration_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_declaration_set_type(ddsts_type_t *declaration, ddsts_type_t *type); - -/** - * @brief Creates a ddsts_forward_t struct for a union forward declaration. - * - * @param[in] name A non-NULL pointer to a string. If the function - * returns success, the string should be considered as - * owned by the created ddsts_forward_t struct. - * @param[out] result Pointer to the created ddsts_forward_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_union_forward_dcl(ddsts_identifier_t name, ddsts_type_t **result); - -/* Union declaration (union_def) - */ -typedef struct { - ddsts_typespec_t type; - ddsts_flags_t switch_type; - ddsts_type_list_t cases; -} ddsts_union_t; - -typedef struct ddsts_union_case_label ddsts_union_case_label_t; -typedef struct { - ddsts_declaration_t decl; - ddsts_union_case_label_t *labels; - bool default_label; -} ddsts_union_case_t; - -struct ddsts_union_case_label { - ddsts_literal_t value; - ddsts_union_case_label_t *next; -}; - -/** - * @brief Create a ddsts_union_t with no cases. - * - * @param[in] name A non-NULL pointer to a string. If the function - * returns success, the string should be considered as - * owned by the created ddsts_struct_t struct. - * @param[in] switch_type Flags indication switch type. - * @param[out] result Pointer to the created ddsts_struct_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_create_union(ddsts_identifier_t name, ddsts_flags_t switch_type, ddsts_type_t **result); - -/** - * @brief Adds a case at the end of the cases of a ddsts_union_t struct. - * - * @param[in,out] union_def A non-NULL pointer to a ddsts_union_t struct. - * @param[in] labels A pointer to the case labels. If the function - * returns success, the labels should be considered - * as owned by the created union case. - * @param[in] default_label A boolean indicating if the default value is - * included in the case. - * @param[out] result Pointer to the created ddsts_struct_t struct. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_union_add_case(ddsts_type_t *union_def, ddsts_union_case_label_t *labels, bool default_label, ddsts_type_t **result); - -DDSTS_EXPORT void -ddsts_free_union_case_labels(ddsts_union_case_label_t *labels); - -/** - * @brief Sets the name and the type on a union case - * - * @param[in,out] union_case A non-NULL pointer to the union case. - * @param[in] name A non-NULL pointer to a string. If the function - * returns success, the string should be considered as - * owned by the created ddsts_struct_t struct. - * @param[in] type A non-NULL pointer to the type of the case. - * If the type was not yet owned, and the - * function returns, it will be owned by the created - * union case. - * - * @returns A dds_return_t indicating success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_union_case_set_decl(ddsts_type_t *union_case, ddsts_identifier_t name, ddsts_type_t *type); - -/* The union of all type specs */ -union ddsts_type { - ddsts_typespec_t type; - ddsts_base_type_t base_type; - ddsts_sequence_t sequence; - ddsts_array_t array; - ddsts_string_t string; - ddsts_fixed_pt_t fixed_pt; - ddsts_map_t map; - ddsts_module_t module; - ddsts_forward_t forward; - ddsts_struct_t struct_def; - ddsts_declaration_t declaration; - ddsts_union_t union_def; - ddsts_union_case_t union_case; -}; - -/* Utility functions */ - -/* Some of the algorithms on the type tree, need to know the path through which - * the type was reached, for example, when a reference to another part of the - * type tree was followed. - */ - -typedef struct ddsts_call_path ddsts_call_path_t; -struct ddsts_call_path { - ddsts_type_t *type; - ddsts_call_path_t *call_parent; -}; - -/** - * @brief Calculates whether a given declaration is a key in a given path - * - * @param[in] path An call path to a struct member declaration - * @param[out] is_key Is set to true when declaration is a key in the given - * path, otherwise false. Undefined in case of failure - * due to error. - * - * @returns A dds_return_t indication success or failure. - */ -DDSTS_EXPORT dds_return_t -ddsts_declaration_is_key(ddsts_call_path_t *path, bool *is_key); - -#endif /* DDS_TYPE_TYPETREE_H */ diff --git a/src/ddsts/src/type_walk.c b/src/ddsts/src/type_walk.c deleted file mode 100644 index d3178c510d..0000000000 --- a/src/ddsts/src/type_walk.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include - -#include "dds/ddsts/typetree.h" -#include "dds/ddsts/type_walk.h" - -dds_return_t ddsts_walk(ddsts_call_path_t *path, ddsts_flags_t visit, ddsts_flags_t call, ddsts_walk_call_func_t func, void *context) -{ - ddsts_call_path_t child_path; - child_path.call_parent = path; - ddsts_type_t *child = NULL; - if (DDSTS_IS_TYPE(path->type, DDSTS_MODULE)) { - child = path->type->module.members.first; - } - else if (DDSTS_IS_TYPE(path->type, DDSTS_STRUCT)) { - child = path->type->struct_def.members.first; - } - for (; child != NULL; child = child->type.next) { - child_path.type = child; - if ((DDSTS_TYPE_OF(child) & call) != 0) { - dds_return_t rc = func(&child_path, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - } - if ((DDSTS_TYPE_OF(child) & visit) != 0) { - dds_return_t rc = ddsts_walk(&child_path, visit, call, func, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - } - } - return DDS_RETCODE_OK; -} - diff --git a/src/ddsts/src/typetree.c b/src/ddsts/src/typetree.c deleted file mode 100644 index 82b392b9ab..0000000000 --- a/src/ddsts/src/typetree.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -#include -#include -#include "dds/ddsrt/retcode.h" -#include "dds/ddsrt/heap.h" -#include "dds/ddsts/typetree.h" - - -void ddsts_free_literal(ddsts_literal_t *literal) -{ - if (literal->flags & DDSTS_STRING) { - ddsrt_free(literal->value.str); - } -} - -dds_return_t ddsts_free_type(ddsts_type_t *type) -{ - if (type != NULL) { - if (type->type.parent != NULL) { - return DDS_RETCODE_ERROR; - } - type->type.free_func(type); - } - return DDS_RETCODE_OK; -} - -static void init_type_ref(ddsts_type_t **ref_type, ddsts_type_t *type, ddsts_type_t *parent, ddsts_flags_t ref_flag) -{ - *ref_type = type; - if (type != NULL) { - if (type->type.parent == NULL) { - type->type.parent = parent; - } - else { - parent->type.flags |= ref_flag; - } - } -} - -static void free_type_ref(ddsts_type_t *type, ddsts_type_t *parent, ddsts_flags_t ref_flag) -{ - if (type != NULL && (parent->type.flags & ref_flag) == 0) { - type->type.free_func(type); - } -} - -static void init_children(ddsts_type_list_t *list) -{ - list->first = NULL; - list->ref_end = &list->first; -} - -static void children_add(ddsts_type_list_t *list, ddsts_type_t *child) -{ - *list->ref_end = child; - list->ref_end = &child->type.next; -} - -static void free_children(ddsts_type_list_t *list) -{ - ddsts_type_t *type = list->first; - while (type != NULL) { - ddsts_type_t *next = type->type.next; - type->type.free_func(type); - type = next; - } -} - -static void init_type(ddsts_type_t *type, void (*free_func)(ddsts_type_t*), ddsts_flags_t flags, ddsts_identifier_t name) -{ - type->type.flags = flags; - type->type.name = name; - type->type.parent = NULL; - type->type.next = NULL; - type->type.free_func = free_func; -} - -static void free_type(ddsts_type_t *type) -{ - ddsrt_free(type->type.name); - ddsrt_free(type); -} - -/* ddsts_base_type_t */ - -dds_return_t ddsts_create_base_type(ddsts_flags_t flags, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_base_type_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_type, flags, NULL); - *result = type; - return DDS_RETCODE_OK; -} - -/* ddsts_sequence_t */ - -static void free_sequence(ddsts_type_t *type) -{ - free_type_ref(type->sequence.element_type, type, DDSTS_REFERENCE_1); - free_type(type); -} - -dds_return_t ddsts_create_sequence(ddsts_type_t* element_type, unsigned long long max, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_sequence_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ddsts_flags_t flags = DDSTS_SEQUENCE; - if (max == 0ULL) { - flags |= DDSTS_UNBOUND; - } - init_type(type, free_sequence, flags, NULL); - init_type_ref(&type->sequence.element_type, element_type, type, DDSTS_REFERENCE_1); - type->sequence.max = max; - *result = type; - return DDS_RETCODE_OK; -} - -/* ddsts_array_t */ - -static void free_array(ddsts_type_t *type) -{ - free_type_ref(type->array.element_type, type, DDSTS_REFERENCE_1); - free_type(type); -} - -dds_return_t ddsts_create_array(ddsts_type_t* element_type, unsigned long long size, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_array_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_array, DDSTS_ARRAY, NULL); - init_type_ref(&type->array.element_type, element_type, type, DDSTS_REFERENCE_1); - type->array.size = size; - *result = type; - return DDS_RETCODE_OK; -} - -dds_return_t ddsts_array_set_element_type(ddsts_type_t *array, ddsts_type_t *element_type) -{ - assert(array->array.element_type == NULL); - init_type_ref(&array->array.element_type, element_type, array, DDSTS_REFERENCE_1); - return DDS_RETCODE_OK; -} - -/* ddsts_string_t */ - -static void free_string(ddsts_type_t *type) -{ - free_type(type); -} - -dds_return_t ddsts_create_string(ddsts_flags_t flags, unsigned long long max, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_string_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - if (max == 0ULL) { - flags |= DDSTS_UNBOUND; - } - init_type(type, free_string, flags, NULL); - type->string.max = max; - *result = type; - return DDS_RETCODE_OK; -} - -/* ddsts_fixed_pt_t */ - -static void free_fixed_pt(ddsts_type_t *type) -{ - free_type(type); -} - -dds_return_t ddsts_create_fixed_pt(unsigned long long digits, unsigned long long fraction_digits, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_fixed_pt_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_fixed_pt, DDSTS_FIXED_PT, NULL); - type->fixed_pt.digits = digits; - type->fixed_pt.fraction_digits = fraction_digits; - *result = type; - return DDS_RETCODE_OK; -} - -/* ddsts_map_t */ - -static void free_map(ddsts_type_t *type) -{ - free_type_ref(type->map.key_type, type, DDSTS_REFERENCE_1); - free_type_ref(type->map.value_type, type, DDSTS_REFERENCE_2); - free_type(type); -} - -dds_return_t ddsts_create_map(ddsts_type_t *key_type, ddsts_type_t *value_type, unsigned long long max, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_map_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ddsts_flags_t flags = DDSTS_MAP; - if (max == 0ULL) { - flags |= DDSTS_UNBOUND; - } - init_type(type, free_map, flags, NULL); - init_type_ref(&type->map.key_type, key_type, type, DDSTS_REFERENCE_1); - init_type_ref(&type->map.value_type, value_type, type, DDSTS_REFERENCE_2); - type->map.max = max; - *result = type; - return DDS_RETCODE_OK; -} - -/* ddsts_module_t */ - -static void free_module(ddsts_type_t *type) -{ - free_children(&type->module.members); - free_type(type); -} - -dds_return_t ddsts_create_module(ddsts_identifier_t name, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_module_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_module, DDSTS_MODULE, name); - init_children(&type->module.members); - type->module.previous = NULL; - *result = type; - return DDS_RETCODE_OK; -} - -dds_return_t ddsts_module_add_member(ddsts_type_t *module, ddsts_type_t *member) -{ - if (module != NULL) { - member->type.parent = module; - children_add(&module->module.members, member); - - /* if the member is a module, find previous open of this module, if any */ - if (DDSTS_IS_TYPE(member, DDSTS_MODULE)) { - ddsts_module_t *parent_module; - for (parent_module = &module->module; parent_module != NULL; parent_module = parent_module->previous) { - ddsts_type_t *child; - for (child = parent_module->members.first; child != NULL; child = child->type.next) { - if (DDSTS_IS_TYPE(child, DDSTS_MODULE) && strcmp(child->type.name, member->type.name) == 0 && child != member) { - member->module.previous = &child->module; - } - } - if (member->module.previous != NULL) { - break; - } - } - } - - /* if the member is a struct, set 'definition' of matching forward declarations */ - if (DDSTS_IS_TYPE(member, DDSTS_STRUCT)) { - ddsts_module_t *parent_module; - for (parent_module = &module->module; parent_module != NULL; parent_module = parent_module->previous) { - ddsts_type_t *child; - for (child = parent_module->members.first; child != NULL; child = child->type.next) { - if (DDSTS_IS_TYPE(child, DDSTS_FORWARD_STRUCT) && strcmp(child->type.name, member->type.name) == 0) { - child->forward.definition = member; - } - } - } - } - } - return DDS_RETCODE_OK; -} - -/* ddsts_forward_declaration_t */ - -static void free_forward(ddsts_type_t *type) -{ - free_type(type); -} - -dds_return_t ddsts_create_struct_forward_dcl(ddsts_identifier_t name, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_forward_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_forward, DDSTS_FORWARD_STRUCT, name); - type->forward.definition = NULL; - *result = type; - return DDS_RETCODE_OK; -} - -/* ddsts_struct_t */ - -static void free_struct(ddsts_type_t *type) -{ - ddsts_struct_key_t *key = type->struct_def.keys; - while (key != NULL) { - ddsts_struct_key_t *next = key->next; - ddsrt_free(key); - key = next; - } - free_children(&type->struct_def.members); - free_type(type); -} - -dds_return_t ddsts_create_struct(ddsts_identifier_t name, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_struct_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_struct, DDSTS_STRUCT, name); - init_children(&type->struct_def.members); - type->struct_def.super = NULL; - type->struct_def.keys = NULL; - *result = type; - return DDS_RETCODE_OK; -} - -dds_return_t ddsts_struct_add_member(ddsts_type_t *struct_def, ddsts_type_t *member) -{ - if (struct_def != NULL) { - member->type.parent = struct_def; - children_add(&struct_def->struct_def.members, member); - } - return DDS_RETCODE_OK; -} - -dds_return_t ddsts_struct_add_key(ddsts_type_t *struct_def, ddsts_type_t *member) -{ - /* We traverse the list to the end and check if 'member' is already included */ - ddsts_struct_key_t **ref_key = &struct_def->struct_def.keys; - while (*ref_key != NULL) { - if ((*ref_key)->member == member) { - return DDS_RETCODE_ERROR; - } - ref_key = &(*ref_key)->next; - } - (*ref_key) = (ddsts_struct_key_t*)ddsrt_malloc(sizeof(ddsts_struct_key_t)); - if (*ref_key == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - (*ref_key)->member = member; - (*ref_key)->next = NULL; - return DDS_RETCODE_OK; -} - -/* ddsts_declaration_t */ - -static void free_declaration(ddsts_type_t *type) -{ - free_type_ref(type->declaration.decl_type, type, DDSTS_REFERENCE_1); - free_type(type); -} - -dds_return_t ddsts_create_declaration(ddsts_identifier_t name, ddsts_type_t *decl_type, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_declaration_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_declaration, DDSTS_DECLARATION, name); - init_type_ref(&type->declaration.decl_type, decl_type, type, DDSTS_REFERENCE_1); - *result = type; - return DDS_RETCODE_OK; -} - -dds_return_t ddsts_declaration_set_type(ddsts_type_t *declaration, ddsts_type_t *type) -{ - assert(declaration->declaration.decl_type == NULL); - init_type_ref(&declaration->declaration.decl_type, type, declaration, DDSTS_REFERENCE_1); - return DDS_RETCODE_OK; -} - -dds_return_t ddsts_create_union_forward_dcl(ddsts_identifier_t name, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_forward_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_forward, DDSTS_FORWARD_UNION, name); - type->forward.definition = NULL; - *result = type; - return DDS_RETCODE_OK; -} - -/* ddsts_union_t */ - -static void free_union(ddsts_type_t *type) -{ - free_children(&type->union_def.cases); - free_type(type); -} - -dds_return_t -ddsts_create_union(ddsts_identifier_t name, ddsts_flags_t switch_type, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_union_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_union, DDSTS_UNION, name); - type->union_def.switch_type = switch_type; - init_children(&type->union_def.cases); - *result = type; - return DDS_RETCODE_OK; -} - -void ddsts_free_union_case_labels(ddsts_union_case_label_t *labels) -{ - while (labels != NULL) { - ddsts_union_case_label_t *next = labels->next; - ddsts_free_literal(&labels->value); - ddsrt_free(labels); - labels = next; - } -} - -static void free_union_case(ddsts_type_t *type) -{ - ddsts_free_union_case_labels(type->union_case.labels); - free_declaration(type); -} - -dds_return_t -ddsts_union_add_case(ddsts_type_t *union_def, ddsts_union_case_label_t *labels, bool default_label, ddsts_type_t **result) -{ - ddsts_type_t *type = (ddsts_type_t*)ddsrt_malloc_s(sizeof(ddsts_union_case_t)); - if (type == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - init_type(type, free_union_case, DDSTS_UNION_CASE, NULL); - type->declaration.decl_type = NULL; - type->union_case.labels = labels; - type->union_case.default_label = default_label; - type->type.parent = union_def; - children_add(&union_def->union_def.cases, type); - *result = type; - return DDS_RETCODE_OK; -} - -dds_return_t -ddsts_union_case_set_decl(ddsts_type_t *union_case, ddsts_identifier_t name, ddsts_type_t *type) -{ - union_case->type.name = name; - ddsts_declaration_set_type(union_case, type); - return DDS_RETCODE_OK; -} -/* Utility functions */ - -dds_return_t -ddsts_declaration_is_key(ddsts_call_path_t *path, bool *is_key) -{ - *is_key = false; - while (path != NULL && DDSTS_IS_TYPE(path->type, DDSTS_DECLARATION)) { - ddsts_call_path_t *struct_path = path->call_parent; - if (struct_path == NULL || !DDSTS_IS_TYPE(struct_path->type, DDSTS_STRUCT)) { - return DDS_RETCODE_ERROR; - } - *is_key = false; - if (struct_path->type->struct_def.keys != NULL) { - for (ddsts_struct_key_t *key = struct_path->type->struct_def.keys; key != NULL; key = key->next) { - if (key->member == path->type) { - *is_key = true; - break; - } - } - if (!*is_key) { - /* The structure has keys, but the declartion is not one of them. */ - return DDS_RETCODE_OK; - } - } - path = struct_path->call_parent; - } - if (path == NULL || !DDSTS_IS_TYPE(path->type, DDSTS_MODULE)) { - return DDS_RETCODE_ERROR; - } - return DDS_RETCODE_OK; -} - diff --git a/src/idl/CMakeLists.txt b/src/idl/CMakeLists.txt new file mode 100644 index 0000000000..aa7caff31f --- /dev/null +++ b/src/idl/CMakeLists.txt @@ -0,0 +1,103 @@ +# +# Copyright(c) 2021 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +cmake_minimum_required(VERSION 3.7) +#project(cyclonedds-idl LANGUAGES C) + +include(GenerateExportHeader) + +find_package(BISON 3.0.4 REQUIRED) +find_package(Threads QUIET REQUIRED) + +set(binary_dir "${CMAKE_CURRENT_BINARY_DIR}") +set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}") + +bison_target(parser src/parser.y "${binary_dir}/parser.c") + +# generate hashid.c from md5.h and md5.c to avoid code duplication +file(READ "${CMAKE_SOURCE_DIR}/src/ddsrt/include/dds/ddsrt/endian.h" endian_h) +file(READ "${CMAKE_SOURCE_DIR}/src/ddsrt/include/dds/ddsrt/md5.h" md5_h) +file(READ "${CMAKE_SOURCE_DIR}/src/ddsrt/src/md5.c" md5_c) +string(CONCAT MD5 "${endian_h}" "${md5_h}" "${md5_c}") +# remove occurrences of DDS_EXPORT +string(REGEX REPLACE "\n[ \t]*DDS_EXPORT[ \t]+" "\n" MD5 "${MD5}") +# remove dds/* includes +string(REGEX REPLACE "\n[ \t]*#[ \t]*include[ \t]+[<\"]dds/[^\n]*" "" MD5 "${MD5}") +# switch functions to static +foreach(func ddsrt_md5_init ddsrt_md5_append ddsrt_md5_finish) + string(REGEX REPLACE "\n[ \t]*void[ \n\t]+${func}" "\nstatic void ${func}" MD5 "${MD5}") +endforeach() + +configure_file(src/hashid.c.in ${CMAKE_CURRENT_BINARY_DIR}/hashid.c @ONLY) + +add_library( + idl SHARED + src/symbol.c + src/directive.c + src/expression.c + src/file.c + src/processor.c + src/scanner.c + src/string.c + src/annotation.c + src/scope.c + src/hashid.c + src/string.c + src/tree.c + src/visit.c + src/thread.c + ${CMAKE_CURRENT_BINARY_DIR}/hashid.c + ${BISON_parser_OUTPUT_SOURCE}) + +set_target_properties( + idl PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}) + +generate_export_header(idl EXPORT_FILE_NAME include/idl/export.h) + +configure_file(include/idl/version.h.in include/idl/version.h @ONLY) + +target_include_directories( + idl + PUBLIC + "$" + "$" + "$" + "$" + INTERFACE + "$") + +target_link_libraries(idl PRIVATE Threads::Threads) + +install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/idl" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + COMPONENT dev + FILES_MATCHING PATTERN "*.h") + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/include/idl/export.h" + "${CMAKE_CURRENT_BINARY_DIR}/include/idl/version.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/idl" + COMPONENT dev) + +install( + TARGETS idl + EXPORT "${CMAKE_PROJECT_NAME}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT lib + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib) + +if(BUILD_TESTING) + add_subdirectory(tests) +endif() diff --git a/src/idl/include/idl/expression.h b/src/idl/include/idl/expression.h new file mode 100644 index 0000000000..9edded7073 --- /dev/null +++ b/src/idl/include/idl/expression.h @@ -0,0 +1,32 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_EXPRESSION_H +#define IDL_EXPRESSION_H + +#include "idl/tree.h" + +typedef enum idl_equality idl_equality_t; +enum idl_equality { + IDL_INVALID = -3, + IDL_MISMATCH = -2, /**< type mismatch */ + IDL_LESS = -1, + IDL_EQUAL, + IDL_GREATER, +}; + +IDL_EXPORT idl_equality_t +idl_compare( + struct idl_pstate *pstate, + const idl_const_expr_t *lhs, + const idl_const_expr_t *rhs); + +#endif /* IDL_EXPRESSION_H */ diff --git a/src/idl/include/idl/file.h b/src/idl/include/idl/file.h new file mode 100644 index 0000000000..6c7ce97eb9 --- /dev/null +++ b/src/idl/include/idl/file.h @@ -0,0 +1,33 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_FILE_H +#define IDL_FILE_H + +#include "idl/export.h" +#include "idl/retcode.h" + +IDL_EXPORT unsigned int +idl_isseparator(int chr); + +IDL_EXPORT unsigned int +idl_isabsolute(const char *path); + +IDL_EXPORT idl_retcode_t +idl_current_path(char **abspathp); + +IDL_EXPORT idl_retcode_t +idl_normalize_path(const char *path, char **abspathp); + +IDL_EXPORT idl_retcode_t +idl_relative_path(const char *base, const char *path, char **relpathp); + +#endif /* IDL_FILE_H */ diff --git a/src/idl/include/idl/processor.h b/src/idl/include/idl/processor.h new file mode 100644 index 0000000000..ba9cd79619 --- /dev/null +++ b/src/idl/include/idl/processor.h @@ -0,0 +1,152 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_COMPILER_H +#define IDL_COMPILER_H + +/** + * @file + * Types and functions for the IDL compiler. + */ + +#include +#include + +#include "idl/export.h" +#include "idl/retcode.h" +#include "idl/tree.h" +#include "idl/scope.h" +#include "idl/visit.h" + +/* enable "#pragma keylist" for backwards compatibility */ +#define IDL_FLAG_KEYLIST (1u<<0) +/* case-sensitive extension can be used to allow e.g. field names in structs + and unions that differ solely in case from the name of the respective + struct or union. i.e. "struct FOO_ { octet foo_[42]; };" */ +#define IDL_FLAG_CASE_SENSITIVE (1u<<1) +/* enable building block extended data types */ +#define IDL_FLAG_EXTENDED_DATA_TYPES (1u<<2) +/* enable building block anonymous types */ +#define IDL_FLAG_ANONYMOUS_TYPES (1u<<3) +/* enable building block annotations */ +#define IDL_FLAG_ANNOTATIONS (1u<<4) +/* flag used by idlc to indicate end-of-buffer (private) */ +#define IDL_WRITE (1u<<31) + +typedef struct idl_buffer idl_buffer_t; +struct idl_buffer { + char *data; + size_t size; /**< total number of bytes available */ + size_t used; /**< number of bytes used */ +}; + +typedef struct idl_pstate idl_pstate_t; +struct idl_pstate { + bool keylists; + bool annotations; + uint32_t flags; /**< processor options */ + idl_file_t *paths; /**< normalized paths used in include statements */ + idl_file_t *files; /**< filenames used in #line directives */ + idl_source_t *sources; + idl_scope_t *global_scope, *annotation_scope, *scope; + void *directive; + idl_node_t *builtin_root, *root; + idl_buffer_t buffer; /**< dynamically sized input buffer */ + struct { + enum { + IDL_SCAN, + /** scanning preprocessor directive */ + IDL_SCAN_DIRECTIVE = (1<<7), + IDL_SCAN_DIRECTIVE_NAME, + /** scanning #line directive */ + IDL_SCAN_LINE = (IDL_SCAN_DIRECTIVE | (1<<6)), + IDL_SCAN_FILENAME, + IDL_SCAN_FLAGS, + IDL_SCAN_EXTRA_TOKENS, + /** scanning #pragma directive */ + IDL_SCAN_PRAGMA = (IDL_SCAN_DIRECTIVE | (1<<5)), + IDL_SCAN_UNKNOWN_PRAGMA, + /** scanning #pragma keylist directive */ + IDL_SCAN_KEYLIST = (IDL_SCAN_PRAGMA | (1<<4)), + IDL_SCAN_DATA_TYPE, + IDL_SCAN_NAME, + IDL_SCAN_SCOPE, + IDL_SCAN_KEY, + IDL_SCAN_FIELD, + IDL_SCAN_ACCESS, + /** scanning IDL */ + IDL_SCAN_GRAMMAR = (1<<8), + /* scanning "@annotation" or scoped name after "@" in IDL */ + /** expect identifier, i.e. annotation in "@annotation" */ + IDL_SCAN_ANNOTATION, + /** expect identifier, i.e. foo in "@annotation foo" */ + IDL_SCAN_ANNOTATION_NAME, + /** expect scope or identifier, i.e. :: in "@::" and foo in "@foo" */ + IDL_SCAN_ANNOTATION_APPL, + /** expect scope, i.e. :: in "@foo::bar::" */ + IDL_SCAN_ANNOTATION_APPL_SCOPE, + /** expect identifier in scoped name, i.e. foo in "@foo::bar" */ + IDL_SCAN_ANNOTATION_APPL_SCOPED_NAME, + /** final identifier in scoped name, i.e. bar in "@foo::bar" or "@bar" */ + IDL_SCAN_ANNOTATION_APPL_NAME, + /** end of input */ + IDL_EOF = (1<<9) + } state; + const char *cursor; + const char *limit; + idl_position_t position; + } scanner; + struct { + enum { + IDL_PARSE, /**< default state */ + IDL_PARSE_ANNOTATION, + IDL_PARSE_ANNOTATION_BODY, + IDL_PARSE_EXISTING_ANNOTATION_BODY, + IDL_PARSE_ANNOTATION_APPL, + IDL_PARSE_ANNOTATION_APPL_PARAMS, + IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS + } state; + void *yypstate; /**< state of Bison generated parser */ + } parser; +}; + +typedef struct idl_builtin_annotation idl_builtin_annotation_t; +struct idl_builtin_annotation { + const char *syntax; /**< precise syntax */ + const char *summary; /**< brief yet significant description */ + const idl_annotation_callback_t callback; +}; + +IDL_EXPORT idl_retcode_t +idl_create_pstate( + uint32_t flags, + const idl_builtin_annotation_t *annotations, + idl_pstate_t **pstatep); + +IDL_EXPORT void +idl_delete_pstate(idl_pstate_t *pstate); + +IDL_EXPORT idl_retcode_t +idl_parse(idl_pstate_t *pstate); + +IDL_EXPORT idl_retcode_t +idl_parse_string(idl_pstate_t *pstate, const char *str); + +IDL_EXPORT void +idl_verror(idl_pstate_t *pstate, const idl_location_t *loc, const char *fmt, va_list ap); + +IDL_EXPORT void +idl_error(idl_pstate_t *pstate, const idl_location_t *loc, const char *fmt, ...); + +IDL_EXPORT void +idl_warning(idl_pstate_t *pstate, const idl_location_t *loc, const char *fmt, ...); + +#endif /* IDL_COMPILER_H */ diff --git a/src/idl/include/idl/retcode.h b/src/idl/include/idl/retcode.h new file mode 100644 index 0000000000..60a815bd41 --- /dev/null +++ b/src/idl/include/idl/retcode.h @@ -0,0 +1,51 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_RETCODE_H +#define IDL_RETCODE_H + +#include + +typedef int32_t idl_retcode_t; + +/** + * @name IDL_Return_Code + */ +/** @{ */ +/** Success */ +#define IDL_RETCODE_OK (0) +/** Push more tokens */ +#define IDL_RETCODE_PUSH_MORE (-1) +/** Processor needs refill in order to continue */ +#define IDL_RETCODE_NEED_REFILL (-2) +/** Syntax error */ +#define IDL_RETCODE_SYNTAX_ERROR (-3) +/** Semantic error */ +#define IDL_RETCODE_SEMANTIC_ERROR (-4) +/** Operation failed due to lack of resources */ +#define IDL_RETCODE_NO_MEMORY (-5) +/** */ +#define IDL_RETCODE_ILLEGAL_EXPRESSION (-6) +/** */ +#define IDL_RETCODE_OUT_OF_RANGE (-7) +/** Permission denied */ +#define IDL_RETCODE_NO_ACCESS (-8) +/** No such file or directory */ +#define IDL_RETCODE_NO_ENTRY (-9) +/** Operation failed due to lack of disk space */ +#define IDL_RETCODE_NO_SPACE (-10) +/** */ +#define IDL_RETCODE_BAD_FORMAT (-11) +/** */ +#define IDL_RETCODE_BAD_PARAMETER (-12) +/** @} */ + +#endif /* IDL_RETCODE_H */ diff --git a/src/idl/include/idl/scope.h b/src/idl/include/idl/scope.h new file mode 100644 index 0000000000..961eb521fc --- /dev/null +++ b/src/idl/include/idl/scope.h @@ -0,0 +1,99 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_SCOPE_H +#define IDL_SCOPE_H + +#include + +#include "idl/tree.h" + +typedef struct idl_scope idl_scope_t; + +typedef struct idl_declaration idl_declaration_t; +struct idl_declaration { + enum idl_declaration_kind { + /** module */ + IDL_MODULE_DECLARATION, + /** annotation */ + IDL_ANNOTATION_DECLARATION, + /** const, enumerator, type, ... */ + IDL_SPECIFIER_DECLARATION, + /** declarator, e.g. declarator of struct member or union element */ + IDL_INSTANCE_DECLARATION, + /** introduced through use of non-absolute qualified name */ + IDL_USE_DECLARATION, + /** enclosing scope, for convenience */ + IDL_SCOPE_DECLARATION + } kind; + idl_declaration_t *next; + const idl_scope_t *local_scope; /**< scope local to declaration */ + idl_name_t *name; + idl_scoped_name_t *scoped_name; + const idl_node_t *node; + idl_scope_t *scope; /**< scope introduced by declaration (optional) */ +}; + +typedef struct idl_import idl_import_t; +struct idl_import { + idl_import_t *next; + const idl_scope_t *scope; +}; + +struct idl_scope { + enum idl_scope_kind { + IDL_GLOBAL_SCOPE, + IDL_MODULE_SCOPE, + IDL_ANNOTATION_SCOPE, + IDL_STRUCT_SCOPE, + IDL_UNION_SCOPE + } kind; + const idl_scope_t *parent; + const idl_name_t *name; + struct { + idl_declaration_t *first, *last; + } declarations; + struct { + idl_import_t *first, *last; + } imports; +}; + +IDL_EXPORT idl_scope_t *idl_scope(const void *node); +IDL_EXPORT idl_declaration_t *idl_declaration(const void *node); + +struct idl_pstate; + +#define IDL_FIND_IGNORE_CASE (1u<<0) +#define IDL_FIND_IGNORE_IMPORTS (1u<<1) +#define IDL_FIND_ANNOTATION (1u<<2) + +IDL_EXPORT const idl_declaration_t * +idl_find( + const struct idl_pstate *pstate, + const idl_scope_t *scope, + const idl_name_t *name, + uint32_t flags); + +IDL_EXPORT const idl_declaration_t * +idl_find_scoped_name( + const struct idl_pstate *pstate, + const idl_scope_t *scope, + const idl_scoped_name_t *scoped_name, + uint32_t flags); + +IDL_EXPORT const idl_declaration_t * +idl_find_field_name( + const struct idl_pstate *pstate, + const idl_scope_t *scope, + const idl_field_name_t *field_name, + uint32_t flags); + +#endif /* IDL_SCOPE_H */ diff --git a/src/idlc/src/org/eclipse/cyclonedds/Symbol.java b/src/idl/include/idl/stream.h similarity index 53% rename from src/idlc/src/org/eclipse/cyclonedds/Symbol.java rename to src/idl/include/idl/stream.h index 31a03735c2..e7b7ff6717 100644 --- a/src/idlc/src/org/eclipse/cyclonedds/Symbol.java +++ b/src/idl/include/idl/stream.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2021 ADLINK Technology Limited and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -9,19 +9,16 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.cyclonedds; +#ifndef IDL_STREAM_H +#define IDL_STREAM_H -public abstract class Symbol -{ - Symbol (ScopedName name) - { - this.name = name; - } +#include +#include - public ScopedName name () - { - return new ScopedName (name); - } +#include "idl/export.h" - private ScopedName name; -} +IDL_EXPORT int idl_fprintf(FILE *fp, const char *fmt, ...); + +IDL_EXPORT int idl_vfprintf(FILE *fp, const char *fmt, va_list ap); + +#endif /* IDL_STREAM_H */ diff --git a/src/idl/include/idl/string.h b/src/idl/include/idl/string.h new file mode 100644 index 0000000000..1960cf2f7b --- /dev/null +++ b/src/idl/include/idl/string.h @@ -0,0 +1,56 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_STRING_H +#define IDL_STRING_H + +#include +#include + +#include "idl/export.h" + +IDL_EXPORT int idl_isalnum(int c); +IDL_EXPORT int idl_isalpha(int c); +IDL_EXPORT int idl_isblank(int c); +IDL_EXPORT int idl_iscntrl(int c); +IDL_EXPORT int idl_isgraph(int c); +IDL_EXPORT int idl_islower(int c); +IDL_EXPORT int idl_isprint(int c); +IDL_EXPORT int idl_ispunct(int c); +IDL_EXPORT int idl_isspace(int c); +IDL_EXPORT int idl_isupper(int c); +IDL_EXPORT int idl_isdigit(int c, int base); +IDL_EXPORT int idl_toupper(int c); +IDL_EXPORT int idl_tolower(int c); + +IDL_EXPORT int idl_strcasecmp(const char *s1, const char *s2); + +IDL_EXPORT int idl_strncasecmp(const char *s1, const char *s2, size_t n); + +IDL_EXPORT char *idl_strdup(const char *str); + +IDL_EXPORT char *idl_strndup(const char *str, size_t len); + +IDL_EXPORT int idl_snprintf(char *str, size_t size, const char *fmt, ...); + +IDL_EXPORT int idl_vsnprintf(char *str, size_t size, const char *fmt, va_list ap); + +IDL_EXPORT int idl_asprintf(char **strp, const char *fmt, ...); + +IDL_EXPORT int idl_vasprintf(char **strp, const char *fmt, va_list ap); + +IDL_EXPORT unsigned long long idl_strtoull(const char *str, char **endptr, int base); + +IDL_EXPORT long double idl_strtold(const char *str, char **endptr); + +IDL_EXPORT char *idl_strtok_r(char *str, const char *delim, char **saveptr); + +#endif /* IDL_STRING_H */ diff --git a/src/idl/include/idl/symbol.h b/src/idl/include/idl/symbol.h new file mode 100644 index 0000000000..16cb07ff66 --- /dev/null +++ b/src/idl/include/idl/symbol.h @@ -0,0 +1,63 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_SYMBOL_H +#define IDL_SYMBOL_H + +#include +#include +#include + +#include "idl/export.h" + +typedef struct idl_file idl_file_t; +struct idl_file { + idl_file_t *next; + char *name; +}; + +typedef struct idl_source idl_source_t; +struct idl_source { + const idl_source_t *parent; + idl_source_t *previous, *next; + idl_source_t *includes; + bool system; /**< system include */ + const idl_file_t *path; /**< normalized path of filename in #line directive */ + const idl_file_t *file; /**< filename in #line directive */ +}; + +typedef struct idl_position { + const idl_source_t *source; + /* for error reporting purposes, the "filename" provided in the #line + directive must be kept. on includes, idlpp provides a (relative) filename + with the proper flags, which becomes the source. user provided #line + directives in the file are used merely in error reporting */ + const idl_file_t *file; /**< (alternate) filename in latest #line directive */ + uint32_t line; + uint32_t column; +} idl_position_t; + +typedef struct idl_location { + idl_position_t first; + idl_position_t last; +} idl_location_t; + +/* symbols are there for the parser(s), nodes are there for the tree. + all nodes are symbols, not all symbols are nodes */ + +typedef struct idl_symbol idl_symbol_t; +struct idl_symbol { + idl_location_t location; +}; + +IDL_EXPORT const idl_location_t *idl_location(const void *symbol); + +#endif /* IDL_SYMBOL_H */ diff --git a/src/idl/include/idl/tree.h b/src/idl/include/idl/tree.h new file mode 100644 index 0000000000..67761115e4 --- /dev/null +++ b/src/idl/include/idl/tree.h @@ -0,0 +1,493 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_TREE_H +#define IDL_TREE_H + +#include +#include + +#include "idl/export.h" +#include "idl/retcode.h" +#include "idl/symbol.h" + +/* the parser constructs a tree representing the idl document from + specialized nodes. each node is derived from the same base node, which + contains properties common accross nodes, and is either a declaration, + specifier, expression, constant, pragma, or combination thereof. constants + contain the result from an expression, pragmas contain compiler-specific + instructions that apply to a specific declaration, much like annotations. + the exact type of a node is stored in the mask property of the base node + and is an constructed by combining preprocessor defines. unique bits are + reserved for categories and properties that generators are likely to filter + on when applying a visitor pattern. */ + +#define IDL_DECLARATION \ + (IDL_MODULE | IDL_CONST | IDL_CONSTR_TYPE | IDL_TYPEDEF | \ + IDL_MEMBER | IDL_CASE | IDL_CASE_LABEL | IDL_ENUMERATOR | IDL_DECLARATOR) + +#define IDL_TYPE \ + (IDL_BASE_TYPE | IDL_TEMPL_TYPE | IDL_CONSTR_TYPE | IDL_TYPEDEF) + +#define IDL_CONSTR_TYPE \ + (IDL_STRUCT | IDL_UNION | IDL_ENUM) + +#define IDL_TEMPL_TYPE \ + (IDL_SEQUENCE | IDL_STRING | IDL_WSTRING | IDL_FIXED_PT) + +/* miscellaneous */ +#define IDL_KEYLIST (1llu<<37) +#define IDL_KEY (1llu<<36) +#define IDL_INHERIT_SPEC (1llu<<35) +#define IDL_SWITCH_TYPE_SPEC (1llu<<34) +#define IDL_LITERAL (1ull<<33) +/* declarations */ +#define IDL_MODULE (1llu<<32) +#define IDL_CONST (1llu<<31) +#define IDL_MEMBER (1llu<<30) +#define IDL_FORWARD (1llu<<29) +#define IDL_CASE (1llu<<28) +#define IDL_CASE_LABEL (1llu<<27) +#define IDL_ENUMERATOR (1llu<<26) +#define IDL_DECLARATOR (1llu<<25) +/* annotations */ +#define IDL_ANNOTATION (1llu<<24) +#define IDL_ANNOTATION_MEMBER (1llu<<23) +#define IDL_ANNOTATION_APPL (1llu<<22) +#define IDL_ANNOTATION_APPL_PARAM (1llu<<21) + +/* bits 19 - 20 are reserved for operators (not exposed in tree) */ + +typedef enum idl_type idl_type_t; +enum idl_type { + IDL_NULL = 0u, + IDL_TYPEDEF = (1llu<<18), + /* constructed types */ + IDL_STRUCT = (1u<<17), + IDL_UNION = (1u<<16), + IDL_ENUM = (1u<<15), + /* template types */ + IDL_SEQUENCE = (1llu<<14), + IDL_STRING = (1llu<<13), + IDL_WSTRING = (1llu<<12), + IDL_FIXED_PT = (1llu<<11), + /* simple types */ + /* miscellaneous base types */ +#define IDL_BASE_TYPE (1llu<<10) +#define IDL_UNSIGNED (1llu<<0) + IDL_CHAR = (IDL_BASE_TYPE | (1u<<1)), + IDL_WCHAR = (IDL_BASE_TYPE | (2u<<1)), + IDL_BOOL = (IDL_BASE_TYPE | (3u<<1)), + IDL_OCTET = (IDL_BASE_TYPE | (4u<<1) | IDL_UNSIGNED), + IDL_ANY = (IDL_BASE_TYPE | (5u<<1)), + /* integer types */ +#define IDL_INTEGER_TYPE (1llu<<9) + IDL_SHORT = (IDL_BASE_TYPE | IDL_INTEGER_TYPE | (1u<<1)), + IDL_USHORT = (IDL_SHORT | IDL_UNSIGNED), + IDL_LONG = (IDL_BASE_TYPE | IDL_INTEGER_TYPE | (2u<<1)), + IDL_ULONG = (IDL_LONG | IDL_UNSIGNED), + IDL_LLONG = (IDL_BASE_TYPE | IDL_INTEGER_TYPE | (3u<<1)), + IDL_ULLONG = (IDL_LLONG | IDL_UNSIGNED), + /* fixed size integer types overlap with legacy integer types in size, but + unique identifiers are required for proper syntax errors. language + bindings may choose to map onto different types as well */ + IDL_INT8 = (IDL_BASE_TYPE | IDL_INTEGER_TYPE | (4u<<1)), + IDL_UINT8 = (IDL_INT8 | IDL_UNSIGNED), + IDL_INT16 = (IDL_BASE_TYPE | IDL_INTEGER_TYPE | (5u<<1)), + IDL_UINT16 = (IDL_INT16 | IDL_UNSIGNED), + IDL_INT32 = (IDL_BASE_TYPE | IDL_INTEGER_TYPE | (6u<<1)), + IDL_UINT32 = (IDL_INT32 | IDL_UNSIGNED), + IDL_INT64 = (IDL_BASE_TYPE | IDL_INTEGER_TYPE | (7u<<1)), + IDL_UINT64 = (IDL_INT64 | IDL_UNSIGNED), + /* floating point types */ +#define IDL_FLOATING_PT_TYPE (1llu<<8) + IDL_FLOAT = (IDL_BASE_TYPE | IDL_FLOATING_PT_TYPE | 1u), + IDL_DOUBLE = (IDL_BASE_TYPE | IDL_FLOATING_PT_TYPE | 2u), + IDL_LDOUBLE = (IDL_BASE_TYPE | IDL_FLOATING_PT_TYPE | 3u) +}; + +typedef struct idl_name idl_name_t; +struct idl_name { + idl_symbol_t symbol; + char *identifier; +}; + +typedef struct idl_scoped_name idl_scoped_name_t; +struct idl_scoped_name { + idl_symbol_t symbol; + bool absolute; + size_t length; + idl_name_t **names; + char *identifier; /**< qualified identifier */ +}; + +typedef struct idl_field_name idl_field_name_t; +struct idl_field_name { + idl_symbol_t symbol; + size_t length; + idl_name_t **names; + char *identifier; /**< field identifier */ +}; + +struct idl_scope; +struct idl_declaration; +struct idl_annotation_appl; + +typedef void idl_const_expr_t; +typedef void idl_definition_t; +typedef void idl_type_spec_t; + +typedef uint64_t idl_mask_t; +typedef void(*idl_delete_t)(void *node); +typedef void *(*idl_iterate_t)(const void *root, const void *node); +typedef const char *(*idl_describe_t)(const void *node); + +typedef struct idl_node idl_node_t; +struct idl_node { + idl_symbol_t symbol; + idl_mask_t mask; + idl_delete_t destructor; + idl_iterate_t iterate; + idl_describe_t describe; + int32_t references; + struct idl_annotation_appl *annotations; + const struct idl_declaration *declaration; + idl_node_t *parent; + idl_node_t *previous, *next; +}; + +typedef struct idl_path idl_path_t; +struct idl_path { + size_t length; + const idl_node_t **nodes; +}; + +typedef struct idl_id idl_id_t; +struct idl_id { + enum { + IDL_AUTOID, /**< value assigned automatically */ + IDL_ID, /**< value assigned by @id */ + IDL_HASHID /**< value assigned by @hashid */ + } annotation; + uint32_t value; +}; + +typedef enum idl_autoid idl_autoid_t; +enum idl_autoid { + IDL_AUTOID_SEQUENTIAL, + IDL_AUTOID_HASH +}; + +typedef enum idl_extensibility idl_extensibility_t; +enum idl_extensibility { + IDL_EXTENSIBILITY_FINAL, + IDL_EXTENSIBILITY_APPENDABLE, + IDL_EXTENSIBILITY_MUTABLE +}; + +/* constructed types are not considered @nested types by default, implicitly + stating the intent to use it as a topic. extensible and dynamic topic types + added @default_nested and @topic to explicitly state the intent to use a + type as a topic. for ease of use, the sum-total is provided as a single + boolean */ +typedef struct idl_nested idl_nested_t; +struct idl_nested { + enum { + IDL_DEFAULT_NESTED, /**< implicit through @default_nested (or not) */ + IDL_NESTED, /**< annotated with @nested */ + IDL_TOPIC /**< annotated with @topic (overrides @nested) */ + } annotation; + bool value; +}; + +/* nullable boolean, like Boolean object in e.g. JavaScript or Java */ +typedef enum idl_boolean idl_boolean_t; +enum idl_boolean { + IDL_DEFAULT, + IDL_FALSE, + IDL_TRUE +}; + +/* annotations */ + +typedef struct idl_const idl_const_t; +struct idl_const { + idl_node_t node; + idl_name_t *name; + idl_type_spec_t *type_spec; + idl_const_expr_t *const_expr; +}; + +/* constants contain the value of resolved constant expressions and are used + if the resulting constant value can be of more than one type, e.g. in + constant declarations, case labels, etc. language native types are used if + the resulting constant value is required to be of a specific base type, + e.g. bounds in sequences */ +typedef struct idl_literal idl_literal_t; +struct idl_literal { + idl_node_t node; + union { + bool bln; + char chr; + int8_t int8; + uint8_t uint8; + int16_t int16; + uint16_t uint16; + int32_t int32; + uint32_t uint32; + int64_t int64; + uint64_t uint64; + float flt; + double dbl; + long double ldbl; + char *str; + } value; +}; + +typedef struct idl_base_type idl_base_type_t; +struct idl_base_type { + idl_node_t node; + /* empty */ +}; + +typedef struct idl_sequence idl_sequence_t; +struct idl_sequence { + idl_node_t node; + idl_type_spec_t *type_spec; + uint32_t maximum; +}; + +typedef struct idl_string idl_string_t; +struct idl_string { + idl_node_t node; + uint32_t maximum; +}; + +typedef struct idl_module idl_module_t; +struct idl_module { + idl_node_t node; + idl_name_t *name; + idl_definition_t *definitions; + const idl_module_t *previous; /**< previous module if module was reopened */ + /* metadata */ + idl_boolean_t default_nested; +}; + +typedef struct idl_declarator idl_declarator_t; +struct idl_declarator { + idl_node_t node; + idl_name_t *name; + idl_const_expr_t *const_expr; +}; + +typedef struct idl_member idl_member_t; +struct idl_member { + idl_node_t node; + idl_type_spec_t *type_spec; + idl_declarator_t *declarators; + /* metadata */ + idl_boolean_t key; + idl_id_t id; +}; + +/* types can inherit from and extend other types (interfaces, values and + structs). declarations in the base type that become available in the + derived type as a consequence are imported into the scope */ +typedef struct idl_inherit_spec idl_inherit_spec_t; +struct idl_inherit_spec { + idl_node_t node; + void *base; +}; + +/* keylist directives can use dotted names, e.g. "#pragma keylist foo bar.baz" + in "struct foo { struct bar { long baz; }; };" to declare a member as key. + this notation makes it possible for "baz" to only be a key member if "bar" + is embedded in "foo" and for key order to differ from field order */ +typedef struct idl_key idl_key_t; +struct idl_key { + idl_node_t node; + /* store entire field name as context matters for embedded struct fields */ + idl_field_name_t *field_name; +}; + +typedef struct idl_keylist idl_keylist_t; +struct idl_keylist { + idl_node_t node; + idl_key_t *keys; +}; + +typedef struct idl_struct idl_struct_t; +struct idl_struct { + idl_node_t node; + idl_inherit_spec_t *inherit_spec; + struct idl_name *name; + idl_member_t *members; + /* metadata */ + idl_nested_t nested; /**< if type is a topic (sum total of annotations) */ + idl_keylist_t *keylist; /**< if type is a topic (#pragma keylist) */ + idl_autoid_t autoid; + idl_extensibility_t extensibility; +}; + +typedef struct idl_case_label idl_case_label_t; +struct idl_case_label { + idl_node_t node; + void *const_expr; +}; + +typedef struct idl_case idl_case_t; +struct idl_case { + idl_node_t node; + idl_case_label_t *case_labels; + idl_type_spec_t *type_spec; + idl_declarator_t *declarator; +}; + +typedef struct idl_switch_type_spec idl_switch_type_spec_t; +struct idl_switch_type_spec { + idl_node_t node; + idl_type_spec_t *type_spec; + /* metadata */ + idl_boolean_t key; +}; + +typedef struct idl_union idl_union_t; +struct idl_union { + idl_node_t node; + struct idl_name *name; + idl_switch_type_spec_t *switch_type_spec; + idl_case_t *cases; + /* metadata */ + idl_nested_t nested; /**< if type is topic (sum total of annotations) */ + idl_extensibility_t extensibility; +}; + +typedef struct idl_enumerator idl_enumerator_t; +struct idl_enumerator { + idl_node_t node; + struct idl_name *name; + uint32_t value; +}; + +typedef struct idl_enum idl_enum_t; +struct idl_enum { + idl_node_t node; + struct idl_name *name; + idl_enumerator_t *enumerators; + idl_extensibility_t extensibility; +}; + +typedef struct idl_typedef idl_typedef_t; +struct idl_typedef { + idl_node_t node; + void *type_spec; + idl_declarator_t *declarators; +}; + +struct idl_pstate; +typedef idl_retcode_t (*idl_annotation_callback_t)( + struct idl_pstate *, + struct idl_annotation_appl *, + idl_node_t *); + +typedef struct idl_annotation_member idl_annotation_member_t; +struct idl_annotation_member { + idl_node_t node; + idl_type_spec_t *type_spec; + idl_declarator_t *declarator; + idl_const_expr_t *const_expr; /**< default value (if any) */ +}; + +typedef void idl_annotation_definition_t; + +typedef struct idl_annotation idl_annotation_t; +struct idl_annotation { + idl_node_t node; + idl_name_t *name; + /** definitions that together form the body, e.g. member, enum, etc */ + idl_definition_t *definitions; + idl_annotation_callback_t callback; +}; + +typedef struct idl_annotation_appl_param idl_annotation_appl_param_t; +struct idl_annotation_appl_param { + idl_node_t node; + idl_annotation_member_t *member; + idl_const_expr_t *const_expr; /**< constant or enumerator */ +}; + +typedef struct idl_annotation_appl idl_annotation_appl_t; +struct idl_annotation_appl { + idl_node_t node; + const idl_annotation_t *annotation; + idl_annotation_appl_param_t *parameters; +}; + +IDL_EXPORT bool idl_is_declaration(const void *node); +IDL_EXPORT bool idl_is_module(const void *node); +IDL_EXPORT bool idl_is_const(const void *node); +IDL_EXPORT bool idl_is_literal(const void *node); +IDL_EXPORT bool idl_is_type_spec(const void *node); +IDL_EXPORT bool idl_is_base_type(const void *node); +IDL_EXPORT bool idl_is_floating_pt_type(const void *node); +IDL_EXPORT bool idl_is_integer_type(const void *node); +IDL_EXPORT bool idl_is_templ_type(const void *node); +IDL_EXPORT bool idl_is_bounded(const void *node); +IDL_EXPORT bool idl_is_sequence(const void *node); +IDL_EXPORT bool idl_is_string(const void *node); +IDL_EXPORT bool idl_is_constr_type(const void *node); +IDL_EXPORT bool idl_is_struct(const void *node); +IDL_EXPORT bool idl_is_inherit_spec(const void *node); +IDL_EXPORT bool idl_is_member(const void *node); +IDL_EXPORT bool idl_is_union(const void *node); +IDL_EXPORT bool idl_is_switch_type_spec(const void *node); +IDL_EXPORT bool idl_is_case(const void *node); +IDL_EXPORT bool idl_is_default_case(const void *node); +IDL_EXPORT bool idl_is_case_label(const void *node); +IDL_EXPORT bool idl_is_enum(const void *node); +IDL_EXPORT bool idl_is_enumerator(const void *node); +IDL_EXPORT bool idl_is_alias(const void *node); +IDL_EXPORT bool idl_is_typedef(const void *node); +IDL_EXPORT bool idl_is_declarator(const void *node); +IDL_EXPORT bool idl_is_array(const void *node); +IDL_EXPORT bool idl_is_annotation_member(const void *node); +IDL_EXPORT bool idl_is_annotation_appl(const void *node); +IDL_EXPORT bool idl_is_topic(const void *node, bool keylist); +/* 1-based, returns 0 if path does not refer to key, non-0 otherwise */ +IDL_EXPORT uint32_t idl_is_topic_key(const void *node, bool keylist, const idl_path_t *path); + +/* accessors */ +IDL_EXPORT idl_mask_t idl_mask(const void *node); +IDL_EXPORT idl_type_t idl_type(const void *node); +IDL_EXPORT idl_type_spec_t *idl_type_spec(const void *node); +/* return a string describing the language construct. e.g. "module" or + "forward struct" for modules and forward struct declarations respectively */ +IDL_EXPORT const char *idl_construct(const void *node); +IDL_EXPORT const char *idl_identifier(const void *node); +IDL_EXPORT const idl_name_t *idl_name(const void *node); +IDL_EXPORT uint32_t idl_array_size(const void *node); +IDL_EXPORT uint32_t idl_bound(const void *node); + +/* navigation */ +IDL_EXPORT void *idl_ancestor(const void *node, size_t levels); +IDL_EXPORT void *idl_parent(const void *node); +IDL_EXPORT size_t idl_degree(const void *node); +IDL_EXPORT void *idl_next(const void *node); +IDL_EXPORT void *idl_previous(const void *node); +IDL_EXPORT void *idl_iterate(const void *root, const void *node); + +#define IDL_FOREACH(node, list) \ + for ((node) = (list); (node); (node) = idl_next(node)) + +#define IDL_UNALIAS_IGNORE_ARRAY (1u<<0) /**< ignore array declarators */ +IDL_EXPORT void *idl_unalias(const void *node, uint32_t flags); + +#endif /* IDL_TREE_H */ diff --git a/src/idl/include/idl/version.h.in b/src/idl/include/idl/version.h.in new file mode 100644 index 0000000000..2d3dbd9b7a --- /dev/null +++ b/src/idl/include/idl/version.h.in @@ -0,0 +1,21 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_VERSION_H +#define IDL_VERSION_H + +#define IDL_VERSION "@CycloneDDS_VERSION@" +#define IDL_VERSION_MAJOR @CycloneDDS_VERSION_MAJOR@ +#define IDL_VERSION_MINOR @CycloneDDS_VERSION_MINOR@ +#define IDL_VERSION_PATCH @CycloneDDS_VERSION_PATCH@ +#define IDL_VERSION_TWEAK @CycloneDDS_VERSION_TWEAK@ + +#endif /* IDL_VERSION_H */ diff --git a/src/idl/include/idl/visit.h b/src/idl/include/idl/visit.h new file mode 100644 index 0000000000..9a241cc89e --- /dev/null +++ b/src/idl/include/idl/visit.h @@ -0,0 +1,123 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDL_VISIT_H +#define IDL_VISIT_H + +#include "idl/export.h" +#include "idl/tree.h" + +struct idl_pstate; + +typedef enum idl_accept idl_accept_t; +enum idl_accept { + IDL_ACCEPT_INHERIT_SPEC, + IDL_ACCEPT_SWITCH_TYPE_SPEC, + IDL_ACCEPT_MODULE, + IDL_ACCEPT_CONST, + IDL_ACCEPT_MEMBER, + IDL_ACCEPT_FORWARD, + IDL_ACCEPT_CASE, + IDL_ACCEPT_CASE_LABEL, + IDL_ACCEPT_ENUMERATOR, + IDL_ACCEPT_DECLARATOR, + IDL_ACCEPT_ANNOTATION, + IDL_ACCEPT_ANNOTATION_APPL, + IDL_ACCEPT_TYPEDEF, + IDL_ACCEPT_STRUCT, + IDL_ACCEPT_UNION, + IDL_ACCEPT_ENUM, + IDL_ACCEPT_SEQUENCE, + IDL_ACCEPT_STRING, + IDL_ACCEPT /**< generic callback, used if no specific callback exists */ +}; + +/* generating native language representations for types is relatively + straightforward, but generating serialization code requires more context. + path objects form a simple stack that generators can iterate */ + +typedef idl_retcode_t(*idl_visitor_callback_t)( + const struct idl_pstate *pstate, + const bool revisit, + const idl_path_t *path, + const void *node, + void *user_data); + +/* the visitor mechanism is a pragmatic combination based on the listener and + visitor mechanisms in ANTLRv4. default behavior is to iterate depth-first + over the (sub)tree, visiting each node once, but the visitor can be + instructed to visit the node again by signalling IDL_VISIT_REVISIT or skip + an entire subtree by signalling IDL_VISIT_DONT_RECURSE. the visitor can be + instructed to visit the type specifier for a declarator by signalling + IDL_VISIT_TYPE_SPEC, which is useful when generating serialization code. + default behavior can be inverted by specifying IDL_VISIT_DONT_RECURSE, + IDL_VISIT_DONT_ITERATE or IDL_VISIT_REVISIT in the visitor, callbacks can + instruct the visitor to recurse, iterate and/or revisit by signalling the + inverse */ + +typedef enum idl_visit_recurse idl_visit_recurse_t; +enum idl_visit_recurse { + IDL_VISIT_RECURSE_BY_DEFAULT = 0, + IDL_VISIT_RECURSE = (1<<0), /**< Recurse into subtree(s) */ + IDL_VISIT_DONT_RECURSE = (1<<1) /**< Do not recurse into subtree(s) */ +}; + +#if 0 +/* FIXME: does not quite make sense in the current implementation. applies to + it now applies to the next level. instead, it should apply to the + current level. in which case IDL_VISIT_ITERATE instructs the + visitor to continue, IDL_VISIT_DONT_ITERATE does the inverse! +*/ +typedef enum idl_visit_iterate idl_visit_iterate_t; +enum idl_visit_iterate { + IDL_VISIT_ITERATE_BY_DEFAULT = 0, + IDL_VISIT_ITERATE = (1<<2), /**< Iterate over subtree(s) */ + IDL_VISIT_DONT_ITERATE = (1<<3) /**< Do not iterate over subtree(s) */ +}; +#endif + +typedef enum idl_visit_revisit idl_visit_revisit_t; +enum idl_visit_revisit { + IDL_VISIT_DONT_REVISIT_BY_DEFAULT = 0, + IDL_VISIT_REVISIT = (1<<4), /**< Revisit node(s) on exit */ + IDL_VISIT_DONT_REVISIT = (1<<5) /**< Do not revisit node(s) on exit */ +}; + +/** Visit associated type specifier (callback signal) */ +#define IDL_VISIT_TYPE_SPEC (1<<6) +/** Unalias associated type specifier (callback signal) */ +#define IDL_VISIT_UNALIAS_TYPE_SPEC (1<<7) + +/* FIXME: add IDL_VISIT_ARRAY that complements IDL_VISIT_TYPE_SPEC and takes + into account array declarators, which is incredibly useful for + backends, like the native generator for Cyclone DDS, that need to + unroll for generating serialization code */ + +typedef struct idl_visitor idl_visitor_t; +struct idl_visitor { + idl_mask_t visit; + idl_visit_recurse_t recurse; +#if 0 + idl_visit_iterate_t iterate; +#endif + idl_visit_revisit_t revisit; + idl_visitor_callback_t accept[IDL_ACCEPT + 1]; + const char **sources; +}; + +IDL_EXPORT idl_retcode_t +idl_visit( + const struct idl_pstate *pstate, + const void *node, + const idl_visitor_t *visitor, + void *user_data); + +#endif /* IDL_VISIT_H */ diff --git a/src/idl/src/annotation.c b/src/idl/src/annotation.c new file mode 100644 index 0000000000..9e017268a6 --- /dev/null +++ b/src/idl/src/annotation.c @@ -0,0 +1,706 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "idl/processor.h" +#include "annotation.h" +#include "expression.h" +#include "hashid.h" +#include "tree.h" + +static idl_retcode_t +annotate_id( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_LITERAL|IDL_ULONG; +#endif + idl_literal_t *literal; + + assert(annotation_appl); + assert(annotation_appl->parameters); + literal = (idl_literal_t *)annotation_appl->parameters->const_expr; + assert((idl_mask(literal) & mask) == mask); + + if (idl_mask(node) & IDL_MEMBER) { + idl_member_t *member = (idl_member_t *)node; + if (idl_next(member->declarators)) { + idl_error(pstate, idl_location(annotation_appl), + "@id cannot be applied to members with multiple declarators"); + return IDL_RETCODE_SEMANTIC_ERROR; + } else if (member->id.annotation != IDL_AUTOID) { + idl_error(pstate, idl_location(annotation_appl), + "@id conflicts with earlier annotation"); + return IDL_RETCODE_SEMANTIC_ERROR; + } + member->id.annotation = IDL_ID; + member->id.value = literal->value.uint32; + } else { + idl_error(pstate, idl_location(annotation_appl), + "@id cannot be applied to %s elements", idl_construct(node)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_hashid( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + const char *name = NULL; + + assert(annotation_appl); + if (annotation_appl->parameters) { +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_LITERAL|IDL_STRING; +#endif + idl_literal_t *literal = annotation_appl->parameters->const_expr; + assert((idl_mask(literal) & mask) == mask); + name = literal->value.str; + } + + if (idl_mask(node) & IDL_MEMBER) { + idl_member_t *member = (idl_member_t *)node; + if (idl_next(member->declarators)) { + idl_error(pstate, idl_location(annotation_appl), + "@hashid cannot be applied to members with multiple declarators"); + return IDL_RETCODE_SEMANTIC_ERROR; + } else if (member->id.annotation != IDL_AUTOID) { + idl_error(pstate, idl_location(annotation_appl), + "@hashid conflicts with earlier annotation"); + return IDL_RETCODE_SEMANTIC_ERROR; + } + if (!name) + name = member->declarators->name->identifier; + member->id.annotation = IDL_ID; + member->id.value = idl_hashid(name); + } else { + idl_error(pstate, idl_location(annotation_appl), + "@hashid cannot be applied to '%s' elements", idl_construct(node)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_autoid( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + idl_autoid_t autoid = IDL_AUTOID_HASH; + const char *enumerator; + + assert(annotation_appl); + assert(annotation_appl->parameters); + if (annotation_appl->parameters) { + enumerator = idl_identifier(annotation_appl->parameters->const_expr); + if (strcmp(enumerator, "HASH") == 0) { + autoid = IDL_AUTOID_HASH; + } else if (strcmp(enumerator, "SEQUENTIAL") == 0) { + autoid = IDL_AUTOID_SEQUENTIAL; + } + } + + if (idl_is_struct(node)) { + ((idl_struct_t *)node)->autoid = autoid; + } else { + idl_error(pstate, idl_location(annotation_appl), + "@autoid cannot be applied to '%s' elements", idl_construct(node)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_optional( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), + "@optional not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_value( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), + "@value not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_extensibility( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + idl_extensibility_t extensibility = IDL_EXTENSIBILITY_FINAL; + const char *annotation; + + assert(annotation_appl); + annotation = idl_identifier(annotation_appl->annotation); + assert(annotation); + + if (strcmp(annotation, "final") == 0) { + extensibility = IDL_EXTENSIBILITY_FINAL; + } else if (strcmp(annotation, "appendable") == 0) { + extensibility = IDL_EXTENSIBILITY_APPENDABLE; + } else if (strcmp(annotation, "mutable") == 0) { + extensibility = IDL_EXTENSIBILITY_MUTABLE; + } else if (strcmp(annotation, "extensibility") == 0) { + const char *enumerator = ""; + + assert(annotation_appl->parameters); + assert(annotation_appl->parameters->const_expr); + enumerator = idl_identifier(annotation_appl->parameters->const_expr); + assert(enumerator); + if (strcmp(enumerator, "FINAL") == 0) { + extensibility = IDL_EXTENSIBILITY_FINAL; + } else if (strcmp(enumerator, "APPENDABLE") == 0) { + extensibility = IDL_EXTENSIBILITY_APPENDABLE; + } else if (strcmp(enumerator, "MUTABLE") == 0) { + extensibility = IDL_EXTENSIBILITY_MUTABLE; + } + } + + if (idl_is_struct(node)) { + ((idl_struct_t *)node)->extensibility = extensibility; + } else if (idl_is_union(node)) { + ((idl_union_t *)node)->extensibility = extensibility; + } else if (idl_is_enum(node)) { + ((idl_enum_t *)node)->extensibility = extensibility; + } else { + idl_error(pstate, idl_location(annotation_appl), + "@%s can only be applied to constructed types", annotation); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_key( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + idl_boolean_t key = IDL_TRUE; + + if (annotation_appl->parameters) { +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_LITERAL|IDL_BOOL; +#endif + idl_literal_t *literal = annotation_appl->parameters->const_expr; + assert((idl_mask(literal) & mask) == mask); + key = literal->value.bln ? IDL_TRUE : IDL_FALSE; + } + + if (idl_mask(node) & IDL_MEMBER) { + ((idl_member_t *)node)->key = key; + } else if (idl_mask(node) & IDL_SWITCH_TYPE_SPEC) { + ((idl_switch_type_spec_t *)node)->key = key; + } else { + idl_error(pstate, idl_location(annotation_appl), + "@key can only be applied to members of constructed types"); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_must_understand( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), + "@must_understand not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_default( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), "@default not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_range( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), "@range not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_min( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), "@min not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_max( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), "@max not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_unit( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + (void)node; + idl_warning(pstate, idl_location(annotation_appl), "@unit not supported"); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_nested( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + bool nested = true; + + if (annotation_appl->parameters) { +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_LITERAL|IDL_BOOL; +#endif + idl_literal_t *literal = annotation_appl->parameters->const_expr; + assert((idl_mask(literal) & mask) == mask); + nested = literal->value.bln; + } + + if (idl_is_struct(node)) { + /* @topic overrides @nested */ + if (((idl_struct_t *)node)->nested.annotation == IDL_TOPIC) + return IDL_RETCODE_OK; + ((idl_struct_t *)node)->nested.annotation = IDL_NESTED; + ((idl_struct_t *)node)->nested.value = nested; + } else if (idl_is_union(node)) { + /* @topic overrides @nested */ + if (((idl_union_t *)node)->nested.annotation == IDL_TOPIC) + return IDL_RETCODE_OK; + ((idl_union_t *)node)->nested.annotation = IDL_NESTED; + ((idl_union_t *)node)->nested.value = nested; + } else { + idl_error(pstate, idl_location(annotation_appl), + "@nested cannot be applied to %s elements", idl_construct(node)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_topic( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + const char *platform = "*"; /* default is any platform */ + const char *identifier; + const idl_annotation_appl_param_t *parameter; + + IDL_FOREACH(parameter, annotation_appl->parameters) { + identifier = idl_identifier(parameter->member); + assert(identifier); + if (strcmp(identifier, "platform") != 0) + continue; + assert(idl_mask(parameter->const_expr) & IDL_STRING); + platform = ((idl_literal_t *)parameter->const_expr)->value.str; + break; + } + + /* only apply topic annotation if platform equals "*" or "DDS" */ + if (strcmp(platform, "*") != 0 && strcmp(platform, "DDS") != 0) + return IDL_RETCODE_OK; + + if (idl_is_struct(node)) { + ((idl_struct_t *)node)->nested.annotation = IDL_TOPIC; + ((idl_struct_t *)node)->nested.value = false; + } else if (idl_is_union(node)) { + ((idl_union_t *)node)->nested.annotation = IDL_TOPIC; + ((idl_union_t *)node)->nested.value = false; + } else { + idl_error(pstate, idl_location(annotation_appl), + "@topic can only be applied to constructed types"); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +annotate_implicitly_nested(void *node) +{ + idl_retcode_t ret = IDL_RETCODE_OK; + + for (; ret == IDL_RETCODE_OK && node; node = idl_next(node)) { + if (idl_is_struct(node)) { + /* skip if annotated with @nested or @topic before */ + if (!((idl_struct_t *)node)->nested.annotation) + ((idl_struct_t *)node)->nested.value = true; + } else if (idl_is_union(node)) { + /* skip if annotated with @nested or @topic before */ + if (!((idl_union_t *)node)->nested.annotation) + ((idl_union_t *)node)->nested.value = true; + } else if (idl_is_module(node)) { + /* skip if annotated with @default_nested before */ + if (!((idl_module_t *)node)->default_nested) + ret = annotate_implicitly_nested(((idl_module_t *)node)->definitions); + } + } + + return ret; +} + +static idl_retcode_t +annotate_default_nested( + idl_pstate_t *pstate, + idl_annotation_appl_t *annotation_appl, + idl_node_t *node) +{ + idl_boolean_t default_nested = IDL_TRUE; + + if (annotation_appl->parameters) { +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_LITERAL|IDL_BOOL; +#endif + idl_literal_t *literal = annotation_appl->parameters->const_expr; + assert((idl_mask(literal) & mask) == mask); + default_nested = literal->value.bln ? IDL_TRUE : IDL_FALSE; + } + + if ((idl_mask(node) & IDL_MODULE)) { + idl_module_t *module = (idl_module_t *)node; + if (module->default_nested == IDL_DEFAULT) { + module->default_nested = default_nested; + if (module->default_nested != IDL_TRUE) + return IDL_RETCODE_OK; + /* annotate all embedded structs and unions implicitly nested unless + explicitly annotated with either @nested or @topic */ + return annotate_implicitly_nested(module->definitions); + } else { + idl_error(pstate, idl_location(annotation_appl), + "@default_nested conflicts with earlier annotation"); + return IDL_RETCODE_SEMANTIC_ERROR; + } + } else { + idl_error(pstate, idl_location(annotation_appl), + "@default_nested cannot be applied to %s elements", idl_construct(node)); + return IDL_RETCODE_SEMANTIC_ERROR; + } +} + +static const idl_builtin_annotation_t annotations[] = { + /* general purpose */ + { .syntax = "@annotation id { unsigned long value; };", + .summary = + "

Assign a 32-bit unsigned integer identifier to an element, with " + "the underlying assumption that an identifier should be unique inside " + "its scope of application. The precise scope of uniqueness depends on " + "the type of specification making use of it.

", + .callback = &annotate_id }, + { .syntax = + "@annotation autoid {\n" + " enum AutoidKind { SEQUENTIAL, HASH };\n" + " AutoidKind value default HASH;\n" + "};", + .summary = + "

Complements @id and is applicable to any set containing elements " + "to which allocating 32-bit unsigned identifiers makes sense. @autoid " + "instructs to automatically allocate identifiers to elements that have " + "not been assigned a 32-bit unsigned identifiers explicitly.

", + .callback = &annotate_autoid }, + { .syntax = "@annotation optional { boolean value default TRUE; };", + .summary = + "

Set optionality on any element that makes to be optional.

", + .callback = annotate_optional }, + { .syntax = "@annotation value { any value; };", + .summary = + "

Set a constant value to any element that may be given a constant " + "value. More versatile than @id as it may carry any constant value, " + "but does not carry any concept of uniqueness among a set.

", + .callback = annotate_value }, + { .syntax = + "@annotation extensibility {\n" + " enum ExtensibilityKind { FINAL, APPEND, MUTABLE };\n" + " ExtensibilityKind value;\n" + "};", + .summary = + "

Specify a given constructed element, such as a data type or an " + "interface, is allowed to evolve.

", + .callback = annotate_extensibility }, + { .syntax = "@annotation final { };", + .summary = "

Shorthand for @extensibility(FINAL).

", + .callback = annotate_extensibility }, + { .syntax = "@annotation appendable { };", + .summary = "

Shorthand for @extensibility(APPENDABLE).

", + .callback = annotate_extensibility }, + { .syntax = "@annotation mutable { };", + .summary = "

Shorthand for @extensibility(MUTABLE).

", + .callback = annotate_extensibility }, + /* data modeling */ + { .syntax = "@annotation key { boolean value default TRUE; };", + .summary = + "

Specify a data member is part of the key for the object whose type " + "is the constructed data type owning this element.

", + .callback = annotate_key }, + { .syntax = "@annotation must_understand { boolean value default TRUE; };", + .summary = + "

Specify the data member must be understood by any application " + "making use of that piece of data.

", + .callback = annotate_must_understand }, + /* units and ranges */ + { .syntax = "@annotation default { any value; };", + .summary = + "

Specify a default value for the annotated element.

", + .callback = annotate_default }, + { .syntax = "@annotation range { any min; any max; };", + .summary = + "

Specify a range of allowed value for the annotated element.

", + .callback = annotate_range }, + { .syntax = "@annotation min { any value; };", + .summary = + "

Specify a minimum value for the annotated element.

", + .callback = annotate_min }, + { .syntax = "@annotation max { any value; };", + .summary = + "

Specify a maximum value for the annotated element.

", + .callback = annotate_max }, + { .syntax = "@annotation unit { string value; };", + .summary = + "

Specify a unit of measurement for the annotated element.

", + .callback = annotate_unit }, + { .syntax = "@annotation nested { boolean value default TRUE; };", + .summary = + "

Specify annotated element is never used as top-level object.

", + .callback = annotate_nested }, + /* extensible and dynamic topic types */ + { .syntax = "@annotation hashid { string value default \"\"; };", + .summary = + "

Assign a 32-bit unsigned integer identifier to an element " + "derived from the member name or a string specified in the " + "annotation parameter.

", + .callback = annotate_hashid }, + { .syntax = + "@annotation topic {\n" + " string name default \"\";\n" + " string platform default \"*\";\n" + "};", + .summary = + "

Specify annotated element is used as top-level object.

", + .callback = annotate_topic }, + { .syntax = "@annotation default_nested { boolean value default TRUE; };", + .summary = + "

Change aggregated types contained in annotated module are " + "considered nested unless otherwise annotated by @topic or @nested.

", + .callback = annotate_default_nested }, + { .syntax = NULL, .summary = NULL, .callback = 0 } +}; + +const idl_builtin_annotation_t *builtin_annotations = annotations; + +static idl_annotation_appl_param_t * +find( + const idl_annotation_appl_t *annotation_appl, + const idl_annotation_member_t *annotation_member) +{ + const idl_annotation_appl_param_t *ap; + + for (ap = annotation_appl->parameters; ap; ap = idl_next(ap)) { + if (ap->member == annotation_member) + return (idl_annotation_appl_param_t *)ap; + } + + return NULL; +} + +static idl_retcode_t +eval(idl_pstate_t *pstate, void *node, idl_annotation_appl_t *appls) +{ + idl_retcode_t ret; + + for (idl_annotation_appl_t *a = appls; a; a = idl_next(a)) { + assert(a->annotation); + idl_annotation_appl_param_t *ap; + for (ap = a->parameters; ap; ap = idl_next(ap)) { + idl_type_t type; + idl_literal_t *literal = NULL; + assert(ap->member); + assert(ap->member->type_spec); + if ((type = idl_type(ap->member->type_spec)) == IDL_ANY) + type = idl_type(node); + if (!type) { + idl_error(pstate, idl_location(ap), + "@%s cannot be applied to '%s' elements", + idl_identifier(a->annotation), idl_construct(node)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + if ((ret = idl_evaluate(pstate, ap->const_expr, type, &literal))) + return ret; + assert(literal); + if (!idl_scope(literal)) + ((idl_node_t *)literal)->parent = (idl_node_t *)ap; + ap->const_expr = literal; + } + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +dedup(idl_pstate_t *pstate, void *node, idl_annotation_appl_t *appls) +{ + (void)node; + + /* deduplicate parameters for annotations */ + for (idl_annotation_appl_t *a = appls; a; a = idl_next(a)) { + idl_definition_t *d; + idl_annotation_member_t *m; + idl_annotation_appl_param_t *ap; + assert(a->annotation); + for (ap = a->parameters; ap; ap = idl_next(ap)) { + assert(ap->member); + idl_annotation_appl_param_t *cap, *nap; + for (cap = idl_next(ap); cap; cap = nap) { + nap = idl_next(cap); + if (cap->member != ap->member) + continue; + if (idl_compare(pstate, cap->const_expr, ap->const_expr) != 0) { + idl_error(pstate, idl_location(cap), + "Incompatible assignment of '%s' in application of @%s", + idl_identifier(cap->member->declarator), + idl_identifier(a->annotation)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + idl_unreference_node(cap); + } + } + /* ensure all required parameters are provided */ + for (d = a->annotation->definitions; d; d = idl_next(d)) { + if (!idl_is_annotation_member(d)) + continue; + m = (idl_annotation_member_t *)d; + if (m->const_expr || find(a, m)) + continue; + idl_error(pstate, idl_location(a), + "Missing assignment of '%s' in application of @%s", + idl_identifier(m->declarator), + idl_identifier(a->annotation)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + } + + /* deduplication */ + for (idl_annotation_appl_t *a = appls; a; a = idl_next(a)) { + idl_definition_t *d; + idl_annotation_member_t *m; + assert(a->annotation); + for (idl_annotation_appl_t *na, *ca = idl_next(a); ca; ca = na) { + na = idl_next(ca); + if (ca->annotation != a->annotation) + continue; + for (d = a->annotation->definitions; d; d = idl_next(d)) { + /* skip non-members */ + if (!idl_is_annotation_member(d)) + continue; + m = (idl_annotation_member_t *)d; + idl_const_expr_t *lval, *rval; + idl_annotation_appl_param_t *ap; + ap = find(a, m); + lval = ap->const_expr ? ap->const_expr : m->const_expr; + ap = find(ca, m); + rval = ap->const_expr ? ap->const_expr : m->const_expr; + if (lval != rval && idl_compare(pstate, lval, rval) != 0) { + idl_error(pstate, idl_location(ap), + "Incompatible reapplication of @%s", + idl_identifier(a->annotation)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + } + idl_unreference_node(ca); + } + } + + return IDL_RETCODE_OK; +} + +idl_retcode_t +idl_annotate( + idl_pstate_t *pstate, + void *node, + idl_annotation_appl_t *annotation_appls) +{ + idl_retcode_t ret; + + assert(pstate); + assert(node); + + /* evaluate constant expressions */ + if ((ret = eval(pstate, node, annotation_appls))) + return ret; + /* discard redundant annotations and annotation parameters */ + if ((ret = dedup(pstate, node, annotation_appls))) + return ret; + + ((idl_node_t *)node)->annotations = annotation_appls; + for (idl_annotation_appl_t *a = annotation_appls; a; a = idl_next(a)) { + idl_annotation_callback_t callback = a->annotation->callback; + if (callback && (ret = callback(pstate, a, node))) + return ret; + a->node.parent = node; + } + + return IDL_RETCODE_OK; +} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/AbstractType.java b/src/idl/src/annotation.h similarity index 53% rename from src/idlc/src/org/eclipse/cyclonedds/generator/AbstractType.java rename to src/idl/src/annotation.h index 18e41e1dfc..f979eb3040 100644 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/AbstractType.java +++ b/src/idl/src/annotation.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2021 ADLINK Technology Limited and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -9,19 +9,17 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.cyclonedds.generator; +#ifndef ANNOTATION_H +#define ANNOTATION_H -public abstract class AbstractType implements Type -{ - public void makeKeyField () - { - iskey = true; - } +#include "idl/processor.h" - public boolean isKeyField () - { - return iskey; - } +extern const idl_builtin_annotation_t *builtin_annotations; - private boolean iskey = false; -} +idl_retcode_t +idl_annotate( + idl_pstate_t *pstate, + void *node, + idl_annotation_appl_t *annotations); + +#endif /* ANNOTATION_H */ diff --git a/src/idl/src/directive.c b/src/idl/src/directive.c new file mode 100644 index 0000000000..f98589ab95 --- /dev/null +++ b/src/idl/src/directive.c @@ -0,0 +1,622 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#include "idl/processor.h" +#include "idl/file.h" +#include "idl/string.h" + +#include "symbol.h" +#include "tree.h" +#include "scope.h" +#include "directive.h" +#include "parser.h" + +struct directive { + enum { + LINE, /**< #line directive */ + LINEMARKER, /**< GCC linemarker (extended line directive) */ + KEYLIST /**< #pragma keylist directive */ + } type; +}; + +struct line { + struct directive directive; + unsigned long long line; + char *file; + unsigned flags; +}; + +struct keylist { + struct directive directive; + idl_scoped_name_t *data_type; + idl_field_name_t **keys; +}; + +static idl_retcode_t +push_file(idl_pstate_t *pstate, const char *inc) +{ + idl_file_t *file = pstate->files; + for (; file && strcmp(file->name, inc); file = file->next) ; + if (!file) { + if (!(file = calloc(1, sizeof(*file)))) + return IDL_RETCODE_NO_MEMORY; + file->next = pstate->files; + pstate->files = file; + if (!(file->name = idl_strdup(inc))) + return IDL_RETCODE_NO_MEMORY; + } + pstate->scanner.position.file = file; + return IDL_RETCODE_OK; +} + +static idl_retcode_t +push_source(idl_pstate_t *pstate, const char *inc, const char *abs, bool sys) +{ + idl_file_t *path = pstate->paths; + idl_source_t *src, *last; + for (; path && strcmp(path->name, abs); path = path->next) ; + if (!path) { + if (!(path = calloc(1, sizeof(*path)))) + return IDL_RETCODE_NO_MEMORY; + path->next = pstate->paths; + pstate->paths = path; + if (!(path->name = idl_strdup(abs))) + return IDL_RETCODE_NO_MEMORY; + } + if (push_file(pstate, inc)) + return IDL_RETCODE_NO_MEMORY; + if (!(src = calloc(1, sizeof(*src)))) + return IDL_RETCODE_NO_MEMORY; + src->file = pstate->files; + src->path = path; + src->system = sys; + if (!pstate->sources) { + pstate->sources = src; + } else if (pstate->scanner.position.source->includes) { + last = ((idl_source_t *)pstate->scanner.position.source)->includes; + for (; last->next; last = last->next) ; + last->next = src; + src->previous = last; + src->parent = pstate->scanner.position.source; + } else { + ((idl_source_t *)pstate->scanner.position.source)->includes = src; + src->parent = pstate->scanner.position.source; + } + pstate->scanner.position.source = src; + return IDL_RETCODE_OK; +} + +#define START_OF_FILE (1u<<0) +#define RETURN_TO_FILE (1u<<1) +#define SYSTEM_FILE (1u<<2) +#define EXTRA_TOKENS (1u<<3) + +static void delete_line(void *ptr) +{ + struct line *dir = (struct line *)ptr; + assert(dir); + if (dir->file) + free(dir->file); + free(dir); +} + +static idl_retcode_t +push_line(idl_pstate_t *pstate, struct line *dir) +{ + idl_retcode_t ret = IDL_RETCODE_OK; + + assert(dir); + if (dir->flags & (START_OF_FILE|RETURN_TO_FILE)) { + bool sys = (dir->flags & SYSTEM_FILE) != 0; + char *norm = NULL, *abs, *inc; + abs = inc = dir->file; + /* convert to normalized file name */ + if (!idl_isabsolute(abs)) { + /* include paths are relative to the current file. so, strip file name, + postfix with "/relative/path/to/file" and normalize */ + const char *cwd = pstate->scanner.position.source->path->name; + const char *sep = cwd; + assert(idl_isabsolute(cwd)); + for (size_t i=0; cwd[i]; i++) { + if (idl_isseparator(cwd[i])) + sep = cwd + i; + } + if (idl_asprintf(&abs, "%.*s/%s", (sep-cwd), cwd, inc) < 0) + return IDL_RETCODE_NO_MEMORY; + } + idl_normalize_path(abs, &norm); + if (abs != dir->file) + free(abs); + if (!norm) + return IDL_RETCODE_NO_MEMORY; + + if (dir->flags & START_OF_FILE) { + ret = push_source(pstate, inc, norm, sys); + } else { + assert(pstate->scanner.position.source); + const idl_source_t *src = pstate->scanner.position.source; + while (src) { + if (strcmp(src->path->name, norm) == 0) + break; + src = src->parent; + } + if (src) { + pstate->scanner.position.source = src; + pstate->scanner.position.file = src->file; + } else { + idl_error(pstate, idl_location(dir), + "Invalid #line directive, file '%s' not on include stack", inc); + ret = IDL_RETCODE_SEMANTIC_ERROR; + } + } + + free(norm); + } else { + ret = push_file(pstate, dir->file); + } + + if (ret) + return ret; + pstate->scanner.position.line = (uint32_t)dir->line; + pstate->scanner.position.column = 1; + delete_line(dir); + pstate->directive = NULL; + return IDL_RETCODE_OK; +} + +/* for proper handling of includes by parsing line controls, GCCs linemarkers + are required. they are enabled in mcpp by defining the compiler to be GNUC + instead of INDEPENDANT. + See: https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html */ +static int32_t +parse_line(idl_pstate_t *pstate, idl_token_t *tok) +{ + struct line *dir = (struct line *)pstate->directive; + unsigned long long ullng; + + switch (pstate->scanner.state) { + case IDL_SCAN_LINE: + if (tok->code != IDL_TOKEN_PP_NUMBER) { + idl_error(pstate, &tok->location, + "No line number in #line directive"); + return IDL_RETCODE_SYNTAX_ERROR; + } + ullng = idl_strtoull(tok->value.str, NULL, 10); + if (ullng == 0 || ullng > INT32_MAX) { + idl_error(pstate, &tok->location, + "Invalid line number in #line directive"); + return IDL_RETCODE_SYNTAX_ERROR; + } else { + dir->line = ullng; + } + pstate->scanner.state = IDL_SCAN_FILENAME; + break; + case IDL_SCAN_FILENAME: + if (tok->code == '\n' || tok->code == '\0') { + return push_line(pstate, dir); + } else if (tok->code != IDL_TOKEN_STRING_LITERAL) { + idl_error(pstate, &tok->location, + "Invalid filename in #line directive"); + return IDL_RETCODE_SYNTAX_ERROR; + } else { + dir->file = tok->value.str; + } + tok->value.str = NULL; /* do not free */ + pstate->scanner.state = IDL_SCAN_FLAGS; + break; + case IDL_SCAN_FLAGS: + if (tok->code == '\n' || tok->code == '\0') { + return push_line(pstate, dir); + } else if (dir->directive.type == LINE) { + goto extra_tokens; + } else if (tok->code == IDL_TOKEN_PP_NUMBER) { + if (strcmp(tok->value.str, "1") == 0) { + if (dir->flags & (START_OF_FILE|RETURN_TO_FILE)) + goto extra_tokens; + dir->flags |= START_OF_FILE; + } else if (strcmp(tok->value.str, "2") == 0) { + if (dir->flags & (START_OF_FILE|RETURN_TO_FILE)) + goto extra_tokens; + dir->flags |= RETURN_TO_FILE; + } else if (strcmp(tok->value.str, "3") == 0) { + if (dir->flags & (SYSTEM_FILE)) + goto extra_tokens; + dir->flags |= SYSTEM_FILE; + } else { + goto extra_tokens; + } + } else { +extra_tokens: + idl_warning(pstate, &tok->location, + "Extra tokens at end of #line directive"); + pstate->scanner.state = IDL_SCAN_EXTRA_TOKENS; + } + break; + default: + if (tok->code == '\n' || tok->code == '\0') + return push_line(pstate, dir); + break; + } + + return IDL_RETCODE_OK; +} + +static void delete_keylist(void *ptr) +{ + struct keylist *dir = ptr; + assert(dir); + idl_delete_scoped_name(dir->data_type); + if (dir->keys) { + for (size_t i=0; dir->keys[i]; i++) + idl_delete_field_name(dir->keys[i]); + free(dir->keys); + } + free(dir); +} + +static idl_retcode_t +push_keylist(idl_pstate_t *pstate, struct keylist *dir) +{ + idl_retcode_t ret; + idl_scope_t *scope; + idl_struct_t *node; + idl_keylist_t *keylist = NULL; + const idl_declaration_t *declaration; + + assert(dir); + if (!(declaration = idl_find_scoped_name(pstate, NULL, dir->data_type, 0u))) { + idl_error(pstate, idl_location(dir->data_type), + "Unknown data-type '%s' in keylist directive", dir->data_type->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + node = (idl_struct_t *)declaration->node; + scope = (idl_scope_t *)declaration->scope; + if (!idl_is_struct(node)) { + idl_error(pstate, idl_location(dir->data_type), + "Invalid data-type '%s' in keylist directive", dir->data_type->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } else if (node->keylist) { + idl_error(pstate, idl_location(dir->data_type), + "Redefinition of keylist for data-type '%s'", dir->data_type->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + /* check for duplicates */ + for (size_t i=0; dir->keys && dir->keys[i]; i++) { + for (size_t j=i+1; dir->keys && dir->keys[j]; j++) { + size_t n=0; + if (dir->keys[i]->length != dir->keys[j]->length) + continue; + for (; n < dir->keys[i]->length; n++) { + const char *s1, *s2; + s1 = dir->keys[i]->names[n]->identifier; + s2 = dir->keys[j]->names[n]->identifier; + if (strcmp(s1, s2) != 0) + break; + } + if (n == dir->keys[i]->length) { + idl_error(pstate, idl_location(dir->keys[j]), + "Duplicate key '%s' in keylist directive", dir->keys[j]->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + } + } + + if ((ret = idl_create_keylist(pstate, idl_location(dir->data_type), &keylist))) + return ret; + keylist->node.parent = (idl_node_t *)node; + node->keylist = keylist; + + for (size_t i=0; dir->keys && dir->keys[i]; i++) { + idl_key_t *key = NULL; + const idl_declarator_t *declarator; + const idl_type_spec_t *type_spec; + + if (!(declaration = idl_find_field_name(pstate, scope, dir->keys[i], 0u))) { + idl_error(pstate, idl_location(dir->keys[i]), + "Unknown key '%s' in keylist directive", dir->keys[i]->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + declarator = (const idl_declarator_t *)declaration->node; + assert(idl_is_declarator(declarator)); + type_spec = idl_type_spec(declarator); + type_spec = idl_unalias(type_spec, IDL_UNALIAS_IGNORE_ARRAY); + if (!(idl_is_base_type(type_spec) || idl_is_string(type_spec))) { + idl_error(pstate, idl_location(dir->keys[i]), + "Invalid key '%s' type in keylist directive", dir->keys[i]->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if ((ret = idl_create_key(pstate, idl_location(dir->keys[i]), &key))) + return ret; + key->node.parent = (idl_node_t *)keylist; + key->field_name = dir->keys[i]; + keylist->keys = idl_push_node(keylist->keys, key); + dir->keys[i] = NULL; /* do not free */ + } + + delete_keylist(dir); + pstate->directive = NULL; + return IDL_RETCODE_OK; +} + +static int stash_name(idl_pstate_t *pstate, idl_location_t *loc, char *str) +{ + struct keylist *dir = (struct keylist *)pstate->directive; + idl_name_t *name = NULL; + + if (idl_create_name(pstate, loc, str, &name)) + goto err_alloc; + if (idl_push_scoped_name(pstate, dir->data_type, name)) + goto err_alloc; + return 0; +err_alloc: + if (name) + free(name); + return -1; +} + +static int stash_data_type(idl_pstate_t *pstate, idl_location_t *loc, char *str) +{ + struct keylist *dir = (struct keylist *)pstate->directive; + idl_name_t *name = NULL; + + if (idl_create_name(pstate, loc, str, &name)) + goto err_alloc; + if (idl_create_scoped_name(pstate, loc, name, false, &dir->data_type)) + goto err_alloc; + return 0; +err_alloc: + if (name) + free(name); + return -1; +} + +static int stash_field(idl_pstate_t *pstate, idl_location_t *loc, char *str) +{ + struct keylist *dir = (struct keylist *)pstate->directive; + idl_name_t *name = NULL; + size_t n; + + assert(dir->keys); + if (idl_create_name(pstate, loc, str, &name)) + goto err_alloc; + assert(dir->keys); + for (n=0; dir->keys[n]; n++) ; + assert(n); + if (idl_push_field_name(pstate, dir->keys[n-1], name)) + goto err_alloc; + return 0; +err_alloc: + if (name) + free(name); + return -1; +} + +static int stash_key(idl_pstate_t *pstate, idl_location_t *loc, char *str) +{ + struct keylist *dir = (struct keylist *)pstate->directive; + idl_name_t *name = NULL; + idl_field_name_t **keys; + size_t n; + + for (n=0; dir->keys && dir->keys[n]; n++) ; + if (!(keys = realloc(dir->keys, (n + 2) * sizeof(*keys)))) + goto err_alloc; + dir->keys = keys; + keys[n+0] = NULL; + if (idl_create_name(pstate, loc, str, &name)) + goto err_alloc; + if (idl_create_field_name(pstate, loc, name, &keys[n+0])) + goto err_alloc; + keys[n+1] = NULL; + return 0; +err_alloc: + if (name) + free(name); + return -1; +} + +static int32_t +parse_keylist(idl_pstate_t *pstate, idl_token_t *tok) +{ + struct keylist *dir = (struct keylist *)pstate->directive; + assert(dir); + + /* #pragma keylist does not support scoped names for data-type */ + switch (pstate->scanner.state) { + case IDL_SCAN_NAME: + if (tok->code != IDL_TOKEN_IDENTIFIER) { + idl_error(pstate, &tok->location, + "Invalid keylist directive, expected identifier"); + return IDL_RETCODE_SEMANTIC_ERROR; + } else if (idl_iskeyword(pstate, tok->value.str, 1)) { + idl_error(pstate, &tok->location, + "Invalid identifier '%s' in keylist data-type", tok->value.str); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if (stash_name(pstate, &tok->location, tok->value.str)) + return IDL_RETCODE_NO_MEMORY; + tok->value.str = NULL; + pstate->scanner.state = IDL_SCAN_SCOPE; + break; + case IDL_SCAN_KEYLIST: + /* accept leading scope, i.e. "::" in "::foo" */ + if (tok->code == IDL_TOKEN_SCOPE) { + pstate->scanner.state = IDL_SCAN_DATA_TYPE; + break; + } + /* fall through */ + case IDL_SCAN_DATA_TYPE: + assert(!dir->data_type); + if (tok->code == '\n' || tok->code == '\0') { + idl_error(pstate, &tok->location, + "Missing data-type in #pragma keylist directive"); + return IDL_RETCODE_SYNTAX_ERROR; + } else if (tok->code != IDL_TOKEN_IDENTIFIER) { + idl_error(pstate, &tok->location, + "Invalid data-type in #pragma keylist directive"); + return IDL_RETCODE_SYNTAX_ERROR; + } + + if (stash_data_type(pstate, &tok->location, tok->value.str)) + return IDL_RETCODE_NO_MEMORY; + tok->value.str = NULL; + pstate->scanner.state = IDL_SCAN_SCOPE; + break; + case IDL_SCAN_FIELD: + assert(dir->keys); + if (tok->code != IDL_TOKEN_IDENTIFIER) { + idl_error(pstate, &tok->location, + "Invalid keylist directive, identifier expected"); + return IDL_RETCODE_SEMANTIC_ERROR; + } else if (idl_iskeyword(pstate, tok->value.str, 1)) { + idl_error(pstate, &tok->location, + "Invalid key '%s' in keylist directive", tok->value.str); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if (stash_field(pstate, &tok->location, tok->value.str)) + return IDL_RETCODE_NO_MEMORY; + tok->value.str = NULL; + pstate->scanner.state = IDL_SCAN_ACCESS; + break; + case IDL_SCAN_SCOPE: + case IDL_SCAN_ACCESS: + if (pstate->scanner.state == IDL_SCAN_SCOPE) { + /* accept scoped name for data-type, assume key otherwise */ + if (tok->code == IDL_TOKEN_SCOPE) { + pstate->scanner.state = IDL_SCAN_NAME; + break; + } + } else if (pstate->scanner.state == IDL_SCAN_ACCESS) { + /* accept field name for key, assume key otherwise */ + if (tok->code == '.') { + pstate->scanner.state = IDL_SCAN_FIELD; + break; + } + } + pstate->scanner.state = IDL_SCAN_KEY; + /* fall through */ + case IDL_SCAN_KEY: + if (tok->code == '\n' || tok->code == '\0') { + return push_keylist(pstate, dir); + } else if (tok->code == ',' && dir->keys) { + /* #pragma keylist takes space or comma separated list of keys */ + break; + } else if (tok->code != IDL_TOKEN_IDENTIFIER) { + idl_error(pstate, &tok->location, + "Invalid token in #pragma keylist directive"); + return IDL_RETCODE_SEMANTIC_ERROR; + } else if (idl_iskeyword(pstate, tok->value.str, 1)) { + idl_error(pstate, &tok->location, + "Invalid key '%s' in #pragma keylist directive", tok->value.str); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if (stash_key(pstate, &tok->location, tok->value.str)) + return IDL_RETCODE_NO_MEMORY; + tok->value.str = NULL; + pstate->scanner.state = IDL_SCAN_ACCESS; + break; + default: + assert(0); + break; + } + + return IDL_RETCODE_OK; +} + +void idl_delete_directive(idl_pstate_t *pstate) +{ + if (pstate->directive) { + struct directive *dir = pstate->directive; + if (dir->type == LINE) + delete_line(dir); + else if (dir->type == LINEMARKER) + delete_line(dir); + else if (dir->type == KEYLIST) + delete_keylist(dir); + } +} + +idl_retcode_t idl_parse_directive(idl_pstate_t *pstate, idl_token_t *tok) +{ + /* order is important here */ + if ((pstate->scanner.state & IDL_SCAN_LINE) == IDL_SCAN_LINE) { + return parse_line(pstate, tok); + } else if ((pstate->scanner.state & IDL_SCAN_KEYLIST) == IDL_SCAN_KEYLIST) { + return parse_keylist(pstate, tok); + } else if (pstate->scanner.state == IDL_SCAN_PRAGMA) { + /* expect keylist */ + if (tok->code == IDL_TOKEN_IDENTIFIER) { + if (strcmp(tok->value.str, "keylist") == 0) { + struct keylist *dir; + if (!(dir = calloc(1, sizeof(*dir)))) + return IDL_RETCODE_NO_MEMORY; + dir->directive.type = KEYLIST; + pstate->keylists = true; /* register keylist occurence */ + pstate->directive = dir; + pstate->scanner.state = IDL_SCAN_KEYLIST; + return IDL_RETCODE_OK; + } + idl_error(pstate, &tok->location, + "Unsupported #pragma directive %s", tok->value.str); + return IDL_RETCODE_SYNTAX_ERROR; + } + } else if (pstate->scanner.state == IDL_SCAN_DIRECTIVE_NAME) { + if (tok->code == IDL_TOKEN_PP_NUMBER) { + /* expect linemarker */ + struct line *dir; + if (!(dir = calloc(1, sizeof(*dir)))) + return IDL_RETCODE_NO_MEMORY; + dir->directive.type = LINEMARKER; + pstate->directive = dir; + pstate->scanner.state = IDL_SCAN_LINE; + return parse_line(pstate, tok); + } else if (tok->code == IDL_TOKEN_IDENTIFIER) { + /* expect line or pragma */ + if (strcmp(tok->value.str, "line") == 0) { + struct line *dir; + if (!(dir = calloc(1, sizeof(*dir)))) + return IDL_RETCODE_NO_MEMORY; + dir->directive.type = LINE; + pstate->directive = dir; + pstate->scanner.state = IDL_SCAN_LINE; + return IDL_RETCODE_OK; + } else if (strcmp(tok->value.str, "pragma") == 0) { + /* support #pragma keylist for backwards compatibility */ + pstate->scanner.state = IDL_SCAN_PRAGMA; + return 0; + } + } else if (tok->code == '\n' || tok->code == '\0') { + pstate->scanner.state = IDL_SCAN; + return 0; + } + } else if (pstate->scanner.state == IDL_SCAN_DIRECTIVE) { + /* expect # */ + if (tok->code == '#') { + pstate->scanner.state = IDL_SCAN_DIRECTIVE_NAME; + return 0; + } + } + + idl_error(pstate, &tok->location, "Invalid compiler directive"); + return IDL_RETCODE_SYNTAX_ERROR; +} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IdlPreprocessorFactory.java b/src/idl/src/directive.h similarity index 51% rename from src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IdlPreprocessorFactory.java rename to src/idl/src/directive.h index eb836a7eb0..bd72217df6 100644 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IdlPreprocessorFactory.java +++ b/src/idl/src/directive.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2021 ADLINK Technology Limited and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -9,15 +9,19 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.cyclonedds.idt.imports.idl.preprocessor; +#ifndef DIRECTIVE_H +#define DIRECTIVE_H -import org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor.IdlPreprocessor; +#include +#include "idl/processor.h" +#include "tree.h" +#include "scanner.h" -public abstract class IdlPreprocessorFactory -{ - public static IIdlPreprocessor create () - { - return new IdlPreprocessor (); - } -} +IDL_EXPORT void +idl_delete_directive(idl_pstate_t *pstate); + +IDL_EXPORT idl_retcode_t +idl_parse_directive(idl_pstate_t *pstate, idl_token_t *tok); + +#endif /* DIRECTIVE_H */ diff --git a/src/idl/src/expression.c b/src/idl/src/expression.c new file mode 100644 index 0000000000..98024ef8d7 --- /dev/null +++ b/src/idl/src/expression.c @@ -0,0 +1,986 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include + +#include "idl/string.h" +#include "idl/processor.h" +#include "tree.h" +#include "expression.h" + +static uint64_t uintmax(idl_type_t type); +static int64_t intmax(idl_type_t type); +static int64_t intmin(idl_type_t type); +static idl_intval_t intval(const idl_const_expr_t *expr); +static idl_floatval_t floatval(const idl_const_expr_t *expr); + +#if _MSC_VER +/* suppress warning C4146: unary minus operator applied to unsigned type */ +__pragma(warning(push)) +__pragma(warning(disable: 4146)) +#endif + +idl_operator_t idl_operator(const void *node) +{ + idl_mask_t mask = idl_mask(node); + + mask &= ((((unsigned)IDL_BINARY_OPERATOR)<<1) - 1) | + ((((unsigned)IDL_UNARY_OPERATOR)<<1) - 1); + switch ((idl_operator_t)mask) { + case IDL_MINUS: + case IDL_PLUS: + case IDL_NOT: + case IDL_OR: + case IDL_XOR: + case IDL_AND: + case IDL_LSHIFT: + case IDL_RSHIFT: + case IDL_ADD: + case IDL_SUBTRACT: + case IDL_MULTIPLY: + case IDL_DIVIDE: + case IDL_MODULO: + return (idl_operator_t)mask; + default: + break; + } + + return IDL_NOP; +} + +static idl_retcode_t +eval_int_expr( + idl_pstate_t *pstate, + const idl_const_expr_t *expr, + idl_type_t type, + idl_intval_t *valp); + +static unsigned greatest(unsigned a, unsigned b) +{ + return a > b ? a : b; +} + +#define n(x) negative(x) +#define s(x) x->value.llng +#define t(x) x->type +#define u(x) x->value.ullng + +static inline bool negative(idl_intval_t *a) +{ + switch (t(a)) { + case IDL_LONG: + case IDL_LLONG: + return s(a) < 0; + default: + return false; + } +} + +static bool int_overflows(idl_intval_t *val, idl_type_t type) +{ + if (((unsigned)type & (unsigned)IDL_UNSIGNED)) + return val->value.ullng > uintmax(type); + else + return val->value.llng < intmin(type) || val->value.llng > intmax(type); +} + +static idl_retcode_t +int_or(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + t(r) = greatest(t(a), t(b)); + u(r) = u(a) | u(b); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_xor(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + t(r) = greatest(t(a), t(b)); + u(r) = u(a) ^ u(b); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_and(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + t(r) = greatest(t(a), t(b)); + u(r) = u(a) & u(b); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_lshift(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + idl_type_t gt = greatest(t(a), t(b)); + if (u(b) >= (uintmax(gt) == UINT64_MAX ? 64 : 32)) + return IDL_RETCODE_ILLEGAL_EXPRESSION; + t(r) = gt; + if (n(a)) + s(r) = s(a) << u(b); + else + u(r) = u(a) << u(b); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_rshift(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + idl_type_t gt = greatest(t(a), t(b)); + if (u(b) >= ((gt & IDL_LLONG) == IDL_LLONG ? 64 : 32)) + return IDL_RETCODE_ILLEGAL_EXPRESSION; + t(r) = gt; + if (n(a)) + s(r) = s(a) >> u(b); + else + u(r) = u(a) >> u(b); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_add(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + idl_type_t gt = greatest(t(a), t(b)); + + switch ((n(a) ? 1:0) + (n(b) ? 2:0)) { + case 0: + if (u(a) > uintmax(gt) - u(b)) + return IDL_RETCODE_OUT_OF_RANGE; + u(r) = u(a) + u(b); + t(r) = gt | (u(r) > (uint64_t)intmax(gt)); + break; + case 1: + if (-u(a) < u(b)) { + u(r) = u(a) + u(b); + t(r) = gt | (u(r) > (uint64_t)intmax(gt)); + } else { + u(r) = u(a) + u(b); + t(r) = gt; + } + break; + case 2: + if (-u(b) >= u(a)) { + u(r) = u(a) + u(b); + t(r) = gt | (u(r) > (uint64_t)intmax(gt)); + } else { + u(r) = u(a) + u(b); + t(r) = gt; + } + break; + case 3: + if (s(b) < (intmin(gt) + -s(a))) + return -1; + s(r) = s(a) + s(b); + t(r) = gt & ~1u; + break; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_subtract(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + idl_type_t gt = greatest(t(a), t(b)); + + switch ((n(a) ? 1:0) + (n(b) ? 2:0)) { + case 0: + if (u(a) < u(b) && u(a) - u(b) > -(uint64_t)intmin(gt)) + return IDL_RETCODE_OUT_OF_RANGE; + u(r) = u(a) - u(b); + t(r) = gt & ~1u; + break; + case 1: + if (u(b) > -(uint64_t)intmin(gt) || -u(a) > -(uint64_t)intmin(gt) - u(b)) + return -1; + u(r) = u(a) - u(b); + t(r) = gt & ~1u; + break; + case 2: + if (-u(b) > uintmax(gt) - u(a)) + return IDL_RETCODE_OUT_OF_RANGE; + u(r) = u(a) - u(b); + t(r) = gt | (-u(b) > u(a)); + break; + case 3: + s(r) = s(a) - s(b); + t(r) = gt; + break; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_multiply(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + idl_type_t gt = greatest(t(a), t(b)); + + switch ((n(a) ? 1:0) + (n(b) ? 2:0)) { + case 0: + if (u(b) && u(a) > uintmax(gt) / u(b)) + return IDL_RETCODE_OUT_OF_RANGE; + u(r) = u(a) * u(b); + t(r) = gt; + break; + case 1: + if (u(b) > (uint64_t)(intmin(gt) / s(a))) + return -1; + u(r) = u(a) * u(b); + t(r) = gt & ~1u; + break; + case 2: + if (u(a) && u(a) > (uint64_t)(intmin(gt) / s(b))) + return -1; + u(r) = u(a) * u(b); + t(r) = gt & ~1u; + break; + case 3: + if (-u(a) > uintmax(gt) / -u(b)) + return IDL_RETCODE_OUT_OF_RANGE; + u(r) = u(a) * u(b); + t(r) = gt | (u(r) > (uint32_t)intmax(gt)); + break; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_divide(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + idl_type_t gt = greatest(t(a), t(b)); + + if (u(b) == 0) + return IDL_RETCODE_ILLEGAL_EXPRESSION; + + switch ((n(a) ? 1:0) + (n(b) ? 2:0)) { + case 0: + u(r) = u(a) / u(b); + t(r) = gt; + break; + case 1: + u(r) = u(a) / u(b); + t(r) = gt; + break; + case 2: + if (-(uint64_t)intmin(gt) < u(a) && s(b) == -1) + return IDL_RETCODE_OUT_OF_RANGE; + u(r) = u(a) / u(b); + t(r) = gt; + break; + case 3: + s(r) = s(a) / s(b); + t(r) = gt; + break; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +int_modulo(idl_intval_t *a, idl_intval_t *b, idl_intval_t *r) +{ + idl_type_t gt = greatest(t(a), t(b)); + + if (u(b) == 0) + return IDL_RETCODE_ILLEGAL_EXPRESSION; + + switch ((n(a) ? 1:0) + (n(b) ? 2:0)) { + case 0: + u(r) = u(a) % u(b); + t(r) = gt; + break; + case 1: + u(r) = -(-u(a) % u(b)); + t(r) = gt; + break; + case 2: + u(r) = u(a) % -u(b); + t(r) = gt; + break; + case 3: + u(r) = u(a) % u(b); + t(r) = gt; + break; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +eval_binary_int_expr( + idl_pstate_t *pstate, + const idl_binary_expr_t *expr, + idl_type_t type, + idl_intval_t *valp) +{ + idl_retcode_t ret; + idl_intval_t val, lhs, rhs; + + assert((type & IDL_LONG) == IDL_LONG || + (type & IDL_LLONG) == IDL_ULLONG); + + if ((ret = eval_int_expr(pstate, expr->left, type, &lhs))) + return ret; + if ((ret = eval_int_expr(pstate, expr->right, type, &rhs))) + return ret; + + switch (idl_operator(expr)) { + case IDL_OR: ret = int_or(&lhs, &rhs, &val); break; + case IDL_XOR: ret = int_xor(&lhs, &rhs, &val); break; + case IDL_AND: ret = int_and(&lhs, &rhs, &val); break; + case IDL_LSHIFT: ret = int_lshift(&lhs, &rhs, &val); break; + case IDL_RSHIFT: ret = int_rshift(&lhs, &rhs, &val); break; + case IDL_ADD: ret = int_add(&lhs, &rhs, &val); break; + case IDL_SUBTRACT: ret = int_subtract(&lhs, &rhs, &val); break; + case IDL_MULTIPLY: ret = int_multiply(&lhs, &rhs, &val); break; + case IDL_DIVIDE: ret = int_divide(&lhs, &rhs, &val); break; + case IDL_MODULO: ret = int_modulo(&lhs, &rhs, &val); break; + default: + idl_error(pstate, idl_location(expr), + "Cannot evaluate %s as integer expression", idl_construct(expr)); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + + if (ret == IDL_RETCODE_ILLEGAL_EXPRESSION) { + idl_error(pstate, idl_location(expr), "Invalid integer expression"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } else if (ret == IDL_RETCODE_OUT_OF_RANGE || int_overflows(&val, type)) { + idl_error(pstate, idl_location(expr), "Integer expression overflows"); + return IDL_RETCODE_OUT_OF_RANGE; + } + + *valp = val; + return IDL_RETCODE_OK; +} + +static int int_minus(idl_intval_t *a, idl_intval_t *r) +{ + t(r) = t(a); + u(r) = -u(a); + return IDL_RETCODE_OK; +} + +static int int_plus(idl_intval_t *a, idl_intval_t *r) +{ + *r = *a; + return IDL_RETCODE_OK; +} + +static int int_not(idl_intval_t *a, idl_intval_t *r) +{ + t(r) = t(a); + u(r) = ~u(a); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +eval_unary_int_expr( + idl_pstate_t *pstate, + const idl_unary_expr_t *expr, + idl_type_t type, + idl_intval_t *valp) +{ + idl_retcode_t ret; + idl_intval_t val, rhs; + + assert((type & IDL_LONG) == IDL_LONG || + (type & IDL_LLONG) == IDL_LLONG); + + if ((ret = eval_int_expr(pstate, expr->right, type, &rhs))) + return ret; + + switch (idl_operator(expr)) { + case IDL_MINUS: ret = int_minus(&rhs, &val); break; + case IDL_PLUS: ret = int_plus(&rhs, &val); break; + case IDL_NOT: ret = int_not(&rhs, &val); break; + default: + idl_error(pstate, idl_location(expr), + "Cannot evaluate %s as integer expression", idl_construct(expr)); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + + if (ret == IDL_RETCODE_ILLEGAL_EXPRESSION) { + idl_error(pstate, idl_location(expr), "Invalid integer expression"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } else if (ret == IDL_RETCODE_OUT_OF_RANGE || int_overflows(&val, type)) { + idl_error(pstate, idl_location(expr), "Integer expression overflows"); + return IDL_RETCODE_OUT_OF_RANGE; + } + + *valp = val; + return IDL_RETCODE_OK; +} + +#undef u +#undef s +#undef t +#undef n + +static idl_retcode_t +eval_int_expr( + idl_pstate_t *pstate, + const idl_const_expr_t *const_expr, + idl_type_t type, + idl_intval_t *valp) +{ + if (idl_mask(const_expr) & IDL_CONST) + const_expr = ((idl_const_t *)const_expr)->const_expr; + + if (idl_mask(const_expr) & IDL_BINARY_OPERATOR) { + return eval_binary_int_expr(pstate, const_expr, type, valp); + } else if (idl_mask(const_expr) & IDL_UNARY_OPERATOR) { + return eval_unary_int_expr(pstate, const_expr, type, valp); + } else if (idl_mask(const_expr) & (IDL_LITERAL|IDL_OCTET|IDL_INTEGER_TYPE)) { + *valp = intval(const_expr); + return IDL_RETCODE_OK; + } + + idl_error(pstate, idl_location(const_expr), + "Cannot evaluate %s as integer expression", idl_construct(const_expr)); + return IDL_RETCODE_ILLEGAL_EXPRESSION; +} + +static idl_retcode_t +eval_int( + idl_pstate_t *pstate, + idl_const_expr_t *expr, + idl_type_t type, + void *nodep) +{ + idl_retcode_t ret; + idl_intval_t val; + idl_literal_t literal; + idl_type_t as = IDL_LONG; + + if (((unsigned)type & (unsigned)IDL_LLONG) == IDL_LLONG) + as = IDL_LLONG; + if ((ret = eval_int_expr(pstate, expr, as, &val))) + return ret; + if (int_overflows(&val, type)) + goto overflow; + + if ((ret = idl_create_literal(pstate, idl_location(expr), type, nodep))) + return ret; + + switch (type) { + case IDL_INT8: literal.value.int8 = (int8_t)val.value.llng; break; + case IDL_OCTET: + case IDL_UINT8: literal.value.uint8 = (uint8_t)val.value.ullng; break; + case IDL_SHORT: + case IDL_INT16: literal.value.int16 = (int16_t)val.value.llng; break; + case IDL_USHORT: + case IDL_UINT16: literal.value.uint16 = (uint16_t)val.value.ullng; break; + case IDL_LONG: + case IDL_INT32: literal.value.int32 = (int32_t)val.value.llng; break; + case IDL_ULONG: + case IDL_UINT32: literal.value.uint32 = (uint32_t)val.value.ullng; break; + case IDL_LLONG: + case IDL_INT64: literal.value.int64 = (int64_t)val.value.llng; break; + case IDL_ULLONG: + case IDL_UINT64: literal.value.uint64 = val.value.ullng; break; + default: + break; + } + + (*((idl_literal_t **)nodep))->value = literal.value; + return IDL_RETCODE_OK; +overflow: + idl_error(pstate, idl_location(expr), "Integer expression overflows"); + return IDL_RETCODE_OUT_OF_RANGE; +} + +static idl_retcode_t +eval_float_expr( + idl_pstate_t *pstate, + const idl_const_expr_t *expr, + idl_type_t type, + idl_floatval_t *valp); + +static bool +float_overflows(long double ldbl, idl_type_t type) +{ + if (type == IDL_FLOAT) + return isnan((float)ldbl) || isinf((float)ldbl); + else if (type == IDL_DOUBLE) + return isnan((double)ldbl) || isinf((double)ldbl); + else if (type == IDL_LDOUBLE) + return isnan(ldbl) || isinf(ldbl); + abort(); +} + +static idl_retcode_t +eval_binary_float_expr( + idl_pstate_t *pstate, + const idl_binary_expr_t *expr, + idl_type_t type, + idl_floatval_t *valp) +{ + idl_retcode_t ret; + idl_floatval_t val, lhs, rhs; + + if ((ret = eval_float_expr(pstate, expr->left, type, &lhs))) + return ret; + if ((ret = eval_float_expr(pstate, expr->right, type, &rhs))) + return ret; + + switch (idl_operator(expr)) { + case IDL_ADD: val = lhs+rhs; break; + case IDL_SUBTRACT: val = lhs-rhs; break; + case IDL_MULTIPLY: val = lhs*rhs; break; + case IDL_DIVIDE: + if (rhs == 0.0l) { + idl_error(pstate, idl_location(expr), + "Division by zero in floating point expression"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + val = lhs/rhs; + break; + default: + idl_error(pstate, idl_location(expr), + "Invalid floating point expression"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + + if (float_overflows(val, type)) { + idl_error(pstate, idl_location(expr), + "Floating point expression overflows"); + return IDL_RETCODE_OUT_OF_RANGE; + } + + *valp = val; + return IDL_RETCODE_OK; +} + +static idl_retcode_t +eval_unary_float_expr( + idl_pstate_t *pstate, + const idl_unary_expr_t *expr, + idl_type_t type, + idl_floatval_t *valp) +{ + idl_retcode_t ret; + idl_floatval_t val, rhs; + + if ((ret = eval_float_expr(pstate, expr->right, type, &rhs))) + return ret; + + switch (idl_operator(expr)) { + case IDL_PLUS: val = +rhs; break; + case IDL_MINUS: val = -rhs; break; + default: + idl_error(pstate, idl_location(expr), + "Invalid floating point expression"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + + if (float_overflows(val, type)) { + idl_error(pstate, idl_location(expr), + "Floating point expression overflows"); + return IDL_RETCODE_OUT_OF_RANGE; + } + + *valp = val; + return IDL_RETCODE_OK; +} + +static idl_retcode_t +eval_float_expr( + idl_pstate_t *pstate, + const idl_const_expr_t *expr, + idl_type_t type, + idl_floatval_t *valp) +{ + if (idl_mask(expr) & IDL_CONST) + expr = ((const idl_const_t *)expr)->const_expr; + + if (idl_mask(expr) & IDL_BINARY_OPERATOR) { + return eval_binary_float_expr(pstate, expr, type, valp); + } else if (idl_mask(expr) & IDL_UNARY_OPERATOR) { + return eval_unary_float_expr(pstate, expr, type, valp); + } else if (idl_mask(expr) & (IDL_LITERAL|IDL_FLOATING_PT_TYPE)) { + *valp = floatval(expr); + return IDL_RETCODE_OK; + } + + idl_error(pstate, idl_location(expr), + "Cannot evaluate %s as floating point expression", idl_construct(expr)); + return IDL_RETCODE_ILLEGAL_EXPRESSION; +} + +static idl_retcode_t +eval_float( + idl_pstate_t *pstate, + idl_const_expr_t *expr, + idl_type_t type, + void *nodep) +{ + idl_retcode_t ret; + idl_floatval_t val; + idl_literal_t *literal = NULL; + idl_type_t as = (type == IDL_LDOUBLE) ? IDL_LDOUBLE : IDL_DOUBLE; + + if ((ret = eval_float_expr(pstate, expr, as, &val))) + return ret; + if (float_overflows(val, type)) + goto overflow; + if ((ret = idl_create_literal(pstate, idl_location(expr), type, &literal))) + return ret; + + switch (type) { + case IDL_FLOAT: literal->value.flt = (float)val; break; + case IDL_DOUBLE: literal->value.dbl = (double)val; break; + case IDL_LDOUBLE: literal->value.ldbl = val; break; + default: + break; + } + + *((idl_literal_t **)nodep) = literal; + return IDL_RETCODE_OK; +overflow: + idl_error(pstate, idl_location(expr), + "Floating point expression overflows"); + return IDL_RETCODE_OUT_OF_RANGE; +} + +idl_retcode_t +idl_evaluate( + idl_pstate_t *pstate, + idl_const_expr_t *const_expr, + idl_type_t type, + void *nodep) +{ + idl_retcode_t ret; + idl_literal_t temporary, *literal = NULL; + static const char fmt[] = "Cannot evaluate %s as %s expression"; + + /* enumerators are referenced */ + if (type == IDL_ENUM) { + const char *constr = idl_construct(const_expr); + if (!(idl_mask(const_expr) & IDL_ENUMERATOR)) { + idl_error(pstate, idl_location(const_expr), fmt, constr, "enumerator"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + *((idl_enumerator_t **)nodep) = const_expr; + return IDL_RETCODE_OK; + } else if (type == IDL_OCTET || (type & IDL_INTEGER_TYPE)) { + if ((ret = eval_int(pstate, const_expr, type, nodep))) + return ret; + goto done; + } else if (type & IDL_FLOATING_PT_TYPE) { + if ((ret = eval_float(pstate, const_expr, type, nodep))) + return ret; + goto done; + } + + if (idl_is_const(const_expr)) + literal = ((idl_const_t *)const_expr)->const_expr; + else if (idl_is_literal(const_expr)) + literal = const_expr; + + if (type == IDL_CHAR) { + if (idl_type(literal) == IDL_CHAR) { + temporary.value.chr = literal->value.chr; + } else { + const char *constr = idl_construct(const_expr); + idl_error(pstate, idl_location(const_expr), fmt, constr, "character"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + } else if (type == IDL_BOOL) { + if (idl_type(literal) == IDL_BOOL) { + temporary.value.bln = literal->value.bln; + } else { + const char *constr = idl_construct(const_expr); + idl_error(pstate, idl_location(const_expr), fmt, constr, "boolean"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + } else if (type == IDL_STRING) { + if (idl_type(literal) == IDL_STRING) { + if (!(temporary.value.str = idl_strdup(literal->value.str))) + return IDL_RETCODE_NO_MEMORY; + } else { + const char *constr = idl_construct(const_expr); + idl_error(pstate, idl_location(const_expr), fmt, constr, "string"); + return IDL_RETCODE_ILLEGAL_EXPRESSION; + } + } + + if ((ret = idl_create_literal(pstate, idl_location(const_expr), type, nodep))) + return ret; + (*((idl_literal_t **)nodep))->value = temporary.value; +done: + idl_unreference_node(const_expr); + return IDL_RETCODE_OK; +} + +static uint64_t uintmax(idl_type_t type) +{ + switch (type) { + case IDL_INT8: + case IDL_UINT8: + case IDL_OCTET: return UINT8_MAX; + case IDL_INT16: + case IDL_SHORT: + case IDL_UINT16: + case IDL_USHORT: return UINT16_MAX; + case IDL_INT32: + case IDL_LONG: + case IDL_UINT32: + case IDL_ULONG: return UINT32_MAX; + case IDL_INT64: + case IDL_LLONG: + case IDL_UINT64: + case IDL_ULLONG: return UINT64_MAX; + default: + break; + } + + return 0llu; +} + +static int64_t intmax(idl_type_t type) +{ + switch (type) { + case IDL_INT8: + case IDL_UINT8: + case IDL_OCTET: return INT8_MAX; + case IDL_INT16: + case IDL_SHORT: + case IDL_UINT16: + case IDL_USHORT: return INT16_MAX; + case IDL_INT32: + case IDL_LONG: + case IDL_UINT32: + case IDL_ULONG: return INT32_MAX; + case IDL_INT64: + case IDL_LLONG: + case IDL_UINT64: + case IDL_ULLONG: return INT64_MAX; + default: + break; + } + + return 0ll; +} + +static int64_t intmin(idl_type_t type) +{ + switch (type) { + case IDL_INT8: + case IDL_UINT8: + case IDL_OCTET: return INT8_MIN; + case IDL_INT16: + case IDL_SHORT: + case IDL_UINT16: + case IDL_USHORT: return INT16_MIN; + case IDL_INT32: + case IDL_LONG: + case IDL_UINT32: + case IDL_ULONG: return INT32_MIN; + case IDL_INT64: + case IDL_LLONG: + case IDL_UINT64: + case IDL_ULLONG: return INT64_MIN; + default: + break; + } + + return 0ll; +} + +static idl_intval_t intval(const idl_const_expr_t *const_expr) +{ + idl_type_t type = idl_type(const_expr); + const idl_literal_t *val = (idl_literal_t *)const_expr; + +#define SIGNED(t,v) (idl_intval_t){ .type = (t), .value = { .llng = (v) } } +#define UNSIGNED(t,v) (idl_intval_t){ .type = (t), .value = { .ullng = (v) } } + + assert(idl_is_literal(const_expr)); + + switch (type) { + case IDL_INT8: return SIGNED(IDL_LONG, val->value.int8); + case IDL_UINT8: + case IDL_OCTET: return UNSIGNED(IDL_ULONG, val->value.uint8); + case IDL_INT16: + case IDL_SHORT: return SIGNED(IDL_LONG, val->value.int16); + case IDL_UINT16: + case IDL_USHORT: return UNSIGNED(IDL_ULONG, val->value.uint16); + case IDL_INT32: + case IDL_LONG: return SIGNED(IDL_LONG, val->value.int32); + case IDL_UINT32: + case IDL_ULONG: return UNSIGNED(IDL_ULONG, val->value.uint32); + case IDL_INT64: + case IDL_LLONG: return SIGNED(IDL_LLONG, val->value.int64); + case IDL_UINT64: + case IDL_ULLONG: + default: + assert(type == IDL_ULLONG); + return UNSIGNED(IDL_ULLONG, val->value.uint64); + } + +#undef UNSIGNED +#undef SIGNED +} + +static idl_equality_t +compare_int(const idl_const_expr_t *lhs, const idl_const_expr_t *rhs) +{ + idl_intval_t lval = intval(lhs), rval = intval(rhs); + + switch ((negative(&lval) ? 1:0) + (negative(&rval) ? 2:0)) { + case 0: + if (lval.value.ullng < rval.value.ullng) + return IDL_LESS; + if (lval.value.ullng > rval.value.ullng) + return IDL_GREATER; + return IDL_EQUAL; + case 1: + return IDL_GREATER; + case 2: + return IDL_LESS; + case 3: + default: + if (lval.value.llng < rval.value.llng) + return IDL_LESS; + if (lval.value.llng > rval.value.llng) + return IDL_GREATER; + return IDL_EQUAL; + } +} + +static idl_floatval_t floatval(const idl_const_expr_t *const_expr) +{ + idl_type_t type = idl_type(const_expr); + const idl_literal_t *val = (idl_literal_t *)const_expr; + + assert(idl_is_literal(const_expr)); + + switch (type) { + case IDL_FLOAT: + return (idl_floatval_t)val->value.flt; + case IDL_DOUBLE: + return (idl_floatval_t)val->value.dbl; + case IDL_LDOUBLE: + default: + assert(type == IDL_LDOUBLE); + return val->value.ldbl; + } +} + +static idl_equality_t +compare_float(const idl_const_expr_t *lhs, const idl_const_expr_t *rhs) +{ + idl_floatval_t lval = floatval(lhs), rval = floatval(rhs); + return (lval < rval) ? IDL_LESS : (lval > rval ? IDL_GREATER : IDL_EQUAL); +} + +static char charval(const idl_const_expr_t *const_expr) +{ + assert(idl_type(const_expr) == IDL_CHAR); + assert(idl_is_literal(const_expr)); + return ((const idl_literal_t *)const_expr)->value.chr; +} + +static idl_equality_t +compare_char(const idl_const_expr_t *lhs, const idl_const_expr_t *rhs) +{ + char lval = charval(lhs), rval = charval(rhs); + return (lval == rval ? IDL_EQUAL : (lval < rval ? IDL_LESS : IDL_GREATER)); +} + +static bool boolval(const idl_const_expr_t *const_expr) +{ + assert(idl_type(const_expr) == IDL_BOOL); + assert(idl_is_literal(const_expr)); + return ((const idl_literal_t *)const_expr)->value.bln; +} + +static idl_equality_t +compare_bool(const idl_const_expr_t *lhs, const idl_const_expr_t *rhs) +{ + bool lval = boolval(lhs), rval = boolval(rhs); + return (lval == rval ? IDL_EQUAL : (!lval ? IDL_LESS : IDL_GREATER)); +} + +static idl_equality_t +compare_enum(const idl_const_expr_t *lhs, const idl_const_expr_t *rhs) +{ + const idl_enumerator_t *lval = lhs, *rval = rhs; + assert(idl_is_enumerator(lval)); + assert(idl_is_enumerator(rval)); + if (lval->node.parent != rval->node.parent) + return IDL_MISMATCH; /* incompatible enums */ + if (lval->value < rval->value) + return IDL_LESS; + if (lval->value > rval->value) + return IDL_GREATER; + return IDL_EQUAL; +} + +static const char *stringval(const idl_const_expr_t *const_expr) +{ + assert(idl_type(const_expr) == IDL_STRING); + assert(idl_is_literal(const_expr)); + return ((const idl_literal_t *)const_expr)->value.str; +} + +static idl_equality_t +compare_string(const idl_const_expr_t *lhs, const idl_const_expr_t *rhs) +{ + int cmp; + const char *lval = stringval(lhs), *rval = stringval(rhs); + if (!lval || !rval) + return (rval ? IDL_LESS : (lval ? IDL_GREATER : IDL_EQUAL)); + cmp = strcmp(lval, rval); + return (cmp < 0 ? IDL_LESS : (cmp > 0 ? IDL_GREATER : IDL_EQUAL)); +} + +#if defined _MSC_VER +__pragma(warning(pop)) +#endif + +idl_equality_t +idl_compare(idl_pstate_t *pstate, const void *lhs, const void *rhs) +{ + idl_type_t ltype, rtype; + + (void)pstate; + ltype = idl_type(lhs); + rtype = idl_type(rhs); + + if ((ltype == IDL_OCTET || (ltype & IDL_INTEGER_TYPE)) && + (rtype == IDL_OCTET || (rtype & IDL_INTEGER_TYPE))) + return compare_int(lhs, rhs); + else if ((ltype & IDL_FLOATING_PT_TYPE) && + (rtype & IDL_FLOATING_PT_TYPE)) + return compare_float(lhs, rhs); + else if (!ltype || !rtype) + return IDL_INVALID; /* non-type */ + else if (ltype != rtype) + return IDL_MISMATCH; /* incompatible types */ + else if (ltype == IDL_CHAR) + return compare_char(lhs, rhs); + else if (ltype == IDL_BOOL) + return compare_bool(lhs, rhs); + else if (ltype == IDL_ENUM) + return compare_enum(lhs, rhs); + else if (ltype == IDL_STRING) + return compare_string(lhs, rhs); + + return IDL_INVALID; /* non-comparable type */ +} diff --git a/src/idl/src/expression.h b/src/idl/src/expression.h new file mode 100644 index 0000000000..78a91d0d50 --- /dev/null +++ b/src/idl/src/expression.h @@ -0,0 +1,64 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef EXPRESSION_H +#define EXPRESSION_H + +#include +#include + +#include "idl/processor.h" +#include "idl/expression.h" + +#define IDL_EXPRESSION \ + (IDL_LITERAL|IDL_UNARY_OPERATOR|IDL_BINARY_OPERATOR) + +typedef enum idl_operator idl_operator_t; +enum idl_operator { + IDL_NOP = 0, +#define IDL_UNARY_OPERATOR (1ull<<20) + IDL_MINUS = (IDL_UNARY_OPERATOR|1u), + IDL_PLUS, + IDL_NOT, +#define IDL_BINARY_OPERATOR (1ull<<19) + IDL_OR = (IDL_BINARY_OPERATOR|1u), + IDL_XOR, + IDL_AND, + IDL_LSHIFT, + IDL_RSHIFT, + IDL_ADD, + IDL_SUBTRACT, + IDL_MULTIPLY, + IDL_DIVIDE, + IDL_MODULO +}; + +idl_operator_t idl_operator(const void *node); + +typedef struct idl_intval idl_intval_t; +struct idl_intval { + idl_type_t type; + union { + int64_t llng; + uint64_t ullng; + } value; +}; + +typedef long double idl_floatval_t; + +IDL_EXPORT idl_retcode_t +idl_evaluate( + idl_pstate_t *pstate, + idl_const_expr_t *expr, + idl_type_t type, + void *nodep); + +#endif /* EXPRESSION_H */ diff --git a/src/idl/src/file.c b/src/idl/src/file.c new file mode 100644 index 0000000000..a585fe3f78 --- /dev/null +++ b/src/idl/src/file.c @@ -0,0 +1,362 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#if _WIN32 +#include +#include +#else +#include +#include +#endif + +#include "file.h" +#include "idl/string.h" + +unsigned int idl_isseparator(int chr) +{ +#if _WIN32 + return chr == '/' || chr == '\\'; +#else + return chr == '/'; +#endif +} + +#define isseparator(chr) idl_isseparator(chr) + +unsigned int idl_isabsolute(const char *path) +{ + assert(path); + if (path[0] == '/') + return 1; +#if _WIN32 + if (((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) && + (path[1] == ':') && + (path[2] == '/' || path[2] == '\\' || path[2] == '\0')) + return 3; +#endif + return 0; +} + +#define isabsolute(chr) idl_isabsolute(chr) + +#if _WIN32 +static const char sep = '\\'; +#else +static const char sep = '/'; +#endif + +idl_retcode_t +idl_current_path(char **abspathp) +{ + char *cwd; + assert(abspathp); +#if _WIN32 + cwd = _getcwd(NULL, 0); +#else + cwd = getcwd(NULL, 0); +#endif + if (!cwd) + return IDL_RETCODE_NO_MEMORY; + *abspathp = cwd; + return IDL_RETCODE_OK; +} + +static int isdelimiter(char chr) +{ + return chr == '\0' || isseparator(chr); +} + +ssize_t idl_untaint_path(char *path) +{ + size_t abs, len; + + assert(path); + + if ((abs = isabsolute(path)) && path[abs - 1] != '\0') + path[abs - 1] = sep; + + len = abs; + for (size_t i=abs,j=i,k,n;;) { + if (isdelimiter(path[i])) { + n = i - j; + if (n == 2 && strncmp(path + j, "..", n) == 0) { + if (len == abs && abs) + return -1; /* invalid path */ + /* drop segment, unless segment is ".." */ + for (k=(len ? len - 1 : 0); k > abs && !isseparator(path[k]); k--) ; + if (strncmp(path + (k + (k != abs)), "..", len - (k + (k != abs))) == 0) + goto move; + len = k; + } else if (n != 0) { +move: + if (len != abs) + path[len++] = sep; + memmove(path + len, path + j, n); + len += n; + } + if (path[i++] == '\0') + break; + goto mark; + } else if (i == abs) { + /* start of segment */ +mark: + n = (path[i] != '.' ? 0 : (path[i+1] != '.' ? 1 : 2)); + if (!isdelimiter(path[i+n]) || n == 2) + j = i; + else + j = i + n; + i += n ? n : i == abs; + } else { + i += 1; + } + } + + path[len] = '\0'; + return (ssize_t)len; +} + +static char *absolute_path(const char *path) +{ + if (isabsolute(path) == 0) { + char *abspath = NULL, *dir; + size_t len, dirlen, pathlen; + if (idl_current_path(&dir)) + goto err_cwd; + dirlen = strlen(dir); + if (dirlen + 0 >= (SIZE_MAX - 2)) + goto err_abs; + pathlen = strlen(path); + if (dirlen + 2 >= (SIZE_MAX - pathlen)) + goto err_abs; + len = dirlen + 1 /* separator */ + pathlen; + if (!(abspath = malloc(len + 1))) + goto err_abs; + memcpy(abspath, dir, dirlen); + abspath[dirlen] = sep; + memcpy(abspath + dirlen + 1, path, pathlen); + abspath[len] = '\0'; +err_abs: + free(dir); +err_cwd: + return abspath; + } + return idl_strdup(path); +} + +#if _WIN32 +static ssize_t normalize_segment(const char *path, char *segment) +{ + WIN32_FIND_DATA find_data; + HANDLE find; + ssize_t seglen = strlen(segment); + + find = FindFirstFile(path, &find_data); + if (find == INVALID_HANDLE_VALUE) + + if (strlen(find_data.cFileName) == (size_t)seglen) + memcpy(segment, find_data.cFileName, seglen); + else + seglen = -1; + FindClose(find); + return seglen; +} +#else +static ssize_t normalize_segment(const char *path, char *segment) +{ + /* FIXME: implement support for case correction on *NIX platforms */ + struct stat buf; + (void)segment; + return stat(path, &buf); +} +#endif + +idl_retcode_t idl_normalize_path(const char *path, char **normpathp) +{ + idl_retcode_t ret; + size_t abs; + ssize_t len; + char *abspath = NULL, *normpath = NULL; + + if (!(abspath = absolute_path(path))) + { ret = IDL_RETCODE_NO_MEMORY; goto err_abs; } + if ((len = idl_untaint_path(abspath)) < 0) + { ret = IDL_RETCODE_BAD_PARAMETER; goto err_norm; } + if (!(normpath = malloc((size_t)len + 1))) + { ret = IDL_RETCODE_NO_MEMORY; goto err_norm; } + + /* ensure Windows drive letters are capitals */ + if (idl_islower((unsigned char)abspath[0])) + abspath[0] = (char)idl_toupper(abspath[0]); + + { + char *seg, *ptr = NULL; + char delim[] = { '/', '\0', '\0' }; + size_t pos = 0, seglen; +#if _WIN32 + delim[1] = sep; +#endif + abs = isabsolute(abspath); + assert(abs && abs <= (size_t)len); + seg = idl_strtok_r(abspath, delim, &ptr); + seglen = strlen(seg); + if (abs == 1) + normpath[pos++] = sep; + memmove(normpath + pos, seg, seglen); + pos += seglen; + if (abs != 1) + normpath[pos++] = sep; + normpath[pos] = '\0'; + while ((seg = idl_strtok_r(NULL, delim, &ptr))) { + seglen = strlen(seg); + if (pos != abs) + normpath[pos++] = sep; + memmove(normpath + pos, seg, seglen); + normpath[pos + seglen] = '\0'; + if (normalize_segment(normpath, normpath + pos) == -1) + { ret = IDL_RETCODE_NO_ENTRY; goto err_seg; } + pos += seglen; + } + assert(pos == (size_t)len); + } + + free(abspath); + *normpathp = normpath; + return (idl_retcode_t)len; +err_seg: + free(normpath); +err_norm: + free(abspath); +err_abs: + return ret; +} + +static unsigned int isresolved(const char *path) +{ + for (size_t i=0,n; path[i];) { + if (isseparator(path[i])) { + i++; + goto segment; + } else if (i == 0) { +segment: + n = (path[i] != '.' ? 0 : (path[i+1] != '.' ? 1 : 2)); + if (n && isdelimiter(path[i+n])) + return 0u; + i += n ? n : i == 0; + } else { + i++; + } + } + return 1u; +} + +#if _WIN32 +static inline int chrcasecmp(int a, int b) +{ + if (a >= 'A' && a <= 'Z') + a = 'a' + (a - 'A'); + if (b >= 'A' && b <= 'Z') + b = 'a' + (b - 'A'); + return a-b; +} +#else +static inline int chrcmp(int a, int b) +{ + return a-b; +} +#endif + +idl_retcode_t idl_relative_path(const char *base, const char *path, char **relpathp) +{ + size_t pc, psc = 0; + size_t bc, bsc = 0; + char *rel = NULL, *rev = NULL; + const char *rew, *fwd, *nop = ""; + +#if _WIN32 + int(*cmp)(int, int) = chrcasecmp; +#else + int(*cmp)(int, int) = chrcmp; +#endif + + /* reject non-absolute paths and non-resolved paths */ + if (!isabsolute(base) || !isresolved(base)) + return IDL_RETCODE_BAD_PARAMETER; + if (!isabsolute(path) || !isresolved(path)) + return IDL_RETCODE_BAD_PARAMETER; + + /* find common prefix to strip */ + do { + pc = psc; + bc = bsc; + /* skip matching characters */ + for (; !isdelimiter(path[pc]) && !isdelimiter(base[bc]); pc++, bc++) { + if (cmp(path[pc], base[bc]) != 0) + break; + } + /* skip separators */ + for (psc=pc; isseparator((unsigned char)path[psc]); psc++) ; + for (bsc=bc; isseparator((unsigned char)base[bsc]); bsc++) ; + /* continue on mismatch between separators */ + } while ((pc!=psc) == (bc!=bsc) && path[psc] && !cmp(path[psc], base[bsc])); + + /* matching paths */ + if (!path[psc] && !base[bsc]) { + rew = nop; + fwd = nop; + /* base is subdirectory of path */ + } else if (!path[psc] && isseparator(base[bc])) { + rew = &base[bsc]; + fwd = nop; + /* path is subdirectory of base */ + } else if (!base[bsc] && isseparator(path[pc])) { + rew = nop; + fwd = &path[psc]; + /* partial match, revert to common prefix */ + } else { + /* rewind to last separator */ + for (; pc > 0 && !isseparator(path[pc]); pc--) ; + for (; bc > 0 && !isseparator(base[bc]); bc--) ; + /* forward to first non-separator */ + for (; isseparator(path[pc]); pc++) ; + for (; isseparator(base[bc]); bc++) ; + rew = &base[bc]; + fwd = &path[pc]; + } + + if (rew != nop) { + size_t len, cnt = 1; + for (size_t i=0; rew[i]; i++) + cnt += (isseparator(rew[i]) && !isdelimiter(rew[i+1])); + len = cnt*3; + if (!(rev = malloc(len+1))) + return IDL_RETCODE_NO_MEMORY; + memset(rev, '.', len); + rev[len] = '\0'; + for (size_t i=0; i < cnt; i++) + rev[(i*3)+2] = sep; + } + + idl_asprintf(&rel, "%s%s", rev ? rev : "", fwd); + if (rev) + free(rev); + if (!rel) + return IDL_RETCODE_NO_MEMORY; + idl_untaint_path(rel); + *relpathp = rel; + return IDL_RETCODE_OK; +} diff --git a/src/idl/src/file.h b/src/idl/src/file.h new file mode 100644 index 0000000000..a20fd6a634 --- /dev/null +++ b/src/idl/src/file.h @@ -0,0 +1,33 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef FILE_H +#define FILE_H + +#include +#include + +#include "idl/export.h" +#include "idl/retcode.h" +#include "idl/file.h" + +#if WIN32 +# include +typedef SSIZE_T ssize_t; +#endif + +/** + * @internal + * @brief Resolve "." and ".." segments and remove consecutive slashes + */ +IDL_EXPORT ssize_t idl_untaint_path(char *path); + +#endif /* FILE_H */ diff --git a/src/idl/src/hashid.c.in b/src/idl/src/hashid.c.in new file mode 100644 index 0000000000..269b2702f0 --- /dev/null +++ b/src/idl/src/hashid.c.in @@ -0,0 +1,31 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "hashid.h" + +@MD5@ /* sources from md5.h and md5.c inserted here */ + +uint32_t idl_hashid(const char *name) +{ + uint32_t id; + + ddsrt_md5_state_t md5st; + ddsrt_md5_byte_t digest[16]; + + ddsrt_md5_init(&md5st); + ddsrt_md5_append(&md5st, (ddsrt_md5_byte_t*)name, (unsigned int)strlen(name)); + ddsrt_md5_finish(&md5st, digest); + memcpy(&id, digest, sizeof(id)); + return id & 0x0fffffffu; +} diff --git a/src/ddsts/src/stringify.h b/src/idl/src/hashid.h similarity index 69% rename from src/ddsts/src/stringify.h rename to src/idl/src/hashid.h index d7e950f051..4cbd5b8ccd 100644 --- a/src/ddsts/src/stringify.h +++ b/src/idl/src/hashid.h @@ -9,13 +9,13 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -#ifndef IDL_STRINGIFY_H -#define IDL_STRINGIFY_H +#ifndef HASHID_H +#define HASHID_H -#include +#include -#include "typetree.h" +#include "idl/export.h" -void dds_ts_stringify(dds_ts_node_t *context, char *buffer, size_t len); +IDL_EXPORT uint32_t idl_hashid(const char *str); -#endif /* IDL_STRINGIFY_H */ +#endif /* HASHID_H */ diff --git a/src/idl/src/parser.y b/src/idl/src/parser.y new file mode 100644 index 0000000000..a7547ef3ce --- /dev/null +++ b/src/idl/src/parser.y @@ -0,0 +1,1131 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +%{ +#include +#include +#include +#include +#include +#include + +#include "idl/string.h" +#include "idl/processor.h" +#include "annotation.h" +#include "expression.h" +#include "scope.h" +#include "symbol.h" +#include "tree.h" + +#if defined(__GNUC__) +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wconversion\"") +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") +_Pragma("GCC diagnostic push") +_Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") +#endif + +static void yyerror(idl_location_t *, idl_pstate_t *, const char *); + +/* convenience macros to complement YYABORT */ +#define NO_MEMORY() \ + do { \ + yylen = 0; \ + goto yyexhaustedlab; \ + } while(0) + +#define SEMANTIC_ERROR(state, loc, ...) \ + do { \ + idl_error(state, loc, __VA_ARGS__); \ + yylen = 0; /* pop right-hand side tokens */ \ + yyresult = IDL_RETCODE_SEMANTIC_ERROR; \ + goto yyreturn; \ + } while(0) + +#define YYLLOC_DEFAULT(Cur, Rhs, N) \ + do { \ + if (N) { \ + (Cur).first.source = YYRHSLOC(Rhs, 1).first.source; \ + (Cur).first.file = YYRHSLOC(Rhs, 1).first.file; \ + (Cur).first.line = YYRHSLOC(Rhs, 1).first.line; \ + (Cur).first.column = YYRHSLOC(Rhs, 1).first.column; \ + } else { \ + (Cur).first.source = YYRHSLOC(Rhs, 0).last.source; \ + (Cur).first.file = YYRHSLOC(Rhs, 0).last.file; \ + (Cur).first.line = YYRHSLOC(Rhs, 0).last.line; \ + (Cur).first.column = YYRHSLOC(Rhs, 0).last.column; \ + } \ + (Cur).last.line = YYRHSLOC(Rhs, N).last.line; \ + (Cur).last.column = YYRHSLOC(Rhs, N).last.column; \ + } while(0) + +#define TRY_EXCEPT(action, except) \ + do { \ + int _ret_; \ + switch ((_ret_ = (action))) { \ + case IDL_RETCODE_OK: \ + break; \ + case IDL_RETCODE_NO_MEMORY: \ + yylen = 0; /* pop right-hand side tokens */ \ + (void)(except);\ + goto yyexhaustedlab; \ + case IDL_RETCODE_SYNTAX_ERROR: \ + yylen = 0; /* pop right-hand side tokens */ \ + (void)(except); \ + goto yyabortlab; \ + default: \ + yylen = 0; \ + yyresult = _ret_; \ + (void)(except); \ + goto yyreturn; \ + } \ + } while(0) + +#define TRY(action) \ + TRY_EXCEPT((action), 0) +%} + +%code requires { +#include "tree.h" + +/* make yytoknum available */ +#define YYPRINT(A,B,C) YYUSE(A) +/* use YYLTYPE definition below */ +#define IDL_YYLTYPE_IS_DECLARED +typedef struct idl_location IDL_YYLTYPE; + +#define LOC(first, last) \ + &(IDL_YYLTYPE){ first, last } +} + +%code provides { +int idl_iskeyword(idl_pstate_t *pstate, const char *str, int nc); +void idl_yypstate_delete_stack(idl_yypstate *yyps); +} + +%union { + void *node; + /* expressions */ + idl_literal_t *literal; + idl_const_expr_t *const_expr; + /* simple specifications */ + idl_mask_t kind; + idl_name_t *name; + idl_scoped_name_t *scoped_name; + idl_inherit_spec_t *inherit_spec; + char *string_literal; + /* specifications */ + idl_switch_type_spec_t *switch_type_spec; + idl_type_spec_t *type_spec; + idl_sequence_t *sequence; + idl_string_t *string; + /* declarations */ + idl_definition_t *definition; + idl_module_t *module_dcl; + idl_struct_t *struct_dcl; + idl_member_t *member; + idl_declarator_t *declarator; + idl_union_t *union_dcl; + idl_case_t *_case; + idl_case_label_t *case_label; + idl_enum_t *enum_dcl; + idl_enumerator_t *enumerator; + idl_typedef_t *typedef_dcl; + idl_const_t *const_dcl; + /* annotations */ + idl_annotation_t *annotation; + idl_annotation_member_t *annotation_member; + idl_annotation_appl_t *annotation_appl; + idl_annotation_appl_param_t *annotation_appl_param; + + bool bln; + char *str; + char chr; + unsigned long long ullng; + long double ldbl; +} + +%define api.pure true +%define api.prefix {idl_yy} +%define api.push-pull push +%define parse.trace + +%locations + +%param { idl_pstate_t *pstate } + +%token-table + +%start specification + +%type definitions definition type_dcl + constr_type_dcl struct_dcl union_dcl enum_dcl +%type type_spec simple_type_spec template_type_spec + switch_type_spec const_type annotation_member_type + any_const_type struct_inherit_spec +%type literal positive_int_const fixed_array_size +%type const_expr or_expr xor_expr and_expr shift_expr add_expr + mult_expr unary_expr primary_expr fixed_array_sizes + annotation_member_default +%type shift_operator add_operator mult_operator unary_operator base_type_spec floating_pt_type integer_type + signed_int unsigned_int char_type wide_char_type boolean_type + octet_type +%type boolean_literal +%type identifier +%type scoped_name annotation_appl_name +%type string_literal +%type sequence_type +%type string_type +%type module_dcl module_header +%type struct_def struct_header +%type members member struct_body +%type union_def union_header +%type <_case> switch_body case element_spec +%type case_labels case_label +%type enum_def +%type enumerators enumerator +%type declarators declarator simple_declarator + complex_declarator array_declarator +%type typedef_dcl +%type const_dcl +%type annotation_dcl annotation_header +%type annotation_body annotation_member +%type annotations annotation_appl annotation_appls +%type annotation_appl_params + annotation_appl_keyword_param + annotation_appl_keyword_params + +%destructor { free($$); } + +%destructor { idl_delete_name($$); } + + +%destructor { idl_delete_scoped_name($$); } + + +%destructor { idl_unreference_node($$); } + + +%destructor { idl_delete_node($$); } + + <_case> + + +%token IDL_TOKEN_LINE_COMMENT +%token IDL_TOKEN_COMMENT +%token IDL_TOKEN_PP_NUMBER +%token IDL_TOKEN_IDENTIFIER +%token IDL_TOKEN_CHAR_LITERAL +%token IDL_TOKEN_STRING_LITERAL +%token IDL_TOKEN_INTEGER_LITERAL +%token IDL_TOKEN_FLOATING_PT_LITERAL + +%token IDL_TOKEN_ANNOTATION_SYMBOL "@" +%token IDL_TOKEN_ANNOTATION "annotation" + +/* scope operators, see scanner.c for details */ +%token IDL_TOKEN_SCOPE +%token IDL_TOKEN_SCOPE_NO_SPACE + +/* keywords */ +%token IDL_TOKEN_MODULE "module" +%token IDL_TOKEN_CONST "const" +%token IDL_TOKEN_NATIVE "native" +%token IDL_TOKEN_STRUCT "struct" +%token IDL_TOKEN_TYPEDEF "typedef" +%token IDL_TOKEN_UNION "union" +%token IDL_TOKEN_SWITCH "switch" +%token IDL_TOKEN_CASE "case" +%token IDL_TOKEN_DEFAULT "default" +%token IDL_TOKEN_ENUM "enum" +%token IDL_TOKEN_UNSIGNED "unsigned" +%token IDL_TOKEN_FIXED "fixed" +%token IDL_TOKEN_SEQUENCE "sequence" +%token IDL_TOKEN_STRING "string" +%token IDL_TOKEN_WSTRING "wstring" + +%token IDL_TOKEN_FLOAT "float" +%token IDL_TOKEN_DOUBLE "double" +%token IDL_TOKEN_SHORT "short" +%token IDL_TOKEN_LONG "long" +%token IDL_TOKEN_CHAR "char" +%token IDL_TOKEN_WCHAR "wchar" +%token IDL_TOKEN_BOOLEAN "boolean" +%token IDL_TOKEN_OCTET "octet" +%token IDL_TOKEN_ANY "any" + +%token IDL_TOKEN_MAP "map" +%token IDL_TOKEN_BITSET "bitset" +%token IDL_TOKEN_BITFIELD "bitfield" +%token IDL_TOKEN_BITMASK "bitmask" + +%token IDL_TOKEN_INT8 "int8" +%token IDL_TOKEN_INT16 "int16" +%token IDL_TOKEN_INT32 "int32" +%token IDL_TOKEN_INT64 "int64" +%token IDL_TOKEN_UINT8 "uint8" +%token IDL_TOKEN_UINT16 "uint16" +%token IDL_TOKEN_UINT32 "uint32" +%token IDL_TOKEN_UINT64 "uint64" + +%token IDL_TOKEN_TRUE "TRUE" +%token IDL_TOKEN_FALSE "FALSE" + +%token IDL_TOKEN_LSHIFT "<<" +%token IDL_TOKEN_RSHIFT ">>" + +%% + +specification: + %empty + { pstate->root = NULL; } + | definitions + { pstate->root = $1; } + ; + +definitions: + definition + { $$ = $1; } + | definitions definition + { $$ = idl_push_node($1, $2); } + ; + +definition: + annotation_dcl ';' + { $$ = $1; } + | annotations module_dcl ';' + { TRY(idl_annotate(pstate, $2, $1)); + $$ = $2; + } + | annotations const_dcl ';' + { TRY(idl_annotate(pstate, $2, $1)); + $$ = $2; + } + | annotations type_dcl ';' + { TRY(idl_annotate(pstate, $2, $1)); + $$ = $2; + } + ; + +module_dcl: + module_header '{' definitions '}' + { TRY(idl_finalize_module(pstate, LOC(@1.first, @4.last), $1, $3)); + $$ = $1; + } + ; + +module_header: + "module" identifier + { TRY(idl_create_module(pstate, LOC(@1.first, @2.last), $2, &$$)); } + ; + +scoped_name: + identifier + { TRY(idl_create_scoped_name(pstate, &@1, $1, false, &$$)); } + | IDL_TOKEN_SCOPE identifier + { TRY(idl_create_scoped_name(pstate, LOC(@1.first, @2.last), $2, true, &$$)); } + | scoped_name IDL_TOKEN_SCOPE identifier + { TRY(idl_push_scoped_name(pstate, $1, $3)); + $$ = $1; + } + ; + +const_dcl: + "const" const_type identifier '=' const_expr + { TRY(idl_create_const(pstate, LOC(@1.first, @5.last), $2, $3, $5, &$$)); } + ; + +const_type: + integer_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | floating_pt_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | char_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | boolean_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | octet_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | string_type + { $$ = (idl_type_spec_t *)$1; } + | scoped_name + { idl_node_t *node; + const idl_declaration_t *declaration; + static const char fmt[] = + "Scoped name '%s' does not resolve to a valid constant type"; + TRY(idl_resolve(pstate, 0u, $1, &declaration)); + node = idl_unalias(declaration->node, 0u); + if (!(idl_mask(node) & (IDL_BASE_TYPE|IDL_STRING|IDL_ENUM))) + SEMANTIC_ERROR(pstate, &@1, fmt, $1->identifier); + $$ = idl_reference_node((idl_node_t *)declaration->node); + idl_delete_scoped_name($1); + } + ; + +const_expr: or_expr { $$ = $1; } ; + +or_expr: + xor_expr + | or_expr '|' xor_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_binary_expr(pstate, &@2, IDL_OR, $1, $3, &$$)); + } + ; + +xor_expr: + and_expr + | xor_expr '^' and_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_binary_expr(pstate, &@2, IDL_XOR, $1, $3, &$$)); + } + ; + +and_expr: + shift_expr + | and_expr '&' shift_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_binary_expr(pstate, &@2, IDL_AND, $1, $3, &$$)); + } + ; + +shift_expr: + add_expr + | shift_expr shift_operator add_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_binary_expr(pstate, &@2, $2, $1, $3, &$$)); + } + ; + +shift_operator: + ">>" { $$ = IDL_RSHIFT; } + | "<<" { $$ = IDL_LSHIFT; } + +add_expr: + mult_expr + | add_expr add_operator mult_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_binary_expr(pstate, &@2, $2, $1, $3, &$$)); + } + ; + +add_operator: + '+' { $$ = IDL_ADD; } + | '-' { $$ = IDL_SUBTRACT; } + +mult_expr: + unary_expr + { $$ = $1; } + | mult_expr mult_operator unary_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_binary_expr(pstate, &@2, $2, $1, $3, &$$)); + } + ; + +mult_operator: + '*' { $$ = IDL_MULTIPLY; } + | '/' { $$ = IDL_DIVIDE; } + | '%' { $$ = IDL_MODULO; } + +unary_expr: + unary_operator primary_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_unary_expr(pstate, &@1, $1, $2, &$$)); + } + | primary_expr + { $$ = $1; } + ; + +unary_operator: + '-' { $$ = IDL_MINUS; } + | '+' { $$ = IDL_PLUS; } + | '~' { $$ = IDL_NOT; } + ; + +primary_expr: + scoped_name + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) { + /* disregard scoped names in application of unknown annotations. + names may or may not have significance in the scope of the + (builtin) annotation, stick to syntax checks */ + const idl_declaration_t *declaration = NULL; + static const char fmt[] = + "Scoped name '%s' does not resolve to an enumerator or a contant"; + TRY(idl_resolve(pstate, 0u, $1, &declaration)); + if (!(idl_mask(declaration->node) & (IDL_CONST|IDL_ENUMERATOR))) + SEMANTIC_ERROR(pstate, &@1, fmt, $1->identifier); + $$ = idl_reference_node((idl_node_t *)declaration->node); + } + idl_delete_scoped_name($1); + } + | literal + { $$ = $1; } + | '(' const_expr ')' + { $$ = $2; } + ; + +literal: + IDL_TOKEN_INTEGER_LITERAL + { idl_type_t type; + idl_literal_t literal; + $$ = NULL; + if (pstate->parser.state == IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + break; + if ($1 <= INT32_MAX) { + type = IDL_LONG; + literal.value.int32 = (int32_t)$1; + } else if ($1 <= UINT32_MAX) { + type = IDL_ULONG; + literal.value.uint32 = (uint32_t)$1; + } else if ($1 <= INT64_MAX) { + type = IDL_LLONG; + literal.value.int64 = (int64_t)$1; + } else { + type = IDL_ULLONG; + literal.value.uint64 = (uint64_t)$1; + } + TRY(idl_create_literal(pstate, &@1, type, &$$)); + $$->value = literal.value; + } + | IDL_TOKEN_FLOATING_PT_LITERAL + { idl_type_t type; + idl_literal_t literal; + $$ = NULL; + if (pstate->parser.state == IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + break; + if (isnan((double)$1) || isinf((double)$1)) { + type = IDL_LDOUBLE; + literal.value.ldbl = $1; + } else { + type = IDL_DOUBLE; + literal.value.dbl = (double)$1; + } + TRY(idl_create_literal(pstate, &@1, type, &$$)); + $$->value = literal.value; + } + | IDL_TOKEN_CHAR_LITERAL + { $$ = NULL; + if (pstate->parser.state == IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + break; + TRY(idl_create_literal(pstate, &@1, IDL_CHAR, &$$)); + $$->value.chr = $1; + } + | boolean_literal + { $$ = NULL; + if (pstate->parser.state == IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + break; + TRY(idl_create_literal(pstate, &@1, IDL_BOOL, &$$)); + $$->value.bln = $1; + } + | string_literal + { $$ = NULL; + if (pstate->parser.state == IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + break; + TRY(idl_create_literal(pstate, &@1, IDL_STRING, &$$)); + $$->value.str = $1; + } + ; + +boolean_literal: + IDL_TOKEN_TRUE + { $$ = true; } + | IDL_TOKEN_FALSE + { $$ = false; } + ; + +string_literal: + IDL_TOKEN_STRING_LITERAL + { $$ = NULL; + if (pstate->parser.state == IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + break; + if (!($$ = idl_strdup($1))) + NO_MEMORY(); + } + | string_literal IDL_TOKEN_STRING_LITERAL + { size_t n1, n2; + $$ = NULL; + if (pstate->parser.state == IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + break; + /* adjacent string literals are concatenated */ + n1 = strlen($1); + n2 = strlen($2); + if (!($$ = realloc($1, n1+n2+1))) + NO_MEMORY(); + memmove($$+n1, $2, n2); + $$[n1+n2] = '\0'; + } + ; + +positive_int_const: + const_expr + { TRY(idl_evaluate(pstate, $1, IDL_ULONG, &$$)); } + ; + +type_dcl: + constr_type_dcl { $$ = $1; } + | typedef_dcl { $$ = $1; } + ; + +type_spec: + simple_type_spec + /* building block anonymous types */ + | template_type_spec + ; + +simple_type_spec: + base_type_spec + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | scoped_name + { const idl_declaration_t *declaration = NULL; + static const char fmt[] = + "Scoped name '%s' does not resolve to a type"; + TRY(idl_resolve(pstate, 0u, $1, &declaration)); + if (!declaration || !idl_is_type_spec(declaration->node)) + SEMANTIC_ERROR(pstate, &@1, fmt, $1->identifier); + $$ = idl_reference_node((idl_node_t *)declaration->node); + idl_delete_scoped_name($1); + } + ; + +base_type_spec: + integer_type + | floating_pt_type + | char_type + | wide_char_type + | boolean_type + | octet_type + ; + +floating_pt_type: + "float" { $$ = IDL_FLOAT; } + | "double" { $$ = IDL_DOUBLE; } + | "long" "double" { $$ = IDL_LDOUBLE; } + ; + +integer_type: + signed_int + | unsigned_int + ; + +signed_int: + "short" { $$ = IDL_SHORT; } + | "long" { $$ = IDL_LONG; } + | "long" "long" { $$ = IDL_LLONG; } + /* building block extended data-types */ + | "int8" { $$ = IDL_INT8; } + | "int16" { $$ = IDL_INT16; } + | "int32" { $$ = IDL_INT32; } + | "int64" { $$ = IDL_INT64; } + ; + +unsigned_int: + "unsigned" "short" { $$ = IDL_USHORT; } + | "unsigned" "long" { $$ = IDL_ULONG; } + | "unsigned" "long" "long" { $$ = IDL_ULLONG; } + /* building block extended data-types */ + | "uint8" { $$ = IDL_UINT8; } + | "uint16" { $$ = IDL_UINT16; } + | "uint32" { $$ = IDL_UINT32; } + | "uint64" { $$ = IDL_UINT64; } + ; + +char_type: + "char" { $$ = IDL_CHAR; }; + +wide_char_type: + "wchar" { $$ = IDL_WCHAR; }; + +boolean_type: + "boolean" { $$ = IDL_BOOL; }; + +octet_type: + "octet" { $$ = IDL_OCTET; }; + +template_type_spec: + sequence_type { $$ = $1; } + | string_type { $$ = $1; } + ; + +sequence_type: + "sequence" '<' type_spec ',' positive_int_const '>' + { TRY(idl_create_sequence(pstate, LOC(@1.first, @6.last), $3, $5, &$$)); } + | "sequence" '<' type_spec '>' + { TRY(idl_create_sequence(pstate, LOC(@1.first, @4.last), $3, NULL, &$$)); } + ; + +string_type: + "string" '<' positive_int_const '>' + { TRY(idl_create_string(pstate, LOC(@1.first, @4.last), $3, &$$)); } + | "string" + { TRY(idl_create_string(pstate, LOC(@1.first, @1.last), NULL, &$$)); } + ; + +constr_type_dcl: + struct_dcl + | union_dcl + | enum_dcl + ; + +struct_dcl: + struct_def { $$ = $1; } + ; + +struct_def: + struct_header '{' struct_body '}' + { TRY(idl_finalize_struct(pstate, LOC(@1.first, @4.last), $1, $3)); + $$ = $1; + } + ; + +struct_header: + "struct" identifier struct_inherit_spec + { TRY(idl_create_struct(pstate, LOC(@1.first, $3 ? @3.last : @2.last), $2, $3, &$$)); } + ; + +struct_inherit_spec: + %empty { $$ = NULL; } + /* IDL 4.2 section 7.4.13 Building Block Extended Data-Types */ + /* %?{ (proc->flags & IDL_FLAG_EXTENDED_DATA_TYPES) } */ + | ':' scoped_name + { idl_node_t *node; + const idl_declaration_t *declaration; + static const char fmt[] = + "Scoped name '%s' does not resolve to a struct"; + TRY(idl_resolve(pstate, 0u, $2, &declaration)); + node = idl_unalias(declaration->node, 0u); + if (!idl_is_struct(node)) + SEMANTIC_ERROR(pstate, &@2, fmt, $2->identifier); + TRY(idl_create_inherit_spec(pstate, &@2, idl_reference_node(node), &$$)); + idl_delete_scoped_name($2); + } + ; + +struct_body: + members + { $$ = $1; } + /* IDL 4.2 section 7.4.13 Building Block Extended Data-Types */ + /* %?{ (proc->flags & IDL_FLAG_EXTENDED_DATA_TYPES) } */ + | %empty + { $$ = NULL; } + ; + +members: + member + { $$ = $1; } + | members member + { $$ = idl_push_node($1, $2); } + ; + +member: + annotations type_spec declarators ';' + { TRY(idl_create_member(pstate, LOC(@2.first, @4.last), $2, $3, &$$)); + TRY_EXCEPT(idl_annotate(pstate, $$, $1), free($$)); + } + ; + +union_dcl: + union_def { $$ = $1; } + ; + +union_def: + union_header '{' switch_body '}' + { TRY(idl_finalize_union(pstate, LOC(@1.first, @4.last), $1, $3)); + $$ = $1; + } + ; + +union_header: + "union" identifier "switch" '(' annotations switch_type_spec + { idl_switch_type_spec_t *node = NULL; + TRY(idl_create_switch_type_spec(pstate, &@6, $6, &node)); + TRY_EXCEPT(idl_annotate(pstate, node, $5), idl_delete_node(node)); + $$ = node; + } + ')' + { idl_switch_type_spec_t *node = $7; + TRY(idl_create_union(pstate, LOC(@1.first, @8.last), $2, node, &$$)); + } + ; + +switch_type_spec: + integer_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | char_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | boolean_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | scoped_name + { const idl_declaration_t *declaration; + TRY(idl_resolve(pstate, 0u, $1, &declaration)); + idl_delete_scoped_name($1); + $$ = idl_reference_node((idl_node_t *)declaration->node); + } + | wide_char_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + | octet_type + { TRY(idl_create_base_type(pstate, &@1, $1, &$$)); } + ; + +switch_body: + case + { $$ = $1; } + | switch_body case + { $$ = idl_push_node($1, $2); } + ; + +case: + case_labels element_spec ';' + { TRY(idl_finalize_case(pstate, &@2, $2, $1)); + $$ = $2; + } + ; + +case_labels: + case_label + { $$ = $1; } + | case_labels case_label + { $$ = idl_push_node($1, $2); } + ; + +case_label: + "case" const_expr ':' + { TRY(idl_create_case_label(pstate, LOC(@1.first, @2.last), $2, &$$)); } + | "default" ':' + { TRY(idl_create_case_label(pstate, &@1, NULL, &$$)); } + ; + +element_spec: + type_spec declarator + { TRY(idl_create_case(pstate, LOC(@1.first, @2.last), $1, $2, &$$)); } + ; + +enum_dcl: enum_def { $$ = $1; } ; + +enum_def: + "enum" identifier '{' enumerators '}' + { TRY(idl_create_enum(pstate, LOC(@1.first, @5.last), $2, $4, &$$)); } + ; + +enumerators: + enumerator + { $$ = $1; } + | enumerators ',' enumerator + { $$ = idl_push_node($1, $3); } + ; + +enumerator: + annotations identifier + { TRY(idl_create_enumerator(pstate, &@2, $2, &$$)); + TRY_EXCEPT(idl_annotate(pstate, $$, $1), free($$)); + } + ; + +array_declarator: + identifier fixed_array_sizes + { TRY(idl_create_declarator(pstate, LOC(@1.first, @2.last), $1, $2, &$$)); } + ; + +fixed_array_sizes: + fixed_array_size + { $$ = $1; } + | fixed_array_sizes fixed_array_size + { $$ = idl_push_node($1, $2); } + ; + +fixed_array_size: + '[' positive_int_const ']' + { $$ = $2; } + ; + +simple_declarator: + identifier + { TRY(idl_create_declarator(pstate, &@1, $1, NULL, &$$)); } + ; + +complex_declarator: array_declarator ; + +typedef_dcl: + "typedef" type_spec declarators + { TRY(idl_create_typedef(pstate, LOC(@1.first, @3.last), $2, $3, &$$)); } + ; + +declarators: + declarator + { $$ = $1; } + | declarators ',' declarator + { $$ = idl_push_node($1, $3); } + ; + +declarator: + simple_declarator + | complex_declarator + ; + +identifier: + IDL_TOKEN_IDENTIFIER + { $$ = NULL; + size_t n; + bool nocase = (pstate->flags & IDL_FLAG_CASE_SENSITIVE) == 0; + if (pstate->parser.state == IDL_PARSE_ANNOTATION_APPL) + n = 0; + else if (pstate->parser.state == IDL_PARSE_ANNOTATION) + n = 0; + else if (!(n = ($1[0] == '_')) && idl_iskeyword(pstate, $1, nocase)) + SEMANTIC_ERROR(pstate, &@1, "Identifier '%s' collides with a keyword", $1); + + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_create_name(pstate, &@1, idl_strdup($1+n), &$$)); + } + ; + +annotation_dcl: + annotation_header '{' annotation_body '}' + { $$ = NULL; + /* discard annotation in case of redefinition */ + if (pstate->parser.state != IDL_PARSE_EXISTING_ANNOTATION_BODY) + $$ = $1; + TRY(idl_finalize_annotation(pstate, LOC(@1.first, @4.last), $1, $3)); + } + ; + +annotation_header: + "@" "annotation" + { pstate->annotations = true; /* register annotation occurence */ + pstate->parser.state = IDL_PARSE_ANNOTATION; + } + identifier + { TRY(idl_create_annotation(pstate, LOC(@1.first, @2.last), $4, &$$)); } + ; + +annotation_body: + %empty + { $$ = NULL; } + | annotation_body annotation_member ';' + { $$ = idl_push_node($1, $2); } + | annotation_body enum_dcl ';' + { $$ = idl_push_node($1, $2); } + | annotation_body const_dcl ';' + { $$ = idl_push_node($1, $2); } + | annotation_body typedef_dcl ';' + { $$ = idl_push_node($1, $2); } + ; + +annotation_member: + annotation_member_type simple_declarator annotation_member_default + { TRY(idl_create_annotation_member(pstate, LOC(@1.first, @3.last), $1, $2, $3, &$$)); } + ; + +annotation_member_type: + const_type + { $$ = $1; } + | any_const_type + { $$ = $1; } + ; + +annotation_member_default: + %empty + { $$ = NULL; } + | IDL_TOKEN_DEFAULT const_expr + { $$ = $2; } + ; + +any_const_type: + IDL_TOKEN_ANY + { TRY(idl_create_base_type(pstate, &@1, IDL_ANY, &$$)); } + ; + +annotations: + annotation_appls + { $$ = $1; } + | %empty + { $$ = NULL; } + ; + +annotation_appls: + annotation_appl + { $$ = $1; } + | annotation_appls annotation_appl + { $$ = idl_push_node($1, $2); } + ; + +annotation_appl: + "@" + { pstate->parser.state = IDL_PARSE_ANNOTATION_APPL; } + annotation_appl_name + { idl_annotation_appl_t *node = NULL; + const idl_annotation_t *annotation; + const idl_declaration_t *declaration = + idl_find_scoped_name(pstate, NULL, $3, IDL_FIND_ANNOTATION); + + pstate->annotations = true; /* register annotation occurence */ + if (!declaration) { + pstate->parser.state = IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS; + } else { + annotation = idl_reference_node((idl_node_t *)declaration->node); + TRY(idl_create_annotation_appl(pstate, LOC(@1.first, @3.last), annotation, &node)); + pstate->parser.state = IDL_PARSE_ANNOTATION_APPL_PARAMS; + pstate->annotation_scope = declaration->scope; + } + $$ = node; + } + annotation_appl_params + { if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) + TRY(idl_finalize_annotation_appl(pstate, LOC(@1.first, @5.last), $4, $5)); + pstate->parser.state = IDL_PARSE; + pstate->annotation_scope = NULL; + $$ = $4; + idl_delete_scoped_name($3); + } + ; + +annotation_appl_name: + identifier + { TRY(idl_create_scoped_name(pstate, &@1, $1, false, &$$)); } + | IDL_TOKEN_SCOPE_NO_SPACE identifier + { TRY(idl_create_scoped_name(pstate, LOC(@1.first, @2.last), $2, true, &$$)); } + | annotation_appl_name IDL_TOKEN_SCOPE_NO_SPACE identifier + { TRY(idl_push_scoped_name(pstate, $1, $3)); + $$ = $1; + } + ; + +annotation_appl_params: + %empty + { $$ = NULL; } + | '(' const_expr ')' + { $$ = $2; } + | '(' annotation_appl_keyword_params ')' + { $$ = $2; } + ; + +annotation_appl_keyword_params: + annotation_appl_keyword_param + { $$ = $1; } + | annotation_appl_keyword_params ',' annotation_appl_keyword_param + { $$ = idl_push_node($1, $3); } + ; + +annotation_appl_keyword_param: + identifier + { idl_annotation_member_t *node = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) { + const idl_declaration_t *declaration = NULL; + static const char fmt[] = + "Unknown annotation member '%s'"; + declaration = idl_find(pstate, pstate->annotation_scope, $1, 0u); + if (declaration && (idl_mask(declaration->node) & IDL_DECLARATOR)) + node = (idl_annotation_member_t *)((const idl_node_t *)declaration->node)->parent; + if (!node || !(idl_mask(node) & IDL_ANNOTATION_MEMBER)) + SEMANTIC_ERROR(pstate, &@1, fmt, $1->identifier); + node = idl_reference_node((idl_node_t *)node); + } + $$ = node; + idl_delete_name($1); + } + '=' const_expr + { $$ = NULL; + if (pstate->parser.state != IDL_PARSE_UNKNOWN_ANNOTATION_APPL_PARAMS) { + TRY(idl_create_annotation_appl_param(pstate, &@1, $2, $4, &$$)); + } + } + ; + +%% + +#if defined(__GNUC__) +_Pragma("GCC diagnostic pop") +_Pragma("GCC diagnostic pop") +_Pragma("GCC diagnostic pop") +#endif + +/* copied from yyreturn in Bison generated parser */ +void idl_yypstate_delete_stack(idl_yypstate *yyps) +{ +#ifndef yyss +# define yyss yyps->yyss +#endif +#ifndef yyssp +# define yyssp yyps->yyssp +#endif +#ifndef yyvsp +# define yyvsp yyps->yyvsp +#endif +#ifndef yylsp +# define yylsp yyps->yylsp +#endif + if (yyps && !yyps->yynew) + { + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, NULL); + YYPOPSTACK (1); + } + } +} + +int idl_iskeyword(idl_pstate_t *pstate, const char *str, int nc) +{ + int toknum = 0; + int(*cmp)(const char *s1, const char *s2, size_t n); + + assert(str != NULL); + + cmp = (nc ? &idl_strncasecmp : strncmp); + + for (size_t i = 0, n = strlen(str); i < YYNTOKENS && !toknum; i++) { + if (yytname[i] != 0 + && yytname[i][ 0] == '"' + && cmp(yytname[i] + 1, str, n) == 0 + && yytname[i][n + 1] == '"' + && yytname[i][n + 2] == '\0') { + toknum = yytoknum[i]; + } + } + + switch (toknum) { + case IDL_TOKEN_ANNOTATION: + return 0; + case IDL_TOKEN_INT8: + case IDL_TOKEN_INT16: + case IDL_TOKEN_INT32: + case IDL_TOKEN_INT64: + case IDL_TOKEN_UINT8: + case IDL_TOKEN_UINT16: + case IDL_TOKEN_UINT32: + case IDL_TOKEN_UINT64: + case IDL_TOKEN_MAP: + /* intX and uintX are considered keywords if and only if building block + extended data-types is enabled */ + if (!(pstate->flags & IDL_FLAG_EXTENDED_DATA_TYPES)) + return 0; + break; + default: + break; + }; + + return toknum; +} + +static void +yyerror(idl_location_t *loc, idl_pstate_t *pstate, const char *str) +{ + idl_error(pstate, loc, str); +} diff --git a/src/idl/src/processor.c b/src/idl/src/processor.c new file mode 100644 index 0000000000..bf84a8d14a --- /dev/null +++ b/src/idl/src/processor.c @@ -0,0 +1,415 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include + +#include "idl/processor.h" +#include "idl/string.h" +#include "annotation.h" +#include "directive.h" +#include "scanner.h" +#include "tree.h" +#include "scope.h" + +#include "parser.h" + +static const idl_file_t builtin_file = + { NULL, "" }; +static const idl_source_t builtin_source = + { NULL, NULL, NULL, NULL, true, &builtin_file, &builtin_file }; +#define BUILTIN_POSITION { &builtin_source, &builtin_file, 1, 1 } +#define BUILTIN_LOCATION { BUILTIN_POSITION, BUILTIN_POSITION } +static const idl_name_t builtin_name = + { { BUILTIN_LOCATION }, "" }; + +static idl_retcode_t parse_grammar(idl_pstate_t *pstate, idl_token_t *tok); + +static idl_retcode_t +parse_builtin_annotations( + idl_pstate_t *pstate, + const idl_builtin_annotation_t *annotations) +{ + idl_token_t token; + idl_retcode_t ret = IDL_RETCODE_OK; + + for (size_t i=0; annotations[i].syntax; i++) { + unsigned seen = 0, save = 0; + idl_scope_t *scope = NULL; + idl_name_t name; + pstate->scanner.state = IDL_SCAN; + pstate->buffer.data = (char *)annotations[i].syntax; + pstate->buffer.size = pstate->buffer.used = strlen(pstate->buffer.data); + pstate->scanner.cursor = pstate->buffer.data; + pstate->scanner.limit = pstate->buffer.data + pstate->buffer.used; + pstate->scanner.position = (idl_position_t)BUILTIN_POSITION; + + memset(&name, 0, sizeof(name)); + memset(&token, 0, sizeof(token)); + do { + save = 0; + if ((ret = idl_scan(pstate, &token)) < 0) + break; + ret = IDL_RETCODE_OK; + /* ignore comments and processor directives */ + if (token.code != '\0' && + token.code != '\n' && + token.code != IDL_TOKEN_COMMENT && + token.code != IDL_TOKEN_LINE_COMMENT && + !((unsigned)pstate->scanner.state & (unsigned)IDL_SCAN_DIRECTIVE)) + { + if (pstate->parser.state == IDL_PARSE_ANNOTATION) { + assert(token.code == IDL_TOKEN_IDENTIFIER); + seen++; + save = (seen == 1); + scope = pstate->scope; + } + ret = parse_grammar(pstate, &token); + } + switch (token.code) { + case '\n': + pstate->scanner.state = IDL_SCAN; + break; + case IDL_TOKEN_IDENTIFIER: + if (save) { + name.symbol.location = token.location; + name.identifier = token.value.str; + } + /* fall through */ + case IDL_TOKEN_STRING_LITERAL: + case IDL_TOKEN_PP_NUMBER: + case IDL_TOKEN_COMMENT: + case IDL_TOKEN_LINE_COMMENT: + if (token.value.str && !save) { + free(token.value.str); + } + break; + default: + break; + } + } while (token.code != '\0' && + (ret == IDL_RETCODE_OK || ret == IDL_RETCODE_PUSH_MORE)); + + if (seen == 1) { + idl_annotation_t *annotation; + const idl_declaration_t *declaration; + declaration = idl_find(pstate, scope, &name, IDL_FIND_ANNOTATION); + if (declaration) { + annotation = (idl_annotation_t *)declaration->node; + /* multiple definitions of the same annotation may exist, provided + they are consistent */ + if (!memcmp(&annotation->name->symbol.location, &name.symbol.location, sizeof(name.symbol.location))) + annotation->callback = annotations[i].callback; + } + } + + if (name.identifier) { + free(name.identifier); + } + + /* builtin annotations must not declare more than one annotation per block + to avoid ambiguity in annotation-callback mapping */ + if (seen > 1) { + idl_error(pstate, &token.location, + "Multiple declarations of builtin annotations in same block"); + return IDL_RETCODE_SYNTAX_ERROR; + } + } + + return ret; +} + +extern int idl_yydebug; + +idl_retcode_t +idl_create_pstate( + uint32_t flags, + const idl_builtin_annotation_t *annotations, + idl_pstate_t **pstatep) +{ + idl_scope_t *scope = NULL; + idl_pstate_t *pstate; + + (void)flags; + if (!(pstate = calloc(1, sizeof(*pstate)))) + goto err_pstate; + if (!(pstate->parser.yypstate = idl_yypstate_new())) + goto err_yypstate; + if (idl_create_scope(pstate, IDL_GLOBAL_SCOPE, &builtin_name, NULL, &scope)) + goto err_scope; + + pstate->flags = flags; + pstate->global_scope = pstate->scope = scope; + + if (pstate->flags & IDL_FLAG_ANNOTATIONS) { + idl_retcode_t ret; + if ((ret = parse_builtin_annotations(pstate, builtin_annotations))) { + idl_delete_pstate(pstate); + return ret; + } + if (annotations && (ret = parse_builtin_annotations(pstate, annotations))) { + idl_delete_pstate(pstate); + return ret; + } + } + + pstate->keylists = false; + pstate->annotations = false; + pstate->parser.state = IDL_PARSE; + pstate->scanner.state = IDL_SCAN; + memset(&pstate->buffer, 0, sizeof(pstate->buffer)); + memset(&pstate->scanner, 0, sizeof(pstate->scanner)); + pstate->builtin_root = pstate->root; + *pstatep = pstate; + return IDL_RETCODE_OK; +err_scope: + idl_yypstate_delete(pstate->parser.yypstate); +err_yypstate: + free(pstate); +err_pstate: + return IDL_RETCODE_NO_MEMORY; +} + +static void delete_source(idl_source_t *src) +{ + if (!src) + return; + for (idl_source_t *n, *s=src; s; s = n) { + n = s->next; + delete_source(s->includes); + free(s); + } +} + +void idl_delete_pstate(idl_pstate_t *pstate) +{ + if (pstate) { + /* parser */ + if (pstate->parser.yypstate) { + idl_yypstate_delete_stack(pstate->parser.yypstate); + idl_yypstate_delete(pstate->parser.yypstate); + } + idl_delete_node(pstate->builtin_root); + /* directive */ + if (pstate->directive) + idl_delete_directive(pstate); + idl_delete_scope(pstate->global_scope); + /* sources */ + delete_source(pstate->sources); + /* files */ + for (idl_file_t *n, *f=pstate->files; f; f = n) { + n = f->next; + if (f->name) + free(f->name); + free(f); + } + /* paths */ + for (idl_file_t *n, *f=pstate->paths; f; f = n) { + n = f->next; + if (f->name) + free(f->name); + free(f); + } + /* buffer */ + if (pstate->buffer.data) + free(pstate->buffer.data); + free(pstate); + } +} + +static void +idl_log( + idl_pstate_t *pstate, uint32_t prio, const idl_location_t *loc, const char *fmt, va_list ap) +{ + char buf[1024]; + int cnt = 0; + size_t off; + + buf[0] = '\0'; + (void)pstate; + (void)prio; + if (loc && loc->first.file) + cnt = snprintf( + buf, sizeof(buf)-1, "%s:%u:%u: ", loc->first.file->name, loc->first.line, loc->first.column); + else if (loc) + cnt = snprintf( + buf, sizeof(buf)-1, "%u:%u: ", loc->first.line, loc->first.column); + + if (cnt == -1) + return; + + off = (size_t)cnt; + cnt = vsnprintf(buf+off, sizeof(buf)-off, fmt, ap); + + if (cnt == -1) + return; + + fprintf(stderr, "%s\n", buf); +} + +#define IDL_LC_ERROR 1 +#define IDL_LC_WARNING 2 + +void +idl_verror( + idl_pstate_t *pstate, const idl_location_t *loc, const char *fmt, va_list ap) +{ + idl_log(pstate, IDL_LC_ERROR, loc, fmt, ap); +} + +void +idl_error( + idl_pstate_t *pstate, const idl_location_t *loc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + idl_log(pstate, IDL_LC_ERROR, loc, fmt, ap); + va_end(ap); +} + +void +idl_warning( + idl_pstate_t *pstate, const idl_location_t *loc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + idl_log(pstate, IDL_LC_WARNING, loc, fmt, ap); + va_end(ap); +} + +static idl_retcode_t parse_grammar(idl_pstate_t *pstate, idl_token_t *tok) +{ + idl_retcode_t ret; + IDL_YYSTYPE yylval; + + switch (tok->code) { + case IDL_TOKEN_CHAR_LITERAL: + yylval.chr = tok->value.chr; + break; + case IDL_TOKEN_IDENTIFIER: + case IDL_TOKEN_STRING_LITERAL: + yylval.str = tok->value.str; + break; + case IDL_TOKEN_INTEGER_LITERAL: + yylval.ullng = tok->value.ullng; + break; + case IDL_TOKEN_FLOATING_PT_LITERAL: + yylval.ldbl = tok->value.ldbl; + break; + default: + memset(&yylval, 0, sizeof(yylval)); + break; + } + + switch ((ret = idl_yypush_parse( + pstate->parser.yypstate, tok->code, &yylval, &tok->location, pstate))) + { + case 0: /* success */ + break; + case 1: /* parse error */ + return IDL_RETCODE_SYNTAX_ERROR; + case 2: /* out of memory */ + return IDL_RETCODE_NO_MEMORY; + case 4: /* push more */ + return IDL_RETCODE_PUSH_MORE; + default: + assert(ret < 0); + return ret; + } + + return IDL_RETCODE_OK; +} + +idl_retcode_t idl_parse(idl_pstate_t *pstate) +{ + idl_retcode_t ret; + idl_token_t tok; + memset(&tok, 0, sizeof(tok)); + + do { + if ((ret = idl_scan(pstate, &tok)) < 0) + break; + ret = IDL_RETCODE_OK; + if (tok.code != IDL_TOKEN_COMMENT && tok.code != IDL_TOKEN_LINE_COMMENT) { + if ((unsigned)pstate->scanner.state & (unsigned)IDL_SCAN_DIRECTIVE) { + ret = idl_parse_directive(pstate, &tok); + if ((tok.code == '\0') && + (ret == IDL_RETCODE_OK || ret == IDL_RETCODE_PUSH_MORE)) + goto grammar; + } else if (tok.code != '\n') { +grammar: + ret = parse_grammar(pstate, &tok); + } + } + /* free memory associated with token value */ + switch (tok.code) { + case '\n': + pstate->scanner.state = IDL_SCAN; + break; + case IDL_TOKEN_IDENTIFIER: + case IDL_TOKEN_STRING_LITERAL: + case IDL_TOKEN_PP_NUMBER: + case IDL_TOKEN_COMMENT: + case IDL_TOKEN_LINE_COMMENT: + if (tok.value.str) + free(tok.value.str); + break; + default: + break; + } + } while ((tok.code != '\0') && + (ret == IDL_RETCODE_OK || ret == IDL_RETCODE_PUSH_MORE)); + + pstate->builtin_root = pstate->root; + for (idl_node_t *node = pstate->root; node; node = node->next) { + if (node->symbol.location.first.file != &builtin_file) { + pstate->root = node; + break; + } + } + + return ret; +} + +idl_retcode_t idl_parse_string(idl_pstate_t *pstate, const char *str) +{ + idl_retcode_t ret; + + assert(str); + + pstate->buffer.data = (char *)str; + pstate->buffer.size = pstate->buffer.used = strlen(str); + pstate->scanner.cursor = pstate->buffer.data; + pstate->scanner.limit = pstate->buffer.data + pstate->buffer.used; + pstate->scanner.position.file = NULL; + pstate->scanner.position.source = NULL; + pstate->scanner.position.line = 1; + pstate->scanner.position.column = 1; + + if ((ret = idl_parse(pstate)) == IDL_RETCODE_OK) { + assert(pstate->root); + } + + pstate->buffer.data = NULL; + pstate->buffer.size = pstate->buffer.used = 0; + pstate->scanner.cursor = pstate->scanner.limit = NULL; + pstate->scanner.position.line = 0; + pstate->scanner.position.column = 0; + + return ret; +} diff --git a/src/idl/src/scanner.c b/src/idl/src/scanner.c new file mode 100644 index 0000000000..9bd9ef630b --- /dev/null +++ b/src/idl/src/scanner.c @@ -0,0 +1,839 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include + +#include "idl/processor.h" +#include "idl/string.h" +#include "scanner.h" +#include "parser.h" + +/* treat every cr+lf, lf+cr, cr, lf sequence as a single newline */ +static int32_t +have_newline(idl_pstate_t *pstate, const char *cur) +{ + if (cur == pstate->scanner.limit) + return pstate->flags & IDL_WRITE ? -2 : 0; + assert(cur < pstate->scanner.limit); + if (cur[0] == '\n') { + if (cur < pstate->scanner.limit - 1) + return cur[1] == '\r' ? 2 : 1; + return pstate->flags & IDL_WRITE ? -1 : 1; + } else if (cur[0] == '\r') { + if (cur < pstate->scanner.limit - 1) + return cur[1] == '\n' ? 2 : 1; + return pstate->flags & IDL_WRITE ? -1 : 1; + } + return 0; +} + +static int32_t +have_skip(idl_pstate_t *pstate, const char *cur) +{ + int cnt = 0; + if (cur == pstate->scanner.limit) + return pstate->flags & IDL_WRITE ? -3 : 0; + assert(cur < pstate->scanner.limit); + if (*cur == '\\' && (cnt = have_newline(pstate, cur + 1)) > 0) + cnt++; + return cnt; +} + +static int32_t +have_space(idl_pstate_t *pstate, const char *cur) +{ + if (cur == pstate->scanner.limit) + return pstate->flags & IDL_WRITE ? -2 : 0; + assert(cur < pstate->scanner.limit); + if (*cur == ' ' || *cur == '\t' || *cur == '\f' || *cur == '\v') + return 1; + return have_newline(pstate, cur); +} + +static int32_t +have_digit(idl_pstate_t *pstate, const char *cur) +{ + if (cur == pstate->scanner.limit) + return pstate->flags & IDL_WRITE ? -1 : 0; + assert(cur < pstate->scanner.limit); + return (*cur >= '0' && *cur <= '9'); +} + +static int32_t +have_alpha(idl_pstate_t *pstate, const char *cur) +{ + if (cur == pstate->scanner.limit) + return pstate->flags & IDL_WRITE ? -1 : 0; + assert(cur < pstate->scanner.limit); + return (*cur >= 'a' && *cur <= 'z') || + (*cur >= 'A' && *cur <= 'Z') || + (*cur == '_'); +} + +static int32_t +have_alnum(idl_pstate_t *pstate, const char *cur) +{ + if (cur == pstate->scanner.limit) + return pstate->flags & IDL_WRITE ? -1 : 0; + assert(cur < pstate->scanner.limit); + return (*cur >= 'a' && *cur <= 'z') || + (*cur >= 'A' && *cur <= 'Z') || + (*cur >= '0' && *cur <= '9') || + (*cur == '_'); +} + +static void +error(idl_pstate_t *pstate, const char *cur, const char *fmt, ...) +{ + int cnt; + const char *ptr = pstate->scanner.cursor; + idl_location_t loc; + va_list ap; + + /* determine exact location */ + loc.first = pstate->scanner.position; + loc.last = (idl_position_t){NULL, NULL, 0, 0}; + while (ptr < cur) { + if ((cnt = have_newline(pstate, ptr)) > 0) { + loc.first.line++; + loc.first.column = 0; + ptr += cnt; + } else { + ptr++; + } + loc.first.column++; + } + + va_start(ap, fmt); + idl_verror(pstate, &loc, fmt, ap); + va_end(ap); +} + +static const char * +next(idl_pstate_t *pstate, const char *cur) +{ + int cnt; + + /* might be positioned at newline */ + if ((cnt = have_newline(pstate, cur))) { + if (cnt < 0) + return pstate->scanner.limit; + cur += (size_t)cnt; + } else { + cur++; /* skip to next character */ + } + /* skip if positioned at line continuation sequence */ + for (; (cnt = have_skip(pstate, cur)) > 0; cur += (size_t)cnt) ; + + return cnt < 0 ? pstate->scanner.limit : cur; +} + +static const char * +move(idl_pstate_t *pstate, const char *cur) +{ + int cnt; + const char *ptr; + + assert(cur >= pstate->scanner.cursor && cur <= pstate->scanner.limit); + for (ptr = pstate->scanner.cursor; ptr < cur; ptr += cnt) { + if ((cnt = have_newline(pstate, ptr)) > 0) { + pstate->scanner.position.line++; + pstate->scanner.position.column = 1; + } else { + cnt = 1; + pstate->scanner.position.column++; + } + } + pstate->scanner.cursor = cur; + return cur; +} + +static int32_t +peek(idl_pstate_t *pstate, const char *cur) +{ + int cnt; + + /* skip if positioned at line continuation sequences */ + for (; (cnt = have_skip(pstate, cur)) > 0; cur += cnt) ; + + if (cnt < 0 || cur == pstate->scanner.limit) + return '\0'; + return *cur; +} + +static int32_t +have(idl_pstate_t *pstate, const char *cur, const char *str) +{ + int cnt; + size_t len, pos; + const char *lim = cur; + + for (pos = 0, len = strlen(str); pos < len; pos++, lim++) { + /* skip any line continuation sequences */ + while ((cnt = have_skip(pstate, lim)) > 0) + lim += cnt; + if (cnt < 0) + return cnt - (int)(len - pos); + if (str[pos] != *lim) + return 0; + } + + return (int)(lim - cur); +} + +static int32_t +need_refill(idl_pstate_t *pstate, const char *cur) +{ + return have_skip(pstate, cur) < 0; +} + +static int32_t +scan_line_comment(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int cnt = 0; + + cur = next(pstate, cur); + while ((cur = next(pstate, cur)) < pstate->scanner.limit) { + if ((cnt = have_newline(pstate, cur))) + break; + } + + if (need_refill(pstate, cur)) + return IDL_RETCODE_NEED_REFILL; + *lim = cur; + return IDL_TOKEN_LINE_COMMENT; +} + +static int32_t +scan_comment(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + enum { initial, escape, asterisk, slash } state = initial; + + cur = next(pstate, cur); + while (state != slash && (cur = next(pstate, cur)) < pstate->scanner.limit) { + switch (state) { + case initial: + if (*cur == '\\') + state = escape; + else if (*cur == '*') + state = asterisk; + break; + case escape: + state = initial; + break; + case asterisk: + if (*cur == '\\') + state = escape; + else if (*cur == '/') + state = slash; + else if (*cur != '*') + state = initial; + break; + default: + assert(state == slash && false); + break; + } + } + + *lim = cur; + if (state == slash) { + assert(cur < pstate->scanner.limit); + *lim = cur + 1; + return IDL_TOKEN_COMMENT; + } else if (need_refill(pstate, cur)) { + return IDL_RETCODE_NEED_REFILL; + } + error(pstate, cur, "unterminated comment"); + return IDL_RETCODE_SYNTAX_ERROR; +} + +static int32_t +scan_char_literal(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int cnt = 0, esc = 0; + size_t pos = 0; + const size_t max = 5; /* \uhhhh */ + + for (; pos < max && (cur = next(pstate, cur)) < pstate->scanner.limit; pos++) { + if (esc) + esc = 0; + else if (*cur == '\\') + esc = 1; + else if (*cur == '\'') + break; + else if ((cnt = have_newline(pstate, cur))) + break; + } + + if (cnt < 0) { + return IDL_RETCODE_NEED_REFILL; + } else if (cnt > 0) { + error(pstate, cur, "unterminated character constant"); + return IDL_RETCODE_SYNTAX_ERROR; + } else if (pos > max) { + error(pstate, cur, "invalid character constant"); + return IDL_RETCODE_SYNTAX_ERROR; + } + + assert(*cur == '\''); + *lim = cur + 1; + return IDL_TOKEN_CHAR_LITERAL; +} + +static int32_t +scan_string_literal(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int cnt = 0, esc = 0; + + while ((cur = next(pstate, cur)) < pstate->scanner.limit) { + if (esc) + esc = 0; + else if (*cur == '\\') + esc = 1; + else if (*cur == '\"') + break; + else if ((cnt = have_newline(pstate, cur))) + break; + } + + if (cnt < 0) { + return IDL_RETCODE_NEED_REFILL; + } else if (cnt > 0) { + error(pstate, cur, "unterminated string literal"); + return IDL_RETCODE_SYNTAX_ERROR; + } + + assert(*cur == '\"'); + *lim = cur + 1; + return IDL_TOKEN_STRING_LITERAL; +} + +static int +scan_floating_pt_literal( + idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int32_t chr = peek(pstate, cur); + enum { integer, fraction, exponent } state = integer; + + if (chr >= '0' && chr <= '9') { + state = integer; + } else { + assert(chr == '.'); + cur = next(pstate, cur); + chr = peek(pstate, cur); + assert(chr >= '0' && chr <= '9'); + state = fraction; + } + + while ((cur = next(pstate, cur)) < pstate->scanner.limit) { + chr = peek(pstate, cur); + assert(chr != '\0'); + if (chr == '.') { + if (state != integer) + break; + state = fraction; + } else if (chr == 'e' || chr == 'E') { + const char *exp; + if (state != integer && state != fraction) + break; + exp = next(pstate, cur); + chr = peek(pstate, exp); + if (chr == '+' || chr == '-') + exp = next(pstate, exp); + if (!have_digit(pstate, exp)) + break; + cur = exp; + } else if (chr < '0' || chr > '9') { + assert(state != integer); + break; + } + } + + if (need_refill(pstate, cur)) + return IDL_RETCODE_NEED_REFILL; + *lim = cur; + return IDL_TOKEN_FLOATING_PT_LITERAL; +} + +static const char oct[] = "01234567"; +static const char dec[] = "0123456789"; +static const char hex[] = "0123456789abcdefABCDEF"; + +static int +scan_integer_literal(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int32_t chr = peek(pstate, cur); + const char *base, *off = cur; + if (chr >= '1' && chr <= '9') { + base = dec; + } else { + assert(chr == '0'); + chr = peek(pstate, next(pstate, cur)); + if (chr == 'x' || chr == 'X') { + cur = next(pstate, cur); /* skip x */ + base = hex; + } else { + base = oct; + } + } + + while ((cur = next(pstate, cur)) < pstate->scanner.limit) { + chr = peek(pstate, cur); + if (base != hex) { + if (chr == '.') { + return scan_floating_pt_literal(pstate, off, lim); + } else if (chr == 'e' || chr == 'E') { + const char *exp; + exp = next(pstate, cur); + chr = peek(pstate, exp); + if (chr == '+' || chr == '-') + exp = next(pstate, exp); + if (!have_digit(pstate, exp)) + break; + return scan_floating_pt_literal(pstate, off, lim); + } + } + if (!strchr(base, chr)) + break; + } + + if (need_refill(pstate, cur)) + return IDL_RETCODE_NEED_REFILL; + *lim = cur; + return IDL_TOKEN_INTEGER_LITERAL; +} + +static int32_t +scan_pp_number(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int32_t chr; + + if (*cur == '.') + cur = next(pstate, cur); + while ((cur = next(pstate, cur)) < pstate->scanner.limit) { + chr = peek(pstate, cur); + if (chr < '0' || chr > '9') + break; + } + + if (need_refill(pstate, cur)) + return IDL_RETCODE_NEED_REFILL; + *lim = cur; + return IDL_TOKEN_PP_NUMBER; +} + +static int32_t +scan_identifier(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int32_t cnt = 0; + + do { + *lim = cur; + /* skip over any line continuation sequences */ + for (; (cnt = have_skip(pstate, cur)) > 0; cur += cnt) ; + if ((cnt = have_alnum(pstate, cur)) == 0 && + (cnt = have(pstate, cur, "_")) == 0) + break; + else if (cnt < 0) + return IDL_RETCODE_NEED_REFILL; + cur += cnt; + } while (cnt); + + switch (pstate->scanner.state) { + case IDL_SCAN_ANNOTATION: + pstate->scanner.state = IDL_SCAN_ANNOTATION_NAME; + return IDL_TOKEN_ANNOTATION; + case IDL_SCAN_ANNOTATION_APPL: + case IDL_SCAN_ANNOTATION_APPL_SCOPED_NAME: + if ((cnt = have(pstate, *lim, "::")) < 0) + return IDL_RETCODE_NEED_REFILL; + else if (cnt > 0) + pstate->scanner.state = IDL_SCAN_ANNOTATION_APPL_SCOPE; + else + pstate->scanner.state = IDL_SCAN_ANNOTATION_APPL_SCOPED_NAME; + /* fall through */ + default: + return IDL_TOKEN_IDENTIFIER; + } +} + +/* grammer for IDL (>=4.0) is incorrect (or at least ambiguous). blanks, + horizontal and vertical tabs, newlines, form feeds, and comments + (collective, "white space") are ignored except as they serve to separate + tokens. the specification does not clearly pstate if white space may occur + between "::" and adjacent identifiers to form a "scoped_name". the same is + true for the "annotation_appl". in C++ "::" is an operator and white space + is therefore allowed, in IDL it is not. this did not use to be a problem, + but with the addition of annotations it became possible to have two + adjacent scoped names. many compilers (probably) implement just the + standardized annotations. the pragmatic approach is to forbid use of white + space in annotations, which works for standardized annotations like "@key" + and allow use of white space for scoped names elsewhere. to implement this + feature the parser must know whether or not white space occurred between an + identifier and the scope operator. however, white space cannot be + communicated to the the parser (the grammer would explode) and an + introducing an extra identifier class is not an option (same reason). to + work around this problem, the lexer communicates different types of scope + operators used by the parser to implement a specialized "scoped_name" + version just for annotations. */ +static int32_t +scan_scope(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int32_t cnt; + + cnt = have(pstate, cur, "::"); + assert(cnt > 0); + *lim = (cur += cnt); + + switch(pstate->scanner.state) { + case IDL_SCAN_ANNOTATION_APPL: + case IDL_SCAN_ANNOTATION_APPL_SCOPE: + if ((cnt = have_alpha(pstate, cur)) == 0 && + (cnt = have(pstate, cur, "_")) == 0) + { + pstate->scanner.state = IDL_SCAN_ANNOTATION_APPL_SCOPED_NAME; + return IDL_TOKEN_SCOPE_NO_SPACE; + } else if (cnt < 0) { + return IDL_RETCODE_NEED_REFILL; + } else { + pstate->scanner.state = IDL_SCAN_GRAMMAR; + } + /* fall through */ + default: + return IDL_TOKEN_SCOPE; + } +} + +static int32_t +scan_at(idl_pstate_t *pstate, const char *cur, const char **lim) +{ + int32_t cnt, code = '@'; + + cnt = have(pstate, cur, "@"); + assert(cnt > 0); + *lim = (cur += cnt); + /* detect @annotation */ + if ((cnt = have(pstate, cur, "annotation")) < 0) { + return IDL_RETCODE_NEED_REFILL; + } else if (cnt > 0) { + cur += cnt; + code = IDL_TOKEN_ANNOTATION_SYMBOL; + } + /* detect @foo and @::foo, catch @annotation:: */ + if ((cnt = have(pstate, cur, "::")) == 0 && + (cnt = have_alpha(pstate, cur)) == 0 && + (cnt = have(pstate, cur, "_")) == 0) + { + if (code == '@') + pstate->scanner.state = IDL_SCAN_GRAMMAR; + else + pstate->scanner.state = IDL_SCAN_ANNOTATION; + return code; + } else if (cnt < 0) { + return IDL_RETCODE_NEED_REFILL; + } else { + pstate->scanner.state = IDL_SCAN_ANNOTATION_APPL; + return IDL_TOKEN_ANNOTATION_SYMBOL; + } +} + +static idl_retcode_t +scan(idl_pstate_t *pstate, idl_lexeme_t *lex) +{ + int chr, cnt, code = '\0'; + const char *cur, *lim = pstate->scanner.cursor; + + do { + /* skip over any line continuation sequences */ + for (; (cnt = have_skip(pstate, lim)) > 0; lim += cnt) ; + + move(pstate, lim); + lex->location.first = pstate->scanner.position; + lex->marker = cur = lim; + + if (need_refill(pstate, lim)) + return IDL_RETCODE_NEED_REFILL; + + chr = peek(pstate, cur); + if (chr == '\0') { + assert(cur == pstate->scanner.limit); + break; + } else if (have(pstate, cur, "/*") > 0) { + code = scan_comment(pstate, cur, &lim); + } else if (have(pstate, cur, "//") > 0) { + code = scan_line_comment(pstate, cur, &lim); + } else if (chr == '\'') { + code = scan_char_literal(pstate, cur, &lim); + } else if (chr == '\"') { + code = scan_string_literal(pstate, cur, &lim); + } else if ((cnt = have_newline(pstate, cur)) > 0) { + lim = cur + cnt; + code = '\n'; + } else if ((cnt = have_space(pstate, cur)) > 0) { + /* skip space characters, except newline */ + lim = cur + cnt; + } else if ((unsigned)pstate->scanner.state & (unsigned)IDL_SCAN_DIRECTIVE) { + /* + * preprocessor + */ + if (chr == '.' && have_digit(pstate, next(pstate, cur))) { + code = scan_pp_number(pstate, cur, &lim); + } else if ((cnt = have_alpha(pstate, cur)) || chr == '_') { + code = scan_identifier(pstate, cur, &lim); + } else if ((cnt = have_digit(pstate, cur))) { + code = scan_pp_number(pstate, cur, &lim); + } else if ((cnt = have(pstate, cur, "::"))) { + code = scan_scope(pstate, cur, &lim); + } else { + lim = cur + 1; + code = (unsigned char)*cur; + } + } else if ((unsigned)pstate->scanner.state & (unsigned)IDL_SCAN_GRAMMAR) { + /* + * interface definition language + */ + if (chr == '.' && have_digit(pstate, next(pstate, cur))) { + code = scan_floating_pt_literal(pstate, cur, &lim); + } else if (have_digit(pstate, cur)) { + /* idl_stroull takes care of decimal vs. octal vs. hexadecimal */ + code = scan_integer_literal(pstate, cur, &lim); + } else if (have_alpha(pstate, cur) || chr == '_') { + code = scan_identifier(pstate, cur, &lim); + } else if ((cnt = have(pstate, cur, "::")) > 0) { + code = scan_scope(pstate, cur, &lim); + } else if ((cnt = have(pstate, cur, "<<")) > 0) { + lim = cur + cnt; + code = IDL_TOKEN_LSHIFT; + } else if ((cnt = have(pstate, cur, ">>")) > 0) { + lim = cur + cnt; + code = IDL_TOKEN_RSHIFT; + } else if (chr == '@') { + code = scan_at(pstate, cur, &lim); + } else { + lim = cur + 1; + code = (unsigned char)*cur; + } + } else if (chr == '#') { + pstate->scanner.state = IDL_SCAN_DIRECTIVE; + lim = cur + 1; + code = (unsigned char)*cur; + } else if ((pstate->flags & IDL_WRITE) && next(pstate, cur) == pstate->scanner.limit) { + code = IDL_RETCODE_NEED_REFILL; + } else { + pstate->scanner.state = IDL_SCAN_GRAMMAR; + } + } while (code == '\0'); + move(pstate, lim); + lex->limit = lim; + lex->location.last = pstate->scanner.position; + + return code; +} + +static idl_retcode_t +unescape( + idl_pstate_t *pstate, idl_lexeme_t *lex, char *str, size_t *len) +{ + size_t pos=0; + static const char seq[][2] = { + {'n','\n'}, /* newline */ + {'t','\t'}, /* horizontal tab */ + {'v','\v'}, /* vertical tab */ + {'b','\b'}, /* backspace */ + {'r','\r'}, /* carriage return */ + {'f','\f'}, /* form feed */ + {'a','\a'}, /* alert */ + {'\\', '\\'}, /* backslash */ + {'?', '\?'}, /* question mark */ + {'\'', '\''}, /* single quote */ + {'\"', '\"'}, /* double quote */ + {'\0', '\0'} /* terminator */ + }; + + for (size_t i=0; i < *len;) { + if (str[i] == '\\') { + i++; + if (idl_isdigit(str[i], 8) != -1) { + int c = 0; + for (size_t j=0; j < 3 && idl_isdigit(str[i], 8) != -1; j++) + c = (c*8) + idl_isdigit(str[i++], 8); + str[pos++] = (char)c; + } else if (str[i] == 'x' || str[i] == 'X') { + int c = 0; + i++; + if (idl_isdigit(str[i], 16) != -1) { + c = (c*16) + idl_isdigit(str[i++], 16); + if (idl_isdigit(str[i], 16) != -1) + c = (c*16) + idl_isdigit(str[i++], 16); + str[pos++] = (char)c; + } else { + idl_error(pstate, &lex->location, + "\\x used with no following hex digits"); + return IDL_RETCODE_SYNTAX_ERROR; + } + } else { + size_t j; + for (j=0; seq[j][0] && seq[j][0] != str[i]; j++) ; + if (seq[j][0]) { + str[pos++] = seq[j][1]; + } else { + str[pos++] = str[i]; + idl_warning(pstate, &lex->location, + "unknown escape sequence '\\%c'", str[i]); + } + i++; + } + } else if (pos != i) { + str[pos++] = str[i++]; + } else { + pos = ++i; + } + } + + assert(pos <= *len); + str[(*len = pos)] = '\0'; + return IDL_RETCODE_OK; +} + +static idl_retcode_t +tokenize( + idl_pstate_t *pstate, idl_lexeme_t *lex, int32_t code, idl_token_t *tok) +{ + int cnt; + char buf[32], *str = buf; + size_t len = 0, pos = 0; + idl_retcode_t ret; + + /* short-circuit if token is a single character */ + if (code < 256) { + tok->code = code; + tok->location = lex->location; + return code; + } + + len = (size_t)((uintptr_t)lex->limit - (uintptr_t)lex->marker); + if (len >= sizeof(buf) && !(str = malloc(len + 1))) + return IDL_RETCODE_NO_MEMORY; + + /* strip line continuation sequences */ + for (const char *ptr = lex->marker; ptr < lex->limit; ) { + if ((cnt = have_skip(pstate, ptr)) > 0) { + ptr += cnt; + } else { + assert(cnt == 0); + str[pos++] = *ptr++; + } + } + assert(pos <= len); + len = pos; + str[pos] = '\0'; + + switch (code) { + case IDL_TOKEN_ANNOTATION: + assert(strcmp(str, "annotation") == 0); + assert(pstate->scanner.state == IDL_SCAN_ANNOTATION_NAME); + break; + case IDL_TOKEN_IDENTIFIER: + /* preprocessor identifiers are not IDL identifiers */ + if ((unsigned)pstate->scanner.state & (unsigned)IDL_SCAN_DIRECTIVE) + break; + /* annotation names cannot be keywords, i.e. "@default" */ + if (pstate->scanner.state == IDL_SCAN_ANNOTATION_APPL_NAME) + goto identifier; + if (pstate->scanner.state == IDL_SCAN_ANNOTATION_NAME) + goto identifier; + if ((code = idl_iskeyword(pstate, str, 0))) + break; +identifier: + pstate->scanner.state = IDL_SCAN_GRAMMAR; + code = IDL_TOKEN_IDENTIFIER; + break; + case IDL_TOKEN_CHAR_LITERAL: + case IDL_TOKEN_STRING_LITERAL: + assert((str[0] == '\'' || str[0] == '"')); + len -= 1 + (size_t)(str[len - 1] == str[0]); + memmove(str, str + 1, len); + str[len] = '\0'; + if ((ret = unescape(pstate, lex, str, &len)) != IDL_RETCODE_OK) { + if (str != buf) + free(str); + return ret; + } + break; + case IDL_TOKEN_INTEGER_LITERAL: { + char *end = NULL; + tok->value.ullng = idl_strtoull(str, &end, 0); + assert(end && *end == '\0'); + } break; + case IDL_TOKEN_FLOATING_PT_LITERAL: { + char *end = NULL; + tok->value.ldbl = idl_strtold(str, &end); + assert(end && *end == '\0'); + } break; + default: + break; + } + + switch (code) { + case IDL_TOKEN_IDENTIFIER: + case IDL_TOKEN_PP_NUMBER: + case IDL_TOKEN_STRING_LITERAL: + case IDL_TOKEN_COMMENT: + case IDL_TOKEN_LINE_COMMENT: + if (str == buf && !(str = idl_strdup(str))) + return IDL_RETCODE_NO_MEMORY; + tok->value.str = str; + break; + case IDL_TOKEN_CHAR_LITERAL: + if (len != 1) { + idl_error(pstate, &lex->location, "invalid character constant"); + if (str != buf) + free(str); + return IDL_RETCODE_SYNTAX_ERROR; + } + tok->value.chr = *str; + /* fall through */ + default: + if (str != buf) + free(str); + break; + } + + tok->code = code; + tok->location = lex->location; + return code; +} + +idl_retcode_t +idl_scan(idl_pstate_t *pstate, idl_token_t *tok) +{ + idl_retcode_t code; + idl_lexeme_t lex; + + if ((code = scan(pstate, &lex)) < 0) { + return code; + /* tokenize. sanitize by removing line continuation, etc */ + } else if ((code = tokenize(pstate, &lex, code, tok)) < 0) { + /* revert pstate on memory allocation failure */ + pstate->scanner.position = lex.location.first; + return code; + } + + // FIXME: verify state is correct, i.e. reset if it does not match token + + return code; +} diff --git a/src/idl/src/scanner.h b/src/idl/src/scanner.h new file mode 100644 index 0000000000..6519028b57 --- /dev/null +++ b/src/idl/src/scanner.h @@ -0,0 +1,38 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef SCANNER_H +#define SCANNER_H + +#include "idl/processor.h" + +typedef struct idl_lexeme idl_lexeme_t; +struct idl_lexeme { + const char *marker; + const char *limit; + idl_location_t location; +}; + +typedef struct idl_token idl_token_t; +struct idl_token { + int32_t code; /**< token identifier */ + union { + char chr; + unsigned long long ullng; + long double ldbl; + char *str; + } value; + idl_location_t location; +}; + +IDL_EXPORT idl_retcode_t idl_scan(idl_pstate_t *pstate, idl_token_t *tok); + +#endif /* SCANNER_H */ diff --git a/src/idl/src/scope.c b/src/idl/src/scope.c new file mode 100644 index 0000000000..b4baa0f618 --- /dev/null +++ b/src/idl/src/scope.c @@ -0,0 +1,534 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "idl/retcode.h" +#include "idl/string.h" +#include "symbol.h" +#include "scope.h" + +static idl_retcode_t +create_declaration( + idl_pstate_t *pstate, + enum idl_declaration_kind kind, + const idl_name_t *name, + idl_declaration_t **declarationp) +{ + char *identifier; + idl_declaration_t *declaration; + + if (!(declaration = calloc(1, sizeof(*declaration)))) + goto err_declaration; + declaration->kind = kind; + if (!(identifier = idl_strdup(name->identifier))) + goto err_identifier; + if (idl_create_name(pstate, idl_location(name), identifier, &declaration->name)) + goto err_name; + *declarationp = declaration; + return IDL_RETCODE_OK; +err_name: + free(identifier); +err_identifier: + free(declaration); +err_declaration: + return IDL_RETCODE_NO_MEMORY; +} + +static void delete_declaration(idl_declaration_t *declaration) +{ + if (declaration) { + if (declaration->name) + idl_delete_name(declaration->name); + if (declaration->scoped_name) { + if (declaration->scoped_name->identifier) + free(declaration->scoped_name->identifier); + if (declaration->scoped_name->names) + free(declaration->scoped_name->names); + free(declaration->scoped_name); + } + free(declaration); + } +} + +idl_retcode_t +idl_create_scope( + idl_pstate_t *pstate, + enum idl_scope_kind kind, + const idl_name_t *name, + const void *node, + idl_scope_t **scopep) +{ + idl_scope_t *scope; + idl_declaration_t *entry; + + assert(name); + assert(node || kind == IDL_GLOBAL_SCOPE); + + if (create_declaration(pstate, IDL_SCOPE_DECLARATION, name, &entry)) + goto err_declaration; + entry->node = node; + if (!(scope = malloc(sizeof(*scope)))) + goto err_scope; + scope->parent = pstate->scope; + scope->kind = kind; + scope->name = (const idl_name_t *)entry->name; + scope->declarations.first = scope->declarations.last = entry; + scope->imports.first = scope->imports.last = NULL; + *scopep = scope; + return IDL_RETCODE_OK; +err_scope: + delete_declaration(entry); +err_declaration: + return IDL_RETCODE_NO_MEMORY; +} + +/* free scopes, not nodes */ +void idl_delete_scope(idl_scope_t *scope) +{ + if (scope) { + for (idl_declaration_t *q, *p = scope->declarations.first; p; p = q) { + q = p->next; + if (p->scope && p->kind != IDL_INSTANCE_DECLARATION) + idl_delete_scope(p->scope); + delete_declaration(p); + } + for (idl_import_t *q, *p = scope->imports.first; p; p = q) { + q = p->next; + free(p); + } + free(scope); + } +} + +idl_retcode_t +idl_import( + idl_pstate_t *pstate, + idl_scope_t *scope, + const idl_scope_t *imported_scope) +{ + idl_import_t *entry; + + (void)pstate; + /* ensure scopes are not imported twice */ + for (entry=scope->imports.first; entry; entry=entry->next) { + if (entry->scope == imported_scope) + return IDL_RETCODE_OK; + } + + if (!(entry = malloc(sizeof(*entry)))) + return IDL_RETCODE_NO_MEMORY; + entry->next = NULL; + entry->scope = imported_scope; + if (scope->imports.first) { + assert(scope->imports.last); + scope->imports.last->next = entry; + scope->imports.last = entry; + } else { + scope->imports.first = scope->imports.last = entry; + } + + return IDL_RETCODE_OK; +} + +static bool +is_consistent( + const idl_pstate_t *pstate, const void *lhs, const void *rhs) +{ + if (pstate->parser.state != IDL_PARSE_EXISTING_ANNOTATION_BODY) + return false; + assert(pstate->scope->kind == IDL_ANNOTATION_SCOPE); + return idl_mask(lhs) == idl_mask(rhs); +} + +idl_retcode_t +idl_declare( + idl_pstate_t *pstate, + enum idl_declaration_kind kind, + const idl_name_t *name, + void *node, + idl_scope_t *scope, + idl_declaration_t **declarationp) +{ + idl_declaration_t *entry = NULL; + int (*cmp)(const char *, const char *); + + assert(pstate && pstate->scope); + cmp = (pstate->flags & IDL_FLAG_CASE_SENSITIVE) ? &strcmp : &idl_strcasecmp; + + /* ensure there is no collision with an earlier declaration */ + for (entry = pstate->scope->declarations.first; entry; entry = entry->next) { + /* identifiers that differ only in case collide, and will yield a + compilation error under certain circumstances */ + if (cmp(name->identifier, entry->name->identifier) == 0) { + switch (entry->kind) { + case IDL_SCOPE_DECLARATION: + /* declaration of the enclosing scope, but if the enclosing scope + is an annotation, an '@' (commercial at) was prepended in its + declaration */ + if (pstate->scope->kind != IDL_ANNOTATION_SCOPE) + goto clash; + break; + case IDL_ANNOTATION_DECLARATION: + /* same here, declaration was actually prepended with '@' */ + if (kind == IDL_ANNOTATION_DECLARATION) + goto clash; + break; + case IDL_MODULE_DECLARATION: + /* modules can be reopened. a module is considered to be defined by + its first occurrence in a scope */ + if (kind == IDL_MODULE_DECLARATION) + goto exists; + goto clash; + case IDL_USE_DECLARATION: + if (kind == IDL_INSTANCE_DECLARATION) + goto exists; + /* fall through */ + case IDL_SPECIFIER_DECLARATION: + if (kind == IDL_USE_DECLARATION) + goto exists; + /* short-circuit on parsing existing annotations */ + if (is_consistent(pstate, node, entry->node)) + goto exists; + /* fall through */ + default: +clash: + idl_error(pstate, idl_location(node), + "Declaration '%s%s' collides with earlier an declaration of '%s%s'", + kind == IDL_ANNOTATION ? "@" : "", name->identifier, + kind == IDL_ANNOTATION ? "@" : "", entry->name->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + } + } + + if (pstate->parser.state == IDL_PARSE_EXISTING_ANNOTATION_BODY) { + assert(pstate->scope->kind == IDL_ANNOTATION_SCOPE); + idl_error(pstate, idl_location(node), + "Declaration of unknown identifier '%s' in redefinition of '@%s'", + name->identifier, pstate->scope->name->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if (create_declaration(pstate, kind, name, &entry)) + return IDL_RETCODE_NO_MEMORY; + entry->local_scope = pstate->scope; + entry->node = node; + entry->scope = scope; + + if (pstate->scope->declarations.first) { + assert(pstate->scope->declarations.last); + pstate->scope->declarations.last->next = entry; + pstate->scope->declarations.last = entry; + } else { + assert(!pstate->scope->declarations.last); + pstate->scope->declarations.last = entry; + pstate->scope->declarations.first = entry; + } + + switch (kind) { + case IDL_MODULE_DECLARATION: + case IDL_ANNOTATION_DECLARATION: + case IDL_SPECIFIER_DECLARATION: { + size_t cnt = 0, len, off = 0; + const char *sep = "::"; + idl_scoped_name_t *scoped_name = NULL; + + cnt++; + len = strlen(sep) + strlen(name->identifier); + for (const idl_scope_t *s = pstate->scope; s != pstate->global_scope; s = s->parent) { + cnt++; + len += strlen(sep) + strlen(s->name->identifier); + } + + if (!(scoped_name = calloc(1, sizeof(*scoped_name))) || + !(scoped_name->names = calloc(cnt, sizeof(*scoped_name->names))) || + !(scoped_name->identifier = malloc(len + 1))) + { + if (scoped_name && scoped_name->names) + free(scoped_name->names); + if (scoped_name) + free(scoped_name); + return IDL_RETCODE_NO_MEMORY; + } + + /* construct name vector */ + scoped_name->symbol = name->symbol; + scoped_name->absolute = true; + scoped_name->length = cnt; + scoped_name->names[--cnt] = (idl_name_t *)name; + for (const idl_scope_t *s = pstate->scope; s != pstate->global_scope; s = s->parent) { + assert(cnt); + scoped_name->names[--cnt] = (idl_name_t *)s->name; + } + assert(!cnt); + /* construct fully qualified scoped name */ + for (size_t i=0; i < scoped_name->length; i++) { + cnt = strlen(sep); + assert(len - cnt >= off); + memcpy(scoped_name->identifier+off, sep, cnt); + off += cnt; + cnt = strlen(scoped_name->names[i]->identifier); + assert(len - cnt >= off); + memcpy(scoped_name->identifier+off, scoped_name->names[i]->identifier, cnt); + off += cnt; + } + assert(off == len); + scoped_name->identifier[off] = '\0'; + entry->scoped_name = scoped_name; + } /* fall through */ + case IDL_INSTANCE_DECLARATION: + ((idl_node_t *)node)->declaration = entry; + /* fall through */ + default: + break; + } + +exists: + if (declarationp) + *declarationp = entry; + return IDL_RETCODE_OK; +} + +static int namecmp(const idl_name_t *n1, const idl_name_t *n2) +{ + return strcmp(n1->identifier, n2->identifier); +} + +static int namecasecmp(const idl_name_t *n1, const idl_name_t *n2) +{ + return idl_strcasecmp(n1->identifier, n2->identifier); +} + +const idl_declaration_t * +idl_find( + const idl_pstate_t *pstate, + const idl_scope_t *scope, + const idl_name_t *name, + uint32_t flags) +{ + const idl_declaration_t *entry; + int (*cmp)(const idl_name_t *, const idl_name_t *); + + if (!scope) + scope = pstate->scope; + assert(name); + assert(name->identifier); + /* identifiers are case insensitive. however, all references to a definition + must use the same case as the defining occurence to allow natural + mappings to case-sensitive languages */ + cmp = (flags & IDL_FIND_IGNORE_CASE) ? &namecasecmp : &namecmp; + + for (entry = scope->declarations.first; entry; entry = entry->next) { + if (entry->kind == IDL_ANNOTATION_DECLARATION && !(flags & IDL_FIND_ANNOTATION)) + continue; + if (cmp(name, entry->name) == 0) + return entry; + } + + if (!(flags & IDL_FIND_IGNORE_IMPORTS)) { + idl_import_t *import; + for (import = scope->imports.first; import; import = import->next) { + if ((entry = idl_find(pstate, import->scope, name, flags))) + return entry; + } + } + + return NULL; +} + +const idl_declaration_t * +idl_find_scoped_name( + const idl_pstate_t *pstate, + const idl_scope_t *scope, + const idl_scoped_name_t *scoped_name, + uint32_t flags) +{ + const idl_declaration_t *entry = NULL; + int (*cmp)(const idl_name_t *, const idl_name_t *); + + if (scoped_name->absolute) + scope = pstate->global_scope; + else if (!scope) + scope = pstate->scope; + cmp = (flags & IDL_FIND_IGNORE_CASE) ? &namecasecmp : &namecmp; + + for (size_t i=0; i < scoped_name->length && scope;) { + const idl_name_t *name = scoped_name->names[i]; + entry = idl_find(pstate, scope, name, (flags|IDL_FIND_IGNORE_CASE)); + if (entry && entry->kind != IDL_USE_DECLARATION) { + if (cmp(name, entry->name) != 0) + return NULL; + scope = entry->kind == IDL_SCOPE_DECLARATION ? scope : entry->scope; + i++; + } else if (scoped_name->absolute || i != 0) { + return NULL; + } else { + /* a name can be used in an unqualified form within a particular scope; + it will be resolved by successively searching farther out in + enclosing scopes, while taking into consideration inheritance + relationships amount interfaces */ + /* assume inheritance applies to extended structs in the same way */ + scope = (idl_scope_t*)scope->parent; + } + } + + return entry; +} + +const idl_declaration_t * +idl_find_field_name( + const idl_pstate_t *pstate, + const idl_scope_t *scope, + const idl_field_name_t *field_name, + uint32_t flags) +{ + const idl_declaration_t *entry; + const void *root; + + assert(pstate); + assert(scope); + assert(field_name); + + /* take declaration that introduced scope */ + entry = scope->declarations.first; + root = entry->node; + if (!idl_is_struct(root) && !idl_is_union(root)) + return NULL; + if (!field_name->length) + return NULL; + + for (size_t i=0; i < field_name->length; i++) { + if (!scope) + return NULL; + if (!(entry = idl_find(pstate, scope, field_name->names[i], flags))) + return NULL; + if (entry->kind != IDL_INSTANCE_DECLARATION) + return NULL; + scope = entry->scope; + } + + return entry; +} + +idl_retcode_t +idl_resolve( + idl_pstate_t *pstate, + enum idl_declaration_kind kind, + const idl_scoped_name_t *scoped_name, + const idl_declaration_t **declarationp) +{ + idl_retcode_t ret = IDL_RETCODE_NO_MEMORY; + const idl_declaration_t *entry = NULL; + idl_scope_t *scope; + idl_node_t *node = NULL; + uint32_t flags = 0u, ignore_case = IDL_FIND_IGNORE_CASE; + + if (kind == IDL_ANNOTATION_DECLARATION) + flags |= IDL_FIND_ANNOTATION; + if (pstate->flags & IDL_FLAG_CASE_SENSITIVE) + ignore_case = 0u; + + scope = (scoped_name->absolute) ? pstate->global_scope : pstate->scope; + assert(scope); + + for (size_t i=0; i < scoped_name->length && scope;) { + const idl_name_t *name = scoped_name->names[i]; + entry = idl_find(pstate, scope, name, flags|ignore_case); + if (entry && entry->kind != IDL_USE_DECLARATION) { + /* identifiers are case insensitive. however, all references to a + definition must use the same case as the defining occurence */ + if (ignore_case && namecmp(name, entry->name) != 0) { + idl_error(pstate, idl_location(name), + "Scoped name matched up to '%s', but identifier differs in case from '%s'", + name->identifier, entry->name->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + if (i == 0) + node = (idl_node_t*)entry->node; + scope = entry->kind == IDL_SCOPE_DECLARATION ? scope : entry->scope; + i++; + } else if (scoped_name->absolute || i != 0) { + // take parser state into account here!!!! + idl_error(pstate, idl_location(scoped_name), + "Scoped name '%s' cannot be resolved", scoped_name->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } else { + /* a name can be used in an unqualified form within a particular scope; + it will be resolved by successively searching farther out in + enclosing scopes, while taking into consideration inheritance + relationships amount interfaces */ + /* assume inheritance applies to extended structs in the same way */ + scope = (idl_scope_t*)scope->parent; + } + } + + if (!entry) { + if (kind != IDL_ANNOTATION_DECLARATION) + idl_error(pstate, idl_location(scoped_name), + "Scoped name '%s' cannot be resolved", scoped_name->identifier); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if (!scoped_name->absolute && scope && scope != pstate->scope) { + /* non-absolute qualified names introduce the identifier of the outermost + scope of the scoped name into the current scope */ + if (kind != IDL_ANNOTATION_DECLARATION) { + /* annotation_appl elements do not introduce a use declaration */ + const idl_name_t *name = scoped_name->names[0]; + if ((ret = idl_declare(pstate, IDL_USE_DECLARATION, name, node, NULL, NULL))) + return ret; + } + } + + *declarationp = entry; + return IDL_RETCODE_OK; +} + +void +idl_enter_scope( + idl_pstate_t *pstate, + idl_scope_t *scope) +{ + pstate->scope = scope; +} + +void +idl_exit_scope( + idl_pstate_t *pstate) +{ + assert(pstate->scope); + assert(pstate->scope != pstate->global_scope); + pstate->scope = (idl_scope_t*)pstate->scope->parent; +} + +idl_scope_t *idl_scope(const void *node) +{ + const idl_declaration_t *declaration = idl_declaration(node); + if (declaration) + return (idl_scope_t *)declaration->local_scope; + + return NULL; +} + +idl_declaration_t *idl_declaration(const void *node) +{ + if (idl_is_declaration(node)) { + assert(((const idl_node_t *)node)->declaration); + return (idl_declaration_t *)((const idl_node_t *)node)->declaration; + } else { + assert(!((const idl_node_t *)node)->declaration); + return NULL; + } +} diff --git a/src/idl/src/scope.h b/src/idl/src/scope.h new file mode 100644 index 0000000000..c435114a6a --- /dev/null +++ b/src/idl/src/scope.h @@ -0,0 +1,54 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef SCOPE_H +#define SCOPE_H + +#include + +#include "idl/processor.h" + +idl_retcode_t +idl_create_scope( + idl_pstate_t *pstate, + enum idl_scope_kind kind, + const idl_name_t *name, + const void *node, + idl_scope_t **scopep); + +void idl_delete_scope(idl_scope_t *scope); + +void idl_enter_scope(idl_pstate_t *pstate, idl_scope_t *scope); +void idl_exit_scope(idl_pstate_t *pstate); + +idl_retcode_t +idl_import( + idl_pstate_t *pstate, + idl_scope_t *scope, + const idl_scope_t *imported_scope); + +idl_retcode_t +idl_declare( + idl_pstate_t *pstate, + enum idl_declaration_kind kind, + const idl_name_t *name, + void *node, + idl_scope_t *scope, + idl_declaration_t **declarationp); + +idl_retcode_t +idl_resolve( + idl_pstate_t *pstate, + enum idl_declaration_kind kind, + const idl_scoped_name_t *scoped_name, + const idl_declaration_t **declarationp); + +#endif /* SCOPE_H */ diff --git a/src/idl/src/string.c b/src/idl/src/string.c new file mode 100644 index 0000000000..63ee14c695 --- /dev/null +++ b/src/idl/src/string.c @@ -0,0 +1,355 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +/* + * Locale-independent C runtime functions, like strtoull_l and strtold_l, are + * available on modern operating systems albeit with some quirks. + * + * Linux exports newlocale and freelocale from locale.h if _GNU_SOURCE is + * defined. strtoull_l and strtold_l are exported from stdlib.h, again if + * _GNU_SOURCE is defined. + * + * FreeBSD and macOS export newlocale and freelocale from xlocale.h and + * export strtoull_l and strtold_l from xlocale.h if stdlib.h is included + * before. + * + * Windows exports _create_locale and _free_locale from locale.h and exports + * _strtoull_l and _strtold_l from stdlib.h. + */ +#if _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#if defined _MSC_VER +# include +typedef _locale_t locale_t; +#else +# include +# include +# if __APPLE__ || __FreeBSD__ +# include +# else +# include +# endif +#endif + +#include "idl/stream.h" +#include "idl/string.h" + +static locale_t posix_locale(void); + +#if _WIN32 +int idl_isalnum(int c) { return _isalnum_l(c, posix_locale()); } +int idl_isalpha(int c) { return _isalpha_l(c, posix_locale()); } +int idl_isblank(int c) { return _isblank_l(c, posix_locale()); } +int idl_iscntrl(int c) { return _iscntrl_l(c, posix_locale()); } +int idl_isgraph(int c) { return _isgraph_l(c, posix_locale()); } +int idl_islower(int c) { return _islower_l(c, posix_locale()); } +int idl_isprint(int c) { return _isprint_l(c, posix_locale()); } +int idl_ispunct(int c) { return _ispunct_l(c, posix_locale()); } +int idl_isspace(int c) { return _isspace_l(c, posix_locale()); } +int idl_isupper(int c) { return _isupper_l(c, posix_locale()); } +int idl_toupper(int c) { return _toupper_l(c, posix_locale()); } +int idl_tolower(int c) { return _tolower_l(c, posix_locale()); } +#else +int idl_isalnum(int c) { return isalnum_l(c, posix_locale()); } +int idl_isalpha(int c) { return isalpha_l(c, posix_locale()); } +int idl_isblank(int c) { return isblank_l(c, posix_locale()); } +int idl_iscntrl(int c) { return iscntrl_l(c, posix_locale()); } +int idl_isgraph(int c) { return isgraph_l(c, posix_locale()); } +int idl_islower(int c) { return islower_l(c, posix_locale()); } +int idl_isprint(int c) { return isprint_l(c, posix_locale()); } +int idl_ispunct(int c) { return ispunct_l(c, posix_locale()); } +int idl_isspace(int c) { return isspace_l(c, posix_locale()); } +int idl_isupper(int c) { return isupper_l(c, posix_locale()); } +int idl_toupper(int c) { return toupper_l(c, posix_locale()); } +int idl_tolower(int c) { return tolower_l(c, posix_locale()); } +#endif + +int idl_isdigit(int chr, int base) +{ + int num = -1; + assert(base > 0 && base < 36); + if (chr >= '0' && chr <= '9') + num = chr - '0'; + else if (chr >= 'a' && chr <= 'z') + num = chr - 'a'; + else if (chr >= 'A' && chr <= 'Z') + num = chr - 'A'; + return num != -1 && num < base ? num : -1; +} + +int idl_strcasecmp(const char *s1, const char *s2) +{ + assert(s1); + assert(s2); +#if _WIN32 + return _stricmp_l(s1, s2, posix_locale()); +#else + return strcasecmp_l(s1, s2, posix_locale()); +#endif +} + +int idl_strncasecmp(const char *s1, const char *s2, size_t n) +{ + assert(s1); + assert(s2); +#if _WIN32 + return _strnicmp_l(s1, s2, n, posix_locale()); +#else + return strncasecmp_l(s1, s2, n, posix_locale()); +#endif +} + +char *idl_strdup(const char *str) +{ +#if _WIN32 + return _strdup(str); +#else + return strdup(str); +#endif +} + +char *idl_strndup(const char *str, size_t len) +{ + char *s; + size_t n; + for (n=0; n < len && str[n]; n++) ; + assert(n <= len); + if (!(s = malloc(n + 1))) + return NULL; + memmove(s, str, n); + s[n] = '\0'; + return s; +} + +int idl_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) +{ +#if _WIN32 +__pragma(warning(push)) +__pragma(warning(disable: 4996)) + int ret; + va_list ap2; + /* _vsprintf_p_l supports positional parameters */ + va_copy(ap2, ap); + if ((ret = _vsprintf_p_l(str, size, fmt, posix_locale(), ap)) < 0) + ret = _vscprintf_p_l(fmt, posix_locale(), ap2); + va_end(ap2); + return ret; +__pragma(warning(pop)) +#elif __APPLE__ || __FreeBSD__ + return vsnprintf_l(str, size, posix_locale(), fmt, ap); +#else + int ret; + locale_t loc, posixloc = posix_locale(); + loc = uselocale(posixloc); + ret = vsnprintf(str, size, fmt, ap); + loc = uselocale(loc); + assert(loc == posixloc); + return ret; +#endif +} + +int idl_snprintf(char *str, size_t size, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = idl_vsnprintf(str, size, fmt, ap); + va_end(ap); + return ret; +} + +int idl_asprintf(char **strp, const char *fmt, ...) +{ + int ret; + unsigned int len; + char buf[1] = { '\0' }; + char *str = NULL; + va_list ap1, ap2; + + assert(strp != NULL); + assert(fmt != NULL); + + va_start(ap1, fmt); + va_copy(ap2, ap1); /* va_list cannot be reused */ + + if ((ret = idl_vsnprintf(buf, sizeof(buf), fmt, ap1)) >= 0) { + len = (unsigned int)ret; /* +1 for null byte */ + if ((str = malloc(len + 1)) == NULL) { + ret = -1; + } else if ((ret = idl_vsnprintf(str, len + 1, fmt, ap2)) >= 0) { + assert(((unsigned int)ret) == len); + *strp = str; + } else { + free(str); + } + } + + va_end(ap1); + va_end(ap2); + + return ret; +} + +int idl_vasprintf(char **strp, const char *fmt, va_list ap) +{ + int ret; + unsigned int len; + char buf[1] = { '\0' }; + char *str = NULL; + va_list ap2; + + assert(strp != NULL); + assert(fmt != NULL); + + va_copy(ap2, ap); /* va_list cannot be reused */ + + if ((ret = idl_vsnprintf(buf, sizeof(buf), fmt, ap)) >= 0) { + len = (unsigned int)ret; + if ((str = malloc(len + 1)) == NULL) { + ret = -1; + } else if ((ret = idl_vsnprintf(str, len + 1, fmt, ap2)) >= 0) { + assert(((unsigned int)ret) == len); + *strp = str; + } else { + free(str); + } + } + + va_end(ap2); + + return ret; +} + +unsigned long long idl_strtoull(const char *str, char **endptr, int base) +{ + assert(str); + assert(base >= 0 && base <= 36); +#if _WIN32 + return _strtoull_l(str, endptr, base, posix_locale()); +#else + return strtoull_l(str, endptr, base, posix_locale()); +#endif +} + +long double idl_strtold(const char *str, char **endptr) +{ + assert(str); +#if _WIN32 + return _strtold_l(str, endptr, posix_locale()); +#else + return strtold_l(str, endptr, posix_locale()); +#endif +} + +char *idl_strtok_r(char *str, const char *delim, char **saveptr) +{ +#if _WIN32 + return strtok_s(str, delim, saveptr); +#else + return strtok_r(str, delim, saveptr); +#endif +} + +/* requires posix_locale */ +int idl_vfprintf(FILE *fp, const char *fmt, va_list ap) +{ + assert(fp); + assert(fmt); + +#if _WIN32 + /* _vfprintf_p_l supports positional parameters */ + return _vfprintf_p_l(fp, fmt, posix_locale(), ap); +#elif __APPLE__ || __FreeBSD__ + return vfprintf_l(fp, posix_locale(), fmt, ap); +#else + int ret; + locale_t loc, posixloc = posix_locale(); + loc = uselocale(posixloc); + ret = vfprintf(fp, fmt, ap); + loc = uselocale(loc); + assert(loc == posixloc); + return ret; +#endif +} + +int idl_fprintf(FILE *fp, const char *fmt, ...) +{ + int ret; + va_list ap; + + assert(fp); + assert(fmt); + + va_start(ap, fmt); + ret = idl_vfprintf(fp, fmt, ap); + va_end(ap); + + return ret; +} + +#if defined _WIN32 +static __declspec(thread) locale_t locale = NULL; + +void idl_create_locale(void) +{ + locale = _create_locale(LC_ALL, "C"); +} + +void idl_delete_locale(void) +{ + _free_locale(locale); + locale = NULL; +} + +static locale_t posix_locale(void) +{ + return locale; +} +#else /* _WIN32 */ +static pthread_key_t key; +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static void free_locale(void *ptr) +{ + freelocale((locale_t)ptr); +} + +static void make_key(void) +{ + (void)pthread_key_create(&key, free_locale); +} + +static locale_t posix_locale(void) +{ + locale_t locale; + (void)pthread_once(&once, make_key); + if ((locale = pthread_getspecific(key))) + return locale; +#if __APPLE__ || __FreeBSD__ + locale = newlocale(LC_ALL_MASK, NULL, NULL); +#else + locale = newlocale(LC_ALL, "C", (locale_t)0); +#endif + pthread_setspecific(key, locale); + return locale; +} +#endif /* _WIN32 */ diff --git a/src/idl/src/symbol.c b/src/idl/src/symbol.c new file mode 100644 index 0000000000..e342997b39 --- /dev/null +++ b/src/idl/src/symbol.c @@ -0,0 +1,233 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "idl/processor.h" +#include "symbol.h" + +const idl_location_t *idl_location(const void *symbol) +{ + return &((const idl_symbol_t *)symbol)->location; +} + +void idl_delete_name(idl_name_t *name) +{ + if (name) { + if (name->identifier) + free(name->identifier); + free(name); + } +} + +idl_retcode_t +idl_create_name( + idl_pstate_t *pstate, + const idl_location_t *location, + char *identifier, + idl_name_t **namep) +{ + idl_name_t *name; + + (void)pstate; + if (!(name = malloc(sizeof(*name)))) + return IDL_RETCODE_NO_MEMORY; + name->symbol.location = *location; + name->identifier = identifier; + *namep = name; + return IDL_RETCODE_OK; +} + +void idl_delete_scoped_name(idl_scoped_name_t *scoped_name) +{ + if (scoped_name) { + free(scoped_name->identifier); + for (size_t i=0; i < scoped_name->length; i++) + idl_delete_name(scoped_name->names[i]); + free(scoped_name->names); + free(scoped_name); + } +} + +idl_retcode_t +idl_create_scoped_name( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + bool absolute, + idl_scoped_name_t **scoped_namep) +{ + idl_scoped_name_t *scoped_name; + char *str; + size_t len, off; + const char *root = absolute ? "::" : ""; + + (void)pstate; + assert(name); + assert(name->identifier); + if (!(scoped_name = calloc(1, sizeof(*scoped_name)))) + goto err_alloc; + if (!(scoped_name->names = calloc(1, sizeof(idl_name_t *)))) + goto err_alloc; + off = strlen(root); + len = strlen(name->identifier); + if (!(str = malloc(off + len + 1))) + goto err_alloc; + memcpy(str, root, off); + memcpy(str+off, name->identifier, len); + str[off + len] = '\0'; + scoped_name->symbol.location.first = location->first; + scoped_name->symbol.location.last = name->symbol.location.last; + scoped_name->absolute = absolute; + scoped_name->length = 1; + scoped_name->names[0] = name; + scoped_name->identifier = str; + *scoped_namep = scoped_name; + return IDL_RETCODE_OK; +err_alloc: + if (scoped_name && scoped_name->names) + free(scoped_name->names); + if (scoped_name) + free(scoped_name); + return IDL_RETCODE_NO_MEMORY; +} + +idl_retcode_t +idl_push_scoped_name( + idl_pstate_t *pstate, + idl_scoped_name_t *scoped_name, + idl_name_t *name) +{ + char *str; + size_t len, off; + size_t size; + static const char *sep = "::"; + idl_name_t **names; + + (void)pstate; + assert(scoped_name); + assert(scoped_name->length >= 1); + assert(name); + + len = strlen(name->identifier); + off = strlen(scoped_name->identifier); + if (!(str = malloc(off + strlen(sep) + len + 1))) + goto err_alloc; + memcpy(str, scoped_name->identifier, off); + memcpy(str+off, sep, strlen(sep)); + off += strlen(sep); + memcpy(str+off, name->identifier, len); + str[off + len] = '\0'; + size = (scoped_name->length + 1) * sizeof(idl_name_t*); + if (!(names = realloc(scoped_name->names, size))) + goto err_alloc; + scoped_name->symbol.location.last = name->symbol.location.last; + scoped_name->names = names; + scoped_name->names[scoped_name->length++] = name; + free(scoped_name->identifier); + scoped_name->identifier = str; + return IDL_RETCODE_OK; +err_alloc: + if (str) free(str); + return IDL_RETCODE_NO_MEMORY; +} + +void idl_delete_field_name(idl_field_name_t *field_name) +{ + if (field_name) { + if (field_name->identifier) + free(field_name->identifier); + for (size_t i=0; i < field_name->length; i++) + idl_delete_name(field_name->names[i]); + free(field_name->names); + free(field_name); + } +} + +idl_retcode_t +idl_create_field_name( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_field_name_t **field_namep) +{ + char *str; + size_t len; + idl_field_name_t *field_name; + + (void)pstate; + assert(name); + assert(name->identifier); + if (!(field_name = calloc(1, sizeof(*field_name)))) + goto err_alloc; + if (!(field_name->names = calloc(1, sizeof(idl_name_t*)))) + goto err_alloc; + len = strlen(name->identifier); + if (!(str = malloc(len + 1))) + goto err_alloc; + memcpy(str, name->identifier, len); + str[len] = '\0'; + field_name->symbol.location = *location; + field_name->symbol.location.last = name->symbol.location.last; + field_name->length = 1; + field_name->names[0] = name; + field_name->identifier = str; + *field_namep = field_name; + return IDL_RETCODE_OK; +err_alloc: + if (field_name && field_name->names) + free(field_name->names); + if (field_name) + free(field_name); + return IDL_RETCODE_NO_MEMORY; +} + +idl_retcode_t +idl_push_field_name( + idl_pstate_t *pstate, + idl_field_name_t *field_name, + idl_name_t *name) +{ + char *str; + size_t len, off; + size_t size; + const char *sep = "."; + idl_name_t **names; + + (void)pstate; + assert(field_name); + assert(field_name->length >= 1); + assert(name); + + off = strlen(field_name->identifier); + len = strlen(name->identifier); + if (!(str = malloc(off + strlen(sep) + len + 1))) + goto err_alloc; + memcpy(str, field_name->identifier, off); + memcpy(str+off, sep, strlen(sep)); + off += strlen(sep); + memcpy(str+off, name->identifier, len); + str[off + len] = '\0'; + size = (field_name->length + 1) * sizeof(idl_name_t*); + if (!(names = realloc(field_name->names, size))) + goto err_alloc; + field_name->symbol.location.last = name->symbol.location.last; + field_name->names = names; + field_name->names[field_name->length++] = name; + free(field_name->identifier); + field_name->identifier = str; + return IDL_RETCODE_OK; +err_alloc: + if (str) free(str); + return IDL_RETCODE_NO_MEMORY; +} diff --git a/src/idl/src/symbol.h b/src/idl/src/symbol.h new file mode 100644 index 0000000000..84c9674e52 --- /dev/null +++ b/src/idl/src/symbol.h @@ -0,0 +1,57 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef SYMBOL_H +#define SYMBOL_H + +#include "idl/processor.h" + +idl_retcode_t +idl_create_name( + idl_pstate_t *state, + const idl_location_t *location, + char *identifier, + idl_name_t **namep); + +void idl_delete_name(idl_name_t *name); + +idl_retcode_t +idl_create_scoped_name( + idl_pstate_t *state, + const idl_location_t *location, + idl_name_t *name, + bool absolute, + idl_scoped_name_t **scoped_namep); + +idl_retcode_t +idl_push_scoped_name( + idl_pstate_t *pstate, + idl_scoped_name_t *scoped_name, + idl_name_t *name); + +void idl_delete_scoped_name(idl_scoped_name_t *scoped_name); + +idl_retcode_t +idl_create_field_name( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_field_name_t **field_namep); + +idl_retcode_t +idl_push_field_name( + idl_pstate_t *pstate, + idl_field_name_t *field_name, + idl_name_t *name); + +void idl_delete_field_name(idl_field_name_t *field_name); + +#endif /* SYMBOL_H */ diff --git a/src/idl/src/thread.c b/src/idl/src/thread.c new file mode 100644 index 0000000000..b16bc63003 --- /dev/null +++ b/src/idl/src/thread.c @@ -0,0 +1,50 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#if defined _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +extern void idl_create_locale(void); +extern void idl_delete_locale(void); + +void WINAPI idl_cdtor(PVOID handle, DWORD reason, PVOID reserved) +{ + switch (reason) { + case DLL_PROCESS_ATTACH: + /* fall through */ + case DLL_THREAD_ATTACH: + idl_create_locale(); + break; + case DLL_THREAD_DETACH: + /* fall through */ + case DLL_PROCESS_DETACH: + idl_delete_locale(); + break; + default: + break; + } +} + +#if defined _WIN64 + #pragma comment (linker, "/INCLUDE:_tls_used") + #pragma comment (linker, "/INCLUDE:tls_callback_func") + #pragma const_seg(".CRT$XLZ") + EXTERN_C const PIMAGE_TLS_CALLBACK tls_callback_func = idl_cdtor; + #pragma const_seg() +#else + #pragma comment (linker, "/INCLUDE:__tls_used") + #pragma comment (linker, "/INCLUDE:_tls_callback_func") + #pragma data_seg(".CRT$XLZ") + EXTERN_C PIMAGE_TLS_CALLBACK tls_callback_func = idl_cdtor; + #pragma data_seg() +#endif /* _WIN64 */ +#endif /* _WIN32 */ diff --git a/src/idl/src/tree.c b/src/idl/src/tree.c new file mode 100644 index 0000000000..7662373730 --- /dev/null +++ b/src/idl/src/tree.c @@ -0,0 +1,2686 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "idl/string.h" + +#include "expression.h" +#include "file.h" /* for ssize_t on Windows */ +#include "tree.h" +#include "scope.h" +#include "symbol.h" + +void *idl_push_node(void *list, void *node) +{ + idl_node_t *last; + + if (!node) + return list; + if (!list) + return node; + + for (last = list; last != node && last->next; last = last->next) ; + assert(last != node); + + last->next = node; + ((idl_node_t *)node)->previous = last; + return list; +} + +void *idl_reference_node(void *node) +{ + if (node) + ((idl_node_t *)node)->references++; + return node; +} + +void *idl_unreference_node(void *ptr) +{ + idl_node_t *node = ptr; + if (!node) + return NULL; + node->references--; + assert(node->references >= 0); + if (node->references == 0) { + idl_node_t *previous, *next; + previous = node->previous; + next = node->next; + if (previous) + previous->next = next; + if (next) + next->previous = previous; + idl_delete_node((idl_node_t *)node->annotations); + if (node->destructor) + node->destructor(node); + return next; + } + return node; +} + +idl_mask_t idl_mask(const void *node) +{ + return node ? ((idl_node_t *)node)->mask : 0u; +} + +idl_type_t idl_type(const void *node) +{ + idl_mask_t mask; + + /* typedef nodes are referenced by their declarator(s) */ + if (idl_mask(node) & IDL_DECLARATOR) + node = idl_parent(node); + else if (idl_mask(node) & IDL_ENUMERATOR) + node = idl_parent(node); + + mask = idl_mask(node) & ((IDL_TYPEDEF << 1) - 1); + switch (mask) { + case IDL_TYPEDEF: + /* constructed types */ + case IDL_STRUCT: + case IDL_UNION: + case IDL_ENUM: + /* template types */ + case IDL_SEQUENCE: + case IDL_STRING: + case IDL_WSTRING: + case IDL_FIXED_PT: + /* simple types */ + /* miscellaneous base types */ + case IDL_CHAR: + case IDL_WCHAR: + case IDL_BOOL: + case IDL_OCTET: + case IDL_ANY: + /* integer types */ + case IDL_SHORT: + case IDL_USHORT: + case IDL_LONG: + case IDL_ULONG: + case IDL_LLONG: + case IDL_ULLONG: + case IDL_INT8: + case IDL_UINT8: + case IDL_INT16: + case IDL_UINT16: + case IDL_INT32: + case IDL_UINT32: + case IDL_INT64: + case IDL_UINT64: + /* floating point types */ + case IDL_FLOAT: + case IDL_DOUBLE: + case IDL_LDOUBLE: + return (idl_type_t)mask; + default: + break; + } + + return IDL_NULL; +} + +const idl_name_t *idl_name(const void *node) +{ + if (idl_mask(node) & IDL_MODULE) + return ((const idl_module_t *)node)->name; + if (idl_mask(node) & IDL_STRUCT) + return ((const idl_struct_t *)node)->name; + if (idl_mask(node) & IDL_UNION) + return ((const idl_union_t *)node)->name; + if (idl_mask(node) & IDL_ENUM) + return ((const idl_enum_t *)node)->name; + if (idl_mask(node) & IDL_ENUMERATOR) + return ((const idl_enumerator_t *)node)->name; + if (idl_mask(node) & IDL_DECLARATOR) + return ((const idl_declarator_t *)node)->name; + if (idl_mask(node) & IDL_CONST) + return ((const idl_const_t *)node)->name; + if (idl_mask(node) & IDL_ANNOTATION) + return ((const idl_annotation_t *)node)->name; + if (idl_mask(node) & IDL_ANNOTATION_MEMBER) + return ((const idl_annotation_member_t *)node)->declarator->name; + return NULL; +} + +const char *idl_construct(const void *node) +{ + return ((const idl_node_t *)node)->describe(node); +} + +const char *idl_identifier(const void *node) +{ + const idl_name_t *name = idl_name(node); + return name ? name->identifier : NULL; +} + +void *idl_ancestor(const void *node, size_t levels) +{ + const idl_node_t *root = NULL; + + if (node) { + root = ((const idl_node_t *)node)->parent; + for (size_t level=0; level < levels && root; level++) + root = root->parent; + } + + return (void *)root; +} + +void *idl_parent(const void *node) +{ + return idl_ancestor(node, 0); +} + +size_t idl_degree(const void *node) +{ + size_t len = 0; + for (const idl_node_t *n = node; n; n = n->next) + len++; + return len; +} + +void *idl_previous(const void *node) +{ + const idl_node_t *n = (const idl_node_t *)node; + if (!n) + return NULL; +#if 0 + /* declarators can have siblings */ + if (idl_is_masked(n, IDL_DECLARATION)) + return n->previous; + /* as do expressions (or constants) if specifying array sizes */ + if (idl_is_masked(n, IDL_CONST) && idl_is_declarator(n->parent)) + return n->previous; + assert(!n->previous); + assert(!n->next); +#endif + return n->previous; +} + +void *idl_next(const void *node) +{ + const idl_node_t *n = (const idl_node_t *)node; + if (!n) + return NULL; +#if 0 + /* declaration can have siblings */ + if (idl_is_masked(n, IDL_DECLARATION)) + return n->next; + /* as do expressions (or constants) if specifying array sizes */ + if (idl_is_masked(n, IDL_CONST) && idl_is_declarator(n->parent)) + return n->next; + assert(!n->previous); + assert(!n->next); +#endif + return n->next; +} + +void *idl_iterate(const void *root, const void *node) +{ + assert(root); + assert(!node || ((const idl_node_t *)node)->parent == root); + if (node && ((const idl_node_t *)node)->next) + return ((const idl_node_t *)node)->next; + if (((const idl_node_t *)root)->iterate) + return ((const idl_node_t *)root)->iterate(root, node); + return NULL; +} + +void *idl_unalias(const void *node, uint32_t flags) +{ + while (idl_is_alias(node)) { + if (!(flags & IDL_UNALIAS_IGNORE_ARRAY) && idl_is_array(node)) + break; + node = idl_type_spec(node); + } + + return (void *)node; +} + +struct methods { + idl_delete_t delete; + idl_iterate_t iterate; + idl_describe_t describe; +}; + +static idl_retcode_t +create_node( + idl_pstate_t *pstate, + size_t size, + idl_mask_t mask, + const idl_location_t *location, + const struct methods *methods, + void *nodep) +{ + idl_node_t *node; + + (void)pstate; + assert(size >= sizeof(*node)); + if (!(node = calloc(1, size))) + return IDL_RETCODE_NO_MEMORY; + node->symbol.location = *location; + node->mask = mask; + node->destructor = methods->delete; + node->iterate = methods->iterate; + node->describe = methods->describe; + node->references = 1; + + *((idl_node_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +static void *delete_type_spec(void *node, idl_type_spec_t *type_spec) +{ + void *next; + if (!type_spec) + return NULL; + if (((idl_node_t *)type_spec)->parent != node) { + next = idl_unreference_node(type_spec); + assert(next == type_spec); + } else { + next = idl_delete_node(type_spec); + assert(next == NULL); + } + return next; +} + +static void *delete_const_expr(void *node, idl_const_expr_t *const_expr) +{ + void *next; + if (!const_expr) + return NULL; + if (((idl_node_t *)const_expr)->parent != node) { + next = idl_unreference_node(const_expr); + assert(next == const_expr); + } else { + next = idl_delete_node(const_expr); + assert(next == NULL); + } + return next; +} + +void *idl_delete_node(void *ptr) +{ + idl_node_t *next, *node = ptr; + if (!node) + return NULL; + if ((next = node->next)) + next = idl_delete_node(node->next); + node->references--; + assert(node->references >= 0); + if (node->references == 0) { + idl_node_t *previous = node->previous; + if (previous) + previous->next = next; + if (next) + next->previous = next; + idl_delete_node((idl_node_t *)node->annotations); + /* self-destruct */ + if (node->destructor) + node->destructor(node); + return next; + } + return node; +} + +bool idl_is_declaration(const void *ptr) +{ + const idl_node_t *node = ptr; + if (!(idl_mask(node) & IDL_DECLARATION)) + return false; + /* a declaration must have been declared */ + assert(node->declaration); + return true; +} + +bool idl_is_module(const void *ptr) +{ +#if !defined NDEBUG + static const idl_mask_t mask = + IDL_MODULE | IDL_CONST | IDL_STRUCT | IDL_UNION | IDL_ENUM | + IDL_TYPEDEF | IDL_ANNOTATION; +#endif + const idl_module_t *node = ptr; + + if (!(idl_mask(node) & IDL_MODULE)) + return false; + /* a module must have a name */ + assert(node->name && node->name->identifier); + /* a module must have a scope */ + assert(node->node.declaration); + /* a module must have at least one definition */ + assert(!node->definitions || (idl_mask(node->definitions) & mask)); + return true; +} + +static void delete_module(void *ptr) +{ + idl_module_t *node = (idl_module_t *)ptr; + idl_delete_node(node->definitions); + idl_delete_name(node->name); + free(node); +} + +static void *iterate_module(const void *ptr, const void *cur) +{ + const idl_module_t *root = ptr; + const idl_node_t *node = cur; + if (node) { + assert(idl_parent(node) == root); + if (node->next) + return node->next; + if (idl_is_annotation_appl(node)) + return root->definitions; + return NULL; + } + if (root->node.annotations) + return root->node.annotations; + return root->definitions; +} + +static const char *describe_module(const void *ptr) { (void)ptr; return "module"; } + +idl_retcode_t +idl_finalize_module( + idl_pstate_t *state, + const idl_location_t *location, + idl_module_t *node, + idl_definition_t *definitions) +{ + idl_exit_scope(state); + node->node.symbol.location.last = location->last; + node->definitions = definitions; + for (idl_node_t *n = (idl_node_t *)definitions; n; n = n->next) { + assert(!n->parent); + n->parent = (idl_node_t *)node; + } + return IDL_RETCODE_OK; +} + +idl_retcode_t +idl_create_module( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + void *nodep) +{ + idl_retcode_t ret; + idl_module_t *node; + idl_scope_t *scope = NULL; + const idl_declaration_t *declaration; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_MODULE; + static const struct methods methods = { + delete_module, iterate_module, describe_module }; + static const enum idl_declaration_kind kind = IDL_MODULE_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + node->name = name; + + /* an identifier declaring a module is considered to be defined by its + first occurence in a scope. subsequent occurrences of a module + declaration with the same identifier within the same scope reopens the + module and hence its scope, allowing additional definitions to be added + to it */ + declaration = idl_find(pstate, NULL, name, 0u); + if (declaration && (idl_mask(declaration->node) & IDL_MODULE)) { + node->node.declaration = declaration; +#if 0 + /* FIXME: the code below always adds the first module as previous, which + is obviously wrong. for now though, it doesn't look like the + reference is needed? */ + node->previous = (const idl_module_t *)declaration->node; +#endif + scope = (idl_scope_t *)declaration->scope; + } else { + if ((ret = idl_create_scope(pstate, IDL_MODULE_SCOPE, name, node, &scope))) + goto err_scope; + if ((ret = idl_declare(pstate, kind, name, node, scope, NULL))) + goto err_declare; + } + + idl_enter_scope(pstate, scope); + *((idl_module_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: + idl_delete_scope(scope); +err_scope: + free(node); +err_node: + return ret; +} + +bool idl_is_const(const void *ptr) +{ +#if !defined(NDEBUG) + static const idl_mask_t mask = + IDL_BASE_TYPE | IDL_STRING | IDL_ENUMERATOR; +#endif + const idl_const_t *node = ptr; + + if (!(idl_mask(node) & IDL_CONST)) + return false; + /* a constant must have a name */ + assert(node->name && node->name->identifier); + /* a constant must have a type specifier */ + assert(idl_mask(node->type_spec) & mask); + /* a constant must have a constant value */ + assert(idl_mask(node->const_expr) & IDL_LITERAL); + assert(idl_mask(node->const_expr) & mask); + return true; +} + +static void delete_const(void *ptr) +{ + idl_const_t *node = (idl_const_t *)ptr; + delete_type_spec(node, node->type_spec); + delete_const_expr(node, node->const_expr); + idl_delete_name(node->name); + free(node); +} + +static void *iterate_const(const void *ptr, const void *cur) +{ + const idl_const_t *root = ptr; + const idl_node_t *node = cur; + if (node) { + assert(idl_parent(node) == root); + if (node->next) + return node->next; + return NULL; + } + return root->node.annotations; +} + +static const char *describe_const(const void *ptr) { (void)ptr; return "const"; } + +idl_retcode_t +idl_create_const( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_name_t *name, + idl_const_expr_t *const_expr, + void *nodep) +{ + idl_retcode_t ret; + idl_const_t *node; + idl_type_spec_t *alias; + idl_const_expr_t *literal = NULL; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_CONST; + static const struct methods methods = { + delete_const, iterate_const, describe_const }; + static const enum idl_declaration_kind kind = IDL_SPECIFIER_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + node->name = name; + /* type specifier can be a type definition */ + alias = type_spec; + type_spec = idl_unalias(type_spec, 0u); + assert(idl_mask(type_spec) & (IDL_BASE_TYPE|IDL_STRING|IDL_ENUM)); + node->type_spec = alias; + if (!idl_scope(alias)) + ((idl_node_t *)alias)->parent = (idl_node_t*)node; + /* evaluate constant expression */ + if ((ret = idl_evaluate(pstate, const_expr, idl_type(type_spec), &literal))) + goto err_evaluate; + node->const_expr = literal; + if (!idl_scope(literal)) + ((idl_node_t *)literal)->parent = (idl_node_t*)node; + if ((ret = idl_declare(pstate, kind, name, node, NULL, NULL))) + goto err_declare; + + *((idl_const_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: +err_evaluate: + free(node); +err_node: + return ret; +} + +bool idl_is_literal(const void *ptr) +{ + const idl_literal_t *node = ptr; + + if (!(idl_mask(node) & IDL_LITERAL)) + return false; + if (idl_mask(node) & IDL_STRING) + assert(node->value.str); + return true; +} + +static void delete_literal(void *ptr) +{ + idl_literal_t *node = ptr; + assert(idl_mask(node) & IDL_LITERAL); + if (idl_mask(node) & IDL_STRING) + free(node->value.str); + free(node); +} + +static const char *describe_literal(const void *ptr) +{ + idl_type_t type; + + assert(idl_mask(ptr) & IDL_LITERAL); + + type = idl_type(ptr); + if (type == IDL_CHAR) + return "character literal"; + if (type == IDL_BOOL) + return "boolean literal"; + if (type == IDL_OCTET) + return "integer literal"; + if (type & IDL_INTEGER_TYPE) + return "integer literal"; + if (type & IDL_FLOATING_PT_TYPE) + return "floating point literal"; + assert(type == IDL_STRING); + return "string literal"; +} + +idl_retcode_t +idl_create_literal( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + void *nodep) +{ + idl_retcode_t ret; + idl_literal_t *node = NULL; + static const size_t size = sizeof(*node); + static const struct methods methods = { + delete_literal, 0, describe_literal }; + + mask |= IDL_LITERAL; + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + *((idl_literal_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +static void delete_binary_expr(void *ptr) +{ + idl_binary_expr_t *node = ptr; + delete_const_expr(node, node->left); + delete_const_expr(node, node->right); + free(node); +} + +static const char *describe_binary_expr(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_BINARY_OPERATOR); + return "expression"; +} + +idl_retcode_t +idl_create_binary_expr( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + idl_primary_expr_t *left, + idl_primary_expr_t *right, + void *nodep) +{ + idl_retcode_t ret; + idl_binary_expr_t *node = NULL; + static const size_t size = sizeof(*node); + static const struct methods methods = { + &delete_binary_expr, 0, describe_binary_expr }; + + mask |= IDL_BINARY_OPERATOR; + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + node->left = left; + if (!idl_scope(left)) + ((idl_node_t *)left)->parent = (idl_node_t *)node; + node->right = right; + if (!idl_scope(right)) + ((idl_node_t *)right)->parent = (idl_node_t *)node; + *((idl_binary_expr_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +static void delete_unary_expr(void *ptr) +{ + idl_unary_expr_t *node = ptr; + delete_const_expr(node, node->right); + free(node); +} + +static const char *describe_unary_expr(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_UNARY_OPERATOR); + return "expression"; +} + +idl_retcode_t +idl_create_unary_expr( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + idl_primary_expr_t *right, + void *nodep) +{ + idl_retcode_t ret; + idl_unary_expr_t *node = NULL; + static const size_t size = sizeof(*node); + static const struct methods methods = { + delete_unary_expr, 0, describe_unary_expr }; + + mask |= IDL_UNARY_OPERATOR; + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + node->right = right; + if (!idl_scope(right)) + ((idl_node_t *)right)->parent = (idl_node_t *)node; + *((idl_unary_expr_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +bool idl_is_type_spec(const void *ptr) +{ + /* a declarator is a type specifier if its parent is a typedef */ + if (idl_mask(ptr) & IDL_DECLARATOR) + ptr = idl_parent(ptr); + return (idl_mask(ptr) & IDL_TYPE) != 0; +} + +bool idl_is_base_type(const void *node) +{ + if (!(idl_mask(node) & IDL_BASE_TYPE) || (idl_mask(node) & IDL_LITERAL)) + return false; + return true; +} + +bool idl_is_floating_pt_type(const void *node) +{ + return (idl_mask(node) & IDL_FLOATING_PT_TYPE) != 0; +} + +bool idl_is_integer_type(const void *node) +{ + return (idl_mask(node) & IDL_INTEGER_TYPE) != 0; +} + +static void delete_base_type(void *ptr) +{ + free(ptr); +} + +static const char *describe_base_type(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_BASE_TYPE); + return "base type"; +} + +idl_retcode_t +idl_create_base_type( + idl_pstate_t *state, + const idl_location_t *location, + idl_mask_t mask, + void *nodep) +{ + static const size_t size = sizeof(idl_base_type_t); + static const struct methods methods = { + delete_base_type, 0, describe_base_type }; + + return create_node(state, size, mask, location, &methods, nodep); +} + +bool idl_is_templ_type(const void *ptr) +{ + return (idl_mask(ptr) & (IDL_SEQUENCE|IDL_STRING)) != 0; +} + +bool idl_is_bounded(const void *node) +{ + idl_mask_t mask = idl_mask(node); + if ((mask & IDL_STRING) == IDL_STRING) + return ((const idl_string_t *)node)->maximum != 0; + if ((mask & IDL_SEQUENCE) == IDL_SEQUENCE) + return ((const idl_sequence_t *)node)->maximum != 0; + return false; +} + +uint32_t idl_bound(const void *node) +{ + idl_mask_t mask = idl_mask(node); + if ((mask & IDL_STRING) == IDL_STRING) + return ((const idl_string_t *)node)->maximum; + if ((mask & IDL_SEQUENCE) == IDL_SEQUENCE) + return ((const idl_sequence_t *)node)->maximum; + return 0u; +} + +bool idl_is_sequence(const void *ptr) +{ + idl_mask_t mask; + const idl_sequence_t *node = ptr; + const idl_type_spec_t *type_spec; + + if (!(idl_mask(node) & IDL_SEQUENCE)) + return false; + assert(!node->node.declaration); + /* a sequence must have a type specifier */ + type_spec = node->type_spec; + if (idl_mask(type_spec) & IDL_DECLARATOR) + type_spec = ((const idl_node_t *)type_spec)->parent; + mask = IDL_STRUCT | IDL_UNION | IDL_ENUM | IDL_TYPEDEF | + IDL_SEQUENCE | IDL_STRING | IDL_BASE_TYPE; + (void)mask; + assert(idl_mask(type_spec) & mask); + mask = IDL_TYPEDEF | IDL_MEMBER | IDL_CASE | + IDL_SEQUENCE | IDL_SWITCH_TYPE_SPEC; + assert(!node->node.parent || (idl_mask(node->node.parent) & mask)); + return true; +} + +static void delete_sequence(void *ptr) +{ + idl_sequence_t *node = (idl_sequence_t *)ptr; + delete_type_spec(node, node->type_spec); + free(node); +} + +static const char *describe_sequence(const void *ptr) +{ + const idl_sequence_t *node = ptr; + assert(idl_mask(node) & IDL_SEQUENCE); + return node->maximum ? "bounded sequence" : "sequence"; +} + +idl_retcode_t +idl_create_sequence( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_literal_t *literal, + void *nodep) +{ + idl_retcode_t ret; + idl_sequence_t *node; + idl_type_spec_t *alias; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_SEQUENCE; + static const struct methods methods = { + delete_sequence, 0, describe_sequence }; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + /* type specifier can be a type definition */ + alias = type_spec; + type_spec = idl_unalias(type_spec, 0u); + node->type_spec = alias; + if (!idl_scope(alias)) + ((idl_node_t *)alias)->parent = (idl_node_t*)node; + assert(!literal || idl_type(literal) == IDL_ULONG); + if (literal) + node->maximum = literal->value.uint32; + idl_delete_node(literal); + *((idl_sequence_t **)nodep) = node; + return IDL_RETCODE_OK; +err_node: + return ret; +} + +bool idl_is_string(const void *ptr) +{ +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_CONST | IDL_TYPEDEF | IDL_MEMBER | + IDL_CASE | IDL_SEQUENCE | + IDL_SWITCH_TYPE_SPEC; +#endif + const idl_string_t *node = ptr; + + if (!(idl_mask(node) & IDL_STRING) || (idl_mask(node) & IDL_CONST)) + return false; + assert(!node->node.declaration); + assert(!node->node.parent || (idl_mask(node->node.parent) & mask)); + return true; +} + +static void delete_string(void *ptr) +{ + free(ptr); +} + +static const char *describe_string(const void *ptr) +{ + const idl_string_t *node = ptr; + assert(idl_mask(node) & IDL_STRING); + return node->maximum ? "bounded string" : "string"; +} + +idl_retcode_t +idl_create_string( + idl_pstate_t *state, + const idl_location_t *location, + idl_literal_t *literal, + void *nodep) +{ + idl_retcode_t ret; + idl_string_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_STRING; + static const struct methods methods = { delete_string, 0, describe_string }; + + if ((ret = create_node(state, size, mask, location, &methods, &node))) + goto err_node; + assert(!literal || idl_type(literal) == IDL_ULONG); + if (literal) + node->maximum = literal->value.uint32; + idl_unreference_node(literal); + *((idl_string_t **)nodep) = node; + return IDL_RETCODE_OK; +err_node: + return ret; +} + +bool idl_is_constr_type(const void *node) +{ + return (idl_mask(node) & (IDL_STRUCT | IDL_UNION | IDL_ENUM)) != 0; +} + +bool idl_is_struct(const void *ptr) +{ + const idl_struct_t *node = ptr; + + if (!(idl_mask(node) & IDL_STRUCT) || (idl_mask(node) & IDL_FORWARD)) + return false; + /* a struct must have a name */ + assert(node->name && node->name->identifier); + /* structs must have at least one member unless building block extended + data types is enabled */ +#if 0 + members = ((const idl_struct_t *)node)->members; + if (!(pstate->flags & IDL_FLAG_EXTENDED_DATA_TYPES)) + assert(members); + if (members) + assert(idl_mask(members) & IDL_MEMBER); +#endif + return true; +} + +static void delete_struct(void *ptr) +{ + idl_struct_t *node = ptr; + idl_delete_node(node->inherit_spec); + idl_delete_node(node->keylist); + idl_delete_node(node->members); + idl_delete_name(node->name); + free(node); +} + +static void *iterate_struct(const void *ptr, const void *cur) +{ + const idl_struct_t *root = (const idl_struct_t *)ptr; + const idl_node_t *node = (const idl_node_t *)cur; + if (node) { + if (node->next) + return node->next; + if (idl_is_inherit_spec(node)) + return root->members; + if (idl_is_annotation_appl(node)) { + if (root->inherit_spec) + return root->inherit_spec; + return root->members; + } + return NULL; + } + if (root->node.annotations) + return root->node.annotations; + if (root->inherit_spec) + return root->inherit_spec; + return root->members; +} + +static const char *describe_struct(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_STRUCT); + return "struct"; +} + +idl_retcode_t +idl_finalize_struct( + idl_pstate_t *state, + const idl_location_t *location, + idl_struct_t *node, + idl_member_t *members) +{ + idl_exit_scope(state); + node->node.symbol.location.last = location->last; + if (members) { + node->members = members; + for (idl_node_t *n = (idl_node_t *)members; n; n = n->next) { + assert(!n->parent); + n->parent = (idl_node_t *)node; + } + } + return IDL_RETCODE_OK; +} + +idl_retcode_t +idl_create_struct( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_inherit_spec_t *inherit_spec, + void *nodep) +{ + idl_retcode_t ret; + idl_struct_t *node; + idl_scope_t *scope; + idl_declaration_t *declaration; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_STRUCT; + static const struct methods methods = { + delete_struct, iterate_struct, describe_struct }; + static const enum idl_declaration_kind kind = IDL_SPECIFIER_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + node->name = name; + if ((ret = idl_create_scope(pstate, IDL_STRUCT_SCOPE, name, node, &scope))) + goto err_scope; + if ((ret = idl_declare(pstate, kind, name, node, scope, &declaration))) + goto err_declare; + + if (inherit_spec) { + const idl_struct_t *base = inherit_spec->base; + + if (!(idl_mask(base) & IDL_STRUCT)) { + idl_error(pstate, idl_location(base), + "Struct types cannot inherit from '%s' elements", idl_construct(base)); + return IDL_RETCODE_SEMANTIC_ERROR; + } else if (inherit_spec->node.next) { + idl_error(pstate, idl_location(inherit_spec->node.next), + "Struct types are limited to single inheritance"); + return IDL_RETCODE_SEMANTIC_ERROR; + } + /* find scope */ + scope = declaration->scope; + /* find imported scope */ + declaration = (void*)idl_find(pstate, idl_scope(base), idl_name(base), 0u); + assert(declaration && declaration->scope); + if ((ret = idl_import(pstate, scope, declaration->scope))) + return ret; + node->inherit_spec = inherit_spec; + inherit_spec->node.parent = (idl_node_t *)node; + } + + idl_enter_scope(pstate, scope); + *((idl_struct_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: + idl_delete_scope(scope); +err_scope: + free(node); +err_node: + return ret; +} + +bool idl_is_inherit_spec(const void *ptr) +{ + const idl_inherit_spec_t *node = ptr; + + if (!(idl_mask(node) & IDL_INHERIT_SPEC)) + return false; + /* inheritance specifier must define a base type */ + assert(idl_mask(node->base) & IDL_STRUCT); + /* inheritance specifier must have a parent of type struct */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_STRUCT)); + return true; +} + +static void delete_inherit_spec(void *ptr) +{ + idl_inherit_spec_t *node = ptr; + idl_unreference_node(node->base); + free(node); +} + +static const char *describe_inherit_spec(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_INHERIT_SPEC); + return "inheritance specifier"; +} + +idl_retcode_t +idl_create_inherit_spec( + idl_pstate_t *pstate, + const idl_location_t *location, + void *base, + void *nodep) +{ + idl_retcode_t ret; + idl_inherit_spec_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_INHERIT_SPEC; + static const struct methods methods = { + delete_inherit_spec, 0, describe_inherit_spec }; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + node->base = base; + *((idl_inherit_spec_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +static void delete_key(void *ptr) +{ + idl_key_t *node = ptr; + idl_delete_field_name(node->field_name); + free(node); +} + +static const char *describe_key(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_KEY); + return "key"; +} + +idl_retcode_t +idl_create_key( + idl_pstate_t *pstate, + const idl_location_t *location, + void *nodep) +{ + idl_key_t *node = NULL; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_KEY; + static const struct methods methods = { delete_key, 0, describe_key }; + + if (create_node(pstate, size, mask, location, &methods, &node)) + return IDL_RETCODE_NO_MEMORY; + *((idl_key_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +static void delete_keylist(void *ptr) +{ + idl_keylist_t *node = ptr; + idl_delete_node(node->keys); + free(node); +} + +static const char *describe_keylist(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_KEYLIST); + return "keylist"; +} + +idl_retcode_t +idl_create_keylist( + idl_pstate_t *pstate, + const idl_location_t *location, + void *nodep) +{ + idl_retcode_t ret; + idl_keylist_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_KEYLIST; + static const struct methods methods = { + delete_keylist, 0, describe_keylist }; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + *((idl_keylist_t **)nodep) = node; + return IDL_RETCODE_OK; +err_node: + return IDL_RETCODE_NO_MEMORY; +} + +bool idl_is_member(const void *ptr) +{ + const idl_member_t *node = ptr; + + if (!(idl_mask(node) & IDL_MEMBER)) + return false; + /* a member must have a struct parent (except when under construction) */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_STRUCT)); + /* a member must have a type specifier */ + assert(node->type_spec); + /* a member must have at least one declarator */ + assert(idl_mask(node->declarators) & IDL_DECLARATOR); + return true; +} + +static void delete_member(void *ptr) +{ + idl_member_t *node = ptr; + delete_type_spec(node, node->type_spec); + idl_delete_node(node->declarators); + free(node); +} + +static void *iterate_member(const void *ptr, const void *cur) +{ + const idl_member_t *root = ptr; + const idl_node_t *node = cur; + if (node) { + if (node->next) + return node->next; + if (idl_is_annotation_appl(node)) + return root->declarators; + return NULL; + } + if (root->node.annotations) + return root->node.annotations; + return root->declarators; +} + +static const char *describe_member(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_MEMBER); + return "member"; +} + +idl_retcode_t +idl_create_member( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_declarator_t *declarators, + void *nodep) +{ + idl_retcode_t ret; + idl_member_t *node; + idl_scope_t *scope = NULL; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_MEMBER; + static const struct methods methods = { + delete_member, iterate_member, describe_member }; + static const enum idl_declaration_kind kind = IDL_INSTANCE_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + node->type_spec = type_spec; + if (idl_scope(type_spec)) { + /* struct and union types introduce a scope. resolve scope and link it for + field name lookup. e.g. #pragma keylist directives */ + type_spec = idl_unalias(type_spec, IDL_UNALIAS_IGNORE_ARRAY); + if (idl_is_struct(type_spec) || idl_is_union(type_spec)) { + const idl_declaration_t *declaration = idl_declaration(type_spec); + assert(declaration); + scope = declaration->scope; + assert(scope); + } + } else { + ((idl_node_t *)type_spec)->parent = (idl_node_t*)node; + } + + assert(declarators); + node->declarators = declarators; + for (idl_declarator_t *d = declarators; d; d = idl_next(d)) { + assert(idl_mask(d) & IDL_DECLARATOR); + assert(!d->node.parent); + d->node.parent = (idl_node_t *)node; + /* FIXME: embedded structs have a scope, fix when implementing IDL3.5 */ + if ((ret = idl_declare(pstate, kind, d->name, d, scope, NULL))) + goto err_declare; + } + + *((idl_member_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: + free(node); +err_node: + return ret; +} + +bool idl_is_union(const void *ptr) +{ + const idl_union_t *node = ptr; + + if (!(idl_mask(node) & IDL_UNION) || (idl_mask(node) & IDL_FORWARD)) + return false; + /* a union must have no parent or a module parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_MODULE)); + /* a union must have a name */ + assert(node->name && node->name->identifier); + /* a union must have a switch type specifier */ + assert(idl_mask(node->switch_type_spec) & IDL_SWITCH_TYPE_SPEC); + /* a union must have at least one case */ + assert(!node->cases || (idl_mask(node->cases) & IDL_CASE)); + return true; +} + +static void delete_union(void *ptr) +{ + idl_union_t *node = ptr; + idl_delete_node(node->switch_type_spec); + idl_delete_node(node->cases); + idl_delete_name(node->name); + free(node); +} + +static void *iterate_union(const void *ptr, const void *cur) +{ + const idl_union_t *root = ptr; + const idl_node_t *node = cur; + assert(root); + if (node) { + assert(idl_parent(node) == root); + if (node->next) + return node->next; + if (idl_is_switch_type_spec(node)) + return root->cases; + if (idl_is_annotation_appl(node)) + return root->switch_type_spec; + return NULL; + } + if (root->node.annotations) + return root->node.annotations; + return root->switch_type_spec; +} + +static const char *describe_union(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_UNION); + return "union"; +} + +idl_retcode_t +idl_finalize_union( + idl_pstate_t *state, + const idl_location_t *location, + idl_union_t *node, + idl_case_t *cases) +{ + idl_retcode_t ret = IDL_RETCODE_OK; + idl_case_t *default_case = NULL; + idl_switch_type_spec_t *switch_type_spec; + idl_type_t type; + + switch_type_spec = node->switch_type_spec; + assert(switch_type_spec); + assert(idl_mask(switch_type_spec) & IDL_SWITCH_TYPE_SPEC); + type = idl_type(switch_type_spec->type_spec); + + assert(cases); + for (idl_case_t *c = cases; c; c = idl_next(c)) { + /* iterate case labels and evaluate constant expressions */ + idl_case_label_t *null_label = NULL; + /* determine if null-label is present */ + for (idl_case_label_t *cl = c->case_labels; cl; cl = idl_next(cl)) { + if (!cl->const_expr) { + null_label = cl; + if (default_case) { + idl_error(state, idl_location(cl), + "error about default case!"); + return IDL_RETCODE_SEMANTIC_ERROR; + } else { + default_case = c; + } + break; + } + } + /* evaluate constant expressions */ + for (idl_case_label_t *cl = c->case_labels; cl; cl = idl_next(cl)) { + if (cl->const_expr) { + if (null_label) { + idl_warning(state, idl_location(cl), + "Label in combination with null-label is not useful"); + } + idl_literal_t *literal = NULL; + ret = idl_evaluate(state, cl->const_expr, type, &literal); + if (ret != IDL_RETCODE_OK) + return ret; + if (type == IDL_ENUMERATOR) { + if ((uintptr_t)switch_type_spec != (uintptr_t)literal->node.parent) { + idl_error(state, idl_location(cl), + "Enumerator of different enum type"); + return IDL_RETCODE_SEMANTIC_ERROR; + } + } + cl->const_expr = literal; + if (!idl_scope(literal)) + literal->node.parent = (idl_node_t*)cl; + } + } + assert(!c->node.parent); + c->node.parent = (idl_node_t *)node; + } + + node->node.symbol.location.last = location->last; + node->cases = cases; + + // FIXME: for C++ the lowest value must be known. if beneficial for other + // language bindings we may consider marking that value or perhaps + // offer convenience functions to do so + + idl_exit_scope(state); + return IDL_RETCODE_OK; +} + +idl_retcode_t +idl_create_union( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_switch_type_spec_t *switch_type_spec, + void *nodep) +{ + idl_retcode_t ret; + idl_union_t *node; + idl_scope_t *scope; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_UNION; + static const struct methods methods = { + delete_union, iterate_union, describe_union }; + static const enum idl_declaration_kind kind = IDL_SPECIFIER_DECLARATION; + + if (!idl_is_switch_type_spec(switch_type_spec)) { + static const char *fmt = + "Type '%s' is not a valid switch type specifier"; + idl_error(pstate, idl_location(switch_type_spec), fmt, idl_construct(switch_type_spec)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + node->name = name; + node->switch_type_spec = switch_type_spec; + assert(!idl_scope(switch_type_spec)); + ((idl_node_t *)switch_type_spec)->parent = (idl_node_t *)node; + if ((ret = idl_create_scope(pstate, IDL_UNION_SCOPE, name, node, &scope))) + goto err_scope; + if ((ret = idl_declare(pstate, kind, name, node, scope, NULL))) + goto err_declare; + + idl_enter_scope(pstate, scope); + *((idl_union_t **)nodep) = node; + return ret; +err_declare: + idl_delete_scope(scope); +err_scope: + free(node); +err_node: + return ret; +} + +bool +idl_is_switch_type_spec(const void *ptr) +{ + const idl_switch_type_spec_t *node = ptr; + const idl_type_spec_t *type_spec; + + if (!(idl_mask(node) & IDL_SWITCH_TYPE_SPEC)) + return false; + /* a switch type specifier must have a union parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_UNION)); + /* a switch type specifier must have a type specifier */ + type_spec = node->type_spec; + assert(type_spec); + type_spec = idl_unalias(type_spec, 0u); + switch (idl_type(type_spec)) { + case IDL_ENUM: + return true; + case IDL_WCHAR: + case IDL_OCTET: +#if 0 + assert(pstate->flags & IDL_FLAG_EXTENDED_DATA_TYPES); +#endif + return true; + default: + assert(idl_is_base_type(type_spec)); + return true; + } +} + +static void delete_switch_type_spec(void *ptr) +{ + idl_switch_type_spec_t *node = ptr; + delete_type_spec(node, node->type_spec); + free(node); +} + +static void *iterate_switch_type_spec(const void *ptr, const void *cur) +{ + const idl_switch_type_spec_t *root = ptr; + const idl_node_t *node = cur; + assert(root); + if (node) { + assert(idl_parent(node) == root); + if (node->next) + return node->next; + return NULL; + } + return root->node.annotations; +} + +static const char *describe_switch_type_spec(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) & IDL_SWITCH_TYPE_SPEC); + return "switch type specifier"; +} + +idl_retcode_t +idl_create_switch_type_spec( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + void *nodep) +{ + idl_retcode_t ret; + idl_switch_type_spec_t *node = NULL; + idl_type_t type; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_SWITCH_TYPE_SPEC; + static const struct methods methods = { delete_switch_type_spec, + iterate_switch_type_spec, + describe_switch_type_spec }; + bool ext = (pstate->flags & IDL_FLAG_EXTENDED_DATA_TYPES) != 0; + + assert(type_spec); + type = idl_type(idl_unalias(type_spec, 0u)); + if (!(type == IDL_ENUM) && + !(type == IDL_BOOL) && + !(type == IDL_CHAR) && + !(((unsigned)type & (unsigned)IDL_INTEGER_TYPE) == IDL_INTEGER_TYPE) && + !(ext && type == IDL_OCTET) && + !(ext && type == IDL_WCHAR)) + { + idl_error(pstate, idl_location(type_spec), + "Invalid switch type '%s'", idl_construct(type_spec)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + node->type_spec = type_spec; + if (!idl_scope(type_spec)) + ((idl_node_t *)type_spec)->parent = (idl_node_t *)node; + *((idl_switch_type_spec_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +bool idl_is_case(const void *ptr) +{ + const idl_case_t *node = ptr; + if (!(idl_mask(node) & IDL_CASE)) + return false; + /* a case must have a union parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_UNION)); + /* a case must have at least one case label */ + assert(!node->case_labels || (idl_mask(node->case_labels) & IDL_CASE_LABEL)); + /* a case must have exactly one declarator */ + assert(idl_mask(node->declarator) & IDL_DECLARATOR); + return true; +} + +bool idl_is_default_case(const void *ptr) +{ + const idl_case_t *node = ptr; + if (!(idl_mask(node) & IDL_CASE)) + return false; + for (const idl_case_label_t *cl = node->case_labels; cl; cl = idl_next(cl)) + if (!cl->const_expr) + return true; + return false; +} + +static void delete_case(void *ptr) +{ + idl_case_t *node = ptr; + delete_type_spec(node, node->type_spec); + idl_delete_node(node->case_labels); + idl_delete_node(node->declarator); + free(node); +} + +static void *iterate_case(const void *ptr, const void *cur) +{ + const idl_case_t *root = ptr; + const idl_node_t *node = cur; + assert(root); + if (node) { + assert(idl_parent(node) == root); + if (node->next) + return node->next; + if (idl_is_case_label(node)) + return root->declarator; + return NULL; + } + return root->case_labels; +} + +static const char *describe_case(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_CASE); + return "switch case"; +} + +idl_retcode_t +idl_finalize_case( + idl_pstate_t *state, + const idl_location_t *location, + idl_case_t *node, + idl_case_label_t *case_labels) +{ + (void)state; + node->node.symbol.location.last = location->last; + node->case_labels = case_labels; + for (idl_node_t *n = (idl_node_t*)case_labels; n; n = n->next) + n->parent = (idl_node_t*)node; + return IDL_RETCODE_OK; + // FIXME: warn for and ignore duplicate labels + // FIXME: warn for and ignore for labels combined with default +} + +idl_retcode_t +idl_create_case( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_declarator_t *declarator, + void *nodep) +{ + idl_retcode_t ret; + idl_case_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_CASE; + static const struct methods methods = { + delete_case, iterate_case, describe_case }; + static const enum idl_declaration_kind kind = IDL_INSTANCE_DECLARATION; + idl_scope_t *scope = NULL; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + node->type_spec = type_spec; + if (idl_scope(type_spec)) { + /* struct and union types introduce a scope. resolve the scope and link it + for field name lookup. e.g. #pragma keylist directives */ + type_spec = idl_unalias(type_spec, 0u); + if (idl_is_struct(type_spec) || idl_is_union(type_spec)) { + const idl_declaration_t *declaration; + + declaration = idl_find( + pstate, idl_scope(type_spec), idl_name(type_spec), 0u); + assert(declaration); + scope = declaration->scope; + } + } else { + ((idl_node_t*)type_spec)->parent = (idl_node_t *)node; + } + node->declarator = declarator; + assert(!declarator->node.parent); + declarator->node.parent = (idl_node_t *)node; + assert(!declarator->node.next); + if ((ret = idl_declare(pstate, kind, declarator->name, declarator, scope, NULL))) + goto err_declare; + + *((idl_case_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: + free(node); +err_node: + return ret; +} + +bool idl_is_case_label(const void *ptr) +{ +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_LITERAL | IDL_ENUMERATOR; +#endif + const idl_case_label_t *node = ptr; + + if (!(idl_mask(node) & IDL_CASE_LABEL)) + return false; + /* a case label must have a case parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_CASE)); + /* a case labels may have an expression (default case does not) */ + assert(!node->const_expr || (idl_mask(node->const_expr) & mask)); + return true; +} + +static void delete_case_label(void *ptr) +{ + idl_case_label_t *node = ptr; + idl_delete_node(node->const_expr); + free(node); +} + +static const char *describe_case_label(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_CASE_LABEL); + return "switch case label"; +} + +idl_retcode_t +idl_create_case_label( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_const_expr_t *const_expr, + void *nodep) +{ + idl_retcode_t ret; + idl_case_label_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_CASE_LABEL; + static const struct methods methods = { + delete_case_label, 0, describe_case_label }; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + node->const_expr = const_expr; + if (const_expr && !idl_scope(const_expr)) + ((idl_node_t *)const_expr)->parent = (idl_node_t *)node; + + *((idl_case_label_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +bool idl_is_enum(const void *ptr) +{ + const idl_enum_t *node = ptr; + + if (!(idl_mask(node) & IDL_ENUM)) + return false; + /* an enum must have a name */ + assert(node->name && node->name->identifier); + /* an enum must have no parent or a module parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_MODULE)); + /* an enum must have at least one enumerator */ + assert(!node->enumerators || (idl_mask(node->enumerators) & IDL_ENUMERATOR)); + return true; +} + +static void delete_enum(void *ptr) +{ + idl_enum_t *node = ptr; + idl_delete_node(node->enumerators); + idl_delete_name(node->name); + free(node); +} + +static void *iterate_enum(const void *ptr, const void *cur) +{ + const idl_enum_t *root = ptr; + const idl_node_t *node = cur; + assert(root); + if (node) { + assert(idl_parent(node) == root); + if (node->next) + return node->next; + if (idl_is_annotation_appl(node)) + return root->enumerators; + return NULL; + } + if (root->node.annotations) + return root->node.annotations; + return root->enumerators; +} + +static const char *describe_enum(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_ENUM); + return "enum"; +} + +idl_retcode_t +idl_create_enum( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_enumerator_t *enumerators, + void *nodep) +{ + idl_retcode_t ret; + idl_enum_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_ENUM; + static const struct methods methods = { + delete_enum, iterate_enum, describe_enum }; + static const enum idl_declaration_kind kind = IDL_SPECIFIER_DECLARATION; + uint32_t value = 0; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_alloc; + node->name = name; + + assert(enumerators); + node->enumerators = enumerators; + for (idl_enumerator_t *e1 = enumerators; e1; e1 = idl_next(e1), value++) { + e1->node.parent = (idl_node_t*)node; + if (e1->value) + value = e1->value; + else + e1->value = value; + for (idl_enumerator_t *e2 = enumerators; e2; e2 = idl_next(e2)) { + if (e2 == e1) + break; + if (e2->value != e1->value) + continue; + idl_error(pstate, idl_location(e1), + "Value of enumerator '%s' clashes with the value of enumerator '%s'", + e1->name->identifier, e2->name->identifier); + ret = IDL_RETCODE_SEMANTIC_ERROR; + goto err_clash; + } + } + + if ((ret = idl_declare(pstate, kind, name, node, NULL, NULL))) + goto err_declare; + + *((idl_enum_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: +err_clash: + free(node); +err_alloc: + return ret; +} + +bool idl_is_enumerator(const void *ptr) +{ + const idl_enumerator_t *node = ptr; + + if (!(idl_mask(node) & IDL_ENUMERATOR)) + return false; + /* an enumerator must have an enum parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_ENUM)); + return true; +} + +static void delete_enumerator(void *ptr) +{ + idl_enumerator_t *node = ptr; + idl_delete_name(node->name); + free(node); +} + +static void *iterate_enumerator(const void *ptr, const void *cur) +{ + const idl_enumerator_t *root = ptr; + const idl_node_t *node = cur; + assert(root); + assert(!node || idl_parent(node) == root); + if (node) + return node->next; + return root->node.annotations; +} + +static const char *describe_enumerator(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_ENUMERATOR); + return "enumerator"; +} + +idl_retcode_t +idl_create_enumerator( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + void *nodep) +{ + idl_retcode_t ret; + idl_enumerator_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_ENUMERATOR; + static const struct methods methods = { + delete_enumerator, iterate_enumerator, describe_enumerator }; + static const enum idl_declaration_kind kind = IDL_SPECIFIER_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_alloc; + node->name = name; + if ((ret = idl_declare(pstate, kind, name, node, NULL, NULL))) + goto err_declare; + + *((idl_enumerator_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: + free(node); +err_alloc: + return ret; +} + +bool idl_is_alias(const void *ptr) +{ + const idl_declarator_t *node = ptr; + + if (!(idl_mask(node) & IDL_DECLARATOR)) + return false; + /* a declarator is an alias if its parent is a typedef */ + return (idl_mask(node->node.parent) & IDL_TYPEDEF) != 0; +} + +bool idl_is_typedef(const void *ptr) +{ + const idl_typedef_t *node = ptr; + + if (!(idl_mask(node) & IDL_TYPEDEF)) + return false; + /* a typedef must have a type specifier */ + assert(node->type_spec); + /* a typedef must have no parent or a module parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & IDL_MODULE)); + /* a typedef must have at least one declarator */ + assert(idl_mask(node->declarators) & IDL_DECLARATOR); + return true; +} + +static void delete_typedef(void *ptr) +{ + idl_typedef_t *node = ptr; + delete_type_spec(node, node->type_spec); + idl_delete_node(node->declarators); + free(node); +} + +static const char *describe_typedef(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_TYPEDEF); + return "typedef"; +} + +idl_retcode_t +idl_create_typedef( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_declarator_t *declarators, + void *nodep) +{ + idl_retcode_t ret; + idl_typedef_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_TYPEDEF; + static const struct methods methods = { + delete_typedef, 0, describe_typedef }; + static const enum idl_declaration_kind kind = IDL_SPECIFIER_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_alloc; + node->type_spec = type_spec; + if (!idl_scope(type_spec)) + ((idl_node_t*)type_spec)->parent = (idl_node_t*)node; + node->declarators = declarators; + for (idl_declarator_t *d = declarators; d; d = idl_next(d)) { + assert(!d->node.parent); + d->node.parent = (idl_node_t*)node; + /* declarators can introduce an array, hence type definitions must refer + to the declarator node, not the typedef node */ + if ((ret = idl_declare(pstate, kind, d->name, d, NULL, NULL))) + goto err_declare; + } + + *((idl_typedef_t **)nodep) = node; + return IDL_RETCODE_OK; +err_declare: + free(node); +err_alloc: + return ret; +} + +bool idl_is_declarator(const void *ptr) +{ + const idl_declarator_t *node = ptr; + + if (!(idl_mask(node) & IDL_DECLARATOR)) + return false; + /* a declarator must have an identifier */ + assert(node->name->identifier); + /* a declarator must have a parent */ + assert(node->node.parent); + /* a declarator can have sizes */ + assert(!node->const_expr || (idl_mask(node->const_expr) & IDL_LITERAL)); + return true; +} + +bool idl_is_array(const void *ptr) +{ + const idl_declarator_t *node = ptr; + + if (!(idl_mask(node) & IDL_DECLARATOR)) + return false; + return node->const_expr != NULL; +} + +static void delete_declarator(void *ptr) +{ + idl_declarator_t *node = ptr; + idl_delete_node(node->const_expr); + idl_delete_name(node->name); + free(node); +} + +static const char *describe_declarator(const void *ptr) +{ + const idl_node_t *node = ptr; + assert(idl_mask(node) == IDL_DECLARATOR); + if (idl_mask(node->parent) == IDL_TYPEDEF) + return "typedef declarator"; + else if (idl_mask(node->parent) == IDL_MEMBER) + return "member declarator"; + else if (idl_mask(node->parent) == IDL_CASE) + return "element declarator"; + else if (idl_mask(node->parent) == IDL_ANNOTATION_MEMBER) + return "annotation member declarator"; + assert(!node->parent); + return "declarator"; +} + +idl_retcode_t +idl_create_declarator( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_const_expr_t *const_expr, + void *nodep) +{ + idl_retcode_t ret; + idl_declarator_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_DECLARATOR; + static const struct methods methods = { + delete_declarator, 0, describe_declarator }; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + node->name = name; + node->const_expr = const_expr; + for (idl_const_expr_t *ce = const_expr; ce; ce = idl_next(ce)) { + assert(idl_mask(ce) & IDL_LITERAL); + assert(!((idl_node_t *)ce)->parent); + ((idl_node_t *)ce)->parent = (idl_node_t *)node; + } + *((idl_declarator_t **)nodep) = node; + return ret; +} + +bool idl_is_annotation_member(const void *ptr) +{ + const idl_annotation_member_t *node = ptr; + if (!(idl_mask(node) & IDL_ANNOTATION_MEMBER)) + return false; + assert(node->type_spec); + assert(node->declarator); + return true; +} + +static void delete_annotation_member(void *ptr) +{ + idl_annotation_member_t *node = ptr; + delete_type_spec(node, node->type_spec); + delete_const_expr(node, node->const_expr); + idl_delete_node(node->declarator); + free(node); +} + +static const char *describe_annotation_member(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_ANNOTATION_MEMBER); + return "annotation member"; +} + +idl_retcode_t +idl_create_annotation_member( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_declarator_t *declarator, + idl_const_expr_t *const_expr, + void *nodep) +{ + idl_retcode_t ret; + idl_annotation_member_t *node = NULL; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_ANNOTATION_MEMBER; + static const struct methods methods = { + delete_annotation_member, 0, describe_annotation_member }; + static const enum idl_declaration_kind kind = IDL_SPECIFIER_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_alloc; + if ((ret = idl_declare(pstate, kind, declarator->name, declarator, NULL, NULL))) + goto err_declare; + node->type_spec = type_spec; + if (!idl_scope(type_spec)) + ((idl_node_t *)type_spec)->parent = (idl_node_t *)node; + node->declarator = declarator; + ((idl_node_t *)declarator)->parent = (idl_node_t *)node; + if (idl_is_enumerator(const_expr)) { + assert(((idl_node_t *)const_expr)->references > 1); + /* verify type specifier is an enum */ + if (!idl_is_enum(type_spec)) { + idl_error(pstate, idl_location(const_expr), + "Invalid default %s for %s", idl_identifier(const_expr), idl_identifier(declarator)); + goto err_enum; + /* verify enumerator is defined within enum */ + } else if (((const idl_node_t *)const_expr)->parent != (const idl_node_t *)type_spec) { + idl_error(pstate, idl_location(const_expr), + "Invalid default %s for %s", idl_identifier(const_expr), idl_identifier(declarator)); + goto err_enum; + } + node->const_expr = const_expr; + } else if (const_expr) { + idl_type_t type = idl_type(type_spec); + idl_literal_t *literal = NULL; + assert(idl_mask(const_expr) & (IDL_CONST|IDL_LITERAL)); + if ((ret = idl_evaluate(pstate, const_expr, type, &literal))) + goto err_evaluate; + assert(literal); + node->const_expr = literal; + ((idl_node_t *)literal)->parent = (idl_node_t *)node; + } + + *((idl_annotation_member_t **)nodep) = node; + return IDL_RETCODE_OK; +err_enum: + ret = IDL_RETCODE_SEMANTIC_ERROR; +err_evaluate: +err_declare: + free(node); +err_alloc: + return ret; +} + +static bool +type_is_consistent( + idl_pstate_t *pstate, + const idl_type_spec_t *lhs, + const idl_type_spec_t *rhs) +{ + const idl_scope_t *lscp, *rscp; + const idl_name_t *lname, *rname; + + (void)pstate; + lscp = idl_scope(lhs); + rscp = idl_scope(rhs); + if (!lscp != !rscp) + return false; + if (!lscp) + return idl_type(lhs) == idl_type(rhs); + if (lscp->kind != rscp->kind) + return false; + if (lscp->kind != IDL_ANNOTATION_SCOPE) + return lhs == rhs; + if (idl_type(lhs) != idl_type(rhs)) + return false; + if (idl_is_typedef(lhs)) { + assert(idl_is_typedef(rhs)); + lname = idl_name(((idl_typedef_t *)lhs)->declarators); + rname = idl_name(((idl_typedef_t *)rhs)->declarators); + } else { + lname = idl_name(lhs); + rname = idl_name(rhs); + } + return strcmp(lname->identifier, rname->identifier) == 0; +} + +static idl_retcode_t +enum_is_consistent( + idl_pstate_t *pstate, + const idl_enum_t *lhs, + const idl_enum_t *rhs) +{ + const idl_enumerator_t *a, *b; + size_t n = 0; + + (void)pstate; + for (a = lhs->enumerators; a; a = idl_next(a), n++) { + for (b = rhs->enumerators; b; b = idl_next(b)) + if (strcmp(idl_identifier(a), idl_identifier(b)) == 0) + break; + if (!n || a->value != b->value) + return false; + } + + return n == idl_degree(rhs->enumerators); +} + +static bool +const_is_consistent( + idl_pstate_t *pstate, + const idl_const_t *lhs, + const idl_const_t *rhs) +{ + if (strcmp(idl_identifier(lhs), idl_identifier(rhs)) != 0) + return false; + if (!type_is_consistent(pstate, lhs->type_spec, rhs->type_spec)) + return false; + return idl_compare(pstate, lhs->const_expr, rhs->const_expr) == IDL_EQUAL; +} + +static bool +typedef_is_consistent( + idl_pstate_t *pstate, + const idl_typedef_t *lhs, + const idl_typedef_t *rhs) +{ + const idl_declarator_t *a, *b; + size_t n = 0; + + /* typedefs may have multiple associated declarators */ + for (a = lhs->declarators; a; a = idl_next(a), n++) { + for (b = rhs->declarators; b; b = idl_next(b)) + if (strcmp(idl_identifier(a), idl_identifier(b)) == 0) + break; + if (!b) + return false; + } + + if (n != idl_degree(rhs->declarators)) + return false; + return type_is_consistent(pstate, lhs->type_spec, rhs->type_spec); +} + +static bool +member_is_consistent( + idl_pstate_t *pstate, + const idl_annotation_member_t *lhs, + const idl_annotation_member_t *rhs) +{ + if (strcmp(idl_identifier(lhs), idl_identifier(rhs)) != 0) + return false; + if (!type_is_consistent(pstate, lhs->type_spec, rhs->type_spec)) + return false; + if (!lhs->const_expr != !rhs->const_expr) + return false; + if (!lhs->const_expr) + return true; + return idl_compare(pstate, lhs->const_expr, rhs->const_expr) == IDL_EQUAL; +} + +static bool +is_consistent(idl_pstate_t *pstate, const void *lhs, const void *rhs) +{ + if (idl_mask(lhs) != idl_mask(rhs)) + return false; + else if (idl_mask(lhs) & IDL_ENUM) + return enum_is_consistent(pstate, lhs, rhs); + else if (idl_mask(lhs) & IDL_CONST) + return const_is_consistent(pstate, lhs, rhs); + else if (idl_mask(lhs) & IDL_TYPEDEF) + return typedef_is_consistent(pstate, lhs, rhs); + assert(idl_is_annotation_member(lhs)); + return member_is_consistent(pstate, lhs, rhs); +} + +idl_retcode_t +idl_finalize_annotation( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_annotation_t *node, + idl_definition_t *definitions) +{ + bool discard = false; + const idl_scope_t *scope; + + node->node.symbol.location.last = location->last; + scope = pstate->scope; + idl_exit_scope(pstate); + + if (pstate->parser.state == IDL_PARSE_EXISTING_ANNOTATION_BODY) { + const idl_name_t *name; + const idl_declaration_t *decl; + idl_definition_t *d; + ssize_t n; + + decl = idl_find(pstate, NULL, node->name, IDL_FIND_ANNOTATION); + /* earlier declaration must exist given the current state */ + assert(decl); + assert(decl->node && decl->node != (void *)node); + assert(decl->scope && decl->scope == scope); + n = (ssize_t)idl_degree(((const idl_annotation_t *)decl->node)->definitions); + for (d = definitions; n >= 0 && d; d = idl_next(d), n--) { + if (idl_is_typedef(d)) + name = idl_name(((idl_typedef_t *)d)->declarators); + else + name = idl_name(d); + decl = idl_find(pstate, scope, name, 0u); + if (!decl || !is_consistent(pstate, d, idl_parent(decl->node))) + goto err_incompat; + } + if (n != 0) + goto err_incompat; + /* declarations are compatible, discard redefinition */ + discard = true; + } + + node->definitions = definitions; + for (idl_node_t *n = (idl_node_t *)definitions; n; n = n->next) + n->parent = (idl_node_t *)node; + if (discard) + idl_unreference_node(node); + pstate->parser.state = IDL_PARSE; + return IDL_RETCODE_OK; +err_incompat: + idl_error(pstate, idl_location(node), + "Incompatible redefinition of '@%s'", idl_identifier(node)); + return IDL_RETCODE_SEMANTIC_ERROR; +} + +static void delete_annotation(void *ptr) +{ + idl_annotation_t *node = ptr; + idl_delete_node(node->definitions); + idl_delete_name(node->name); + free(node); +} + +static void *iterate_annotation(const void *ptr, const void *cur) +{ + const idl_annotation_t *root = ptr; + const idl_node_t *node = cur; + assert(root); + if (node) { + assert(idl_parent(root) == node); + return node->next; + } + return root->definitions; +} + +static const char *describe_annotation(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_ANNOTATION); + return "annotation"; +} + +idl_retcode_t +idl_create_annotation( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + void *nodep) +{ + idl_retcode_t ret; + idl_annotation_t *node = NULL; + idl_scope_t *scope = NULL; + const idl_declaration_t *declaration; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_ANNOTATION; + static const struct methods methods = { + delete_annotation, iterate_annotation, describe_annotation }; + static const enum idl_declaration_kind kind = IDL_ANNOTATION_DECLARATION; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + goto err_node; + declaration = idl_find(pstate, NULL, name, IDL_FIND_ANNOTATION); + if (declaration) { + /* annotations should not cause more compile errors than strictly needed. + therefore, in case of multiple definitions of the same annotation in + one IDL specification, the compiler should accept them, provided that + they are consistent */ + assert(declaration->kind == IDL_ANNOTATION_DECLARATION); + node->name = name; + idl_enter_scope(pstate, declaration->scope); + *((idl_annotation_t **)nodep) = node; + pstate->parser.state = IDL_PARSE_EXISTING_ANNOTATION_BODY; + return IDL_RETCODE_OK; + } + if ((ret = idl_create_scope(pstate, IDL_ANNOTATION_SCOPE, name, node, &scope))) + goto err_scope; + if ((ret = idl_declare(pstate, kind, name, node, scope, NULL))) + goto err_declare; + node->name = name; + idl_enter_scope(pstate, scope); + *((idl_annotation_t **)nodep) = node; + pstate->parser.state = IDL_PARSE_ANNOTATION_BODY; + return IDL_RETCODE_OK; +err_declare: + idl_delete_scope(scope); +err_scope: + free(node); +err_node: + return ret; +} + +static void delete_annotation_appl_param(void *ptr) +{ + idl_annotation_appl_param_t *node = ptr; + delete_const_expr(node, node->const_expr); + idl_unreference_node(node->member); + free(node); +} + +static const char *describe_annotation_appl_param(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_ANNOTATION_APPL_PARAM); + return "annotation application parameter"; +} + +idl_retcode_t +idl_create_annotation_appl_param( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_annotation_member_t *member, + idl_const_expr_t *const_expr, + void *nodep) +{ + idl_retcode_t ret; + idl_annotation_appl_param_t *node; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_ANNOTATION_APPL_PARAM; + static const struct methods methods = { + delete_annotation_appl_param, 0, describe_annotation_appl_param }; + + if ((ret = create_node(pstate, size, mask, location, &methods, &node))) + return ret; + node->member = member; + assert((idl_mask(const_expr) & IDL_EXPRESSION) || + (idl_mask(const_expr) & IDL_CONST) || + (idl_mask(const_expr) & IDL_ENUMERATOR)); + node->const_expr = const_expr; + *((idl_annotation_appl_param_t **)nodep) = node; + return ret; +} + +bool idl_is_annotation_appl(const void *ptr) +{ +#if !defined(NDEBUG) + static const idl_mask_t mask = IDL_MODULE | + IDL_STRUCT | IDL_MEMBER | + IDL_UNION | IDL_SWITCH_TYPE_SPEC; +#endif + const idl_annotation_appl_t *node = ptr; + + if (!(idl_mask(node) & IDL_ANNOTATION_APPL)) + return false; + /* an annotation application must have a parent */ + assert(!node->node.parent || (idl_mask(node->node.parent) & mask)); + /* an annotation application must have an annotation */ + assert(idl_mask(node->annotation) & IDL_ANNOTATION); + return true; +} + +static void delete_annotation_appl(void *ptr) +{ + idl_annotation_appl_t *node = ptr; + idl_unreference_node((idl_annotation_t *)node->annotation); + idl_delete_node(node->parameters); + free(node); +} + +static void *iterate_annotation_appl(const void *ptr, const void *cur) +{ + const idl_annotation_appl_t *root = ptr; + const idl_node_t *node = cur; + assert(root); + assert(!node || idl_parent(node) == root); + if (node) + return node->next; + return root->parameters; +} + +static const char *describe_annotation_appl(const void *ptr) +{ + (void)ptr; + assert(idl_mask(ptr) == IDL_ANNOTATION_APPL); + return "annotation application"; +} + +idl_retcode_t +idl_finalize_annotation_appl( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_annotation_appl_t *node, + idl_annotation_appl_param_t *parameters) +{ + assert(node); + assert(node->annotation); + node->node.symbol.location.last = location->last; + + /* constant expressions cannot be evaluated until annotations are applied + as values for members of type any must match with the element under + annotation */ + if (idl_mask(parameters) & IDL_EXPRESSION) { + idl_definition_t *definition = node->annotation->definitions; + idl_annotation_member_t *member = NULL; + while (definition && !member) { + if (idl_is_annotation_member(definition)) + member = definition; + } + idl_annotation_appl_param_t *parameter = NULL; + static const size_t size = sizeof(*parameter); + static const idl_mask_t mask = IDL_ANNOTATION_APPL_PARAM; + static const struct methods methods = { + delete_annotation_appl_param, 0, describe_annotation_appl_param }; + if (!member) { + idl_error(pstate, idl_location(parameters), + "@%s does not take any parameters", idl_identifier(node->annotation)); + return IDL_RETCODE_SEMANTIC_ERROR; + } + if (create_node(pstate, size, mask, location, &methods, ¶meter)) { + return IDL_RETCODE_NO_MEMORY; + } + node->parameters = parameter; + ((idl_node_t *)parameter)->parent = (idl_node_t *)node; + parameter->member = idl_reference_node(member); + parameter->const_expr = parameters; + ((idl_node_t *)parameters)->parent = (idl_node_t *)parameter; + } else if (idl_mask(parameters) & IDL_ANNOTATION_APPL_PARAM) { + node->parameters = parameters; + for (idl_annotation_appl_param_t *ap = parameters; ap; ap = idl_next(ap)) + ((idl_node_t *)parameters)->parent = (idl_node_t *)node; + } + + return IDL_RETCODE_OK; +} + +idl_retcode_t +idl_create_annotation_appl( + idl_pstate_t *state, + const idl_location_t *location, + const idl_annotation_t *annotation, + void *nodep) +{ + idl_retcode_t ret; + idl_annotation_appl_t *node = NULL; + static const size_t size = sizeof(*node); + static const idl_mask_t mask = IDL_ANNOTATION_APPL; + static const struct methods methods = { delete_annotation_appl, + iterate_annotation_appl, + describe_annotation_appl }; + + if ((ret = create_node(state, size, mask, location, &methods, &node))) + return ret; + + node->annotation = annotation; + *((idl_annotation_appl_t **)nodep) = node; + return IDL_RETCODE_OK; +} + +idl_type_spec_t *idl_type_spec(const void *node) +{ + idl_mask_t mask; + + mask = idl_mask(node); + if (idl_mask(node) & IDL_DECLARATOR) + node = idl_parent(node); + mask = idl_mask(node); + if (mask & IDL_TYPEDEF) + return ((const idl_typedef_t *)node)->type_spec; + if (mask & IDL_MEMBER) + return ((const idl_member_t *)node)->type_spec; + if (mask & IDL_CASE) + return ((const idl_case_t *)node)->type_spec; + if (mask & IDL_SEQUENCE) + return ((const idl_sequence_t *)node)->type_spec; + if (mask & IDL_SWITCH_TYPE_SPEC) + return ((const idl_switch_type_spec_t *)node)->type_spec; + return NULL; +} + +uint32_t idl_array_size(const void *node) +{ + uint32_t dims = 1; + const idl_literal_t *literal; + if (!(idl_mask(node) & IDL_DECLARATOR)) + return 0u; + literal = ((const idl_declarator_t *)node)->const_expr; + if (!literal) + return 0u; + for (; literal; literal = idl_next(literal)) + dims *= literal->value.uint32; + return dims; +} + +bool idl_is_topic(const void *node, bool keylist) +{ + if (keylist) { + if (!idl_is_struct(node)) + return false; + if (((const idl_struct_t *)node)->keylist) + return true; + } else { + if (idl_is_struct(node)) + return !((const idl_struct_t *)node)->nested.value; + else if (idl_is_union(node)) + return !((const idl_struct_t *)node)->nested.value; + return false; + } + return false; +} + +static bool no_specific_key(const void *node) +{ + /* @key(FALSE) is equivalent to missing @key(?) */ + if (idl_mask(node) & IDL_STRUCT) { + const idl_member_t *member = ((const idl_struct_t *)node)->members; + for (; member; member = idl_next(member)) { + if (member->key == IDL_TRUE) + return false; + } + } else { + assert(idl_mask(node) & IDL_UNION); + if (((const idl_union_t *)node)->switch_type_spec->key == IDL_TRUE) + return false; + } + + return true; +} + +static uint32_t is_key_by_path(const void *node, const idl_path_t *path) +{ + bool all_keys = false; + uint32_t key = 0; + /* constructed types, sequences, aliases and declarators carry the key */ + static const idl_mask_t mask = + IDL_CONSTR_TYPE | IDL_MEMBER | IDL_SWITCH_TYPE_SPEC | IDL_CASE | + IDL_SEQUENCE | IDL_DECLARATOR; + + for (size_t i=0; (key || i == 0) && i < path->length; i++) { + assert(path->nodes[i]); + + /* struct members can be explicitly annotated */ + if (idl_is_member(path->nodes[i])) { + const idl_member_t *instance = (const idl_member_t *)path->nodes[i]; + /* path cannot be valid if not preceeded by struct */ + if (i != 0 && !idl_is_struct(path->nodes[i - 1])) + return 0; + + if (instance->key == IDL_TRUE) + key = 1; + /* possibly implicit @key, but only if no other members are explicitly + annotated, an intermediate aggregate type has no explicitly annotated + fields and node is not on the first level */ + else if (all_keys || no_specific_key(idl_parent(instance))) + key = all_keys = (i != 0); + + /* union cases cannot be explicitly annotated */ + } else if (idl_is_case(path->nodes[i])) { + const idl_case_t *instance = (const idl_case_t *)path->nodes[i]; + /* path cannot be valid if not preceeded by union */ + if (i != 0 && !idl_is_union(path->nodes[i - 1])) + return 0; + + /* union cases cannot be annotated, but can be part of the key if an + intermediate aggregate type has no explicitly annotated fields or if + the switch type specifier is not annotated */ + if (all_keys || no_specific_key(idl_parent(instance))) + key = all_keys = (i != 0); + + /* switch type specifiers can be explicitly annotated */ + } else if (idl_is_switch_type_spec(path->nodes[i])) { + const idl_switch_type_spec_t *instance = (const idl_switch_type_spec_t *)path->nodes[i - 1]; + /* path cannot be valid if not preceeded by union */ + if (i != 0 && !idl_is_union(path->nodes[i - 1])) + return 0; + + /* possibly (implicit) @key, but only if last in path and not first */ + if (instance->key == IDL_TRUE) + key = (i == path->length - 1); + else + key = (i == path->length - 1) ? (i != 0) : 0; + } else if (!(idl_mask(node) & mask)) { + key = 0; + } + } + + return key ? (idl_mask(path->nodes[path->length - 1]) & mask) != 0 : 0; +} + +static uint32_t is_key_by_keylist(const void *node, const idl_path_t *path) +{ + const idl_key_t *key = ((const idl_struct_t *)node)->keylist->keys; + uint32_t index = 0; + + for (; key; key = idl_next(key), index++) { + int cmp = 0; + size_t cnt = 0; + for (size_t i=0; cmp == 0 && i < path->length; i++) { + if (idl_is_declarator(path->nodes[i])) { + if (key->field_name->length == cnt) { + cmp = 1; + } else { + const char *s1, *s2; + s1 = key->field_name->names[cnt++]->identifier; + s2 = idl_identifier(path->nodes[i]); + cmp = idl_strcasecmp(s1, s2); + } + } + } + if (cmp == 0 && cnt == key->field_name->length) + return index + 1; + } + + return 0; +} + +uint32_t idl_is_topic_key(const void *node, bool keylist, const idl_path_t *path) +{ + if (!idl_is_topic(node, keylist)) + return 0; + if (!path->length || node != path->nodes[0]->parent) + return 0; + + return keylist ? is_key_by_keylist(node, path) : is_key_by_path(node, path); +} diff --git a/src/idl/src/tree.h b/src/idl/src/tree.h new file mode 100644 index 0000000000..609b03bba9 --- /dev/null +++ b/src/idl/src/tree.h @@ -0,0 +1,277 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef TREE_H +#define TREE_H + +#include "idl/processor.h" + + +typedef void idl_primary_expr_t; + +typedef struct idl_binary_expr idl_binary_expr_t; +struct idl_binary_expr { + idl_node_t node; + idl_const_expr_t *left; + idl_const_expr_t *right; +}; + +typedef struct idl_unary_expr idl_unary_expr_t; +struct idl_unary_expr { + idl_node_t node; + idl_const_expr_t *right; +}; + +void *idl_push_node(void *list, void *node); +void *idl_reference_node(void *node); +void *idl_unreference_node(void *node); +void *idl_delete_node(void *node); + +idl_retcode_t +idl_create_literal( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + void *nodep); + +idl_retcode_t +idl_create_binary_expr( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + idl_primary_expr_t *left, + idl_primary_expr_t *right, + void *nodep); + +idl_retcode_t +idl_create_unary_expr( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + idl_primary_expr_t *right, + void *nodep); + +idl_retcode_t +idl_finalize_module( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_module_t *node, + void *definitions); + +idl_retcode_t +idl_create_module( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + void *nodep); + +idl_retcode_t +idl_create_const( + idl_pstate_t *pstate, + const idl_location_t *location, + void *type_spec, + idl_name_t *name, + void *const_expr, + void *nodep); + +idl_retcode_t +idl_create_sequence( + idl_pstate_t *pstate, + const idl_location_t *location, + void *type_spec, + idl_literal_t *literal, + void *nodep); + +idl_retcode_t +idl_create_string( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_literal_t *literal, + void *nodep); + +idl_retcode_t +idl_finalize_struct( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_struct_t *node, + idl_member_t *members); + +idl_retcode_t +idl_create_struct( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_inherit_spec_t *inherit_spec, + void *nodep); + +idl_retcode_t +idl_create_key( + idl_pstate_t *pstate, + const idl_location_t *location, + void *nodep); + +idl_retcode_t +idl_create_keylist( + idl_pstate_t *pstate, + const idl_location_t *location, + void *nodep); + +idl_retcode_t +idl_create_member( + idl_pstate_t *pstate, + const idl_location_t *location, + void *type_spec, + idl_declarator_t *declarators, + void *nodep); + +idl_retcode_t +idl_create_forward( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + idl_name_t *name, + void *nodep); + +idl_retcode_t +idl_create_switch_type_spec( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + void *nodep); + +idl_retcode_t +idl_create_case_label( + idl_pstate_t *pstate, + const idl_location_t *location, + void *const_expr, + void *nodep); + +idl_retcode_t +idl_finalize_case( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_case_t *node, + idl_case_label_t *case_labels); + +idl_retcode_t +idl_create_case( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_declarator_t *declarator, + void *nodep); + +idl_retcode_t +idl_finalize_union( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_union_t *node, + idl_case_t *cases); + +idl_retcode_t +idl_create_union( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_switch_type_spec_t *switch_type_spec, + void *nodep); + +idl_retcode_t +idl_create_enumerator( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + void *nodep); + +idl_retcode_t +idl_create_enum( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_enumerator_t *enumerators, + void *nodep); + +idl_retcode_t +idl_create_typedef( + idl_pstate_t *pstate, + const idl_location_t *location, + void *type_spec, + idl_declarator_t *declarators, + void *nodep); + +idl_retcode_t +idl_create_declarator( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + idl_const_expr_t *const_expr, + void *nodep); + +idl_retcode_t +idl_create_annotation_member( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_type_spec_t *type_spec, + idl_declarator_t *declarator, + idl_const_expr_t *default_value, + void *nodep); + +idl_retcode_t +idl_finalize_annotation( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_annotation_t *node, + idl_definition_t *definitions); + +idl_retcode_t +idl_create_annotation( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_name_t *name, + void *nodep); + +idl_retcode_t +idl_finalize_annotation_appl( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_annotation_appl_t *node, + idl_annotation_appl_param_t *parameters); + +idl_retcode_t +idl_create_annotation_appl( + idl_pstate_t *pstate, + const idl_location_t *location, + const idl_annotation_t *annotation, + void *nodep); + +idl_retcode_t +idl_create_annotation_appl_param( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_annotation_member_t *member, + idl_const_expr_t *const_expr, + void *nodep); + +idl_retcode_t +idl_create_base_type( + idl_pstate_t *pstate, + const idl_location_t *location, + idl_mask_t mask, + void *nodep); + +idl_retcode_t +idl_create_inherit_spec( + idl_pstate_t *pstate, + const idl_location_t *location, + void *base, + void *nodep); + +#endif /* TREE_H */ diff --git a/src/idl/src/visit.c b/src/idl/src/visit.c new file mode 100644 index 0000000000..3938df91e6 --- /dev/null +++ b/src/idl/src/visit.c @@ -0,0 +1,277 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "idl/processor.h" + +static idl_accept_t idl_accept(const void *node) +{ + idl_mask_t mask = idl_mask(node); + if ((mask & IDL_SEQUENCE) == IDL_SEQUENCE) + return IDL_ACCEPT_SEQUENCE; + if ((mask & IDL_STRING) == IDL_STRING) + return IDL_ACCEPT_STRING; + if (mask & IDL_INHERIT_SPEC) + return IDL_ACCEPT_INHERIT_SPEC; + if (mask & IDL_SWITCH_TYPE_SPEC) + return IDL_ACCEPT_SWITCH_TYPE_SPEC; + if (!(mask & IDL_DECLARATION)) + return IDL_ACCEPT; + if (mask & IDL_MODULE) + return IDL_ACCEPT_MODULE; + if (mask & IDL_CONST) + return IDL_ACCEPT_CONST; + if (mask & IDL_MEMBER) + return IDL_ACCEPT_MEMBER; + if (mask & IDL_FORWARD) + return IDL_ACCEPT_FORWARD; + if (mask & IDL_CASE) + return IDL_ACCEPT_CASE; + if (mask & IDL_CASE_LABEL) + return IDL_ACCEPT_CASE_LABEL; + if (mask & IDL_ENUMERATOR) + return IDL_ACCEPT_ENUMERATOR; + if (mask & IDL_DECLARATOR) + return IDL_ACCEPT_DECLARATOR; + if (mask & IDL_ANNOTATION) + return IDL_ACCEPT_ANNOTATION; + if (mask & IDL_ANNOTATION_APPL) + return IDL_ACCEPT_ANNOTATION_APPL; + if (mask & IDL_TYPEDEF) + return IDL_ACCEPT_TYPEDEF; + if (mask & IDL_STRUCT) + return IDL_ACCEPT_STRUCT; + if (mask & IDL_UNION) + return IDL_ACCEPT_UNION; + if (mask & IDL_ENUM) + return IDL_ACCEPT_ENUM; + return IDL_ACCEPT; +} + +struct stack { + size_t size; /**< available number of slots */ + size_t depth; /**< number of slots in use */ + idl_path_t path; + uint32_t *flags; +}; + +static const idl_node_t *pop(struct stack *stack) +{ + const idl_node_t *node; + + assert(stack); + assert(stack->depth && stack->depth == stack->path.length); + /* FIXME: implement shrinking the stack */ + stack->path.length = --stack->depth; + node = stack->path.nodes[stack->depth]; + stack->path.nodes[stack->depth] = NULL; + stack->flags[stack->depth] = 0u; + return node; +} + +static const idl_node_t *push(struct stack *stack, const idl_node_t *node) +{ + assert(stack->depth == stack->path.length); + + /* grow stack if necessary */ + if (stack->depth == stack->size) { + size_t size = stack->size + 10; + uint32_t *flags = NULL; + const idl_node_t **nodes = NULL; + if (!(flags = realloc(stack->flags, size*sizeof(*flags)))) + return NULL; + stack->flags = flags; +#if _MSC_VER +__pragma(warning(push)) +__pragma(warning(disable: 4090)) +#endif + if (!(nodes = realloc(stack->path.nodes, size*sizeof(*nodes)))) + return NULL; +#if _MSC_VER +__pragma(warning(pop)) +#endif + stack->path.nodes = nodes; + stack->size = size; + } + + stack->flags[stack->depth] = 0; + stack->path.nodes[stack->depth] = node; + stack->path.length = ++stack->depth; + return node; +} + +#define YES (0) +#define NO (1) +#define MAYBE (2) + +static const uint32_t recurse[] = { + IDL_VISIT_RECURSE, + IDL_VISIT_DONT_RECURSE, + IDL_VISIT_RECURSE|IDL_VISIT_DONT_RECURSE +}; + +#if 0 +static idl_visit_iterate_t iterate[] = { + IDL_VISIT_ITERATE, + IDL_VISIT_DONT_ITERATE, + IDL_VISIT_ITERATE|IDL_VISIT_DONT_ITERATE +}; +#endif + +static const uint32_t revisit[] = { + IDL_VISIT_REVISIT, + IDL_VISIT_DONT_REVISIT, + IDL_VISIT_REVISIT|IDL_VISIT_DONT_REVISIT +}; + +/* visit iteratively to save stack space */ +idl_retcode_t +idl_visit( + const idl_pstate_t *pstate, + const void *node, + const idl_visitor_t *visitor, + void *user_data) +{ + idl_retcode_t ret = IDL_RETCODE_OK; + idl_accept_t accept; + idl_visitor_callback_t callback; + struct stack stack = { 0, 0, { 0, NULL }, NULL }; + uint32_t flags = 0u; + bool walk = true; + + assert(pstate); + assert(node); + assert(visitor); + + flags |= recurse[ visitor->recurse == recurse[NO] ]; +#if 0 + flags |= iterate[ visitor->iterate == iterate[NO] ]; +#endif + flags |= revisit[ visitor->revisit != revisit[YES] ]; + + if (!push(&stack, node)) + goto err_push; + stack.flags[0] = flags; + + while (stack.depth > 0) { + node = stack.path.nodes[stack.depth - 1]; + accept = idl_accept(node); + if (visitor->accept[accept]) + callback = visitor->accept[accept]; + else + callback = visitor->accept[IDL_ACCEPT]; + + if (walk) { + /* skip or visit */ + if (!callback || !(idl_mask(node) & visitor->visit)) { + ret = IDL_RETCODE_OK; + } else if (!visitor->sources) { + if ((ret = callback(pstate, false, &stack.path, node, user_data)) < 0) + goto err_visit; + } else if (visitor->sources) { + const char *source = ((const idl_node_t *)node)->symbol.location.first.source->path->name; + + ret = IDL_RETCODE_OK; + for (size_t i=0; visitor->sources[i]; i++) { + if (strcmp(source, visitor->sources[i]) != 0) + continue; + if ((ret = callback(pstate, false, &stack.path, node, user_data)) < 0) + goto err_visit; + break; + } + } + + /* override default flags */ + if (ret & (idl_retcode_t)recurse[MAYBE]) { + stack.flags[stack.depth - 1] &= ~recurse[MAYBE]; + stack.flags[stack.depth - 1] |= recurse[ ((unsigned)ret & recurse[NO]) != 0 ]; + } +#if 0 + if (ret & (idl_retcode_t)iterate[MAYBE]) { + stack.flags[stack.depth - 1] &= ~iterate[MAYBE]; + stack.flags[stack.depth - 1] |= iterate[ (ret & iterate[NO]) != 0 ]; + } +#endif + if (ret & (idl_retcode_t)revisit[MAYBE]) { + stack.flags[stack.depth - 1] &= ~revisit[MAYBE]; + stack.flags[stack.depth - 1] |= revisit[ ((unsigned)ret & revisit[NO]) != 0 ]; + } + + if (ret & IDL_VISIT_TYPE_SPEC) { + node = idl_type_spec(node); + if (ret & IDL_VISIT_UNALIAS_TYPE_SPEC) + node = idl_unalias(node, IDL_UNALIAS_IGNORE_ARRAY); + assert(node); + if (!push(&stack, node)) + goto err_push; + stack.flags[stack.depth - 1] = flags | IDL_VISIT_TYPE_SPEC; + walk = true; + } else if (stack.flags[stack.depth - 1] & IDL_VISIT_RECURSE) { + node = idl_iterate(node, NULL); + if (node) { + if (!push(&stack, node)) + goto err_push; + stack.flags[stack.depth - 1] = flags; + walk = true; + } else { + walk = false; + } + } else { + walk = false; + } + } else { + if (callback && (stack.flags[stack.depth - 1] & IDL_VISIT_REVISIT)) { + /* callback must exist if revisit is true */ + if ((ret = callback(pstate, true, &stack.path, node, user_data)) < 0) + goto err_revisit; + } +#if 0 + if (stack.flags[stack.depth - 1] & (IDL_VISIT_TYPE_SPEC|IDL_VISIT_DONT_ITERATE)) { +#endif + if (stack.flags[stack.depth - 1] & (IDL_VISIT_TYPE_SPEC)) { + (void)pop(&stack); + } else { + (void)pop(&stack); + if (stack.depth > 0) + node = idl_iterate(stack.path.nodes[stack.depth - 1], node); + else + node = idl_next(node); + if (node) { + if (!push(&stack, node)) + goto err_push; + stack.flags[stack.depth - 1] = flags; + walk = true; + } + } + } + } + +#if _MSC_VER +__pragma(warning(push)) +__pragma(warning(disable: 4090)) +#endif + if (stack.flags) free(stack.flags); + if (stack.path.nodes) free(stack.path.nodes); + return IDL_RETCODE_OK; +err_push: + ret = IDL_RETCODE_NO_MEMORY; +err_visit: +err_revisit: + if (stack.flags) free(stack.flags); + if (stack.path.nodes) free(stack.path.nodes); + return ret; +#if _MSC_VER +__pragma(warning(pop)) +#endif +} diff --git a/src/tools/idlc/tests/CMakeLists.txt b/src/idl/tests/CMakeLists.txt similarity index 67% rename from src/tools/idlc/tests/CMakeLists.txt rename to src/idl/tests/CMakeLists.txt index 0d84e4ec3c..98885f5521 100644 --- a/src/tools/idlc/tests/CMakeLists.txt +++ b/src/idl/tests/CMakeLists.txt @@ -11,5 +11,17 @@ # include(CUnit) -add_cunit_executable(cunit_idlc "parser.c" "gen_C99.c" "scanner.c") -target_link_libraries(cunit_idlc PRIVATE idlc-lib) +add_cunit_executable(cunit_idl + file.c + scanner.c + annotation.c + expression.c + inheritance.c + parser.c + typedef.c + union.c + enum.c + pragma.c + module.c) + +target_link_libraries(cunit_idl PRIVATE idl) diff --git a/src/idl/tests/annotation.c b/src/idl/tests/annotation.c new file mode 100644 index 0000000000..e1cbb86f1a --- /dev/null +++ b/src/idl/tests/annotation.c @@ -0,0 +1,391 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "hashid.h" +#include "tree.h" +#include "idl/processor.h" + +#include "CUnit/Test.h" + +CU_Test(idl_hashid, color) +{ + uint32_t id = idl_hashid("color"); + CU_ASSERT_EQUAL(id, 0x0fa5dd70u); +} + +CU_Test(idl_hashid, shapesize) +{ + uint32_t id = idl_hashid("shapesize"); + CU_ASSERT_EQUAL(id, 0x047790dau); +} + +static idl_retcode_t +parse_string(uint32_t flags, const char *str, idl_pstate_t **pstatep) +{ + idl_pstate_t *pstate = NULL; + idl_retcode_t ret; + + if ((ret = idl_create_pstate(flags, NULL, &pstate)) != IDL_RETCODE_OK) + return ret; + ret = idl_parse_string(pstate, str); + if (ret != IDL_RETCODE_OK) + idl_delete_pstate(pstate); + else + *pstatep = pstate; + return ret; +} + +CU_Test(idl_annotation, id_member) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_struct_t *s; + idl_member_t *c; + const char str[] = "struct s { @id(1) @optional char c; };"; + + ret = parse_string(IDL_FLAG_ANNOTATIONS, str, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + s = (idl_struct_t *)pstate->root; + CU_ASSERT_PTR_NOT_NULL_FATAL(s); + CU_ASSERT_FATAL(idl_is_struct(s)); + c = (idl_member_t *)s->members; + CU_ASSERT_PTR_NOT_NULL(c); + CU_ASSERT_FATAL(idl_is_member(c)); + CU_ASSERT_EQUAL(c->id.annotation, IDL_ID); + CU_ASSERT_EQUAL(c->id.value, 1); + idl_delete_pstate(pstate); +} + +CU_Test(idl_annotation, key) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_struct_t *s; + idl_member_t *m; + const char str[] = "struct s {\n" + " @key char a;\n" + " @key(TRUE) char b;\n" + " @key(FALSE) char c;\n" + " char d;\n" + "};"; + + ret = parse_string(IDL_FLAG_ANNOTATIONS, str, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + s = (idl_struct_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_struct(s)); + m = (idl_member_t *)s->members; + CU_ASSERT_FATAL(idl_is_member(m)); + CU_ASSERT_EQUAL(m->key, IDL_TRUE); + m = idl_next(m); + CU_ASSERT_FATAL(idl_is_member(m)); + CU_ASSERT_EQUAL(m->key, IDL_TRUE); + m = idl_next(m); + CU_ASSERT_FATAL(idl_is_member(m)); + CU_ASSERT_EQUAL(m->key, IDL_FALSE); + m = idl_next(m); + CU_ASSERT_FATAL(idl_is_member(m)); + CU_ASSERT_EQUAL(m->key, IDL_DEFAULT); + idl_delete_pstate(pstate); +} + +CU_Test(idl_annotation, nested) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_struct_t *s; + const char str[] = "struct s1 { char c; };\n" + "@nested struct s2 { char c; };\n" + "@nested(TRUE) struct s3 { char c; };\n" + "@nested(FALSE) struct s4 { char c; };"; + + ret = parse_string(IDL_FLAG_ANNOTATIONS, str, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + s = (idl_struct_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_EQUAL(s->nested.annotation, IDL_DEFAULT_NESTED); + CU_ASSERT(s->nested.value == false); + s = idl_next(s); + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_EQUAL(s->nested.annotation, IDL_NESTED); + CU_ASSERT(s->nested.value == true); + s = idl_next(s); + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_EQUAL(s->nested.annotation, IDL_NESTED); + CU_ASSERT(s->nested.value == true); + s = idl_next(s); + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_EQUAL(s->nested.annotation, IDL_NESTED); + CU_ASSERT(s->nested.value == false); + idl_delete_pstate(pstate); +} + +#define M(name, definitions) " module " name " { " definitions " }; " +#define S(name) " struct " name " { char c; }; " + +#define DN(...) " @default_nested " __VA_ARGS__ +#define N(...) " @nested " __VA_ARGS__ +#define T(...) " @topic " __VA_ARGS__ +#define P(platform) " (platform = \"" platform "\") " + +#define YES " (TRUE) " +#define NO " (FALSE) " + +CU_Test(idl_annotation, topic) +{ + static const struct { + const char *s; + idl_nested_t n; + } tests[] = { + { S("s1"), {0,0} }, + { N() S("s1"), {1,1} }, + { T() S("s1"), {2,0} }, + { T() N() S("s1"), {2,0} }, + { T(P("!DDS")) S("s1"), {0,0} }, + { T(P("DDS")) S("s1"), {2,0} }, + { T(P("!DDS")) N() S("s1"), {1,1} } + }; + + static const size_t n = sizeof(tests)/sizeof(tests[0]); + + idl_retcode_t ret; + idl_pstate_t *pstate; + idl_struct_t *s; + + for (size_t i=0; i < n; i++) { + pstate = NULL; + ret = parse_string(IDL_FLAG_ANNOTATIONS, tests[i].s, &pstate); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_OK); + if (ret == IDL_RETCODE_OK) { + s = (idl_struct_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT(memcmp(&s->nested, &tests[i].n, sizeof(s->nested)) == 0); + } + idl_delete_pstate(pstate); + } +} + +CU_Test(idl_annotation, default_nested) +{ + static const struct { + const char *str; + idl_boolean_t dn[3]; + idl_nested_t n[2]; + } tests[] = { + { M("m1", M("m2", S("s1")) M("m3", S("s2"))), {0,0,0}, {{0,0},{0,0}} }, + { DN() M("m1", M("m2", S("s1")) M("m3", S("s2"))), {2,0,0}, {{0,1},{0,1}} }, + { DN() M("m1", DN(NO) M("m2", S("s1")) M("m3", S("s2"))), {2,1,0}, {{0,0},{0,1}} }, + { DN(NO) M("m1", DN(YES) M("m2", S("s1")) M("m3", S("s2"))), {1,2,0}, {{0,1},{0,0}} }, + { DN(YES) M("m1", M("m2", N(NO) S("s1")) M("m3", S("s2"))), {2,0,0}, {{1,0},{0,1}} } + }; + + static const size_t n = sizeof(tests)/sizeof(tests[0]); + + idl_retcode_t ret; + idl_pstate_t *pstate; + idl_module_t *m; + idl_struct_t *s; + + for (size_t i=0; i < n; i++) { + pstate = NULL; + ret = parse_string(IDL_FLAG_ANNOTATIONS, tests[i].str, &pstate); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_OK); + if (ret == IDL_RETCODE_OK) { + m = (idl_module_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_module(m)); + CU_ASSERT_EQUAL(m->default_nested, tests[i].dn[0]); + m = m->definitions; + CU_ASSERT_FATAL(idl_is_module(m)); + CU_ASSERT_EQUAL(m->default_nested, tests[i].dn[1]); + s = m->definitions; + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT(memcmp(&s->nested, &tests[i].n[0], sizeof(s->nested)) == 0); + m = idl_next(m); + CU_ASSERT_FATAL(idl_is_module(m)); + CU_ASSERT_EQUAL(m->default_nested, tests[i].dn[2]); + s = m->definitions; + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT(memcmp(&s->nested, &tests[i].n[1], sizeof(s->nested)) == 0); + } + idl_delete_pstate(pstate); + } +} + +#define ok IDL_RETCODE_OK +#define semantic_error IDL_RETCODE_SEMANTIC_ERROR + +static struct { + idl_retcode_t ret; + const char *str; +} redef[] = { + { ok, "@annotation foo { boolean bar default TRUE; };" + "@annotation foo { boolean bar default TRUE; };" }, + { semantic_error, "@annotation foo { boolean bar default TRUE; };" + "@annotation foo { boolean bar default FALSE; };" }, + { semantic_error, "@annotation foo { boolean bar default TRUE; };" + "@annotation foo { boolean bar; };" } +}; + +CU_Test(idl_annotation, redefinition) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + static const size_t n = sizeof(redef)/sizeof(redef[0]); + + for (size_t i = 0; i < n; i++) { + pstate = NULL; + ret = parse_string(IDL_FLAG_ANNOTATIONS, redef[i].str, &pstate); + CU_ASSERT_EQUAL(ret, redef[i].ret); + if (ret == IDL_RETCODE_OK) { + CU_ASSERT_PTR_NOT_NULL(pstate); + CU_ASSERT_PTR_NOT_NULL(pstate->builtin_root); + } + idl_delete_pstate(pstate); + } +} + +// x. do not allow annotation_appl in annotation + +#if 0 +CU _ Test(idl_annotation, id_non_member) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + const char str[] = "@id(1) struct s { char c; };"; + + ret = idl_parse_string(str, IDL_FLAG_ANNOTATIONS, &tree); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SEMANTIC_ERROR); + idl_delete_tree(tree); +} + +CU _ Test(idl_annotation, hashid_member) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + idl_struct_t *s; + idl_member_t *m; + const char str[] = "struct s { @hashid char color; @hashid(\"shapesize\") char size; };"; + + ret = idl_parse_string(str, IDL_FLAG_ANNOTATIONS, &tree); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(tree); + s = (idl_struct_t *)tree->root; + CU_ASSERT_PTR_NOT_NULL_FATAL(s); + CU_ASSERT_FATAL(idl_is_struct(s)); + m = s->members; + CU_ASSERT_PTR_NOT_NULL(m); + CU_ASSERT_FATAL(idl_is_member(m)); + CU_ASSERT_EQUAL(m->id, 0x0fa5dd70u); + m = idl_next(m); + CU_ASSERT_PTR_NOT_NULL(m); + CU_ASSERT_FATAL(idl_is_member(m)); + CU_ASSERT_EQUAL(m->id, 0x047790dau); + idl_delete_tree(tree); +} + +// x. @hashid on non-member +// x. @id without const_expr +// x. both @id and @hashid +// x. @id twice +// x. @hashid twice + +CU _ Test(idl_annotation, autoid_struct) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + idl_struct_t *s1; + const char str[] = "@autoid struct s { char c; };"; + + ret = idl_parse_string(str, IDL_FLAG_ANNOTATIONS, &tree); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(tree); + s1 = (idl_struct_t *)tree->root; + CU_ASSERT_PTR_NOT_NULL_FATAL(s1); + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT_EQUAL(s1->autoid, IDL_AUTOID_SEQUENTIAL); + idl_delete_tree(tree); +} + +// x. autoid twice +// x. autoid (HASH) +// x. autoid (SEQUENTIAL) + +// x. @extensibility(FINAL) +// x. @extensibility(APPENDABLE) +// x. @extensibility(MUTABLE) + +CU _ Test(idl_annotation, final_struct) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + idl_struct_t *s; + const char str[] = "@final struct s { char c; };"; + + ret = idl_parse_string(str, IDL_FLAG_ANNOTATIONS, &tree); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(tree); + s = (idl_struct_t *)tree->root; + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_EQUAL(s->extensibility, IDL_EXTENSIBILITY_FINAL); + idl_delete_tree(tree); +} + +CU _ Test(idl_annotation, appendable_struct) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + idl_struct_t *s; + const char str[] = "@appendable struct s { char c; };"; + + ret = idl_parse_string(str, IDL_FLAG_ANNOTATIONS, &tree); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(tree); + s = (idl_struct_t *)tree->root; + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_EQUAL(s->extensibility, IDL_EXTENSIBILITY_APPENDABLE); + idl_delete_tree(tree); +} + +CU _ Test(idl_annotation, mutable_struct) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + idl_struct_t *s; + const char str[] = "@mutable struct s { char c; };"; + + ret = idl_parse_string(str, IDL_FLAG_ANNOTATIONS, &tree); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(tree); + s = (idl_struct_t *)tree->root; + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_EQUAL(s->extensibility, IDL_EXTENSIBILITY_MUTABLE); + idl_delete_tree(tree); +} + +CU _ Test(idl_annotation, foobar_struct) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + idl_struct_t *s; + const char str[] = "@foobar struct s { char c; };"; + + ret = idl_parse_string(str, IDL_FLAG_ANNOTATIONS, &tree); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(tree); + s = (idl_struct_t *)tree->root; + CU_ASSERT_FATAL(idl_is_struct(s)); + idl_delete_tree(tree); +} +#endif diff --git a/src/idl/tests/enum.c b/src/idl/tests/enum.c new file mode 100644 index 0000000000..642405b832 --- /dev/null +++ b/src/idl/tests/enum.c @@ -0,0 +1,128 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "idl/processor.h" + +#include "CUnit/Test.h" + +CU_Test(idl_enum, no_enumerator) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + const char str[] = "enum foo { };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SYNTAX_ERROR); + CU_ASSERT_PTR_NULL(pstate->root); + idl_delete_pstate(pstate); +} + +CU_Test(idl_enum, duplicate_enumerators) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + const char str[] = "enum foo { bar, bar };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SEMANTIC_ERROR); + CU_ASSERT_PTR_NULL(pstate->root); + idl_delete_pstate(pstate); +} + +CU_Test(idl_enum, enumerator_matches_enum) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + const char str[] = "enum foo { foo };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SEMANTIC_ERROR); + CU_ASSERT_PTR_NULL(pstate->root); + idl_delete_pstate(pstate); +} + +#if 0 +CU _ Test(idl_enum, enumerator_used_name) +{ + idl_retcode_t ret; + idl_tree_t *tree = NULL; + + const char str[] = "struct s { char c; }; enum e { e1 };"; + ret = idl_parse_string(str, 0u, &tree); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SEMANTIC_ERROR); + CU_ASSERT_PTR_NULL(tree); + idl_delete_tree(tree); +} +#endif + +CU_Test(idl_enum, single_enumerator) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_enum_t *e; + idl_enumerator_t *er; + + const char str[] = "enum foo { bar };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_OK); + e = (idl_enum_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_enum(e)); + er = (idl_enumerator_t *)e->enumerators; + CU_ASSERT_FATAL(idl_is_enumerator(er)); + CU_ASSERT_PTR_NOT_NULL_FATAL(idl_identifier(er)); + CU_ASSERT_STRING_EQUAL(idl_identifier(er), "bar"); + CU_ASSERT_PTR_EQUAL(idl_parent(er), e); + idl_delete_pstate(pstate); +} + +CU_Test(idl_enum, multiple_enumerators) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_enum_t *e; + idl_enumerator_t *er; + + const char str[] = "enum foo { bar, baz };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_OK); + e = (idl_enum_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_enum(e)); + er = (idl_enumerator_t *)e->enumerators; + CU_ASSERT_FATAL(idl_is_enumerator(er)); + CU_ASSERT_PTR_NOT_NULL_FATAL(idl_identifier(er)); + CU_ASSERT_STRING_EQUAL(idl_identifier(er), "bar"); + CU_ASSERT_PTR_EQUAL(idl_parent(er), e); + er = idl_next(er); + CU_ASSERT_FATAL(idl_is_enumerator(er)); + CU_ASSERT_PTR_NOT_NULL_FATAL(idl_identifier(er)); + CU_ASSERT_STRING_EQUAL(idl_identifier(er), "baz"); + CU_ASSERT_PTR_EQUAL(idl_parent(er), e); + idl_delete_pstate(pstate); +} diff --git a/src/idl/tests/expression.c b/src/idl/tests/expression.c new file mode 100644 index 0000000000..c640f15c14 --- /dev/null +++ b/src/idl/tests/expression.c @@ -0,0 +1,150 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#include "idl/processor.h" +#include "idl/retcode.h" +#include "idl/tree.h" +#include "expression.h" +#include "tree.h" + +#include "CUnit/Test.h" + +#define SYMBOL { \ + .location = { { NULL, NULL, 0, 0 }, { NULL, NULL, 0, 0 } } \ + } + +#define NODE(type) { \ + .symbol = SYMBOL, \ + .mask = (IDL_LITERAL|type), \ + .destructor = 0, \ + .iterate = 0, \ + .describe = 0, \ + .references = 0, \ + .annotations = NULL, \ + .declaration = NULL, \ + .parent = NULL, \ + .previous = NULL, \ + .next = NULL \ + } + +#define LITERAL(type, assignment) \ + (idl_literal_t){ .node = NODE(type), .value = { assignment } } + +#define CHAR(value) LITERAL(IDL_CHAR, .chr = (value)) +#define BOOL(value) LITERAL(IDL_BOOL, .bln = (value)) +#define OCTET(value) LITERAL(IDL_OCTET, .uint8 = (value)) +#define SHORT(value) LITERAL(IDL_SHORT, .int16 = (value)) +#define USHORT(value) LITERAL(IDL_USHORT, .uint16 = (value)) +#define LONG(value) LITERAL(IDL_LONG, .int32 = (value)) +#define ULONG(value) LITERAL(IDL_ULONG, .uint32 = (value)) +#define LLONG(value) LITERAL(IDL_LLONG, .int64 = (value)) +#define ULLONG(value) LITERAL(IDL_ULLONG, .uint64 = (value)) +#define INT8(value) LITERAL(IDL_INT8, .int8 = (value)) +#define UINT8(value) LITERAL(IDL_UINT8, .uint8 = (value)) +#define INT16(value) LITERAL(IDL_INT16, .int16 = (value)) +#define UINT16(value) LITERAL(IDL_UINT16, .uint16 = (value)) +#define INT32(value) LITERAL(IDL_INT32, .int32 = (value)) +#define UINT32(value) LITERAL(IDL_UINT32, .uint32 = (value)) +#define INT64(value) LITERAL(IDL_INT64, .int64 = (value)) +#define UINT64(value) LITERAL(IDL_UINT64, .uint64 = (value)) + +static void +test_expr( + const char *str, + const idl_retcode_t ret, + const idl_literal_t *exp) +{ + idl_retcode_t r; + idl_pstate_t *pstate = NULL; + idl_const_t *c; + idl_literal_t *cv; + + r = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(r, IDL_RETCODE_OK); + r = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(r, ret); + if (r != IDL_RETCODE_OK) { + idl_delete_pstate(pstate); + return; + } + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + c = (void *)pstate->root; + do { + if (idl_is_const(c) && strcmp(idl_identifier(c), "x") == 0) + break; + c = idl_next(c); + } while (c); + CU_ASSERT_FATAL(idl_is_const(c)); + cv = c->const_expr; + CU_ASSERT_FATAL(idl_is_literal(cv)); + CU_ASSERT(idl_compare(pstate, cv, exp) == IDL_EQUAL); + idl_delete_pstate(pstate); +} + +#define ok (IDL_RETCODE_OK) +#define semantic_error (IDL_RETCODE_SEMANTIC_ERROR) +#define illegal_expression (IDL_RETCODE_ILLEGAL_EXPRESSION) +#define out_of_range (IDL_RETCODE_OUT_OF_RANGE) + +struct expr { + const char *str; + const idl_retcode_t ret; + const idl_literal_t *val; +}; + +#define x "const char x" +static struct expr chr_exprs[] = { + { x " = 'c';", ok, &CHAR('c') }, + { x " = '\\n';", ok, &CHAR('\n') }, + { x " = \"c\";", illegal_expression, NULL } +}; +#undef x + +CU_Test(idl_expression, character) +{ + const size_t n = (sizeof(chr_exprs)/sizeof(chr_exprs[0])); + for (size_t i=0; i < n; i++) + test_expr(chr_exprs[i].str, chr_exprs[i].ret, chr_exprs[i].val); +} + +#define x "const octet x" +#define y "const octet y" +static struct expr oct_exprs[] = { + { x " = +1;", ok, &OCTET(1) }, + { x " = -1;", out_of_range, NULL }, + { x " = -1 - -1;", ok, &OCTET(0) }, + { x " = -1 * -1;", ok, &OCTET(1) }, + { x " = (65535 * 0) / 1;", ok, &OCTET(0) }, + { x " = (65535 * 1) / 65535;", ok, &OCTET(1) }, + { y " = 1; " x " = y;", ok, &OCTET(1) }, + { x " = 1 - 2;", out_of_range, NULL }, + { x " = 255;", ok, &OCTET(255) }, + { x " = 256;", out_of_range, NULL }, + { x " = 256 - 1;", ok, &OCTET(255) }, + { x " = 1 << 1;", ok, &OCTET(2) }, + { x " = 1 >> 1;", ok, &OCTET(0) } +}; +#undef x +#undef y + +CU_Test(idl_expression, octet) +{ + const size_t n = (sizeof(oct_exprs)/sizeof(oct_exprs[0])); + for (size_t i=0; i < n; i++) + test_expr(oct_exprs[i].str, oct_exprs[i].ret, oct_exprs[i].val); +} diff --git a/src/idl/tests/file.c b/src/idl/tests/file.c new file mode 100644 index 0000000000..e374931083 --- /dev/null +++ b/src/idl/tests/file.c @@ -0,0 +1,320 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "idl/string.h" +#include "file.h" + +#include "CUnit/Theory.h" + +#define ok (IDL_RETCODE_OK) +#define bad_param (IDL_RETCODE_BAD_PARAMETER) + +#if _WIN32 +# define ROOT "C:\\" +# define SEP "\\" +#else +# define ROOT "/" +# define SEP "/" +#endif + +static char *prefix = NULL; + +CU_Init(idl_file) +{ + idl_current_path(&prefix); + return 0; +} + +CU_Clean(idl_file) +{ + if (prefix) + free(prefix); + return 0; +} + +struct scrub_test { + const char *input; + const char *output; + const char length; +}; + +const struct scrub_test tests[] = { + { ROOT "..", "", -1 }, + { ROOT "/..", "", -1 }, + { ROOT "//..", "", -1 }, + { ROOT "a/../..", "", -1 }, + { ROOT "/a//..//..", "", -1 }, + { ROOT "//a///..///..", "", -1 }, + { "", "", 0 }, + { ".", "", 0 }, + { "./", "", 0 }, + { ".//", "", 0 }, + { ".///", "", 0 }, + { "././", "", 0 }, + { ".//.//", "", 0 }, + { ".///.///", "", 0 }, + { "..", "..", 2 }, + { "../", "..", 2 }, + { "..//", "..", 2 }, + { "..///", "..", 2 }, + { "./..", "..", 2 }, + { ".//..", "..", 2 }, + { ".///..", "..", 2 }, + { ".///..///", "..", 2 }, + { "../..", ".." SEP "..", 5 }, + { "..//..", ".." SEP "..", 5 }, + { "..///..", ".." SEP "..", 5 }, + { "../../../", ".." SEP ".." SEP "..", 8 }, + { ROOT , ROOT, 1 }, + { ROOT "/", ROOT, 1 }, + { ROOT "//", ROOT, 1 }, + { ROOT ".", ROOT, 1 }, + { ROOT "/.", ROOT, 1 }, + { ROOT "//.", ROOT, 1 }, + { ROOT "./", ROOT, 1 }, + { ROOT "/.//", ROOT, 1 }, + { ROOT "//.///", ROOT, 1 }, + { "a/..", "", 0 }, + { "a//..", "", 0 }, + { "a///..", "", 0 }, + { "a/b/../..", "", 0 }, + { "a//b//..//..", "", 0 }, + { "a///b///..///..", "", 0 }, + { "a/../b/..", "", 0 }, + { "a//..//b//..", "", 0 }, + { "a///..///b///..", "", 0 }, + { "a/./.././b", "b", 1 }, + { "a//.//..//.//b", "b", 1 }, + { "a///.///..///.///b", "b", 1 }, + { "ab/./.././cd", "cd", 2 }, + { "ab//.//..//.//cd", "cd", 2 }, + { "ab///.///..///.///cd", "cd", 2 }, + { "abc/./.././def", "def", 3 }, + { "abc//.//..//.//def", "def", 3 }, + { "abc///.///..///.///def", "def", 3 }, + { ROOT "a/..", ROOT, 1 }, + { ROOT "/a//..", ROOT, 1 }, + { ROOT "//a///..", ROOT, 1 }, + { ROOT "a/b/../..", ROOT, 1 }, + { ROOT "/a//b//..//..", ROOT, 1 }, + { ROOT "//a///b///..///..", ROOT, 1 }, + { ROOT "a/../b/..", ROOT, 1 }, + { ROOT "/a//..//b//..", ROOT, 1 }, + { ROOT "//a///..///b///..", ROOT, 1 }, + { ROOT "ab/./.././cd", ROOT "cd", 3 }, + { ROOT "/ab//.//..//.//cd", ROOT "cd", 3 }, + { ROOT "//ab///.///..///.///cd", ROOT "cd", 3 }, + { ROOT "abc/./.././def", ROOT "def", 4 }, + { ROOT "/abc//.//..//.//def", ROOT "def", 4 }, + { ROOT "//abc///.///..///.///def", ROOT "def", 4 } +}; + +/* FIXME: add Windows-specific tests */ + +CU_Test(idl_file, untaint) +{ + const size_t n = sizeof(tests) / sizeof(tests[0]); + + for (size_t i=0; i < n; i++) { + char *str; + ssize_t len; + + str = idl_strdup(tests[i].input); + CU_ASSERT_PTR_NOT_NULL_FATAL(str); + fprintf(stderr, "input: '%s'\n", str); + len = idl_untaint_path(str); + if (tests[i].length == -1) { + CU_ASSERT_EQUAL(len, -1); + } else { + CU_ASSERT_EQUAL(len, (ssize_t)strlen(tests[i].output)); + } + if (len >= 0) { + fprintf(stderr, "output: '%s'\n", str); + CU_ASSERT_STRING_EQUAL(str, tests[i].output); + } + free(str); + } +} + +CU_Test(idl_file, normalize_empty) +{ + idl_retcode_t ret; + char *norm = NULL; + + ret = idl_normalize_path("", &norm); + CU_ASSERT_FATAL(ret >= 0); + CU_ASSERT_PTR_NOT_NULL_FATAL(norm); + fprintf(stderr, "path: %s\nexpect: %s\nnormalized: %s\n", prefix, prefix, norm); + CU_ASSERT_STRING_EQUAL(norm, prefix); + free(norm); +} + +CU_Test(idl_file, normalize_revert) +{ + idl_retcode_t ret; + char *norm = NULL, *path = NULL; + + idl_asprintf(&path, "%s/..", prefix); + CU_ASSERT_PTR_NOT_NULL_FATAL(path); + ret = idl_normalize_path(path, &norm); + CU_ASSERT_FATAL(ret >= 0); + CU_ASSERT_PTR_NOT_NULL_FATAL(norm); + fprintf(stderr, "path: %s\n", path); + { size_t sep = 0; + for (size_t i=0,n=strlen(prefix); i < n; i++) { + if (idl_isseparator(path[i])) + sep = i; + } + CU_ASSERT_NOT_EQUAL_FATAL(sep, 0); + path[sep] = '\0'; + } + fprintf(stderr, "expect: %s\nnormalized: %s\n", path, norm); + CU_ASSERT_STRING_EQUAL(path, norm); + free(path); + free(norm); +} + +CU_Test(idl_file, normalize_revert_too_many) +{ + idl_retcode_t ret; + size_t size, step, steps = 1; /* one too many */ + char *revert = NULL, *path = NULL, *norm = NULL; + + fprintf(stderr, "prefix: %s\n", prefix); + + for (size_t i=0; prefix[i]; i++) + steps += idl_isseparator(prefix[i]); + + step = sizeof("/..") - 1; + size = steps * step; + revert = malloc(size + 1); + CU_ASSERT_PTR_NOT_NULL_FATAL(revert); + for (size_t i=0; i < steps; i++) + memcpy(revert + (i*step), "/..", step); + revert[size] = '\0'; + + fprintf(stderr, "revert: %s\n", revert); + + path = NULL; + idl_asprintf(&path, "%s%s", prefix, revert); + CU_ASSERT_PTR_NOT_NULL_FATAL(path); + + fprintf(stderr, "path: %s\n", path); + + norm = NULL; + ret = idl_normalize_path(path, &norm); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_BAD_PARAMETER); + CU_ASSERT_PTR_NULL(norm); + free(revert); + free(path); + if (norm) + free(norm); +} + +struct relative_test { + const char *base; + const char *path; + const char *relpath; + idl_retcode_t retcode; +}; + +static struct relative_test relative_bad_params_tests[] = { + /* test absolute, fully resolved, paths are required */ + { "", ROOT "foo", NULL, bad_param }, + { ".", ROOT "foo", NULL, bad_param }, + { "./", ROOT "foo", NULL, bad_param }, + { ROOT ".", ROOT "foo", NULL, bad_param }, + { ROOT "./", ROOT "foo", NULL, bad_param }, + { "./foo/bar", ROOT "foo", NULL, bad_param }, + { ROOT "foo/./bar", ROOT "foo", NULL, bad_param }, + { ROOT "foo/bar/.", ROOT "foo", NULL, bad_param }, + { "..", ROOT "foo", NULL, bad_param }, + { "../", ROOT "foo", NULL, bad_param }, + { ROOT "..", ROOT "foo", NULL, bad_param }, + { "../foo/bar", ROOT "foo", NULL, bad_param }, + { ROOT "foo/../bar", ROOT "foo", NULL, bad_param }, + { ROOT "foo/bar/..", ROOT "foo", NULL, bad_param } +}; + +CU_Test(idl_file, relative_bad_params) +{ + idl_retcode_t ret; + char *rel; + + struct relative_test *t = relative_bad_params_tests; + size_t n = sizeof(relative_bad_params_tests)/sizeof(relative_bad_params_tests[0]); + + for (size_t i=0; i < n; i++) { + const char *base, *path; + for (size_t j=0; j < 2; j++) { + rel = NULL; + base = j ? t[i].path : t[i].base; + path = j ? t[i].base : t[i].path; + fprintf(stderr, "base: %s\n", base); + fprintf(stderr, "path: %s\n", path); + ret = idl_relative_path(base, path, &rel); + fprintf(stderr, "relative: %s\n", rel ? rel : "-"); + if (rel) + free(rel); + CU_ASSERT_EQUAL_FATAL(ret, bad_param); + CU_ASSERT_PTR_NULL(rel); + } + } +} + +static struct relative_test relative_tests[] = { + { ROOT "", ROOT "", "", ok }, + { ROOT "f/o/o", ROOT "", ".." SEP ".." SEP "..", ok }, + { ROOT "", ROOT "f/o/o", "f" SEP "o" SEP "o", ok }, + { ROOT "f/o/o", ROOT "b/a/r", ".." SEP ".." SEP ".." SEP "b" SEP "a" SEP "r", ok }, + { ROOT "f/o/o", ROOT "f/o", "..", ok }, + { ROOT "f/oo", ROOT "f/o", ".." SEP "o", ok }, + { ROOT "f/o", ROOT "f/o", "", ok }, + { ROOT "f/o", ROOT "f/oo", ".." SEP "oo", ok }, + { ROOT "f/o", ROOT "f/o/o", "o", ok }, + { ROOT "foo/bar", ROOT "foo/baz", ".." SEP "baz", ok }, + { ROOT "f//o///o////", ROOT "f////o///o//", "", ok }, + { ROOT "f/o//o///", ROOT "f///o//o/", "", ok }, + { ROOT "b/a//r///", ROOT "b/a/r", "", ok }, + { ROOT "b//a//r", ROOT "b/a/r", "", ok }, + { ROOT "b/a//r///", ROOT "b/a/z", ".." SEP "z", ok } +}; + +CU_Test(idl_file, relative) +{ + idl_retcode_t ret; + char *rel; + + struct relative_test *t = relative_tests; + size_t n = sizeof(relative_tests)/sizeof(relative_tests[0]); + + for (size_t i=0; i < n; i++) { + rel = NULL; + fprintf(stderr, "base: '%s'\n", t[i].base); + fprintf(stderr, "path: '%s'\n", t[i].path); + ret = idl_relative_path(t[i].base, t[i].path, &rel); + CU_ASSERT_EQUAL(ret, t[i].retcode); + if (rel) + fprintf(stderr, "relative: '%s'\n", rel); + if (t[i].relpath) { + CU_ASSERT_PTR_NOT_NULL_FATAL(rel); + CU_ASSERT_STRING_EQUAL(t[i].relpath, rel); + } else { + CU_ASSERT_PTR_NULL(rel); + } + if (rel) + free(rel); + } +} diff --git a/src/idl/tests/inheritance.c b/src/idl/tests/inheritance.c new file mode 100644 index 0000000000..d201ab75c7 --- /dev/null +++ b/src/idl/tests/inheritance.c @@ -0,0 +1,42 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "idl/processor.h" + +#include "CUnit/Test.h" + +CU_Test(idl_inheritance, base_struct) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_struct_t *s1, *s2; + + const char str[] = "struct s1 { char c; }; struct s2 : s1 { octet o; };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate->root); + s1 = (idl_struct_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT_STRING_EQUAL(idl_identifier(s1), "s1"); + s2 = idl_next(s1); + CU_ASSERT_FATAL(idl_is_struct(s2)); + CU_ASSERT_STRING_EQUAL(idl_identifier(s2), "s2"); + CU_ASSERT_PTR_NOT_NULL_FATAL(s2->inherit_spec); + CU_ASSERT_PTR_EQUAL(s2->inherit_spec->base, s1); + idl_delete_pstate(pstate); +} diff --git a/src/idl/tests/module.c b/src/idl/tests/module.c new file mode 100644 index 0000000000..8f4442df3f --- /dev/null +++ b/src/idl/tests/module.c @@ -0,0 +1,91 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "idl/processor.h" + +#include "CUnit/Test.h" + +CU_Test(idl_module, reopen) +{ + idl_retcode_t ret; + idl_pstate_t* pstate = NULL; + + const char str[] = + "module m1 {\n"\ + " struct s1 {\n"\ + " long l;\n"\ + " };\n"\ + "};\n"\ + "module m1 {\n"\ + " struct s2 {\n"\ + " m1::s1 m_s1;\n"\ + " };\n"\ + "};\n"; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + + idl_module_t* m1 = (idl_module_t*)pstate->root; + CU_ASSERT_FATAL(idl_is_module(m1)); + CU_ASSERT_STRING_EQUAL(m1->name->identifier, "m1"); + + idl_struct_t *s1 = (idl_struct_t*)m1->definitions; + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT_PTR_EQUAL(s1->node.parent, m1); + CU_ASSERT_PTR_NULL_FATAL(s1->inherit_spec); + + idl_member_t* mem1 = s1->members; + CU_ASSERT_PTR_NOT_NULL_FATAL(mem1); + CU_ASSERT_PTR_EQUAL(s1,mem1->node.parent); + CU_ASSERT((idl_mask(mem1->type_spec) & IDL_LONG) == IDL_LONG); + CU_ASSERT(!mem1->key); + + idl_declarator_t* decl1 = mem1->declarators; + CU_ASSERT_PTR_NOT_NULL_FATAL(decl1); + CU_ASSERT_PTR_NULL(decl1->node.next); + CU_ASSERT_STRING_EQUAL(decl1->name->identifier, "l"); + CU_ASSERT_EQUAL(idl_array_size(decl1), 0); + + idl_module_t* m2 = (idl_module_t*)m1->node.next; + CU_ASSERT_FATAL(idl_is_module(m2)); + CU_ASSERT_STRING_EQUAL(m2->name->identifier, "m1"); +#if 0 + /* see comment in idl_create_module in tree.c */ + CU_ASSERT_PTR_EQUAL(m2->previous, m1); +#endif + + idl_struct_t* s2 = (idl_struct_t*)m2->definitions; + CU_ASSERT_FATAL(idl_is_struct(s2)); + CU_ASSERT_PTR_EQUAL(s2->node.parent, m2); + CU_ASSERT_PTR_NULL_FATAL(s2->inherit_spec); + + idl_member_t* mem2 = s2->members; + CU_ASSERT_PTR_NOT_NULL_FATAL(mem2); + CU_ASSERT_PTR_EQUAL(s2, mem2->node.parent); + CU_ASSERT_PTR_EQUAL(mem2->type_spec, s1); + CU_ASSERT(!mem2->key); + + idl_declarator_t* decl2 = mem2->declarators; + CU_ASSERT_PTR_NOT_NULL_FATAL(decl2); + CU_ASSERT_PTR_NULL(decl2->node.next); + CU_ASSERT_STRING_EQUAL(decl2->name->identifier, "m_s1"); + CU_ASSERT_EQUAL(idl_array_size(decl2), 0); + + idl_delete_pstate(pstate); +} diff --git a/src/idl/tests/parser.c b/src/idl/tests/parser.c new file mode 100644 index 0000000000..d596005f80 --- /dev/null +++ b/src/idl/tests/parser.c @@ -0,0 +1,238 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "idl/processor.h" + +#include "CUnit/Theory.h" + +#define T(type) "struct s{" type " c;};" + +static void +test_base_type(const char *str, uint32_t flags, int32_t retcode, idl_mask_t mask) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_node_t *node; + + ret = idl_create_pstate(flags, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT(ret == retcode); + if (ret != IDL_RETCODE_OK) + goto bail; + node = pstate->root; + CU_ASSERT_PTR_NOT_NULL(node); + if (!node) + goto bail; + CU_ASSERT_EQUAL(idl_mask(node), IDL_STRUCT); + if (idl_mask(node) == (IDL_DECLARATION | IDL_TYPE | IDL_STRUCT)) { + idl_member_t *member = ((idl_struct_t *)node)->members; + CU_ASSERT_PTR_NOT_NULL(member); + if (!member) + goto bail; + CU_ASSERT_EQUAL(idl_mask(member), IDL_DECLARATION | IDL_MEMBER); + CU_ASSERT_PTR_NOT_NULL(member->type_spec); + if (!member->type_spec) + goto bail; + CU_ASSERT_EQUAL(idl_mask(member->type_spec), IDL_TYPE | mask); + CU_ASSERT_PTR_NOT_NULL(member->declarators); + if (!member->declarators) + goto bail; + CU_ASSERT_PTR_NOT_NULL(member->declarators->name); + CU_ASSERT_PTR_NOT_NULL(member->declarators->name->identifier); + if (!member->declarators->name || !member->declarators->name->identifier) + goto bail; + CU_ASSERT_STRING_EQUAL(member->declarators->name->identifier, "c"); + } + +bail: + idl_delete_pstate(pstate); +} + +CU_TheoryDataPoints(idl_parser, base_types) = { + CU_DataPoints(const char *, + T("short"), T("unsigned short"), + T("long"), T("unsigned long"), + T("long long"), T("unsigned long long"), + T("float"), T("double"), T("long double"), + T("char"), T("wchar"), + T("boolean"), T("octet")), + CU_DataPoints(uint32_t, + IDL_SHORT, IDL_USHORT, + IDL_LONG, IDL_ULONG, + IDL_LLONG, IDL_ULLONG, + IDL_FLOAT, IDL_DOUBLE, IDL_LDOUBLE, + IDL_CHAR, IDL_WCHAR, + IDL_BOOL, IDL_OCTET) +}; + +CU_Theory((const char *s, uint32_t t), idl_parser, base_types) +{ + test_base_type(s, IDL_FLAG_EXTENDED_DATA_TYPES, 0, t); +} + +CU_TheoryDataPoints(idl_parser, extended_base_types) = { + CU_DataPoints(const char *, T("int8"), T("uint8"), + T("int16"), T("uint16"), + T("int32"), T("uint32"), + T("int64"), T("uint64")), + CU_DataPoints(uint32_t, IDL_INT8, IDL_UINT8, + IDL_INT16, IDL_UINT16, + IDL_INT32, IDL_UINT32, + IDL_INT64, IDL_UINT64) +}; + +CU_Theory((const char *s, uint32_t t), idl_parser, extended_base_types) +{ + test_base_type(s, IDL_FLAG_EXTENDED_DATA_TYPES, 0, t); + test_base_type(s, 0u, IDL_RETCODE_SEMANTIC_ERROR, 0); +} + +#define M(name, contents) "module " name " { " contents " };" +#define S(name, contents) "struct " name " { " contents " };" +#define LL(name) "long long " name ";" +#define LD(name) "long double " name ";" + +CU_Test(idl_parser, embedded_module) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_node_t *p; + idl_module_t *m; + idl_struct_t *s; + idl_member_t *sm; + const char str[] = M("foo", M("bar", S("baz", LL("foobar") LD("foobaz")))); + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + m = (idl_module_t*)pstate->root; + CU_ASSERT_PTR_NOT_NULL_FATAL(m); + CU_ASSERT_PTR_NULL(idl_parent(m)); + //CU_ASSERT_PTR_NULL(idl_previous(m)); + CU_ASSERT_PTR_NULL(idl_next(m)); + CU_ASSERT_FATAL(idl_is_module(m)); + CU_ASSERT_STRING_EQUAL(idl_identifier(m), "foo"); + p = (idl_node_t*)m; + m = (idl_module_t *)m->definitions; + CU_ASSERT_PTR_NOT_NULL_FATAL(m); + CU_ASSERT_PTR_EQUAL(idl_parent(m), p); + CU_ASSERT_PTR_NULL(idl_previous(m)); + CU_ASSERT_PTR_NULL(idl_next(m)); + CU_ASSERT_FATAL(idl_is_module(m)); + CU_ASSERT_STRING_EQUAL(idl_identifier(m), "bar"); + p = (idl_node_t*)m; + s = (idl_struct_t *)m->definitions; + CU_ASSERT_PTR_NOT_NULL_FATAL(s); + CU_ASSERT_PTR_EQUAL(idl_parent(s), p); + CU_ASSERT_PTR_NULL(idl_previous(s)); + CU_ASSERT_PTR_NULL(idl_next(s)); + CU_ASSERT_FATAL(idl_is_struct(s)); + CU_ASSERT_STRING_EQUAL(idl_identifier(s), "baz"); + p = (idl_node_t*)s; + sm = s->members; + CU_ASSERT_PTR_NOT_NULL_FATAL(sm); + CU_ASSERT_PTR_EQUAL(idl_parent(sm), p); + CU_ASSERT_PTR_NULL(idl_previous(sm)); + CU_ASSERT_PTR_NOT_NULL_FATAL(idl_next(sm)); + CU_ASSERT_FATAL(idl_is_member(sm)); + CU_ASSERT(idl_type(sm->type_spec) == IDL_LLONG); + CU_ASSERT(idl_is_declarator(sm->declarators)); + CU_ASSERT_STRING_EQUAL(idl_identifier(sm->declarators), "foobar"); + CU_ASSERT_PTR_EQUAL(sm, idl_previous(idl_next(sm))); + sm = idl_next(sm); + CU_ASSERT_PTR_EQUAL(idl_parent(sm), p); + CU_ASSERT_PTR_NULL(idl_next(sm)); + CU_ASSERT_FATAL(idl_is_member(sm)); + CU_ASSERT(idl_type(sm->type_spec) == IDL_LDOUBLE); + CU_ASSERT(idl_is_declarator(sm->declarators)); + CU_ASSERT_STRING_EQUAL(idl_identifier(sm->declarators), "foobaz"); + idl_delete_pstate(pstate); +} + +// x. use already existing name + +CU_Test(idl_parser, struct_in_struct_same_module) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_module_t *m; + idl_struct_t *s1, *s2; + idl_member_t *s; + const char str[] = "module m { struct s1 { char c; }; struct s2 { s1 s; }; };"; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + m = (idl_module_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_module(m)); + s1 = (idl_struct_t *)m->definitions; + CU_ASSERT_FATAL(idl_is_struct(s1)); + s2 = idl_next(s1); + CU_ASSERT_FATAL(idl_is_struct(s2)); + s = s2->members; + CU_ASSERT_PTR_EQUAL(s->type_spec, s1); + idl_delete_pstate(pstate); +} + +CU_Test(idl_parser, struct_in_struct_other_module) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_module_t *m1, *m2; + idl_struct_t *s1, *s2; + idl_member_t *s; + const char str[] = "module m1 { struct s1 { char c; }; }; " + "module m2 { struct s2 { m1::s1 s; }; };"; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + m1 = (idl_module_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_module(m1)); + s1 = (idl_struct_t *)m1->definitions; + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT_PTR_EQUAL(s1->node.parent, m1); + m2 = idl_next(m1); + CU_ASSERT_FATAL(idl_is_module(m2)); + s2 = (idl_struct_t *)m2->definitions; + CU_ASSERT_FATAL(idl_is_struct(s2)); + s = s2->members; + CU_ASSERT_PTR_EQUAL(s->type_spec, s1); + CU_ASSERT_PTR_EQUAL(s2->node.parent, m2); + idl_delete_pstate(pstate); +} + +// x. use nonexisting type! +// x. union with same declarators +// x. struct with same declarators +// x. struct with embedded struct +// x. struct with anonymous embedded struct +// x. forward declared union +// x.x. forward declared union before definition +// x.x. forward declared union after definition +// x.x. forward declared union with no definition at all +// x. forward declared struct +// x.x. see union +// x. constant expressions +// x. identifier that collides with a keyword diff --git a/src/idl/tests/pragma.c b/src/idl/tests/pragma.c new file mode 100644 index 0000000000..62fdde1d74 --- /dev/null +++ b/src/idl/tests/pragma.c @@ -0,0 +1,141 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "idl/processor.h" + +#include "CUnit/Test.h" + +static void test_bad_use(const char *str) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SEMANTIC_ERROR); + CU_ASSERT_PTR_NULL(pstate->root); + idl_delete_pstate(pstate); +} + +CU_Test(idl_pragma, keylist_bad_use) +{ + const char *str[] = { + /* non-existent type */ + "#pragma keylist foo bar", + /* non-existent member */ + "struct s { char c; };\n" + "#pragma keylist s foo\n", + /* duplicate keylists */ + "struct s { char c; };\n" + "#pragma keylist s c\n" + "#pragma keylist s c\n", + /* duplicate keys */ + "struct s { char c; };\n" + "#pragma keylist s c c\n", + NULL + }; + + for (const char **ptr = str; *ptr; ptr++) + test_bad_use(*ptr); +} + +static idl_retcode_t parse_string(const char *str, idl_pstate_t **pstatep) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + if ((ret = idl_create_pstate(0u, NULL, &pstate))) + return ret; + assert(pstate); + ret = idl_parse_string(pstate, str); + if (ret == IDL_RETCODE_OK) + *pstatep = pstate; + else + idl_delete_pstate(pstate); + return ret; +} + +CU_Test(idl_pragma, keylist) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_struct_t *s1; + const char str[] = "struct s1 { char c; };\n" + "#pragma keylist s1 c"; + + ret = parse_string(str, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + s1 = (idl_struct_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT((idl_mask(s1->keylist) & IDL_KEYLIST) != 0); + idl_delete_pstate(pstate); +} + +CU_Test(idl_pragma, keylist_nested_key) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_struct_t *s1; + static const char str[] = "module m1 { struct s2 { char c; }; };\n" + "struct s1 { m1::s2 s; };\n" + "#pragma keylist s1 s.c"; + + ret = parse_string(str, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + s1 = idl_next(pstate->root); + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT((idl_mask(s1->keylist) & IDL_KEYLIST) != 0); + idl_delete_pstate(pstate); +} + +CU_Test(idl_pragma, keylist_scoped_name) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_module_t *m1; + idl_struct_t *s1; + static const char str[] = "module m1 { struct s1 { char c; }; };\n" + "#pragma keylist m1::s1 c"; + + ret = parse_string(str, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + m1 = (idl_module_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_module(m1)); + s1 = (idl_struct_t *)m1->definitions; + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT((idl_mask(s1->keylist) & IDL_KEYLIST) != 0); + idl_delete_pstate(pstate); +} + +CU_Test(idl_pragma, keylist_outer_scope) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_struct_t *s1; + static const char str[] = "struct s1 { char c; };\n" + "module m1 {\n" + " struct s2 { char c; };\n" + " #pragma keylist s1 c\n" + "};\n"; + + ret = parse_string(str, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + s1 = (idl_struct_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_struct(s1)); + CU_ASSERT((idl_mask(s1->keylist) & IDL_KEYLIST) != 0); + idl_delete_pstate(pstate); +} diff --git a/src/tools/idlc/tests/scanner.c b/src/idl/tests/scanner.c similarity index 60% rename from src/tools/idlc/tests/scanner.c rename to src/idl/tests/scanner.c index 1c29ca4f23..b8da857525 100644 --- a/src/tools/idlc/tests/scanner.c +++ b/src/idl/tests/scanner.c @@ -15,23 +15,12 @@ #include #include -#include "idl.h" +#include "idl/processor.h" +#include "scanner.h" #include "parser.h" -#include "dds/ddsrt/heap.h" - #include "CUnit/Theory.h" -static void -setup_scanner(idl_processor_t *proc, const char *str) -{ - memset(proc, 0, sizeof(*proc)); - proc->scanner.cursor = str; - proc->scanner.limit = str + strlen(str); - proc->scanner.position.line = 1; - proc->scanner.position.column = 1; -} - static int compare_position(idl_position_t *a, idl_position_t *b) { @@ -42,10 +31,10 @@ compare_position(idl_position_t *a, idl_position_t *b) if (a->column != b->column) return (int)a->column - (int)b->column; if (!a->file) - return 0; + return !b->file ? 0 : -1; if (!b->file) return 1; - return strcmp(a->file, b->file); + return strcmp(a->file->name, b->file->name); } static void @@ -88,20 +77,25 @@ assert_token(idl_token_t *tok, idl_token_t *xtok) } static void -test_scanner(idl_processor_t *proc, idl_token_t *tokvec) +test_scanner(idl_pstate_t *pstate, idl_token_t *tokvec) { int32_t code; idl_token_t tok; for (int i = 0; tokvec[i].code >= 0; i++) { - code = idl_scan(proc, &tok); + code = idl_scan(pstate, &tok); + if (code < 0) { + CU_FAIL("unexpected return code"); + break; + } assert_token(&tok, &tokvec[i]); switch (code) { case IDL_TOKEN_IDENTIFIER: case IDL_TOKEN_PP_NUMBER: - case IDL_TOKEN_CHAR_LITERAL: case IDL_TOKEN_STRING_LITERAL: - ddsrt_free(tok.value.str); + case IDL_TOKEN_LINE_COMMENT: + case IDL_TOKEN_COMMENT: + free(tok.value.str); break; default: break; @@ -114,17 +108,35 @@ test_scanner(idl_processor_t *proc, idl_token_t *tokvec) static void test(const char *str, idl_token_t *tokvec) { - idl_processor_t proc; - setup_scanner(&proc, str); - test_scanner(&proc, tokvec); + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + if ((ret = idl_create_pstate(0u, NULL, &pstate))) { + CU_FAIL("Failed to create parser"); + return; + } + pstate->scanner.cursor = str; + pstate->scanner.limit = str + strlen(str); + pstate->scanner.position.source = NULL; + pstate->scanner.position.file = NULL; + pstate->scanner.position.line = 1; + pstate->scanner.position.column = 1; + test_scanner(pstate, tokvec); + pstate->scanner.cursor = NULL; + pstate->scanner.limit = NULL; + idl_delete_pstate(pstate); } #define C(c, fl, fc, ll, lc) \ - { c, { c }, { { NULL, fl, fc }, { NULL, ll, lc } } } + { c, { .chr = 0 }, { { NULL, NULL, fl, fc }, { NULL, NULL, ll, lc } } } #define T(c, fl, fc, ll, lc) \ - { c, { c }, { { NULL, fl, fc }, { NULL, ll, lc } } } + { c, { .chr = 0 }, { { NULL, NULL, fl, fc }, { NULL, NULL, ll, lc } } } #define T_STR(c, s, fl, fc, ll, lc) \ - { c, { .str = s }, { { NULL, fl, fc }, { NULL, ll, lc } } } + { c, { .str = s }, { { NULL, NULL, fl, fc }, { NULL, NULL, ll, lc } } } +#define T_ULLNG(c, n, fl, fc, ll, lc) \ + { c, { .ullng = n }, { { NULL, NULL, fl, fc }, { NULL, NULL, ll, lc } } } +#define T_LDBL(c, n, fl, fc, ll, lc) \ + { c, { .ldbl = n }, { { NULL, NULL, fl, fc }, { NULL, NULL, ll, lc } } } #define T0(fl, fc) T('\0', fl, fc, fl, fc) #define TLC(fl, fc, ll, lc) T(IDL_TOKEN_LINE_COMMENT, fl, fc, ll, lc) @@ -134,6 +146,10 @@ test(const char *str, idl_token_t *tokvec) T_STR(IDL_TOKEN_STRING_LITERAL, NULL, fl, fc, ll, lc) #define TSL_STR(str, fl, fc, ll, lc) \ T_STR(IDL_TOKEN_STRING_LITERAL, str, fl, fc ll, lc) +#define TIL(ullng, fl, fc, ll, lc) \ + T_ULLNG(IDL_TOKEN_INTEGER_LITERAL, 0, fl, fc, ll, lc) +#define TFL(ldbl, fl, fc, ll, lc) \ + T_LDBL(IDL_TOKEN_FLOATING_PT_LITERAL, 0.0, fl, fc, ll, lc) #define TI(fl, fc, ll, lc) \ T_STR(IDL_TOKEN_IDENTIFIER, NULL, fl, fc, ll, lc) #define TI_STR(str, fl, fc, ll, lc) \ @@ -142,119 +158,130 @@ test(const char *str, idl_token_t *tokvec) T_STR(IDL_TOKEN_PP_NUMBER, str, fl, fc, ll, lc) #define TS(fl, fc, ll, lc) T(IDL_TOKEN_SCOPE, fl, fc, ll, lc) -#define TS_L(fl, fc, ll, lc) T(IDL_TOKEN_SCOPE_L, fl, fc, ll, lc) -#define TS_R(fl, fc, ll, lc) T(IDL_TOKEN_SCOPE_R, fl, fc, ll, lc) -#define TS_LR(fl, fc, ll, lc) T(IDL_TOKEN_SCOPE_LR, fl, fc, ll, lc) #define TOKVEC(...) (idl_token_t[]){ __VA_ARGS__} /* blank */ -CU_Test(idlc_scanner, blank) +CU_Test(idl_scanner, blank) { test("", TOKVEC( T0(1,1) )); } -CU_Test(idlc_scanner, blank_cseq) +CU_Test(idl_scanner, blank_cseq) { test("\\\n", TOKVEC( T0(2,1) )); } -CU_Test(idlc_scanner, blank_wsp_cseq_wsp) +CU_Test(idl_scanner, blank_wsp_cseq_wsp) { test(" \\\n ", TOKVEC( T0(2,3) )); } -CU_Test(idlc_scanner, blank_2x_cseq) +CU_Test(idl_scanner, blank_2x_cseq) { test("\\\n\\\n", TOKVEC( T0(3,1) )); } /* line comment */ -CU_Test(idlc_scanner, line_comment) +CU_Test(idl_scanner, line_comment) { test("//", TOKVEC( TLC(1,1,1,3), T0(1,3) )); } -CU_Test(idlc_scanner, line_comment_wrp_cseq) +CU_Test(idl_scanner, line_comment_wrp_cseq) { test("/\\\n/\\\n", TOKVEC( TLC(1,1,3,1), T0(3,1) )); } -CU_Test(idlc_scanner, line_comment_wrp_cseq_ident) +CU_Test(idl_scanner, line_comment_wrp_cseq_ident) { test("//\\\nfoo\\\nbar\nbaz", TOKVEC( TLC(1,1,3,4), C('\n',3,4,4,1), TI(4,1,4,4), T0(4,4) )); } /* comment */ -CU_Test(idlc_scanner, comment) +CU_Test(idl_scanner, comment) { test("/**/", TOKVEC( TC(1,1,1,5), T0(1,5) )); } -CU_Test(idlc_scanner, comment_x) +CU_Test(idl_scanner, comment_x) { test("/*/*/", TOKVEC( TC(1,1,1,6), T0(1,6) )); } -CU_Test(idlc_scanner, comment_wrp_cseq) +CU_Test(idl_scanner, comment_wrp_cseq) { test("/\\\n*\\\n*\\\n/", TOKVEC( TC(1,1,4,2), T0(4,2) )); } -CU_Test(idlc_scanner, comment_wrp_cseq_ident) +CU_Test(idl_scanner, comment_wrp_cseq_ident) { test("/\\\n*foo\\\n/bar\\\n*\\\n/baz", TOKVEC( TC(1,1,5,2), TI(5,2,5,5), T0(5,5) )); } /* char literal */ -CU_Test(idlc_scanner, char_literal) -{ test("\'foo\'", TOKVEC( TCL(1,1,1,6), T0(1,6) )); } +CU_Test(idl_scanner, char_literal) +{ test("\'f\'", TOKVEC( TCL(1,1,1,4), T0(1,4) )); } -CU_Test(idlc_scanner, char_literal_wrp_cseq) -{ test("\'foo\\\n\'\\\n", TOKVEC( TCL(1,1,2,2), T0(3,1) )); } +CU_Test(idl_scanner, char_literal_wrp_cseq) +{ test("\'\\n\\\n\'\\\n", TOKVEC( TCL(1,1,2,2), T0(3,1) )); } /* string literal */ -CU_Test(idlc_scanner, string_literal) +CU_Test(idl_scanner, string_literal) { test("\"foo bar baz\"", TOKVEC( TSL(1,1,1,14), T0(1,14) )); } -CU_Test(idlc_scanner, string_literal_wrp_seq) +CU_Test(idl_scanner, string_literal_wrp_seq) { test("\"foo bar baz\\\n\"\\\n", TOKVEC( TSL(1,1,2,2), T0(3,1) )); } +/* integer literal */ +CU_Test(idl_scanner, integer_literal) +{ test("1", TOKVEC( TIL(1,1,1,1,2), T0(1,2) )); } + +CU_Test(idl_scanner, integer_literal_hex_dot) +{ test("0x1.", TOKVEC( TIL(0x1,1,1,1,4), T('.',1,4,1,5), T0(1,5) )); } + +/* floating point literal */ +CU_Test(idl_scanner, floating_pt_literal) +{ test("1\\\n23.", TOKVEC( TFL(123.0,1,1,2,4), T0(2,4) )); } + +CU_Test(idl_scanner, floating_pt_literal_dot_fraction) +{ test(".1", TOKVEC( TFL(.1,1,1,1,3), T0(1,3) )); } + /* identifier */ -CU_Test(idlc_scanner, ident) +CU_Test(idl_scanner, ident) { test("a", TOKVEC( TI(1,1,1,2), T0(1,2) )); } -CU_Test(idlc_scanner, ident_tr_cseq) +CU_Test(idl_scanner, ident_tr_cseq) { test("a\\\r\n", TOKVEC( TI(1,1,1,2), T0(2,1) )); } -CU_Test(idlc_scanner, ident_wrp_cseq) +CU_Test(idl_scanner, ident_wrp_cseq) { test("\\\na\\\r\nb\\\n", TOKVEC( TI(2,1,3,2), T0(4,1) )); } /* scope */ -CU_Test(idlc_scanner, scope) +CU_Test(idl_scanner, scope) { test("::", TOKVEC( TS(1,1,1,3), T0(1,3) )); } -CU_Test(idlc_scanner, scope_wrp_cseq) +CU_Test(idl_scanner, scope_wrp_cseq) { test("\\\n:\\\r\n:\\\n", TOKVEC( TS(2,1,3,2), T0(4,1) )); } /* scoped name (IDL_TOKEN_SCOPE_L) */ -CU_Test(idlc_scanner, scope_l) -{ test("foo::", TOKVEC( TI(1,1,1,4), TS_L(1,4,1,6), T0(1,6) )); } +CU_Test(idl_scanner, scope_l) +{ test("foo::", TOKVEC( TI(1,1,1,4), TS(1,4,1,6), T0(1,6) )); } -CU_Test(idlc_scanner, scope_l_wrp_cseq) -{ test("foo\\\n::", TOKVEC( TI(1,1,1,4), TS_L(2,1,2,3), T0(2,3) )); } +CU_Test(idl_scanner, scope_l_wrp_cseq) +{ test("foo\\\n::", TOKVEC( TI(1,1,1,4), TS(2,1,2,3), T0(2,3) )); } -CU_Test(idlc_scanner, scope_non_l) +CU_Test(idl_scanner, scope_non_l) { test("foo ::", TOKVEC( TI(1,1,1,4), TS(1,5,1,7), T0(1,7) )); } /* scoped name (IDL_TOKEN_SCOPE_R) */ -CU_Test(idlc_scanner, scope_r) -{ test("::foo", TOKVEC( TS_R(1,1,1,3), TI(1,3,1,6), T0(1,6) )); } +CU_Test(idl_scanner, scope_r) +{ test("::foo", TOKVEC( TS(1,1,1,3), TI(1,3,1,6), T0(1,6) )); } -CU_Test(idlc_scanner, scope_r_wrp_cseq) -{ test("::\\\r\nfoo", TOKVEC( TS_R(1,1,1,3), TI(2,1,2,4), T0(2,4) )); } +CU_Test(idl_scanner, scope_r_wrp_cseq) +{ test("::\\\r\nfoo", TOKVEC( TS(1,1,1,3), TI(2,1,2,4), T0(2,4) )); } -CU_Test(idlc_scanner, scope_non_r) +CU_Test(idl_scanner, scope_non_r) { test(":: foo", TOKVEC( TS(1,1,1,3), TI(1,4,1,7), T0(1,7) )); } /* scoped name (IDL_TOKEN_SCOPE_LR) */ -CU_Test(idlc_scanner, scope_lr) +CU_Test(idl_scanner, scope_lr) { test("foo::bar", - TOKVEC( TI(1,1,1,4), TS_LR(1,4,1,6), TI(1,6,1,9), T0(1,9) )); } + TOKVEC( TI(1,1,1,4), TS(1,4,1,6), TI(1,6,1,9), T0(1,9) )); } -CU_Test(idlc_scanner, scope_lr_wrp_cseq) +CU_Test(idl_scanner, scope_lr_wrp_cseq) { test("foo\\\n::\\\r\nbar", - TOKVEC( TI(1,1,1,4), TS_LR(2,1,2,3), TI(3,1,3,4), T0(3,4) )); } + TOKVEC( TI(1,1,1,4), TS(2,1,2,3), TI(3,1,3,4), T0(3,4) )); } -CU_Test(idlc_scanner, scope_non_lr) +CU_Test(idl_scanner, scope_non_lr) { test("foo :: bar", TOKVEC( TI(1,1,1,4), TS(1,5,1,7), TI(1,8,1,11), T0(1,11) )); } -CU_Test(idlc_scanner, scope_non_lr_l) +CU_Test(idl_scanner, scope_non_lr_l) { test("foo:: bar", - TOKVEC( TI(1,1,1,4), TS_L(1,4,1,6), TI(1,7,1,10), T0(1,10) )); } + TOKVEC( TI(1,1,1,4), TS(1,4,1,6), TI(1,7,1,10), T0(1,10) )); } -CU_Test(idlc_scanner, scope_non_lr_r) +CU_Test(idl_scanner, scope_non_lr_r) { test("foo ::bar", - TOKVEC( TI(1,1,1,4), TS_R(1,5,1,7), TI(1,7,1,10), T0(1,10) )); } + TOKVEC( TI(1,1,1,4), TS(1,5,1,7), TI(1,7,1,10), T0(1,10) )); } // extended char literal tests // x. escape sequences @@ -265,11 +292,11 @@ CU_Test(idlc_scanner, scope_non_lr_r) // x. escape sequences // x. unterminated string literal -CU_Test(idlc_scanner, hash_line) +CU_Test(idl_scanner, hash_line) { test("#line\\\n 1", TOKVEC( T('#',1,1,1,2), TI_STR("line",1,2,1,6), TN_STR("1",2,2,2,3), T0(2,3) )); } -CU_Test(idlc_scanner, hash_pragma) +CU_Test(idl_scanner, hash_pragma) { test("#pragma keylist foo bar baz\n", TOKVEC( T('#',1,1,1,2), TI_STR("pragma",1,2,1,8), diff --git a/src/idl/tests/typedef.c b/src/idl/tests/typedef.c new file mode 100644 index 0000000000..0fffa8ab1e --- /dev/null +++ b/src/idl/tests/typedef.c @@ -0,0 +1,204 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "idl/processor.h" + +#include "CUnit/Test.h" + +CU_Test(idl_typedef, bogus_type) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + const char str[] = "typedef foo bar;"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SEMANTIC_ERROR); + idl_delete_pstate(pstate); +} + +CU_Test(idl_typedef, simple_declarator) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_typedef_t *t; + idl_declarator_t *d; + + const char str[] = "typedef char foo;"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + t = (idl_typedef_t *)pstate->root; + CU_ASSERT_PTR_NOT_NULL_FATAL(t); + CU_ASSERT_FATAL(idl_is_typedef(t)); + CU_ASSERT_PTR_NULL(idl_next(t)); + CU_ASSERT_PTR_NULL(idl_parent(t)); + CU_ASSERT_PTR_NOT_NULL(t->type_spec); + CU_ASSERT(idl_type(t->type_spec) == IDL_CHAR); + d = t->declarators; + CU_ASSERT_PTR_NOT_NULL_FATAL(d); + CU_ASSERT_FATAL(idl_is_declarator(d)); + CU_ASSERT_PTR_NULL(idl_previous(d)); + CU_ASSERT_PTR_NULL(idl_next(d)); + CU_ASSERT_PTR_EQUAL(idl_parent(d), t); + CU_ASSERT_STRING_EQUAL(idl_identifier(d), "foo"); + CU_ASSERT_PTR_NULL(d->const_expr); + idl_delete_pstate(pstate); +} + +CU_Test(idl_typedef, simple_declarators) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_typedef_t *t; + idl_declarator_t *d; + + const char str[] = "typedef char foo, bar, baz;"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_OK); + t = (idl_typedef_t *)pstate->root; + CU_ASSERT_PTR_NOT_NULL_FATAL(t); + CU_ASSERT_FATAL(idl_is_typedef(t)); + CU_ASSERT_PTR_NOT_NULL(t->type_spec); + CU_ASSERT(idl_type(t->type_spec) == IDL_CHAR); + d = t->declarators; + CU_ASSERT_PTR_NOT_NULL_FATAL(d); + CU_ASSERT_FATAL(idl_is_declarator(d)); + CU_ASSERT_PTR_NULL(idl_previous(d)); + CU_ASSERT_PTR_EQUAL(idl_parent(d), t); + CU_ASSERT_PTR_NOT_NULL_FATAL(idl_identifier(d)); + CU_ASSERT_STRING_EQUAL(idl_identifier(d), "foo"); + CU_ASSERT_PTR_NULL(d->const_expr); + d = idl_next(d); + CU_ASSERT_PTR_NOT_NULL_FATAL(d); + CU_ASSERT_FATAL(idl_is_declarator(d)); + CU_ASSERT_PTR_EQUAL(idl_parent(d), t); + CU_ASSERT_PTR_NOT_NULL_FATAL(idl_identifier(d)); + CU_ASSERT_STRING_EQUAL(idl_identifier(d), "bar"); + CU_ASSERT_PTR_NULL(d->const_expr); + d = idl_next(d); + CU_ASSERT_PTR_NOT_NULL_FATAL(d); + CU_ASSERT_FATAL(idl_is_declarator(d)); + CU_ASSERT_PTR_EQUAL(idl_parent(d), t); + CU_ASSERT_PTR_NOT_NULL_FATAL(idl_identifier(d)); + CU_ASSERT_STRING_EQUAL(idl_identifier(d), "baz"); + CU_ASSERT_PTR_NULL(d->const_expr); + CU_ASSERT_PTR_NULL(idl_next(d)); + idl_delete_pstate(pstate); +} + +// x. typedef with complex declarator +// x. typedef with more than one complex declarator +// x. typedef to typedef + +CU_Test(idl_typedef, sequence) +{ + idl_retcode_t ret; + idl_pstate_t *pstate; + idl_typedef_t *t; + idl_struct_t *s; + idl_member_t *m; + + const char str[] = "typedef sequence t; struct s { t m; };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + t = (idl_typedef_t *)pstate->root; + CU_ASSERT_PTR_NOT_NULL_FATAL(t); + CU_ASSERT_FATAL(idl_is_typedef(t)); + s = idl_next(t); + CU_ASSERT_PTR_NOT_NULL_FATAL(s); + CU_ASSERT_FATAL(idl_is_struct(s)); + m = s->members; + CU_ASSERT_PTR_NOT_NULL_FATAL(m); + CU_ASSERT_FATAL(idl_is_member(m)); + CU_ASSERT_PTR_EQUAL(m->type_spec, t->declarators); + idl_delete_pstate(pstate); +} + +CU_Test(idl_typedef, typedef_of_typedef_sequence) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_module_t *m1, *m2; + idl_typedef_t *t0, *t1, *t2, *t3; + idl_struct_t *s1; + idl_sequence_t *s2; + idl_member_t *m_t2, *m_t3; + + const char str[] = + "module m1 {\n"\ + " typedef long t0;\n" + " typedef t0 t1;\n" + " typedef t1 t2;\n" + " typedef sequence t3;\n" + "};\n" + "module m2 {\n" + " struct s1 {\n" + " m1::t2 m_t2;\n" + " sequence m_t3;\n" + " };\n" + "};\n"; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + m1 = (idl_module_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_module(m1)); + t0 = (idl_typedef_t *)m1->definitions; + CU_ASSERT_FATAL(idl_is_typedef(t0)); + CU_ASSERT_PTR_EQUAL(t0->node.parent, m1); + t1 = idl_next(t0); + CU_ASSERT_FATAL(idl_is_typedef(t1)); + CU_ASSERT_PTR_EQUAL(t1->node.parent, m1); + CU_ASSERT_PTR_EQUAL(t1->type_spec, t0->declarators); + t2 = idl_next(t1); + CU_ASSERT_FATAL(idl_is_typedef(t2)); + CU_ASSERT_PTR_EQUAL(t2->node.parent, m1); + CU_ASSERT_PTR_EQUAL(t2->type_spec, t1->declarators); + t3 = idl_next(t2); + CU_ASSERT_FATAL(idl_is_typedef(t3)); + CU_ASSERT_PTR_EQUAL(t3->node.parent, m1); + s2 = idl_type_spec(t3); + CU_ASSERT_FATAL(idl_is_sequence(s2)); + CU_ASSERT(idl_is_alias(s2->type_spec)); + CU_ASSERT_PTR_EQUAL(s2->type_spec, t2->declarators); + m2 = idl_next(m1); + CU_ASSERT_FATAL(idl_is_module(m2)); + s1 = (idl_struct_t *)m2->definitions; + CU_ASSERT_FATAL(idl_is_struct(s1)); + m_t2 = (idl_member_t *)s1->members; + CU_ASSERT_FATAL(idl_is_member(m_t2)); + CU_ASSERT_PTR_EQUAL(m_t2->type_spec, t2->declarators); + m_t3 = idl_next(m_t2); + CU_ASSERT_FATAL(idl_is_member(m_t3)); + CU_ASSERT_FATAL(idl_is_sequence(m_t3->type_spec)); + CU_ASSERT_PTR_EQUAL(((idl_sequence_t *)m_t3->type_spec)->type_spec, t3->declarators); + idl_delete_pstate(pstate); +} diff --git a/src/idl/tests/union.c b/src/idl/tests/union.c new file mode 100644 index 0000000000..71b79bb492 --- /dev/null +++ b/src/idl/tests/union.c @@ -0,0 +1,227 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "idl/processor.h" + +#include "CUnit/Theory.h" + +/* a union must have at least one case */ +CU_Test(idl_union, no_case) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + const char str[] = "union u switch(char) { };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, IDL_RETCODE_SYNTAX_ERROR); + idl_delete_pstate(pstate); +} + +CU_Test(idl_union, single_case) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_union_t *u; + idl_case_t *c; + + const char str[] = "union u switch(long) { case 1: char c; };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + u = (idl_union_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_union(u)); + CU_ASSERT(idl_type(u->switch_type_spec->type_spec) == IDL_LONG); + c = (idl_case_t *)u->cases; + CU_ASSERT_FATAL(idl_is_case(c)); + CU_ASSERT_PTR_EQUAL(idl_parent(c), u); + CU_ASSERT(idl_is_case_label(c->case_labels)); + CU_ASSERT(idl_type(c->type_spec) == IDL_CHAR); + CU_ASSERT_FATAL(idl_is_declarator(c->declarator)); + CU_ASSERT_STRING_EQUAL(idl_identifier(c->declarator), "c"); + c = idl_next(c); + CU_ASSERT_PTR_NULL(c); + idl_delete_pstate(pstate); +} + +CU_Test(idl_union, single_default_case) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_union_t *u; + idl_case_t *c; + + const char str[] = "union u switch(char) { default: char c; };"; + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + u = (idl_union_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_union(u)); + CU_ASSERT(idl_type(u->switch_type_spec->type_spec) == IDL_CHAR); + c = (idl_case_t *)u->cases; + CU_ASSERT_FATAL(idl_is_case(c)); + CU_ASSERT_PTR_EQUAL(idl_parent(c), u); + CU_ASSERT(idl_is_default_case(c)); + CU_ASSERT(idl_type(c->type_spec) == IDL_CHAR); + CU_ASSERT_FATAL(idl_is_declarator(c->declarator)); + CU_ASSERT_STRING_EQUAL(idl_identifier(c->declarator), "c"); + c = idl_next(c); + CU_ASSERT_PTR_NULL(c); + idl_delete_pstate(pstate); +} + +// x. union with same declarators +// x. forward declared union +// x.x. forward declared union before definition +// x.x. forward declared union after definition +// x.x. forward declared union with no definition at all +// x. forward declared struct +// x.x. see union +// x. constant expressions +// x. identifier that collides with a keyword +// x. union with default +// x. union with two default branches +// x. union with multile labels for branch +// x. union with enumeration A and an enumerator from enumeration B + +CU_Test(idl_union, enumerator_switch_type) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_enum_t *e; + idl_enumerator_t *el; + idl_union_t *u; + idl_case_t *c; + const char *str; + + str = "enum Color { Red, Yellow, Blue };\n" + "union u switch(Color) { case Red: char c; default: long l; };"; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + e = (idl_enum_t *)pstate->root; + CU_ASSERT_FATAL(idl_is_enum(e)); + el = e->enumerators; + CU_ASSERT_FATAL(idl_is_enumerator(el)); + CU_ASSERT_STRING_EQUAL(idl_identifier(el), "Red"); + el = idl_next(el); + CU_ASSERT_FATAL(idl_is_enumerator(el)); + CU_ASSERT_STRING_EQUAL(idl_identifier(el), "Yellow"); + el = idl_next(el); + CU_ASSERT_FATAL(idl_is_enumerator(el)); + CU_ASSERT_STRING_EQUAL(idl_identifier(el), "Blue"); + u = (idl_union_t *)idl_next(e); + CU_ASSERT_FATAL(idl_is_union(u)); + c = u->cases; + CU_ASSERT_FATAL(idl_is_case(c)); + CU_ASSERT((uintptr_t)c->case_labels->const_expr == (uintptr_t)e->enumerators); + idl_delete_pstate(pstate); +} + +/* the type for the union discriminator must be an integer, char, boolean, + enumeration, or a reference to one of these */ +#define M(name, definitions) "module " name " { " definitions " };" +#define S(name) "struct " name " { char c; };" +#define T(type, name) "typedef " type " " name ";" +#define U(type) "union u switch (" type ") { default: char c; };" + +CU_Test(idl_union, typedef_switch_types) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + idl_module_t *m; + idl_typedef_t *t; + idl_union_t *u; + const char *str; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + str = T("char", "baz") U("baz"); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + t = (idl_typedef_t *)pstate->root; + CU_ASSERT(idl_is_typedef(t)); + u = idl_next(t); + CU_ASSERT_FATAL(idl_is_union(u)); + CU_ASSERT_PTR_EQUAL(t->declarators, u->switch_type_spec->type_spec); + idl_delete_pstate(pstate); + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + str = M("foo", T("char", "baz") U("baz")); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + m = (idl_module_t *)pstate->root; + CU_ASSERT(idl_is_module(m)); + t = (idl_typedef_t *)m->definitions; + CU_ASSERT(idl_is_typedef(t)); + u = idl_next(t); + CU_ASSERT(idl_is_union(u)); + CU_ASSERT_PTR_EQUAL(t->declarators, u->switch_type_spec->type_spec); + idl_delete_pstate(pstate); + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + str = M("foo", T("char", "baz")) M("bar", U("foo::baz")); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + m = (idl_module_t *)pstate->root; + CU_ASSERT(idl_is_module(m)); + t = (idl_typedef_t *)m->definitions; + CU_ASSERT(idl_is_typedef(t)); + m = idl_next(m); + CU_ASSERT(idl_is_module(m)); + u = (idl_union_t *)m->definitions; + CU_ASSERT(idl_is_union(u)); + CU_ASSERT_PTR_EQUAL(t->declarators, u->switch_type_spec->type_spec); + idl_delete_pstate(pstate); +} + +CU_TheoryDataPoints(idl_union, bad_switch_types) = { + CU_DataPoints(const char *, + S("baz") U("baz"), + U("baz"), + M("foo", T("float", "baz")) M("bar", U("foo::baz"))), + CU_DataPoints(idl_retcode_t, + IDL_RETCODE_SEMANTIC_ERROR, + IDL_RETCODE_SEMANTIC_ERROR, + IDL_RETCODE_SEMANTIC_ERROR) +}; + +CU_Theory((const char *str, idl_retcode_t expret), idl_union, bad_switch_types) +{ + idl_retcode_t ret; + idl_pstate_t *pstate = NULL; + + ret = idl_create_pstate(0u, NULL, &pstate); + CU_ASSERT_EQUAL_FATAL(ret, IDL_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(pstate); + ret = idl_parse_string(pstate, str); + CU_ASSERT_EQUAL(ret, expret); + idl_delete_pstate(pstate); +} diff --git a/src/idlc/CMakeLists.txt b/src/idlc/CMakeLists.txt deleted file mode 100644 index 1d50a0559b..0000000000 --- a/src/idlc/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -# -# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License v. 2.0 which is available at -# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -# v. 1.0 which is available at -# http://www.eclipse.org/org/documents/edl-v10.php. -# -# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause -# -# Verify Maven is available -find_package(Maven 3.0 REQUIRED) - -file(GLOB_RECURSE IDLC_G_SOURCES LIST_DIRECTORIES false *.g) -file(GLOB_RECURSE IDLC_G4_SOURCES LIST_DIRECTORIES false *.g4) -file(GLOB_RECURSE IDLC_JAVA_SOURCES LIST_DIRECTORIES false *.java) -file(GLOB_RECURSE IDLC_ST_SOURCES LIST_DIRECTORIES false *.st?) - -set(IDLC_JAR "${CMAKE_CURRENT_BINARY_DIR}/target/idlc-jar-with-dependencies.jar") -mark_as_advanced(IDLC_JAR) - -# Maven is executed within the idlc directory located in the build directory -# and generated sources are stored in idlc/target. Non-generated sources, -# however, do not reside in the build directory and Maven must be instructed -# to use those. To allow maven to be executed from both the source and build -# directories (idlc may be moved to it's own repository), the pom.xml file is -# pulled through the configure_file function with basedir set to the original -# source directory. It is a cute little hack to avoid having to use different -# profiles etc. -set(basedir "${CMAKE_CURRENT_SOURCE_DIR}/src") -mark_as_advanced(basedir) -set(IDLC_POM_FILE "src/pom.xml.in") -configure_file(${IDLC_POM_FILE} "pom.xml") -configure_file("src/org/eclipse/cyclonedds/Project.java.in" "org/eclipse/cyclonedds/Project.java") - -add_custom_command( - OUTPUT "${IDLC_JAR}" - COMMAND "${Maven_EXECUTABLE}" - ARGS "-q" "package" - DEPENDS ${IDLC_POM_FILE} ${IDLC_G_SOURCES} ${IDLC_G4_SOURCES} ${IDLC_JAVA_SOURCES} ${IDLC_ST_SOURCES} - COMMENT "Building JAR file ${IDLC_JAR}") - -include(cmake/IdlcGenerate.cmake) - -install( - FILES "cmake/IdlcGenerate.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/idlc" - COMPONENT idlc) - -install( - FILES "${IDLC_SCRIPT_IN}" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/idlc" - COMPONENT idlc) - -install( - FILES "${IDLC_JAR}" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/idlc" - PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE - COMPONENT idlc) - diff --git a/src/idlc/cmake/IdlcGenerate.cmake b/src/idlc/cmake/IdlcGenerate.cmake deleted file mode 100644 index d6e1d97162..0000000000 --- a/src/idlc/cmake/IdlcGenerate.cmake +++ /dev/null @@ -1,89 +0,0 @@ -# -# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License v. 2.0 which is available at -# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -# v. 1.0 which is available at -# http://www.eclipse.org/org/documents/edl-v10.php. -# -# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause -# -find_package(Java 1.8 REQUIRED) - -if(NOT IDLC_JAR) - set(IDLC_JAR "${CMAKE_CURRENT_LIST_DIR}/idlc-jar-with-dependencies.jar") -endif() - -set(LINE_ENDINGS "UNIX") -if(WIN32) - set(EXTENSION ".bat") - set(LINE_ENDINGS "WIN32") -endif() - -set(IDLC_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "") -set(IDLC "dds_idlc${EXTENSION}" CACHE STRING "") -mark_as_advanced(IDLC_DIR IDLC) - -set(IDLC_SCRIPT_IN "${CMAKE_CURRENT_LIST_DIR}/dds_idlc${EXTENSION}.in") - -configure_file( - "${IDLC_SCRIPT_IN}" "${IDLC}" - @ONLY - NEWLINE_STYLE ${LINE_ENDINGS}) - -if(NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")) - execute_process(COMMAND chmod +x "${IDLC_DIR}/${IDLC}") -endif() - -add_custom_target(idlc-jar ALL DEPENDS "${IDLC_JAR}") - -function(IDLC_GENERATE _target) - if(NOT ARGN) - message(FATAL_ERROR "idlc_generate called without any idl files") - endif() - - if (NOT IDLC_ARGS) - set(IDLC_ARGS) - endif() - - set(_files) - foreach(FIL ${ARGN}) - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - list(APPEND _files ${ABS_FIL}) - endforeach() - - set(_dir "${CMAKE_CURRENT_BINARY_DIR}") - set(_sources) - set(_headers) - foreach(FIL ${ARGN}) - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - get_filename_component(FIL_WE ${FIL} NAME_WE) - - set(_source "${_dir}/${FIL_WE}.c") - set(_header "${_dir}/${FIL_WE}.h") - list(APPEND _sources "${_source}") - list(APPEND _headers "${_header}") - - add_custom_command( - OUTPUT "${_source}" "${_header}" - COMMAND "${IDLC_DIR}/${IDLC}" - ARGS ${IDLC_ARGS} ${ABS_FIL} - DEPENDS "${_files}" idlc-jar - COMMENT "Running idlc on ${FIL}" - VERBATIM) - endforeach() - - add_custom_target( - "${_target}_idlc_generate" - DEPENDS "${_sources}" "${_headers}" - ) - - set_source_files_properties( - ${_sources} ${_headers} PROPERTIES GENERATED TRUE) - add_library(${_target} INTERFACE) - target_sources(${_target} INTERFACE ${_sources} ${_headers}) - target_include_directories(${_target} INTERFACE "${_dir}") - add_dependencies(${_target} "${_target}_idlc_generate") -endfunction() - diff --git a/src/idlc/cmake/dds_idlc.bat.in b/src/idlc/cmake/dds_idlc.bat.in deleted file mode 100644 index 7b7f1749e1..0000000000 --- a/src/idlc/cmake/dds_idlc.bat.in +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -REM Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -REM -REM This program and the accompanying materials are made available under the -REM terms of the Eclipse Public License v. 2.0 which is available at -REM http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -REM v. 1.0 which is available at -REM http://www.eclipse.org/org/documents/edl-v10.php. -REM -REM SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -if "%CLASSPATH%"=="" ( - set "CLASSPATH=@IDLC_JAR@" -) else ( - set "CLASSPATH=@IDLC_JAR@;%CLASSPATH%" -) - -"@Java_JAVA_EXECUTABLE@" org.eclipse.cyclonedds.compilers.Idlc %* - diff --git a/src/idlc/cmake/dds_idlc.in b/src/idlc/cmake/dds_idlc.in deleted file mode 100644 index 9929aacd2e..0000000000 --- a/src/idlc/cmake/dds_idlc.in +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# -# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License v. 2.0 which is available at -# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -# v. 1.0 which is available at -# http://www.eclipse.org/org/documents/edl-v10.php. -# -# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause -# -java -classpath "@IDLC_JAR@" org.eclipse.cyclonedds.compilers.Idlc "$@" diff --git a/src/idlc/src/org/eclipse/cyclonedds/Compiler.java b/src/idlc/src/org/eclipse/cyclonedds/Compiler.java deleted file mode 100644 index 6c945e57e8..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/Compiler.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import java.io.*; -import java.util.*; - -import org.antlr.v4.runtime.*; - -import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.*; -import org.eclipse.cyclonedds.parser.*; -import org.eclipse.cyclonedds.generator.GenVisitor; -import org.eclipse.cyclonedds.compilers.IdlcCmdOptions; - -public class Compiler -{ - private static class PreProcAwareListener extends BaseErrorListener - { - public void syntaxError - ( - Recognizer recognizer, - Object wrongSymbol, - int line, - int column, - String msg, - RecognitionException e - ) - { - System.err.println - ("Error: At " + params.linetab.getRealPosition (line) + ", " + msg); - } - } - - public static void run (IdlcCmdOptions opts) - { - if (opts.version) - { - version (); - return; - } - - try - { - String pathSep = System.getProperty ("file.separator"); - String outpath = (opts.outputdir == null) ? "" : opts.outputdir + pathSep; - String fileRoot; - - IIdlPreprocessor preprocessor = IdlPreprocessorFactory.create (); - IIdlPreprocessorStatus ppstatus; - Map> ppdependencies = new TreeMap> (); - CharArrayWriter ppresult = new CharArrayWriter (); - IIdlPreprocessorParams ppparams = preprocessor.createPreprocessorParams (); - for (String s : opts.includes) - { - ppparams.addIncludeDirectory (new File (s)); - } - for (Map.Entry macro : opts.macros.entrySet ()) - { - ppparams.addMacroDefinition (macro.getKey (), macro.getValue ()); - } - - for (String arg : opts.files) - { - params = new IdlParams (opts); - if (!arg.endsWith (".idl")) - { - arg += ".idl"; - } - if (System.getProperty ("file.separator").equals ("\\")) - { - /* Preprocessor does this conversion on Windows, so we do the same */ - arg = arg.replace ('\\', '/'); - } - - File idl = new File(arg); - if (idl.exists() && idl.isFile()) - { - if (!opts.quiet && !opts.pponly) - { - System.out.println ("Compiling " + idl.getPath ()); - } - } - else - { - System.err.println - ("Input IDL file " + idl.getPath () + " is not valid"); - System.exit (1); - } - fileRoot = - idl.getName ().substring (0, idl.getName ().lastIndexOf ('.')); - - ppstatus = - preprocessor.preprocess (ppparams, idl, ppresult, ppdependencies); - - if (!ppstatus.isOK ()) - { - System.err.println ("Error: At " + ppstatus.getFilename () + ":" + ppstatus.getLine () + ", " + ppstatus.getMessage ()); - System.exit(1); - } - if (opts.pponly) - { - System.out.println (ppresult.toCharArray ()); - System.exit (0); - } - - ANTLRInputStream input = - new ANTLRInputStream (ppresult.toCharArray(), ppresult.size ()); - Lexer lexer = new IDLLexer (input); - CommonTokenStream tokens = new CommonTokenStream (lexer); - tokens.fill (); - - if (opts.dumptokens) - { - List tlist = tokens.getTokens (); - Iterator it = tlist.iterator (); - Token t; - while (it.hasNext ()) - { - t = it.next (); - if (t.getChannel() == Token.DEFAULT_CHANNEL) - { - System.out.println (t.getText ()); - } - } - System.exit (0); - } - - params.linetab = - new LineTable (arg, tokens.getTokens ().iterator (), params.forcpp); - IDLParser parser = new IDLParser (tokens); - parser.removeErrorListeners (); - parser.addErrorListener (new PreProcAwareListener ()); - try - { - ParserRuleContext tree = (ParserRuleContext)parser.specification (); - if (parser.getNumberOfSyntaxErrors () != 0) - { - System.exit (1); - } - if (opts.dumptree) - { - if (java.awt.GraphicsEnvironment.isHeadless ()) - { - System.out.println (tree.toStringTree (parser)); - } - else - { - javax.swing.JDialog jd = tree.inspect (parser).get (); - jd.setVisible (false); - jd.setModalityType (java.awt.Dialog.ModalityType.APPLICATION_MODAL); - jd.setVisible (true); - } - System.exit(0); - } - - params.symtab = new SymbolTable (); - GenSymbolTable gst = new GenSymbolTable (params); - gst.visit (tree); - if (gst.getErrorCount () != 0) - { - System.exit (1); - } - if (gst.unresolvedSymbols ()) - { - System.exit (1); - } - - if (opts.dumpsymbols) - { - System.out.println ("Symbol table pass complete, symbols are:"); - params.symtab.dump (); - System.exit (0); - } - - params.basename = fileRoot; - - if (params.forcpp) - { - fileRoot = fileRoot.concat ("-cyclonedds"); - } - try - { - GenVisitor codegenh = new GenVisitor (params, "org/eclipse/cyclonedds/templates/h/templates.stg"); - codegenh.visit (tree); - codegenh.writeToFile (outpath + fileRoot + ".h"); - - if (!params.notopics) - { - params.quiet = true; - GenVisitor codegenc = new GenVisitor (params, "org/eclipse/cyclonedds/templates/c/templates.stg"); - codegenc.visit (tree); - codegenc.writeToFile (outpath + fileRoot + ".c"); - } - } - catch (IOException x) - { - System.err.format("IOException: %s%n", x); - System.exit (1); - } - } - catch (RecognitionException r) - { - r.printStackTrace (); - System.exit (1); - } - } - } - catch (Exception e) - { - e.printStackTrace (); - } - } - - private static void version () - { - System.out.print (Project.name); - System.out.println ("C IDL Compiler v" + Project.version); - } - - private static IdlParams params; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/EnumSymbol.java b/src/idlc/src/org/eclipse/cyclonedds/EnumSymbol.java deleted file mode 100644 index 4309ef9017..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/EnumSymbol.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -public class EnumSymbol extends TypeDefSymbol -{ - public EnumSymbol (ScopedName name) - { - super (name); - } - - public String toString () - { - return "Enum"; - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/GenSymbolTable.java b/src/idlc/src/org/eclipse/cyclonedds/GenSymbolTable.java deleted file mode 100644 index f7ac931511..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/GenSymbolTable.java +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import java.io.*; -import java.util.*; - -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.tree.TerminalNode; - -import org.eclipse.cyclonedds.parser.IDLParser; - -public class GenSymbolTable extends org.eclipse.cyclonedds.parser.IDLBaseVisitor -{ - private static class TD - { - private void invalidate () - { - valid = false; - } - private boolean isValid () - { - return valid; - } - private void setInteger () - { - isint = true; - } - private boolean isInteger () - { - return isint; - } - private void setNonintConst () - { - isnonint = true; - } - private boolean isNonintConst () - { - return isnonint; - } - - private boolean isint = false; - private boolean valid = true; - private boolean isnonint = false; - } - - public GenSymbolTable (IdlParams params) - { - currentscope = new ScopedName (); - currentstruct = null; - currentTD = null; - inIntConst = false; - inNonintConst = false; - inSwitch = false; - declarations = new HashSet (); - errorcount = 0; - this.params = params; - } - - public int getErrorCount () - { - return errorcount; - } - - public Void visitModule (IDLParser.ModuleContext ctx) - { - Void result; - currentscope.addComponent (ctx.ID().getText()); - result = super.visitModule (ctx); - currentscope.popComponent (); - return result; - } - - public Void visitInterface_decl (IDLParser.Interface_declContext ctx) - { - Void result; - currentscope.addComponent (ctx.interface_header ().ID ().getText ()); - result = super.visitInterface_body (ctx.interface_body ()); - currentscope.popComponent (); - return result; - } - - public Void visitStruct_type (IDLParser.Struct_typeContext ctx) - { - Void result; - boolean declared; - StructSymbol oldstruct = currentstruct; - currentscope.addComponent (ctx.ID ().getText ()); - currentstruct = new StructSymbol (new ScopedName (currentscope)); - result = super.visitStruct_type (ctx); - declared = declarations.remove (currentscope); - if (currentstruct.isValid ()) - { - params.symtab.add (currentstruct); - } - else - { - if (params.lax && declared) - { - printErr - ( - ctx.KW_STRUCT ().getSymbol ().getLine (), - "Definition of predeclared struct " + currentscope + - " contains unsupported data types" - ); - } - } - currentstruct = oldstruct; - currentscope.popComponent (); - return result; - } - - public Void visitSimple_declarator (IDLParser.Simple_declaratorContext ctx) - { - if (currentstruct != null) - { - StructSymbol stype = null; - try - { - IDLParser.MemberContext mem = (IDLParser.MemberContext)ctx.getParent ().getParent ().getParent (); - if (mem.type_spec ().simple_type_spec () != null) - { - IDLParser.Scoped_nameContext snctx = mem.type_spec ().simple_type_spec ().scoped_name (); - if (snctx != null) - { - Symbol stype_or_typedef = stresolve (snfromctx (snctx), isRelative (snctx)); - while (stype_or_typedef instanceof TypeDeclSymbol) - { - TypeDeclSymbol td = (TypeDeclSymbol)stype_or_typedef; - stype_or_typedef = params.symtab.resolve (td.isRelative() ? td.name() : null, td.definition()); - } - stype = (StructSymbol) stype_or_typedef; - } - } - else - { - if (mem.type_spec ().constr_type_spec () != null) - { - IDLParser.Struct_typeContext stctx = mem.type_spec ().constr_type_spec ().struct_type (); - if (stctx != null) - { - ScopedName stname = new ScopedName (currentscope); - stname.addComponent (stctx.ID ().getText ()); - stype = (StructSymbol)params.symtab.getSymbol (stname); - } - } - } - } - catch (Exception ex) - { - } - if (stype != null) - { - currentstruct.addStructMember (ctx.ID ().getText (), stype); - } - else - { - currentstruct.addMember (ctx.ID ().getText ()); - } - } - return super.visitSimple_declarator (ctx); - } - - public Void visitArray_declarator (IDLParser.Array_declaratorContext ctx) - { - if (currentstruct != null) - { - currentstruct.addMember (ctx.ID ().getText ()); - } - return super.visitArray_declarator (ctx); - } - - public Void visitPragma_decl (IDLParser.Pragma_declContext ctx) - { - int line = ctx.LINE_PRAGMA().getSymbol ().getLine (); - StringTokenizer pragma = new StringTokenizer (ctx.LINE_PRAGMA().getText ()); - pragma.nextToken (); /* Skip "#pragma" */ - if (pragma.hasMoreTokens () && pragma.nextToken ().equals ("keylist")) - { - String topicType = pragma.nextToken (); - ScopedName topicSN = new ScopedName (topicType); - Symbol topic; - if (topicType.startsWith ("::")) - { - topic = params.symtab.resolve (null, topicSN); - } - else - { - topic = params.symtab.resolve (currentscope, topicSN); - } - if (topic == null || !(topic instanceof StructSymbol)) - { - printErr - ( - line, - "unable to resolve topic " + topicType + " for key, in scope " + - currentscope - ); - } - else - { - StructSymbol topicStruct = (StructSymbol)topic; - String field; - while (pragma.hasMoreTokens ()) - { - field = pragma.nextToken (); - if (!topicStruct.hasMember (field)) - { - printErr - (line, "keyfield " + field + " is either missing or unsupported"); - } - } - } - } - return super.visitPragma_decl (ctx); - } - - public Void visitEnum_type (IDLParser.Enum_typeContext ctx) - { - Void result; - currentscope.addComponent (ctx.ID ().getText ()); - params.symtab.add (new EnumSymbol (new ScopedName (currentscope))); - result = super.visitEnum_type (ctx); - currentscope.popComponent (); - return result; - } - - public Void visitEnumerator (IDLParser.EnumeratorContext ctx) - { - ScopedName SN = new ScopedName (currentscope); - SN.popComponent (); - SN.addComponent (ctx.ID ().getText ()); - params.symtab.add (new IntConstSymbol (SN)); - return super.visitEnumerator (ctx); - } - - public Void visitType_declarator (IDLParser.Type_declaratorContext ctx) - { - ScopedName newscope; - TypeDeclSymbol newTD; - Void result; - - currentTD = new TD (); - result = super.visitType_declarator (ctx); - - if (currentTD.isValid ()) - { - for (IDLParser.DeclaratorContext dctx : ctx.declarators ().declarator ()) - { - newscope = new ScopedName (currentscope); - if (dctx.simple_declarator () != null) - { - newscope.addComponent (dctx.simple_declarator ().ID ().getText ()); - newTD = new TypeDeclSymbol - ( - newscope, - ctx.type_spec (), - null, - currentTD.isInteger (), - currentTD.isNonintConst () - ); - } - else - { - newscope.addComponent - (dctx.complex_declarator ().array_declarator ().ID ().getText ()); - newTD = new TypeDeclSymbol - ( - newscope, - ctx.type_spec (), - dctx.complex_declarator ().array_declarator ().fixed_array_size (), - currentTD.isInteger (), - currentTD.isNonintConst () - ); - } - params.symtab.add (newTD); - } - } - currentTD = null; - return result; - } - - private boolean isStructMember (IDLParser.Scoped_nameContext ctx) - { - try - { - return ctx.getParent ().getParent ().getParent () instanceof IDLParser.MemberContext; - } - catch (NullPointerException ex) - { - } - return false; - } - - private ScopedName snfromctx (IDLParser.Scoped_nameContext ctx) - { - ScopedName result = new ScopedName (); - for (TerminalNode element : ctx.ID ()) - { - result.addComponent (element.getSymbol ().getText ()); - } - return result; - } - - private boolean isRelative (IDLParser.Scoped_nameContext ctx) - { - return ctx.ID ().size () > ctx.DOUBLE_COLON ().size (); - } - - private Symbol stresolve (ScopedName sn, boolean relative) - { - return params.symtab.resolve ((relative ? currentscope : null), sn); - } - - public Void visitScoped_name (IDLParser.Scoped_nameContext ctx) - { - Symbol target; - ScopedName requestSN = snfromctx (ctx); - boolean relative = isRelative (ctx); - int line = ctx.ID (0).getSymbol ().getLine (); - - target = stresolve (requestSN, relative); - - if (target == null) - { - if (isStructMember (ctx) || inIntConst) - { - printErr (line, requestSN + " is not defined."); - } - else if (relative) - { - boolean found; - ScopedName s = new ScopedName (currentscope); - do - { - found = declarations.contains (s.catenate (requestSN)); - } - while (!found && !s.popComponent().equals ("")); - if (!found) - { - printErr (line, "unable to resolve name " + requestSN + " in scope " + currentscope); - } - } - else - { - if (!declarations.contains (requestSN)) - { - printErr (line, "unable to resolve name " + requestSN); - } - } - } - else - { - boolean targetint = target instanceof IntConstSymbol; - boolean targetnonint = target instanceof OtherConstSymbol; - if (target instanceof TypeDeclSymbol) - { - targetint = ((TypeDeclSymbol)target).isInteger (); - targetnonint = ((TypeDeclSymbol)target).isNonintConst (); - } - if (currentTD != null) - { - if (targetint) - { - currentTD.setInteger (); - } - if (targetnonint) - { - currentTD.setNonintConst (); - } - } - - boolean valid = true; - if (inIntConst || inSwitch) - { - valid = targetint; - } - else - if (inNonintConst) - { - valid = targetnonint; - } - if (!valid) - { - printErr (line, "scoped name " + target.name () + " does not refer to a valid type"); - } - } - - return super.visitScoped_name (ctx); - } - - public Void visitConstr_forward_decl (IDLParser.Constr_forward_declContext ctx) - { - ScopedName decl = new ScopedName (currentscope); - decl.addComponent (ctx.ID ().getText ()); - declarations.add (decl); - return super.visitConstr_forward_decl (ctx); - } - - public Void visitCase_label (IDLParser.Case_labelContext ctx) - { - Void result; - inSwitch = true; - result = super.visitCase_label (ctx); - inSwitch = false; - return result; - } - - public Void visitLiteral (IDLParser.LiteralContext ctx) - { - if (inIntConst) - { - if (ctx.INTEGER_LITERAL () == null && ctx.HEX_LITERAL () == null && ctx.OCTAL_LITERAL () == null) - { - printErr - ( - ctx.getStart ().getLine (), - "non-integer literal in integer constant definition" - ); - } - } - return super.visitLiteral (ctx); - } - - public Void visitConst_decl (IDLParser.Const_declContext ctx) - { - Void result; - boolean iic = inIntConst; - boolean inic = inNonintConst; - boolean integral = false; - boolean valid = true; - - IDLParser.Const_typeContext const_type = ctx.const_type (); - currentscope.addComponent (ctx.ID ().getText ()); - if (const_type.integer_type() != null || const_type.octet_type () != null) - { - integral = true; - } - else - { - if (const_type.scoped_name() != null) - { - IDLParser.Scoped_nameContext snctx = const_type.scoped_name (); - Symbol stype = stresolve (snfromctx (snctx), isRelative (snctx)); - if (stype instanceof TypeDeclSymbol) - { - if (((TypeDeclSymbol)stype).isInteger ()) - { - integral = true; - } - else if (((TypeDeclSymbol)stype).isNonintConst ()) - { - integral = false; - } - else - { - valid = false; - printErr - ( - ctx.KW_CONST ().getSymbol ().getLine (), - "typedef " + stype.name () + " is not valid for const declaration" - ); - } - } - else - { - // Error will be generated upstream - } - } - else - { - integral = false; - } - } - - if (valid) - { - if (integral) - { - params.symtab.add (new IntConstSymbol (new ScopedName (currentscope))); - inIntConst = true; - } - else - { - params.symtab.add - (new OtherConstSymbol (new ScopedName (currentscope))); - inNonintConst = true; - } - } - - result = super.visitConst_decl (ctx); - currentscope.popComponent (); - inIntConst = iic; - inNonintConst = inic; - return result; - } - - public Void visitPositive_int_const (IDLParser.Positive_int_constContext ctx) - { - Void result; - boolean iic = inIntConst; - inIntConst = true; - result = super.visitPositive_int_const (ctx); - inIntConst = iic; - return result; - } - - public Void visitUnion_type (IDLParser.Union_typeContext ctx) - { - Void result; - currentscope.addComponent (ctx.ID ().getText ()); - params.symtab.add (new UnionSymbol (new ScopedName (currentscope))); - result = super.visitUnion_type (ctx); - currentscope.popComponent (); - return result; - } - - /* Unsupported types */ - - private void bogusType (String reason, TerminalNode where) - { - if (currentstruct != null) - { - if (params.lax) - { - currentstruct.invalidate (); - } - else - { - printErr (where.getSymbol ().getLine (), reason); - } - } - if (currentTD != null) - { - if (params.lax) - { - currentTD.invalidate (); - } - else - { - printErr (where.getSymbol ().getLine (), reason); - } - } - } - - /* Unsupported but mappable types */ - - public Void visitWide_char_type (IDLParser.Wide_char_typeContext ctx) - { - if (!params.mapwide) - { - bogusType - ("wide char data not supported in" + Project.name, ctx.KW_WCHAR ()); - } - return super.visitWide_char_type (ctx); - } - - public Void visitWide_string_type (IDLParser.Wide_string_typeContext ctx) - { - if (!params.mapwide) - { - bogusType - ("wide string data not supported in " + Project.name, ctx.KW_WSTRING ()); - } - return super.visitWide_string_type (ctx); - } - - /* These next ones NYI or potentially so */ - - public Void visitFixed_pt_type (IDLParser.Fixed_pt_typeContext ctx) - { - bogusType - ("fixed point data not supported in " + Project.name, ctx.KW_FIXED ()); - return super.visitFixed_pt_type (ctx); - } - - public Void visitSequence_type (IDLParser.Sequence_typeContext ctx) - { - if (ctx.positive_int_const() != null) - { - bogusType - ("bounded sequences not supported in " + Project.name, ctx.KW_SEQUENCE ()); - } - return super.visitSequence_type (ctx); - } - - /* And these aren't DDS */ - - public Void visitAny_type (IDLParser.Any_typeContext ctx) - { - bogusType ("any data not valid for DDS", ctx.KW_ANY ()); - return super.visitAny_type (ctx); - } - - public Void visitObject_type (IDLParser.Object_typeContext ctx) - { - bogusType ("Object data not valid for DDS", ctx.KW_OBJECT ()); - return super.visitObject_type (ctx); - } - - public Void visitValue_base_type (IDLParser.Value_base_typeContext ctx) - { - bogusType ("ValueBase data not valid for DDS", ctx.KW_VALUEBASE ()); - return super.visitValue_base_type (ctx); - } - - /* Verification of const types */ - - public Void visitInteger_type (IDLParser.Integer_typeContext ctx) - { - if (currentTD != null) - { - currentTD.setInteger (); - } - return super.visitInteger_type (ctx); - } - - public Void visitFloating_pt_type (IDLParser.Floating_pt_typeContext ctx) - { - if (ctx.KW_LONG () != null && !params.mapld) - { - bogusType - ("long double data not supported in " + Project.name, ctx.KW_LONG ()); - } - if (currentTD != null) - { - currentTD.setNonintConst (); - } - return super.visitFloating_pt_type (ctx); - } - - public Void visitBoolean_type (IDLParser.Boolean_typeContext ctx) - { - if (currentTD != null) - { - currentTD.setNonintConst (); - } - return super.visitBoolean_type (ctx); - } - - public boolean unresolvedSymbols () - { - if (declarations.isEmpty ()) - { - return false; - } - else - { - System.err.print ("Error: The following declarations were not defined:"); - for (ScopedName decl : declarations) - { - System.err.print (" " + decl); - } - System.err.println (); - return true; - } - } - - private void printErr (int line, String err) - { - System.err.println - ("Error: At " + params.linetab.getRealPosition (line) + ", " + err); - errorcount++; - } - - private IdlParams params; - private ScopedName currentscope; - private StructSymbol currentstruct; - private TD currentTD; - private boolean inIntConst, inNonintConst, inSwitch; - private Set declarations; - private int errorcount; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/IdlParams.java b/src/idlc/src/org/eclipse/cyclonedds/IdlParams.java deleted file mode 100644 index dbb22e015b..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/IdlParams.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import org.eclipse.cyclonedds.compilers.IdlcCmdOptions; - -public class IdlParams -{ - public IdlParams (IdlcCmdOptions opts) - { - timestamp = !opts.nostamp; - quiet = opts.quiet; - lax = opts.lax; - mapwide = opts.mapwide; - mapld = opts.mapld; - forcpp = opts.forcpp; - dllname = opts.dllname; - dllfile = opts.dllfile; - xmlgen = !opts.noxml; - allstructs = opts.allstructs; - notopics = opts.notopics; - } - - public boolean timestamp; - public boolean quiet; - public boolean lax; - public boolean mapwide; - public boolean mapld; - public boolean forcpp; - public boolean xmlgen; - public boolean allstructs; - public boolean notopics; - public String dllname; - public String dllfile; - public String basename = null; - public SymbolTable symtab = null; - public LineTable linetab = null; -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/IntConstSymbol.java b/src/idlc/src/org/eclipse/cyclonedds/IntConstSymbol.java deleted file mode 100644 index 09d26b2d32..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/IntConstSymbol.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -public class IntConstSymbol extends Symbol -{ - public IntConstSymbol (ScopedName name) - { - super (name); - } - - public String toString () - { - return "Integer constant"; - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/LineTable.java b/src/idlc/src/org/eclipse/cyclonedds/LineTable.java deleted file mode 100644 index 448e1496ae..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/LineTable.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import java.util.*; -import java.io.File; -import org.antlr.v4.runtime.*; -import org.stringtemplate.v4.ST; - -import org.eclipse.cyclonedds.parser.IDLParser; - -public class LineTable -{ - private static class Entry - { - int position; - int line; - String file; - } - - public LineTable (String filename, Iterator it, boolean forcpp) - { - Token t; - Entry e; - StringTokenizer lineinfo; - StringBuffer realfile; - String basename; - int depth = 0; - - this.filename = filename; - if (forcpp) - { - suffix = "-cyclone"; - } - else - { - suffix = ""; - } - table = new LinkedList (); - subfiles = new ArrayList (); - - while (it.hasNext ()) - { - t = it.next (); - if (t.getType () == IDLParser.CODEPOS) - { - e = new Entry (); - e.position = t.getLine (); - lineinfo = new StringTokenizer (t.getText ()); - lineinfo.nextToken (); // Skip '#' - e.line = Integer.parseInt (lineinfo.nextToken ()); - realfile = new StringBuffer (lineinfo.nextToken ()); - while (realfile.charAt (realfile.length () - 1) != '"') - { - realfile.append (" " + lineinfo.nextToken ()); - } - e.file = realfile.substring (1, realfile.length () - 1); // Strip quotes - - table.add (e); - - if (t.getText ().endsWith (" 1")) - { - if (depth++ == 0) - { - subfiles.add - (e.file.substring (0, e.file.lastIndexOf (".")) + suffix); - } - } - else if (t.getText ().endsWith (" 2")) - { - depth--; - } - } - } - } - - private Entry getRelevantEntry (int pos) - { - Entry e; - Iterator iter = table.descendingIterator (); - - do - { - e = iter.next (); - } while (e.position > pos); - - return e; - } - - public String getRealPosition (int pos) - { - Entry e = getRelevantEntry (pos); - return e.file + ":" + (pos + e.line - e.position - 1); - } - - public boolean inMain (int pos) - { - return getRelevantEntry (pos).file.equals (filename); - } - - public void populateIncs (ST template) - { - for (String s : subfiles) - { - template.add ("includes", new File (s).getName ()); - } - } - - private String filename; - private String suffix; - private LinkedList table; - private ArrayList subfiles; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/OtherConstSymbol.java b/src/idlc/src/org/eclipse/cyclonedds/OtherConstSymbol.java deleted file mode 100644 index ff8819f25b..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/OtherConstSymbol.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -public class OtherConstSymbol extends Symbol -{ - public OtherConstSymbol (ScopedName name) - { - super (name); - } - - public String toString () - { - return "Non-integer constant"; - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/Project.java.in b/src/idlc/src/org/eclipse/cyclonedds/Project.java.in deleted file mode 100644 index bb01a3bb11..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/Project.java.in +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -public class Project -{ - public static String version = "@PROJECT_VERSION@"; - public static String name = "@PROJECT_NAME@"; - public static String nameCaps = "@PROJECT_NAME_CAPS@"; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/ScopedName.java b/src/idlc/src/org/eclipse/cyclonedds/ScopedName.java deleted file mode 100644 index 8964d3990a..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/ScopedName.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import java.util.*; - -public class ScopedName implements Comparable -{ - public ScopedName () - { - components = new ArrayList (); - } - - public ScopedName (ScopedName rhs) - { - components = new ArrayList (rhs.components.size ()); - for (String s : rhs.components) - { - components.add (s); - } - } - - public ScopedName (String[] components) - { - this.components = new ArrayList (components.length); - for (String s : components) - { - if (!s.equals ("")) - { - this.components.add (s); - } - } - } - - public ScopedName (List components) - { - this.components = new ArrayList (components); - } - - public ScopedName (String colonscopedname) - { - this (colonscopedname.split ("::")); - } - - public void addComponent (String x) - { - components.add (x); - } - - public String popComponent () - { - if (components.isEmpty ()) - { - return ""; - } - else - { - return components.remove (components.size () - 1); - } - } - - public String getLeaf () - { - if (components.isEmpty ()) - { - return ""; - } - else - { - return components.get (components.size () - 1); - } - } - - public String[] getPath () - { - String[] result = new String[0]; - - if (components.size () >= 2) - { - result = components.subList (0, components.size () - 1).toArray (result); - } - return result; - } - - public String[] getComponents () - { - return components.toArray (new String[0]); - } - - public String toString (String scoper) - { - boolean first = true; - StringBuffer result = new StringBuffer (""); - for (String element: components) - { - if (first) - { - first = false; - } - else - { - result.append (scoper); - } - result.append (element); - } - return result.toString (); - } - - public String toString () - { - return toString ("::"); - } - - public ScopedName catenate (ScopedName more) - { - ScopedName result = new ScopedName (); - result.components.addAll (components); - result.components.addAll (more.components); - return result; - } - - public int compareTo (ScopedName rhs) - { - int result = 0, pos = 0; - int ldepth = depth (); - int rdepth = rhs.depth (); - while (result == 0 && pos < ldepth && pos < rdepth) - { - result = components.get (pos).compareTo (rhs.components.get (pos)); - pos++; - } - if (result == 0) - { - result = Integer.compare (ldepth, rdepth); - } - return result; - } - - public static Comparator osplComparator - = new Comparator () - { - public int compare(ScopedName lhs, ScopedName rhs) - { - int ldepth = lhs.depth (); - int rdepth = rhs.depth (); - if (ldepth == 0 || rdepth == 0) - { - return Integer.compare (ldepth, rdepth); - } - else - { - int result = 0, pos = 0; - while (result == 0 && pos < ldepth && pos < rdepth) - { - result = - lhs.components.get (pos).compareTo (rhs.components.get (pos)); - pos++; - } - if (result == 0) - { - result = Integer.compare (rdepth, ldepth); - } - return result; - } - } - }; - - public boolean isParentOf (ScopedName other) - { - if (other.components.size() <= components.size ()) - { - return false; - } - for (int i = 0; i < components.size (); i++) - { - if (!components.get (i).equals (other.components.get (i))) - { - return false; - } - } - return true; - } - - public boolean equals (Object o) - { - return (o instanceof ScopedName && compareTo ((ScopedName)o) == 0); - } - - public int hashCode () - { - int result = 0; - for (String c : components) - { - result ^= c.hashCode (); - } - return result; - } - - public int depth () - { - return components.size (); - } - - public void reset () - { - components.clear (); - } - - private ArrayList components; -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/StructSymbol.java b/src/idlc/src/org/eclipse/cyclonedds/StructSymbol.java deleted file mode 100644 index dc19499cb4..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/StructSymbol.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import java.util.*; - -public class StructSymbol extends TypeDefSymbol -{ - public StructSymbol (ScopedName name) - { - super (name); - members = new ArrayList (); - valid = true; - } - - public String toString () - { - StringBuffer result = new StringBuffer ("Struct, members are"); - for (String s : members) - { - result.append (' '); - result.append (s); - } - return result.toString (); - } - - public void addMember (String membername) - { - members.add (membername); - } - - public void addStructMember (String membername, StructSymbol membertype) - { - for (String s : membertype.members) - { - members.add (membername + "." + s); - } - } - - public boolean hasMember (String membername) - { - return members.contains (membername); - } - - public void invalidate () - { - valid = false; - } - - public boolean isValid () - { - return valid; - } - - private List members; - private boolean valid; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/SymbolTable.java b/src/idlc/src/org/eclipse/cyclonedds/SymbolTable.java deleted file mode 100644 index 8e5a0540c7..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/SymbolTable.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import java.util.*; - -public class SymbolTable -{ - public SymbolTable() - { - map = new HashMap (); - } - - public void add (Symbol newsym) - { - Symbol oldval; - oldval = map.put (newsym.name (), newsym); - if (oldval != null) - { - System.err.println ("Internal inconsistency, multiple definition for " + newsym.name ()); - System.err.println ("Old value was " + oldval.toString ()); - System.err.println ("New value is " + newsym.toString ()); - } - } - - public Symbol resolve (ScopedName current, ScopedName request) - { - Symbol result = null; - if (current != null) - { - ScopedName searchscope = new ScopedName (current); - do - { - result = map.get (searchscope.catenate (request)); - } - while (result == null && ! searchscope.popComponent().equals ("")); - } - if (result == null) - { - result = map.get (request); - } - return result; - } - - public Symbol getSymbol (ScopedName request) - { - return map.get (request); - } - - public void dump () - { - for (Map.Entry sym : map.entrySet ()) - { - System.out.println (sym.getKey () + " is a " + sym.getValue ()); - } - } - - Map map; -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/TypeDeclSymbol.java b/src/idlc/src/org/eclipse/cyclonedds/TypeDeclSymbol.java deleted file mode 100644 index d3fd45996e..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/TypeDeclSymbol.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -import java.util.List; - -import org.eclipse.cyclonedds.parser.IDLParser; - -public class TypeDeclSymbol extends TypeDefSymbol -{ - public TypeDeclSymbol - ( - ScopedName name, - IDLParser.Type_specContext definition, - List dimensions, - boolean isint, - boolean isnonint - ) - { - super (name); - if (definition.simple_type_spec () != null) - { - def = definition.getText (); - } - else - { - IDLParser.Constr_type_specContext cts = (IDLParser.Constr_type_specContext) definition.constr_type_spec (); - if (cts.struct_type () != null) { - def = cts.struct_type ().ID ().getText (); - } else if (cts.union_type () != null) { - def = cts.union_type ().ID ().getText (); - } else { - def = cts.enum_type ().ID ().getText (); - } - } - this.isint = isint; - this.isnonint = isnonint; - } - - public String toString () - { - return "Typedef = " + def; - } - - public ScopedName definition () - { - return new ScopedName(def); - } - - public boolean isRelative () - { - return !def.startsWith("::"); - } - - public boolean isInteger () - { - return isint; - } - public boolean isNonintConst () - { - return isnonint; - } - - private String def; - private boolean isint; - private boolean isnonint; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/UnionSymbol.java b/src/idlc/src/org/eclipse/cyclonedds/UnionSymbol.java deleted file mode 100644 index 4a28e905c2..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/UnionSymbol.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds; - -public class UnionSymbol extends TypeDefSymbol -{ - public UnionSymbol (ScopedName name) - { - super (name); - valid = true; - } - - public String toString () - { - return "Union"; - } - - public void invalidate () - { - valid = false; - } - - public boolean isValid () - { - return valid; - } - - private boolean valid; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/compilers/CmdException.java b/src/idlc/src/org/eclipse/cyclonedds/compilers/CmdException.java deleted file mode 100644 index 98b42aa89d..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/compilers/CmdException.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.compilers; - -public class CmdException extends Exception -{ - public CmdException (int retcode) - { - this.retcode = retcode; - } - - public final int retcode; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/compilers/CmdOptions.java b/src/idlc/src/org/eclipse/cyclonedds/compilers/CmdOptions.java deleted file mode 100644 index e4862017ff..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/compilers/CmdOptions.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.compilers; - -import java.util.*; - -public class CmdOptions -{ - public CmdOptions (String compilername, String[] args) throws CmdException - { - this.name = compilername; - files = new ArrayList (); - includes = new ArrayList (); - macros = new HashMap (); - - int i = 0; - while (i < args.length && args[i].startsWith ("-")) - { - if (process (args[i], ((i + 1 < args.length) ? args[i + 1] : null))) - { - i++; - } - i++; - } - while (i < args.length) - { - files.add (args[i++]); - } - } - - public CmdOptions (CmdOptions rhs) - { - dllname = rhs.dllname; - dllfile = rhs.dllfile; - outputdir = rhs.outputdir; - includes = new ArrayList (rhs.includes); - macros = new HashMap (rhs.macros); - version = rhs.version; - files = new ArrayList (rhs.files); - name = rhs.name; - noxml = rhs.noxml; - } - - public void optHelp (java.io.PrintStream io) - { - io.println ("Usage: " + name + " [options] file(s).idl"); - io.println (); - io.println (" options:"); - io.println (" -help This help screen"); - io.println (" -version Print compiler version"); - io.println (" -d directory Output directory for generated files"); - io.println (" -I path Add directory to #include search path"); - io.println (" -D macro Define conditional compilation symbol"); - io.println (" -dll name[,file] Generate DLL linkage declarations"); - io.println (" -noxml Do not generate XML Topic descriptors"); - } - - public boolean process (String arg1, String arg2) throws CmdException - { - boolean result = false; // whether or not we used arg2 - if (arg1.equals ("-h") || arg1.equals ("-?") || arg1.equals ("-help")) - { - optHelp (System.out); - throw new CmdException (0); - } - else if (arg1.equals ("-v") || arg1.equals ("-version")) - { - version = true; - } - else if (arg1.equals ("-d")) - { - if (arg2 == null || arg2.charAt (0) == '-') - { - System.err.println - (name + ": Directory name expected following -d option"); - throw new CmdException (1); - } - outputdir = arg2; - result = true; - } - else if (arg1.startsWith ("-dll") || arg1.startsWith ("-P")) - { - if (arg1.equals ("-dll") || arg1.equals ("-P")) - { - if (arg2 == null || arg2.charAt (0) == '-') - { - System.err.println - (name + ": DLL name expected following " + arg1 + " option"); - throw new CmdException (1); - } - processDll (arg2); - result = true; - } - else - { - if (arg1.startsWith ("-dll")) - { - processDll (arg2.substring (4)); - } - else - { - processDll (arg2.substring (2)); - } - } - } - else if (arg1.equals ("-noxml")) - { - noxml = true; - } - else if (arg1.startsWith ("-I")) - { - if (arg1.equals ("-I")) - { - if (arg2 == null || arg2.charAt (0) == '-') - { - System.err.println (name + ": Include search path directory expected following -I option"); - throw new CmdException (1); - } - includes.add (arg2); - result = true; - } - else - { - includes.add (arg1.substring (2)); - } - } - else if (arg1.startsWith ("-D")) - { - if (arg1.equals ("-D")) - { - if (arg2 == null || arg2.charAt (0) == '-') - { - System.err.println (name + ": Conditional compilation identifier expected following -D option"); - throw new CmdException (1); - } - addMacro (arg2); - result = true; - } - else - { - addMacro (arg1.substring (2)); - } - } - else - { - optHelp (System.out); - throw new CmdException (1); - } - return result; - } - - private void addMacro (String m) - { - int pos = m.indexOf ("="); - if (pos > 0) - { - macros.put (m.substring (0, pos), m.substring (pos + 1)); - } - else - { - macros.put (m, ""); - } - } - - private void processDll (String arg) - { - int pos = arg.indexOf (","); - if (pos > 0) - { - dllname = arg.substring (0, pos); - dllfile = arg.substring (pos + 1); - } - else - { - dllname = arg; - } - } - - public String dllname = null; - public String dllfile = null; - public String outputdir = null; - public boolean noxml; - public List includes; - public Map macros; - public boolean version = false; - public List files; - final String name; -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/compilers/Idlc.java b/src/idlc/src/org/eclipse/cyclonedds/compilers/Idlc.java deleted file mode 100644 index 47947d0933..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/compilers/Idlc.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.compilers; - -public class Idlc -{ - public static void main (String[] args) - { - IdlcCmdOptions opts = null; - - try - { - opts = new IdlcCmdOptions (args); - } - catch (CmdException ex) - { - System.exit (ex.retcode); - } - - org.eclipse.cyclonedds.Compiler.run (opts); - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/compilers/IdlcCmdOptions.java b/src/idlc/src/org/eclipse/cyclonedds/compilers/IdlcCmdOptions.java deleted file mode 100644 index 75898b389e..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/compilers/IdlcCmdOptions.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.compilers; - -public class IdlcCmdOptions extends CmdOptions -{ - public IdlcCmdOptions (String[] args) throws CmdException - { - super ("dds_idlc", args); - } - - public IdlcCmdOptions (IdlcppCmdOptions cppopts) - { - super (cppopts); - forcpp = true; - pponly = cppopts.pponly; - quiet = cppopts.quiet; - nostamp = cppopts.nostamp; - } - - public void optHelp (java.io.PrintStream io) - { - super.optHelp (io); - io.println (" -E Preprocess only, to standard output"); - io.println (" -allstructs All structs are Topics"); - io.println (" -notopics Generate type definitions only"); - io.println (" -nostamp Do not timestamp generated code"); - io.println (" -lax Skip over structs containing unsupported datatypes"); - io.println (" -quiet Suppress console output other than error messages (default)"); - io.println (" -verbose Enable console output other than error messages"); - io.println (" -map_wide Map the unsupported wchar and wstring types to char and string"); - io.println (" -map_longdouble Map the unsupported long double type to double"); - } - - public boolean process (String arg1, String arg2) throws CmdException - { - if (arg1.equals ("-E")) - { - pponly = true; - } - else if (arg1.equals ("-allstructs")) - { - if (notopics) - { - System.err.println (name + ": -allstructs and -notopics are mutually exclusive options"); - throw new CmdException (1); - } - allstructs = true; - } - else if (arg1.equals ("-notopics")) - { - if (allstructs) - { - System.err.println (name + ": -allstructs and -notopics are mutually exclusive options"); - throw new CmdException (1); - } - notopics = true; - } - else if (arg1.equals ("-nostamp")) - { - nostamp = true; - } - else if (arg1.equals ("-quiet") || arg1.equals ("-q")) - { - quiet = true; - } - else if (arg1.equals ("-verbose") || arg1.equals ("-v")) - { - quiet = false; - } - else if (arg1.equals ("-lax")) - { - lax = true; - } - else if (arg1.equals ("-map_wide")) - { - mapwide = true; - } - else if (arg1.equals ("-map_longdouble")) - { - mapld = true; - } - else if (arg1.equals ("-dumptokens")) - { - dumptokens = true; - } - else if (arg1.equals ("-dumptree")) - { - dumptree = true; - } - else if (arg1.equals ("-dumpsymbols")) - { - dumpsymbols = true; - } - else if (arg1.equals ("-forcpp")) - { - forcpp = true; - } - else - { - return super.process (arg1, arg2); - } - return false; - } - - public boolean pponly; - public boolean allstructs; - public boolean notopics; - public boolean nostamp; - public boolean quiet = true; - public boolean lax; - public boolean mapwide; - public boolean mapld; - public boolean dumptokens; - public boolean dumptree; - public boolean dumpsymbols; - public boolean forcpp; -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/compilers/Idlcpp.java b/src/idlc/src/org/eclipse/cyclonedds/compilers/Idlcpp.java deleted file mode 100644 index e56157acb1..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/compilers/Idlcpp.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.compilers; - -import java.util.*; -import org.eclipse.cyclonedds.Project; - -public class Idlcpp -{ - public static void main (String[] args) - { - IdlcppCmdOptions opts = null; - int status = 0; - - try - { - opts = new IdlcppCmdOptions (args); - } - catch (CmdException ex) - { - System.exit (ex.retcode); - } - - List idlppcmd = new ArrayList (); - - if (opts.version) - { - System.out.print ("Eclipse Cyclone DDS "); - System.out.println ("IDL to C++ compiler v" + Project.version); - } - else - { - String FS = System.getProperty ("file.separator"); - String projecthome = System.getProperty (Project.nameCaps + "_HOME"); - String projecthost = System.getProperty (Project.nameCaps + "_HOST"); - - opts.includes.add (projecthome + FS + "etc" + FS + "idl"); - - IdlcCmdOptions idlcopts = new IdlcCmdOptions (opts); - - if (!opts.pponly) - { - idlppcmd.add (projecthome + FS + "bin" + FS + projecthost + FS + "idlpp"); - idlppcmd.add ("-S"); - idlppcmd.add ("-a"); - idlppcmd.add (projecthome + FS + "etc" + FS + "idlpp"); - idlppcmd.add ("-x"); - idlppcmd.add ("cyclone"); - - idlppcmd.add ("-l"); - if (opts.language == null) - { - idlppcmd.add ("isoc++"); - } - else - { - idlppcmd.add (opts.language); - } - - if (opts.dllname != null) - { - idlppcmd.add ("-P"); - if (opts.dllfile != null) - { - idlppcmd.add (opts.dllname + "," + opts.dllfile); - } - else - { - idlppcmd.add (opts.dllname); - } - } - if (opts.outputdir != null) - { - idlppcmd.add ("-d"); - idlppcmd.add (opts.outputdir); - } - for (String s : opts.includes) - { - idlppcmd.add ("-I"); - idlppcmd.add (s); - } - for (String s : opts.macros.keySet ()) - { - idlppcmd.add ("-D"); - String val = opts.macros.get (s); - if (!val.equals ("")) - { - idlppcmd.add (s + "=" + val); - } - else - { - idlppcmd.add (s); - } - } - - if (opts.testmethods) - { - idlppcmd.add ("-T"); - } - - idlppcmd.addAll (opts.files); - - status = runcmd (idlppcmd); - } - org.eclipse.cyclonedds.Compiler.run (idlcopts); - } - System.exit (status); - } - - private static int runcmd (List cmdline) - { - int result; - try - { - result = new ProcessBuilder (cmdline).inheritIO ().start (). waitFor (); - if (result != 0) - { - System.err.print ("dds_idlcpp: nonzero return from"); - for (String s : cmdline) - { - System.err.print (" " + s); - } - System.err.println (); - } - } - catch (Exception ex) - { - System.err.print ("dds_idlcpp: exception when running"); - for (String s : cmdline) - { - System.err.print (" " + s); - } - System.err.println (); - System.err.println (ex); - result = 1; - } - return result; - } -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/compilers/IdlcppCmdOptions.java b/src/idlc/src/org/eclipse/cyclonedds/compilers/IdlcppCmdOptions.java deleted file mode 100644 index cb64dee741..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/compilers/IdlcppCmdOptions.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.compilers; - -public class IdlcppCmdOptions extends CmdOptions -{ - public IdlcppCmdOptions (String[] args) throws CmdException - { - super ("dds_idlcpp", args); - } - - public void optHelp (java.io.PrintStream io) - { - super.optHelp (io); - io.println (" -l [isocpp|cpp] Select ISO C++ or classic generation"); - io.println (" -E Preprocess only, to standard output"); - io.println (" -nostamp Do not timestamp generated code"); - io.println (" -quiet Suppress console output other than error messages"); - } - - public boolean process (String arg1, String arg2) throws CmdException - { - boolean result = false; - if (arg1.equals ("-E")) - { - pponly = true; - } - else if (arg1.equals ("-nostamp")) - { - nostamp = true; - } - else if (arg1.equals ("-quiet") || arg1.equals ("-q")) - { - quiet = true; - } - else if (arg1.equals ("-T")) - { - testmethods = true; - } - else if (arg1.equals ("-l")) - { - if (arg2 == null || arg2.charAt (0) == '-') - { - System.err.println - (name + ": target language expected following -l option"); - throw new CmdException (1); - } - if (arg2.equals ("cpp") || arg2.equals ("c++")) - { - language = "c++"; - } - else if (arg2.equals ("isocpp") || arg2.equals ("isoc++")) - { - language = "isoc++"; - } - else - { - System.err.println (name + ": supported target languages are isocpp (isoc++) and cpp (c++)"); - throw new CmdException (1); - } - result = true; - } - else - { - return super.process (arg1, arg2); - } - return result; - } - - public boolean pponly; - public boolean nostamp; - public boolean quiet; - public String language; - public boolean testmethods; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/Alignment.java b/src/idlc/src/org/eclipse/cyclonedds/generator/Alignment.java deleted file mode 100644 index 8aefa07e7b..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/Alignment.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -public enum Alignment -{ - ONE (1, 0, "1u"), - BOOL (0, 0, "sizeof(bool)"), - ONE_OR_BOOL (0, 1, "(sizeof(bool)>1u)?sizeof(bool):1u"), - TWO (2, 2, "2u"), - TWO_OR_BOOL (0, 3, "(sizeof(bool)>2u)?sizeof(bool):2u"), - FOUR (4, 4, "4u"), - PTR (0, 6, "sizeof (char *)"), - EIGHT (8, 8, "8u"); - - private final int value; - private final int ordering; - private final String rendering; - - Alignment (int val, int order, String render) - { - value = val; - ordering = order; - rendering = render; - } - - public String toString () - { - return rendering; - } - - public Alignment maximum (Alignment rhs) - { - if (rhs.equals (BOOL)) - { - if (this.equals (ONE)) - { - return ONE_OR_BOOL; - } - else if (this.equals (TWO)) - { - return TWO_OR_BOOL; - } - else - { - return this; - } - } - if (rhs.ordering > ordering) - { - return rhs; - } - else - { - return this; - } - } - - public boolean isUncertain () - { - return (this.value == 0); - } - - public int getValue () - { - return value; - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/ArrayDeclarator.java b/src/idlc/src/org/eclipse/cyclonedds/generator/ArrayDeclarator.java deleted file mode 100644 index b5a7bbab9c..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/ArrayDeclarator.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.util.*; - -public class ArrayDeclarator -{ - public ArrayDeclarator (String name) - { - this.name = name; - this.dims = new ArrayList (); - size = 1; - } - - public void addDimension (long dim) - { - dims.add (new Long (dim)); - size *= dim; - } - - public String getName () - { - return name; - } - - public long getSize () - { - return size; - } - - public String getDimString () - { - StringBuffer result = new StringBuffer (); - for (Long dim : dims) - { - result.append ("["); - result.append (dim.toString ()); - result.append ("]"); - } - return result.toString (); - } - - public Collection getDims () - { - return dims; - } - - private final String name; - private List dims; - private long size; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/ArrayType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/ArrayType.java deleted file mode 100644 index b418668383..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/ArrayType.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.util.*; -import org.eclipse.cyclonedds.ScopedName; - -public class ArrayType extends AbstractType -{ - public ArrayType (Collection dimensions, Type subtype) - { - realsub = subtype; - while (realsub instanceof TypedefType) - { - realsub = ((TypedefType)realsub).getRef (); - } - - this.dimensions = new ArrayList (); - if (realsub instanceof ArrayType) - { - ArrayType subarray = (ArrayType)realsub; - dimensions.addAll (subarray.dimensions); - this.subtype = subarray.subtype; - realsub = this.subtype; - while (realsub instanceof TypedefType) - { - realsub = ((TypedefType)realsub).getRef (); - } - } - else - { - this.subtype = subtype; - } - this.dimensions.addAll (dimensions); - } - - public Type dup () - { - return new ArrayType (dimensions, subtype); - } - - public boolean containsUnion () - { - Type t = subtype; - while (t instanceof TypedefType) - { - t = ((TypedefType)t).getRef (); - } - return t.containsUnion (); - } - - public ArrayList getMetaOp (String myname, String structname) - { - ArrayList result = new ArrayList (); - String offset; - - if (myname != null) - { - offset = "offsetof (" + structname + ", " + myname + ")"; - } - else - { - offset = "0u"; - } - - result.add (new String - ( - "DDS_OP_ADR | DDS_OP_TYPE_ARR | " + realsub.getSubOp () + (isKeyField () ? " | DDS_OP_FLAG_KEY" : "") + ", " + - offset + ", " + Long.toString (size ()) - )); - - if (!(realsub instanceof BasicType)) - { - if (realsub instanceof BoundedStringType) - { - result.add ("0, " + Long.toString (((BoundedStringType)realsub).getBound () + 1)); - } - else - { - result.add (new String ("(" + new Integer (getMetaOpSize ()) + "u << 16u) + 5u, sizeof (" + realsub.getCType () + ")")); - result.addAll (realsub.getMetaOp (null, null)); - result.add (new String ("DDS_OP_RTS")); - } - } - return result; - } - - public String getSubOp () - { - return "DDS_OP_SUBTYPE_ARR"; - } - - public String getOp () - { - return "DDS_OP_TYPE_ARR"; - } - - public String getCType () - { - StringBuffer str = new StringBuffer (subtype.getCType ()); - for (Long d : dimensions) - { - str.append ("["); - str.append (d.toString ()); - str.append ("]"); - } - return str.toString (); - } - - public int getMetaOpSize () - { - if (realsub instanceof BasicType) - { - return 3; - } - else - { - if (realsub instanceof BoundedStringType) - { - return 5; - } - else - { - return 6 + realsub.getMetaOpSize (); - } - } - } - - public Alignment getAlignment () - { - return subtype.getAlignment (); - } - - public long getKeySize () - { - long keysize = subtype.getKeySize (); - if (keysize == -1) - { - return -1; - } - return keysize * size (); - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - for (Long d : dimensions) - { - str.append (""); - } - subtype.getXML (str, mod); - for (Long d : dimensions) - { - str.append (""); - } - } - - public void populateDeps (Set depset, NamedType current) - { - subtype.populateDeps (depset, current); - } - - public boolean depsOK (Set deps) - { - return TypeUtil.deptest (subtype, deps, null); - } - - private long size() - { - long result = 1; - for (Long d : dimensions) - { - result *= d.longValue (); - } - return result; - } - - private final Type subtype; - private Type realsub; - private final List dimensions; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/BasicType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/BasicType.java deleted file mode 100644 index 8964e7fb4b..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/BasicType.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.util.*; -import org.eclipse.cyclonedds.ScopedName; - -public class BasicType extends AbstractType -{ - public enum BT - { - BOOLEAN ("bool", "DDS_OP_TYPE_BOO", "DDS_OP_SUBTYPE_BOO", Alignment.BOOL, "Boolean"), - OCTET ("uint8_t", "DDS_OP_TYPE_1BY", "DDS_OP_SUBTYPE_1BY", Alignment.ONE, "Octet"), - CHAR ("char", "DDS_OP_TYPE_1BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_1BY | DDS_OP_FLAG_SGN", Alignment.ONE, "Char"), - SHORT ("int16_t", "DDS_OP_TYPE_2BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_2BY | DDS_OP_FLAG_SGN", Alignment.TWO, "Short"), - USHORT ("uint16_t", "DDS_OP_TYPE_2BY", "DDS_OP_SUBTYPE_2BY", Alignment.TWO, "UShort"), - LONG ("int32_t", "DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_4BY | DDS_OP_FLAG_SGN", Alignment.FOUR, "Long"), - ULONG ("uint32_t", "DDS_OP_TYPE_4BY", "DDS_OP_SUBTYPE_4BY", Alignment.FOUR, "ULong"), - LONGLONG ("int64_t", "DDS_OP_TYPE_8BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_8BY | DDS_OP_FLAG_SGN", Alignment.EIGHT, "LongLong"), - ULONGLONG ("uint64_t", "DDS_OP_TYPE_8BY", "DDS_OP_SUBTYPE_8BY", Alignment.EIGHT, "ULongLong"), - FLOAT ("float", "DDS_OP_TYPE_4BY | DDS_OP_FLAG_FP", "DDS_OP_SUBTYPE_4BY | DDS_OP_FLAG_FP", Alignment.FOUR, "Float"), - DOUBLE ("double", "DDS_OP_TYPE_8BY | DDS_OP_FLAG_FP", "DDS_OP_SUBTYPE_8BY | DDS_OP_FLAG_FP", Alignment.EIGHT, "Double"), - STRING ("char *", "DDS_OP_TYPE_STR", "DDS_OP_SUBTYPE_STR", Alignment.PTR, "String"); - - public final String cType; - public final String op; - public final String subop; - public final Alignment align; - public final String XML; - - BT (String cType, String op, String subop, Alignment align, String XML) - { - this.cType = cType; - this.op = op; - this.subop = subop; - this.align = align; - this.XML = XML; - } - } - - public BasicType (BT type) - { - this.type = type; - } - - public Type dup () - { - return new BasicType (type); - } - - public boolean containsUnion () - { - return false; - } - - public ArrayList getMetaOp (String myname, String structname) - { - ArrayList result = new ArrayList (1); - result.add (new String - ( - "DDS_OP_ADR | " + type.op + (isKeyField () ? " | DDS_OP_FLAG_KEY" : "") + - ", offsetof (" + structname + ", " + myname + ")" - )); - return result; - } - - public String getSubOp () - { - return type.subop; - } - - public String getOp () - { - return type.op; - } - - public String getCType () - { - return type.cType; - } - - public int getMetaOpSize () - { - return 2; - } - - public Alignment getAlignment () - { - return type.align; - } - - public long getKeySize () - { - switch (type) - { - case BOOLEAN: - return 1; - case STRING: - return -1; - default: - return type.align.getValue (); - } - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - str.append ("<"); - str.append (type.XML); - str.append ("/>"); - } - - public void populateDeps (Set depset, NamedType current) - { - } - - public boolean depsOK (Set deps) - { - return true; - } - - final BT type; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/BasicTypedefType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/BasicTypedefType.java deleted file mode 100644 index eb579513d7..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/BasicTypedefType.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import org.eclipse.cyclonedds.ScopedName; -import java.util.*; - -public class BasicTypedefType extends BasicType implements NamedType -{ - public BasicTypedefType (ScopedName name, BasicType ref) - { - super (ref.type); - this.name = new ScopedName (name); - } - - public Type dup () - { - return new TypedefType (name, new BasicType (type)); - } - - public void getToplevelXML (StringBuffer str, ModuleContext mod) - { - mod.enter (str, name); - str.append (""); - super.getXML (str, mod); - str.append (""); - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - str.append (""); - } - - public void populateDeps (Set depset, NamedType current) - { - depset.add (name); - } - - public boolean depsOK (Set deps) - { - return true; - } - - public ScopedName getSN () - { - return name; - } - - public boolean isInline () - { - return false; - } - - private final ScopedName name; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/BoundedStringType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/BoundedStringType.java deleted file mode 100644 index 62e04c1935..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/BoundedStringType.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.util.*; -import org.eclipse.cyclonedds.ScopedName; - -public class BoundedStringType extends AbstractType -{ - public BoundedStringType (long size) - { - this.size = size; - } - - public Type dup () - { - return new BoundedStringType (size); - } - - public long getKeySize () - { - return size + 5; - } - - public long getBound () - { - return size; - } - - public boolean containsUnion () - { - return false; - } - - public ArrayList getMetaOp (String myname, String structname) - { - ArrayList result = new ArrayList (); - String offset; - if (myname != null) - { - offset = "offsetof (" + structname + ", " + myname + ")"; - } - else - { - offset = "0u"; - } - - result.add (new String - ( - "DDS_OP_ADR | DDS_OP_TYPE_BST" + - (isKeyField () ? " | DDS_OP_FLAG_KEY" : "") + ", " + - offset + ", " + Long.toString (size + 1) - )); - - return result; - } - - public String getSubOp () - { - return "DDS_OP_SUBTYPE_BST"; - } - - public String getOp () - { - return "DDS_OP_TYPE_BST"; - } - - public String getCType () - { - return "char"; - } - - public int getMetaOpSize () - { - return 3; - } - - public Alignment getAlignment () - { - return Alignment.ONE; - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - str.append (""); - } - - public void populateDeps (Set depset, NamedType current) - { - } - - public boolean depsOK (Set deps) - { - return true; - } - - private final long size; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/EnumType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/EnumType.java deleted file mode 100644 index 739add727c..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/EnumType.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.util.*; -import org.eclipse.cyclonedds.ScopedName; - -public class EnumType extends BasicType implements NamedType -{ - public EnumType (ScopedName SN, NamedType parent) - { - super (BT.LONG); - this.SN = SN; - this.parent = parent; - vals = new ArrayList (); - scopelen = SN.toString ("_").length () - SN.getLeaf ().length (); - } - - public Type dup () - { - EnumType res = new EnumType (SN, parent); - for (String s : vals) - { - res.addEnumerand (s); - } - return res; - } - - public String getCType () - { - return SN.toString ("_"); - } - - public boolean containsUnion () - { - return false; - } - - public void addEnumerand (String val) - { - vals.add (val); - } - - public Iterable getEnumerands () - { - return vals; - } - - private void getXMLbase (StringBuffer str) - { - int val = 0; - str.append (""); - for (String s : vals) - { - str.append (""); - } - str.append (""); - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - if (parent != null && mod.isParent (SN)) - { - getXMLbase (str); - } - else - { - str.append (""); - } - } - - public void getToplevelXML (StringBuffer str, ModuleContext mod) - { - mod.enter (str, SN); - getXMLbase (str); - } - - public void populateDeps (Set depset, NamedType current) - { - if (parent == null) - { - depset.add (SN); - } - else - { - if (!(parent.getSN ().equals (current.getSN ()))) - { - parent.populateDeps (depset, current); - } - } - } - - public boolean depsOK (Set deps) - { - return true; - } - - public String descope (String s) - { - return s.substring (scopelen); - } - - public ScopedName getSN () - { - return SN; - } - - private final NamedType parent; - private final ScopedName SN; - private final int scopelen; - private List vals; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/GenVisitor.java b/src/idlc/src/org/eclipse/cyclonedds/generator/GenVisitor.java deleted file mode 100644 index d5152a4d3f..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/GenVisitor.java +++ /dev/null @@ -1,1355 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.io.*; -import java.util.*; - -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.tree.*; -import org.stringtemplate.v4.*; - -import org.eclipse.cyclonedds.parser.IDLParser; -import org.eclipse.cyclonedds.*; - -public class GenVisitor extends org.eclipse.cyclonedds.parser.IDLBaseVisitor -{ - private static class ParseState - { - private ParseState () - { - decl_ctx = null; - struct = null; - member = null; - seqtypedef = null; - type = null; - structMeta = null; - s_union = null; - s_unionST = null; - decls = new ArrayList (); - arraydecls = new LinkedList (); - scopes = new LinkedList (); - literal = 0; - } - - private ParseState (ParseState state) - { - decl_ctx = state.decl_ctx; - struct = state.struct; - member = state.member; - s_union = state.s_union; - s_unionST = state.s_unionST; - seqtypedef = state.seqtypedef; - type = state.type; - structMeta = state.structMeta; - decls = new ArrayList (state.decls); - arraydecls = new LinkedList (state.arraydecls); - scopes = new LinkedList (state.scopes); - literal = state.literal; - } - - private void pushScope (String newscope) - { - scopes.addLast (newscope); - } - - private String popScope () - { - return scopes.removeLast (); - } - - private void setScope (ST templ) - { - for (String element : scopes) - { - templ.add ("scope", element); - } - } - - private ScopedName getSN () - { - return new ScopedName (scopes); - } - - private ST decl_ctx, struct, member, s_unionST, seqtypedef; - private LinkedList scopes; - private ArrayList decls; - private LinkedList arraydecls; - private Type type; - private StructType structMeta; - private UnionType s_union; - private long literal; - } - - public GenVisitor (IdlParams params, String templates) - { - this.params = params; - String basesafe = params.basename.replace ('-', '_').replace (' ', '_'); - topics = new HashMap (); - alltypes = new LinkedHashMap (); - constants = new HashMap (); - group = new STGroupFile (templates); - file = group.getInstanceOf ("file"); - - ST banner = group.getInstanceOf ("banner"); - banner.add ("file", params.basename); - if (params.timestamp) - { - banner.add ("date", new Date ()); - } - banner.add ("version", Project.version); - - file.add ("banner", banner); - if (params.forcpp) - { - file.add ("name", params.basename + "-cyclonedds"); - } - else - { - file.add ("name", params.basename); - } - file.add ("nameupper", basesafe.toUpperCase ()); - params.linetab.populateIncs (file); - - if (params.dllname != null) - { - ST dll = group.getInstanceOf ("dlldef"); - dll.add ("name", basesafe.toUpperCase ()); - dll.add ("dllname", params.dllname); - if (params.dllfile != null) - { - dll.add ("dllfile", params.dllfile); - } - file.add ("dll", dll); - } - - state = new ParseState (); - state.decl_ctx = file; - } - - public Void visitModule (IDLParser.ModuleContext ctx) - { - Void result; - ParseState oldstate = new ParseState (state); - - state.decl_ctx = group.getInstanceOf ("module"); - state.setScope (state.decl_ctx); - state.decl_ctx.add ("name", ctx.ID ().getText ()); - state.pushScope (ctx.ID ().getText ()); - - oldstate.decl_ctx.add ("declarations", state.decl_ctx); - - result = super.visitModule (ctx); - state = oldstate; - return result; - } - - public Void visitInterface_decl (IDLParser.Interface_declContext ctx) - { - Void result; - String name = ctx.interface_header ().ID ().getText (); - ParseState oldstate = new ParseState (state); - state.decl_ctx = group.getInstanceOf ("module"); - state.setScope (state.decl_ctx); - state.decl_ctx.add ("name", name); - state.pushScope (name); - - oldstate.decl_ctx.add ("declarations", state.decl_ctx); - - result = super.visitInterface_body (ctx.interface_body ()); - state = oldstate; - return result; - } - - public Void visitStruct_type (IDLParser.Struct_typeContext ctx) - { - Void result; - NamedType parent = - (state.structMeta != null) ? state.structMeta : state.s_union; - boolean generate = params.linetab.inMain (ctx.ID ().getSymbol ().getLine ()); - ParseState oldstate = new ParseState (state); - - state.struct = group.getInstanceOf ("struct"); - state.decl_ctx = state.struct; - state.setScope (state.struct); - state.struct.add ("name", ctx.ID ().getText ()); - state.struct.add - ("extern", (params.dllname != null) ? "extern DDS_EXPORT" : "extern"); - if (params.allstructs) - { - state.struct.add ("istopic", "true"); - } - state.pushScope (ctx.ID ().getText ()); - state.structMeta = new StructType (state.getSN (), parent); - - result = super.visitStruct_type (ctx); - - if (state.structMeta.isInvalid ()) - { - if (!params.quiet) - { - System.out.print - ( - "Struct " + state.structMeta.getSN ().toString ("::") + - " contains unsupported data types, skipped." - ); - } - } - else - { - if (oldstate.member != null) - { - oldstate.type = state.structMeta; - oldstate.decl_ctx.add ("declarations", state.struct); - oldstate.member.add ("type", state.struct.getAttribute ("name")); - oldstate.member.add ("scope", state.struct.getAttribute ("scope")); - } - else - { - if (generate) - { - oldstate.decl_ctx.add ("declarations", state.struct); - } - } - alltypes.put (state.getSN (), state.structMeta); - topics.put (state.getSN (), state.struct); - } - - state = oldstate; - return result; - } - - public Void visitEnum_type (IDLParser.Enum_typeContext ctx) - { - Void result; - EnumType etype; - String enumname = ctx.ID ().getText (); - boolean generate = - params.linetab.inMain (ctx.ID ().getSymbol ().getLine ()); - - ScopedName enumSN = new ScopedName (state.getSN ()); - enumSN.addComponent (enumname); - etype = new EnumType - (enumSN, (state.structMeta != null) ? state.structMeta : state.s_union); - - ST etmpl = group.getInstanceOf ("enum"); - state.setScope (etmpl); - etmpl.add ("name", enumname); - - Type oldtype = state.type; - state.type = etype; - result = super.visitEnum_type (ctx); - state.type = oldtype; - - for (String s : etype.getEnumerands ()) - { - etmpl.add ("values", s); - } - - if (state.member != null) - { - state.decl_ctx.add ("declarations", etmpl); - state.member.add ("type", enumname); - state.setScope (state.member); - state.type = etype; - } - else - { - if (generate) - { - state.decl_ctx.add ("declarations", etmpl); - } - } - alltypes.put (enumSN, etype); - return result; - } - - public Void visitEnumerator (IDLParser.EnumeratorContext ctx) - { - ((EnumType)state.type).addEnumerand (ctx.ID ().getText ()); - return super.visitEnumerator (ctx); - } - - public Void visitMember (IDLParser.MemberContext ctx) - { - Void result; - ST seqtd, newmember; - String scopeprefix, seqtypename; - Type realtype; - boolean implicitTD; - - state.member = group.getInstanceOf ("member"); - state.decls.clear (); - state.arraydecls.clear (); - result = super.visitMember (ctx); - if (state.type == null) - { - state.member = null; - if (state.struct != null) - { - state.structMeta.invalidate (); - } - return result; - } - - implicitTD = - ( - state.seqtypedef != null && - state.seqtypedef.getName().equals ("/seqdef") - ); - scopeprefix = state.getSN ().toString ("_"); - if (scopeprefix.length () > 0) - { - scopeprefix = scopeprefix + "_"; - } - - for (String simpledec : state.decls) - { - newmember = new ST (state.member); - - if (implicitTD) - { - seqtypename = simpledec + "_seq"; - seqtd = new ST (state.seqtypedef); - seqtd.add ("name", seqtypename); - state.decl_ctx.add ("declarations", seqtd); - newmember.add ("type", seqtypename); - realtype = ((SequenceType)state.type).clone (scopeprefix + seqtypename); - } - else - { - realtype = state.type; - } - - newmember.add ("name", simpledec); - state.decl_ctx.add ("fields", newmember); - state.structMeta.addMember (simpledec, realtype); - } - - for (ArrayDeclarator arraydec : state.arraydecls) - { - newmember = new ST (state.member); - - if (implicitTD) - { - seqtypename = arraydec.getName () + "_seq"; - seqtd = new ST (state.seqtypedef); - seqtd.add ("name", seqtypename); - state.decl_ctx.add ("declarations", seqtd); - newmember.add ("type", seqtypename); - realtype = ((SequenceType)state.type).clone (scopeprefix + seqtypename); - } - else - { - realtype = state.type; - } - newmember.add ("arraydim", arraydec.getDimString ()); - newmember.add ("name", arraydec.getName ()); - state.decl_ctx.add ("fields", newmember); - state.structMeta.addMember - (arraydec.getName (), new ArrayType (arraydec.getDims (), realtype)); - } - - state.seqtypedef = null; - return result; - } - - public Void visitType_declarator (IDLParser.Type_declaratorContext ctx) - { - /* this is a typedef */ - Void result; - ScopedName SN; - ST td, basetd, newmember; - ParseState oldstate = new ParseState (state); - String[] scopearray = state.scopes.toArray (new String[0]); - boolean generate = params.linetab.inMain (((IDLParser.Type_declContext)ctx.getParent ()).KW_TYPEDEF ().getSymbol ().getLine ()); - - state.member = group.getInstanceOf ("member"); - state.decls.clear (); - state.arraydecls.clear (); - - result = super.visitType_declarator (ctx); - - if (state.type == null) - { - if (!params.quiet) - { - System.out.print ("Typedef "); - for (String s : oldstate.scopes) - { - System.out.print (s + "::"); - } - System.out.println (state.member.getAttribute ("name") + " is an unsupported data type, skipped."); - } - state = oldstate; - return result; - } - - if (state.seqtypedef == null) - { - basetd = group.getInstanceOf ("scalar_typedef"); - for (String s : scopearray) - { - basetd.add ("namescope", s); - } - copyAttrIfSet (state.member, basetd, "type"); - copyAttrIfSet (state.member, basetd, "scope"); - copyAttrIfSet (state.member, basetd, "str_size"); - } - else - { - basetd = state.seqtypedef; - } - - for (String simpledec : state.decls) - { - SN = new ScopedName (scopearray); - SN.addComponent (simpledec); - if (state.type instanceof BasicType && !(state.type instanceof EnumType)) - { - alltypes.put (SN, new BasicTypedefType (SN, (BasicType)state.type)); - } - else - { - alltypes.put (SN, new TypedefType (SN, state.type)); - } - if (generate) - { - td = new ST (basetd); - td.add ("name", simpledec); - state.decl_ctx.add ("declarations", td); - } - } - - for (ArrayDeclarator arraydec : state.arraydecls) - { - SN = new ScopedName (scopearray); - SN.addComponent (arraydec.getName ()); - alltypes.put (SN, new TypedefType (SN, new ArrayType (arraydec.getDims (), state.type))); - - newmember = new ST (state.member); - newmember.add ("arraydim", arraydec.getDimString ()); - newmember.add ("name", arraydec.getName ()); - if (generate) - { - td = new ST (basetd); - td.add ("name", arraydec.getName ()); - td.add ("arraydim", arraydec.getDimString ()); - state.decl_ctx.add ("declarations", td); - } - } - - state = oldstate; - return result; - } - - public Void visitSimple_declarator (IDLParser.Simple_declaratorContext ctx) - { - state.decls.add (ctx.ID ().getText ()); - return super.visitSimple_declarator (ctx); - } - - public Void visitArray_declarator (IDLParser.Array_declaratorContext ctx) - { - state.arraydecls.addLast (new ArrayDeclarator (ctx.ID ().getText ())); - return super.visitArray_declarator (ctx); - } - - public Void visitFixed_array_size (IDLParser.Fixed_array_sizeContext ctx) - { - Void result = super.visitFixed_array_size (ctx); - state.arraydecls.getLast ().addDimension (state.literal); - return result; - } - - public Void visitConst_exp (IDLParser.Const_expContext ctx) - { - state.literal = 0L; - return super.visitConst_exp (ctx); - } - - public Void visitOr_expr (IDLParser.Or_exprContext ctx) - { - long result = 0L; - for (IDLParser.Xor_exprContext child : ctx.xor_expr ()) - { - state.literal = 0L; - visitXor_expr (child); - result |= state.literal; - } - state.literal = result; - return null; - } - - public Void visitXor_expr (IDLParser.Xor_exprContext ctx) - { - long result = 0L; - for (IDLParser.And_exprContext child : ctx.and_expr ()) - { - state.literal = 0L; - visitAnd_expr (child); - result ^= state.literal; - } - state.literal = result; - return null; - } - - public Void visitAnd_expr (IDLParser.And_exprContext ctx) - { - long result = ~0L; - for (IDLParser.Shift_exprContext child : ctx.shift_expr ()) - { - state.literal = 0L; - visitShift_expr (child); - result &= state.literal; - } - state.literal = result; - return null; - } - - public Void visitShift_expr (IDLParser.Shift_exprContext ctx) - { - long result = 0L; - int subex = 0; - state.literal = 0L; - - visitAdd_expr (ctx.add_expr (subex++)); - result = state.literal; - for (int i = 1; i < ctx.getChildCount (); i+=2) - { - state.literal = 0L; - visitAdd_expr (ctx.add_expr (subex++)); - if (ctx.getChild (i).getText ().equals ("<<")) - { - result <<= state.literal; - } - else - { - result >>= state.literal; - } - } - state.literal = result; - return null; - } - - public Void visitAdd_expr (IDLParser.Add_exprContext ctx) - { - long result = 0L; - int subex = 0; - state.literal = 0L; - - visitMult_expr (ctx.mult_expr (subex++)); - result = state.literal; - for (int i = 1; i < ctx.getChildCount (); i+=2) - { - state.literal = 0L; - visitMult_expr (ctx.mult_expr (subex++)); - if (ctx.getChild (i).getText ().equals ("+")) - { - result += state.literal; - } - else - { - result -= state.literal; - } - } - state.literal = result; - return null; - } - - public Void visitMult_expr (IDLParser.Mult_exprContext ctx) - { - long result = 0L; - int subex = 0; - state.literal = 0L; - - visitUnary_expr (ctx.unary_expr (subex++)); - result = state.literal; - for (int i = 1; i < ctx.getChildCount (); i+=2) - { - state.literal = 0L; - visitUnary_expr (ctx.unary_expr (subex++)); - if (ctx.getChild (i).getText ().equals ("*")) - { - result *= state.literal; - } - else - { - if (state.literal == 0) - { - throw new NumberFormatException ("divide by zero"); - } - if (ctx.getChild (i).getText ().equals ("/")) - { - result /= state.literal; - } - else - { - result %= state.literal; - } - } - } - state.literal = result; - return null; - } - - public Void visitUnary_expr (IDLParser.Unary_exprContext ctx) - { - IDLParser.Unary_operatorContext op = ctx.unary_operator (); - visitPrimary_expr (ctx.primary_expr ()); - - if (op != null) - { - if (op.MINUS () != null) - { - state.literal = -state.literal; - } - else if (op.TILDE () != null) - { - state.literal = ~state.literal; - } - } - return null; - } - - public Void visitPrimary_expr (IDLParser.Primary_exprContext ctx) - { - if (ctx.scoped_name () != null) - { - ScopedName sn = resolveName (ctx.scoped_name ().ID ()); - Long val = constants.get (sn); - if (val != null) - { - state.literal = val.longValue (); - } - else - { - throw new NumberFormatException (sn.toString () + " - not integer"); - } - } - else - { - if (ctx.literal () != null) - { - String lit = ctx.literal ().getText (); - if (lit.endsWith ("L") || lit.endsWith ("l")) - { - lit = lit.substring (0, lit.length () - 1); - } - state.literal = Long.decode (lit); - } - else - { - visitConst_exp (ctx.const_exp ()); - } - } - return null; - } - - public Void visitOp_decl (IDLParser.Op_declContext ctx) - { - // Don't care about operations - return null; - } - - public Void visitConst_decl (IDLParser.Const_declContext ctx) - { - Void result = null; - boolean integral; - - ST cdecl = group.getInstanceOf ("const"); - String constname = ctx.ID ().getText (); - ScopedName constSN = new ScopedName (state.getSN ()); - constSN.addComponent (constname); - state.setScope (cdecl); - cdecl.add ("name", constname); - - integral = - (ctx.const_type ().integer_type () != null) || - (ctx.const_type ().octet_type () != null); - if (!integral) - { - if (ctx.const_type ().scoped_name () != null) - { - ScopedName typeSN = - resolveName (ctx.const_type ().scoped_name ().ID ()); - Type ctype = alltypes.get (typeSN); - integral = (ctype.getCType ().contains ("int")); - } - } - if (integral) - { - visitConst_exp (ctx.const_exp ()); - cdecl.add ("expression", Long.toString (state.literal)); - constants.put (constSN, new Long (state.literal)); - } - else - { - StringBuffer buf = new StringBuffer ("("); - traverseExpression (ctx.const_exp (), buf); - buf.append (")"); - cdecl.add ("expression", buf.toString ()); - } - if (params.linetab.inMain (ctx.ID ().getSymbol ().getLine ())) - { - state.decl_ctx.add ("declarations", cdecl); - } - return result; - } - - private void traverseExpression (ParseTree exp, StringBuffer result) - { - ParseTree child; - for (int i = 0; i < exp.getChildCount(); i++) - { - child = exp.getChild (i); - if (child instanceof IDLParser.Scoped_nameContext) - { - ST sn = group.getInstanceOf ("scopedname"); - ScopedName actual = - resolveName (((IDLParser.Scoped_nameContext)child).ID ()); - sn.add ("name", actual.getLeaf ()); - for (String s : actual.getPath()) - { - sn.add ("scope", s); - } - result.append (sn.render ()); - } - else if (child instanceof IDLParser.LiteralContext) - { - IDLParser.LiteralContext lit = (IDLParser.LiteralContext)child; - if (lit.BOOLEAN_LITERAL () != null) - { - if (lit.BOOLEAN_LITERAL ().getText ().equals ("TRUE")) - { - result.append ("true"); - } - else - { - result.append ("false"); - } - } - else - { - result.append (child.getText ()); - } - } - else if (child instanceof TerminalNode) - { - result.append (child.getText ()); - } - else - { - traverseExpression (child, result); - } - } - } - - public Void visitUnion_type (IDLParser.Union_typeContext ctx) - { - Void result; - NamedType parent = - (state.structMeta != null) ? state.structMeta : state.s_union; - boolean generate = params.linetab.inMain (ctx.ID ().getSymbol ().getLine ()); - ParseState oldstate = new ParseState (state); - - String unionname = ctx.ID ().getText (); - ScopedName unionSN = new ScopedName (state.getSN ()); - unionSN.addComponent (unionname); - - state.s_unionST = group.getInstanceOf ("union"); - state.setScope (state.s_unionST); - state.s_unionST.add ("name", unionname); - state.decl_ctx = state.s_unionST; - state.pushScope (unionname); - state.s_union = new UnionType (unionSN, parent); - - result = super.visitUnion_type (ctx); - - if (oldstate.member != null) - { - oldstate.decl_ctx.add ("declarations", state.s_unionST); - oldstate.member.add ("type", unionname); - oldstate.setScope (state.member); - oldstate.type = state.s_union; - } - else - { - if (generate) - { - oldstate.decl_ctx.add ("declarations", state.s_unionST); - } - } - - alltypes.put (unionSN, state.s_union); - state = oldstate; - return result; - } - - public Void visitSwitch_type_spec (IDLParser.Switch_type_specContext ctx) - { - Void result; - ParseState oldstate = new ParseState (state); - state.member = group.getInstanceOf ("member"); - result = super.visitSwitch_type_spec (ctx); - oldstate.s_unionST.add ("disc", state.member.getAttribute ("type")); - oldstate.s_unionST.add ("discscope", state.member.getAttribute ("scope")); - oldstate.s_union.setDiscriminant (state.type); - state = oldstate; - return result; - } - - public Void visitCase_stmt (IDLParser.Case_stmtContext ctx) - { - boolean implicitTD; - ParseState oldstate = new ParseState (state); - state.member = group.getInstanceOf ("member"); - state.decls.clear (); - state.arraydecls.clear (); - - ArrayList labels = new ArrayList (); - boolean includedefault = false; - - for (IDLParser.Case_labelContext labelctx : ctx.case_label ()) - { - if (labelctx.KW_DEFAULT () == null) - { - try - { - visitConst_exp (labelctx.const_exp ()); - labels.add (Long.toString (state.literal)); - } - catch (NumberFormatException ex) - { - // could be a bool or enum discriminant - StringBuffer buf = new StringBuffer (); - traverseExpression (labelctx.const_exp (), buf); - labels.add (buf.toString ()); - } - } - else - { - includedefault = true; - } - } - - String memname; - Void result = visitElement_spec (ctx.element_spec ()); - - implicitTD = - ( - state.seqtypedef != null && - state.seqtypedef.getName().equals ("/seqdef") - ); - - if (!state.decls.isEmpty ()) - { - memname = state.decls.get (0); - } - else - { - ArrayDeclarator dec = state.arraydecls.get (0); - memname = dec.getName (); - state.type = new ArrayType (dec.getDims (), state.type); - state.member.add ("arraydim", dec.getDimString ()); - } - state.member.add ("name", memname); - - if (implicitTD) - { - String seqtypename = memname + "_seq"; - String prefix = state.getSN ().toString ("_"); - if (prefix.length () > 0) - { - prefix = prefix + "_"; - } - state.seqtypedef.add ("name", seqtypename); - state.decl_ctx.add ("declarations", state.seqtypedef); - state.member.add ("type", seqtypename); - state.type = ((SequenceType)state.type).clone (prefix + seqtypename); - } - - oldstate.s_unionST.add ("fields", state.member); - oldstate.s_union.addMember (memname, state.type, labels.toArray (new String[labels.size ()]), includedefault); - state = oldstate; - return result; - } - - private void copyAttrIfSet (ST from, ST to, String name) - { - Object attr = from.getAttribute (name); - if (attr != null) - { - to.add (name, attr); - } - } - - private ScopedName resolveName (List query) - { - ScopedName current = new ScopedName (); - ScopedName request = new ScopedName (); - - for (String s : state.scopes) - { - current.addComponent (s); - } - - for (TerminalNode element : query) - { - request.addComponent (element.getSymbol ().getText ()); - } - - return params.symtab.resolve (current, request).name (); - } - - public Void visitScoped_name (IDLParser.Scoped_nameContext ctx) - { - ScopedName resultSN; - Type resultType; - - resultSN = resolveName (ctx.ID ()); - state.type = alltypes.get (resultSN); - - for (String s : resultSN.getPath()) - { - state.member.add ("scope", s); - } - state.member.add ("type", resultSN.getLeaf()); - - return super.visitScoped_name (ctx); - } - - public Void visitSequence_type (IDLParser.Sequence_typeContext ctx) - { - if (ctx.positive_int_const () != null) - { - // Bounded sequence NYI - return null; - } - - Void result; - boolean generate = - params.linetab.inMain (ctx.KW_SEQUENCE ().getSymbol ().getLine ()); - ParseState oldstate = new ParseState (state); - - state.member = group.getInstanceOf ("member"); - result = super.visitSequence_type (ctx); - - if (state.type == null) - { - state = oldstate; - return result; - } - - oldstate.type = new SequenceType (state.type); - - Type realsub = state.type; - while (realsub instanceof TypedefType) - { - realsub = ((TypedefType)realsub).getRef (); - } - - boolean isbstring = realsub instanceof BoundedStringType; - boolean isbasic = isbstring || (realsub instanceof BasicType); - - if (isbasic) - { - oldstate.member.add ("type", "dds_sequence_t"); - } - else - { - for (String s : oldstate.scopes.toArray (new String[0])) - { - oldstate.member.add ("scope", s); - } - } - - if (generate) - { - if (isbasic) - { - oldstate.seqtypedef = group.getInstanceOf ("seqdef_base"); - oldstate.seqtypedef.add ("type", realsub.getCType ()); - if (isbstring) - { - oldstate.seqtypedef.add - ("str_size", "[" + Long.toString (((BoundedStringType)realsub).getBound () + 1) + "]"); - } - } - else - { - oldstate.seqtypedef = group.getInstanceOf ("seqdef"); - oldstate.seqtypedef.add - ("typescope", state.member.getAttribute ("scope")); - oldstate.seqtypedef.add ("type", state.member.getAttribute ("type")); - } - for (String s : oldstate.scopes.toArray (new String[0])) - { - oldstate.seqtypedef.add ("scope", s); - } - } - - state = oldstate; - return result; - } - - public Void visitOctet_type (IDLParser.Octet_typeContext ctx) - { - state.member.add ("type", "octet"); - state.type = new BasicType (BasicType.BT.OCTET); - return super.visitOctet_type (ctx); - } - - public Void visitSigned_short_int (IDLParser.Signed_short_intContext ctx) - { - state.member.add ("type", "short"); - state.type = new BasicType (BasicType.BT.SHORT); - return super.visitSigned_short_int (ctx); - } - - public Void visitSigned_long_int (IDLParser.Signed_long_intContext ctx) - { - state.member.add ("type", "long"); - state.type = new BasicType (BasicType.BT.LONG); - return super.visitSigned_long_int (ctx); - } - - public Void visitSigned_longlong_int (IDLParser.Signed_longlong_intContext ctx) - { - state.member.add ("type", "long long"); - state.type = new BasicType (BasicType.BT.LONGLONG); - return super.visitSigned_longlong_int (ctx); - } - - public Void visitUnsigned_short_int (IDLParser.Unsigned_short_intContext ctx) - { - state.member.add ("type", "unsigned short"); - state.type = new BasicType (BasicType.BT.USHORT); - return super.visitUnsigned_short_int (ctx); - } - - public Void visitUnsigned_long_int (IDLParser.Unsigned_long_intContext ctx) - { - state.member.add ("type", "unsigned long"); - state.type = new BasicType (BasicType.BT.ULONG); - return super.visitUnsigned_long_int (ctx); - } - - public Void visitUnsigned_longlong_int (IDLParser.Unsigned_longlong_intContext ctx) - { - state.member.add ("type", "unsigned long long"); - state.type = new BasicType (BasicType.BT.ULONGLONG); - return super.visitUnsigned_longlong_int (ctx); - } - - public Void visitBoolean_type (IDLParser.Boolean_typeContext ctx) - { - state.member.add ("type", "boolean"); - state.type = new BasicType (BasicType.BT.BOOLEAN); - return super.visitBoolean_type (ctx); - } - - private void charMember () - { - state.member.add ("type", "char"); - state.type = new BasicType (BasicType.BT.CHAR); - } - - public Void visitChar_type (IDLParser.Char_typeContext ctx) - { - charMember (); - return super.visitChar_type (ctx); - } - - public Void visitWide_char_type (IDLParser.Wide_char_typeContext ctx) - { - if (params.mapwide) - { - charMember (); - } - return super.visitWide_char_type (ctx); - } - - public Void visitFloating_pt_type (IDLParser.Floating_pt_typeContext ctx) - { - if (ctx.KW_LONG () == null || params.mapld) - { - if (ctx.KW_FLOAT () != null) - { - state.member.add ("type", "float"); - state.type = new BasicType (BasicType.BT.FLOAT); - } - else - { - state.member.add ("type", "double"); - state.type = new BasicType (BasicType.BT.DOUBLE); - } - } - return super.visitFloating_pt_type (ctx); - } - - private void stringMember () - { - state.member.add ("type", "string"); - state.type = new BasicType (BasicType.BT.STRING); - } - - private void boundedStringMember (long length) - { - state.member.add ("type", "bstring"); - state.member.add ("str_size", "[" + Long.toString (length + 1) + "]"); - state.type = new BoundedStringType (length); - } - - public Void visitString_type (IDLParser.String_typeContext ctx) - { - Void result = super.visitString_type (ctx); - if (ctx.positive_int_const() == null) - { - stringMember (); - } - else - { - boundedStringMember (state.literal); - } - return result; - } - - public Void visitWide_string_type (IDLParser.Wide_string_typeContext ctx) - { - Void result = super.visitWide_string_type (ctx); - if (params.mapwide) - { - if (ctx.positive_int_const() == null) - { - stringMember (); - } - else - { - boundedStringMember (state.literal); - } - } - return result; - } - - public Void visitPragma_decl (IDLParser.Pragma_declContext ctx) - { - StringTokenizer pragma = new StringTokenizer (ctx.LINE_PRAGMA().getText ()); - pragma.nextToken (); /* Skip "#pragma" */ - if (pragma.hasMoreTokens () && pragma.nextToken ().equals ("keylist")) - { - ScopedName currentSN, requestSN, resultSN; - String topicType = pragma.nextToken (); - - currentSN = new ScopedName (); - for (String s : state.scopes) - { - currentSN.addComponent (s); - } - requestSN = new ScopedName (topicType); - resultSN = params.symtab.resolve (currentSN, requestSN).name (); - - ST topic = topics.get (resultSN); - StructType structMeta = (StructType)alltypes.get (resultSN); - - if (!params.allstructs && !params.notopics) - { - topic.add ("istopic", "true"); - } - while (pragma.hasMoreTokens ()) - { - String fieldname = pragma.nextToken (); - ST field = group.getInstanceOf ("keyfield"); - field.add ("name", fieldname); - field.add - ("offset", Integer.toString (structMeta.addKeyField (fieldname))); - topic.add ("keys", field); - } - long size = structMeta.getKeySize (); - if (size > 0 && size <= MAX_KEYSIZE) - { - topic.add ("flags", "DDS_TOPIC_FIXED_KEY"); - } - } - return super.visitPragma_decl (ctx); - } - - public void writeToFile (String filename) throws IOException - { - ST topicST; - StructType topicmeta; - BufferedOutputStream bos = null; - - for (ScopedName topicname : topics.keySet ()) - { - topicmeta = (StructType)alltypes.get (topicname); - topicST = topics.get (topicname); - if (params.xmlgen) - { - StringBuffer str = new StringBuffer (); - Set depset = new LinkedHashSet (); - topicmeta.populateDeps (depset, null); - generateXMLospl (str, depset); - topicST.add ("xml", str.toString ()); - } - topicST.add ("marshalling", topicmeta.getMetaOp (null, null)); - topicST.add ("marshalling", "DDS_OP_RTS"); - if (topicmeta.isUnoptimizable ()) - { - topicST.add ("flags", "DDS_TOPIC_NO_OPTIMIZE"); - } - if (topicmeta.containsUnion ()) - { - topicST.add ("flags", "DDS_TOPIC_CONTAINS_UNION"); - } - topicST.add ("alignment", topicmeta.getAlignment ()); - } - - try - { - bos = new BufferedOutputStream (new FileOutputStream (filename)); - bos.write (file.render ().getBytes ("UTF-8")); - } - finally - { - if (bos != null) - { - bos.close (); - } - } - } - - private void generateXMLlite (StringBuffer str, Set depset) - { - ModuleContext mod = new ModuleContext (); - for (ScopedName sn : alltypes.keySet ()) - { - if (depset.contains (sn)) - { - alltypes.get (sn).getToplevelXML (str, mod); - } - } - mod.exit (str); - } - - private void generateXMLospl (StringBuffer str, Set depset) - { - ScopedName snparent; - ScopedName modname; - Set module; - Set written = new HashSet (); - - ModuleContext mod = new ModuleContext (); - Map > modules = - new LinkedHashMap > (); - - /* Re-order depset */ - - Set depsorder = new LinkedHashSet (); - Set tmpwritten = new LinkedHashSet (); - - while (depsorder.size () != depset.size ()) - { - for (ScopedName s : depset) - { - NamedType nt = alltypes.get (s); - if (nt.depsOK (depsorder)) - { - tmpwritten.add (s); - } - } - for (ScopedName s : tmpwritten) - { - depsorder.add (s); - } - tmpwritten.clear (); - } - - /* Populate depset into a map keyed by module */ - - for (ScopedName sn : depset) - { - snparent = new ScopedName (sn); - snparent.popComponent (); - module = modules.get (snparent); - if (module == null) - { - module = new HashSet (); - modules.put (snparent, module); - } - module.add ((NamedType)alltypes.get (sn)); - } - - while (!modules.isEmpty ()) - { - module = null; - modname = null; - int bestscore = 0; - - /* Find module with the most types ready to be written */ - - for (Map.Entry > e : modules.entrySet ()) - { - int score = 0; - for (NamedType nt : e.getValue ()) - { - if (nt.depsOK (written)) - { - score++; - } - } - if (score >= bestscore) - { - module = e.getValue (); - modname = e.getKey (); - bestscore = score; - } - } - - /* Write all the ready types in that module */ - if (module != null) { - tmpwritten = new HashSet (); - do { - tmpwritten.clear (); - for (ScopedName sn : depsorder) - { - NamedType nt = alltypes.get (sn); - if (module.contains (nt) && nt.depsOK (written)) - { - nt.getToplevelXML (str, mod); - module.remove (nt); - tmpwritten.add (sn); - } - } - written.addAll (tmpwritten); - } while (!tmpwritten.isEmpty ()); - - /* Terminate when there's nothing left */ - if (module.isEmpty ()) { - modules.remove (modname); - } - } - } - - mod.exit (str); - } - - private ParseState state; - private IdlParams params; - private Map topics; - private Map alltypes; - private Map constants; - private ST file; - private STGroup group; - private static final int MAX_KEYSIZE = 16; -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/ModuleContext.java b/src/idlc/src/org/eclipse/cyclonedds/generator/ModuleContext.java deleted file mode 100644 index 22f6d9d282..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/ModuleContext.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.util.*; -import org.eclipse.cyclonedds.ScopedName; - -public class ModuleContext -{ - public ModuleContext () - { - current = new ScopedName (); - struct = new ScopedName (); - } - - public void enter (StringBuffer str, ScopedName target) - { - ScopedName common = new ScopedName (target); - common.popComponent (); - while (common.depth () > current.depth ()) - { - common.popComponent (); - } - while (common.depth () < current.depth ()) - { - current.popComponent (); - str.append (""); - } - while (!common.equals (current)) - { - current.popComponent (); - common.popComponent (); - str.append (""); - } - String[] submods = target.getComponents (); - for (int i = current.depth (); i < submods.length - 1; i++) - { - current.addComponent (submods [i]); - str.append (""); - } - } - - public void exit (StringBuffer str) - { - for (int i = 0; i < current.depth (); i++) - { - str.append (""); - } - current.reset (); - } - - public void pushStruct (String s) - { - struct.addComponent (s); - } - - public void popStruct () - { - struct.popComponent (); - } - - public boolean isParent (ScopedName name) - { - ScopedName dup = new ScopedName (name); - dup.popComponent (); - return dup.equals (current.catenate (struct)); - } - - public String nameFrom (ScopedName to) - { - String[] toArr = to.getComponents (); - String[] fromArr = current.getComponents (); - - if (toArr.length == fromArr.length + 1) - { - boolean same = true; - for (int i = 0; i < fromArr.length; i++) - { - if (!toArr[i].equals (fromArr[i])) - { - same = false; - break; - } - } - if (same) - { - return to.getLeaf (); - } - } - - if (fromArr.length > 0 && toArr.length > 0 && fromArr[0].equals (toArr[0])) - { - return to.toString ("::"); - } - else - { - return "::" + to.toString ("::"); - } - } - - public ScopedName getScope () - { - return new ScopedName (current); - } - - private ScopedName current; - private ScopedName struct; -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/NamedType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/NamedType.java deleted file mode 100644 index 329fb4c9e1..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/NamedType.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import org.eclipse.cyclonedds.ScopedName; - -public interface NamedType extends Type -{ - public ScopedName getSN (); - public void getToplevelXML (StringBuffer str, ModuleContext mod); -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/SequenceType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/SequenceType.java deleted file mode 100644 index 1df4d89b93..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/SequenceType.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import java.util.*; -import org.eclipse.cyclonedds.ScopedName; - -public class SequenceType extends AbstractType -{ - public SequenceType (Type subtype) - { - this.subtype = subtype; - realsub = subtype; - while (realsub instanceof TypedefType) - { - realsub = ((TypedefType)realsub).getRef (); - } - ctype = "dds_sequence_t"; - } - - private SequenceType (Type subtype, String ctype) - { - this.subtype = subtype; - realsub = subtype; - while (realsub instanceof TypedefType) - { - realsub = ((TypedefType)realsub).getRef (); - } - this.ctype = ctype; - } - - public Type dup () - { - return new SequenceType (subtype.dup (), ctype); - } - - public SequenceType clone (String name) - { - return new SequenceType (subtype.dup (), name); - } - - public boolean containsUnion () - { - Type t = subtype; - while (t instanceof TypedefType) - { - t = ((TypedefType)t).getRef (); - } - return t.containsUnion (); - } - - public ArrayList getMetaOp (String myname, String structname) - { - ArrayList result = new ArrayList (); - String offset; - - if (myname != null) - { - offset = "offsetof (" + structname + ", " + myname + ")"; - } - else - { - offset = "0u"; - } - - result.add (new String - ( - "DDS_OP_ADR | DDS_OP_TYPE_SEQ | " + realsub.getSubOp () + ", " + offset - )); - - if (!(realsub instanceof BasicType)) - { - if (realsub instanceof BoundedStringType) - { - result.add (Long.toString (((BoundedStringType)realsub).getBound () + 1)); - } - else - { - result.add (new String ("sizeof (" + realsub.getCType () + "), (" + new Integer (getMetaOpSize ()) + "u << 16u) + 4u")); - result.addAll (realsub.getMetaOp (null, null)); - result.add (new String ("DDS_OP_RTS")); - } - } - return result; - } - - public String getSubOp () - { - return "DDS_OP_SUBTYPE_SEQ"; - } - - public String getOp () - { - return "DDS_OP_TYPE_SEQ"; - } - - public String getCType () - { - return ctype; - } - - public long getKeySize () - { - return -1; - } - - public int getMetaOpSize () - { - if (realsub instanceof BasicType) - { - return 2; - } - else - { - if (realsub instanceof BoundedStringType) - { - return 3; - } - else - { - return 5 + realsub.getMetaOpSize (); - } - } - } - - public Alignment getAlignment () - { - return Alignment.PTR; - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - str.append (""); - subtype.getXML (str, mod); - str.append (""); - } - - public void populateDeps (Set depset, NamedType current) - { - subtype.populateDeps (depset, current); - } - - public boolean depsOK (Set deps) - { - return TypeUtil.deptest (subtype, deps, null); - } - - private final Type subtype; - private Type realsub; - private final String ctype; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/StructType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/StructType.java deleted file mode 100644 index 198f476634..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/StructType.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import org.eclipse.cyclonedds.ScopedName; - -import java.util.*; - -public class StructType extends AbstractType implements NamedType -{ - private static class Member - { - private Member (String n, Type t) - { - name = n; - type = t; - } - - private final String name; - private final Type type; - }; - - public StructType (ScopedName name, NamedType parent) - { - this.name = name; - this.parent = parent; - members = new ArrayList (); - } - - public void addMember (String name, Type type) - { - members.add (new Member (name, type.dup ())); - } - - public int addKeyField (String fieldname) - { - // returns the offset in metadata of the field - - int result = 0; - String search; - Type mtype = null; - - int dotpos = fieldname.indexOf ('.'); - if (dotpos == -1) - { - search = fieldname; - } - else - { - search = fieldname.substring (0, dotpos); - } - - for (Member m : members) - { - mtype = m.type; - while (mtype instanceof TypedefType) - { - mtype = ((TypedefType)mtype).getRef (); - } - if (m.name.equals (search)) - { - if (dotpos != -1) - { - result += - ((StructType)mtype).addKeyField (fieldname.substring (dotpos + 1)); - } - mtype.makeKeyField (); - break; - } - else - { - result += mtype.getMetaOpSize (); - } - } - - return result; - } - - public ArrayList getMetaOp (String myname, String structname) - { - ArrayList result = new ArrayList (); - - for (Member m : members) - { - if (myname == null) - { - result.addAll (m.type.getMetaOp (m.name, getCType ())); - } - else - { - result.addAll (m.type.getMetaOp (myname + "." + m.name, structname)); - } - } - - return result; - } - - public String getSubOp () - { - return "DDS_OP_SUBTYPE_STU"; - } - - public String getOp () - { - return "DDS_OP_TYPE_STU"; - } - - public String getCType () - { - return name.toString ("_"); - } - - public int getMetaOpSize () - { - int result = 0; - for (Member m : members) - { - result += m.type.getMetaOpSize (); - } - return result; - } - - public Alignment getAlignment () - { - Alignment result = Alignment.ONE; - for (Member m : members) - { - result = result.maximum (m.type.getAlignment ()); - } - return result; - } - - public boolean isUnoptimizable () - { - Type mtype; - - for (Member m : members) - { - mtype = m.type; - while (mtype instanceof TypedefType) - { - mtype = ((TypedefType)mtype).getRef (); - } - - if (mtype instanceof UnionType && !((UnionType)mtype).canOptimize ()) - { - return true; - } - if (mtype instanceof BoundedStringType) - { - return true; - } - - if (mtype instanceof StructType) - { - if (((StructType)mtype).isUnoptimizable ()) - { - return true; - } - } - - if (mtype.getAlignment ().equals (Alignment.PTR)) - { - return true; - } - } - return false; - } - - public boolean containsUnion () - { - for (Member m : members) - { - Type mtype = m.type; - while (mtype instanceof TypedefType) - { - mtype = ((TypedefType)mtype).getRef (); - } - if (mtype.containsUnion ()) - { - return true; - } - } - return false; - } - - public long getKeySize () - { - Type mtype; - long result = 0; - - for (Member m : members) - { - mtype = m.type; - while (mtype instanceof TypedefType) - { - mtype = ((TypedefType)mtype).getRef (); - } - if (mtype.isKeyField ()) - { - long subresult = mtype.getKeySize (); - if (subresult == -1) - { - return -1; - } - else - { - result += subresult; - } - } - } - return result; - } - - public StructType dup () - { - StructType result = new StructType (getSN (), parent); - for (Member m : members) - { - result.addMember (m.name, m.type); - } - return result; - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - if (parent != null && mod.isParent (name)) - { - getXMLbase (str, mod); - } - else - { - str.append (""); - } - } - - public void getToplevelXML (StringBuffer str, ModuleContext mod) - { - mod.enter (str, name); - getXMLbase (str, mod); - } - - private void getXMLbase (StringBuffer str, ModuleContext mod) - { - mod.pushStruct (name.getLeaf ()); - str.append (""); - for (Member m : members) - { - str.append (""); - m.type.getXML (str, mod); - str.append (""); - } - str.append (""); - mod.popStruct (); - } - - public void populateDeps (Set depset, NamedType current) - { - if (parent != null && current != null && !(parent.getSN ().equals (current.getSN ()))) - { - parent.populateDeps (depset, current); - } - else - { - for (Member m : members) - { - m.type.populateDeps (depset, this); - } - if (parent == null || current == null) - { - depset.add (name); - } - } - } - - public boolean depsOK (Set deps) - { - for (Member m : members) - { - if (!TypeUtil.deptest (m.type, deps, name)) - { - return false; - } - } - return true; - } - - public ScopedName getSN () - { - return new ScopedName (name); - } - - public void invalidate () - { - invalid = true; - } - - public boolean isInvalid () - { - return invalid; - } - - private final NamedType parent; - private final ScopedName name; - private boolean invalid = false; - private ArrayList members; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/Type.java b/src/idlc/src/org/eclipse/cyclonedds/generator/Type.java deleted file mode 100644 index b8a599db90..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/Type.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import org.eclipse.cyclonedds.ScopedName; -import java.util.*; - -public interface Type -{ - public ArrayList getMetaOp (String myname, String structname); - public String getSubOp (); - public String getOp (); - public String getCType (); - public void getXML (StringBuffer str, ModuleContext mod); - public void populateDeps (Set depset, NamedType current); - public boolean depsOK (Set deps); - public void makeKeyField (); - public boolean isKeyField (); - public long getKeySize (); - public int getMetaOpSize (); - public Alignment getAlignment (); - public Type dup (); - public boolean containsUnion (); -} - diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/TypeUtil.java b/src/idlc/src/org/eclipse/cyclonedds/generator/TypeUtil.java deleted file mode 100644 index 0040eaf53f..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/TypeUtil.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import org.eclipse.cyclonedds.ScopedName; -import java.util.Set; - -public class TypeUtil -{ - public static boolean deptest - (Type t, Set deps, ScopedName parent) - - /* t - the Type we're testing for - * deps - the types that have been written - * parent - the containing type, if any - */ - { - if (!t.depsOK (deps)) - { - return false; - } - - if (t instanceof NamedType) - { - NamedType nt = (NamedType)t; - ScopedName sn; - if (parent != null) - { - sn = new ScopedName (nt.getSN ()); - sn.popComponent (); - if (sn.equals (parent)) // It's inline - { - return true; - } - } - sn = new ScopedName (nt.getSN ()); - - // deps only has toplevel containing types, so we may need to go up - do - { - if (deps.contains (sn)) - { - return true; - } - } while (!sn.popComponent ().equals ("")); - return false; - } - else - { - return true; - } - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/TypedefType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/TypedefType.java deleted file mode 100644 index f27b86a245..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/TypedefType.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import org.eclipse.cyclonedds.ScopedName; -import java.util.*; - -public class TypedefType extends AbstractType implements NamedType -{ - public TypedefType (ScopedName name, Type ref) - { - this.ref = ref.dup (); - this.name = new ScopedName (name); - } - - public Type dup () - { - return new TypedefType (name, ref); - } - - public boolean containsUnion () - { - return ref.containsUnion (); - } - - public ArrayList getMetaOp (String myname, String structname) - { - return ref.getMetaOp (myname, structname); - } - - public String getSubOp () - { - return ref.getSubOp (); - } - - public String getOp () - { - return ref.getOp (); - } - - public String getCType () - { - return ref.getCType (); - } - - public long getKeySize () - { - return ref.getKeySize (); - } - - public int getMetaOpSize () - { - return ref.getMetaOpSize (); - } - - public Alignment getAlignment () - { - return ref.getAlignment (); - } - - public void getToplevelXML (StringBuffer str, ModuleContext mod) - { - mod.enter (str, name); - str.append (""); - ref.getXML (str, mod); - str.append (""); - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - str.append (""); - } - - public void populateDeps (Set depset, NamedType current) - { - ref.populateDeps (depset, this); - depset.add (name); - } - - public boolean depsOK (Set deps) - { - return TypeUtil.deptest (ref, deps, name); - } - - public ScopedName getSN () - { - return name; - } - - public Type getRef () - { - return ref; - } - - private final Type ref; - private final ScopedName name; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/UnionType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/UnionType.java deleted file mode 100644 index 5885c77244..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/UnionType.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.generator; - -import org.eclipse.cyclonedds.ScopedName; - -import java.util.*; - -public class UnionType extends AbstractType implements NamedType -{ - private static class Member - { - private Member (String n, Type t, String[] l) - { - name = n; - type = t; - labels = l; - } - - private final String name; - private final Type type; - private final String[] labels; - }; - - public UnionType (ScopedName name, NamedType parent) - { - this.name = name; - members = new LinkedList (); - discriminant = null; - cardinality = 0; - hasdefault = false; - this.parent = parent; - } - - public void setDiscriminant (Type discriminant) - { - this.discriminant = discriminant; - } - - public void addMember - (String name, Type type, String[] labels, boolean isdefault) - { -/* We add an extra label for 'default'. Given the different requirements - * for meta-op gen and xml gen, it may be better not to, and remember that - * if (hasdefault && we are on the last member), there should be a default. - */ - if (isdefault) - { - String[] alllabels = new String[labels.length + 1]; - System.arraycopy (labels, 0, alllabels, 0, labels.length); - alllabels [labels.length] = "0"; - members.addLast (new Member (name, type, alllabels)); - cardinality += alllabels.length; - hasdefault = true; - } - else - { - if (hasdefault) - { - Member def = members.removeLast (); - members.addLast (new Member (name, type, labels)); - members.addLast (def); - } - else - { - members.addLast (new Member (name, type, labels)); - } - cardinality += labels.length; - } - } - - public ArrayList getMetaOp (String myname, String structname) - { - ArrayList result = new ArrayList (); - - String mynamedot; - if (structname == null) - { - structname = getCType (); - mynamedot = ""; - } - else - { - mynamedot = myname + "."; - } - - /* pre-calculate offsets for JEQ instructions */ - - int[] offsets = new int[getCardinality ()]; - int opcount = 0; - int i = 0; - int l = 0; - for (Member m : members) - { - if (m.type instanceof BasicType) - { - for (l = 0; l < m.labels.length; l++) - { - offsets [i++] = 0; - } - } - else - { - for (l = 0; l < m.labels.length; l++) - { - offsets [i] = 3 * (getCardinality () - i) + opcount; - i++; - } - opcount += (m.type.getMetaOpSize () + 1); - } - } - - /* discriminant */ - - result.add - ( - "DDS_OP_ADR | DDS_OP_TYPE_UNI | " + discriminant.getSubOp () + - (hasdefault ? " | DDS_OP_FLAG_DEF" : "") + ", " + - "offsetof (" + structname + ", " + mynamedot + "_d), " + - new Integer (getCardinality ()) + "u, " + - "(" + new Integer (getMetaOpSize ()) + "u << 16) + 4u" - ); - - /* JEQs */ - - i = 0; - for (Member m : members) - { - for (l = 0; l < m.labels.length; l++) - { - result.add - ( - "DDS_OP_JEQ | " + m.type.getOp () + " | " + - new Integer (offsets [i++]) + ", " + - m.labels[l] + ", " + - "offsetof (" + structname + ", " + mynamedot + "_u." + m.name + ")" - ); - } - } - - /* Subroutines for nonbasic types */ - - for (Member m : members) - { - if (!(m.type instanceof BasicType)) - { - result.addAll (m.type.getMetaOp (null, null)); - result.add (new String ("DDS_OP_RTS")); - } - } - - /* Done */ - - return result; - } - - public String getSubOp () - { - return "DDS_OP_SUBTYPE_UNI"; - } - - public String getOp () - { - return "DDS_OP_TYPE_UNI"; - } - - public String getCType () - { - return name.toString ("_"); - } - - public long getKeySize () - { - return -1; - } - - public int getMetaOpSize () - { - int result = 4 + 3 * getCardinality (); - - for (Member m : members) - { - if (!(m.type instanceof BasicType)) - { - result += (m.type.getMetaOpSize () + 1); - } - } - - return result; - } - - public boolean canOptimize () - { - return false; - /* strictly speaking this could be true. condition would be, if all the - members have the same size, and if the non-basetype members are all - optimizable themselves, and the alignment of the discriminant is not - less than the alignment of the members. */ - } - - public boolean containsUnion () - { - return true; - } - - public Alignment getAlignment () - { - Alignment result = discriminant.getAlignment (); - for (Member m : members) - { - result = result.maximum (m.type.getAlignment ()); - } - return result; - } - - public UnionType dup () - { - UnionType result = new UnionType (name, parent); - result.setDiscriminant (discriminant); - result.members.addAll (members); - result.hasdefault = hasdefault; - result.cardinality = cardinality; - return result; - } - - public void getXML (StringBuffer str, ModuleContext mod) - { - if (parent != null && mod.isParent (name)) - { - getXMLbase (str, mod); - } - else - { - str.append (""); - } - } - - public void getToplevelXML (StringBuffer str, ModuleContext mod) - { - mod.enter (str, name); - getXMLbase (str, mod); - } - - private void getXMLbase (StringBuffer str, ModuleContext mod) - { - mod.pushStruct (name.getLeaf ()); - str.append (""); - discriminant.getXML (str, mod); - str.append (""); - for (Member m : members) - { - str.append (""); - m.type.getXML (str, mod); - for (int l = 0; l < m.labels.length; l++) - { - if (!hasdefault || m != members.getLast () || l != m.labels.length - 1) - { - str.append (""); - } - str.append (""); - mod.popStruct (); - } - - private String mungeLabel (String orig) - { - Type rt = discriminant; - while (rt instanceof TypedefType) - { - rt = ((TypedefType)rt).getRef (); - } - if (((BasicType)rt).type == BasicType.BT.CHAR) - { - return orig.substring (1, 2); - } - else if (((BasicType)rt).type == BasicType.BT.BOOLEAN) - { - return (orig.equals ("true") ? "True" : "False"); - } - else if (discriminant instanceof EnumType) - { - return ((EnumType)discriminant).descope (orig); - } - else - { - return orig; - } - } - - public void populateDeps (Set depset, NamedType current) - { - if (parent != null && current != null && !(parent.getSN ().equals (current.getSN ()))) - { - parent.populateDeps (depset, current); - } - else - { - for (Member m : members) - { - m.type.populateDeps (depset, this); - } - discriminant.populateDeps (depset, this); - if (parent == null || current == null) - { - depset.add (name); - } - } - } - - public boolean depsOK (Set deps) - { - if (!TypeUtil.deptest (discriminant, deps, name)) - { - return false; - } - - for (Member m : members) - { - if (!TypeUtil.deptest (m.type, deps, name)) - { - return false; - } - } - return true; - } - - private int getCardinality() - { - return cardinality; - } - - public ScopedName getSN () - { - return name; - } - - private final NamedType parent; - private final ScopedName name; - private Type discriminant; - private LinkedList members; - private int cardinality; - private boolean hasdefault; -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/CppLexer.g b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/CppLexer.g deleted file mode 100644 index 2ce081a968..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/CppLexer.g +++ /dev/null @@ -1,782 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -/* - * Based on CppPreprocessor by Eric Mahurin - */ - -header -{ - package org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor; -} - -options -{ - language="Java"; -} - -{ - import java.io.*; - import java.util.*; - import antlr.*; - import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessorStatus; -} - -class CppLexer extends Lexer; - -options -{ - charVocabulary = '\3'..'\377'; - testLiterals = false; - caseSensitive = true; - noConstructors = true; - k = 4; -} - -tokens -{ - ENDIF ; -} - -{ - private List m_status = new ArrayList (); - - protected TokenStreamSelector selector; - protected Integer ifState = 1; // -1: no-else false, 0: false, 1: true - protected List ifStates = new ArrayList(); // holds nested if conditions - protected List includePath = new ArrayList(); - protected List openFiles = new ArrayList(); - protected Map> defines = new HashMap>(); // holds the defines - protected Map> defineArgs = new HashMap>(); // holds the args for a macro call - protected Map> dependencies = new HashMap>(); - protected boolean stripComments = true; - protected boolean generateHashLine = true; - protected boolean processIncludes = true; - protected boolean inIncludeFile = false; - protected boolean concat = false; - protected boolean inMacro = false; - protected String escaped = ""; - protected String stripped = ""; - protected PreprocessorFile currentFile; - protected File baseDir; - protected CppLexer parent; - - public CppLexer(PreprocessorFile file, File baseDir, Map> dependencies, boolean generateHashLine) throws FileNotFoundException - { - this(file.getInputStream()); - this.setFilename(file.getOriginalPath()); - this.currentFile = file; - this.openFiles.add(currentFile); - this.baseDir = baseDir; - if(dependencies != null) - this.dependencies = dependencies; - this.dependencies.put(file.getOriginalFile(), new ArrayList()); - this.generateHashLine = generateHashLine; - - selector = new TokenStreamSelector(); - selector.select(this); - String line = "# " + getLine() + " \"" + getFilename() + "\"\n"; - CppLexer sublexer = new CppLexer(line, this); - selector.push(sublexer); - } - - private CppLexer(String str, CppLexer parent) - { - this(new ByteArrayInputStream(str.getBytes())); - this.selector = parent.selector; - this.ifState = parent.ifState; - this.ifStates = parent.ifStates; - this.defines = parent.defines; - this.defineArgs = parent.defineArgs; - this.stripComments = parent.stripComments; - this.generateHashLine = parent.generateHashLine; - this.processIncludes = parent.processIncludes; - this.inIncludeFile = parent.inIncludeFile; - this.inMacro = parent.inMacro; - this.m_status = parent.m_status; - selector.push(this); - } - - private CppLexer(PreprocessorFile file, CppLexer parent) throws FileNotFoundException - { - this(file.getInputStream()); - this.setFilename(file.getOriginalPath()); - this.dependencies = parent.dependencies; - dependencies.put(file.getOriginalFile(), new ArrayList()); - this.currentFile = file; - this.openFiles = parent.openFiles; - this.openFiles.add(currentFile); - this.baseDir = parent.baseDir; - - this.includePath = parent.includePath; - this.selector = parent.selector; - this.ifState = parent.ifState; - this.ifStates = parent.ifStates; - this.defines = parent.defines; - this.stripComments = parent.stripComments; - this.generateHashLine = parent.generateHashLine; - this.processIncludes = parent.processIncludes; - this.inIncludeFile = true; - this.m_status = parent.m_status; - this.parent = parent; - - if(cycleCheck(file)) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, "Cycle in includes; " + file + " included with itself", null)); - } - else - { - selector.push(this); - String line = "# " + getLine() + " \"" + getFilename() + "\" 1\n"; - new CppLexer(line, this); - } - } - - private boolean cycleCheck(PreprocessorFile file) - { - if(parent == null) - return false; - else if(parent.currentFile.equals(file)) - return true; - else - return parent.cycleCheck(file); - } - - private void include(String name) - { - PreprocessorFile toInclude = null; - File temp = null; - File currentDir = null; - - //Evaluate included file against directory containing the current file - String currentFilePath = currentFile.getOriginalPath(); - if(currentFilePath.contains("/")) - { - currentDir = new File(currentFilePath.substring(0, currentFilePath.lastIndexOf("/"))); - } - temp = new File(currentDir, name); - if(currentDir != null && currentDir.isAbsolute()) - { - toInclude = new PreprocessorFile(null, temp.getPath()); - } - else - { - toInclude = new PreprocessorFile(baseDir, temp.getPath()); - } - - //Search include paths for included file - if(!toInclude.exists()) - { - for(File dir:includePath) - { - temp = new File(dir, name); - if(dir.isAbsolute()) - { - toInclude = new PreprocessorFile(null, temp.getPath()); - } - else - { - toInclude = new PreprocessorFile(baseDir, temp.getPath()); - } - - if(toInclude.exists()) - { - break; - } - } - } - - List deps = dependencies.get(currentFile.getOriginalFile()); - deps.add(toInclude.getOriginalFile()); - try - { - String line = "# " + getLine() + " \"" + getFilename() + "\" 2\n"; - new CppLexer(line, this); - new CppLexer(toInclude, this); - } - catch (FileNotFoundException fnf) - { - setLine(getLine()-1); - reportError("Could not find file " + name); - newline(); - } - } - - public void close() - { - for(PreprocessorFile toClose : openFiles) - { - toClose.close(); - } - } - - public void setTokenStreamSelector(TokenStreamSelector selector) - { - this.selector = selector; - } - - public void setProcessIncludes(boolean processIncludes) - { - this.processIncludes = processIncludes; - } - - public void setCurrentFile(PreprocessorFile currentFile) - { - this.currentFile = currentFile; - } - - public void setDefines(Map> defines) - { - this.defines = defines; - } - - public void setDependencies(Map> dependencies) - { - this.dependencies = dependencies; - } - - public void setIncludePath(List includePath) - { - this.includePath = includePath; - } - - public void setBaseDir(File baseDir) - { - this.baseDir = baseDir; - } - - public void setStripComments(boolean stripComments) - { - this.stripComments = stripComments; - } - - public Map> getDependencies() - { - return dependencies; - } - - public boolean evaluateExpression(String expr) throws TokenStreamException, RecognitionException, PreprocessorException - { - //Perform macro substitution on the expression - expr = subLex(expr); - //Parse the expression - ExpLexer lexer = new ExpLexer(new ByteArrayInputStream(expr.getBytes())); - ExpParser parser = new ExpParser(this, lexer); - IIdlPreprocessorStatus parseStatus = parser.parse(); - - if(!parseStatus.isOK()) - { - m_status.add(parseStatus); - throw new PreprocessorException(); - } - - //Evaluate the expression - ExpTreeParser treeParser = new ExpTreeParser(this); - boolean result = treeParser.expression(parser.getAST()); - IIdlPreprocessorStatus treeParseStatus = treeParser.getStatus(); - - if(!treeParseStatus.isOK()) - { - m_status.add(treeParseStatus); - throw new PreprocessorException(); - } - - return result; - } - - public String subLex(String str) throws TokenStreamException, RecognitionException, PreprocessorException - { - CppLexer cppLexer = new CppLexer(new ByteArrayInputStream(str.getBytes())); - cppLexer.defines = defines; - cppLexer.selector = new TokenStreamSelector(); - cppLexer.selector.select(cppLexer); - - IIdlPreprocessorStatus cppStatus = cppLexer.getStatus(); - if(!cppStatus.isOK()) - { - m_status.add(cppStatus); - throw new PreprocessorException(); - } - - str = ""; - for (;;) - { - Token t = cppLexer.getNextToken(); - if (t.getType() == Token.EOF_TYPE) - { - break; - } - str += t.getText(); - } - return str; - } - - public void consumeConditionBody() throws TokenStreamException - { - String consumed = ""; - int lineNo = getLine(); - for (;;) - { - try - { - consumeUntil('#'); - Token t = selector.nextToken(); - if (t.getType() == ENDIF || t.getType() == EOF) - { - break; - } - } - catch (ANTLRException r) - { - // just continue if someone tried retry - } - } - for(int i = lineNo; i < getLine(); i++) - { - consumed += "\n"; - } - new CppLexer(consumed, this); - } - - public Token getNextToken() throws TokenStreamException - { - try - { - Token t = selector.nextToken(); - return t; - } - catch (TokenStreamException e) - { - m_status.add(new PreprocessorStatus(this, IIdlPreprocessorStatus.ERROR, e.getMessage(), e)); - throw e; - } - } - - public void uponEOF() throws TokenStreamException - { - try - { - selector.pop(); // return to old lexer/stream - selector.retry(); - } - catch (NoSuchElementException e) - { - // return a real EOF if nothing in stack - } - if(ifStates.size() != 0) - { - ifStates.remove(ifStates.size()-1); - reportError("Reached EOF expecting #endif"); - } - } - - public IIdlPreprocessorStatus getStatus() - { - switch (m_status.size()) - { - case 0 : - { - return new PreprocessorStatus(IIdlPreprocessorStatus.OK); - } - case 1 : - { - return m_status.get(0); - } - default : - { - PreprocessorStatus status = new PreprocessorStatus(); - for (IIdlPreprocessorStatus s : m_status) - status.add (s); - return status; - } - } - } - - @Override - public void reportError(RecognitionException recex) - { - m_status.add(new PreprocessorStatus(this, IIdlPreprocessorStatus.ERROR, recex.getMessage(), recex)); - } - - @Override - public void reportError(String message) - { - m_status.add(new PreprocessorStatus(this, IIdlPreprocessorStatus.ERROR, message, null)); - } - - @Override - public void reportWarning(String message) - { - m_status.add(new PreprocessorStatus(this, IIdlPreprocessorStatus.WARNING, message, null)); - } -} - -DIRECTIVE -{ - List args = new ArrayList(); - boolean condition = true; -} -: "#"! ( { inMacro && LA(1)=='#'}? - { - concat = true; - } - | { inMacro }? (WS)* hashExpr:EXPR! - { - if(ifState == 1) - { - if(concat) - { - concat = false; - CppLexer subLexer = new CppLexer(hashExpr.getText(), this); - } - else - { - CppLexer subLexer = new CppLexer('"' + hashExpr.getText() + '"', this); - } - } - } - | (WS)* ("include" (WS)+ includeFile:INCLUDE_STRING (WS)* DNL - { - if (ifState==1) - { - $setType(Token.SKIP); - String name = includeFile.getText(); - name = name.substring(1,name.length()-1); - include(name); - selector.retry(); - } - } - |"define" (WS)+ defineMacro:RAW_IDENTIFIER (WS)* {args.add("");} - ( - ( '(' - (WS)* defineArg0:RAW_IDENTIFIER (WS)* {args.add(defineArg0.getText());} - ( COMMA (WS)* defineArg1:RAW_IDENTIFIER (WS)* {args.add(defineArg1.getText());} )* - ')' - | WS - ) - (WS)* - defineText:MACRO_TEXT {args.set(0,defineText.getText());} - )? NL - { - if (ifState==1) - { - defines.put( defineMacro.getText(), args ); - } - $setText("\n" + escaped); - escaped = ""; - } - |"undef" (WS)+ undefMacro:RAW_IDENTIFIER (WS)* DNL - { - if (ifState==1) - { - defines.remove(undefMacro.getText()); - } - $setText("\n"); - } - |("ifdef"|"ifndef"{condition=false;}) (WS)+ ifMacro:RAW_IDENTIFIER (WS)* DNL - { - ifStates.add(ifState); - if (ifState==1) - { - condition = (defines.containsKey(ifMacro.getText())==condition); - ifState = condition?1:0; - } - else - { - ifState = -1; - } - if (ifState==1) - { - $setText("\n"); - } - else - { - // gobble up tokens until ENDIF (could be caused by else) - consumeConditionBody(); - } - } - | "if" (WS)+ ifExpr:MACRO_TEXT NL - { - ifStates.add(ifState); - if (ifState==1) - { - try - { - condition = evaluateExpression(ifExpr.getText());; - ifState = condition?1:0; - } - catch(PreprocessorException p) - { - // failed to evaluate expression set ifState so the rest of the ifstatement is discarded - ifState = -1; - } - } - else - { - ifState = -1; - } - if (ifState==1) - { - $setText("\n"); - } - else - { - // gobble up tokens until ENDIF (could be caused by else) - consumeConditionBody(); - } - } - | ( "else" {condition=true;} (WS)* DNL // treat like elif (true) - |"elif" (WS)+ expr:MACRO_TEXT NL - { - try - { - condition=evaluateExpression(expr.getText()); - } - catch(PreprocessorException p) - { - // failed to evaluate expression set ifState so the rest of the ifstatement is discarded - ifState = 1; - } - } - ) - { - if (ifState==1) - { - // previous if/elif was taken - discard rest - ifState = -1; - consumeConditionBody(); - } - else if (ifState==0 && condition) - { - // "elif" (true) or "else" - $setText("\n"); - $setType(ENDIF); - ifState = 1; - } - } - | "endif" (WS)* DNL - { - condition = (ifState==1); - try - { - // return to previous if state - ifState = ifStates.remove(ifStates.size()-1); - $setText("\n"); - if (!condition) - { - // tell if/else/elif to stop discarding tokens - $setType(ENDIF); - } - } - catch (ArrayIndexOutOfBoundsException e) - { - reportError("#endif without matching #if"); - } - } - | "line" (WS)+ ln:NUMBER ((WS)+ file:STRING)? (WS)* DNL - { - if(ifState==1) - { - $setType(Token.SKIP); - String line = "# " + ln.getText(); - if(file != null) - { - String filename = file.getText(); - line += " " + filename; - setFilename(filename.substring(1,filename.length()-1)); - } - else - { - line += " \"" + getFilename() + "\""; - } - line += "\n"; - setLine(Integer.parseInt(ln.getText())); - - CppLexer subLexer = new CppLexer(line, this); - selector.retry(); - } - } - | "error" (WS)+ errMsg:MACRO_TEXT NL - { - if(ifState == 1) - { - reportError(errMsg.getText()); - } - } - | "warning" (WS)+ warnMsg:MACRO_TEXT NL - { - if(ifState == 1) - { - $setText("\n" + escaped); - escaped = ""; - reportWarning(warnMsg.getText()); - } - } - | "pragma" (WS)+ pragma:MACRO_TEXT NL - { - if(inIncludeFile && !processIncludes) - { - $setType(Token.SKIP); - } - else - { - try - { - String pText = pragma.getText() + '\n'; - $setText("#pragma " + subLex(pText)); - } - catch(PreprocessorException e) - { - //Status already updated ignore error and continue - $setText('\n'); - } - } - } - | l:NUMBER (WS)+ f:STRING ((WS)+ flag:NUMBER)? (WS)* DNL - { - if(!generateHashLine) - { - $setText('\n'); - } - else - { - String fl = (flag == null) ? "" : " " + flag.getText(); - $setText("# " + l.getText() + " " + f.getText() + fl + '\n'); - } - } - | DNL - { - $setText('\n'); - } - ) - ) -; - -NON_DIRECTIVE -{ - if(inIncludeFile && !processIncludes) - $setType(Token.SKIP); -} -: (STRING | NUMBER | COMMENT | LEFT | RIGHT | COMMA | OPERATOR | WS) -; - -IDENTIFIER options {testLiterals=true;} -{ - List define = new ArrayList(); - List args = new ArrayList(); - if(inIncludeFile && !processIncludes) - $setType(Token.SKIP); -} -: identifier:RAW_IDENTIFIER - { - define = defineArgs.get(identifier.getText()); - if (_createToken && define==null) - { - define = defines.get(identifier.getText()); - } - } - ( { (define!=null) && (define.size()>1) }? (WS)* - '(' (WS)* - callArg0:EXPR {args.add(callArg0.getText());} - ( (WS)* COMMA (WS)* callArg1:EXPR {args.add(callArg1.getText());} )* - { args.size()==define.size()-1 }? // better have right amount - (WS)* ')' - | { !((define!=null) && (define.size()>1)) }? - ) - { - if (define!=null) - { - String defineText = define.get(0); - if (!_createToken) - { - $setText(defineText); - } - else - { - for (int i=0;i arg = new ArrayList(); - arg.add(args.get(i)); - defineArgs.put(define.get(1+i), arg); - } - inMacro=true; - CppLexer sublexer = new CppLexer(defineText, this); - selector.retry(); - inMacro=false; - } - } - } -; - -protected STRING - : '"' ( '\\' . | ~('\\'|'"') )* '"' // double quoted string - | '\'' ( '\\' . | ~('\\'|'\'') )* '\'' // single quoted string - ; - -protected INCLUDE_STRING - : '<' (~'>')* '>' - | STRING - ; - -protected MACRO_TEXT : ( options{greedy=false;} : . | ESC_NL )+; - -protected WS: (' ' | '\t' | '\f'); -protected DNL: (COMMENT | NL); -NL: (CR)? '\n' {newline();}; -CR!: ('\r')+; -protected ESC_NL : '\\'! NL! {escaped += "\n";}; - -protected COMMENT - : ( "//" ( options{greedy=false;} : . )* NL {if(stripComments || (inIncludeFile && !processIncludes))stripped+="\n";} // single line comment - | "/*" ( options{greedy=false;} : NL {if(stripComments || (inIncludeFile && !processIncludes))stripped+="\n";} - | . {if(stripComments || (inIncludeFile && !processIncludes))stripped+=" ";})* "*/" // multi-line comment - ) - { - if(stripComments || (inIncludeFile && !processIncludes)) - { - $setText(stripped); - stripped=""; - } - } - ; - -protected RAW_IDENTIFIER : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')* ; - -protected INT_SUFFIX: ("l"|"L"|"u"|"U"|"lu"|"Lu"|"lU"|"LU"|"ul"|"Ul"|"uL"|"UL"); -protected DEC_DIGITS: ('1'..'9') ('0'..'9')*; -protected HEX_PREFIX: '0' ('x'|'X'); -protected HEX_DIGITS: ('0'..'9' | 'a'..'f' | 'A'..'F')+; -protected OCT_PREFIX: '0'; -protected OCT_DIGITS: ('0'..'7')*; -protected DEC_INT: DEC_DIGITS (INT_SUFFIX)? ; -protected HEX_INT: HEX_PREFIX HEX_DIGITS (INT_SUFFIX)? ; -protected OCT_INT: OCT_PREFIX OCT_DIGITS (INT_SUFFIX)? ; -protected NUMBER : (DEC_INT | HEX_INT | OCT_INT); // allow alpha suffixes on numbers (i.e. L:long) - -// group symbols into categories to parse EXPR -protected LEFT : '(' | '[' | '{' ; -protected RIGHT : ')' | ']' | '}' ; -protected COMMA : ',' ; -protected OPERATOR : '!' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '\\' | '^' | '`' | '|' | '~' ; -DEFINED : "defined" ((LEFT) RAW_IDENTIFIER (RIGHT)| (WS)+ RAW_IDENTIFIER); - -protected EXPR // allow just about anything without being ambiguous - : (WS)? (NUMBER|IDENTIFIER)? - ( - ( LEFT EXPR ( COMMA EXPR )* RIGHT - | STRING - | OPERATOR // quotes, COMMA, LEFT, and RIGHT not in here - | WS - ) - EXPR - )? - ; diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/ExpLexer.g b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/ExpLexer.g deleted file mode 100644 index d3c0c66769..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/ExpLexer.g +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -header -{ - package org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor; -} - -options -{ - language = "Java"; -} - -class ExpLexer extends Lexer; -options -{ - k=2; -} - -RAW_IDENTIFIER: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*; -protected INT_SUFFIX: ("l"|"L"|"u"|"U"|"lu"|"Lu"|"lU"|"LU"|"ul"|"Ul"|"uL"|"UL"); -protected DEC_DIGITS: ('1'..'9') ('0'..'9')*; -protected HEX_PREFIX: '0' ('x'|'X'); -protected HEX_DIGITS: ('0'..'9' | 'a'..'f' | 'A'..'F')+; -protected OCT_PREFIX: '0'; -protected OCT_DIGITS: ('0'..'7')*; -DEC_INT: DEC_DIGITS (INT_SUFFIX!)? ; -HEX_INT: HEX_PREFIX! HEX_DIGITS (INT_SUFFIX!)? ; -OCT_INT: OCT_PREFIX OCT_DIGITS (INT_SUFFIX!)? ; - -WS : (' '|'\t'|'\r'|'\n') { $setType(Token.SKIP); } ; - -LPAREN : '(' ; -RPAREN : ')' ; -PLUS : '+' ; -MINUS : '-' ; -MULTIPLY : '*' ; -DIVIDE : '/' ; -REMAINDER : '%' ; -COMPLIMENT: '~' ; -LSHIFT : "<<" ; -RSHIFT : ">>" ; -BIT_AND : "&" ; -BIT_INC_OR: "|" ; -BIT_EXC_OR: "^" ; -OR : "||" ; -AND : "&&" ; -EQUAL : "==" ; -NOT_EQUAL : "!=" ; -NOT : '!' ; -LT : '<' ; -LE : "<=" ; -GE : ">=" ; -GT : '>' ; -DEFINED : "defined"; - - -{ - import java.util.*; - import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessorStatus; -} -class ExpParser extends Parser; -options -{ - k=4; - buildAST = true; -} -{ - private List m_status = new ArrayList (); - CppLexer parent; - - public ExpParser(CppLexer parent, ExpLexer expLexer) - { - this(expLexer); - this.parent = parent; - } - - public IIdlPreprocessorStatus parse() - { - try - { - orExpr(); - if(LA(1) != EOF) - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, "Invalid token " + LA(1), null)); - } - catch (RecognitionException e) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, e.getMessage(), e)); - } - catch (TokenStreamException e) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, e.getMessage(), e)); - } - - return getStatus (); - } - - public IIdlPreprocessorStatus getStatus() - { - switch (m_status.size()) - { - case 0 : - { - return new PreprocessorStatus(IIdlPreprocessorStatus.OK); - } - case 1 : - { - return m_status.get(0); - } - default : - { - PreprocessorStatus status = new PreprocessorStatus(); - for (IIdlPreprocessorStatus s : m_status) - status.add (s); - return status; - } - } - } - - @Override - public void reportError(RecognitionException recex) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, recex.getMessage(), recex)); - } - - @Override - public void reportError(String message) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, message, null)); - } - - @Override - public void reportWarning(String message) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.WARNING, message, null)); - } -} - -value - : HEX_INT | DEC_INT | OCT_INT | RAW_IDENTIFIER - ; - -orExpr - : andExpr (OR^ andExpr)* - ; - -andExpr - : bitIncOr (AND^ bitIncOr)* - ; - -bitIncOr - : bitExcOr (BIT_INC_OR^ bitExcOr)* - ; - -bitExcOr - : bitAnd (BIT_EXC_OR^ bitAnd)* - ; - -bitAnd - : equal (BIT_AND^ equal)* - ; - -equal - : compare ((EQUAL^ | NOT_EQUAL^) compare)* - ; - -compare - : shift ((LT^ | LE^ | GE^ | GT^) shift)* - ; - -shift - : addition ((LSHIFT^|RSHIFT^) addition)* - ; - -addition - : multiplication ((PLUS^|MINUS^) multiplication)* - ; - -multiplication - : unary ((MULTIPLY^|DIVIDE^|REMAINDER^) unary)* - ; - -unary - : (PLUS^ | MINUS^ | COMPLIMENT^)? value - | NOT^ unary - | DEFINED^ LPAREN! RAW_IDENTIFIER RPAREN! - | DEFINED^ RAW_IDENTIFIER - | LPAREN! orExpr RPAREN! - ; - - -{ - import java.util.*; - import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessorStatus; -} - -class ExpTreeParser extends TreeParser; -{ - private List m_status = new ArrayList (); - CppLexer parent; - - public ExpTreeParser(CppLexer parent) - { - this.parent = parent; - } - - public IIdlPreprocessorStatus getStatus() - { - switch (m_status.size()) - { - case 0 : - { - return new PreprocessorStatus(IIdlPreprocessorStatus.OK); - } - case 1 : - { - return m_status.get(0); - } - default : - { - PreprocessorStatus status = new PreprocessorStatus(); - for (IIdlPreprocessorStatus s : m_status) - status.add (s); - return status; - } - } - } - - @Override - public void reportError(RecognitionException recex) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, recex.getMessage(), recex)); - } - - @Override - public void reportError(String message) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.ERROR, message, null)); - } - - @Override - public void reportWarning(String message) - { - m_status.add(new PreprocessorStatus(parent, IIdlPreprocessorStatus.WARNING, message, null)); - } -} - -value returns [ int i ] -{ - int x, y; - i = 0; -} -: #(BIT_INC_OR x=value y=value { i = x|y; } ) -| #(BIT_EXC_OR x=value y=value { i = x^y; } ) -| #(BIT_AND x=value y=value { i = x&y; } ) -| #(LSHIFT x=value y=value { i = x<>y; } ) -| (#(PLUS x=value y=value)) => #(PLUS x=value y=value { i = x+y; } ) -| #(PLUS x=value { i = x; } ) -| (#(MINUS x=value y=value)) => #(MINUS x=value y=value { i = x-y; } ) -| #(MINUS x=value { i = -1*x; } ) -| #(MULTIPLY x=value y=value { i = x*y; } ) -| #(DIVIDE x=value y=value { i = x/y; } ) -| #(REMAINDER x=value y=value { i = x%y; } ) -| #(COMPLIMENT x=value { i = ~x; } ) -| d:DEC_INT { i = Integer.parseInt(d.getText(), 10); } -| h:HEX_INT { i = Integer.parseInt(h.getText(), 16); } -| o:OCT_INT { i = Integer.parseInt(o.getText(), 8); } -| r:RAW_IDENTIFIER { i = 0; } -; - -identifier returns [ String s ] -{ - s = null; -} -: i:RAW_IDENTIFIER -{ - s = i.getText(); -} -; - -expression returns [ boolean e ] -{ - boolean a, b; - int l, r; - String i; - - e = false; -} -: #(AND a=expression b=expression { e = a && b; } ) -| #(BAND a=expression b=expression { e = a & b; } ) -| #(OR a=expression b=expression { e = a || b; } ) -| #(BOR a=expression b=expression { e = a | b; } ) -| #(NOT a=expression { e = !a; } ) -| #(EQUAL l=value r=value { e = l==r; } ) -| #(NOT_EQUAL l=value r=value { e = l!=r; } ) -| #(LT l=value r=value { e = l=r; } ) -| #(GT l=value r=value { e = l>r; } ) -| #(DEFINED i=identifier { e = parent.defines.containsKey(i); } ) -; diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/IdlPreprocessor.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/IdlPreprocessor.java deleted file mode 100644 index e677c60f12..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/IdlPreprocessor.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import antlr.Token; -import antlr.TokenStreamRecognitionException; - -import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessor; -import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessorParams; -import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessorStatus; - - -/** - * Public interface to the C IIdlPreprocessor. This preprocessor will produce almost the - * same output as running the {@link http://gcc.gnu.org/onlinedocs/cpp/ gcc preprocessor}. Details - * of the output format can be found - * {@link http://gcc.gnu.org/onlinedocs/cpp/IIdlPreprocessor-Output.html#Preprocessor-Output here}. - *

- * This preprocessor differs from gcc in the way it deals with blank lines. The gcc preprocessor - * removes long sequences of blank lines and replaces them with an appropriate line marker, - * whereas this preprocessor preserves all blank lines.. - * - *


- * File input = ..;
- * StringWriter output = new StringWriter ();
- * 
- * IIdlPreprocessor preprocessor = new IIdlPreprocessor ();
- * 
- * preprocessor.setWorkingDirectory (new File ("/home/ted/project1");
- * preprocessor.addIncludeDirectory (new File ("includes"));
- * preprocessor.setStripComments (false);
- * preprocessor.setStripIncludes (true);
- * 
- * IStatus status = preprocessor.preprocess (input, output, null);
- * 
- */ -public class IdlPreprocessor implements IIdlPreprocessor -{ - public IIdlPreprocessorParams createPreprocessorParams () - { - return new IdlPreprocessorParams (); - } - - /** - * Runs the preprocessor on the specified {@link File file} and sends the resulting output to the - * specified {@link Writer writer}. It also populates the optional dependencies - * map, if one is provided. - * - * @param input - * The file to be preprocessed - * @param output - * Where to put the preprocessed output - * @param dependencies - * An optional Map containing a key for each file encountered during preprocessing. - * Each key (file) entry lists the files that it included. - */ - - public IIdlPreprocessorStatus preprocess (IIdlPreprocessorParams params, File input, Writer output, Map> dependencies) - { - CppLexer mainLexer = null; - try - { - PreprocessorFile toProcess; - if (input.isAbsolute ()) - { - toProcess = new PreprocessorFile (null, input.getPath ()); - } - else - { - toProcess = new PreprocessorFile (params.getWorkingDirectory (), input.getPath ()); - } - - List includes = new ArrayList (); - includes.addAll (params.getIncludeDirectories ()); - String path = input.getPath ().substring (0, input.getPath ().length () - input.getName ().length ()); - if (!path.equals ("")) - { - includes.add (new File (path)); - } - - Map> defines = new HashMap> (); - defines.putAll (params.getMacroDefinitions ()); - - mainLexer = new CppLexer (toProcess, params.getWorkingDirectory (), dependencies, !params.getStripLineMarkers ()); - mainLexer.setIncludePath (includes); - mainLexer.setDefines (defines); - mainLexer.setProcessIncludes (!params.getStripIncludes ()); - mainLexer.setStripComments (params.getStripComments ()); - - for (;;) - { - Token t = mainLexer.getNextToken (); - if (t.getType () == Token.EOF_TYPE) - { - break; - } - output.write (t.getText ()); - output.flush (); - } - - IIdlPreprocessorStatus status = mainLexer.getStatus (); - return status; - } - catch (TokenStreamRecognitionException e) - { - return new PreprocessorStatus (e); - } - catch (FileNotFoundException e) - { - return new PreprocessorStatus (e, input); - } - catch (Exception e) - { - String message = e.getClass ().getSimpleName () + " caught during preprocessing"; - return new PreprocessorStatus (mainLexer, IIdlPreprocessorStatus.ERROR, message, e); - } - finally - { - if (mainLexer != null) - mainLexer.close (); - } - } - - /** - * An example command line driver. This is not really part of the public API - */ - public static void main (String[] args) - { - try - { - File input = null; - IdlPreprocessor preprocessor = new IdlPreprocessor (); - IIdlPreprocessorParams params = new IdlPreprocessorParams (); - Map> dependencies = null; - Writer output = new OutputStreamWriter (System.out); - - for (int i = 0; i < args.length;) - { - String arg = args[i++]; - - if (arg.equals ("-I")) - { - if (i >= args.length) - { - usage (); - System.exit (-1); - } - else - { - params.addIncludeDirectory (new File (args[i++])); - } - } - else if (arg.equals ("-O")) - { - if (i >= args.length) - { - usage (); - System.exit (-1); - } - else - { - output = new FileWriter (args[i++]); - } - } - else if (arg.equals ("-D")) - { - if (i >= args.length) - { - usage (); - System.exit (-1); - } - else - { - arg = args[i++]; - int equals = arg.indexOf ('='); - - if (equals == -1) - { - params.addMacroDefinition (arg); - } - else - { - String name = arg.substring (0, equals); - String value = arg.substring (equals + 1); - - params.addMacroDefinition (name, value); - } - } - } - else if (arg.equals ("-U")) - { - if (i >= args.length) - { - usage (); - System.exit (-1); - } - else - { - params.removeMacroDefinition (args[i++]); - } - } - else if (arg.equals ("-B")) - { - if (i >= args.length) - { - usage (); - System.exit (-1); - } - else - { - params.setWorkingDirectory (new File (args[i++])); - } - } - else if (arg.equals ("-M")) - { - dependencies = new HashMap> (); - } - else if (arg.equals ("--LeaveComments")) - { - params.setStripComments (false); - } - else if (arg.equals ("--NoFileInline")) - { - params.setStripIncludes (true); - } - else if (arg.equals ("--NoLineMarkers")) - { - params.setStripLineMarkers (true); - } - else - { - if (i < args.length) - { - usage (); - System.exit (-1); - } - else - { - input = new File (arg); - } - } - } - - if (input == null) - { - usage (); - System.exit (-1); - } - - IIdlPreprocessorStatus status = preprocessor.preprocess (params, input, output, dependencies); - if (status.getChildStati ().length == 0) - System.err.println (status); - for (IIdlPreprocessorStatus child : status.getChildStati ()) - { - System.err.println (child); - } - - if (dependencies != null) - { - for (File file : dependencies.keySet ()) - { - System.out.println (); - System.out.println (" " + file.getPath () + " :"); - - for (File included : dependencies.get (file)) - { - System.out.println (" " + included.getPath ()); - } - } - } - } - catch (Exception e) - { - e.printStackTrace (); - } - } - - private static void usage () - { - System.err - .println ("USAGE : " - + IdlPreprocessor.class.getName () - + " [-I ] [-B ] [-O [=]] [-U ] "); - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/IdlPreprocessorParams.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/IdlPreprocessorParams.java deleted file mode 100644 index b6e839fa8d..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/IdlPreprocessorParams.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessorParams; - - -public class IdlPreprocessorParams implements IIdlPreprocessorParams -{ - private List includeDirectories = new ArrayList (); - - private boolean stripComments = true; - - private boolean stripIncludes = false; - - private boolean stripLineMarkers = false; - - private File workingDirectory = new File (System.getProperty ("user.dir")); - - private Map> defines = new HashMap> (); - - public void addIncludeDirectory (File directory) throws FileNotFoundException - { - if (directory != null && directory.exists () && directory.isDirectory ()) - { - includeDirectories.add (directory); - } - } - - public void addMacroDefinition (String name) - { - List args = new ArrayList (); - args.add (""); - defines.put (name, args); - } - - public void addMacroDefinition (String name, String value) - { - List args = new ArrayList (); - args.add (value); - defines.put (name, args); - } - - public List getIncludeDirectories () - { - return includeDirectories; - } - - public Map> getMacroDefinitions () - { - return defines; - } - - public boolean getStripComments () - { - return stripComments; - } - - public boolean getStripIncludes () - { - return stripIncludes; - } - - public boolean getStripLineMarkers () - { - return stripLineMarkers; - } - - public File getWorkingDirectory () - { - return workingDirectory; - } - - public void removeIncludeDirectory (File directory) - { - includeDirectories.remove (directory); - } - - public void removeMacroDefinition (String name) - { - defines.remove (name); - } - - public void setStripComments (boolean stripComments) - { - this.stripComments = stripComments; - } - - public void setStripIncludes (boolean stripIncludes) - { - this.stripIncludes = stripIncludes; - } - - public void setStripLineMarkers (boolean stripLineMarkers) - { - this.stripLineMarkers = stripLineMarkers; - } - - public void setWorkingDirectory (File directory) throws FileNotFoundException - { - if (directory != null && directory.exists () && directory.isDirectory ()) - { - this.workingDirectory = directory; - } - else - { - throw new FileNotFoundException ("Can't find directory " + directory.getPath ()); - } - } - -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorException.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorException.java deleted file mode 100644 index 470106d31e..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor; - -public class PreprocessorException extends Exception -{ - static final long serialVersionUID = 1; - - public PreprocessorException () - { - super (); - } - - public PreprocessorException (String message) - { - super (message); - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorFile.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorFile.java deleted file mode 100644 index 1829de874c..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorFile.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - - -public class PreprocessorFile extends File -{ - /** - * - */ - private static final long serialVersionUID = 1L; - -private String originalPath; - - private File originalFile; - - private FileInputStream inputStr; - - private boolean reachedEOF = false; - - public PreprocessorFile (File workingDir, String originalPath) - { - super (workingDir, originalPath.replace ('\\', '/')); - - this.originalPath = originalPath.replace ('\\', '/'); - this.originalFile = new File (this.originalPath); - } - - public String getOriginalPath () - { - return originalPath; - } - - public File getOriginalFile () - { - return originalFile; - } - - public InputStream getInputStream () throws FileNotFoundException - { - if (inputStr == null) - { - inputStr = new FileInputStream (this) - { - @Override - public int read () throws IOException - { - int i = super.read (); - if (reachedEOF) - { - return -1; - } - else if (i == -1) - { - reachedEOF = true; - return '\n'; - } - else - { - return i; - } - } - }; - } - return inputStr; - } - - public void close () - { - try - { - inputStr.close (); - } - catch (Exception e) - { - } - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorStatus.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorStatus.java deleted file mode 100644 index cce2fdc8a1..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/internal/preprocessor/PreprocessorStatus.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.internal.preprocessor; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.List; - -import antlr.TokenStreamRecognitionException; - -import org.eclipse.cyclonedds.idt.imports.idl.preprocessor.IIdlPreprocessorStatus; - - -public class PreprocessorStatus implements IIdlPreprocessorStatus -{ - private int m_severity; - - private String m_message; - - private String m_filename; - - private int m_line; - - private int m_column; - - private Throwable m_cause; - - private List m_children; - - public PreprocessorStatus () - { - m_children = new ArrayList(); - } - - public PreprocessorStatus (int severity) - { - m_severity = severity; - m_children = new ArrayList(); - } - - public PreprocessorStatus (CppLexer lexer, int severity, String message, Throwable cause) - { - m_severity = severity; - m_message = message; - m_filename = lexer.getFilename (); - m_line = lexer.getLine (); - m_column = lexer.getColumn (); - m_cause = cause; - m_children = new ArrayList(); - } - - public PreprocessorStatus (TokenStreamRecognitionException cause) - { - m_severity = IIdlPreprocessorStatus.ERROR; - m_message = cause.getMessage (); - m_filename = cause.recog.getFilename (); - m_line = cause.recog.getLine (); - m_column = cause.recog.getColumn (); - m_cause = cause; - m_children = new ArrayList(); - } - - public PreprocessorStatus (FileNotFoundException cause, File file) - { - m_severity = IIdlPreprocessorStatus.ERROR; - m_message = cause.getMessage (); - m_filename = file.getName (); - m_line = -1; - m_column = -1; - m_cause = cause; - m_children = new ArrayList(); - } - - public int getSeverity () - { - return m_severity; - } - - public String getMessage () - { - return m_message; - } - - public String getFilename () - { - return m_filename; - } - - public int getLine () - { - return m_line; - } - - public int getColumn () - { - return m_column; - } - - public Throwable getException () - { - return m_cause; - } - - public IIdlPreprocessorStatus[] getChildStati () - { - return (IIdlPreprocessorStatus[]) m_children.toArray (new IIdlPreprocessorStatus[m_children.size ()]); - } - - public void add (IIdlPreprocessorStatus status) - { - m_children.add (status); - if(this.m_severity < status.getSeverity ()) - { - this.m_severity = status.getSeverity (); - } - } - - public boolean isMultiStatus () - { - return !m_children.isEmpty (); - } - - public boolean isOK () - { - if(isMultiStatus()) - { - for(IIdlPreprocessorStatus child : m_children) - { - if(!child.isOK ()) - { - return false; - } - } - } - return m_severity == IIdlPreprocessorStatus.OK; - } - - public String toString () - { - return m_filename + ':' + m_line + ':' + m_column + ':' + getMessage (); - } -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessor.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessor.java deleted file mode 100644 index 6bcac1ede4..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessor.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.preprocessor; - -import java.io.File; -import java.io.Writer; -import java.util.List; -import java.util.Map; - - -/** - * Public interface to the C Preprocessor. This preprocessor will produce almost the same - * output as running the {@link http://gcc.gnu.org/onlinedocs/cpp/ gcc preprocessor}. Details of - * the output format can be found - * {@link http://gcc.gnu.org/onlinedocs/cpp/IIdlPreprocessor-Output.html#Preprocessor-Output here}. - *

- * This preprocessor differs from gcc in the way it deals with blank lines. The gcc preprocessor - * removes long sequences of blank lines and replaces them with an appropriate line marker, - * whereas this preprocessor preserves all blank lines.. - * - *


- * File input = ..;
- * StringWriter output = new StringWriter ();
- * 
- * IIdlPreprocessor preprocessor = IdlPreprocessorFactory.create ();
- * 
- * preprocessor.setWorkingDirectory (new File ("/home/ted/project1");
- * preprocessor.addIncludeDirectory (new File ("includes"));
- * preprocessor.setStripComments (false);
- * preprocessor.setStripIncludes (true);
- * 
- * IStatus status = preprocessor.preprocess (input, output, null);
- * 
- */ -public interface IIdlPreprocessor -{ - static final String PLUGIN_ID = IIdlPreprocessor.class.getPackage ().getName (); - - /** - * Runs the preprocessor on the specified {@link File file} and sends the resulting output to the - * specified {@link Writer writer}. It also populates the optional dependencies - * map, if one is provided. - * - * @param input - * The file to be preprocessed - * @param output - * Where to put the preprocessed output - * @param dependencies - * An optional Map containing a key for each file encountered during preprocessing. - * Each key (file) entry lists the files that it included. - */ - public IIdlPreprocessorStatus preprocess (IIdlPreprocessorParams params, File input, Writer output, Map> dependencies); - - public IIdlPreprocessorParams createPreprocessorParams (); -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessorParams.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessorParams.java deleted file mode 100644 index 2b6303eee7..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessorParams.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.preprocessor; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.List; -import java.util.Map; - - -/** - * FIXME: Document it! - */ -public interface IIdlPreprocessorParams -{ - /** - * Sets the working directory for this preprocessor. Any relative paths, such as the - * input file, or include directories, are resolved relative to this directory. The default value - * is taken as the value of the user.dir system property. - *

- * Setting this property on the preprocessor is equivalent to changing the current working - * directory prior to running it. - * - * @param directory - * The workig directory for this preprocessor. - * @throws FileNotFoundException - * @see System#getProperties() - * @see #getWorkingDirectory() - */ - public void setWorkingDirectory (File directory) throws FileNotFoundException; - - /** - * Returns the preprocessors current working directory. - * - * @return File - * @see #setWorkingDirectory(File) - */ - public File getWorkingDirectory (); - - /** - * Determines whether to preserve comments in the preprocessed output. The default value is - * true, meaning that comments will be stripped and therefore not present in the - * output. - * - * @param strip - */ - public void setStripComments (boolean strip); - - /** - * @return boolean - * @see #setStripComments(boolean) - */ - public boolean getStripComments (); - - /** - * Controls whether the content of included files is passed through to the preprocessed output. - * The default value is false, meaning that all content from the primary, - * and included files is passed through to the preprocessed output. If set to - * true, only the content from the primary file will be present in the - * preprocessed output. In both cases, full preprocessing takes place. This option only controls - * what is present in the output. - * - * @param strip - */ - public void setStripIncludes (boolean strip); - - /** - * @return boolean - * @see #setStripIncludes(boolean) - */ - public boolean getStripIncludes (); - - /** - * Controls whether line markers are produced in the output of this preprocessor. Line - * markers are additional lines, introduced into the output, which look like this: - *

# <line> <filename> <flags> - *

- * These lines are inserted as needed into the output (but never within a string or character - * constant). They mean that the following line originated in file <filename> at line - * <line>. <filename> will never contain any non-printing characters; they are - * replaced with octal escape sequences. - * - * @param strip - * @see #getStripLineMarkers() - */ - public void setStripLineMarkers (boolean strip); - - /** - * @return boolean - * @see #setStripLineMarkers(boolean) - */ - public boolean getStripLineMarkers (); - - /** - * Adds the specified directory to the include path (like the - * -I<directory> flag). If the specified directory is - * {@link File#isAbsolute() relative} then it will be interpreted relative to this preprocessors - * current {@link #setWorkingDirectory(File) working directory}. - * - * @param directory - * @throws FileNotFoundException - * @see #setWorkingDirectory(File) - */ - public void addIncludeDirectory (File directory) throws FileNotFoundException; - - /** - * Removes the specified directory from the include path. - * - * @param directory - */ - public void removeIncludeDirectory (File directory); - - /** - * Returns the list of include directories that make up the include path - * - * @return List - */ - public List getIncludeDirectories (); - - /** - * Predefine the specified name as a macro, with the value 1. - * - * @param name - */ - public void addMacroDefinition (String name); - - /** - * Predefine the specified name as a macro, with the specified value - * - * @param name - * @param value - */ - public void addMacroDefinition (String name, String value); - - /** - * Cancel any previous definition of name, either built in or provided with - * {@link #addMacroDefinition(String)} - * - * @param name - */ - public void removeMacroDefinition (String name); - - /** - * Returns the list of macro definitions for this preprocessor - * - * @return Map - */ - public Map> getMacroDefinitions (); -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessorStatus.java b/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessorStatus.java deleted file mode 100644 index dd7899ea39..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/idt/imports/idl/preprocessor/IIdlPreprocessorStatus.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -package org.eclipse.cyclonedds.idt.imports.idl.preprocessor; - -public interface IIdlPreprocessorStatus -{ - public static final int OK = 0; - - public static final int INFO = 0x01; - - public static final int WARNING = 0x02; - - public static final int ERROR = 0x04; - - public static final int CANCEL = 0x08; - - public int getSeverity (); - - public String getMessage (); - - public String getFilename (); - - public int getLine (); - - public int getColumn (); - - public Throwable getException (); - - public IIdlPreprocessorStatus[] getChildStati(); - - public boolean isOK(); - - public boolean isMultiStatus(); -} diff --git a/src/idlc/src/org/eclipse/cyclonedds/parser/grammar/IDL.g4 b/src/idlc/src/org/eclipse/cyclonedds/parser/grammar/IDL.g4 deleted file mode 100644 index f5326b433c..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/parser/grammar/IDL.g4 +++ /dev/null @@ -1,908 +0,0 @@ -/* -[The "BSD licence"] -Copyright (c) 2014 AutoTest Technologies, LLC -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -*/ - -/** CORBA IDL v3.5 grammar built from the OMG IDL language spec 'ptc-13-02-02' - http://www.omg.org/spec/IDL35/Beta1/PDF/ - - Initial IDL spec implementation in ANTLR v3 by Dong Nguyen. - Migrated to ANTLR v4 by Steve Osselton. - Current revision prepared by Nikita Visnevski. -*/ - -grammar IDL; - -@header { -package org.eclipse.cyclonedds.parser; -} - -specification - : import_decl* definition+ - ; - -definition - : type_decl SEMICOLON - | const_decl SEMICOLON - | except_decl SEMICOLON - | interface_or_forward_decl SEMICOLON - | module SEMICOLON - | value SEMICOLON - | type_id_decl SEMICOLON - | type_prefix_decl SEMICOLON - | event SEMICOLON - | component SEMICOLON - | home_decl SEMICOLON - | pragma_decl - | codepos_decl - ; - -module - : KW_MODULE ID LEFT_BRACE definition+ RIGHT_BRACE - ; - -interface_or_forward_decl - : interface_decl - | forward_decl - ; - -interface_decl - : interface_header LEFT_BRACE interface_body RIGHT_BRACE - ; - -forward_decl - : ( KW_ABSTRACT | KW_LOCAL )? KW_INTERFACE ID - ; - -interface_header - : ( KW_ABSTRACT | KW_LOCAL )? KW_INTERFACE ID ( interface_inheritance_spec )? - ; - -interface_body - : export* - ; - -export - : type_decl SEMICOLON - | const_decl SEMICOLON - | except_decl SEMICOLON - | attr_decl SEMICOLON - | op_decl SEMICOLON - | type_id_decl SEMICOLON - | type_prefix_decl SEMICOLON - | pragma_decl - ; - -interface_inheritance_spec - : COLON interface_name ( COMA interface_name )* - ; - -interface_name - : scoped_name - ; - -scoped_name - : ( DOUBLE_COLON )? ID ( DOUBLE_COLON ID )* - ; - -value - : ( value_decl | value_abs_decl | value_box_decl | value_forward_decl ) - ; - -value_forward_decl - : ( KW_ABSTRACT )? KW_VALUETYPE ID - ; - -value_box_decl - : KW_VALUETYPE ID type_spec - ; - -value_abs_decl - : KW_ABSTRACT KW_VALUETYPE ID value_inheritance_spec LEFT_BRACE export* RIGHT_BRACE - ; - -value_decl - : value_header LEFT_BRACE value_element* RIGHT_BRACE - ; - -value_header - : ( KW_CUSTOM )? KW_VALUETYPE ID value_inheritance_spec - ; - -value_inheritance_spec - : ( COLON ( KW_TRUNCATABLE )? value_name ( COMA value_name )* )? ( KW_SUPPORTS interface_name ( COMA interface_name )* )? - ; - -value_name - : scoped_name - ; - -value_element - : ( export | state_member | init_decl ) - ; - -state_member - : ( KW_PUBLIC | KW_PRIVATE ) type_spec declarators SEMICOLON - ; - -init_decl - : KW_FACTORY ID LEFT_BRACKET ( init_param_decls )? RIGHT_BRACKET ( raises_expr )? SEMICOLON - ; - -init_param_decls - : init_param_decl ( COMA init_param_decl )* - ; - -init_param_decl - : init_param_attribute param_type_spec simple_declarator - ; - -init_param_attribute - : KW_IN - ; - -const_decl - : KW_CONST const_type ID EQUAL const_exp - ; - -const_type - : integer_type - | char_type - | wide_char_type - | boolean_type - | floating_pt_type - | string_type - | wide_string_type - | fixed_pt_const_type - | scoped_name - | octet_type - ; - -const_exp - : or_expr - ; - -or_expr - : xor_expr ( PIPE xor_expr )* - ; - -xor_expr - : and_expr ( CARET and_expr )* - ; - -and_expr - : shift_expr ( AMPERSAND shift_expr )* - ; - -shift_expr - : add_expr ( ( RIGHT_SHIFT | LEFT_SHIFT ) add_expr )* - ; - -add_expr - : mult_expr ( ( PLUS | MINUS ) mult_expr )* - ; - -mult_expr - : unary_expr ( ( '*' | SLASH | PERCENT ) unary_expr )* - ; - -unary_expr - : unary_operator primary_expr - | primary_expr - ; - -unary_operator - : ( MINUS | PLUS | TILDE ) - ; - -primary_expr - : scoped_name - | literal - | LEFT_BRACKET const_exp RIGHT_BRACKET - ; - -literal - : ( HEX_LITERAL | INTEGER_LITERAL | OCTAL_LITERAL | STRING_LITERAL | WIDE_STRING_LITERAL | CHARACTER_LITERAL | WIDE_CHARACTER_LITERAL | FIXED_PT_LITERAL | FLOATING_PT_LITERAL | BOOLEAN_LITERAL ) - ; - -positive_int_const - : const_exp - ; - -type_decl - : KW_TYPEDEF type_declarator - | struct_type - | union_type - | enum_type - | KW_NATIVE simple_declarator - | constr_forward_decl - ; - -type_declarator - : type_spec declarators - ; - -type_spec - : simple_type_spec - | constr_type_spec - ; - -simple_type_spec - : base_type_spec - | template_type_spec - | scoped_name - ; - -base_type_spec - : floating_pt_type - | integer_type - | char_type - | wide_char_type - | boolean_type - | octet_type - | any_type - | object_type - | value_base_type - ; - -template_type_spec - : sequence_type - | string_type - | wide_string_type - | fixed_pt_type - ; - -constr_type_spec - : struct_type - | union_type - | enum_type - ; - -declarators - : declarator ( COMA declarator )* - ; - -declarator - : simple_declarator - | complex_declarator - ; - -simple_declarator - : ID - ; - -complex_declarator - : array_declarator - ; - -floating_pt_type - : ( KW_FLOAT | KW_DOUBLE | KW_LONG KW_DOUBLE ) - ; - -integer_type - : signed_int - | unsigned_int - ; - -signed_int - : signed_short_int - | signed_long_int - | signed_longlong_int - ; - -signed_short_int - : KW_SHORT - ; - -signed_long_int - : KW_LONG - ; - -signed_longlong_int - : KW_LONG KW_LONG - ; - -unsigned_int - : unsigned_short_int - | unsigned_long_int - | unsigned_longlong_int - ; - -unsigned_short_int - : KW_UNSIGNED KW_SHORT - ; - -unsigned_long_int - : KW_UNSIGNED KW_LONG - ; - -unsigned_longlong_int - : KW_UNSIGNED KW_LONG KW_LONG - ; - -char_type - : KW_CHAR - ; - -wide_char_type - : KW_WCHAR - ; - -boolean_type - : KW_BOOLEAN - ; - -octet_type - : KW_OCTET - ; - -any_type - : KW_ANY - ; - -object_type - : KW_OBJECT - ; - -struct_type - : KW_STRUCT ID LEFT_BRACE member_list RIGHT_BRACE - ; - -member_list - : member+ - ; - -member - : type_spec declarators SEMICOLON - ; - -union_type - : KW_UNION ID KW_SWITCH LEFT_BRACKET switch_type_spec RIGHT_BRACKET LEFT_BRACE switch_body RIGHT_BRACE - ; - -switch_type_spec - : integer_type - | char_type - | boolean_type - | enum_type - | scoped_name - ; - -switch_body - : case_stmt+ - ; - -case_stmt - : case_label+ element_spec SEMICOLON - ; - -case_label - : KW_CASE const_exp COLON - | KW_DEFAULT COLON - ; - -element_spec - : type_spec declarator - ; - -enum_type - : KW_ENUM ID LEFT_BRACE enumerator ( COMA enumerator )* RIGHT_BRACE - ; - -enumerator - : ID - ; - -sequence_type - : KW_SEQUENCE LEFT_ANG_BRACKET simple_type_spec COMA positive_int_const RIGHT_ANG_BRACKET - | KW_SEQUENCE LEFT_ANG_BRACKET simple_type_spec RIGHT_ANG_BRACKET - ; - -string_type - : KW_STRING LEFT_ANG_BRACKET positive_int_const RIGHT_ANG_BRACKET - | KW_STRING - ; - -wide_string_type - : KW_WSTRING LEFT_ANG_BRACKET positive_int_const RIGHT_ANG_BRACKET - | KW_WSTRING - ; - -array_declarator - : ID fixed_array_size+ - ; - -fixed_array_size - : LEFT_SQUARE_BRACKET positive_int_const RIGHT_SQUARE_BRACKET - ; - -attr_decl - : readonly_attr_spec - | attr_spec - ; - -except_decl - : KW_EXCEPTION ID LEFT_BRACE member* RIGHT_BRACE - ; - -op_decl - : ( op_attribute )? op_type_spec ID parameter_decls ( raises_expr )? ( context_expr )? - ; - -op_attribute - : KW_ONEWAY - ; - -op_type_spec - : param_type_spec - | KW_VOID - ; - -parameter_decls - : LEFT_BRACKET param_decl ( COMA param_decl )* RIGHT_BRACKET - | LEFT_BRACKET RIGHT_BRACKET - ; - -param_decl - : param_attribute param_type_spec - simple_declarator - ; - -param_attribute - : KW_IN - | KW_OUT - | KW_INOUT - ; - -raises_expr - : KW_RAISES LEFT_BRACKET scoped_name ( COMA scoped_name )* RIGHT_BRACKET - ; - -context_expr - : KW_CONTEXT LEFT_BRACKET STRING_LITERAL ( COMA STRING_LITERAL )* RIGHT_BRACKET - ; - -param_type_spec - : base_type_spec - | string_type - | wide_string_type - | scoped_name - ; - -fixed_pt_type - : KW_FIXED LEFT_ANG_BRACKET positive_int_const COMA positive_int_const RIGHT_ANG_BRACKET - ; - -fixed_pt_const_type - : KW_FIXED - ; - -value_base_type - : KW_VALUEBASE - ; - -constr_forward_decl - : KW_STRUCT ID - | KW_UNION ID - ; - -import_decl - : KW_IMPORT imported_scope SEMICOLON - ; - -imported_scope - : scoped_name | STRING_LITERAL - ; - -type_id_decl - : KW_TYPEID scoped_name STRING_LITERAL - ; - -type_prefix_decl - : KW_TYPEPREFIX scoped_name STRING_LITERAL - ; - -readonly_attr_spec - : KW_READONLY KW_ATTRIBUTE param_type_spec readonly_attr_declarator - ; - -readonly_attr_declarator - : simple_declarator raises_expr - | simple_declarator ( COMA simple_declarator )* - ; - -attr_spec - : KW_ATTRIBUTE param_type_spec attr_declarator - ; - -attr_declarator - : simple_declarator attr_raises_expr - | simple_declarator ( COMA simple_declarator )* - ; - -attr_raises_expr - : get_excep_expr ( set_excep_expr )? - | set_excep_expr - ; - -get_excep_expr - : KW_GETRAISES exception_list - ; - -set_excep_expr - : KW_SETRAISES exception_list - ; - -exception_list - : LEFT_BRACKET scoped_name ( COMA scoped_name )* RIGHT_BRACKET - ; - -component - : component_decl - | component_forward_decl - ; - -component_forward_decl - : KW_COMPONENT ID - ; - -component_decl - : component_header LEFT_BRACE component_body RIGHT_BRACE - ; - -component_header - : KW_COMPONENT ID ( component_inheritance_spec )? ( supported_interface_spec )? - ; - -supported_interface_spec - : KW_SUPPORTS scoped_name ( COMA scoped_name )* - ; - -component_inheritance_spec - : COLON scoped_name - ; - -component_body - : component_export* - ; - -component_export - : provides_decl SEMICOLON - | uses_decl SEMICOLON - | emits_decl SEMICOLON - | publishes_decl SEMICOLON - | consumes_decl SEMICOLON - | attr_decl SEMICOLON - ; - -provides_decl - : KW_PROVIDES interface_type ID - ; - -interface_type - : scoped_name - | KW_OBJECT - ; - -uses_decl - : KW_USES ( KW_MULTIPLE )? interface_type ID - ; - -emits_decl - : KW_EMITS scoped_name ID - ; - -publishes_decl - : KW_PUBLISHES scoped_name ID - ; - -consumes_decl - : KW_CONSUMES scoped_name ID - ; - -home_decl - : home_header home_body - ; - -home_header - : KW_HOME ID ( home_inheritance_spec )? ( supported_interface_spec )? KW_MANAGES scoped_name ( primary_key_spec )? - ; - -home_inheritance_spec - : COLON scoped_name - ; - -primary_key_spec - : KW_PRIMARYKEY scoped_name - ; - -home_body - : LEFT_BRACE home_export* RIGHT_BRACE - ; - -home_export - : export - | factory_decl SEMICOLON - | finder_decl SEMICOLON - ; - -factory_decl - : KW_FACTORY ID LEFT_BRACKET ( init_param_decls )? RIGHT_BRACKET ( raises_expr )? - ; - -finder_decl - : KW_FINDER ID LEFT_BRACKET ( init_param_decls )? RIGHT_BRACKET ( raises_expr )? - ; - -event - : ( event_decl | event_abs_decl | event_forward_decl) - ; - -event_forward_decl - : ( KW_ABSTRACT )? KW_EVENTTYPE ID - ; - -event_abs_decl - : KW_ABSTRACT KW_EVENTTYPE ID value_inheritance_spec LEFT_BRACE export* RIGHT_BRACE - ; - -event_decl - : event_header LEFT_BRACE value_element* RIGHT_BRACE - ; - -event_header - : ( KW_CUSTOM )? KW_EVENTTYPE ID value_inheritance_spec - ; - -pragma_decl - : LINE_PRAGMA - ; - -codepos_decl - : CODEPOS - ; - -CODEPOS - : NUMSIGN ' ' INTEGER_LITERAL ' ' STRING_LITERAL (' ' INTEGER_LITERAL )? - ; - -INTEGER_LITERAL : ('0' | '1'..'9' '0'..'9'*) INTEGER_TYPE_SUFFIX? ; - -OCTAL_LITERAL : '0' ('0'..'7')+ INTEGER_TYPE_SUFFIX? ; - -HEX_LITERAL : '0' ('x' | 'X') HEX_DIGIT+ INTEGER_TYPE_SUFFIX? ; - -fragment -HEX_DIGIT : ( '0'..'9' | 'a'..'f' | 'A'..'F' ) ; - -fragment -INTEGER_TYPE_SUFFIX : ('l' | 'L') ; - -FLOATING_PT_LITERAL - : ('0'..'9')+ '.' ('0'..'9')* EXPONENT? FLOAT_TYPE_SUFFIX? - | '.' ('0'..'9')+ EXPONENT? FLOAT_TYPE_SUFFIX? - | ('0'..'9')+ EXPONENT FLOAT_TYPE_SUFFIX? - | ('0'..'9')+ EXPONENT? FLOAT_TYPE_SUFFIX - ; - -FIXED_PT_LITERAL - : FLOATING_PT_LITERAL - ; - -fragment -EXPONENT : ('e' | 'E') (PLUS|MINUS)? ('0'..'9')+ ; - -fragment -FLOAT_TYPE_SUFFIX : ('f' | 'F' | 'd' | 'D') ; - -WIDE_CHARACTER_LITERAL - : 'L' CHARACTER_LITERAL - ; - -CHARACTER_LITERAL - : '\'' ( ESCAPE_SEQUENCE | ~('\'' | '\\') ) '\'' - ; - -WIDE_STRING_LITERAL - : 'L' STRING_LITERAL - ; - -STRING_LITERAL - : '"' ( ESCAPE_SEQUENCE | ~('\\' | '"') )* '"' - ; - -BOOLEAN_LITERAL - : 'TRUE' - | 'FALSE' - ; - -fragment -ESCAPE_SEQUENCE - : '\\' ('b' | 't' | 'n' | 'f' | 'r' | '"' | '\'' | '\\') - | UNICODE_ESCAPE - | OCTAL_ESCAPE - ; - -fragment -OCTAL_ESCAPE - : '\\' ('0'..'3') ('0'..'7') ('0'..'7') - | '\\' ('0'..'7') ('0'..'7') - | '\\' ('0'..'7') - ; - -fragment -UNICODE_ESCAPE - : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT - ; - -fragment -LETTER - : '\u0024' - | '\u0041'..'\u005a' - | '\u005f' - | '\u0061'..'\u007a' - | '\u00c0'..'\u00d6' - | '\u00d8'..'\u00f6' - | '\u00f8'..'\u00ff' - | '\u0100'..'\u1fff' - | '\u3040'..'\u318f' - | '\u3300'..'\u337f' - | '\u3400'..'\u3d2d' - | '\u4e00'..'\u9fff' - | '\uf900'..'\ufaff' - ; - -fragment -ID_DIGIT - : '\u0030'..'\u0039' - | '\u0660'..'\u0669' - | '\u06f0'..'\u06f9' - | '\u0966'..'\u096f' - | '\u09e6'..'\u09ef' - | '\u0a66'..'\u0a6f' - | '\u0ae6'..'\u0aef' - | '\u0b66'..'\u0b6f' - | '\u0be7'..'\u0bef' - | '\u0c66'..'\u0c6f' - | '\u0ce6'..'\u0cef' - | '\u0d66'..'\u0d6f' - | '\u0e50'..'\u0e59' - | '\u0ed0'..'\u0ed9' - | '\u1040'..'\u1049' - ; - -SEMICOLON: ';'; -COLON: ':'; -COMA: ','; -LEFT_BRACE: '{'; -RIGHT_BRACE: '}'; -LEFT_BRACKET: '('; -RIGHT_BRACKET: ')'; -LEFT_SQUARE_BRACKET: '['; -RIGHT_SQUARE_BRACKET: ']'; -TILDE: '~'; -SLASH: '/'; -LEFT_ANG_BRACKET: '<'; -RIGHT_ANG_BRACKET: '>'; -STAR: '*'; -PLUS: '+'; -MINUS: '-'; -CARET: '^'; -AMPERSAND: '&'; -PIPE: '|'; -EQUAL: '='; -PERCENT: '%'; -NUMSIGN: '#'; - -DOUBLE_COLON: '::'; -RIGHT_SHIFT: '>>'; -LEFT_SHIFT: '<<'; - -KW_SETRAISES: 'setraises'; -KW_OUT: 'out'; -KW_EMITS: 'emits'; -KW_STRING: 'string'; -KW_SWITCH: 'switch'; -KW_PUBLISHES: 'publishes'; -KW_TYPEDEF: 'typedef'; -KW_USES: 'uses'; -KW_PRIMARYKEY: 'primarykey'; -KW_CUSTOM: 'custom'; -KW_OCTET: 'octet'; -KW_SEQUENCE: 'sequence'; -KW_IMPORT: 'import'; -KW_STRUCT: 'struct'; -KW_NATIVE: 'native'; -KW_READONLY: 'readonly'; -KW_FINDER: 'finder'; -KW_RAISES: 'raises'; -KW_VOID: 'void'; -KW_PRIVATE: 'private'; -KW_EVENTTYPE: 'eventtype'; -KW_WCHAR: 'wchar'; -KW_IN: 'in'; -KW_DEFAULT: 'default'; -KW_PUBLIC: 'public'; -KW_SHORT: 'short'; -KW_LONG: 'long'; -KW_ENUM: 'enum'; -KW_WSTRING: 'wstring'; -KW_CONTEXT: 'context'; -KW_HOME: 'home'; -KW_FACTORY: 'factory'; -KW_EXCEPTION: 'exception'; -KW_GETRAISES: 'getraises'; -KW_CONST: 'const'; -KW_VALUEBASE: 'ValueBase'; -KW_VALUETYPE: 'valuetype'; -KW_SUPPORTS: 'supports'; -KW_MODULE: 'module'; -KW_OBJECT: 'Object'; -KW_TRUNCATABLE: 'truncatable'; -KW_UNSIGNED: 'unsigned'; -KW_FIXED: 'fixed'; -KW_UNION: 'union'; -KW_ONEWAY: 'oneway'; -KW_ANY: 'any'; -KW_CHAR: 'char'; -KW_CASE: 'case'; -KW_FLOAT: 'float'; -KW_BOOLEAN: 'boolean'; -KW_MULTIPLE: 'multiple'; -KW_ABSTRACT: 'abstract'; -KW_INOUT: 'inout'; -KW_PROVIDES: 'provides'; -KW_CONSUMES: 'consumes'; -KW_DOUBLE: 'double'; -KW_TYPEPREFIX: 'typeprefix'; -KW_TYPEID: 'typeid'; -KW_ATTRIBUTE: 'attribute'; -KW_LOCAL: 'local'; -KW_MANAGES: 'manages'; -KW_INTERFACE: 'interface'; -KW_COMPONENT: 'component'; - -ID - : LETTER (LETTER|ID_DIGIT)* - ; - -WS - : (' ' | '\r' | '\t' | '\u000C' | '\n') -> channel(HIDDEN) - ; - -COMMENT - : '/*' .*? '*/' -> channel(HIDDEN) - ; - -LINE_COMMENT - : '//' ~('\n' | '\r')* '\r'? '\n' -> channel(HIDDEN) - ; - -LINE_PRAGMA - : '#pragma' ~('\n' | '\r')* '\r'? '\n' - ; - -// [EOF] IDL.g4 diff --git a/src/idlc/src/org/eclipse/cyclonedds/parser/grammar/README.txt b/src/idlc/src/org/eclipse/cyclonedds/parser/grammar/README.txt deleted file mode 100644 index d97b5aaebc..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/parser/grammar/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -Classes in org.eclipse.cyclonedds.parser generated from IDL.g4: - -java org.antlr.v4.Tool -visitor -no-listener -package org.eclipse.cyclonedds.parser IDL.g4 diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/c/banner.st b/src/idlc/src/org/eclipse/cyclonedds/templates/c/banner.st deleted file mode 100644 index 44334aeed9..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/c/banner.st +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -banner (file, date, version) ::= << -/**************************************************************** - - Generated by Eclipse Cyclone DDS IDL to C Translator - File name: .c - Source: .idl - Cyclone DDS: V - -*****************************************************************/ ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/c/dlldef.st b/src/idlc/src/org/eclipse/cyclonedds/templates/c/dlldef.st deleted file mode 100644 index 46b6eb0d68..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/c/dlldef.st +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -dlldef (name, dllname, dllfile) ::= << -#define __DLL_ ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/c/file.st b/src/idlc/src/org/eclipse/cyclonedds/templates/c/file.st deleted file mode 100644 index cc4274f3ff..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/c/file.st +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -file (banner, name, nameupper, declarations, dll, includes) ::= << - - -#include ".h" - - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/c/module.st b/src/idlc/src/org/eclipse/cyclonedds/templates/c/module.st deleted file mode 100644 index 13f87cc86a..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/c/module.st +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -module (name, scope, declarations) ::= << - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/c/struct.st b/src/idlc/src/org/eclipse/cyclonedds/templates/c/struct.st deleted file mode 100644 index 1b196374a0..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/c/struct.st +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -struct (name, scope, extern, alignment, fields, keys, flags, declarations, marshalling, xml, istopic) ::= << - - - - - -static const dds_key_descriptor_t _keys[] = -{ - ", }; separator="},\n">} -}; - - -static const uint32_t _ops [] = -{ - -}; - -const dds_topic_descriptor_t _desc = -{ - sizeof (), - , - 0u, - 0u, - "", - _keysNULL, - , - _ops, - "\\"NULL -}; - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/c/templates.stg b/src/idlc/src/org/eclipse/cyclonedds/templates/c/templates.stg deleted file mode 100644 index 8e999bd106..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/c/templates.stg +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -import "banner.st" -import "file.st" -import "dlldef.st" -import "module.st" -import "struct.st" - -scopedname (scope, name) ::= << -_ ->> - -colonscopedname (scope, name) ::= << :: ->> - -member (name, arraydim, scope, type, str_size) ::= << ->> - -scalar_typedef (namescope, name, scope, type, arraydim, str_size) ::= << ->> - -enum (name, scope, values) ::= << ->> - -const (name, scope, expression) ::= << ->> - -union (name, scope, disc, discscope, fields, declarations) ::= << ->> - -keyfield (name, offset) ::= << ->> - -seqdef (name, scope, type, typescope) ::= << ->> - -seqdef_base (name, scope, type, arraydim, str_size) ::= << ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/allocs.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/allocs.st deleted file mode 100644 index 3d0b4f3597..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/allocs.st +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -allocs (scope, name) ::= << -#define __alloc() \ -((*) dds_alloc (sizeof ())); ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/banner.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/banner.st deleted file mode 100644 index 17c56c73d2..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/banner.st +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -banner (file, date, version) ::= << -/**************************************************************** - - Generated by Eclipse Cyclone DDS IDL to C Translator - File name: .h - Source: .idl - Cyclone DDS: V - -*****************************************************************/ ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/const.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/const.st deleted file mode 100644 index 2db25e5f08..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/const.st +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -const (name, scope, expression) ::= << -#define ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/dlldef.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/dlldef.st deleted file mode 100644 index 58961f5896..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/dlldef.st +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -dlldef (name, dllname, dllfile) ::= << - -#include "" -#undef DDS_EXPORT -#ifdef _WIN32_DLL_ - #ifdef __DLL_ - #define DDS_EXPORT extern __declspec (dllexport) - #else - #ifdef DDS_BUILD__DLL - #define DDS_EXPORT extern - #else - #define DDS_EXPORT extern __declspec (dllimport) - #endif - #endif -#else - #define DDS_EXPORT extern -#endif - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/enum.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/enum.st deleted file mode 100644 index ff690d9d40..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/enum.st +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -enum (name, scope, values) ::= << -typedef enum -{ - }; separator=",\n"> -} ; - - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/file.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/file.st deleted file mode 100644 index 06d8074fef..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/file.st +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -file (banner, name, nameupper, declarations, dll, includes) ::= << - - -#include "dds/ddsc/dds_public_impl.h" -.h"}; separator="\n"> - -#ifndef _DDSL__H_ -#define _DDSL__H_ - - - -#ifdef __cplusplus -extern "C" { -#endif - - -#ifdef __cplusplus -} -#endif -#endif /* _DDSL__H_ */ - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/module.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/module.st deleted file mode 100644 index 13f87cc86a..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/module.st +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -module (name, scope, declarations) ::= << - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/seqdef.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/seqdef.st deleted file mode 100644 index dcd9bd6989..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/seqdef.st +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -seqdef (name, scope, type, typescope) ::= << -typedef struct -{ - uint32_t _maximum; - uint32_t _length; - *_buffer; - bool _release; -} ; - - - -#define _allocbuf(l) \ -(( *) dds_alloc ((l) * sizeof ())) - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/seqdef_base.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/seqdef_base.st deleted file mode 100644 index 35fd50ad7f..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/seqdef_base.st +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -seqdef_base (name, scope, type, arraydim, str_size) ::= << -typedef struct -{ - uint32_t _maximum; - uint32_t _length; - (*_buffer); - bool _release; -} ; - - - -#define _allocbuf(l) \ -(( (*)) dds_alloc ((l) * sizeof ())) - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/struct.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/struct.st deleted file mode 100644 index a9d4c04b4c..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/struct.st +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -struct (name, scope, fields, extern, alignment, keys, flags, declarations, marshalling, xml, istopic) ::= << - - - -typedef struct -{ - -} ; - - - const dds_topic_descriptor_t _desc; - - - -#define _free(d,o) \ -dds_sample_free ((d), &_desc, (o)) - ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/templates.stg b/src/idlc/src/org/eclipse/cyclonedds/templates/h/templates.stg deleted file mode 100644 index 214f294b0d..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/templates.stg +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -import "allocs.st" -import "banner.st" -import "file.st" -import "module.st" -import "struct.st" -import "union.st" -import "dlldef.st" -import "enum.st" -import "seqdef.st" -import "seqdef_base.st" -import "const.st" - -idlToCTypeMap ::= [ - "octet":"uint8_t", - "boolean":"bool", - "char":"char", - "short":"int16_t", - "unsigned short":"uint16_t", - "long":"int32_t", - "unsigned long":"uint32_t", - "long long":"int64_t", - "unsigned long long":"uint64_t", - "float":"float", - "double":"double", - "string":"char *", - "bstring":"char", - default:key -] - -ctype (scope, type) ::= << - ->> - -member (name, arraydim, scope, type, str_size) ::= << - ; ->> - -scalar_typedef (namescope, name, scope, type, arraydim, str_size) ::= << -typedef ; - - ->> - -scopedname (scope, name) ::= << -_ ->> - -keyfield (name, offset) ::= << ->> diff --git a/src/idlc/src/org/eclipse/cyclonedds/templates/h/union.st b/src/idlc/src/org/eclipse/cyclonedds/templates/h/union.st deleted file mode 100644 index 0e2a298254..0000000000 --- a/src/idlc/src/org/eclipse/cyclonedds/templates/h/union.st +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright(c) 2006 to 2018 ADLINK Technology Limited and others -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License -// v. 1.0 which is available at -// http://www.eclipse.org/org/documents/edl-v10.php. -// -// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - -union (name, scope, disc, discscope, fields, declarations) ::= << - - - -typedef struct -{ - _d; - union - { - - } _u; -} ; - - ->> diff --git a/src/idlc/src/pom.xml.in b/src/idlc/src/pom.xml.in deleted file mode 100644 index f5e8ad92c6..0000000000 --- a/src/idlc/src/pom.xml.in +++ /dev/null @@ -1,178 +0,0 @@ - - - 4.0.0 - org.eclipse.cyclonedds - idlc - @PROJECT_VERSION@ - jar - IDL Compiler - - - - org.antlr - antlr-complete - 3.5.2 - - - org.antlr - antlr4-runtime - 4.5 - - - org.antlr - ST4 - 4.0.8 - - - - - idlc - ${basedir} - - - ${basedir} - - org/eclipse/cyclonedds/templates/** - - - - - - org.apache.maven.plugins - maven-resources-plugin - 3.0.2 - - UTF-8 - - - - org.antlr - antlr4-maven-plugin - 4.5 - - ${basedir}/org/eclipse/cyclonedds/parser/grammar - true - false - - - - antlr - generate-sources - - antlr4 - - - - - - - com.coderplus.maven.plugins - copy-rename-maven-plugin - 1.0 - - - copy-Version - generate-sources - - copy - - - ${CMAKE_CURRENT_BINARY_DIR}/org/eclipse/cyclonedds/Project.java - target/generated-sources/idlc/org/eclipse/cyclonedds/Project.java - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 3.0.0 - - - generate-sources - - add-source - - - - target/generated-sources/idlc - - - - - - - maven-assembly-plugin - - - package - - single - - - - - - jar-with-dependencies - - - - - org.apache.maven.plugins - maven-antrun-plugin - 1.8 - - - antlr - antlr - 2.7.7 - - - org.apache.ant - ant-antlr - 1.9.4 - - - - - compile - generate-sources - - - - - - - - - run - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - - diff --git a/src/security/core/tests/CMakeLists.txt b/src/security/core/tests/CMakeLists.txt index 1232589986..4b009e00f8 100644 --- a/src/security/core/tests/CMakeLists.txt +++ b/src/security/core/tests/CMakeLists.txt @@ -12,7 +12,7 @@ include (GenerateExportHeader) include (CUnit) -idlc_generate(SecurityCoreTests SecurityCoreTests.idl) +idlc_generate(TARGET SecurityCoreTests FILES SecurityCoreTests.idl) function(add_wrapper libname linklibs) set(srcs_wrapper diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 5430621067..273837ffa4 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -15,6 +15,6 @@ add_subdirectory(ddsls) add_subdirectory(ddsconf) add_subdirectory(idlpp) add_subdirectory(idlc) -if(BUILD_IDLC) +if(TARGET idlc) add_subdirectory(ddsperf) endif() diff --git a/src/tools/ddsconf/CMakeLists.txt b/src/tools/ddsconf/CMakeLists.txt index 0b6feb57c6..b11783a1a5 100644 --- a/src/tools/ddsconf/CMakeLists.txt +++ b/src/tools/ddsconf/CMakeLists.txt @@ -17,6 +17,8 @@ if(CMAKE_CROSSCOMPILING) add_executable(ddsconf IMPORTED GLOBAL) set_property(TARGET ddsconf PROPERTY IMPORTED_LOCATION ${DDSCONF_EXECUTABLE}) else() + include(GenerateDummyExportHeader) + add_executable(ddsconf ddsconf.c rnc.c md.c xsd.c defconfig.c ${CMAKE_CURRENT_LIST_DIR}/../../core/ddsi/src/q_config.c diff --git a/src/tools/ddsperf/CMakeLists.txt b/src/tools/ddsperf/CMakeLists.txt index 25374b34f3..b737778834 100644 --- a/src/tools/ddsperf/CMakeLists.txt +++ b/src/tools/ddsperf/CMakeLists.txt @@ -10,7 +10,7 @@ # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -idlc_generate(ddsperf_types ddsperf_types.idl) +idlc_generate(TARGET ddsperf_types FILES ddsperf_types.idl) add_executable(ddsperf ddsperf.c cputime.c cputime.h netload.c netload.h) target_link_libraries(ddsperf ddsperf_types ddsc) diff --git a/src/tools/ddsperf/ddsperf.c b/src/tools/ddsperf/ddsperf.c index 6449984891..f145eb2f72 100644 --- a/src/tools/ddsperf/ddsperf.c +++ b/src/tools/ddsperf/ddsperf.c @@ -523,7 +523,7 @@ static void hist_print (const char *prefix, struct hist *h, dds_time_t dt, int r hist_reset (h); } -static void *make_baggage (dds_sequence_t *b, uint32_t cnt) +static void *make_baggage (dds_sequence_octet *b, uint32_t cnt) { b->_maximum = b->_length = cnt; if (cnt == 0) diff --git a/src/tools/idlc/CMakeLists.txt b/src/tools/idlc/CMakeLists.txt index 360551ccaf..09e1c1a5a3 100644 --- a/src/tools/idlc/CMakeLists.txt +++ b/src/tools/idlc/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright(c) 2006 to 2020 ADLINK Technology Limited and others +# Copyright(c) 2021 ADLINK Technology Limited and others # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0 which is available at @@ -9,27 +9,61 @@ # # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # -if(BUILD_TESTING) - add_subdirectory(tests) -endif() +if(CMAKE_CROSSCOMPILING) + find_program(IDLC_EXECUTABLE idlc REQUIRED) + add_executable(idlc IMPORTED GLOBAL) + set_property(TARGET idlc PROPERTY IMPORTED_LOCATION ${IDLC_EXECUTABLE}}) +else() + include(CheckIncludeFile) + + check_include_file(getopt.h HAVE_GETOPT_H) + + configure_file(src/config.h.in config.h) -find_package(BISON REQUIRED) + add_executable(idlc src/idlc.c src/plugin.c src/options.c src/generator.c src/descriptor.c src/types.c) + target_link_libraries(idlc PRIVATE idl idlpp ${CMAKE_DL_LIBS}) + target_include_directories( + idlc PRIVATE + include + ${CMAKE_CURRENT_BINARY_DIR} + $>) -bison_target(parser src/parser.y "${CMAKE_CURRENT_BINARY_DIR}/parser.c") + if(NOT HAVE_GETOPT_H) + # use getopt.h from ddsrt + file(READ "${CMAKE_SOURCE_DIR}/src/ddsrt/include/getopt.h.in" getopt_h) + # remove occurrences of DDS_EXPORT + string(REGEX REPLACE "\n[ \t]*DDS_EXPORT[ \t]+" "\n" getopt_h "${getopt_h}") + # remove dds/* includes + string(REGEX REPLACE "\n[ \t]*#[ \t]*include[ \t]+[<\"]dds/[^\n]*" "" getopt_h "${getopt_h}") + # generate getopt.h + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/getopt.h" CONTENT "${getopt_h}") + target_include_directories(idlc PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") + # add getopt.c + configure_file( + "${CMAKE_SOURCE_DIR}/src/ddsrt/src/getopt.c" + "${CMAKE_CURRENT_BINARY_DIR}/getopt.c" + COPYONLY) + target_sources(idlc PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/getopt.c) + endif() -add_library(idlc-lib STATIC - src/idl.c - src/tt_create.c - src/gen_c99.c - src/gen_ostream.c - src/scanner.c - src/directive.c - ${BISON_parser_OUTPUTS}) + add_executable(${PROJECT_NAME}::idlc ALIAS idlc) -target_include_directories(idlc-lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src") -target_include_directories(idlc-lib PUBLIC "${CMAKE_CURRENT_BINARY_DIR}") + install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/idlc" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + COMPONENT dev + FILES_MATCHING PATTERN "*.h") -target_link_libraries(idlc-lib PUBLIC ddsts) + install( + TARGETS idlc + EXPORT "${CMAKE_PROJECT_NAME}" + DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT dev) + + install( + FILES Generate.cmake + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/idlc" + COMPONENT dev) +endif() -add_executable(idlc "src/main.c") -target_link_libraries(idlc PRIVATE idlc-lib idlpp) +include(Generate.cmake) diff --git a/src/tools/idlc/Generate.cmake b/src/tools/idlc/Generate.cmake new file mode 100644 index 0000000000..9b30769996 --- /dev/null +++ b/src/tools/idlc/Generate.cmake @@ -0,0 +1,70 @@ +# +# Copyright(c) 2021 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +function(IDLC_GENERATE) + set(one_value_keywords TARGET) + set(multi_value_keywords FILES FEATURES) + cmake_parse_arguments( + IDLC "" "${one_value_keywords}" "${multi_value_keywords}" "" ${ARGN}) + + if(NOT IDLC_TARGET AND NOT IDLC_FILES) + # assume deprecated invocation: TARGET FILE [FILE..] + list(GET IDLC_UNPARSED_ARGUMENTS 0 IDLC_TARGET) + list(REMOVE_AT IDLC_UNPARSED_ARGUMENTS 0 IDLC_) + set(IDLC_FILES ${IDLC_UNPARSED_ARGUMENTS}) + if (IDLC_TARGET AND IDLC_FILES) + message(WARNING " Deprecated use of idlc_generate. \n" + " Consider switching to keyword based invocation.") + endif() + # Java based compiler used to be case sensitive + list(APPEND IDLC_FEATURES "case-sensitive") + endif() + + if(NOT IDLC_TARGET) + message(FATAL_ERROR "idlc_generate called without TARGET") + elseif(NOT IDLC_FILES) + message(FATAL_ERROR "idlc_generate called without FILES") + endif() + + # remove duplicate features + if(IDLC_FEATURES) + list(REMOVE_DUPLICATES IDLC_FEATURES) + endif() + foreach(_feature ${IDLC_FEATURES}) + list(APPEND IDLC_ARGS "-f" ${_feature}) + endforeach() + + set(_dir ${CMAKE_CURRENT_BINARY_DIR}) + set(_target ${IDLC_TARGET}) + foreach(_file ${IDLC_FILES}) + get_filename_component(_path ${_file} ABSOLUTE) + list(APPEND _files "${_path}") + endforeach() + + foreach(_file ${_files}) + get_filename_component(_name ${_file} NAME_WE) + set(_source "${_dir}/${_name}.c") + set(_header "${_dir}/${_name}.h") + list(APPEND _sources "${_source}") + list(APPEND _headers "${_header}") + add_custom_command( + OUTPUT "${_source}" "${_header}" + COMMAND CycloneDDS::idlc + ARGS ${_file} ${IDLC_ARGS} + DEPENDS ${_files} CycloneDDS::idlc) + endforeach() + + add_custom_target("${_target}_generate" DEPENDS "${_sources}" "${_headers}") + add_library(${_target} INTERFACE) + target_sources(${_target} INTERFACE ${_sources} ${_headers}) + target_include_directories(${_target} INTERFACE "${_dir}") + add_dependencies(${_target} "${_target}_generate") +endfunction() diff --git a/src/tools/idlc/include/idlc/generator.h b/src/tools/idlc/include/idlc/generator.h new file mode 100644 index 0000000000..f41b59eed5 --- /dev/null +++ b/src/tools/idlc/include/idlc/generator.h @@ -0,0 +1,36 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDLC_GENERATOR_H +#define IDLC_GENERATOR_H + +#include + +#include "idl/processor.h" +#include "idlc/options.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#define IDLC_GENERATOR_OPTIONS generator_options +#define IDLC_GENERATOR_ANNOTATIONS generator_annotations +#define IDLC_GENERATE generate + +typedef const idlc_option_t **(*idlc_generator_options_t)(void); +typedef const idl_builtin_annotation_t **(*idlc_generator_annotations_t)(void); +typedef int(*idlc_generate_t)(const idl_pstate_t *); + +#if defined(__cplusplus) +} +#endif + +#endif /* IDLC_GENERATOR_H */ diff --git a/src/tools/idlc/include/idlc/options.h b/src/tools/idlc/include/idlc/options.h new file mode 100644 index 0000000000..1196c42f37 --- /dev/null +++ b/src/tools/idlc/include/idlc/options.h @@ -0,0 +1,48 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef IDLC_OPTIONS_H +#define IDLC_OPTIONS_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#define IDLC_NO_MEMORY (-1) +#define IDLC_BAD_OPTION (-2) +#define IDLC_NO_ARGUMENT (-3) +#define IDLC_BAD_ARGUMENT (-4) + +typedef struct idlc_option idlc_option_t; +struct idlc_option { + enum { + IDLC_FLAG, /**< flag-only, i.e. (sub)option without argument */ + IDLC_STRING, + IDLC_FUNCTION, + } type; + union { + int *flag; + const char **string; + int (*function)(const idlc_option_t *, const char *); + } store; + char option; /**< option, i.e. "o" in "-o". "-h" is reserved */ + char *suboption; /**< name of suboption, i.e. "mount" in "-o mount" */ + char *argument; + char *help; +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* IDLC_OPTIONS_H */ diff --git a/src/tools/idlc/src/config.h.in b/src/tools/idlc/src/config.h.in new file mode 100644 index 0000000000..aed42a2cbc --- /dev/null +++ b/src/tools/idlc/src/config.h.in @@ -0,0 +1 @@ +#cmakedefine01 HAVE_GETOPT_H diff --git a/src/tools/idlc/src/descriptor.c b/src/tools/idlc/src/descriptor.c new file mode 100644 index 0000000000..7500f69d3c --- /dev/null +++ b/src/tools/idlc/src/descriptor.c @@ -0,0 +1,1444 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#include "idl/processor.h" +#include "idl/stream.h" +#include "idl/string.h" + +#include "generator.h" +#include "descriptor.h" +#include "dds/ddsc/dds_opcodes.h" + +#define TYPE (16) +#define SUBTYPE (8) + +#define MAX_SIZE (16) + +extern char *typename(const void *node); +extern char *absolute_name(const void *node, const char *separator); + +static const uint16_t nop = UINT16_MAX; + +/* store each instruction separately for easy post processing and reduced + complexity. arrays and sequences introduce a new scope and the relative + offset to the next field is stored with the instructions for the respective + field. this requires the generator to revert its position. using separate + streams intruduces too much complexity. the table is also used to generate + a key offset table after the fact */ +struct instruction { + enum { + OPCODE, + OFFSET, + SIZE, + CONSTANT, + COUPLE, + SINGLE, + } type; + union { + struct { + uint32_t code; + uint32_t order; /**< key order if DDS_OP_FLAG_KEY */ + } opcode; + struct { + char *type; + char *member; + } offset; /**< name of type and member to generate offsetof */ + struct { + char *type; + } size; /**< name of type to generate sizeof */ + struct { + char *value; + } constant; + struct { + uint16_t high; + uint16_t low; + } couple; + uint32_t single; + } data; +}; + +struct field { + struct field *previous; + const void *node; +}; + +struct type { + struct type *previous; + struct field *fields; + const void *node; + uint32_t offset; + uint32_t label, labels; +}; + +struct alignment { + int value; + int ordering; + const char *rendering; +}; + +struct descriptor { + const idl_node_t *topic; + const struct alignment *alignment; /**< alignment of topic type */ + uint32_t keys; /**< number of keys in topic */ + uint32_t opcodes; /**< number of opcodes in descriptor */ + uint32_t flags; /**< topic descriptor flag values */ + struct type *types; + struct { + uint32_t size; /**< available number of instructions */ + uint32_t count; /**< used number of instructions */ + struct instruction *table; + } instructions; +}; + +static const struct alignment alignments[] = { +#define ALIGNMENT_1BY (&alignments[0]) + { 1, 0, "1u" }, +#define ALIGNMENT_2BY (&alignments[1]) + { 2, 2, "2u" }, +#define ALIGNMENT_4BY (&alignments[2]) + { 4, 4, "4u" }, +#define ALIGNMENT_PTR (&alignments[3]) + { 0, 6, "sizeof (char *)" }, +#define ALIGNMENT_8BY (&alignments[4]) + { 8, 8, "8u" } +}; + +static const struct alignment * +max_alignment(const struct alignment *a, const struct alignment *b) +{ + if (!a) + return b; + if (!b) + return a; + return b->ordering > a->ordering ? b : a; +} + +static idl_retcode_t push_field( + struct descriptor *descriptor, const void *node, struct field **fieldp) +{ + struct type *type; + struct field *field; + assert(descriptor); + assert(idl_is_declarator(node) || + idl_is_switch_type_spec(node) || + idl_is_case(node)); + type = descriptor->types; + assert(type); + if (!(field = calloc(1, sizeof(*field)))) + return IDL_RETCODE_NO_MEMORY; + field->previous = type->fields; + field->node = node; + type->fields = field; + if (fieldp) + *fieldp = field; + return IDL_RETCODE_OK; +} + +static void pop_field(struct descriptor *descriptor) +{ + struct field *field; + struct type *type; + assert(descriptor); + type = descriptor->types; + assert(type); + field = type->fields; + assert(field); + type->fields = field->previous; + free(field); +} + +static idl_retcode_t push_type( + struct descriptor *descriptor, const void *node, struct type **typep) +{ + struct type *type; + assert(descriptor); + assert(idl_is_struct(node) || + idl_is_union(node) || + idl_is_sequence(node) || + idl_is_array(node)); + if (!(type = calloc(1, sizeof(*type)))) + return IDL_RETCODE_NO_MEMORY; + type->previous = descriptor->types; + type->node = node; + descriptor->types = type; + if (typep) + *typep = type; + /* non-constructed types never carry fields */ + if (!idl_is_constr_type(node)) + return IDL_RETCODE_OK; + /* constructed types carry fields if previous type is a struct */ + if (!type->previous || !idl_is_struct(type->previous->node)) + return IDL_RETCODE_OK; + type->fields = type->previous->fields; + return IDL_RETCODE_OK; +} + +static void pop_type(struct descriptor *descriptor) +{ + struct type *type; + assert(descriptor); + assert(descriptor->types); + type = descriptor->types; + descriptor->types = type->previous; + assert(!type->fields || (type->previous && type->fields == type->previous->fields)); + free(type); +} + +static idl_retcode_t +stash_instruction( + struct descriptor *descriptor, uint32_t index, const struct instruction *inst) +{ + /* make more slots available as necessary */ + if (descriptor->instructions.count == descriptor->instructions.size) { + uint32_t size = descriptor->instructions.size + 100; + struct instruction *table = descriptor->instructions.table; + if (!(table = realloc(table, size * sizeof(*table)))) + return IDL_RETCODE_NO_MEMORY; + descriptor->instructions.size = size; + descriptor->instructions.table = table; + } + + if (index >= descriptor->instructions.count) { + index = descriptor->instructions.count; + } else { + size_t size = descriptor->instructions.count - index; + struct instruction *table = descriptor->instructions.table; + memmove(&table[index+1], &table[index], size * sizeof(*table)); + } + + descriptor->instructions.table[index] = *inst; + descriptor->instructions.count++; + return IDL_RETCODE_OK; +} + +static idl_retcode_t +stash_opcode( + struct descriptor *descriptor, uint32_t index, uint32_t code, uint32_t order) +{ + uint32_t type = 0; + struct instruction inst = { OPCODE, { .opcode = { .code=code, .order=order } } }; + const struct alignment *alignment = NULL; + + descriptor->opcodes++; + switch ((code & (0xffu<<24))) { + case DDS_OP_ADR: + if (code & DDS_OP_FLAG_KEY) { + descriptor->keys++; + assert(order > 0); + } else { + assert(order == 0); + } + /* fall through */ + case DDS_OP_JEQ: + type = (code >> 16) & 0xffu; + if (type == DDS_OP_VAL_ARR) + type = (code >> 8) & 0xffu; + break; + default: + return stash_instruction(descriptor, index, &inst); + } + + switch (type) { + case DDS_OP_VAL_STR: + case DDS_OP_VAL_SEQ: + alignment = ALIGNMENT_PTR; + descriptor->flags |= DDS_TOPIC_NO_OPTIMIZE; + break; + case DDS_OP_VAL_BST: + alignment = ALIGNMENT_1BY; + descriptor->flags |= DDS_TOPIC_NO_OPTIMIZE; + break; + case DDS_OP_VAL_8BY: + alignment = ALIGNMENT_8BY; + break; + case DDS_OP_VAL_4BY: + alignment = ALIGNMENT_4BY; + break; + case DDS_OP_VAL_2BY: + alignment = ALIGNMENT_2BY; + break; + case DDS_OP_VAL_1BY: + alignment = ALIGNMENT_1BY; + break; + case DDS_OP_VAL_UNI: + /* strictly speaking a topic with a union can be optimized if all + members have the same size, and if the non-basetype members are all + optimizable themselves, and the alignment of the discriminant is not + less than the alignment of the members */ + descriptor->flags |= DDS_TOPIC_NO_OPTIMIZE | DDS_TOPIC_CONTAINS_UNION; + break; + default: + break; + } + + descriptor->alignment = max_alignment(descriptor->alignment, alignment); + return stash_instruction(descriptor, index, &inst); +} + +static idl_retcode_t +stash_offset( + struct descriptor *descriptor, + uint32_t index, + const struct field *field) +{ + size_t cnt, pos, len, levels; + const char *ident; + const struct field *fld; + struct instruction inst = { OFFSET, { .offset = { NULL, NULL } } }; + + if (!field) + return stash_instruction(descriptor, index, &inst); + + assert(field); + + len = 0; + for (fld=field; fld; fld = fld->previous) { + if (idl_is_switch_type_spec(fld->node)) + ident = "_d"; + else if (idl_is_case(fld->node)) + ident = "_u"; + else + ident = idl_identifier(fld->node); + len += strlen(ident); + if (!fld->previous) + break; + len += strlen("."); + } + + pos = len; + if (!(inst.data.offset.member = malloc(len + 1))) + goto err_member; + + inst.data.offset.member[pos] = '\0'; + for (fld=field; fld; fld = fld->previous) { + if (idl_is_switch_type_spec(fld->node)) + ident = "_d"; + else if (idl_is_case(fld->node)) + ident = "_u"; + else + ident = idl_identifier(fld->node); + cnt = strlen(ident); + assert(pos >= cnt); + pos -= cnt; + memcpy(inst.data.offset.member+pos, ident, cnt); + if (!fld->previous) + break; + assert(pos > 1); + pos -= 1; + inst.data.offset.member[pos] = '.'; + } + assert(pos == 0); + + levels = idl_is_declarator(fld->node) != 0; + if (!(inst.data.offset.type = typename(idl_ancestor(fld->node, levels)))) + goto err_type; + + if (stash_instruction(descriptor, index, &inst)) + goto err_stash; + + return IDL_RETCODE_OK; +err_stash: + free(inst.data.offset.type); +err_type: + free(inst.data.offset.member); +err_member: + return IDL_RETCODE_NO_MEMORY; +} + +static idl_retcode_t +stash_size( + struct descriptor *descriptor, uint32_t index, const void *node) +{ + const idl_type_spec_t *type_spec; + struct instruction inst = { SIZE, { .size = { NULL } } }; + + if (idl_is_sequence(node)) { + bool array; + type_spec = idl_unalias(idl_type_spec(node), 0u); + array = idl_is_array(type_spec); + type_spec = idl_type_spec(node); + + /* sequence of array */ + if (array) { + char buf[1]; + char *name; + const char *fmt = "[%" PRIu32 "]"; + int cnt; + size_t len = 0, pos; + uint32_t dims; + const idl_literal_t *literal = NULL; + /* sequence of (multi-)dimensional array requires sizes in a sizeof */ + type_spec = idl_type_spec(node); + for (; idl_is_alias(type_spec); type_spec = idl_type_spec(type_spec)) { + if (!idl_is_declarator(type_spec)) + break; + literal = ((const idl_declarator_t *)type_spec)->const_expr; + for (; literal; literal = idl_next(literal)) { + assert(idl_type(literal) == IDL_ULONG); + cnt = idl_snprintf(buf, sizeof(buf), fmt, literal->value.uint32); + assert(cnt > 0); + len += (size_t)cnt; + } + } + if (idl_is_string(type_spec) && idl_is_bounded(type_spec)) { + dims = ((const idl_string_t *)type_spec)->maximum; + cnt = idl_snprintf(buf, sizeof(buf), fmt, dims); + assert(cnt > 0); + len += (size_t)cnt; + if (!(name = AUTO(idl_strdup("char")))) + return IDL_RETCODE_NO_MEMORY; + } else if (idl_is_string(type_spec)) { + if (!(name = AUTO(idl_strdup("char *")))) + return IDL_RETCODE_NO_MEMORY; + } else { + if (!(name = AUTO(typename(type_spec)))) + return IDL_RETCODE_NO_MEMORY; + } + len += strlen(name); + if (!(inst.data.size.type = malloc(len + 1))) + return IDL_RETCODE_NO_MEMORY; + pos = strlen(name); + memcpy(inst.data.size.type, name, pos); + type_spec = idl_type_spec(node); + for (; idl_is_alias(type_spec); type_spec = idl_type_spec(type_spec)) { + if (!idl_is_declarator(type_spec)) + break; + literal = ((const idl_declarator_t *)type_spec)->const_expr; + for(; literal && pos < len; literal = idl_next(literal)) { + dims = literal->value.uint32; + cnt = idl_snprintf(inst.data.size.type+pos, (len+1)-pos, fmt, dims); + assert(cnt > 0); + pos += (size_t)cnt; + } + } + if (idl_is_string(node) && idl_is_bounded(node)) { + dims = ((const idl_string_t *)type_spec)->maximum; + cnt = idl_snprintf(inst.data.size.type+pos, (len+1)-pos, fmt, dims); + assert(cnt > 0); + pos += (size_t)cnt; + } + assert(pos == len && !literal); + } else if (idl_is_string(type_spec) && idl_is_bounded(type_spec)) { + uint32_t dims = ((const idl_string_t *)type_spec)->maximum; + if (idl_asprintf(&inst.data.size.type, "char[%"PRIu32"]", dims) == -1) + goto err_type; + } else if (idl_is_string(type_spec)) { + if (!(inst.data.size.type = idl_strdup("char *"))) + goto err_type; + } else { + if (!(inst.data.size.type = typename(type_spec))) + goto err_type; + } + } else { + type_spec = idl_unalias(idl_type_spec(node), 0u); + + assert(idl_is_array(node) || idl_is_array(type_spec)); + type_spec = idl_unalias(type_spec, IDL_UNALIAS_IGNORE_ARRAY); + if (idl_is_string(type_spec) && idl_is_bounded(type_spec)) { + uint32_t dims = ((const idl_string_t *)type_spec)->maximum; + if (idl_asprintf(&inst.data.size.type, "char[%"PRIu32"]", dims) == -1) + goto err_type; + } else if (idl_is_string(type_spec)) { + if (!(inst.data.size.type = idl_strdup("char *"))) + goto err_type; + } else { + if (!(inst.data.size.type = typename(type_spec))) + goto err_type; + } + } + + if (stash_instruction(descriptor, index, &inst)) + goto err_stash; + + return IDL_RETCODE_OK; +err_stash: + free(inst.data.size.type); +err_type: + return IDL_RETCODE_NO_MEMORY; +} + +/* used to stash case labels. no need to take into account strings etc */ +static idl_retcode_t +stash_constant( + struct descriptor *descriptor, uint32_t index, const idl_const_expr_t *const_expr) +{ + int cnt = 0; + struct instruction inst = { CONSTANT, { .constant = { NULL } } }; + char **strp = &inst.data.constant.value; + + if (idl_is_enumerator(const_expr)) { + *strp = typename(const_expr); + } else { + const idl_literal_t *literal = const_expr; + + switch (idl_type(const_expr)) { + case IDL_CHAR: + cnt = idl_asprintf(strp, "'%c'", literal->value.chr); + break; + case IDL_BOOL: + cnt = idl_asprintf(strp, "%s", literal->value.bln ? "true" : "false"); + break; + case IDL_INT8: + cnt = idl_asprintf(strp, "%" PRId8, literal->value.int8); + break; + case IDL_OCTET: + case IDL_UINT8: + cnt = idl_asprintf(strp, "%" PRIu8, literal->value.uint8); + break; + case IDL_SHORT: + case IDL_INT16: + cnt = idl_asprintf(strp, "%" PRId16, literal->value.int16); + break; + case IDL_USHORT: + case IDL_UINT16: + cnt = idl_asprintf(strp, "%" PRIu16, literal->value.uint16); + break; + case IDL_LONG: + case IDL_INT32: + cnt = idl_asprintf(strp, "%" PRId32, literal->value.int32); + break; + case IDL_ULONG: + case IDL_UINT32: + cnt = idl_asprintf(strp, "%" PRIu32, literal->value.uint32); + break; + case IDL_LLONG: + case IDL_INT64: + cnt = idl_asprintf(strp, "%" PRId64, literal->value.int64); + break; + case IDL_ULLONG: + case IDL_UINT64: + cnt = idl_asprintf(strp, "%" PRIu64, literal->value.uint64); + break; + default: + break; + } + } + + if (!strp || cnt < 0) + goto err_value; + if (stash_instruction(descriptor, index, &inst)) + goto err_stash; + return IDL_RETCODE_OK; +err_stash: + free(inst.data.constant.value); +err_value: + return IDL_RETCODE_NO_MEMORY; +} + +static idl_retcode_t +stash_couple( + struct descriptor *desc, uint32_t index, uint16_t high, uint16_t low) +{ + struct instruction inst = { COUPLE, { .couple = { high, low } } }; + return stash_instruction(desc, index, &inst); +} + +static idl_retcode_t +stash_single( + struct descriptor *desc, uint32_t index, uint32_t single) +{ + struct instruction inst = { SINGLE, { .single = single } }; + return stash_instruction(desc, index, &inst); +} + +static uint32_t typecode(const idl_type_spec_t *type_spec, uint32_t shift) +{ + assert(shift == 8 || shift == 16); + if (idl_is_array(type_spec)) + return ((uint32_t)DDS_OP_VAL_ARR << shift); + type_spec = idl_unalias(type_spec, 0u); + assert(!idl_is_typedef(type_spec)); + switch (idl_type(type_spec)) { + case IDL_CHAR: + return ((uint32_t)DDS_OP_VAL_1BY << shift) | (uint32_t)DDS_OP_FLAG_SGN; + case IDL_BOOL: + return ((uint32_t)DDS_OP_VAL_1BY << shift); + case IDL_INT8: + return ((uint32_t)DDS_OP_VAL_1BY << shift) | (uint32_t)DDS_OP_FLAG_SGN; + case IDL_OCTET: + case IDL_UINT8: + return ((uint32_t)DDS_OP_VAL_1BY << shift); + case IDL_SHORT: + case IDL_INT16: + return ((uint32_t)DDS_OP_VAL_2BY << shift) | (uint32_t)DDS_OP_FLAG_SGN; + case IDL_USHORT: + case IDL_UINT16: + return ((uint32_t)DDS_OP_VAL_2BY << shift); + case IDL_LONG: + case IDL_INT32: + return ((uint32_t)DDS_OP_VAL_4BY << shift) | (uint32_t)DDS_OP_FLAG_SGN; + case IDL_ULONG: + case IDL_UINT32: + return ((uint32_t)DDS_OP_VAL_4BY << shift); + case IDL_LLONG: + case IDL_INT64: + return ((uint32_t)DDS_OP_VAL_8BY << shift) | (uint32_t)DDS_OP_FLAG_SGN; + case IDL_ULLONG: + case IDL_UINT64: + return ((uint32_t)DDS_OP_VAL_8BY << shift); + case IDL_FLOAT: + return ((uint32_t)DDS_OP_VAL_4BY << shift) | (uint32_t)DDS_OP_FLAG_FP; + case IDL_DOUBLE: + return ((uint32_t)DDS_OP_VAL_8BY << shift) | (uint32_t)DDS_OP_FLAG_FP; + case IDL_LDOUBLE: + /* long doubles are not supported (yet) */ + abort(); + case IDL_STRING: + if (idl_is_bounded(type_spec)) + return ((uint32_t)DDS_OP_VAL_BST << shift); + return ((uint32_t)DDS_OP_VAL_STR << shift); + case IDL_SEQUENCE: + /* bounded sequences are not supported (yet) */ + if (idl_is_bounded(type_spec)) + abort(); + return ((uint32_t)DDS_OP_VAL_SEQ << shift); + case IDL_ENUM: + return ((uint32_t)DDS_OP_VAL_4BY << shift); + case IDL_UNION: + return ((uint32_t)DDS_OP_VAL_UNI << shift); + case IDL_STRUCT: + return ((uint32_t)DDS_OP_VAL_STU << shift); + default: + break; + } + return 0u; +} + +static idl_retcode_t +emit_case( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + struct descriptor *descriptor = user_data; + + (void)pstate; + (void)path; + if (revisit) { + if ((ret = stash_opcode(descriptor, nop, DDS_OP_RTS, 0u))) + return ret; + pop_field(descriptor); + } else { + bool simple = true; + uint32_t off, cnt; + uint32_t opcode = DDS_OP_JEQ; + const idl_case_t *_case = node; + const idl_case_label_t *case_label; + const idl_type_spec_t *type_spec; + struct type *type = descriptor->types; + + type_spec = idl_unalias(idl_type_spec(node), 0u); + + /* simple elements are embedded, complex elements are not */ + if (idl_is_array(_case->declarator)) { + opcode |= DDS_OP_TYPE_ARR; + simple = false; + } else { + opcode |= typecode(type_spec, TYPE); + if (idl_is_array(type_spec) || !(idl_is_base_type(type_spec) || idl_is_string(type_spec))) + simple = false; + } + + if ((ret = push_field(descriptor, _case, NULL))) + return ret; + if ((ret = push_field(descriptor, _case->declarator, NULL))) + return ret; + + cnt = descriptor->instructions.count + (type->labels - type->label) * 3; + case_label = _case->case_labels; + for (; case_label; case_label = idl_next(case_label)) { + off = type->offset + 2 + (type->label * 3); + /* update offset to first instruction for complex cases */ + if (!simple) + opcode = (opcode & ~0xffffu) | (cnt - off); + /* generate union case opcode */ + if ((ret = stash_opcode(descriptor, off++, opcode, 0u))) + return ret; + /* generate union case discriminator */ + if ((ret = stash_constant(descriptor, off++, case_label->const_expr))) + return ret; + /* generate union case offset */ + if ((ret = stash_offset(descriptor, off++, type->fields))) + return ret; + type->label++; + } + + pop_field(descriptor); /* field readded by declarator for complex types */ + if (simple) { + pop_field(descriptor); + /* field readded by declarator for complex types */ + return IDL_VISIT_DONT_RECURSE; + } + + return IDL_VISIT_REVISIT; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_switch_type_spec( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + uint32_t opcode, order; + const idl_type_spec_t *type_spec; + struct descriptor *descriptor = user_data; + struct field *field = NULL; + + (void)revisit; + + type_spec = idl_unalias(idl_type_spec(node), 0u); + assert(!idl_is_typedef(type_spec) && !idl_is_array(type_spec)); + + if ((ret = push_field(descriptor, node, &field))) + return ret; + + opcode = DDS_OP_ADR | DDS_OP_TYPE_UNI | typecode(type_spec, SUBTYPE); + if ((order = idl_is_topic_key(descriptor->topic, (pstate->flags & IDL_FLAG_KEYLIST) != 0, path))) + opcode |= DDS_OP_FLAG_KEY; + if ((ret = stash_opcode(descriptor, nop, opcode, order))) + return ret; + if ((ret = stash_offset(descriptor, nop, field))) + return ret; + pop_field(descriptor); + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_union( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + struct descriptor *descriptor = user_data; + struct type *type = descriptor->types; + + (void)pstate; + (void)path; + if (revisit) { + uint32_t cnt; + assert(type->label == type->labels); + cnt = (descriptor->instructions.count - type->offset) + 2; + if ((ret = stash_single(descriptor, type->offset+2, type->labels))) + return ret; + if ((ret = stash_couple(descriptor, type->offset+3, (uint16_t)cnt, 4u))) + return ret; + pop_type(descriptor); + } else { + const idl_case_t *_case; + const idl_case_label_t *case_label; + + if ((ret = push_type(descriptor, node, &type))) + return ret; + type->offset = descriptor->instructions.count; + type->labels = type->label = 0; + + /* determine total number of case labels as opcodes for complex elements + are stored after case label opcodes */ + _case = ((const idl_union_t *)node)->cases; + for (; _case; _case = idl_next(_case)) { + case_label = _case->case_labels; + for (; case_label; case_label = idl_next(case_label)) + type->labels++; + } + + return IDL_VISIT_REVISIT; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_struct( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + struct descriptor *descriptor = user_data; + + (void)pstate; + (void)path; + if (revisit) { + pop_type(descriptor); + } else { + if ((ret = push_type(descriptor, node, NULL))) + return ret; + return IDL_VISIT_REVISIT; + } + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_sequence( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + struct descriptor *descriptor = user_data; + struct type *type = descriptor->types; + const idl_type_spec_t *type_spec; + + (void)pstate; + (void)path; + + /* resolve non-array aliases */ + type_spec = idl_unalias(idl_type_spec(node), 0u); + if (revisit) { + uint32_t off, cnt; + off = type->offset; + cnt = descriptor->instructions.count; + /* generate data field [elem-size] */ + if ((ret = stash_size(descriptor, off+2, node))) + return ret; + /* generate data field [next-insn, elem-insn] */ + if ((ret = stash_couple(descriptor, off+3, (uint16_t)((cnt-off)+3u), 4u))) + return ret; + /* generate return from subroutine */ + if ((ret = stash_opcode(descriptor, nop, DDS_OP_RTS, 0u))) + return ret; + pop_type(descriptor); + } else { + uint32_t off; + uint32_t opcode = DDS_OP_ADR | DDS_OP_TYPE_SEQ; + struct field *field = NULL; + + opcode |= typecode(type_spec, SUBTYPE); + + off = descriptor->instructions.count; + if ((ret = stash_opcode(descriptor, nop, opcode, 0u))) + return ret; + if (idl_is_struct(type->node)) + field = type->fields; + if ((ret = stash_offset(descriptor, nop, field))) + return ret; + + /* short-circuit on simple types */ + if (idl_is_string(type_spec) || idl_is_base_type(type_spec)) { + if (idl_is_bounded(type_spec)) { + if ((ret = stash_single(descriptor, nop, idl_bound(type_spec)+1))) + return ret; + } + return IDL_RETCODE_OK; + } + + if ((ret = push_type(descriptor, node, &type))) + return ret; + type->offset = off; + return IDL_VISIT_TYPE_SPEC | IDL_VISIT_REVISIT; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_array( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + struct descriptor *descriptor = user_data; + struct type *type = descriptor->types; + const idl_type_spec_t *type_spec; + bool simple = false; + uint32_t dims = 1; + + if (idl_is_array(node)) { + dims = idl_array_size(node); + type_spec = idl_type_spec(node); + } else { + type_spec = idl_unalias(idl_type_spec(node), 0u); + assert(idl_is_array(type_spec)); + dims = idl_array_size(type_spec); + type_spec = idl_type_spec(type_spec); + } + + /* resolve aliases, squash multi-dimensional arrays */ + for (; idl_is_alias(type_spec); type_spec = idl_type_spec(type_spec)) + if (idl_is_array(type_spec)) + dims *= idl_array_size(type_spec); + + simple = (idl_mask(type_spec) & (IDL_BASE_TYPE|IDL_STRING|IDL_ENUM)) != 0; + + if (revisit) { + uint32_t off, cnt; + + off = type->offset; + cnt = descriptor->instructions.count; + /* generate data field [next-insn, elem-insn] */ + if ((ret = stash_couple(descriptor, off+3, (uint16_t)((cnt-off)+3u), 5u))) + return ret; + /* generate data field [elem-size] */ + if ((ret = stash_size(descriptor, off+4, node))) + return ret; + /* generate return from subroutine */ + if ((ret = stash_opcode(descriptor, nop, DDS_OP_RTS, 0u))) + return ret; + + pop_type(descriptor); + type = descriptor->types; + if (!idl_is_alias(node) && idl_is_struct(type->node)) + pop_field(descriptor); + } else { + uint32_t off; + uint32_t opcode = DDS_OP_ADR | DDS_OP_TYPE_ARR; + uint32_t order; + struct field *field = NULL; + + /* type definitions do not introduce a field */ + if (idl_is_alias(node)) + assert(idl_is_sequence(type->node)); + else if (idl_is_struct(type->node) && (ret = push_field(descriptor, node, &field))) + return ret; + + opcode |= typecode(type_spec, SUBTYPE); + if ((order = idl_is_topic_key(descriptor->topic, (pstate->flags & IDL_FLAG_KEYLIST) != 0, path))) + opcode |= DDS_OP_FLAG_KEY; + + off = descriptor->instructions.count; + /* generate data field opcode */ + if ((ret = stash_opcode(descriptor, nop, opcode, order))) + return ret; + /* generate data field offset */ + if ((ret = stash_offset(descriptor, nop, field))) + return ret; + /* generate data field alen */ + if ((ret = stash_single(descriptor, nop, dims))) + return ret; + + /* short-circuit on simple types */ + if (simple) { + if (idl_is_bounded(type_spec)) { + uint32_t max = ((const idl_string_t *)type_spec)->maximum; + /* generate data field noop [next-insn, elem-insn] */ + if ((ret = stash_single(descriptor, nop, 0))) + return ret; + /* generate data field bound */ + if ((ret = stash_single(descriptor, nop, max))) + return ret; + } + if (!idl_is_alias(node) && idl_is_struct(type->node)) + pop_field(descriptor); + return IDL_RETCODE_OK; + } + + if ((ret = push_type(descriptor, node, &type))) + return ret; + type->offset = off; + return IDL_VISIT_TYPE_SPEC | IDL_VISIT_UNALIAS_TYPE_SPEC | IDL_VISIT_REVISIT; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_declarator( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + const idl_type_spec_t *type_spec; + struct descriptor *descriptor = user_data; + + type_spec = idl_unalias(idl_type_spec(node), 0u); + /* delegate array type specifiers or declarators */ + if (idl_is_array(node) || idl_is_array(type_spec)) + return emit_array(pstate, revisit, path, node, user_data); + + if (revisit) { + if (!idl_is_alias(node)) + pop_field(descriptor); + } else { + uint32_t opcode; + uint32_t order; + struct field *field = NULL; + + if (!idl_is_alias(node) && (ret = push_field(descriptor, node, &field))) + return ret; + + if (idl_is_sequence(type_spec)) + return IDL_VISIT_TYPE_SPEC | IDL_VISIT_REVISIT; + else if (idl_is_union(type_spec)) + return IDL_VISIT_TYPE_SPEC | IDL_VISIT_REVISIT; + else if (idl_is_struct(type_spec)) + return IDL_VISIT_TYPE_SPEC | IDL_VISIT_REVISIT; + + opcode = DDS_OP_ADR | typecode(type_spec, TYPE); + if ((order = idl_is_topic_key(descriptor->topic, (pstate->flags & IDL_FLAG_KEYLIST) != 0, path))) + opcode |= DDS_OP_FLAG_KEY; + + /* generate data field opcode */ + if ((ret = stash_opcode(descriptor, nop, opcode, order))) + return ret; + /* generate data field offset */ + if ((ret = stash_offset(descriptor, nop, field))) + return ret; + /* generate data field bound */ + if (idl_is_string(type_spec) && idl_is_bounded(type_spec)) { + uint32_t max = ((const idl_string_t *)type_spec)->maximum; + if ((ret = stash_single(descriptor, nop, max))) + return ret; + } + + return IDL_VISIT_REVISIT; + } + + return IDL_RETCODE_OK; +} + +static int print_opcode(FILE *fp, const struct instruction *inst) +{ + char buf[16]; + const char *vec[10]; + size_t len = 0; + enum dds_stream_opcode opcode; + enum dds_stream_typecode_primary type; + enum dds_stream_typecode_subtype subtype; + + assert(inst->type == OPCODE); + + opcode = inst->data.opcode.code & (0xffu << 24); + + switch (opcode) { + case DDS_OP_RTS: + vec[len++] = "DDS_OP_RTS"; + goto print; + case DDS_OP_JEQ: + vec[len++] = "DDS_OP_JEQ"; + break; + default: + assert(opcode == DDS_OP_ADR); + vec[len++] = "DDS_OP_ADR"; + break; + } + + type = inst->data.opcode.code & (0xffu << 16); + assert(type); + switch (type) { + case DDS_OP_TYPE_1BY: vec[len++] = " | DDS_OP_TYPE_1BY"; break; + case DDS_OP_TYPE_2BY: vec[len++] = " | DDS_OP_TYPE_2BY"; break; + case DDS_OP_TYPE_4BY: vec[len++] = " | DDS_OP_TYPE_4BY"; break; + case DDS_OP_TYPE_8BY: vec[len++] = " | DDS_OP_TYPE_8BY"; break; + case DDS_OP_TYPE_STR: vec[len++] = " | DDS_OP_TYPE_STR"; break; + case DDS_OP_TYPE_BST: vec[len++] = " | DDS_OP_TYPE_BST"; break; + case DDS_OP_TYPE_SEQ: vec[len++] = " | DDS_OP_TYPE_SEQ"; break; + case DDS_OP_TYPE_ARR: vec[len++] = " | DDS_OP_TYPE_ARR"; break; + case DDS_OP_TYPE_UNI: vec[len++] = " | DDS_OP_TYPE_UNI"; break; + case DDS_OP_TYPE_STU: vec[len++] = " | DDS_OP_TYPE_STU"; break; + } + + if (opcode == DDS_OP_JEQ) { + /* lower 16 bits contain offset to next instruction */ + idl_snprintf(buf, sizeof(buf), " | %u", inst->data.opcode.code & 0xffff); + vec[len++] = buf; + } else { + subtype = inst->data.opcode.code & (0xffu << 8); + assert(( subtype && (type == DDS_OP_TYPE_SEQ || + type == DDS_OP_TYPE_ARR || + type == DDS_OP_TYPE_UNI || + type == DDS_OP_TYPE_STU)) + || (!subtype && !(type == DDS_OP_TYPE_SEQ || + type == DDS_OP_TYPE_ARR || + type == DDS_OP_TYPE_UNI || + type == DDS_OP_TYPE_STU))); + switch (subtype) { + case DDS_OP_SUBTYPE_1BY: vec[len++] = " | DDS_OP_SUBTYPE_1BY"; break; + case DDS_OP_SUBTYPE_2BY: vec[len++] = " | DDS_OP_SUBTYPE_2BY"; break; + case DDS_OP_SUBTYPE_4BY: vec[len++] = " | DDS_OP_SUBTYPE_4BY"; break; + case DDS_OP_SUBTYPE_8BY: vec[len++] = " | DDS_OP_SUBTYPE_8BY"; break; + case DDS_OP_SUBTYPE_STR: vec[len++] = " | DDS_OP_SUBTYPE_STR"; break; + case DDS_OP_SUBTYPE_BST: vec[len++] = " | DDS_OP_SUBTYPE_BST"; break; + case DDS_OP_SUBTYPE_SEQ: vec[len++] = " | DDS_OP_SUBTYPE_SEQ"; break; + case DDS_OP_SUBTYPE_ARR: vec[len++] = " | DDS_OP_SUBTYPE_ARR"; break; + case DDS_OP_SUBTYPE_UNI: vec[len++] = " | DDS_OP_SUBTYPE_UNI"; break; + case DDS_OP_SUBTYPE_STU: vec[len++] = " | DDS_OP_SUBTYPE_STU"; break; + } + + if (type == DDS_OP_TYPE_UNI && (inst->data.opcode.code & DDS_OP_FLAG_DEF)) + vec[len++] = " | DDS_OP_FLAG_DEF"; + else if (inst->data.opcode.code & DDS_OP_FLAG_FP) + vec[len++] = " | DDS_OP_FLAG_FP"; + if (inst->data.opcode.code & DDS_OP_FLAG_SGN) + vec[len++] = " | DDS_OP_FLAG_SGN"; + if (inst->data.opcode.code & DDS_OP_FLAG_KEY) + vec[len++] = " | DDS_OP_FLAG_KEY"; + } + +print: + for (size_t cnt=0; cnt < len; cnt++) { + if (fputs(vec[cnt], fp) < 0) + return -1; + } + return 0; +} + +static int print_offset(FILE *fp, const struct instruction *inst) +{ + const char *type, *member; + assert(inst->type == OFFSET); + type = inst->data.offset.type; + member = inst->data.offset.member; + assert((!type && !member) || (type && member)); + if (!type) + return fputs("0u", fp); + else + return idl_fprintf(fp, "offsetof (%s, %s)", type, member); +} + +static int print_size(FILE *fp, const struct instruction *inst) +{ + const char *type; + assert(inst->type == SIZE); + type = inst->data.offset.type; + return idl_fprintf(fp, "sizeof (%s)", type) < 0 ? -1 : 0; +} + +static int print_constant(FILE *fp, const struct instruction *inst) +{ + const char *value; + value = inst->data.constant.value ? inst->data.constant.value : "0"; + return fputs(value, fp); +} + +static int print_couple(FILE *fp, const struct instruction *inst) +{ + uint16_t high, low; + assert(inst->type == COUPLE); + high = inst->data.couple.high; + low = inst->data.couple.low; + return idl_fprintf(fp, "(%"PRIu16"u << 16u) + %"PRIu16"u", high, low); +} + +static int print_single(FILE *fp, const struct instruction *inst) +{ + assert(inst->type == SINGLE); + return idl_fprintf(fp, "%"PRIu32"u", inst->data.single); +} + +static int print_opcodes(FILE *fp, const struct descriptor *descriptor) +{ + const struct instruction *inst; + enum dds_stream_opcode opcode; + enum dds_stream_typecode_primary optype; + char *type; + const char *seps[] = { ", ", ",\n " }; + const char *sep = " "; + + if (!(type = AUTO(typename(descriptor->topic)))) + return -1; + if (idl_fprintf(fp, "static const uint32_t %s_ops [] =\n{\n", type) < 0) + return -1; + for (size_t op=0, brk=0; op < descriptor->instructions.count; op++) { + inst = &descriptor->instructions.table[op]; + sep = seps[op==brk]; + switch (inst->type) { + case OPCODE: + sep = op ? seps[1] : " "; /* indent, always */ + /* determine when to break line */ + opcode = inst->data.opcode.code & (0xffu << 24); + optype = inst->data.opcode.code & (0xffu << 16); + if (opcode == DDS_OP_RTS) + brk = op+1; + else if (opcode == DDS_OP_JEQ) + brk = op+3; + else if (optype == DDS_OP_TYPE_ARR || optype == DDS_OP_TYPE_BST) + brk = op+3; + else if (optype == DDS_OP_TYPE_UNI) + brk = op+4; + else + brk = op+2; + if (fputs(sep, fp) < 0 || print_opcode(fp, inst) < 0) + return -1; + break; + case OFFSET: + if (fputs(sep, fp) < 0 || print_offset(fp, inst) < 0) + return -1; + break; + case SIZE: + if (fputs(sep, fp) < 0 || print_size(fp, inst) < 0) + return -1; + break; + case CONSTANT: + if (fputs(sep, fp) < 0 || print_constant(fp, inst) < 0) + return -1; + break; + case COUPLE: + if (fputs(sep, fp) < 0 || print_couple(fp, inst) < 0) + return -1; + break; + case SINGLE: + if (fputs(sep, fp) < 0 || print_single(fp, inst) < 0) + return -1; + break; + } + } + if (fputs("\n};\n\n", fp) < 0) + return -1; + return 0; +} + +static int print_keys(FILE *fp, struct descriptor *descriptor, bool keylist) +{ + char *type = NULL; + const char *fmt, *sep=""; + uint32_t fixed = 0; + struct { const char *member; uint32_t index; } *keys = NULL; + + if (descriptor->keys == 0) + return 0; + if (!(keys = calloc(descriptor->keys, sizeof(*keys)))) + goto err_keys; + if (!(type = typename(descriptor->topic))) + goto err_type; + for (uint32_t i=0,k=0; i < descriptor->instructions.count && k < descriptor->keys; i++) { + const struct instruction *inst = &descriptor->instructions.table[i]; + uint32_t code, size = 0, dims = 1; + uint32_t order = 0; + + if (inst->type != OPCODE) + continue; + code = inst->data.opcode.code; + if ((code & (0xffu<<24)) != DDS_OP_ADR || !(code & DDS_OP_FLAG_KEY)) + continue; + order = inst->data.opcode.order; + assert(order); + order--; + if (code & DDS_OP_TYPE_ARR) { + /* dimensions stored two instructions to the right */ + assert(i+2 < descriptor->instructions.count); + assert(descriptor->instructions.table[i+2].type == SINGLE); + dims = descriptor->instructions.table[i+2].data.single; + code >>= 8; + } else { + code >>= 16; + } + + switch (code & 0xffu) { + case DDS_OP_VAL_1BY: size = 1; break; + case DDS_OP_VAL_2BY: size = 2; break; + case DDS_OP_VAL_4BY: size = 4; break; + case DDS_OP_VAL_8BY: size = 8; break; + /* FIXME: handle bounded strings by size too? */ + default: + fixed = MAX_SIZE+1; + break; + } + + if (size > MAX_SIZE || dims > MAX_SIZE || (size*dims)+fixed > MAX_SIZE) + fixed = MAX_SIZE+1; + else + fixed += size*dims; + + inst = &descriptor->instructions.table[i+1]; + assert(inst->type == OFFSET); + assert(inst->data.offset.type); + assert(inst->data.offset.member); + if (keylist) { + assert(order < descriptor->keys); + keys[order].member = inst->data.offset.member; + keys[order].index = i; + } else { + keys[k].member = inst->data.offset.member; + keys[k].index = i; + } + k++; + } + + if (fixed && fixed <= MAX_SIZE) + descriptor->flags |= DDS_TOPIC_FIXED_KEY; + + fmt = "static const dds_key_descriptor_t %s_keys[%"PRIu32"] =\n{\n"; + if (idl_fprintf(fp, fmt, type, descriptor->keys) < 0) + goto err_print; + sep = ""; + fmt = "%s { \"%s\", %"PRIu32" }"; + for (uint32_t k=0; k < descriptor->keys; k++) { + assert(keys[k].member); + if (idl_fprintf(fp, fmt, sep, keys[k].member, keys[k].index) < 0) + goto err_print; + sep=",\n"; + } + if (fputs("\n};\n\n", fp) < 0) + goto err_print; + + free(type); + free(keys); + return 0; +err_print: + free(type); +err_type: + free(keys); +err_keys: + return -1; +} + +static int print_flags(FILE *fp, struct descriptor *descriptor) +{ + const char *fmt; + const char *vec[3] = { NULL, NULL, NULL }; + size_t cnt, len = 0; + + if (descriptor->flags & DDS_TOPIC_NO_OPTIMIZE) + vec[len++] = "DDS_TOPIC_NO_OPTIMIZE"; + if (descriptor->flags & DDS_TOPIC_CONTAINS_UNION) + vec[len++] = "DDS_TOPIC_CONTAINS_UNION"; + if (descriptor->flags & DDS_TOPIC_FIXED_KEY) + vec[len++] = "DDS_TOPIC_FIXED_KEY"; + + if (!len) + vec[len++] = "0u"; + + for (cnt=0, fmt="%s"; cnt < len; cnt++, fmt=" | %s") { + if (idl_fprintf(fp, fmt, vec[cnt]) < 0) + return -1; + } + + return fputs(",\n", fp) < 0 ? -1 : 0; +} + +static int print_descriptor(FILE *fp, struct descriptor *descriptor) +{ + char *name, *type; + const char *fmt; + + if (!(name = AUTO(absolute_name(descriptor->topic, "::")))) + return -1; + if (!(type = AUTO(typename(descriptor->topic)))) + return -1; + fmt = "const dds_topic_descriptor_t %1$s_desc =\n{\n" + " sizeof (%1$s),\n" /* size of type */ + " %2$s,\n "; /* alignment */ + if (idl_fprintf(fp, fmt, type, descriptor->alignment->rendering) < 0) + return -1; + if (print_flags(fp, descriptor) < 0) + return -1; + if (descriptor->keys) + fmt = " %1$"PRIu32"u,\n" /* number of keys */ + " \"%2$s\",\n" /* fully qualified name in IDL */ + " %3$s_keys,\n" /* key array */ + " %4$"PRIu32",\n" /* number of ops */ + " %3$s_ops,\n" /* ops array */ + " \"\"\n" /* OpenSplice metadata */ + "};\n"; + else + fmt = " %1$"PRIu32"u,\n" /* number of keys */ + " \"%2$s\",\n" /* fully qualified name in IDL */ + " NULL,\n" /* key array */ + " %4$"PRIu32",\n" /* number of ops */ + " %3$s_ops,\n" /* ops array */ + " \"\"\n" /* OpenSplice metadata */ + "};\n"; + if (idl_fprintf(fp, fmt, descriptor->keys, name, type, descriptor->opcodes) < 0) + return -1; + + return 0; +} + +idl_retcode_t generate_descriptor(const idl_pstate_t *pstate, struct generator *generator, const idl_node_t *node); + +idl_retcode_t +generate_descriptor( + const idl_pstate_t *pstate, + struct generator *generator, + const idl_node_t *node) +{ + idl_retcode_t ret; + bool keylist; + struct descriptor descriptor; + idl_visitor_t visitor; + + memset(&descriptor, 0, sizeof(descriptor)); + memset(&visitor, 0, sizeof(visitor)); + + visitor.visit = IDL_DECLARATOR | IDL_SEQUENCE | IDL_STRUCT | IDL_UNION | IDL_SWITCH_TYPE_SPEC | IDL_CASE; + visitor.accept[IDL_ACCEPT_SEQUENCE] = &emit_sequence; + visitor.accept[IDL_ACCEPT_UNION] = &emit_union; + visitor.accept[IDL_ACCEPT_SWITCH_TYPE_SPEC] = &emit_switch_type_spec; + visitor.accept[IDL_ACCEPT_CASE] = &emit_case; + visitor.accept[IDL_ACCEPT_STRUCT] = &emit_struct; + visitor.accept[IDL_ACCEPT_DECLARATOR] = &emit_declarator; + + /* must be invoked for topics only, so structs (and unions?) */ + assert(idl_is_struct(node)); + + descriptor.topic = node; + + if ((ret = push_type(&descriptor, node, NULL))) + goto err_emit; + if ((ret = idl_visit(pstate, ((const idl_struct_t *)node)->members, &visitor, &descriptor))) + goto err_emit; + pop_type(&descriptor); + if ((ret = stash_opcode(&descriptor, nop, DDS_OP_RTS, 0u))) + goto err_emit; + keylist = (pstate->flags & IDL_FLAG_KEYLIST) != 0; + if (print_keys(generator->source.handle, &descriptor, keylist) < 0) + { ret = IDL_RETCODE_NO_MEMORY; goto err_print; } + if (print_opcodes(generator->source.handle, &descriptor) < 0) + { ret = IDL_RETCODE_NO_MEMORY; goto err_print; } + if (print_descriptor(generator->source.handle, &descriptor) < 0) + { ret = IDL_RETCODE_NO_MEMORY; goto err_print; } + +err_print: +err_emit: + for (size_t i=0; i < descriptor.instructions.count; i++) { + struct instruction *inst = &descriptor.instructions.table[i]; + switch (inst->type) { + case OFFSET: + if (inst->data.offset.member) + free(inst->data.offset.member); + if (inst->data.offset.type) + free(inst->data.offset.type); + break; + case SIZE: + if (inst->data.size.type) + free(inst->data.size.type); + break; + case CONSTANT: + if (inst->data.constant.value) + free(inst->data.constant.value); + break; + default: + break; + } + } + if (descriptor.instructions.table) + free(descriptor.instructions.table); + return ret; +} diff --git a/src/idlc/src/org/eclipse/cyclonedds/TypeDefSymbol.java b/src/tools/idlc/src/descriptor.h similarity index 62% rename from src/idlc/src/org/eclipse/cyclonedds/TypeDefSymbol.java rename to src/tools/idlc/src/descriptor.h index 1275c5c294..0d18233981 100644 --- a/src/idlc/src/org/eclipse/cyclonedds/TypeDefSymbol.java +++ b/src/tools/idlc/src/descriptor.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2021 ADLINK Technology Limited and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -9,12 +9,10 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ -package org.eclipse.cyclonedds; +#include "idl/processor.h" -public abstract class TypeDefSymbol extends Symbol -{ - public TypeDefSymbol (ScopedName name) - { - super (name); - } -} +idl_retcode_t +emit_topic_descriptor( + const idl_pstate_t *pstate, + const idl_node_t *node, + void *user_data); diff --git a/src/tools/idlc/src/directive.c b/src/tools/idlc/src/directive.c deleted file mode 100644 index fbe04b055a..0000000000 --- a/src/tools/idlc/src/directive.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright(c) 2020 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include -#include -#include -#include - -#include "idl.h" -#include "parser.h" - -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/strtol.h" - -static int32_t -push_line(idl_processor_t *proc, idl_line_t *dir) -{ - if (dir->file) { - idl_file_t *file; - for (file = proc->files; file; file = file->next) { - if (strcmp(dir->file, file->name) == 0) - break; - } - if (!file) { - if (!(file = ddsrt_malloc(sizeof(*file)))) - return IDL_MEMORY_EXHAUSTED; - file->name = dir->file; - file->next = proc->files; - proc->files = file; - /* do not free filename on return */ - dir->file = NULL; - } else { - ddsrt_free(dir->file); - } - proc->scanner.position.file = (const char *)file->name; - } - proc->scanner.position.line = dir->line; - proc->scanner.position.column = 1; - ddsrt_free(dir); - proc->directive = NULL; - return 0; -} - -static int32_t -parse_line(idl_processor_t *proc, idl_token_t *tok) -{ - idl_line_t *dir = (idl_line_t *)proc->directive; - - switch (proc->state) { - case IDL_SCAN_LINE: { - char *end; - unsigned long long ullng; - - assert(!dir); - - if (tok->code != IDL_TOKEN_PP_NUMBER) { - idl_error(proc, &tok->location, - "no line number in #line directive"); - return IDL_PARSE_ERROR; - } - ddsrt_strtoull(tok->value.str, &end, 10, &ullng); - if (end == tok->value.str || *end != '\0' || ullng > INT32_MAX) { - idl_error(proc, &tok->location, - "invalid line number in #line directive"); - return IDL_PARSE_ERROR; - } - if (!(dir = ddsrt_malloc(sizeof(*dir)))) { - return IDL_MEMORY_EXHAUSTED; - } - dir->directive.type = IDL_LINE; - dir->line = (uint32_t)ullng; - dir->file = NULL; - dir->extra_tokens = false; - proc->directive = (idl_directive_t *)dir; - proc->state = IDL_SCAN_FILENAME; - } break; - case IDL_SCAN_FILENAME: - assert(dir); - proc->state = IDL_SCAN_EXTRA_TOKEN; - if (tok->code != '\n' && tok->code != 0) { - if (tok->code != IDL_TOKEN_STRING_LITERAL) { - idl_error(proc, &tok->location, - "invalid filename in #line directive"); - return IDL_PARSE_ERROR; - } - assert(dir && !dir->file); - dir->file = tok->value.str; - /* do not free string on return */ - tok->value.str = NULL; - break; - } - /* fall through */ - case IDL_SCAN_EXTRA_TOKEN: - assert(dir); - if (tok->code == '\n' || tok->code == 0) { - proc->state = IDL_SCAN; - return push_line(proc, dir); - } else if (!dir->extra_tokens) { - idl_warning(proc, &tok->location, - "extra tokens at end of #line directive"); - } - break; - default: - assert(0); - break; - } - return 0; -} - -static int32_t -push_keylist(idl_processor_t *proc, idl_keylist_t *dir) -{ - ddsts_pragma_open(proc->context); - if (!ddsts_pragma_add_identifier(proc->context, dir->data_type)) - return IDL_MEMORY_EXHAUSTED; - ddsrt_free(dir->data_type); - dir->data_type = NULL; - for (char **key = dir->keys; key && *key; key++) { - if (!ddsts_pragma_add_identifier(proc->context, *key)) - return IDL_MEMORY_EXHAUSTED; - ddsrt_free(*key); - *key = NULL; - } - ddsrt_free(dir->keys); - ddsrt_free(dir); - proc->directive = NULL; - switch (ddsts_pragma_close(proc->context)) { - case DDS_RETCODE_OUT_OF_RESOURCES: - return IDL_MEMORY_EXHAUSTED; - case DDS_RETCODE_OK: - break; - default: - return IDL_PARSE_ERROR; - } - return 0; -} - -static int32_t -parse_keylist(idl_processor_t *proc, idl_token_t *tok) -{ - idl_keylist_t *dir = (idl_keylist_t *)proc->directive; - - /* #pragma keylist does not support scoped names */ - - switch (proc->state) { - case IDL_SCAN_KEYLIST: - if (tok->code == '\n' || tok->code == '\0') { - idl_error(proc, &tok->location, - "no data-type in #pragma keylist directive"); - return IDL_PARSE_ERROR; - } else if (tok->code != IDL_TOKEN_IDENTIFIER) { - idl_error(proc, &tok->location, - "invalid data-type in #pragma keylist directive"); - return IDL_PARSE_ERROR; - } - assert(!dir); - if (!(dir = ddsrt_malloc(sizeof(*dir)))) - return IDL_MEMORY_EXHAUSTED; - dir->directive.type = IDL_KEYLIST; - dir->data_type = tok->value.str; - dir->keys = NULL; - proc->directive = (idl_directive_t *)dir; - /* do not free identifier on return */ - tok->value.str = NULL; - proc->state = IDL_SCAN_KEY; - break; - case IDL_SCAN_DATA_TYPE: - case IDL_SCAN_KEY: { - char **keys = dir->keys; - size_t cnt = 0; - - if (tok->code == '\n' || tok->code == '\0') { - proc->state = IDL_SCAN; - return push_keylist(proc, dir); - } else if (tok->code == ',' && keys) { - /* #pragma keylist takes space or comma separated list of keys */ - break; - } else if (tok->code != IDL_TOKEN_IDENTIFIER) { - idl_error(proc, &tok->location, - "invalid key in #pragma keylist directive"); - return IDL_PARSE_ERROR; - } else if (idl_istoken(tok->value.str, 1)) { - idl_error(proc, &tok->location, - "invalid key %s in #pragma keylist directive", tok->value.str); - return IDL_PARSE_ERROR; - } - - for (; keys && *keys; keys++, cnt++) /* count keys */ ; - - if (!(keys = ddsrt_realloc(dir->keys, sizeof(*keys) * (cnt + 2)))) - return IDL_MEMORY_EXHAUSTED; - - keys[cnt++] = tok->value.str; - keys[cnt ] = NULL; - dir->keys = keys; - /* do not free identifier on return */ - tok->value.str = NULL; - } break; - default: - assert(0); - break; - } - return 0; -} - -int32_t idl_parse_directive(idl_processor_t *proc, idl_token_t *tok) -{ - /* order is important here */ - if ((proc->state & IDL_SCAN_LINE) == IDL_SCAN_LINE) { - return parse_line(proc, tok); - } else if ((proc->state & IDL_SCAN_KEYLIST) == IDL_SCAN_KEYLIST) { - return parse_keylist(proc, tok); - } else if (proc->state == IDL_SCAN_PRAGMA) { - /* expect keylist */ - if (tok->code == IDL_TOKEN_IDENTIFIER) { - if (strcmp(tok->value.str, "keylist") == 0) { - proc->state = IDL_SCAN_KEYLIST; - return 0; - } - idl_error(proc, &tok->location, - "unsupported #pragma directive %s", tok->value.str); - return IDL_PARSE_ERROR; - } - } else if (proc->state == IDL_SCAN_DIRECTIVE_NAME) { - if (tok->code == IDL_TOKEN_IDENTIFIER) { - /* expect line or pragma */ - if (strcmp(tok->value.str, "line") == 0) { - proc->state = IDL_SCAN_LINE; - return 0; - } else if (strcmp(tok->value.str, "pragma") == 0) { - /* support #pragma keylist for backwards compatibility */ - proc->state = IDL_SCAN_PRAGMA; - return 0; - } - } else if (tok->code == '\n' || tok->code == '\0') { - proc->state = IDL_SCAN; - return 0; - } - } else if (proc->state == IDL_SCAN_DIRECTIVE) { - /* expect # */ - if (tok->code == '#') { - proc->state = IDL_SCAN_DIRECTIVE_NAME; - return 0; - } - } - - idl_error(proc, &tok->location, "invalid compiler directive"); - return IDL_PARSE_ERROR; -} diff --git a/src/tools/idlc/src/gen_c99.c b/src/tools/idlc/src/gen_c99.c deleted file mode 100644 index dbac2d24ea..0000000000 --- a/src/tools/idlc/src/gen_c99.c +++ /dev/null @@ -1,2046 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -#include -#include -#include -#include -#include "dds/ddsrt/retcode.h" -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/string.h" -#include "dds/ddsrt/time.h" -#include "dds/ddsrt/strtol.h" -#include "dds/ddsrt/misc.h" -#include "dds/ddsrt/log.h" -#include "dds/ddsc/dds_public_impl.h" -#include "dds/ddsts/typetree.h" -#include "dds/ddsts/type_walk.h" -#include "gen_ostream.h" -#include "gen_c99.h" - -/* Some administration used during the traverse process */ - -/* For each sequence of struct in IDL, a separate struct is defined in the C header, - * which uses the struct definition generated for the struct (from IDL). In case - * for this IDL struct no struct has been generated in the C header, a forward - * declaration (with a typedef) needs to be generated. For this reason we need - * to track for which IDL structs a forward definition and/or a struct declaration - * have occured. - */ - -typedef struct struct_def_used struct_def_used_t; -struct struct_def_used { - ddsts_type_t *struct_def; - bool as_forward; - bool as_definition; - struct_def_used_t *next; -}; - -typedef struct { - ddsts_ostream_t *ostream; -} output_context_t; - -typedef struct { - output_context_t output_context; - struct_def_used_t *struct_def_used; -} gen_header_context_t; - -static void gen_header_context_init(gen_header_context_t *gen_header_context, ddsts_ostream_t *ostream) -{ - gen_header_context->output_context.ostream = ostream; - gen_header_context->struct_def_used = NULL; -} - -static void gen_header_context_fini(gen_header_context_t *gen_header_context) -{ - struct_def_used_t *struct_def_used; - for (struct_def_used = gen_header_context->struct_def_used; struct_def_used != NULL;) { - struct_def_used_t *next = struct_def_used->next; - ddsrt_free(struct_def_used); - struct_def_used = next; - } -} - -static struct_def_used_t *find_struct_def_used(gen_header_context_t *gen_header_context, ddsts_type_t *struct_def) -{ - struct_def_used_t *struct_def_used; - for (struct_def_used = gen_header_context->struct_def_used; struct_def_used != NULL; struct_def_used = struct_def_used->next) - if (struct_def_used->struct_def == struct_def) - return struct_def_used; - struct_def_used = (struct_def_used_t*)ddsrt_malloc(sizeof(struct_def_used_t)); - if (struct_def_used == NULL) { - return NULL; - } - struct_def_used->struct_def = struct_def; - struct_def_used->as_forward = false; - struct_def_used->as_definition = false; - struct_def_used->next = gen_header_context->struct_def_used; - gen_header_context->struct_def_used = struct_def_used; - return struct_def_used; -} - -/* Included modules and structs */ - -/* Given a struct, find all modules and structs that need to be included because - * they are used (recursively) - */ - -typedef struct included_type included_type_t; -struct included_type { - ddsts_type_t *type; - included_type_t *next; -}; - -static dds_return_t included_types_add(included_type_t **ref_included_nodes, ddsts_type_t *type) -{ - included_type_t *new_included_node = (included_type_t*)ddsrt_malloc(sizeof(included_type_t)); - if (new_included_node == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - new_included_node->type = type; - new_included_node->next = *ref_included_nodes; - *ref_included_nodes = new_included_node; - return DDS_RETCODE_OK; -} - -static void free_included_types(included_type_t *included_types) -{ - while (included_types != NULL) { - included_type_t *next = included_types->next; - ddsrt_free((void*)included_types); - included_types = next; - } -} - -static bool included_types_contains(included_type_t *included_types, ddsts_type_t *type) -{ - for (; included_types != NULL; included_types = included_types->next) - if (included_types->type == type) - return true; - return false; -} - -static ddsts_type_t *get_struct_def(ddsts_type_t *type) -{ - return DDSTS_IS_TYPE(type, DDSTS_FORWARD_STRUCT) ? type->forward.definition : type; -} - -static dds_return_t find_used_structs(included_type_t **ref_included_nodes, ddsts_type_t *struct_def); - -static dds_return_t find_used_structs_in_type_def(included_type_t **ref_included_nodes, ddsts_type_t *type) -{ - switch (DDSTS_TYPE_OF(type)) { - case DDSTS_SEQUENCE: - return find_used_structs_in_type_def(ref_included_nodes, type->sequence.element_type); - break; - case DDSTS_STRUCT: - case DDSTS_FORWARD_STRUCT: { - ddsts_type_t *struct_def = get_struct_def(type); - if (struct_def != NULL) - return find_used_structs(ref_included_nodes, struct_def); - break; - } - default: - break; - } - return DDS_RETCODE_OK; -} - -static dds_return_t find_used_structs(included_type_t **ref_included_nodes, ddsts_type_t *struct_def) -{ - if (included_types_contains(*ref_included_nodes, struct_def)) - return DDS_RETCODE_OK; - dds_return_t rc = included_types_add(ref_included_nodes, struct_def); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - /* include modules in which this struct occurs */ - ddsts_type_t *type = struct_def; - for (type = type->type.parent; type != NULL && type->type.parent != NULL ; type = type->type.parent) { - if (included_types_contains(*ref_included_nodes, type)) - break; - rc = included_types_add(ref_included_nodes, type); - if (rc != DDS_RETCODE_OK) { - return rc; - } - } - - ddsts_type_t *member; - for (member = struct_def->struct_def.members.first; member != NULL; member = member->type.next) { - if (DDSTS_IS_TYPE(member, DDSTS_DECLARATION)) { - rc = find_used_structs_in_type_def(ref_included_nodes, member->declaration.decl_type); - if (rc != DDS_RETCODE_OK) { - return rc; - } - } - } - - return DDS_RETCODE_OK; -} - -/* Finding specific parent of a type */ - -static ddsts_type_t *ddsts_type_get_parent(ddsts_type_t *type, ddsts_flags_t flags) -{ - while (type != NULL) { - type = type->type.parent; - if (type != NULL && DDSTS_IS_TYPE(type, flags)) { - return type; - } - } - return NULL; -} - -/* Output function with named string arguments */ - -static void output(ddsts_ostream_t *ostream, const char *fmt, ...) -{ - const char *values[26]; - for (int i = 0; i < 26; i++) { - values[i] = ""; - } - - /* Parse variable arguments: pairs of a capital letter and a string */ - va_list args; - va_start(args, fmt); - for (;;) { - char letter = (char)va_arg(args, int); - if (letter < 'A' || letter > 'Z') { - break; - } - values[letter - 'A'] = va_arg(args, const char*); - } - va_end(args); - - const char *s; - for (s = fmt; *s != '\0'; s++) { - if (*s == '$') { - s++; - if (*s == '$') - ddsts_ostream_put(ostream, *s); - else if ('A' <= *s && *s <= 'Z') { - const char *t; - for (t = values[*s - 'A']; *t != '\0'; t++) { - ddsts_ostream_put(ostream, *t); - } - } - } - else { - ddsts_ostream_put(ostream, *s); - } - } -} - - -/* File name functions */ - -static dds_return_t output_file_name(const char *file_name, const char *ext, const char **ref_result) -{ - *ref_result = NULL; - size_t file_name_len = strlen(file_name); - if (file_name_len < 4 || strcmp(file_name + file_name_len - 4, ".idl") != 0) { - DDS_ERROR("Error: File name '%s' does not have '.idl' extension", file_name); - return DDS_RETCODE_ERROR; - } - size_t result_len = file_name_len - 2 + strlen(ext); - char *result = (char*)ddsrt_malloc(sizeof(char)*(result_len)); - if (result == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ddsrt_strlcpy(result, file_name, file_name_len - 2); - ddsrt_strlcat(result, ext, result_len); - *ref_result = result; - return DDS_RETCODE_OK; -} - -static dds_return_t uppercase_file_name(const char *file_name, const char **ref_result) -{ - *ref_result = NULL; - size_t file_name_len = strlen(file_name); - if (file_name_len < 4 || strcmp(file_name + file_name_len - 4, ".idl") != 0) { - DDS_ERROR("Error: File name '%s' does not have '.idl' extension", file_name); - return DDS_RETCODE_ERROR; - } - char *result = (char*)ddsrt_malloc(sizeof(char)*(file_name_len - 3)); - if (result == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - size_t i; - for (i = 0; i < file_name_len - 4; i++) - result[i] = (char)toupper(file_name[i]); - result[i] = '\0'; - *ref_result = result; - return DDS_RETCODE_OK; -} - -/* Generate file header */ - -static void write_file_header(ddsts_ostream_t *ostream, const char *target_file_name, const char *source_file_name) -{ - dds_time_t time_now = dds_time(); - char time_descr[DDSRT_RFC3339STRLEN+1]; - ddsrt_ctime(time_now, time_descr, DDSRT_RFC3339STRLEN); - - output(ostream, - "/****************************************************************\n" - "\n" - " Generated by Eclipse Cyclone DDS IDL to C Translator\n" - " File name: $T\n" - " Source: $S\n" - " Generated: $D\n" - " Eclipse Cyclone DDS: V0.1.0\n" - "\n" - "*****************************************************************/\n" - "\n", - 'T', target_file_name, - 'S', source_file_name, - 'D', time_descr, - '\0'); -} - -/* Generate C99 header file */ - -static dds_return_t write_header_intro(ddsts_ostream_t *ostream, const char *file_name) -{ - const char *uc_file_name = NULL; - dds_return_t rc = uppercase_file_name(file_name, &uc_file_name); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - output(ostream, - "#include \"ddsc/dds_public_impl.h\"\n" - "\n" - "#ifndef _DDSL_$U_H_\n" - "#define _DDSL_$U_H_\n" - "\n" - "\n" - "#ifdef __cplusplus\n" - "extern \"C\" {\n" - "#endif\n" - "\n", - 'U', uc_file_name, - '\0'); - - ddsrt_free((void*)uc_file_name); - - return DDS_RETCODE_OK; -} - -static dds_return_t write_header_close(ddsts_ostream_t *ostream, const char *file_name) -{ - const char *uc_file_name = NULL; - dds_return_t rc = uppercase_file_name(file_name, &uc_file_name); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - output(ostream, - "#ifdef __cplusplus\n" - "}\n" - "#endif\n" - "#endif /* _DDSL_$U_H_ */\n", - 'U', uc_file_name, - '\0'); - - ddsrt_free((void*)uc_file_name); - - return DDS_RETCODE_OK; -} - -static const char *name_with_module_prefix(ddsts_type_t *def_type, const char *infix) -{ - size_t infix_len = strlen(infix); - size_t len = 0; - ddsts_type_t *cur = def_type; - while (cur != NULL) { - len += strlen(cur->type.name); - if ( cur->type.parent != NULL - && DDSTS_IS_TYPE(cur->type.parent, DDSTS_MODULE | DDSTS_STRUCT) - && cur->type.parent->type.parent != NULL) { - cur = cur->type.parent; - len += infix_len; - } - else - cur = NULL; - } - char *result = (char*)ddsrt_malloc(sizeof(char)*(len+1)); - if (result == NULL) { - return NULL; - } - result[len] = '\0'; - for (cur = def_type; cur != NULL;) { - size_t cur_name_len = strlen(cur->type.name); - len -= cur_name_len; - size_t i; - for (i = 0; i < cur_name_len; i++) { - result[len + i] = cur->type.name[i]; - } - if ( cur->type.parent != NULL - && DDSTS_IS_TYPE(cur->type.parent, DDSTS_MODULE | DDSTS_STRUCT) - && cur->type.parent->type.parent != NULL) { - cur = cur->type.parent; - len -= infix_len; - for (i = 0; i < infix_len; i++) { - result[len + i] = infix[i]; - } - } - else { - cur = NULL; - } - } - return result; -} - -/* Functions called from walker for the include file */ - -static dds_return_t write_header_forward_struct(ddsts_call_path_t *path, void *context) -{ - ddsts_type_t *struct_def = NULL; - if (DDSTS_IS_TYPE(path->type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT)) { - struct_def = get_struct_def(path->type); - } - if (struct_def == NULL) { - DDS_ERROR("no struct definition"); - return DDS_RETCODE_ERROR; - } - struct_def_used_t *struct_def_used = find_struct_def_used((gen_header_context_t*)context, struct_def); - if (struct_def_used == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - if (struct_def_used->as_forward || struct_def_used->as_definition) { - return DDS_RETCODE_OK; - } - struct_def_used->as_forward = true; - - const char *full_name = name_with_module_prefix(struct_def, "_"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - - output(((output_context_t*)context)->ostream, - "typedef struct $N $N;\n" - "\n", - 'N', full_name, - '\0'); - - ddsrt_free((void*)full_name); - - return DDS_RETCODE_OK; -} - -static dds_return_t write_header_seq_struct_with_name(ddsts_type_t *type, const char *element_type_name, ddsts_ostream_t *ostream) -{ - const char *base_name = name_with_module_prefix(type, "_"); - if (base_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - - output(ostream, - "typedef struct $B_seq\n" - "{\n" - " uint32_t _maximum;\n" - " uint32_t _length;\n" - " $E *_buffer;\n" - " bool _release;\n" - "} $B_seq;\n" - "\n" - "#define $B_seq__alloc() \\\n" - "(($B_seq*) dds_alloc (sizeof ($B_seq)));\n" - "\n" - "#define $B_seq_allocbuf(l) \\\n" - "(($E *) dds_alloc ((l) * sizeof ($E)))\n" - "\n", - 'B', base_name, - 'E', element_type_name, - '\0'); - - ddsrt_free((void*)base_name); - return DDS_RETCODE_OK; -} - -static dds_return_t write_header_open_struct(ddsts_call_path_t *path, void *context) -{ - assert(DDSTS_IS_TYPE(path->type, DDSTS_STRUCT)); - - struct_def_used_t *struct_def_used = find_struct_def_used((gen_header_context_t*)context, path->type); - if (struct_def_used == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - struct_def_used->as_definition = true; - - const char *full_name = name_with_module_prefix(path->type, "_"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - - output(((output_context_t*)context)->ostream, - "typedef struct $N\n" - "{\n", - 'N', full_name, - '\0'); - - ddsrt_free((void*)full_name); - - return DDS_RETCODE_OK; -} - -static dds_return_t write_header_close_struct(ddsts_call_path_t *path, void *context) -{ - DDSRT_UNUSED_ARG(context); - - assert(DDSTS_IS_TYPE(path->type, DDSTS_STRUCT)); - ddsts_type_t *struct_def = path->type; - - const char *full_name = name_with_module_prefix(struct_def, "_"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - - output(((output_context_t*)context)->ostream, - "} $N;\n" - "\n", - 'N', full_name, - '\0'); - if (struct_def->struct_def.keys != NULL) { - output(((output_context_t*)context)->ostream, - "extern const dds_topic_descriptor_t $N_desc;\n" - "\n" - "#define $N__alloc() \\\n" - "(($N*) dds_alloc (sizeof ($N)));\n" - "\n" - "#define $N_free(d,o) \\\n" - "dds_sample_free ((d), &$N_desc, (o))\n", - 'N', full_name, - '\0'); - } - output(((output_context_t*)context)->ostream, "\n", '\0'); - - ddsrt_free((void*)full_name); - - return DDS_RETCODE_OK; -} - - -static dds_return_t write_header_struct_member(ddsts_call_path_t *path, void *context) -{ - DDSRT_UNUSED_ARG(context); - - ddsts_ostream_puts(((output_context_t*)context)->ostream, " "); - - assert(DDSTS_IS_TYPE(path->type, DDSTS_DECLARATION)); - - const char *decl_name = path->type->type.name; - ddsts_type_t *type = path->type->declaration.decl_type; - while (DDSTS_IS_TYPE(type, DDSTS_ARRAY)) { - type = type->array.element_type; - assert(type != NULL); - } - - switch (DDSTS_TYPE_OF(type)) { - case DDSTS_INT16: output(((output_context_t*)context)->ostream, "int16_t $D", 'D', decl_name, '\0'); break; - case DDSTS_INT32: output(((output_context_t*)context)->ostream, "int32_t $D", 'D', decl_name, '\0'); break; - case DDSTS_INT64: output(((output_context_t*)context)->ostream, "int64_t $D", 'D', decl_name, '\0'); break; - case DDSTS_INT16 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "uint16_t $D", 'D', decl_name, '\0'); break; - case DDSTS_INT32 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "uint32_t $D", 'D', decl_name, '\0'); break; - case DDSTS_INT64 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "uint64_t $D", 'D', decl_name, '\0'); break; - case DDSTS_CHAR: output(((output_context_t*)context)->ostream, "char $D", 'D', decl_name, '\0'); break; - case DDSTS_BOOLEAN: output(((output_context_t*)context)->ostream, "bool $D", 'D', decl_name, '\0'); break; - case DDSTS_OCTET: output(((output_context_t*)context)->ostream, "uint8_t $D", 'D', decl_name, '\0'); break; - case DDSTS_INT8: output(((output_context_t*)context)->ostream, "int8_t $D", 'D', decl_name, '\0'); break; - case DDSTS_INT8 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "uint8_t $D", 'D', decl_name, '\0'); break; - case DDSTS_FLOAT: output(((output_context_t*)context)->ostream, "float $D", 'D', decl_name, '\0'); break; - case DDSTS_DOUBLE: output(((output_context_t*)context)->ostream, "double $D", 'D', decl_name, '\0'); break; - case DDSTS_STRING: { - if (type->string.max > 0) { - char size_string[30]; - ddsrt_ulltostr(type->string.max + 1, size_string, 30, NULL); - output(((output_context_t*)context)->ostream, "char $D[$S]", 'D', decl_name, 'S', size_string, '\0'); - } - else { - output(((output_context_t*)context)->ostream, "char * $D", 'D', decl_name, '\0'); - } - break; - } - case DDSTS_SEQUENCE: { - if (DDSTS_IS_TYPE(type->sequence.element_type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT | DDSTS_SEQUENCE)) { - ddsts_type_t *struct_node = ddsts_type_get_parent(type, DDSTS_STRUCT); - if (struct_node == NULL) { - assert(false); - return DDS_RETCODE_ERROR; - } - const char *full_name = name_with_module_prefix(struct_node, "_"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - output(((output_context_t*)context)->ostream, "$N_$D_seq $D", 'N', full_name, 'D', decl_name, '\0'); - ddsrt_free((void*)full_name); - } - else { - output(((output_context_t*)context)->ostream, "dds_sequence_t $D", 'D', decl_name, '\0'); - } - break; - } - case DDSTS_STRUCT: - case DDSTS_FORWARD_STRUCT: { - ddsts_type_t *struct_def = get_struct_def(type); - if (struct_def != NULL) { - const char *struct_name = name_with_module_prefix(struct_def, "_"); - if (struct_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - output(((output_context_t*)context)->ostream, "$S $D", 'S', struct_name, 'D', decl_name, '\0'); - ddsrt_free((void*)struct_name); - } - break; - } - default: - output(((output_context_t*)context)->ostream, "// type not supported: $D", 'D', decl_name, '\0'); - break; - } - - type = path->type->declaration.decl_type; - while (DDSTS_IS_TYPE(type, DDSTS_ARRAY)) { - char size_string[30]; - ddsrt_ulltostr(type->array.size, size_string, 30, NULL); - output(((output_context_t*)context)->ostream, "[$S]", 'S', size_string, '\0'); - type = type->array.element_type; - assert(type != NULL); - } - - ddsts_ostream_puts(((output_context_t*)context)->ostream, ";\n"); - return DDS_RETCODE_OK; -} - -static dds_return_t write_header_struct(ddsts_call_path_t *path, void *context); - -static dds_return_t write_header_struct_pre(ddsts_call_path_t *path, void *context) -{ - switch (DDSTS_TYPE_OF(path->type)) { - case DDSTS_STRUCT: - return write_header_struct(path, context); - break; - case DDSTS_DECLARATION: { - ddsts_type_t *type = path->type->declaration.decl_type; - while (DDSTS_IS_TYPE(type, DDSTS_ARRAY)) { - type = type->array.element_type; - } - if (DDSTS_IS_TYPE(type, DDSTS_SEQUENCE)) { - ddsts_type_t *element_type = type->sequence.element_type; - if (DDSTS_IS_TYPE(element_type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT)) { - const char *element_type_name = name_with_module_prefix(element_type, "_"); - if (element_type_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ddsts_call_path_t elem_path; - elem_path.call_parent = path; - elem_path.type = element_type; - dds_return_t rc; - rc = write_header_forward_struct(&elem_path, context); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)element_type_name); - return rc; - } - rc = write_header_seq_struct_with_name(path->type, element_type_name, ((output_context_t*)context)->ostream); - ddsrt_free((void*)element_type_name); - return rc; - } - else if (DDSTS_IS_TYPE(element_type, DDSTS_SEQUENCE)) { - return write_header_seq_struct_with_name(path->type, "dds_sequence_t", ((output_context_t*)context)->ostream); - } - } - break; - } - default: - assert(false); - break; - } - return DDS_RETCODE_OK; -} - -static dds_return_t write_header_struct(ddsts_call_path_t *path, void *context) -{ - dds_return_t rc; - rc = ddsts_walk(path, 0, DDSTS_STRUCT | DDSTS_DECLARATION, write_header_struct_pre, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - rc = write_header_open_struct(path, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - rc = ddsts_walk(path, 0, DDSTS_DECLARATION, write_header_struct_member, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - return write_header_close_struct(path, context); -} - -static dds_return_t write_header_modules(ddsts_call_path_t *path, void *context) -{ - switch (DDSTS_TYPE_OF(path->type)) { - case DDSTS_STRUCT: - return write_header_struct(path, context); - break; - case DDSTS_FORWARD_STRUCT: - return write_header_forward_struct(path, context); - break; - default: - break; - } - assert(false); - return DDS_RETCODE_ERROR; -} - -static dds_return_t generate_header_file(const char *file_name, ddsts_type_t *root_node, ddsts_ostream_t *ostream) -{ - DDSRT_UNUSED_ARG(root_node); - const char *h_file_name = NULL; - dds_return_t rc; - rc = output_file_name(file_name, "h", &h_file_name); - if (rc != DDS_RETCODE_OK) { - return rc; - } - if (!ddsts_ostream_open(ostream, h_file_name)) { - DDS_ERROR("Could not open file '%s' for writing", h_file_name); - ddsrt_free((void*)h_file_name); - return DDS_RETCODE_OUT_OF_RESOURCES; - } - - write_file_header(ostream, h_file_name, file_name); - rc = write_header_intro(ostream, file_name); - if (rc != DDS_RETCODE_OK) { - ddsts_ostream_close(ostream); - ddsrt_free((void*)h_file_name); - return rc; - } - - gen_header_context_t context; - gen_header_context_init(&context, ostream); - - ddsts_call_path_t path; - path.call_parent = NULL; - path.type = root_node; - - rc = ddsts_walk(&path, DDSTS_MODULE, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT, write_header_modules, &context.output_context); - if (rc != DDS_RETCODE_OK) { - ddsts_ostream_close(ostream); - ddsrt_free((void*)h_file_name); - return rc; - } - - rc = write_header_close(ostream, file_name); - if (rc != DDS_RETCODE_OK) { - ddsts_ostream_close(ostream); - ddsrt_free((void*)h_file_name); - return rc; - } - - gen_header_context_fini(&context); - - ddsts_ostream_close(ostream); - ddsrt_free((void*)h_file_name); - - return DDS_RETCODE_OK; -} - -/* Generate source file */ - -/* Context for storing sizes and positions for op codes */ - -typedef struct type_dim type_dim_t; -struct type_dim { - ddsts_type_t *type; - bool generated; - uint32_t start; - uint32_t size; - type_dim_t *next; -}; - -typedef struct key_offset key_offset_t; -struct key_offset { - ddsts_type_t *decl; - uint32_t offset; - key_offset_t *next; -}; - -typedef struct { - output_context_t output_context; - type_dim_t *struct_dims; - key_offset_t *key_offsets; - uint32_t cur_offset; - uint32_t nr_ops; - uint32_t nr_keys; - uint32_t bounded_key_size; - uint32_t key_size; -} op_codes_context_t; - -static void op_codes_context_init(op_codes_context_t *op_codes_context, ddsts_ostream_t *ostream) -{ - op_codes_context->output_context.ostream = ostream; - op_codes_context->struct_dims = NULL; - op_codes_context->key_offsets = NULL; - op_codes_context->cur_offset = 0U; - op_codes_context->nr_ops = 0U; - op_codes_context->nr_keys = 0U; - op_codes_context->bounded_key_size = true; - op_codes_context->key_size = 0U; -} - -static void op_codes_context_reset(op_codes_context_t *op_codes_context, ddsts_ostream_t *ostream) -{ - op_codes_context->output_context.ostream = ostream; - for (type_dim_t *type_dim = op_codes_context->struct_dims; type_dim != NULL; type_dim = type_dim->next) { - type_dim->generated = false; - } - op_codes_context->cur_offset = 0U; - op_codes_context->nr_ops = 0U; -} - -static void op_codes_context_fini(op_codes_context_t *context) -{ - for (type_dim_t *type_dim = context->struct_dims; type_dim != NULL;) { - type_dim_t *next = type_dim->next; - ddsrt_free((void*)type_dim); - type_dim = next; - } - for (key_offset_t *key_offset = context->key_offsets; key_offset != NULL;) { - key_offset_t *next =key_offset->next; - ddsrt_free((void*)key_offset); - key_offset = next; - } -} - -static type_dim_t *op_codes_context_find(op_codes_context_t *context, ddsts_type_t *type) -{ - type_dim_t **ref_type_dim = &context->struct_dims; - for (; *ref_type_dim != NULL; ref_type_dim = &(*ref_type_dim)->next) { - if ((*ref_type_dim)->type == type) { - return (*ref_type_dim); - } - } - (*ref_type_dim) = (type_dim_t*)ddsrt_malloc(sizeof(type_dim_t)); - if ((*ref_type_dim) == NULL) { - return NULL; - } - (*ref_type_dim)->type = type; - (*ref_type_dim)->generated = false; - (*ref_type_dim)->start = 0U; - (*ref_type_dim)->size = 0U; - (*ref_type_dim)->next = NULL; - return (*ref_type_dim); -} - -static key_offset_t *op_codes_context_find_key(op_codes_context_t *context, ddsts_type_t *decl) -{ - key_offset_t **ref_key_offset = &context->key_offsets; - for (; *ref_key_offset != NULL; ref_key_offset = &(*ref_key_offset)->next) { - if ((*ref_key_offset)->decl == decl) { - return (*ref_key_offset); - } - } - (*ref_key_offset) = (key_offset_t*)ddsrt_malloc(sizeof(key_offset_t)); - if ((*ref_key_offset) == NULL) { - return NULL; - } - (*ref_key_offset)->decl = decl; - (*ref_key_offset)->offset = 0U; - (*ref_key_offset)->next = NULL; - return (*ref_key_offset); -} - -/* Generate operation codes */ - -static dds_return_t generate_op_codes_field_name(ddsts_call_path_t *path, bool top, ddsts_ostream_t *ostream) -{ - if ( DDSTS_IS_TYPE(path->type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT) - && !DDSTS_IS_TYPE(path->call_parent->type, DDSTS_DECLARATION)) { - const char *full_name = name_with_module_prefix(path->type, "_"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ddsts_ostream_puts(ostream, full_name); - ddsts_ostream_puts(ostream, ", "); - ddsrt_free((void*)full_name); - } - else { - if (DDSTS_IS_TYPE(path->type, DDSTS_DECLARATION)) { - dds_return_t rc = generate_op_codes_field_name(path->call_parent, false, ostream); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(ostream, path->type->type.name); - if (!top) { - ddsts_ostream_put(ostream, '.'); - } - } - else { - return generate_op_codes_field_name(path->call_parent, top, ostream); - } - } - return DDS_RETCODE_OK; -} - -static dds_return_t generate_op_codes_offsetof(ddsts_call_path_t *declaration, void *context) -{ - ddsts_ostream_t *ostream = ((op_codes_context_t*)context)->output_context.ostream; - - if (declaration == 0 || !DDSTS_IS_TYPE(declaration->type, DDSTS_DECLARATION)) { - ddsts_ostream_puts(ostream, " 0u,"); - } - else { - ddsts_ostream_puts(ostream, " offsetof ("); - dds_return_t rc = generate_op_codes_field_name(declaration, true, ostream); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(ostream, "),"); - } - ((op_codes_context_t*)context)->cur_offset += 1U; - return DDS_RETCODE_OK; -} - -static void generate_op_codes_array_size(unsigned long long array_size, void *context) -{ - char array_size_string[30]; - ddsrt_ulltostr(array_size & 0xffffffff, array_size_string, 30, NULL); - output(((op_codes_context_t*)context)->output_context.ostream, " $N,", 'N', array_size_string, '\0'); - ((op_codes_context_t*)context)->cur_offset += 1U; -} - -static dds_return_t generate_op_codes_simple_type(ddsts_call_path_t *declaration, uint32_t dds_op_type, unsigned long long array_size, void *context) -{ - ddsts_ostream_t *ostream = ((op_codes_context_t*)context)->output_context.ostream; - ddsts_ostream_puts(ostream, " DDS_OP_ADR"); - - if (array_size > 0ULL) { - ddsts_ostream_puts(ostream, " | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_"); - } - else { - ddsts_ostream_puts(ostream, " | DDS_OP_TYPE_"); - } - switch (dds_op_type) { - case DDS_OP_TYPE_1BY: ddsts_ostream_puts(ostream, "1BY"); break; - case DDS_OP_TYPE_2BY: ddsts_ostream_puts(ostream, "2BY"); break; - case DDS_OP_TYPE_4BY: ddsts_ostream_puts(ostream, "4BY"); break; - case DDS_OP_TYPE_8BY: ddsts_ostream_puts(ostream, "8BY"); break; - case DDS_OP_TYPE_STR: ddsts_ostream_puts(ostream, "STR"); break; - default: - assert(false); - return DDS_RETCODE_ERROR; - break; - } - bool declaration_is_key = false; - dds_return_t rc; - (void)ddsts_declaration_is_key(declaration, &declaration_is_key); - - if (declaration_is_key) { - ddsts_ostream_puts(ostream, " | DDS_OP_FLAG_KEY"); - key_offset_t *key_offset = op_codes_context_find_key((op_codes_context_t*)context, declaration->type); - if (key_offset == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - key_offset->offset = ((op_codes_context_t*)context)->cur_offset; - } - ddsts_ostream_puts(ostream, ","); - ((op_codes_context_t*)context)->cur_offset += 1U; - ((op_codes_context_t*)context)->nr_ops += 1U; - - rc = generate_op_codes_offsetof(declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - if (array_size > 0ULL) { - generate_op_codes_array_size(array_size, context); - } - - ddsts_ostream_puts(ostream, "\n"); - - return DDS_RETCODE_OK; -} - -static dds_return_t generate_op_codes_sequence(ddsts_call_path_t *declaration, uint32_t dds_op_type, void *context) -{ - ddsts_ostream_t *ostream = ((op_codes_context_t*)context)->output_context.ostream; - ddsts_ostream_puts(ostream, " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_"); - - switch (dds_op_type) { - case DDS_OP_TYPE_1BY: ddsts_ostream_puts(ostream, "1BY"); break; - case DDS_OP_TYPE_2BY: ddsts_ostream_puts(ostream, "2BY"); break; - case DDS_OP_TYPE_4BY: ddsts_ostream_puts(ostream, "4BY"); break; - case DDS_OP_TYPE_8BY: ddsts_ostream_puts(ostream, "8BY"); break; - case DDS_OP_TYPE_STR: ddsts_ostream_puts(ostream, "STR"); break; - case DDS_OP_TYPE_SEQ: ddsts_ostream_puts(ostream, "SEQ"); break; - case DDS_OP_TYPE_STU: ddsts_ostream_puts(ostream, "STU"); break; - default: - assert(false); - return DDS_RETCODE_ERROR; - break; - } - ddsts_ostream_puts(ostream, ","); - ((op_codes_context_t*)context)->cur_offset += 1U; - ((op_codes_context_t*)context)->nr_ops += 1U; - - dds_return_t rc = generate_op_codes_offsetof(declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(ostream, "\n"); - return DDS_RETCODE_OK; -} - -static dds_return_t generate_op_codes_sequence_struct(ddsts_call_path_t *declaration, uint32_t dds_op_type, const char* struct_name, uint32_t op_code_size, void *context) -{ - dds_return_t rc; - rc = generate_op_codes_sequence(declaration, dds_op_type, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - char size_string[30]; - ddsrt_ulltostr(op_code_size + 4, size_string, 30, NULL); - output(((op_codes_context_t*)context)->output_context.ostream, - " sizeof ($T), ($Su << 16u) + 4u,\n", - 'T', struct_name, - 'S', size_string, '\0'); - ((op_codes_context_t*)context)->cur_offset += 2U; - return DDS_RETCODE_OK; -} - -static dds_return_t generate_op_codes_struct(ddsts_call_path_t *path, void *context); - -static void generate_op_codes_generated_struct(type_dim_t *type_dim, void *context) -{ - char jump_string[30]; - ddsrt_ulltostr((unsigned long long)(((op_codes_context_t*)context)->cur_offset - type_dim->start), jump_string, 30, NULL); - output(((op_codes_context_t*)context)->output_context.ostream, - " DDS_OP_JSR, (uint32_t)-$J,\n" - " DDS_OP_RTS,\n", - 'J', jump_string, - '\0'); - ((op_codes_context_t*)context)->cur_offset += 3U; - ((op_codes_context_t*)context)->nr_ops += 2U; -} - -static dds_return_t generate_op_codes_seq_element(ddsts_call_path_t *path, ddsts_call_path_t *declaration, void *context) -{ - ddsts_ostream_t *ostream = ((op_codes_context_t*)context)->output_context.ostream; - ddsts_type_t *type = path->type; - - switch (DDSTS_TYPE_OF_IGNORE_SIGN(type)) { - case DDSTS_INT16: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_2BY, context); break; - case DDSTS_INT32: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_4BY, context); break; - case DDSTS_INT64: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_8BY, context); break; - case DDSTS_CHAR: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_1BY, context); break; - case DDSTS_BOOLEAN: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_1BY, context); break; - case DDSTS_OCTET: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_1BY, context); break; - case DDSTS_INT8: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_1BY, context); break; - case DDSTS_FLOAT: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_4BY, context); break; - case DDSTS_DOUBLE: return generate_op_codes_sequence(declaration, DDS_OP_TYPE_8BY, context); break; - case DDSTS_STRING: { - if (type->string.max > 0) { - ddsts_ostream_puts(ostream, " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_BST,"); - ((op_codes_context_t*)context)->cur_offset += 1U; - ((op_codes_context_t*)context)->nr_ops += 1U; - dds_return_t rc = generate_op_codes_offsetof(declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - char size_string[30]; - ddsrt_ulltostr(type->string.max + 1, size_string, 30, NULL); - output(ostream, "\n $S,\n", 'S', size_string, '\0'); - ((op_codes_context_t*)context)->cur_offset += 1U; - } - else { - return generate_op_codes_sequence(declaration, DDS_OP_TYPE_STR, context); - } - break; - } - case DDSTS_ARRAY: { - assert(false); - return DDS_RETCODE_ERROR; - break; - } - case DDSTS_SEQUENCE: { - type_dim_t *type_dim = op_codes_context_find((op_codes_context_t*)context, type); - if (type_dim == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - dds_return_t rc; - rc = generate_op_codes_sequence_struct(declaration, DDS_OP_TYPE_SEQ, "dds_sequence_t", type_dim->size, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - uint32_t offset = ((op_codes_context_t*)context)->cur_offset; - ddsts_call_path_t type_spec_path; - type_spec_path.type = type->sequence.element_type; - type_spec_path.call_parent = path; - rc = generate_op_codes_seq_element(&type_spec_path, NULL, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(ostream, " DDS_OP_RTS,\n"); - ((op_codes_context_t*)context)->cur_offset += 1U; - ((op_codes_context_t*)context)->nr_ops += 1U; - type_dim->size = ((op_codes_context_t*)context)->cur_offset - offset; - break; - } - case DDSTS_STRUCT: - case DDSTS_FORWARD_STRUCT: { - ddsts_type_t *struct_def = get_struct_def(type); - if (struct_def == NULL) { - DDS_ERROR("forward definition '%s' has no definition", path->type->type.name); - return DDS_RETCODE_ERROR; - } - const char *struct_full_name = name_with_module_prefix(struct_def, "_"); - if (struct_full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - type_dim_t *type_dim = op_codes_context_find((op_codes_context_t*)context, struct_def); - if (type_dim == NULL) { - ddsrt_free((void*)struct_full_name); - return DDS_RETCODE_OUT_OF_RESOURCES; - } - if (type_dim->generated) { - dds_return_t rc = generate_op_codes_sequence_struct(declaration, DDS_OP_TYPE_STU, struct_full_name, 3, context); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)struct_full_name); - return rc; - } - generate_op_codes_generated_struct(type_dim, context); - } - else { - dds_return_t rc; - rc = generate_op_codes_sequence_struct(declaration, DDS_OP_TYPE_STU, struct_full_name, type_dim->size, context); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)struct_full_name); - return rc; - } - ddsts_call_path_t struct_path; - struct_path.type = struct_def; - struct_path.call_parent = path; - rc = generate_op_codes_struct(&struct_path, context); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)struct_full_name); - return rc; - } - ddsts_ostream_puts(((op_codes_context_t*)context)->output_context.ostream, ",\n"); - } - ddsrt_free((void*)struct_full_name); - break; - } - default: - assert(false); - return DDS_RETCODE_ERROR; - break; - } - return DDS_RETCODE_OK; -} - -static dds_return_t generate_op_codes_array_struct(ddsts_call_path_t *declaration, uint32_t dds_op_type, unsigned long long array_size, uint32_t op_code_size, void *context) -{ - ddsts_ostream_t *ostream = ((op_codes_context_t*)context)->output_context.ostream; - ddsts_ostream_puts(ostream, " DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_"); - switch (dds_op_type) { - case DDS_OP_TYPE_SEQ: ddsts_ostream_puts(ostream, "SEQ"); break; - case DDS_OP_TYPE_STU: ddsts_ostream_puts(ostream, "STU"); break; - default: - assert(false); - return DDS_RETCODE_ERROR; - break; - } - ddsts_ostream_puts(ostream, ","); - ((op_codes_context_t*)context)->cur_offset += 1U; - ((op_codes_context_t*)context)->nr_ops += 1U; - dds_return_t rc; - rc = generate_op_codes_offsetof(declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - generate_op_codes_array_size(array_size, context); - ddsts_ostream_puts(ostream, "\n"); - char size_string[30]; - ddsrt_ulltostr(op_code_size + 5, size_string, 30, NULL); - output(ostream, " ($Su << 16u) + 5u,", 'S', size_string, '\0'); - ((op_codes_context_t*)context)->cur_offset += 1U; - return DDS_RETCODE_OK; -} - -static dds_return_t generate_op_codes_declaration(ddsts_call_path_t *path, void *context) -{ - op_codes_context_t *op_codes_context = (op_codes_context_t*)context; - ddsts_ostream_t *ostream = op_codes_context->output_context.ostream; - - assert(DDSTS_IS_TYPE(path->type, DDSTS_DECLARATION)); - - ddsts_call_path_t *declaration = path; - - ddsts_type_t *type = path->type->declaration.decl_type; - - if (DDSTS_IS_TYPE(type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT)) { - ddsts_type_t *struct_def = get_struct_def(type); - if (struct_def == NULL) { - return DDS_RETCODE_ERROR; - } - /* embedded struct */ - ddsts_call_path_t struct_path; - struct_path.type = struct_def; - struct_path.call_parent = path; - dds_return_t rc = ddsts_walk(&struct_path, 0, DDSTS_DECLARATION, generate_op_codes_declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - } - else { - /* Check if we have a (simple) array type. If so, array_size will be multiplied size. If not, array_size is zero. */ - unsigned long long array_size = 0ULL; - if (DDSTS_IS_TYPE(type, DDSTS_ARRAY)) { - ddsts_type_t *element_type = type; - array_size = 1ULL; - while (DDSTS_IS_TYPE(element_type, DDSTS_ARRAY)) { - array_size *= element_type->array.size; - element_type = element_type->array.element_type; - } - if (DDSTS_IS_TYPE(element_type, - DDSTS_INT16 | DDSTS_INT32 | DDSTS_INT64 | - DDSTS_CHAR | DDSTS_BOOLEAN | DDSTS_OCTET | DDSTS_INT8 | - DDSTS_FLOAT | DDSTS_DOUBLE | DDSTS_SEQUENCE | DDSTS_STRING | - DDSTS_STRUCT | DDSTS_FORWARD_STRUCT)) { - type = element_type; - } - else { - /* This cannot be handled as simple array */ - array_size = 0ULL; - } - } - switch (DDSTS_TYPE_OF_IGNORE_SIGN(type)) { - case DDSTS_INT16: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_2BY, array_size, context); break; - case DDSTS_INT32: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_4BY, array_size, context); break; - case DDSTS_INT64: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_8BY, array_size, context); break; - case DDSTS_CHAR: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_1BY, array_size, context); break; - case DDSTS_BOOLEAN: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_1BY, array_size, context); break; - case DDSTS_OCTET: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_1BY, array_size, context); break; - case DDSTS_INT8: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_1BY, array_size, context); break; - case DDSTS_FLOAT: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_4BY, array_size, context); break; - case DDSTS_DOUBLE: return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_8BY, array_size, context); break; - case DDSTS_STRING: - if (type->string.max > 0ULL) { - if (array_size == 0ULL) { - ddsts_ostream_puts(ostream, " DDS_OP_ADR | DDS_OP_TYPE_BST,"); - } - else { - ddsts_ostream_puts(ostream, " DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_BST,"); - } - op_codes_context->cur_offset += 1U; - op_codes_context->nr_ops += 1U; - dds_return_t rc = generate_op_codes_offsetof(declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - if (array_size > 0ULL) { - generate_op_codes_array_size(array_size, context); - ddsts_ostream_puts(ostream, "\n 0,"); - op_codes_context->cur_offset += 1U; - } - char size_string[30]; - ddsrt_ulltostr(type->string.max + 1, size_string, 30, NULL); - output(ostream, " $S,\n", 'S', size_string, '\0'); - op_codes_context->cur_offset += 1U; - } - else { - return generate_op_codes_simple_type(declaration, DDS_OP_TYPE_STR, array_size, context); - } - break; - case DDSTS_SEQUENCE: { - if (array_size == 0ULL) { - ddsts_call_path_t type_spec_path; - type_spec_path.type = type->sequence.element_type; - type_spec_path.call_parent = path; - return generate_op_codes_seq_element(&type_spec_path, declaration, context); - } - else { - type_dim_t *type_dim = op_codes_context_find((op_codes_context_t*)context, type); - if (type_dim == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - dds_return_t rc; - rc = generate_op_codes_array_struct(declaration, DDS_OP_TYPE_SEQ, array_size, type_dim->size, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - declaration = NULL; - if (DDSTS_IS_TYPE(type->sequence.element_type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT | DDSTS_SEQUENCE)) { - ddsts_type_t *struct_node = ddsts_type_get_parent(path->type, DDSTS_STRUCT); - if (struct_node == NULL) { - assert(false); - return DDS_RETCODE_ERROR; - } - const char *full_name = name_with_module_prefix(struct_node, "_"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - output(ostream, " sizeof ($N_$D_seq),\n", 'N', full_name, 'D', path->type->type.name, '\0'); - ((op_codes_context_t*)context)->cur_offset += 1U; - ddsrt_free((void*)full_name); - } - else { - output(ostream, " sizeof (dds_sequence_t),\n", '\0'); - ((op_codes_context_t*)context)->cur_offset += 1U; - } - uint32_t offset = ((op_codes_context_t*)context)->cur_offset; - - ddsts_call_path_t type_spec_path; - type_spec_path.type = type->sequence.element_type; - type_spec_path.call_parent = path; - rc = generate_op_codes_seq_element(&type_spec_path, declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(ostream, " DDS_OP_RTS,\n"); - op_codes_context->cur_offset += 1U; - op_codes_context->nr_ops += 1U; - type_dim->size = ((op_codes_context_t*)context)->cur_offset - offset; - } - break; - } - case DDSTS_STRUCT: - case DDSTS_FORWARD_STRUCT: { - ddsts_type_t *struct_def = get_struct_def(type); - if (struct_def == NULL) { - return DDS_RETCODE_ERROR; - } - assert(array_size > 0ULL); - type_dim_t *type_dim = op_codes_context_find((op_codes_context_t*)context, struct_def); - if (type_dim == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - const char *struct_full_name = name_with_module_prefix(struct_def, "_"); - if (struct_full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - if (type_dim->generated) { - dds_return_t rc = generate_op_codes_array_struct(declaration, DDS_OP_TYPE_STU, array_size, 3, context); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)struct_full_name); - return rc; - } - output(((op_codes_context_t*)context)->output_context.ostream, " sizeof ($T),\n", 'T', struct_full_name, '\0'); - ((op_codes_context_t*)context)->cur_offset += 1U; - generate_op_codes_generated_struct(type_dim, context); - } - else { - dds_return_t rc; - rc = generate_op_codes_array_struct(declaration, DDS_OP_TYPE_STU, array_size, type_dim->size, context); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)struct_full_name); - return rc; - } - output(((op_codes_context_t*)context)->output_context.ostream, " sizeof ($T),\n", 'T', struct_full_name, '\0'); - ((op_codes_context_t*)context)->cur_offset += 1U; - ddsts_call_path_t array_path; - array_path.type = path->type->declaration.decl_type; - array_path.call_parent = path; - ddsts_call_path_t struct_path; - struct_path.type = struct_def; - struct_path.call_parent = &array_path; - rc = generate_op_codes_struct(&struct_path, context); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)struct_full_name); - return rc; - } - ddsts_ostream_puts(((op_codes_context_t*)context)->output_context.ostream, ",\n"); - } - ddsrt_free((void*)struct_full_name); - break; - } - default: - /* Type not supported. No op codes are generated */ - break; - } - } - return DDS_RETCODE_OK; -} - -static dds_return_t generate_op_codes_struct(ddsts_call_path_t *path, void *context) -{ - op_codes_context_t *op_codes_context = (op_codes_context_t*)context; - - assert(DDSTS_IS_TYPE(path->type, DDSTS_STRUCT)); - - ddsts_type_t *struct_def = path->type; - type_dim_t *type_dim = op_codes_context_find(op_codes_context, struct_def); - if (type_dim == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - assert(!type_dim->generated); - type_dim->generated = true; - type_dim->start = op_codes_context->cur_offset; - - dds_return_t rc = ddsts_walk(path, 0, DDSTS_DECLARATION, generate_op_codes_declaration, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - ddsts_ostream_puts(op_codes_context->output_context.ostream, " DDS_OP_RTS"); - op_codes_context->cur_offset += 1U; - op_codes_context->nr_ops += 1U; - - type_dim->size = (uint32_t)(op_codes_context->cur_offset - type_dim->start); - - return DDS_RETCODE_OK; -} - -/* Functions for generating meta data */ - -typedef struct { - output_context_t output_context; - included_type_t *included_types; -} meta_data_context_t; - -static void meta_data_context_init(meta_data_context_t *context, ddsts_ostream_t *ostream, included_type_t *included_types) -{ - context->output_context.ostream = ostream; - context->included_types = included_types; -} - -static dds_return_t write_meta_data_elem(ddsts_call_path_t *path, void *context); - -static dds_return_t write_meta_data_type_spec(ddsts_call_path_t *path, void *context) -{ - ddsts_type_t *type = path->type; - switch (DDSTS_TYPE_OF(type)) { - case DDSTS_INT16: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_INT32: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_INT64: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_INT16 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_INT32 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_INT64 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_CHAR: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_BOOLEAN: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_OCTET: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_INT8: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_INT8 | DDSTS_UNSIGNED: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_FLOAT: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_DOUBLE: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_LONGDOUBLE: output(((output_context_t*)context)->ostream, "", '\0'); break; - case DDSTS_STRING: { - if (type->string.max > 0ULL) { - char size_string[30]; - ddsrt_ulltostr(type->string.max, size_string, 30, NULL); - output(((output_context_t*)context)->ostream, "", 'S', size_string, '\0'); - } - else { - output(((output_context_t*)context)->ostream, "", '\0'); - } - break; - } - case DDSTS_ARRAY: { - char size_string[30]; - ddsrt_ulltostr(type->array.size, size_string, 30, NULL); - output(((output_context_t*)context)->ostream, "", 'S', size_string, '\0'); - ddsts_call_path_t element_path; - element_path.type = path->type->array.element_type; - element_path.call_parent = path; - dds_return_t rc = write_meta_data_type_spec(&element_path, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(((output_context_t*)context)->ostream, ""); - break; - } - case DDSTS_SEQUENCE: { - if (type->sequence.max > 0ULL) { - char size_string[30]; - ddsrt_ulltostr(type->sequence.max, size_string, 30, NULL); - output(((output_context_t*)context)->ostream, "", 'S', size_string, '\0'); - } - else { - ddsts_ostream_puts(((output_context_t*)context)->ostream, ""); - } - ddsts_call_path_t element_path; - element_path.type = path->type->sequence.element_type; - element_path.call_parent = path; - dds_return_t rc = write_meta_data_type_spec(&element_path, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(((output_context_t*)context)->ostream, ""); - break; - } - case DDSTS_STRUCT: - case DDSTS_FORWARD_STRUCT: - if (DDSTS_IS_TYPE(type, DDSTS_STRUCT) && type->type.parent != NULL && DDSTS_IS_TYPE(type->type.parent, DDSTS_STRUCT)) { - /* embedded struct */ - write_meta_data_elem(path, context); - } - else { - ddsts_type_t *struct_def = get_struct_def(type); - if (struct_def != NULL) { - bool in_context = false; - for (ddsts_call_path_t *parent = path->call_parent; parent != NULL; parent = parent->call_parent) { - if (parent->type == struct_def->type.parent) { - in_context = true; - break; - } - } - if (in_context) { - output(((output_context_t*)context)->ostream, "", 'N', type->type.name, '\0'); - } - else { - const char *full_name = name_with_module_prefix(struct_def, "::"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - output(((output_context_t*)context)->ostream, "", 'N', full_name, '\0'); - ddsrt_free((void*)full_name); - } - } - } - break; - default: - //assert(false); - break; - } - return DDS_RETCODE_OK; -} - -static dds_return_t write_meta_data_elem(ddsts_call_path_t *path, void *context) -{ - switch (DDSTS_TYPE_OF(path->type)) { - case DDSTS_MODULE: - if (included_types_contains(((meta_data_context_t*)context)->included_types, path->type)) { - output(((output_context_t*)context)->ostream, "", 'N', path->type->type.name, '\0'); - dds_return_t rc = ddsts_walk(path, 0, DDSTS_MODULE | DDSTS_STRUCT, write_meta_data_elem, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(((output_context_t*)context)->ostream, ""); - } - break; - case DDSTS_STRUCT: - if (included_types_contains(((meta_data_context_t*)context)->included_types, path->type)) { - output(((output_context_t*)context)->ostream, "", 'N', path->type->type.name, '\0'); - dds_return_t rc = ddsts_walk(path, 0, DDSTS_DECLARATION, write_meta_data_elem, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(((output_context_t*)context)->ostream, ""); - } - break; - case DDSTS_DECLARATION: { - output(((output_context_t*)context)->ostream, "", 'N', path->type->type.name, '\0'); - ddsts_call_path_t type_spec_path; - type_spec_path.type = path->type->declaration.decl_type; - type_spec_path.call_parent = path; - dds_return_t rc = write_meta_data_type_spec(&type_spec_path, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - ddsts_ostream_puts(((output_context_t*)context)->ostream, ""); - break; - } - default: - assert(false); - return DDS_RETCODE_ERROR; - break; - } - return DDS_RETCODE_OK; -} - -static dds_return_t write_meta_data(ddsts_ostream_t *ostream, ddsts_type_t *struct_def) -{ - /* Determine which structs should be include */ - included_type_t *included_types = NULL; - dds_return_t rc = find_used_structs(&included_types, struct_def); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - ddsts_type_t *root_type = struct_def; - while (root_type->type.parent != NULL) - root_type = root_type->type.parent; - - output(ostream, "", '\0'); - - ddsts_call_path_t path; - path.type = root_type; - path.call_parent = NULL; - - meta_data_context_t context; - meta_data_context_init(&context, ostream, included_types); - rc = ddsts_walk(&path, 0, DDSTS_MODULE | DDSTS_STRUCT, write_meta_data_elem, &context.output_context); - if (rc != DDS_RETCODE_OK) { - free_included_types(included_types); - return rc; - } - - output(ostream, "", '\0'); - - free_included_types(included_types); - - return DDS_RETCODE_OK; -} - -/* Functions for generating the source file */ - -typedef struct { - int value; - int ordering; - const char *rendering; -} alignment_t; - -alignment_t alignment_types[8] = { -#define ALIGNMENT_ONE (&alignment_types[0]) - { 1, 0, "1u"}, -#define ALIGNMENT_BOOL (&alignment_types[1]) - { 0, 0, "sizeof(bool)"}, -#define ALIGNMENT_ONE_OR_BOOL (&alignment_types[2]) - { 0, 1, "(sizeof(bool)>1u)?sizeof(bool):1u"}, -#define ALIGNMENT_TWO (&alignment_types[3]) - { 2, 2, "2u"}, -#define ALIGNMENT_TWO_OR_BOOL (&alignment_types[4]) - { 0, 3, "(sizeof(bool)>2u)?sizeof(bool):2u"}, -#define ALIGNMENT_FOUR (&alignment_types[5]) - { 4, 4, "4u"}, -#define ALIGNMENT_PTR (&alignment_types[6]) - { 0, 6, "sizeof (char *)"}, -#define ALIGNMENT_EIGHT (&alignment_types[7]) - { 8, 8, "8u"} -}; - -static alignment_t *max_alignment(alignment_t *a, alignment_t *b) -{ - if ( (a == ALIGNMENT_BOOL && b == ALIGNMENT_ONE) - || (b == ALIGNMENT_BOOL && a == ALIGNMENT_ONE)) { - return ALIGNMENT_ONE_OR_BOOL; - } - if ( (a == ALIGNMENT_BOOL && b == ALIGNMENT_TWO) - || (b == ALIGNMENT_BOOL && a == ALIGNMENT_TWO)) { - return ALIGNMENT_TWO_OR_BOOL; - } - return a->ordering > b->ordering ? a : b; -} - -static alignment_t *ddsts_type_alignment(ddsts_type_t *type) -{ - switch (DDSTS_TYPE_OF_IGNORE_SIGN(type)) { - case DDSTS_CHAR: return ALIGNMENT_ONE; break; - case DDSTS_OCTET: return ALIGNMENT_ONE; break; - case DDSTS_INT8: return ALIGNMENT_ONE; break; - case DDSTS_BOOLEAN: return ALIGNMENT_BOOL; break; - case DDSTS_INT16: return ALIGNMENT_TWO; break; - case DDSTS_INT32: return ALIGNMENT_FOUR; break; - case DDSTS_FLOAT: return ALIGNMENT_FOUR; break; - case DDSTS_INT64: return ALIGNMENT_EIGHT; break; - case DDSTS_DOUBLE: return ALIGNMENT_EIGHT; break; - case DDSTS_SEQUENCE: return ALIGNMENT_PTR; break; - case DDSTS_MAP: return ALIGNMENT_PTR; break; - case DDSTS_STRING: - return DDSTS_IS_UNBOUND(type) ? ALIGNMENT_PTR : ALIGNMENT_ONE; - break; - case DDSTS_ARRAY: - return ddsts_type_alignment(type->array.element_type); - break; - case DDSTS_STRUCT: { - alignment_t *alignment = ALIGNMENT_ONE; - for (ddsts_type_t *member = type->struct_def.members.first; member != NULL; member = member->type.next) { - if (DDSTS_IS_TYPE(member, DDSTS_DECLARATION)) { - alignment = max_alignment(alignment, ddsts_type_alignment(member->declaration.decl_type)); - } - } - return alignment; - break; - } - case DDSTS_FORWARD_STRUCT: - if (type->forward.definition != NULL) { - return ddsts_type_alignment(type->forward.definition); - } - break; - case DDSTS_CHAR | DDSTS_WIDE: - case DDSTS_LONGDOUBLE: - case DDSTS_FIXED_PT_CONST: - case DDSTS_ANY: - case DDSTS_STRING | DDSTS_WIDE: - case DDSTS_FIXED_PT: - /* not supported */ - return ALIGNMENT_ONE; - break; - default: - assert(0); - } - return ALIGNMENT_ONE; -} - -static bool ddsts_type_optimizable(ddsts_type_t *type) -{ - if (DDSTS_IS_TYPE(type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT)) { - ddsts_type_t *struct_def = get_struct_def(type); - if (struct_def == NULL) { - return false; - } - for (ddsts_type_t *member = struct_def->struct_def.members.first; member != NULL; member = member->type.next) { - if (DDSTS_IS_TYPE(member, DDSTS_DECLARATION)) { - if (!ddsts_type_optimizable(member->declaration.decl_type)) { - return false; - } - } - } - return true; - } - if (DDSTS_IS_TYPE(type, DDSTS_FORWARD_STRUCT)) { - return ddsts_type_optimizable(type->forward.definition); - } - if (DDSTS_IS_TYPE(type, DDSTS_STRING) && !DDSTS_IS_UNBOUND(type)) { - return false; - } - return ddsts_type_alignment(type) != ALIGNMENT_PTR; -} - -static dds_return_t walk_struct_keys(ddsts_call_path_t *path, bool top, ddsts_walk_call_func_t func, op_codes_context_t *context) -{ - assert(path != NULL && DDSTS_IS_TYPE(path->type, DDSTS_STRUCT)); - ddsts_type_t *struct_def = get_struct_def(path->type); - if (struct_def == NULL) { - return DDS_RETCODE_ERROR; - } - for (ddsts_type_t *member = struct_def->struct_def.members.first; member != NULL; member = member->type.next) { - if (DDSTS_IS_TYPE(member, DDSTS_DECLARATION)) { - bool member_is_key = !top && struct_def->struct_def.keys == NULL; - for (ddsts_struct_key_t *key = struct_def->struct_def.keys; key != NULL; key = key->next) { - if (key->member == member) { - member_is_key = true; - break; - } - } - if (member_is_key) { - ddsts_call_path_t declaration_path; - declaration_path.type = member; - declaration_path.call_parent = path; - if (DDSTS_IS_TYPE(member->declaration.decl_type, DDSTS_STRUCT | DDSTS_FORWARD_STRUCT)) { - ddsts_type_t *sd = get_struct_def(member->declaration.decl_type); - if (sd == NULL) { - return DDS_RETCODE_ERROR; - } - ddsts_call_path_t struct_decl_path; - struct_decl_path.type = sd; - struct_decl_path.call_parent = &declaration_path; - dds_return_t rc = walk_struct_keys(&struct_decl_path, false, func, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - } - else { - dds_return_t rc = func(&declaration_path, context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - } - } - } - } - - return DDS_RETCODE_OK; -} - -static dds_return_t collect_key_properties(ddsts_call_path_t *path, void *context) -{ - ((op_codes_context_t*)context)->nr_keys++; - ddsts_type_t *type = path->type->declaration.decl_type; - unsigned long long size = 1; - while (DDSTS_IS_TYPE(type, DDSTS_ARRAY)) { - size *= type->array.size; - type = type->array.element_type; - } - switch (DDSTS_TYPE_OF_IGNORE_SIGN(type)) { - case DDSTS_CHAR: - case DDSTS_BOOLEAN: - case DDSTS_OCTET: - case DDSTS_INT8: - break; - case DDSTS_INT16: - size *= 2ULL; - break; - case DDSTS_INT32: - case DDSTS_FLOAT: - size *= 4ULL; - break; - case DDSTS_INT64: - case DDSTS_DOUBLE: - size *= 8ULL; - break; - case DDSTS_STRING: - if (type->string.max > 0) { - size *= type->string.max + 5ULL; - } - else { - size = 0ULL; - ((op_codes_context_t*)context)->bounded_key_size = false; - } - break; - default: - assert(0); - return DDS_RETCODE_ERROR; - break; - } - if (size >= (1ULL << 32)) { - return DDS_RETCODE_ERROR; - } - ((op_codes_context_t*)context)->key_size += (uint32_t)size; - return DDS_RETCODE_OK; -} - -static void write_key_name(ddsts_call_path_t *path, bool top, ddsts_ostream_t *ostream) -{ - if (DDSTS_IS_TYPE(path->type, DDSTS_MODULE)) { - return; - } - if (DDSTS_IS_TYPE(path->type, DDSTS_DECLARATION)) { - write_key_name(path->call_parent, false, ostream); - ddsts_ostream_puts(ostream, path->type->type.name); - if (!top) { - ddsts_ostream_put(ostream, '.'); - } - } - else { - write_key_name(path->call_parent, top, ostream); - } -} - -static dds_return_t write_key_description(ddsts_call_path_t *path, void *context) -{ - ddsts_ostream_t *ostream = ((op_codes_context_t*)context)->output_context.ostream; - - key_offset_t *key_offset = op_codes_context_find_key((op_codes_context_t*)context, path->type); - if (key_offset == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - if (((op_codes_context_t*)context)->nr_keys != 0) { - ddsts_ostream_puts(ostream, ",\n"); - } - ((op_codes_context_t*)context)->nr_keys++; - ddsts_ostream_puts(ostream, " { \""); - write_key_name(path, true, ostream); - char offset_string[30]; - ddsrt_ulltostr(key_offset->offset, offset_string, 30, NULL); - output(((output_context_t*)context)->ostream, - "\", $O }", - 'O', offset_string, - '\0'); - return DDS_RETCODE_OK; -} - -static dds_return_t write_source_struct(ddsts_call_path_t *path, void *context) -{ - DDSRT_UNUSED_ARG(context); - - assert(DDSTS_IS_TYPE(path->type, DDSTS_STRUCT)); - ddsts_type_t *struct_def = path->type; - - if (struct_def->struct_def.keys == NULL) { - return DDS_RETCODE_OK; - } - - const char *full_name = name_with_module_prefix(struct_def, "_"); - if (full_name == NULL) { - return DDS_RETCODE_OUT_OF_RESOURCES; - } - - /* We first run the op-code generation, discarding output, to calculate - * the sizes of the various types and the positions of the topic keys - */ - ddsts_ostream_t *null_ostream = NULL; - dds_return_t rc; - rc = ddsts_create_ostream_to_null(&null_ostream); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)full_name); - return rc; - } - op_codes_context_t op_codes_context; - op_codes_context_init(&op_codes_context, null_ostream); - - rc = generate_op_codes_struct(path, &op_codes_context); - if (rc != DDS_RETCODE_OK) { - op_codes_context_fini(&op_codes_context); - ddsrt_free(null_ostream); - ddsrt_free((void*)full_name); - return rc; - } - op_codes_context_reset(&op_codes_context, ((output_context_t*)context)->ostream); - ddsrt_free(null_ostream); - - rc = walk_struct_keys(path, true, collect_key_properties, &op_codes_context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - - char nr_keys_string[30]; - ddsrt_ulltostr(op_codes_context.nr_keys, nr_keys_string, 30, NULL); - - output(((output_context_t*)context)->ostream, - "\n\n" - "static const dds_key_descriptor_t $N_keys[$C] =\n" - "{\n", - 'N', full_name, - 'C', nr_keys_string, - '\0'); - op_codes_context.nr_keys = 0; - rc = walk_struct_keys(path, true, write_key_description, &op_codes_context); - if (rc != DDS_RETCODE_OK) { - return rc; - } - output(((output_context_t*)context)->ostream, - "\n};\n" - "\n" - "static const uint32_t $N_ops [] =\n" - "{\n", - 'N', full_name, - '\0'); - - - /* Next we run the op-code generation to the stream */ - rc = generate_op_codes_struct(path, &op_codes_context); - if (rc != DDS_RETCODE_OK) { - op_codes_context_fini(&op_codes_context); - ddsrt_free((void*)full_name); - return rc; - } - - op_codes_context_fini(&op_codes_context); - - const char *dotted_full_name = name_with_module_prefix(struct_def, "::"); - if (dotted_full_name == NULL) { - ddsrt_free((void*)full_name); - return rc; - } - - bool fixed_key = op_codes_context.bounded_key_size && op_codes_context.key_size <= 16; - bool no_optimize = !ddsts_type_optimizable(struct_def); - char nr_ops_string[30]; - ddsrt_ulltostr(op_codes_context.nr_ops, nr_ops_string, 30, NULL); - output(((output_context_t*)context)->ostream, - "\n};\n" - "\n" - "const dds_topic_descriptor_t $N_desc =\n" - "{\n" - " sizeof ($N),\n" - " $A,\n" - " $F,\n" - " $Ku,\n" - " \"$M\",\n" - " $N_keys,\n" - " $S,\n" - " $N_ops,\n" - " \"", - 'N', full_name, - 'A', ddsts_type_alignment(struct_def)->rendering, - 'K', nr_keys_string, - 'F', fixed_key - ? (no_optimize ? "DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE" : "DDS_TOPIC_FIXED_KEY") - : (no_optimize ? "DDS_TOPIC_NO_OPTIMIZE" : "0u"), - 'M', dotted_full_name, - 'S', nr_ops_string, - '\0'); - rc = write_meta_data(((output_context_t*)context)->ostream, struct_def); - if (rc != DDS_RETCODE_OK) { - ddsrt_free((void*)dotted_full_name); - ddsrt_free((void*)full_name); - return rc; - } - output(((output_context_t*)context)->ostream, - "\"\n" - "};\n", - '\0'); - - ddsrt_free((void*)dotted_full_name); - ddsrt_free((void*)full_name); - - return DDS_RETCODE_OK; -} - -static dds_return_t generate_source_file(const char *file_name, ddsts_type_t *root_node, ddsts_ostream_t *ostream) -{ - DDSRT_UNUSED_ARG(root_node); - const char *c_file_name = NULL; - dds_return_t rc; - rc = output_file_name(file_name, "c", &c_file_name); - if (rc != DDS_RETCODE_OK) { - return rc; - } - if (!ddsts_ostream_open(ostream, c_file_name)) { - DDS_ERROR("Could not open file '%s' for writing", c_file_name); - ddsrt_free((void*)c_file_name); - return DDS_RETCODE_OUT_OF_RESOURCES; - } - const char *h_file_name = NULL; - rc = output_file_name(file_name, "h", &h_file_name); - if (rc != DDS_RETCODE_OK) { - ddsts_ostream_close(ostream); - ddsrt_free((void*)c_file_name); - return rc; - } - - write_file_header(ostream, c_file_name, file_name); - output(ostream, "#include \"$F\"\n\n\n\n", 'F', h_file_name, '\0'); - - ddsts_call_path_t path; - path.type = root_node; - path.call_parent = NULL; - - output_context_t output_context; - output_context.ostream = ostream; - rc = ddsts_walk(&path, DDSTS_MODULE, DDSTS_STRUCT, write_source_struct, &output_context); - - ddsrt_free((void*)h_file_name); - ddsts_ostream_close(ostream); - ddsrt_free((void*)c_file_name); - - return rc; -} - -/* Function for generating C99 files */ - -static dds_return_t ddsts_generate_C99_to_ostream(const char *file_name, ddsts_type_t *root_node, ddsts_ostream_t *ostream) -{ - dds_return_t rc = generate_header_file(file_name, root_node, ostream); - if (rc != DDS_RETCODE_OK) { - return rc; - } - return generate_source_file(file_name, root_node, ostream); -} - -extern dds_return_t ddsts_generate_C99(const char *file_name, ddsts_type_t *root_node) -{ - ddsts_ostream_t *ostream = NULL; - dds_return_t rc; - rc = ddsts_create_ostream_to_files(&ostream); - if (rc != DDS_RETCODE_OK) { - return rc; - } - rc = ddsts_generate_C99_to_ostream(file_name, root_node, ostream); - ddsrt_free((void*)ostream); - return rc; -} - -extern dds_return_t ddsts_generate_C99_to_buffer(const char *file_name, ddsts_type_t *root_node, char *buffer, size_t buffer_len) -{ - ddsts_ostream_t *ostream = NULL; - dds_return_t rc; - rc = ddsts_create_ostream_to_buffer(buffer, buffer_len, &ostream); - if (rc != DDS_RETCODE_OK) { - return rc; - } - rc = ddsts_generate_C99_to_ostream(file_name, root_node, ostream); - ddsrt_free((void*)ostream); - return rc; -} diff --git a/src/tools/idlc/src/gen_c99.h b/src/tools/idlc/src/gen_c99.h deleted file mode 100644 index 68b335fcf9..0000000000 --- a/src/tools/idlc/src/gen_c99.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#ifndef DDSTS_GEN_C99_H -#define DDSTS_GEN_C99_H - -#include "dds/ddsrt/retcode.h" - -dds_return_t ddsts_generate_C99(const char *file, ddsts_type_t *root_type); -dds_return_t ddsts_generate_C99_to_buffer(const char* file, ddsts_type_t *root_type, char *buffer, size_t buffer_len); - -#endif /* DDSTS_GEN_C99_H */ diff --git a/src/tools/idlc/src/gen_ostream.c b/src/tools/idlc/src/gen_ostream.c deleted file mode 100644 index 514abfc4b4..0000000000 --- a/src/tools/idlc/src/gen_ostream.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include "dds/ddsrt/retcode.h" -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/misc.h" - -#include "gen_ostream.h" - - -extern bool ddsts_ostream_open(ddsts_ostream_t *ostream, const char *name) -{ - return ostream->open(ostream, name); -} - -extern void ddsts_ostream_close(ddsts_ostream_t *ostream) -{ - ostream->close(ostream); -} - -extern void ddsts_ostream_put(ddsts_ostream_t *ostream, char ch) -{ - ostream->put(ostream, ch); -} - -extern void ddsts_ostream_puts(ddsts_ostream_t *ostream, const char *str) -{ - for (; *str != '\0'; str++) { - ostream->put(ostream, *str); - } -} - -/* output stream to null */ - -typedef struct { - ddsts_ostream_t ostream; -} ostream_to_null_t; - -static bool null_ostream_open(ddsts_ostream_t *ostream, const char *name) -{ - DDSRT_UNUSED_ARG(ostream); - DDSRT_UNUSED_ARG(name); - return true; -} - -static void null_ostream_close(ddsts_ostream_t *ostream) -{ - DDSRT_UNUSED_ARG(ostream); -} - -static void null_ostream_put(ddsts_ostream_t *ostream, char ch) -{ - DDSRT_UNUSED_ARG(ostream); - DDSRT_UNUSED_ARG(ch); -} - -extern dds_return_t ddsts_create_ostream_to_null(ddsts_ostream_t **ref_ostream) -{ - ostream_to_null_t *ostream_to_null = (ostream_to_null_t*)ddsrt_malloc(sizeof(ostream_to_null_t)); - if (ostream_to_null == NULL) { - *ref_ostream = NULL; - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ostream_to_null->ostream.open = null_ostream_open; - ostream_to_null->ostream.close = null_ostream_close; - ostream_to_null->ostream.put = null_ostream_put; - *ref_ostream = &ostream_to_null->ostream; - return DDS_RETCODE_OK; -} - - -/* output stream to files */ - -typedef struct { - ddsts_ostream_t ostream; - FILE *f; -} ostream_to_files_t; - -static bool files_ostream_open(ddsts_ostream_t *ostream, const char *name) -{ -DDSRT_WARNING_MSVC_OFF(4996); - return (((ostream_to_files_t*)ostream)->f = fopen(name, "wt")) != 0; -DDSRT_WARNING_MSVC_ON(4996); -} - -static void files_ostream_close(ddsts_ostream_t *ostream) -{ - fclose(((ostream_to_files_t*)ostream)->f); -} - -static void files_ostream_put(ddsts_ostream_t *ostream, char ch) -{ - fputc(ch, ((ostream_to_files_t*)ostream)->f); -} - -extern dds_return_t ddsts_create_ostream_to_files(ddsts_ostream_t **ref_ostream) -{ - ostream_to_files_t *ostream_to_files = (ostream_to_files_t*)ddsrt_malloc(sizeof(ostream_to_files_t)); - if (ostream_to_files == NULL) { - *ref_ostream = NULL; - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ostream_to_files->ostream.open = files_ostream_open; - ostream_to_files->ostream.close = files_ostream_close; - ostream_to_files->ostream.put = files_ostream_put; - ostream_to_files->f = NULL; - *ref_ostream = &ostream_to_files->ostream; - return DDS_RETCODE_OK; -} - -/* output stream to buffer */ - -typedef struct { - ddsts_ostream_t ostream; - char *s; - const char *e; -} ostream_to_buffer_t; - -static void buffer_ostream_put(ddsts_ostream_t *ostream, char ch) -{ - if (((ostream_to_buffer_t*)ostream)->s < ((ostream_to_buffer_t*)ostream)->e) { - *((ostream_to_buffer_t*)ostream)->s++ = ch; - *((ostream_to_buffer_t*)ostream)->s = '\0'; - } -} - -static bool buffer_ostream_open(ddsts_ostream_t *ostream, const char* name) -{ - DDSRT_UNUSED_ARG(ostream); - DDSRT_UNUSED_ARG(name); - return true; -} - -static void buffer_ostream_close(ddsts_ostream_t *ostream) -{ - DDSRT_UNUSED_ARG(ostream); -} - -extern dds_return_t ddsts_create_ostream_to_buffer(char *buffer, size_t len, ddsts_ostream_t **ref_ostream) -{ - ostream_to_buffer_t *ostream_to_buffer = (ostream_to_buffer_t*)ddsrt_malloc(sizeof(ostream_to_buffer_t)); - if (ostream_to_buffer == NULL) { - *ref_ostream = NULL; - return DDS_RETCODE_OUT_OF_RESOURCES; - } - ostream_to_buffer->ostream.open = buffer_ostream_open; - ostream_to_buffer->ostream.close = buffer_ostream_close; - ostream_to_buffer->ostream.put = buffer_ostream_put; - ostream_to_buffer->s = buffer; - ostream_to_buffer->e = buffer + len - 1; - *ref_ostream = &ostream_to_buffer->ostream; - return DDS_RETCODE_OK; -} - diff --git a/src/tools/idlc/src/gen_ostream.h b/src/tools/idlc/src/gen_ostream.h deleted file mode 100644 index 4bb1ca7bd2..0000000000 --- a/src/tools/idlc/src/gen_ostream.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#ifndef DDSTS_GEN_OSTREAM_H -#define DDSTS_GEN_OSTREAM_H - -typedef struct ddsts_ostream_t ddsts_ostream_t; -struct ddsts_ostream_t { - bool (*open)(ddsts_ostream_t *ostream, const char *name); - void (*close)(ddsts_ostream_t *ostream); - void (*put)(ddsts_ostream_t *ostream, char ch); -}; - -bool ddsts_ostream_open(ddsts_ostream_t *ostream, const char *name); -void ddsts_ostream_close(ddsts_ostream_t *ostream); -void ddsts_ostream_put(ddsts_ostream_t *ostream, char ch); -void ddsts_ostream_puts(ddsts_ostream_t *ostream, const char *str); - -dds_return_t ddsts_create_ostream_to_null(ddsts_ostream_t **ref_ostream); -dds_return_t ddsts_create_ostream_to_files(ddsts_ostream_t **ref_ostream); -dds_return_t ddsts_create_ostream_to_buffer(char *buffer, size_t len, ddsts_ostream_t **ref_ostream); - -#endif /* DDSTS_GEN_OSTREAM_H */ diff --git a/src/tools/idlc/src/generator.c b/src/tools/idlc/src/generator.c new file mode 100644 index 0000000000..d079cf414d --- /dev/null +++ b/src/tools/idlc/src/generator.c @@ -0,0 +1,388 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#include "generator.h" + +#include "idl/file.h" +#include "idl/retcode.h" +#include "idl/stream.h" +#include "idl/string.h" +#include "idl/version.h" +#include "idl/processor.h" + +idlc_thread_local struct idlc_auto idlc_auto__; + +char *absolute_name(const void *node, const char *separator); + +char *absolute_name(const void *node, const char *separator) +{ + char *str; + size_t cnt, len = 0; + const char *sep, *ident; + const idl_node_t *root; + for (root=node, sep=""; root; root=root->parent) { + if ((idl_mask(root) & IDL_TYPEDEF) == IDL_TYPEDEF) + continue; + if ((idl_mask(root) & IDL_ENUM) == IDL_ENUM && root != node) + continue; + ident = idl_identifier(root); + assert(ident); + len += strlen(sep) + strlen(ident); + sep = separator; + } + if (!(str = malloc(len + 1))) + return NULL; + str[len] = '\0'; + for (root=node, sep=separator; root; root=root->parent) { + if ((idl_mask(root) & IDL_TYPEDEF) == IDL_TYPEDEF) + continue; + if ((idl_mask(root) & IDL_ENUM) == IDL_ENUM && root != node) + continue; + ident = idl_identifier(root); + assert(ident); + cnt = strlen(ident); + assert(cnt <= len); + len -= cnt; + memmove(str+len, ident, cnt); + if (len == 0) + break; + cnt = strlen(sep); + assert(cnt <= len); + len -= cnt; + memmove(str+len, sep, cnt); + } + assert(len == 0); + return str; +} + +char *typename(const void *node); + +char *typename(const void *node) +{ + switch (idl_type(node)) { + case IDL_BOOL: return idl_strdup("bool"); + case IDL_CHAR: return idl_strdup("char"); + case IDL_INT8: return idl_strdup("int8_t"); + case IDL_OCTET: + case IDL_UINT8: return idl_strdup("uint8_t"); + case IDL_SHORT: + case IDL_INT16: return idl_strdup("int16_t"); + case IDL_USHORT: + case IDL_UINT16: return idl_strdup("uint16_t"); + case IDL_LONG: + case IDL_INT32: return idl_strdup("int32_t"); + case IDL_ULONG: + case IDL_UINT32: return idl_strdup("uint32_t"); + case IDL_LLONG: + case IDL_INT64: return idl_strdup("int64_t"); + case IDL_ULLONG: + case IDL_UINT64: return idl_strdup("uint64_t"); + case IDL_FLOAT: return idl_strdup("float"); + case IDL_DOUBLE: return idl_strdup("double"); + case IDL_LDOUBLE: return idl_strdup("long double"); + case IDL_STRING: return idl_strdup("char"); + case IDL_SEQUENCE: { + /* sequences require a little magic */ + const char pref[] = "dds_sequence_"; + const char seq[] = "sequence_"; + char dims[32] = ""; + const idl_type_spec_t *type_spec; + char *type, *seqtype = NULL; + size_t cnt = 0, len = 0, pos = 0; + + type_spec = idl_type_spec(node); + for (; idl_is_sequence(type_spec); type_spec = idl_type_spec(type_spec)) + cnt++; + if (idl_is_base_type(type_spec) || idl_is_string(type_spec)) + switch (idl_type(type_spec)) { + case IDL_BOOL: type = "bool"; break; + case IDL_CHAR: type = "char"; break; + case IDL_INT8: type = "int8"; break; + case IDL_OCTET: type = "octet"; break; + case IDL_UINT8: type = "uint8"; break; + case IDL_SHORT: type = "short"; break; + case IDL_INT16: type = "int16"; break; + case IDL_USHORT: type = "unsigned_short"; break; + case IDL_UINT16: type = "uint16"; break; + case IDL_LONG: type = "long"; break; + case IDL_INT32: type = "int32"; break; + case IDL_ULONG: type = "unsigned_long"; break; + case IDL_UINT32: type = "uint32"; break; + case IDL_LLONG: type = "long_long"; break; + case IDL_INT64: type = "int64"; break; + case IDL_ULLONG: type = "unsigned_long_long"; break; + case IDL_UINT64: type = "uint64"; break; + case IDL_FLOAT: type = "float"; break; + case IDL_DOUBLE: type = "double"; break; + case IDL_LDOUBLE: type = "long_double"; break; + case IDL_STRING: + if (idl_is_bounded(type_spec)) + idl_snprintf(dims, sizeof(dims), "%"PRIu32, idl_bound(type_spec)); + type = "string"; + break; + default: + abort(); + } + else if (!(type = absolute_name(type_spec, "_"))) + goto err_type; + len = strlen(pref) + strlen(type) + strlen(dims); + if (!(seqtype = malloc(len + (cnt * strlen(seq)) + 1))) + goto err_seqtype; + len = strlen(pref); + memcpy(seqtype, pref, len); + pos += len; + for (; cnt; pos += strlen(seq), cnt--) + memcpy(seqtype+pos, seq, strlen(seq)); + len = strlen(type); + memcpy(seqtype+pos, type, len); + pos += len; + len = strlen(dims); + memcpy(seqtype+pos, dims, len); + pos += len; + seqtype[pos] = '\0'; +err_seqtype: + if (!idl_is_base_type(type_spec) && !idl_is_string(type_spec)) + free(type); +err_type: + return seqtype; + } + default: + break; + } + + return absolute_name(node, "_"); +} +static char *figure_guard(const char *file) +{ + char *inc = NULL; + + if (idl_asprintf(&inc, "DDSC_%s", file) == -1) + return NULL; + + /* replace any non-alphanumeric characters */ + for (char *ptr = inc; *ptr; ptr++) { + if (idl_islower((unsigned char)*ptr)) + *ptr = (char)idl_toupper((unsigned char)*ptr); + else if (!idl_isalnum((unsigned char)*ptr)) + *ptr = '_'; + } + + return inc; +} + +static idl_retcode_t print_header(FILE *fh, const char *in, const char *out) +{ + static const char fmt[] = + "/****************************************************************\n" + "\n" + " Generated by Eclipse Cyclone DDS IDL to C Translator\n" + " File name: %s\n" + " Source: %s\n" + " Cyclone DDS: V%s\n" + "\n" + "*****************************************************************/\n"; + + if (idl_fprintf(fh, fmt, out, in, IDL_VERSION) < 0) + return IDL_RETCODE_NO_MEMORY; + return IDL_RETCODE_OK; +} + +static idl_retcode_t print_guard_if(FILE *fh, const char *guard) +{ + static const char fmt[] = + "#ifndef %1$s\n" + "#define %1$s\n\n"; + if (idl_fprintf(fh, fmt, guard) < 0) + return IDL_RETCODE_NO_MEMORY; + return IDL_RETCODE_OK; +} + +static idl_retcode_t print_guard_endif(FILE *fh, const char *guard) +{ + static const char fmt[] = + "#endif /* %1$s */\n"; + if (idl_fprintf(fh, fmt, guard) < 0) + return IDL_RETCODE_NO_MEMORY; + return IDL_RETCODE_OK; +} + +static idl_retcode_t print_includes(FILE *fh, const idl_source_t *source) +{ + idl_retcode_t ret; + char *sep = NULL, *path; + const idl_source_t *include; + + if (!(path = AUTO(idl_strdup(source->path->name)))) + return IDL_RETCODE_NO_MEMORY; + for (char *ptr = path; *ptr; ptr++) + if (idl_isseparator(*ptr)) + sep = ptr; + if (sep) + *sep = '\0'; + + for (include = source->includes; include; include = include->next) { + char *ext, *relpath = NULL; + if ((ret = idl_relative_path(path, include->path->name, &relpath))) + return ret; + if (!(relpath = AUTO(relpath))) + return IDL_RETCODE_NO_MEMORY; + ext = relpath; + for (char *ptr = ext; *ptr; ptr++) { + if (*ptr == '.') + ext = ptr; + } + if (ext > relpath && idl_strcasecmp(ext, ".idl") == 0) { + const char *fmt = "#include \"%.*s.h\"\n"; + int len = (int)(ext - relpath); + if (idl_fprintf(fh, fmt, len, relpath) < 0) + return IDL_RETCODE_NO_MEMORY; + } else { + const char *fmt = "#include \"%s\"\n"; + if (idl_fprintf(fh, fmt, relpath) < 0) + return IDL_RETCODE_NO_MEMORY; + } + if (fputs("\n", fh) < 0) + return IDL_RETCODE_NO_MEMORY; + } + + return IDL_RETCODE_OK; +} + +extern idl_retcode_t +generate_types(const idl_pstate_t *pstate, struct generator *generator); + +idl_retcode_t +generate_nosetup(const idl_pstate_t *pstate, struct generator *generator) +{ + idl_retcode_t ret; + char *guard; + const char *sep, *file = generator->path; + char *const header_file = generator->header.path; + char *const source_file = generator->source.path; + + if (!(guard = AUTO(figure_guard(header_file)))) + return IDL_RETCODE_NO_MEMORY; + if ((ret = print_header(generator->header.handle, file, header_file))) + return ret; + if ((ret = print_guard_if(generator->header.handle, guard))) + return ret; + if ((ret = print_includes(generator->header.handle, pstate->sources))) + return ret; + if (fputs("#include \"dds/ddsc/dds_public_impl.h\"\n\n", generator->header.handle) < 0) + return IDL_RETCODE_NO_MEMORY; + if (fputs("#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n", generator->header.handle) < 0) + return IDL_RETCODE_NO_MEMORY; + if ((ret = print_header(generator->source.handle, file, source_file))) + return ret; + /* generate include statement for header in source */ + sep = header_file; + for (const char *ptr = sep; *ptr; ptr++) + if (idl_isseparator((unsigned char)*ptr)) + sep = ptr+1; + if (idl_fprintf(generator->source.handle, "#include \"%s\"\n\n", sep) < 0) + return IDL_RETCODE_NO_MEMORY; + if ((ret = generate_types(pstate, generator))) + return ret; + if (fputs("#ifdef __cplusplus\n}\n#endif\n\n", generator->header.handle) < 0) + return IDL_RETCODE_NO_MEMORY; + if ((ret = print_guard_endif(generator->header.handle, guard))) + return ret; + + return IDL_RETCODE_OK; +} + +static FILE *open_file(const char *pathname, const char *mode) +{ +#if _WIN32 + FILE *handle = NULL; + if (fopen_s(&handle, pathname, mode) != 0) + return NULL; + return handle; +#else + return fopen(pathname, mode); +#endif +} + +idl_retcode_t +idlc_generate(const idl_pstate_t *pstate) +{ + idl_retcode_t ret = IDL_RETCODE_NO_MEMORY; + const char *sep, *ext, *file, *path; + char empty[1] = { '\0' }; + char *dir = NULL, *basename = NULL; + struct generator generator; + + assert(pstate->paths); + assert(pstate->paths->name); + path = pstate->sources->path->name; + /* use relative directory if user provided a relative path, use current + word directory otherwise */ + sep = ext = NULL; + for (const char *ptr = path; ptr[0]; ptr++) { + if (idl_isseparator((unsigned char)ptr[0]) && ptr[1] != '\0') + sep = ptr; + else if (ptr[0] == '.') + ext = ptr; + } + + file = sep ? sep + 1 : path; + if (idl_isabsolute(path) || !sep) + dir = empty; + else if (!(dir = idl_strndup(path, (size_t)(sep-path)))) + goto err_dir; + if (!(basename = idl_strndup(file, ext ? (size_t)(ext-file) : strlen(file)))) + goto err_basename; + + /* replace backslashes by forward slashes */ + for (char *ptr = dir; *ptr; ptr++) { + if (*ptr == '\\') + *ptr = '/'; + } + + memset(&generator, 0, sizeof(generator)); + generator.path = file; + + sep = dir[0] == '\0' ? "" : "/"; + if (idl_asprintf(&generator.header.path, "%s%s%s.h", dir, sep, basename) < 0) + goto err_header; + if (!(generator.header.handle = open_file(generator.header.path, "wb"))) + goto err_header; + if (idl_asprintf(&generator.source.path, "%s%s%s.c", dir, sep, basename) < 0) + goto err_source; + if (!(generator.source.handle = open_file(generator.source.path, "wb"))) + goto err_source; + ret = generate_nosetup(pstate, &generator); + +err_source: + if (generator.source.handle) + fclose(generator.source.handle); + if (generator.source.path) + free(generator.source.path); +err_header: + if (generator.header.handle) + fclose(generator.header.handle); + if (generator.header.path) + free(generator.header.path); + if (basename) + free(basename); +err_basename: + if (dir && dir != empty) + free(dir); +err_dir: + return ret; +} diff --git a/src/tools/idlc/src/generator.h b/src/tools/idlc/src/generator.h new file mode 100644 index 0000000000..9fa9c8ce95 --- /dev/null +++ b/src/tools/idlc/src/generator.h @@ -0,0 +1,76 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef GENERATOR_H +#define GENERATOR_H + +#include + +#include "idl/processor.h" + +#include +#include +#if defined(_MSC_VER) +# include +# define idlc_thread_local __declspec(thread) +#elif defined(__GNUC__) || (defined(__clang__) && __clang_major__ >= 2) +# if !defined(__FreeBSD__) +# include +# endif +# define idlc_thread_local __thread +#elif defined(__SUNPROC_C) || defined(__SUNPRO_CC) +# include +# define idlc_thread_local __thread +#else +# error "Thread-local storage is not supported" +#endif + +/** @private */ +struct idlc_auto { + void *src; + size_t len; + void *dest; +}; + +extern idlc_thread_local struct idlc_auto idlc_auto__; + +#define AUTO(str) \ + ((idlc_auto__.src = (str)) \ + ? (idlc_auto__.len = strlen(idlc_auto__.src), \ + idlc_auto__.dest = alloca(idlc_auto__.len + 1), \ + memmove(idlc_auto__.dest, idlc_auto__.src, idlc_auto__.len + 1), \ + free(idlc_auto__.src), \ + idlc_auto__.dest) \ + : (NULL)) + +struct generator { + const char *path; + struct { + FILE *handle; + char *path; + } header; + struct { + FILE *handle; + char *path; + } source; +}; + +#if _WIN32 +__declspec(dllexport) +#endif +idl_retcode_t idlc_generate(const idl_pstate_t *pstate); + +#if _WIN32 +__declspec(dllexport) +#endif +idl_retcode_t generate_nosetup(const idl_pstate_t *pstate, struct generator *generator); + +#endif /* GENERATOR_H */ diff --git a/src/tools/idlc/src/idl.c b/src/tools/idlc/src/idl.c deleted file mode 100644 index 82e0b8c57c..0000000000 --- a/src/tools/idlc/src/idl.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright(c) 2020 Jeroen Koekkoek - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -#include -#include -#include -#include -#include -#include - -#include "idl.h" -#include "parser.h" -#include "tt_create.h" - -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/io.h" -#include "dds/ddsrt/log.h" -#include "dds/ddsrt/misc.h" -#include "dds/ddsrt/string.h" - -int32_t idl_processor_init(idl_processor_t *proc) -{ - memset(proc, 0, sizeof(*proc)); - if (!(proc->context = ddsts_create_context())) { - return IDL_MEMORY_EXHAUSTED; - } else if (!(proc->parser.yypstate = (void *)idl_yypstate_new())) { - ddsts_free_context(proc->context); - return IDL_MEMORY_EXHAUSTED; - } - - return 0; -} - -void idl_processor_fini(idl_processor_t *proc) -{ - if (proc) { - idl_file_t *file, *next; - - if (proc->parser.yypstate) - idl_yypstate_delete((idl_yypstate *)proc->parser.yypstate); - if (proc->context) - ddsts_free_context(proc->context); - if (proc->directive) { - switch (proc->directive->type) { - case IDL_LINE: { - idl_line_t *dir = (idl_line_t *)proc->directive; - ddsrt_free(dir->file); - } break; - case IDL_KEYLIST: { - idl_keylist_t *dir = (idl_keylist_t *)proc->directive; - ddsrt_free(dir->data_type); - for (char **keys = dir->keys; keys && *keys; keys++) - ddsrt_free(*keys); - ddsrt_free(dir->keys); - } break; - default: - break; - } - ddsrt_free(proc->directive); - } - for (file = proc->files; file; file = next) { - next = file->next; - if (file->name) - ddsrt_free(file->name); - ddsrt_free(file); - } - - if (proc->buffer.data) - ddsrt_free(proc->buffer.data); - } -} - -static void -idl_log( - idl_processor_t *proc, uint32_t prio, idl_location_t *loc, const char *fmt, va_list ap) -{ - char buf[1024]; - int cnt; - size_t off; - - (void)proc; - (void)prio; - if (loc->first.file) - cnt = snprintf( - buf, sizeof(buf)-1, "%s:%u:%u: ", loc->first.file, loc->first.line, loc->first.column); - else - cnt = snprintf( - buf, sizeof(buf)-1, "%u:%u: ", loc->first.line, loc->first.column); - - if (cnt == -1) - return; - - off = (size_t)cnt; - cnt = vsnprintf(buf+off, sizeof(buf)-off, fmt, ap); - - if (cnt == -1) - return; - - fprintf(stderr, "%s\n", buf); -} - -void -idl_verror( - idl_processor_t *proc, idl_location_t *loc, const char *fmt, va_list ap) -{ - idl_log(proc, DDS_LC_ERROR, loc, fmt, ap); -} - -void -idl_error( - idl_processor_t *proc, idl_location_t *loc, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - idl_log(proc, DDS_LC_ERROR, loc, fmt, ap); - va_end(ap); -} - -void -idl_warning( - idl_processor_t *proc, idl_location_t *loc, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - idl_log(proc, DDS_LC_WARNING, loc, fmt, ap); - va_end(ap); -} - -int32_t idl_parse_code(idl_processor_t *proc, idl_token_t *tok) -{ - YYSTYPE yylval; - - /* prepare Bison yylval */ - switch (tok->code) { - case IDL_TOKEN_IDENTIFIER: - case IDL_TOKEN_CHAR_LITERAL: - case IDL_TOKEN_STRING_LITERAL: - yylval.str = tok->value.str; - break; - case IDL_TOKEN_INTEGER_LITERAL: - yylval.ullng = tok->value.ullng; - break; - default: - memset(&yylval, 0, sizeof(yylval)); - break; - } - - switch (idl_yypush_parse( - proc->parser.yypstate, tok->code, &yylval, &tok->location, proc)) - { - case YYPUSH_MORE: - return IDL_PUSH_MORE; - case 1: /* parse error */ - return IDL_PARSE_ERROR; - case 2: /* out of memory */ - return IDL_MEMORY_EXHAUSTED; - default: - break; - } - - return 0; -} - -int32_t idl_parse(idl_processor_t *proc) -{ - int32_t code; - idl_token_t tok; - memset(&tok, 0, sizeof(tok)); - - do { - if ((code = idl_scan(proc, &tok)) < 0) - break; - if ((unsigned)proc->state & (unsigned)IDL_SCAN_DIRECTIVE) - code = idl_parse_directive(proc, &tok); - else if (code != '\n') - code = idl_parse_code(proc, &tok); - else - code = 0; - /* free memory associated with token value */ - switch (tok.code) { - case '\n': - proc->state = IDL_SCAN; - break; - case IDL_TOKEN_IDENTIFIER: - case IDL_TOKEN_CHAR_LITERAL: - case IDL_TOKEN_STRING_LITERAL: - case IDL_TOKEN_PP_NUMBER: - if (tok.value.str) - ddsrt_free(tok.value.str); - break; - default: - break; - } - } while (tok.code != '\0' && (code == 0 || code == IDL_PUSH_MORE)); - - return code; -} - -int32_t -idl_parse_string(const char *str, ddsts_type_t **typeptr) -{ - int32_t ret; - idl_processor_t proc; - - assert(str != NULL); - assert(typeptr != NULL); - - if ((ret = idl_processor_init(&proc)) != 0) - return ret; - - proc.buffer.data = (char *)str; - proc.buffer.size = proc.buffer.used = strlen(str); - proc.scanner.cursor = proc.buffer.data; - proc.scanner.limit = proc.buffer.data + proc.buffer.used; - proc.scanner.position.line = 1; - proc.scanner.position.column = 1; - - if ((ret = idl_parse(&proc)) == 0) - *typeptr = ddsts_context_take_root_type(proc.context); - - proc.buffer.data = NULL; - - idl_processor_fini(&proc); - - return ret; -} diff --git a/src/tools/idlc/src/idl.h b/src/tools/idlc/src/idl.h deleted file mode 100644 index 7da6f9c5fa..0000000000 --- a/src/tools/idlc/src/idl.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#ifndef IDL_H -#define IDL_H - -#include - -#include "dds/ddsrt/attributes.h" -#include "dds/ddsrt/retcode.h" - -#include "dds/ddsts/typetree.h" -#include "tt_create.h" - -/** @private */ -typedef struct idl_file idl_file_t; -struct idl_file { - idl_file_t *next; - char *name; -}; - -/** @private */ -typedef struct idl_buffer idl_buffer_t; -struct idl_buffer { - char *data; - size_t size; /**< total number of bytes available */ - size_t used; /**< number of bytes used */ -}; - -/** @private */ -typedef struct idl_position idl_position_t; -struct idl_position { - const char *file; - uint32_t line; - uint32_t column; -}; - -/** @private */ -typedef struct idl_location idl_location_t; -struct idl_location { - idl_position_t first; - idl_position_t last; -}; - -/** @private */ -typedef struct idl_lexeme idl_lexeme_t; -struct idl_lexeme { - const char *marker; - const char *limit; - idl_location_t location; -}; - -/** @private */ -typedef struct idl_token idl_token_t; -struct idl_token { - int32_t code; /**< token identifier (generated by Bison) */ - union { - int32_t chr; - long long llng; - unsigned long long ullng; - char *str; - } value; - idl_location_t location; -}; - -/** @private */ -typedef struct idl_scanner idl_scanner_t; -struct idl_scanner { - const char *cursor; - const char *limit; - idl_position_t position; -}; - -/** @private */ -typedef struct idl_directive idl_directive_t; -struct idl_directive { - enum { IDL_LINE, IDL_KEYLIST } type; -}; - -/** @private */ -typedef struct idl_line idl_line_t; -struct idl_line { - idl_directive_t directive; - uint32_t line; - char *file; - bool extra_tokens; -}; - -/** @private */ -typedef struct idl_keylist idl_keylist_t; -struct idl_keylist { - idl_directive_t directive; - char *data_type; - char **keys; -}; - -/** @private */ -typedef struct idl_parser idl_parser_t; -struct idl_parser { - void *yypstate; /**< state of Bison generated parser */ -}; - -/** - * @name processor_options - * IDL processor options - * @{ - */ -/** Debug */ -#define IDL_FLAG_DEBUG (1u<<1) -/** Preprocess */ -#define IDL_PREPROCESS (1u<<0) - -#define IDL_WRITE (1u<<11) -/** @} */ - -/** @private */ -typedef struct idl_processor idl_processor_t; -struct idl_processor { - uint32_t flags; /**< processor options */ - enum { - IDL_SCAN, - /** scanning preprocessor directive */ - IDL_SCAN_DIRECTIVE = (1<<7), - IDL_SCAN_DIRECTIVE_NAME, - /** scanning #line directive */ - IDL_SCAN_LINE = (IDL_SCAN_DIRECTIVE | 1<<6), - IDL_SCAN_FILENAME, - IDL_SCAN_EXTRA_TOKEN, - /** scanning #pragma directive */ - IDL_SCAN_PRAGMA = (IDL_SCAN_DIRECTIVE | 1<<5), - IDL_SCAN_UNKNOWN_PRAGMA, - /** scanning #pragma keylist directive */ - IDL_SCAN_KEYLIST = (IDL_SCAN_PRAGMA | 1<<4), - IDL_SCAN_DATA_TYPE, - IDL_SCAN_KEY, - /** scanning IDL code */ - IDL_SCAN_CODE = (1<<9), - /** scanning a scoped name in IDL code */ - IDL_SCAN_SCOPED_NAME = (IDL_SCAN_CODE | (1<<8)), - /** end of input */ - IDL_EOF = (1<<10) - } state; /**< processor state */ - idl_file_t *files; /**< list of encountered files */ - idl_directive_t *directive; /**< */ - idl_buffer_t buffer; /**< dynamically sized input buffer */ - idl_scanner_t scanner; - idl_parser_t parser; - ddsts_context_t *context; -}; - -#define IDL_PUSH_MORE (-1) -#define IDL_NEED_REFILL (-2) -#define IDL_SCAN_ERROR (-3) -#define IDL_PARSE_ERROR IDL_SCAN_ERROR -#define IDL_MEMORY_EXHAUSTED (-5) -#define IDL_READ_ERROR (-6) - -int32_t idl_lex(idl_processor_t *proc, idl_lexeme_t *lex); - -int32_t idl_scan(idl_processor_t *proc, idl_token_t *tok); - -int32_t idl_parse(idl_processor_t *proc); - -int32_t idl_parse_directive(idl_processor_t *proc, idl_token_t *tok); - -int32_t idl_parse_code(idl_processor_t *proc, idl_token_t *tok); - -void idl_error( - idl_processor_t *proc, idl_location_t *loc, const char *fmt, ...); - -void idl_verror( - idl_processor_t *proc, idl_location_t *loc, const char *fmt, va_list ap); - -void idl_warning( - idl_processor_t *proc, idl_location_t *loc, const char *fmt, ...); - -int32_t idl_parse_file(const char *filename, ddsts_type_t **root); - -int32_t idl_parse_string(const char *str, ddsts_type_t **root); - -int32_t idl_processor_init(idl_processor_t *proc); - -void idl_processor_fini(idl_processor_t *proc); - -int32_t idl_parse_string(const char *str, ddsts_type_t **ref_root_type); - -#endif /* IDL_H */ diff --git a/src/tools/idlc/src/idlc.c b/src/tools/idlc/src/idlc.c new file mode 100644 index 0000000000..c78293e797 --- /dev/null +++ b/src/tools/idlc/src/idlc.c @@ -0,0 +1,601 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "config.h" + +#include +#include +#if HAVE_GETOPT_H +# include +#else +# include "getopt.h" +#endif +#include +#include +#include +#include +#include + +#include "idl/tree.h" +#include "idl/string.h" +#include "idl/processor.h" +#include "idl/file.h" +#include "idl/version.h" + +#include "mcpp_lib.h" +#include "mcpp_out.h" + +#include "plugin.h" +#include "options.h" + +#if 0 +#define IDLC_DEBUG_PREPROCESSOR (1u<<2) +#define IDLC_DEBUG_SCANNER (1u<<3) +#define IDLC_DEBUG_PARSER (1u<<4) +#endif + +static struct { + char *file; /* path of input file or "-" for STDIN */ + const char *lang; + int compile; + int preprocess; + int keylist; + int case_sensitive; + int help; + int version; + /* (emulated) command line options for mcpp */ + int argc; + char **argv; +} config; + +/* mcpp does not accept userdata */ +static idl_retcode_t retcode = IDL_RETCODE_OK; +static idl_pstate_t *pstate = NULL; + +static int idlc_putc(int chr, OUTDEST od); +static int idlc_puts(const char *str, OUTDEST od); +static int idlc_printf(OUTDEST od, const char *str, ...); + +#define CHUNK (4096) + +static int idlc_putn(const char *str, size_t len) +{ + assert(pstate->flags & IDL_WRITE); + + /* tokenize to free up space */ + if ((pstate->buffer.size - pstate->buffer.used) <= len) { + if ((retcode = idl_parse(pstate)) == IDL_RETCODE_NEED_REFILL) + retcode = IDL_RETCODE_OK; + /* move non-tokenized data to start of buffer */ + pstate->buffer.used = + (uintptr_t)pstate->scanner.limit - (uintptr_t)pstate->scanner.cursor; + memmove(pstate->buffer.data, pstate->scanner.cursor, pstate->buffer.used); + pstate->scanner.cursor = pstate->buffer.data; + pstate->scanner.limit = pstate->scanner.cursor + pstate->buffer.used; + } + + if (retcode != IDL_RETCODE_OK) + return -1; + + /* expand buffer if necessary */ + if ((pstate->buffer.size - pstate->buffer.used) <= len) { + size_t size = pstate->buffer.size + (((len / CHUNK) + 1) * CHUNK); + char *buf = realloc(pstate->buffer.data, size + 2 /* '\0' + '\0' */); + if (buf == NULL) { + retcode = IDL_RETCODE_NO_MEMORY; + return -1; + } + /* update scanner location */ + pstate->scanner.cursor = buf + (pstate->scanner.cursor - pstate->buffer.data); + pstate->scanner.limit = buf + pstate->buffer.used; + /* update input buffer */ + pstate->buffer.data = buf; + pstate->buffer.size = size; + } + + /* write to buffer */ + memcpy(pstate->buffer.data + pstate->buffer.used, str, len); + pstate->buffer.used += len; + assert(pstate->buffer.used <= pstate->buffer.size); + /* update scanner location */ + pstate->scanner.limit = pstate->buffer.data + pstate->buffer.used; + + return 0; +} + +static int idlc_putc(int chr, OUTDEST od) +{ + int ret = -1; + char str[2] = { (char)chr, '\0' }; + + switch (od) { + case OUT: + if (!(config.compile)) + ret = printf("%c", chr); + else + ret = idlc_putn(str, 1); + break; + case ERR: + ret = fprintf(stderr, "%c", chr); + break; + case DBG: +#if 0 + if (config.flags & IDLC_DEBUG_PREPROCESSOR) +#endif + ret = fprintf(stderr, "%c", chr); + break; + default: + assert(0); + break; + } + + return ret < 0 ? -1 : ret; +} + +static int idlc_puts(const char *str, OUTDEST od) +{ + int ret; + size_t len = strlen(str); + + assert(str != NULL); + assert(len <= INT_MAX); + ret = (int)len; + + switch (od) { + case OUT: + if (!(config.compile)) + ret = printf("%s", str); + else + ret = idlc_putn(str, len); + break; + case ERR: + ret = fprintf(stderr, "%s", str); + break; + case DBG: +#if 0 + if (config.flags & IDLC_DEBUG_PREPROCESSOR) +#endif + ret = fprintf(stderr, "%s", str); + break; + default: + assert(0); + break; + } + + return ret < 0 ? -1 : ret; +} + +static int idlc_printf(OUTDEST od, const char *fmt, ...) +{ + int ret = -1; + char *str = NULL; + int len; + va_list ap; + + assert(fmt != NULL); + + va_start(ap, fmt); + if ((len = idl_vasprintf(&str, fmt, ap)) < 0) { /* FIXME: optimize */ + retcode = IDL_RETCODE_NO_MEMORY; + return -1; + } + va_end(ap); + + switch (od) { + case OUT: + if (!(config.compile)) + ret = printf("%s", str); + else + ret = idlc_putn(str, (size_t)len); + break; + case ERR: + ret = fprintf(stderr, "%s", str); + break; + case DBG: +#if 0 + if (config.flags & IDLC_DEBUG_PREPROCESSOR) +#endif + ret = fprintf(stderr, "%s", str); + break; + default: + assert(0); + break; + } + + free(str); + + return ret < 0 ? -1 : ret; +} + +static idl_retcode_t figure_file(idl_file_t **filep) +{ + idl_file_t *file; + idl_retcode_t ret = IDL_RETCODE_NO_MEMORY; + char *dir = NULL, *abs = NULL, *norm = NULL; + + if (!(file = malloc(sizeof(*file)))) + goto err_file; + if (idl_isabsolute(config.file)) { + if ((ret = idl_normalize_path(config.file, &norm)) < 0) + goto err_norm; + } else { + if (idl_current_path(&dir) < 0) + goto err_dir; + if (idl_asprintf(&abs, "%s/%s", dir, config.file) == -1) + goto err_abs; + if ((ret = idl_normalize_path(abs, &norm)) < 0) + goto err_norm; + free(abs); + free(dir); + } + file->next = NULL; + file->name = norm; + *filep = file; + return IDL_RETCODE_OK; +err_norm: + if (abs) free(abs); +err_abs: + if (dir) free(dir); +err_dir: + free(file); +err_file: + return ret; +} + +static idl_retcode_t idlc_parse(void) +{ + idl_retcode_t ret = IDL_RETCODE_OK; + idl_file_t *path = NULL; + idl_file_t *file = NULL; + uint32_t flags = IDL_FLAG_EXTENDED_DATA_TYPES | + IDL_FLAG_ANONYMOUS_TYPES | + IDL_FLAG_ANNOTATIONS; + + if(config.case_sensitive) + flags |= IDL_FLAG_CASE_SENSITIVE; + + if(config.compile) { + idl_source_t *source; + if ((ret = idl_create_pstate(flags, NULL, &pstate))) { + return ret; + } + assert(config.file); + if (strcmp(config.file, "-") != 0 && (ret = figure_file(&path)) != 0) { + idl_delete_pstate(pstate); + return ret; + } + file = malloc(sizeof(*file)); + file->next = NULL; + file->name = idl_strdup(config.file); + pstate->files = file; + pstate->paths = path; + source = malloc(sizeof(*source)); + source->parent = NULL; + source->previous = source->next = NULL; + source->includes = NULL; + source->system = false; + source->path = path; + source->file = file; + pstate->sources = source; + /* populate first source file */ + pstate->scanner.position.source = source; + pstate->scanner.position.file = (const idl_file_t *)file; + pstate->scanner.position.line = 1; + pstate->scanner.position.column = 1; + pstate->flags |= IDL_WRITE; + } + + if (config.preprocess) { + if (pstate) { + assert(config.compile); + pstate->flags |= IDL_WRITE; + } + mcpp_set_out_func(&idlc_putc, &idlc_puts, &idlc_printf); + if (mcpp_lib_main(config.argc, config.argv) == 0) { + assert(!config.compile || retcode == IDL_RETCODE_OK); + } else if (config.compile) { + assert(retcode != IDL_RETCODE_OK); + ret = retcode; + } + if (pstate) { + pstate->flags &= ~IDL_WRITE; + } + } else { + FILE *fin = NULL; + char buf[1024]; + size_t nrd; + int nwr; + + if (strcmp(config.file, "-") == 0) { + fin = stdin; + } else { +#if _WIN32 + fopen_s(&fin, config.file, "rb"); +#else + fin = fopen(config.file, "rb"); +#endif + } + + if (!fin) { + if (errno == ENOMEM) + ret = IDL_RETCODE_NO_MEMORY; + else if (errno == EACCES) + ret = IDL_RETCODE_NO_ACCESS; + else + ret = IDL_RETCODE_NO_ENTRY; + } else { + while ((nrd = fread(buf, sizeof(buf), 1, fin)) > 0) { + if ((nwr = idlc_putn(buf, nrd)) == -1) { + ret = retcode; + assert(ret != 0); + } + assert(nrd == (size_t)nwr); + } + if (fin != stdin) + fclose(fin); + } + } + + if (ret == IDL_RETCODE_OK && config.compile) { + ret = idl_parse(pstate); + assert(ret != IDL_RETCODE_NEED_REFILL); + if (ret == IDL_RETCODE_OK) { + if (config.keylist) { + pstate->flags |= IDL_FLAG_KEYLIST; + } else if (pstate->keylists && pstate->annotations) { + idl_warning(pstate, NULL, + "Translation unit contained both annotations and #pragma keylist " + "directives, annotations selected by default"); + } else if (pstate->keylists) { + pstate->flags |= IDL_FLAG_KEYLIST; + } + } + } + + return ret; +} + +#if 0 +static int set_debug(const idlc_option_t *opt, const char *optarg) +{ + (void)opt; + for (size_t off=0, pos=0; ; pos++) { + if (optarg[pos] == '\0' || optarg[pos] == ',') { + size_t len = pos - off; + if (strncmp(optarg + off, "preprocessor", len) == 0) + config.flags |= IDLC_DEBUG_PREPROCESSOR; + else if (strncmp(optarg + off, "scanner", len) == 0) + config.flags |= IDLC_DEBUG_SCANNER; + else if (strncmp(optarg + off, "parser", len) == 0) + config.flags |= IDLC_DEBUG_PARSER; + else if (len) + return IDLC_BAD_ARGUMENT; + if (optarg[pos] == '\0') + break; + off = pos + 1; + } + } + return 0; +} +#endif + +static int set_compile_only(const idlc_option_t *opt, const char *arg) +{ + (void)opt; + (void)arg; + config.compile = 1; + config.preprocess = 1; + return 0; +} + +static int set_preprocess_only(const idlc_option_t *opt, const char *arg) +{ + (void)opt; + (void)arg; + config.compile = 0; + config.preprocess = 1; + return 0; +} + +static int add_include(const idlc_option_t *opt, const char *arg) +{ + (void)opt; + config.argv[config.argc++] = "-I"; + config.argv[config.argc++] = (char*)arg; + return 0; +} + +static int add_macro(const idlc_option_t *opt, const char *arg) +{ + (void)opt; + config.argv[config.argc++] = "-D"; + config.argv[config.argc++] = (char*)arg; + return 0; +} + + /* FIXME: introduce compatibility options + * -e(xtension) with e.g. embedded-struct-def. The -e flags can also be used + * to enable/disable building blocks from IDL 4.x. + * -s with e.g. 3.5 and 4.0 to enable everything allowed in the specific IDL + * specification. + */ +static const idlc_option_t *compopts[] = { +#if 0 + &(idlc_option_t){ + IDLC_FUNCTION, { .function = &set_debug }, 'd', "", "", + "Display debug information for (s). Comma separate or use " + "more than one -d option to specify multiple components.\n" + "Components: preprocessor, scanner, parser." }, +#endif + &(idlc_option_t){ + IDLC_FUNCTION, { .function = &set_compile_only }, 'S', "", "", + "Compile only." }, + &(idlc_option_t){ + IDLC_FUNCTION, { .function = &set_preprocess_only }, 'E', "", NULL, + "Preprocess only."}, + &(idlc_option_t){ + IDLC_FLAG, { .flag = &config.keylist }, 'f', "keylist", "", + "Force use of #pragma keylist directive even if annotations occur " + "in the translation unit." }, + &(idlc_option_t){ + IDLC_FLAG, { .flag = &config.case_sensitive }, 'f', "case-sensitive", "", + "Switch to case-sensitive mode of operation. e.g. to allow constructed " + "entities to contain fields that differ only in case." }, + &(idlc_option_t){ + IDLC_FLAG, { .flag = &config.help }, 'h', "", "", + "Display available options." }, + &(idlc_option_t){ + IDLC_FUNCTION, { .function = &add_include }, 'I', "", "", + "Add to include search list." }, + &(idlc_option_t){ + IDLC_FUNCTION, { .function = &add_macro }, 'D', "", "[=value]", + "Define to (default:1)." }, + &(idlc_option_t){ + IDLC_STRING, { .string = &config.lang }, 'l', "", "", + "Compile representation for . (default:c)." }, + &(idlc_option_t){ + IDLC_FLAG, { .flag = &config.version }, 'v', "", "", + "Display version information." }, + NULL +}; + +static void print_version(const char *prog) +{ + printf("%s (Eclipse Cyclone DDS) %s\n", prog, IDL_VERSION); +} + +static const char *figure_language(int argc, char **argv) +{ + const char *lang = "c"; + + for (int i=1; i < argc; ) { + if (argv[i][0] != '-' || argv[i][1] == '\0') + break; + if (strcmp(argv[i], "--") == 0) + break; + if (argv[i][1] == 'l') { + if (argv[i][2] != '\0') + lang = &argv[i][2]; + else if (++i < argc) + lang = &argv[i][0]; + break; + } else if (argv[i++][2] == '\0') { + /* assume argument if not option */ + i += (i < argc && argv[i][0] != '-'); + } + } + + return lang; +} + +#define xstr(s) str(s) +#define str(s) #s + +int main(int argc, char *argv[]) +{ + int exit_code = EXIT_FAILURE; + const char *prog = argv[0]; + const char *lang; + idlc_generator_plugin_t gen; + idlc_option_t **opts = NULL; + const idlc_option_t **genopts = NULL; + size_t nopts = 0, ncompopts = 0, ngenopts = 0; + + for (const char *sep = argv[0]; *sep; sep++) { + if (idl_isseparator(*sep)) + prog = sep + 1; + } + + config.compile = 1; + config.preprocess = 1; + + /* determine which generator to use */ + lang = figure_language(argc, argv); + memset(&gen, 0, sizeof(gen)); + if (idlc_load_generator(&gen, lang) == -1) + fprintf(stderr, "%s: cannot load generator %s\n", prog, lang); + + config.argc = 0; + if (!(config.argv = calloc((size_t)argc + 7, sizeof(config.argv[0])))) + goto err_argv; + + config.argv[config.argc++] = argv[0]; + config.argv[config.argc++] = "-C"; /* keep comments */ +#if 0 + config.argv[config.argc++] = "-I-"; /* unset system include directories */ +#endif + config.argv[config.argc++] = "-k"; /* keep white space as is */ + config.argv[config.argc++] = "-N"; /* unset predefined macros */ + /* define __IDLC__, __IDLC_MINOR__ and __IDLC_PATCHLEVEL__ so that sections + in a file can be enabled or disabled based on preprocessor macros */ + config.argv[config.argc++] = "-D__IDLC__=" xstr(IDL_VERSION_MAJOR); + config.argv[config.argc++] = "-D__IDLC_MINOR__=" xstr(IDL_VERSION_MINOR); + config.argv[config.argc++] = "-D__IDLC_PATCHLEVEL__=" xstr(IDL_VERSION_PATCH); + /* parse command line options */ + ncompopts = (sizeof(compopts)/sizeof(compopts[0])) - 1; + if (gen.generator_options) { + genopts = gen.generator_options(); + for (; genopts[ngenopts]; ngenopts++) ; + } + nopts = ncompopts + ngenopts; + if (!(opts = calloc(nopts + 1, sizeof(opts[0])))) + goto err_alloc_opts; + memcpy(opts, compopts, ncompopts * sizeof(opts[0])); + memcpy(opts+ncompopts, genopts, ngenopts * sizeof(opts[0])); + opts[nopts] = NULL; + + switch (parse_options(argc, argv, opts)) { + case 0: + break; + case IDLC_BAD_INPUT: + fprintf(stderr, "%s: conflicting options in generator %s\n", prog, lang); + /* fall through */ + default: + print_usage(prog, "[OPTIONS] FILE"); + goto err_parse_opts; + } + + if (config.help) { + print_help(prog, "[OPTIONS] FILE", opts); + } else if (config.version) { + print_version(prog); + } else { + idl_retcode_t ret; + if (optind != (argc - 1)) { + print_usage(prog, "[OPTIONS] FILE"); + goto err_parse_opts; + } + config.file = argv[optind]; + config.argv[config.argc++] = config.file; + if ((ret = idlc_parse())) { + fprintf(stderr, "Cannot parse '%s'\n", config.file); + goto err_parse; + } else if (config.compile) { + if (gen.generate) + ret = gen.generate(pstate); + idl_delete_pstate(pstate); + if (ret) { + fprintf(stderr, "Failed to compile '%s'\n", config.file); + goto err_generate; + } + } + } + + exit_code = EXIT_SUCCESS; +err_generate: +err_parse: +err_parse_opts: + free(opts); +err_alloc_opts: + free(config.argv); +err_argv: + return exit_code; +} diff --git a/src/tools/idlc/src/main.c b/src/tools/idlc/src/main.c deleted file mode 100644 index 50ae399f8a..0000000000 --- a/src/tools/idlc/src/main.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright(c) 2019 Jeroen Koekkoek - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dds/version.h" -#include "dds/ddsrt/attributes.h" -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/io.h" -#include "dds/ddsrt/string.h" -#include "dds/ddsrt/misc.h" -#include "dds/ddsts/typetree.h" - -#include "idl.h" -#include "mcpp_lib.h" -#include "mcpp_out.h" -#include "gen_c99.h" - -#define IDLC_PREPROCESS (1<<0) -#define IDLC_COMPILE (1<<1) -#define IDLC_DEBUG_PREPROCESSOR (1<<2) -#define IDLC_DEBUG_PROCESSOR (1<<3) -/* FIXME: make more granular. e.g. parsser, directive parser, scaner, etc */ - -typedef struct { - char *file; /* path of input file or "-" for STDIN */ - char *lang; - int flags; /* preprocess and/or compile */ - /* (emulated) command line options for mcpp */ - int argc; - char **argv; -} idlc_options_t; - -/* mcpp does not accept userdata */ -static int32_t retcode = 0; -static idlc_options_t opts; -static idl_processor_t proc; - -static int idlc_putc(int chr, OUTDEST od); -static int idlc_puts(const char *str, OUTDEST od) - ddsrt_nonnull((1)); -static int idlc_printf(OUTDEST od, const char *str, ...) - ddsrt_nonnull((2)) - ddsrt_attribute_format((printf, 2, 3)); -static int32_t idlc_parse(ddsts_type_t **typeptr); - -#define CHUNK (4096) - -static int idlc_putn(const char *str, size_t len) -{ - assert(proc.state & IDL_WRITE); - - /* tokenize to free up space */ - if ((proc.buffer.size - proc.buffer.used) <= len) { - if ((retcode = idl_parse(&proc)) == IDL_NEED_REFILL) - retcode = 0; - /* move non-tokenized data to start of buffer */ - proc.buffer.used = - (uintptr_t)proc.scanner.limit - (uintptr_t)proc.scanner.cursor; - memmove(proc.buffer.data, proc.scanner.cursor, proc.buffer.used); - proc.scanner.cursor = proc.buffer.data; - proc.scanner.limit = proc.scanner.cursor + proc.buffer.used; - } - - if (retcode != 0) - return -1; - - /* expand buffer if necessary */ - if ((proc.buffer.size - proc.buffer.used) <= len) { - size_t size = proc.buffer.size + (((len / CHUNK) + 1) * CHUNK); - char *buf = ddsrt_realloc(proc.buffer.data, size + 2 /* '\0' + '\0' */); - if (buf == NULL) { - retcode = IDL_MEMORY_EXHAUSTED; - return -1; - } - /* update scanner location */ - proc.scanner.cursor = buf + (proc.scanner.cursor - proc.buffer.data); - proc.scanner.limit = proc.scanner.cursor + proc.buffer.used; - /* update input buffer */ - proc.buffer.data = buf; - proc.buffer.size = size; - } - - /* write to buffer */ - memcpy(proc.buffer.data + proc.buffer.used, str, len); - proc.buffer.used += len; - assert(proc.buffer.used <= proc.buffer.size); - /* update scanner location */ - proc.scanner.limit = proc.buffer.data + proc.buffer.used; - - return 0; -} - -static int idlc_putc(int chr, OUTDEST od) -{ - int ret = -1; - char str[2] = { (char)chr, '\0' }; - - switch (od) { - case OUT: - if (!(opts.flags & IDLC_COMPILE)) - ret = printf("%c", chr); - else - ret = idlc_putn(str, 1); - break; - case ERR: - ret = fprintf(stderr, "%c", chr); - break; - case DBG: - if (opts.flags & IDLC_DEBUG_PREPROCESSOR) - ret = fprintf(stderr, "%c", chr); - break; - default: - assert(0); - break; - } - - return ret < 0 ? -1 : ret; -} - -static int idlc_puts(const char *str, OUTDEST od) -{ - int ret; - size_t len = strlen(str); - - assert(str != NULL); - assert(len <= INT_MAX); - ret = (int)len; - - switch (od) { - case OUT: - if (!(opts.flags & IDLC_COMPILE)) - ret = printf("%s", str); - else - ret = idlc_putn(str, len); - break; - case ERR: - ret = fprintf(stderr, "%s", str); - break; - case DBG: - if (opts.flags & IDLC_DEBUG_PREPROCESSOR) - ret = fprintf(stderr, "%s", str); - break; - default: - assert(0); - break; - } - - return ret < 0 ? -1 : ret; -} - -static int idlc_printf(OUTDEST od, const char *fmt, ...) -{ - int ret = -1; - char *str = NULL; - int len; - va_list ap; - - assert(fmt != NULL); - - va_start(ap, fmt); - if ((len = ddsrt_vasprintf(&str, fmt, ap)) < 0) { /* FIXME: optimize */ - retcode = IDL_MEMORY_EXHAUSTED; - return -1; - } - va_end(ap); - - switch (od) { - case OUT: - if (!(opts.flags & IDLC_COMPILE)) - ret = printf("%s", str); - else - ret = idlc_putn(str, (size_t)len); - break; - case ERR: - ret = fprintf(stderr, "%s", str); - break; - case DBG: - if (opts.flags & IDLC_DEBUG_PREPROCESSOR) - ret = fprintf(stderr, "%s", str); - break; - default: - assert(0); - break; - } - - ddsrt_free(str); - - return ret < 0 ? -1 : ret; -} - -int32_t idlc_parse(ddsts_type_t **typeptr) -{ - int32_t ret = 0; - - if(opts.flags & IDLC_COMPILE) { - if ((ret = idl_processor_init(&proc)) != 0) - return ret; - assert(opts.file); - if (strcmp(opts.file, "-") != 0) - proc.scanner.position.file = (const char *)opts.file; - proc.scanner.position.line = 1; - proc.scanner.position.column = 1; - } - - if (opts.flags & IDLC_PREPROCESS) { - proc.flags |= IDL_WRITE; - mcpp_set_out_func(&idlc_putc, &idlc_puts, &idlc_printf); - if (mcpp_lib_main(opts.argc, opts.argv) == 0) { - assert(!(opts.flags & IDLC_COMPILE) || retcode == 0); - } else if (opts.flags & IDLC_COMPILE) { - assert(retcode != 0); - ret = retcode; - } - proc.flags &= ~IDL_WRITE; - } else { - FILE *fin; - char buf[1024]; - size_t nrd; - int nwr; - - if (strcmp(opts.file, "-") == 0) { - fin = stdin; - } else { - DDSRT_WARNING_MSVC_OFF(4996) - fin = fopen(opts.file, "rb"); - DDSRT_WARNING_MSVC_ON(4996) - } - - if (fin == NULL) { - switch (errno) { - case ENOMEM: - ret = IDL_MEMORY_EXHAUSTED; - break; - default: - ret = IDL_READ_ERROR; - break; - } - } else { - while ((nrd = fread(buf, sizeof(buf), 1, fin)) > 0) { - if ((nwr = idlc_putn(buf, nrd)) == -1) { - ret = retcode; - assert(ret != 0); - } - assert(nrd == (size_t)nwr); - } - } - - if (fin != stdin) - fclose(fin); - } - - if (ret == 0 && (opts.flags & IDLC_COMPILE)) { - ret = idl_parse(&proc); - assert(ret != IDL_NEED_REFILL); - if (ret == 0) - *typeptr = ddsts_context_take_root_type(proc.context); - } - - idl_processor_fini(&proc); - - return ret; -} - -static void -usage(const char *prog) -{ - fprintf(stderr, "Usage: %s FILE\n", prog); -} - -static void -help(const char *prog) -{ - static const char fmt[] = -"Usage: %s [OPTIONS] FILE\n" -"Options:\n" -" -d Display debug information for (s)\n" -" Comma separate or use more than one -d option to\n" -" specify multiple components\n" -" Components: preprocessor, parser\n" -" -D [=value] Define to (default:1)\n" -" -E Preprocess only\n" -" -h Display available options\n" -" -I Add to include search list\n" -" -l Compile representation for \n" -" -S Compile only\n" -" -v Display version information\n"; - - printf(fmt, prog); -} - -static void -version(const char *prog) -{ - printf("%s (Eclipse Cyclone DDS) %s\n", prog, DDS_VERSION); -} - -int main(int argc, char *argv[]) -{ - int opt; - char *prog = argv[0]; - int32_t ret; - ddsts_type_t *root = NULL; - - /* determine basename */ - for (char *sep = argv[0]; *sep; sep++) { - if (*sep == '/' || *sep == '\\') { - prog = sep + 1; - } - } - - opts.file = "-"; /* default to STDIN */ - opts.flags = IDLC_PREPROCESS | IDLC_COMPILE; - opts.lang = "c"; - opts.argc = 0; - opts.argv = ddsrt_calloc((unsigned int)argc + 6, sizeof(char *)); - if (opts.argv == NULL) { - return EXIT_FAILURE; - } - - opts.argv[opts.argc++] = argv[0]; - opts.argv[opts.argc++] = "-C"; /* keep comments */ - opts.argv[opts.argc++] = "-I-"; /* unset system include directories */ - opts.argv[opts.argc++] = "-k"; /* keep white space as is */ - opts.argv[opts.argc++] = "-N"; /* unset predefined macros */ - /* FIXME: mcpp option -K embeds macro notifications into comments to allow - reconstruction of the original source position from the - preprocessed output */ - - /* parse command line options */ - while ((opt = getopt(argc, argv, "Cd:D:EhI:l:Sv")) != -1) { - switch (opt) { - case 'd': - { - char *tok, *str = optarg; - while ((tok = ddsrt_strsep(&str, ",")) != NULL) { - if (ddsrt_strcasecmp(tok, "preprocessor") == 0) { - opts.flags |= IDLC_DEBUG_PREPROCESSOR; - } else if (ddsrt_strcasecmp(tok, "parser") == 0) { - opts.flags |= IDLC_DEBUG_PROCESSOR; - } - } - } - break; - case 'D': - opts.argv[opts.argc++] = "-D"; - opts.argv[opts.argc++] = optarg; - break; - case 'E': - opts.flags &= ~IDLC_COMPILE; - opts.flags |= IDLC_PREPROCESS; - break; - case 'h': - help(prog); - exit(EXIT_SUCCESS); - case 'I': - opts.argv[opts.argc++] = "-I"; - opts.argv[opts.argc++] = optarg; - break; - case 'l': - opts.lang = optarg; - break; - case 'S': - opts.flags &= ~IDLC_PREPROCESS; - opts.flags |= IDLC_COMPILE; - break; - case 'v': - version(prog); - exit(EXIT_SUCCESS); - case '?': - usage(prog); - exit(EXIT_FAILURE); - } - } - - if (optind == argc) { /* default to STDIN */ - assert(opts.file != NULL); - assert(strcmp(opts.file, "-") == 0); - } else { - opts.file = argv[optind]; - } - - opts.argv[opts.argc++] = opts.file; - - if ((ret = idlc_parse(&root)) == 0 && (opts.flags & IDLC_COMPILE)) { - assert(root != NULL); - assert(ddsrt_strcasecmp(opts.lang, "c") == 0); - ddsts_generate_C99(opts.file, root); - ddsts_free_type(root); - } - - ddsrt_free(opts.argv); - - return EXIT_SUCCESS; -} diff --git a/src/tools/idlc/src/options.c b/src/tools/idlc/src/options.c new file mode 100644 index 0000000000..9be16a181f --- /dev/null +++ b/src/tools/idlc/src/options.c @@ -0,0 +1,292 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "idl/string.h" + +#include "config.h" +#include "options.h" +#if HAVE_GETOPT_H +# include +#else +# include "getopt.h" +#endif + +static void print_description (const char *desc, int indent, int init_indent, int maxwidth) +{ + int cindent = indent; + int pos = init_indent; + while (*desc) + { + if (*desc == '\n') + { + int n = (int)strspn (desc + 1, " "); + desc += 1 + n; + cindent = indent + n; + printf ("\n%*s", cindent, ""); + pos = cindent; + } + else + { + int n = (int)strcspn (desc, " \t\n"); + if (pos + n > maxwidth) + { + printf ("\n%*s", cindent, ""); + pos = cindent; + } + printf ("%*s%*.*s", (pos == cindent) ? 0 : 1, "", n, n, desc); + pos += n + ((pos == cindent) ? 0 : 1); + desc += n + (int)strspn (desc + n, " "); + } + while (*desc == '\t') + { + int n = 8 - (pos % 8); + desc++; + pos += printf ("%*.*s", n, n, ""); + cindent = pos; + } + } + printf ("\n"); +} + +static int ascending(const void *va, const void *vb) +{ + const idlc_option_t *const *const a = va; + const idlc_option_t *const *const b = vb; + int la = idl_tolower((*a)->option); + int lb = idl_tolower((*b)->option); + if (la != lb) + return la - lb; + if ((*a)->option != (*b)->option) + return la == (*a)->option ? -1 : 1; + if (!(*a)->suboption) + return !(*b)->suboption ? 0 : -1; + if (!(*b)->suboption) + return 1; + return idl_strcasecmp((*a)->suboption, (*b)->suboption); +} + +static int descending(const void *va, const void *vb) +{ + return -ascending(va, vb); +} + +static idlc_option_t **sort_options( + idlc_option_t **options, int(*cmp)(const void *, const void *)) +{ + size_t len; + idlc_option_t **vec; + + for (len=0; options[len]; len++) ; + if (!(vec = malloc((len+1) * sizeof(*vec)))) + return NULL; + memcpy(vec, options, len * sizeof(*vec)); + vec[len] = NULL; + qsort(vec, len, sizeof(*vec), cmp); + return vec; +} + +static bool isempty(const char *str) +{ + return !(str && *str); +} + +static int format_option( + char *str, size_t size, int indent, const idlc_option_t *option) +{ + int opt = option->option; + const char *arg = option->argument; + const char *subopt = option->suboption; + + if (!isempty(subopt) && !isempty(arg) && option->type) + return snprintf(str, size, "%-*s-%c %s=%s", indent, "", opt, subopt, arg); + if (!isempty(subopt)) + return snprintf(str, size, "%-*s-%c %s", indent, "", opt, subopt); + if (!isempty(option->argument) && option->type) + return snprintf(str, size, "%-*s-%c %s", indent, "", opt, arg); + return snprintf(str, size, "%-*s-%c", indent, "", opt); +} + +#define WIDTH (78) +#define INDENT (25) + +void print_help( + const char *argv0, const char *rest, idlc_option_t **options) +{ + idlc_option_t **opts; + printf("Usage: %s%s%s\n", argv0, rest ? " " : "", rest ? rest : ""); + if (!(opts = sort_options(options, &ascending))) + return; + printf("Options:\n"); + for (size_t i=0; opts[i]; i++) { + int cnt, off = INDENT; + char buf[WIDTH + 1]; + cnt = format_option(buf, sizeof(buf), 2, opts[i]); + if (cnt <= off) + printf("%-*s", off, buf); + else + printf("%s\n%*s", buf, off, ""); + print_description(opts[i]->help, off, off, WIDTH); + } + free(opts); +} + +void print_usage( + const char *argv0, const char *rest) +{ + fprintf(stderr, "Usage: %s%s%s\n", argv0, rest ? " " : "", rest ? rest : ""); + fprintf(stderr, "Try '%s -h' for more information.\n", argv0); +} + +static void print_error( + const char *argv0, const char *errstr, char opt, const char *subopt) +{ + if (!isempty(subopt)) { + int len = (int)strcspn(subopt, "="); + fprintf(stderr,"%s%s%c %.*s\n",argv0, errstr, opt, len, subopt); + } else { + fprintf(stderr,"%s%s%c\n",argv0, errstr, opt); + } +} + +static int matches_option( + int opt, const char *arg, const idlc_option_t *option) +{ + char chr; + size_t len; + + if (option->option != opt) + return -1; + if (!option->suboption || !*option->suboption) + return 0; + len = strlen(option->suboption); + if (!arg || strncmp(option->suboption, arg, len) != 0) + return -1; + chr = option->type ? '=' : '\0'; + return arg[len] == chr ? (int)len + (chr == '=') : -1; +} + +static int handle_option( + int opt, const char *arg, const idlc_option_t *option) +{ + (void)opt; + switch (option->type) { + case IDLC_FLAG: + *option->store.flag = 1; + break; + case IDLC_STRING: + *option->store.string = arg; + break; + case IDLC_FUNCTION: + return (option->store.function)(option, arg); + } + return 0; +} + +static int handle_options( + int argc, char **argv, const char *optstr, idlc_option_t **options) +{ + int opt, off, ret; + + while ((opt = getopt(argc, argv, optstr)) != EOF) { + size_t i; + if (opt == '?') + return IDLC_BAD_OPTION; + if (opt == ':') + return IDLC_NO_ARGUMENT; + for (i=0; options[i]; i++) { + if ((off = matches_option(opt, optarg, options[i])) == -1) + continue; + assert(off >= 0); + assert(optarg || off == 0); + if (!(ret = handle_option(opt, optarg+off, options[i]))) + break; + else if (ret == IDLC_NO_ARGUMENT) + print_error(argv[0], ": option requires an argument -- ", (char)opt, optarg); + else if (ret == IDLC_BAD_ARGUMENT) + print_error(argv[0], ": illegal argument -- ", (char)opt, optarg); + return ret; + } + if (options[i]) + continue; + print_error(argv[0], ": illegal option -- ", (char)opt, optarg); + return IDLC_BAD_OPTION; + } + return 0; +} + +static int make_optstring(idlc_option_t **options, char **optstrp) +{ + char *str; + unsigned char opt, seen[256], expect; + size_t len = 0, pos = 0; + + memset(seen, 0, sizeof(seen)); + for (size_t i=0; options[i]; i++) { + opt = (unsigned char)options[i]->option; + expect = 1; + if (!isempty(options[i]->suboption)) + expect = 2; + else if (options[i]->type && options[i]->argument) + expect = 3; + if (!seen[opt]) + seen[opt] = expect; + else if (seen[opt] != expect) + return IDLC_BAD_INPUT; + len += (size_t)(1 + (expect > 1)); + } + if (seen['h'] != 1) /* -h is required and cannot have suboptions */ + return IDLC_BAD_INPUT; + if (!(str = calloc(len + 1, sizeof(*str)))) + return IDLC_NO_MEMORY; + memset(seen, 0, sizeof(seen)); + for (size_t i=0; options[i]; i++) { + opt = (unsigned char)options[i]->option; + if (seen[opt]) + continue; + str[pos++] = options[i]->option; + if (!isempty(options[i]->suboption)) + str[pos++] = ':'; + else if (options[i]->type && options[i]->argument) + str[pos++] = ':'; + seen[opt] = 1; + } + str[pos] = '\0'; + *optstrp = str; + return 0; +} + +int parse_options( + int argc, char **argv, idlc_option_t **options) +{ + int ret = IDLC_NO_MEMORY; + char *optstr = NULL; + idlc_option_t **opts = NULL; + + if ((ret = make_optstring(options, &optstr))) + goto err_optstr; + /* order is important if the same flag is used for options with and + without suboptions. e.g. "-o" and "-o subopt". if the option with no + suboption is encountered first, options with suboptions are never + triggered */ + if (!(opts = sort_options(options, &descending))) + goto err_sort; + ret = handle_options(argc, argv, optstr, opts); + free(opts); +err_sort: + free(optstr); +err_optstr: + return ret; +} diff --git a/src/tools/idlc/src/options.h b/src/tools/idlc/src/options.h new file mode 100644 index 0000000000..6b63289697 --- /dev/null +++ b/src/tools/idlc/src/options.h @@ -0,0 +1,23 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef OPTIONS_H +#define OPTIONS_H + +#include "idlc/options.h" + +#define IDLC_BAD_INPUT (-5) /**< conflicting options or missing "-h" */ + +int parse_options(int argc, char **argv, idlc_option_t **options); +void print_help(const char *argv0, const char *rest, idlc_option_t **options); +void print_usage(const char *argv0, const char *rest); + +#endif /* OPTIONS_H */ diff --git a/src/tools/idlc/src/parser.y b/src/tools/idlc/src/parser.y deleted file mode 100644 index 1206c9cef4..0000000000 --- a/src/tools/idlc/src/parser.y +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -%{ -#include -#include -#include -#include - -#if defined(__GNUC__) -_Pragma("GCC diagnostic push") -_Pragma("GCC diagnostic ignored \"-Wconversion\"") -_Pragma("GCC diagnostic push") -_Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") -_Pragma("GCC diagnostic push") -_Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") -#endif - -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/misc.h" -#include "dds/ddsrt/string.h" -#include "dds/ddsts/typetree.h" - -#include "idl.h" -#include "tt_create.h" - -#if defined(__GNUC__) -_Pragma("GCC diagnostic push") -_Pragma("GCC diagnostic ignored \"-Wconversion\"") -_Pragma("GCC diagnostic push") -_Pragma("GCC diagnostic ignored \"-Wsign-conversion\"") -#endif - -static void yyerror(idl_location_t *loc, idl_processor_t *proc, const char *); -%} - -%code provides { -int idl_istoken(const char *str, int nc); -} - -%code requires { - -/* convenience macro to complement YYABORT */ -#define ABORT(proc, loc, ...) \ - do { idl_error(proc, loc, __VA_ARGS__); YYABORT; } while(0) -#define EXHAUSTED \ - do { goto yyexhaustedlab; } while (0) - -/* Make yytoknum available */ -#define YYPRINT(A,B,C) YYUSE(A) -/* Use YYLTYPE definition below */ -#define IDL_YYLTYPE_IS_DECLARED - -#define YYSTYPE IDL_YYSTYPE -#define YYLTYPE IDL_YYLTYPE - -typedef struct idl_location YYLTYPE; - -#define YYLLOC_DEFAULT(Cur, Rhs, N) \ - do { \ - if (N) { \ - (Cur).first.file = YYRHSLOC(Rhs, 1).first.file; \ - (Cur).first.line = YYRHSLOC(Rhs, 1).first.line; \ - (Cur).first.column = YYRHSLOC(Rhs, 1).first.column; \ - } else { \ - (Cur).first.file = YYRHSLOC(Rhs, 0).last.file; \ - (Cur).first.line = YYRHSLOC(Rhs, 0).last.line; \ - (Cur).first.column = YYRHSLOC(Rhs, 0).last.column; \ - } \ - (Cur).last.line = YYRHSLOC(Rhs, N).last.line; \ - (Cur).last.column = YYRHSLOC(Rhs, N).last.column; \ - } while (0) - -#define YYLLOC_INITIAL(Cur, File) \ - do { \ - (Cur).first.file = NULL; \ - (Cur).first.line = 0; \ - (Cur).first.column = 0; \ - (Cur).last.file = (File); \ - (Cur).last.line = 1; \ - (Cur).last.column = 1; \ - } while (0); -} - -%union { - ddsts_flags_t base_type_flags; - ddsts_type_t *type_ptr; - ddsts_literal_t literal; - ddsts_scoped_name_t *scoped_name; - ddsts_identifier_t identifier; - char *str; - long long llng; - unsigned long long ullng; -} - -%define api.pure true -%define api.prefix {idl_yy} -%define api.push-pull push -%define parse.trace - -%locations - -%param { idl_processor_t *proc } -%initial-action { YYLLOC_INITIAL(@$, proc->files ? proc->files->name : NULL); } - - -%token-table - -%start specification - -%token IDL_TOKEN_LINE_COMMENT -%token IDL_TOKEN_COMMENT - -%token IDL_TOKEN_PP_NUMBER -%token IDL_TOKEN_IDENTIFIER -%token IDL_TOKEN_CHAR_LITERAL -%token IDL_TOKEN_STRING_LITERAL -%token IDL_TOKEN_INTEGER_LITERAL - -%type - base_type_spec - switch_type_spec - floating_pt_type - integer_type - signed_int - signed_tiny_int - signed_short_int - signed_long_int - signed_longlong_int - unsigned_int - unsigned_tiny_int - unsigned_short_int - unsigned_long_int - unsigned_longlong_int - char_type - wide_char_type - boolean_type - octet_type - -%type - type_spec - simple_type_spec - template_type_spec - sequence_type - string_type - wide_string_type - fixed_pt_type - map_type - struct_type - struct_def - -%destructor { ddsts_free_type($$); } - -%type - scoped_name - at_scoped_name - -%destructor { ddsts_free_scoped_name($$); } - -%type - positive_int_const - literal - const_expr - -%destructor { ddsts_free_literal(&($$)); } - -%type - simple_declarator - identifier - -%token IDL_TOKEN_AT "@" - -/* scope operators, see idl.l for details */ -%token IDL_TOKEN_SCOPE -%token IDL_TOKEN_SCOPE_L -%token IDL_TOKEN_SCOPE_R -%token IDL_TOKEN_SCOPE_LR - -/* keywords */ -%token IDL_TOKEN_MODULE "module" -%token IDL_TOKEN_CONST "const" -%token IDL_TOKEN_NATIVE "native" -%token IDL_TOKEN_STRUCT "struct" -%token IDL_TOKEN_TYPEDEF "typedef" -%token IDL_TOKEN_UNION "union" -%token IDL_TOKEN_SWITCH "switch" -%token IDL_TOKEN_CASE "case" -%token IDL_TOKEN_DEFAULT "default" -%token IDL_TOKEN_ENUM "enum" -%token IDL_TOKEN_UNSIGNED "unsigned" -%token IDL_TOKEN_FIXED "fixed" -%token IDL_TOKEN_SEQUENCE "sequence" -%token IDL_TOKEN_STRING "string" -%token IDL_TOKEN_WSTRING "wstring" - -%token IDL_TOKEN_FLOAT "float" -%token IDL_TOKEN_DOUBLE "double" -%token IDL_TOKEN_SHORT "short" -%token IDL_TOKEN_LONG "long" -%token IDL_TOKEN_CHAR "char" -%token IDL_TOKEN_WCHAR "wchar" -%token IDL_TOKEN_BOOLEAN "boolean" -%token IDL_TOKEN_OCTET "octet" -%token IDL_TOKEN_ANY "any" - -%token IDL_TOKEN_MAP "map" -%token IDL_TOKEN_BITSET "bitset" -%token IDL_TOKEN_BITFIELD "bitfield" -%token IDL_TOKEN_BITMASK "bitmask" - -%token IDL_TOKEN_INT8 "int8" -%token IDL_TOKEN_INT16 "int16" -%token IDL_TOKEN_INT32 "int32" -%token IDL_TOKEN_INT64 "int64" -%token IDL_TOKEN_UINT8 "uint8" -%token IDL_TOKEN_UINT16 "uint16" -%token IDL_TOKEN_UINT32 "uint32" -%token IDL_TOKEN_UINT64 "uint64" - -%% - -/* Constant Declaration */ - -specification: - definitions - { ddsts_accept(proc->context); YYACCEPT; } - ; - -definitions: - definition definitions - | definition - ; - -definition: - module_dcl ';' - | type_dcl ';' - ; - -module_dcl: - "module" identifier - { - if (!ddsts_module_open(proc->context, $2)) { - EXHAUSTED; - } - } - '{' definitions '}' - { ddsts_module_close(proc->context); }; - -at_scoped_name: - identifier - { - if (!ddsts_new_scoped_name(proc->context, 0, false, $1, &($$))) { - EXHAUSTED; - } - } - | IDL_TOKEN_SCOPE_R identifier - { - if (!ddsts_new_scoped_name(proc->context, 0, true, $2, &($$))) { - EXHAUSTED; - } - } - | at_scoped_name IDL_TOKEN_SCOPE_LR identifier - { - if (!ddsts_new_scoped_name(proc->context, $1, false, $3, &($$))) { - EXHAUSTED; - } - } - ; - -scope: - IDL_TOKEN_SCOPE - | IDL_TOKEN_SCOPE_L - | IDL_TOKEN_SCOPE_R - | IDL_TOKEN_SCOPE_LR - ; - -scoped_name: - identifier - { - if (!ddsts_new_scoped_name(proc->context, 0, false, $1, &($$))) { - EXHAUSTED; - } - } - | scope identifier - { - if (!ddsts_new_scoped_name(proc->context, 0, true, $2, &($$))) { - EXHAUSTED; - } - } - | scoped_name scope identifier - { - if (!ddsts_new_scoped_name(proc->context, $1, false, $3, &($$))) { - EXHAUSTED; - } - } - ; - -const_expr: - literal - | '(' const_expr ')' - { $$ = $2; }; - -literal: - IDL_TOKEN_INTEGER_LITERAL - { $$.flags = DDSTS_INT64 | DDSTS_UNSIGNED; $$.value.ullng = $1; } - ; - -positive_int_const: - const_expr; - -type_dcl: - constr_type_dcl - ; - -type_spec: - simple_type_spec - ; - -simple_type_spec: - base_type_spec - { - if (!ddsts_new_base_type(proc->context, $1, &($$))) { - EXHAUSTED; - } - } - | scoped_name - { - ddsts_type_t *type = NULL; - if (!ddsts_get_type_from_scoped_name(proc->context, $1, &type)) { - ABORT(proc, &@1, "scoped name cannot be resolved"); - } - $$ = type; - } - ; - -base_type_spec: - integer_type - | floating_pt_type - | char_type - | wide_char_type - | boolean_type - | octet_type - ; - -/* Basic Types */ -floating_pt_type: - "float" { $$ = DDSTS_FLOAT; } - | "double" { $$ = DDSTS_DOUBLE; } - | "long" "double" { $$ = DDSTS_LONGDOUBLE; }; - -integer_type: - signed_int - | unsigned_int - ; - -signed_int: - "short" { $$ = DDSTS_INT16; } - | "long" { $$ = DDSTS_INT32; } - | "long" "long" { $$ = DDSTS_INT64; } - ; - -unsigned_int: - "unsigned" "short" { $$ = DDSTS_INT16 | DDSTS_UNSIGNED; } - | "unsigned" "long" { $$ = DDSTS_INT32 | DDSTS_UNSIGNED; } - | "unsigned" "long" "long" { $$ = DDSTS_INT64 | DDSTS_UNSIGNED; } - ; - -char_type: - "char" { $$ = DDSTS_CHAR; }; - -wide_char_type: - "wchar" { $$ = DDSTS_CHAR | DDSTS_WIDE; }; - -boolean_type: - "boolean" { $$ = DDSTS_BOOLEAN; }; - -octet_type: - "octet" { $$ = DDSTS_OCTET; }; - -template_type_spec: - sequence_type - | string_type - | wide_string_type - | fixed_pt_type - | struct_type - ; - -sequence_type: - "sequence" '<' type_spec ',' positive_int_const '>' - { - if (!ddsts_new_sequence(proc->context, $3, &($5), &($$))) { - EXHAUSTED; - } - } - | "sequence" '<' type_spec '>' - { - if (!ddsts_new_sequence_unbound(proc->context, $3, &($$))) { - EXHAUSTED; - } - } - ; - -string_type: - "string" '<' positive_int_const '>' - { - if (!ddsts_new_string(proc->context, &($3), &($$))) { - EXHAUSTED; - } - } - | "string" - { - if (!ddsts_new_string_unbound(proc->context, &($$))) { - EXHAUSTED; - } - } - ; - -wide_string_type: - "wstring" '<' positive_int_const '>' - { - if (!ddsts_new_wide_string(proc->context, &($3), &($$))) { - EXHAUSTED; - } - } - | "wstring" - { - if (!ddsts_new_wide_string_unbound(proc->context, &($$))) { - EXHAUSTED; - } - } - ; - -fixed_pt_type: - "fixed" '<' positive_int_const ',' positive_int_const '>' - { - if (!ddsts_new_fixed_pt(proc->context, &($3), &($5), &($$))) { - EXHAUSTED; - } - } - ; - -/* Annonimous struct extension: */ -struct_type: - "struct" '{' - { - if (!ddsts_add_struct_open(proc->context, NULL)) { - EXHAUSTED; - } - } - members '}' - { ddsts_struct_close(proc->context, &($$)); } - ; - -constr_type_dcl: - struct_dcl - | union_dcl - ; - -struct_dcl: - struct_def - | struct_forward_dcl - ; - -struct_def: - "struct" identifier '{' - { - if (!ddsts_add_struct_open(proc->context, $2)) { - EXHAUSTED; - } - } - members '}' - { ddsts_struct_close(proc->context, &($$)); } - ; -members: - member members - | member - ; - -member: - annotation_appls type_spec - { - if (!ddsts_add_struct_member(proc->context, &($2))) { - ABORT(proc, &@2, "forward struct used as type for member declaration"); - } - } - declarators ';' - { - ddsts_struct_member_close(proc->context); - } - | type_spec - { - if (!ddsts_add_struct_member(proc->context, &($1))) { - ABORT(proc, &@1, "forward struct used as type for member declaration"); - } - } - declarators ';' - { ddsts_struct_member_close(proc->context); } -/* Embedded struct extension: */ - | struct_def { ddsts_add_struct_member(proc->context, &($1)); } - declarators ';' - ; - -struct_forward_dcl: - "struct" identifier - { - if (!ddsts_add_struct_forward(proc->context, $2)) { - EXHAUSTED; - } - }; - -union_dcl: - union_def - | union_forward_dcl - ; - -union_def: - "union" identifier - { - if (!ddsts_add_union_open(proc->context, $2)) { - EXHAUSTED; - } - } - "switch" '(' switch_type_spec ')' - { - if (!ddsts_union_set_switch_type(proc->context, $6)) { - EXHAUSTED; - } - } - '{' switch_body '}' - { ddsts_union_close(proc->context); } - ; - -switch_type_spec: - integer_type - | char_type - | boolean_type - | scoped_name - { - ddsts_type_t *type = NULL; - if (!ddsts_get_type_from_scoped_name(proc->context, $1, &type)) { - ABORT(proc, &@1, "scoped name cannot be resolved"); - } - if (!(DDSTS_TYPE_OF(type) & DDSTS_BASIC_TYPES)) { - ABORT(proc, &@1, "scoped name does not resolve to a basic type"); - } - $$ = DDSTS_TYPE_OF(type); - } - ; - -switch_body: cases ; -cases: - case cases - | case - ; - -case: - case_labels element_spec ';' - ; - -case_labels: - case_label case_labels - | case_label - ; - -case_label: - "case" const_expr ':' - { - switch (ddsts_union_add_case_label(proc->context, &($2))) { - case DDS_RETCODE_OUT_OF_RESOURCES: - EXHAUSTED; - case DDS_RETCODE_OK: - break; - default: - YYABORT; - } - } - | "default" ':' - { - if (!ddsts_union_add_case_default(proc->context)) { - EXHAUSTED; - } - } - ; - -element_spec: - type_spec - { - if (!ddsts_union_add_element(proc->context, &($1))) { - EXHAUSTED; - } - } - declarator - ; - -union_forward_dcl: - "union" identifier - { - if (!ddsts_add_union_forward(proc->context, $2)) { - EXHAUSTED; - } - } - ; - -array_declarator: - identifier fixed_array_sizes - { - switch (ddsts_add_declarator(proc->context, $1)) { - case DDS_RETCODE_OUT_OF_RESOURCES: - EXHAUSTED; - case DDS_RETCODE_OK: - break; - default: - YYABORT; - } - } - ; - -fixed_array_sizes: - fixed_array_size fixed_array_sizes - | fixed_array_size - ; - -fixed_array_size: - '[' positive_int_const ']' - { - if (!ddsts_add_array_size(proc->context, &($2))) { - EXHAUSTED; - } - } - ; - -simple_declarator: identifier ; - -declarators: - declarator ',' declarators - | declarator - ; - -declarator: - simple_declarator - { - switch (ddsts_add_declarator(proc->context, $1)) { - case DDS_RETCODE_OUT_OF_RESOURCES: - EXHAUSTED; - case DDS_RETCODE_OK: - break; - default: - YYABORT; - } - }; - - -/* From Building Block Extended Data-Types: */ -struct_def: - "struct" identifier ':' scoped_name '{' - { - if (!ddsts_add_struct_extension_open(proc->context, $2, $4)) { - EXHAUSTED; - } - } - members '}' - { ddsts_struct_close(proc->context, &($$)); } - | "struct" identifier '{' - { - if (!ddsts_add_struct_open(proc->context, $2)) { - EXHAUSTED; - } - } - '}' - { ddsts_struct_empty_close(proc->context, &($$)); } - ; - -template_type_spec: - map_type - ; - -map_type: - "map" '<' type_spec ',' type_spec ',' positive_int_const '>' - { - if (!ddsts_new_map(proc->context, $3, $5, &($7), &($$))) { - EXHAUSTED; - } - } - | "map" '<' type_spec ',' type_spec '>' - { - if (!ddsts_new_map_unbound(proc->context, $3, $5, &($$))) { - EXHAUSTED; - } - } - ; - -signed_int: - signed_tiny_int - | signed_short_int - | signed_long_int - | signed_longlong_int - ; - -unsigned_int: - unsigned_tiny_int - | unsigned_short_int - | unsigned_long_int - | unsigned_longlong_int - ; - -signed_tiny_int: "int8" { $$ = DDSTS_INT8; }; -unsigned_tiny_int: "uint8" { $$ = DDSTS_INT8 | DDSTS_UNSIGNED; }; -signed_short_int: "int16" { $$ = DDSTS_INT16; }; -signed_long_int: "int32" { $$ = DDSTS_INT32; }; -signed_longlong_int: "int64" { $$ = DDSTS_INT64; }; -unsigned_short_int: "uint16" { $$ = DDSTS_INT16 | DDSTS_UNSIGNED; }; -unsigned_long_int: "uint32" { $$ = DDSTS_INT32 | DDSTS_UNSIGNED; }; -unsigned_longlong_int: "uint64" { $$ = DDSTS_INT64 | DDSTS_UNSIGNED; }; - -/* From Building Block Anonymous Types: */ -type_spec: template_type_spec ; -declarator: array_declarator ; - - -/* From Building Block Annotations (minimal for support of @key): */ - -annotation_appls: - annotation_appl annotation_appls - | annotation_appl - ; - -annotation_appl: - "@" at_scoped_name - { - if (!ddsts_add_annotation(proc->context, $2)) { - EXHAUSTED; - } - } - ; - -identifier: - IDL_TOKEN_IDENTIFIER - { - size_t off = 0; - if ($1[0] == '_') { - off = 1; - } else if (idl_istoken($1, 1)) { - ABORT(proc, &@1, "identifier '%s' collides with a keyword", $1); - } - if (!ddsts_context_copy_identifier(proc->context, $1 + off, &($$))) { - EXHAUSTED; - } - }; - -%% - -#if defined(__GNUC__) -_Pragma("GCC diagnostic pop") -_Pragma("GCC diagnostic pop") -#endif - -static void -yyerror(idl_location_t *loc, idl_processor_t *proc, const char *str) -{ - idl_error(proc, loc, str); -} - -int32_t idl_istoken(const char *str, int nc) -{ - size_t i, n; - int(*cmp)(const char *s1, const char *s2, size_t n); - - assert(str != NULL); - - cmp = (nc ? &ddsrt_strncasecmp : strncmp); - for (i = 0, n = strlen(str); i < YYNTOKENS; i++) { - if (yytname[i] != 0 - && yytname[i][ 0] == '"' - && cmp(yytname[i] + 1, str, n) == 0 - && yytname[i][n + 1] == '"' - && yytname[i][n + 2] == '\0') { - return yytoknum[i]; - } - } - - return 0; -} diff --git a/src/tools/idlc/src/plugin.c b/src/tools/idlc/src/plugin.c new file mode 100644 index 0000000000..184bb09e40 --- /dev/null +++ b/src/tools/idlc/src/plugin.c @@ -0,0 +1,136 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include + +#if WIN32 +#include +static const char sep[] = "/\\"; +static const char lib[] = ""; +static const char ext[] = "dll"; +#else +#include +static const char sep[] = "/"; +static const char lib[] = "lib"; +#if __APPLE__ +static const char ext[] = "dylib"; +#else +static const char ext[] = "so"; +#endif +#endif + +#include "plugin.h" +#include "idl/string.h" + +static size_t extlen = sizeof(ext) - 1; + +static void *openlib(const char *filename) +{ +#if WIN32 + return (void *)LoadLibrary(filename); +#else + return dlopen(filename, RTLD_GLOBAL | RTLD_NOW); +#endif +} + +static void closelib(void *handle) +{ +#if WIN32 + (void)FreeLibrary((HMODULE)handle); +#else + (void)dlclose(handle); +#endif +} + +static void *loadsym(void *handle, const char *symbol) +{ +#if WIN32 + return (void *)GetProcAddress((HMODULE)handle, symbol); +#else + return dlsym(handle, symbol); +#endif +} + +extern int idlc_generate(const idl_pstate_t *pstate); + +int32_t +idlc_load_generator(idlc_generator_plugin_t *plugin, const char *lang) +{ + char buf[64], *file = NULL; + const char *path; + size_t len = strlen(lang); + void *handle = NULL; + idlc_generate_t generate = 0; + + /* short-circuit on builtin generator */ + if (idl_strcasecmp(lang, "C") == 0) { + plugin->handle = NULL; + plugin->generator_options = 0; + plugin->generator_annotations = 0; + plugin->generate = &idlc_generate; + return 0; + } + + /* figure out if user passed library or language */ + if ((sep[0] && strchr(lang, sep[0])) || (sep[1] && strchr(lang, sep[1]))) { + path = lang; + } else if (len > extlen && strcmp(lang + (len - extlen), ext) == 0) { + path = lang; + } else { + int cnt; + const char fmt[] = "%sidl%s.%s"; + cnt = snprintf(buf, sizeof(buf), fmt, lib, lang, ext); + assert(cnt != -1); + if ((size_t)cnt <= sizeof(buf)) { + path = (const char *)buf; + } else if (!(file = malloc((size_t)cnt+1))) { + return -1; + } else { + cnt = snprintf(file, (size_t)cnt+1, fmt, lib, lang, ext); + assert(cnt != -1); + path = (const char *)file; + } + } + + if ((handle = openlib(path)) || (lang != path && (handle = openlib(lang)))) { + generate = loadsym(handle, "generate"); + if (generate) { + plugin->handle = handle; + plugin->generate = generate; + plugin->generator_options = loadsym(handle, "generator_options"); + plugin->generator_annotations = loadsym(handle, "generator_annotations"); + } else { + closelib(handle); + } + } + + if (file) { + free(file); + } + + return (handle && generate) ? 0 : -1; +} + +void idlc_unload_generator(idlc_generator_plugin_t *plugin) +{ + if (!plugin || !plugin->handle) + return; + closelib(plugin->handle); + plugin->handle = NULL; + plugin->generator_options = 0; + plugin->generator_annotations = 0; + plugin->generate = 0; +} diff --git a/src/tools/idlc/src/plugin.h b/src/tools/idlc/src/plugin.h new file mode 100644 index 0000000000..f235ca2c8e --- /dev/null +++ b/src/tools/idlc/src/plugin.h @@ -0,0 +1,28 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef PLUGIN_H +#define PLUGIN_H + +#include "idlc/generator.h" + +typedef struct idlc_generator_plugin idlc_generator_plugin_t; +struct idlc_generator_plugin { + void *handle; + idlc_generator_options_t generator_options; /* optional */ + idlc_generator_annotations_t generator_annotations; /* optional */ + idlc_generate_t generate; +}; + +int idlc_load_generator(idlc_generator_plugin_t *gen, const char *lang); +void idlc_unload_generator(idlc_generator_plugin_t *gen); + +#endif /* PLUGIN_H */ diff --git a/src/tools/idlc/src/scanner.c b/src/tools/idlc/src/scanner.c deleted file mode 100644 index 3661077950..0000000000 --- a/src/tools/idlc/src/scanner.c +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Copyright(c) 2020 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include -#include -#include -#include -#include - -#include "idl.h" -#include "parser.h" /* Bison tokens */ - -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/string.h" -#include "dds/ddsrt/strtol.h" - -/* treat every cr+lf, lf+cr, cr, lf sequence as a single newline */ -static int32_t -have_newline(idl_processor_t *proc, const char *cur) -{ - if (cur == proc->scanner.limit) - return proc->flags & IDL_WRITE ? -2 : 0; - assert(cur < proc->scanner.limit); - if (cur[0] == '\n') { - if (cur < proc->scanner.limit - 1) - return cur[1] == '\r' ? 2 : 1; - return proc->flags & IDL_WRITE ? -1 : 1; - } else if (cur[0] == '\r') { - if (cur < proc->scanner.limit - 1) - return cur[1] == '\n' ? 2 : 1; - return proc->flags & IDL_WRITE ? -1 : 1; - } - return 0; -} - -static int32_t -have_skip(idl_processor_t *proc, const char *cur) -{ - int cnt = 0; - if (cur == proc->scanner.limit) - return proc->flags & IDL_WRITE ? -3 : 0; - assert(cur < proc->scanner.limit); - if (*cur == '\\' && (cnt = have_newline(proc, cur + 1)) > 0) - cnt++; - return cnt; -} - -static int32_t -have_space(idl_processor_t *proc, const char *cur) -{ - if (cur == proc->scanner.limit) - return proc->flags & IDL_WRITE ? -2 : 0; - assert(cur < proc->scanner.limit); - if (*cur == ' ' || *cur == '\t' || *cur == '\f' || *cur == '\v') - return 1; - return have_newline(proc, cur); -} - -static int32_t -have_digit(idl_processor_t *proc, const char *cur) -{ - if (cur == proc->scanner.limit) - return proc->flags & IDL_WRITE ? -1 : 0; - assert(cur < proc->scanner.limit); - return (*cur >= '0' && *cur <= '9'); -} - -static int32_t -have_alpha(idl_processor_t *proc, const char *cur) -{ - if (cur == proc->scanner.limit) - return proc->flags & IDL_WRITE ? -1 : 0; - assert(cur < proc->scanner.limit); - return (*cur >= 'a' && *cur <= 'z') || - (*cur >= 'A' && *cur <= 'Z') || - (*cur == '_'); -} - -static int32_t -have_alnum(idl_processor_t *proc, const char *cur) -{ - if (cur == proc->scanner.limit) - return proc->flags & IDL_WRITE ? -1 : 0; - assert(cur < proc->scanner.limit); - return (*cur >= 'a' && *cur <= 'z') || - (*cur >= 'A' && *cur <= 'Z') || - (*cur >= '0' && *cur <= '9') || - (*cur == '_'); -} - -static void -error(idl_processor_t *proc, const char *cur, const char *fmt, ...) -{ - int cnt; - const char *ptr = proc->scanner.cursor; - idl_location_t loc; - va_list ap; - - /* determine exact location */ - loc.first = proc->scanner.position; - loc.last = (idl_position_t){NULL, 0, 0}; - while (ptr < cur) { - if ((cnt = have_newline(proc, ptr)) > 0) { - loc.first.line++; - loc.first.column = 0; - ptr += cnt; - } else { - ptr++; - } - loc.first.column++; - } - - va_start(ap, fmt); - idl_verror(proc, &loc, fmt, ap); - va_end(ap); -} - -static const char * -next(idl_processor_t *proc, const char *cur) -{ - int cnt; - - /* might be positioned at newline */ - if ((cnt = have_newline(proc, cur))) { - if (cnt < 0) - return proc->scanner.limit; - cur += (size_t)cnt; - } else { - cur++; /* skip to next character */ - } - /* skip if positioned at line continuation sequence */ - for (; (cnt = have_skip(proc, cur)) > 0; cur += (size_t)cnt) ; - - return cnt < 0 ? proc->scanner.limit : cur; -} - -static const char * -move(idl_processor_t *proc, const char *cur) -{ - int cnt; - const char *ptr; - - assert(cur >= proc->scanner.cursor && cur <= proc->scanner.limit); - for (ptr = proc->scanner.cursor; ptr < cur; ptr += cnt) { - if ((cnt = have_newline(proc, ptr)) > 0) { - proc->scanner.position.line++; - proc->scanner.position.column = 1; - } else { - cnt = 1; - proc->scanner.position.column++; - } - } - proc->scanner.cursor = cur; - return cur; -} - -static int32_t -peek(idl_processor_t *proc, const char *cur) -{ - int cnt; - - /* skip if positioned at line continuation sequences */ - for (; (cnt = have_skip(proc, cur)) > 0; cur += cnt) ; - - if (cnt < 0 || cur == proc->scanner.limit) - return '\0'; - return *cur; -} - -static int32_t -have(idl_processor_t *proc, const char *cur, const char *str) -{ - int cnt; - size_t len, pos; - const char *lim = cur; - - for (pos = 0, len = strlen(str); pos < len; pos++, lim++) { - /* skip any line continuation sequences */ - while ((cnt = have_skip(proc, lim)) > 0) - lim += cnt; - if (cnt < 0) - return cnt - (int)(len - pos); - if (str[pos] != *lim) - return 0; - } - - return (int)(lim - cur); -} - -static int32_t -need_refill(idl_processor_t *proc, const char *cur) -{ - return have_skip(proc, cur) < 0; -} - -static int32_t -scan_line_comment(idl_processor_t *proc, const char *cur, const char **lim) -{ - int cnt = 0; - - cur = next(proc, cur); - while ((cur = next(proc, cur)) < proc->scanner.limit) { - if ((cnt = have_newline(proc, cur))) - break; - } - - if (need_refill(proc, cur)) - return IDL_NEED_REFILL; - *lim = cur; - return IDL_TOKEN_LINE_COMMENT; -} - -static int32_t -scan_comment(idl_processor_t *proc, const char *cur, const char **lim) -{ - enum { initial, escape, asterisk, slash } state = initial; - - cur = next(proc, cur); - while (state != slash && (cur = next(proc, cur)) < proc->scanner.limit) { - switch (state) { - case initial: - if (*cur == '\\') - state = escape; - else if (*cur == '*') - state = asterisk; - break; - case escape: - state = initial; - break; - case asterisk: - if (*cur == '\\') - state = escape; - else if (*cur == '/') - state = slash; - else if (*cur != '*') - state = initial; - break; - default: - assert(state == slash && false); - break; - } - } - - *lim = cur; - if (state == slash) { - assert(cur < proc->scanner.limit); - *lim = cur + 1; - return IDL_TOKEN_COMMENT; - } else if (need_refill(proc, cur)) { - return IDL_NEED_REFILL; - } - error(proc, cur, "unterminated comment"); - return IDL_SCAN_ERROR; -} - -static int -scan_quoted_literal( - idl_processor_t *proc, const char *cur, const char **lim, int quot) -{ - int cnt, esc = 0; - int code = quot == '"' ? IDL_TOKEN_STRING_LITERAL : IDL_TOKEN_CHAR_LITERAL; - const char *type = quot == '"' ? "string" : "char"; - - while ((cur = next(proc, cur)) < proc->scanner.limit) { - if (esc) { - esc = 0; - } else { - if (*cur == '\\') { - esc = 1; - } else if (*cur == quot) { - *lim = cur + 1; - return code; - } else if ((cnt = have_newline(proc, cur))) { - break; - } - } - } - - if (need_refill(proc, cur)) - return IDL_NEED_REFILL; - *lim = cur; - error(proc, cur, "unterminated %s literal", type); - return IDL_SCAN_ERROR; -} - -const char oct[] = "01234567"; -const char dec[] = "0123456789"; -const char hex[] = "0123456789abcdefABCDEF"; - -static int -scan_integer_literal(idl_processor_t *proc, const char *cur, const char **lim) -{ - int32_t chr = peek(proc, cur); - const char *base; - if (chr >= '1' && chr <= '9') { - base = dec; - } else { - assert(chr == '0'); - chr = peek(proc, next(proc, cur)); - if (chr == 'x' || chr == 'X') { - cur = next(proc, cur); /* skip x */ - base = hex; - } else { - base = oct; - } - } - - while ((cur = next(proc, cur)) < proc->scanner.limit) { - chr = peek(proc, cur); - if (!strchr(base, chr)) - break; - } - - if (need_refill(proc, cur)) - return IDL_NEED_REFILL; - *lim = cur; - return IDL_TOKEN_INTEGER_LITERAL; -} - -static int32_t -scan_pp_number(idl_processor_t *proc, const char *cur, const char **lim) -{ - int cnt; - - if (*cur == '.') - cur = next(proc, cur); - for (; (cur = next(proc, cur)) < proc->scanner.limit; cur += cnt) { - if ((cnt = have_digit(proc, cur)) <= 0) - break; - } - - if (need_refill(proc, cur)) - return IDL_NEED_REFILL; - *lim = cur; - return IDL_TOKEN_PP_NUMBER; -} - -static int32_t -scan_identifier(idl_processor_t *proc, const char *cur, const char **lim) -{ - int cnt = 0; - const char *end; - - for (end = cur; cur < proc->scanner.limit; end = cur) { - /* skip over any line continuation sequences */ - for (; (cnt = have_skip(proc, cur)) > 0; cur += cnt) ; - - if (cnt < 0 || cur == proc->scanner.limit) - break; - else if (*cur == '_') - cnt = 1; - else if ((cnt = have_alnum(proc, cur)) <= 0) - break; - cur += cnt; - } - - if (cnt < 0) - return IDL_NEED_REFILL; - /* detect if scope is attached to identifier if scanning code */ - if (((unsigned)proc->state & (unsigned)IDL_SCAN_CODE) && - (cnt = have(proc, cur, "::")) < 0) - return IDL_NEED_REFILL; - if (cnt > 0) - proc->state = IDL_SCAN_SCOPED_NAME; - *lim = end; - return IDL_TOKEN_IDENTIFIER; -} - -/* grammer for IDL (>=4.0) is incorrect (or at least ambiguous). blanks, - horizontal and vertical tabs, newlines, form feeds, and comments - (collective, "white space") are ignored except as they serve to separate - tokens. the specification does not clearly state if white space may occur - between "::" and adjacent identifiers to form a "scoped_name". the same is - true for the "annotation_appl". in C++ "::" is an operator and white space - is therefore allowed, in IDL it is not. this did not use to be a problem, - but with the addition of annotations it became possible to have two - adjacent scoped names. many compilers (probably) implement just the - standardized annotations. the pragmatic approach is to forbid use of white - space in annotations, which works for standardized annotations like "@key" - and allow use of white space for scoped names elsewhere. to implement this - feature the parser must know whether or not white space occurred between an - identifier and the scope operator. however, white space cannot be - communicated to the the parser (the grammer would explode) and an - introducing an extra identifier class is not an option (same reason). to - work around this problem, the lexer communicates different types of scope - operators used by the parser to implement a specialized "scoped_name" - version just for annotations. */ -static int32_t -scan_scope(idl_processor_t *proc, const char *cur, const char **lim) -{ - int cnt; - - cnt = have(proc, cur, "::"); - assert(cnt > 0); - - cur += cnt; - *lim = cur; - - /* skip over any line continuation sequences */ - for (; (cnt = have_skip(proc, cur)) > 0; cur += cnt) ; - - if (cnt < 0) - return IDL_NEED_REFILL; - - if ((*cur >= 'a' && *cur <= 'z') || - (*cur >= 'A' && *cur <= 'Z') || - (*cur == '_')) - { - if (proc->state == IDL_SCAN_SCOPED_NAME) - return IDL_TOKEN_SCOPE_LR; - else - return IDL_TOKEN_SCOPE_R; - } else { - if (proc->state == IDL_SCAN_SCOPED_NAME) - return IDL_TOKEN_SCOPE_L; - else - return IDL_TOKEN_SCOPE; - } -} - -int32_t -idl_lex(idl_processor_t *proc, idl_lexeme_t *lex) -{ - int chr, cnt, code = '\0'; - const char *cur, *lim = proc->scanner.cursor; - - do { - /* skip over any line continuation sequences */ - for (; (cnt = have_skip(proc, lim)) > 0; lim += cnt) ; - - move(proc, lim); - lex->location.first = proc->scanner.position; - lex->marker = cur = lim; - - if (need_refill(proc, lim)) - return IDL_NEED_REFILL; - - chr = peek(proc, cur); - if (chr == '\0') { - assert(cur == proc->scanner.limit); - break; - } else if (have(proc, cur, "/*") > 0) { - code = scan_comment(proc, cur, &lim); - } else if (have(proc, cur, "//") > 0) { - code = scan_line_comment(proc, cur, &lim); - } else if (chr == '\'' || chr == '\"') { - code = scan_quoted_literal(proc, cur, &lim, chr); - } else if ((cnt = have_newline(proc, cur)) > 0) { - lim = cur + cnt; - code = '\n'; - } else if ((cnt = have_space(proc, cur)) > 0) { - /* skip space characters, except newline */ - lim = cur + cnt; - } else if ((unsigned)proc->state & (unsigned)IDL_SCAN_DIRECTIVE) { - /* - * preprocessor - */ - if (chr == '.' && have_digit(proc, next(proc, cur))) { - code = scan_pp_number(proc, cur, &lim); - } else if ((cnt = have_alpha(proc, cur)) || chr == '_') { - code = scan_identifier(proc, cur, &lim); - } else if ((cnt = have_digit(proc, cur))) { - code = scan_pp_number(proc, cur, &lim); - } else { - lim = cur + 1; - code = (unsigned char)*cur; - } - } else if ((unsigned)proc->state & (unsigned)IDL_SCAN_CODE) { - /* - * interface definition language - */ - if (have_digit(proc, cur)) { - /* stroll takes care of decimal vs. octal vs. hexadecimal */ - code = scan_integer_literal(proc, cur, &lim); - } else if (have_alpha(proc, cur) || chr == '_') { - code = scan_identifier(proc, cur, &lim); - } else if ((cnt = have(proc, cur, "::")) > 0) { - code = scan_scope(proc, cur, &lim); - } else if (chr == '@') { - if ((cnt = have(proc, next(proc, cur), "::")) || - (cnt = have(proc, next(proc, cur), "_")) || - (cnt = have_alpha(proc, next(proc, cur)))) - code = cnt < 0 ? IDL_NEED_REFILL : IDL_TOKEN_AT; - else - code = (unsigned char)*cur; - lim = cur + 1; - } else { - lim = cur + 1; - code = (unsigned char)*cur; - } - } else if (chr == '#') { - proc->state = IDL_SCAN_DIRECTIVE; - lim = cur + 1; - code = (unsigned char)*cur; - } else { - proc->state = IDL_SCAN_CODE; - } - } while (code == '\0'); - - move(proc, lim); - lex->limit = lim; - lex->location.last = proc->scanner.position; - - if (proc->state == IDL_SCAN_SCOPED_NAME && code != IDL_TOKEN_IDENTIFIER) - proc->state = IDL_SCAN_CODE; - - return code; -} - -static int32_t -tokenize( - idl_processor_t *proc, idl_lexeme_t *lex, int32_t code, idl_token_t *tok) -{ - int cnt, quot = '\''; - char buf[32], *str = buf; - size_t len, pos = 0; - - if (code < 256) { - /* short circuit if token is a single character */ - tok->code = code; - tok->location = lex->location; - tok->value.chr = code; - return code; - } - len = (size_t)((uintptr_t)lex->limit - (uintptr_t)lex->marker); - if (len >= sizeof(buf) && !(str = ddsrt_malloc(len + 1))) - return IDL_MEMORY_EXHAUSTED; - - /* strip line continuation sequences */ - for (const char *ptr = lex->marker; ptr < lex->limit; ) { - if ((cnt = have_skip(proc, ptr)) > 0) { - ptr += cnt; - } else { - assert(cnt == 0); - str[pos++] = *ptr++; - } - } - assert(pos <= len); - len = pos; - str[pos] = '\0'; - - switch (code) { - case IDL_TOKEN_IDENTIFIER: - /* preprocessor identifiers are different from idl identifiers */ - if ((unsigned)proc->state & (unsigned)IDL_SCAN_DIRECTIVE) - break; - code = idl_istoken(str, 0); - if (code == 0) - code = IDL_TOKEN_IDENTIFIER; - break; - case IDL_TOKEN_STRING_LITERAL: - quot = '\"'; - /* fall through */ - case IDL_TOKEN_CHAR_LITERAL: - assert(str[0] == quot); - len -= 1 + (size_t)(str[len - 1] == quot); - memmove(str, str + 1, len); - str[len] = '\0'; - break; - case IDL_TOKEN_INTEGER_LITERAL: { - char *end = NULL; - ddsrt_strtoull(str, &end, 0, &tok->value.ullng); - assert(end && *end == '\0'); - } break; - default: - break; - } - - switch (code) { - case IDL_TOKEN_IDENTIFIER: - case IDL_TOKEN_PP_NUMBER: - case IDL_TOKEN_STRING_LITERAL: - case IDL_TOKEN_CHAR_LITERAL: - if (str == buf && !(str = ddsrt_strdup(str))) - return IDL_MEMORY_EXHAUSTED; - tok->value.str = str; - break; - default: - if (str != buf) - ddsrt_free(str); - break; - } - - tok->code = code; - tok->location = lex->location; - return tok->code; -} - -int32_t -idl_scan(idl_processor_t *proc, idl_token_t *tok) -{ - int code; - idl_lexeme_t lex; - - switch ((code = idl_lex(proc, &lex))) { - case IDL_NEED_REFILL: - case IDL_SCAN_ERROR: - return code; - default: - /* tokenize. sanitize by removing line continuation, etc */ - if ((code = tokenize(proc, &lex, code, tok)) == IDL_MEMORY_EXHAUSTED) { - /* revert state on memory allocation failure */ - proc->scanner.position = lex.location.first; - } - break; - } - - return code; -} diff --git a/src/tools/idlc/src/tt_create.c b/src/tools/idlc/src/tt_create.c deleted file mode 100644 index 682e982a00..0000000000 --- a/src/tools/idlc/src/tt_create.c +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include -#include -#include "dds/ddsrt/retcode.h" -#include "dds/ddsrt/heap.h" -#include "dds/ddsrt/string.h" -#include "dds/ddsrt/misc.h" -#include "dds/ddsrt/log.h" -#include "dds/ddsts/typetree.h" -#include "tt_create.h" - -typedef struct array_size array_size_t; -struct array_size { - unsigned long long size; - array_size_t *next; -}; - -typedef struct annotation annotation_t; -struct annotation { - ddsts_scoped_name_t *scoped_name; - annotation_t *next; -}; - -typedef struct annotations_stack annotations_stack_t; -struct annotations_stack { - annotation_t *annotations; - annotations_stack_t *deeper; -}; - -typedef struct pragma_arg pragma_arg_t; -struct pragma_arg { - ddsts_identifier_t arg; - pragma_arg_t *next; -}; - -struct ddsts_context { - ddsts_type_t *root_type; - ddsts_type_t *cur_type; - ddsts_type_t *type_for_declarator; - ddsts_union_case_label_t *union_case_labels; - bool union_case_default_label; - array_size_t *array_sizes; - annotations_stack_t *annotations_stack; - pragma_arg_t *pragma_args; - dds_return_t retcode; - bool semantic_error; - ddsts_identifier_t dangling_identifier; -}; - -extern bool ddsts_new_base_type(ddsts_context_t *context, ddsts_flags_t flags, ddsts_type_t **result) -{ - assert(context != NULL); - ddsts_type_t *base_type; - dds_return_t rc = ddsts_create_base_type(flags, &base_type); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - *result = base_type; - return true; -} - -static bool new_sequence(ddsts_context_t *context, ddsts_type_t *element_type, unsigned long long max, ddsts_type_t **result) -{ - assert(context != NULL); - ddsts_type_t *sequence; - dds_return_t rc = ddsts_create_sequence(element_type, max, &sequence); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - *result = sequence; - return true; -} - -extern bool ddsts_new_sequence(ddsts_context_t *context, ddsts_type_t *base, ddsts_literal_t *size, ddsts_type_t **result) -{ - assert(size->flags == (DDSTS_INT64 | DDSTS_UNSIGNED)); - return new_sequence(context, base, size->value.ullng, result); -} - -extern bool ddsts_new_sequence_unbound(ddsts_context_t *context, ddsts_type_t *base, ddsts_type_t **result) -{ - return new_sequence(context, base, 0ULL, result); -} - -static bool new_string(ddsts_context_t *context, ddsts_flags_t flags, unsigned long long max, ddsts_type_t **result) -{ - assert(context != NULL); - ddsts_type_t *string; - dds_return_t rc = ddsts_create_string(flags, max, &string); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - *result = string; - return true; -} - -extern bool ddsts_new_string(ddsts_context_t *context, ddsts_literal_t *size, ddsts_type_t **result) -{ - assert(size->flags == (DDSTS_INT64 | DDSTS_UNSIGNED)); - return new_string(context, DDSTS_STRING, size->value.ullng, result); -} - -extern bool ddsts_new_string_unbound(ddsts_context_t *context, ddsts_type_t **result) -{ - return new_string(context, DDSTS_STRING, 0ULL, result); -} - -extern bool ddsts_new_wide_string(ddsts_context_t *context, ddsts_literal_t *size, ddsts_type_t **result) -{ - assert(size->flags == (DDSTS_INT64 | DDSTS_UNSIGNED)); - return new_string(context, DDSTS_STRING | DDSTS_WIDE, size->value.ullng, result); -} - -extern bool ddsts_new_wide_string_unbound(ddsts_context_t *context, ddsts_type_t **result) -{ - return new_string(context, DDSTS_STRING | DDSTS_WIDE, 0ULL, result); -} - -extern bool ddsts_new_fixed_pt(ddsts_context_t *context, ddsts_literal_t *digits, ddsts_literal_t *fraction_digits, ddsts_type_t **result) -{ - assert(context != NULL); - assert(digits->flags == (DDSTS_INT64 | DDSTS_UNSIGNED)); - assert(fraction_digits->flags == (DDSTS_INT64 | DDSTS_UNSIGNED)); - ddsts_type_t *fixed_pt; - dds_return_t rc = ddsts_create_fixed_pt(digits->value.ullng, fraction_digits->value.ullng, &fixed_pt); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - *result = fixed_pt; - return true; -} - -static bool new_map(ddsts_context_t *context, ddsts_type_t *key_type, ddsts_type_t *value_type, unsigned long long max, ddsts_type_t **result) -{ - ddsts_type_t *map; - dds_return_t rc = ddsts_create_map(key_type, value_type, max, &map); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - *result = map; - return true; -} - -extern bool ddsts_new_map(ddsts_context_t *context, ddsts_type_t *key_type, ddsts_type_t *value_type, ddsts_literal_t *size, ddsts_type_t **result) -{ - assert(size->flags == (DDSTS_INT64 | DDSTS_UNSIGNED)); - return new_map(context, key_type, value_type, size->value.ullng, result); -} - -extern bool ddsts_new_map_unbound(ddsts_context_t *context, ddsts_type_t *key_type, ddsts_type_t *value_type, ddsts_type_t **result) -{ - return new_map(context, key_type, value_type, 0UL, result); -} - -struct ddsts_scoped_name { - ddsts_identifier_t name; - bool top; - ddsts_scoped_name_t *next; -}; - -extern bool ddsts_new_scoped_name(ddsts_context_t *context, ddsts_scoped_name_t* prev, bool top, ddsts_identifier_t name, ddsts_scoped_name_t **result) -{ - assert(context != NULL); - assert(context->dangling_identifier == name); - ddsts_scoped_name_t *scoped_name = (ddsts_scoped_name_t*)ddsrt_malloc(sizeof(ddsts_scoped_name_t)); - if (scoped_name == NULL) { - context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - return false; - } - context->dangling_identifier = NULL; - scoped_name->name = name; - scoped_name->top = top; - scoped_name->next = NULL; - if (prev == NULL) { - *result = scoped_name; - } - else { - ddsts_scoped_name_t **ref_scoped_name = &prev->next; - while (*ref_scoped_name != NULL) { - ref_scoped_name = &(*ref_scoped_name)->next; - } - *ref_scoped_name = scoped_name; - *result = prev; - } - return true; -} - -static bool resolve_scoped_name(ddsts_context_t *context, ddsts_scoped_name_t *scoped_name, ddsts_type_t **result) -{ - assert(context != NULL); - assert(scoped_name != NULL); - ddsts_type_t *cur_type = scoped_name->top ? context->root_type : context->cur_type; - for (; cur_type != NULL; cur_type = cur_type->type.parent) { - ddsts_type_t *found_type = cur_type; - ddsts_scoped_name_t *cur_scoped_name; - for (cur_scoped_name = scoped_name; cur_scoped_name != NULL && found_type != NULL; cur_scoped_name = cur_scoped_name->next) { - ddsts_type_t *child = NULL; - if (DDSTS_IS_TYPE(found_type, DDSTS_MODULE)) { - child = found_type->module.members.first; - } - else if (DDSTS_IS_TYPE(found_type, DDSTS_STRUCT)) { - child = found_type->struct_def.members.first; - } - found_type = NULL; - for (; child != NULL; child = child->type.next) { - if (DDSTS_IS_DEFINITION(child) && strcmp(child->type.name, cur_scoped_name->name) == 0) { - found_type = child; - break; - } - } - } - if (found_type != NULL) { - *result = found_type; - return true; - } - } - /* Could not resolve scoped name */ - //DDS_ERROR("Could not resolve scoped name\n"); - *result = NULL; - return false; -} - -extern void ddsts_free_scoped_name(ddsts_scoped_name_t *scoped_name) -{ - while (scoped_name != NULL) { - ddsts_scoped_name_t *next = scoped_name->next; - ddsrt_free(scoped_name->name); - ddsrt_free(scoped_name); - scoped_name = next; - } -} - -extern bool ddsts_get_type_from_scoped_name(ddsts_context_t *context, ddsts_scoped_name_t *scoped_name, ddsts_type_t **result) -{ - ddsts_type_t *definition = NULL; - if (!resolve_scoped_name(context, scoped_name, &definition)) { - ddsts_free_scoped_name(scoped_name); - return false; - } - ddsts_free_scoped_name(scoped_name); - *result = definition; - return true; -} - -extern bool ddsts_get_base_type_from_scoped_name(ddsts_context_t *context, ddsts_scoped_name_t *scoped_name, ddsts_flags_t *result) -{ - ddsts_type_t *type = NULL; - if (!ddsts_get_type_from_scoped_name(context, scoped_name, &type)) { - return false; - } - assert(type != NULL); - if ((DDSTS_TYPE_OF(type) & DDSTS_BASIC_TYPES) == 0) { - return false; - } - *result = DDSTS_TYPE_OF(type); - return true; -} - -static void scoped_name_dds_error(ddsts_scoped_name_t *scoped_name) -{ - if (scoped_name == NULL) { - return; - } - bool collon = scoped_name->top; - for (; scoped_name != NULL; scoped_name = scoped_name->next) { - if (collon) { - DDS_ERROR("::"); - } - DDS_ERROR("%s", scoped_name->name); - collon = true; - } -} - -static bool new_module_definition(ddsts_context_t *context, ddsts_identifier_t name, ddsts_type_t *parent, ddsts_type_t **result) -{ - assert(context != NULL); - assert(context->dangling_identifier == name); - ddsts_type_t *module; - dds_return_t rc = ddsts_create_module(name, &module); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - context->dangling_identifier = NULL; - ddsts_module_add_member(parent, module); - *result = module; - return true; -} - -static bool context_push_annotations_stack(ddsts_context_t *context) -{ - annotations_stack_t *annotations_stack = (annotations_stack_t*)ddsrt_malloc(sizeof(annotations_stack_t)); - if (annotations_stack == NULL) { - return false; - } - annotations_stack->annotations = NULL; - annotations_stack->deeper = context->annotations_stack; - context->annotations_stack = annotations_stack; - return true; -} - -static void context_pop_annotations_stack(ddsts_context_t *context) -{ - assert(context->annotations_stack != NULL); - annotations_stack_t *annotations_stack = context->annotations_stack; - context->annotations_stack = annotations_stack->deeper; - assert(annotations_stack->annotations == NULL); - ddsrt_free(annotations_stack); -} - -extern ddsts_context_t* ddsts_create_context(void) -{ - ddsts_context_t *context = (ddsts_context_t*)ddsrt_malloc(sizeof(ddsts_context_t)); - if (context == NULL) { - return NULL; - } - context->dangling_identifier = NULL; - ddsts_type_t *module; - if (!new_module_definition(context, NULL, NULL, &module)) { - ddsrt_free(context); - return NULL; - } - context->root_type = module; - context->cur_type = context->root_type; - context->union_case_labels = NULL; - context->union_case_default_label = false; - context->type_for_declarator = NULL; - context->array_sizes = NULL; - context->annotations_stack = NULL; - if (!context_push_annotations_stack(context)) { - ddsts_free_type(module); - ddsrt_free(context); - return NULL; - } - context->pragma_args = NULL; - context->retcode = DDS_RETCODE_OK; - context->semantic_error = false; - return context; -} - -extern void ddsts_context_set_retcode(ddsts_context_t *context, dds_return_t retcode) -{ - assert(context != NULL); - context->retcode = retcode; -} - -extern dds_return_t ddsts_context_get_retcode(ddsts_context_t* context) -{ - assert(context != NULL); - if (context->retcode != DDS_RETCODE_OK) { - return context->retcode; - } else if (context->semantic_error) { - return DDS_RETCODE_ERROR; - } - return DDS_RETCODE_OK; -} - -extern ddsts_type_t* ddsts_context_take_root_type(ddsts_context_t *context) -{ - ddsts_type_t* result = context->root_type; - context->root_type = NULL; - return result; -} - -static void ddsts_context_free_array_sizes(ddsts_context_t *context) -{ - while (context->array_sizes != NULL) { - array_size_t *next = context->array_sizes->next; - ddsrt_free(context->array_sizes); - context->array_sizes = next; - } -} - -static void context_free_pragma_args(ddsts_context_t *context) -{ - pragma_arg_t *pragma_arg = context->pragma_args; - while (pragma_arg != NULL) { - pragma_arg_t *next = pragma_arg->next; - ddsrt_free(pragma_arg->arg); - ddsrt_free(pragma_arg); - pragma_arg = next; - } - context->pragma_args = NULL; -} - -static void context_free_annotations(ddsts_context_t *context) -{ - assert(context->annotations_stack != NULL); - annotation_t *annotation = context->annotations_stack->annotations; - while (annotation != NULL) { - annotation_t *next = annotation->next; - ddsts_free_scoped_name(annotation->scoped_name); - ddsrt_free(annotation); - annotation = next; - } - context->annotations_stack->annotations = NULL; -} - -static void ddsts_context_close_member(ddsts_context_t *context) -{ - ddsts_free_type(context->type_for_declarator); - context->type_for_declarator = NULL; - ddsts_context_free_array_sizes(context); -} - -extern void ddsts_free_context(ddsts_context_t *context) -{ - assert(context != NULL); - ddsts_context_close_member(context); - ddsts_free_union_case_labels(context->union_case_labels); - ddsts_free_type(context->root_type); - while (context->annotations_stack != NULL) { - context_free_annotations(context); - context_pop_annotations_stack(context); - } - context_free_pragma_args(context); - ddsrt_free(context->dangling_identifier); - ddsrt_free(context); -} - -bool ddsts_context_copy_identifier(ddsts_context_t *context, ddsts_identifier_t source, ddsts_identifier_t *dest) -{ - assert(context != NULL && source != NULL); - assert(context->dangling_identifier == NULL); - context->dangling_identifier = *dest = ddsrt_strdup(source); - if (context->dangling_identifier == NULL) { - context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - return false; - } - return true; -} - -#if (!defined(NDEBUG)) -static bool cur_scope_is_definition_type(ddsts_context_t *context, ddsts_flags_t flags) -{ - assert(context != NULL && context->cur_type != NULL); - return DDSTS_IS_TYPE(context->cur_type, flags); -} -#endif - -extern bool ddsts_module_open(ddsts_context_t *context, ddsts_identifier_t name) -{ - assert(cur_scope_is_definition_type(context, DDSTS_MODULE)); - ddsts_type_t *module; - if (!new_module_definition(context, name, context->cur_type, &module)) { - return false; - } - context->cur_type = module; - return true; -} - -extern void ddsts_module_close(ddsts_context_t *context) -{ - assert(cur_scope_is_definition_type(context, DDSTS_MODULE)); - assert(context->cur_type->type.parent != NULL); - context->cur_type = context->cur_type->type.parent; -} - -extern bool ddsts_add_struct_forward(ddsts_context_t *context, ddsts_identifier_t name) -{ - assert(cur_scope_is_definition_type(context, DDSTS_MODULE)); - assert(context->dangling_identifier == name); - ddsts_type_t *forward_dcl; - dds_return_t rc = ddsts_create_struct_forward_dcl(name, &forward_dcl); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - context->dangling_identifier = NULL; - ddsts_module_add_member(context->cur_type, forward_dcl); - return true; -} - -extern bool ddsts_add_struct_open(ddsts_context_t *context, ddsts_identifier_t name) -{ - assert( cur_scope_is_definition_type(context, DDSTS_MODULE) - || cur_scope_is_definition_type(context, DDSTS_STRUCT)); - assert(context->dangling_identifier == name); - ddsts_type_t *new_struct; - dds_return_t rc = ddsts_create_struct(name, &new_struct); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - context->dangling_identifier = NULL; - if (DDSTS_IS_TYPE(context->cur_type, DDSTS_MODULE)) { - ddsts_module_add_member(context->cur_type, new_struct); - } - else { - ddsts_struct_add_member(context->cur_type, new_struct); - } - context->cur_type = new_struct; - if (!context_push_annotations_stack(context)) { - return false; - } - return true; -} - -extern bool ddsts_add_struct_extension_open(ddsts_context_t *context, ddsts_identifier_t name, ddsts_scoped_name_t *scoped_name) -{ - assert(cur_scope_is_definition_type(context, DDSTS_MODULE)); - assert(context->dangling_identifier == name); - ddsts_type_t *new_struct; - dds_return_t rc = ddsts_create_struct(name, &new_struct); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - context->dangling_identifier = NULL; - ddsts_module_add_member(context->cur_type, new_struct); - /* find super */ - ddsts_type_t *definition; - if (!resolve_scoped_name(context, scoped_name, &definition)) { - DDS_ERROR("Could not resolve scoped name\n"); - ddsts_free_scoped_name(scoped_name); - return false; - } - ddsts_free_scoped_name(scoped_name); - if (definition != NULL && DDSTS_IS_TYPE(definition, DDSTS_STRUCT)) { - new_struct->struct_def.super = definition; - } - context->cur_type = new_struct; - return true; -} - -extern bool ddsts_add_struct_member(ddsts_context_t *context, ddsts_type_t **ref_type) -{ - assert(cur_scope_is_definition_type(context, DDSTS_STRUCT)); - ddsts_context_close_member(context); - ddsts_type_t *type = *ref_type; - if (DDSTS_IS_TYPE(type, DDSTS_FORWARD_STRUCT)) { - if (type->forward.definition == NULL) { - //DDS_ERROR("Cannot use forward struct as type for member declaration\n"); - context->semantic_error = true; - return false; - } - type = type->forward.definition; - } - context->type_for_declarator = type; - *ref_type = NULL; - return true; -} - -extern void ddsts_struct_member_close(ddsts_context_t *context) -{ - context_free_annotations(context); -} - -extern void ddsts_struct_close(ddsts_context_t *context, ddsts_type_t **result) -{ - assert(cur_scope_is_definition_type(context, DDSTS_STRUCT)); - ddsts_context_close_member(context); - *result = context->cur_type; - context->cur_type = context->cur_type->type.parent; - context_pop_annotations_stack(context); -} - -extern void ddsts_struct_empty_close(ddsts_context_t *context, ddsts_type_t **result) -{ - assert(cur_scope_is_definition_type(context, DDSTS_STRUCT)); - *result = context->cur_type; - context->cur_type = context->cur_type->type.parent; -} - -extern bool ddsts_add_union_forward(ddsts_context_t *context, ddsts_identifier_t name) -{ - assert(cur_scope_is_definition_type(context, DDSTS_MODULE)); - assert(context->dangling_identifier == name); - ddsts_type_t *forward_dcl; - dds_return_t rc = ddsts_create_union_forward_dcl(name, &forward_dcl); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - context->dangling_identifier = NULL; - ddsts_module_add_member(context->cur_type, forward_dcl); - return true; -} - -extern bool ddsts_add_union_open(ddsts_context_t *context, ddsts_identifier_t name) -{ - assert( cur_scope_is_definition_type(context, DDSTS_MODULE) - || cur_scope_is_definition_type(context, DDSTS_STRUCT)); - assert(context->dangling_identifier == name); - context->dangling_identifier = NULL; - ddsts_type_t *new_union; - dds_return_t rc = ddsts_create_union(name, DDSTS_NOTYPE, &new_union); - if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - return false; - } - context->dangling_identifier = NULL; - if (DDSTS_IS_TYPE(context->cur_type, DDSTS_MODULE)) { - ddsts_module_add_member(context->cur_type, new_union); - } - else { - ddsts_struct_add_member(context->cur_type, new_union); - } - context->cur_type = new_union; - if (!context_push_annotations_stack(context)) { - return false; - } - return true; -} - -extern bool ddsts_union_set_switch_type(ddsts_context_t *context, ddsts_flags_t base_type) -{ - assert(cur_scope_is_definition_type(context, DDSTS_UNION)); - context->cur_type->union_def.switch_type = base_type; - return true; -} - -static const char* name_of_type(ddsts_flags_t flags) -{ - switch(flags) { - case DDSTS_INT16: return "short"; break; - case DDSTS_INT32: return "long"; break; - case DDSTS_INT64: return "long long"; break; - case DDSTS_INT16 | DDSTS_UNSIGNED: return "unsigned short"; break; - case DDSTS_INT32 | DDSTS_UNSIGNED: return "unsigned long"; break; - case DDSTS_INT64 | DDSTS_UNSIGNED: return "unsigned long long"; break; - case DDSTS_CHAR: return "char"; break; - case DDSTS_CHAR | DDSTS_WIDE: return "wide char"; break; - case DDSTS_BOOLEAN: return "boolean"; break; - case DDSTS_OCTET: return "octet"; break; - case DDSTS_INT8: return "int8"; break; - case DDSTS_INT8 | DDSTS_UNSIGNED: return "uint8"; break; - case DDSTS_FLOAT: return "float"; break; - case DDSTS_DOUBLE: return "double"; break; - case DDSTS_LONGDOUBLE: return "long double"; break; - case DDSTS_FIXED_PT_CONST: return "fixed point const"; break; - case DDSTS_ANY: return "any"; - case DDSTS_SEQUENCE: return "sequence"; - case DDSTS_ARRAY: return "array"; - case DDSTS_STRING: return "string"; - case DDSTS_STRING | DDSTS_WIDE: return "wide string"; - case DDSTS_FIXED_PT: return "fixed point"; - case DDSTS_MAP: return "map"; - case DDSTS_MODULE: return "module"; - case DDSTS_FORWARD_STRUCT: return "forward struct"; - case DDSTS_STRUCT: return "struct"; - case DDSTS_FORWARD_UNION: return "forward union"; - case DDSTS_UNION: return "union"; - default: - assert(0); - break; - } - return ""; -} - -static dds_return_t cast_value_to_type(ddsts_literal_t *value, ddsts_flags_t flags, ddsts_literal_t *cast_type) -{ - switch (value->flags) { - case DDSTS_INT64 | DDSTS_UNSIGNED: - switch (flags) { - case DDSTS_OCTET: - case DDSTS_INT8 | DDSTS_UNSIGNED: - case DDSTS_INT16 | DDSTS_UNSIGNED: - case DDSTS_INT32 | DDSTS_UNSIGNED: - case DDSTS_INT64 | DDSTS_UNSIGNED: - cast_type->value.ullng = value->value.ullng; - cast_type->flags = flags; - return DDS_RETCODE_OK; - case DDSTS_INT8: - case DDSTS_INT16: - case DDSTS_INT32: - cast_type->value.llng = (signed long long)value->value.ullng; - cast_type->flags = flags; - return DDS_RETCODE_OK; - default: - DDS_ERROR("Cannot cast unsigned long long to %s\n", name_of_type(flags)); - return DDS_RETCODE_ERROR; - break; - } - break; - default: - assert(0); - break; - } - return DDS_RETCODE_ERROR; -} - -static bool equal_values(ddsts_literal_t *a, ddsts_literal_t *b) -{ - assert(a->flags == b->flags); - switch (a->flags) { - case DDSTS_OCTET: - case DDSTS_INT8 | DDSTS_UNSIGNED: - case DDSTS_INT16 | DDSTS_UNSIGNED: - case DDSTS_INT32 | DDSTS_UNSIGNED: - case DDSTS_INT64 | DDSTS_UNSIGNED: - return a->value.ullng == b->value.ullng; - break; - case DDSTS_INT8: - case DDSTS_INT16: - case DDSTS_INT32: - return a->value.llng == b->value.llng; - break; - default: - assert(0); - break; - } - return false; -} - -extern dds_return_t ddsts_union_add_case_label(ddsts_context_t *context, ddsts_literal_t *value) -{ - assert(cur_scope_is_definition_type(context, DDSTS_UNION)); - ddsts_literal_t casted_value; - dds_return_t rc = cast_value_to_type(value, context->cur_type->union_def.switch_type, &casted_value); - if (rc != DDS_RETCODE_OK) { - return context->retcode = rc; - } - for (ddsts_type_t *cases = context->cur_type->union_def.cases.first; cases != NULL; cases = cases->type.next) { - for (ddsts_union_case_label_t *label = cases->union_case.labels; label != NULL; label = label->next) { - if (equal_values(&label->value, &casted_value)) { - DDS_ERROR("Same case label used in more than one case.\n"); - return context->retcode = DDS_RETCODE_ERROR; - } - } - } - if (context->union_case_default_label) { - DDS_WARNING("Case label in combination with default is not useful.\n"); - } - ddsts_union_case_label_t **ref_label = &context->union_case_labels; - while (*ref_label != NULL) { - if (equal_values(&(*ref_label)->value, &casted_value)) { - DDS_WARNING("Label value in case is repeated. It is ignored.\n"); - return DDS_RETCODE_OK; - } - ref_label = &(*ref_label)->next; - } - *ref_label = (ddsts_union_case_label_t*)ddsrt_malloc(sizeof(ddsts_union_case_label_t)); - if (*ref_label == NULL) { - return context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - } - (*ref_label)->value = casted_value; - (*ref_label)->next = NULL; - return DDS_RETCODE_OK; -} - -extern bool ddsts_union_add_case_default(ddsts_context_t *context) -{ - for (ddsts_type_t *cases = context->cur_type->union_def.cases.first; cases != NULL; cases = cases->type.next) { - if (cases->union_case.default_label) { - DDS_ERROR("More than one default case is not allowed.\n"); - context->retcode = DDS_RETCODE_ERROR; - return false; - } - } - if (context->union_case_default_label) { - DDS_WARNING("Default is repeated.\n"); - } - if (context->union_case_labels != NULL) { - DDS_WARNING("Case label in combination with default is not usefull.\n"); - } - context->union_case_default_label = true; - return true; -} - -extern bool ddsts_union_add_element(ddsts_context_t *context, ddsts_type_t **type) -{ - assert(cur_scope_is_definition_type(context, DDSTS_UNION)); - ddsts_type_t *union_case; - dds_return_t rc = ddsts_union_add_case(context->cur_type, context->union_case_labels, context->union_case_default_label, &union_case); - if (rc != DDS_RETCODE_OK) { - ddsts_free_union_case_labels(context->union_case_labels); - context->union_case_labels = NULL; - context->union_case_default_label = false; - return false; - } - context->type_for_declarator = *type; - *type = NULL; - context->cur_type = union_case; - context->union_case_labels = NULL; - context->union_case_default_label = false; - return true; -} - -extern void ddsts_union_close(ddsts_context_t *context) -{ - assert(cur_scope_is_definition_type(context, DDSTS_UNION)); - context->cur_type = context->cur_type->type.parent; - context_pop_annotations_stack(context); -} - -static ddsts_type_t *create_array_type(array_size_t *array_size, ddsts_type_t *type) -{ - if (array_size == NULL) { - return type; - } - ddsts_type_t *array; - dds_return_t rc = ddsts_create_array(NULL, array_size->size, &array); - if (rc != DDS_RETCODE_OK) { - return NULL; - } - ddsts_type_t *element_type = create_array_type(array_size->next, type); - if (element_type == NULL) { - ddsts_free_type(array); - return NULL; - } - ddsts_array_set_element_type(array, element_type); - return array; -} - -static bool keyable_type(ddsts_type_t *type) -{ - bool is_array = false; - while (type != NULL && DDSTS_IS_TYPE(type, DDSTS_ARRAY)) { - type = type->array.element_type; - is_array = true; - } - if (type == NULL) { - return false; - } - if ( DDSTS_IS_TYPE(type, - DDSTS_INT16 | DDSTS_INT32 | DDSTS_INT64 | - DDSTS_CHAR | DDSTS_BOOLEAN | DDSTS_OCTET | - DDSTS_INT8 | DDSTS_FLOAT | DDSTS_DOUBLE) - || (DDSTS_IS_TYPE(type, DDSTS_STRING) && !is_array)) { - return true; - } - if (DDSTS_IS_TYPE(type, DDSTS_STRUCT)) { - if (type->struct_def.keys == NULL) { - /* All fields should be keyable */ - for (ddsts_type_t *member = type->struct_def.members.first; member != NULL; member = member->type.next) { - if (DDSTS_IS_TYPE(member, DDSTS_DECLARATION)) { - if (!keyable_type(member->declaration.decl_type)) { - return false; - } - } - } - } - return true; - } - return false; -} - -extern dds_return_t ddsts_add_declarator(ddsts_context_t *context, ddsts_identifier_t name) -{ - assert(context != NULL); - assert(context->dangling_identifier == name); - if (DDSTS_IS_TYPE(context->cur_type, DDSTS_STRUCT)) { - assert(context->type_for_declarator != NULL); - ddsts_type_t *decl = NULL; - dds_return_t rc; - rc = ddsts_create_declaration(name, NULL, &decl); - if (rc != DDS_RETCODE_OK) { - ddsts_context_free_array_sizes(context); - return context->retcode = rc; - } - context->dangling_identifier = NULL; - ddsts_type_t* type = create_array_type(context->array_sizes, context->type_for_declarator); - if (type == NULL) { - ddsts_context_free_array_sizes(context); - ddsts_free_type(decl); - return context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - } - ddsts_context_free_array_sizes(context); - ddsts_declaration_set_type(decl, type); - ddsts_struct_add_member(context->cur_type, decl); - /* Process annotations */ - assert(context->annotations_stack != NULL); - for (annotation_t *annotation = context->annotations_stack->annotations; annotation != NULL; annotation = annotation->next) { - if ( annotation->scoped_name != NULL - && !annotation->scoped_name->top - && strcmp(annotation->scoped_name->name, "key") == 0 - && annotation->scoped_name->next == NULL) { - if (keyable_type(type)) { - rc = ddsts_struct_add_key(context->cur_type, decl); - if (rc == DDS_RETCODE_ERROR) { - /* FIXME: does not return an error, so warning instead? */ - DDS_ERROR("Field '%s' already defined as key\n", name); - context->semantic_error = true; - return DDS_RETCODE_ERROR; - } - else if (rc != DDS_RETCODE_OK) { - ddsts_context_free_array_sizes(context); - return context->retcode = rc; - } - } - else { - DDS_ERROR("Type of '%s' is not valid for key\n", name); - context->semantic_error = true; - return DDS_RETCODE_ERROR; - } - } - else { - DDS_ERROR("Unsupported annotation '"); - scoped_name_dds_error(annotation->scoped_name); - DDS_ERROR("' is ignored\n"); - return DDS_RETCODE_ERROR; - } - } - - return DDS_RETCODE_OK; - } - else if (DDSTS_IS_TYPE(context->cur_type, DDSTS_UNION_CASE)) { - assert(context->type_for_declarator != NULL); - ddsts_type_t* type = create_array_type(context->array_sizes, context->type_for_declarator); - if (type == NULL) { - ddsts_context_free_array_sizes(context); - return context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - } - ddsts_context_free_array_sizes(context); - context->dangling_identifier = NULL; - ddsts_union_case_set_decl(context->cur_type, name, type); - context->cur_type = context->cur_type->type.parent; - return DDS_RETCODE_OK; - } - assert(false); - return DDS_RETCODE_ERROR; -} - -extern bool ddsts_add_array_size(ddsts_context_t *context, ddsts_literal_t *value) -{ - assert(context != NULL); - assert(value->flags == (DDSTS_INT64 | DDSTS_UNSIGNED)); - array_size_t **ref_array_size = &context->array_sizes; - while (*ref_array_size != NULL) { - ref_array_size = &(*ref_array_size)->next; - } - *ref_array_size = (array_size_t*)ddsrt_malloc(sizeof(array_size_t)); - if (*ref_array_size == NULL) { - context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - return false; - } - (*ref_array_size)->size = value->value.ullng; - (*ref_array_size)->next = NULL; - return true; -} - -bool ddsts_add_annotation(ddsts_context_t *context, ddsts_scoped_name_t *scoped_name) -{ - assert(context != NULL); - assert(context->annotations_stack != NULL); - - annotation_t **ref_annotation = &context->annotations_stack->annotations; - while (*ref_annotation != NULL) { - ref_annotation = &(*ref_annotation)->next; - } - (*ref_annotation) = (annotation_t*)ddsrt_malloc(sizeof(annotation_t)); - if ((*ref_annotation) == NULL) { - context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - return false; - } - context->dangling_identifier = NULL; - (*ref_annotation)->scoped_name = scoped_name; - (*ref_annotation)->next = NULL; - return true; -} - -void ddsts_pragma_open(ddsts_context_t *context) -{ - assert(context != NULL); - assert(context->pragma_args == NULL); - DDSRT_UNUSED_ARG(context); -} - -bool ddsts_pragma_add_identifier(ddsts_context_t *context, ddsts_identifier_t name) -{ - ddsts_identifier_t copy; - assert(context != NULL); - - pragma_arg_t **ref_pragma_arg = &context->pragma_args; - while (*ref_pragma_arg != NULL) { - ref_pragma_arg = &(*ref_pragma_arg)->next; - } - copy = ddsrt_strdup(name); - if (copy == NULL) { - context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - return false; - } - (*ref_pragma_arg) = (pragma_arg_t*)ddsrt_malloc(sizeof(pragma_arg_t)); - if ((*ref_pragma_arg) == NULL) { - ddsrt_free(copy); - context->retcode = DDS_RETCODE_OUT_OF_RESOURCES; - return false; - } - context->dangling_identifier = NULL; - (*ref_pragma_arg)->arg = copy; - (*ref_pragma_arg)->next = NULL; - return true; -} - -dds_return_t ddsts_pragma_close(ddsts_context_t *context) -{ - assert(context != NULL); - assert(context->cur_type != NULL); - - pragma_arg_t *pragma_arg = context->pragma_args; - - /* Find struct in currect context */ - ddsts_type_t *member = NULL; - if (DDSTS_IS_TYPE(context->cur_type, DDSTS_MODULE)) { - member = context->cur_type->module.members.first; - } else if (DDSTS_IS_TYPE(context->cur_type, DDSTS_STRUCT)) { - member = context->cur_type->struct_def.members.first; - } - - ddsts_type_t *struct_def = NULL; - for (; member != NULL; member = member->type.next) { - if (DDSTS_IS_TYPE(member, DDSTS_STRUCT) && strcmp(pragma_arg->arg, member->type.name) == 0) { - struct_def = member; - break; - } - } - if (struct_def == NULL) { - DDS_ERROR("Struct '%s' for keylist pragma is undefined here\n", pragma_arg->arg); - context->semantic_error = true; - context_free_pragma_args(context); - return DDS_RETCODE_ERROR; - } - /* The '@key' and '#pragma keylist' may not be mixed */ - if (struct_def->struct_def.keys != NULL) { - DDS_ERROR("Cannot use keylist pragma for struct '%s' in combination with @key annotation\n", pragma_arg->arg); - context->semantic_error = true; - context_free_pragma_args(context); - return DDS_RETCODE_ERROR; - } - - for (pragma_arg = pragma_arg->next; pragma_arg != NULL; pragma_arg = pragma_arg->next) { - /* Find declarator in struct */ - ddsts_type_t *declaration = NULL; - for (ddsts_type_t *m = struct_def->struct_def.members.first; m != NULL && declaration == NULL; m = m->type.next) { - if (DDSTS_IS_TYPE(m, DDSTS_DECLARATION) && strcmp(m->type.name, pragma_arg->arg) == 0) { - declaration = m; - break; - } - } - if (declaration == NULL) { - DDS_ERROR("Member '%s' in struct '%s' for keylist pragma is undefined\n", pragma_arg->arg, struct_def->type.name); - context->semantic_error = true; - return DDS_RETCODE_ERROR; - } - else if (keyable_type(declaration->declaration.decl_type)) { - dds_return_t rc = ddsts_struct_add_key(struct_def, declaration); - if (rc == DDS_RETCODE_ERROR) { - DDS_ERROR("Field '%s' already defined as key\n", pragma_arg->arg); - context->semantic_error = true; - return rc; - } - else if (rc != DDS_RETCODE_OK) { - context->retcode = rc; - context_free_pragma_args(context); - return rc; - } - } - else { - DDS_ERROR("Type of '%s' is not valid for key\n", pragma_arg->arg); - context->semantic_error = true; - return DDS_RETCODE_ERROR; - } - } - - context_free_pragma_args(context); - return DDS_RETCODE_OK; -} - -extern void ddsts_accept(ddsts_context_t *context) -{ - assert(context != NULL); - context->retcode = context->semantic_error ? DDS_RETCODE_ERROR : DDS_RETCODE_OK; -} diff --git a/src/tools/idlc/src/tt_create.h b/src/tools/idlc/src/tt_create.h deleted file mode 100644 index 9fd432978a..0000000000 --- a/src/tools/idlc/src/tt_create.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#ifndef DDSTS_CREATE_H -#define DDSTS_CREATE_H - -#include -#include "dds/ddsrt/retcode.h" - -/* Some types only used during parsing */ - -typedef struct ddsts_scoped_name ddsts_scoped_name_t; -typedef struct ddsts_context ddsts_context_t; - -ddsts_context_t* ddsts_create_context(void); -void ddsts_context_error(ddsts_context_t *context, int line, int column, const char *msg); -void ddsts_context_set_error_func(ddsts_context_t *context, void (*error)(int line, int column, const char *msg)); -void ddsts_context_set_retcode(ddsts_context_t *context, dds_return_t retcode); -dds_return_t ddsts_context_get_retcode(ddsts_context_t* context); -ddsts_type_t* ddsts_context_take_root_type(ddsts_context_t *context); -void ddsts_free_context(ddsts_context_t* context); - -bool ddsts_context_copy_identifier(ddsts_context_t *context, ddsts_identifier_t source, ddsts_identifier_t *dest); - -bool ddsts_new_base_type(ddsts_context_t *context, ddsts_flags_t flags, ddsts_type_t **result); -bool ddsts_new_sequence(ddsts_context_t *context, ddsts_type_t *element_type, ddsts_literal_t *size, ddsts_type_t **result); -bool ddsts_new_sequence_unbound(ddsts_context_t *context, ddsts_type_t *base, ddsts_type_t **result); -bool ddsts_new_string(ddsts_context_t *context, ddsts_literal_t *size, ddsts_type_t **result); -bool ddsts_new_string_unbound(ddsts_context_t *context, ddsts_type_t **result); -bool ddsts_new_wide_string(ddsts_context_t *context, ddsts_literal_t *size, ddsts_type_t **result); -bool ddsts_new_wide_string_unbound(ddsts_context_t *context, ddsts_type_t **result); -bool ddsts_new_fixed_pt(ddsts_context_t *context, ddsts_literal_t *digits, ddsts_literal_t *fraction_digits, ddsts_type_t **result); -bool ddsts_new_map(ddsts_context_t *context, ddsts_type_t *key_type, ddsts_type_t *value_type, ddsts_literal_t *size, ddsts_type_t **result); -bool ddsts_new_map_unbound(ddsts_context_t *context, ddsts_type_t *key_type, ddsts_type_t *value_type, ddsts_type_t **result); -bool ddsts_new_scoped_name(ddsts_context_t *context, ddsts_scoped_name_t* prev, bool top, ddsts_identifier_t name, ddsts_scoped_name_t **result); -bool ddsts_get_type_from_scoped_name(ddsts_context_t *context, ddsts_scoped_name_t *scoped_name, ddsts_type_t **result); -bool ddsts_get_base_type_from_scoped_name(ddsts_context_t *context, ddsts_scoped_name_t *scoped_name, ddsts_flags_t *result); -void ddsts_free_scoped_name(ddsts_scoped_name_t *scoped_name); - -bool ddsts_module_open(ddsts_context_t *context, ddsts_identifier_t name); -void ddsts_module_close(ddsts_context_t *context); - -bool ddsts_add_struct_forward(ddsts_context_t *context, ddsts_identifier_t name); -bool ddsts_add_struct_open(ddsts_context_t *context, ddsts_identifier_t name); -bool ddsts_add_struct_extension_open(ddsts_context_t *context, ddsts_identifier_t name, ddsts_scoped_name_t *scoped_name); -bool ddsts_add_struct_member(ddsts_context_t *context, ddsts_type_t **ref_type); -void ddsts_struct_member_close(ddsts_context_t *context); -void ddsts_struct_close(ddsts_context_t *context, ddsts_type_t **result); -void ddsts_struct_empty_close(ddsts_context_t *context, ddsts_type_t **result); - -bool ddsts_add_union_forward(ddsts_context_t *context, ddsts_identifier_t name); -bool ddsts_add_union_open(ddsts_context_t *context, ddsts_identifier_t name); -bool ddsts_union_set_switch_type(ddsts_context_t *context, ddsts_flags_t base_type); -dds_return_t ddsts_union_add_case_label(ddsts_context_t *context, ddsts_literal_t *value); -bool ddsts_union_add_case_default(ddsts_context_t *context); -bool ddsts_union_add_element(ddsts_context_t *context, ddsts_type_t **type); -void ddsts_union_close(ddsts_context_t *context); - -dds_return_t ddsts_add_declarator(ddsts_context_t *context, ddsts_identifier_t name); - -bool ddsts_add_array_size(ddsts_context_t *context, ddsts_literal_t *value); - -bool ddsts_add_annotation(ddsts_context_t *context, ddsts_scoped_name_t* scoped_name); - -void ddsts_pragma_open(ddsts_context_t *context); -bool ddsts_pragma_add_identifier(ddsts_context_t *context, ddsts_identifier_t name); -dds_return_t ddsts_pragma_close(ddsts_context_t *context); - -void ddsts_accept(ddsts_context_t *context); - -#endif /* DDSTS_CREATE_H */ diff --git a/src/tools/idlc/src/types.c b/src/tools/idlc/src/types.c new file mode 100644 index 0000000000..5b3c02d594 --- /dev/null +++ b/src/tools/idlc/src/types.c @@ -0,0 +1,534 @@ +/* + * Copyright(c) 2021 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include + +#include "idl/stream.h" +#include "idl/string.h" +#include "idl/processor.h" + +#include "generator.h" +#include "descriptor.h" + +extern char *typename(const void *node); + +static idl_retcode_t +emit_implicit_sequence( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + struct generator *gen = user_data; + char *name, *type, *macro, dims[32] = ""; + const char *fmt, *star = "", *lpar = "", *rpar = ""; + const idl_type_spec_t *type_spec = idl_type_spec(node); + + (void)pstate; + (void)path; + if (revisit) { + assert(idl_is_sequence(node)); + } else if (idl_is_sequence(node)) { + if (idl_is_sequence(type_spec)) + return IDL_VISIT_REVISIT | IDL_VISIT_TYPE_SPEC; + } else { + assert(idl_is_member(node)); + if (!idl_is_sequence(type_spec)) + return IDL_VISIT_DONT_RECURSE; + return IDL_VISIT_TYPE_SPEC; + } + + /* strings are special */ + if (idl_is_string(type_spec) && idl_is_bounded(type_spec)) { + lpar = "("; + rpar = ")"; + if (idl_is_bounded(type_spec)) + idl_snprintf(dims, sizeof(dims), "[%"PRIu32"]", idl_bound(type_spec)+1); + } else if (idl_is_string(type_spec)) { + star = "*"; + } + + /* https://www.omg.org/spec/C/1.0/PDF section 1.11 */ + if (!(name = AUTO(typename(node)))) + return IDL_RETCODE_NO_MEMORY; + if (!(type = AUTO(typename(type_spec)))) + return IDL_RETCODE_NO_MEMORY; + if (!(macro = AUTO(idl_strdup(name)))) + return IDL_RETCODE_NO_MEMORY;; + for (char *ptr=macro; *ptr; ptr++) + if (idl_islower((unsigned char)*ptr)) + *ptr = (char)idl_toupper((unsigned char)*ptr); + fmt = "#ifndef %1$s_DEFINED\n" + "#define %1$s_DEFINED\n" + "typedef struct %2$s\n{\n" + " uint32_t _maximum;\n" + " uint32_t _length;\n" + " %3$s %4$s%5$s*_buffer%6$s%7$s;\n" + " bool _release;\n" + "} %2$s;\n\n" + "#define %2$s__alloc() \\\n" + "((%2$s*) dds_alloc (sizeof (%2$s)));\n\n" + "#define %2$s_allocbuf(l) \\\n" + "((%3$s %4$s%5$s*%6$s%7$s) dds_alloc ((l) * sizeof (%3$s%4$s%7$s)))\n" + "#endif /* %1$s_DEFINED */\n\n"; + if (idl_fprintf(gen->header.handle, fmt, macro, name, type, star, lpar, rpar, dims) < 0) + return IDL_RETCODE_NO_MEMORY; + + return IDL_VISIT_DONT_RECURSE; +} + +static idl_retcode_t +generate_implicit_sequences( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + idl_visitor_t visitor; + + (void)pstate; + (void)revisit; + (void)path; + memset(&visitor, 0, sizeof(visitor)); + visitor.visit = IDL_MEMBER | IDL_SEQUENCE; + visitor.accept[IDL_ACCEPT] = &emit_implicit_sequence; + assert(idl_is_member(node) || idl_is_sequence(node)); + if ((ret = idl_visit(pstate, node, &visitor, user_data)) < 0) + return ret; + return IDL_RETCODE_OK; +} + +/* members with multiple declarators result in multiple members */ +static idl_retcode_t +emit_field( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + struct generator *gen = user_data; + char *type, dims[32] = ""; + const char *fmt, *indent, *name, *star = ""; + const void *root; + idl_literal_t *literal; + idl_type_spec_t *type_spec; + + (void)pstate; + (void)revisit; + (void)path; + root = idl_parent(node); + indent = idl_is_case(root) ? " " : " "; + + name = idl_identifier(node); + type_spec = idl_type_spec(node); + if (!(type = AUTO(typename(type_spec)))) + return IDL_RETCODE_NO_MEMORY; + + /* strings are special */ + if (idl_is_string(type_spec) && idl_is_bounded(type_spec)) { + idl_snprintf(dims, sizeof(dims), "[%"PRIu32"]", idl_bound(type_spec)+1); + } else if (idl_is_string(type_spec)) { + star = "* "; + } + + fmt = "%s%s %s%s%s"; + if (idl_fprintf(gen->header.handle, fmt, indent, type, star, name, dims) < 0) + return IDL_RETCODE_NO_MEMORY; + fmt = "[%" PRIu32 "]"; + literal = ((const idl_declarator_t *)node)->const_expr; + for (; literal; literal = idl_next(literal)) { + assert(idl_type(literal) == IDL_ULONG); + if (idl_fprintf(gen->header.handle, fmt, literal->value.uint32) < 0) + return IDL_RETCODE_NO_MEMORY; + } + if (fputs(";\n", gen->header.handle) < 0) + return IDL_RETCODE_NO_MEMORY; + + return IDL_RETCODE_OK; +} + +extern idl_retcode_t generate_descriptor(const idl_pstate_t *, struct generator *, const idl_node_t *); + +static idl_retcode_t +emit_struct( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret = IDL_RETCODE_NO_MEMORY; + struct generator *gen = user_data; + char *name = NULL; + const char *fmt; + + if (!(name = AUTO(typename(node)))) + return IDL_RETCODE_NO_MEMORY; + + if (revisit) { + fmt = "} %1$s;\n" + "\n"; + if (idl_fprintf(gen->header.handle, fmt, name) < 0) + return IDL_RETCODE_NO_MEMORY; + if (idl_is_topic(node, (pstate->flags & IDL_FLAG_KEYLIST) != 0)) { + fmt = "extern const dds_topic_descriptor_t %1$s_desc;\n" + "\n" + "#define %1$s__alloc() \\\n" + "((%1$s*) dds_alloc (sizeof (%1$s)));\n" + "\n" + "#define %1$s_free(d,o) \\\n" + "dds_sample_free ((d), &%1$s_desc, (o))\n" + "\n"; + if (idl_fprintf(gen->header.handle, fmt, name) < 0) + return IDL_RETCODE_NO_MEMORY; + if ((ret = generate_descriptor(pstate, gen, node))) + return ret; + } + } else { + const idl_member_t *members = ((const idl_struct_t *)node)->members; + /* ensure typedefs for unnamed sequences exist beforehand */ + if ((ret = generate_implicit_sequences(pstate, revisit, path, members, user_data))) + return ret; + fmt = "typedef struct %1$s\n" + "{\n"; + if (idl_fprintf(gen->header.handle, fmt, name) < 0) + return IDL_RETCODE_NO_MEMORY; + return IDL_VISIT_REVISIT; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_union( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + struct generator *gen = user_data; + char *name, *type; + const char *fmt; + const idl_switch_type_spec_t *switch_type_spec; + + (void)pstate; + (void)path; + assert(idl_is_union(node)); + if (!(name = AUTO(typename(node)))) + return IDL_RETCODE_NO_MEMORY; + switch_type_spec = ((const idl_union_t *)node)->switch_type_spec; + assert(idl_is_switch_type_spec(switch_type_spec)); + if (!(type = AUTO(typename(switch_type_spec->type_spec)))) + return IDL_RETCODE_NO_MEMORY; + + if (revisit) { + fmt = " } _u;\n" + "} %1$s;\n" + "\n" + "#define %1$s__alloc() \\\n" + "((%1$s*) dds_alloc (sizeof (%1$s)));\n" + "\n"; + if (idl_fprintf(gen->header.handle, fmt, name) < 0) + return IDL_RETCODE_NO_MEMORY; + } else { + fmt = "typedef struct %1$s\n" + "{\n" + " %2$s _d;\n" + " union\n" + " {\n"; + if (idl_fprintf(gen->header.handle, fmt, name, type) < 0) + return IDL_RETCODE_NO_MEMORY; + return IDL_VISIT_REVISIT; + } + + return IDL_RETCODE_OK; +} + +static idl_retcode_t +emit_sequence_typedef( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + idl_retcode_t ret; + struct generator *gen = user_data; + char *type, *name, dims[32] = ""; + const char *fmt, *spc = " ", *star = "", *lpar = "", *rpar = ""; + const idl_declarator_t *declarator; + const idl_literal_t *literal; + const idl_type_spec_t *type_spec; + + type_spec = idl_type_spec(node); + assert(idl_is_sequence(type_spec)); + type_spec = idl_type_spec(type_spec); + /* ensure typedefs for implicit sequences exist beforehand */ + if (idl_is_sequence(type_spec) && + (ret = generate_implicit_sequences(pstate, revisit, path, type_spec, user_data))) + return ret; + + /* strings are special */ + if (idl_is_string(type_spec) && idl_is_bounded(type_spec)) { + lpar = "("; + rpar = ")"; + if (idl_is_bounded(type_spec)) + idl_snprintf(dims, sizeof(dims), "[%"PRIu32"]", idl_bound(type_spec)+1); + } else if (idl_is_string(type_spec)) { + star = "*"; + } + + if (!(type = AUTO(typename(type_spec)))) + return IDL_RETCODE_NO_MEMORY; + declarator = ((const idl_typedef_t *)node)->declarators; + for (; declarator; declarator = idl_next(declarator)) { + if (!(name = AUTO(typename(declarator)))) + return IDL_RETCODE_NO_MEMORY; + fmt = "typedef struct %1$s\n{\n" + " uint32_t _maximum;\n" + " uint32_t _length;\n" + " %2$s %3$s%4$s*_buffer%5$s%6$s;\n" + " bool _release;\n" + "} %1$s"; + if (idl_fprintf(gen->header.handle, fmt, name, type, star, lpar, rpar, dims) < 0) + return IDL_RETCODE_NO_MEMORY; + literal = declarator->const_expr; + for (; literal; literal = idl_next(literal)) { + fmt = "%s[%" PRIu32 "]"; + if (idl_fprintf(gen->header.handle, fmt, spc, literal->value.uint32) < 0) + return IDL_RETCODE_NO_MEMORY; + } + fmt = ";\n\n" + "#define %1$s__alloc() \\\n" + "((%1$s*) dds_alloc (sizeof (%1$s)));\n\n" + "#define %1$s_allocbuf(l) \\\n" + "((%2$s %3$s%4$s*%5$s%6$s) dds_alloc ((l) * sizeof (%2$s%3$s%6$s)))\n"; + if (idl_fprintf(gen->header.handle, fmt, name, type, star, lpar, rpar, dims) < 0) + return IDL_RETCODE_NO_MEMORY; + } + + return IDL_VISIT_DONT_RECURSE; +} + +static idl_retcode_t +emit_typedef( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + struct generator *gen = user_data; + const char *fmt, *spc = " "; + const char *name = NULL, *type = NULL; + const idl_declarator_t *declarator; + const idl_literal_t *literal; + const idl_type_spec_t *type_spec; + + type_spec = idl_type_spec(node); + /* typedef of sequence requires a little magic */ + if (idl_is_sequence(type_spec)) + return emit_sequence_typedef(pstate, revisit, path, node, user_data); + if (!(type = AUTO(typename(type_spec)))) + return IDL_RETCODE_NO_MEMORY; + declarator = ((const idl_typedef_t *)node)->declarators; + for (; declarator; declarator = idl_next(declarator)) { + if (!(name = AUTO(typename(declarator)))) + return IDL_RETCODE_NO_MEMORY; + fmt = "typedef %1$s %2$s"; + if (idl_fprintf(gen->header.handle, fmt, type, name) < 0) + return IDL_RETCODE_NO_MEMORY; + literal = declarator->const_expr; + for (; literal; literal = idl_next(literal)) { + fmt = "%s[%" PRIu32 "]"; + if (idl_fprintf(gen->header.handle, fmt, spc, literal->value.uint32) < 0) + return IDL_RETCODE_NO_MEMORY; + spc = ""; + } + fmt = ";\n\n" + "#define %1$s__alloc() \\\n" + "((%1$s*) dds_alloc (sizeof (%1$s)));\n\n"; + if (idl_fprintf(gen->header.handle, fmt, name) < 0) + return IDL_RETCODE_NO_MEMORY; + } + + return IDL_VISIT_DONT_RECURSE; +} + +static idl_retcode_t +emit_enum( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + struct generator *gen = user_data; + const char *name = NULL, *type = NULL; + const char *fmt, *sep = ""; + const idl_enumerator_t *enumerator; + uint32_t skip = 0, value = 0; + + (void)pstate; + (void)revisit; + (void)path; + if (!(type = AUTO(typename(node)))) + return IDL_RETCODE_NO_MEMORY; + if (idl_fprintf(gen->header.handle, "typedef enum %s\n{\n", type) < 0) + return IDL_RETCODE_NO_MEMORY; + + enumerator = ((const idl_enum_t *)node)->enumerators; + for (; enumerator; enumerator = idl_next(enumerator)) { + if (!(name = AUTO(typename(enumerator)))) + return IDL_RETCODE_NO_MEMORY; + value = enumerator->value; + /* FIXME: IDL 3.5 did not support fixed enumerator values */ + if (value == skip) + fmt = "%s %s"; + else + fmt = "%s %s = %" PRIu32; + if (idl_fprintf(gen->header.handle, fmt, sep, name, value) < 0) + return IDL_RETCODE_NO_MEMORY; + sep = ",\n"; + skip = value + 1; + } + + fmt = "\n} %1$s;\n\n" + "#define %1$s__alloc() \\\n" + "((%1$s*) dds_alloc (sizeof (%1$s)));\n\n"; + if (idl_fprintf(gen->header.handle, fmt, type) < 0) + return IDL_RETCODE_NO_MEMORY; + + return IDL_VISIT_DONT_RECURSE; +} + +static int +print_literal( + const idl_pstate_t *pstate, + struct generator *gen, + const idl_literal_t *literal) +{ + idl_type_t type; + FILE *fp = gen->header.handle; + + (void)pstate; + switch ((type = idl_type(literal))) { + case IDL_CHAR: + return idl_fprintf(fp, "'%c'", literal->value.chr); + case IDL_BOOL: + return idl_fprintf(fp, "%s", literal->value.bln ? "true" : "false"); + case IDL_INT8: + return idl_fprintf(fp, "%" PRId8, literal->value.int8); + case IDL_OCTET: + case IDL_UINT8: + return idl_fprintf(fp, "%" PRIu8, literal->value.uint8); + case IDL_SHORT: + case IDL_INT16: + return idl_fprintf(fp, "%" PRId16, literal->value.int16); + case IDL_USHORT: + case IDL_UINT16: + return idl_fprintf(fp, "%" PRIu16, literal->value.uint16); + case IDL_LONG: + case IDL_INT32: + return idl_fprintf(fp, "%" PRId32, literal->value.int32); + case IDL_ULONG: + case IDL_UINT32: + return idl_fprintf(fp, "%" PRIu32, literal->value.uint32); + case IDL_LLONG: + case IDL_INT64: + return idl_fprintf(fp, "%" PRId64, literal->value.int64); + case IDL_ULLONG: + case IDL_UINT64: + return idl_fprintf(fp, "%" PRIu64, literal->value.uint64); + case IDL_FLOAT: + return idl_fprintf(fp, "%.6f", literal->value.flt); + case IDL_DOUBLE: + return idl_fprintf(fp, "%f", literal->value.dbl); + case IDL_LDOUBLE: + return idl_fprintf(fp, "%lf", literal->value.ldbl); + case IDL_STRING: + return idl_fprintf(fp, "\"%s\"", literal->value.str); + default: { + const char *name; + assert(type == IDL_ENUM); + if (!(name = AUTO(typename(literal)))) + return -1; + return idl_fprintf(fp, "%s", name); + } + } +} + +static idl_retcode_t +emit_const( + const idl_pstate_t *pstate, + bool revisit, + const idl_path_t *path, + const void *node, + void *user_data) +{ + struct generator *gen = user_data; + char *type; + const char *lparen = "", *rparen = ""; + const idl_literal_t *literal = ((const idl_const_t *)node)->const_expr; + + (void)revisit; + (void)path; + if (!(type = AUTO(typename(node)))) + return IDL_RETCODE_NO_MEMORY; + switch (idl_type(literal)) { + case IDL_CHAR: + case IDL_STRING: + lparen = "("; + rparen = ")"; + break; + default: + break; + } + if (idl_fprintf(gen->header.handle, "#define %s %s", type, lparen) < 0) + return IDL_RETCODE_NO_MEMORY; + if (print_literal(pstate, gen, literal) < 0) + return IDL_RETCODE_NO_MEMORY; + if (idl_fprintf(gen->header.handle, "%s\n", rparen) < 0) + return IDL_RETCODE_NO_MEMORY; + return IDL_RETCODE_OK; +} + +idl_retcode_t generate_types(const idl_pstate_t *pstate, struct generator *generator); + +idl_retcode_t generate_types(const idl_pstate_t *pstate, struct generator *generator) +{ + idl_retcode_t ret; + idl_visitor_t visitor; + + memset(&visitor, 0, sizeof(visitor)); + visitor.visit = IDL_CONST | IDL_TYPEDEF | IDL_STRUCT | IDL_UNION | IDL_ENUM | IDL_DECLARATOR; + visitor.accept[IDL_ACCEPT_CONST] = &emit_const; + visitor.accept[IDL_ACCEPT_TYPEDEF] = &emit_typedef; + visitor.accept[IDL_ACCEPT_STRUCT] = &emit_struct; + visitor.accept[IDL_ACCEPT_UNION] = &emit_union; + visitor.accept[IDL_ACCEPT_ENUM] = &emit_enum; + visitor.accept[IDL_ACCEPT_DECLARATOR] = &emit_field; + visitor.sources = (const char *[]){ pstate->sources->path->name, NULL }; + if ((ret = idl_visit(pstate, pstate->root, &visitor, generator))) + return ret; + return IDL_RETCODE_OK; +} diff --git a/src/tools/idlc/tests/gen_C99.c b/src/tools/idlc/tests/gen_C99.c deleted file mode 100644 index c77e6504cb..0000000000 --- a/src/tools/idlc/tests/gen_C99.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include -#include -#include "CUnit/Test.h" -#include "dds/ddsts/typetree.h" -#include "idl.h" -#include "gen_c99.h" - -static bool test_parse_gen_C99(const char *input, const char *str) -{ - ddsts_type_t *root_type = NULL; - if (idl_parse_string(input, &root_type) != DDS_RETCODE_OK) { - return false; - } - - char buffer[10000]; - - ddsts_generate_C99_to_buffer("test.idl", root_type, buffer, 9999); - - ddsts_free_type(root_type); - - if (strstr(buffer, str) != 0) { - return true; - } - printf("Did not find |%s|\n in |%s|\n", str, buffer); - return false; -} - -static bool test_parse_gen_C99_descr(const char *input, const char *name, const char *align, const char *flags) -{ - ddsts_type_t *root_type = NULL; - if (idl_parse_string(input, &root_type) != DDS_RETCODE_OK) { - return false; - } - - char buffer[10000]; - - ddsts_generate_C99_to_buffer("test.idl", root_type, buffer, 9999); - - ddsts_free_type(root_type); - - char sizeof_name[40]; - snprintf(sizeof_name, 39, "sizeof (%s),\n ", name); - const char *s = strstr(buffer, sizeof_name); - if (s == NULL) { - printf("Did not find |%s| in |%s|\n", sizeof_name, buffer); - return false; - } - s += strlen(sizeof_name); - if (strncmp(s, align, strlen(align)) != 0 || s[strlen(align)] != ',') { - printf("Did not find alignment |%s| at |%s|\n", align, s); - return false; - } - s += strlen(align) + 4; - if (strncmp(s, flags, strlen(flags)) != 0 || s[strlen(flags)] != ',') { - printf("Did not find flags |%s| at |%s|\n", flags, s); - return false; - } - return true; -} - -CU_Test(idlc_gen_c99, module) -{ - CU_ASSERT(test_parse_gen_C99("module a { struct e{@key char c;};};", - "typedef struct a_e\n{\n char c;\n} a_e;")); - CU_ASSERT(test_parse_gen_C99("module a { struct e{@key char c;};};", - "DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (a_e, c),\n")); - CU_ASSERT(test_parse_gen_C99("module a { struct e{@key char c;};};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("module a { struct e{@key char c;};};", "a_e", "1u", "DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("module a{struct f{char y;};}; module a { struct e{char x;};};", "typedef struct a_f\n{\n char y;\n} a_f;")); - CU_ASSERT(test_parse_gen_C99("module a{struct f{char y;};}; module a { struct e{char x;};};", "typedef struct a_e\n{\n char x;\n} a_e;")); - CU_ASSERT(test_parse_gen_C99("module x {module a { struct e{char c;};}; };", "typedef struct x_a_e\n{\n char c;\n} x_a_e;")); -} - -CU_Test(idlc_gen_c99, base_types) -{ - CU_ASSERT(test_parse_gen_C99("struct s {@key char c;};","typedef struct s\n{\n char c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char c;};","DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key char c;};","s","1u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key boolean c;};","typedef struct s\n{\n bool c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key boolean c;};","DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key boolean c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key boolean c;};","s","(sizeof(bool)>1u)?sizeof(bool):1u","DDS_TOPIC_FIXED_KEY")); - /* wchar not supported yet */ - CU_ASSERT(test_parse_gen_C99("struct s {wchar c;};","typedef struct s\n{\n // type not supported: c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key short c;};","typedef struct s\n{\n int16_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key short c;};","DDS_OP_ADR | DDS_OP_TYPE_2BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key short c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key short c;};","s","2u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int16 c;};","typedef struct s\n{\n int16_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int16 c;};","DDS_OP_ADR | DDS_OP_TYPE_2BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int16 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key int16 c;};","s","2u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key long c;};","typedef struct s\n{\n int32_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key long c;};","DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key long c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key long c;};","s","4u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int32 c;};","typedef struct s\n{\n int32_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int32 c;};","DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int32 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key int32 c;};","s","4u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key long long c;};","typedef struct s\n{\n int64_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key long long c;};","DDS_OP_ADR | DDS_OP_TYPE_8BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key long long c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key long long c;};","s","8u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int64 c;};","typedef struct s\n{\n int64_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int64 c;};","DDS_OP_ADR | DDS_OP_TYPE_8BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int64 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key int64 c;};","s","8u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned short c;};","typedef struct s\n{\n uint16_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned short c;};","DDS_OP_ADR | DDS_OP_TYPE_2BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned short c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key unsigned short c;};","s","2u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint16 c;};","typedef struct s\n{\n uint16_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint16 c;};","DDS_OP_ADR | DDS_OP_TYPE_2BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint16 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key uint16 c;};","s","2u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned long c;};","typedef struct s\n{\n uint32_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned long c;};","DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned long c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key unsigned long c;};","s","4u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint32 c;};","typedef struct s\n{\n uint32_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint32 c;};","DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint32 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key uint32 c;};","s","4u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned long long c;};","typedef struct s\n{\n uint64_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned long long c;};","DDS_OP_ADR | DDS_OP_TYPE_8BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key unsigned long long c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key unsigned long long c;};","s","8u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint64 c;};","typedef struct s\n{\n uint64_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint64 c;};","DDS_OP_ADR | DDS_OP_TYPE_8BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint64 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key uint64 c;};","s","8u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key octet c;};","typedef struct s\n{\n uint8_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key octet c;};","DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key octet c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key octet c;};","s","1u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int8 c;};","typedef struct s\n{\n int8_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int8 c;};","DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key int8 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key int8 c;};","s","1u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint8 c;};","typedef struct s\n{\n uint8_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint8 c;};","DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key uint8 c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key uint32 c;};","s","4u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key float c;};","typedef struct s\n{\n float c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key float c;};","DDS_OP_ADR | DDS_OP_TYPE_4BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key float c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key float c;};","s","4u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99("struct s {@key double c;};","typedef struct s\n{\n double c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key double c;};","DDS_OP_ADR | DDS_OP_TYPE_8BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key double c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key double c;};","s","8u","DDS_TOPIC_FIXED_KEY")); - /* not supported yet */ - CU_ASSERT(test_parse_gen_C99("struct s {long double c;};","typedef struct s\n{\n // type not supported: c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char x; long double c;};","")); - /* not supported yet */ - CU_ASSERT(test_parse_gen_C99("struct s {fixed<5,3> c; @key char x;};","typedef struct s\n{\n // type not supported: c;\n char x;\n} s;")); -} - -CU_Test(idlc_gen_c99, sequence) -{ - /* sequence of short */ - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;sequence c;};","typedef struct s\n{\n char k;\n dds_sequence_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;sequence c;};","DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_2BY, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;sequence c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key char k;sequence c;};","s","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;sequence c;};","typedef struct s\n{\n char k;\n dds_sequence_t c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;sequence c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s {@key char k;sequence c;};","s","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - /* sequence of struct */ - CU_ASSERT(test_parse_gen_C99("struct x{char c;};struct m{@key char k;sequence a;};", - "typedef struct x\n{\n char c;\n} x;")); - CU_ASSERT(test_parse_gen_C99("struct x{char c;};struct m{@key char k;sequence a;};", - "typedef struct m_a_seq\n{\n uint32_t _maximum;\n uint32_t _length;\n x *_buffer;\n bool _release;\n} m_a_seq;")); - CU_ASSERT(test_parse_gen_C99("struct x{char c;};struct m{@key char k;sequence a;};", - "typedef struct m\n{\n char k;\n m_a_seq a;\n} m;")); - CU_ASSERT(test_parse_gen_C99("struct x{char c;};struct m{@key char k;sequence a;};", - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, offsetof (m, a),\n" - " sizeof (x), (7u << 16u) + 4u,\n" - " DDS_OP_ADR | DDS_OP_TYPE_1BY, offsetof (x, c),\n" - " DDS_OP_RTS,\n")); - CU_ASSERT(test_parse_gen_C99("struct x{char c;};struct m{@key char k;sequence a;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct x{char c;};struct m{@key char k;sequence a;};","m","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - /* sequence of forward struct */ - CU_ASSERT(test_parse_gen_C99("struct x;struct m{@key char k;sequence a;};struct x{char c;};", - "typedef struct x\n{\n char c;\n} x;")); - CU_ASSERT(test_parse_gen_C99("struct x;struct m{@key char k;sequence a;};struct x{char c;};", - "typedef struct m_a_seq\n{\n uint32_t _maximum;\n uint32_t _length;\n x *_buffer;\n bool _release;\n} m_a_seq;")); - CU_ASSERT(test_parse_gen_C99("struct x;struct m{@key char k;sequence a;};struct x{char c;};", - "typedef struct m\n{\n char k;\n m_a_seq a;\n} m;")); - CU_ASSERT(test_parse_gen_C99("struct x;struct m{@key char k;sequence a;};struct x{char c;};", - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, offsetof (m, a),\n" - " sizeof (x), (7u << 16u) + 4u,\n" - " DDS_OP_ADR | DDS_OP_TYPE_1BY, offsetof (x, c),\n" - " DDS_OP_RTS,\n")); - CU_ASSERT(test_parse_gen_C99("struct x;struct m{@key char k;sequence a;};struct x{char c;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct x;struct m{@key char k;sequence a;};struct x{char c;};","m","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - /* sequence of sequence */ - CU_ASSERT(test_parse_gen_C99("struct x{sequence > cs;@key char k;};", - "typedef struct x_cs_seq\n{\n uint32_t _maximum;\n uint32_t _length;\n dds_sequence_t *_buffer;\n bool _release;\n} x_cs_seq;\n")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence > cs;@key char k;};", - "typedef struct x\n{\n x_cs_seq cs;\n char k;\n} x;\n")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence > cs;@key char k;};", - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_SEQ, offsetof (x, cs),\n" - " sizeof (dds_sequence_t), (7u << 16u) + 4u,\n" - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_1BY, 0u,\n" - " DDS_OP_RTS,\n")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence > cs;@key char k;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct x{sequence > cs;@key char k;};", - "x","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - /* map is not supported yet */ - CU_ASSERT(test_parse_gen_C99("struct s {map c;};","typedef struct s\n{\n // type not supported: c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {map c;};","typedef struct s\n{\n // type not supported: c;\n} s;")); -} - -CU_Test(idlc_gen_c99, string) -{ - CU_ASSERT(test_parse_gen_C99("struct s {string c;};","typedef struct s\n{\n char * c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;string c;};","DDS_OP_ADR | DDS_OP_TYPE_STR, offsetof (s, c),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;string c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s{@key char k;string c;};","s","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - CU_ASSERT(test_parse_gen_C99_descr("struct s{char k;@key string c;};","s","sizeof (char *)","DDS_TOPIC_NO_OPTIMIZE")); - CU_ASSERT(test_parse_gen_C99("struct s {string<9> c;};","typedef struct s\n{\n char c[10];\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;string<9> c;};","DDS_OP_ADR | DDS_OP_TYPE_BST, offsetof (s, c), 10,\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char k;string<9> c;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s{@key char k;string<9> c;};","s","1u","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - CU_ASSERT(test_parse_gen_C99_descr("struct s{char k;@key string<9> c;};","s","1u","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - /* wstring not supported yet */ - CU_ASSERT(test_parse_gen_C99("struct s {wstring c;};","typedef struct s\n{\n // type not supported: c;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {wstring<9> c;};","typedef struct s\n{\n // type not supported: c;\n} s;")); -} - -CU_Test(idlc_gen_c99, structs) -{ - /* struct with two key fields */ - CU_ASSERT(test_parse_gen_C99("struct s {@key char c,b;};","typedef struct s\n{\n char c;\n char b;\n} s;")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char c,b;};","{ \"c\", 0 },\n { \"b\", 2 }\n}")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char c,b;};","DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (s, c),\n DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (s, b),\n")); - CU_ASSERT(test_parse_gen_C99("struct s {@key char c,b;};","")); - CU_ASSERT(test_parse_gen_C99_descr("struct s{@key char c,b;};","s","1u","DDS_TOPIC_FIXED_KEY")); - /* embedded struct */ - CU_ASSERT(test_parse_gen_C99("struct x{struct y{char c;}a;};", - "typedef struct x_y\n{\n char c;\n} x_y;")); - CU_ASSERT(test_parse_gen_C99("struct x{struct y{char c;}a;};", - "typedef struct x\n{\n x_y a;\n} x;")); - CU_ASSERT(test_parse_gen_C99("struct x{char k;struct y{char c;}a;};\n#pragma keylist x k\n", - "DDS_OP_ADR | DDS_OP_TYPE_1BY, offsetof (x, a.c),\n")); - CU_ASSERT(test_parse_gen_C99("struct x{char k;struct y{char c;}a;};\n#pragma keylist x k\n", - "")); - CU_ASSERT(test_parse_gen_C99("module a{struct x{char c;};};module b{struct y{a::x d;char k;};\n#pragma keylist y k\n};", - "DDS_OP_ADR | DDS_OP_TYPE_1BY, offsetof (b_y, d.c),\n" - " DDS_OP_ADR | DDS_OP_TYPE_1BY | DDS_OP_FLAG_KEY, offsetof (b_y, k),\n")); - CU_ASSERT(test_parse_gen_C99_descr("module a{struct x{char c;};};module b{struct y{a::x d;char k;};\n#pragma keylist y k\n};","b_y","1u","DDS_TOPIC_FIXED_KEY")); -} - -CU_Test(idlc_gen_c99, array) -{ - CU_ASSERT(test_parse_gen_C99("struct x{char a[10][3];};", - "typedef struct x\n{\n char a[10][3];\n} x;")); - CU_ASSERT(test_parse_gen_C99("struct x{char a[10][3];};\n#pragma keylist x a\n", - "DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_1BY | DDS_OP_FLAG_KEY, offsetof (x, a), 30,\n")); - CU_ASSERT(test_parse_gen_C99("struct x{char a[10][3];};\n#pragma keylist x a\n", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct x{char a[10][3];};\n#pragma keylist x a\n","x","1u","0u")); - CU_ASSERT(test_parse_gen_C99("struct x{string a[5];@key char k;};", - "typedef struct x\n{\n char * a[5];\n char k;\n} x;\n")); - CU_ASSERT(test_parse_gen_C99("struct x{string a[5];@key char k;};", - "DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_STR, offsetof (x, a), 5,\n")); - CU_ASSERT(test_parse_gen_C99("struct x{string a[5];@key char k;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct x{string a[5];@key char k;};", - "x","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence a[5];char k;};", - "typedef struct x\n{\n dds_sequence_t a[5];\n char k;\n} x;\n")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence a[5];@key char k;};", - " DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_SEQ, offsetof (x, a), 5,\n" - " (8u << 16u) + 5u, sizeof (dds_sequence_t),\n" - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_1BY, 0u,\n" - " DDS_OP_RTS,\n")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence a[5];@key char k;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct x{sequence a[5];@key char k;};", - "x","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - CU_ASSERT(test_parse_gen_C99("struct s{sequence cs;};struct x{s a[5];@key char k;};", - "typedef struct x\n{\n s a[5];\n char k;\n} x;\n")); - CU_ASSERT(test_parse_gen_C99("struct s{sequence cs;};struct x{s a[5];@key char k;};", - " DDS_OP_ADR | DDS_OP_TYPE_ARR | DDS_OP_SUBTYPE_STU, offsetof (x, a), 5,\n" - " (8u << 16u) + 5u, sizeof (s),\n" - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_1BY, offsetof (s, cs),\n" - " DDS_OP_RTS,\n")); - CU_ASSERT(test_parse_gen_C99("struct s{sequence cs;};struct x{s a[5];@key char k;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct s{sequence cs;};struct x{s a[5];@key char k;};", - "x","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - /* fixed topic key when key is at most 16 bytes */ - CU_ASSERT(test_parse_gen_C99_descr("struct x{char a[16];};\n#pragma keylist x a\n","x","1u","DDS_TOPIC_FIXED_KEY")); - CU_ASSERT(test_parse_gen_C99_descr("struct x{char a[17];};\n#pragma keylist x a\n","x","1u","0u")); -} - -CU_Test(idlc_gen_c99, recursive) -{ - CU_ASSERT(test_parse_gen_C99("struct x{sequence a;};", - "typedef struct x_a_seq\n{\n uint32_t _maximum;\n uint32_t _length;\n x *_buffer;\n bool _release;\n} x_a_seq;")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence a;};", - "typedef struct x\n{\n x_a_seq a;\n} x;")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence a;@key char k;};", - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, offsetof (x, a),\n" - " sizeof (x), (7u << 16u) + 4u,\n" - " DDS_OP_JSR, (uint32_t)-4,\n" - " DDS_OP_RTS,\n")); - CU_ASSERT(test_parse_gen_C99("struct x{sequence a;@key char k;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct x{sequence a;@key char k;};","x","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); - CU_ASSERT(test_parse_gen_C99("struct a; struct b{sequence as;}; struct a{char k;sequence bs;};", - "typedef struct b\n{\n b_as_seq as;\n} b;\n")); - CU_ASSERT(test_parse_gen_C99("struct a; struct b{sequence as;}; struct a{char k;sequence bs;};", - "typedef struct a\n{\n char k;\n a_bs_seq bs;\n} a;\n")); - CU_ASSERT(test_parse_gen_C99("struct a; struct b{sequence as;}; struct a{@key char k;sequence bs;};", - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, offsetof (a, bs),\n" - " sizeof (b), (12u << 16u) + 4u,\n" - " DDS_OP_ADR | DDS_OP_TYPE_SEQ | DDS_OP_SUBTYPE_STU, offsetof (b, as),\n" - " sizeof (a), (7u << 16u) + 4u,\n" - " DDS_OP_JSR, (uint32_t)-10,\n" - " DDS_OP_RTS,\n" - " DDS_OP_RTS,\n")); - CU_ASSERT(test_parse_gen_C99("struct a; struct b{sequence as;}; struct a{@key char k;sequence bs;};", - "")); - CU_ASSERT(test_parse_gen_C99_descr("struct a; struct b{sequence as;}; struct a{@key char k;sequence bs;};", - "a","sizeof (char *)","DDS_TOPIC_FIXED_KEY | DDS_TOPIC_NO_OPTIMIZE")); -} - diff --git a/src/tools/idlc/tests/parser.c b/src/tools/idlc/tests/parser.c deleted file mode 100644 index 54dce11620..0000000000 --- a/src/tools/idlc/tests/parser.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License - * v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ -#include -#include -#include -#include -#include "CUnit/Test.h" -#include "dds/ddsts/typetree.h" -#include "idl.h" - -static bool test_type(ddsts_type_t *type, ddsts_flags_t flags, const char *name, ddsts_type_t *parent, bool next_is_null) -{ - return type != NULL && DDSTS_IS_TYPE(type, flags) && (name == NULL ? type->type.name == NULL : type->type.name != NULL && strcmp(type->type.name, name) == 0) - && type->type.parent == parent - && (next_is_null == (type->type.next == NULL)); -} - -static void test_basic_type(const char *idl, ddsts_flags_t flags) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string(idl, &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *struct_s = root_type->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", root_type, true)); - ddsts_type_t *decl_c = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl_c, DDSTS_DECLARATION, "c", struct_s, true)); - ddsts_type_t *char_type = decl_c->declaration.decl_type; - CU_ASSERT(test_type(char_type, flags, NULL, decl_c, true)); - CU_ASSERT(struct_s->struct_def.keys == NULL); - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, basic_types) -{ - test_basic_type("struct s{boolean c;};", DDSTS_BOOLEAN); - test_basic_type("struct s{char c;};", DDSTS_CHAR); - test_basic_type("struct s{wchar c;};", DDSTS_CHAR | DDSTS_WIDE); - test_basic_type("struct s{short c;};", DDSTS_INT16); - test_basic_type("struct s{int16 c;};", DDSTS_INT16); - test_basic_type("struct s{long c;};", DDSTS_INT32); - test_basic_type("struct s{int32 c;};", DDSTS_INT32); - test_basic_type("struct s{long long c;};", DDSTS_INT64); - test_basic_type("struct s{int64 c;};", DDSTS_INT64); - test_basic_type("struct s{unsigned short c;};", DDSTS_INT16 | DDSTS_UNSIGNED); - test_basic_type("struct s{uint16 c;};", DDSTS_INT16 | DDSTS_UNSIGNED); - test_basic_type("struct s{unsigned long c;};", DDSTS_INT32 | DDSTS_UNSIGNED); - test_basic_type("struct s{uint32 c;};", DDSTS_INT32 | DDSTS_UNSIGNED); - test_basic_type("struct s{unsigned long long c;};", DDSTS_INT64 | DDSTS_UNSIGNED); - test_basic_type("struct s{uint64 c;};", DDSTS_INT64 | DDSTS_UNSIGNED); - test_basic_type("struct s{octet c;};", DDSTS_OCTET); - test_basic_type("struct s{int8 c;};", DDSTS_INT8); - test_basic_type("struct s{uint8 c;};", DDSTS_INT8 | DDSTS_UNSIGNED); - test_basic_type("struct s{float c;};", DDSTS_FLOAT); - test_basic_type("struct s{double c;};", DDSTS_DOUBLE); - test_basic_type("struct s{long double c;};", DDSTS_LONGDOUBLE); -} - -CU_Test(idlc_parser, one_module1) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string("module a{ struct s{char c;};};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *module_a = root_type->module.members.first; - CU_ASSERT(test_type(module_a, DDSTS_MODULE, "a", root_type, true)); - CU_ASSERT(module_a->module.previous == NULL); - ddsts_type_t *struct_s = module_a->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", module_a, true)); - ddsts_type_t *decl_c = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl_c, DDSTS_DECLARATION, "c", struct_s, true)); - ddsts_type_t *char_type = decl_c->declaration.decl_type; - CU_ASSERT(test_type(char_type, DDSTS_CHAR, NULL, decl_c, true)); - CU_ASSERT(struct_s->struct_def.keys == NULL); - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, reopen_module) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string("module a{ struct s{char c;};}; module a { struct t{char x;};};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *module_a = root_type->module.members.first; - CU_ASSERT(test_type(module_a, DDSTS_MODULE, "a", root_type, false)); - CU_ASSERT(module_a->module.previous == NULL); - { - ddsts_type_t *struct_s = module_a->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", module_a, true)); - ddsts_type_t *decl_c = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl_c, DDSTS_DECLARATION, "c", struct_s, true)); - ddsts_type_t *char_type = decl_c->declaration.decl_type; - CU_ASSERT(test_type(char_type, DDSTS_CHAR, NULL, decl_c, true)); - CU_ASSERT(struct_s->struct_def.keys == NULL); - } - ddsts_type_t *module_a2 = module_a->type.next; - CU_ASSERT(test_type(module_a2, DDSTS_MODULE, "a", root_type, true)); - CU_ASSERT(module_a2->module.previous == &module_a->module); - { - ddsts_type_t *struct_t = module_a2->module.members.first; - CU_ASSERT(test_type(struct_t, DDSTS_STRUCT, "t", module_a2, true)); - ddsts_type_t *decl_x = struct_t->struct_def.members.first; - CU_ASSERT(test_type(decl_x, DDSTS_DECLARATION, "x", struct_t, true)); - ddsts_type_t *char_type = decl_x->declaration.decl_type; - CU_ASSERT(test_type(char_type, DDSTS_CHAR, NULL, decl_x, true)); - CU_ASSERT(struct_t->struct_def.keys == NULL); - } - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, scoped_name) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string("module a{ struct s{char c;};}; module b { struct t{a::s x;};};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *module_a = root_type->module.members.first; - CU_ASSERT(test_type(module_a, DDSTS_MODULE, "a", root_type, false)); - CU_ASSERT(module_a->module.previous == NULL); - ddsts_type_t *struct_s = module_a->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", module_a, true)); - ddsts_type_t *decl_c = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl_c, DDSTS_DECLARATION, "c", struct_s, true)); - ddsts_type_t *char_type = decl_c->declaration.decl_type; - CU_ASSERT(test_type(char_type, DDSTS_CHAR, NULL, decl_c, true)); - ddsts_type_t *module_b = module_a->type.next; - CU_ASSERT(test_type(module_b, DDSTS_MODULE, "b", root_type, true)); - CU_ASSERT(module_b->module.previous == NULL); - { - ddsts_type_t *struct_t = module_b->module.members.first; - CU_ASSERT(test_type(struct_t, DDSTS_STRUCT, "t", module_b, true)); - ddsts_type_t *decl_x = struct_t->struct_def.members.first; - CU_ASSERT(test_type(decl_x, DDSTS_DECLARATION, "x", struct_t, true)); - ddsts_type_t *x_type = decl_x->declaration.decl_type; - CU_ASSERT(x_type == struct_s); - } - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, comma) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string("struct s{char a, b;};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *struct_s = root_type->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", root_type, true)); - ddsts_type_t *decl_a = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl_a, DDSTS_DECLARATION, "a", struct_s, false)); - ddsts_type_t *char_type = decl_a->declaration.decl_type; - CU_ASSERT(test_type(char_type, DDSTS_CHAR, NULL, decl_a, true)); - ddsts_type_t *decl_b = decl_a->type.next; - CU_ASSERT(test_type(decl_b, DDSTS_DECLARATION, "b", struct_s, true)); - CU_ASSERT(decl_b->declaration.decl_type == char_type); - CU_ASSERT(struct_s->struct_def.keys == NULL); - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, types) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string("struct s{sequence us; sequence bs; string ust; string<7> bst; wstring uwst; wstring<6> bwst; fixed<5,3> fp; map um; map bm;};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *struct_s = root_type->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", root_type, true)); - ddsts_type_t *decl = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "us", struct_s, false)); - ddsts_type_t *s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_SEQUENCE, NULL, decl, true)); - CU_ASSERT(s_type->sequence.max == 0); - CU_ASSERT(DDSTS_IS_UNBOUND(s_type)); - ddsts_type_t *elem_type = s_type->sequence.element_type; - CU_ASSERT(test_type(elem_type, DDSTS_CHAR, NULL, s_type, true)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "bs", struct_s, false)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_SEQUENCE, NULL, decl, true)); - CU_ASSERT(s_type->sequence.max == 8); - CU_ASSERT(!DDSTS_IS_UNBOUND(s_type)); - elem_type = s_type->sequence.element_type; - CU_ASSERT(test_type(elem_type, DDSTS_CHAR, NULL, s_type, true)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "ust", struct_s, false)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_STRING, NULL, decl, true)); - CU_ASSERT(s_type->string.max == 0); - CU_ASSERT(DDSTS_IS_UNBOUND(s_type)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "bst", struct_s, false)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_STRING, NULL, decl, true)); - CU_ASSERT(s_type->string.max == 7); - CU_ASSERT(!DDSTS_IS_UNBOUND(s_type)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "uwst", struct_s, false)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_STRING | DDSTS_WIDE, NULL, decl, true)); - CU_ASSERT(s_type->string.max == 0); - CU_ASSERT(DDSTS_IS_UNBOUND(s_type)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "bwst", struct_s, false)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_STRING | DDSTS_WIDE, NULL, decl, true)); - CU_ASSERT(s_type->string.max == 6); - CU_ASSERT(!DDSTS_IS_UNBOUND(s_type)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "fp", struct_s, false)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_FIXED_PT, NULL, decl, true)); - CU_ASSERT(s_type->fixed_pt.digits == 5); - CU_ASSERT(s_type->fixed_pt.fraction_digits == 3); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "um", struct_s, false)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_MAP, NULL, decl, true)); - CU_ASSERT(s_type->map.max == 0); - CU_ASSERT(DDSTS_IS_UNBOUND(s_type)); - ddsts_type_t *key_type = s_type->map.key_type; - CU_ASSERT(test_type(key_type, DDSTS_INT16, NULL, s_type, true)); - ddsts_type_t *value_type = s_type->map.value_type; - CU_ASSERT(test_type(value_type, DDSTS_CHAR, NULL, s_type, true)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "bm", struct_s, true)); - s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_MAP, NULL, decl, true)); - CU_ASSERT(s_type->map.max == 5); - CU_ASSERT(!DDSTS_IS_UNBOUND(s_type)); - key_type = s_type->map.key_type; - CU_ASSERT(test_type(key_type, DDSTS_INT16, NULL, s_type, true)); - value_type = s_type->map.value_type; - CU_ASSERT(test_type(value_type, DDSTS_CHAR, NULL, s_type, true)); - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, union) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT_FATAL(idl_parse_string("union a switch(short) { case 0: short b; case 1: case 4: octet c; default: char d; };", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *union_s = root_type->module.members.first; - CU_ASSERT(test_type(union_s, DDSTS_UNION, "a", root_type, true)); - CU_ASSERT(union_s->union_def.switch_type == DDSTS_INT16); - ddsts_type_t *union_case = union_s->union_def.cases.first; - CU_ASSERT(test_type(union_case, DDSTS_UNION_CASE, "b", union_s, false)); - CU_ASSERT(!union_case->union_case.default_label); - ddsts_union_case_label_t *label = union_case->union_case.labels; - CU_ASSERT_FATAL(label != NULL); - CU_ASSERT(label->value.flags == DDSTS_INT16); - CU_ASSERT(label->value.value.ullng == 0ULL); - CU_ASSERT(label->next == NULL); - ddsts_type_t *case_type = union_case->declaration.decl_type; - CU_ASSERT(test_type(case_type, DDSTS_INT16, NULL, union_case, true)); - union_case = union_case->type.next; - CU_ASSERT(test_type(union_case, DDSTS_UNION_CASE, "c", union_s, false)); - CU_ASSERT(!union_case->union_case.default_label); - label = union_case->union_case.labels; - CU_ASSERT_FATAL(label != NULL); - CU_ASSERT(label->value.flags == DDSTS_INT16); - CU_ASSERT(label->value.value.ullng == 1ULL); - label = label->next; - CU_ASSERT_FATAL(label != NULL); - CU_ASSERT(label->value.flags == DDSTS_INT16); - CU_ASSERT(label->value.value.ullng == 4ULL); - CU_ASSERT(label->next == NULL); - case_type = union_case->declaration.decl_type; - CU_ASSERT(test_type(case_type, DDSTS_OCTET, NULL, union_case, true)); - union_case = union_case->type.next; - CU_ASSERT(test_type(union_case, DDSTS_UNION_CASE, "d", union_s, true)); - CU_ASSERT(union_case->union_case.default_label); - label = union_case->union_case.labels; - CU_ASSERT(label == NULL); - case_type = union_case->declaration.decl_type; - CU_ASSERT(test_type(case_type, DDSTS_CHAR, NULL, union_case, true)); - ddsts_free_type(root_type); - CU_ASSERT_FATAL(idl_parse_string("union u switch(short) { case 0: short b;}; struct s{u a;};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *union_u = root_type->module.members.first; - CU_ASSERT(test_type(union_u, DDSTS_UNION, "u", root_type, false)); - CU_ASSERT(union_u->union_def.switch_type == DDSTS_INT16); - union_case = union_u->union_def.cases.first; - CU_ASSERT(test_type(union_case, DDSTS_UNION_CASE, "b", union_u, true)); - CU_ASSERT(!union_case->union_case.default_label); - label = union_case->union_case.labels; - CU_ASSERT_FATAL(label != NULL); - CU_ASSERT(label->value.flags == DDSTS_INT16); - CU_ASSERT(label->value.value.ullng == 0ULL); - CU_ASSERT(label->next == NULL); - case_type = union_case->declaration.decl_type; - CU_ASSERT(test_type(case_type, DDSTS_INT16, NULL, union_case, true)); - ddsts_type_t *struct_s = union_u->type.next; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", root_type, true)); - ddsts_type_t *decl = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "a", struct_s, true)); - ddsts_type_t *s_type = decl->declaration.decl_type; - CU_ASSERT(s_type == union_u); - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, array) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string("struct s{short a[3], b[4][5]; sequence s[6];};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *struct_s = root_type->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", root_type, true)); - ddsts_type_t *decl = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "a", struct_s, false)); - ddsts_type_t *a_type = decl->declaration.decl_type; - CU_ASSERT(test_type(a_type, DDSTS_ARRAY, NULL, decl, true)); - CU_ASSERT(a_type->array.size == 3); - ddsts_type_t *elem_type = a_type->array.element_type; - CU_ASSERT(test_type(elem_type, DDSTS_INT16, NULL, a_type, true)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "b", struct_s, false)); - ddsts_type_t *b_type = decl->declaration.decl_type; - CU_ASSERT(test_type(b_type, DDSTS_ARRAY, NULL, decl, true)); - CU_ASSERT(b_type->array.size == 4); - elem_type = b_type->array.element_type; - CU_ASSERT(test_type(elem_type, DDSTS_ARRAY, NULL, b_type, true)); - CU_ASSERT(elem_type->array.size == 5); - ddsts_type_t *elem_type2 = elem_type->array.element_type; - CU_ASSERT(test_type(elem_type2, DDSTS_INT16, NULL, a_type, true)); - decl = decl->type.next; - CU_ASSERT(test_type(decl, DDSTS_DECLARATION, "s", struct_s, true)); - ddsts_type_t *s_type = decl->declaration.decl_type; - CU_ASSERT(test_type(s_type, DDSTS_ARRAY, NULL, decl, true)); - CU_ASSERT(s_type->array.size == 6); - elem_type = s_type->array.element_type; - CU_ASSERT(test_type(elem_type, DDSTS_SEQUENCE, NULL, s_type, true)); - elem_type2 = elem_type->sequence.element_type; - CU_ASSERT(test_type(elem_type2, DDSTS_CHAR, NULL, elem_type, true)); - CU_ASSERT(struct_s->struct_def.keys == NULL); - ddsts_free_type(root_type); -} - -static void test_topic_keys(const char *idl, const char *keystr) -{ - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string(idl, &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - CU_ASSERT(root_type->module.previous == NULL); - ddsts_type_t *struct_s = root_type->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", root_type, true)); - ddsts_type_t *decl_a = struct_s->struct_def.members.first; - CU_ASSERT(test_type(decl_a, DDSTS_DECLARATION, "a", struct_s, false)); - ddsts_type_t *char_type = decl_a->declaration.decl_type; - CU_ASSERT(test_type(char_type, DDSTS_CHAR, NULL, decl_a, true)); - ddsts_type_t *decl_b = decl_a->type.next; - CU_ASSERT(test_type(decl_b, DDSTS_DECLARATION, "b", struct_s, true)); - char_type = decl_b->declaration.decl_type; - CU_ASSERT(decl_b->declaration.decl_type == char_type); - ddsts_struct_key_t *keys = struct_s->struct_def.keys; - for (; *keystr != '\0'; keystr++, keys = keys->next) - { - CU_ASSERT_FATAL(keys != NULL); - CU_ASSERT(*keystr != 'a' || keys->member == decl_a); - CU_ASSERT(*keystr != 'b' || keys->member == decl_b); - } - CU_ASSERT(keys == NULL); - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, topic_keys) -{ - test_topic_keys("struct s{ @key char a; char b;};", "a"); - test_topic_keys("struct s{ char a; @key char b;};", "b"); - test_topic_keys("struct s{ @key char a; @key char b;};", "ab"); - test_topic_keys("struct s{ @key char a, b;};", "ab"); - test_topic_keys("struct s{ char a; char b;};\n#pragma keylist s a\n", "a"); - test_topic_keys("struct s{ char a; char b;};\n#pragma keylist s a b\n", "ab"); - test_topic_keys("struct s{ char a; char b;};\n#pragma keylist s b a\n", "ba"); - ddsts_type_t *root_type = NULL; - CU_ASSERT(idl_parse_string("module a{ struct s{char c;};}; module b { struct t{@key ::a::s x;};};", &root_type) == DDS_RETCODE_OK); - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - ddsts_type_t *module_a = root_type->module.members.first; - CU_ASSERT(test_type(module_a, DDSTS_MODULE, "a", root_type, false)); - ddsts_type_t *module_b = module_a->type.next; - CU_ASSERT(test_type(module_b, DDSTS_MODULE, "b", root_type, true)); - ddsts_type_t *struct_t = module_b->module.members.first; - CU_ASSERT(test_type(struct_t, DDSTS_STRUCT, "t", module_b, true)); - CU_ASSERT(struct_t->struct_def.keys != NULL); - CU_ASSERT(struct_t->struct_def.keys->member != NULL); - CU_ASSERT(strcmp(struct_t->struct_def.keys->member->type.name, "x") == 0); - ddsts_free_type(root_type); - root_type = NULL; - CU_ASSERT(idl_parse_string("struct s{@key struct{char x;} a;};", &root_type) == DDS_RETCODE_OK); - /* verify that the @key is applied to 'a' and not to 'x': */ - CU_ASSERT(test_type(root_type, DDSTS_MODULE, NULL, NULL, true)); - ddsts_type_t *struct_s = root_type->module.members.first; - CU_ASSERT(test_type(struct_s, DDSTS_STRUCT, "s", root_type, true)); - ddsts_type_t *anno_struct = struct_s->struct_def.members.first; - CU_ASSERT(test_type(anno_struct, DDSTS_STRUCT, NULL, struct_s, false)); - CU_ASSERT(anno_struct->struct_def.keys == NULL); - ddsts_type_t *decl_a = anno_struct->type.next; - CU_ASSERT(test_type(decl_a, DDSTS_DECLARATION, "a", struct_s, true)); - CU_ASSERT(struct_s->struct_def.keys != NULL); - CU_ASSERT(struct_s->struct_def.keys->member == decl_a); - ddsts_free_type(root_type); -} - -CU_Test(idlc_parser, errors) -{ - /* The purpose of these tests is also to verify that all memory is freed correctly */ - ddsts_type_t *root_type = NULL; - CU_ASSERT(root_type == NULL); - CU_ASSERT(idl_parse_string("xyz", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(root_type == NULL); - CU_ASSERT(idl_parse_string("struct s{char a[3][4];};", &root_type) == 0); - ddsts_free_type(root_type); - root_type = NULL; - CU_ASSERT(idl_parse_string("struct s{char a[3][4];}", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(root_type == NULL); - CU_ASSERT(idl_parse_string("struct s{char a[3][4];", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char a[3][4]", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char a[3][4", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char a[3][", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char a[3]", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char a[3", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char a[", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char a;", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{sequence seqa;}", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{sequence seqa", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{sequence", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{sequence m;}", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m;", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map ", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m;};!", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m;}!;", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m;!};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m!;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map !m;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map! m;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{map m;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct v{char c;};struct s{v", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct v{char c;};struct s{sequence", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct v{char c;};struct s{sequence a;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{@key struct{sequence cs;} a;};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{@key @key char c;};", &root_type) == IDL_PARSE_ERROR); - /* Unsupported pragma directives are ignored */ - CU_ASSERT(idl_parse_string("struct s{char c;};\n#pragma keylis\n", &root_type) == IDL_PARSE_ERROR); - ddsts_free_type(root_type); - root_type = NULL; - CU_ASSERT(idl_parse_string("struct s{char c;};\n#pragma keylist\n", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char c;};\n#pragma keylist v\n", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char c;};\n#pragma keylist s\n", &root_type) == 0); - ddsts_free_type(root_type); - root_type = NULL; - CU_ASSERT(idl_parse_string("struct s{char c;};\n#pragma keylist s v\n", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{char c;};\n#pragma keylist s c c\n", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("struct s{@key char c; char d;};\n#pragma keylist s d\n", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("module a{ struct s{char c;};}; module b { struct t{@ key a::s x;};};", &root_type) == IDL_PARSE_ERROR); - CU_ASSERT(idl_parse_string("module a{ struct s{char c;};}; module b { struct t{@key a ::s x;};};", &root_type) == 0); - ddsts_free_type(root_type); - root_type = NULL; - CU_ASSERT(idl_parse_string("module a{ struct s{char c;};}; module b { struct t{@key a:: s x;};};", &root_type) == 0); - ddsts_free_type(root_type); - root_type = NULL; - CU_ASSERT(idl_parse_string("struct v;struct s{v a;};struct v{char x;};", &root_type) == IDL_PARSE_ERROR); -} -