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. --> <!-- 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"? - [ ] 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 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"? - [ ] 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: env:
BUILD_DEPS: automake bison flex git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config 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: jobs:
# TODO windows and macos # TODO windows and macos
compiler: compiler:
strategy: strategy:
matrix: matrix:
os: [ubuntu-18.04, ubuntu-20.04] os: [ubuntu-20.04, ubuntu-22.04]
fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -49,18 +78,78 @@ jobs:
path: compiler/cpp/thrift path: compiler/cpp/thrift
retention-days: 3 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: lib-java-kotlin:
needs: compiler needs: compiler
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
env: env:
GRADLE_VERSION: 7.4.2 GRADLE_VERSION: "8.0.2"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-java@v3 - uses: actions/setup-java@v3
with: with:
distribution: temurin distribution: temurin
java-version: 11 java-version: 17
cache: "gradle" cache: "gradle"
- name: Install dependencies - name: Install dependencies
@ -72,7 +161,7 @@ jobs:
- name: Setup gradle - name: Setup gradle
run: | run: |
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip 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 unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip
sudo mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle sudo mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle
sudo ln -s /usr/local/gradle/bin/gradle /usr/local/bin sudo ln -s /usr/local/gradle/bin/gradle /usr/local/bin
@ -93,31 +182,7 @@ jobs:
- name: Run configure - name: Run configure
run: | run: |
./configure \ ./configure $(echo $CONFIG_ARGS_FOR_LIBS | sed 's/without-java/with-java/' | sed 's/without-kotlin/with-kotlin/')
--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
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v3
with: with:
@ -181,22 +246,198 @@ jobs:
lib/kotlin/cross-test-server/build/install/TestServer/ lib/kotlin/cross-test-server/build/install/TestServer/
retention-days: 3 retention-days: 3
cross-test: lib-swift:
needs: needs: compiler
- lib-java-kotlin
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - 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: with:
python-version: "3.x" python-version: "3.x"
- uses: actions/setup-java@v3 - uses: actions/setup-java@v3
with: with:
distribution: temurin 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 java-version: 8
cache: "gradle" 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 - name: Download java precross artifacts
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
with: with:
@ -209,23 +450,43 @@ jobs:
name: kotlin-precross name: kotlin-precross
path: lib/kotlin 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 - name: Set back executable flags
run: | run: |
chmod a+x \ chmod a+x \
lib/java/build/run* \ lib/java/build/run* \
lib/kotlin/cross-test-client/build/install/TestClient/bin/* \ 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 - name: Run cross test
env: env:
THRIFT_CROSSTEST_CONCURRENCY: 4 THRIFT_CROSSTEST_CONCURRENCY: 4
PRECROSS_LANGS: java,kotlin
run: | run: |
python test/test.py \ python test/test.py \
--retry-count 5 \ --retry-count 5 \
--skip-known-failures \ --skip-known-failures \
--server $PRECROSS_LANGS \ --server ${{ matrix.server_lang }} \
--client $PRECROSS_LANGS --client ${{ matrix.client_lang }}
- name: Upload log files from failed cross test runs - name: Upload log files from failed cross test runs
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@ -234,3 +495,4 @@ jobs:
name: cross-test-log name: cross-test-log
path: test/log/ path: test/log/
retention-days: 3 retention-days: 3

View File

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

22
.gitignore vendored
View File

@ -49,6 +49,7 @@ test-driver
erl_crash.dump erl_crash.dump
project.lock.json project.lock.json
.Dockerfile.sha512
.sonar .sonar
.DS_Store .DS_Store
.svn .svn
@ -201,9 +202,9 @@ project.lock.json
/lib/delphi/*.local /lib/delphi/*.local
/lib/delphi/*.identcache /lib/delphi/*.identcache
/lib/delphi/test/skip/bin /lib/delphi/test/skip/bin
/lib/delphi/test/serializer/*.dat /lib/delphi/test/serializer/**/*.dat
/lib/delphi/test/serializer/bin /lib/delphi/test/serializer/bin
/lib/delphi/test/thrift-testing /lib/delphi/test/thrift-testing/*.thrift
/lib/delphi/**/*.identcache /lib/delphi/**/*.identcache
/lib/delphi/**/*.local /lib/delphi/**/*.local
/lib/delphi/**/*.dcu /lib/delphi/**/*.dcu
@ -224,6 +225,9 @@ project.lock.json
/lib/haxe/test/data.tmp /lib/haxe/test/data.tmp
/lib/hs/dist /lib/hs/dist
/lib/java/.gradle /lib/java/.gradle
/lib/java/gradle/wrapper
/lib/java/gradlew
/lib/java/gradlew.bat
/lib/java/android/.gradle /lib/java/android/.gradle
/lib/java/build /lib/java/build
/lib/java/out /lib/java/out
@ -285,7 +289,7 @@ project.lock.json
/lib/go/src /lib/go/src
/lib/go/test/fuzz/gopathfuzz /lib/go/test/fuzz/gopathfuzz
/lib/go/test/gopath/ /lib/go/test/gopath/
/lib/go/test/ThriftTest.thrift /lib/go/test/ThriftTest*.thrift
/lib/nodets/test-compiled/ /lib/nodets/test-compiled/
/lib/ocaml/_build/ /lib/ocaml/_build/
/lib/ocaml/_tags /lib/ocaml/_tags
@ -355,7 +359,7 @@ project.lock.json
/test/erl/_build/ /test/erl/_build/
/test/erl/rebar.lock /test/erl/rebar.lock
/test/go/bin/ /test/go/bin/
/test/go/ThriftTest.thrift /test/go/ThriftTest*.thrift
/test/go/gopath /test/go/gopath
/test/go/pkg/ /test/go/pkg/
/test/go/src/code.google.com/ /test/go/src/code.google.com/
@ -388,6 +392,7 @@ project.lock.json
/test/rs/target/ /test/rs/target/
/test/rs/*.iml /test/rs/*.iml
/test/rs/**/*.iml /test/rs/**/*.iml
/test/swift/CrossTests/.build
/lib/cl/backport-update.zip /lib/cl/backport-update.zip
/lib/cl/lib /lib/cl/lib
/tutorial/cl/quicklisp.lisp /tutorial/cl/quicklisp.lisp
@ -441,3 +446,12 @@ project.lock.json
/tutorial/netstd/Server/Properties/launchSettings.json /tutorial/netstd/Server/Properties/launchSettings.json
/tutorial/netstd/Client/Properties/launchSettings.json /tutorial/netstd/Client/Properties/launchSettings.json
/ylwrap /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. # 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 # Docker Integration
@ -26,7 +26,7 @@
sudo: required sudo: required
# https://docs.travis-ci.com/user/reference/linux # https://docs.travis-ci.com/user/reference/linux
dist: xenial dist: focal
language: cpp language: cpp
services: services:
@ -61,13 +61,18 @@ jobs:
- stage: docker - stage: docker
script: true script: true
env: env:
- JOB="Docker Build ubuntu-xenial 16.04 LTS" - JOB="Docker Build ubuntu-bionic 18.04 LTS"
- DISTRO=ubuntu-xenial - DISTRO=ubuntu-bionic
- TRAVIS_BUILD_STAGE=docker - TRAVIS_BUILD_STAGE=docker
- script: true - script: true
env: env:
- JOB="Docker Build ubuntu-bionic 18.04 LTS" - JOB="Docker Build ubuntu-focal 20.04 LTS"
- DISTRO=ubuntu-bionic - 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 - TRAVIS_BUILD_STAGE=docker
# ========================= stage: thrift ======================= # ========================= stage: thrift =======================
@ -112,15 +117,24 @@ jobs:
# ------------------------- phase: autotools -------------------- # ------------------------- phase: autotools --------------------
# TODO: Remove them once migrated to CMake # 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 - script: build/docker/run.sh
env: env:
- JOB="Autotools (Ubuntu Bionic)" - JOB="Autotools (Ubuntu Focal)"
- DISTRO=ubuntu-focal
- SCRIPT="autotools.sh" - SCRIPT="autotools.sh"
- script: build/docker/run.sh - script: build/docker/run.sh
env: env:
- JOB="Autotools (Ubuntu Xenial)" - JOB="Autotools (Ubuntu Bionic)"
- DISTRO=ubuntu-xenial - DISTRO=ubuntu-bionic
- SCRIPT="autotools.sh" - SCRIPT="autotools.sh"
# ------------------------- phase: cmake ------------------------ # ------------------------- phase: cmake ------------------------

View File

@ -19,14 +19,14 @@
the "Thrift" project. the "Thrift" project.
2. nuget setApiKey <your-api-key> 2. nuget setApiKey <your-api-key>
3. nuget pack ApacheThrift.nuspec -Symbols -SymbolPackageFormat snupkg 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"> <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata> <metadata>
<id>ApacheThrift</id> <id>ApacheThrift</id>
<version>0.17.0</version> <version>0.19.0</version>
<title>Apache Thrift 0.17.0</title> <title>Apache Thrift 0.19.0</title>
<authors>Apache Thrift Developers</authors> <authors>Apache Thrift Developers</authors>
<owners>Apache Software Foundation</owners> <owners>Apache Software Foundation</owners>
<license type="expression">Apache-2.0</license> <license type="expression">Apache-2.0</license>
@ -36,7 +36,7 @@
<description> <description>
Contains runtime libraries from lib/netstd for netstandard2.0 framework development. Contains runtime libraries from lib/netstd for netstandard2.0 framework development.
</description> </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> <tags>Apache Thrift RPC</tags>
</metadata> </metadata>
<files> <files>

View File

@ -1,5 +1,184 @@
# Apache Thrift Changelog # 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 ## 0.17.0
### Known Open Issues (Blocker or Critical) ### Known Open Issues (Blocker or Critical)

View File

@ -28,7 +28,7 @@ endif()
# PACKAGE_VERSION is used by cpack scripts currently # PACKAGE_VERSION is used by cpack scripts currently
# Both thrift_VERSION and PACKAGE_VERSION should be the same for now # 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}) set(PACKAGE_VERSION ${thrift_VERSION})
project("thrift" VERSION ${PACKAGE_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> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/c_glib/README.md">C (glib)</a></td> <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> <!-- 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> <!-- Language Levels -------><td>2.48.2</td><td>2.56.4</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/cpp/README.md">C++</a></td> <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> <!-- 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> <!-- Language Levels -------><td colspan=2>C++11</td>
<!-- Field types -----------><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/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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/cl/README.md">Common LISP</a></td> <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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/d/README.md">Dlang</a></td> <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> <!-- 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> <!-- Language Levels -------><td>2.087.0</td><td>2.087.0</td>
<!-- Field types -----------><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/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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/dart/README.md">Dart</a></td> <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> <!-- 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> <!-- Language Levels -------><td>2.0.0</td><td>2.4.0</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/delphi/README.md">Delphi</a></td> <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> <!-- 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> <!-- 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> <!-- Language Levels -------><td>2010</td><td>Alexandria 11.2</td>
<!-- Field types -----------><td><img src="doc/images/cgrn.png" alt="Yes"/><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/netstd/README.md">.NET Standard</a></td> <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> <!-- 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> <!-- 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> <!-- Language Levels -------><td colspan=2>.NET Standard 2.x, .NET 6</td>
<!-- Field types -----------><td><img src="doc/images/cgrn.png" alt="Yes"/><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/erl/README.md">Erlang</a></td> <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> <!-- 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> <!-- Language Levels -------><td>18.3</td><td>22.0</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/go/README.md">Go</a></td> <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> <!-- 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> <!-- 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> <!-- Language Levels -------><td>1.20</td><td>1.21</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/haxe/README.md">Haxe</a></td> <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> <!-- 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> <!-- 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> <!-- Language Levels -------><td>4.1.5</td><td>4.2.5</td>
<!-- Field types -----------><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/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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/java/README.md">Java (SE)</a></td> <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> <!-- 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>1.8.0_151</td><td>11.0.3</td> <!-- Language Levels -------><td>11</td><td>19</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/javame/README.md">Java (ME)</a></td> <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> <!-- 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> <!-- Language Levels -------><td colspan=2>unknown</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/js/README.md">Javascript</a></td> <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> <!-- 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> <!-- Language Levels -------><td>ES5</td><td>ES6</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/lua/README.md">Lua</a></td> <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> <!-- 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> <!-- Language Levels -------><td>5.1.5</td><td>5.2.4</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/nodejs/README.md">node.js</a></td> <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> <!-- 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> <!-- Language Levels -------><td>10.x</td><td>10.x</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/nodets/README.md">node.ts</a></td> <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> <!-- 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> <!-- Language Levels -------><td>3.1.6</td><td></td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/ocaml/README.md">OCaml</a></td> <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> <!-- 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> <!-- Language Levels -------><td colspan=2>4.04.0</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/perl/README.md">Perl</a></td> <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> <!-- 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> <!-- Language Levels -------><td>5.22.1</td><td>5.26.1</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/php/README.md">PHP</a></td> <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> <!-- 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> <!-- Language Levels -------><td>7.0.22</td><td>7.2.19</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/py/README.md">Python</a></td> <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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/rb/README.md">Ruby</a></td> <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> <!-- 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> <!-- Language Levels -------><td>2.3.1p112</td><td>2.5.1p57</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/rs/README.md">Rust</a></td> <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> <!-- 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> <!-- 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> <!-- Language Levels -------><td>1.61.0</td><td>1.xx.x</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/st/README.md">Smalltalk</a></td> <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> <!-- 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> <!-- Language Levels -------><td colspan=2>unknown</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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>
<tr align=center> <tr align=center>
<td align=left><a href="https://github.com/apache/thrift/blob/master/lib/swift/README.md">Swift</a></td> <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> <!-- 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 colspan=2>4.2.1</td> <!-- Language Levels -------><td colspan=2>5.7</td>
<!-- Field types -----------><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> <!-- 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> <!-- 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> <!-- 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> <!-- 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> <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> </tr>
</tbody> </tbody>

View File

@ -78,7 +78,7 @@ empty :=
space := $(empty) $(empty) space := $(empty) $(empty)
comma := , 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)) CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS))
if WITH_PY3 if WITH_PY3
@ -157,7 +157,6 @@ EXTRA_DIST = \
doc \ doc \
dub.json \ dub.json \
go.mod \ go.mod \
go.sum \
jitpack.yml \ jitpack.yml \
LANGUAGES.md \ LANGUAGES.md \
LICENSE \ LICENSE \

View File

