Merge pull request #15 from valitydev/ft/0.19.0

Upgrade to 0.19.0
This commit is contained in:
Egor Cherniak 2024-05-24 12:56:44 +03:00 committed by GitHub
commit 85cab54341
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
582 changed files with 24888 additions and 7672 deletions

33
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,33 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: monthly
- package-ecosystem: "gradle"
directory: "/lib/java"
schedule:
interval: monthly
- package-ecosystem: "gradle"
directory: "/lib/kotlin"
schedule:
interval: monthly

View File

@ -3,7 +3,7 @@
<!-- We recommend you review the checklist/tips before submitting a pull request. -->
- [ ] Did you create an [Apache Jira](https://issues.apache.org/jira/projects/THRIFT/issues/) ticket? (not required for trivial changes)
- [ ] Did you create an [Apache Jira](https://issues.apache.org/jira/projects/THRIFT/issues/) ticket? ([Request account here](https://selfserve.apache.org/jira-account.html), not required for trivial changes)
- [ ] If a ticket exists: Does your pull request title follow the pattern "THRIFT-NNNN: describe my issue"?
- [ ] Did you squash your changes to a single commit? (not required, but preferred)
- [ ] Did you do your best to avoid breaking changes? If one was needed, did you label the Jira ticket with "Breaking-Change"?

View File

@ -9,13 +9,42 @@ on:
env:
BUILD_DEPS: automake bison flex git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
CONFIG_ARGS_FOR_LIBS: >
--disable-debug
--disable-tests
--disable-dependency-tracking
--without-cpp
--without-c_glib
--without-java
--without-kotlin
--without-python
--without-py3
--without-ruby
--without-haxe
--without-netstd
--without-perl
--without-php
--without-php_extension
--without-dart
--without-erlang
--without-go
--without-d
--without-nodejs
--without-nodets
--without-lua
--without-rs
--without-swift
permissions:
contents: read
jobs:
# TODO windows and macos
compiler:
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04]
os: [ubuntu-20.04, ubuntu-22.04]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
@ -49,18 +78,78 @@ jobs:
path: compiler/cpp/thrift
retention-days: 3
lib-go:
needs: compiler
runs-on: ubuntu-20.04
strategy:
matrix:
go:
- '1.20'
- '1.21'
fail-fast: false
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
- name: Install dependencies
run: |
sudo apt-get update -yq
sudo apt-get install -y --no-install-recommends $BUILD_DEPS
- name: Run bootstrap
run: ./bootstrap.sh
- name: Run configure
run: |
./configure $(echo $CONFIG_ARGS_FOR_LIBS | sed 's/without-go/with-go/')
- uses: actions/download-artifact@v3
with:
name: thrift-compiler
path: compiler/cpp
- name: Run thrift-compiler
run: |
chmod a+x compiler/cpp/thrift
compiler/cpp/thrift -version
- name: Run make for go
run: make -C lib/go
- name: Run make check for lib/go
run: make -C lib/go check
- name: Run make check for test/go
run: make -C test/go check
- name: Run make precross for go test
run: make -C test/go precross
- name: Upload go precross artifacts
if: matrix.go == '1.21'
uses: actions/upload-artifact@v3
with:
name: go-precross
if-no-files-found: error
path: |
test/go/bin/*
retention-days: 3
lib-java-kotlin:
needs: compiler
runs-on: ubuntu-20.04
env:
GRADLE_VERSION: 7.4.2
GRADLE_VERSION: "8.0.2"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 11
java-version: 17
cache: "gradle"
- name: Install dependencies
@ -72,7 +161,7 @@ jobs:
- name: Setup gradle
run: |
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip
(echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -)
(echo "ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7 /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -)
unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip
sudo mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle
sudo ln -s /usr/local/gradle/bin/gradle /usr/local/bin
@ -93,31 +182,7 @@ jobs:
- name: Run configure
run: |
./configure \
--disable-debug \
--disable-tests \
--disable-dependency-tracking \
--without-cpp \
--without-c_glib \
--with-java \
--with-kotlin \
--without-python \
--without-py3 \
--without-ruby \
--without-haxe \
--without-netstd \
--without-perl \
--without-php \
--without-php_extension \
--without-dart \
--without-erlang \
--without-go \
--without-d \
--without-nodejs \
--without-nodets \
--without-lua \
--without-rs \
--without-swift
./configure $(echo $CONFIG_ARGS_FOR_LIBS | sed 's/without-java/with-java/' | sed 's/without-kotlin/with-kotlin/')
- uses: actions/download-artifact@v3
with:
@ -181,22 +246,198 @@ jobs:
lib/kotlin/cross-test-server/build/install/TestServer/
retention-days: 3
cross-test:
needs:
- lib-java-kotlin
lib-swift:
needs: compiler
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- name: Run bootstrap
run: ./bootstrap.sh
- name: Run configure
run: |
./configure $(echo $CONFIG_ARGS_FOR_LIBS | sed 's/without-swift/with-swift/')
- uses: actions/download-artifact@v3
with:
name: thrift-compiler
path: compiler/cpp
- name: Run thrift-compiler
run: |
chmod a+x compiler/cpp/thrift
compiler/cpp/thrift -version
- name: Run make precross for swift
run: make -C test/swift precross
- name: Upload swift precross artifacts
uses: actions/upload-artifact@v3
with:
name: swift-precross
if-no-files-found: error
path: |
test/swift/CrossTests/.build/x86_64-unknown-linux-gnu/debug/TestServer
test/swift/CrossTests/.build/x86_64-unknown-linux-gnu/debug/TestClient
retention-days: 3
lib-rust:
needs: compiler
runs-on: ubuntu-20.04
env:
TOOLCHAIN_VERSION: 1.61.0
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get update -yq
sudo apt-get install -y --no-install-recommends curl $BUILD_DEPS
- name: Setup cargo
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
rustup update
rustup install $TOOLCHAIN_VERSION
rustup default $TOOLCHAIN_VERSION
rustup --version
cargo --version
rustc --version
- name: Run bootstrap
run: ./bootstrap.sh
- name: Run configure
run: |
./configure $(echo $CONFIG_ARGS_FOR_LIBS | sed 's/without-rs/with-rs/')
- uses: actions/download-artifact@v3
with:
name: thrift-compiler
path: compiler/cpp
- name: Run thrift-compiler
run: |
chmod a+x compiler/cpp/thrift
compiler/cpp/thrift -version
- name: Run make for rust
run: make -C lib/rs
- name: Run make check for rust
run: make -C lib/rs check
- name: Run make test for rust
run: make -C lib/rs/test check
- name: Run make precross for test rust
run: make -C test/rs precross
- name: Upload rust precross artifacts
uses: actions/upload-artifact@v3
with:
name: rs-precross
if-no-files-found: error
path: |
test/rs/bin/test_server
test/rs/bin/test_client
retention-days: 3
- name: Run make test_recursive for rust
run: make -C lib/rs/test_recursive check
lib-python:
needs: compiler
runs-on: ubuntu-20.04
strategy:
matrix:
python-version:
- "3.x"
fail-fast: false
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt-get update -yq
sudo apt-get install -y --no-install-recommends $BUILD_DEPS
sudo apt-get install -y --no-install-recommends curl openssl ca-certificates
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Python setup
run: |
python -m pip install --upgrade pip setuptools wheel flake8 tornado twisted zope.interface
python --version
pip --version
- name: Run bootstrap
run: ./bootstrap.sh
- name: Run configure 3.x
if: matrix.python-version == '3.x'
run: |
./configure $(echo $CONFIG_ARGS_FOR_LIBS | sed 's/without-py3/with-py3/')
- uses: actions/download-artifact@v3
with:
name: thrift-compiler
path: compiler/cpp
- name: Run thrift-compiler
run: |
chmod a+x compiler/cpp/thrift
compiler/cpp/thrift -version
- name: Run make for python
run: make -C lib/py
- name: Run make install for python
run: sudo make -C lib/py install
# - name: Run make install-exec-hook for python
# run: sudo make -C lib/py install-exec-hook
- name: Run make check for python
run: make -C lib/py check
cross-test:
needs:
- lib-java-kotlin
- lib-swift
- lib-rust
- lib-go
- lib-python
runs-on: ubuntu-20.04
strategy:
matrix:
server_lang: ['java', 'kotlin', 'go', 'rs', 'swift']
# we always use comma join as many client langs as possible, to reduce the number of jobs
client_lang: ['java,kotlin', 'go,rs', 'swift']
fail-fast: false
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.x"
- uses: actions/setup-java@v3
with:
distribution: temurin
# here we intentionally use java 8 so that we also verify java 11 compiles to version 8
# here we intentionally use an older version so that we also verify Java 17 compiles to it
java-version: 8
cache: "gradle"
- name: Install openssl and certificates (for SSL tests)
run: |
sudo apt-get update -yq
sudo apt-get install -y --no-install-recommends openssl ca-certificates
- name: Download java precross artifacts
uses: actions/download-artifact@v3
with:
@ -209,23 +450,43 @@ jobs:
name: kotlin-precross
path: lib/kotlin
- name: Download swift precross artifacts
uses: actions/download-artifact@v3
with:
name: swift-precross
path: test/swift/CrossTests/.build/x86_64-unknown-linux-gnu/debug
- name: Download rust precross artifacts
uses: actions/download-artifact@v3
with:
name: rs-precross
path: test/rs/bin
- name: Download go precross artifacts
uses: actions/download-artifact@v3
with:
name: go-precross
path: test/go/bin
- name: Set back executable flags
run: |
chmod a+x \
lib/java/build/run* \
lib/kotlin/cross-test-client/build/install/TestClient/bin/* \
lib/kotlin/cross-test-server/build/install/TestServer/bin/*
lib/kotlin/cross-test-server/build/install/TestServer/bin/* \
test/swift/CrossTests/.build/x86_64-unknown-linux-gnu/debug/* \
test/rs/bin/* \
test/go/bin/*
- name: Run cross test
env:
THRIFT_CROSSTEST_CONCURRENCY: 4
PRECROSS_LANGS: java,kotlin
run: |
python test/test.py \
--retry-count 5 \
--skip-known-failures \
--server $PRECROSS_LANGS \
--client $PRECROSS_LANGS
--server ${{ matrix.server_lang }} \
--client ${{ matrix.client_lang }}
- name: Upload log files from failed cross test runs
uses: actions/upload-artifact@v3
@ -234,3 +495,4 @@ jobs:
name: cross-test-log
path: test/log/
retention-days: 3

View File

@ -9,6 +9,9 @@ on:
env:
BUILD_DEPS: bison flex g++ libboost-all-dev libevent-dev libssl-dev make cmake
permissions:
contents: read
jobs:
compiler:
runs-on: ubuntu-20.04

22
.gitignore vendored
View File

@ -49,6 +49,7 @@ test-driver
erl_crash.dump
project.lock.json
.Dockerfile.sha512
.sonar
.DS_Store
.svn
@ -201,9 +202,9 @@ project.lock.json
/lib/delphi/*.local
/lib/delphi/*.identcache
/lib/delphi/test/skip/bin
/lib/delphi/test/serializer/*.dat
/lib/delphi/test/serializer/**/*.dat
/lib/delphi/test/serializer/bin
/lib/delphi/test/thrift-testing
/lib/delphi/test/thrift-testing/*.thrift
/lib/delphi/**/*.identcache
/lib/delphi/**/*.local
/lib/delphi/**/*.dcu
@ -224,6 +225,9 @@ project.lock.json
/lib/haxe/test/data.tmp
/lib/hs/dist
/lib/java/.gradle
/lib/java/gradle/wrapper
/lib/java/gradlew
/lib/java/gradlew.bat
/lib/java/android/.gradle
/lib/java/build
/lib/java/out
@ -285,7 +289,7 @@ project.lock.json
/lib/go/src
/lib/go/test/fuzz/gopathfuzz
/lib/go/test/gopath/
/lib/go/test/ThriftTest.thrift
/lib/go/test/ThriftTest*.thrift
/lib/nodets/test-compiled/
/lib/ocaml/_build/
/lib/ocaml/_tags
@ -355,7 +359,7 @@ project.lock.json
/test/erl/_build/
/test/erl/rebar.lock
/test/go/bin/
/test/go/ThriftTest.thrift
/test/go/ThriftTest*.thrift
/test/go/gopath
/test/go/pkg/
/test/go/src/code.google.com/
@ -388,6 +392,7 @@ project.lock.json
/test/rs/target/
/test/rs/*.iml
/test/rs/**/*.iml
/test/swift/CrossTests/.build
/lib/cl/backport-update.zip
/lib/cl/lib
/tutorial/cl/quicklisp.lisp
@ -441,3 +446,12 @@ project.lock.json
/tutorial/netstd/Server/Properties/launchSettings.json
/tutorial/netstd/Client/Properties/launchSettings.json
/ylwrap
# Unit test generated artifacts
CMakeCache.txt
CMakeFiles
compiler/cpp/tests/*.cmake
compiler/cpp/tests/Testing/
compiler/cpp/tests/bin/
compiler/cpp/tests/*.a

View File

@ -17,7 +17,7 @@
# under the License.
#
# build Apache Thrift on Travis CI - https://travis-ci.org/
# build Apache Thrift on Travis CI - https://travis-ci.com/
#
# Docker Integration
@ -26,7 +26,7 @@
sudo: required
# https://docs.travis-ci.com/user/reference/linux
dist: xenial
dist: focal
language: cpp
services:
@ -61,13 +61,18 @@ jobs:
- stage: docker
script: true
env:
- JOB="Docker Build ubuntu-xenial 16.04 LTS"
- DISTRO=ubuntu-xenial
- JOB="Docker Build ubuntu-bionic 18.04 LTS"
- DISTRO=ubuntu-bionic
- TRAVIS_BUILD_STAGE=docker
- script: true
env:
- JOB="Docker Build ubuntu-bionic 18.04 LTS"
- DISTRO=ubuntu-bionic
- JOB="Docker Build ubuntu-focal 20.04 LTS"
- DISTRO=ubuntu-focal
- TRAVIS_BUILD_STAGE=docker
- script: true
env:
- JOB="Docker Build ubuntu-jammy 22.04 LTS"
- DISTRO=ubuntu-jammy
- TRAVIS_BUILD_STAGE=docker
# ========================= stage: thrift =======================
@ -112,15 +117,24 @@ jobs:
# ------------------------- phase: autotools --------------------
# TODO: Remove them once migrated to CMake
# TODO fix the missing python2 deps or get rid of python2
# - script: build/docker/run.sh
# env:
# - JOB="Autotools (Ubuntu Jammy)"
# - DISTRO=ubuntu-jammy
# - SCRIPT="autotools.sh"
- script: build/docker/run.sh
env:
- JOB="Autotools (Ubuntu Bionic)"
- JOB="Autotools (Ubuntu Focal)"
- DISTRO=ubuntu-focal
- SCRIPT="autotools.sh"
- script: build/docker/run.sh
env:
- JOB="Autotools (Ubuntu Xenial)"
- DISTRO=ubuntu-xenial
- JOB="Autotools (Ubuntu Bionic)"
- DISTRO=ubuntu-bionic
- SCRIPT="autotools.sh"
# ------------------------- phase: cmake ------------------------

View File

@ -19,14 +19,14 @@
the "Thrift" project.
2. nuget setApiKey <your-api-key>
3. nuget pack ApacheThrift.nuspec -Symbols -SymbolPackageFormat snupkg
4. nuget push ApacheThrift.0.17.0.nupkg -Source https://api.nuget.org/v3/index.json
4. nuget push ApacheThrift.0.19.0.nupkg -Source https://api.nuget.org/v3/index.json
-->
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>ApacheThrift</id>
<version>0.17.0</version>
<title>Apache Thrift 0.17.0</title>
<version>0.19.0</version>
<title>Apache Thrift 0.19.0</title>
<authors>Apache Thrift Developers</authors>
<owners>Apache Software Foundation</owners>
<license type="expression">Apache-2.0</license>
@ -36,7 +36,7 @@
<description>
Contains runtime libraries from lib/netstd for netstandard2.0 framework development.
</description>
<repository type="GitHub" url="https://github.com/apache/thrift" branch="release/0.17.0" />
<repository type="GitHub" url="https://github.com/apache/thrift" branch="release/0.19.0" />
<tags>Apache Thrift RPC</tags>
</metadata>
<files>

View File

@ -1,5 +1,184 @@
# Apache Thrift Changelog
## 0.19.0
### Known Open Issues (Blocker or Critical)
- [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++ library don't work with HTTP (csharp server, cpp client; need cross test enhancement)
- [THRIFT-5468](https://issues.apache.org/jira/browse/THRIFT-5468) - Swift service generator doesn't support oneway
- [THRIFT-5654](https://issues.apache.org/jira/browse/THRIFT-5654) - LNK4042 and LNK2019 in go_validator_generator.cc
## Build Process
- [THRIFT-5701](https://issues.apache.org/jira/browse/THRIFT-5701) - Add dependabot
## C++
- [THRIFT-5725](https://issues.apache.org/jira/browse/THRIFT-5725) - Thrift SSL server stops working if the file descriptor returned is zero
- [THRIFT-5716](https://issues.apache.org/jira/browse/THRIFT-5716) - TMemoryBuffer resizing might shrink the buffer size due to uint32_t overflow
## Compiler (General)
- [THRIFT-5690](https://issues.apache.org/jira/browse/THRIFT-5690) - Constant expects type to be defined before
## Delphi
- [THRIFT-5686](https://issues.apache.org/jira/browse/THRIFT-5686) - Add comparer and capacity arguments to container classes
## Go
- [THRIFT-5731](https://issues.apache.org/jira/browse/THRIFT-5731) - Handle ErrAbandonRequest automatically
## Haxe
- [THRIFT-5717](https://issues.apache.org/jira/browse/THRIFT-5717) - uuid sets and map keys may throw on some Haxe targets
- [THRIFT-5704](https://issues.apache.org/jira/browse/THRIFT-5704) - Superfluous block scope in generated write() code
- [THRIFT-5703](https://issues.apache.org/jira/browse/THRIFT-5703) - Haxe 4.30 emits "Local variable retval used without being initialized" on generated code
- [THRIFT-5692](https://issues.apache.org/jira/browse/THRIFT-5692) - Support for deprecated methods (via annotation)
- [THRIFT-5707](https://issues.apache.org/jira/browse/THRIFT-5707) - deprecation warning fixes for @:extern and @:enum
## Java
- [THRIFT-5700](https://issues.apache.org/jira/browse/THRIFT-5700) - Migration to JakartaEE and Apache HttpComponents 5
- [THRIFT-5711](https://issues.apache.org/jira/browse/THRIFT-5711) - FutureClient does not extend when service extends from another service
- [THRIFT-5702](https://issues.apache.org/jira/browse/THRIFT-5702) - Support Java 8
- [THRIFT-5696](https://issues.apache.org/jira/browse/THRIFT-5696) - TByteBuffer.java does not allow non-default TConfiguration
- [THRIFT-5653](https://issues.apache.org/jira/browse/THRIFT-5653) - Fix Java UUID typeid
## JavaScript
- [THRIFT-5674](https://issues.apache.org/jira/browse/THRIFT-5674) - Server implementation exceptions are not sent to client in ES6 promise-style invocation
## netstd
- [THRIFT-5684](https://issues.apache.org/jira/browse/THRIFT-5684) - Upgrade to net7.0
## Node.js
- [THRIFT-5710](https://issues.apache.org/jira/browse/THRIFT-5710) - NodeJS header transport leaks headers between all instances
## PHP
- [THRIFT-5723](https://issues.apache.org/jira/browse/THRIFT-5723) - Php8.1 fix warnings
## Swift
- [THRIFT-5714](https://issues.apache.org/jira/browse/THRIFT-5714) - add TJSONProtocol support in thrift-swift
## 0.18.1
### Known Open Issues (Blocker or Critical)
- [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++ library don't work with HTTP (csharp server, cpp client; need cross test enhancement)
- [THRIFT-5468](https://issues.apache.org/jira/browse/THRIFT-5468) - Swift service generator doesn't support oneway
### Reopened issues
- [THRIFT-5601](https://issues.apache.org/jira/browse/THRIFT-5601) - Typedef after first use causes incorrect go code
### Go
- [THRIFT-5685](https://issues.apache.org/jira/browse/THRIFT-5685) - Compiler generates wrong go code for forward defined types in optional fields
- [THRIFT-5679](https://issues.apache.org/jira/browse/THRIFT-5679) - libthrift-0.17.0 has wrong version numbers in MANIFEST.MF
## 0.18.0
### Known Open Issues (Blocker or Critical)
- [THRIFT-3877](https://issues.apache.org/jira/browse/THRIFT-3877) - C++ library don't work with HTTP (csharp server, cpp client; need cross test enhancement)
- [THRIFT-5468](https://issues.apache.org/jira/browse/THRIFT-5468) - Swift service generator doesn't support oneway
### Compiler (General)
- [THRIFT-5587](https://issues.apache.org/jira/browse/THRIFT-5587) - Introduce uuid as additional builtin type
- [THRIFT-5591](https://issues.apache.org/jira/browse/THRIFT-5591) - Add uuid type to IDL and implement reference code
- [THRIFT-5626](https://issues.apache.org/jira/browse/THRIFT-5626) - Parser should not confuse data types and field names
- [THRIFT-5627](https://issues.apache.org/jira/browse/THRIFT-5627) - More consistent syntax for cpp_type
- [THRIFT-5652](https://issues.apache.org/jira/browse/THRIFT-5652) - IDL uuid literals can be improved
- [THRIFT-5669](https://issues.apache.org/jira/browse/THRIFT-5669) - "required" keyword is illegal in a "throws" clause
### C++
- [THRIFT-5661](https://issues.apache.org/jira/browse/THRIFT-5661) - TOutput: add zephyr-specific strerror_s implementation
- [THRIFT-5658](https://issues.apache.org/jira/browse/THRIFT-5658) - TProtocol: support zephyr byteorder
- [THRIFT-5659](https://issues.apache.org/jira/browse/THRIFT-5659) - protocol: declare when methods override
### D language
- [THRIFT-5647](https://issues.apache.org/jira/browse/THRIFT-5647) - Fix undeclared identifier ECONNRESET on macOS
### Delphi
- [THRIFT-5618](https://issues.apache.org/jira/browse/THRIFT-5618) - More consistent naming of container classes
- [THRIFT-5620](https://issues.apache.org/jira/browse/THRIFT-5620) - Option to force usage of COM types to allow for cross-module references
- [THRIFT-5656](https://issues.apache.org/jira/browse/THRIFT-5656) - Escape Delphi keywords with '&' prefix instead of '_' suffix
- [THRIFT-5619](https://issues.apache.org/jira/browse/THRIFT-5619) - make sure CheckReadBytesAvailable() and CountConsumedMessageBytes() handle negative sizes properly
- [THRIFT-5622](https://issues.apache.org/jira/browse/THRIFT-5622) - Garbled test output with multithreaded clients
- [THRIFT-5625](https://issues.apache.org/jira/browse/THRIFT-5625) - SysUtils.TGuidHelper collides with ThriftUtils.TGuidHelper
### Erlang
- [THRIFT-5636](https://issues.apache.org/jira/browse/THRIFT-5636) - Broken client in erlang client library
### Go
- [THRIFT-5601](https://issues.apache.org/jira/browse/THRIFT-5601) - Typedef after first use causes incorrect go code
- [THRIFT-5650](https://issues.apache.org/jira/browse/THRIFT-5650) - Add UUID support in go
### Haxe
- [THRIFT-5593](https://issues.apache.org/jira/browse/THRIFT-5593) - Implement uuid for hx
### Java
- [THRIFT-3956](https://issues.apache.org/jira/browse/THRIFT-3956) - Java keywords that are legal in IDL can lead to generated code that will not compile
- [THRIFT-4655](https://issues.apache.org/jira/browse/THRIFT-4655) - Parser fails on the word "from"
- [THRIFT-5631](https://issues.apache.org/jira/browse/THRIFT-5631) - Execution failed for task ':generateBeanJava'.
- [THRIFT-5632](https://issues.apache.org/jira/browse/THRIFT-5632) - Fix java lib pmd main offending errors
### Kotlin
- [THRIFT-5646](https://issues.apache.org/jira/browse/THRIFT-5646) - Kotlin library should check to see if Gradle is present
### netstd
- [THRIFT-5610](https://issues.apache.org/jira/browse/THRIFT-5610) - Inconsistent constructors TSocketTransport
- [THRIFT-5623](https://issues.apache.org/jira/browse/THRIFT-5623) - ref to disposed instance should be set to null
- [THRIFT-5624](https://issues.apache.org/jira/browse/THRIFT-5624) - suboptimal performance of the c# named pipe server transport in multithread servers
- [THRIFT-5628](https://issues.apache.org/jira/browse/THRIFT-5628) - MaxMessageSize is never reset on a read buffer
- [THRIFT-5639](https://issues.apache.org/jira/browse/THRIFT-5639) - ToString() should use InvariantCulture
### OCaml
- [THRIFT-5208](https://issues.apache.org/jira/browse/THRIFT-5208) - OCaml codegen exception pattern match syntax error
- [THRIFT-5642](https://issues.apache.org/jira/browse/THRIFT-5642) - OCaml in docker build environment is broken
### Python
- [THRIFT-5617](https://issues.apache.org/jira/browse/THRIFT-5617) - T(SSL)Socket TCP keep-alive incorrectly applies SO_KEEPALIVE to IPPROTO_TCP
### Rust
- [THRIFT-5124](https://issues.apache.org/jira/browse/THRIFT-5124) - Cannot use reserved language keyword
- [THRIFT-5606](https://issues.apache.org/jira/browse/THRIFT-5606) - Wrong indent for const double
- [THRIFT-5600](https://issues.apache.org/jira/browse/THRIFT-5600) - Upgrade rust toolchain to 1.61 and edition 2021
- [THRIFT-5643](https://issues.apache.org/jira/browse/THRIFT-5643) - Please publish latest version of the Rust lib to crates.io
### Swift
- [THRIFT-5629](https://issues.apache.org/jira/browse/THRIFT-5629) - Add UUID support for Swift
- [THRIFT-4547](https://issues.apache.org/jira/browse/THRIFT-4547) - Finish the conversion to native swift (LANGUAGES.md, cross test)
- [THRIFT-5621](https://issues.apache.org/jira/browse/THRIFT-5621) - Create Swift Tutorial
- [THRIFT-5630](https://issues.apache.org/jira/browse/THRIFT-5630) - Swift TSocketServer not working on Linux
### Website
- [THRIFT-5634](https://issues.apache.org/jira/browse/THRIFT-5634) - thrift docs picture was broken
## 0.17.0
### Known Open Issues (Blocker or Critical)

View File

@ -28,7 +28,7 @@ endif()
# PACKAGE_VERSION is used by cpack scripts currently
# Both thrift_VERSION and PACKAGE_VERSION should be the same for now
set(thrift_VERSION "0.17.0")
set(thrift_VERSION "0.19.0")
set(PACKAGE_VERSION ${thrift_VERSION})
project("thrift" VERSION ${PACKAGE_VERSION})

View File

@ -66,289 +66,289 @@ Thrift's core protocol is TBinary, supported by all languages except for JavaScr
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/c_glib/README.md">C (glib)</a></td>
<!-- Since -----------------><td>0.6.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Language Levels -------><td>2.48.2</td><td>2.56.4</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22C%20glib%20-%20Compiler%22%2C%20%22C%20glib%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">C (glib)</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/cpp/README.md">C++</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Language Levels -------><td colspan=2>C++11</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22C%2B%2B%20-%20Compiler%22%2C%20%22C%2B%2B%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">C++</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/cl/README.md">Common LISP</a></td>
<!-- Since -----------------><td>0.12.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>SBCL 1.4.x</td><td>SBCL 1.5.3</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Common%20LISP%20-%20Compiler%22%2C%20%22Common%20LISP%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Common LISP</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/d/README.md">Dlang</a></td>
<!-- Since -----------------><td>0.9.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>2.087.0</td><td>2.087.0</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22D%20-%20Compiler%22%2C%20%22D%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">D</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/dart/README.md">Dart</a></td>
<!-- Since -----------------><td>0.10.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>2.0.0</td><td>2.4.0</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Dart%20-%20Compiler%22%2C%20%22Dart%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Dart</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/delphi/README.md">Delphi</a></td>
<!-- Since -----------------><td>0.8.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>2010</td><td>Sydney 10.4.1</td>
<!-- Field types -----------><td><img src="doc/images/cgrn.png" alt="Yes"/><td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>2010</td><td>Alexandria 11.2</td>
<!-- Field types -----------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Delphi%20-%20Compiler%22%2C%20%22Delphi%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Delphi</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/netstd/README.md">.NET Standard</a></td>
<!-- Since -----------------><td>0.13.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td colspan=2>.NET 4.5+, .NET Standard 2.x, .NET 5.0</td>
<!-- Field types -----------><td><img src="doc/images/cgrn.png" alt="Yes"/><td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td colspan=2>.NET Standard 2.x, .NET 6</td>
<!-- Field types -----------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22netstd%20-%20Compiler%22%2C%20%22netstd%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">.NET Standard</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/erl/README.md">Erlang</a></td>
<!-- Since -----------------><td>0.3.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>18.3</td><td>22.0</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Erlang%20-%20Compiler%22%2C%20%22Erlang%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Erlang</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/go/README.md">Go</a></td>
<!-- Since -----------------><td>0.7.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>1.18.5</td><td>1.19</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>1.20</td><td>1.21</td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Go%20-%20Compiler%22%2C%20%22Go%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Go</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/haxe/README.md">Haxe</a></td>
<!-- Since -----------------><td>0.9.3</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>4.1.5</td><td>4.2.1</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>4.1.5</td><td>4.2.5</td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Haxe%20-%20Compiler%22%2C%20%22Haxe%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Haxe</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/java/README.md">Java (SE)</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Language Levels -------><td>1.8.0_151</td><td>11.0.3</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Language Levels -------><td>11</td><td>19</td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Java%20-%20Compiler%22%2C%20%22Java%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Java SE</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/javame/README.md">Java (ME)</a></td>
<!-- Since -----------------><td>0.5.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td colspan=2>unknown</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22JavaME%20-%20Compiler%22%2C%20%22JavaME%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Java ME</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/js/README.md">Javascript</a></td>
<!-- Since -----------------><td>0.3.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>ES5</td><td>ES6</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Javascript%20-%20Compiler%22%2C%20%22Javascript%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Javascript</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/lua/README.md">Lua</a></td>
<!-- Since -----------------><td>0.9.2</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>5.1.5</td><td>5.2.4</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Lua%20-%20Compiler%22%2C%20%22Lua%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Lua</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/nodejs/README.md">node.js</a></td>
<!-- Since -----------------><td>0.6.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>10.x</td><td>10.x</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Node.js%20-%20Compiler%22%2C%20%22Node.js%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">node.js</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/nodets/README.md">node.ts</a></td>
<!-- Since -----------------><td>0.12.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>3.1.6</td><td></td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22TypeScript%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">node.ts</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/ocaml/README.md">OCaml</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td colspan=2>4.04.0</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22OCaml%20-%20Compiler%22%2C%20%22OCaml%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">OCaml</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/perl/README.md">Perl</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>5.22.1</td><td>5.26.1</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Perl%20-%20Compiler%22%2C%20%22Perl%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Perl</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/php/README.md">PHP</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>7.0.22</td><td>7.2.19</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22PHP%20-%20Compiler%22%2C%20%22PHP%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">PHP</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/py/README.md">Python</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Language Levels -------><td>2.7.12, 3.5.2</td><td>2.7.15, 3.6.8</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Python%20-%20Compiler%22%2C%20%22Python%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Python</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/rb/README.md">Ruby</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>2.3.1p112</td><td>2.5.1p57</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Ruby%20-%20Compiler%22%2C%20%22Ruby%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Ruby</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/rs/README.md">Rust</a></td>
<!-- Since -----------------><td>0.11.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>1.40.0</td><td>1.xx.x</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td>1.61.0</td><td>1.xx.x</td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Rust%20-%20Compiler%22%2C%20%22Rust%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Rust</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/st/README.md">Smalltalk</a></td>
<!-- Since -----------------><td>0.2.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td colspan=2>unknown</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Smalltalk%20-%20Compiler%22%2C%20%22Smalltalk%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Smalltalk</a></td>
</tr>
<tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/swift/README.md">Swift</a></td>
<!-- Since -----------------><td>0.12.0</td>
<!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td colspan=2>4.2.1</td>
<!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td>
<!-- Build Systems ---------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Language Levels -------><td colspan=2>5.7</td>
<!-- Field types -----------><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Low-Level Transports --><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Transport Wrappers ----><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td>
<!-- Protocols -------------><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<!-- Servers ---------------><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cred.png" alt=""/></td><td><img src="/doc/images/cgrn.png" alt="Yes"/></td>
<td align=left><a href="https://issues.apache.org/jira/issues/?jql=project%20%3D%20THRIFT%20AND%20component%20in%20(%22Swift%20-%20Compiler%22%2C%20%22Swift%20-%20Library%22)%20and%20status%20not%20in%20(fixed%2C%20resolved%2C%20closed)">Swift</a></td>
</tr>
</tbody>

View File

@ -78,7 +78,7 @@ empty :=
space := $(empty) $(empty)
comma := ,
CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_NETSTD@ @MAYBE_NODETS@ @MAYBE_KOTLIN@
CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_CL@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_NETSTD@ @MAYBE_NODETS@ @MAYBE_KOTLIN@ @MAYBE_SWIFT@
CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS))
if WITH_PY3
@ -157,7 +157,6 @@ EXTRA_DIST = \
doc \
dub.json \
go.mod \
go.sum \
jitpack.yml \
LANGUAGES.md \
LICENSE \

View File

@ -35,8 +35,8 @@ Status
| Branch | Travis | Appveyor | Coverity Scan | codecov.io | Website |
| :----- | :----- | :------- | :------------ | :--------- | :------ |
| [`master`](https://github.com/apache/thrift/tree/master) | [![Build Status](https://travis-ci.org/apache/thrift.svg?branch=master)](https://travis-ci.org/apache/thrift/branches) | [![Build status](https://ci.appveyor.com/api/projects/status/github/apache/thrift?branch=master&svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/thrift/history) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/1345/badge.svg)](https://scan.coverity.com/projects/thrift) | | [![Website](https://img.shields.io/badge/official-website-brightgreen.svg)](https://thrift.apache.org/) |
| [`0.14.0`](https://github.com/apache/thrift/tree/0.14.0) | [![Build Status](https://travis-ci.org/apache/thrift.svg?branch=0.14.0)](https://travis-ci.org/apache/thrift/branches) | | | | |
| [`master`](https://github.com/apache/thrift/tree/master) | [![Build Status](https://api.travis-ci.com/apache/thrift.svg?branch=master)](https://app.travis-ci.com/apache/thrift/branches) | [![Build status](https://ci.appveyor.com/api/projects/status/github/apache/thrift?branch=master&svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/thrift/history) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/1345/badge.svg)](https://scan.coverity.com/projects/thrift) | | [![Website](https://img.shields.io/badge/official-website-brightgreen.svg)](https://thrift.apache.org/) |
| [`0.17.0`](https://github.com/apache/thrift/tree/0.17.0) | [![Build Status](https://api.travis-ci.com/apache/thrift.svg?branch=0.17.0)](https://app.travis-ci.com/apache/thrift/branches) | | | | |
Releases
========

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Thrift'
s.version = '0.17.0'
s.version = '0.19.0'
s.summary = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC."
s.description = <<-DESC
The Apache Thrift scalable cross-language software framework for networked services development combines a software stack with a code generation engine to build services that work efficiently and seamlessly between many programming languages.
@ -10,6 +10,6 @@ The Apache Thrift scalable cross-language software framework for networked servi
s.author = { 'Apache Thrift Developers' => 'dev@thrift.apache.org' }
s.ios.deployment_target = '9.0'
s.osx.deployment_target = '10.10'
s.source = { :git => 'https://github.com/apache/thrift.git', :tag => 'v0.17.0' }
s.source = { :git => 'https://github.com/apache/thrift.git', :tag => 'v0.19.0' }
s.source_files = 'lib/swift/Sources/*.swift'
end

View File

@ -19,7 +19,7 @@
# build Apache Thrift on AppVeyor - https://ci.appveyor.com
version: '0.17.0.{build}'
version: '0.19.0.{build}'
shallow_clone: true

View File

@ -1,6 +1,6 @@
{
"name": "thrift",
"version": "0.17.0",
"version": "0.19.0",
"homepage": "https://github.com/apache/thrift.git",
"authors": [
"Apache Thrift <dev@thrift.apache.org>"

View File

@ -40,5 +40,6 @@ if (NOT CYGWIN)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ThriftConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/ThriftConfigVersion.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/FindLibevent.cmake"
DESTINATION "${CMAKE_INSTALL_DIR}/thrift")
endif()

View File

@ -24,7 +24,9 @@ set(THRIFT_VERSION @thrift_VERSION@)
set_and_check(THRIFT_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(THRIFT_CMAKE_DIR "@PACKAGE_CMAKE_INSTALL_DIR@")
set_and_check(THRIFT_BIN_DIR "@PACKAGE_BIN_INSTALL_DIR@")
if(NOT DEFINED THRIFT_COMPILER)
set(THRIFT_COMPILER "${THRIFT_BIN_DIR}/thrift@CMAKE_EXECUTABLE_SUFFIX@")
endif()
if (NOT TARGET thrift::thrift)
include("${THRIFT_CMAKE_DIR}/thriftTargets.cmake")
@ -57,7 +59,19 @@ if(@OPENSSL_FOUND@ AND @WITH_OPENSSL@)
endif()
if(@Libevent_FOUND@ AND @WITH_LIBEVENT@)
if(DEFINED CMAKE_MODULE_PATH)
set(THRIFT_CMAKE_MODULE_PATH_OLD ${CMAKE_MODULE_PATH})
else()
unset(THRIFT_CMAKE_MODULE_PATH_OLD)
endif()
set(CMAKE_MODULE_PATH "${THRIFT_CMAKE_DIR}")
find_dependency(Libevent)
if(DEFINED THRIFT_CMAKE_MODULE_PATH_OLD)
set(CMAKE_MODULE_PATH ${THRIFT_CMAKE_MODULE_PATH_OLD})
unset(THRIFT_CMAKE_MODULE_PATH_OLD)
else()
unset(CMAKE_MODULE_PATH)
endif()
endif()
check_required_components(Thrift)

View File

@ -52,9 +52,9 @@ coverage.
### Ubuntu ###
* bionic (stable, current)
* artful (previous stable)
* xenial (legacy)
* focal (stable, current)
* bionic (previous stable)
* jammy (next stable, WIP)
## Unsupported Containers ##
@ -172,17 +172,18 @@ Last updated: October 1, 2017
| C++ gcc | 5.4.0 | 7.4.0 | |
| C++ clang | 3.8 | 6.0 | |
| C# (mono) | 4.2.1.0 | 4.6.2.7 | |
| c_glib | 2.48.2 | 2.56.4 | |
| c\_glib | 2.48.2 | 2.56.4 | |
| cl (sbcl) | | 1.5.3 | |
| d | 2.087.0 | 2.087.0 | |
| dart | 2.0.0 | 2.4.0 | |
| delphi | | | Not in CI |
| erlang | OTP-18 | OTP-23 | |
| go | 1.15.10 | 1.16.2 | |
| haxe | 3.2.1 | 3.4.4 | THRIFT-4352: avoid 3.4.2 |
| java | 1.8.0_191 | 11.0.3 | |
| java | 1.8.0\_191 | 17 | |
| js | Node.js 6.17.1, V8 5.1.281.111, npm 3.10.10 | Node.js 10.18.0, V8 6.8.275.32, npm 6.13.4 | |
| lua | | 5.2.4 | Lua 5.3: see THRIFT-4386 |
| netstd | 6.0 | 6.0 | |
| netstd | 7.0 | 7.0 | |
| nodejs | 6.16.0 | 10.16.0 | |
| ocaml | | 4.05.0 | THRIFT-4517: ocaml 4.02.3 on xenial appears broken |
| perl | 5.22.1 | 5.26.1 | |
@ -190,6 +191,6 @@ Last updated: October 1, 2017
| python | 2.7.12 | 2.7.15 | |
| python3 | 3.5.2 | 3.6.8 | |
| ruby | 2.3.1p112 | 2.5.1p57 | |
| rust | 1.40.0 | 1.40.0 | |
| rust | 1.61.0 | 1.61.0 | |
| smalltalk | | | Not in CI |
| swift | | 5.1.4 | |

View File

@ -102,10 +102,10 @@ ENV PATH /usr/lib/dart/bin:$PATH
# project isn't ready for this quite yet:
# RUN apt-get install -y --no-install-recommends \
# `# dotnet core dependencies` \
# dotnet-sdk-6.0 \
# dotnet-runtime-6.0 \
# aspnetcore-runtime-6.0 \
# dotnet-apphost-pack-6.0
# dotnet-sdk-7.0 \
# dotnet-runtime-7.0 \
# aspnetcore-runtime-7.0 \
# dotnet-apphost-pack-7.0
RUN apt-get install -y --no-install-recommends \
`# Erlang dependencies` \

View File

@ -85,6 +85,17 @@ RUN apt-get install -y --no-install-recommends \
qtbase5-dev \
qtbase5-dev-tools
ENV SBCL_VERSION 1.4.5
RUN \
`# Common Lisp (sbcl) dependencies` \
curl --version && \
curl -O -J -L https://kent.dl.sourceforge.net/project/sbcl/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
cd sbcl-${SBCL_VERSION}-x86-64-linux && \
./install.sh && \
sbcl --version && \
rm -rf sbcl*
ENV D_VERSION 2.080.0
ENV DMD_DEB dmd_2.080.0-0_amd64.deb
RUN \
@ -109,10 +120,10 @@ ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \
dotnet-sdk-6.0 \
dotnet-runtime-6.0 \
aspnetcore-runtime-6.0 \
dotnet-apphost-pack-6.0
dotnet-sdk-7.0 \
dotnet-runtime-7.0 \
aspnetcore-runtime-7.0 \
dotnet-apphost-pack-7.0
RUN apt-get install -y --no-install-recommends \
`# Erlang dependencies` \

View File

@ -89,6 +89,18 @@ RUN apt-get install -y --no-install-recommends \
qtbase5-dev \
qtbase5-dev-tools
ENV SBCL_VERSION 1.5.3
RUN \
`# Common Lisp (sbcl) dependencies` \
curl --version && \
curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \
tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
cd sbcl-${SBCL_VERSION}-x86-64-linux && \
./install.sh && \
sbcl --version && \
cd .. && \
rm -rf sbcl*
ENV D_VERSION 2.087.0
ENV DMD_DEB dmd_2.087.0-0_amd64.deb
RUN \
@ -114,10 +126,10 @@ ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \
dotnet-sdk-6.0 \
dotnet-runtime-6.0 \
aspnetcore-runtime-6.0 \
dotnet-apphost-pack-6.0
dotnet-sdk-7.0 \
dotnet-runtime-7.0 \
aspnetcore-runtime-7.0 \
dotnet-apphost-pack-7.0
RUN apt-get install -y --no-install-recommends \
`# Erlang dependencies` \
@ -148,7 +160,7 @@ RUN apt-get install -y --no-install-recommends \
haxelib setup --always /usr/share/haxe/lib && \
haxelib install --always hxcpp 2>&1 > /dev/null
ENV GRADLE_VERSION="7.4.2"
ENV GRADLE_VERSION="8.0.2"
RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \
ant \
@ -157,7 +169,7 @@ RUN apt-get install -y --no-install-recommends \
openjdk-11-jdk-headless && \
`# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
(echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
(echo "ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7 /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin
@ -242,7 +254,7 @@ RUN apt-get install -y --no-install-recommends \
ruby-bundler
# Rust dependencies
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
ENV PATH /root/.cargo/bin:$PATH
# Swift on Linux for cross tests

View File

@ -115,10 +115,10 @@ ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \
dotnet-sdk-6.0 \
dotnet-runtime-6.0 \
aspnetcore-runtime-6.0 \
dotnet-apphost-pack-6.0
dotnet-sdk-7.0 \
dotnet-runtime-7.0 \
aspnetcore-runtime-7.0 \
dotnet-apphost-pack-7.0
# Erlang dependencies
ARG ERLANG_OTP_VERSION=18.3.4.11
@ -155,7 +155,7 @@ RUN apt-get install -y --no-install-recommends \
haxelib install --always hxcpp 3.4.64 2>&1 > /dev/null
# note: hxcpp 3.4.185 (latest) no longer ships static libraries, and caused a build failure
ENV GRADLE_VERSION="7.4.2"
ENV GRADLE_VERSION="8.0.2"
RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \
ant \
@ -165,7 +165,7 @@ RUN apt-get install -y --no-install-recommends \
unzip && \
`# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
(echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
(echo "ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7 /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin
@ -249,7 +249,7 @@ RUN apt-get install -y --no-install-recommends \
ruby-bundler
# Rust dependencies
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
# Locale(s) for cpp unit tests
RUN apt-get install -y --no-install-recommends \

View File

@ -1,7 +1,7 @@
#!/bin/sh
set -ev
mkdir ~/.m2
mkdir -p ~/.m2
tee >~/.m2/settings.xml <<EOF
<settings xmlns='http://maven.apache.org/SETTINGS/1.0.0'>
<mirrors>

View File

@ -16,12 +16,12 @@
#
FROM buildpack-deps:bionic-scm
MAINTAINER Apache Thrift <dev@thrift.apache.org>
LABEL MAINTAINER='Apache Thrift <dev@thrift.apache.org>'
ENV DEBIAN_FRONTEND noninteractive
### Add apt repos
RUN apt-get update && \
RUN apt-get update -yq && \
apt-get dist-upgrade -y && \
apt-get install -y --no-install-recommends --fix-missing \
apt \
@ -87,6 +87,18 @@ RUN apt-get install -y --no-install-recommends \
qtbase5-dev \
qtbase5-dev-tools
ENV SBCL_VERSION 1.5.3
RUN \
`# Common Lisp (sbcl) dependencies` \
curl --version && \
curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \
tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
cd sbcl-${SBCL_VERSION}-x86-64-linux && \
./install.sh && \
sbcl --version && \
cd .. && \
rm -rf sbcl*
ENV D_VERSION 2.087.0
ENV DMD_DEB dmd_2.087.0-0_amd64.deb
RUN \
@ -112,10 +124,10 @@ ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \
dotnet-sdk-6.0 \
dotnet-runtime-6.0 \
aspnetcore-runtime-6.0 \
dotnet-apphost-pack-6.0
dotnet-sdk-7.0 \
dotnet-runtime-7.0 \
aspnetcore-runtime-7.0 \
dotnet-apphost-pack-7.0
# Erlang dependencies
ARG ERLANG_OTP_VERSION=23.3.4.11
@ -132,9 +144,9 @@ RUN apt-get install -y --no-install-recommends \
libglib2.0-dev
# golang
ENV GOLANG_VERSION 1.19
ENV GOLANG_VERSION 1.19.5
ENV GOLANG_DOWNLOAD_URL https://go.dev/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 464b6b66591f6cf055bc5df90a9750bf5fbc9d038722bb84a9d56a2bea974be6
ENV GOLANG_DOWNLOAD_SHA256 36519702ae2fd573c9869461990ae550c8c0d955cd28d2827a6b159fda81ff95
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \
tar -C /usr/local -xzf golang.tar.gz && \
@ -149,16 +161,16 @@ RUN apt-get install -y --no-install-recommends \
haxelib setup --always /usr/share/haxe/lib && \
haxelib install --always hxcpp 2>&1 > /dev/null
ENV GRADLE_VERSION="7.4.2"
ENV GRADLE_VERSION="8.0.2"
RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \
ant \
ant-optional \
maven \
openjdk-11-jdk-headless && \
openjdk-17-jdk-headless && \
`# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
(echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
(echo "ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7 /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin
@ -242,15 +254,23 @@ RUN apt-get install -y --no-install-recommends \
ruby-bundler
# Rust dependencies
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
ENV PATH /root/.cargo/bin:$PATH
# Swift on Linux for cross tests
RUN cd / && \
wget --quiet https://swift.org/builds/swift-5.1.4-release/ubuntu1804/swift-5.1.4-RELEASE/swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \
tar xf swift-5.1.4-RELEASE-ubuntu18.04.tar.gz --strip-components=1 && \
rm swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \
swift --version
RUN apt-get install -yq \
libedit-dev \
libz3-dev \
libpython-dev \
libxml2-dev && \
cd / && \
wget --quiet https://download.swift.org/swift-5.7-release/ubuntu1804/swift-5.7-RELEASE/swift-5.7-RELEASE-ubuntu18.04.tar.gz && \
tar xf swift-5.7-RELEASE-ubuntu18.04.tar.gz && \
mv swift-5.7-RELEASE-ubuntu18.04 /usr/share/swift && \
rm swift-5.7-RELEASE-ubuntu18.04.tar.gz
ENV PATH /usr/share/swift/usr/bin:$PATH
RUN swift --version
# Locale(s) for cpp unit tests
RUN apt-get install -y --no-install-recommends \
@ -260,15 +280,11 @@ RUN apt-get install -y --no-install-recommends \
locale-gen de_DE.UTF-8 && \
update-locale
# cppcheck-1.82 has a nasty cpp parser bug, so we're using something newer
RUN apt-get install -y --no-install-recommends \
`# Static Code Analysis dependencies` \
cppcheck \
sloccount && \
pip install flake8 && \
wget -q "https://launchpad.net/ubuntu/+source/cppcheck/1.83-2/+build/14874703/+files/cppcheck_1.83-2_amd64.deb" && \
dpkg -i cppcheck_1.83-2_amd64.deb && \
rm cppcheck_1.83-2_amd64.deb
pip install flake8
# NOTE: this does not reduce the image size but adds an additional layer.
# # Clean up

View File

@ -0,0 +1,286 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Apache Thrift Docker build environment for Ubuntu Focal
# with some updated packages.
#
FROM buildpack-deps:focal-scm
LABEL MAINTAINER="Apache Thrift <dev@thrift.apache.org>"
ENV DEBIAN_FRONTEND=noninteractive
### Add apt repos
RUN apt-get update -yq && \
apt-get dist-upgrade -y && \
apt-get install -y --no-install-recommends --fix-missing \
apt \
apt-transport-https \
apt-utils \
curl \
dirmngr \
software-properties-common \
wget
# Dart
RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
/etc/apt/sources.list.d/dart_stable.list
# dotnet (netcore)
RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \
chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \
chown root:root /etc/apt/sources.list.d/microsoft-prod.list
# node.js
RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
echo "deb https://deb.nodesource.com/node_16.x focal main" | tee /etc/apt/sources.list.d/nodesource.list
### install general dependencies
RUN apt-get update -yq && \
apt-get install -y --no-install-recommends \
`# General dependencies` \
bash-completion \
bison \
build-essential \
clang \
cmake \
debhelper \
flex \
gdb \
libasound2 \
libatk-bridge2.0-0 \
libgtk-3-0 \
llvm \
ninja-build \
pkg-config \
unzip \
valgrind \
vim
ENV PATH /usr/lib/llvm-6.0/bin:$PATH
# lib/as3 (ActionScript)
RUN mkdir -p /usr/local/adobe/flex/4.6 && \
cd /usr/local/adobe/flex/4.6 && \
wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \
unzip flex_sdk_4.6.zip
ENV FLEX_HOME /usr/local/adobe/flex/4.6
# TODO: "apt-get install" without "apt-get update" in the same "RUN" step can cause cache issues if modified later.
# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
RUN apt-get install -y --no-install-recommends \
`# C++ dependencies` \
libboost-all-dev \
libevent-dev \
libssl-dev \
qt5-default \
qtbase5-dev \
qtbase5-dev-tools
ENV SBCL_VERSION 1.5.3
RUN \
`# Common Lisp (sbcl) dependencies` \
curl --version && \
curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \
tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
cd sbcl-${SBCL_VERSION}-x86-64-linux && \
./install.sh && \
sbcl --version && \
cd .. && \
rm -rf sbcl*
ENV D_VERSION 2.087.0
ENV DMD_DEB dmd_2.087.0-0_amd64.deb
RUN \
`# D dependencies` \
wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
dpkg --install ${DMD_DEB} && \
rm -f ${DMD_DEB} && \
mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
rm -rf deimos-libevent-2.0 && \
git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \
mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \
rm -rf deimos-openssl-1.1.0h
ENV DART_VERSION 2.7.2-1
RUN apt-get install -y --no-install-recommends \
`# Dart dependencies` \
dart=$DART_VERSION
ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \
dotnet-sdk-7.0 \
dotnet-runtime-7.0 \
aspnetcore-runtime-7.0 \
dotnet-apphost-pack-7.0
# Erlang dependencies
ARG ERLANG_OTP_VERSION=23.3.4.11
ARG ERLANG_REBAR_VERSION=3.18.0
RUN apt-get update && apt-get install -y --no-install-recommends libncurses5-dev && \
curl -ssLo /usr/local/bin/kerl https://raw.githubusercontent.com/kerl/kerl/master/kerl && chmod +x /usr/local/bin/kerl && \
kerl build $ERLANG_OTP_VERSION && kerl install $ERLANG_OTP_VERSION /usr/local/lib/otp/ && . /usr/local/lib/otp/activate && \
curl -ssLo /usr/local/bin/rebar3 https://github.com/erlang/rebar3/releases/download/${ERLANG_REBAR_VERSION}/rebar3 && chmod +x /usr/local/bin/rebar3 && \
rebar3 --version
ENV PATH /usr/local/lib/otp/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# GlibC dependencies` \
libglib2.0-dev
# golang
ENV GOLANG_VERSION 1.20
ENV GOLANG_DOWNLOAD_URL https://go.dev/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 5a9ebcc65c1cce56e0d2dc616aff4c4cedcfbda8cc6f0288cc08cda3b18dcbf1
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \
tar -C /usr/local -xzf golang.tar.gz && \
ln -s /usr/local/go/bin/go /usr/local/bin && \
rm golang.tar.gz
RUN apt-get install -y --no-install-recommends \
`# Haxe dependencies` \
haxe \
neko \
neko-dev && \
haxelib setup --always /usr/share/haxe/lib && \
haxelib install --always hxcpp 2>&1 > /dev/null
ENV GRADLE_VERSION="8.0.2"
RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \
ant \
ant-optional \
maven \
openjdk-17-jdk-headless && \
`# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
(echo "ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7 /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin
RUN apt-get install -y --no-install-recommends \
`# Lua dependencies` \
lua5.2 \
lua5.2-dev
# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
# lua5.3 does not install alternatives!
# need to update our luasocket code, lua doesn't have luaL_openlib any more
RUN apt-get install -y --no-install-recommends \
`# Node.js dependencies` \
nodejs
# Test dependencies for running puppeteer
RUN apt-get install -y --no-install-recommends \
`# JS dependencies` \
libxss1 \
libxtst6
RUN apt-get install -y --no-install-recommends \
`# OCaml dependencies` \
ocaml \
opam && \
`# disable sandboxing see https://github.com/ocaml/opam/issues/4327` \
opam init --yes --disable-sandboxing && \
opam install --yes oasis
RUN apt-get install -y --no-install-recommends \
`# Perl dependencies` \
libbit-vector-perl \
libclass-accessor-class-perl \
libcrypt-ssleay-perl \
libio-socket-ssl-perl \
libnet-ssleay-perl \
libtest-exception-perl
RUN apt-get install -y --no-install-recommends \
`# Php dependencies` \
php \
php-cli \
php-dev \
php-json \
php-pear \
re2c \
composer
RUN apt-get install -y --no-install-recommends \
`# Python3 dependencies` \
python3-all \
python3-all-dbg \
python3-all-dev \
python3-pip \
python3-setuptools \
python3-six \
python3-tornado \
python3-twisted \
python3-wheel \
python3-zope.interface
RUN apt-get install -y --no-install-recommends \
`# Ruby dependencies` \
ruby \
ruby-dev \
ruby-bundler
# Rust dependencies
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
ENV PATH /root/.cargo/bin:$PATH
# Swift on Linux for cross tests
RUN apt-get install -yq \
libedit-dev \
libz3-dev \
libpython2-dev \
libxml2-dev && \
cd / && \
wget --quiet https://download.swift.org/swift-5.7-release/ubuntu2004/swift-5.7-RELEASE/swift-5.7-RELEASE-ubuntu20.04.tar.gz && \
tar xf swift-5.7-RELEASE-ubuntu20.04.tar.gz && \
mv swift-5.7-RELEASE-ubuntu20.04 /usr/share/swift && \
rm swift-5.7-RELEASE-ubuntu20.04.tar.gz
ENV PATH /usr/share/swift/usr/bin:$PATH
RUN swift --version
# Locale(s) for cpp unit tests
RUN apt-get install -y --no-install-recommends \
`# Locale dependencies` \
locales && \
locale-gen en_US.UTF-8 && \
locale-gen de_DE.UTF-8 && \
update-locale
RUN apt-get install -y --no-install-recommends \
`# Static Code Analysis dependencies` \
cppcheck \
sloccount && \
pip install flake8
# NOTE: this does not reduce the image size but adds an additional layer.
# # Clean up
# RUN rm -rf /var/cache/apt/* && \
# rm -rf /var/lib/apt/lists/* && \
# rm -rf /tmp/* && \
# rm -rf /var/tmp/*
ENV THRIFT_ROOT /thrift
RUN mkdir -p $THRIFT_ROOT/src
COPY Dockerfile $THRIFT_ROOT/
WORKDIR $THRIFT_ROOT/src

View File

@ -0,0 +1,286 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Apache Thrift Docker build environment for Ubuntu Jammy
# with some updated packages.
#
FROM buildpack-deps:jammy-scm
LABEL MAINTAINER="Apache Thrift <dev@thrift.apache.org>"
ENV DEBIAN_FRONTEND=noninteractive
### Add apt repos
RUN apt-get update -yq && \
apt-get dist-upgrade -y && \
apt-get install -y --no-install-recommends --fix-missing \
apt \
apt-transport-https \
apt-utils \
curl \
dirmngr \
software-properties-common \
wget
# Dart
RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
/etc/apt/sources.list.d/dart_stable.list
# dotnet (netcore)
RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \
chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \
chown root:root /etc/apt/sources.list.d/microsoft-prod.list
# node.js
RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
echo "deb https://deb.nodesource.com/node_16.x focal main" | tee /etc/apt/sources.list.d/nodesource.list
### install general dependencies
RUN apt-get update -yq && \
apt-get install -y --no-install-recommends \
`# General dependencies` \
bash-completion \
bison \
build-essential \
clang \
cmake \
debhelper \
flex \
gdb \
libasound2 \
libatk-bridge2.0-0 \
libgtk-3-0 \
llvm \
ninja-build \
pkg-config \
unzip \
valgrind \
vim
ENV PATH /usr/lib/llvm-6.0/bin:$PATH
# lib/as3 (ActionScript)
RUN mkdir -p /usr/local/adobe/flex/4.6 && \
cd /usr/local/adobe/flex/4.6 && \
wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \
unzip flex_sdk_4.6.zip
ENV FLEX_HOME /usr/local/adobe/flex/4.6
# TODO: "apt-get install" without "apt-get update" in the same "RUN" step can cause cache issues if modified later.
# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
RUN apt-get install -y --no-install-recommends \
`# C++ dependencies` \
libboost-all-dev \
libevent-dev \
libssl-dev \
qt5-default \
qtbase5-dev \
qtbase5-dev-tools
ENV SBCL_VERSION 1.5.3
RUN \
`# Common Lisp (sbcl) dependencies` \
curl --version && \
curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \
tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
cd sbcl-${SBCL_VERSION}-x86-64-linux && \
./install.sh && \
sbcl --version && \
cd .. && \
rm -rf sbcl*
ENV D_VERSION 2.087.0
ENV DMD_DEB dmd_2.087.0-0_amd64.deb
RUN \
`# D dependencies` \
wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
dpkg --install ${DMD_DEB} && \
rm -f ${DMD_DEB} && \
mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
rm -rf deimos-libevent-2.0 && \
git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \
mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \
rm -rf deimos-openssl-1.1.0h
ENV DART_VERSION 2.7.2-1
RUN apt-get install -y --no-install-recommends \
`# Dart dependencies` \
dart=$DART_VERSION
ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \
dotnet-sdk-7.0 \
dotnet-runtime-7.0 \
aspnetcore-runtime-7.0 \
dotnet-apphost-pack-7.0
# Erlang dependencies
ARG ERLANG_OTP_VERSION=23.3.4.11
ARG ERLANG_REBAR_VERSION=3.18.0
RUN apt-get update && apt-get install -y --no-install-recommends libncurses5-dev && \
curl -ssLo /usr/local/bin/kerl https://raw.githubusercontent.com/kerl/kerl/master/kerl && chmod +x /usr/local/bin/kerl && \
kerl build $ERLANG_OTP_VERSION && kerl install $ERLANG_OTP_VERSION /usr/local/lib/otp/ && . /usr/local/lib/otp/activate && \
curl -ssLo /usr/local/bin/rebar3 https://github.com/erlang/rebar3/releases/download/${ERLANG_REBAR_VERSION}/rebar3 && chmod +x /usr/local/bin/rebar3 && \
rebar3 --version
ENV PATH /usr/local/lib/otp/bin:$PATH
RUN apt-get install -y --no-install-recommends \
`# GlibC dependencies` \
libglib2.0-dev
# golang
ENV GOLANG_VERSION 1.20
ENV GOLANG_DOWNLOAD_URL https://go.dev/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 5a9ebcc65c1cce56e0d2dc616aff4c4cedcfbda8cc6f0288cc08cda3b18dcbf1
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \
tar -C /usr/local -xzf golang.tar.gz && \
ln -s /usr/local/go/bin/go /usr/local/bin && \
rm golang.tar.gz
RUN apt-get install -y --no-install-recommends \
`# Haxe dependencies` \
haxe \
neko \
neko-dev && \
haxelib setup --always /usr/share/haxe/lib && \
haxelib install --always hxcpp 2>&1 > /dev/null
ENV GRADLE_VERSION="8.0.2"
RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \
ant \
ant-optional \
maven \
openjdk-11-jdk-headless && \
`# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
(echo "ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7 /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin
RUN apt-get install -y --no-install-recommends \
`# Lua dependencies` \
lua5.2 \
lua5.2-dev
# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
# lua5.3 does not install alternatives!
# need to update our luasocket code, lua doesn't have luaL_openlib any more
RUN apt-get install -y --no-install-recommends \
`# Node.js dependencies` \
nodejs
# Test dependencies for running puppeteer
RUN apt-get install -y --no-install-recommends \
`# JS dependencies` \
libxss1 \
libxtst6
RUN apt-get install -y --no-install-recommends \
`# OCaml dependencies` \
ocaml \
opam && \
`# disable sandboxing see https://github.com/ocaml/opam/issues/4327` \
opam init --yes --disable-sandboxing && \
opam install --yes oasis
RUN apt-get install -y --no-install-recommends \
`# Perl dependencies` \
libbit-vector-perl \
libclass-accessor-class-perl \
libcrypt-ssleay-perl \
libio-socket-ssl-perl \
libnet-ssleay-perl \
libtest-exception-perl
RUN apt-get install -y --no-install-recommends \
`# Php dependencies` \
php \
php-cli \
php-dev \
php-json \
php-pear \
re2c \
composer
RUN apt-get install -y --no-install-recommends \
`# Python3 dependencies` \
python3-all \
python3-all-dbg \
python3-all-dev \
python3-pip \
python3-setuptools \
python3-six \
python3-tornado \
python3-twisted \
python3-wheel \
python3-zope.interface
RUN apt-get install -y --no-install-recommends \
`# Ruby dependencies` \
ruby \
ruby-dev \
ruby-bundler
# Rust dependencies
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
ENV PATH /root/.cargo/bin:$PATH
# Swift on Linux for cross tests
RUN apt-get install -yq \
libedit-dev \
libz3-dev \
libpython2-dev \
libxml2-dev && \
cd / && \
wget --quiet https://download.swift.org/swift-5.7-release/ubuntu2204/swift-5.7-RELEASE/swift-5.7-RELEASE-ubuntu22.04.tar.gz && \
tar xf swift-5.7-RELEASE-ubuntu22.04.tar.gz && \
mv swift-5.7-RELEASE-ubuntu22.04 /usr/share/swift && \
rm swift-5.7-RELEASE-ubuntu22.04.tar.gz
ENV PATH /usr/share/swift/usr/bin:$PATH
RUN swift --version
# Locale(s) for cpp unit tests
RUN apt-get install -y --no-install-recommends \
`# Locale dependencies` \
locales && \
locale-gen en_US.UTF-8 && \
locale-gen de_DE.UTF-8 && \
update-locale
RUN apt-get install -y --no-install-recommends \
`# Static Code Analysis dependencies` \
cppcheck \
sloccount && \
pip install flake8
# NOTE: this does not reduce the image size but adds an additional layer.
# # Clean up
# RUN rm -rf /var/cache/apt/* && \
# rm -rf /var/lib/apt/lists/* && \
# rm -rf /tmp/* && \
# rm -rf /var/tmp/*
ENV THRIFT_ROOT /thrift
RUN mkdir -p $THRIFT_ROOT/src
COPY Dockerfile $THRIFT_ROOT/
WORKDIR $THRIFT_ROOT/src

View File

@ -1,4 +1,4 @@
x#!/usr/bin/env bash
#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file

View File

@ -46,6 +46,8 @@ add_library(parse STATIC ${parse_SOURCES})
set(compiler_core
src/thrift/common.cc
src/thrift/generate/t_generator.cc
src/thrift/generate/validator_parser.cc
src/thrift/generate/validator_parser.h
src/thrift/parse/t_typedef.cc
src/thrift/parse/parse.cc
src/thrift/version.h
@ -71,8 +73,21 @@ macro(THRIFT_ADD_COMPILER name description initial)
endif()
endmacro()
# This macro adds an option THRIFT_VALIDATOR_COMPILER_${NAME}
# that allows enabling or disabling certain languages' validator
macro(THRIFT_ADD_VALIDATOR_COMPILER name description initial)
string(TOUPPER "THRIFT_COMPILER_${name}" enabler)
set(src "src/thrift/generate/${name}_validator_generator.cc")
list(APPEND "src/thrift/generate/${name}_validator_generator.h")
option(${enabler} ${description} ${initial})
if(${enabler})
list(APPEND thrift-compiler_SOURCES ${src})
endif()
endmacro()
# The following compiler can be enabled or disabled
THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" ON)
THRIFT_ADD_COMPILER(cl "Enable compiler for Common LISP" ON)
THRIFT_ADD_COMPILER(cpp "Enable compiler for C++" ON)
THRIFT_ADD_COMPILER(d "Enable compiler for D" ON)
THRIFT_ADD_COMPILER(dart "Enable compiler for Dart" ON)
@ -102,6 +117,9 @@ THRIFT_ADD_COMPILER(swift "Enable compiler for Cocoa Swift" ON)
THRIFT_ADD_COMPILER(xml "Enable compiler for XML" ON)
THRIFT_ADD_COMPILER(xsd "Enable compiler for XSD" ON)
# The following compiler can be enabled or disabled by enabling or disabling certain languages
THRIFT_ADD_VALIDATOR_COMPILER(go "Enable validator compiler for Go" ON)
option(STATIC "Enable static linking of core libraries (libgcc / libstdc++)")
set(thrift-compiler_LINKER_FLAGS)

View File

@ -70,6 +70,7 @@ thrift_SOURCES = src/thrift/audit/t_audit.cpp \
# Specific client generator source
thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \
src/thrift/generate/t_cl_generator.cc \
src/thrift/generate/t_cpp_generator.cc \
src/thrift/generate/t_d_generator.cc \
src/thrift/generate/t_dart_generator.cc \
@ -77,6 +78,7 @@ thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \
src/thrift/generate/t_erl_generator.cc \
src/thrift/generate/t_erlang_generator.cc \
src/thrift/generate/t_go_generator.cc \
src/thrift/generate/t_go_generator.h \
src/thrift/generate/t_gv_generator.cc \
src/thrift/generate/t_haxe_generator.cc \
src/thrift/generate/t_html_generator.cc \
@ -98,7 +100,11 @@ thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \
src/thrift/generate/t_st_generator.cc \
src/thrift/generate/t_swift_generator.cc \
src/thrift/generate/t_xml_generator.cc \
src/thrift/generate/t_xsd_generator.cc
src/thrift/generate/t_xsd_generator.cc \
src/thrift/generate/validator_parser.cc \
src/thrift/generate/validator_parser.h \
src/thrift/generate/go_validator_generator.cc \
src/thrift/generate/go_validator_generator.h
thrift_CPPFLAGS = -I$(srcdir)/src
thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror

View File

@ -54,6 +54,7 @@
<ClCompile Include="src\thrift\audit\t_audit.cpp" />
<ClCompile Include="src\thrift\common.cc" />
<ClCompile Include="src\thrift\generate\t_c_glib_generator.cc" />
<ClCompile Include="src\thrift\generate\t_cl_generator.cc" />
<ClCompile Include="src\thrift\generate\t_cpp_generator.cc" />
<ClCompile Include="src\thrift\generate\t_d_generator.cc" />
<ClCompile Include="src\thrift\generate\t_dart_generator.cc" />

View File

@ -23,6 +23,7 @@
t_type* g_type_void;
t_type* g_type_string;
t_type* g_type_binary;
t_type* g_type_uuid;
t_type* g_type_bool;
t_type* g_type_i8;
t_type* g_type_i16;
@ -35,6 +36,7 @@ void initGlobals() {
g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
((t_base_type*)g_type_binary)->set_binary(true);
g_type_uuid = new t_base_type("string", t_base_type::TYPE_UUID);
g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL);
g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8);
g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
@ -46,6 +48,8 @@ void initGlobals() {
void clearGlobals() {
delete g_type_void;
delete g_type_string;
delete g_type_binary;
delete g_type_uuid;
delete g_type_bool;
delete g_type_i8;
delete g_type_i16;

View File

@ -29,6 +29,7 @@
extern t_type* g_type_void;
extern t_type* g_type_string;
extern t_type* g_type_binary;
extern t_type* g_type_uuid;
extern t_type* g_type_bool;
extern t_type* g_type_i8;
extern t_type* g_type_i16;

View File

@ -0,0 +1,906 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* This file is programmatically sanitized for style:
* astyle --style=1tbs -f -p -H -j -U go_validator_generator.cc
*
* The output of astyle should not be taken unquestioningly, but it is a good
* guide for ensuring uniformity and readability.
*/
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>
#include "thrift/generate/go_validator_generator.h"
#include "thrift/generate/validator_parser.h"
#include "thrift/platform.h"
#include "thrift/version.h"
#include <algorithm>
#include <clocale>
#include <sstream>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
std::string go_validator_generator::get_field_reference_name(t_field* field) {
t_type* type(field->get_type());
std::string tgt;
t_const_value* def_value;
go_generator->get_publicized_name_and_def_value(field, &tgt, &def_value);
tgt = "p." + tgt;
if (go_generator->is_pointer_field(field)
&& (type->is_base_type() || type->is_enum() || type->is_container())) {
tgt = "*" + tgt;
}
return tgt;
}
void go_validator_generator::generate_struct_validator(std::ostream& out, t_struct* tstruct) {
std::vector<t_field*> members = tstruct->get_members();
validation_parser parser(tstruct);
for (auto it = members.begin(); it != members.end(); it++) {
t_field* field(*it);
const std::vector<validation_rule*>& rules
= parser.parse_field(field->get_type(), field->annotations_);
if (rules.size() == 0) {
continue;
}
bool opt = field->get_req() == t_field::T_OPTIONAL;
t_type* type = field->get_type();
std::string tgt = get_field_reference_name(field);
std::string field_symbol = tstruct->get_name() + "." + field->get_name();
generate_field_validator(out, generator_context{field_symbol, "", tgt, opt, type, rules});
}
}
void go_validator_generator::generate_field_validator(std::ostream& out,
const generator_context& context) {
t_type* type = context.type;
if (type->is_typedef()) {
type = type->get_true_type();
}
if (type->is_enum()) {
if (context.tgt[0] == '*') {
out << indent() << "if " << context.tgt.substr(1) << " != nil {" << endl;
indent_up();
}
generate_enum_field_validator(out, context);
if (context.tgt[0] == '*') {
indent_down();
out << indent() << "}" << endl;
}
return;
} else if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
if (context.tgt[0] == '*') {
out << indent() << "if " << context.tgt.substr(1) << " != nil {" << endl;
indent_up();
}
switch (tbase) {
case t_base_type::TYPE_UUID:
case t_base_type::TYPE_VOID:
break;
case t_base_type::TYPE_I8:
case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64:
generate_integer_field_validator(out, context);
break;
case t_base_type::TYPE_DOUBLE:
generate_double_field_validator(out, context);
break;
case t_base_type::TYPE_STRING:
generate_string_field_validator(out, context);
break;
case t_base_type::TYPE_BOOL:
generate_bool_field_validator(out, context);
break;
}
if (context.tgt[0] == '*') {
indent_down();
out << indent() << "}" << endl;
}
return;
} else if (type->is_list()) {
return generate_list_field_validator(out, context);
} else if (type->is_set()) {
return generate_set_field_validator(out, context);
} else if (type->is_map()) {
return generate_map_field_validator(out, context);
} else if (type->is_struct() || type->is_xception()) {
return generate_struct_field_validator(out, context);
}
throw "validator error: unsupported type: " + type->get_name();
}
void go_validator_generator::generate_enum_field_validator(std::ostream& out,
const generator_context& context) {
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
if (values.size() == 0) {
continue;
}
std::string key = (*it)->get_name();
if (key == "vt.in") {
if (values.size() > 1) {
std::string exist = GenID("_exist");
out << indent() << "var " << exist << " bool" << endl;
std::string src = GenID("_src");
out << indent() << src << " := []int64{";
for (auto it = values.begin(); it != values.end(); it++) {
if (it != values.begin()) {
out << ", ";
}
out << "int64(";
if ((*it)->is_field_reference()) {
out << get_field_reference_name((*it)->get_field_reference());
} else {
out << (*it)->get_enum()->get_value();
}
out << ")";
}
out << "}" << endl;
out << indent() << "for _, src := range " << src << " {" << endl;
indent_up();
out << indent() << "if int64(" << context.tgt << ") == src {" << endl;
indent_up();
out << indent() << exist << " = true" << endl;
out << indent() << "break" << endl;
indent_down();
out << indent() << "}" << endl;
indent_down();
out << indent() << "}" << endl;
out << indent() << "if " << exist << " == false {" << endl;
} else {
out << indent() << "if int64(" << context.tgt << ") != int64(";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else {
out << values[0]->get_enum()->get_value();
}
out << ") {" << endl;
}
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.in\", \""
<< context.field_symbol << "\", \"" << context.field_symbol
<< " not valid, rule vt.in check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
if (values.size() > 1) {
indent_down();
out << indent() << "}" << endl;
}
} else if (key == "vt.not_in") {
if (values.size() > 1) {
std::string src = GenID("_src");
out << indent() << src << " := []int64{";
for (auto it = values.begin(); it != values.end(); it++) {
if (it != values.begin()) {
out << ", ";
}
out << "int64(";
if ((*it)->is_field_reference()) {
out << get_field_reference_name((*it)->get_field_reference());
} else {
out << (*it)->get_enum()->get_value();
}
out << ")";
}
out << "}" << endl;
out << indent() << "for _, src := range " << src << " {" << endl;
indent_up();
out << indent() << "if int64(" << context.tgt << ") == src {" << endl;
} else {
out << indent() << "if int64(" << context.tgt << ") == ";
out << "int64(";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else {
out << values[0]->get_enum()->get_value();
}
out << ") {" << endl;
}
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.not_in\", \""
<< context.field_symbol << "\", \"" << context.field_symbol
<< " not valid, rule vt.not_in check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
if (values.size() > 1) {
indent_down();
out << indent() << "}" << endl;
}
} else if (key == "vt.defined_only") {
if (values[0]->get_bool()) {
out << indent() << "if (" << context.tgt << ").String() == \"<UNSET>\" ";
} else {
continue;
}
out << "{" << endl;
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
<< context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
<< " check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
}
}
}
void go_validator_generator::generate_bool_field_validator(std::ostream& out,
const generator_context& context) {
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
if (values.size() == 0) {
continue;
}
std::string key = (*it)->get_name();
if (key == "vt.const") {
out << indent() << "if " << context.tgt << " != ";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else {
if (values[0]->get_bool()) {
out << "true";
} else {
out << "false";
}
}
}
out << "{" << endl;
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
<< context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
<< " check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
}
}
void go_validator_generator::generate_double_field_validator(std::ostream& out,
const generator_context& context) {
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
if (values.size() == 0) {
continue;
}
std::map<std::string, std::string> signs{{"vt.lt", ">="},
{"vt.le", ">"},
{"vt.gt", "<="},
{"vt.ge", "<"}};
std::string key = (*it)->get_name();
auto key_it = signs.find(key);
if (key_it != signs.end()) {
out << indent() << "if " << context.tgt << " " << key_it->second << " ";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else {
out << values[0]->get_double();
}
out << "{" << endl;
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
<< context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
<< " check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
continue;
} else if (key == "vt.in") {
if (values.size() > 1) {
std::string exist = GenID("_exist");
out << indent() << "var " << exist << " bool" << endl;
std::string src = GenID("_src");
out << indent() << src << " := []float64{";
for (auto it = values.begin(); it != values.end(); it++) {
if (it != values.begin()) {
out << ", ";
}
if ((*it)->is_field_reference()) {
out << get_field_reference_name((*it)->get_field_reference());
} else {
out << (*it)->get_double();
}
}
out << "}" << endl;
out << indent() << "for _, src := range " << src << " {" << endl;
indent_up();
out << indent() << "if " << context.tgt << " == src {" << endl;
indent_up();
out << indent() << exist << " = true" << endl;
out << indent() << "break" << endl;
indent_down();
out << indent() << "}" << endl;
indent_down();
out << indent() << "}" << endl;
out << indent() << "if " << exist << " == false {" << endl;
} else {
out << indent() << "if " << context.tgt << " != ";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else {
out << values[0]->get_double();
}
out << "{" << endl;
}
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.in\", \""
<< context.field_symbol << "\", \"" << context.field_symbol
<< " not valid, rule vt.in check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
} else if (key == "vt.not_in") {
if (values.size() > 1) {
std::string src = GenID("_src");
out << indent() << src << " := []float64{";
for (auto it = values.begin(); it != values.end(); it++) {
if (it != values.begin()) {
out << ", ";
}
if ((*it)->is_field_reference()) {
out << get_field_reference_name((*it)->get_field_reference());
} else {
out << (*it)->get_double();
}
}
out << "}" << endl;
out << indent() << "for _, src := range " << src << " {" << endl;
indent_up();
out << indent() << "if " << context.tgt << " == src {" << endl;
} else {
out << indent() << "if " << context.tgt << " == ";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else {
out << values[0]->get_double();
}
out << "{" << endl;
}
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.not_in\", \""
<< context.field_symbol << "\", \"" << context.field_symbol
<< " not valid, rule vt.not_in check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
if (values.size() > 1) {
indent_down();
out << indent() << "}" << endl;
}
}
}
}
void go_validator_generator::generate_integer_field_validator(std::ostream& out,
const generator_context& context) {
auto generate_current_type = [](std::ostream& out, t_type* type) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
switch (tbase) {
case t_base_type::TYPE_I8:
out << "int8";
break;
case t_base_type::TYPE_I16:
out << "int16";
break;
case t_base_type::TYPE_I32:
out << "int32";
break;
case t_base_type::TYPE_I64:
out << "int64";
break;
default:
throw "validator error: unsupported integer type: " + type->get_name();
}
};
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
if (values.size() == 0) {
continue;
}
std::map<std::string, std::string> signs{{"vt.lt", ">="},
{"vt.le", ">"},
{"vt.gt", "<="},
{"vt.ge", "<"}};
std::string key = (*it)->get_name();
auto key_it = signs.find(key);
if (key_it != signs.end()) {
out << indent() << "if " << context.tgt << " " << key_it->second << " ";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else if (values[0]->is_validation_function()) {
generate_current_type(out, context.type);
out << "(";
validation_value::validation_function* func = values[0]->get_function();
if (func->name == "len") {
out << "len(";
if (func->arguments[0]->is_field_reference()) {
out << get_field_reference_name(func->arguments[0]->get_field_reference());
}
out << ")";
}
out << ")";
} else {
out << values[0]->get_int();
}
out << "{" << endl;
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
<< context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
<< " check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
} else if (key == "vt.in") {
if (values.size() > 1) {
std::string exist = GenID("_exist");
out << indent() << "var " << exist << " bool" << endl;
std::string src = GenID("_src");
out << indent() << src << " := []";
generate_current_type(out, context.type);
out << "{";
for (auto it = values.begin(); it != values.end(); it++) {
if (it != values.begin()) {
out << ", ";
}
if ((*it)->is_field_reference()) {
out << get_field_reference_name((*it)->get_field_reference());
} else if ((*it)->is_validation_function()) {
generate_current_type(out, context.type);
out << "(";
validation_value::validation_function* func = (*it)->get_function();
if (func->name == "len") {
out << "len(";
if (func->arguments[0]->is_field_reference()) {
out << get_field_reference_name(func->arguments[0]->get_field_reference());
}
out << ")";
}
out << ")";
} else {
out << (*it)->get_int();
}
}
out << "}" << endl;
out << indent() << "for _, src := range " << src << " {" << endl;
indent_up();
out << indent() << "if " << context.tgt << " == src {" << endl;
indent_up();
out << indent() << exist << " = true" << endl;
out << indent() << "break" << endl;
indent_down();
out << indent() << "}" << endl;
indent_down();
out << indent() << "}" << endl;
out << indent() << "if " << exist << " == false {" << endl;
} else {
out << indent() << "if " << context.tgt << " != ";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else if (values[0]->is_validation_function()) {
generate_current_type(out, context.type);
out << "(";
validation_value::validation_function* func = values[0]->get_function();
if (func->name == "len") {
out << "len(";
if (func->arguments[0]->is_field_reference()) {
out << get_field_reference_name(func->arguments[0]->get_field_reference());
}
out << ")";
}
out << ")";
} else {
out << values[0]->get_int();
}
out << "{" << endl;
}
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.in\", \""
<< context.field_symbol << "\", \"" << context.field_symbol
<< " not valid, rule vt.in check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
} else if (key == "vt.not_in") {
if (values.size() > 1) {
std::string src = GenID("_src");
out << indent() << src << " := []";
t_base_type::t_base tbase = ((t_base_type*)context.type)->get_base();
switch (tbase) {
case t_base_type::TYPE_I8:
out << "int8";
break;
case t_base_type::TYPE_I16:
out << "int16";
break;
case t_base_type::TYPE_I32:
out << "int32";
break;
case t_base_type::TYPE_I64:
out << "int64";
break;
default:
throw "validator error: unsupported integer type: " + context.type->get_name();
}
out << "{";
for (auto it = values.begin(); it != values.end(); it++) {
if (it != values.begin()) {
out << ", ";
}
if ((*it)->is_field_reference()) {
out << get_field_reference_name((*it)->get_field_reference());
} else if ((*it)->is_validation_function()) {
generate_current_type(out, context.type);
out << "(";
validation_value::validation_function* func = (*it)->get_function();
if (func->name == "len") {
out << "len(";
if (func->arguments[0]->is_field_reference()) {
out << get_field_reference_name(func->arguments[0]->get_field_reference());
}
out << ")";
}
out << ")";
} else {
out << (*it)->get_int();
}
}
out << "}" << endl;
out << indent() << "for _, src := range " << src << " {" << endl;
indent_up();
out << indent() << "if " << context.tgt << " == src {" << endl;
} else {
out << indent() << "if " << context.tgt << " == ";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else if (values[0]->is_validation_function()) {
generate_current_type(out, context.type);
out << "(";
validation_value::validation_function* func = values[0]->get_function();
if (func->name == "len") {
out << "len(";
if (func->arguments[0]->is_field_reference()) {
out << get_field_reference_name(func->arguments[0]->get_field_reference());
}
out << ")";
}
out << ")";
} else {
out << values[0]->get_int();
}
out << "{" << endl;
}
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.not_in\", \""
<< context.field_symbol << "\", \"" << context.field_symbol
<< " not valid, rule vt.not_in check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
if (values.size() > 1) {
indent_down();
out << indent() << "}" << endl;
}
}
}
}
void go_validator_generator::generate_string_field_validator(std::ostream& out,
const generator_context& context) {
std::string target = context.tgt;
t_type* type = context.type;
if (type->is_typedef()) {
type = type->get_true_type();
}
if (type->is_binary()) {
target = GenID("_tgt");
out << indent() << target << " := "
<< "string(" << context.tgt << ")" << endl;
}
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
if (values.size() == 0) {
continue;
}
std::string key = (*it)->get_name();
if (key == "vt.const") {
out << indent() << "if " << target << " != ";
if (values[0]->is_field_reference()) {
out << "string(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << "\"" << values[0]->get_string() << "\"";
}
} else if (key == "vt.min_size" || key == "vt.max_size") {
out << indent() << "if len(" << target << ") ";
if (key == "vt.min_size") {
out << "<";
} else {
out << ">";
}
out << " int(";
if (values[0]->is_field_reference()) {
out << get_field_reference_name(values[0]->get_field_reference());
} else if (values[0]->is_validation_function()) {
validation_value::validation_function* func = values[0]->get_function();
if (func->name == "len") {
out << "len(";
if (func->arguments[0]->is_field_reference()) {
out << "string(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
}
out << ")";
}
} else {
out << values[0]->get_int();
}
out << ")";
} else if (key == "vt.pattern") {
out << indent() << "if ok, _ := regexp.MatchString(" << target << ",";
if (values[0]->is_field_reference()) {
out << "string(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << "\"" << values[0]->get_string() << "\"";
}
out << "); ok ";
} else if (key == "vt.prefix") {
out << indent() << "if !strings.HasPrefix(" << target << ",";
if (values[0]->is_field_reference()) {
out << "string(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << "\"" << values[0]->get_string() << "\"";
}
out << ")";
} else if (key == "vt.suffix") {
out << indent() << "if !strings.HasSuffix(" << target << ",";
if (values[0]->is_field_reference()) {
out << "string(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << "\"" << values[0]->get_string() << "\"";
}
out << ")";
} else if (key == "vt.contains") {
out << indent() << "if !strings.Contains(" << target << ",";
if (values[0]->is_field_reference()) {
out << "string(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << "\"" << values[0]->get_string() << "\"";
}
out << ")";
} else if (key == "vt.not_contains") {
out << indent() << "if strings.Contains(" << target << ",";
if (values[0]->is_field_reference()) {
out << "string(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << "\"" << values[0]->get_string() << "\"";
}
out << ")";
}
out << "{" << endl;
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
<< context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
<< " check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
}
}
void go_validator_generator::generate_set_field_validator(std::ostream& out,
const generator_context& context) {
return generate_list_field_validator(out, context);
}
void go_validator_generator::generate_list_field_validator(std::ostream& out,
const generator_context& context) {
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
std::string key = (*it)->get_name();
if (key == "vt.min_size" || key == "vt.max_size") {
out << indent() << "if len(" << context.tgt << ")";
if (key == "vt.min_size") {
out << " < ";
} else {
out << " > ";
}
if (values[0]->is_field_reference()) {
out << "int(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << values[0]->get_int();
}
out << "{" << endl;
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
<< context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
<< " check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
} else if (key == "vt.elem") {
out << indent() << "for i := 0; i < len(" << context.tgt << ");i++ {" << endl;
indent_up();
std::string src = GenID("_elem");
out << indent() << src << " := " << context.tgt << "[i]" << endl;
t_type* elem_type;
if (context.type->is_list()) {
elem_type = ((t_list*)context.type)->get_elem_type();
} else {
elem_type = ((t_set*)context.type)->get_elem_type();
}
generator_context ctx{context.field_symbol + ".elem",
"",
src,
false,
elem_type,
std::vector<validation_rule*>{(*it)->get_inner()}};
generate_field_validator(out, ctx);
indent_down();
out << indent() << "}" << endl;
}
}
}
void go_validator_generator::generate_map_field_validator(std::ostream& out,
const generator_context& context) {
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
std::string key = (*it)->get_name();
if (key == "vt.min_size" || key == "vt.max_size") {
out << indent() << "if len(" << context.tgt << ")";
if (key == "vt.min_size") {
out << " < ";
} else {
out << " > ";
}
if (values[0]->is_field_reference()) {
out << "int(";
out << get_field_reference_name(values[0]->get_field_reference());
out << ")";
} else {
out << values[0]->get_int();
}
out << "{" << endl;
indent_up();
out << indent()
<< "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
<< context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
<< " check failed\")" << endl;
indent_down();
out << indent() << "}" << endl;
} else if (key == "vt.key") {
std::string src = GenID("_key");
out << indent() << "for " << src << " := range " << context.tgt << " {" << endl;
indent_up();
generator_context ctx{context.field_symbol + ".key",
"",
src,
false,
((t_map*)context.type)->get_key_type(),
std::vector<validation_rule*>{(*it)->get_inner()}};
generate_field_validator(out, ctx);
indent_down();
out << indent() << "}" << endl;
} else if (key == "vt.value") {
std::string src = GenID("_value");
out << indent() << "for _, " << src << " := range " << context.tgt << " {" << endl;
indent_up();
generator_context ctx{context.field_symbol + ".value",
"",
src,
false,
((t_map*)context.type)->get_val_type(),
std::vector<validation_rule*>{(*it)->get_inner()}};
generate_field_validator(out, ctx);
indent_down();
out << indent() << "}" << endl;
}
}
}
void go_validator_generator::generate_struct_field_validator(std::ostream& out,
const generator_context& context) {
bool generate_valid = true;
validation_rule* last_valid_rule = nullptr;
for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
const std::vector<validation_value*>& values = (*it)->get_values();
if (values.size() == 0) {
continue;
}
std::string key = (*it)->get_name();
if (key == "vt.skip") {
if (values[0]->is_field_reference() || !values[0]->get_bool()) {
generate_valid = true;
} else if (values[0]->get_bool()) {
generate_valid = false;
}
last_valid_rule = *it;
}
}
if (generate_valid) {
if (last_valid_rule == nullptr) {
out << indent() << "if err := " << context.tgt << ".Validate(); err != nil {" << endl;
indent_up();
out << indent() << "return err" << endl;
indent_down();
out << indent() << "}" << endl;
} else {
const std::vector<validation_value*>& values = last_valid_rule->get_values();
if (!values[0]->get_bool()) {
out << indent() << "if err := " << context.tgt << ".Validate(); err != nil {" << endl;
indent_up();
out << indent() << "return err" << endl;
indent_down();
out << indent() << "}" << endl;
} else if (values[0]->is_field_reference()) {
out << indent() << "if !";
out << get_field_reference_name(values[0]->get_field_reference());
out << "{" << endl;
indent_up();
out << indent() << "if err := " << context.tgt << ".Validate(); err != nil {" << endl;
indent_up();
out << indent() << "return err" << endl;
indent_down();
out << indent() << "}" << endl;
indent_down();
out << indent() << "}" << endl;
}
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef T_GO_VALIDATOR_GENERATOR_H
#define T_GO_VALIDATOR_GENERATOR_H
#include "thrift/generate/t_generator.h"
#include "thrift/generate/t_go_generator.h"
#include "thrift/generate/validator_parser.h"
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <vector>
class go_validator_generator {
public:
go_validator_generator(t_go_generator* gg) : go_generator(gg){};
void generate_struct_validator(std::ostream& out, t_struct* tstruct);
struct generator_context {
std::string field_symbol;
std::string src;
std::string tgt;
bool opt;
t_type* type;
std::vector<validation_rule*> rules;
};
private:
void generate_field_validator(std::ostream& out, const generator_context& context);
void generate_enum_field_validator(std::ostream& out, const generator_context& context);
void generate_bool_field_validator(std::ostream& out, const generator_context& context);
void generate_integer_field_validator(std::ostream& out, const generator_context& context);
void generate_double_field_validator(std::ostream& out, const generator_context& context);
void generate_string_field_validator(std::ostream& out, const generator_context& context);
void generate_list_field_validator(std::ostream& out, const generator_context& context);
void generate_set_field_validator(std::ostream& out, const generator_context& context);
void generate_map_field_validator(std::ostream& out, const generator_context& context);
void generate_struct_field_validator(std::ostream& out, const generator_context& context);
void indent_up() { go_generator->indent_up(); }
void indent_down() { go_generator->indent_down(); }
std::string indent() { return go_generator->indent(); }
//std::string get_field_name(t_field* field); -- no impl?
std::string get_field_reference_name(t_field* field);
std::string GenID(std::string id) { return id + std::to_string(tmp_[id]++); };
t_go_generator* go_generator;
std::map<std::string, int> tmp_;
};
#endif

View File

@ -105,6 +105,7 @@ public:
/* initialization and destruction */
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/* generation functions */
void generate_typedef(t_typedef* ttypedef) override;
@ -723,6 +724,8 @@ string t_c_glib_generator::type_to_enum(t_type* type) {
return "T_I64";
case t_base_type::TYPE_DOUBLE:
return "T_DOUBLE";
default:
break;
}
} else if (type->is_enum()) {
return "T_I32";
@ -4581,4 +4584,9 @@ string underscores_to_initial_caps(string name) {
}
/* register this generator with the main program */
std::string t_c_glib_generator::display_name() const {
return "C, using GLib";
}
THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "")

View File

@ -0,0 +1,564 @@
/*
* Copyright (c) 2008- Patrick Collison <patrick@collison.ie>
* Copyright (c) 2006- Facebook
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string>
#include <fstream>
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sstream>
#include <string>
#include <algorithm>
#include "thrift/platform.h"
#include "t_oop_generator.h"
using namespace std;
/**
* Common Lisp code generator.
*
* @author Patrick Collison <patrick@collison.ie>
*/
class t_cl_generator : public t_oop_generator {
public:
t_cl_generator(
t_program* program,
const std::map<std::string, std::string>& parsed_options,
const std::string& option_string)
: t_oop_generator(program)
{
no_asd = false;
system_prefix = "thrift-gen-";
std::map<std::string, std::string>::const_iterator iter;
for(iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
if(iter->first.compare("no_asd") == 0) {
no_asd = true;
} else if (iter->first.compare("sys_pref") == 0) {
system_prefix = iter->second;
} else {
throw "unknown option cl:" + iter->first;
}
}
out_dir_base_ = "gen-cl";
copy_options_ = option_string;
}
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_typedef (t_typedef* ttypedef) override;
void generate_enum (t_enum* tenum) override;
void generate_const (t_const* tconst) override;
void generate_struct (t_struct* tstruct) override;
void generate_xception (t_struct* txception) override;
void generate_service (t_service* tservice) override;
void generate_cl_struct (std::ostream& out, t_struct* tstruct, bool is_exception);
void generate_cl_struct_internal (std::ostream& out, t_struct* tstruct, bool is_exception);
void generate_exception_sig(std::ostream& out, t_function* f);
std::string render_const_value(t_type* type, t_const_value* value);
std::string cl_autogen_comment();
void asdf_def(std::ostream &out);
void package_def(std::ostream &out);
void package_in(std::ostream &out);
std::string generated_package();
std::string prefix(std::string name);
std::string package_of(t_program* program);
std::string package();
std::string render_includes();
std::string type_name(t_type* ttype);
std::string typespec (t_type *t);
std::string function_signature(t_function* tfunction);
std::string argument_list(t_struct* tstruct);
std::string cl_docstring(std::string raw);
private:
int temporary_var;
/**
* Isolate the variable definitions, as they can require structure definitions
*/
ofstream_with_content_based_conditional_update f_asd_;
ofstream_with_content_based_conditional_update f_types_;
ofstream_with_content_based_conditional_update f_vars_;
std::string copy_options_;
bool no_asd;
std::string system_prefix;
};
void t_cl_generator::init_generator() {
MKDIR(get_out_dir().c_str());
string program_dir = get_out_dir() + "/" + program_name_;
MKDIR(program_dir.c_str());
temporary_var = 0;
string f_types_name = program_dir + "/" + program_name_ + "-types.lisp";
string f_vars_name = program_dir + "/" + program_name_ + "-vars.lisp";
f_types_.open(f_types_name);
f_types_ << cl_autogen_comment() << endl;
f_vars_.open(f_vars_name);
f_vars_ << cl_autogen_comment() << endl;
package_def(f_types_);
package_in(f_types_);
package_in(f_vars_);
if (!no_asd) {
string f_asd_name = program_dir + "/" + system_prefix + program_name_ + ".asd";
f_asd_.open(f_asd_name);
f_asd_ << cl_autogen_comment() << endl;
asdf_def(f_asd_);
}
}
/**
* Renders all the imports necessary for including another Thrift program
*/
string t_cl_generator::render_includes() {
const vector<t_program*>& includes = program_->get_includes();
string result = "";
result += ":depends-on (:thrift";
for (auto include : includes) {
result += " :" + system_prefix + underscore(include->get_name());
}
result += ")\n";
return result;
}
string t_cl_generator::package_of(t_program* program) {
string prefix = program->get_namespace("cl");
return prefix.empty() ? "thrift-generated" : prefix;
}
string t_cl_generator::package() {
return package_of(program_);
}
string t_cl_generator::prefix(string symbol) {
return "\"" + symbol + "\"";
}
string t_cl_generator::cl_autogen_comment() {
return
std::string(";;; ") + "Autogenerated by Thrift\n" +
";;; DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
";;; options string: " + copy_options_ + "\n";
}
string t_cl_generator::cl_docstring(string raw) {
replace(raw.begin(), raw.end(), '"', '\'');
return raw;
}
void t_cl_generator::close_generator() {
f_asd_.close();
f_types_.close();
f_vars_.close();
}
string t_cl_generator::generated_package() {
return program_->get_namespace("cpp");
}
void t_cl_generator::asdf_def(std::ostream &out) {
out << "(asdf:defsystem #:" << system_prefix << program_name_ << endl;
indent_up();
out << indent() << render_includes()
<< indent() << ":serial t" << endl
<< indent() << ":components ("
<< "(:file \"" << program_name_ << "-types\") "
<< "(:file \"" << program_name_ << "-vars\")))" << endl;
indent_down();
}
/***
* Generate a package definition. Add use references equivalent to the idl file's include statements.
*/
void t_cl_generator::package_def(std::ostream &out) {
const vector<t_program*>& includes = program_->get_includes();
out << "(thrift:def-package :" << package();
if ( includes.size() > 0 ) {
out << " :use (";
for (auto include : includes) {
out << " :" << include->get_name();
}
out << ")";
}
out << ")" << endl << endl;
}
void t_cl_generator::package_in(std::ostream &out) {
out << "(cl:in-package :" << package() << ")" << endl << endl;
}
/**
* Generates a typedef. This is not done in Common Lisp, types are all implicit.
*
* @param ttypedef The type definition
*/
void t_cl_generator::generate_typedef(t_typedef* ttypedef) {
(void)ttypedef;
}
void t_cl_generator::generate_enum(t_enum* tenum) {
f_types_ << "(thrift:def-enum " << prefix(tenum->get_name()) << endl;
vector<t_enum_value*> constants = tenum->get_constants();
vector<t_enum_value*>::iterator c_iter;
int value = -1;
indent_up();
f_types_ << indent() << "(";
for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
value = (*c_iter)->get_value();
if(c_iter != constants.begin()) f_types_ << endl << indent() << " ";
f_types_ << "(\"" << (*c_iter)->get_name() << "\" . " << value << ")";
}
indent_down();
f_types_ << "))" << endl << endl;
}
/**
* Generate a constant value
*/
void t_cl_generator::generate_const(t_const* tconst) {
t_type* type = tconst->get_type();
string name = tconst->get_name();
t_const_value* value = tconst->get_value();
f_vars_ << "(thrift:def-constant " << prefix(name) << " " << render_const_value(type, value) << ")"
<< endl << endl;
}
/**
* Prints the value of a constant with the given type. Note that type checking
* is NOT performed in this function as it is always run beforehand using the
* validate_types method in main.cc
*/
string t_cl_generator::render_const_value(t_type* type, t_const_value* value) {
type = get_true_type(type);
std::ostringstream out;
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
switch (tbase) {
case t_base_type::TYPE_STRING:
out << "\"" << value->get_string() << "\"";
break;
case t_base_type::TYPE_BOOL:
out << (value->get_integer() > 0 ? "t" : "nil");
break;
case t_base_type::TYPE_I8:
case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64:
out << value->get_integer();
break;
case t_base_type::TYPE_DOUBLE:
if (value->get_type() == t_const_value::CV_INTEGER) {
out << value->get_integer();
} else {
out << value->get_double();
}
break;
default:
throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
}
} else if (type->is_enum()) {
indent(out) << value->get_integer();
} else if (type->is_struct() || type->is_xception()) {
out << (type->is_struct() ? "(make-instance '" : "(make-exception '") <<
lowercase(type->get_name()) << " " << endl;
indent_up();
const vector<t_field*>& fields = ((t_struct*)type)->get_members();
vector<t_field*>::const_iterator f_iter;
const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
t_type* field_type = nullptr;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if ((*f_iter)->get_name() == v_iter->first->get_string()) {
field_type = (*f_iter)->get_type();
}
}
if (field_type == nullptr) {
throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
}
out << indent() << ":" << v_iter->first->get_string() << " " <<
render_const_value(field_type, v_iter->second) << endl;
}
out << indent() << ")";
indent_down();
} else if (type->is_map()) {
// emit an hash form with both keys and values to be evaluated
t_type* ktype = ((t_map*)type)->get_key_type();
t_type* vtype = ((t_map*)type)->get_val_type();
out << "(thrift:map ";
indent_up();
const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
out << endl << indent()
<< "(cl:cons " << render_const_value(ktype, v_iter->first) << " "
<< render_const_value(vtype, v_iter->second) << ")";
}
indent_down();
out << indent() << ")";
} else if (type->is_list() || type->is_set()) {
t_type* etype;
if (type->is_list()) {
etype = ((t_list*)type)->get_elem_type();
} else {
etype = ((t_set*)type)->get_elem_type();
}
if (type->is_set()) {
out << "(thrift:set" << endl;
} else {
out << "(thrift:list" << endl;
}
indent_up();
indent_up();
const vector<t_const_value*>& val = value->get_list();
vector<t_const_value*>::const_iterator v_iter;
for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
out << indent() << render_const_value(etype, *v_iter) << endl;
}
out << indent() << ")";
indent_down();
indent_down();
} else {
throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
}
return out.str();
}
void t_cl_generator::generate_struct(t_struct* tstruct) {
generate_cl_struct(f_types_, tstruct, false);
}
void t_cl_generator::generate_xception(t_struct* txception) {
generate_cl_struct(f_types_, txception, true);
}
void t_cl_generator::generate_cl_struct_internal(std::ostream& out, t_struct* tstruct, bool is_exception) {
(void)is_exception;
const vector<t_field*>& members = tstruct->get_members();
vector<t_field*>::const_iterator m_iter;
out << "(";
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
t_const_value* value = (*m_iter)->get_value();
t_type* type = (*m_iter)->get_type();
if (m_iter != members.begin()) {
out << endl << indent() << " ";
}
out << "(" << prefix((*m_iter)->get_name()) << " " <<
( (nullptr != value) ? render_const_value(type, value) : "nil" ) <<
" :id " << (*m_iter)->get_key();
if ( type->is_base_type() && "string" == typespec(type) )
if ( ((t_base_type*)type)->is_binary() )
out << " :type binary";
else
out << " :type string";
else
out << " :type " << typespec(type);
if ( (*m_iter)->get_req() == t_field::T_OPTIONAL ) {
out << " :optional t";
}
if ( (*m_iter)->has_doc()) {
out << " :documentation \"" << cl_docstring((*m_iter)->get_doc()) << "\"";
}
out <<")";
}
out << ")";
}
void t_cl_generator::generate_cl_struct(std::ostream& out, t_struct* tstruct, bool is_exception = false) {
std::string name = type_name(tstruct);
out << (is_exception ? "(thrift:def-exception " : "(thrift:def-struct ") <<
prefix(name) << endl;
indent_up();
if ( tstruct->has_doc() ) {
out << indent() ;
out << "\"" << cl_docstring(tstruct->get_doc()) << "\"" << endl;
}
out << indent() ;
generate_cl_struct_internal(out, tstruct, is_exception);
indent_down();
out << ")" << endl << endl;
}
void t_cl_generator::generate_exception_sig(std::ostream& out, t_function* f) {
generate_cl_struct_internal(out, f->get_xceptions(), true);
}
void t_cl_generator::generate_service(t_service* tservice) {
string extends_client;
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
if (tservice->get_extends() != nullptr) {
extends_client = type_name(tservice->get_extends());
}
extends_client = extends_client.empty() ? "nil" : prefix(extends_client);
f_types_ << "(thrift:def-service " << prefix(service_name_) << " "
<< extends_client;
indent_up();
if ( tservice->has_doc()) {
f_types_ << endl << indent()
<< "(:documentation \"" << cl_docstring(tservice->get_doc()) << "\")";
}
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
t_function* function = *f_iter;
string fname = function->get_name();
string signature = function_signature(function);
t_struct* exceptions = function->get_xceptions();
const vector<t_field*>& xmembers = exceptions->get_members();
f_types_ << endl << indent() << "(:method " << prefix(fname);
f_types_ << " (" << signature << " " << typespec((*f_iter)->get_returntype()) << ")";
if (xmembers.size() > 0) {
f_types_ << endl << indent() << " :exceptions " ;
generate_exception_sig(f_types_, function);
}
if ( (*f_iter)->is_oneway() ) {
f_types_ << endl << indent() << " :oneway t";
}
if ( (*f_iter)->has_doc() ) {
f_types_ << endl << indent() << " :documentation \""
<< cl_docstring((*f_iter)->get_doc()) << "\"";
}
f_types_ << ")";
}
f_types_ << ")" << endl << endl;
indent_down();
}
string t_cl_generator::typespec(t_type *t) {
t = get_true_type(t);
if (t -> is_binary()){
return "binary";
} else if (t->is_base_type()) {
return type_name(t);
} else if (t->is_map()) {
t_map *m = (t_map*) t;
return "(thrift:map " + typespec(m->get_key_type()) + " " +
typespec(m->get_val_type()) + ")";
} else if (t->is_struct() || t->is_xception()) {
return "(struct " + prefix(type_name(t)) + ")";
} else if (t->is_list()) {
return "(thrift:list " + typespec(((t_list*) t)->get_elem_type()) + ")";
} else if (t->is_set()) {
return "(thrift:set " + typespec(((t_set*) t)->get_elem_type()) + ")";
} else if (t->is_enum()) {
return "(enum \"" + ((t_enum*) t)->get_name() + "\")";
} else {
throw "Sorry, I don't know how to generate this: " + type_name(t);
}
}
string t_cl_generator::function_signature(t_function* tfunction) {
return argument_list(tfunction->get_arglist());
}
string t_cl_generator::argument_list(t_struct* tstruct) {
stringstream res;
res << "(";
const vector<t_field*>& fields = tstruct->get_members();
vector<t_field*>::const_iterator f_iter;
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
first = false;
} else {
res << " ";
}
res << "(" + prefix((*f_iter)->get_name()) << " " <<
typespec((*f_iter)->get_type()) << " " <<
(*f_iter)->get_key() << ")";
}
res << ")";
return res.str();
}
string t_cl_generator::type_name(t_type* ttype) {
string prefix = "";
t_program* program = ttype->get_program();
if (program != nullptr && program != program_)
prefix = package_of(program) == package() ? "" : package_of(program) + ":";
string name = ttype->get_name();
if (ttype->is_struct() || ttype->is_xception())
name = lowercase(ttype->get_name());
return prefix + name;
}
std::string t_cl_generator::display_name() const {
return "Common Lisp";
}
THRIFT_REGISTER_GENERATOR(
cl,
"Common Lisp",
" no_asd: Do not define ASDF systems for each generated Thrift program.\n"
" sys_pref= The prefix to give ASDF system names. Default: thrift-gen-\n")