@ -35,8 +35,8 @@ Status
| Branch | Travis | Appveyor | Coverity Scan | codecov.io | Website | | 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/) | | [`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.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) | | | | | | [`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 Releases
======== ========

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'Thrift' 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.summary = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC."
s.description = <<-DESC 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. 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.author = { 'Apache Thrift Developers' => 'dev@thrift.apache.org' }
s.ios.deployment_target = '9.0' s.ios.deployment_target = '9.0'
s.osx.deployment_target = '10.10' 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' s.source_files = 'lib/swift/Sources/*.swift'
end end

View File

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

View File

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

View File

@ -40,5 +40,6 @@ if (NOT CYGWIN)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ThriftConfig.cmake" install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ThriftConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/ThriftConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/ThriftConfigVersion.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/FindLibevent.cmake"
DESTINATION "${CMAKE_INSTALL_DIR}/thrift") DESTINATION "${CMAKE_INSTALL_DIR}/thrift")
endif() 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_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(THRIFT_CMAKE_DIR "@PACKAGE_CMAKE_INSTALL_DIR@") set_and_check(THRIFT_CMAKE_DIR "@PACKAGE_CMAKE_INSTALL_DIR@")
set_and_check(THRIFT_BIN_DIR "@PACKAGE_BIN_INSTALL_DIR@") set_and_check(THRIFT_BIN_DIR "@PACKAGE_BIN_INSTALL_DIR@")
set(THRIFT_COMPILER "${THRIFT_BIN_DIR}/thrift@CMAKE_EXECUTABLE_SUFFIX@") if(NOT DEFINED THRIFT_COMPILER)
set(THRIFT_COMPILER "${THRIFT_BIN_DIR}/thrift@CMAKE_EXECUTABLE_SUFFIX@")
endif()
if (NOT TARGET thrift::thrift) if (NOT TARGET thrift::thrift)
include("${THRIFT_CMAKE_DIR}/thriftTargets.cmake") include("${THRIFT_CMAKE_DIR}/thriftTargets.cmake")
@ -57,7 +59,19 @@ if(@OPENSSL_FOUND@ AND @WITH_OPENSSL@)
endif() endif()
if(@Libevent_FOUND@ AND @WITH_LIBEVENT@) 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) 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() endif()
check_required_components(Thrift) check_required_components(Thrift)

View File

@ -52,9 +52,9 @@ coverage.
### Ubuntu ### ### Ubuntu ###
* bionic (stable, current) * focal (stable, current)
* artful (previous stable) * bionic (previous stable)
* xenial (legacy) * jammy (next stable, WIP)
## Unsupported Containers ## ## Unsupported Containers ##
@ -172,17 +172,18 @@ Last updated: October 1, 2017
| C++ gcc | 5.4.0 | 7.4.0 | | | C++ gcc | 5.4.0 | 7.4.0 | |
| C++ clang | 3.8 | 6.0 | | | C++ clang | 3.8 | 6.0 | |
| C# (mono) | 4.2.1.0 | 4.6.2.7 | | | 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 | | | d | 2.087.0 | 2.087.0 | |
| dart | 2.0.0 | 2.4.0 | | | dart | 2.0.0 | 2.4.0 | |
| delphi | | | Not in CI | | delphi | | | Not in CI |
| erlang | OTP-18 | OTP-23 | | | erlang | OTP-18 | OTP-23 | |
| go | 1.15.10 | 1.16.2 | | | go | 1.15.10 | 1.16.2 | |
| haxe | 3.2.1 | 3.4.4 | THRIFT-4352: avoid 3.4.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 | | | 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 | | 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 | | | nodejs | 6.16.0 | 10.16.0 | |
| ocaml | | 4.05.0 | THRIFT-4517: ocaml 4.02.3 on xenial appears broken | | ocaml | | 4.05.0 | THRIFT-4517: ocaml 4.02.3 on xenial appears broken |
| perl | 5.22.1 | 5.26.1 | | | perl | 5.22.1 | 5.26.1 | |
@ -190,6 +191,6 @@ Last updated: October 1, 2017
| python | 2.7.12 | 2.7.15 | | | python | 2.7.12 | 2.7.15 | |
| python3 | 3.5.2 | 3.6.8 | | | python3 | 3.5.2 | 3.6.8 | |
| ruby | 2.3.1p112 | 2.5.1p57 | | | 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 | | smalltalk | | | Not in CI |
| swift | | 5.1.4 | | | 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: # project isn't ready for this quite yet:
# RUN apt-get install -y --no-install-recommends \ # RUN apt-get install -y --no-install-recommends \
# `# dotnet core dependencies` \ # `# dotnet core dependencies` \
# dotnet-sdk-6.0 \ # dotnet-sdk-7.0 \
# dotnet-runtime-6.0 \ # dotnet-runtime-7.0 \
# aspnetcore-runtime-6.0 \ # aspnetcore-runtime-7.0 \
# dotnet-apphost-pack-6.0 # dotnet-apphost-pack-7.0
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Erlang dependencies` \ `# Erlang dependencies` \

View File

@ -85,6 +85,17 @@ RUN apt-get install -y --no-install-recommends \
qtbase5-dev \ qtbase5-dev \
qtbase5-dev-tools 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 D_VERSION 2.080.0
ENV DMD_DEB dmd_2.080.0-0_amd64.deb ENV DMD_DEB dmd_2.080.0-0_amd64.deb
RUN \ RUN \
@ -109,10 +120,10 @@ ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \ `# dotnet core dependencies` \
dotnet-sdk-6.0 \ dotnet-sdk-7.0 \
dotnet-runtime-6.0 \ dotnet-runtime-7.0 \
aspnetcore-runtime-6.0 \ aspnetcore-runtime-7.0 \
dotnet-apphost-pack-6.0 dotnet-apphost-pack-7.0
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Erlang dependencies` \ `# Erlang dependencies` \

View File

@ -53,7 +53,7 @@ RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add
### install general dependencies ### install general dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
`# General dependencies` \ `# General dependencies` \
bash-completion \ bash-completion \
bison \ bison \
build-essential \ build-essential \
@ -81,7 +81,7 @@ RUN mkdir -p /usr/local/adobe/flex/4.6 && \
ENV FLEX_HOME /usr/local/adobe/flex/4.6 ENV FLEX_HOME /usr/local/adobe/flex/4.6
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# C++ dependencies` \ `# C++ dependencies` \
libboost-all-dev \ libboost-all-dev \
libevent-dev \ libevent-dev \
libssl-dev \ libssl-dev \
@ -89,10 +89,22 @@ RUN apt-get install -y --no-install-recommends \
qtbase5-dev \ qtbase5-dev \
qtbase5-dev-tools 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 D_VERSION 2.087.0
ENV DMD_DEB dmd_2.087.0-0_amd64.deb ENV DMD_DEB dmd_2.087.0-0_amd64.deb
RUN \ RUN \
`# D dependencies` \ `# D dependencies` \
wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \ wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
dpkg --install ${DMD_DEB} && \ dpkg --install ${DMD_DEB} && \
rm -f ${DMD_DEB} && \ rm -f ${DMD_DEB} && \
@ -108,26 +120,26 @@ RUN \
ENV DART_VERSION 2.7.2-1 ENV DART_VERSION 2.7.2-1
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Dart dependencies` \ `# Dart dependencies` \
dart=$DART_VERSION dart=$DART_VERSION
ENV PATH /usr/lib/dart/bin:$PATH ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \ `# dotnet core dependencies` \
dotnet-sdk-6.0 \ dotnet-sdk-7.0 \
dotnet-runtime-6.0 \ dotnet-runtime-7.0 \
aspnetcore-runtime-6.0 \ aspnetcore-runtime-7.0 \
dotnet-apphost-pack-6.0 dotnet-apphost-pack-7.0
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Erlang dependencies` \ `# Erlang dependencies` \
erlang && \ erlang && \
wget https://s3.amazonaws.com/rebar3/rebar3 -O /usr/bin/rebar3 && \ wget https://s3.amazonaws.com/rebar3/rebar3 -O /usr/bin/rebar3 && \
chmod 755 /usr/bin/rebar3 && \ chmod 755 /usr/bin/rebar3 && \
rebar3 --version rebar3 --version
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# GlibC dependencies` \ `# GlibC dependencies` \
libglib2.0-dev libglib2.0-dev
# golang # golang
@ -141,29 +153,29 @@ RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
rm golang.tar.gz rm golang.tar.gz
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Haxe dependencies` \ `# Haxe dependencies` \
haxe \ haxe \
neko \ neko \
neko-dev && \ neko-dev && \
haxelib setup --always /usr/share/haxe/lib && \ haxelib setup --always /usr/share/haxe/lib && \
haxelib install --always hxcpp 2>&1 > /dev/null 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 \ RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \ `# Java dependencies` \
ant \ ant \
ant-optional \ ant-optional \
maven \ maven \
openjdk-11-jdk-headless && \ openjdk-11-jdk-headless && \
`# Gradle` \ `# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \ 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 && \ unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \ mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin ln -s /usr/local/gradle/bin/gradle /usr/local/bin
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Lua dependencies` \ `# Lua dependencies` \
lua5.2 \ lua5.2 \
lua5.2-dev lua5.2-dev
# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
@ -171,12 +183,12 @@ RUN apt-get install -y --no-install-recommends \
# need to update our luasocket code, lua doesn't have luaL_openlib any more # need to update our luasocket code, lua doesn't have luaL_openlib any more
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Node.js dependencies` \ `# Node.js dependencies` \
nodejs nodejs
# Test dependencies for running puppeteer # Test dependencies for running puppeteer
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# JS dependencies` \ `# JS dependencies` \
libxss1 \ libxss1 \
libxtst6 libxtst6
@ -189,7 +201,7 @@ RUN apt-get install -y --no-install-recommends \
# opam install --yes oasis # opam install --yes oasis
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Perl dependencies` \ `# Perl dependencies` \
libbit-vector-perl \ libbit-vector-perl \
libclass-accessor-class-perl \ libclass-accessor-class-perl \
libcrypt-ssleay-perl \ libcrypt-ssleay-perl \
@ -198,7 +210,7 @@ RUN apt-get install -y --no-install-recommends \
libtest-exception-perl libtest-exception-perl
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Php dependencies` \ `# Php dependencies` \
php \ php \
php-cli \ php-cli \
php-dev \ php-dev \
@ -208,7 +220,7 @@ RUN apt-get install -y --no-install-recommends \
composer composer
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Python dependencies` \ `# Python dependencies` \
python-all \ python-all \
python-all-dbg \ python-all-dbg \
python-all-dev \ python-all-dev \
@ -223,7 +235,7 @@ RUN apt-get install -y --no-install-recommends \
pip install --upgrade backports.ssl_match_hostname pip install --upgrade backports.ssl_match_hostname
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Python3 dependencies` \ `# Python3 dependencies` \
python3-all \ python3-all \
python3-all-dbg \ python3-all-dbg \
python3-all-dev \ python3-all-dev \
@ -236,13 +248,13 @@ RUN apt-get install -y --no-install-recommends \
python3-zope.interface python3-zope.interface
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Ruby dependencies` \ `# Ruby dependencies` \
ruby \ ruby \
ruby-dev \ ruby-dev \
ruby-bundler ruby-bundler
# Rust dependencies # 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 ENV PATH /root/.cargo/bin:$PATH
# Swift on Linux for cross tests # Swift on Linux for cross tests
@ -255,7 +267,7 @@ ENV PATH /root/.cargo/bin:$PATH
# Locale(s) for cpp unit tests # Locale(s) for cpp unit tests
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Locale dependencies` \ `# Locale dependencies` \
locales && \ locales && \
locale-gen en_US.UTF-8 && \ locale-gen en_US.UTF-8 && \
locale-gen de_DE.UTF-8 && \ locale-gen de_DE.UTF-8 && \

View File

@ -37,26 +37,26 @@ RUN apt-get update && \
software-properties-common \ software-properties-common \
wget && \ wget && \
# Dart # Dart
curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ 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 > \ curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
/etc/apt/sources.list.d/dart_stable.list && \ /etc/apt/sources.list.d/dart_stable.list && \
# dotnet (core) # dotnet (core)
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > \ echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > \
/etc/apt/sources.list.d/dotnetdev.list && \ /etc/apt/sources.list.d/dotnetdev.list && \
# node.js # node.js
curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \ curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
echo "deb https://deb.nodesource.com/node_10.x xenial main" | tee /etc/apt/sources.list.d/nodesource.list && \ echo "deb https://deb.nodesource.com/node_10.x xenial main" | tee /etc/apt/sources.list.d/nodesource.list && \
# ruby 2.4 # ruby 2.4
apt-add-repository ppa:brightbox/ruby-ng apt-add-repository ppa:brightbox/ruby-ng
### install general dependencies ### install general dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
`# General dependencies` \ `# General dependencies` \
bash-completion \ bash-completion \
bison \ bison \
build-essential \ build-essential \
@ -77,7 +77,7 @@ ENV PATH /usr/lib/llvm-3.8/bin:$PATH
# TODO: "apt-get install" without "apt-get update" in the same "RUN" step can cause cache issues if modified later. # 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 # See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# C++ dependencies` \ `# C++ dependencies` \
libboost-dev \ libboost-dev \
libboost-filesystem-dev \ libboost-filesystem-dev \
libboost-program-options-dev \ libboost-program-options-dev \
@ -93,7 +93,7 @@ RUN apt-get install -y --no-install-recommends \
ENV D_VERSION 2.087.0 ENV D_VERSION 2.087.0
ENV DMD_DEB dmd_2.087.0-0_amd64.deb ENV DMD_DEB dmd_2.087.0-0_amd64.deb
RUN \ RUN \
`# D dependencies` \ `# D dependencies` \
wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \ wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
dpkg --install ${DMD_DEB} && \ dpkg --install ${DMD_DEB} && \
rm -f ${DMD_DEB} && \ rm -f ${DMD_DEB} && \
@ -109,16 +109,16 @@ RUN \
ENV DART_VERSION 2.7.2-1 ENV DART_VERSION 2.7.2-1
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Dart dependencies` \ `# Dart dependencies` \
dart=$DART_VERSION dart=$DART_VERSION
ENV PATH /usr/lib/dart/bin:$PATH ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \ `# dotnet core dependencies` \
dotnet-sdk-6.0 \ dotnet-sdk-7.0 \
dotnet-runtime-6.0 \ dotnet-runtime-7.0 \
aspnetcore-runtime-6.0 \ aspnetcore-runtime-7.0 \
dotnet-apphost-pack-6.0 dotnet-apphost-pack-7.0
# Erlang dependencies # Erlang dependencies
ARG ERLANG_OTP_VERSION=18.3.4.11 ARG ERLANG_OTP_VERSION=18.3.4.11
@ -132,7 +132,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends automake libncu
ENV PATH /usr/local/lib/otp/bin:$PATH ENV PATH /usr/local/lib/otp/bin:$PATH
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# GlibC dependencies` \ `# GlibC dependencies` \
libglib2.0-dev libglib2.0-dev
# golang # golang
@ -146,7 +146,7 @@ RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
rm golang.tar.gz rm golang.tar.gz
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Haxe dependencies` \ `# Haxe dependencies` \
haxe \ haxe \
neko \ neko \
neko-dev \ neko-dev \
@ -155,17 +155,17 @@ RUN apt-get install -y --no-install-recommends \
haxelib install --always hxcpp 3.4.64 2>&1 > /dev/null 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 # 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 \ RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \ `# Java dependencies` \
ant \ ant \
ant-optional \ ant-optional \
openjdk-8-jdk \ openjdk-8-jdk \
maven \ maven \
unzip && \ unzip && \
`# Gradle` \ `# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \ 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 && \ unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \ mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin ln -s /usr/local/gradle/bin/gradle /usr/local/bin
@ -179,12 +179,12 @@ RUN apt-get install -y --no-install-recommends \
# lua5.3 does not install alternatives so stick with 5.2 here # lua5.3 does not install alternatives so stick with 5.2 here
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Node.js dependencies` \ `# Node.js dependencies` \
nodejs nodejs
# Test dependencies for running puppeteer # Test dependencies for running puppeteer
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# JS dependencies` \ `# JS dependencies` \
libxss1 \ libxss1 \
libxtst6 \ libxtst6 \
libatk-bridge2.0-0 \ libatk-bridge2.0-0 \
@ -199,7 +199,7 @@ RUN apt-get install -y --no-install-recommends \
# opam install --yes oasis # opam install --yes oasis
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Perl dependencies` \ `# Perl dependencies` \
libbit-vector-perl \ libbit-vector-perl \
libclass-accessor-class-perl \ libclass-accessor-class-perl \
libcrypt-ssleay-perl \ libcrypt-ssleay-perl \
@ -208,7 +208,7 @@ RUN apt-get install -y --no-install-recommends \
libtest-exception-perl libtest-exception-perl
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Php dependencies` \ `# Php dependencies` \
php7.0 \ php7.0 \
php7.0-cli \ php7.0-cli \
php7.0-dev \ php7.0-dev \
@ -218,7 +218,7 @@ RUN apt-get install -y --no-install-recommends \
composer composer
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Python dependencies` \ `# Python dependencies` \
python-all \ python-all \
python-all-dbg \ python-all-dbg \
python-all-dev \ python-all-dev \
@ -243,17 +243,17 @@ RUN apt-get install -y --no-install-recommends \
pip install --upgrade backports.ssl_match_hostname pip install --upgrade backports.ssl_match_hostname
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Ruby dependencies` \ `# Ruby dependencies` \
ruby2.4 \ ruby2.4 \
ruby2.4-dev \ ruby2.4-dev \
ruby-bundler ruby-bundler
# Rust dependencies # 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 # Locale(s) for cpp unit tests
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Locale dependencies` \ `# Locale dependencies` \
locales && \ locales && \
locale-gen en_US.UTF-8 && \ locale-gen en_US.UTF-8 && \
locale-gen de_DE.UTF-8 && \ locale-gen de_DE.UTF-8 && \

View File

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

View File

@ -16,12 +16,12 @@
# #
FROM buildpack-deps:bionic-scm FROM buildpack-deps:bionic-scm
MAINTAINER Apache Thrift <dev@thrift.apache.org> LABEL MAINTAINER='Apache Thrift <dev@thrift.apache.org>'
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive
### Add apt repos ### Add apt repos
RUN apt-get update && \ RUN apt-get update -yq && \
apt-get dist-upgrade -y && \ apt-get dist-upgrade -y && \
apt-get install -y --no-install-recommends --fix-missing \ apt-get install -y --no-install-recommends --fix-missing \
apt \ apt \
@ -49,7 +49,7 @@ RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add
### install general dependencies ### install general dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
`# General dependencies` \ `# General dependencies` \
bash-completion \ bash-completion \
bison \ bison \
build-essential \ build-essential \
@ -79,7 +79,7 @@ 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. # 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 # See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# C++ dependencies` \ `# C++ dependencies` \
libboost-all-dev \ libboost-all-dev \
libevent-dev \ libevent-dev \
libssl-dev \ libssl-dev \
@ -87,10 +87,22 @@ RUN apt-get install -y --no-install-recommends \
qtbase5-dev \ qtbase5-dev \
qtbase5-dev-tools 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 D_VERSION 2.087.0
ENV DMD_DEB dmd_2.087.0-0_amd64.deb ENV DMD_DEB dmd_2.087.0-0_amd64.deb
RUN \ RUN \
`# D dependencies` \ `# D dependencies` \
wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \ wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
dpkg --install ${DMD_DEB} && \ dpkg --install ${DMD_DEB} && \
rm -f ${DMD_DEB} && \ rm -f ${DMD_DEB} && \
@ -106,16 +118,16 @@ RUN \
ENV DART_VERSION 2.7.2-1 ENV DART_VERSION 2.7.2-1
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Dart dependencies` \ `# Dart dependencies` \
dart=$DART_VERSION dart=$DART_VERSION
ENV PATH /usr/lib/dart/bin:$PATH ENV PATH /usr/lib/dart/bin:$PATH
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# dotnet core dependencies` \ `# dotnet core dependencies` \
dotnet-sdk-6.0 \ dotnet-sdk-7.0 \
dotnet-runtime-6.0 \ dotnet-runtime-7.0 \
aspnetcore-runtime-6.0 \ aspnetcore-runtime-7.0 \
dotnet-apphost-pack-6.0 dotnet-apphost-pack-7.0
# Erlang dependencies # Erlang dependencies
ARG ERLANG_OTP_VERSION=23.3.4.11 ARG ERLANG_OTP_VERSION=23.3.4.11
@ -128,13 +140,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends libncurses5-dev
ENV PATH /usr/local/lib/otp/bin:$PATH ENV PATH /usr/local/lib/otp/bin:$PATH
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# GlibC dependencies` \ `# GlibC dependencies` \
libglib2.0-dev libglib2.0-dev
# golang # 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_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 && \ RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \ echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && \
tar -C /usr/local -xzf golang.tar.gz && \ tar -C /usr/local -xzf golang.tar.gz && \
@ -142,29 +154,29 @@ RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
rm golang.tar.gz rm golang.tar.gz
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Haxe dependencies` \ `# Haxe dependencies` \
haxe \ haxe \
neko \ neko \
neko-dev && \ neko-dev && \
haxelib setup --always /usr/share/haxe/lib && \ haxelib setup --always /usr/share/haxe/lib && \
haxelib install --always hxcpp 2>&1 > /dev/null 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 \ RUN apt-get install -y --no-install-recommends \
`# Java dependencies` \ `# Java dependencies` \
ant \ ant \
ant-optional \ ant-optional \
maven \ maven \
openjdk-11-jdk-headless && \ openjdk-17-jdk-headless && \
`# Gradle` \ `# Gradle` \
wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \ 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 && \ unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \ mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
ln -s /usr/local/gradle/bin/gradle /usr/local/bin ln -s /usr/local/gradle/bin/gradle /usr/local/bin
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Lua dependencies` \ `# Lua dependencies` \
lua5.2 \ lua5.2 \
lua5.2-dev lua5.2-dev
# https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212 # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
@ -172,24 +184,24 @@ RUN apt-get install -y --no-install-recommends \
# need to update our luasocket code, lua doesn't have luaL_openlib any more # need to update our luasocket code, lua doesn't have luaL_openlib any more
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Node.js dependencies` \ `# Node.js dependencies` \
nodejs nodejs
# Test dependencies for running puppeteer # Test dependencies for running puppeteer
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# JS dependencies` \ `# JS dependencies` \
libxss1 \ libxss1 \
libxtst6 libxtst6
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# OCaml dependencies` \ `# OCaml dependencies` \
ocaml \ ocaml \
opam && \ opam && \
opam init --yes && \ opam init --yes && \
opam install --yes oasis opam install --yes oasis
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Perl dependencies` \ `# Perl dependencies` \
libbit-vector-perl \ libbit-vector-perl \
libclass-accessor-class-perl \ libclass-accessor-class-perl \
libcrypt-ssleay-perl \ libcrypt-ssleay-perl \
@ -198,7 +210,7 @@ RUN apt-get install -y --no-install-recommends \
libtest-exception-perl libtest-exception-perl
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Php dependencies` \ `# Php dependencies` \
php \ php \
php-cli \ php-cli \
php-dev \ php-dev \
@ -208,7 +220,7 @@ RUN apt-get install -y --no-install-recommends \
composer composer
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Python dependencies` \ `# Python dependencies` \
python-all \ python-all \
python-all-dbg \ python-all-dbg \
python-all-dev \ python-all-dev \
@ -223,7 +235,7 @@ RUN apt-get install -y --no-install-recommends \
pip install --upgrade backports.ssl_match_hostname pip install --upgrade backports.ssl_match_hostname
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Python3 dependencies` \ `# Python3 dependencies` \
python3-all \ python3-all \
python3-all-dbg \ python3-all-dbg \
python3-all-dev \ python3-all-dev \
@ -236,39 +248,43 @@ RUN apt-get install -y --no-install-recommends \
python3-zope.interface python3-zope.interface
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Ruby dependencies` \ `# Ruby dependencies` \
ruby \ ruby \
ruby-dev \ ruby-dev \
ruby-bundler ruby-bundler
# Rust dependencies # 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 ENV PATH /root/.cargo/bin:$PATH
# Swift on Linux for cross tests # Swift on Linux for cross tests
RUN cd / && \ RUN apt-get install -yq \
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 && \ libedit-dev \
tar xf swift-5.1.4-RELEASE-ubuntu18.04.tar.gz --strip-components=1 && \ libz3-dev \
rm swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \ libpython-dev \
swift --version 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 # Locale(s) for cpp unit tests
RUN apt-get install -y --no-install-recommends \ RUN apt-get install -y --no-install-recommends \
`# Locale dependencies` \ `# Locale dependencies` \
locales && \ locales && \
locale-gen en_US.UTF-8 && \ locale-gen en_US.UTF-8 && \
locale-gen de_DE.UTF-8 && \ locale-gen de_DE.UTF-8 && \
update-locale 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 \ RUN apt-get install -y --no-install-recommends \
`# Static Code Analysis dependencies` \ `# Static Code Analysis dependencies` \
cppcheck \ cppcheck \
sloccount && \ sloccount && \
pip install flake8 && \ 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
# NOTE: this does not reduce the image size but adds an additional layer. # NOTE: this does not reduce the image size but adds an additional layer.
# # Clean up # # 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 # Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file # or more contributor license agreements. See the NOTICE file

View File

@ -46,6 +46,8 @@ add_library(parse STATIC ${parse_SOURCES})
set(compiler_core set(compiler_core
src/thrift/common.cc src/thrift/common.cc
src/thrift/generate/t_generator.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/t_typedef.cc
src/thrift/parse/parse.cc src/thrift/parse/parse.cc
src/thrift/version.h src/thrift/version.h
@ -71,8 +73,21 @@ macro(THRIFT_ADD_COMPILER name description initial)
endif() endif()
endmacro() 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 # The following compiler can be enabled or disabled
THRIFT_ADD_COMPILER(c_glib "Enable compiler for C with Glib" ON) 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(cpp "Enable compiler for C++" ON)
THRIFT_ADD_COMPILER(d "Enable compiler for D" ON) THRIFT_ADD_COMPILER(d "Enable compiler for D" ON)
THRIFT_ADD_COMPILER(dart "Enable compiler for Dart" 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(xml "Enable compiler for XML" ON)
THRIFT_ADD_COMPILER(xsd "Enable compiler for XSD" 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++)") option(STATIC "Enable static linking of core libraries (libgcc / libstdc++)")
set(thrift-compiler_LINKER_FLAGS) set(thrift-compiler_LINKER_FLAGS)

View File

@ -70,6 +70,7 @@ thrift_SOURCES = src/thrift/audit/t_audit.cpp \
# Specific client generator source # Specific client generator source
thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \ 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_cpp_generator.cc \
src/thrift/generate/t_d_generator.cc \ src/thrift/generate/t_d_generator.cc \
src/thrift/generate/t_dart_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_erl_generator.cc \
src/thrift/generate/t_erlang_generator.cc \ src/thrift/generate/t_erlang_generator.cc \
src/thrift/generate/t_go_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_gv_generator.cc \
src/thrift/generate/t_haxe_generator.cc \ src/thrift/generate/t_haxe_generator.cc \
src/thrift/generate/t_html_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_st_generator.cc \
src/thrift/generate/t_swift_generator.cc \ src/thrift/generate/t_swift_generator.cc \
src/thrift/generate/t_xml_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_CPPFLAGS = -I$(srcdir)/src
thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror

View File

@ -54,6 +54,7 @@
<ClCompile Include="src\thrift\audit\t_audit.cpp" /> <ClCompile Include="src\thrift\audit\t_audit.cpp" />
<ClCompile Include="src\thrift\common.cc" /> <ClCompile Include="src\thrift\common.cc" />
<ClCompile Include="src\thrift\generate\t_c_glib_generator.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_cpp_generator.cc" />
<ClCompile Include="src\thrift\generate\t_d_generator.cc" /> <ClCompile Include="src\thrift\generate\t_d_generator.cc" />
<ClCompile Include="src\thrift\generate\t_dart_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_void;
t_type* g_type_string; t_type* g_type_string;
t_type* g_type_binary; t_type* g_type_binary;
t_type* g_type_uuid;
t_type* g_type_bool; t_type* g_type_bool;
t_type* g_type_i8; t_type* g_type_i8;
t_type* g_type_i16; 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_string = new t_base_type("string", t_base_type::TYPE_STRING);
g_type_binary = 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); ((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_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_i8 = new t_base_type("i8", t_base_type::TYPE_I8);
g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16); g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
@ -46,6 +48,8 @@ void initGlobals() {
void clearGlobals() { void clearGlobals() {
delete g_type_void; delete g_type_void;
delete g_type_string; delete g_type_string;
delete g_type_binary;
delete g_type_uuid;
delete g_type_bool; delete g_type_bool;
delete g_type_i8; delete g_type_i8;
delete g_type_i16; delete g_type_i16;

View File

@ -29,6 +29,7 @@
extern t_type* g_type_void; extern t_type* g_type_void;
extern t_type* g_type_string; extern t_type* g_type_string;
extern t_type* g_type_binary; extern t_type* g_type_binary;
extern t_type* g_type_uuid;
extern t_type* g_type_bool; extern t_type* g_type_bool;
extern t_type* g_type_i8; extern t_type* g_type_i8;
extern t_type* g_type_i16; 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 */ /* initialization and destruction */
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/* generation functions */ /* generation functions */
void generate_typedef(t_typedef* ttypedef) override; 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"; return "T_I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "T_DOUBLE"; return "T_DOUBLE";
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "T_I32"; return "T_I32";
@ -4581,4 +4584,9 @@ string underscores_to_initial_caps(string name) {
} }
/* register this generator with the main program */ /* 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", "") 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 init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) 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) { string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
if (ttype->is_base_type()) { if (ttype->is_base_type()) {
string bname = base_type_name(((t_base_type*)ttype)->get_base()); string bname = base_type_name(((t_base_type*)ttype)->get_base());
std::map<string, string>::iterator it = ttype->annotations_.find("cpp.type"); std::map<string, std::vector<string>>::iterator it = ttype->annotations_.find("cpp.type");
if (it != ttype->annotations_.end()) { if (it != ttype->annotations_.end() && !it->second.empty()) {
bname = it->second; bname = it->second.back();
} }
if (!arg) { if (!arg) {
@ -4660,6 +4661,8 @@ string t_cpp_generator::type_to_enum(t_type* type) {
return "::apache::thrift::protocol::T_I64"; return "::apache::thrift::protocol::T_I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "::apache::thrift::protocol::T_DOUBLE"; return "::apache::thrift::protocol::T_DOUBLE";
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "::apache::thrift::protocol::T_I32"; 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; return program_name;
} }
std::string t_cpp_generator::display_name() const {
return "C++";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
cpp, cpp,
"C++", "C++",

View File

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

View File

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

View File

@ -45,6 +45,7 @@
#endif #endif
using std::map; using std::map;
using std::set;
using std::ofstream; using std::ofstream;
using std::ostream; using std::ostream;
using std::ostringstream; using std::ostringstream;
@ -70,14 +71,18 @@ public:
ansistr_binary_ = false; ansistr_binary_ = false;
register_types_ = false; register_types_ = false;
constprefix_ = false; constprefix_ = false;
old_names_ = false;
events_ = false; events_ = false;
xmldoc_ = false; xmldoc_ = false;
async_ = false; async_ = false;
com_types_ = false;
for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
if( iter->first.compare("ansistr_binary") == 0) { if( iter->first.compare("ansistr_binary") == 0) {
ansistr_binary_ = true; ansistr_binary_ = true;
} else if( iter->first.compare("register_types") == 0) { } else if( iter->first.compare("register_types") == 0) {
register_types_ = true; register_types_ = true;
} else if( iter->first.compare("old_names") == 0) {
old_names_ = true;
} else if( iter->first.compare("constprefix") == 0) { } else if( iter->first.compare("constprefix") == 0) {
constprefix_ = true; constprefix_ = true;
} else if( iter->first.compare("events") == 0) { } else if( iter->first.compare("events") == 0) {
@ -86,11 +91,17 @@ public:
xmldoc_ = true; xmldoc_ = true;
} else if( iter->first.compare("async") == 0) { } else if( iter->first.compare("async") == 0) {
async_ = true; async_ = true;
} else if( iter->first.compare("com_types") == 0) {
com_types_ = true;
} else { } else {
throw "unknown option delphi:" + iter->first; 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"; out_dir_base_ = "gen-delphi";
escape_.clear(); escape_.clear();
escape_['\''] = "''"; escape_['\''] = "''";
@ -98,6 +109,7 @@ public:
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) override; void generate_consts(std::vector<t_const*> consts) override;
@ -345,8 +357,8 @@ public:
std::string argument_list(t_struct* tstruct); std::string argument_list(t_struct* tstruct);
std::string constructor_argument_list(t_struct* tstruct, std::string current_indent); std::string constructor_argument_list(t_struct* tstruct, std::string current_indent);
std::string type_to_enum(t_type* ttype); std::string type_to_enum(t_type* ttype);
std::string prop_name(t_field* tfield, 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 prop_name(std::string name, bool is_xception = false, std::string prefix = "");
std::string constructor_param_name(string name); std::string constructor_param_name(string name);
void write_enum(std::string line); void write_enum(std::string line);
@ -394,18 +406,59 @@ private:
bool has_enum; bool has_enum;
bool has_const; bool has_const;
std::string namespace_dir_; std::string namespace_dir_;
std::map<std::string, int> delphi_keywords; std::set<std::string> types_known;
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::list<t_typedef*> typedefs_pending; std::list<t_typedef*> typedefs_pending;
std::vector<std::string> uses_list; std::vector<std::string> uses_list;
void create_keywords(); std::string empty_value(t_type* type);
bool find_keyword(std::map<std::string, int>& keyword_map, std::string name);
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, std::string normalize_name(std::string name,
bool b_method = false, bool b_method = false,
bool b_exception_method = false); bool b_exception_method = false,
std::string empty_value(t_type* type); bool b_force_underscore = false);
bool is_fully_defined_type(t_type* ttype); bool is_fully_defined_type(t_type* ttype);
void add_defined_type(t_type* ttype); void add_defined_type(t_type* ttype);
void init_known_types_list(); void init_known_types_list();
@ -414,9 +467,11 @@ private:
bool ansistr_binary_; bool ansistr_binary_;
bool register_types_; bool register_types_;
bool constprefix_; bool constprefix_;
bool old_names_;
bool events_; bool events_;
bool xmldoc_; bool xmldoc_;
bool async_; bool async_;
bool com_types_;
void indent_up_impl() { ++indent_impl_; }; void indent_up_impl() { ++indent_impl_; };
void indent_down_impl() { --indent_impl_; }; void indent_down_impl() { --indent_impl_; };
std::string 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(); std::string::size_type len = name.length();
if (len <= 0) { 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 >= 1) {
if (nlast == (len - 1)) { if (nlast == (len - 1)) {
string new_name(name, 0, nlast); 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, std::string t_delphi_generator::normalize_name(std::string name,
bool b_method, bool b_method,
bool b_exception_method) { bool b_exception_method,
bool b_force_underscore) {
string tmp(name); string tmp(name);
std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower)); 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)) { 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)) { } 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)) { } else if (b_exception_method && find_keyword(delphi_reserved_method_exception, tmp)) {
b_found = true; b_reserved = true;
} }
if (b_found) { // neither reserved nor keyword?
return name + "_"; if (!(b_reserved || b_keyword)) {
} else {
return name; return name;
} }
}
void t_delphi_generator::create_keywords() { // apply the rule: old style '_' postfix or more modern '&' prefix?
delphi_keywords["and"] = 1; // underscore always on non-keywords or when explicitly asked via arg
delphi_keywords["end"] = 1; if( (!b_keyword) || old_names_ || b_force_underscore) {
delphi_keywords["interface"] = 1; return name + "_";
delphi_keywords["raise"] = 1; } else {
delphi_keywords["uses"] = 1; return "&" + name;
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) { void t_delphi_generator::add_delphi_uses_list(string unitname) {
@ -747,7 +665,6 @@ void t_delphi_generator::init_generator() {
has_forward = false; has_forward = false;
has_enum = false; has_enum = false;
has_const = false; has_const = false;
create_keywords();
add_delphi_uses_list("Classes"); add_delphi_uses_list("Classes");
add_delphi_uses_list("SysUtils"); add_delphi_uses_list("SysUtils");
@ -773,7 +690,7 @@ void t_delphi_generator::init_generator() {
unitname = include->get_name(); unitname = include->get_name();
nsname = include->get_namespace("delphi"); nsname = include->get_namespace("delphi");
if ("" != nsname) { if ("" != nsname) {
unitname = normalize_name(nsname); unitname = normalize_name(nsname,false,false,true/*force underscore*/);
} }
add_delphi_uses_list(unitname); 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"; std::string f_name = get_out_dir() + "/" + unitname + ".pas";
ofstream_with_content_based_conditional_update f_all; ofstream_with_content_based_conditional_update f_all;
@ -804,6 +721,9 @@ void t_delphi_generator::close_generator() {
generate_delphi_doc(f_all, program_); generate_delphi_doc(f_all, program_);
f_all << "unit " << unitname << ";" << endl << endl; f_all << "unit " << unitname << ";" << endl << endl;
f_all << "{$WARN SYMBOL_DEPRECATED OFF}" << 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 << "interface" << endl << endl;
f_all << "uses" << endl; f_all << "uses" << endl;
@ -831,18 +751,14 @@ void t_delphi_generator::close_generator() {
f_all << "const" << endl; f_all << "const" << endl;
indent_up(); indent_up();
indent(f_all) << "c" << tmp_unit indent(f_all) << "c" << tmp_unit << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";" << endl;
<< "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";" indent(f_all) << "c" << tmp_unit << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";" << endl;
<< endl; indent(f_all) << "c" << tmp_unit << "_Option_ConstPrefix = " << (constprefix_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit indent(f_all) << "c" << tmp_unit << "_Option_Events = " << (events_ ? "True" : "False") << ";" << endl;
<< "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";" indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc = " << (xmldoc_ ? "True" : "False") << ";" << endl;
<< endl; indent(f_all) << "c" << tmp_unit << "_Option_Async = " << (async_ ? "True" : "False") << ";" << endl;
indent(f_all) << "c" << tmp_unit indent(f_all) << "c" << tmp_unit << "_Option_COM_types = " << (com_types_ ? "True" : "False") << ";" << endl;
<< "_Option_ConstPrefix = " << (constprefix_ ? "True" : "False") << ";" << endl; indent(f_all) << "c" << tmp_unit << "_Option_Old_Names = " << (old_names_ ? "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_down(); indent_down();
f_all << endl; 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) { void t_delphi_generator::generate_forward_declaration(t_struct* tstruct) {
// Forward declare struct def // Forward declare struct def
has_forward = true; 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"; 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()) { 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()) { 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()) { } else if (ttype->is_enum()) {
return true; // enums are written first, before all other types return true; // enums are written first, before all other types
} else if (ttype->is_map()) { } 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 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) { void t_delphi_generator::add_defined_type(t_type* ttype) {
// mark as known type // mark as known type
types_known[type_name(ttype)] = 1; types_known.insert(type_name(ttype));
// check all pending typedefs // check all pending typedefs
std::list<t_typedef*>::iterator iter; 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() { void t_delphi_generator::init_known_types_list() {
// known base types // known base types
types_known[type_name(g_type_string)] = 1; types_known.insert( type_name(g_type_string));
types_known[type_name(g_type_binary)] = 1; types_known.insert( type_name(g_type_binary));
types_known[type_name(g_type_bool)] = 1; types_known.insert( type_name(g_type_uuid));
types_known[type_name(g_type_i8)] = 1; types_known.insert( type_name(g_type_bool));
types_known[type_name(g_type_i16)] = 1; types_known.insert( type_name(g_type_i8));
types_known[type_name(g_type_i32)] = 1; types_known.insert( type_name(g_type_i16));
types_known[type_name(g_type_i64)] = 1; types_known.insert( type_name(g_type_i32));
types_known[type_name(g_type_double)] = 1; 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) { 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) { for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
initialize_field(vars, initialize_field(vars,
code, code,
"F" + prop_name((*c_iter)->get_name()), prop_name((*c_iter)->get_name(), false, "F"),
(*c_iter)->get_type(), (*c_iter)->get_type(),
(*c_iter)->get_value()); (*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())) { if (const_needs_var((*c_iter)->get_type())) {
initialize_field(vars, initialize_field(vars,
code, 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_type(),
(*c_iter)->get_value()); (*c_iter)->get_value());
} }
@ -1392,6 +1309,9 @@ string t_delphi_generator::render_const_value(ostream& vars,
case t_base_type::TYPE_STRING: case t_base_type::TYPE_STRING:
render << "'" << get_escaped_string(value) << "'"; render << "'" << get_escaped_string(value) << "'";
break; break;
case t_base_type::TYPE_UUID:
render << "['{" << value->get_uuid() << "}']";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
render << ((value->get_integer() > 0) ? "True" : "False"); render << ((value->get_integer() > 0) ? "True" : "False");
break; break;
@ -1493,11 +1413,11 @@ void t_delphi_generator::generate_delphi_struct_impl(ostream& out,
if ((*m_iter)->get_value() != nullptr) { if ((*m_iter)->get_value() != nullptr) {
initialize_field(vars, initialize_field(vars,
code, code,
"F" + prop_name((*m_iter)->get_name(), is_exception), prop_name((*m_iter)->get_name(), is_exception, ""),
t, t,
(*m_iter)->get_value()); (*m_iter)->get_value());
if ((*m_iter)->get_req() != t_field::T_REQUIRED) { 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; << endl;
} }
} }
@ -1777,7 +1697,7 @@ void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
out << endl; out << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) { 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 << ";" indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";"
<< endl; << endl;
} }
@ -1826,7 +1746,7 @@ void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
indent(out) << endl; indent(out) << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) { 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; indent(out) << isset_name << ": System.Boolean;" << endl;
} }
} }
@ -1849,7 +1769,7 @@ void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
out << endl; out << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) { 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) << "function Get" << isset_name << ": System.Boolean;" << endl;
indent(out) << "procedure Set" << isset_name << "( const value : 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; indent(out) << "// isset" << endl;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
if ((*m_iter)->get_req() != t_field::T_REQUIRED) { 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 << ";" indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";"
<< endl; << 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 #ifdef _WIN32 // TODO: add support for non-windows platforms if needed
GUID guid; GUID guid;
if (SUCCEEDED(CoCreateGuid(&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) { if (StringFromGUID2(guid, &guid_chars[0], sizeof(guid_chars) / sizeof(guid_chars[0])) > 0) {
std::wstring guid_wstr(guid_chars); std::wstring guid_wstr(guid_chars);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert; 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; vector<t_field*>::const_iterator x_iter;
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++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; << ") then begin" << endl;
indent_up_impl(); indent_up_impl();
indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter) 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_) { if (ansistr_binary_) {
out << "ReadAnsiString();"; out << "ReadAnsiString();";
} else { } else {
out << "ReadBinary();"; out << (com_types_ ? "ReadBinaryCOM();" : "ReadBinary();");
} }
} else { } else {
out << "ReadString();"; out << "ReadString();";
} }
break; break;
case t_base_type::TYPE_UUID:
out << "ReadUuid();";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
out << "ReadBool();"; out << "ReadBool();";
break; break;
@ -2904,6 +2827,9 @@ void t_delphi_generator::generate_serialize_field(ostream& out,
} }
out << name << ");"; out << name << ");";
break; break;
case t_base_type::TYPE_UUID:
out << "WriteUuid(" << name << ");";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
out << "WriteBool(" << name << ");"; out << "WriteBool(" << name << ");";
break; break;
@ -3061,26 +2987,26 @@ void t_delphi_generator::generate_delphi_property(ostream& out,
bool is_xception = ftype->is_xception(); bool is_xception = ftype->is_xception();
generate_delphi_doc(out, tfield); generate_delphi_doc(out, tfield);
indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": " indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": "
<< type_name(ftype, false, true, is_xception, true) << " read " << type_name(ftype, false, true, is_xception, true)
<< fieldPrefix + prop_name(tfield, struct_is_xception) << " write Set" << " read " << prop_name(tfield, struct_is_xception, fieldPrefix)
<< prop_name(tfield, struct_is_xception) << ";" << endl; << " write " << prop_name(tfield, struct_is_xception, "Set")
<< ";" << endl;
} }
std::string t_delphi_generator::prop_name(t_field* tfield, bool 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); 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; string ret = name;
ret[0] = toupper(ret[0]); 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) { std::string t_delphi_generator::constructor_param_name(string name) {
string ret = name; string ret = name;
ret[0] = toupper(ret[0]); ret[0] = toupper(ret[0]);
ret = "A" + ret; return normalize_name("a" + ret, false, false);
return normalize_name(ret, false, false);
} }
string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) { 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()) { } else if (ttype->is_set()) {
t_set* tset = (t_set*)ttype; t_set* tset = (t_set*)ttype;
if (b_cls) { if (b_cls) {
typ_nm = "THashSetImpl"; typ_nm = "TThriftHashSetImpl";
} else { } else {
typ_nm = "IHashSet"; typ_nm = "IThriftHashSet";
} }
return typ_nm + "<" + type_name(tset->get_elem_type()) + ">"; return typ_nm + "<" + type_name(tset->get_elem_type()) + ">";
} else if (ttype->is_list()) { } 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 // these should be const'ed for optimal performamce
case t_base_type::TYPE_STRING: // refcounted pointer 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_I64: // larger than 32 bit
case t_base_type::TYPE_DOUBLE: // larger than 32 bit case t_base_type::TYPE_DOUBLE: // larger than 32 bit
return "const "; return "const ";
@ -3236,11 +3163,13 @@ string t_delphi_generator::base_type_name(t_base_type* tbase) {
if (ansistr_binary_) { if (ansistr_binary_) {
return "System.AnsiString"; return "System.AnsiString";
} else { } else {
return "SysUtils.TBytes"; return com_types_ ? "IThriftBytes" : "SysUtils.TBytes";
} }
} else { } 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: case t_base_type::TYPE_BOOL:
return "System.Boolean"; return "System.Boolean";
case t_base_type::TYPE_I8: 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(); t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception(); 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) + ";"; + type_name(ftype, false, true, is_xception, true) + ";";
return result; return result;
} }
@ -3310,11 +3239,11 @@ string t_delphi_generator::function_signature(t_function* tfunction,
// deprecated method? only at intf decl! // deprecated method? only at intf decl!
if( full_cls == "") { if( full_cls == "") {
auto iter = tfunction->annotations_.find("deprecated"); auto iter = tfunction->annotations_.find("deprecated");
if( tfunction->annotations_.end() != iter) { if( tfunction->annotations_.end() != iter && !iter->second.empty()) {
signature += " deprecated"; signature += " deprecated";
// empty annotation values end up with "1" somewhere, ignore these as well // empty annotation values end up with "1" somewhere, ignore these as well
if ((iter->second.length() > 0) && (iter->second != "1")) { if ((iter->second.back().length() > 0) && (iter->second.back() != "1")) {
signature += " " + make_pascal_string_literal(iter->second); signature += " " + make_pascal_string_literal(iter->second.back());
} }
signature += ";"; signature += ";";
} }
@ -3407,6 +3336,8 @@ string t_delphi_generator::type_to_enum(t_type* type) {
throw "NO T_VOID CONSTRUCT"; throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING: case t_base_type::TYPE_STRING:
return "TType.String_"; return "TType.String_";
case t_base_type::TYPE_UUID:
return "TType.Uuid";
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return "TType.Bool_"; return "TType.Bool_";
case t_base_type::TYPE_I8: case t_base_type::TYPE_I8:
@ -3455,6 +3386,8 @@ string t_delphi_generator::empty_value(t_type* type) {
} else { } else {
return "''"; return "''";
} }
case t_base_type::TYPE_UUID:
return "System.TGuid.Empty";
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return "False"; return "False";
case t_base_type::TYPE_I8: 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(); t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception(); 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) << ");" << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
<< endl; << endl;
} }
@ -3497,15 +3430,15 @@ void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out
t_type* ftype = tfield->get_type(); t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception(); 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; << type_name(ftype, false, true, is_xception, true) << ";" << endl;
} }
void t_delphi_generator::generate_delphi_isset_reader_writer_definition(ostream& out, void t_delphi_generator::generate_delphi_isset_reader_writer_definition(ostream& out,
t_field* tfield, t_field* tfield,
bool is_xception) { bool is_xception) {
indent(out) << "function Get__isset_" << prop_name(tfield, is_xception) << ": System.Boolean;" << endl; indent(out) << "function " << prop_name(tfield, is_xception,"Get__isset_") << ": System.Boolean;" << endl;
indent(out) << "procedure Set__isset_" << prop_name(tfield, is_xception) << "( const value : 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, 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(); t_type* ftype = tfield->get_type();
bool is_xception = ftype->is_xception(); 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; << endl;
indent_up_impl(); indent_up_impl();
indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl; indent_impl(out) << prop_name(tfield, is_xception_class,"F__isset_") << " := False;" << endl;
indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := " indent_impl(out) << prop_name(tfield, is_xception_class,fieldPrefix) << " := "
<< "Default( " << type_name(ftype, false, true, is_xception, true) << ");" << "Default( " << type_name(ftype, false, true, is_xception, true) << ");"
<< endl; << endl;
indent_down_impl(); indent_down_impl();
@ -3555,7 +3488,7 @@ void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out,
bool is_xception = ftype->is_xception(); bool is_xception = ftype->is_xception();
indent_impl(out) << "procedure " << cls_prefix << name << "." 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) << ");" << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
<< endl; << endl;
indent_impl(out) << "begin" << 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; indent_impl(out) << "ClearUnionValues;" << endl;
} }
if (tfield->get_req() != t_field::T_REQUIRED) { 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)) { if (is_xception_class && (!is_xception_factory)) {
indent_impl(out) << xception_factory_name << "." << prop_name(tfield, is_xception_class) 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(); bool is_xception = ftype->is_xception();
indent_impl(out) << "function " << cls_prefix << name << "." 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; << type_name(ftype, false, true, is_xception, true) << ";" << endl;
indent_impl(out) << "begin" << endl; indent_impl(out) << "begin" << endl;
indent_up_impl(); 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; << endl;
indent_down_impl(); indent_down_impl();
indent_impl(out) << "end;" << endl << endl; 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) { bool is_xception) {
(void)type; (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 << "." indent_impl(out) << "function " << cls_prefix << name << "."
<< "Get" << isset_name << ": System.Boolean;" << endl; << "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) { for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
propname = prop_name(*f_iter, is_exception); propname = prop_name(*f_iter, is_exception);
if ((*f_iter)->get_req() != t_field::T_REQUIRED) { 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_up_impl();
} }
indent_impl(out) << "Result." << propname << " := " << propname << ";" << endl; 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 // local bools for required fields
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if ((*f_iter)->get_req() == t_field::T_REQUIRED) { 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; << 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; << endl;
} }
} }
@ -3736,7 +3669,7 @@ void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out,
// required field? // required field?
if ((*f_iter)->get_req() == t_field::T_REQUIRED) { 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; << endl;
} }
@ -3786,7 +3719,7 @@ void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out,
code_block << endl; code_block << endl;
first = false; 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) indent_impl(code_block)
<< "then raise TProtocolExceptionInvalidData.Create(" << "then raise TProtocolExceptionInvalidData.Create("
<< "'required field " << prop_name(*f_iter, is_exception) << " not set');" << "'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) { if (fields.size() > 0) {
indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl; indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { 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; << endl;
indent_impl(code_block) << "begin" << endl; indent_impl(code_block) << "begin" << endl;
indent_up_impl(); 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) { for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
string fieldname = prop_name((*f_iter), is_exception); 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 null_allowed = type_can_be_null((*f_iter)->get_type());
bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED); bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED);
bool has_isset = (!is_required); bool has_isset = (!is_required);
@ -3922,13 +3856,13 @@ void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out,
if (null_allowed) { if (null_allowed) {
indent_impl(code_block) << "if (Self." << fieldname << " <> nil)"; indent_impl(code_block) << "if (Self." << fieldname << " <> nil)";
if (has_isset) { if (has_isset) {
code_block << " and __isset_" << fieldname; code_block << " and " << isset_name;
} }
code_block << " then begin" << endl; code_block << " then begin" << endl;
indent_up_impl(); indent_up_impl();
} else { } else {
if (has_isset) { 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(); indent_up_impl();
} }
} }
@ -4021,13 +3955,13 @@ void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out,
if (null_allowed) { if (null_allowed) {
indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)"; indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)";
if (is_optional) { 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; out << " then begin" << endl;
indent_up_impl(); indent_up_impl();
} else { } else {
if (is_optional) { 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; << endl;
indent_up_impl(); 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) << type_name(ttype, false, true, false, false)
<< ">.ToString( System.Ord( Self." << ">.ToString( System.Ord( Self."
<< prop_name((*f_iter), is_exception) << ")));" << endl; << 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 { } else {
indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");" indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");"
<< endl; << endl;
@ -4105,13 +4042,20 @@ bool t_delphi_generator::is_void(t_type* type) {
return false; return false;
} }
std::string t_delphi_generator::display_name() const {
return "Delphi";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
delphi, delphi,
"delphi", "Delphi",
" ansistr_binary: Use AnsiString for binary datatype (default is TBytes).\n" " ansistr_binary: Use AnsiString for binary datatype (default is TBytes).\n"
" register_types: Enable TypeRegistry, allows for creation of struct, union\n" " register_types: Enable TypeRegistry, allows for creation of struct, union\n"
" and container instances by interface or TypeInfo()\n" " and container instances by interface or TypeInfo()\n"
" constprefix: Name TConstants classes after IDL to reduce ambiguities\n" " constprefix: Name TConstants classes after IDL to reduce ambiguities\n"
" events: Enable and use processing events in the generated code.\n" " events: Enable and use processing events in the generated code.\n"
" xmldoc: Enable XMLDoc comments for Help Insight etc.\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 init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/** /**
* Program-level generation functions * Program-level generation functions
@ -1168,6 +1169,8 @@ string t_erl_generator::type_to_enum(t_type* type) {
return "?tType_I64"; return "?tType_I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "?tType_DOUBLE"; return "?tType_DOUBLE";
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "?tType_I32"; return "?tType_I32";
@ -1211,6 +1214,8 @@ std::string t_erl_generator::render_type_term(t_type* type,
return "i64"; return "i64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "double"; return "double";
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "i32"; 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"; 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( THRIFT_REGISTER_GENERATOR(
erl, erl,
"Erlang", "Erlang",

View File

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

View File

@ -76,20 +76,11 @@ void t_generator::generate_program() {
close_generator(); close_generator();
} }
std::set<std::string> t_generator::lang_keywords() const { std::set<std::string> t_generator::lang_keywords_for_validation() const {
std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__", // Nothing by default. It makes no sense to restrict the whole world to use non-PHP keywords only.
"__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as", // Override on a per-generator(!) basis if you cannot live without it, e.g. that particular language has no
"assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare", // mechanism or way to deal with it properly, so we absolutely need to fail on it as the last possible resort.
"def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif", return {};
"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]) );
} }
void t_generator::validate_input() const { 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 { void t_generator::validate_id(const string& id) const {
if (keywords_.find(id) != keywords_.end()) { 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 { class t_generator {
public: public:
t_generator(t_program* program) { t_generator(t_program* program) {
update_keywords(); update_keywords_for_validation();
tmp_ = 0; tmp_ = 0;
indent_ = 0; indent_ = 0;
@ -100,18 +100,24 @@ public:
/** /**
* Check if all identifiers are valid for the target language * Check if all identifiers are valid for the target language
* See update_keywords() * See update_keywords_for_validation()
*/ */
virtual void validate_input() const; 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: 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/platform.h"
#include "thrift/version.h" #include "thrift/version.h"
#include "thrift/generate/t_generator.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::map;
using std::ostream; using std::ostream;
@ -49,8 +51,6 @@ using std::string;
using std::stringstream; using std::stringstream;
using std::vector; 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 * A helper for automatically formatting the emitted Go code from the Thrift
* IDL per the Go style guide. * 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); 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 // returns true if field initialization can be omitted since it has corresponding go type zero value
// or default value is not set // or default value is not set
bool t_go_generator::omit_initialization(t_field* tfield) { bool t_go_generator::omit_initialization(t_field* tfield) {
@ -368,6 +97,13 @@ bool t_go_generator::omit_initialization(t_field* tfield) {
} else { } else {
return value->get_double() == 0.; 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; 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_I32:
case t_base_type::TYPE_I64: case t_base_type::TYPE_I64:
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
return !has_default; return !has_default;
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return !has_default; return !has_default;
@ -969,6 +709,10 @@ string t_go_generator::go_imports_begin(bool consts) {
system_packages.push_back("time"); system_packages.push_back("time");
// For the thrift import, always do rename import to make sure it's called thrift. // For the thrift import, always do rename import to make sure it's called thrift.
system_packages.push_back("thrift \"" + gen_thrift_import_ + "\""); 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); 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 * This will have to do in lieu of more intelligent import statement construction
*/ */
string t_go_generator::go_imports_end() { string t_go_generator::go_imports_end() {
return string( string import_end = string(
")\n\n" ")\n\n"
"// (needed to ensure safety because of naive import list construction.)\n" "// (needed to ensure safety because of naive import list construction.)\n"
"var _ = thrift.ZERO\n" "var _ = thrift.ZERO\n"
@ -987,7 +731,11 @@ string t_go_generator::go_imports_end() {
"var _ = errors.New\n" "var _ = errors.New\n"
"var _ = context.Background\n" "var _ = context.Background\n"
"var _ = time.Now\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(); t_type* type = tconst->get_type();
string name = publicize(tconst->get_name()); string name = publicize(tconst->get_name());
t_const_value* value = tconst->get_value(); 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; indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
} else { } else {
f_const_values_ << indent() << name << " = " << render_const_value(type, value, name) << endl 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 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_ptr;
string typedef_opt;
if (type->is_typedef()) { 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); type = get_true_type(type);
std::ostringstream out; 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) + '"'; out << '"' + get_escaped_string(value) + '"';
break; 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: default:
throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); 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; 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: default:
throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); 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) { void t_go_generator::generate_go_struct(t_struct* tstruct, bool is_exception) {
generate_go_struct_definition(f_types_, tstruct, 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, 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 // Check for user defined tags and them if there are any. User defined tags
// can override the above db and json 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()) { if (it != (*m_iter)->annotations_.end()) {
parse_go_tags(&tags, it->second); parse_go_tags(&tags, it->second.back());
} }
string gotag; string gotag;
@ -2676,6 +2458,15 @@ void t_go_generator::generate_service_remote(t_service* tservice) {
f_remote << indent() << "}" << endl; f_remote << indent() << "}" << endl;
break; 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: default:
throw("Invalid base type in generate_service_remote"); 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_I32:
case t_base_type::TYPE_I64: case t_base_type::TYPE_I64:
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
f_remote << "value" << i; f_remote << "value" << i;
break; 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; f_types_ << indent() << "if thrift.ServerConnectivityCheckInterval > 0 {" << endl;
indent_up(); indent_up();
f_types_ << indent() << "var cancel context.CancelFunc" << endl; f_types_ << indent() << "var cancel context.CancelCauseFunc" << endl;
f_types_ << indent() << "ctx, cancel = context.WithCancel(ctx)" << endl; f_types_ << indent() << "ctx, cancel = context.WithCancelCause(ctx)" << endl;
f_types_ << indent() << "defer cancel()" << endl; f_types_ << indent() << "defer cancel(nil)" << endl;
f_types_ << indent() << "var tickerCtx context.Context" << endl; f_types_ << indent() << "var tickerCtx context.Context" << endl;
f_types_ << indent() << "tickerCtx, tickerCancel = context.WithCancel(context.Background())" << endl; f_types_ << indent() << "tickerCtx, tickerCancel = context.WithCancel(context.Background())" << endl;
f_types_ << indent() << "defer tickerCancel()" << 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(); indent_up();
f_types_ << indent() << "ticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)" << endl; 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(); indent_up();
f_types_ << indent() << "if !iprot.Transport().IsOpen() {" << endl; f_types_ << indent() << "if !iprot.Transport().IsOpen() {" << endl;
indent_up(); indent_up();
f_types_ << indent() << "cancel()" << endl; f_types_ << indent() << "cancel(thrift.ErrAbandonRequest)" << endl;
f_types_ << indent() << "return" << endl; f_types_ << indent() << "return" << endl;
indent_down(); indent_down();
f_types_ << indent() << "}" << endl; 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; f_types_ << indent() << "return false, thrift.WrapTException(err2)" << endl;
indent_down(); indent_down();
f_types_ << indent() << "}" << endl; 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")); string exc(tmp("_exc"));
f_types_ << indent() << exc << " := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, " 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)"; out << "ReadDouble(ctx)";
break; break;
case t_base_type::TYPE_UUID:
out << "ReadUUID(ctx)";
break;
default: default:
throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase); 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 << "))"; out << "WriteDouble(ctx, float64(" << name << "))";
break; break;
case t_base_type::TYPE_UUID:
out << "WriteUUID(ctx, thrift.Tuuid(" << name << "))";
break;
default: default:
throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase); 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_I32:
case t_base_type::TYPE_I64: case t_base_type::TYPE_I64:
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
case t_base_type::TYPE_UUID:
out << tgt << " != " << src; out << tgt << " != " << src;
break; break;
@ -4057,6 +3867,12 @@ string t_go_generator::type_to_enum(t_type* type) {
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "thrift.DOUBLE"; return "thrift.DOUBLE";
case t_base_type::TYPE_UUID:
return "thrift.UUID";
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "thrift.I32"; 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: case t_base_type::TYPE_DOUBLE:
return maybe_pointer + "float64"; return maybe_pointer + "float64";
case t_base_type::TYPE_UUID:
return maybe_pointer + "thrift.Tuuid";
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return maybe_pointer + publicize(type_name(type)); 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", THRIFT_REGISTER_GENERATOR(go, "Go",
" package_prefix= Package prefix for generated files.\n" \ " package_prefix= Package prefix for generated files.\n" \
" thrift_import= Override thrift package import path (default:" + DEFAULT_THRIFT_IMPORT + ")\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 * Init and end of generator
*/ */
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/** /**
* Program-level generation functions * Program-level generation functions
*/ */
void generate_typedef(t_typedef* ttypedef) override; void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override; void generate_enum(t_enum* tenum) override;
void generate_const(t_const* tconst) override; void generate_const(t_const* tconst) override;
@ -83,6 +86,7 @@ protected:
/** /**
* Helpers * Helpers
*/ */
void print_type(t_type* ttype, string struct_field_ref); void print_type(t_type* ttype, string struct_field_ref);
void print_const_value(t_type* type, t_const_value* tvalue); 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; f_out_ << " }" << endl;
} }
std::string t_gv_generator::display_name() const {
return "Graphviz";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
gv, gv,
"Graphviz", "Graphviz",

View File

@ -75,6 +75,7 @@ public:
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
void generate_consts(std::vector<t_const*> consts) 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 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 base_type_name(t_base_type* tbase, bool in_container = false);
std::string declare_field(t_field* tfield, bool init = 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_combined(t_function* tfunction);
std::string function_signature_normal(t_function* tfunction); std::string function_signature_normal(t_function* tfunction);
std::string argument_list(t_struct* tstruct); 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); 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_combined(t_function* tfunction, bool is_interface);
void generate_service_method_signature_normal(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) { bool type_can_be_null(t_type* ttype) {
ttype = get_true_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: case t_base_type::TYPE_STRING:
out << '"' << get_escaped_string(value) << '"'; out << '"' << get_escaped_string(value) << '"';
break; break;
case t_base_type::TYPE_UUID:
out << '"' << get_escaped_string(value) << '"';
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
out << ((value->get_integer() > 0) ? "true" : "false"); out << ((value->get_integer() > 0) ? "true" : "false");
break; break;
@ -1443,6 +1450,9 @@ std::string t_haxe_generator::get_haxe_type_string(t_type* type) {
case t_base_type::TYPE_STRING: case t_base_type::TYPE_STRING:
return "TType.STRING"; return "TType.STRING";
break; break;
case t_base_type::TYPE_UUID:
return "TType.UUID";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return "TType.BOOL"; return "TType.BOOL";
break; 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, void t_haxe_generator::generate_service_method_signature_normal(t_function* tfunction,
bool is_interface) { bool is_interface) {
if (is_interface) { if (is_interface) {
generate_deprecation_attribute(f_service_, tfunction, true);
indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl; indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl;
} else { } else {
indent(f_service_) << "public " << function_signature_normal(tfunction) << " {" << endl; 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) { if (is_interface) {
generate_deprecation_attribute(f_service_, tfunction, false);
indent(f_service_) << function_signature_combined(tfunction) << ";" << endl << endl; indent(f_service_) << function_signature_combined(tfunction) << ";" << endl << endl;
} else { } else {
indent(f_service_) << "public " << function_signature_combined(tfunction) << " {" << endl; 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. * Generates a service interface definition.
* *
@ -1820,8 +1879,9 @@ void t_haxe_generator::generate_service_client(t_service* tservice) {
string retval = tmp("retval"); string retval = tmp("retval");
if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) {
f_service_ << indent() << "var " << retval << " : " << type_name((*f_iter)->get_returntype()) << ";" f_service_ << indent() << "var " << retval << " : " << type_name((*f_iter)->get_returntype())
<< endl; << " = " << render_default_value_for_type((*f_iter)->get_returntype(),true)
<< ";" << endl;
} }
if ((*f_iter)->is_oneway()) { if ((*f_iter)->is_oneway()) {
@ -2222,6 +2282,9 @@ void t_haxe_generator::generate_deserialize_field(ostream& out, t_field* tfield,
out << "readString();"; out << "readString();";
} }
break; break;
case t_base_type::TYPE_UUID:
out << "readUuid();";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
out << "readBool();"; out << "readBool();";
break; break;
@ -2406,6 +2469,9 @@ void t_haxe_generator::generate_serialize_field(ostream& out, t_field* tfield, s
out << "writeString(" << name << ");"; out << "writeString(" << name << ");";
} }
break; break;
case t_base_type::TYPE_UUID:
out << "writeUuid(" << name << ");";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
out << "writeBool(" << name << ");"; out << "writeBool(" << name << ");";
break; break;
@ -2457,7 +2523,6 @@ void t_haxe_generator::generate_serialize_struct(ostream& out, t_struct* tstruct
* @param prefix String prefix for fields * @param prefix String prefix for fields
*/ */
void t_haxe_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { void t_haxe_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
scope_up(out);
if (ttype->is_map()) { if (ttype->is_map()) {
string iter = tmp("_key"); 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; 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) + ">"; return "StringMap< " + type_name(tval) + ">";
} }
break; // default to ObjectMap<> 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_I8:
case t_base_type::TYPE_I16: case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32: 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"; return "StringSet";
} }
break; // default to ObjectSet 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_I8:
case t_base_type::TYPE_I16: case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32: 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 { } else {
return "String"; return "String";
} }
case t_base_type::TYPE_UUID:
return "String";
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return "Bool"; return "Bool";
case t_base_type::TYPE_I8: case t_base_type::TYPE_I8:
@ -2672,43 +2742,49 @@ string t_haxe_generator::base_type_name(t_base_type* type, bool in_container) {
* @param ttype The type * @param ttype The type
*/ */
string t_haxe_generator::declare_field(t_field* tfield, bool init) { 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()); string result = "var " + tfield->get_name() + " : " + type_name(tfield->get_type());
if (init) { if (init) {
t_type* ttype = get_true_type(tfield->get_type()); t_type* ttype = get_true_type(tfield->get_type());
if (ttype->is_base_type() && tfield->get_value() != nullptr) { if (ttype->is_base_type() && tfield->get_value() != nullptr) {
result += " = " + render_const_value_str( ttype, tfield->get_value()); 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(); t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
switch (tbase) { switch (tbase) {
case t_base_type::TYPE_VOID: case t_base_type::TYPE_VOID:
throw "NO T_VOID CONSTRUCT"; throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING: case t_base_type::TYPE_STRING:
result += " = null"; return "null";
break; case t_base_type::TYPE_UUID:
return "uuid.Uuid.NIL";
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
result += " = false"; return "false";
break;
case t_base_type::TYPE_I8: case t_base_type::TYPE_I8:
case t_base_type::TYPE_I16: case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32: case t_base_type::TYPE_I32:
case t_base_type::TYPE_I64: case t_base_type::TYPE_I64:
result += " = 0"; return "0";
break;
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
result += " = (double)0"; return "0.0";
break; default:
throw "unhandled type";
} }
} else if (ttype->is_enum()) { } else if (ttype->is_enum()) {
result += " = 0"; return "0";
} else if (ttype->is_container()) { } else if (ttype->is_container()) {
result += " = new " + type_name(ttype, false, true) + "()"; return allow_null ? "null" : "new " + type_name(ttype, false, true) + "()";
} else { } else {
result += " = new " + type_name(ttype, false, true) + "()"; return allow_null ? "null" : "new " + type_name(ttype, false, true) + "()";
} }
}
return result + ";";
} }
/** /**
@ -2793,6 +2869,8 @@ string t_haxe_generator::type_to_enum(t_type* type) {
throw "NO T_VOID CONSTRUCT"; throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING: case t_base_type::TYPE_STRING:
return "TType.STRING"; return "TType.STRING";
case t_base_type::TYPE_UUID:
return "TType.UUID";
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return "TType.BOOL"; return "TType.BOOL";
case t_base_type::TYPE_I8: case t_base_type::TYPE_I8:
@ -2805,6 +2883,8 @@ string t_haxe_generator::type_to_enum(t_type* type) {
return "TType.I64"; return "TType.I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "TType.DOUBLE"; return "TType.DOUBLE";
default:
break;
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "TType.I32"; return "TType.I32";
@ -2994,6 +3074,11 @@ std::string t_haxe_generator::get_enum_class_name(t_type* type) {
return package + type->get_name(); return package + type->get_name();
} }
std::string t_haxe_generator::display_name() const {
return "Haxe";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
haxe, haxe,
"Haxe", "Haxe",

View File

@ -81,6 +81,7 @@ public:
init_allowed__markup(); init_allowed__markup();
} }
std::string display_name() const override;
void generate_program() override; void generate_program() override;
void generate_program_toc(); 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( THRIFT_REGISTER_GENERATOR(
html, html,
"HTML", "HTML",

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -84,6 +84,8 @@ public:
init_allowed__markup(); init_allowed__markup();
} }
std::string display_name() const override;
void generate_program() override; void generate_program() override;
void generate_program_toc(); void generate_program_toc();
void generate_program_toc_row(t_program* tprog); 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( THRIFT_REGISTER_GENERATOR(
markdown, markdown,
"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_; } 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() void t_netstd_generator::init_generator()
{ {
MKDIR(get_out_dir().c_str()); MKDIR(get_out_dir().c_str());
@ -151,7 +146,6 @@ void t_netstd_generator::init_generator()
} }
namespace_dir_ = subdir; namespace_dir_ = subdir;
init_keywords();
while (!member_mapping_scopes.empty()) while (!member_mapping_scopes.empty())
{ {
@ -185,120 +179,16 @@ string t_netstd_generator::normalize_name(string name, bool is_arg_name)
return "@" + 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 // no changes necessary
return name; 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() { void t_netstd_generator::reset_indent() {
while( indent_count() > 0) { 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); generate_netstd_doc(out, *c_iter);
int value = (*c_iter)->get_value(); 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); 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) for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter)
{ {
generate_netstd_doc(out, *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; 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()) if (type->is_base_type())
{ {
string v2 = render_const_value(out, name, type, value); string v2 = render_const_value(out, name, type, value);
out << normalize_name(name) << " = " << v2 << ";" << endl; out << name << " = " << v2 << ";" << endl;
need_static_construction = false; need_static_construction = false;
} }
else if (type->is_enum()) 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) << '"'; render << '"' << get_escaped_string(value) << '"';
} }
break; break;
case t_base_type::TYPE_UUID:
render << "new System.Guid(\"" << get_escaped_string(value) << "\")";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
render << ((value->get_integer() > 0) ? "true" : "false"); render << ((value->get_integer() > 0) ? "true" : "false");
break; break;
@ -665,7 +558,7 @@ string t_netstd_generator::render_const_value(ostream& out, string name, t_type*
} }
else else
{ {
string t = tmp("tmp"); string t = normalize_name(tmp("tmp"));
print_const_value(out, t, type, value, true, true, true); print_const_value(out, t, type, value, true, true, true);
render << t; render << t;
} }
@ -1053,7 +946,7 @@ void t_netstd_generator::generate_netstd_struct_definition(ostream& out, t_struc
{ {
if (field_is_required((*m_iter))) 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 else
{ {
@ -1569,14 +1462,14 @@ void t_netstd_generator::generate_netstd_union_definition(ostream& out, t_struct
// Let's define the class first // Let's define the class first
start_netstd_namespace(out); 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; out << indent() << "{" << endl;
indent_up(); indent_up();
out << indent() << "public abstract global::System.Threading.Tasks.Task WriteAsync(TProtocol tProtocol, CancellationToken " << CANCELLATION_TOKEN_NAME << ");" << endl 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 readonly int Isset;" << endl
<< indent() << "public abstract object" << nullable_suffix() <<" Data { get; }" << 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() << "{" << endl;
indent_up(); indent_up();
out << indent() << "Isset = isset;" << endl; out << indent() << "Isset = isset;" << endl;
@ -1782,13 +1675,13 @@ void t_netstd_generator::generate_netstd_union_class(ostream& out, t_struct* tun
<< endl; << 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; out << indent() << "{" << endl;
indent_up(); indent_up();
out << indent() << "private readonly " << type_name(tfield->get_type()) << " _data;" << endl out << indent() << "private readonly " << type_name(tfield->get_type()) << " _data;" << endl
<< indent() << "public override object" << nullable_suffix() <<" Data { get { return _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() << "{" << endl;
indent_up(); indent_up();
out << indent() << "this._data = data;" << endl; 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; out << indent() << "}" << endl;
if( ! suppress_deepcopy) { 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; out << indent() << "{" << endl;
indent_up(); indent_up();
bool needs_typecast = false; bool needs_typecast = false;
string suffix(""); string suffix("");
string copy_op = get_deep_copy_method_call(tfield->get_type(), true, needs_typecast, 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(); indent_down();
out << indent() << "}" << endl << endl; out << indent() << "}" << endl << endl;
} }
@ -2056,8 +1949,8 @@ void t_netstd_generator::generate_deprecation_attribute(ostream& out, t_function
if( func->annotations_.end() != iter) { if( func->annotations_.end() != iter) {
out << indent() << "[Obsolete"; out << indent() << "[Obsolete";
// empty annotation values end up with "1" somewhere, ignore these as well // empty annotation values end up with "1" somewhere, ignore these as well
if ((iter->second.length() > 0) && (iter->second != "1")) { if ((iter->second.back().length() > 0) && (iter->second.back() != "1")) {
out << "(" << make_csharp_string_literal(iter->second) << ")"; out << "(" << make_csharp_string_literal(iter->second.back()) << ")";
} }
out << "]" << endl; out << "]" << endl;
} }
@ -2703,6 +2596,9 @@ void t_netstd_generator::generate_deserialize_field(ostream& out, t_field* tfiel
out << "ReadStringAsync(" << CANCELLATION_TOKEN_NAME << ");"; out << "ReadStringAsync(" << CANCELLATION_TOKEN_NAME << ");";
} }
break; break;
case t_base_type::TYPE_UUID:
out << "ReadUuidAsync(" << CANCELLATION_TOKEN_NAME << ");";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
out << "ReadBoolAsync(" << CANCELLATION_TOKEN_NAME << ");"; out << "ReadBoolAsync(" << CANCELLATION_TOKEN_NAME << ");";
break; break;
@ -2906,6 +2802,9 @@ void t_netstd_generator::generate_serialize_field(ostream& out, t_field* tfield,
} }
out << name << ", " << CANCELLATION_TOKEN_NAME << ");"; out << name << ", " << CANCELLATION_TOKEN_NAME << ");";
break; break;
case t_base_type::TYPE_UUID:
out << "WriteUuidAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
out << "WriteBoolAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");"; out << "WriteBoolAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");";
break; break;
@ -3492,6 +3391,8 @@ string t_netstd_generator::base_type_name(t_base_type* tbase)
} else { } else {
return "string"; return "string";
} }
case t_base_type::TYPE_UUID:
return "global::System.Guid";
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return "bool"; return "bool";
case t_base_type::TYPE_I8: case t_base_type::TYPE_I8:
@ -3614,6 +3515,9 @@ string t_netstd_generator::initialize_field(t_field* tfield)
return " = null"; return " = null";
} }
break; break;
case t_base_type::TYPE_UUID:
return " = System.Guid.Empty";
break;
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return " = false"; return " = false";
break; break;
@ -3725,6 +3629,8 @@ string t_netstd_generator::type_to_enum(t_type* type)
throw "NO T_VOID CONSTRUCT"; throw "NO T_VOID CONSTRUCT";
case t_base_type::TYPE_STRING: case t_base_type::TYPE_STRING:
return "TType.String"; return "TType.String";
case t_base_type::TYPE_UUID:
return "TType.Uuid";
case t_base_type::TYPE_BOOL: case t_base_type::TYPE_BOOL:
return "TType.Bool"; return "TType.Bool";
case t_base_type::TYPE_I8: 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(); return "global::" + package + type->get_name();
} }
std::string t_netstd_generator::display_name() const {
return "C#";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
netstd, netstd,
"C#", "C#",

View File

@ -37,6 +37,7 @@
#include "thrift/generate/t_oop_generator.h" #include "thrift/generate/t_oop_generator.h"
using std::map; using std::map;
using std::set;
using std::ostream; using std::ostream;
using std::ostringstream; using std::ostringstream;
using std::string; using std::string;
@ -66,11 +67,11 @@ public:
bool is_hashcode_enabled() const; bool is_hashcode_enabled() const;
bool is_serialize_enabled() const; bool is_serialize_enabled() const;
bool is_union_enabled() const; bool is_union_enabled() const;
map<string, int> get_keywords_list() const;
// overrides // overrides
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
void generate_consts(vector<t_const*> consts) override; void generate_consts(vector<t_const*> consts) override;
void generate_consts(ostream& out, vector<t_const*> consts); void generate_consts(ostream& out, vector<t_const*> consts);
void generate_typedef(t_typedef* ttypedef) override; void generate_typedef(t_typedef* ttypedef) override;
@ -179,13 +180,26 @@ private:
bool use_net6_features; bool use_net6_features;
bool add_async_postfix; 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_; 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; vector<member_mapping_scope> member_mapping_scopes;
map<string, t_type*> collected_extension_types; map<string, t_type*> collected_extension_types;
map<string, t_type*> checked_extension_types; map<string, t_type*> checked_extension_types;
void init_keywords();
string normalize_name(string name, bool is_arg_name = false); string normalize_name(string name, bool is_arg_name = false);
string make_valid_csharp_identifier(string const& fromName); string make_valid_csharp_identifier(string const& fromName);
string make_csharp_string_literal( string const& value); string make_csharp_string_literal( string const& value);

View File

@ -61,16 +61,15 @@ public:
out_dir_base_ = "gen-ocaml"; out_dir_base_ = "gen-ocaml";
} }
/** ~t_ocaml_generator() override;
* Init and close methods
*/
void init_generator() override; void init_generator() override;
void close_generator() override; std::string display_name() const override;
/** /**
* Program-level generation functions * Program-level generation functions
*/ */
void generate_program() override; void generate_program() override;
void generate_typedef(t_typedef* ttypedef) override; void generate_typedef(t_typedef* ttypedef) override;
void generate_enum(t_enum* tenum) override; void generate_enum(t_enum* tenum) override;
@ -147,16 +146,20 @@ public:
* Helper rendering functions * 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 ocaml_imports();
std::string type_name(t_type* ttype); 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_signature(t_function* tfunction, std::string prefix = "");
std::string function_type(t_function* tfunc, bool method = false, bool options = false); std::string function_type(t_function* tfunc, bool method = false, bool options = false);
std::string argument_list(t_struct* tstruct); std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype); std::string type_to_enum(t_type* ttype);
std::string render_ocaml_type(t_type* type); std::string render_ocaml_type(t_type* type);
private: // Need access to output file streams for testing.
protected:
/** /**
* File streams * File streams
*/ */
@ -216,9 +219,6 @@ void t_ocaml_generator::generate_program() {
// Generate constants // Generate constants
vector<t_const*> consts = program_->get_consts(); vector<t_const*> consts = program_->get_consts();
generate_consts(consts); generate_consts(consts);
// Close the generator
close_generator();
} }
/** /**
@ -262,12 +262,12 @@ string t_ocaml_generator::ocaml_imports() {
return "open Thrift"; return "open Thrift";
} }
/** t_ocaml_generator::~t_ocaml_generator() {
* Closes the type files f_consts_.close();
*/
void t_ocaml_generator::close_generator() {
// Close types file
f_types_.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_interface(tservice);
generate_service_client(tservice); generate_service_client(tservice);
generate_service_server(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) { for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
f_service_ << indent() << "(match result#get_" << (*x_iter)->get_name() f_service_ << indent() << "(match result#get_" << (*x_iter)->get_name()
<< " with None -> () | Some _v ->" << endl; << " 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; << " _v));" << endl;
} }
@ -1270,7 +1266,7 @@ void t_ocaml_generator::generate_process_function(t_service* tservice, t_functio
indent(f_service_) << "with" << endl; indent(f_service_) << "with" << endl;
indent_up(); indent_up();
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { 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; << (*x_iter)->get_name() << " -> " << endl;
indent_up(); indent_up();
indent_up(); indent_up();
@ -1673,6 +1669,18 @@ string t_ocaml_generator::type_name(t_type* ttype) {
return prefix + name; 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 * 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"; return "Protocol.T_I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "Protocol.T_DOUBLE"; return "Protocol.T_DOUBLE";
default:
throw "compiler error: unhandled type";
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "Protocol.T_I32"; return "Protocol.T_I32";
@ -1739,6 +1749,8 @@ string t_ocaml_generator::render_ocaml_type(t_type* type) {
return "Int64.t"; return "Int64.t";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "float"; return "float";
default:
throw "compiler error: unhandled type";
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return capitalize(((t_enum*)type)->get_name()) + ".t"; 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(); 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", "") THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "")

View File

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

View File

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

View File

@ -99,6 +99,7 @@ public:
throw "oop and inlined are mutually exclusive."; throw "oop and inlined are mutually exclusive.";
} }
update_keywords_for_validation();
out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php"); out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
escape_['$'] = "\\$"; escape_['$'] = "\\$";
} }
@ -115,6 +116,7 @@ public:
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/** /**
* Program-level generation functions * Program-level generation functions
@ -128,6 +130,7 @@ public:
void generate_service(t_service* tservice) override; void generate_service(t_service* tservice) override;
std::string render_const_value(t_type* type, t_const_value* value); std::string render_const_value(t_type* type, t_const_value* value);
std::set<std::string> lang_keywords_for_validation() const override;
/** /**
* Structs! * Structs!
@ -418,6 +421,22 @@ private:
bool getters_setters_; 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) { bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) {
return sub_namespace == "path"; return sub_namespace == "path";
} }
@ -2798,6 +2817,8 @@ string t_php_generator::type_to_enum(t_type* type) {
return "TType::I64"; return "TType::I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "TType::DOUBLE"; return "TType::DOUBLE";
default:
throw "compiler error: unhandled type";
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "TType::I32"; return "TType::I32";
@ -2839,6 +2860,8 @@ string t_php_generator::type_to_phpdoc(t_type* type) {
return "int"; return "int";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "double"; return "double";
default:
throw "compiler error: unhandled type";
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "int"; 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(); throw "INVALID TYPE IN type_to_enum: " + type->get_name();
} }
std::string t_php_generator::display_name() const {
return "PHP";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
php, php,
"PHP", "PHP",

View File

@ -52,7 +52,7 @@ public:
const std::map<std::string, std::string>& parsed_options, const std::map<std::string, std::string>& parsed_options,
const std::string& option_string) const std::string& option_string)
: t_generator (program) { : t_generator (program) {
update_keywords(); update_keywords_for_validation();
std::map<std::string, std::string>::const_iterator iter; std::map<std::string, std::string>::const_iterator iter;
@ -157,6 +157,7 @@ public:
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/** /**
* Program-level generation functions * Program-level generation functions
@ -280,12 +281,12 @@ public:
} }
static bool is_immutable(t_type* ttype) { 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()) { if (it == ttype->annotations_.end()) {
// Exceptions are immutable by default. // Exceptions are immutable by default.
return ttype->is_xception(); return ttype->is_xception();
} else if (it->second == "false") { } else if (!it->second.empty() && it->second.back() == "false") {
return false; return false;
} else { } else {
return true; return true;
@ -357,7 +358,7 @@ private:
std::string module_; std::string module_;
protected: 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", std::string keywords[] = { "False", "None", "True", "and", "as", "assert", "break", "class",
"continue", "def", "del", "elif", "else", "except", "exec", "finally", "for", "from", "continue", "def", "del", "elif", "else", "except", "exec", "finally", "for", "from",
"global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "print", "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(); int64_t int_val = value->get_integer();
if (gen_enum_) { if (gen_enum_) {
t_enum_value* enum_val = ((t_enum*)type)->get_constant_by_value(int_val); 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 { } else {
out << int_val; out << int_val;
} }
@ -870,7 +871,12 @@ void t_py_generator::generate_py_struct_definition(ostream& out,
} }
if (is_immutable(tstruct)) { 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__('" indent(out) << "super(" << tstruct->get_name() << ", self).__setattr__('"
<< (*m_iter)->get_name() << "', " << (*m_iter)->get_name() << ")" << endl; << (*m_iter)->get_name() << "', " << (*m_iter)->get_name() << ")" << endl;
} else { } else {
@ -887,12 +893,42 @@ void t_py_generator::generate_py_struct_definition(ostream& out,
if (is_immutable(tstruct)) { if (is_immutable(tstruct)) {
out << endl; out << endl;
out << indent() << "def __setattr__(self, *args):" << endl out << indent() << "def __setattr__(self, *args):" << endl;
<< indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl indent_up();
<< endl;
out << indent() << "def __delattr__(self, *args):" << endl // Not user-provided fields should be editable so that the Python Standard Library can edit
<< indent() << indent_str() << "raise TypeError(\"can't modify immutable instance\")" << endl // internal fields of std library base classes. For example, in Python 3.11 ContextManager
<< endl; // 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 // Hash all of the members in order, and also hash in the class
// to avoid collisions for stuff like single-field structures. // 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; 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_) { if (!gen_dynamic_) {
@ -2286,7 +2348,7 @@ void t_py_generator::generate_deserialize_field(ostream& out,
out << endl; out << endl;
} else if (type->is_enum()) { } else if (type->is_enum()) {
if (gen_enum_) { if (gen_enum_) {
indent(out) << name << " = " << type_name(type) << "(iprot.readI32()).name"; indent(out) << name << " = " << type_name(type) << "(iprot.readI32())";
} else { } else {
indent(out) << name << " = iprot.readI32()"; 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()) { } else if (type->is_enum()) {
if (gen_enum_){ if (gen_enum_){
out << "writeI32(" << type_name(type) << "[" << name << "].value)"; out << "writeI32(" << name << ".value)";
} else { } else {
out << "writeI32(" << name << ")"; out << "writeI32(" << name << ")";
} }
@ -2767,6 +2829,8 @@ string t_py_generator::type_to_enum(t_type* type) {
return "TType.I64"; return "TType.I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "TType.DOUBLE"; return "TType.DOUBLE";
default:
throw "compiler error: unhandled type";
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "TType.I32"; 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(); throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
} }
std::string t_py_generator::display_name() const {
return "Python";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
py, py,
"Python", "Python",

View File

@ -104,6 +104,7 @@ public:
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/** /**
* Program-level generation functions * 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() << "def " << function_signature(&recv_function) << endl;
f_service_.indent_up(); 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; 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"; return "::Thrift::Types::I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "::Thrift::Types::DOUBLE"; return "::Thrift::Types::DOUBLE";
default:
throw "compiler error: unhandled type";
} }
} else if (type->is_enum()) { } else if (type->is_enum()) {
return "::Thrift::Types::I32"; 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; out.indent() << "end" << endl << endl;
} }
std::string t_rb_generator::display_name() const {
return "Ruby";
}
THRIFT_REGISTER_GENERATOR( THRIFT_REGISTER_GENERATOR(
rb, rb,
"Ruby", "Ruby",

View File

@ -76,6 +76,7 @@ public:
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/** /**
* Program-level generation functions * Program-level generation functions
@ -127,7 +128,7 @@ private:
void render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue); 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. // 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). // Write a const struct (returned from `const_value` method).
void render_const_struct(t_type* ttype, t_const_value* tvalue); 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). // Write a const map (returned from `const_value` method).
void render_const_map(t_type* ttype, t_const_value* tvalue); 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` // 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 // 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 // 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. // user-defined exception to be properly handled as Rust errors.
void render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct); 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` // 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. // 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); 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() { void t_rs_generator::render_attributes_and_includes() {
// turn off some compiler/clippy warnings // turn off some compiler/clippy warnings
// code may not be used
f_gen_ << "#![allow(dead_code)]" << endl;
// code always includes BTreeMap/BTreeSet/OrderedFloat // code always includes BTreeMap/BTreeSet/OrderedFloat
f_gen_ << "#![allow(unused_imports)]" << endl; f_gen_ << "#![allow(unused_imports)]" << endl;
// code might not include imports from crates // code might not include imports from crates
f_gen_ << "#![allow(unused_extern_crates)]" << endl; f_gen_ << "#![allow(unused_extern_crates)]" << endl;
// constructors take *all* struct parameters, which can trigger the "too many arguments" warning // 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 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) // 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 // 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: // and it's a forward typedef. This (typedef + forward typedef) can happen in two situations:
// 1. When the type is recursive // 1. When the type is recursive
// 2. When you define types out of order // 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 // prevent rustfmt from running against this file
// lines are too long, code is (thankfully!) not visual-indented, etc. // 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 // 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; f_gen_ << indent() << "pub fn const_value() -> " << to_rust_type(ttype) << " {" << endl;
indent_up(); indent_up();
render_const_value(ttype, tvalue); render_const_value(ttype, tvalue, true, false);
indent_down(); indent_down();
f_gen_ << indent() << "}" << endl; 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; 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()) { if (ttype->is_base_type()) {
t_base_type* tbase_type = (t_base_type*)ttype; t_base_type* tbase_type = (t_base_type*)ttype;
switch (tbase_type->get_base()) { 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()); throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base());
} }
} else if (ttype->is_typedef()) { } 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()) { } else if (ttype->is_enum()) {
f_gen_ << indent() << "{" << endl; f_gen_ << "{" << endl;
indent_up(); indent_up();
f_gen_ f_gen_
<< indent() << 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\")" << ").expect(\"expecting valid const value\")"
<< endl; << endl;
indent_down(); indent_down();
f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "}";
} else if (ttype->is_struct() || ttype->is_xception()) { } else if (ttype->is_struct() || ttype->is_xception()) {
render_const_struct(ttype, tvalue); render_const_struct(ttype, tvalue);
} else if (ttype->is_container()) { } else if (ttype->is_container()) {
f_gen_ << indent() << "{" << endl; // all of them use vec! or from(), extra block is no longer needed
indent_up();
if (ttype->is_list()) { if (ttype->is_list()) {
render_const_list(ttype, tvalue); render_const_list(ttype, tvalue);
} else if (ttype->is_set()) { } 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 { } else {
throw "cannot generate const container value for " + ttype->get_name(); throw "cannot generate const container value for " + ttype->get_name();
} }
indent_down();
f_gen_ << indent() << "}" << endl;
} else { } else {
throw "cannot generate const value for " + ttype->get_name(); 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*) { void t_rs_generator::render_const_struct(t_type* ttype, t_const_value*) {
if (((t_struct*)ttype)->is_union()) { if (((t_struct*)ttype)->is_union()) {
f_gen_ << indent() << "{" << endl; f_gen_ << "{" << endl;
indent_up(); indent_up();
f_gen_ << indent() << "unimplemented!()" << endl; f_gen_ << indent() << "unimplemented!()" << endl;
indent_down(); indent_down();
f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "}";
} else { } else {
f_gen_ << indent() << "{" << endl; f_gen_ << "{" << endl;
indent_up(); indent_up();
f_gen_ << indent() << "unimplemented!()" << endl; f_gen_ << indent() << "unimplemented!()" << endl;
indent_down(); indent_down();
f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "}";
} }
} }
void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) { void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) {
t_type* elem_type = ((t_list*)ttype)->get_elem_type(); 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(); const vector<t_const_value*>& elems = tvalue->get_list();
vector<t_const_value*>::const_iterator elem_iter; vector<t_const_value*>::const_iterator elem_iter;
for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
f_gen_ << indent();
t_const_value* elem_value = (*elem_iter); 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) { void t_rs_generator::render_const_set(t_type* ttype, t_const_value* tvalue) {
t_type* elem_type = ((t_set*)ttype)->get_elem_type(); 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(); const vector<t_const_value*>& elems = tvalue->get_list();
vector<t_const_value*>::const_iterator elem_iter; vector<t_const_value*>::const_iterator elem_iter;
for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) { for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
f_gen_ << indent();
t_const_value* elem_value = (*elem_iter); 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) { 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* key_type = ((t_map*)ttype)->get_key_type();
t_type* val_type = ((t_map*)ttype)->get_val_type(); t_type* val_type = ((t_map*)ttype)->get_val_type();
f_gen_ f_gen_ << "BTreeMap::from([" << endl;
<< indent() indent_up();
<< "let mut m: BTreeMap<"
<< to_rust_type(key_type) << ", " << to_rust_type(val_type)
<< "> = BTreeMap::new();"
<< endl;
const map<t_const_value*, t_const_value*, t_const_value::value_compare>& elems = tvalue->get_map(); 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; 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) { for (elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
t_const_value* key_value = elem_iter->first; t_const_value* key_value = elem_iter->first;
t_const_value* val_value = elem_iter->second; 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( f_gen_ << indent() << "(" << endl;
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;
indent_up(); 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(); 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_type_comment(struct_name);
render_struct_definition(struct_name, tstruct, struct_type); render_struct_definition(struct_name, tstruct, struct_type);
render_struct_impl(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) { if (struct_type == t_rs_generator::T_EXCEPTION) {
render_exception_struct_error_trait_impls(struct_name, tstruct); 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 t_rs_generator::e_struct_type struct_type
) { ) {
render_rustdoc((t_doc*) tstruct); 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; f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl;
// render the members // render the members
vector<t_field*> members = tstruct->get_sorted_members();
if (!members.empty()) { if (!members.empty()) {
indent_up(); indent_up();
vector<t_field*>::iterator members_iter;
for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) { for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
t_field* member = (*members_iter); t_field* member = (*members_iter);
t_field::e_req member_req = actual_field_req(member, struct_type); 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; 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( void t_rs_generator::render_struct_impl(
const string& struct_name, const string& struct_name,
t_struct* tstruct, 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: case t_base_type::TYPE_DOUBLE:
f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl; f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl;
return; return;
default:
throw "compiler error: unhandled type";
} }
} else if (ttype->is_typedef()) { } else if (ttype->is_typedef()) {
t_typedef* ttypedef = (t_typedef*) ttype; t_typedef* ttypedef = (t_typedef*) ttype;
@ -1777,6 +1715,10 @@ void t_rs_generator::render_struct_sync_read(
f_gen_ << indent() << "}" << endl; f_gen_ << indent() << "}" << endl;
// now read all the fields found // 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() << "let field_id = field_id(&field_ident)?;" << endl;
f_gen_ << indent() << "match field_id {" << endl; // start match f_gen_ << indent() << "match field_id {" << endl; // start match
indent_up(); indent_up();
@ -1800,6 +1742,8 @@ void t_rs_generator::render_struct_sync_read(
indent_down(); indent_down();
f_gen_ << indent() << "};" << endl; // finish match f_gen_ << indent() << "};" << endl; // finish match
}
f_gen_ << indent() << "i_prot.read_field_end()?;" << endl; f_gen_ << indent() << "i_prot.read_field_end()?;" << endl;
indent_down(); indent_down();
f_gen_ << indent() << "}" << endl; // finish loop 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: case t_base_type::TYPE_DOUBLE:
f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl; f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl;
return; return;
default:
throw "compiler error: unhandled type";
} }
} else if (ttype->is_typedef()) { } else if (ttype->is_typedef()) {
// FIXME: not a fan of separate `is_boxed` parameter // 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"; return "i64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "OrderedFloat<f64>"; return "OrderedFloat<f64>";
default:
throw "compiler error: unhandled type";
} }
} else if (ttype->is_typedef()) { } else if (ttype->is_typedef()) {
t_typedef* ttypedef = (t_typedef*)ttype; 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"; return "TType::I64";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "TType::Double"; return "TType::Double";
default:
throw "compiler error: unhandled type";
} }
} else if (ttype->is_enum()) { } else if (ttype->is_enum()) {
return "TType::I32"; return "TType::I32";
@ -3182,6 +3132,8 @@ string t_rs_generator::opt_in_req_out_value(t_type* ttype) {
return "Some(0)"; return "Some(0)";
case t_base_type::TYPE_DOUBLE: case t_base_type::TYPE_DOUBLE:
return "Some(OrderedFloat::from(0.0))"; return "Some(OrderedFloat::from(0.0))";
default:
throw "compiler error: unhandled type";
} }
} else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) { } 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( THRIFT_REGISTER_GENERATOR(
rs, rs,
"Rust", "Rust",

View File

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

View File

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

View File

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

View File

@ -67,6 +67,7 @@ public:
void init_generator() override; void init_generator() override;
void close_generator() override; void close_generator() override;
std::string display_name() const override;
/** /**
* Program-level generation functions * 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()); f_xsd_.open(f_xsd_name.c_str());
string ns = program_->get_namespace("xsd"); 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::vector<std::string>> annot = program_->get_namespace_annotations("xsd");
const std::map<std::string, std::string>::const_iterator uri = annot.find("uri"); const std::map<std::string, std::vector<std::string>>::const_iterator uri = annot.find("uri");
if (uri != annot.end()) { if (uri != annot.end() && !uri->second.empty()) {
ns = uri->second; ns = uri->second.back();
} }
if (ns.size() > 0) { if (ns.size() > 0) {
ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" " 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", "") 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"; throw "type error: const \"" + name + "\" was declared as string";
} }
break; 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: case t_base_type::TYPE_BOOL:
if (value->get_type() != t_const_value::CV_INTEGER) { if (value->get_type() != t_const_value::CV_INTEGER) {
throw "type error: const \"" + name + "\" was declared as bool"; throw "type error: const \"" + name + "\" was declared as bool";

View File

@ -36,6 +36,7 @@ public:
enum t_base { enum t_base {
TYPE_VOID, TYPE_VOID,
TYPE_STRING, TYPE_STRING,
TYPE_UUID,
TYPE_BOOL, TYPE_BOOL,
TYPE_I8, TYPE_I8,
TYPE_I16, TYPE_I16,
@ -55,6 +56,8 @@ public:
bool is_bool() const override { return base_ == TYPE_BOOL; } 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; } void set_binary(bool val) { binary_ = val; }
bool is_binary() const override { return binary_ && (base_ == TYPE_STRING); } bool is_binary() const override { return binary_ && (base_ == TYPE_STRING); }
@ -69,6 +72,9 @@ public:
case TYPE_STRING: case TYPE_STRING:
return "string"; return "string";
break; break;
case TYPE_UUID:
return "uuid";
break;
case TYPE_BOOL: case TYPE_BOOL:
return "bool"; return "bool";
break; 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) { void set_double(double val) {
valType_ = CV_DOUBLE; valType_ = CV_DOUBLE;
doubleVal_ = val; doubleVal_ = val;
@ -199,6 +211,39 @@ private:
t_enum* enum_; t_enum* enum_;
t_const_value_type valType_; 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 #endif

View File

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

View File

@ -21,8 +21,8 @@
#define T_FIELD_H #define T_FIELD_H
#include <map> #include <map>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include "thrift/parse/t_doc.h" #include "thrift/parse/t_doc.h"
#include "thrift/parse/t_type.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_; } bool get_reference() const { return reference_; }

View File

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

View File

@ -331,20 +331,20 @@ public:
return namespaces_; 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; 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); auto it = namespace_annotations_.find(language);
if (namespace_annotations_.end() != it) { if (namespace_annotations_.end() != it) {
return it->second; 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; 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]; return namespace_annotations_[language];
} }
@ -400,7 +400,7 @@ private:
std::map<std::string, std::string> namespaces_; std::map<std::string, std::string> namespaces_;
// Annotations for dynamic 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 // C++ extra includes
std::vector<std::string> cpp_includes_; std::vector<std::string> cpp_includes_;

View File

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

View File

@ -44,64 +44,40 @@ public:
: t_type(program), : t_type(program),
is_xception_(false), is_xception_(false),
is_union_(false), is_union_(false),
members_validated(false), is_method_xcepts_(false),
members_with_value(0), union_validated_(false),
xcepts_validated_(false),
members_with_value_(0),
xsd_all_(false) {} xsd_all_(false) {}
t_struct(t_program* program, const std::string& name) t_struct(t_program* program, const std::string& name)
: t_type(program, name), : t_type(program, name),
is_xception_(false), is_xception_(false),
is_union_(false), is_union_(false),
members_validated(false), is_method_xcepts_(false),
members_with_value(0), union_validated_(false),
xcepts_validated_(false),
members_with_value_(0),
xsd_all_(false) {} xsd_all_(false) {}
void set_name(const std::string& name) override { void set_name(const std::string& name) override {
name_ = name; name_ = name;
validate_union_members(); union_validated_= false;
validate_members();
} }
void set_xception(bool is_xception) { is_xception_ = is_xception; } void set_xception(bool is_xception) { is_xception_ = is_xception; }
void validate_union_member(t_field* field) { void set_method_xcepts(bool is_method_xcepts) {
if (is_union_ && (!name_.empty())) { is_method_xcepts_ = is_method_xcepts;
xcepts_validated_ = false;
// 1) unions can't have required fields validate_members();
// 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_union(bool is_union) { void set_union(bool is_union) {
is_union_ = 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; } void set_xsd_all(bool xsd_all) { xsd_all_ = xsd_all; }
@ -123,7 +99,11 @@ public:
} }
members_.push_back(elem); members_.push_back(elem);
members_in_id_order_.insert(bounds.second, 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; return true;
} }
@ -154,12 +134,80 @@ public:
private: private:
members_type members_; members_type members_;
members_type members_in_id_order_; members_type members_in_id_order_;
bool is_xception_; bool is_xception_; // struct is an IDL exception
bool is_union_; bool is_union_; // struct is an IDL union
bool members_validated; bool is_method_xcepts_; // struct holds the exceptions declared at a service method
int members_with_value; bool union_validated_;
bool xcepts_validated_;
int members_with_value_;
bool xsd_all_; 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 #endif

View File

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

View File

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

View File

@ -97,6 +97,7 @@ const int struct_is_union = 1;
t_function* tfunction; t_function* tfunction;
t_field* tfield; t_field* tfield;
char* dtext; char* dtext;
char* keyword;
t_field::e_req ereq; t_field::e_req ereq;
t_annotation* tannot; t_annotation* tannot;
t_field_id tfieldid; t_field_id tfieldid;
@ -118,55 +119,58 @@ const int struct_is_union = 1;
/** /**
* Header keywords * Header keywords
*/ */
%token tok_include %token<keyword> tok_include
%token tok_namespace %token<keyword> tok_namespace
%token tok_cpp_include %token<keyword> tok_cpp_include
%token tok_cpp_type %token<keyword> tok_cpp_type
%token tok_xsd_all %token<keyword> tok_xsd_all
%token tok_xsd_optional %token<keyword> tok_xsd_optional
%token tok_xsd_nillable %token<keyword> tok_xsd_nillable
%token tok_xsd_attrs %token<keyword> tok_xsd_attrs
/** /**
* Base datatype keywords * Base datatype keywords
*/ */
%token tok_void %token<keyword> tok_void
%token tok_bool %token<keyword> tok_bool
%token tok_string %token<keyword> tok_string
%token tok_binary %token<keyword> tok_binary
%token tok_i8 %token<keyword> tok_uuid
%token tok_i16 %token<keyword> tok_byte
%token tok_i32 %token<keyword> tok_i8
%token tok_i64 %token<keyword> tok_i16
%token tok_double %token<keyword> tok_i32
%token<keyword> tok_i64
%token<keyword> tok_double
/** /**
* Complex type keywords * Complex type keywords
*/ */
%token tok_map %token<keyword> tok_map
%token tok_list %token<keyword> tok_list
%token tok_set %token<keyword> tok_set
/** /**
* Function modifiers * Function modifiers
*/ */
%token tok_oneway %token<keyword> tok_oneway
%token<keyword> tok_async
/** /**
* Thrift language keywords * Thrift language keywords
*/ */
%token tok_typedef %token<keyword> tok_typedef
%token tok_struct %token<keyword> tok_struct
%token tok_xception %token<keyword> tok_xception
%token tok_throws %token<keyword> tok_throws
%token tok_extends %token<keyword> tok_extends
%token tok_service %token<keyword> tok_service
%token tok_enum %token<keyword> tok_enum
%token tok_const %token<keyword> tok_const
%token tok_required %token<keyword> tok_required
%token tok_optional %token<keyword> tok_optional
%token tok_union %token<keyword> tok_union
%token tok_reference %token<keyword> tok_reference
/** /**
* Grammar nodes * Grammar nodes
@ -192,6 +196,7 @@ const int struct_is_union = 1;
%type<tfield> Field %type<tfield> Field
%type<tfieldid> FieldIdentifier %type<tfieldid> FieldIdentifier
%type<id> FieldName
%type<ereq> FieldRequiredness %type<ereq> FieldRequiredness
%type<ttype> FieldType %type<ttype> FieldType
%type<tconstv> FieldValue %type<tconstv> FieldValue
@ -770,6 +775,10 @@ Oneway:
{ {
$$ = true; $$ = true;
} }
| tok_async // deprecated
{
$$ = true;
}
| |
{ {
$$ = false; $$ = false;
@ -808,9 +817,9 @@ FieldList:
} }
Field: 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) { if ($2.auto_assigned) {
pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6); pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6);
if (g_strict >= 192) { 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: FieldIdentifier:
tok_int_constant ':' tok_int_constant ':'
{ {
@ -1002,11 +1176,21 @@ SimpleBaseType:
pdebug("BaseType -> tok_binary"); pdebug("BaseType -> tok_binary");
$$ = g_type_binary; $$ = g_type_binary;
} }
| tok_uuid
{
pdebug("BaseType -> tok_uuid");
$$ = g_type_uuid;
}
| tok_bool | tok_bool
{ {
pdebug("BaseType -> tok_bool"); pdebug("BaseType -> tok_bool");
$$ = g_type_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 | tok_i8
{ {
pdebug("BaseType -> tok_i8"); pdebug("BaseType -> tok_i8");
@ -1081,13 +1265,20 @@ SetType:
} }
ListType: ListType:
tok_list '<' FieldType '>' CppType tok_list CppType '<' FieldType '>' CppType // the second CppType is for compatibility reasons = deprecated
{ {
pdebug("ListType -> tok_list<FieldType>"); pdebug("ListType -> tok_list<FieldType>");
check_for_list_of_bytes($3); check_for_list_of_bytes($4);
$$ = new t_list($3); $$ = new t_list($4);
if ($5 != nullptr) { if ($2 != nullptr) {
((t_container*)$$)->set_cpp_name(std::string($5)); ((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"); pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
$$ = $1; $$ = $1;
$$->annotations_[$2->key] = $2->val; $$->annotations_[$2->key].push_back($2->val);
delete $2; delete $2;
} }
| |

View File

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

View File

@ -18,8 +18,8 @@
# #
file(GLOB KEYWORD_SAMPLES "${CMAKE_CURRENT_SOURCE_DIR}/keyword-samples/*.thrift") file(GLOB KEYWORD_SAMPLES "${CMAKE_CURRENT_SOURCE_DIR}/keyword-samples/*.thrift")
set(KEYWORD_LANGS ${thrift_compiler_LANGS}) 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 LIST(REMOVE_ITEM KEYWORD_LANGS swift) # in Swift you can escape reserved words (and in other languages as well)
foreach(LANG ${KEYWORD_LANGS}) foreach(LANG ${KEYWORD_LANGS})
foreach(SAMPLE ${KEYWORD_SAMPLES}) foreach(SAMPLE ${KEYWORD_SAMPLES})
get_filename_component(FILENAME ${SAMPLE} NAME_WE) 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" const string foo = "bar"
struct a_struct { 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" include "Included.thrift"
const string s = "string" 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" 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 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 { 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 { enum enum_name {
return 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 {} 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 { exception exception_name {
1: required i8 return 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 {} 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 { service service_name {
bool function_name(1: i32 return) 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 { service service_name {
void return() 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 {} exception exception_name {}
service service_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 {} 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 { struct struct_name {
1: required bool return = 1 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 typedef bool return

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