View File

@ -104,6 +104,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) override;
@ -4398,9 +4399,9 @@ string t_cpp_generator::namespace_close(string ns) {
string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
if (ttype->is_base_type()) {
string bname = base_type_name(((t_base_type*)ttype)->get_base());
std::map<string, string>::iterator it = ttype->annotations_.find("cpp.type");
if (it != ttype->annotations_.end()) {
bname = it->second;
std::map<string, std::vector<string>>::iterator it = ttype->annotations_.find("cpp.type");
if (it != ttype->annotations_.end() && !it->second.empty()) {
bname = it->second.back();
}
if (!arg) {
@ -4660,6 +4661,8 @@ string t_cpp_generator::type_to_enum(t_type* type) {
return "::apache::thrift::protocol::T_I64";
case t_base_type::TYPE_DOUBLE:
return "::apache::thrift::protocol::T_DOUBLE";
default:
break;
}
} else if (type->is_enum()) {
return "::apache::thrift::protocol::T_I32";
@ -4749,6 +4752,11 @@ string t_cpp_generator::get_legal_program_name(std::string program_name)
return program_name;
}
std::string t_cpp_generator::display_name() const {
return "C++";
}
THRIFT_REGISTER_GENERATOR(
cpp,
"C++",

View File

@ -69,6 +69,7 @@ public:
out_dir_base_ = "gen-d";
}
std::string display_name() const override;
protected:
@ -371,6 +372,7 @@ private:
/**
* Writes a server skeleton for the passed service to out.
*/
void print_server_skeleton(ostream& out, t_service* tservice) {
string svc_name = suffix_if_reserved(tservice->get_name());
@ -432,6 +434,7 @@ private:
/**
* Writes the definition of a struct or an exception type to out.
*/
void print_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) {
const vector<t_field*>& members = tstruct->get_members();
@ -495,6 +498,7 @@ private:
* Prints the D function signature (including return type) for the given
* method.
*/
void print_function_signature(ostream& out, t_function* fn) {
out << render_type_name(fn->get_returntype()) << " " << suffix_if_reserved(fn->get_name()) << "(";
@ -722,6 +726,7 @@ private:
* Writes the default list of imports (which are written to every generated
* module) to f.
*/
void print_default_imports(ostream& out) {
indent(out) << "import thrift.base;" << endl << "import thrift.codegen.base;" << endl
<< "import thrift.util.hashset;" << endl << endl;
@ -771,4 +776,9 @@ vector<string> t_d_generator::d_reserved_words = {
"ushort", "version", "void", "wchar", "while", "with"
};
std::string t_d_generator::display_name() const {
return "D";
}
THRIFT_REGISTER_GENERATOR(d, "D", "")

View File

@ -123,6 +123,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void export_class_to_library(string file_name, string class_name);
@ -2216,6 +2217,8 @@ string t_dart_generator::declare_field(t_field* tfield, bool init) {
case t_base_type::TYPE_DOUBLE:
result += " = 0.0";
break;
default:
throw "compiler error: unhandled type";
}
} else if (ttype->is_enum()) {
@ -2297,6 +2300,8 @@ string t_dart_generator::type_to_enum(t_type* type) {
return "TType.I64";
case t_base_type::TYPE_DOUBLE:
return "TType.DOUBLE";
default:
break;
}
} else if (type->is_enum()) {
return "TType.I32";
@ -2351,6 +2356,8 @@ std::string t_dart_generator::init_value(t_field* field) {
case t_base_type::TYPE_STRING:
result = "";
break;
default:
throw "compiler error: unhandled type";
}
return result;
@ -2502,6 +2509,11 @@ std::string t_dart_generator::get_ttype_class_name(t_type* ttype) {
}
}
std::string t_dart_generator::display_name() const {
return "Dart";
}
THRIFT_REGISTER_GENERATOR(
dart,
"Dart",

View File

@ -45,6 +45,7 @@
#endif
using std::map;
using std::set;
using std::ofstream;
using std::ostream;
using std::ostringstream;
@ -70,14 +71,18 @@ public:
ansistr_binary_ = false;
register_types_ = false;
constprefix_ = false;
old_names_ = false;
events_ = false;
xmldoc_ = false;
async_ = false;
com_types_ = false;
for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
if( iter->first.compare("ansistr_binary") == 0) {
ansistr_binary_ = true;
} else if( iter->first.compare("register_types") == 0) {
register_types_ = true;
} else if( iter->first.compare("old_names") == 0) {
old_names_ = true;
} else if( iter->first.compare("constprefix") == 0) {
constprefix_ = true;
} else if( iter->first.compare("events") == 0) {
@ -86,11 +91,17 @@ public:
xmldoc_ = true;
} else if( iter->first.compare("async") == 0) {
async_ = true;
} else if( iter->first.compare("com_types") == 0) {
com_types_ = true;
} else {
throw "unknown option delphi:" + iter->first;
}
}
if(com_types_ && ansistr_binary_) {
throw "com_types and ansistr_binary are mutually exclusive";
}
out_dir_base_ = "gen-delphi";
escape_.clear();
escape_['\''] = "''";
@ -98,6 +109,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) override;
@ -345,8 +357,8 @@ public:
std::string argument_list(t_struct* tstruct);
std::string constructor_argument_list(t_struct* tstruct, std::string current_indent);
std::string type_to_enum(t_type* ttype);
std::string prop_name(t_field* tfield, bool is_xception = false);
std::string prop_name(std::string name, bool is_xception = false);
std::string prop_name(t_field* tfield, bool is_xception = false, std::string prefix = "");
std::string prop_name(std::string name, bool is_xception = false, std::string prefix = "");
std::string constructor_param_name(string name);
void write_enum(std::string line);
@ -394,18 +406,59 @@ private:
bool has_enum;
bool has_const;
std::string namespace_dir_;
std::map<std::string, int> delphi_keywords;
std::map<std::string, int> delphi_reserved_method;
std::map<std::string, int> delphi_reserved_method_exception;
std::map<std::string, int> types_known;
std::set<std::string> types_known;
std::list<t_typedef*> typedefs_pending;
std::vector<std::string> uses_list;
void create_keywords();
bool find_keyword(std::map<std::string, int>& keyword_map, std::string name);
std::string empty_value(t_type* type);
const std::string DELPHI_KEYWORDS[81] = {
// keywords
"and", "array", "as", "asm", "at", "automated", "begin", "case", "class", "const", "constructor",
"destructor", "dispinterface", "div", "do", "downto", "else", "end", "except", "exports", "file",
"finalization", "finally", "for", "function", "goto", "if", "implementation", "in", "inherited",
"initialization", "inline", "interface", "is", "label", "library", "mod", "nil", "not", "object",
"of", "on", "or", "out", "packed", "private", "procedure", "program", "property", "protected",
"public", "published", "raise", "record", "repeat", "resourcestring", "set", "shl", "shr", "string",
"then", "threadvar", "to", "try", "type", "unit", "until", "uses", "var", "while", "with", "xor",
// predefined types (lowercase!)
"ansistring", "boolean", "double", "int64", "integer", "shortint", "smallint", "string", "unicodestring"
};
// reserved variables and types (lowercase!)
const std::string DELPHI_RESERVED_NAMES[8] = {
"result", "system", "sysutils", "tbytes", "tclass", "thrift", "tinterfacedobject", "tobject"
};
// reserved method names (lowercase!)
const std::string DELPHI_RESERVED_METHOD[31] = {
"afterconstruction", "beforedestruction", "classinfo", "classname", "classnameis", "classparent",
"classtype", "cleanupinstance", "create", "defaulthandler", "destroy", "dispatch", "equals",
"fieldaddress", "free", "freeinstance", "gethashcode", "getinterface", "getinterfaceentry",
"getinterfacetable", "inheritsfrom", "initinstance", "instancesize", "methodaddress", "methodname",
"newinstance", "read", "safecallexception", "tostring", "unitname", "write"
};
// reserved exception class method names (lowercase!)
const std::string DELPHI_RESERVED_METHOD_EXCEPTION[23] = {
"setinnerexception", "setstackinfo", "getstacktrace", "raisingexception", "createfmt", "createres",
"createresfmt", "createhelp", "createfmthelp", "createreshelp", "createresfmthelp", "getbaseexception",
"baseexception", "helpcontext", "innerexception", "message", "stacktrace", "stackinfo",
"getexceptionstackinfoproc", "getstackinfostringproc", "cleanupstackinfoproc", "raiseouterexception",
"throwouterexception"
};
// TODO: put all into one map, value=flags tells what it is
std::set<std::string> delphi_keywords = std::set<string>(DELPHI_KEYWORDS, DELPHI_KEYWORDS + sizeof(DELPHI_KEYWORDS) / sizeof(DELPHI_KEYWORDS[0]));
std::set<std::string> delphi_reserved_names = std::set<string>(DELPHI_RESERVED_NAMES, DELPHI_RESERVED_NAMES + sizeof(DELPHI_RESERVED_NAMES) / sizeof(DELPHI_RESERVED_NAMES[0]));
std::set<std::string> delphi_reserved_method = std::set<string>(DELPHI_RESERVED_METHOD, DELPHI_RESERVED_METHOD + sizeof(DELPHI_RESERVED_METHOD) / sizeof(DELPHI_RESERVED_METHOD[0]));
std::set<std::string> delphi_reserved_method_exception = std::set<string>(DELPHI_RESERVED_METHOD_EXCEPTION, DELPHI_RESERVED_METHOD_EXCEPTION + sizeof(DELPHI_RESERVED_METHOD_EXCEPTION) / sizeof(DELPHI_RESERVED_METHOD_EXCEPTION[0]));
bool find_keyword(std::set<std::string>& keywords, std::string name);
std::string normalize_name(std::string name,
bool b_method = false,
bool b_exception_method = false);
std::string empty_value(t_type* type);
bool b_exception_method = false,
bool b_force_underscore = false);
bool is_fully_defined_type(t_type* ttype);
void add_defined_type(t_type* ttype);
void init_known_types_list();
@ -414,9 +467,11 @@ private:
bool ansistr_binary_;
bool register_types_;
bool constprefix_;
bool old_names_;
bool events_;
bool xmldoc_;
bool async_;
bool com_types_;
void indent_up_impl() { ++indent_impl_; };
void indent_down_impl() { --indent_impl_; };
std::string indent_impl() {
@ -537,7 +592,7 @@ void t_delphi_generator::generate_delphi_doc(ostream& out, t_function* tfunction
}
}
bool t_delphi_generator::find_keyword(std::map<std::string, int>& keyword_map, std::string name) {
bool t_delphi_generator::find_keyword(std::set<std::string>& keywords, std::string name) {
std::string::size_type len = name.length();
if (len <= 0) {
@ -549,182 +604,45 @@ bool t_delphi_generator::find_keyword(std::map<std::string, int>& keyword_map, s
if (nlast >= 1) {
if (nlast == (len - 1)) {
string new_name(name, 0, nlast);
return find_keyword(keyword_map, new_name);
return find_keyword(keywords, new_name);
}
}
return (keyword_map[name] == 1);
return (keywords.find(name) != keywords.end());
}
std::string t_delphi_generator::normalize_name(std::string name,
bool b_method,
bool b_exception_method) {
bool b_exception_method,
bool b_force_underscore) {
string tmp(name);
std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower));
bool b_found = false;
bool b_reserved = false;
bool b_keyword = false;
if (find_keyword(delphi_keywords, tmp)) {
b_found = true;
b_keyword = true;
} else if (find_keyword(delphi_reserved_names, tmp)) {
b_reserved = true;
} else if (b_method && find_keyword(delphi_reserved_method, tmp)) {
b_found = true;
b_reserved = true;
} else if (b_exception_method && find_keyword(delphi_reserved_method_exception, tmp)) {
b_found = true;
b_reserved = true;
}
if (b_found) {
return name + "_";
} else {
// neither reserved nor keyword?
if (!(b_reserved || b_keyword)) {
return name;
}
// apply the rule: old style '_' postfix or more modern '&' prefix?
// underscore always on non-keywords or when explicitly asked via arg
if( (!b_keyword) || old_names_ || b_force_underscore) {
return name + "_";
} else {
return "&" + name;
}
void t_delphi_generator::create_keywords() {
delphi_keywords["and"] = 1;
delphi_keywords["end"] = 1;
delphi_keywords["interface"] = 1;
delphi_keywords["raise"] = 1;
delphi_keywords["uses"] = 1;
delphi_keywords["array"] = 1;
delphi_keywords["except"] = 1;
delphi_keywords["is"] = 1;
delphi_keywords["record"] = 1;
delphi_keywords["var"] = 1;
delphi_keywords["as"] = 1;
delphi_keywords["exports"] = 1;
delphi_keywords["label"] = 1;
delphi_keywords["repeat"] = 1;
delphi_keywords["while"] = 1;
delphi_keywords["asm"] = 1;
delphi_keywords["file"] = 1;
delphi_keywords["library"] = 1;
delphi_keywords["resourcestring"] = 1;
delphi_keywords["with"] = 1;
delphi_keywords["begin"] = 1;
delphi_keywords["finalization"] = 1;
delphi_keywords["mod"] = 1;
delphi_keywords["set"] = 1;
delphi_keywords["xor"] = 1;
delphi_keywords["case"] = 1;
delphi_keywords["finally"] = 1;
delphi_keywords["nil"] = 1;
delphi_keywords["shl"] = 1;
delphi_keywords["class"] = 1;
delphi_keywords["for"] = 1;
delphi_keywords["not"] = 1;
delphi_keywords["shr"] = 1;
delphi_keywords["const"] = 1;
delphi_keywords["function"] = 1;
delphi_keywords["object"] = 1;
delphi_keywords["string"] = 1;
delphi_keywords["constructor"] = 1;
delphi_keywords["goto"] = 1;
delphi_keywords["of"] = 1;
delphi_keywords["then"] = 1;
delphi_keywords["destructor"] = 1;
delphi_keywords["if"] = 1;
delphi_keywords["or"] = 1;
delphi_keywords["threadvar"] = 1;
delphi_keywords["dispinterface"] = 1;
delphi_keywords["implementation"] = 1;
delphi_keywords["out"] = 1;
delphi_keywords["to"] = 1;
delphi_keywords["div"] = 1;
delphi_keywords["in"] = 1;
delphi_keywords["packed"] = 1;
delphi_keywords["try"] = 1;
delphi_keywords["do"] = 1;
delphi_keywords["inherited"] = 1;
delphi_keywords["procedure"] = 1;
delphi_keywords["type"] = 1;
delphi_keywords["downto"] = 1;
delphi_keywords["initialization"] = 1;
delphi_keywords["program"] = 1;
delphi_keywords["unit"] = 1;
delphi_keywords["else"] = 1;
delphi_keywords["inline"] = 1;
delphi_keywords["property"] = 1;
delphi_keywords["until"] = 1;
delphi_keywords["private"] = 1;
delphi_keywords["protected"] = 1;
delphi_keywords["public"] = 1;
delphi_keywords["published"] = 1;
delphi_keywords["automated"] = 1;
delphi_keywords["at"] = 1;
delphi_keywords["on"] = 1;
// reserved/predefined variables and types (lowercase!)
delphi_keywords["result"] = 1;
delphi_keywords["system"] = 1;
delphi_keywords["sysutils"] = 1;
delphi_keywords["thrift"] = 1;
delphi_keywords["tbytes"] = 1;
delphi_keywords["tobject"] = 1;
delphi_keywords["tclass"] = 1;
delphi_keywords["tinterfacedobject"] = 1;
delphi_keywords["ansistring"] = 1;
delphi_keywords["string"] = 1;
delphi_keywords["boolean"] = 1;
delphi_keywords["shortint"] = 1;
delphi_keywords["smallint"] = 1;
delphi_keywords["integer"] = 1;
delphi_keywords["int64"] = 1;
delphi_keywords["double"] = 1;
delphi_reserved_method["create"] = 1;
delphi_reserved_method["free"] = 1;
delphi_reserved_method["initinstance"] = 1;
delphi_reserved_method["cleanupinstance"] = 1;
delphi_reserved_method["classtype"] = 1;
delphi_reserved_method["classname"] = 1;
delphi_reserved_method["classnameis"] = 1;
delphi_reserved_method["classparent"] = 1;
delphi_reserved_method["classinfo"] = 1;
delphi_reserved_method["instancesize"] = 1;
delphi_reserved_method["inheritsfrom"] = 1;
delphi_reserved_method["methodaddress"] = 1;
delphi_reserved_method["methodname"] = 1;
delphi_reserved_method["fieldaddress"] = 1;
delphi_reserved_method["getinterface"] = 1;
delphi_reserved_method["getinterfaceentry"] = 1;
delphi_reserved_method["getinterfacetable"] = 1;
delphi_reserved_method["unitname"] = 1;
delphi_reserved_method["equals"] = 1;
delphi_reserved_method["gethashcode"] = 1;
delphi_reserved_method["tostring"] = 1;
delphi_reserved_method["safecallexception"] = 1;
delphi_reserved_method["afterconstruction"] = 1;
delphi_reserved_method["beforedestruction"] = 1;
delphi_reserved_method["dispatch"] = 1;
delphi_reserved_method["defaulthandler"] = 1;
delphi_reserved_method["newinstance"] = 1;
delphi_reserved_method["freeinstance"] = 1;
delphi_reserved_method["destroy"] = 1;
delphi_reserved_method["read"] = 1;
delphi_reserved_method["write"] = 1;
delphi_reserved_method_exception["setinnerexception"] = 1;
delphi_reserved_method_exception["setstackinfo"] = 1;
delphi_reserved_method_exception["getstacktrace"] = 1;
delphi_reserved_method_exception["raisingexception"] = 1;
delphi_reserved_method_exception["createfmt"] = 1;
delphi_reserved_method_exception["createres"] = 1;
delphi_reserved_method_exception["createresfmt"] = 1;
delphi_reserved_method_exception["createhelp"] = 1;
delphi_reserved_method_exception["createfmthelp"] = 1;
delphi_reserved_method_exception["createreshelp"] = 1;
delphi_reserved_method_exception["createresfmthelp"] = 1;
delphi_reserved_method_exception["getbaseexception"] = 1;
delphi_reserved_method_exception["baseexception"] = 1;
delphi_reserved_method_exception["helpcontext"] = 1;
delphi_reserved_method_exception["innerexception"] = 1;
delphi_reserved_method_exception["message"] = 1;
delphi_reserved_method_exception["stacktrace"] = 1;
delphi_reserved_method_exception["stackinfo"] = 1;
delphi_reserved_method_exception["getexceptionstackinfoproc"] = 1;
delphi_reserved_method_exception["getstackinfostringproc"] = 1;
delphi_reserved_method_exception["cleanupstackinfoproc"] = 1;
delphi_reserved_method_exception["raiseouterexception"] = 1;
delphi_reserved_method_exception["throwouterexception"] = 1;
}
void t_delphi_generator::add_delphi_uses_list(string unitname) {
@ -747,7 +665,6 @@ void t_delphi_generator::init_generator() {
has_forward = false;
has_enum = false;
has_const = false;
create_keywords();
add_delphi_uses_list("Classes");
add_delphi_uses_list("SysUtils");
@ -773,7 +690,7 @@ void t_delphi_generator::init_generator() {
unitname = include->get_name();
nsname = include->get_namespace("delphi");
if ("" != nsname) {
unitname = normalize_name(nsname);
unitname = normalize_name(nsname,false,false,true/*force underscore*/);
}
add_delphi_uses_list(unitname);
}
@ -793,7 +710,7 @@ void t_delphi_generator::close_generator() {
}
}
unitname = normalize_name(unitname);
unitname = normalize_name(unitname,false,false,true/*force underscore*/);
std::string f_name = get_out_dir() + "/" + unitname + ".pas";
ofstream_with_content_based_conditional_update f_all;
@ -804,6 +721,9 @@ void t_delphi_generator::close_generator() {
generate_delphi_doc(f_all, program_);
f_all << "unit " << unitname << ";" << endl << endl;
f_all << "{$WARN SYMBOL_DEPRECATED OFF}" << endl << endl;
if(com_types_) {
f_all << "{$MINENUMSIZE 4}" << endl << endl;
}
f_all << "interface" << endl << endl;
f_all << "uses" << endl;
@ -831,18 +751,14 @@ void t_delphi_generator::close_generator() {
f_all << "const" << endl;
indent_up();
indent(f_all) << "c" << tmp_unit
<< "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";"
<< endl;
indent(f_all) << "c" << tmp_unit
<< "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";"
<< endl;
indent(f_all) << "c" << tmp_unit
<< "_Option_ConstPrefix = " << (constprefix_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_Events = " << (events_ ? "True" : "False")
<< ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc = " << (xmldoc_ ? "True" : "False")
<< ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_ConstPrefix = " << (constprefix_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_Events = " << (events_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc = " << (xmldoc_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_Async = " << (async_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_COM_types = " << (com_types_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit << "_Option_Old_Names = " << (old_names_ ? "True" : "False") << ";" << endl;
indent_down();
f_all << endl;
@ -920,7 +836,7 @@ void t_delphi_generator::delphi_type_usings(ostream& out) {
void t_delphi_generator::generate_forward_declaration(t_struct* tstruct) {
// Forward declare struct def
has_forward = true;
pverbose("forward declaration of %s\n", type_name(tstruct).c_str());
pdebug("forward declaration of %s\n", type_name(tstruct).c_str());
string what = tstruct->is_xception() ? "class" : "interface";
@ -968,11 +884,11 @@ bool t_delphi_generator::is_fully_defined_type(t_type* ttype) {
}
if (ttype->is_typedef()) {
return (1 == types_known[type_name(ttype)]);
return (types_known.find(type_name(ttype)) != types_known.end());
}
if (ttype->is_base_type()) {
return (1 == types_known[base_type_name((t_base_type*)ttype)]);
return (types_known.find(base_type_name((t_base_type*)ttype)) != types_known.end());
} else if (ttype->is_enum()) {
return true; // enums are written first, before all other types
} else if (ttype->is_map()) {
@ -987,12 +903,12 @@ bool t_delphi_generator::is_fully_defined_type(t_type* ttype) {
return is_fully_defined_type(tlist->get_elem_type());
}
return (1 == types_known[type_name(ttype)]);
return (types_known.find(type_name(ttype)) != types_known.end());
}
void t_delphi_generator::add_defined_type(t_type* ttype) {
// mark as known type
types_known[type_name(ttype)] = 1;
types_known.insert(type_name(ttype));
// check all pending typedefs
std::list<t_typedef*>::iterator iter;
@ -1016,14 +932,15 @@ void t_delphi_generator::add_defined_type(t_type* ttype) {
void t_delphi_generator::init_known_types_list() {
// known base types
types_known[type_name(g_type_string)] = 1;
types_known[type_name(g_type_binary)] = 1;
types_known[type_name(g_type_bool)] = 1;
types_known[type_name(g_type_i8)] = 1;
types_known[type_name(g_type_i16)] = 1;
types_known[type_name(g_type_i32)] = 1;
types_known[type_name(g_type_i64)] = 1;
types_known[type_name(g_type_double)] = 1;
types_known.insert( type_name(g_type_string));
types_known.insert( type_name(g_type_binary));
types_known.insert( type_name(g_type_uuid));
types_known.insert( type_name(g_type_bool));
types_known.insert( type_name(g_type_i8));
types_known.insert( type_name(g_type_i16));
types_known.insert( type_name(g_type_i32));
types_known.insert( type_name(g_type_i64));
types_known.insert( type_name(g_type_double));
}
void t_delphi_generator::generate_enum(t_enum* tenum) {
@ -1156,7 +1073,7 @@ void t_delphi_generator::generate_consts(std::vector<t_const*> consts) {
for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
initialize_field(vars,
code,
"F" + prop_name((*c_iter)->get_name()),
prop_name((*c_iter)->get_name(), false, "F"),
(*c_iter)->get_type(),
(*c_iter)->get_value());
}
@ -1200,7 +1117,7 @@ void t_delphi_generator::generate_consts(std::vector<t_const*> consts) {
if (const_needs_var((*c_iter)->get_type())) {
initialize_field(vars,
code,
constants_class + ".F" + prop_name((*c_iter)->get_name()),
constants_class + "." + prop_name((*c_iter)->get_name(), false, "F"),
(*c_iter)->get_type(),
(*c_iter)->get_value());
}
@ -1392,6 +1309,9 @@ string t_delphi_generator::render_const_value(ostream& vars,
case t_base_type::TYPE_STRING:
render << "'" << get_escaped_string(value) << "'";
break;
case t_base_type::TYPE_UUID:
render << "['{" << value->get_uuid() << "}']";
break;
case t_base_type::TYPE_BOOL:
render << ((value->get_integer() > 0) ? "True" : "False");
break;
@ -1493,11 +1413,11 @@ void t_delphi_generator::generate_delphi_struct_impl(ostream& out,
if ((*m_iter)->get_value() != nullptr) {
initialize_field(vars,
code,
"F" + prop_name((*m_iter)->get_name(), is_exception),
prop_name((*m_iter)->get_name(), is_exception, ""),
t,
(*m_iter)->get_value());
if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
indent_impl(code) << "F__isset_" << prop_name((*m_iter), is_exception) << " := True;"
indent_impl(code) << prop_name((*m_iter), is_exception, "F__isset_") << " := True;"
<< endl;
}
}
@ -1777,7 +1697,7 @@ void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
out << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
isset_name = "__isset_" + prop_name(*m_iter, is_exception);
isset_name = prop_name(*m_iter, is_exception, "__isset_");
indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";"
<< endl;
}
@ -1826,7 +1746,7 @@ void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
indent(out) << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
isset_name = "F__isset_" + prop_name(*m_iter, is_exception);
isset_name = prop_name(*m_iter, is_exception, "F__isset_");
indent(out) << isset_name << ": System.Boolean;" << endl;
}
}
@ -1849,7 +1769,7 @@ void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
out << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
isset_name = "__isset_" + prop_name(*m_iter, is_exception);
isset_name = prop_name(*m_iter, is_exception, "__isset_");
indent(out) << "function Get" << isset_name << ": System.Boolean;" << endl;
indent(out) << "procedure Set" << isset_name << "( const value : System.Boolean);" << endl;
}
@ -1914,7 +1834,7 @@ void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
indent(out) << "// isset" << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
isset_name = "__isset_" + prop_name(*m_iter, is_exception);
isset_name = prop_name(*m_iter, is_exception, "__isset_");
indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";"
<< endl;
}
@ -1986,7 +1906,7 @@ void t_delphi_generator::generate_guid(std::ostream& out) {
#ifdef _WIN32 // TODO: add support for non-windows platforms if needed
GUID guid;
if (SUCCEEDED(CoCreateGuid(&guid))) {
OLECHAR guid_chars[40];
OLECHAR guid_chars[40]{};
if (StringFromGUID2(guid, &guid_chars[0], sizeof(guid_chars) / sizeof(guid_chars[0])) > 0) {
std::wstring guid_wstr(guid_chars);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
@ -2272,7 +2192,7 @@ void t_delphi_generator::generate_service_client(t_service* tservice) {
vector<t_field*>::const_iterator x_iter;
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
indent_impl(s_service_impl) << "if (" << retvar << ".__isset_" << prop_name(*x_iter)
indent_impl(s_service_impl) << "if (" << retvar << "." << prop_name(*x_iter, false, "__isset_")
<< ") then begin" << endl;
indent_up_impl();
indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter)
@ -2697,12 +2617,15 @@ void t_delphi_generator::generate_deserialize_field(ostream& out,
if (ansistr_binary_) {
out << "ReadAnsiString();";
} else {
out << "ReadBinary();";
out << (com_types_ ? "ReadBinaryCOM();" : "ReadBinary();");
}
} else {
out << "ReadString();";
}
break;
case t_base_type::TYPE_UUID:
out << "ReadUuid();";
break;
case t_base_type::TYPE_BOOL:
out << "ReadBool();";
break;
@ -2904,6 +2827,9 @@ void t_delphi_generator::generate_serialize_field(ostream& out,
}
out << name << ");";
break;
case t_base_type::TYPE_UUID:
out << "WriteUuid(" << name << ");";
break;
case t_base_type::TYPE_BOOL:
out << "WriteBool(" << name << ");";
break;
@ -3061,26 +2987,26 @@ void t_delphi_generator::generate_delphi_property(ostream& out,
bool is_xception = ftype->is_xception();
generate_delphi_doc(out, tfield);
indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": "
<< type_name(ftype, false, true, is_xception, true) << " read "
<< fieldPrefix + prop_name(tfield, struct_is_xception) << " write Set"
<< prop_name(tfield, struct_is_xception) << ";" << endl;
<< type_name(ftype, false, true, is_xception, true)
<< " read " << prop_name(tfield, struct_is_xception, fieldPrefix)
<< " write " << prop_name(tfield, struct_is_xception, "Set")
<< ";" << endl;
}
std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception) {
return prop_name(tfield->get_name(), is_xception);
std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception, std::string prefix) {
return prop_name(tfield->get_name(), is_xception, prefix);
}
std::string t_delphi_generator::prop_name(string name, bool is_xception) {
std::string t_delphi_generator::prop_name(string name, bool is_xception, std::string prefix) {
string ret = name;
ret[0] = toupper(ret[0]);
return normalize_name(ret, true, is_xception);
return normalize_name(prefix + ret, true, is_xception);
}
std::string t_delphi_generator::constructor_param_name(string name) {
string ret = name;
ret[0] = toupper(ret[0]);
ret = "A" + ret;
return normalize_name(ret, false, false);
return normalize_name("a" + ret, false, false);
}
string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) {
@ -3138,9 +3064,9 @@ string t_delphi_generator::type_name(t_type* ttype,
} else if (ttype->is_set()) {
t_set* tset = (t_set*)ttype;
if (b_cls) {
typ_nm = "THashSetImpl";
typ_nm = "TThriftHashSetImpl";
} else {
typ_nm = "IHashSet";
typ_nm = "IThriftHashSet";
}
return typ_nm + "<" + type_name(tset->get_elem_type()) + ">";
} else if (ttype->is_list()) {
@ -3189,6 +3115,7 @@ string t_delphi_generator::input_arg_prefix(t_type* ttype) {
// these should be const'ed for optimal performamce
case t_base_type::TYPE_STRING: // refcounted pointer
case t_base_type::TYPE_UUID: // refcounted pointer
case t_base_type::TYPE_I64: // larger than 32 bit
case t_base_type::TYPE_DOUBLE: // larger than 32 bit
return "const ";
@ -3236,11 +3163,13 @@ string t_delphi_generator::base_type_name(t_base_type* tbase) {
if (ansistr_binary_) {
return "System.AnsiString";
} else {
return "SysUtils.TBytes";
return com_types_ ? "IThriftBytes" : "SysUtils.TBytes";
}
} else {
return "System.string";
return com_types_ ? "System.WideString" : "System.string";
}
case t_base_type::TYPE_UUID:
return "System.TGuid";
case t_base_type::TYPE_BOOL:
return "System.Boolean";
case t_base_type::TYPE_I8:
@ -3268,7 +3197,7 @@ string t_delphi_generator::declare_field(t_field* tfield,
t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception();
string result = prefix + prop_name(tfield, is_xception_class) + ": "
string result = prop_name(tfield, is_xception_class, prefix) + ": "
+ type_name(ftype, false, true, is_xception, true) + ";";
return result;
}
@ -3310,11 +3239,11 @@ string t_delphi_generator::function_signature(t_function* tfunction,
// deprecated method? only at intf decl!
if( full_cls == "") {
auto iter = tfunction->annotations_.find("deprecated");
if( tfunction->annotations_.end() != iter) {
if( tfunction->annotations_.end() != iter && !iter->second.empty()) {
signature += " deprecated";
// empty annotation values end up with "1" somewhere, ignore these as well
if ((iter->second.length() > 0) && (iter->second != "1")) {
signature += " " + make_pascal_string_literal(iter->second);
if ((iter->second.back().length() > 0) && (iter->second.back() != "1")) {
signature += " " + make_pascal_string_literal(iter->second.back());
}
signature += ";";
}
@ -3407,6 +3336,8 @@ string t_delphi_generator::type_to_enum(t_type* type) {
throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING:
return "TType.String_";
case t_base_type::TYPE_UUID:
return "TType.Uuid";
case t_base_type::TYPE_BOOL:
return "TType.Bool_";
case t_base_type::TYPE_I8:
@ -3455,6 +3386,8 @@ string t_delphi_generator::empty_value(t_type* type) {
} else {
return "''";
}
case t_base_type::TYPE_UUID:
return "System.TGuid.Empty";
case t_base_type::TYPE_BOOL:
return "False";
case t_base_type::TYPE_I8:
@ -3486,7 +3419,7 @@ void t_delphi_generator::generate_delphi_property_writer_definition(ostream& out
t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception();
indent(out) << "procedure Set" << prop_name(tfield, is_xception_class)
indent(out) << "procedure " << prop_name(tfield, is_xception_class, "Set")
<< "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
<< endl;
}
@ -3497,15 +3430,15 @@ void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out
t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception();
indent(out) << "function Get" << prop_name(tfield, is_xception_class) << ": "
indent(out) << "function " << prop_name(tfield, is_xception_class, "Get") << ": "
<< type_name(ftype, false, true, is_xception, true) << ";" << endl;
}
void t_delphi_generator::generate_delphi_isset_reader_writer_definition(ostream& out,
t_field* tfield,
bool is_xception) {
indent(out) << "function Get__isset_" << prop_name(tfield, is_xception) << ": System.Boolean;" << endl;
indent(out) << "procedure Set__isset_" << prop_name(tfield, is_xception) << "( const value : System.Boolean);" << endl;
indent(out) << "function " << prop_name(tfield, is_xception,"Get__isset_") << ": System.Boolean;" << endl;
indent(out) << "procedure " << prop_name(tfield, is_xception, "Set__isset_") << "( const value : System.Boolean);" << endl;
}
void t_delphi_generator::generate_delphi_clear_union_value(ostream& out,
@ -3528,11 +3461,11 @@ void t_delphi_generator::generate_delphi_clear_union_value(ostream& out,
t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception();
indent_impl(out) << "if F__isset_" << prop_name(tfield, is_xception_class) << " then begin"
indent_impl(out) << "if " << prop_name(tfield, is_xception_class,"F__isset_") << " then begin"
<< endl;
indent_up_impl();
indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl;
indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := "
indent_impl(out) << prop_name(tfield, is_xception_class,"F__isset_") << " := False;" << endl;
indent_impl(out) << prop_name(tfield, is_xception_class,fieldPrefix) << " := "
<< "Default( " << type_name(ftype, false, true, is_xception, true) << ");"
<< endl;
indent_down_impl();
@ -3555,7 +3488,7 @@ void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out,
bool is_xception = ftype->is_xception();
indent_impl(out) << "procedure " << cls_prefix << name << "."
<< "Set" << prop_name(tfield, is_xception_class)
<< prop_name(tfield, is_xception_class,"Set")
<< "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
<< endl;
indent_impl(out) << "begin" << endl;
@ -3564,9 +3497,9 @@ void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out,
indent_impl(out) << "ClearUnionValues;" << endl;
}
if (tfield->get_req() != t_field::T_REQUIRED) {
indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := True;" << endl;
indent_impl(out) << prop_name(tfield, is_xception_class,"F__isset_") << " := True;" << endl;
}
indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := Value;" << endl;
indent_impl(out) << prop_name(tfield, is_xception_class,fieldPrefix) << " := Value;" << endl;
if (is_xception_class && (!is_xception_factory)) {
indent_impl(out) << xception_factory_name << "." << prop_name(tfield, is_xception_class)
@ -3590,11 +3523,11 @@ void t_delphi_generator::generate_delphi_property_reader_impl(ostream& out,
bool is_xception = ftype->is_xception();
indent_impl(out) << "function " << cls_prefix << name << "."
<< "Get" << prop_name(tfield, is_xception_class) << ": "
<< prop_name(tfield, is_xception_class,"Get") << ": "
<< type_name(ftype, false, true, is_xception, true) << ";" << endl;
indent_impl(out) << "begin" << endl;
indent_up_impl();
indent_impl(out) << "Result := " << fieldPrefix << prop_name(tfield, is_xception_class) << ";"
indent_impl(out) << "Result := " << prop_name(tfield, is_xception_class,fieldPrefix) << ";"
<< endl;
indent_down_impl();
indent_impl(out) << "end;" << endl << endl;
@ -3609,7 +3542,7 @@ void t_delphi_generator::generate_delphi_isset_reader_writer_impl(ostream& out,
bool is_xception) {
(void)type;
string isset_name = "__isset_" + prop_name(tfield, is_xception);
string isset_name = prop_name(tfield, is_xception, "__isset_");
indent_impl(out) << "function " << cls_prefix << name << "."
<< "Get" << isset_name << ": System.Boolean;" << endl;
@ -3655,7 +3588,7 @@ void t_delphi_generator::generate_delphi_create_exception_impl(ostream& out,
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
propname = prop_name(*f_iter, is_exception);
if ((*f_iter)->get_req() != t_field::T_REQUIRED) {
indent_impl(out) << "if __isset_" << propname << " then begin" << endl;
indent_impl(out) << "if " << prop_name(*f_iter, is_exception,"__isset_") << " then begin" << endl;
indent_up_impl();
}
indent_impl(out) << "Result." << propname << " := " << propname << ";" << endl;
@ -3692,9 +3625,9 @@ void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out,
// local bools for required fields
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
indent_impl(local_vars) << "_req_isset_" << prop_name(*f_iter, is_exception) << " : System.Boolean;"
indent_impl(local_vars) << prop_name(*f_iter, is_exception,"_req_isset_") << " : System.Boolean;"
<< endl;
indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := FALSE;"
indent_impl(code_block) << prop_name(*f_iter, is_exception,"_req_isset_") << " := FALSE;"
<< endl;
}
}
@ -3736,7 +3669,7 @@ void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out,
// required field?
if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := TRUE;"
indent_impl(code_block) << prop_name(*f_iter, is_exception,"_req_isset_") << " := TRUE;"
<< endl;
}
@ -3786,7 +3719,7 @@ void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out,
code_block << endl;
first = false;
}
indent_impl(code_block) << "if not _req_isset_" << prop_name(*f_iter, is_exception) << endl;
indent_impl(code_block) << "if not " << prop_name(*f_iter, is_exception,"_req_isset_") << endl;
indent_impl(code_block)
<< "then raise TProtocolExceptionInvalidData.Create("
<< "'required field " << prop_name(*f_iter, is_exception) << " not set');"
@ -3841,7 +3774,7 @@ void t_delphi_generator::generate_delphi_struct_result_writer_impl(ostream& out,
if (fields.size() > 0) {
indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then"
indent_impl(code_block) << "if (" << prop_name(*f_iter, is_exception,"__isset_") << ") then"
<< endl;
indent_impl(code_block) << "begin" << endl;
indent_up_impl();
@ -3909,6 +3842,7 @@ void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out,
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
string fieldname = prop_name((*f_iter), is_exception);
string isset_name = prop_name((*f_iter), is_exception, "__isset_");
bool null_allowed = type_can_be_null((*f_iter)->get_type());
bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED);
bool has_isset = (!is_required);
@ -3922,13 +3856,13 @@ void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out,
if (null_allowed) {
indent_impl(code_block) << "if (Self." << fieldname << " <> nil)";
if (has_isset) {
code_block << " and __isset_" << fieldname;
code_block << " and " << isset_name;
}
code_block << " then begin" << endl;
indent_up_impl();
} else {
if (has_isset) {
indent_impl(code_block) << "if (__isset_" << fieldname << ") then begin" << endl;
indent_impl(code_block) << "if (" << isset_name << ") then begin" << endl;
indent_up_impl();
}
}
@ -4021,13 +3955,13 @@ void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out,
if (null_allowed) {
indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)";
if (is_optional) {
out << " and __isset_" << prop_name(*f_iter, is_exception);
out << " and " << prop_name(*f_iter, is_exception,"__isset_");
}
out << " then begin" << endl;
indent_up_impl();
} else {
if (is_optional) {
indent_impl(out) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then begin"
indent_impl(out) << "if (" << prop_name(*f_iter, is_exception, "__isset_") << ") then begin"
<< endl;
indent_up_impl();
}
@ -4059,6 +3993,9 @@ void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out,
<< type_name(ttype, false, true, false, false)
<< ">.ToString( System.Ord( Self."
<< prop_name((*f_iter), is_exception) << ")));" << endl;
} else if (ttype->is_uuid()) {
indent_impl(out) << tmp_sb << ".Append( GUIDToString(Self." << prop_name((*f_iter), is_exception) << "));"
<< endl;
} else {
indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");"
<< endl;
@ -4105,13 +4042,20 @@ bool t_delphi_generator::is_void(t_type* type) {
return false;
}
std::string t_delphi_generator::display_name() const {
return "Delphi";
}
THRIFT_REGISTER_GENERATOR(
delphi,
"delphi",
"Delphi",
" ansistr_binary: Use AnsiString for binary datatype (default is TBytes).\n"
" register_types: Enable TypeRegistry, allows for creation of struct, union\n"
" and container instances by interface or TypeInfo()\n"
" constprefix: Name TConstants classes after IDL to reduce ambiguities\n"
" events: Enable and use processing events in the generated code.\n"
" xmldoc: Enable XMLDoc comments for Help Insight etc.\n"
" async: Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n")
" async: Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n"
" com_types: Use COM-compatible data types (e.g. WideString).\n"
" old_names: Compatibility: generate \"reserved\" identifiers with '_' postfix instead of '&' prefix.\n")

View File

@ -84,6 +84,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -1168,6 +1169,8 @@ string t_erl_generator::type_to_enum(t_type* type) {
return "?tType_I64";
case t_base_type::TYPE_DOUBLE:
return "?tType_DOUBLE";
default:
break;
}
} else if (type->is_enum()) {
return "?tType_I32";
@ -1211,6 +1214,8 @@ std::string t_erl_generator::render_type_term(t_type* type,
return "i64";
case t_base_type::TYPE_DOUBLE:
return "double";
default:
break;
}
} else if (type->is_enum()) {
return "i32";
@ -1276,6 +1281,11 @@ std::string t_erl_generator::type_module(t_type* ttype) {
return make_safe_for_module_name(ttype->get_program()->get_name()) + "_types";
}
std::string t_erl_generator::display_name() const {
return "Erl";
}
THRIFT_REGISTER_GENERATOR(
erl,
"Erlang",

View File

@ -154,6 +154,7 @@ public:
*/
void init_generator();
void close_generator();
std::string display_name() const override;
/**
* Program-level generation functions
@ -1366,6 +1367,8 @@ string t_erlang_generator::type_to_enum(t_type* type) {
return "?tType_I64";
case t_base_type::TYPE_DOUBLE:
return "?tType_DOUBLE";
default:
break;
}
} else if (type->is_enum()) {
return "?tType_I32";
@ -1409,6 +1412,8 @@ std::string t_erlang_generator::render_type_term(t_type* type,
return "i64";
case t_base_type::TYPE_DOUBLE:
return "double";
default:
break;
}
} else if (type->is_enum()) {
return "{enum, {" + type_module(type) + ", " + type_name(type) + "}}";
@ -1554,6 +1559,10 @@ string t_erlang_generator::erl_autogen_comment() {
);
}
std::string t_erlang_generator::display_name() const {
return "Erlang";
}
THRIFT_REGISTER_GENERATOR(
erlang,
"Erlang",

View File

@ -76,20 +76,11 @@ void t_generator::generate_program() {
close_generator();
}
std::set<std::string> t_generator::lang_keywords() const {
std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__",
"__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as",
"assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare",
"def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif",
"end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure",
"except", "exec", "finally", "float", "for", "foreach", "from", "function", "global",
"goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is",
"lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass",
"public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register",
"return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this",
"throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var",
"virtual", "volatile", "when", "while", "with", "xor", "yield" };
return std::set<std::string>(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) );
std::set<std::string> t_generator::lang_keywords_for_validation() const {
// Nothing by default. It makes no sense to restrict the whole world to use non-PHP keywords only.
// Override on a per-generator(!) basis if you cannot live without it, e.g. that particular language has no
// mechanism or way to deal with it properly, so we absolutely need to fail on it as the last possible resort.
return {};
}
void t_generator::validate_input() const {
@ -143,7 +134,8 @@ void t_generator::validate(t_field const* f) const {
void t_generator::validate_id(const string& id) const {
if (keywords_.find(id) != keywords_.end()) {
failure("Cannot use reserved language keyword: \"%s\"", id.c_str());
// What the message really means is "we did not get it done yet"
failure("Cannot use reserved language keyword \"%s\" with target language %s", id.c_str(), display_name().c_str());
}
}

View File

@ -43,7 +43,7 @@
class t_generator {
public:
t_generator(t_program* program) {
update_keywords();
update_keywords_for_validation();
tmp_ = 0;
indent_ = 0;
@ -100,18 +100,24 @@ public:
/**
* Check if all identifiers are valid for the target language
* See update_keywords()
* See update_keywords_for_validation()
*/
virtual void validate_input() const;
/**
* Must override. Should be equivalent to the "long name" parameter at THRIFT_REGISTER_GENERATOR.
* TODO: essentially duplicates, so we should find a way to get rid of one
*/
virtual std::string display_name() const = 0;
protected:
virtual std::set<std::string> lang_keywords() const;
virtual std::set<std::string> lang_keywords_for_validation() const;
/**
* Call this from constructor if you implement lang_keywords()
* Call this from constructor if you implement lang_keywords_for_validation()
*/
void update_keywords() {
keywords_ = lang_keywords();
void update_keywords_for_validation() {
keywords_ = lang_keywords_for_validation();
}
/**

View File

@ -41,6 +41,8 @@
#include "thrift/platform.h"
#include "thrift/version.h"
#include "thrift/generate/t_generator.h"
#include "thrift/generate/t_go_generator.h"
#include "thrift/generate/go_validator_generator.h"
using std::map;
using std::ostream;
@ -49,8 +51,6 @@ using std::string;
using std::stringstream;
using std::vector;
static const string endl = "\n"; // avoid ostream << std::endl flushes
/**
* A helper for automatically formatting the emitted Go code from the Thrift
* IDL per the Go style guide.
@ -62,277 +62,6 @@ static const string endl = "\n"; // avoid ostream << std::endl flushes
*/
bool format_go_output(const string& file_path);
const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift";
static std::string package_flag;
/**
* Go code generator.
*/
class t_go_generator : public t_generator {
public:
t_go_generator(t_program* program,
const std::map<std::string, std::string>& parsed_options,
const std::string& option_string)
: t_generator(program) {
(void)option_string;
std::map<std::string, std::string>::const_iterator iter;
gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
gen_package_prefix_ = "";
package_flag = "";
read_write_private_ = false;
ignore_initialisms_ = false;
skip_remote_ = false;
for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
if( iter->first.compare("package_prefix") == 0) {
gen_package_prefix_ = (iter->second);
} else if( iter->first.compare("thrift_import") == 0) {
gen_thrift_import_ = (iter->second);
} else if( iter->first.compare("package") == 0) {
package_flag = (iter->second);
} else if( iter->first.compare("read_write_private") == 0) {
read_write_private_ = true;
} else if( iter->first.compare("ignore_initialisms") == 0) {
ignore_initialisms_ = true;
} else if( iter->first.compare("skip_remote") == 0) {
skip_remote_ = true;
} else {
throw "unknown option go:" + iter->first;
}
}
out_dir_base_ = "gen-go";
}
/**
* Init and close methods
*/
void init_generator() override;
void close_generator() override;
/**
* Program-level generation functions
*/
void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override;
void generate_const(t_const* tconst) override;
void generate_struct(t_struct* tstruct) override;
void generate_xception(t_struct* txception) override;
void generate_service(t_service* tservice) override;
std::string render_const_value(t_type* type, t_const_value* value, const string& name, bool opt = false);
/**
* Struct generation code
*/
void generate_go_struct(t_struct* tstruct, bool is_exception);
void generate_go_struct_definition(std::ostream& out,
t_struct* tstruct,
bool is_xception = false,
bool is_result = false,
bool is_args = false);
void generate_go_struct_initializer(std::ostream& out,
t_struct* tstruct,
bool is_args_or_result = false);
void generate_isset_helpers(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false);
void generate_countsetfields_helper(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false);
void generate_go_struct_reader(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false);
void generate_go_struct_writer(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false,
bool uses_countsetfields = false);
void generate_go_struct_equals(std::ostream& out, t_struct* tstruct, const string& tstruct_name);
void generate_go_function_helpers(t_function* tfunction);
void get_publicized_name_and_def_value(t_field* tfield,
string* OUT_pub_name,
t_const_value** OUT_def_value) const;
/**
* Service-level generation functions
*/
void generate_service_helpers(t_service* tservice);
void generate_service_interface(t_service* tservice);
void generate_service_client(t_service* tservice);
void generate_service_remote(t_service* tservice);
void generate_service_server(t_service* tservice);
void generate_process_function(t_service* tservice, t_function* tfunction);
/**
* Serialization constructs
*/
void generate_deserialize_field(std::ostream& out,
t_field* tfield,
bool declare,
std::string prefix = "",
bool inclass = false,
bool coerceData = false,
bool inkey = false,
bool in_container = false);
void generate_deserialize_struct(std::ostream& out,
t_struct* tstruct,
bool is_pointer_field,
bool declare,
std::string prefix = "");
void generate_deserialize_container(std::ostream& out,
t_type* ttype,
bool pointer_field,
bool declare,
std::string prefix = "");
void generate_deserialize_set_element(std::ostream& out,
t_set* tset,
bool declare,
std::string prefix = "");
void generate_deserialize_map_element(std::ostream& out,
t_map* tmap,
bool declare,
std::string prefix = "");
void generate_deserialize_list_element(std::ostream& out,
t_list* tlist,
bool declare,
std::string prefix = "");
void generate_serialize_field(std::ostream& out,
t_field* tfield,
std::string prefix = "",
bool inkey = false);
void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
void generate_serialize_container(std::ostream& out,
t_type* ttype,
bool pointer_field,
std::string prefix = "");
void generate_serialize_map_element(std::ostream& out,
t_map* tmap,
std::string kiter,
std::string viter);
void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
void generate_go_equals(std::ostream& out, t_type* ttype, string tgt, string src);
void generate_go_equals_struct(std::ostream& out, t_type* ttype, string tgt, string src);
void generate_go_equals_container(std::ostream& out, t_type* ttype, string tgt, string src);
void generate_go_docstring(std::ostream& out, t_struct* tstruct);
void generate_go_docstring(std::ostream& out, t_function* tfunction);
void generate_go_docstring(std::ostream& out,
t_doc* tdoc,
t_struct* tstruct,
const char* subheader);
void generate_go_docstring(std::ostream& out, t_doc* tdoc);
void parse_go_tags(map<string,string>* tags, const string in);
/**
* Helper rendering functions
*/
std::string go_autogen_comment();
std::string go_package();
std::string go_imports_begin(bool consts);
std::string go_imports_end();
std::string render_includes(bool consts);
std::string render_included_programs(string& unused_protection);
std::string render_program_import(const t_program* program, string& unused_protection);
std::string render_system_packages(std::vector<string> &system_packages);
std::string render_import_protection();
std::string render_fastbinary_includes();
std::string declare_argument(t_field* tfield);
std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field);
std::string type_name(t_type* ttype);
std::string module_name(t_type* ttype);
std::string function_signature(t_function* tfunction, std::string prefix = "");
std::string function_signature_if(t_function* tfunction,
std::string prefix = "",
bool addError = false);
std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype);
std::string type_to_go_type(t_type* ttype);
std::string type_to_go_type_with_opt(t_type* ttype,
bool optional_field);
std::string type_to_go_key_type(t_type* ttype);
std::string type_to_spec_args(t_type* ttype);
static std::string get_real_go_module(const t_program* program) {
if (!package_flag.empty()) {
return package_flag;
}
std::string real_module = program->get_namespace("go");
if (!real_module.empty()) {
return real_module;
}
return lowercase(program->get_name());
}
private:
std::string gen_package_prefix_;
std::string gen_thrift_import_;
bool read_write_private_;
bool ignore_initialisms_;
bool skip_remote_;
/**
* File streams
*/
ofstream_with_content_based_conditional_update f_types_;
std::string f_types_name_;
ofstream_with_content_based_conditional_update f_consts_;
std::string f_consts_name_;
std::stringstream f_const_values_;
std::string package_name_;
std::string package_dir_;
std::unordered_map<std::string, std::string> package_identifiers_;
std::set<std::string> package_identifiers_set_;
std::string read_method_name_;
std::string write_method_name_;
std::string equals_method_name_;
std::set<std::string> commonInitialisms;
std::string camelcase(const std::string& value) const;
void fix_common_initialism(std::string& value, int i) const;
std::string publicize(const std::string& value, bool is_args_or_result = false) const;
std::string publicize(const std::string& value, bool is_args_or_result, const std::string& service_name) const;
std::string privatize(const std::string& value) const;
std::string new_prefix(const std::string& value) const;
static std::string variable_name_to_go_name(const std::string& value);
static bool is_pointer_field(t_field* tfield, bool in_container = false);
static bool omit_initialization(t_field* tfield);
};
// returns true if field initialization can be omitted since it has corresponding go type zero value
// or default value is not set
bool t_go_generator::omit_initialization(t_field* tfield) {
@ -368,6 +97,13 @@ bool t_go_generator::omit_initialization(t_field* tfield) {
} else {
return value->get_double() == 0.;
}
case t_base_type::TYPE_UUID:
// it's hard to detect all zero uuid here, so just always inline it.
return false;
default:
throw "compiler error: unhandled type";
}
}
return false;
@ -419,7 +155,11 @@ bool t_go_generator::is_pointer_field(t_field* tfield, bool in_container_value)
case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64:
case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
return !has_default;
default:
break;
}
} else if (type->is_enum()) {
return !has_default;
@ -969,6 +709,10 @@ string t_go_generator::go_imports_begin(bool consts) {
system_packages.push_back("time");
// For the thrift import, always do rename import to make sure it's called thrift.
system_packages.push_back("thrift \"" + gen_thrift_import_ + "\"");
// validator import
system_packages.push_back("strings");
system_packages.push_back("regexp");
return "import (\n" + render_system_packages(system_packages);
}
@ -979,7 +723,7 @@ string t_go_generator::go_imports_begin(bool consts) {
* This will have to do in lieu of more intelligent import statement construction
*/
string t_go_generator::go_imports_end() {
return string(
string import_end = string(
")\n\n"
"// (needed to ensure safety because of naive import list construction.)\n"
"var _ = thrift.ZERO\n"
@ -987,7 +731,11 @@ string t_go_generator::go_imports_end() {
"var _ = errors.New\n"
"var _ = context.Background\n"
"var _ = time.Now\n"
"var _ = bytes.Equal\n\n");
"var _ = bytes.Equal\n"
"// (needed by validator.)\n"
"var _ = strings.Contains\n"
"var _ = regexp.MatchString\n\n");
return import_end;
}
/**
@ -1126,7 +874,7 @@ void t_go_generator::generate_const(t_const* tconst) {
t_type* type = tconst->get_type();
string name = publicize(tconst->get_name());
t_const_value* value = tconst->get_value();
if (type->is_base_type() || type->is_enum()) {
if (type->is_enum() || (type->is_base_type() && ((t_base_type*)type)->get_base() != t_base_type::TYPE_UUID)) {
indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
} else {
f_const_values_ << indent() << name << " = " << render_const_value(type, value, name) << endl
@ -1143,8 +891,10 @@ void t_go_generator::generate_const(t_const* tconst) {
*/
string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name, bool opt) {
string typedef_opt_ptr;
string typedef_opt;
if (type->is_typedef()) {
typedef_opt_ptr = type_name(type) + "Ptr";
typedef_opt = publicize(type_name(type));
typedef_opt_ptr = typedef_opt + "Ptr";
}
type = get_true_type(type);
std::ostringstream out;
@ -1225,6 +975,19 @@ string t_go_generator::render_const_value(t_type* type, t_const_value* value, co
out << '"' + get_escaped_string(value) + '"';
break;
case t_base_type::TYPE_UUID:
if (typedef_opt_ptr != "") {
out << typedef_opt_ptr << "(" << typedef_opt;
} else {
out << "thrift.TuuidPtr";
}
out << "(";
out << "thrift.Must(thrift.ParseTuuid(\"" + get_escaped_string(value) + "\"))";
if (typedef_opt_ptr != "") {
out << ")";
}
break;
default:
throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
}
@ -1266,6 +1029,17 @@ string t_go_generator::render_const_value(t_type* type, t_const_value* value, co
break;
case t_base_type::TYPE_UUID:
if (typedef_opt != "") {
out << typedef_opt << "(";
}
out << "thrift.Must(thrift.ParseTuuid(\"" + get_escaped_string(value) + "\"))";
if (typedef_opt != "") {
out << ")";
}
break;
default:
throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
}
@ -1380,6 +1154,14 @@ void t_go_generator::generate_xception(t_struct* txception) {
*/
void t_go_generator::generate_go_struct(t_struct* tstruct, bool is_exception) {
generate_go_struct_definition(f_types_, tstruct, is_exception);
// generate Validate function
std::string tstruct_name(publicize(tstruct->get_name(), false));
f_types_ << "func (p *" << tstruct_name << ") Validate() error {" << endl;
indent_up();
go_validator_generator(this).generate_struct_validator(f_types_, tstruct);
f_types_ << indent() << "return nil" << endl;
indent_down();
f_types_ << "}" << endl;
}
void t_go_generator::get_publicized_name_and_def_value(t_field* tfield,
@ -1494,9 +1276,9 @@ void t_go_generator::generate_go_struct_definition(ostream& out,
// Check for user defined tags and them if there are any. User defined tags
// can override the above db and json tags.
std::map<string, string>::iterator it = (*m_iter)->annotations_.find("go.tag");
std::map<string, std::vector<string>>::iterator it = (*m_iter)->annotations_.find("go.tag");
if (it != (*m_iter)->annotations_.end()) {
parse_go_tags(&tags, it->second);
parse_go_tags(&tags, it->second.back());
}
string gotag;
@ -2676,6 +2458,15 @@ void t_go_generator::generate_service_remote(t_service* tservice) {
f_remote << indent() << "}" << endl;
break;
case t_base_type::TYPE_UUID:
f_remote << indent() << "argvalue" << i << ", " << err
<< " := (thrift.ParseTuuid(flag.Arg(" << flagArg << ")))" << endl;
f_remote << indent() << "if " << err << " != nil {" << endl;
f_remote << indent() << " Usage()" << endl;
f_remote << indent() << " return" << endl;
f_remote << indent() << "}" << endl;
break;
default:
throw("Invalid base type in generate_service_remote");
}
@ -2790,6 +2581,7 @@ void t_go_generator::generate_service_remote(t_service* tservice) {
case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64:
case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
f_remote << "value" << i;
break;
@ -3005,13 +2797,13 @@ void t_go_generator::generate_process_function(t_service* tservice, t_function*
f_types_ << indent() << "if thrift.ServerConnectivityCheckInterval > 0 {" << endl;
indent_up();
f_types_ << indent() << "var cancel context.CancelFunc" << endl;
f_types_ << indent() << "ctx, cancel = context.WithCancel(ctx)" << endl;
f_types_ << indent() << "defer cancel()" << endl;
f_types_ << indent() << "var cancel context.CancelCauseFunc" << endl;
f_types_ << indent() << "ctx, cancel = context.WithCancelCause(ctx)" << endl;
f_types_ << indent() << "defer cancel(nil)" << endl;
f_types_ << indent() << "var tickerCtx context.Context" << endl;
f_types_ << indent() << "tickerCtx, tickerCancel = context.WithCancel(context.Background())" << endl;
f_types_ << indent() << "defer tickerCancel()" << endl;
f_types_ << indent() << "go func(ctx context.Context, cancel context.CancelFunc) {" << endl;
f_types_ << indent() << "go func(ctx context.Context, cancel context.CancelCauseFunc) {" << endl;
indent_up();
f_types_ << indent() << "ticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)" << endl;
@ -3029,7 +2821,7 @@ void t_go_generator::generate_process_function(t_service* tservice, t_function*
indent_up();
f_types_ << indent() << "if !iprot.Transport().IsOpen() {" << endl;
indent_up();
f_types_ << indent() << "cancel()" << endl;
f_types_ << indent() << "cancel(thrift.ErrAbandonRequest)" << endl;
f_types_ << indent() << "return" << endl;
indent_down();
f_types_ << indent() << "}" << endl;
@ -3109,6 +2901,15 @@ void t_go_generator::generate_process_function(t_service* tservice, t_function*
f_types_ << indent() << "return false, thrift.WrapTException(err2)" << endl;
indent_down();
f_types_ << indent() << "}" << endl;
f_types_ << indent() << "if errors.Is(err2, context.Canceled) {" << endl;
indent_up();
f_types_ << indent() << "if err := context.Cause(ctx); errors.Is(err, thrift.ErrAbandonRequest) {" << endl;
indent_up();
f_types_ << indent() << "return false, thrift.WrapTException(err)" << endl;
indent_down();
f_types_ << indent() << "}" << endl;
indent_down();
f_types_ << indent() << "}" << endl;
string exc(tmp("_exc"));
f_types_ << indent() << exc << " := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "
@ -3303,6 +3104,10 @@ void t_go_generator::generate_deserialize_field(ostream& out,
out << "ReadDouble(ctx)";
break;
case t_base_type::TYPE_UUID:
out << "ReadUUID(ctx)";
break;
default:
throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase);
}
@ -3552,6 +3357,10 @@ void t_go_generator::generate_serialize_field(ostream& out,
out << "WriteDouble(ctx, float64(" << name << "))";
break;
case t_base_type::TYPE_UUID:
out << "WriteUUID(ctx, thrift.Tuuid(" << name << "))";
break;
default:
throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase);
}
@ -3751,6 +3560,7 @@ void t_go_generator::generate_go_equals(ostream& out, t_type* ori_type, string t
case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64:
case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
out << tgt << " != " << src;
break;
@ -4057,6 +3867,12 @@ string t_go_generator::type_to_enum(t_type* type) {
case t_base_type::TYPE_DOUBLE:
return "thrift.DOUBLE";
case t_base_type::TYPE_UUID:
return "thrift.UUID";
default:
break;
}
} else if (type->is_enum()) {
return "thrift.I32";
@ -4144,6 +3960,12 @@ string t_go_generator::type_to_go_type_with_opt(t_type* type,
case t_base_type::TYPE_DOUBLE:
return maybe_pointer + "float64";
case t_base_type::TYPE_UUID:
return maybe_pointer + "thrift.Tuuid";
default:
break;
}
} else if (type->is_enum()) {
return maybe_pointer + publicize(type_name(type));
@ -4257,6 +4079,11 @@ bool format_go_output(const string& file_path) {
*/
}
std::string t_go_generator::display_name() const {
return "Go";
}
THRIFT_REGISTER_GENERATOR(go, "Go",
" package_prefix= Package prefix for generated files.\n" \
" thrift_import= Override thrift package import path (default:" + DEFAULT_THRIFT_IMPORT + ")\n" \

View File

@ -0,0 +1,330 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef T_GO_GENERATOR_H
#define T_GO_GENERATOR_H
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>
#include "thrift/generate/t_generator.h"
#include "thrift/platform.h"
#include "thrift/version.h"
#include <algorithm>
#include <clocale>
#include <sstream>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
using std::map;
using std::ostream;
using std::ostringstream;
using std::string;
using std::stringstream;
using std::vector;
static const string endl = "\n"; // avoid ostream << std::endl flushes
const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift";
static std::string package_flag;
/**
* Go code generator.
*/
class t_go_generator : public t_generator {
public:
t_go_generator(t_program* program,
const std::map<std::string, std::string>& parsed_options,
const std::string& option_string)
: t_generator(program) {
(void)option_string;
std::map<std::string, std::string>::const_iterator iter;
gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
gen_package_prefix_ = "";
package_flag = "";
read_write_private_ = false;
ignore_initialisms_ = false;
skip_remote_ = false;
for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
if (iter->first.compare("package_prefix") == 0) {
gen_package_prefix_ = (iter->second);
} else if (iter->first.compare("thrift_import") == 0) {
gen_thrift_import_ = (iter->second);
} else if (iter->first.compare("package") == 0) {
package_flag = (iter->second);
} else if (iter->first.compare("read_write_private") == 0) {
read_write_private_ = true;
} else if (iter->first.compare("ignore_initialisms") == 0) {
ignore_initialisms_ = true;
} else if( iter->first.compare("skip_remote") == 0) {
skip_remote_ = true;
} else {
throw "unknown option go:" + iter->first;
}
}
out_dir_base_ = "gen-go";
}
/**
* Init and close methods
*/
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
*/
void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override;
void generate_const(t_const* tconst) override;
void generate_struct(t_struct* tstruct) override;
void generate_xception(t_struct* txception) override;
void generate_service(t_service* tservice) override;
std::string render_const_value(t_type* type,
t_const_value* value,
const string& name,
bool opt = false);
/**
* Struct generation code
*/
void generate_go_struct(t_struct* tstruct, bool is_exception);
void generate_go_struct_definition(std::ostream& out,
t_struct* tstruct,
bool is_xception = false,
bool is_result = false,
bool is_args = false);
void generate_go_struct_initializer(std::ostream& out,
t_struct* tstruct,
bool is_args_or_result = false);
void generate_isset_helpers(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false);
void generate_countsetfields_helper(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false);
void generate_go_struct_reader(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false);
void generate_go_struct_writer(std::ostream& out,
t_struct* tstruct,
const string& tstruct_name,
bool is_result = false,
bool uses_countsetfields = false);
void generate_go_struct_equals(std::ostream& out, t_struct* tstruct, const string& tstruct_name);
void generate_go_function_helpers(t_function* tfunction);
void get_publicized_name_and_def_value(t_field* tfield,
string* OUT_pub_name,
t_const_value** OUT_def_value) const;
/**
* Service-level generation functions
*/
void generate_service_helpers(t_service* tservice);
void generate_service_interface(t_service* tservice);
void generate_service_client(t_service* tservice);
void generate_service_remote(t_service* tservice);
void generate_service_server(t_service* tservice);
void generate_process_function(t_service* tservice, t_function* tfunction);
/**
* Serialization constructs
*/
void generate_deserialize_field(std::ostream& out,
t_field* tfield,
bool declare,
std::string prefix = "",
bool inclass = false,
bool coerceData = false,
bool inkey = false,
bool in_container = false);
void generate_deserialize_struct(std::ostream& out,
t_struct* tstruct,
bool is_pointer_field,
bool declare,
std::string prefix = "");
void generate_deserialize_container(std::ostream& out,
t_type* ttype,
bool pointer_field,
bool declare,
std::string prefix = "");
void generate_deserialize_set_element(std::ostream& out,
t_set* tset,
bool declare,
std::string prefix = "");
void generate_deserialize_map_element(std::ostream& out,
t_map* tmap,
bool declare,
std::string prefix = "");
void generate_deserialize_list_element(std::ostream& out,
t_list* tlist,
bool declare,
std::string prefix = "");
void generate_serialize_field(std::ostream& out,
t_field* tfield,
std::string prefix = "",
bool inkey = false);
void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
void generate_serialize_container(std::ostream& out,
t_type* ttype,
bool pointer_field,
std::string prefix = "");
void generate_serialize_map_element(std::ostream& out,
t_map* tmap,
std::string kiter,
std::string viter);
void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
void generate_go_equals(std::ostream& out, t_type* ttype, string tgt, string src);
void generate_go_equals_struct(std::ostream& out, t_type* ttype, string tgt, string src);
void generate_go_equals_container(std::ostream& out, t_type* ttype, string tgt, string src);
void generate_go_docstring(std::ostream& out, t_struct* tstruct);
void generate_go_docstring(std::ostream& out, t_function* tfunction);
void generate_go_docstring(std::ostream& out,
t_doc* tdoc,
t_struct* tstruct,
const char* subheader);
void generate_go_docstring(std::ostream& out, t_doc* tdoc);
void parse_go_tags(map<string, string>* tags, const string in);
/**
* Helper rendering functions
*/
std::string go_autogen_comment();
std::string go_package();
std::string go_imports_begin(bool consts);
std::string go_imports_end();
std::string render_includes(bool consts);
std::string render_included_programs(string& unused_protection);
std::string render_program_import(const t_program* program, string& unused_protection);
std::string render_system_packages(std::vector<string>& system_packages);
std::string render_import_protection();
std::string render_fastbinary_includes();
std::string declare_argument(t_field* tfield);
std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field);
std::string type_name(t_type* ttype);
std::string module_name(t_type* ttype);
std::string function_signature(t_function* tfunction, std::string prefix = "");
std::string function_signature_if(t_function* tfunction,
std::string prefix = "",
bool addError = false);
std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype);
std::string type_to_go_type(t_type* ttype);
std::string type_to_go_type_with_opt(t_type* ttype, bool optional_field);
std::string type_to_go_key_type(t_type* ttype);
std::string type_to_spec_args(t_type* ttype);
void indent_up() { t_generator::indent_up(); }
void indent_down() { t_generator::indent_down(); }
std::string indent() { return t_generator::indent(); }
std::ostream& indent(std::ostream& os) { return t_generator::indent(os); }
static std::string get_real_go_module(const t_program* program) {
if (!package_flag.empty()) {
return package_flag;
}
std::string real_module = program->get_namespace("go");
if (!real_module.empty()) {
return real_module;
}
return lowercase(program->get_name());
}
static bool is_pointer_field(t_field* tfield, bool in_container = false);
private:
std::string gen_package_prefix_;
std::string gen_thrift_import_;
bool read_write_private_;
bool ignore_initialisms_;
bool skip_remote_;
/**
* File streams
*/
ofstream_with_content_based_conditional_update f_types_;
std::string f_types_name_;
ofstream_with_content_based_conditional_update f_consts_;
std::string f_consts_name_;
std::stringstream f_const_values_;
std::string package_name_;
std::string package_dir_;
std::unordered_map<std::string, std::string> package_identifiers_;
std::set<std::string> package_identifiers_set_;
std::string read_method_name_;
std::string write_method_name_;
std::string equals_method_name_;
std::set<std::string> commonInitialisms;
std::string camelcase(const std::string& value) const;
void fix_common_initialism(std::string& value, int i) const;
std::string publicize(const std::string& value, bool is_args_or_result = false) const;
std::string publicize(const std::string& value,
bool is_args_or_result,
const std::string& service_name) const;
std::string privatize(const std::string& value) const;
std::string new_prefix(const std::string& value) const;
static std::string variable_name_to_go_name(const std::string& value);
static bool omit_initialization(t_field* tfield);
};
#endif

View File

@ -67,12 +67,15 @@ public:
/**
* Init and end of generator
*/
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
*/
void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override;
void generate_const(t_const* tconst) override;
@ -83,6 +86,7 @@ protected:
/**
* Helpers
*/
void print_type(t_type* ttype, string struct_field_ref);
void print_const_value(t_type* type, t_const_value* tvalue);
@ -339,6 +343,11 @@ void t_gv_generator::generate_service(t_service* tservice) {
f_out_ << " }" << endl;
}
std::string t_gv_generator::display_name() const {
return "Graphviz";
}
THRIFT_REGISTER_GENERATOR(
gv,
"Graphviz",

View File

@ -75,6 +75,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) override;
@ -200,6 +201,7 @@ public:
std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false);
std::string base_type_name(t_base_type* tbase, bool in_container = false);
std::string declare_field(t_field* tfield, bool init = false);
std::string render_default_value_for_type(t_type* type, bool allow_null);
std::string function_signature_combined(t_function* tfunction);
std::string function_signature_normal(t_function* tfunction);
std::string argument_list(t_struct* tstruct);
@ -208,6 +210,8 @@ public:
string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name);
void generate_service_method_signature_combined(t_function* tfunction, bool is_interface);
void generate_service_method_signature_normal(t_function* tfunction, bool is_interface);
void generate_deprecation_attribute(ostream& out, t_function* func, bool as_comment);
string make_haxe_string_literal( string const& value);
bool type_can_be_null(t_type* ttype) {
ttype = get_true_type(ttype);
@ -544,6 +548,9 @@ void t_haxe_generator::render_const_value(std::ostream& out,
case t_base_type::TYPE_STRING:
out << '"' << get_escaped_string(value) << '"';
break;
case t_base_type::TYPE_UUID:
out << '"' << get_escaped_string(value) << '"';
break;
case t_base_type::TYPE_BOOL:
out << ((value->get_integer() > 0) ? "true" : "false");
break;
@ -1443,6 +1450,9 @@ std::string t_haxe_generator::get_haxe_type_string(t_type* type) {
case t_base_type::TYPE_STRING:
return "TType.STRING";
break;
case t_base_type::TYPE_UUID:
return "TType.UUID";
break;
case t_base_type::TYPE_BOOL:
return "TType.BOOL";
break;
@ -1657,6 +1667,7 @@ void t_haxe_generator::generate_service_method_signature(t_function* tfunction,
void t_haxe_generator::generate_service_method_signature_normal(t_function* tfunction,
bool is_interface) {
if (is_interface) {
generate_deprecation_attribute(f_service_, tfunction, true);
indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl;
} else {
indent(f_service_) << "public " << function_signature_normal(tfunction) << " {" << endl;
@ -1677,12 +1688,60 @@ void t_haxe_generator::generate_service_method_signature_combined(t_function* tf
}
if (is_interface) {
generate_deprecation_attribute(f_service_, tfunction, false);
indent(f_service_) << function_signature_combined(tfunction) << ";" << endl << endl;
} else {
indent(f_service_) << "public " << function_signature_combined(tfunction) << " {" << endl;
}
}
string t_haxe_generator::make_haxe_string_literal( string const& value)
{
if (value.length() == 0) {
return "";
}
std::stringstream result;
result << "\"";
for (signed char const c: value) {
if( (c >= 0) && (c < 32)) { // convert ctrl chars, but leave UTF-8 alone
int width = std::min( (int)sizeof(c), 6);
result << "\\u{" << std::hex << std::setw(width) << std::setfill('0') << (int)c << '}';
} else if ((c == '\\') || (c == '"')) {
result << "\\" << c;
} else {
result << c; // anything else "as is"
}
}
result << "\"";
return result.str();
}
void t_haxe_generator::generate_deprecation_attribute(ostream& out, t_function* func, bool as_comment)
{
auto iter = func->annotations_.find("deprecated");
if( func->annotations_.end() != iter) {
if( as_comment) {
out << indent() << "// DEPRECATED";
} else {
out << indent() << "@:deprecated";
}
// empty annotation values end up with "1" somewhere, ignore these as well
if ((iter->second.back().length() > 0) && (iter->second.back() != "1")) {
string text = make_haxe_string_literal(iter->second.back());
if( as_comment) {
out << ": " << text;
} else {
out << "(" << text << ")";
}
}
out << endl;
}
}
/**
* Generates a service interface definition.
*
@ -1820,8 +1879,9 @@ void t_haxe_generator::generate_service_client(t_service* tservice) {
string retval = tmp("retval");
if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) {
f_service_ << indent() << "var " << retval << " : " << type_name((*f_iter)->get_returntype()) << ";"
<< endl;
f_service_ << indent() << "var " << retval << " : " << type_name((*f_iter)->get_returntype())
<< " = " << render_default_value_for_type((*f_iter)->get_returntype(),true)
<< ";" << endl;
}
if ((*f_iter)->is_oneway()) {
@ -2222,6 +2282,9 @@ void t_haxe_generator::generate_deserialize_field(ostream& out, t_field* tfield,
out << "readString();";
}
break;
case t_base_type::TYPE_UUID:
out << "readUuid();";
break;
case t_base_type::TYPE_BOOL:
out << "readBool();";
break;
@ -2406,6 +2469,9 @@ void t_haxe_generator::generate_serialize_field(ostream& out, t_field* tfield, s
out << "writeString(" << name << ");";
}
break;
case t_base_type::TYPE_UUID:
out << "writeUuid(" << name << ");";
break;
case t_base_type::TYPE_BOOL:
out << "writeBool(" << name << ");";
break;
@ -2457,7 +2523,6 @@ void t_haxe_generator::generate_serialize_struct(ostream& out, t_struct* tstruct
* @param prefix String prefix for fields
*/
void t_haxe_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
scope_up(out);
if (ttype->is_map()) {
string iter = tmp("_key");
@ -2508,7 +2573,6 @@ void t_haxe_generator::generate_serialize_container(ostream& out, t_type* ttype,
indent(out) << "oprot.writeListEnd();" << endl;
}
scope_down(out);
}
/**
@ -2573,6 +2637,8 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini
return "StringMap< " + type_name(tval) + ">";
}
break; // default to ObjectMap<>
case t_base_type::TYPE_UUID:
return "StringMap< " + type_name(tval) + ">"; // uuids are stored as strings
case t_base_type::TYPE_I8:
case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
@ -2599,6 +2665,8 @@ string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_ini
return "StringSet";
}
break; // default to ObjectSet
case t_base_type::TYPE_UUID:
return "StringSet"; // uuids are stored as strings
case t_base_type::TYPE_I8:
case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
@ -2651,6 +2719,8 @@ string t_haxe_generator::base_type_name(t_base_type* type, bool in_container) {
} else {
return "String";
}
case t_base_type::TYPE_UUID:
return "String";
case t_base_type::TYPE_BOOL:
return "Bool";
case t_base_type::TYPE_I8:
@ -2672,44 +2742,50 @@ string t_haxe_generator::base_type_name(t_base_type* type, bool in_container) {
* @param ttype The type
*/
string t_haxe_generator::declare_field(t_field* tfield, bool init) {
// TODO(mcslee): do we ever need to initialize the field?
string result = "var " + tfield->get_name() + " : " + type_name(tfield->get_type());
if (init) {
t_type* ttype = get_true_type(tfield->get_type());
if (ttype->is_base_type() && tfield->get_value() != nullptr) {
result += " = " + render_const_value_str( ttype, tfield->get_value());
} else if (ttype->is_base_type()) {
} else {
result += " = " + render_default_value_for_type( ttype, false);
}
}
return result + ";";
}
string t_haxe_generator::render_default_value_for_type( t_type* type, bool allow_null) {
t_type* ttype = get_true_type(type);
if (ttype->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
switch (tbase) {
case t_base_type::TYPE_VOID:
throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING:
result += " = null";
break;
return "null";
case t_base_type::TYPE_UUID:
return "uuid.Uuid.NIL";
case t_base_type::TYPE_BOOL:
result += " = false";
break;
return "false";
case t_base_type::TYPE_I8:
case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64:
result += " = 0";
break;
return "0";
case t_base_type::TYPE_DOUBLE:
result += " = (double)0";
break;
return "0.0";
default:
throw "unhandled type";
}
} else if (ttype->is_enum()) {
result += " = 0";
return "0";
} else if (ttype->is_container()) {
result += " = new " + type_name(ttype, false, true) + "()";
return allow_null ? "null" : "new " + type_name(ttype, false, true) + "()";
} else {
result += " = new " + type_name(ttype, false, true) + "()";
return allow_null ? "null" : "new " + type_name(ttype, false, true) + "()";
}
}
return result + ";";
}
/**
* Renders a function signature of the form 'type name(args)'
@ -2793,6 +2869,8 @@ string t_haxe_generator::type_to_enum(t_type* type) {
throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING:
return "TType.STRING";
case t_base_type::TYPE_UUID:
return "TType.UUID";
case t_base_type::TYPE_BOOL:
return "TType.BOOL";
case t_base_type::TYPE_I8:
@ -2805,6 +2883,8 @@ string t_haxe_generator::type_to_enum(t_type* type) {
return "TType.I64";
case t_base_type::TYPE_DOUBLE:
return "TType.DOUBLE";
default:
break;
}
} else if (type->is_enum()) {
return "TType.I32";
@ -2994,6 +3074,11 @@ std::string t_haxe_generator::get_enum_class_name(t_type* type) {
return package + type->get_name();
}
std::string t_haxe_generator::display_name() const {
return "Haxe";
}
THRIFT_REGISTER_GENERATOR(
haxe,
"Haxe",

View File

@ -81,6 +81,7 @@ public:
init_allowed__markup();
}
std::string display_name() const override;
void generate_program() override;
void generate_program_toc();
@ -1076,6 +1077,11 @@ void t_html_generator::generate_service(t_service* tservice) {
}
}
std::string t_html_generator::display_name() const {
return "HTML";
}
THRIFT_REGISTER_GENERATOR(
html,
"HTML",

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) override;
@ -2869,6 +2870,8 @@ string t_javame_generator::declare_field(t_field* tfield, bool init) {
case t_base_type::TYPE_DOUBLE:
result += " = (double)0";
break;
default:
throw "compiler error: unhandled type";
}
} else if (ttype->is_enum()) {
@ -2951,6 +2954,8 @@ string t_javame_generator::type_to_enum(t_type* type) {
return "TType.I64";
case t_base_type::TYPE_DOUBLE:
return "TType.DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "TType.I32";
@ -3291,4 +3296,9 @@ void t_javame_generator::generate_java_struct_clear(std::ostream& out, t_struct*
indent(out) << "}" << endl << endl;
}
std::string t_javame_generator::display_name() const {
return "Java ME";
}
THRIFT_REGISTER_GENERATOR(javame, "Java ME", "")

View File

@ -134,6 +134,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -154,6 +155,7 @@ public:
/**
* Structs!
*/
void generate_js_struct(t_struct* tstruct, bool is_exception);
void generate_js_struct_definition(std::ostream& out,
t_struct* tstruct,
@ -166,6 +168,7 @@ public:
/**
* Service-level generation functions
*/
void generate_service_helpers(t_service* tservice);
void generate_service_interface(t_service* tservice);
void generate_service_rest(t_service* tservice);
@ -232,6 +235,7 @@ public:
/**
* Helper parser functions
*/
void parse_imports(t_program* program, const std::string& imports_string);
void parse_thrift_package_output_directory(const std::string& thrift_package_output_directory);
@ -1489,7 +1493,7 @@ void t_js_generator::generate_process_function(t_service* tservice, t_function*
indent_up();
if (gen_es6_) {
indent(f_service_) << "Promise.resolve(this._handler." << tfunction->get_name() << ".bind(this._handler)(" << endl;
indent(f_service_) << "new Promise((resolve) => resolve(this._handler." << tfunction->get_name() << ".bind(this._handler)(" << endl;
} else {
string maybeComma = (fields.size() > 0 ? "," : "");
indent(f_service_) << "Q.fcall(this._handler." << tfunction->get_name() << ".bind(this._handler)"
@ -1504,7 +1508,7 @@ void t_js_generator::generate_process_function(t_service* tservice, t_function*
indent_down();
if (gen_es6_) {
indent(f_service_) << ")).then(result => {" << endl;
indent(f_service_) << "))).then(result => {" << endl;
} else {
indent(f_service_) << ").then(function(result) {" << endl;
}
@ -2703,6 +2707,8 @@ string t_js_generator::type_to_enum(t_type* type) {
return "Thrift.Type.I64";
case t_base_type::TYPE_DOUBLE:
return "Thrift.Type.DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "Thrift.Type.I32";
@ -2751,6 +2757,9 @@ string t_js_generator::ts_get_type(t_type* type) {
break;
case t_base_type::TYPE_VOID:
ts_type = "void";
break;
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum() || type->is_struct() || type->is_xception()) {
std::string type_name;
@ -2998,6 +3007,11 @@ std::string t_js_generator::next_identifier_name(const std::vector<t_field*>& fi
return current_name;
}
std::string t_js_generator::display_name() const {
return "Javascript";
}
THRIFT_REGISTER_GENERATOR(js,
"Javascript",
" jquery: Generate jQuery compatible code.\n"

View File

@ -73,9 +73,9 @@ public:
/**
* Init and close methods
*/
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override;
@ -245,7 +245,7 @@ void t_json_generator::end_array() {
void t_json_generator::write_type_spec_object(const char* name, t_type* ttype) {
ttype = ttype->get_true_type();
if (ttype->is_struct() || ttype->is_xception() || ttype->is_container()) {
if (ttype->is_struct() || ttype->is_xception() || ttype->is_container() || ttype->is_enum()) {
write_key_and(name);
start_object(NO_INDENT);
write_key_and("typeId");
@ -268,12 +268,14 @@ void t_json_generator::write_type_spec(t_type* ttype) {
write_key_and("annotations");
start_object();
for (auto & annotation : ttype->annotations_) {
write_key_and_string(annotation.first, annotation.second);
for (auto& annotation_value : annotation.second) {
write_key_and_string(annotation.first, annotation_value);
}
}
end_object();
}
if (ttype->is_struct() || ttype->is_xception()) {
if (ttype->is_struct() || ttype->is_xception() || ttype->is_enum()) {
write_key_and_string("class", get_qualified_name(ttype));
} else if (ttype->is_map()) {
t_type* ktype = ((t_map*)ttype)->get_key_type();
@ -459,7 +461,9 @@ void t_json_generator::generate_typedef(t_typedef* ttypedef) {
write_key_and("annotations");
start_object();
for (auto & annotation : ttypedef->annotations_) {
write_key_and_string(annotation.first, annotation.second);
for (auto& annotation_value : annotation.second) {
write_key_and_string(annotation.first, annotation_value);
}
}
end_object();
}
@ -566,7 +570,9 @@ void t_json_generator::generate_enum(t_enum* tenum) {
write_key_and("annotations");
start_object();
for (auto & annotation : tenum->annotations_) {
write_key_and_string(annotation.first, annotation.second);
for (auto& annotation_value : annotation.second) {
write_key_and_string(annotation.first, annotation_value);
}
}
end_object();
}
@ -605,7 +611,9 @@ void t_json_generator::generate_struct(t_struct* tstruct) {
write_key_and("annotations");
start_object();
for (auto & annotation : tstruct->annotations_) {
write_key_and_string(annotation.first, annotation.second);
for (auto& annotation_value : annotation.second) {
write_key_and_string(annotation.first, annotation_value);
}
}
end_object();
}
@ -645,7 +653,9 @@ void t_json_generator::generate_service(t_service* tservice) {
write_key_and("annotations");
start_object();
for (auto & annotation : tservice->annotations_) {
write_key_and_string(annotation.first, annotation.second);
for (auto& annotation_value : annotation.second) {
write_key_and_string(annotation.first, annotation_value);
}
}
end_object();
}
@ -682,7 +692,9 @@ void t_json_generator::generate_function(t_function* tfunc) {
write_key_and("annotations");
start_object();
for (auto & annotation : tfunc->annotations_) {
write_key_and_string(annotation.first, annotation.second);
for (auto& annotation_value : annotation.second) {
write_key_and_string(annotation.first, annotation_value);
}
}
end_object();
}
@ -728,7 +740,9 @@ void t_json_generator::generate_field(t_field* field) {
write_key_and("annotations");
start_object();
for (auto & annotation : field->annotations_) {
write_key_and_string(annotation.first, annotation.second);
for (auto& annotation_value : annotation.second) {
write_key_and_string(annotation.first, annotation_value);
}
}
end_object();
}
@ -766,7 +780,7 @@ string t_json_generator::get_type_name(t_type* ttype) {
return "map";
}
if (ttype->is_enum()) {
return "i32";
return "enum";
}
if (ttype->is_struct()) {
return ((t_struct*)ttype)->is_union() ? "union" : "struct";
@ -789,6 +803,11 @@ string t_json_generator::get_qualified_name(t_type* ttype) {
return ttype->get_program()->get_name() + "." + ttype->get_name();
}
std::string t_json_generator::display_name() const {
return "JSON";
}
THRIFT_REGISTER_GENERATOR(json,
"JSON",
" merge: Generate output with included files merged\n")

View File

@ -75,8 +75,10 @@ public:
/**
* Init and close methods
*/
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) override;
@ -348,6 +350,8 @@ string t_kotlin_generator::base_type_name(t_base_type* type) {
return "kotlin.Int";
case t_base_type::TYPE_I64:
return "kotlin.Long";
case t_base_type::TYPE_UUID:
return "java.util.UUID";
case t_base_type::TYPE_DOUBLE:
return "kotlin.Double";
default:
@ -583,7 +587,7 @@ void t_kotlin_generator::generate_metadata_for_field_annotations(std::ostream& o
out << "mapOf(" << endl;
indent_up();
for (auto& annotation : field->annotations_) {
indent(out) << "\"" + annotation.first + "\" to \"" + annotation.second + "\"," << endl;
indent(out) << "\"" + annotation.first + "\" to \"" + annotation.second.back() + "\"," << endl;
}
indent_down();
indent(out) << ")";
@ -1218,6 +1222,8 @@ string t_kotlin_generator::base_type_write_expression(t_base_type* tbase, string
return "writeI32(" + it + ")";
case t_base_type::TYPE_I64:
return "writeI64(" + it + ")";
case t_base_type::TYPE_UUID:
return "writeUuid(" + it + ")";
case t_base_type::TYPE_DOUBLE:
return "writeDouble(" + it + ")";
default:
@ -1246,6 +1252,8 @@ string t_kotlin_generator::base_type_read_expression(t_base_type* tbase) {
return "readI32()";
case t_base_type::TYPE_I64:
return "readI64()";
case t_base_type::TYPE_UUID:
return "readUuid()";
case t_base_type::TYPE_DOUBLE:
return "readDouble()";
default:
@ -1908,8 +1916,12 @@ string t_kotlin_generator::type_to_enum(t_type* type) {
return "org.apache.thrift.protocol.TType.I32";
case t_base_type::TYPE_I64:
return "org.apache.thrift.protocol.TType.I64";
case t_base_type::TYPE_UUID:
return "org.apache.thrift.protocol.TType.UUID";
case t_base_type::TYPE_DOUBLE:
return "org.apache.thrift.protocol.TType.DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "org.apache.thrift.protocol.TType.I32";
@ -2013,4 +2025,9 @@ void t_kotlin_generator::generate_kdoc_comment(ostream& out, t_doc* tdoc) {
}
}
std::string t_kotlin_generator::display_name() const {
return "Kotlin";
}
THRIFT_REGISTER_GENERATOR(kotlin, "Kotlin", "")

View File

@ -56,12 +56,15 @@ public:
/**
* Init and close methods
*/
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
*/
void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override;
void generate_const(t_const* tconst) override;
@ -80,6 +83,7 @@ private:
/**
* Struct-level generation functions
*/
void generate_lua_struct_definition(std::ostream& out,
t_struct* tstruct,
bool is_xception = false);
@ -89,6 +93,7 @@ private:
/**
* Service-level generation functions
*/
void generate_service_client(std::ostream& out, t_service* tservice);
void generate_service_interface(std::ostream& out, t_service* tservice);
void generate_service_processor(std::ostream& out, t_service* tservice);
@ -99,6 +104,7 @@ private:
/**
* Deserialization (Read)
*/
void generate_deserialize_field(std::ostream& out,
t_field* tfield,
bool local,
@ -125,6 +131,7 @@ private:
/**
* Serialization (Write)
*/
void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
@ -1146,6 +1153,8 @@ string t_lua_generator::type_to_enum(t_type* type) {
return "TType.I64";
case t_base_type::TYPE_DOUBLE:
return "TType.DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "TType.I32";
@ -1162,6 +1171,11 @@ string t_lua_generator::type_to_enum(t_type* type) {
throw "INVALID TYPE IN type_to_enum: " + type->get_name();
}
std::string t_lua_generator::display_name() const {
return "Lua";
}
THRIFT_REGISTER_GENERATOR(
lua,
"Lua",

View File

@ -84,6 +84,8 @@ public:
init_allowed__markup();
}
std::string display_name() const override;
void generate_program() override;
void generate_program_toc();
void generate_program_toc_row(t_program* tprog);
@ -1103,6 +1105,11 @@ void t_markdown_generator::generate_service(t_service* tservice) {
}
}
std::string t_markdown_generator::display_name() const {
return "Markdown";
}
THRIFT_REGISTER_GENERATOR(
markdown,
"Markdown",

View File

@ -123,11 +123,6 @@ bool t_netstd_generator::is_serialize_enabled() const { return serialize_; }
bool t_netstd_generator::is_union_enabled() const { return union_; }
map<string, int> t_netstd_generator::get_keywords_list() const
{
return netstd_keywords;
}
void t_netstd_generator::init_generator()
{
MKDIR(get_out_dir().c_str());
@ -151,7 +146,6 @@ void t_netstd_generator::init_generator()
}
namespace_dir_ = subdir;
init_keywords();
while (!member_mapping_scopes.empty())
{
@ -185,120 +179,16 @@ string t_netstd_generator::normalize_name(string name, bool is_arg_name)
return "@" + name;
}
// prevent CS8981 "The type name only contains lower-cased ascii characters"
if( name.find_first_not_of("abcdefghijklmnopqrstuvwxyz") == std::string::npos)
{
return "@" + name;
}
// no changes necessary
return name;
}
void t_netstd_generator::init_keywords()
{
netstd_keywords.clear();
// C# keywords
netstd_keywords["abstract"] = 1;
netstd_keywords["as"] = 1;
netstd_keywords["base"] = 1;
netstd_keywords["bool"] = 1;
netstd_keywords["break"] = 1;
netstd_keywords["byte"] = 1;
netstd_keywords["case"] = 1;
netstd_keywords["catch"] = 1;
netstd_keywords["char"] = 1;
netstd_keywords["checked"] = 1;
netstd_keywords["class"] = 1;
netstd_keywords["const"] = 1;
netstd_keywords["continue"] = 1;
netstd_keywords["decimal"] = 1;
netstd_keywords["default"] = 1;
netstd_keywords["delegate"] = 1;
netstd_keywords["do"] = 1;
netstd_keywords["double"] = 1;
netstd_keywords["else"] = 1;
netstd_keywords["enum"] = 1;
netstd_keywords["event"] = 1;
netstd_keywords["explicit"] = 1;
netstd_keywords["extern"] = 1;
netstd_keywords["false"] = 1;
netstd_keywords["finally"] = 1;
netstd_keywords["fixed"] = 1;
netstd_keywords["float"] = 1;
netstd_keywords["for"] = 1;
netstd_keywords["foreach"] = 1;
netstd_keywords["goto"] = 1;
netstd_keywords["if"] = 1;
netstd_keywords["implicit"] = 1;
netstd_keywords["in"] = 1;
netstd_keywords["int"] = 1;
netstd_keywords["interface"] = 1;
netstd_keywords["internal"] = 1;
netstd_keywords["is"] = 1;
netstd_keywords["lock"] = 1;
netstd_keywords["long"] = 1;
netstd_keywords["namespace"] = 1;
netstd_keywords["new"] = 1;
netstd_keywords["null"] = 1;
netstd_keywords["object"] = 1;
netstd_keywords["operator"] = 1;
netstd_keywords["out"] = 1;
netstd_keywords["override"] = 1;
netstd_keywords["params"] = 1;
netstd_keywords["private"] = 1;
netstd_keywords["protected"] = 1;
netstd_keywords["public"] = 1;
netstd_keywords["readonly"] = 1;
netstd_keywords["ref"] = 1;
netstd_keywords["return"] = 1;
netstd_keywords["sbyte"] = 1;
netstd_keywords["sealed"] = 1;
netstd_keywords["short"] = 1;
netstd_keywords["sizeof"] = 1;
netstd_keywords["stackalloc"] = 1;
netstd_keywords["static"] = 1;
netstd_keywords["string"] = 1;
netstd_keywords["struct"] = 1;
netstd_keywords["switch"] = 1;
netstd_keywords["this"] = 1;
netstd_keywords["throw"] = 1;
netstd_keywords["true"] = 1;
netstd_keywords["try"] = 1;
netstd_keywords["typeof"] = 1;
netstd_keywords["uint"] = 1;
netstd_keywords["ulong"] = 1;
netstd_keywords["unchecked"] = 1;
netstd_keywords["unsafe"] = 1;
netstd_keywords["ushort"] = 1;
netstd_keywords["using"] = 1;
netstd_keywords["virtual"] = 1;
netstd_keywords["void"] = 1;
netstd_keywords["volatile"] = 1;
netstd_keywords["while"] = 1;
// C# contextual keywords
netstd_keywords["add"] = 1;
netstd_keywords["alias"] = 1;
netstd_keywords["ascending"] = 1;
netstd_keywords["async"] = 1;
netstd_keywords["await"] = 1;
netstd_keywords["descending"] = 1;
netstd_keywords["dynamic"] = 1;
netstd_keywords["from"] = 1;
netstd_keywords["get"] = 1;
netstd_keywords["global"] = 1;
netstd_keywords["group"] = 1;
netstd_keywords["into"] = 1;
netstd_keywords["join"] = 1;
netstd_keywords["let"] = 1;
netstd_keywords["orderby"] = 1;
netstd_keywords["partial"] = 1;
netstd_keywords["remove"] = 1;
netstd_keywords["select"] = 1;
netstd_keywords["set"] = 1;
netstd_keywords["value"] = 1;
netstd_keywords["var"] = 1;
netstd_keywords["where"] = 1;
netstd_keywords["yield"] = 1;
netstd_keywords["when"] = 1;
}
void t_netstd_generator::reset_indent() {
while( indent_count() > 0) {
@ -427,7 +317,7 @@ void t_netstd_generator::generate_enum(ostream& out, t_enum* tenum)
{
generate_netstd_doc(out, *c_iter);
int value = (*c_iter)->get_value();
out << indent() << (*c_iter)->get_name() << " = " << value << "," << endl;
out << indent() << normalize_name((*c_iter)->get_name()) << " = " << value << "," << endl;
}
scope_down(out);
@ -472,7 +362,7 @@ void t_netstd_generator::generate_consts(ostream& out, vector<t_const*> consts)
for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter)
{
generate_netstd_doc(out, *c_iter);
if (print_const_value(out, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false))
if (print_const_value(out, normalize_name((*c_iter)->get_name()), (*c_iter)->get_type(), (*c_iter)->get_value(), false))
{
need_static_constructor = true;
}
@ -590,7 +480,7 @@ bool t_netstd_generator::print_const_value(ostream& out, string name, t_type* ty
if (type->is_base_type())
{
string v2 = render_const_value(out, name, type, value);
out << normalize_name(name) << " = " << v2 << ";" << endl;
out << name << " = " << v2 << ";" << endl;
need_static_construction = false;
}
else if (type->is_enum())
@ -636,6 +526,9 @@ string t_netstd_generator::render_const_value(ostream& out, string name, t_type*
render << '"' << get_escaped_string(value) << '"';
}
break;
case t_base_type::TYPE_UUID:
render << "new System.Guid(\"" << get_escaped_string(value) << "\")";
break;
case t_base_type::TYPE_BOOL:
render << ((value->get_integer() > 0) ? "true" : "false");
break;
@ -665,7 +558,7 @@ string t_netstd_generator::render_const_value(ostream& out, string name, t_type*
}
else
{
string t = tmp("tmp");
string t = normalize_name(tmp("tmp"));
print_const_value(out, t, type, value, true, true, true);
render << t;
}
@ -1053,7 +946,7 @@ void t_netstd_generator::generate_netstd_struct_definition(ostream& out, t_struc
{
if (field_is_required((*m_iter)))
{
print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true);
print_const_value(out, "this." + normalize_name(prop_name(*m_iter)), t, (*m_iter)->get_value(), true, true);
}
else
{
@ -1569,14 +1462,14 @@ void t_netstd_generator::generate_netstd_union_definition(ostream& out, t_struct
// Let's define the class first
start_netstd_namespace(out);
out << indent() << "public abstract partial class " << tunion->get_name() << " : TUnionBase" << endl;
out << indent() << "public abstract partial class " << normalize_name(tunion->get_name()) << " : TUnionBase" << endl;
out << indent() << "{" << endl;
indent_up();
out << indent() << "public abstract global::System.Threading.Tasks.Task WriteAsync(TProtocol tProtocol, CancellationToken " << CANCELLATION_TOKEN_NAME << ");" << endl
<< indent() << "public readonly int Isset;" << endl
<< indent() << "public abstract object" << nullable_suffix() <<" Data { get; }" << endl
<< indent() << "protected " << tunion->get_name() << "(int isset)" << endl
<< indent() << "protected " << normalize_name(tunion->get_name()) << "(int isset)" << endl
<< indent() << "{" << endl;
indent_up();
out << indent() << "Isset = isset;" << endl;
@ -1782,13 +1675,13 @@ void t_netstd_generator::generate_netstd_union_class(ostream& out, t_struct* tun
<< endl;
out << indent() << "public class " << tfield->get_name() << " : " << tunion->get_name() << endl;
out << indent() << "public class " << normalize_name(tfield->get_name()) << " : " << normalize_name(tunion->get_name()) << endl;
out << indent() << "{" << endl;
indent_up();
out << indent() << "private readonly " << type_name(tfield->get_type()) << " _data;" << endl
<< indent() << "public override object" << nullable_suffix() <<" Data { get { return _data; } }" << endl
<< indent() << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) << " data) : base("<< tfield->get_key() <<")" << endl
<< indent() << "public " << normalize_name(tfield->get_name()) << "(" << type_name(tfield->get_type()) << " data) : base("<< tfield->get_key() <<")" << endl
<< indent() << "{" << endl;
indent_up();
out << indent() << "this._data = data;" << endl;
@ -1796,13 +1689,13 @@ void t_netstd_generator::generate_netstd_union_class(ostream& out, t_struct* tun
out << indent() << "}" << endl;
if( ! suppress_deepcopy) {
out << indent() << "public new " << tfield->get_name() << " " << DEEP_COPY_METHOD_NAME << "()" << endl;
out << indent() << "public new " << normalize_name(tfield->get_name()) << " " << DEEP_COPY_METHOD_NAME << "()" << endl;
out << indent() << "{" << endl;
indent_up();
bool needs_typecast = false;
string suffix("");
string copy_op = get_deep_copy_method_call(tfield->get_type(), true, needs_typecast, suffix);
out << indent() << "return new " << tfield->get_name() << "(_data" << copy_op << ");" << endl;
out << indent() << "return new " << normalize_name(tfield->get_name()) << "(_data" << copy_op << ");" << endl;
indent_down();
out << indent() << "}" << endl << endl;
}
@ -2056,8 +1949,8 @@ void t_netstd_generator::generate_deprecation_attribute(ostream& out, t_function
if( func->annotations_.end() != iter) {
out << indent() << "[Obsolete";
// empty annotation values end up with "1" somewhere, ignore these as well
if ((iter->second.length() > 0) && (iter->second != "1")) {
out << "(" << make_csharp_string_literal(iter->second) << ")";
if ((iter->second.back().length() > 0) && (iter->second.back() != "1")) {
out << "(" << make_csharp_string_literal(iter->second.back()) << ")";
}
out << "]" << endl;
}
@ -2703,6 +2596,9 @@ void t_netstd_generator::generate_deserialize_field(ostream& out, t_field* tfiel
out << "ReadStringAsync(" << CANCELLATION_TOKEN_NAME << ");";
}
break;
case t_base_type::TYPE_UUID:
out << "ReadUuidAsync(" << CANCELLATION_TOKEN_NAME << ");";
break;
case t_base_type::TYPE_BOOL:
out << "ReadBoolAsync(" << CANCELLATION_TOKEN_NAME << ");";
break;
@ -2906,6 +2802,9 @@ void t_netstd_generator::generate_serialize_field(ostream& out, t_field* tfield,
}
out << name << ", " << CANCELLATION_TOKEN_NAME << ");";
break;
case t_base_type::TYPE_UUID:
out << "WriteUuidAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");";
break;
case t_base_type::TYPE_BOOL:
out << "WriteBoolAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");";
break;
@ -3492,6 +3391,8 @@ string t_netstd_generator::base_type_name(t_base_type* tbase)
} else {
return "string";
}
case t_base_type::TYPE_UUID:
return "global::System.Guid";
case t_base_type::TYPE_BOOL:
return "bool";
case t_base_type::TYPE_I8:
@ -3614,6 +3515,9 @@ string t_netstd_generator::initialize_field(t_field* tfield)
return " = null";
}
break;
case t_base_type::TYPE_UUID:
return " = System.Guid.Empty";
break;
case t_base_type::TYPE_BOOL:
return " = false";
break;
@ -3725,6 +3629,8 @@ string t_netstd_generator::type_to_enum(t_type* type)
throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING:
return "TType.String";
case t_base_type::TYPE_UUID:
return "TType.Uuid";
case t_base_type::TYPE_BOOL:
return "TType.Bool";
case t_base_type::TYPE_I8:
@ -3858,6 +3764,11 @@ string t_netstd_generator::get_enum_class_name(t_type* type)
return "global::" + package + type->get_name();
}
std::string t_netstd_generator::display_name() const {
return "C#";
}
THRIFT_REGISTER_GENERATOR(
netstd,
"C#",

View File

@ -37,6 +37,7 @@
#include "thrift/generate/t_oop_generator.h"
using std::map;
using std::set;
using std::ostream;
using std::ostringstream;
using std::string;
@ -66,11 +67,11 @@ public:
bool is_hashcode_enabled() const;
bool is_serialize_enabled() const;
bool is_union_enabled() const;
map<string, int> get_keywords_list() const;
// overrides
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_consts(vector<t_const*> consts) override;
void generate_consts(ostream& out, vector<t_const*> consts);
void generate_typedef(t_typedef* ttypedef) override;
@ -179,13 +180,26 @@ private:
bool use_net6_features;
bool add_async_postfix;
const std::string CSHARP_KEYWORDS[101] = {
// C# keywords
"abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue",
"decimal", "default", "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally",
"fixed", "float", "for", "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock",
"long", "namespace", "new", "null", "object", "operator", "out", "override", "params", "private", "protected",
"public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", "static", "string",
"struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort",
"using", "virtual", "void", "volatile", "while",
// C# contextual keywords
"add", "alias", "ascending", "async", "await", "descending", "dynamic", "from", "get", "global", "group", "into",
"join", "let", "orderby", "partial", "remove", "select", "set", "value", "var", "when", "where", "yield"
};
string wcf_namespace_;
map<string, int> netstd_keywords;
std::set<string> netstd_keywords = std::set<string>(CSHARP_KEYWORDS, CSHARP_KEYWORDS + sizeof(CSHARP_KEYWORDS) / sizeof(CSHARP_KEYWORDS[0]));
vector<member_mapping_scope> member_mapping_scopes;
map<string, t_type*> collected_extension_types;
map<string, t_type*> checked_extension_types;
void init_keywords();
string normalize_name(string name, bool is_arg_name = false);
string make_valid_csharp_identifier(string const& fromName);
string make_csharp_string_literal( string const& value);

View File

@ -61,16 +61,15 @@ public:
out_dir_base_ = "gen-ocaml";
}
/**
* Init and close methods
*/
~t_ocaml_generator() override;
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
*/
void generate_program() override;
void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override;
@ -147,16 +146,20 @@ public:
* Helper rendering functions
*/
std::string ocaml_autogen_comment();
/** Need to disable codegen comment for unit tests to be version-agnostic */
virtual std::string ocaml_autogen_comment();
std::string ocaml_imports();
std::string type_name(t_type* ttype);
std::string exception_ctor(t_type* ttype);
std::string function_signature(t_function* tfunction, std::string prefix = "");
std::string function_type(t_function* tfunc, bool method = false, bool options = false);
std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype);
std::string render_ocaml_type(t_type* type);
private:
// Need access to output file streams for testing.
protected:
/**
* File streams
*/
@ -216,9 +219,6 @@ void t_ocaml_generator::generate_program() {
// Generate constants
vector<t_const*> consts = program_->get_consts();
generate_consts(consts);
// Close the generator
close_generator();
}
/**
@ -262,12 +262,12 @@ string t_ocaml_generator::ocaml_imports() {
return "open Thrift";
}
/**
* Closes the type files
*/
void t_ocaml_generator::close_generator() {
// Close types file
t_ocaml_generator::~t_ocaml_generator() {
f_consts_.close();
f_types_.close();
f_types_i_.close();
f_service_.close();
f_service_i_.close();
}
/**
@ -914,10 +914,6 @@ void t_ocaml_generator::generate_service(t_service* tservice) {
generate_service_interface(tservice);
generate_service_client(tservice);
generate_service_server(tservice);
// Close service file
f_service_.close();
f_service_i_.close();
}
/**
@ -1108,7 +1104,7 @@ void t_ocaml_generator::generate_service_client(t_service* tservice) {
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
f_service_ << indent() << "(match result#get_" << (*x_iter)->get_name()
<< " with None -> () | Some _v ->" << endl;
indent(f_service_) << " raise (" << capitalize(type_name((*x_iter)->get_type()))
indent(f_service_) << " raise (" << capitalize(exception_ctor((*x_iter)->get_type()))
<< " _v));" << endl;
}
@ -1270,7 +1266,7 @@ void t_ocaml_generator::generate_process_function(t_service* tservice, t_functio
indent(f_service_) << "with" << endl;
indent_up();
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
f_service_ << indent() << "| " << capitalize(type_name((*x_iter)->get_type())) << " "
f_service_ << indent() << "| " << capitalize(exception_ctor((*x_iter)->get_type())) << " "
<< (*x_iter)->get_name() << " -> " << endl;
indent_up();
indent_up();
@ -1673,6 +1669,18 @@ string t_ocaml_generator::type_name(t_type* ttype) {
return prefix + name;
}
string t_ocaml_generator::exception_ctor(t_type* ttype) {
string prefix = "";
t_program* program = ttype->get_program();
if (program != nullptr && program != program_) {
if (!ttype->is_service()) {
prefix = capitalize(program->get_name()) + "_types.";
}
}
return prefix + capitalize(ttype->get_name());
}
/**
* Converts the parse type to a Protocol.t_type enum
*/
@ -1698,6 +1706,8 @@ string t_ocaml_generator::type_to_enum(t_type* type) {
return "Protocol.T_I64";
case t_base_type::TYPE_DOUBLE:
return "Protocol.T_DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "Protocol.T_I32";
@ -1739,6 +1749,8 @@ string t_ocaml_generator::render_ocaml_type(t_type* type) {
return "Int64.t";
case t_base_type::TYPE_DOUBLE:
return "float";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return capitalize(((t_enum*)type)->get_name()) + ".t";
@ -1759,4 +1771,9 @@ string t_ocaml_generator::render_ocaml_type(t_type* type) {
throw "INVALID TYPE IN type_to_enum: " + type->get_name();
}
std::string t_ocaml_generator::display_name() const {
return "OCaml";
}
THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "")

View File

@ -70,7 +70,7 @@ public:
}
virtual void generate_java_doc(std::ostream& out, t_field* field) {
if (field->get_type()->is_enum()) {
if (get_true_type(field->get_type())->is_enum()) {
std::string combined_message = field->get_doc() + "\n@see "
+ get_enum_class_name(field->get_type());
generate_java_docstring_comment(out, combined_message);

View File

@ -68,6 +68,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -1666,6 +1667,8 @@ string t_perl_generator::type_to_enum(t_type* type) {
return "Thrift::TType::I64";
case t_base_type::TYPE_DOUBLE:
return "Thrift::TType::DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "Thrift::TType::I32";
@ -1682,4 +1685,9 @@ string t_perl_generator::type_to_enum(t_type* type) {
throw "INVALID TYPE IN type_to_enum: " + type->get_name();
}
std::string t_perl_generator::display_name() const {
return "Perl";
}
THRIFT_REGISTER_GENERATOR(perl, "Perl", "")

View File

@ -99,6 +99,7 @@ public:
throw "oop and inlined are mutually exclusive.";
}
update_keywords_for_validation();
out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
escape_['$'] = "\\$";
}
@ -115,6 +116,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -128,6 +130,7 @@ public:
void generate_service(t_service* tservice) override;
std::string render_const_value(t_type* type, t_const_value* value);
std::set<std::string> lang_keywords_for_validation() const override;
/**
* Structs!
@ -418,6 +421,22 @@ private:
bool getters_setters_;
};
std::set<std::string> t_php_generator::lang_keywords_for_validation() const {
std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__",
"__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as",
"assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare",
"def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif",
"end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure",
"except", "exec", "finally", "float", "for", "foreach", "from", "function", "global",
"goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is",
"lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass",
"public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register",
"return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this",
"throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var",
"virtual", "volatile", "when", "while", "with", "xor", "yield" };
return std::set<std::string>(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) );
}
bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) {
return sub_namespace == "path";
}
@ -2798,6 +2817,8 @@ string t_php_generator::type_to_enum(t_type* type) {
return "TType::I64";
case t_base_type::TYPE_DOUBLE:
return "TType::DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "TType::I32";
@ -2839,6 +2860,8 @@ string t_php_generator::type_to_phpdoc(t_type* type) {
return "int";
case t_base_type::TYPE_DOUBLE:
return "double";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "int";
@ -2867,6 +2890,11 @@ string t_php_generator::type_to_phpdoc(t_type* type) {
throw "INVALID TYPE IN type_to_enum: " + type->get_name();
}
std::string t_php_generator::display_name() const {
return "PHP";
}
THRIFT_REGISTER_GENERATOR(
php,
"PHP",

View File

@ -52,7 +52,7 @@ public:
const std::map<std::string, std::string>& parsed_options,
const std::string& option_string)
: t_generator (program) {
update_keywords();
update_keywords_for_validation();
std::map<std::string, std::string>::const_iterator iter;
@ -157,6 +157,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -280,12 +281,12 @@ public:
}
static bool is_immutable(t_type* ttype) {
std::map<std::string, std::string>::iterator it = ttype->annotations_.find("python.immutable");
std::map<std::string, std::vector<std::string>>::iterator it = ttype->annotations_.find("python.immutable");
if (it == ttype->annotations_.end()) {
// Exceptions are immutable by default.
return ttype->is_xception();
} else if (it->second == "false") {
} else if (!it->second.empty() && it->second.back() == "false") {
return false;
} else {
return true;
@ -357,7 +358,7 @@ private:
std::string module_;
protected:
std::set<std::string> lang_keywords() const override {
std::set<std::string> lang_keywords_for_validation() const override {
std::string keywords[] = { "False", "None", "True", "and", "as", "assert", "break", "class",
"continue", "def", "del", "elif", "else", "except", "exec", "finally", "for", "from",
"global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "print",
@ -606,7 +607,7 @@ string t_py_generator::render_const_value(t_type* type, t_const_value* value) {
int64_t int_val = value->get_integer();
if (gen_enum_) {
t_enum_value* enum_val = ((t_enum*)type)->get_constant_by_value(int_val);
out << type->get_name() << "." << enum_val->get_name();
out << type_name(type) << "." << enum_val->get_name();
} else {
out << int_val;
}
@ -870,7 +871,12 @@ void t_py_generator::generate_py_struct_definition(ostream& out,
}
if (is_immutable(tstruct)) {
if (gen_newstyle_ || gen_dynamic_) {
if (gen_enum_ && type->is_enum()) {
indent(out) << "super(" << tstruct->get_name() << ", self).__setattr__('"
<< (*m_iter)->get_name() << "', " << (*m_iter)->get_name()
<< " if hasattr(" << (*m_iter)->get_name() << ", 'value') else "
<< type_name(type) << ".__members__.get(" << (*m_iter)->get_name() << "))" << endl;
} else if (gen_newstyle_ || gen_dynamic_) {
indent(out) << "super(" << tstruct->get_name() << ", self).__setattr__('"
<< (*m_iter)->get_name() << "', " << (*m_iter)->get_name() << ")" << endl;
} else {
@ -887,12 +893,42 @@ void t_py_generator::generate_py_struct_definition(ostream& out,
if (is_immutable(tstruct)) {
out << endl;
out << indent() << "def __setattr__(self, *args):" << endl
<< indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl
<< endl;
out << indent() << "def __delattr__(self, *args):" << endl
<< indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl
<< endl;
out << indent() << "def __setattr__(self, *args):" << endl;
indent_up();
// Not user-provided fields should be editable so that the Python Standard Library can edit
// internal fields of std library base classes. For example, in Python 3.11 ContextManager
// edits the `__traceback__` field on Exceptions. Allowing this to work with `__slots__` is
// trivial because we know which fields are user-provided, without slots we need to build a
// way to know which fields are user-provided.
if (gen_slots_ && !gen_dynamic_) {
out << indent() << "if args[0] not in self.__slots__:" << endl;
indent_up();
out << indent() << "super().__setattr__(*args)" << endl
<< indent() << "return" << endl;
indent_down();
}
out << indent() << "raise TypeError(\"can't modify immutable instance\")" << endl;
indent_down();
out << endl;
out << indent() << "def __delattr__(self, *args):" << endl;
indent_up();
// Not user-provided fields should be editable so that the Python Standard Library can edit
// internal fields of std library base classes. For example, in Python 3.11 ContextManager
// edits the `__traceback__` field on Exceptions. Allowing this to work with `__slots__` is
// trivial because we know which fields are user-provided, without slots we need to build a
// way to know which fields are user-provided.
if (gen_slots_ && !gen_dynamic_) {
out << indent() << "if args[0] not in self.__slots__:" << endl;
indent_up();
out << indent() << "super().__delattr__(*args)" << endl
<< indent() << "return" << endl;
indent_down();
}
out << indent() << "raise TypeError(\"can't modify immutable instance\")" << endl;
indent_down();
out << endl;
// Hash all of the members in order, and also hash in the class
// to avoid collisions for stuff like single-field structures.
@ -904,6 +940,32 @@ void t_py_generator::generate_py_struct_definition(ostream& out,
}
out << "))" << endl;
} else if (gen_enum_) {
bool has_enum = false;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
t_type* type = (*m_iter)->get_type();
if (type->is_enum()) {
has_enum = true;
break;
}
}
if (has_enum) {
out << endl;
indent(out) << "def __setattr__(self, name, value):" << endl;
indent_up();
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
t_type* type = (*m_iter)->get_type();
if (type->is_enum()) {
out << indent() << "if name == \"" << (*m_iter)->get_name() << "\":" << endl
<< indent() << indent_str() << "super().__setattr__(name, value if hasattr(value, 'value') else "
<< type_name(type) << ".__members__.get(value))" << endl
<< indent() << indent_str() << "return" << endl;
}
}
indent(out) << "super().__setattr__(name, value)" << endl << endl;
indent_down();
}
}
if (!gen_dynamic_) {
@ -2286,7 +2348,7 @@ void t_py_generator::generate_deserialize_field(ostream& out,
out << endl;
} else if (type->is_enum()) {
if (gen_enum_) {
indent(out) << name << " = " << type_name(type) << "(iprot.readI32()).name";
indent(out) << name << " = " << type_name(type) << "(iprot.readI32())";
} else {
indent(out) << name << " = iprot.readI32()";
}
@ -2476,7 +2538,7 @@ void t_py_generator::generate_serialize_field(ostream& out, t_field* tfield, str
}
} else if (type->is_enum()) {
if (gen_enum_){
out << "writeI32(" << type_name(type) << "[" << name << "].value)";
out << "writeI32(" << name << ".value)";
} else {
out << "writeI32(" << name << ")";
}
@ -2767,6 +2829,8 @@ string t_py_generator::type_to_enum(t_type* type) {
return "TType.I64";
case t_base_type::TYPE_DOUBLE:
return "TType.DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "TType.I32";
@ -2819,6 +2883,11 @@ string t_py_generator::type_to_spec_args(t_type* ttype) {
throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
}
std::string t_py_generator::display_name() const {
return "Python";
}
THRIFT_REGISTER_GENERATOR(
py,
"Python",

View File

@ -104,6 +104,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -943,7 +944,12 @@ void t_rb_generator::generate_service_client(t_service* tservice) {
f_service_.indent() << "def " << function_signature(&recv_function) << endl;
f_service_.indent_up();
// TODO(mcslee): Validate message reply here, seq ids etc.
f_service_.indent() << "fname, mtype, rseqid = receive_message_begin()" << endl;
f_service_.indent() << "handle_exception(mtype)" << endl;
f_service_.indent() << "if reply_seqid(rseqid)==false" << endl;
f_service_.indent() << " raise \"seqid reply faild\"" << endl;
f_service_.indent() << "end" << endl;
f_service_.indent() << "result = receive_message(" << resultname << ")" << endl;
@ -1171,6 +1177,8 @@ string t_rb_generator::type_to_enum(t_type* type) {
return "::Thrift::Types::I64";
case t_base_type::TYPE_DOUBLE:
return "::Thrift::Types::DOUBLE";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "::Thrift::Types::I32";
@ -1281,6 +1289,11 @@ void t_rb_generator::generate_rb_union_validator(t_rb_ofstream& out, t_struct* t
out.indent() << "end" << endl << endl;
}
std::string t_rb_generator::display_name() const {
return "Ruby";
}
THRIFT_REGISTER_GENERATOR(
rb,
"Ruby",

View File

@ -76,6 +76,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -127,7 +128,7 @@ private:
void render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue);
// Write the actual const value - the right side of a const definition.
void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true);
void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true, bool is_inline = true);
// Write a const struct (returned from `const_value` method).
void render_const_struct(t_type* ttype, t_const_value* tvalue);
@ -141,14 +142,6 @@ private:
// Write a const map (returned from `const_value` method).
void render_const_map(t_type* ttype, t_const_value* tvalue);
// Write the code to insert constant values into a rust vec or set. The
// `insert_function` is the rust function that we'll use to insert the elements.
void render_container_const_value(
const string& insert_function,
t_type* ttype,
t_const_value* tvalue
);
// Write the rust representation of a thrift struct to the generated file. Set `struct_type` to `T_ARGS`
// if rendering the struct used to pack arguments for a service call. When `struct_type` is `T_ARGS` the
// struct and its members have module visibility, and all fields are required. When `struct_type` is
@ -195,10 +188,6 @@ private:
// user-defined exception to be properly handled as Rust errors.
void render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct);
// Write the implementations for the `Default`. This trait allows you to specify only the fields you want
// and use `..Default::default()` to fill in the rest.
void render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct);
// Write the function that serializes a struct to its wire representation. If `struct_type` is `T_ARGS`
// then all fields are considered "required", if not, the default optionality is used.
void render_struct_sync_write(t_struct *tstruct, t_rs_generator::e_struct_type struct_type);
@ -541,18 +530,21 @@ void t_rs_generator::init_generator() {
void t_rs_generator::render_attributes_and_includes() {
// turn off some compiler/clippy warnings
// code may not be used
f_gen_ << "#![allow(dead_code)]" << endl;
// code always includes BTreeMap/BTreeSet/OrderedFloat
f_gen_ << "#![allow(unused_imports)]" << endl;
// code might not include imports from crates
f_gen_ << "#![allow(unused_extern_crates)]" << endl;
// constructors take *all* struct parameters, which can trigger the "too many arguments" warning
// some auto-gen'd types can be deeply nested. clippy recommends factoring them out which is hard to autogen
// some methods may start with "is_"
// FIXME: re-enable the 'vec_box' lint see: [THRIFT-5364](https://issues.apache.org/jira/browse/THRIFT-5364)
// This can happen because we automatically generate a Vec<Box<Type>> when the type is a typedef
// and it's a forward typedef. This (typedef + forward typedef) can happen in two situations:
// 1. When the type is recursive
// 2. When you define types out of order
f_gen_ << "#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box)]" << endl;
f_gen_ << "#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box, clippy::wrong_self_convention)]" << endl;
// prevent rustfmt from running against this file
// lines are too long, code is (thankfully!) not visual-indented, etc.
// can't use #[rustfmt::skip] see: https://github.com/rust-lang/rust/issues/54726
@ -684,7 +676,7 @@ void t_rs_generator::render_const_value_holder(const string& name, t_type* ttype
f_gen_ << indent() << "pub fn const_value() -> " << to_rust_type(ttype) << " {" << endl;
indent_up();
render_const_value(ttype, tvalue);
render_const_value(ttype, tvalue, true, false);
indent_down();
f_gen_ << indent() << "}" << endl;
@ -693,7 +685,11 @@ void t_rs_generator::render_const_value_holder(const string& name, t_type* ttype
f_gen_ << endl;
}
void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned) {
void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned, bool is_inline) {
if (!is_inline) {
f_gen_ << indent();
}
if (ttype->is_base_type()) {
t_base_type* tbase_type = (t_base_type*)ttype;
switch (tbase_type->get_base()) {
@ -727,9 +723,9 @@ void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bo
throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base());
}
} else if (ttype->is_typedef()) {
render_const_value(get_true_type(ttype), tvalue);
render_const_value(get_true_type(ttype), tvalue, is_owned, true);
} else if (ttype->is_enum()) {
f_gen_ << indent() << "{" << endl;
f_gen_ << "{" << endl;
indent_up();
f_gen_
<< indent()
@ -739,13 +735,11 @@ void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bo
<< ").expect(\"expecting valid const value\")"
<< endl;
indent_down();
f_gen_ << indent() << "}" << endl;
f_gen_ << indent() << "}";
} else if (ttype->is_struct() || ttype->is_xception()) {
render_const_struct(ttype, tvalue);
} else if (ttype->is_container()) {
f_gen_ << indent() << "{" << endl;
indent_up();
// all of them use vec! or from(), extra block is no longer needed
if (ttype->is_list()) {
render_const_list(ttype, tvalue);
} else if (ttype->is_set()) {
@ -755,111 +749,87 @@ void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bo
} else {
throw "cannot generate const container value for " + ttype->get_name();
}
indent_down();
f_gen_ << indent() << "}" << endl;
} else {
throw "cannot generate const value for " + ttype->get_name();
}
if (!is_inline) {
f_gen_ << endl;
}
}
void t_rs_generator::render_const_struct(t_type* ttype, t_const_value*) {
if (((t_struct*)ttype)->is_union()) {
f_gen_ << indent() << "{" << endl;
f_gen_ << "{" << endl;
indent_up();
f_gen_ << indent() << "unimplemented!()" << endl;
indent_down();
f_gen_ << indent() << "}" << endl;
f_gen_ << indent() << "}";
} else {
f_gen_ << indent() << "{" << endl;
f_gen_ << "{" << endl;
indent_up();
f_gen_ << indent() << "unimplemented!()" << endl;
indent_down();
f_gen_ << indent() << "}" << endl;
f_gen_ << indent() << "}";
}
}
void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) {
t_type* elem_type = ((t_list*)ttype)->get_elem_type();
f_gen_ << indent() << "let mut l: Vec<" << to_rust_type(elem_type) << "> = Vec::new();" << endl;
f_gen_ << "vec![" << endl;
indent_up();
const vector<t_const_value*>& elems = tvalue->get_list();
vector<t_const_value*>::const_iterator elem_iter;
for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
f_gen_ << indent();
t_const_value* elem_value = (*elem_iter);
render_container_const_value("l.push", elem_type, elem_value);
render_const_value(elem_type, elem_value);
f_gen_ << "," << endl;
}
f_gen_ << indent() << "l" << endl;
indent_down();
f_gen_ << indent() << "]";
}
void t_rs_generator::render_const_set(t_type* ttype, t_const_value* tvalue) {
t_type* elem_type = ((t_set*)ttype)->get_elem_type();
f_gen_ << indent() << "let mut s: BTreeSet<" << to_rust_type(elem_type) << "> = BTreeSet::new();" << endl;
f_gen_ << "BTreeSet::from([" << endl;
indent_up();
const vector<t_const_value*>& elems = tvalue->get_list();
vector<t_const_value*>::const_iterator elem_iter;
for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
f_gen_ << indent();
t_const_value* elem_value = (*elem_iter);
render_container_const_value("s.insert", elem_type, elem_value);
render_const_value(elem_type, elem_value);
f_gen_ << "," << endl;
}
f_gen_ << indent() << "s" << endl;
indent_down();
f_gen_ << indent() << "])";
}
void t_rs_generator::render_const_map(t_type* ttype, t_const_value* tvalue) {
t_type* key_type = ((t_map*)ttype)->get_key_type();
t_type* val_type = ((t_map*)ttype)->get_val_type();
f_gen_
<< indent()
<< "let mut m: BTreeMap<"
<< to_rust_type(key_type) << ", " << to_rust_type(val_type)
<< "> = BTreeMap::new();"
<< endl;
f_gen_ << "BTreeMap::from([" << endl;
indent_up();
const map<t_const_value*, t_const_value*, t_const_value::value_compare>& elems = tvalue->get_map();
map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator elem_iter;
for (elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
t_const_value* key_value = elem_iter->first;
t_const_value* val_value = elem_iter->second;
if (get_true_type(key_type)->is_base_type()) {
f_gen_ << indent() << "let k = ";
render_const_value(key_type, key_value);
f_gen_ << ";" << endl;
} else {
f_gen_ << indent() << "let k = {" << endl;
indent_up();
render_const_value(key_type, key_value);
indent_down();
f_gen_ << indent() << "};" << endl;
}
if (get_true_type(val_type)->is_base_type()) {
f_gen_ << indent() << "let v = ";
render_const_value(val_type, val_value);
f_gen_ << ";" << endl;
} else {
f_gen_ << indent() << "let v = {" << endl;
indent_up();
render_const_value(val_type, val_value);
indent_down();
f_gen_ << indent() << "};" << endl;
}
f_gen_ << indent() << "m.insert(k, v);" << endl;
}
f_gen_ << indent() << "m" << endl;
}
void t_rs_generator::render_container_const_value(
const string& insert_function,
t_type* ttype,
t_const_value* tvalue
) {
if (get_true_type(ttype)->is_base_type()) {
f_gen_ << indent() << insert_function << "(";
render_const_value(ttype, tvalue);
f_gen_ << ");" << endl;
} else {
f_gen_ << indent() << insert_function << "(" << endl;
f_gen_ << indent() << "(" << endl;
indent_up();
render_const_value(ttype, tvalue);
f_gen_ << indent();
render_const_value(key_type, key_value);
f_gen_ << "," << endl;
f_gen_ << indent();
render_const_value(val_type, val_value);
f_gen_ << "," << endl;
indent_down();
f_gen_ << indent() << ");" << endl;
f_gen_ << indent() << ")," << endl;
}
indent_down();
f_gen_ << indent() << "])";
}
//-----------------------------------------------------------------------------
@ -1057,9 +1027,6 @@ void t_rs_generator::render_struct(
render_type_comment(struct_name);
render_struct_definition(struct_name, tstruct, struct_type);
render_struct_impl(struct_name, tstruct, struct_type);
if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) {
render_struct_default_trait_impl(struct_name, tstruct);
}
if (struct_type == t_rs_generator::T_EXCEPTION) {
render_exception_struct_error_trait_impls(struct_name, tstruct);
}
@ -1071,15 +1038,27 @@ void t_rs_generator::render_struct_definition(
t_rs_generator::e_struct_type struct_type
) {
render_rustdoc((t_doc*) tstruct);
f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
const vector<t_field*> members = tstruct->get_sorted_members();
vector<t_field*>::const_iterator members_iter;
bool need_default = struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION;
for (members_iter = members.begin(); need_default && members_iter != members.end(); ++members_iter) {
t_field* member = *members_iter;
if (!is_optional(member->get_req())) {
need_default = false;
}
}
f_gen_
<< "#[derive(Clone, Debug"
<< (need_default ? ", Default" : "")
<< ", Eq, Hash, Ord, PartialEq, PartialOrd)]"
<< endl;
f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl;
// render the members
vector<t_field*> members = tstruct->get_sorted_members();
if (!members.empty()) {
indent_up();
vector<t_field*>::iterator members_iter;
for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
t_field* member = (*members_iter);
t_field::e_req member_req = actual_field_req(member, struct_type);
@ -1137,49 +1116,6 @@ void t_rs_generator::render_exception_struct_error_trait_impls(const string& str
f_gen_ << endl;
}
void t_rs_generator::render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct) {
bool has_required_field = false;
const vector<t_field*>& members = tstruct->get_sorted_members();
vector<t_field*>::const_iterator members_iter;
for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
t_field* member = *members_iter;
if (!is_optional(member->get_req())) {
has_required_field = true;
break;
}
}
if (has_required_field) {
return;
}
f_gen_ << "impl Default for " << struct_name << " {" << endl;
indent_up();
f_gen_ << indent() << "fn default() -> Self {" << endl;
indent_up();
if (members.empty()) {
f_gen_ << indent() << struct_name << "{}" << endl;
} else {
f_gen_ << indent() << struct_name << "{" << endl;
indent_up();
for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
t_field *member = (*members_iter);
string member_name(rust_field_name(member));
f_gen_ << indent() << member_name << ": " << opt_in_req_out_value(member->get_type()) << "," << endl;
}
indent_down();
f_gen_ << indent() << "}" << endl;
}
indent_down();
f_gen_ << indent() << "}" << endl;
indent_down();
f_gen_ << "}" << endl;
f_gen_ << endl;
}
void t_rs_generator::render_struct_impl(
const string& struct_name,
t_struct* tstruct,
@ -1616,6 +1552,8 @@ void t_rs_generator::render_type_sync_write(const string &type_var, bool type_va
case t_base_type::TYPE_DOUBLE:
f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl;
return;
default:
throw "compiler error: unhandled type";
}
} else if (ttype->is_typedef()) {
t_typedef* ttypedef = (t_typedef*) ttype;
@ -1777,6 +1715,10 @@ void t_rs_generator::render_struct_sync_read(
f_gen_ << indent() << "}" << endl;
// now read all the fields found
// avoid clippy::match_single_binding
if (members.empty()) {
f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
} else {
f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl;
f_gen_ << indent() << "match field_id {" << endl; // start match
indent_up();
@ -1800,6 +1742,8 @@ void t_rs_generator::render_struct_sync_read(
indent_down();
f_gen_ << indent() << "};" << endl; // finish match
}
f_gen_ << indent() << "i_prot.read_field_end()?;" << endl;
indent_down();
f_gen_ << indent() << "}" << endl; // finish loop
@ -1985,6 +1929,8 @@ void t_rs_generator::render_type_sync_read(const string &type_var, t_type *ttype
case t_base_type::TYPE_DOUBLE:
f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl;
return;
default:
throw "compiler error: unhandled type";
}
} else if (ttype->is_typedef()) {
// FIXME: not a fan of separate `is_boxed` parameter
@ -3084,6 +3030,8 @@ string t_rs_generator::to_rust_type(t_type* ttype) {
return "i64";
case t_base_type::TYPE_DOUBLE:
return "OrderedFloat<f64>";
default:
throw "compiler error: unhandled type";
}
} else if (ttype->is_typedef()) {
t_typedef* ttypedef = (t_typedef*)ttype;
@ -3144,6 +3092,8 @@ string t_rs_generator::to_rust_field_type_enum(t_type* ttype) {
return "TType::I64";
case t_base_type::TYPE_DOUBLE:
return "TType::Double";
default:
throw "compiler error: unhandled type";
}
} else if (ttype->is_enum()) {
return "TType::I32";
@ -3182,6 +3132,8 @@ string t_rs_generator::opt_in_req_out_value(t_type* ttype) {
return "Some(0)";
case t_base_type::TYPE_DOUBLE:
return "Some(OrderedFloat::from(0.0))";
default:
throw "compiler error: unhandled type";
}
} else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) {
@ -3415,6 +3367,11 @@ void t_rs_generator::string_replace(string& target, const string& search_string,
}
}
std::string t_rs_generator::display_name() const {
return "Rust";
}
THRIFT_REGISTER_GENERATOR(
rs,
"Rust",

View File

@ -73,6 +73,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -1037,6 +1038,8 @@ string t_st_generator::type_to_enum(t_type* type) {
return "TType i64";
case t_base_type::TYPE_DOUBLE:
return "TType double";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return "TType i32";
@ -1053,4 +1056,9 @@ string t_st_generator::type_to_enum(t_type* type) {
throw "INVALID TYPE IN type_to_enum: " + type->get_name();
}
std::string t_st_generator::display_name() const {
return "Smalltalk";
}
THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "")

View File

@ -50,7 +50,7 @@ public:
const map<string, string>& parsed_options,
const string& option_string)
: t_oop_generator(program) {
update_keywords();
update_keywords_for_validation();
(void)option_string;
map<string, string>::const_iterator iter;
@ -98,6 +98,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_consts(vector<t_const*> consts) override;
@ -291,7 +292,7 @@ private:
bool promise_kit_;
protected:
std::set<std::string> lang_keywords() const override {
std::set<std::string> lang_keywords_for_validation() const override {
return {};
}
};
@ -1067,6 +1068,7 @@ void t_swift_generator::generate_swift_union_reader(ostream& out, t_struct* tstr
switch (tbase) {
case t_base_type::TYPE_STRING:
case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
padding = " ";
break;
@ -1172,6 +1174,7 @@ void t_swift_generator::generate_swift_struct_reader(ostream& out,
switch (tbase) {
case t_base_type::TYPE_STRING:
case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
padding = " ";
break;
@ -2591,6 +2594,8 @@ string t_swift_generator::base_type_name(t_base_type* type) {
return "Int64";
case t_base_type::TYPE_DOUBLE:
return "Double";
case t_base_type::TYPE_UUID:
return "UUID";
default:
throw "compiler error: no Swift name for base type " + t_base_type::t_base_name(tbase);
}
@ -2629,6 +2634,9 @@ void t_swift_generator::render_const_value(ostream& out,
}
out << ")";
break;
case t_base_type::TYPE_UUID:
out << "UUID(uuidString: \"" << get_escaped_string(value) << "\")";
break;
default:
throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
}
@ -3136,6 +3144,10 @@ string t_swift_generator::type_to_enum(t_type* type, bool qualified) {
return result + "i64";
case t_base_type::TYPE_DOUBLE:
return result + "double";
case t_base_type::TYPE_UUID:
return result + "uuid";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return result + "i32";
@ -3168,6 +3180,10 @@ string t_swift_generator::type_to_enum(t_type* type, bool qualified) {
return result + "I64";
case t_base_type::TYPE_DOUBLE:
return result + "DOUBLE";
case t_base_type::TYPE_UUID:
return result + "UUID";
default:
throw "compiler error: unhandled type";
}
} else if (type->is_enum()) {
return result + "I32";
@ -3186,6 +3202,11 @@ string t_swift_generator::type_to_enum(t_type* type, bool qualified) {
}
std::string t_swift_generator::display_name() const {
return "Swift 3.0";
}
THRIFT_REGISTER_GENERATOR(
swift,
"Swift 3.0",

View File

@ -83,6 +83,8 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
void generate_program() override;
void iterate_program(t_program* program);
@ -94,7 +96,7 @@ public:
void generate_service(t_service* tservice) override;
void generate_struct(t_struct* tstruct) override;
void generate_annotations(std::map<std::string, std::string> annotations);
void generate_annotations(std::map<std::string, std::vector<std::string>> annotations);
private:
bool should_merge_includes_;
@ -165,17 +167,23 @@ void t_xml_generator::init_generator() {
string t_xml_generator::target_namespace(t_program* program) {
std::map<std::string, std::string> map;
std::map<std::string, std::string>::iterator iter;
map = program->get_namespace_annotations("xml");
if ((iter = map.find("targetNamespace")) != map.end()) {
return iter->second;
std::map<std::string, std::vector<std::string>> annotations;
std::map<std::string, std::vector<std::string>>::iterator annotations_iter;
annotations = program->get_namespace_annotations("xml");
if ((annotations_iter = annotations.find("targetNamespace")) != annotations.end()) {
if (!annotations_iter->second.empty()) {
return annotations_iter->second.back();
}
}
map = program->get_namespaces();
if ((iter = map.find("xml")) != map.end()) {
return default_ns_prefix + iter->second;
}
map = program->get_namespace_annotations("*");
if ((iter = map.find("xml.targetNamespace")) != map.end()) {
return iter->second;
annotations = program->get_namespace_annotations("*");
if ((annotations_iter = annotations.find("xml.targetNamespace")) != annotations.end()) {
if (!annotations_iter->second.empty()) {
return annotations_iter->second.back();
}
}
map = program->get_namespaces();
if ((iter = map.find("*")) != map.end()) {
@ -432,15 +440,17 @@ void t_xml_generator::write_doc(t_doc* tdoc) {
}
void t_xml_generator::generate_annotations(
std::map<std::string, std::string> annotations) {
std::map<std::string, std::string>::iterator iter;
std::map<std::string, std::vector<std::string>> annotations) {
std::map<std::string, std::vector<std::string>>::iterator iter;
for (iter = annotations.begin(); iter != annotations.end(); ++iter) {
for (auto& annotations_value : iter->second) {
write_element_start("annotation");
write_attribute("key", iter->first);
write_attribute("value", iter->second);
write_attribute("value", annotations_value);
write_element_end();
}
}
}
void t_xml_generator::generate_constant(t_const* con) {
write_element_start("const");
@ -684,6 +694,11 @@ string t_xml_generator::get_type_name(t_type* ttype) {
return "(unknown)";
}
std::string t_xml_generator::display_name() const {
return "XML";
}
THRIFT_REGISTER_GENERATOR(
xml,
"XML",

View File

@ -67,6 +67,7 @@ public:
void init_generator() override;
void close_generator() override;
std::string display_name() const override;
/**
* Program-level generation functions
@ -262,10 +263,10 @@ void t_xsd_generator::generate_service(t_service* tservice) {
f_xsd_.open(f_xsd_name.c_str());
string ns = program_->get_namespace("xsd");
const std::map<std::string, std::string> annot = program_->get_namespace_annotations("xsd");
const std::map<std::string, std::string>::const_iterator uri = annot.find("uri");
if (uri != annot.end()) {
ns = uri->second;
const std::map<std::string, std::vector<std::string>> annot = program_->get_namespace_annotations("xsd");
const std::map<std::string, std::vector<std::string>>::const_iterator uri = annot.find("uri");
if (uri != annot.end() && !uri->second.empty()) {
ns = uri->second.back();
}
if (ns.size() > 0) {
ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" "
@ -360,4 +361,9 @@ string t_xsd_generator::base_type_name(t_base_type::t_base tbase) {
}
}
std::string t_xsd_generator::display_name() const {
return "XSD";
}
THRIFT_REGISTER_GENERATOR(xsd, "XSD", "")

View File

@ -0,0 +1,551 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* This file is programmatically sanitized for style:
* astyle --style=1tbs -f -p -H -j -U t_validator_parser.cc
*
* The output of astyle should not be taken unquestioningly, but it is a good
* guide for ensuring uniformity and readability.
*/
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>
#include "thrift/generate/t_generator.h"
#include "thrift/generate/validator_parser.h"
#include "thrift/platform.h"
#include "thrift/version.h"
#include <algorithm>
#include <clocale>
#include <sstream>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
const char* list_delimiter = "[], ";
std::vector<validation_rule*> validation_parser::parse_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
std::vector<validation_rule*> empty_rules;
if (type->is_typedef()) {
type = type->get_true_type();
}
if (type->is_enum()) {
return parse_enum_field(type, annotations);
} else if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
switch (tbase) {
case t_base_type::TYPE_UUID:
case t_base_type::TYPE_VOID:
return empty_rules;
case t_base_type::TYPE_I8:
case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64:
return parse_integer_field(type, annotations);
case t_base_type::TYPE_DOUBLE:
return parse_double_field(type, annotations);
case t_base_type::TYPE_STRING:
return parse_string_field(type, annotations);
case t_base_type::TYPE_BOOL:
return parse_bool_field(type, annotations);
}
} else if (type->is_list()) {
return parse_list_field(type, annotations);
} else if (type->is_set()) {
return parse_set_field(type, annotations);
} else if (type->is_map()) {
return parse_map_field(type, annotations);
} else if (type->is_struct()) {
if (((t_struct*)type)->is_union()) {
return parse_union_field(type, annotations);
}
return parse_struct_field(type, annotations);
} else if (type->is_xception()) {
return parse_xception_field(type, annotations);
}
throw "validator error: unsupported type: " + type->get_name();
}
std::vector<validation_rule*> validation_parser::parse_bool_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
(void)type;
std::vector<validation_rule*> rules;
add_bool_rule(rules, "vt.const", annotations);
return rules;
}
std::vector<validation_rule*> validation_parser::parse_enum_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
std::vector<validation_rule*> rules;
add_bool_rule(rules, "vt.defined_only", annotations);
add_enum_list_rule(rules, (t_enum*)type, "vt.in", annotations);
add_enum_list_rule(rules, (t_enum*)type, "vt.not_in", annotations);
return rules;
}
std::vector<validation_rule*> validation_parser::parse_double_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
(void)type;
std::vector<validation_rule*> rules;
add_double_rule(rules, "vt.lt", annotations);
add_double_rule(rules, "vt.le", annotations);
add_double_rule(rules, "vt.gt", annotations);
add_double_rule(rules, "vt.ge", annotations);
add_double_list_rule(rules, "vt.in", annotations);
add_double_list_rule(rules, "vt.not_in", annotations);
return rules;
}
std::vector<validation_rule*> validation_parser::parse_integer_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
(void)type;
std::vector<validation_rule*> rules;
add_integer_rule(rules, "vt.lt", annotations);
add_integer_rule(rules, "vt.le", annotations);
add_integer_rule(rules, "vt.gt", annotations);
add_integer_rule(rules, "vt.ge", annotations);
add_integer_list_rule(rules, "vt.in", annotations);
add_integer_list_rule(rules, "vt.not_in", annotations);
return rules;
}
std::vector<validation_rule*> validation_parser::parse_string_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
(void)type;
std::vector<validation_rule*> rules;
add_string_rule(rules, "vt.const", annotations);
add_integer_rule(rules, "vt.min_size", annotations);
add_integer_rule(rules, "vt.max_size", annotations);
add_string_rule(rules, "vt.pattern", annotations);
add_string_rule(rules, "vt.prefix", annotations);
add_string_rule(rules, "vt.suffix", annotations);
add_string_rule(rules, "vt.contains", annotations);
add_string_rule(rules, "vt.not_contains", annotations);
return rules;
}
std::vector<validation_rule*> validation_parser::parse_set_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
(void)type;
return parse_list_field(type, annotations);
}
std::vector<validation_rule*> validation_parser::parse_list_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
(void)type;
std::vector<validation_rule*> rules;
add_integer_rule(rules, "vt.min_size", annotations);
add_integer_rule(rules, "vt.max_size", annotations);
std::string elem_prefix("vt.elem");
std::map<std::string, std::vector<std::string>> elem_annotations;
for (auto it = annotations.begin(); it != annotations.end(); it++) {
if (it->first.compare(0, elem_prefix.size(), elem_prefix) == 0) {
std::string elem_key = "vt" + it->first.substr(elem_prefix.size());
elem_annotations[elem_key] = it->second;
}
}
std::vector<validation_rule*> elem_rules;
if (type->is_list()) {
elem_rules = parse_field(((t_list*)type)->get_elem_type(), elem_annotations);
} else if (type->is_set()) {
elem_rules = parse_field(((t_set*)type)->get_elem_type(), elem_annotations);
}
for (auto it = elem_rules.begin(); it != elem_rules.end(); it++) {
validation_rule* rule = new validation_rule(elem_prefix, *it);
rules.push_back(rule);
}
return rules;
}
std::vector<validation_rule*> validation_parser::parse_map_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
std::vector<validation_rule*> rules;
add_integer_rule(rules, "vt.min_size", annotations);
add_integer_rule(rules, "vt.max_size", annotations);
std::string key_prefix("vt.key");
std::map<std::string, std::vector<std::string>> key_annotations;
for (auto it = annotations.begin(); it != annotations.end(); it++) {
if (it->first.compare(0, key_prefix.size(), key_prefix) == 0) {
std::string key_key = "vt" + it->first.substr(key_prefix.size());
key_annotations[key_key] = it->second;
}
}
std::vector<validation_rule*> key_rules;
key_rules = parse_field(((t_map*)type)->get_key_type(), key_annotations);
for (auto it = key_rules.begin(); it != key_rules.end(); it++) {
validation_rule* rule = new validation_rule(key_prefix, *it);
rules.push_back(rule);
}
std::string value_prefix("vt.value");
std::map<std::string, std::vector<std::string>> value_annotations;
for (auto it = annotations.begin(); it != annotations.end(); it++) {
if (it->first.compare(0, value_prefix.size(), value_prefix) == 0) {
std::string value_key = "vt" + it->first.substr(value_prefix.size());
value_annotations[value_key] = it->second;
}
}
std::vector<validation_rule*> value_rules;
value_rules = parse_field(((t_map*)type)->get_val_type(), value_annotations);
for (auto it = value_rules.begin(); it != value_rules.end(); it++) {
validation_rule* rule = new validation_rule(value_prefix, *it);
rules.push_back(rule);
}
return rules;
}
std::vector<validation_rule*> validation_parser::parse_struct_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
(void)type;
std::vector<validation_rule*> rules;
add_bool_rule(rules, "vt.skip", annotations);
return rules;
}
std::vector<validation_rule*> validation_parser::parse_xception_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
return parse_struct_field(type, annotations);
}
std::vector<validation_rule*> validation_parser::parse_union_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations) {
return parse_struct_field(type, annotations);
}
bool validation_parser::is_reference_field(std::string value) {
if (value[0] != '$') {
return false;
}
value.erase(value.begin());
t_field* field = this->reference->get_field_by_name(value);
return field != nullptr;
}
bool validation_parser::is_validation_function(std::string value) {
if (value[0] != '@') {
return false;
}
return true;
}
void validation_parser::add_bool_rule(
std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations) {
auto it = annotations.find(key);
if (it != annotations.end() && !it->second.empty()) {
for (auto& annotation_value : it->second) {
validation_rule* rule = new validation_rule(key);
validation_value* value;
if (is_reference_field(annotation_value)) {
t_field* field = get_referenced_field(annotation_value);
value = new validation_value(field);
} else {
bool constant;
std::istringstream(it->second.back()) >> std::boolalpha >> constant;
value = new validation_value(constant);
}
rule->append_value(value);
rules.push_back(rule);
}
}
}
void validation_parser::add_double_rule(
std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations) {
auto it = annotations.find(key);
if (it != annotations.end() && !it->second.empty()) {
for (auto& annotation_value : it->second) {
if (annotation_value.size() == 0) {
continue;
}
validation_rule* rule = new validation_rule(key);
validation_value* value;
if (is_validation_function(annotation_value)) {
validation_value::validation_function* function = get_validation_function(annotation_value);
value = new validation_value(function);
} else if (is_reference_field(annotation_value)) {
t_field* field = get_referenced_field(annotation_value);
value = new validation_value(field);
} else {
double constant = std::stod(annotation_value);
value = new validation_value(constant);
}
rule->append_value(value);
rules.push_back(rule);
}
}
}
void validation_parser::add_enum_list_rule(
std::vector<validation_rule*>& rules,
t_enum* enum_,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations) {
auto it = annotations.find(key);
if (it != annotations.end() && !it->second.empty()) {
for (auto& annotation_value : it->second) {
if (annotation_value.size() == 0) {
continue;
}
validation_rule* rule = new validation_rule(key);
if (annotation_value[0] == '[') {
validation_value* value;
char* str = strdup(annotation_value.c_str());
char* pch = strtok(str, list_delimiter);
std::string val;
while (pch != NULL) {
std::string temp(pch);
if (is_validation_function(temp)) {
validation_value::validation_function* function = get_validation_function(temp);
value = new validation_value(function);
} else if (is_reference_field(temp)) {
t_field* field = get_referenced_field(temp);
value = new validation_value(field);
} else if (std::stringstream(temp) >> val) {
std::string::size_type dot = val.rfind('.');
if (dot != std::string::npos) {
val = val.substr(dot + 1);
}
t_enum_value* enum_val = enum_->get_constant_by_name(val);
value = new validation_value(enum_val);
} else {
delete rule;
throw "validator error: validation double list parse failed: " + temp;
}
rule->append_value(value);
pch = strtok(NULL, list_delimiter);
}
} else {
validation_value* value;
std::string val = annotation_value;
std::string::size_type dot = val.rfind('.');
if (dot != std::string::npos) {
val = val.substr(dot + 1);
}
t_enum_value* enum_val = enum_->get_constant_by_name(val);
value = new validation_value(enum_val);
rule->append_value(value);
}
rules.push_back(rule);
}
}
}
void validation_parser::add_double_list_rule(
std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations) {
std::map<std::string, std::vector<std::string>> double_rules;
auto it = annotations.find(key);
if (it != annotations.end() && !it->second.empty()) {
for (auto& annotation_value : it->second) {
if (annotation_value.size() == 0) {
continue;
}
if (annotation_value[0] == '[') {
validation_rule* rule = new validation_rule(key);
validation_value* value;
char* str = strdup(annotation_value.c_str());
char* pch = strtok(str, list_delimiter);
double val;
while (pch != NULL) {
std::string temp(pch);
if (is_validation_function(temp)) {
validation_value::validation_function* function = get_validation_function(temp);
value = new validation_value(function);
} else if (is_reference_field(temp)) {
t_field* field = get_referenced_field(temp);
value = new validation_value(field);
} else if (std::stringstream(temp) >> val) {
value = new validation_value(val);
} else {
delete rule;
throw "validator error: validation double list parse failed: " + temp;
}
rule->append_value(value);
pch = strtok(NULL, list_delimiter);
}
rules.push_back(rule);
} else {
double_rules[key].push_back(annotation_value);
}
}
}
if (double_rules[key].size() > 0) {
add_double_rule(rules, key, double_rules);
}
}
void validation_parser::add_integer_rule(
std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations) {
auto it = annotations.find(key);
if (it != annotations.end() && !it->second.empty()) {
for (auto& annotation_value : it->second) {
if (annotation_value.size() == 0) {
continue;
}
validation_rule* rule = new validation_rule(key);
validation_value* value;
if (is_reference_field(annotation_value)) {
t_field* field = get_referenced_field(annotation_value);
value = new validation_value(field);
} else if (is_validation_function(annotation_value)) {
validation_value::validation_function* function = get_validation_function(annotation_value);
value = new validation_value(function);
} else {
int64_t constant = std::stoll(annotation_value);
value = new validation_value(constant);
}
rule->append_value(value);
rules.push_back(rule);
}
}
}
void validation_parser::add_integer_list_rule(
std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations) {
std::map<std::string, std::vector<std::string>> integer_rules;
auto it = annotations.find(key);
if (it != annotations.end() && !it->second.empty()) {
for (auto& annotation_value : it->second) {
if (annotation_value.size() == 0) {
continue;
}
if (annotation_value[0] == '[') {
validation_rule* rule = new validation_rule(key);
validation_value* value;
char* str = strdup(annotation_value.c_str());
char* pch = strtok(str, list_delimiter);
int64_t val;
while (pch != NULL) {
std::string temp(pch);
if (is_validation_function(temp)) {
validation_value::validation_function* function = get_validation_function(temp);
value = new validation_value(function);
} else if (is_reference_field(temp)) {
t_field* field = get_referenced_field(temp);
value = new validation_value(field);
} else if (std::stringstream(temp) >> val) {
value = new validation_value(val);
} else {
delete rule;
throw "validator error: validation integer list parse failed: " + temp;
}
rule->append_value(value);
pch = strtok(NULL, list_delimiter);
}
rules.push_back(rule);
} else {
integer_rules[key].push_back(annotation_value);
}
}
}
if (integer_rules[key].size() > 0) {
add_integer_rule(rules, key, integer_rules);
}
}
void validation_parser::add_string_rule(
std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations) {
auto it = annotations.find(key);
if (it != annotations.end() && !it->second.empty()) {
for (auto& annotation_value : it->second) {
validation_rule* rule = new validation_rule(key);
validation_value* value;
if (is_reference_field(annotation_value)) {
t_field* field = get_referenced_field(annotation_value);
value = new validation_value(field);
} else {
value = new validation_value(annotation_value);
}
rule->append_value(value);
rules.push_back(rule);
}
}
}
t_field* validation_parser::get_referenced_field(std::string annotation_value) {
annotation_value.erase(annotation_value.begin());
return reference->get_field_by_name(annotation_value);
}
validation_value::validation_function* validation_parser::get_validation_function(
std::string annotation_value) {
std::string value = annotation_value;
value.erase(value.begin());
validation_value::validation_function* function = new validation_value::validation_function;
size_t name_end = value.find_first_of('(');
if (name_end >= value.size()) {
delete function;
throw "validator error: validation function parse failed: " + annotation_value;
}
function->name = value.substr(0, name_end);
value.erase(0, name_end + 1); // name(
if (function->name == "len") {
size_t argument_end = value.find_first_of(')');
if (argument_end >= value.size()) {
delete function;
throw "validator error: validation function parse failed: " + annotation_value;
}
std::string argument = value.substr(0, argument_end);
if (argument.size() > 0 && argument[0] == '$') {
t_field* field = get_referenced_field(argument);
validation_value* value = new validation_value(field);
function->arguments.push_back(value);
} else {
delete function;
throw "validator error: validation function parse failed, unrecognized argument: "
+ annotation_value;
}
} else {
delete function;
throw "validator error: validation function parse failed, function not supported: "
+ annotation_value;
}
return function;
}

View File

@ -0,0 +1,208 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef T_VALIDATOR_GENERATOR_H
#define T_VALIDATOR_GENERATOR_H
#include "thrift/generate/t_generator.h"
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <vector>
class validation_value {
public:
struct validation_function {
public:
std::string name;
std::vector<validation_value*> arguments;
};
enum validation_value_type {
VV_INTEGER,
VV_DOUBLE,
VV_BOOL,
VV_ENUM,
VV_STRING,
VV_FUNCTION,
VV_FIELD_REFERENCE,
VV_UNKNOWN
};
validation_value() : val_type(VV_UNKNOWN) {}
validation_value(const int64_t val) : int_val(val), val_type(VV_INTEGER) {}
validation_value(const double val) : double_val(val), val_type(VV_DOUBLE) {}
validation_value(const bool val) : bool_val(val), val_type(VV_BOOL) {}
validation_value(t_enum_value* val) : enum_val(val), val_type(VV_ENUM) {}
validation_value(const std::string val) : string_val(val), val_type(VV_STRING) {}
validation_value(validation_function* val) : function_val(val), val_type(VV_FUNCTION) {}
validation_value(t_field* val) : field_reference_val(val), val_type(VV_FIELD_REFERENCE) {}
void set_int(const int64_t val) {
int_val = val;
val_type = VV_INTEGER;
}
int64_t get_int() const { return int_val; };
void set_double(const double val) {
double_val = val;
val_type = VV_DOUBLE;
}
double get_double() { return double_val; };
void set_bool(const bool val) {
bool_val = val;
val_type = VV_BOOL;
}
bool get_bool() const { return bool_val; };
void set_enum(t_enum_value* val) {
enum_val = val;
val_type = VV_ENUM;
}
t_enum_value* get_enum() const { return enum_val; };
void set_string(const std::string val) {
string_val = val;
val_type = VV_STRING;
}
std::string get_string() const { return string_val; };
void set_function(validation_function* val) {
function_val = val;
val_type = VV_FUNCTION;
}
validation_function* get_function() { return function_val; };
void set_field_reference(t_field* val) {
field_reference_val = val;
val_type = VV_FIELD_REFERENCE;
}
t_field* get_field_reference() const { return field_reference_val; };
bool is_field_reference() const { return val_type == VV_FIELD_REFERENCE; };
bool is_validation_function() const { return val_type == VV_FUNCTION; };
validation_value_type get_type() const { return val_type; };
private:
int64_t int_val = 0;
double double_val = 0.0;
bool bool_val = false;
t_enum_value* enum_val = nullptr;
std::string string_val;
validation_function* function_val = nullptr;
t_field* field_reference_val = nullptr;
validation_value_type val_type;
};
class validation_rule {
public:
validation_rule(){};
validation_rule(std::string name) : name(name){};
validation_rule(std::string name, validation_rule* inner) : name(name), inner(inner){};
std::string get_name() { return name; };
void append_value(validation_value* value) { values.push_back(value); }
const std::vector<validation_value*>& get_values() { return values; };
validation_rule* get_inner() { return inner; };
private:
std::string name;
std::vector<validation_value*> values;
validation_rule* inner = nullptr;
};
class validation_parser {
public:
validation_parser() {}
validation_parser(t_struct* reference) : reference(reference) {}
std::vector<validation_rule*> parse_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
void set_reference(t_struct* reference) { this->reference = reference; };
private:
std::vector<validation_rule*> parse_bool_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_enum_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_double_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_integer_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_string_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_set_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_list_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_map_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_struct_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_xception_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
std::vector<validation_rule*> parse_union_field(
t_type* type,
std::map<std::string, std::vector<std::string>>& annotations);
bool is_reference_field(std::string value);
bool is_validation_function(std::string value);
void add_bool_rule(std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations);
void add_double_rule(std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations);
void add_double_list_rule(std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations);
void add_integer_rule(std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations);
void add_integer_list_rule(std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations);
void add_string_rule(std::vector<validation_rule*>& rules,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations);
void add_enum_list_rule(std::vector<validation_rule*>& rules,
t_enum* enum_,
std::string key,
std::map<std::string, std::vector<std::string>>& annotations);
t_field* get_referenced_field(std::string annotation_value);
validation_value::validation_function* get_validation_function(std::string annotation_value);
t_struct* reference = nullptr;
};
#endif

View File

@ -738,6 +738,12 @@ void validate_const_rec(std::string name, t_type* type, t_const_value* value) {
throw "type error: const \"" + name + "\" was declared as string";
}
break;
case t_base_type::TYPE_UUID:
if (value->get_type() != t_const_value::CV_STRING) {
throw "type error: const \"" + name + "\" was declared as uuid";
}
value->set_uuid(value->get_uuid()); // validates constant
break;
case t_base_type::TYPE_BOOL:
if (value->get_type() != t_const_value::CV_INTEGER) {
throw "type error: const \"" + name + "\" was declared as bool";

View File

@ -36,6 +36,7 @@ public:
enum t_base {
TYPE_VOID,
TYPE_STRING,
TYPE_UUID,
TYPE_BOOL,
TYPE_I8,
TYPE_I16,
@ -55,6 +56,8 @@ public:
bool is_bool() const override { return base_ == TYPE_BOOL; }
bool is_uuid() const override { return base_ == TYPE_UUID; }
void set_binary(bool val) { binary_ = val; }
bool is_binary() const override { return binary_ && (base_ == TYPE_STRING); }
@ -69,6 +72,9 @@ public:
case TYPE_STRING:
return "string";
break;
case TYPE_UUID:
return "uuid";
break;
case TYPE_BOOL:
return "bool";
break;

View File

@ -85,6 +85,18 @@ public:
}
}
void set_uuid(std::string val) {
validate_uuid(val);
valType_ = CV_STRING;
stringVal_ = val;
}
std::string get_uuid() const {
std::string tmp = stringVal_;
validate_uuid(tmp);
return tmp;
}
void set_double(double val) {
valType_ = CV_DOUBLE;
doubleVal_ = val;
@ -199,6 +211,39 @@ private:
t_enum* enum_;
t_const_value_type valType_;
void validate_uuid(std::string & uuid) const {
const std::string HEXCHARS = std::string("0123456789ABCDEFabcdef");
// we also allow for usual "Windows GUID" format "{01234567-9012-4567-9012-456789012345}"
if ((uuid.length() == 38) && ('{' == uuid[0]) && ('}' == uuid[37])) {
uuid = uuid.substr(1, 36);
}
// canonical format "01234567-9012-4567-9012-456789012345" expected
bool valid = (uuid.length() == 36);
for (size_t i = 0; valid && (i < uuid.length()); ++i) {
switch(i) {
case 8:
case 13:
case 18:
case 23:
if(uuid[i] != '-') {
valid = false;
}
break;
default:
if(HEXCHARS.find(uuid[i]) == std::string::npos) {
valid = false;
}
break;
}
}
if( ! valid) {
throw "invalid uuid " + uuid;
}
}
};
#endif

View File

@ -20,9 +20,9 @@
#ifndef T_ENUM_VALUE_H
#define T_ENUM_VALUE_H
#include "thrift/parse/t_doc.h"
#include <map>
#include <string>
#include "thrift/parse/t_doc.h"
/**
* A constant. These are used inside of enum definitions. Constants are just
@ -40,7 +40,7 @@ public:
int get_value() const { return value_; }
std::map<std::string, std::string> annotations_;
std::map<std::string, std::vector<std::string>> annotations_;
private:
std::string name_;

View File

@ -21,8 +21,8 @@
#define T_FIELD_H
#include <map>
#include <string>
#include <sstream>
#include <string>
#include "thrift/parse/t_doc.h"
#include "thrift/parse/t_type.h"
@ -106,7 +106,7 @@ public:
}
};
std::map<std::string, std::string> annotations_;
std::map<std::string, std::vector<std::string>> annotations_;
bool get_reference() const { return reference_; }

View File

@ -20,10 +20,10 @@
#ifndef T_FUNCTION_H
#define T_FUNCTION_H
#include <string>
#include "thrift/parse/t_type.h"
#include "thrift/parse/t_struct.h"
#include "thrift/parse/t_doc.h"
#include "thrift/parse/t_struct.h"
#include "thrift/parse/t_type.h"
#include <string>
/**
* Representation of a function. Key parts are return type, function name,
@ -40,6 +40,7 @@ public:
xceptions_(new t_struct(nullptr)),
own_xceptions_(true),
oneway_(oneway) {
xceptions_->set_method_xcepts(true);
if (oneway_ && (!returntype_->is_void())) {
pwarning(1, "Oneway methods should return void.\n");
}
@ -56,6 +57,7 @@ public:
xceptions_(xceptions),
own_xceptions_(false),
oneway_(oneway) {
xceptions_->set_method_xcepts(true);
if (oneway_ && !xceptions_->get_members().empty()) {
throw std::string("Oneway methods can't throw exceptions.");
}
@ -79,7 +81,7 @@ public:
bool is_oneway() const { return oneway_; }
std::map<std::string, std::string> annotations_;
std::map<std::string, std::vector<std::string>> annotations_;
private:
t_type* returntype_;

View File

@ -331,20 +331,20 @@ public:
return namespaces_;
}
void set_namespace_annotations(std::string language, std::map<std::string, std::string> annotations) {
void set_namespace_annotations(std::string language, std::map<std::string, std::vector<std::string>> annotations) {
namespace_annotations_[language] = annotations;
}
const std::map<std::string, std::string>& get_namespace_annotations(const std::string& language) const {
const std::map<std::string, std::vector<std::string>>& get_namespace_annotations(const std::string& language) const {
auto it = namespace_annotations_.find(language);
if (namespace_annotations_.end() != it) {
return it->second;
}
static const std::map<std::string, std::string> emptyMap;
static const std::map<std::string, std::vector<std::string>> emptyMap;
return emptyMap;
}
std::map<std::string, std::string>& get_namespace_annotations(const std::string& language) {
std::map<std::string, std::vector<std::string>>& get_namespace_annotations(const std::string& language) {
return namespace_annotations_[language];
}
@ -400,7 +400,7 @@ private:
std::map<std::string, std::string> namespaces_;
// Annotations for dynamic namespaces
std::map<std::string, std::map<std::string, std::string> > namespace_annotations_;
std::map<std::string, std::map<std::string, std::vector<std::string>>> namespace_annotations_;
// C++ extra includes
std::vector<std::string> cpp_includes_;

View File

@ -166,6 +166,9 @@ public:
case t_base_type::TYPE_STRING:
const_val->set_string(constant->get_value()->get_string());
break;
case t_base_type::TYPE_UUID:
const_val->set_uuid(constant->get_value()->get_uuid());
break;
case t_base_type::TYPE_DOUBLE:
const_val->set_double(constant->get_value()->get_double());
break;

View File

@ -44,64 +44,40 @@ public:
: t_type(program),
is_xception_(false),
is_union_(false),
members_validated(false),
members_with_value(0),
is_method_xcepts_(false),
union_validated_(false),
xcepts_validated_(false),
members_with_value_(0),
xsd_all_(false) {}
t_struct(t_program* program, const std::string& name)
: t_type(program, name),
is_xception_(false),
is_union_(false),
members_validated(false),
members_with_value(0),
is_method_xcepts_(false),
union_validated_(false),
xcepts_validated_(false),
members_with_value_(0),
xsd_all_(false) {}
void set_name(const std::string& name) override {
name_ = name;
validate_union_members();
union_validated_= false;
validate_members();
}
void set_xception(bool is_xception) { is_xception_ = is_xception; }
void validate_union_member(t_field* field) {
if (is_union_ && (!name_.empty())) {
// 1) unions can't have required fields
// 2) union members are implicitly optional, otherwise bugs like THRIFT-3650 wait to happen
if (field->get_req() != t_field::T_OPTIONAL) {
// no warning on default requiredness, but do warn on anything else that is explicitly asked for
if(field->get_req() != t_field::T_OPT_IN_REQ_OUT) {
pwarning(1,
"Union %s field %s: union members must be optional, ignoring specified requiredness.\n",
name_.c_str(),
field->get_name().c_str());
}
field->set_req(t_field::T_OPTIONAL);
}
// unions may have up to one member defaulted, but not more
if (field->get_value() != nullptr) {
if (1 < ++members_with_value) {
throw "Error: Field " + field->get_name() + " provides another default value for union "
+ name_;
}
}
}
}
void validate_union_members() {
if (is_union_ && (!name_.empty()) && (!members_validated)) {
members_type::const_iterator m_iter;
for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
validate_union_member(*m_iter);
}
members_validated = true;
}
void set_method_xcepts(bool is_method_xcepts) {
is_method_xcepts_ = is_method_xcepts;
xcepts_validated_ = false;
validate_members();
}
void set_union(bool is_union) {
is_union_ = is_union;
validate_union_members();
union_validated_= false;
validate_members();
}
void set_xsd_all(bool xsd_all) { xsd_all_ = xsd_all; }
@ -123,7 +99,11 @@ public:
}
members_.push_back(elem);
members_in_id_order_.insert(bounds.second, elem);
validate_union_member(elem);
if (needs_validation()) {
validate_members();
} else {
validate_member_field(elem);
}
return true;
}
@ -154,12 +134,80 @@ public:
private:
members_type members_;
members_type members_in_id_order_;
bool is_xception_;
bool is_union_;
bool members_validated;
int members_with_value;
bool is_xception_; // struct is an IDL exception
bool is_union_; // struct is an IDL union
bool is_method_xcepts_; // struct holds the exceptions declared at a service method
bool union_validated_;
bool xcepts_validated_;
int members_with_value_;
bool xsd_all_;
void validate_member_field(t_field* field) {
validate_union_member(field);
validate_method_exception_field(field);
}
void validate_union_member(t_field* field) {
if (is_union_ && (!name_.empty())) {
union_validated_ = true;
// 1) unions can't have required fields
// 2) union members are implicitly optional, otherwise bugs like THRIFT-3650 wait to happen
if (field->get_req() != t_field::T_OPTIONAL) {
// no warning on default requiredness, but do warn on anything else that is explicitly asked for
if(field->get_req() != t_field::T_OPT_IN_REQ_OUT) {
pwarning(1,
"Union %s field %s: union members must be optional, ignoring specified requiredness.\n",
name_.c_str(),
field->get_name().c_str());
}
field->set_req(t_field::T_OPTIONAL);
}
// unions may have up to one member defaulted, but not more
if (field->get_value() != nullptr) {
if (1 < ++members_with_value_) {
throw "Error: Field " + field->get_name() + " provides another default value for union "
+ name_;
}
}
}
}
void validate_method_exception_field(t_field* field) {
if (is_method_xcepts_) {
xcepts_validated_ = true;
// THRIFT-5669: "required" makes no sense at "throws" clauses
if (field->get_req() == t_field::T_REQUIRED) {
field->set_req(t_field::T_OPT_IN_REQ_OUT);
pwarning(1,
"Exception field %s: \"required\" is illegal here, ignoring.\n",
field->get_name().c_str());
}
}
}
bool needs_validation() {
if (is_method_xcepts_) {
return !xcepts_validated_;
}
if (is_union_) {
return !union_validated_;
}
return false;
}
void validate_members() {
if (needs_validation()) {
members_type::const_iterator m_iter;
for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) {
validate_member_field(*m_iter);
}
}
}
};
#endif

View File

@ -20,11 +20,11 @@
#ifndef T_TYPE_H
#define T_TYPE_H
#include <string>
#include <map>
#include <cstring>
#include <stdint.h>
#include "thrift/parse/t_doc.h"
#include <cstring>
#include <map>
#include <stdint.h>
#include <string>
class t_program;
@ -47,6 +47,7 @@ public:
virtual bool is_void() const { return false; }
virtual bool is_base_type() const { return false; }
virtual bool is_string() const { return false; }
virtual bool is_uuid() const { return false; }
virtual bool is_binary() const { return false; }
virtual bool is_bool() const { return false; }
virtual bool is_typedef() const { return false; }
@ -82,7 +83,7 @@ public:
return rv;
}
std::map<std::string, std::string> annotations_;
std::map<std::string, std::vector<std::string>> annotations_;
protected:
t_type() : program_(nullptr) { ; }

View File

@ -76,17 +76,17 @@
#include "thrift/thrifty.hh"
#endif
void integer_overflow(char* text) {
void integer_overflow(const char* text) {
yyerror("This integer is too big: \"%s\"\n", text);
exit(1);
}
void unexpected_token(char* text) {
void unexpected_token(const char* text) {
yyerror("Unexpected token in input: \"%s\"\n", text);
exit(1);
}
void error_no_longer_supported(char* text, char* replace_with) {
void error_no_longer_supported(const char* text, const char* replace_with) {
yyerror("\"%s\" is no longer supported, use \"%s\" instead. Line %d\n", text, replace_with, yylineno);
exit(1);
}
@ -209,29 +209,16 @@ literal_begin (['\"])
"true" { yylval.iconst=1; return tok_int_constant; }
"namespace" { return tok_namespace; }
"cpp_namespace" { error_unsupported_namespace_decl("cpp"); /* do nothing */ }
"cpp_include" { return tok_cpp_include; }
"cpp_type" { return tok_cpp_type; }
"java_package" { error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ }
"delphi_namespace" { error_unsupported_namespace_decl("delphi"); /* do nothing */ }
"php_namespace" { error_unsupported_namespace_decl("php"); /* do nothing */ }
"py_module" { error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ }
"perl_package" { error_unsupported_namespace_decl("perl_package", "perl"); /* do nothing */ }
"ruby_namespace" { error_unsupported_namespace_decl("ruby"); /* do nothing */ }
"smalltalk_category" { error_unsupported_namespace_decl("smalltalk_category", "st"); /* do nothing */ }
"smalltalk_prefix" { error_unsupported_namespace_decl("smalltalk_prefix", "st"); /* do nothing */ }
"xsd_all" { return tok_xsd_all; }
"xsd_optional" { return tok_xsd_optional; }
"xsd_nillable" { return tok_xsd_nillable; }
"xsd_namespace" { error_unsupported_namespace_decl("xsd"); /* do nothing */ }
"xsd_attrs" { return tok_xsd_attrs; }
"include" { return tok_include; }
"void" { return tok_void; }
"bool" { return tok_bool; }
"byte" {
emit_byte_type_warning();
return tok_i8;
}
"byte" { emit_byte_type_warning(); return tok_byte; }
"i8" { return tok_i8; }
"i16" { return tok_i16; }
"i32" { return tok_i32; }
@ -239,12 +226,7 @@ literal_begin (['\"])
"double" { return tok_double; }
"string" { return tok_string; }
"binary" { return tok_binary; }
"slist" {
error_no_longer_supported("slist","string");
}
"senum" {
error_no_longer_supported("senum","string");
}
"uuid" { return tok_uuid; }
"map" { return tok_map; }
"list" { return tok_list; }
"set" { return tok_set; }
@ -262,7 +244,7 @@ literal_begin (['\"])
"optional" { return tok_optional; }
"async" {
pwarning(0, "\"async\" is deprecated. It is called \"oneway\" now.\n");
return tok_oneway;
return tok_async;
}
"&" { return tok_reference; }

View File

@ -97,6 +97,7 @@ const int struct_is_union = 1;
t_function* tfunction;
t_field* tfield;
char* dtext;
char* keyword;
t_field::e_req ereq;
t_annotation* tannot;
t_field_id tfieldid;
@ -118,55 +119,58 @@ const int struct_is_union = 1;
/**
* Header keywords
*/
%token tok_include
%token tok_namespace
%token tok_cpp_include
%token tok_cpp_type
%token tok_xsd_all
%token tok_xsd_optional
%token tok_xsd_nillable
%token tok_xsd_attrs
%token<keyword> tok_include
%token<keyword> tok_namespace
%token<keyword> tok_cpp_include
%token<keyword> tok_cpp_type
%token<keyword> tok_xsd_all
%token<keyword> tok_xsd_optional
%token<keyword> tok_xsd_nillable
%token<keyword> tok_xsd_attrs
/**
* Base datatype keywords
*/
%token tok_void
%token tok_bool
%token tok_string
%token tok_binary
%token tok_i8
%token tok_i16
%token tok_i32
%token tok_i64
%token tok_double
%token<keyword> tok_void
%token<keyword> tok_bool
%token<keyword> tok_string
%token<keyword> tok_binary
%token<keyword> tok_uuid
%token<keyword> tok_byte
%token<keyword> tok_i8
%token<keyword> tok_i16
%token<keyword> tok_i32
%token<keyword> tok_i64
%token<keyword> tok_double
/**
* Complex type keywords
*/
%token tok_map
%token tok_list
%token tok_set
%token<keyword> tok_map
%token<keyword> tok_list
%token<keyword> tok_set
/**
* Function modifiers
*/
%token tok_oneway
%token<keyword> tok_oneway
%token<keyword> tok_async
/**
* Thrift language keywords
*/
%token tok_typedef
%token tok_struct
%token tok_xception
%token tok_throws
%token tok_extends
%token tok_service
%token tok_enum
%token tok_const
%token tok_required
%token tok_optional
%token tok_union
%token tok_reference
%token<keyword> tok_typedef
%token<keyword> tok_struct
%token<keyword> tok_xception
%token<keyword> tok_throws
%token<keyword> tok_extends
%token<keyword> tok_service
%token<keyword> tok_enum
%token<keyword> tok_const
%token<keyword> tok_required
%token<keyword> tok_optional
%token<keyword> tok_union
%token<keyword> tok_reference
/**
* Grammar nodes
@ -192,6 +196,7 @@ const int struct_is_union = 1;
%type<tfield> Field
%type<tfieldid> FieldIdentifier
%type<id> FieldName
%type<ereq> FieldRequiredness
%type<ttype> FieldType
%type<tconstv> FieldValue
@ -770,6 +775,10 @@ Oneway:
{
$$ = true;
}
| tok_async // deprecated
{
$$ = true;
}
|
{
$$ = false;
@ -808,9 +817,9 @@ FieldList:
}
Field:
CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference FieldName FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
{
pdebug("tok_int_constant : Field -> FieldType tok_identifier");
pdebug("tok_int_constant : Field -> FieldType FieldName");
if ($2.auto_assigned) {
pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6);
if (g_strict >= 192) {
@ -841,6 +850,171 @@ Field:
}
}
FieldName: // identifiers and everything that could be one if it would not be identified as a different token already and excluding the "xsd*" keywords to follow a FieldName
tok_identifier
{
pdebug("FieldName -> tok_identifier");
$$ = $1;
}
| tok_namespace
{
pdebug("FieldName -> tok_namespace");
$$ = strdup("namespace");
}
| tok_cpp_include
{
pdebug("FieldName -> tok_cpp_include");
$$ = strdup("cpp_include");
}
/* see THRIFT-5627 "More consistent syntax for cpp_type" -> activate when this issue is resolved
| tok_cpp_type
{
pdebug("FieldName -> tok_cpp_type");
$$ = $strdup("cpp_type");
}
*/
| tok_include
{
pdebug("FieldName -> tok_include");
$$ = strdup("include");
}
| tok_void
{
pdebug("FieldName -> tok_void");
$$ = strdup("void");
}
| tok_bool
{
pdebug("FieldName -> tok_bool");
$$ = strdup("bool");
}
| tok_byte
{
pdebug("FieldName -> tok_byte");
$$ = strdup("byte");
}
| tok_i8
{
pdebug("FieldName -> tok_i8");
$$ = strdup("i8");
}
| tok_i16
{
pdebug("FieldName -> tok_i16");
$$ = strdup("i16");
}
| tok_i32
{
pdebug("FieldName -> tok_i32");
$$ = strdup("i32");
}
| tok_i64
{
pdebug("FieldName -> tok_i64");
$$ = strdup("i64");
}
| tok_double
{
pdebug("FieldName -> tok_double");
$$ = strdup("double");
}
| tok_string
{
pdebug("FieldName -> tok_string");
$$ = strdup("string");
}
| tok_binary
{
pdebug("FieldName -> tok_binary");
$$ = strdup("binary");
}
| tok_uuid
{
pdebug("FieldName -> tok_uuid");
$$ = strdup("uuid");
}
| tok_map
{
pdebug("FieldName -> tok_map");
$$ = strdup("map");
}
| tok_list
{
pdebug("FieldName -> tok_list");
$$ = strdup("list");
}
| tok_set
{
pdebug("FieldName -> tok_set");
$$ = strdup("set");
}
| tok_oneway
{
pdebug("FieldName -> tok_oneway");
$$ = strdup("oneway");
}
| tok_async
{
pdebug("FieldName -> tok_async");
$$ = strdup("async");
}
| tok_typedef
{
pdebug("FieldName -> tok_typedef");
$$ = strdup("typedef");
}
| tok_struct
{
pdebug("FieldName -> tok_struct");
$$ = strdup("struct");
}
| tok_union
{
pdebug("FieldName -> tok_union");
$$ = strdup("union");
}
| tok_xception
{
pdebug("FieldName -> tok_xception");
$$ = strdup("exception");
}
| tok_extends
{
pdebug("FieldName -> tok_extends");
$$ = strdup("extends");
}
| tok_throws
{
pdebug("FieldName -> tok_throws");
$$ = strdup("throws");
}
| tok_service
{
pdebug("FieldName -> tok_service");
$$ = strdup("service");
}
| tok_enum
{
pdebug("FieldName -> tok_enum");
$$ = strdup("enum");
}
| tok_const
{
pdebug("FieldName -> tok_const");
$$ = strdup("const");
}
| tok_required
{
pdebug("FieldName -> tok_required");
$$ = strdup("required");
}
| tok_optional
{
pdebug("FieldName -> tok_optional");
$$ = strdup("optional");
}
FieldIdentifier:
tok_int_constant ':'
{
@ -1002,11 +1176,21 @@ SimpleBaseType:
pdebug("BaseType -> tok_binary");
$$ = g_type_binary;
}
| tok_uuid
{
pdebug("BaseType -> tok_uuid");
$$ = g_type_uuid;
}
| tok_bool
{
pdebug("BaseType -> tok_bool");
$$ = g_type_bool;
}
| tok_byte
{
pdebug("BaseType -> tok_byte");
$$ = g_type_i8; // byte is signed in Thrift, just an alias for i8
}
| tok_i8
{
pdebug("BaseType -> tok_i8");
@ -1081,13 +1265,20 @@ SetType:
}
ListType:
tok_list '<' FieldType '>' CppType
tok_list CppType '<' FieldType '>' CppType // the second CppType is for compatibility reasons = deprecated
{
pdebug("ListType -> tok_list<FieldType>");
check_for_list_of_bytes($3);
$$ = new t_list($3);
if ($5 != nullptr) {
((t_container*)$$)->set_cpp_name(std::string($5));
check_for_list_of_bytes($4);
$$ = new t_list($4);
if ($2 != nullptr) {
((t_container*)$$)->set_cpp_name(std::string($2));
}
if ($6 != nullptr) {
((t_container*)$$)->set_cpp_name(std::string($6));
pwarning(1, "The syntax 'list<type> cpp_type \"c++ type\"' is deprecated. Use 'list cpp_type \"c++ type\" <type>' instead.\n");
}
if (($2 != nullptr) && ($6 != nullptr)) {
pwarning(1, "Two cpp_types clauses at list<%>\n", $2);
}
}
@ -1117,7 +1308,7 @@ TypeAnnotationList:
{
pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
$$ = $1;
$$->annotations_[$2->key] = $2->val;
$$->annotations_[$2->key].push_back($2->val);
delete $2;
}
|

View File

@ -24,6 +24,6 @@
#pragma once
#endif // _MSC_VER
#define THRIFT_VERSION "0.17.0"
#define THRIFT_VERSION "0.19.0"
#endif // _THRIFT_VERSION_H_

View File

@ -18,8 +18,8 @@
#
file(GLOB KEYWORD_SAMPLES "${CMAKE_CURRENT_SOURCE_DIR}/keyword-samples/*.thrift")
set(KEYWORD_LANGS ${thrift_compiler_LANGS})
LIST(REMOVE_ITEM KEYWORD_LANGS swift) # in Swift you can escape reserved words
set(KEYWORD_LANGS php) # the whole ticket THRIFT-4655 is only about PHP so leave other languages alone
LIST(REMOVE_ITEM KEYWORD_LANGS swift) # in Swift you can escape reserved words (and in other languages as well)
foreach(LANG ${KEYWORD_LANGS})
foreach(SAMPLE ${KEYWORD_SAMPLES})
get_filename_component(FILENAME ${SAMPLE} NAME_WE)

View File

@ -1,3 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* /*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const string foo = "bar"
struct a_struct {

View File

@ -1,3 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
include "Included.thrift"
const string s = "string"

View File

@ -1 +1,20 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const string foo = "bar"

View File

@ -1 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_007
const bool return = 0

View File

@ -1,2 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_008
enum return {
}

View File

@ -1,3 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_009
enum enum_name {
return
}

View File

@ -1 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_010
exception return {}

View File

@ -1,3 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_011
exception exception_name {
1: required i8 return
}

View File

@ -1 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_012
service return {}

View File

@ -1,3 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_013
service service_name {
bool function_name(1: i32 return)
}

View File

@ -1,3 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_014
service service_name {
void return()
}

View File

@ -1,3 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_001
exception exception_name {}
service service_name {

View File

@ -1 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_002
struct return {}

View File

@ -1,3 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_003
struct struct_name {
1: required bool return = 1
}

View File

@ -1 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace * keyword_test_004
typedef bool return

Some files were not shown because too many files have changed in this diff Show More