mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-10-29 02:17:29 +08:00
Compare commits
No commits in common. "develop" and "Test_Release" have entirely different histories.
develop
...
Test_Relea
@ -1,43 +0,0 @@
|
|||||||
# clang-format: 19
|
|
||||||
AccessModifierOffset: -2
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignConsecutiveBitFields: false
|
|
||||||
AllowShortBlocksOnASingleLine: Always
|
|
||||||
AllowShortCaseLabelsOnASingleLine: true
|
|
||||||
AllowShortEnumsOnASingleLine: true
|
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
|
||||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
AllowShortLoopsOnASingleLine: true
|
|
||||||
AlwaysBreakTemplateDeclarations: true
|
|
||||||
BasedOnStyle: WebKit
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
ColumnLimit: 0
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
FixNamespaceComments: true
|
|
||||||
IfMacros: ['SECTION']
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IndentCaseLabels: true
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentWidth: 2
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
|
||||||
NamespaceIndentation: All
|
|
||||||
PackConstructorInitializers: CurrentLine
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 200
|
|
||||||
PenaltyBreakComment: 5
|
|
||||||
PenaltyBreakFirstLessLess: 50
|
|
||||||
PenaltyExcessCharacter: 4
|
|
||||||
PointerAlignment: Right
|
|
||||||
SortIncludes: true
|
|
||||||
SpaceAfterTemplateKeyword: false
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeParens: Custom
|
|
||||||
SpaceBeforeParensOptions:
|
|
||||||
AfterControlStatements: true
|
|
||||||
AfterIfMacros: false
|
|
||||||
SpaceInEmptyBlock: false
|
|
||||||
Standard: Latest
|
|
||||||
TabWidth: 2
|
|
||||||
UseTab: Never
|
|
||||||
@ -1,53 +1,30 @@
|
|||||||
compilers:
|
compilers:
|
||||||
- name: "clang"
|
- name: "clang"
|
||||||
version: "3.6"
|
version: "3.5"
|
||||||
skip_packaging: true
|
skip_packaging: true
|
||||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||||
collect_performance_results: true
|
|
||||||
- name: "clang"
|
- name: "clang"
|
||||||
build_tag: "LibC++"
|
build_tag: "LibC++"
|
||||||
version: "3.6"
|
version: "3.5"
|
||||||
skip_packaging: true
|
skip_packaging: true
|
||||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||||
- name: "clang"
|
- name: "clang"
|
||||||
build_tag: AddressSanitizer
|
build_tag: AddressSanitizer
|
||||||
version: "3.6"
|
version: "3.6"
|
||||||
skip_packaging: true
|
skip_packaging: true
|
||||||
cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
|
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
|
||||||
- name: "clang"
|
- name: "clang"
|
||||||
build_tag: ThreadSanitizer
|
build_tag: ThreadSanitizer
|
||||||
version: "3.6"
|
version: "3.6"
|
||||||
skip_packaging: true
|
skip_packaging: true
|
||||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
|
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
|
||||||
- name: "clang"
|
|
||||||
version: "3.7"
|
|
||||||
skip_packaging: true
|
|
||||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
|
||||||
collect_performance_results: true
|
|
||||||
- name: "clang"
|
|
||||||
build_tag: "LibC++"
|
|
||||||
version: "3.7"
|
|
||||||
skip_packaging: true
|
|
||||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
|
||||||
- name: "gcc"
|
- name: "gcc"
|
||||||
version: "4.9"
|
version: "4.8"
|
||||||
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||||
collect_performance_results: true
|
|
||||||
- name: "gcc"
|
- name: "gcc"
|
||||||
version: "4.9"
|
version: "4.6"
|
||||||
skip_packaging: true
|
skip_packaging: true
|
||||||
build_tag: "NoThreads"
|
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||||
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON -DMULTITHREAD_SUPPORT_ENABLED:BOOL=OFF
|
|
||||||
collect_performance_results: true
|
|
||||||
- name: "gcc"
|
|
||||||
version: "5"
|
|
||||||
skip_packaging: true
|
|
||||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
|
||||||
collect_performance_results: true
|
|
||||||
- name: cppcheck
|
- name: cppcheck
|
||||||
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*"
|
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:cmake*" --suppress="*:unittests/catch.hpp" --force
|
||||||
- name: custom_check
|
|
||||||
commands:
|
|
||||||
- ./contrib/check_for_tabs.rb
|
|
||||||
- ./contrib/check_for_todos.rb
|
|
||||||
|
|
||||||
|
|||||||
@ -2,4 +2,8 @@ compilers:
|
|||||||
- name: clang
|
- name: clang
|
||||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
|
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
|
||||||
build_package_generator: TBZ2
|
build_package_generator: TBZ2
|
||||||
|
- name: clang
|
||||||
|
build_type: Debug
|
||||||
|
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
|
||||||
|
skip_packaging: true
|
||||||
|
|
||||||
|
|||||||
@ -11,11 +11,10 @@ compilers:
|
|||||||
compiler_extra_flags: /analyze
|
compiler_extra_flags: /analyze
|
||||||
skip_packaging: true
|
skip_packaging: true
|
||||||
- name: Visual Studio
|
- name: Visual Studio
|
||||||
version: 14
|
version: 12
|
||||||
build_type: Debug
|
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
|
||||||
|
- name: Visual Studio
|
||||||
|
version: 12
|
||||||
architecture: Win64
|
architecture: Win64
|
||||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
|
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
|
||||||
compiler_extra_flags: /analyze
|
|
||||||
skip_packaging: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
41
.github/CONTRIBUTING.md
vendored
41
.github/CONTRIBUTING.md
vendored
@ -1,41 +0,0 @@
|
|||||||
# Contributing to ChaiScript
|
|
||||||
|
|
||||||
Thank you for contributing!
|
|
||||||
|
|
||||||
# Pull Requests
|
|
||||||
|
|
||||||
Please follow the existing style in the code you are patching.
|
|
||||||
|
|
||||||
- two space indent
|
|
||||||
- no tabs EVER
|
|
||||||
- match the existing indentation level
|
|
||||||
|
|
||||||
All ChaiScript commits are run through a large set of builds and analysis on all supported platforms. Those results are posted on the
|
|
||||||
[build dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html). No PR will be accepted until all tests pass.
|
|
||||||
|
|
||||||
The build system has full integration with GitHub and you will be notified automatically if all tests have passed.
|
|
||||||
|
|
||||||
# Issues
|
|
||||||
|
|
||||||
Please do not post a "chaiscript is too slow", "chaiscript compiles too slowly", or "chaiscript needs more documentation" issue
|
|
||||||
without first reading the following notes.
|
|
||||||
|
|
||||||
## ChaiScript is Too Slow
|
|
||||||
|
|
||||||
We are actively working on constently improving the runtime performance of ChaiScript. With the performance being
|
|
||||||
[monitored with each commit](http://chaiscript.com/ChaiScript-BuildResults/performance.html).
|
|
||||||
|
|
||||||
If you feel you *must* post an issue about performance, please post a complete example that illustrates the exact case you
|
|
||||||
feel should be better optimized.
|
|
||||||
|
|
||||||
Any issue request regarding performance without a complete example of the issue experienced will be closed.
|
|
||||||
|
|
||||||
## ChaiScript Compiles Too Slowly
|
|
||||||
|
|
||||||
This is also something we are actively working on. If you need highly optimized build times, please see [this discussion
|
|
||||||
on the discourse site](http://discourse.chaiscript.com/t/slow-build-times/94).
|
|
||||||
|
|
||||||
## ChaiScript Needs More Documentation
|
|
||||||
|
|
||||||
If you have a question that is not addressed in the [cheatsheet](https://github.com/ChaiScript/ChaiScript/blob/develop/cheatsheet.md)
|
|
||||||
please open an issue so we can get the Cheatsheet updated.
|
|
||||||
10
.github/ISSUE_TEMPLATE.md
vendored
10
.github/ISSUE_TEMPLATE.md
vendored
@ -1,10 +0,0 @@
|
|||||||
* Compiler Used:
|
|
||||||
* Operating System:
|
|
||||||
* Architecture (ARM/x86/32bit/64bit/etc):
|
|
||||||
|
|
||||||
|
|
||||||
### Expected Behavior
|
|
||||||
|
|
||||||
### Actual Behavior
|
|
||||||
|
|
||||||
### Minimal Example to Reproduce Behavior
|
|
||||||
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,8 +0,0 @@
|
|||||||
Issue this pull request references: #
|
|
||||||
|
|
||||||
Changes proposed in this pull request
|
|
||||||
|
|
||||||
-
|
|
||||||
-
|
|
||||||
-
|
|
||||||
|
|
||||||
27
.github/workflows/auto-clang-format.yml
vendored
27
.github/workflows/auto-clang-format.yml
vendored
@ -1,27 +0,0 @@
|
|||||||
name: auto-clang-format
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- develop
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- uses: DoozyX/clang-format-lint-action@v0.20
|
|
||||||
with:
|
|
||||||
source: '.'
|
|
||||||
exclude: './third_party ./external ./unittests/catch.hpp'
|
|
||||||
extensions: 'h,cpp,hpp'
|
|
||||||
clangFormatVersion: 19
|
|
||||||
inplace: True
|
|
||||||
- uses: EndBug/add-and-commit@v9
|
|
||||||
with:
|
|
||||||
author_name: Clang Robot
|
|
||||||
author_email: robot@example.com
|
|
||||||
message: ':art: Committing clang-format changes'
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
163
.github/workflows/ci.yml
vendored
163
.github/workflows/ci.yml
vendored
@ -1,163 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [develop, main]
|
|
||||||
pull_request:
|
|
||||||
branches: [develop, main]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
linux:
|
|
||||||
name: Linux GCC ${{ matrix.build_type }} threads=${{ matrix.multithread }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
build_type: [Debug, Release]
|
|
||||||
multithread: [ON, OFF]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Ninja
|
|
||||||
run: sudo apt-get install -y ninja-build
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DMULTITHREAD_SUPPORT_ENABLED=${{ matrix.multithread }}
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ctest --test-dir build --output-on-failure
|
|
||||||
|
|
||||||
macos:
|
|
||||||
name: macOS AppleClang ${{ matrix.build_type }} threads=${{ matrix.multithread }}
|
|
||||||
runs-on: macos-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
build_type: [Debug, Release]
|
|
||||||
multithread: [ON, OFF]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Ninja
|
|
||||||
run: brew install ninja
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DMULTITHREAD_SUPPORT_ENABLED=${{ matrix.multithread }}
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ctest --test-dir build --output-on-failure
|
|
||||||
|
|
||||||
linux-sanitizers:
|
|
||||||
name: Linux GCC ASAN+UBSAN ${{ matrix.build_type }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
build_type: [Debug, Release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Ninja
|
|
||||||
run: sudo apt-get install -y ninja-build
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_SANITIZER=ON
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ctest --test-dir build --output-on-failure
|
|
||||||
|
|
||||||
macos-sanitizers:
|
|
||||||
name: macOS AppleClang ASAN+UBSAN ${{ matrix.build_type }}
|
|
||||||
runs-on: macos-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
build_type: [Debug, Release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Ninja
|
|
||||||
run: brew install ninja
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_ADDRESS_SANITIZER=ON -DENABLE_UNDEFINED_SANITIZER=ON
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ctest --test-dir build --output-on-failure
|
|
||||||
|
|
||||||
windows:
|
|
||||||
name: Windows MSVC ${{ matrix.build_type }} threads=${{ matrix.multithread }}
|
|
||||||
runs-on: windows-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
build_type: [Debug, Release]
|
|
||||||
multithread: [ON, OFF]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: cmake -B build -DMULTITHREAD_SUPPORT_ENABLED=${{ matrix.multithread }}
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build --config ${{ matrix.build_type }} -j
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ctest --test-dir build --output-on-failure -C ${{ matrix.build_type }}
|
|
||||||
|
|
||||||
linux-tsan:
|
|
||||||
name: Linux GCC TSAN ${{ matrix.build_type }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
build_type: [Debug, Release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Ninja
|
|
||||||
run: sudo apt-get install -y ninja-build
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_THREAD_SANITIZER=ON -DMULTITHREAD_SUPPORT_ENABLED=ON
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ctest --test-dir build --output-on-failure
|
|
||||||
|
|
||||||
macos-tsan:
|
|
||||||
name: macOS AppleClang TSAN ${{ matrix.build_type }}
|
|
||||||
runs-on: macos-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
build_type: [Debug, Release]
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Ninja
|
|
||||||
run: brew install ninja
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DENABLE_THREAD_SANITIZER=ON -DMULTITHREAD_SUPPORT_ENABLED=ON
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: ctest --test-dir build --output-on-failure
|
|
||||||
71
.github/workflows/emscripten.yml
vendored
71
.github/workflows/emscripten.yml
vendored
@ -1,71 +0,0 @@
|
|||||||
name: Emscripten
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [develop, main]
|
|
||||||
pull_request:
|
|
||||||
branches: [develop, main]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
emscripten:
|
|
||||||
name: Emscripten WebAssembly Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Emscripten
|
|
||||||
uses: mymindstorm/setup-emsdk@v14
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: emcmake cmake -B build-em -S emscripten -DCMAKE_BUILD_TYPE=Release
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cmake --build build-em -j
|
|
||||||
|
|
||||||
- name: Verify artifacts
|
|
||||||
run: |
|
|
||||||
test -f build-em/chaiscript.js
|
|
||||||
test -f build-em/chaiscript.wasm
|
|
||||||
test -f build-em/chaiscript.html
|
|
||||||
echo "All expected artifacts present"
|
|
||||||
ls -lh build-em/chaiscript.*
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: chaiscript-web
|
|
||||||
path: |
|
|
||||||
build-em/chaiscript.js
|
|
||||||
build-em/chaiscript.wasm
|
|
||||||
build-em/chaiscript.html
|
|
||||||
retention-days: 90
|
|
||||||
|
|
||||||
publish:
|
|
||||||
name: Publish WASM Release
|
|
||||||
needs: emscripten
|
|
||||||
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: chaiscript-web
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
- name: Publish to wasm-latest release
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
# Flatten: artifacts may contain build-em/ subdirectory
|
|
||||||
find artifacts -type f \( -name 'chaiscript.js' -o -name 'chaiscript.wasm' -o -name 'chaiscript.html' \) -exec cp {} . \;
|
|
||||||
|
|
||||||
# Delete existing release if present, then recreate
|
|
||||||
gh release delete wasm-latest --repo "$GITHUB_REPOSITORY" -y 2>/dev/null || true
|
|
||||||
gh release create wasm-latest \
|
|
||||||
--repo "$GITHUB_REPOSITORY" \
|
|
||||||
--title "ChaiScript WASM Build (latest)" \
|
|
||||||
--notes "Auto-published from develop branch. Built with Emscripten for browser use." \
|
|
||||||
--prerelease \
|
|
||||||
chaiscript.js chaiscript.wasm chaiscript.html
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +0,0 @@
|
|||||||
/buck-out/
|
|
||||||
/.buckd/
|
|
||||||
/buckaroo/
|
|
||||||
.buckconfig.local
|
|
||||||
BUCKAROO_DEPS
|
|
||||||
/build
|
|
||||||
88
.travis.yml
88
.travis.yml
@ -1,71 +1,33 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
|
compiler:
|
||||||
|
- gcc
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
- llvm-toolchain-trusty-5.0
|
|
||||||
- sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main'
|
|
||||||
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
|
||||||
packages:
|
|
||||||
- g++-7
|
|
||||||
- g++-8
|
|
||||||
coverity_scan:
|
|
||||||
project:
|
|
||||||
name: "ChaiScript/ChaiScript"
|
|
||||||
description: "Build submitted via Travis CI"
|
|
||||||
notification_email: jason@emptycrate.com
|
|
||||||
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
|
|
||||||
build_command: "cmake --build . -- -j2"
|
|
||||||
branch_pattern: coverity_scan
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: linux
|
|
||||||
sudo: false
|
|
||||||
env: GCC_VER="7"
|
|
||||||
compiler: gcc
|
|
||||||
# - os: linux
|
|
||||||
#sudo: false
|
|
||||||
#env: GCC_VER="6" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
|
||||||
#compiler: gcc
|
|
||||||
- os: linux
|
|
||||||
sudo: false
|
|
||||||
env: GCC_VER="7" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
|
||||||
compiler: gcc
|
|
||||||
- os: linux
|
|
||||||
sudo: false
|
|
||||||
env: GCC_VER="8" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
|
||||||
compiler: gcc
|
|
||||||
#- os: osx
|
|
||||||
# compiler: clang
|
|
||||||
# osx_image: xcode10
|
|
||||||
# env: CLANG_VER="5.0"
|
|
||||||
#- os: osx
|
|
||||||
# compiler: clang
|
|
||||||
# osx_image: xcode10
|
|
||||||
# env: CLANG_VER="5.0" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
matrix:
|
||||||
|
- GCC_VER="4.6"
|
||||||
|
- GCC_VER="4.8"
|
||||||
|
|
||||||
global:
|
global:
|
||||||
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||||
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
|
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
|
- export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER"
|
||||||
#- if [ "${CLANG_VER}" != "" ]; then export CXX="clang++-$CLANG_VER"; fi
|
- if [ "$GCC_VER" = "4.8" ]; then export COVERAGE=1 CPPCHECK=1; fi
|
||||||
- pip install --user cpp-coveralls
|
- if [ ${COVERAGE} = 1 ]; then export FUZZY_CMD="-D RUN_FUZZY_TESTS:BOOL=TRUE"; fi
|
||||||
|
- sudo pip install cpp-coveralls
|
||||||
|
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install -qq g++-$GCC_VER
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
|
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $FUZZY_CMD . ; fi
|
||||||
- cmake --build . -- -j2
|
- if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j2 ; fi
|
||||||
- if [ "${BUILD_ONLY}" != "1" ]; then ctest; fi
|
- make test
|
||||||
- if [ "${COVERAGE}" = "1" ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
|
- if [ ${COVERAGE} = 1 ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
|
||||||
|
|
||||||
#after_script:
|
after_script:
|
||||||
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
|
- if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
|
||||||
|
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
@ -80,3 +42,15 @@ notifications:
|
|||||||
on_success: change # options: [always|never|change] default: always
|
on_success: change # options: [always|never|change] default: always
|
||||||
on_failure: always # options: [always|never|change] default: always
|
on_failure: always # options: [always|never|change] default: always
|
||||||
on_start: false # default: false
|
on_start: false # default: false
|
||||||
|
|
||||||
|
addons:
|
||||||
|
coverity_scan:
|
||||||
|
project:
|
||||||
|
name: "ChaiScript/ChaiScript"
|
||||||
|
description: "Build submitted via Travis CI"
|
||||||
|
notification_email: jason@emptycrate.com
|
||||||
|
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
|
||||||
|
build_command: "cmake --build . -- -j2"
|
||||||
|
branch_pattern: coverity_scan
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
11
BUCK
11
BUCK
@ -1,11 +0,0 @@
|
|||||||
prebuilt_cxx_library(
|
|
||||||
name = 'chaiscript',
|
|
||||||
header_only = True,
|
|
||||||
header_namespace = 'chaiscript',
|
|
||||||
exported_headers = subdir_glob([
|
|
||||||
('include/chaiscript', '**/*.hpp'),
|
|
||||||
]),
|
|
||||||
visibility = [
|
|
||||||
'PUBLIC',
|
|
||||||
],
|
|
||||||
)
|
|
||||||
285
CMakeLists.txt
285
CMakeLists.txt
@ -1,23 +1,25 @@
|
|||||||
cmake_minimum_required(VERSION 3.12)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
|
||||||
cmake_policy(SET CMP0054 NEW)
|
cmake_policy(SET CMP0054 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
IF(BIICODE)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
INIT_BIICODE_BLOCK()
|
||||||
|
ADD_BIICODE_TARGETS()
|
||||||
|
ELSE()
|
||||||
|
# Your regular CMakeLists configuration here
|
||||||
|
|
||||||
# required since cmake 3.4 at least for libc++
|
|
||||||
set(CMAKE_ENABLE_EXPORTS ON)
|
|
||||||
|
|
||||||
project(chaiscript)
|
project(chaiscript)
|
||||||
|
|
||||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||||
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
|
|
||||||
|
|
||||||
|
|
||||||
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
||||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||||
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
|
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
|
||||||
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
|
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
|
||||||
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
|
|
||||||
|
|
||||||
mark_as_advanced(USE_STD_MAKE_SHARED)
|
mark_as_advanced(USE_STD_MAKE_SHARED)
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
option(ENABLE_THREAD_SANITIZER "Enable thread sanitizer testing in gcc/clang" FALSE)
|
option(ENABLE_THREAD_SANITIZER "Enable thread sanitizer testing in gcc/clang" FALSE)
|
||||||
if(ENABLE_THREAD_SANITIZER)
|
if(ENABLE_THREAD_SANITIZER)
|
||||||
add_definitions(-fsanitize=thread -g)
|
add_definitions(-fsanitize=thread -g)
|
||||||
@ -45,14 +47,12 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${
|
|||||||
if(ENABLE_ADDRESS_SANITIZER)
|
if(ENABLE_ADDRESS_SANITIZER)
|
||||||
add_definitions(-fsanitize=address -g)
|
add_definitions(-fsanitize=address -g)
|
||||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
|
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
|
||||||
|
|
||||||
option(BUILD_LIBFUZZ_TESTER "Build libfuzzer tool" FALSE)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
|
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
|
||||||
if(ENABLE_MEMORY_SANITIZER)
|
if(ENABLE_MEMORY_SANITIZER)
|
||||||
add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g)
|
add_definitions(-fsanitize=memory -g)
|
||||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ")
|
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
|
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
|
||||||
@ -62,9 +62,10 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
|
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
|
||||||
|
|
||||||
if (ENABLE_LTO)
|
if (ENABLE_LTO)
|
||||||
check_ipo_supported()
|
add_definitions(-flto)
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(GPROF_OUTPUT "Generate profile data" FALSE)
|
option(GPROF_OUTPUT "Generate profile data" FALSE)
|
||||||
@ -87,16 +88,6 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
elseif(MSVC)
|
|
||||||
option(ENABLE_ADDRESS_SANITIZER "Enable address sanitizer testing in MSVC" FALSE)
|
|
||||||
if(ENABLE_ADDRESS_SANITIZER)
|
|
||||||
add_compile_options(/fsanitize=address)
|
|
||||||
# ASAN is incompatible with /RTC (runtime error checks) and incremental linking
|
|
||||||
string(REGEX REPLACE "/RTC[^ ]*" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
|
||||||
string(REGEX REPLACE "/RTC[^ ]*" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
|
||||||
add_link_options(/INCREMENTAL:NO)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
|
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
@ -109,9 +100,9 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
|
|||||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
|
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
||||||
|
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR 7)
|
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR 0)
|
set(CPACK_PACKAGE_VERSION_MINOR 7)
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
set(CPACK_PACKAGE_VERSION_PATCH 2)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||||
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
set(CPACK_PACKAGE_VENDOR "ChaiScript.com")
|
||||||
@ -130,14 +121,17 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
|
|||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(CPack)
|
include(CPack)
|
||||||
include(cmake/Catch.cmake)
|
|
||||||
|
include(cmake/CheckCXX11Features.cmake)
|
||||||
|
|
||||||
if(NOT MINGW)
|
if(NOT MINGW)
|
||||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(HAS_CXX11_VARIADIC_TEMPLATES)
|
||||||
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
|
message(STATUS "Variadic Template support detected")
|
||||||
|
else()
|
||||||
|
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
@ -154,18 +148,27 @@ else()
|
|||||||
set(READLINE_FLAG)
|
set(READLINE_FLAG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
add_definitions(/WX /W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||||
|
|
||||||
if(MSVC_VERSION STREQUAL "1800")
|
if(GCC_VERSION VERSION_LESS 4.8)
|
||||||
# VS2013 doesn't have magic statics
|
set(CPP11_FLAG "-std=c++0x")
|
||||||
add_definitions(/w44640)
|
|
||||||
else()
|
else()
|
||||||
# enum warnings are too noisy on MSVC2013
|
set(CPP11_FLAG "-std=c++11")
|
||||||
add_definitions(/w34062)
|
endif()
|
||||||
|
else()
|
||||||
|
set(CPP11_FLAG "-std=c++11")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(/bigobj /permissive- /utf-8)
|
if(MSVC)
|
||||||
|
add_definitions(/W4)
|
||||||
|
|
||||||
|
# VS2013 doesn't have magic statics
|
||||||
|
if (MSVC_VERSION STREQUAL "1800")
|
||||||
|
add_definitions(/w44640)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_definitions(/bigobj)
|
||||||
# Note on MSVC compiler flags.
|
# Note on MSVC compiler flags.
|
||||||
# The code base selective disables warnings as necessary when the compiler is complaining too much
|
# The code base selective disables warnings as necessary when the compiler is complaining too much
|
||||||
# about something that is perfectly valid, or there is simply no technical way around it
|
# about something that is perfectly valid, or there is simply no technical way around it
|
||||||
@ -175,10 +178,10 @@ if(MSVC)
|
|||||||
# how to workaround or fix the error. So I'm disabling it globally.
|
# how to workaround or fix the error. So I'm disabling it globally.
|
||||||
add_definitions(/wd4503)
|
add_definitions(/wd4503)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Werror -Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic -Werror=return-type)
|
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
|
||||||
|
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef -Wno-double-promotion -Wno-switch-default -Wno-nrvo -Wno-shadow-uncaptured-local -Wno-unsafe-buffer-usage-in-libc-call -Wno-c++20-extensions -Wno-unknown-warning-option -Wno-poison-system-directories -Wno-c++20-compat -Wno-c++17-compat)
|
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Wnoexcept)
|
add_definitions(-Wnoexcept)
|
||||||
endif()
|
endif()
|
||||||
@ -189,12 +192,16 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
option(USE_LIBCXX "Use clang's libcxx" FALSE)
|
option(USE_LIBCXX "Use clang's libcxx" TRUE)
|
||||||
|
|
||||||
if(USE_LIBCXX)
|
if(USE_LIBCXX)
|
||||||
add_definitions(-stdlib=libc++)
|
add_definitions(-stdlib=libc++)
|
||||||
set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++")
|
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++")
|
||||||
|
else()
|
||||||
|
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
|
||||||
endif()
|
endif()
|
||||||
|
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# limitations in MinGW require us to make an optimized build
|
# limitations in MinGW require us to make an optimized build
|
||||||
@ -206,7 +213,7 @@ endif()
|
|||||||
include_directories(include)
|
include_directories(include)
|
||||||
|
|
||||||
|
|
||||||
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp)
|
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
|
||||||
|
|
||||||
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
|
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|
||||||
@ -214,16 +221,10 @@ if(NOT MULTITHREAD_SUPPORT_ENABLED)
|
|||||||
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT DYNLOAD_ENABLED)
|
|
||||||
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_HOST_UNIX)
|
if(CMAKE_HOST_UNIX)
|
||||||
if(DYNLOAD_ENABLED)
|
|
||||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
|
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
|
||||||
list(APPEND LIBS "dl")
|
list(APPEND LIBS "dl")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MULTITHREAD_SUPPORT_ENABLED)
|
if(MULTITHREAD_SUPPORT_ENABLED)
|
||||||
if(CMAKE_COMPILER_IS_GNUCC)
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
@ -248,80 +249,70 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
|||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||||
|
|
||||||
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
|
|
||||||
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
|
|
||||||
|
|
||||||
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp)
|
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib.cpp)
|
||||||
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
|
||||||
set(CHAISCRIPT_LIBS stdlib parser)
|
|
||||||
|
|
||||||
add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||||
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(chai ${LIBS})
|
||||||
|
add_dependencies(chai chaiscript_stdlib-${CHAI_VERSION})
|
||||||
add_library(chaiscript INTERFACE)
|
|
||||||
target_include_directories(chaiscript INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
||||||
|
|
||||||
if(BUILD_SAMPLES)
|
if(BUILD_SAMPLES)
|
||||||
add_executable(sanity_checks src/sanity_checks.cpp)
|
add_executable(example samples/example.cpp)
|
||||||
target_link_libraries(sanity_checks ${LIBS})
|
target_link_libraries(example ${LIBS})
|
||||||
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
||||||
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(test_num_exceptions ${LIBS})
|
||||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||||
target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(memory_leak_test ${LIBS})
|
||||||
add_executable(inheritance samples/inheritance.cpp)
|
add_executable(inheritance samples/inheritance.cpp)
|
||||||
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(inheritance ${LIBS})
|
||||||
add_executable(factory samples/factory.cpp)
|
|
||||||
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS})
|
|
||||||
add_executable(fun_call_performance samples/fun_call_performance.cpp)
|
add_executable(fun_call_performance samples/fun_call_performance.cpp)
|
||||||
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(fun_call_performance ${LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if(BUILD_MODULES)
|
if(BUILD_MODULES)
|
||||||
add_library(test_module MODULE src/test_module.cpp)
|
|
||||||
target_link_libraries(test_module ${LIBS})
|
|
||||||
|
|
||||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||||
target_link_libraries(stl_extra ${LIBS})
|
target_link_libraries(stl_extra ${LIBS})
|
||||||
|
|
||||||
set(MODULES stl_extra)
|
set(MODULES stl_extra)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
|
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
|
||||||
list(SORT UNIT_TESTS)
|
list(SORT UNIT_TESTS)
|
||||||
|
|
||||||
if(NOT MULTITHREAD_SUPPORT_ENABLED)
|
|
||||||
list(REMOVE_ITEM UNIT_TESTS
|
|
||||||
async_engine_lifetime.chai
|
|
||||||
async_return_value.chai
|
|
||||||
future.chai
|
|
||||||
list_push_front.chai
|
|
||||||
move_async.chai
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
|
|
||||||
list(SORT PERFORMANCE_TESTS)
|
|
||||||
|
|
||||||
|
|
||||||
if (RUN_FUZZY_TESTS)
|
if (RUN_FUZZY_TESTS)
|
||||||
|
|
||||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2017-07-20.tar.bz2
|
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2015-07-16.tar.bz2
|
||||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
file(GLOB FUZZY_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/MINIMIZED/*)
|
file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*)
|
||||||
list(SORT FUZZY_TESTS)
|
list(SORT FUZZY_CRASH_TESTS)
|
||||||
|
|
||||||
foreach(filename ${FUZZY_TESTS})
|
file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*)
|
||||||
|
list(SORT FUZZY_EXCEPTION_TESTS)
|
||||||
|
|
||||||
|
|
||||||
|
foreach(filename ${FUZZY_CRASH_TESTS})
|
||||||
message(STATUS "Adding test ${filename}")
|
message(STATUS "Adding test ${filename}")
|
||||||
add_test(fuzz.${filename} chai "-e" "--exception" "--any-exception" ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzz_unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
add_test(${filename} chai "-e" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set_property(TEST ${FUZZY_CRASH_TESTS}
|
||||||
|
PROPERTY ENVIRONMENT
|
||||||
|
"CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/"
|
||||||
|
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(filename ${FUZZY_EXCEPTION_TESTS})
|
||||||
|
message(STATUS "Adding test ${filename}")
|
||||||
|
add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
|
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
|
||||||
@ -335,6 +326,37 @@ endif()
|
|||||||
|
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
|
|
||||||
|
# Add catch tests macro
|
||||||
|
macro(ADD_CATCH_TESTS executable)
|
||||||
|
if (MSVC)
|
||||||
|
file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH)
|
||||||
|
set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}")
|
||||||
|
else()
|
||||||
|
set(NEWPATH $ENV{PATH})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_target_property(target_files ${executable} SOURCES)
|
||||||
|
|
||||||
|
foreach(source ${target_files})
|
||||||
|
if(NOT "${source}" MATCHES "/moc_.*cxx")
|
||||||
|
string(REGEX MATCH .*cpp source "${source}")
|
||||||
|
if(source)
|
||||||
|
file(READ "${source}" contents)
|
||||||
|
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
|
||||||
|
foreach(hit ${found_tests})
|
||||||
|
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
|
||||||
|
add_test(${test_name} "${executable}" ${test_name})
|
||||||
|
set_tests_properties(${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
||||||
|
|
||||||
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
|
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
|
||||||
@ -358,68 +380,37 @@ if(BUILD_TESTING)
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
set(TESTS "")
|
|
||||||
|
|
||||||
foreach(filename ${UNIT_TESTS})
|
foreach(filename ${UNIT_TESTS})
|
||||||
message(STATUS "Adding unit test ${filename}")
|
message(STATUS "Adding test ${filename}")
|
||||||
add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
|
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
|
||||||
list(APPEND TESTS unit.${filename})
|
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(RUN_PERFORMANCE_TESTS)
|
set_property(TEST ${UNIT_TESTS}
|
||||||
foreach(filename ${PERFORMANCE_TESTS})
|
|
||||||
message(STATUS "Adding performance test ${filename}")
|
|
||||||
|
|
||||||
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
|
|
||||||
list(APPEND TESTS performance.${filename})
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
|
|
||||||
target_link_libraries(profile_cpp_calls_2 ${LIBS})
|
|
||||||
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
|
|
||||||
|
|
||||||
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
|
|
||||||
target_link_libraries(profile_fun_wrappers ${LIBS})
|
|
||||||
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_property(TEST ${TESTS}
|
|
||||||
PROPERTY ENVIRONMENT
|
PROPERTY ENVIRONMENT
|
||||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT UNIT_TEST_LIGHT)
|
if(NOT UNIT_TEST_LIGHT)
|
||||||
add_library(catch2 STATIC unittests/catch_amalgamated.cpp)
|
|
||||||
if(NOT MSVC)
|
|
||||||
target_compile_options(catch2 PRIVATE -Wno-conversion -Wno-noexcept -Wno-maybe-uninitialized)
|
|
||||||
endif()
|
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
|
||||||
target_compile_options(catch2 PUBLIC -Wno-unknown-warning-option -Wno-covered-switch-default -Wno-disabled-macro-expansion -Wno-unsafe-buffer-usage -Wno-unused-macros)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable(compiled_tests unittests/compiled_tests.cpp)
|
add_executable(compiled_tests unittests/compiled_tests.cpp)
|
||||||
target_link_libraries(compiled_tests catch2 ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(compiled_tests ${LIBS})
|
||||||
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.")
|
ADD_CATCH_TESTS(compiled_tests)
|
||||||
|
|
||||||
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
|
|
||||||
target_link_libraries(static_chaiscript_test ${LIBS})
|
|
||||||
add_test(NAME Static_ChaiScript_Test COMMAND static_chaiscript_test)
|
|
||||||
|
|
||||||
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
|
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
|
||||||
target_link_libraries(boxed_cast_test ${LIBS})
|
target_link_libraries(boxed_cast_test ${LIBS})
|
||||||
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
|
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
|
||||||
|
|
||||||
add_executable(type_info_test unittests/type_info_test.cpp)
|
add_executable(type_info_test unittests/type_info_test.cpp)
|
||||||
target_link_libraries(type_info_test catch2 ${LIBS})
|
target_link_libraries(type_info_test ${LIBS})
|
||||||
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
||||||
|
|
||||||
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
||||||
target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(c_linkage_test ${LIBS})
|
||||||
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
|
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
|
||||||
|
|
||||||
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
|
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
|
||||||
target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS})
|
target_link_libraries(integer_literal_test ${LIBS})
|
||||||
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
|
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
|
||||||
|
|
||||||
if(MULTITHREAD_SUPPORT_ENABLED)
|
if(MULTITHREAD_SUPPORT_ENABLED)
|
||||||
@ -431,11 +422,10 @@ if(BUILD_TESTING)
|
|||||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||||
)
|
)
|
||||||
add_executable(async_engine_lifetime_test unittests/async_engine_lifetime_test.cpp)
|
|
||||||
target_link_libraries(async_engine_lifetime_test ${LIBS})
|
|
||||||
add_test(NAME Async_Engine_Lifetime_Test COMMAND async_engine_lifetime_test)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
add_executable(multifile_test
|
add_executable(multifile_test
|
||||||
unittests/multifile_test_main.cpp
|
unittests/multifile_test_main.cpp
|
||||||
unittests/multifile_test_chai.cpp
|
unittests/multifile_test_chai.cpp
|
||||||
@ -444,35 +434,14 @@ if(BUILD_TESTING)
|
|||||||
target_link_libraries(multifile_test ${LIBS})
|
target_link_libraries(multifile_test ${LIBS})
|
||||||
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
||||||
|
|
||||||
add_executable(emscripten_eval_test unittests/emscripten_eval_test.cpp)
|
add_library(test_module MODULE src/test_module.cpp)
|
||||||
target_link_libraries(emscripten_eval_test ${LIBS})
|
target_link_libraries(test_module ${LIBS})
|
||||||
add_test(NAME Emscripten_Eval_Test COMMAND emscripten_eval_test)
|
|
||||||
|
|
||||||
add_executable(emscripten_exception_test unittests/emscripten_exception_test.cpp)
|
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||||
target_link_libraries(emscripten_exception_test ${LIBS})
|
|
||||||
add_test(NAME Emscripten_Exception_Test COMMAND emscripten_exception_test)
|
|
||||||
|
|
||||||
add_executable(emscripten_state_test unittests/emscripten_state_test.cpp)
|
|
||||||
target_link_libraries(emscripten_state_test ${LIBS})
|
|
||||||
add_test(NAME Emscripten_State_Test COMMAND emscripten_state_test)
|
|
||||||
|
|
||||||
add_executable(threading_config_test unittests/threading_config_test.cpp)
|
|
||||||
target_link_libraries(threading_config_test ${LIBS})
|
|
||||||
add_test(NAME Threading_Config_Test COMMAND threading_config_test)
|
|
||||||
|
|
||||||
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||||
if(BUILD_LIBFUZZ_TESTER)
|
|
||||||
add_executable(fuzzer src/libfuzzer_client.cpp src/sha3.cpp)
|
|
||||||
target_compile_options(fuzzer PRIVATE "-fsanitize=fuzzer,address")
|
|
||||||
target_link_libraries(fuzzer PRIVATE ${LIBS} "-fsanitize=fuzzer,address")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
|
|
||||||
|
|
||||||
install(DIRECTORY include/chaiscript DESTINATION include
|
install(DIRECTORY include/chaiscript DESTINATION include
|
||||||
PATTERN "*.hpp"
|
PATTERN "*.hpp"
|
||||||
@ -493,6 +462,8 @@ install(DIRECTORY samples DESTINATION share/chaiscript
|
|||||||
|
|
||||||
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
|
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
|
||||||
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
||||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
DESTINATION lib/pkgconfig)
|
||||||
|
|
||||||
|
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
# Introduction
|
|
||||||
|
|
||||||
This document outlines the principles that drive the development of ChaiScript. ChaiScript does not intent to be the perfect tool for *every* situation, but it does intend to be a good general purpose tool for *most* situations.
|
|
||||||
|
|
||||||
# Goals
|
|
||||||
|
|
||||||
1. Trivially easy to integrate with C++ projects
|
|
||||||
2. 0 external depenencies
|
|
||||||
3. "Perfect" integration with C++
|
|
||||||
* Direct mapping between ChaiScript objects and C++ objects
|
|
||||||
* Direct mapping between ChaiScript functions and C++ functions
|
|
||||||
* Direct mapping between ChaiScript exceptions and C++ exceptions
|
|
||||||
3. Never surprise the C++ developer
|
|
||||||
* Object lifetimes managed by the stack
|
|
||||||
* Familiar syntax to C++ developers
|
|
||||||
4. Perform "well enough" to not get in the way
|
|
||||||
|
|
||||||
|
|
||||||
# Alternatives
|
|
||||||
|
|
||||||
## Sol2
|
|
||||||
|
|
||||||
If you are looking for the fastest performing scripting language and don't mind Lua, you might want to consider [sol2](https://github.com/ThePhD/sol2).
|
|
||||||
|
|
||||||
## SWIG
|
|
||||||
|
|
||||||
If you are looking for the most flexible solution to be able to support multiple target languages, consider [SWIG](http://swig.org)
|
|
||||||
|
|
||||||
4
LICENSE
4
LICENSE
@ -1,6 +1,4 @@
|
|||||||
BSD-3-Clause License
|
Copyright 2009-2015 Jason Turner
|
||||||
|
|
||||||
Copyright 2009-2018 Jason Turner
|
|
||||||
Copyright 2009-2012 Jonathan Turner.
|
Copyright 2009-2012 Jonathan Turner.
|
||||||
|
|
||||||
All Rights Reserved.
|
All Rights Reserved.
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ChaiScript"
|
|
||||||
}
|
|
||||||
877
cheatsheet.md
877
cheatsheet.md
File diff suppressed because it is too large
Load Diff
@ -1,318 +0,0 @@
|
|||||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
||||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
|
||||||
|
|
||||||
#[=======================================================================[.rst:
|
|
||||||
Catch
|
|
||||||
-----
|
|
||||||
|
|
||||||
This module defines a function to help use the Catch test framework.
|
|
||||||
|
|
||||||
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
|
||||||
executable to enumerate its tests. This does not require CMake to be re-run
|
|
||||||
when tests change. However, it may not work in a cross-compiling environment,
|
|
||||||
and setting test properties is less convenient.
|
|
||||||
|
|
||||||
This command is intended to replace use of :command:`add_test` to register
|
|
||||||
tests, and will create a separate CTest test for each Catch test case. Note
|
|
||||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
|
||||||
cannot be shared by multiple test cases executing in the same instance.
|
|
||||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
|
||||||
usually considered as more beneficial. By default, the CTest test name is the
|
|
||||||
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
|
||||||
|
|
||||||
.. command:: catch_discover_tests
|
|
||||||
|
|
||||||
Automatically add tests with CTest by querying the compiled test executable
|
|
||||||
for available tests::
|
|
||||||
|
|
||||||
catch_discover_tests(target
|
|
||||||
[TEST_SPEC arg1...]
|
|
||||||
[EXTRA_ARGS arg1...]
|
|
||||||
[WORKING_DIRECTORY dir]
|
|
||||||
[TEST_PREFIX prefix]
|
|
||||||
[TEST_SUFFIX suffix]
|
|
||||||
[PROPERTIES name1 value1...]
|
|
||||||
[TEST_LIST var]
|
|
||||||
[REPORTER reporter]
|
|
||||||
[OUTPUT_DIR dir]
|
|
||||||
[OUTPUT_PREFIX prefix]
|
|
||||||
[OUTPUT_SUFFIX suffix]
|
|
||||||
[DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
|
|
||||||
[SKIP_IS_FAILURE]
|
|
||||||
[ADD_TAGS_AS_LABELS]
|
|
||||||
)
|
|
||||||
|
|
||||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
|
||||||
that generates the list of tests by parsing the output from running the test
|
|
||||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
|
||||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
|
||||||
not necessary to re-run CMake when the list of tests changes.
|
|
||||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
|
||||||
in order to function in a cross-compiling environment.
|
|
||||||
|
|
||||||
Additionally, setting properties on tests is somewhat less convenient, since
|
|
||||||
the tests are not available at CMake time. Additional test properties may be
|
|
||||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
|
||||||
more fine-grained test control is needed, custom content may be provided
|
|
||||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
|
||||||
directory property. The set of discovered tests is made accessible to such a
|
|
||||||
script via the ``<target>_TESTS`` variable.
|
|
||||||
|
|
||||||
The options are:
|
|
||||||
|
|
||||||
``target``
|
|
||||||
Specifies the Catch executable, which must be a known CMake executable
|
|
||||||
target. CMake will substitute the location of the built executable when
|
|
||||||
running the test.
|
|
||||||
|
|
||||||
``TEST_SPEC arg1...``
|
|
||||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
|
||||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
|
||||||
|
|
||||||
``EXTRA_ARGS arg1...``
|
|
||||||
Any extra arguments to pass on the command line to each test case.
|
|
||||||
|
|
||||||
``WORKING_DIRECTORY dir``
|
|
||||||
Specifies the directory in which to run the discovered test cases. If this
|
|
||||||
option is not provided, the current binary directory is used.
|
|
||||||
|
|
||||||
``TEST_PREFIX prefix``
|
|
||||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
|
||||||
case. This can be useful when the same test executable is being used in
|
|
||||||
multiple calls to ``catch_discover_tests()`` but with different
|
|
||||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
|
||||||
|
|
||||||
``TEST_SUFFIX suffix``
|
|
||||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
|
||||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
|
||||||
be specified.
|
|
||||||
|
|
||||||
``PROPERTIES name1 value1...``
|
|
||||||
Specifies additional properties to be set on all tests discovered by this
|
|
||||||
invocation of ``catch_discover_tests``.
|
|
||||||
|
|
||||||
``TEST_LIST var``
|
|
||||||
Make the list of tests available in the variable ``var``, rather than the
|
|
||||||
default ``<target>_TESTS``. This can be useful when the same test
|
|
||||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
|
||||||
Note that this variable is only available in CTest.
|
|
||||||
|
|
||||||
``REPORTER reporter``
|
|
||||||
Use the specified reporter when running the test case. The reporter will
|
|
||||||
be passed to the Catch executable as ``--reporter reporter``.
|
|
||||||
|
|
||||||
``OUTPUT_DIR dir``
|
|
||||||
If specified, the parameter is passed along as
|
|
||||||
``--out dir/<test_name>`` to Catch executable. The actual file name is the
|
|
||||||
same as the test name. This should be used instead of
|
|
||||||
``EXTRA_ARGS --out foo`` to avoid race conditions writing the result output
|
|
||||||
when using parallel test execution.
|
|
||||||
|
|
||||||
``OUTPUT_PREFIX prefix``
|
|
||||||
May be used in conjunction with ``OUTPUT_DIR``.
|
|
||||||
If specified, ``prefix`` is added to each output file name, like so
|
|
||||||
``--out dir/prefix<test_name>``.
|
|
||||||
|
|
||||||
``OUTPUT_SUFFIX suffix``
|
|
||||||
May be used in conjunction with ``OUTPUT_DIR``.
|
|
||||||
If specified, ``suffix`` is added to each output file name, like so
|
|
||||||
``--out dir/<test_name>suffix``. This can be used to add a file extension to
|
|
||||||
the output e.g. ".xml".
|
|
||||||
|
|
||||||
``DL_PATHS path...``
|
|
||||||
Specifies paths that need to be set for the dynamic linker to find shared
|
|
||||||
libraries/DLLs when running the test executable (PATH/LD_LIBRARY_PATH respectively).
|
|
||||||
These paths will both be set when retrieving the list of test cases from the
|
|
||||||
test executable and when the tests are executed themselves. This requires
|
|
||||||
cmake/ctest >= 3.22.
|
|
||||||
|
|
||||||
``DL_FRAMEWORK_PATHS path...``
|
|
||||||
Specifies paths that need to be set for the dynamic linker to find libraries
|
|
||||||
packaged as frameworks on Apple platforms when running the test executable
|
|
||||||
(DYLD_FRAMEWORK_PATH). These paths will both be set when retrieving the list
|
|
||||||
of test cases from the test executable and when the tests are executed themselves.
|
|
||||||
This requires cmake/ctest >= 3.22.
|
|
||||||
|
|
||||||
``DISCOVERY_MODE mode``
|
|
||||||
Provides control over when ``catch_discover_tests`` performs test discovery.
|
|
||||||
By default, ``POST_BUILD`` sets up a post-build command to perform test discovery
|
|
||||||
at build time. In certain scenarios, like cross-compiling, this ``POST_BUILD``
|
|
||||||
behavior is not desirable. By contrast, ``PRE_TEST`` delays test discovery until
|
|
||||||
just prior to test execution. This way test discovery occurs in the target environment
|
|
||||||
where the test has a better chance at finding appropriate runtime dependencies.
|
|
||||||
|
|
||||||
``DISCOVERY_MODE`` defaults to the value of the
|
|
||||||
``CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE`` variable if it is not passed when
|
|
||||||
calling ``catch_discover_tests``. This provides a mechanism for globally selecting
|
|
||||||
a preferred test discovery behavior without having to modify each call site.
|
|
||||||
|
|
||||||
``SKIP_IS_FAILURE``
|
|
||||||
Disables skipped test detection.
|
|
||||||
|
|
||||||
``ADD_TAGS_AS_LABELS``
|
|
||||||
Adds all test tags as CTest labels.
|
|
||||||
|
|
||||||
#]=======================================================================]
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
function(catch_discover_tests TARGET)
|
|
||||||
|
|
||||||
cmake_parse_arguments(
|
|
||||||
""
|
|
||||||
"SKIP_IS_FAILURE;ADD_TAGS_AS_LABELS"
|
|
||||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX;DISCOVERY_MODE"
|
|
||||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES;DL_PATHS;DL_FRAMEWORK_PATHS"
|
|
||||||
${ARGN}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(${CMAKE_VERSION} VERSION_LESS "3.19")
|
|
||||||
message(FATAL_ERROR "This script requires JSON support from CMake version 3.19 or greater.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT _WORKING_DIRECTORY)
|
|
||||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
|
||||||
endif()
|
|
||||||
if(NOT _TEST_LIST)
|
|
||||||
set(_TEST_LIST ${TARGET}_TESTS)
|
|
||||||
endif()
|
|
||||||
if(_DL_PATHS AND ${CMAKE_VERSION} VERSION_LESS "3.22.0")
|
|
||||||
message(FATAL_ERROR "The DL_PATHS option requires at least cmake 3.22")
|
|
||||||
endif()
|
|
||||||
if(_DL_FRAMEWORK_PATHS AND ${CMAKE_VERSION} VERSION_LESS "3.22.0")
|
|
||||||
message(FATAL_ERROR "The DL_FRAMEWORK_PATHS option requires at least cmake 3.22")
|
|
||||||
endif()
|
|
||||||
if(NOT _DISCOVERY_MODE)
|
|
||||||
if(NOT CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE)
|
|
||||||
set(CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE "POST_BUILD")
|
|
||||||
endif()
|
|
||||||
set(_DISCOVERY_MODE ${CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE})
|
|
||||||
endif()
|
|
||||||
if(NOT _DISCOVERY_MODE MATCHES "^(POST_BUILD|PRE_TEST)$")
|
|
||||||
message(FATAL_ERROR "Unknown DISCOVERY_MODE: ${_DISCOVERY_MODE}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
## Generate a unique name based on the extra arguments
|
|
||||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
|
|
||||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
|
||||||
|
|
||||||
# Define rule to generate test list for aforementioned test executable
|
|
||||||
set(ctest_file_base "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-${args_hash}")
|
|
||||||
set(ctest_include_file "${ctest_file_base}_include.cmake")
|
|
||||||
set(ctest_tests_file "${ctest_file_base}_tests.cmake")
|
|
||||||
|
|
||||||
get_property(crosscompiling_emulator
|
|
||||||
TARGET ${TARGET}
|
|
||||||
PROPERTY CROSSCOMPILING_EMULATOR
|
|
||||||
)
|
|
||||||
if(NOT _SKIP_IS_FAILURE)
|
|
||||||
set(_PROPERTIES ${_PROPERTIES} SKIP_RETURN_CODE 4)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(_DISCOVERY_MODE STREQUAL "POST_BUILD")
|
|
||||||
add_custom_command(
|
|
||||||
TARGET ${TARGET} POST_BUILD
|
|
||||||
BYPRODUCTS "${ctest_tests_file}"
|
|
||||||
COMMAND "${CMAKE_COMMAND}"
|
|
||||||
-D "TEST_TARGET=${TARGET}"
|
|
||||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
|
||||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
|
||||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
|
||||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
|
||||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
|
||||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
|
||||||
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
|
||||||
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
|
||||||
-D "TEST_LIST=${_TEST_LIST}"
|
|
||||||
-D "TEST_REPORTER=${_REPORTER}"
|
|
||||||
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
|
|
||||||
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
|
|
||||||
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
|
|
||||||
-D "TEST_DL_PATHS=${_DL_PATHS}"
|
|
||||||
-D "TEST_DL_FRAMEWORK_PATHS=${_DL_FRAMEWORK_PATHS}"
|
|
||||||
-D "CTEST_FILE=${ctest_tests_file}"
|
|
||||||
-D "ADD_TAGS_AS_LABELS=${_ADD_TAGS_AS_LABELS}"
|
|
||||||
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
|
|
||||||
file(WRITE "${ctest_include_file}"
|
|
||||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
|
||||||
" include(\"${ctest_tests_file}\")\n"
|
|
||||||
"else()\n"
|
|
||||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
|
||||||
"endif()\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
elseif(_DISCOVERY_MODE STREQUAL "PRE_TEST")
|
|
||||||
|
|
||||||
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL
|
|
||||||
PROPERTY GENERATOR_IS_MULTI_CONFIG
|
|
||||||
)
|
|
||||||
|
|
||||||
if(GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
set(ctest_tests_file "${ctest_file_base}_tests-$<CONFIG>.cmake")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
string(CONCAT ctest_include_content
|
|
||||||
"if(EXISTS \"$<TARGET_FILE:${TARGET}>\")" "\n"
|
|
||||||
" if(NOT EXISTS \"${ctest_tests_file}\" OR" "\n"
|
|
||||||
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\" OR\n"
|
|
||||||
" NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"\${CMAKE_CURRENT_LIST_FILE}\")\n"
|
|
||||||
" include(\"${_CATCH_DISCOVER_TESTS_SCRIPT}\")" "\n"
|
|
||||||
" catch_discover_tests_impl(" "\n"
|
|
||||||
" TEST_EXECUTABLE" " [==[" "$<TARGET_FILE:${TARGET}>" "]==]" "\n"
|
|
||||||
" TEST_EXECUTOR" " [==[" "${crosscompiling_emulator}" "]==]" "\n"
|
|
||||||
" TEST_WORKING_DIR" " [==[" "${_WORKING_DIRECTORY}" "]==]" "\n"
|
|
||||||
" TEST_SPEC" " [==[" "${_TEST_SPEC}" "]==]" "\n"
|
|
||||||
" TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS}" "]==]" "\n"
|
|
||||||
" TEST_PROPERTIES" " [==[" "${_PROPERTIES}" "]==]" "\n"
|
|
||||||
" TEST_PREFIX" " [==[" "${_TEST_PREFIX}" "]==]" "\n"
|
|
||||||
" TEST_SUFFIX" " [==[" "${_TEST_SUFFIX}" "]==]" "\n"
|
|
||||||
" TEST_LIST" " [==[" "${_TEST_LIST}" "]==]" "\n"
|
|
||||||
" TEST_REPORTER" " [==[" "${_REPORTER}" "]==]" "\n"
|
|
||||||
" TEST_OUTPUT_DIR" " [==[" "${_OUTPUT_DIR}" "]==]" "\n"
|
|
||||||
" TEST_OUTPUT_PREFIX" " [==[" "${_OUTPUT_PREFIX}" "]==]" "\n"
|
|
||||||
" TEST_OUTPUT_SUFFIX" " [==[" "${_OUTPUT_SUFFIX}" "]==]" "\n"
|
|
||||||
" CTEST_FILE" " [==[" "${ctest_tests_file}" "]==]" "\n"
|
|
||||||
" TEST_DL_PATHS" " [==[" "${_DL_PATHS}" "]==]" "\n"
|
|
||||||
" TEST_DL_FRAMEWORK_PATHS" " [==[" "${_DL_FRAMEWORK_PATHS}" "]==]" "\n"
|
|
||||||
" ADD_TAGS_AS_LABELS" " [==[" "${_ADD_TAGS_AS_LABELS}" "]==]" "\n"
|
|
||||||
" )" "\n"
|
|
||||||
" endif()" "\n"
|
|
||||||
" include(\"${ctest_tests_file}\")" "\n"
|
|
||||||
"else()" "\n"
|
|
||||||
" add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)" "\n"
|
|
||||||
"endif()" "\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(GENERATOR_IS_MULTI_CONFIG)
|
|
||||||
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
|
|
||||||
file(GENERATE OUTPUT "${ctest_file_base}_include-${_config}.cmake" CONTENT "${ctest_include_content}" CONDITION $<CONFIG:${_config}>)
|
|
||||||
endforeach()
|
|
||||||
string(CONCAT ctest_include_multi_content
|
|
||||||
"if(NOT CTEST_CONFIGURATION_TYPE)" "\n"
|
|
||||||
" message(\"No configuration for testing specified, use '-C <cfg>'.\")" "\n"
|
|
||||||
"else()" "\n"
|
|
||||||
" include(\"${ctest_file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")" "\n"
|
|
||||||
"endif()" "\n"
|
|
||||||
)
|
|
||||||
file(GENERATE OUTPUT "${ctest_include_file}" CONTENT "${ctest_include_multi_content}")
|
|
||||||
else()
|
|
||||||
file(GENERATE OUTPUT "${ctest_file_base}_include.cmake" CONTENT "${ctest_include_content}")
|
|
||||||
file(WRITE "${ctest_include_file}" "include(\"${ctest_file_base}_include.cmake\")")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
|
||||||
set_property(DIRECTORY
|
|
||||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
|
||||||
)
|
|
||||||
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
|
||||||
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
|
|
||||||
)
|
|
||||||
@ -1,254 +0,0 @@
|
|||||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
||||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
|
||||||
|
|
||||||
function(add_command NAME)
|
|
||||||
set(_args "")
|
|
||||||
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
|
|
||||||
math(EXPR _last_arg ${ARGC}-1)
|
|
||||||
foreach(_n RANGE 1 ${_last_arg})
|
|
||||||
set(_arg "${ARGV${_n}}")
|
|
||||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
|
||||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
|
||||||
else()
|
|
||||||
set(_args "${_args} ${_arg}")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(catch_discover_tests_impl)
|
|
||||||
|
|
||||||
cmake_parse_arguments(
|
|
||||||
""
|
|
||||||
""
|
|
||||||
"TEST_EXECUTABLE;TEST_WORKING_DIR;TEST_OUTPUT_DIR;TEST_OUTPUT_PREFIX;TEST_OUTPUT_SUFFIX;TEST_PREFIX;TEST_REPORTER;TEST_SPEC;TEST_SUFFIX;TEST_LIST;CTEST_FILE"
|
|
||||||
"TEST_EXTRA_ARGS;TEST_PROPERTIES;TEST_EXECUTOR;TEST_DL_PATHS;TEST_DL_FRAMEWORK_PATHS;ADD_TAGS_AS_LABELS"
|
|
||||||
${ARGN}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(add_tags "${_ADD_TAGS_AS_LABELS}")
|
|
||||||
set(prefix "${_TEST_PREFIX}")
|
|
||||||
set(suffix "${_TEST_SUFFIX}")
|
|
||||||
set(spec ${_TEST_SPEC})
|
|
||||||
set(extra_args ${_TEST_EXTRA_ARGS})
|
|
||||||
set(properties ${_TEST_PROPERTIES})
|
|
||||||
set(reporter ${_TEST_REPORTER})
|
|
||||||
set(output_dir ${_TEST_OUTPUT_DIR})
|
|
||||||
set(output_prefix ${_TEST_OUTPUT_PREFIX})
|
|
||||||
set(output_suffix ${_TEST_OUTPUT_SUFFIX})
|
|
||||||
set(dl_paths ${_TEST_DL_PATHS})
|
|
||||||
set(dl_framework_paths ${_TEST_DL_FRAMEWORK_PATHS})
|
|
||||||
set(environment_modifications "")
|
|
||||||
set(script)
|
|
||||||
set(suite)
|
|
||||||
set(tests)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
set(dl_paths_variable_name PATH)
|
|
||||||
elseif(APPLE)
|
|
||||||
set(dl_paths_variable_name DYLD_LIBRARY_PATH)
|
|
||||||
else()
|
|
||||||
set(dl_paths_variable_name LD_LIBRARY_PATH)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Run test executable to get list of available tests
|
|
||||||
if(NOT EXISTS "${_TEST_EXECUTABLE}")
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"Specified test executable '${_TEST_EXECUTABLE}' does not exist"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(dl_paths)
|
|
||||||
cmake_path(CONVERT "$ENV{${dl_paths_variable_name}}" TO_NATIVE_PATH_LIST env_dl_paths)
|
|
||||||
list(PREPEND env_dl_paths "${dl_paths}")
|
|
||||||
cmake_path(CONVERT "${env_dl_paths}" TO_NATIVE_PATH_LIST paths)
|
|
||||||
set(ENV{${dl_paths_variable_name}} "${paths}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE AND dl_framework_paths)
|
|
||||||
cmake_path(CONVERT "$ENV{DYLD_FRAMEWORK_PATH}" TO_NATIVE_PATH_LIST env_dl_framework_paths)
|
|
||||||
list(PREPEND env_dl_framework_paths "${dl_framework_paths}")
|
|
||||||
cmake_path(CONVERT "${env_dl_framework_paths}" TO_NATIVE_PATH_LIST paths)
|
|
||||||
set(ENV{DYLD_FRAMEWORK_PATH} "${paths}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} --list-tests --reporter json
|
|
||||||
OUTPUT_VARIABLE listing_output
|
|
||||||
RESULT_VARIABLE result
|
|
||||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
|
||||||
)
|
|
||||||
if(NOT ${result} EQUAL 0)
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"Error listing tests from executable '${_TEST_EXECUTABLE}':\n"
|
|
||||||
" Result: ${result}\n"
|
|
||||||
" Output: ${listing_output}\n"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Prepare reporter
|
|
||||||
if(reporter)
|
|
||||||
set(reporter_arg "--reporter ${reporter}")
|
|
||||||
|
|
||||||
# Run test executable to check whether reporter is available
|
|
||||||
# note that the use of --list-reporters is not the important part,
|
|
||||||
# we only want to check whether the execution succeeds with ${reporter_arg}
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec} ${reporter_arg} --list-reporters
|
|
||||||
OUTPUT_VARIABLE reporter_check_output
|
|
||||||
RESULT_VARIABLE reporter_check_result
|
|
||||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
|
||||||
)
|
|
||||||
if(${reporter_check_result} EQUAL 255)
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"\"${reporter}\" is not a valid reporter!\n"
|
|
||||||
)
|
|
||||||
elseif(NOT ${reporter_check_result} EQUAL 0)
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"Error checking for reporter in test executable '${_TEST_EXECUTABLE}':\n"
|
|
||||||
" Result: ${reporter_check_result}\n"
|
|
||||||
" Output: ${reporter_check_output}\n"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Prepare output dir
|
|
||||||
if(output_dir AND NOT IS_ABSOLUTE ${output_dir})
|
|
||||||
set(output_dir "${_TEST_WORKING_DIR}/${output_dir}")
|
|
||||||
if(NOT EXISTS ${output_dir})
|
|
||||||
file(MAKE_DIRECTORY ${output_dir})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(dl_paths)
|
|
||||||
foreach(path ${dl_paths})
|
|
||||||
cmake_path(NATIVE_PATH path native_path)
|
|
||||||
list(PREPEND environment_modifications "${dl_paths_variable_name}=path_list_prepend:${native_path}")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE AND dl_framework_paths)
|
|
||||||
foreach(path ${dl_framework_paths})
|
|
||||||
cmake_path(NATIVE_PATH path native_path)
|
|
||||||
list(PREPEND environment_modifications "DYLD_FRAMEWORK_PATH=path_list_prepend:${native_path}")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Parse JSON output for list of tests/class names/tags
|
|
||||||
string(JSON version GET "${listing_output}" "version")
|
|
||||||
if(NOT version STREQUAL "1")
|
|
||||||
message(FATAL_ERROR "Unsupported catch output version: '${version}'")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Speed-up reparsing by cutting away unneeded parts of JSON.
|
|
||||||
string(JSON test_listing GET "${listing_output}" "listings" "tests")
|
|
||||||
string(JSON num_tests LENGTH "${test_listing}")
|
|
||||||
|
|
||||||
# Exit early if no tests are detected
|
|
||||||
if(num_tests STREQUAL "0")
|
|
||||||
file(WRITE "${_CTEST_FILE}" "")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# CMake's foreach-RANGE is inclusive, so we have to subtract 1
|
|
||||||
math(EXPR num_tests "${num_tests} - 1")
|
|
||||||
|
|
||||||
foreach(idx RANGE ${num_tests})
|
|
||||||
string(JSON single_test GET ${test_listing} ${idx})
|
|
||||||
string(JSON test_tags GET "${single_test}" "tags")
|
|
||||||
string(JSON plain_name GET "${single_test}" "name")
|
|
||||||
|
|
||||||
# Escape characters in test case names that would be parsed by Catch2
|
|
||||||
# Note that the \ escaping must happen FIRST! Do not change the order.
|
|
||||||
set(escaped_name "${plain_name}")
|
|
||||||
foreach(char \\ , [ ] ;)
|
|
||||||
string(REPLACE ${char} "\\${char}" escaped_name "${escaped_name}")
|
|
||||||
endforeach(char)
|
|
||||||
# ...add output dir
|
|
||||||
if(output_dir)
|
|
||||||
string(REGEX REPLACE "[^A-Za-z0-9_]" "_" escaped_name_clean "${escaped_name}")
|
|
||||||
set(output_dir_arg "--out ${output_dir}/${output_prefix}${escaped_name_clean}${output_suffix}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# ...and add to script
|
|
||||||
add_command(add_test
|
|
||||||
"${prefix}${plain_name}${suffix}"
|
|
||||||
${_TEST_EXECUTOR}
|
|
||||||
"${_TEST_EXECUTABLE}"
|
|
||||||
"${escaped_name}"
|
|
||||||
${extra_args}
|
|
||||||
"${reporter_arg}"
|
|
||||||
"${output_dir_arg}"
|
|
||||||
)
|
|
||||||
add_command(set_tests_properties
|
|
||||||
"${prefix}${plain_name}${suffix}"
|
|
||||||
PROPERTIES
|
|
||||||
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
|
|
||||||
${properties}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(add_tags)
|
|
||||||
string(JSON num_tags LENGTH "${test_tags}")
|
|
||||||
math(EXPR num_tags "${num_tags} - 1")
|
|
||||||
set(tag_list "")
|
|
||||||
if(num_tags GREATER_EQUAL "0")
|
|
||||||
foreach(tag_idx RANGE ${num_tags})
|
|
||||||
string(JSON a_tag GET "${test_tags}" "${tag_idx}")
|
|
||||||
# Catch2's tags can contain semicolons, which are list element separators
|
|
||||||
# in CMake, so we have to escape them. Ideally we could use the [=[...]=]
|
|
||||||
# syntax for this, but CTest currently keeps the square quotes in the label
|
|
||||||
# name. So we add 2 backslashes to escape it instead.
|
|
||||||
# **IMPORTANT**: The number of backslashes depends on how many layers
|
|
||||||
# of CMake the tag goes. If this script is changed, the
|
|
||||||
# number of backslashes to escape may change as well.
|
|
||||||
string(REPLACE ";" "\\;" a_tag "${a_tag}")
|
|
||||||
list(APPEND tag_list "${a_tag}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
add_command(set_tests_properties
|
|
||||||
"${prefix}${plain_name}${suffix}"
|
|
||||||
PROPERTIES
|
|
||||||
LABELS "${tag_list}"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif(add_tags)
|
|
||||||
|
|
||||||
if(environment_modifications)
|
|
||||||
add_command(set_tests_properties
|
|
||||||
"${prefix}${plain_name}${suffix}"
|
|
||||||
PROPERTIES
|
|
||||||
ENVIRONMENT_MODIFICATION "${environment_modifications}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND tests "${prefix}${plain_name}${suffix}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# Create a list of all discovered tests, which users may use to e.g. set
|
|
||||||
# properties on the tests
|
|
||||||
add_command(set ${_TEST_LIST} ${tests})
|
|
||||||
|
|
||||||
# Write CTest script
|
|
||||||
file(WRITE "${_CTEST_FILE}" "${script}")
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
if(CMAKE_SCRIPT_MODE_FILE)
|
|
||||||
catch_discover_tests_impl(
|
|
||||||
TEST_EXECUTABLE ${TEST_EXECUTABLE}
|
|
||||||
TEST_EXECUTOR ${TEST_EXECUTOR}
|
|
||||||
TEST_WORKING_DIR ${TEST_WORKING_DIR}
|
|
||||||
TEST_SPEC ${TEST_SPEC}
|
|
||||||
TEST_EXTRA_ARGS ${TEST_EXTRA_ARGS}
|
|
||||||
TEST_PROPERTIES ${TEST_PROPERTIES}
|
|
||||||
TEST_PREFIX ${TEST_PREFIX}
|
|
||||||
TEST_SUFFIX ${TEST_SUFFIX}
|
|
||||||
TEST_LIST ${TEST_LIST}
|
|
||||||
TEST_REPORTER ${TEST_REPORTER}
|
|
||||||
TEST_OUTPUT_DIR ${TEST_OUTPUT_DIR}
|
|
||||||
TEST_OUTPUT_PREFIX ${TEST_OUTPUT_PREFIX}
|
|
||||||
TEST_OUTPUT_SUFFIX ${TEST_OUTPUT_SUFFIX}
|
|
||||||
TEST_DL_PATHS ${TEST_DL_PATHS}
|
|
||||||
TEST_DL_FRAMEWORK_PATHS ${TEST_DL_FRAMEWORK_PATHS}
|
|
||||||
CTEST_FILE ${CTEST_FILE}
|
|
||||||
ADD_TAGS_AS_LABELS ${ADD_TAGS_AS_LABELS}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
|
|
||||||
# Copyright Catch2 Authors
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE.txt or copy at
|
|
||||||
# https://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: BSL-1.0
|
|
||||||
|
|
||||||
# Supported optional args:
|
|
||||||
# * SHARD_COUNT - number of shards to split target's tests into
|
|
||||||
# * REPORTER - reporter spec to use for tests
|
|
||||||
# * TEST_SPEC - test spec used for filtering tests
|
|
||||||
function(catch_add_sharded_tests TARGET)
|
|
||||||
if(${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
|
||||||
message(FATAL_ERROR "add_sharded_catch_tests only supports CMake versions 3.10.0 and up")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
cmake_parse_arguments(
|
|
||||||
""
|
|
||||||
""
|
|
||||||
"SHARD_COUNT;REPORTER;TEST_SPEC"
|
|
||||||
""
|
|
||||||
${ARGN}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT DEFINED _SHARD_COUNT)
|
|
||||||
set(_SHARD_COUNT 2)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Generate a unique name based on the extra arguments
|
|
||||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX} ${_SHARD_COUNT}")
|
|
||||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
|
||||||
|
|
||||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-sharded-tests-include-${args_hash}.cmake")
|
|
||||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-sharded-tests-impl-${args_hash}.cmake")
|
|
||||||
|
|
||||||
file(WRITE "${ctest_include_file}"
|
|
||||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
|
||||||
" include(\"${ctest_tests_file}\")\n"
|
|
||||||
"else()\n"
|
|
||||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
|
||||||
"endif()\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
set_property(DIRECTORY
|
|
||||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(shard_impl_script_file "${_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT}")
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
TARGET ${TARGET} POST_BUILD
|
|
||||||
BYPRODUCTS "${ctest_tests_file}"
|
|
||||||
COMMAND "${CMAKE_COMMAND}"
|
|
||||||
-D "TARGET_NAME=${TARGET}"
|
|
||||||
-D "TEST_BINARY=$<TARGET_FILE:${TARGET}>"
|
|
||||||
-D "CTEST_FILE=${ctest_tests_file}"
|
|
||||||
-D "SHARD_COUNT=${_SHARD_COUNT}"
|
|
||||||
-D "REPORTER_SPEC=${_REPORTER}"
|
|
||||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
|
||||||
-P "${shard_impl_script_file}"
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
set(_CATCH_DISCOVER_SHARD_TESTS_IMPL_SCRIPT
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/CatchShardTestsImpl.cmake
|
|
||||||
CACHE INTERNAL "Catch2 full path to CatchShardTestsImpl.cmake helper file"
|
|
||||||
)
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
|
|
||||||
# Copyright Catch2 Authors
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE.txt or copy at
|
|
||||||
# https://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
# SPDX-License-Identifier: BSL-1.0
|
|
||||||
|
|
||||||
# Indirection for CatchShardTests that allows us to delay the script
|
|
||||||
# file generation until build time.
|
|
||||||
|
|
||||||
# Expected args:
|
|
||||||
# * TEST_BINARY - full path to the test binary to run sharded
|
|
||||||
# * CTEST_FILE - full path to ctest script file to write to
|
|
||||||
# * TARGET_NAME - name of the target to shard (used for test names)
|
|
||||||
# * SHARD_COUNT - number of shards to split the binary into
|
|
||||||
# Optional args:
|
|
||||||
# * REPORTER_SPEC - reporter specs to be passed down to the binary
|
|
||||||
# * TEST_SPEC - test spec to pass down to the test binary
|
|
||||||
|
|
||||||
if(NOT EXISTS "${TEST_BINARY}")
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"Specified test binary '${TEST_BINARY}' does not exist"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(other_args "")
|
|
||||||
if(TEST_SPEC)
|
|
||||||
set(other_args "${other_args} ${TEST_SPEC}")
|
|
||||||
endif()
|
|
||||||
if(REPORTER_SPEC)
|
|
||||||
set(other_args "${other_args} --reporter ${REPORTER_SPEC}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# foreach RANGE in cmake is inclusive of the end, so we have to adjust it
|
|
||||||
math(EXPR adjusted_shard_count "${SHARD_COUNT} - 1")
|
|
||||||
|
|
||||||
file(WRITE "${CTEST_FILE}"
|
|
||||||
"string(RANDOM LENGTH 8 ALPHABET \"0123456789abcdef\" rng_seed)\n"
|
|
||||||
"\n"
|
|
||||||
"foreach(shard_idx RANGE ${adjusted_shard_count})\n"
|
|
||||||
" add_test(${TARGET_NAME}-shard-" [[${shard_idx}]] "/${adjusted_shard_count}\n"
|
|
||||||
" ${TEST_BINARY}"
|
|
||||||
" --shard-index " [[${shard_idx}]]
|
|
||||||
" --shard-count ${SHARD_COUNT}"
|
|
||||||
" --rng-seed " [[0x${rng_seed}]]
|
|
||||||
" --order rand"
|
|
||||||
"${other_args}"
|
|
||||||
"\n"
|
|
||||||
" )\n"
|
|
||||||
"endforeach()\n"
|
|
||||||
)
|
|
||||||
103
cmake/CheckCXX11Features.cmake
Normal file
103
cmake/CheckCXX11Features.cmake
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# Checks for C++11 features
|
||||||
|
# CXX11_FEATURE_LIST - a list containing all supported features
|
||||||
|
# HAS_CXX11_AUTO - auto keyword
|
||||||
|
# HAS_CXX11_NULLPTR - nullptr
|
||||||
|
# HAS_CXX11_LAMBDA - lambdas
|
||||||
|
# HAS_CXX11_STATIC_ASSERT - static_assert()
|
||||||
|
# HAS_CXX11_RVALUE_REFERENCES - rvalue references
|
||||||
|
# HAS_CXX11_DECLTYPE - decltype keyword
|
||||||
|
# HAS_CXX11_CSTDINT_H - cstdint header
|
||||||
|
# HAS_CXX11_LONG_LONG - long long signed & unsigned types
|
||||||
|
# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates
|
||||||
|
# HAS_CXX11_CONSTEXPR - constexpr keyword
|
||||||
|
# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members
|
||||||
|
# HAS_CXX11_FUNC - __func__ preprocessor constant
|
||||||
|
#
|
||||||
|
# Original script by Rolf Eike Beer
|
||||||
|
# Modifications by Andreas Weis
|
||||||
|
#
|
||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
|
||||||
|
|
||||||
|
SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||||
|
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
SET(CMAKE_CXX_FLAGS "-std=c++0x")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
|
||||||
|
IF (NOT DEFINED ${RESULT_VAR})
|
||||||
|
SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}")
|
||||||
|
|
||||||
|
IF (${FEATURE_NUMBER})
|
||||||
|
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
|
||||||
|
SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
|
||||||
|
ELSE (${FEATURE_NUMBER})
|
||||||
|
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME})
|
||||||
|
SET(_LOG_NAME "\"${FEATURE_NAME}\"")
|
||||||
|
ENDIF (${FEATURE_NUMBER})
|
||||||
|
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}")
|
||||||
|
|
||||||
|
SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
|
||||||
|
SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
|
||||||
|
SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")
|
||||||
|
|
||||||
|
IF (CROSS_COMPILING)
|
||||||
|
try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
|
||||||
|
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||||
|
try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||||
|
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||||
|
ELSE (CROSS_COMPILING)
|
||||||
|
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||||
|
"${_bindir}" "${_SRCFILE}")
|
||||||
|
IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||||
|
SET(${RESULT_VAR} TRUE)
|
||||||
|
ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||||
|
SET(${RESULT_VAR} FALSE)
|
||||||
|
ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||||
|
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||||
|
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||||
|
"${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||||
|
IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||||
|
SET(${RESULT_VAR} TRUE)
|
||||||
|
ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||||
|
SET(${RESULT_VAR} FALSE)
|
||||||
|
ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||||
|
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||||
|
ENDIF (CROSS_COMPILING)
|
||||||
|
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||||
|
try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
|
||||||
|
IF (_TMP_RESULT)
|
||||||
|
SET(${RESULT_VAR} FALSE)
|
||||||
|
ELSE (_TMP_RESULT)
|
||||||
|
SET(${RESULT_VAR} TRUE)
|
||||||
|
ENDIF (_TMP_RESULT)
|
||||||
|
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||||
|
|
||||||
|
IF (${RESULT_VAR})
|
||||||
|
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works")
|
||||||
|
LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR})
|
||||||
|
ELSE (${RESULT_VAR})
|
||||||
|
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported")
|
||||||
|
ENDIF (${RESULT_VAR})
|
||||||
|
SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}")
|
||||||
|
ENDIF (NOT DEFINED ${RESULT_VAR})
|
||||||
|
ENDMACRO(CXX11_CHECK_FEATURE)
|
||||||
|
|
||||||
|
CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO)
|
||||||
|
CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR)
|
||||||
|
CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA)
|
||||||
|
CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT)
|
||||||
|
CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES)
|
||||||
|
CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE)
|
||||||
|
CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H)
|
||||||
|
CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG)
|
||||||
|
CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES)
|
||||||
|
CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR)
|
||||||
|
CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER)
|
||||||
|
CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC)
|
||||||
|
|
||||||
|
SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list")
|
||||||
|
MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST)
|
||||||
|
|
||||||
|
SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS})
|
||||||
|
UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS)
|
||||||
|
|
||||||
@ -1,250 +0,0 @@
|
|||||||
#==================================================================================================#
|
|
||||||
# supported macros #
|
|
||||||
# - TEST_CASE, #
|
|
||||||
# - TEMPLATE_TEST_CASE #
|
|
||||||
# - SCENARIO, #
|
|
||||||
# - TEST_CASE_METHOD, #
|
|
||||||
# - CATCH_TEST_CASE, #
|
|
||||||
# - CATCH_TEMPLATE_TEST_CASE #
|
|
||||||
# - CATCH_SCENARIO, #
|
|
||||||
# - CATCH_TEST_CASE_METHOD. #
|
|
||||||
# #
|
|
||||||
# Usage #
|
|
||||||
# 1. make sure this module is in the path or add this otherwise: #
|
|
||||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
|
||||||
# 2. make sure that you've enabled testing option for the project by the call: #
|
|
||||||
# enable_testing() #
|
|
||||||
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
|
|
||||||
# project(testing_target) #
|
|
||||||
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
|
||||||
# enable_testing() #
|
|
||||||
# #
|
|
||||||
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
|
|
||||||
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
|
|
||||||
# #
|
|
||||||
# file(GLOB SOURCE_FILES "*.cpp") #
|
|
||||||
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
|
|
||||||
# #
|
|
||||||
# include(ParseAndAddCatchTests) #
|
|
||||||
# ParseAndAddCatchTests(${PROJECT_NAME}) #
|
|
||||||
# #
|
|
||||||
# The following variables affect the behavior of the script: #
|
|
||||||
# #
|
|
||||||
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
|
|
||||||
# -- enables debug messages #
|
|
||||||
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
|
|
||||||
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
|
|
||||||
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
|
|
||||||
# -- adds fixture class name to the test name #
|
|
||||||
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
|
|
||||||
# -- adds cmake target name to the test name #
|
|
||||||
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
|
|
||||||
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
|
|
||||||
# #
|
|
||||||
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
|
|
||||||
# a test should be run. For instance to use test MPI, one can write #
|
|
||||||
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
|
|
||||||
# just before calling this ParseAndAddCatchTests function #
|
|
||||||
# #
|
|
||||||
# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
|
|
||||||
# command. For example, to include successful tests in the output, one can write #
|
|
||||||
# set(AdditionalCatchParameters --success) #
|
|
||||||
# #
|
|
||||||
# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
|
|
||||||
# file in the target is set, and contains the list of the tests extracted from that target, or #
|
|
||||||
# from that file. This is useful, for example to add further labels or properties to the tests. #
|
|
||||||
# #
|
|
||||||
#==================================================================================================#
|
|
||||||
|
|
||||||
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
|
|
||||||
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
|
|
||||||
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
|
|
||||||
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
|
|
||||||
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
|
|
||||||
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
|
|
||||||
|
|
||||||
function(ParseAndAddCatchTests_PrintDebugMessage)
|
|
||||||
if(PARSE_CATCH_TESTS_VERBOSE)
|
|
||||||
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# This removes the contents between
|
|
||||||
# - block comments (i.e. /* ... */)
|
|
||||||
# - full line comments (i.e. // ... )
|
|
||||||
# contents have been read into '${CppCode}'.
|
|
||||||
# !keep partial line comments
|
|
||||||
function(ParseAndAddCatchTests_RemoveComments CppCode)
|
|
||||||
string(ASCII 2 CMakeBeginBlockComment)
|
|
||||||
string(ASCII 3 CMakeEndBlockComment)
|
|
||||||
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
|
||||||
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
|
|
||||||
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
|
|
||||||
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
|
|
||||||
|
|
||||||
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Worker function
|
|
||||||
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
|
|
||||||
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
|
|
||||||
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
|
||||||
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
|
||||||
if(NOT EXISTS ${SourceFile})
|
|
||||||
message(WARNING "Cannot find source file: ${SourceFile}")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
|
|
||||||
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
|
||||||
|
|
||||||
# Remove block and fullline comments
|
|
||||||
ParseAndAddCatchTests_RemoveComments(Contents)
|
|
||||||
|
|
||||||
# Find definition of test names
|
|
||||||
# https://regex101.com/r/JygOND/1
|
|
||||||
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([ \t\n]*\"[^\"]*\"[ \t\n]*(,[ \t\n]*\"[^\"]*\")?(,[ \t\n]*[^\,\)]*)*\\)[ \t\n]*\{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
|
||||||
|
|
||||||
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
|
||||||
set_property(
|
|
||||||
DIRECTORY
|
|
||||||
APPEND
|
|
||||||
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# check CMP0110 policy for new add_test() behavior
|
|
||||||
if(POLICY CMP0110)
|
|
||||||
cmake_policy(GET CMP0110 _cmp0110_value) # new add_test() behavior
|
|
||||||
else()
|
|
||||||
# just to be thorough explicitly set the variable
|
|
||||||
set(_cmp0110_value)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
foreach(TestName ${Tests})
|
|
||||||
# Strip newlines
|
|
||||||
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
|
||||||
|
|
||||||
# Get test type and fixture if applicable
|
|
||||||
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
|
||||||
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
|
||||||
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
|
|
||||||
|
|
||||||
# Get string parts of test definition
|
|
||||||
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
|
||||||
|
|
||||||
# Strip wrapping quotation marks
|
|
||||||
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
|
||||||
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
|
||||||
|
|
||||||
# Validate that a test name and tags have been provided
|
|
||||||
list(LENGTH TestStrings TestStringsLength)
|
|
||||||
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
|
||||||
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Assign name and tags
|
|
||||||
list(GET TestStrings 0 Name)
|
|
||||||
if("${TestType}" STREQUAL "SCENARIO")
|
|
||||||
set(Name "Scenario: ${Name}")
|
|
||||||
endif()
|
|
||||||
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture)
|
|
||||||
set(CTestName "${TestFixture}:${Name}")
|
|
||||||
else()
|
|
||||||
set(CTestName "${Name}")
|
|
||||||
endif()
|
|
||||||
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
|
||||||
set(CTestName "${TestTarget}:${CTestName}")
|
|
||||||
endif()
|
|
||||||
# add target to labels to enable running all tests added from this target
|
|
||||||
set(Labels ${TestTarget})
|
|
||||||
if(TestStringsLength EQUAL 2)
|
|
||||||
list(GET TestStrings 1 Tags)
|
|
||||||
string(TOLOWER "${Tags}" Tags)
|
|
||||||
# remove target from labels if the test is hidden
|
|
||||||
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
|
||||||
list(REMOVE_ITEM Labels ${TestTarget})
|
|
||||||
endif()
|
|
||||||
string(REPLACE "]" ";" Tags "${Tags}")
|
|
||||||
string(REPLACE "[" "" Tags "${Tags}")
|
|
||||||
else()
|
|
||||||
# unset tags variable from previous loop
|
|
||||||
unset(Tags)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND Labels ${Tags})
|
|
||||||
|
|
||||||
set(HiddenTagFound OFF)
|
|
||||||
foreach(label ${Labels})
|
|
||||||
string(REGEX MATCH "^!hide|^\\." result ${label})
|
|
||||||
if(result)
|
|
||||||
set(HiddenTagFound ON)
|
|
||||||
break()
|
|
||||||
endif()
|
|
||||||
endforeach(label)
|
|
||||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
|
||||||
else()
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
|
|
||||||
if(Labels)
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Escape commas in the test spec
|
|
||||||
string(REPLACE "," "\\," Name ${Name})
|
|
||||||
|
|
||||||
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were necessary,
|
|
||||||
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
|
|
||||||
# And properly introduced in 3.19 with the CMP0110 policy
|
|
||||||
if(_cmp0110_value STREQUAL "NEW" OR ${CMAKE_VERSION} VERSION_EQUAL "3.18")
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to NEW, no need for add_test(\"\") workaround")
|
|
||||||
else()
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to OLD adding \"\" for add_test() workaround")
|
|
||||||
set(CTestName "\"${CTestName}\"")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Handle template test cases
|
|
||||||
if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*")
|
|
||||||
set(Name "${Name} - *")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add the test and set its properties
|
|
||||||
add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
|
|
||||||
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
|
|
||||||
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
|
|
||||||
set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
|
|
||||||
else()
|
|
||||||
set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
|
||||||
LABELS "${Labels}")
|
|
||||||
endif()
|
|
||||||
set_property(
|
|
||||||
TARGET ${TestTarget}
|
|
||||||
APPEND
|
|
||||||
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
|
||||||
set_property(
|
|
||||||
SOURCE ${SourceFile}
|
|
||||||
APPEND
|
|
||||||
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# entry point
|
|
||||||
function(ParseAndAddCatchTests TestTarget)
|
|
||||||
message(DEPRECATION "ParseAndAddCatchTest: function deprecated because of possibility of missed test cases. Consider using 'catch_discover_tests' from 'Catch.cmake'")
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
|
|
||||||
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
|
||||||
foreach(SourceFile ${SourceFiles})
|
|
||||||
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
|
|
||||||
endforeach()
|
|
||||||
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
|
|
||||||
endfunction()
|
|
||||||
8
cmake/c++11-test-__func__-N2340.cpp
Normal file
8
cmake/c++11-test-__func__-N2340.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
if (!__func__) { return 1; }
|
||||||
|
if(std::strlen(__func__) <= 0) { return 1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
12
cmake/c++11-test-auto-N2546.cpp
Normal file
12
cmake/c++11-test-auto-N2546.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
auto i = 5;
|
||||||
|
auto f = 3.14159f;
|
||||||
|
auto d = 3.14159;
|
||||||
|
bool ret = (
|
||||||
|
(sizeof(f) < sizeof(d)) &&
|
||||||
|
(sizeof(i) == sizeof(int))
|
||||||
|
);
|
||||||
|
return ret ? 0 : 1;
|
||||||
|
}
|
||||||
19
cmake/c++11-test-constexpr-N2235.cpp
Normal file
19
cmake/c++11-test-constexpr-N2235.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
constexpr int square(int x)
|
||||||
|
{
|
||||||
|
return x*x;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int the_answer()
|
||||||
|
{
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int test_arr[square(3)];
|
||||||
|
bool ret = (
|
||||||
|
(square(the_answer()) == 1764) &&
|
||||||
|
(sizeof(test_arr)/sizeof(test_arr[0]) == 9)
|
||||||
|
);
|
||||||
|
return ret ? 0 : 1;
|
||||||
|
}
|
||||||
10
cmake/c++11-test-cstdint.cpp
Normal file
10
cmake/c++11-test-cstdint.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
bool test =
|
||||||
|
(sizeof(int8_t) == 1) &&
|
||||||
|
(sizeof(int16_t) == 2) &&
|
||||||
|
(sizeof(int32_t) == 4) &&
|
||||||
|
(sizeof(int64_t) == 8);
|
||||||
|
return test ? 0 : 1;
|
||||||
|
}
|
||||||
11
cmake/c++11-test-decltype-N2343.cpp
Normal file
11
cmake/c++11-test-decltype-N2343.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
bool check_size(int i)
|
||||||
|
{
|
||||||
|
return sizeof(int) == sizeof(decltype(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
bool ret = check_size(42);
|
||||||
|
return ret ? 0 : 1;
|
||||||
|
}
|
||||||
5
cmake/c++11-test-lambda-N2927.cpp
Normal file
5
cmake/c++11-test-lambda-N2927.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
return ([&ret]() -> int { return ret; })();
|
||||||
|
}
|
||||||
7
cmake/c++11-test-long_long-N1811.cpp
Normal file
7
cmake/c++11-test-long_long-N1811.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
long long l;
|
||||||
|
unsigned long long ul;
|
||||||
|
|
||||||
|
return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1;
|
||||||
|
}
|
||||||
5
cmake/c++11-test-nullptr-N2431.cpp
Normal file
5
cmake/c++11-test-nullptr-N2431.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
int* test = nullptr;
|
||||||
|
return test ? 1 : 0;
|
||||||
|
}
|
||||||
5
cmake/c++11-test-nullptr-N2431_fail_compile.cpp
Normal file
5
cmake/c++11-test-nullptr-N2431_fail_compile.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i = nullptr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
15
cmake/c++11-test-rvalue_references-N2118.cpp
Normal file
15
cmake/c++11-test-rvalue_references-N2118.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
int foo(int& lvalue)
|
||||||
|
{
|
||||||
|
return 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
int foo(int&& rvalue)
|
||||||
|
{
|
||||||
|
return 321;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i = 42;
|
||||||
|
return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1;
|
||||||
|
}
|
||||||
14
cmake/c++11-test-sizeof_member-N2253.cpp
Normal file
14
cmake/c++11-test-sizeof_member-N2253.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
struct foo {
|
||||||
|
char bar;
|
||||||
|
int baz;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
bool ret = (
|
||||||
|
(sizeof(foo::bar) == 1) &&
|
||||||
|
(sizeof(foo::baz) >= sizeof(foo::bar)) &&
|
||||||
|
(sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz))
|
||||||
|
);
|
||||||
|
return ret ? 0 : 1;
|
||||||
|
}
|
||||||
5
cmake/c++11-test-static_assert-N1720.cpp
Normal file
5
cmake/c++11-test-static_assert-N1720.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
static_assert(0 < 1, "your ordering of integers is screwed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
5
cmake/c++11-test-static_assert-N1720_fail_compile.cpp
Normal file
5
cmake/c++11-test-static_assert-N1720_fail_compile.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
static_assert(1 < 0, "this should fail");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
23
cmake/c++11-test-variadic_templates-N2555.cpp
Normal file
23
cmake/c++11-test-variadic_templates-N2555.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
int Accumulate()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Ts>
|
||||||
|
int Accumulate(T v, Ts... vs)
|
||||||
|
{
|
||||||
|
return v + Accumulate(vs...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int... Is>
|
||||||
|
int CountElements()
|
||||||
|
{
|
||||||
|
return sizeof...(Is);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int acc = Accumulate(1, 2, 3, 4, -5);
|
||||||
|
int count = CountElements<1,2,3,4,5>();
|
||||||
|
return ((acc == 5) && (count == 5)) ? 0 : 1;
|
||||||
|
}
|
||||||
@ -1,11 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require 'json'
|
|
||||||
|
|
||||||
`grep -rPIHn '\t' src/* include/* samples/*`.lines { |line|
|
|
||||||
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
|
|
||||||
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "tab_checker", :message => "Source Code Line Contains Tabs", :messagetype => "warning"}))
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require 'json'
|
|
||||||
|
|
||||||
`grep -rPIHni 'todo' src/* include/* samples/*`.lines { |line|
|
|
||||||
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
|
|
||||||
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "todo_checker", :message => "todo: #{restofline.strip}", :messagetype => "info"}))
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
# My dict
|
|
||||||
|
|
||||||
|
|
||||||
for="for"
|
|
||||||
while="while"
|
|
||||||
def="def"
|
|
||||||
fun="fun"
|
|
||||||
if="if"
|
|
||||||
else="else"
|
|
||||||
and="&&"
|
|
||||||
or="||"
|
|
||||||
auto="auto"
|
|
||||||
var="var"
|
|
||||||
begin_block="{"
|
|
||||||
end_block="}"
|
|
||||||
empty_vec="[]"
|
|
||||||
string="string"
|
|
||||||
vector="Vector"
|
|
||||||
map="Map"
|
|
||||||
return="return"
|
|
||||||
break="break"
|
|
||||||
true="true"
|
|
||||||
false="false"
|
|
||||||
class="class"
|
|
||||||
attr="attr"
|
|
||||||
var="var"
|
|
||||||
global="global"
|
|
||||||
empty_lambda=" fun(){} "
|
|
||||||
empty_fun=" def empty_fun() {} "
|
|
||||||
continue="continue"
|
|
||||||
float=" 1.1f "
|
|
||||||
double=" 2.2 "
|
|
||||||
long_double=" 2.2ll "
|
|
||||||
unsigned=" 3u "
|
|
||||||
unsigned_long=" 4ul "
|
|
||||||
unsigned_long_long=" 4ull "
|
|
||||||
long_long=" 5ll "
|
|
||||||
attr="attr"
|
|
||||||
reference_del="auto &"
|
|
||||||
int8=" int8_t(1) "
|
|
||||||
int16=" int16_t(2) "
|
|
||||||
int32=" int32_t(3) "
|
|
||||||
int64=" int64_t(4) "
|
|
||||||
uint8=" uint8_t(1) "
|
|
||||||
uint16=" uint16_t(2) "
|
|
||||||
uint32=" uint32_t(3) "
|
|
||||||
uint64=" uint64_t(4) "
|
|
||||||
int8t="int8_t"
|
|
||||||
int16t="int16_t"
|
|
||||||
int32t="int32_t"
|
|
||||||
int64t="int64_t"
|
|
||||||
uint8t="uint8_t"
|
|
||||||
uint16t="uint16_t"
|
|
||||||
uint32t="uint32_t"
|
|
||||||
uint64t="uint64_t"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
Command line used to find this crash:
|
|
||||||
|
|
||||||
../../Downloads/afl-1.80b/afl-fuzz -i- -o findings -x chaiscript.dict -- ../a.out unit_test.inc @@
|
|
||||||
|
|
||||||
If you can't reproduce a bug outside of afl-fuzz, be sure to set the same
|
|
||||||
memory limit. The limit used for this fuzzing session was 50.0 MB.
|
|
||||||
|
|
||||||
Need a tool to minimize test cases before investigating the crashes or sending
|
|
||||||
them to a vendor? Check out the afl-tmin that comes with the fuzzer!
|
|
||||||
|
|
||||||
Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop
|
|
||||||
me a mail at <lcamtuf@coredump.cx> once the issues are fixed - I'd love to
|
|
||||||
add your finds to the gallery at:
|
|
||||||
|
|
||||||
http://lcamtuf.coredump.cx/afl/
|
|
||||||
|
|
||||||
Thanks :-)
|
|
||||||
@ -4,7 +4,7 @@ pushd ..
|
|||||||
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
|
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
|
||||||
tar -xvf cppcheck-1.66.tar.bz2
|
tar -xvf cppcheck-1.66.tar.bz2
|
||||||
cd cppcheck-1.66
|
cd cppcheck-1.66
|
||||||
make -j2
|
CXX=g++-4.8 make -j2
|
||||||
popd
|
popd
|
||||||
../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
|
../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
|
||||||
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output
|
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output
|
||||||
|
|||||||
93
contrib/sublimetext/ChaiScript.YAML-tmLanguage
Normal file
93
contrib/sublimetext/ChaiScript.YAML-tmLanguage
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# [PackageDev] target_format: plist, ext: tmLanguage
|
||||||
|
---
|
||||||
|
comment: 'ChaiScript Syntax: version 2.0'
|
||||||
|
fileTypes: [chai]
|
||||||
|
firstLineMatch: ^#!/usr/bin/env node
|
||||||
|
foldingStartMarker: ^.*\bdef\s*(\w+\s*)?\([^\)]*\)(\s*\{[^\}]*)?\s*$
|
||||||
|
foldingStopMarker: ^\s*\}
|
||||||
|
keyEquivalent: ^~J
|
||||||
|
name: ChaiScript
|
||||||
|
patterns:
|
||||||
|
- {comment: chaiscript shebang, match: ^#, name: comment.line.chai}
|
||||||
|
- {match: '\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?))\b', name: constant.numeric.chai}
|
||||||
|
- begin: ''''
|
||||||
|
beginCaptures:
|
||||||
|
'0': {name: punctuation.definition.string.begin.chai}
|
||||||
|
end: ''''
|
||||||
|
endCaptures:
|
||||||
|
'0': {name: punctuation.definition.string.end.chai}
|
||||||
|
name: string.quoted.single.chai
|
||||||
|
patterns:
|
||||||
|
- {match: '\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)', name: constant.character.escape.chai}
|
||||||
|
- begin: '"'
|
||||||
|
beginCaptures:
|
||||||
|
'0': {name: punctuation.definition.string.begin.chai}
|
||||||
|
end: '"'
|
||||||
|
endCaptures:
|
||||||
|
'0': {name: punctuation.definition.string.end.chai}
|
||||||
|
name: string.quoted.double.chai
|
||||||
|
patterns:
|
||||||
|
- {match: '\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)', name: constant.character.escape.chai}
|
||||||
|
- begin: /\*\*(?!/)
|
||||||
|
captures:
|
||||||
|
'0': {name: punctuation.definition.comment.chai}
|
||||||
|
end: \*/
|
||||||
|
name: comment.block.documentation.chai
|
||||||
|
- begin: /\*
|
||||||
|
captures:
|
||||||
|
'0': {name: punctuation.definition.comment.chai}
|
||||||
|
end: \*/
|
||||||
|
name: comment.block.chai
|
||||||
|
- captures:
|
||||||
|
'1': {name: punctuation.definition.comment.chai}
|
||||||
|
match: (//).*$\n?
|
||||||
|
name: comment.line.double-slash.chai
|
||||||
|
- captures:
|
||||||
|
'0': {name: punctuation.definition.comment.html.chai}
|
||||||
|
'2': {name: punctuation.definition.comment.html.chai}
|
||||||
|
match: (<!--|-->)
|
||||||
|
name: comment.block.html.chai
|
||||||
|
- {match: \b(boolean|byte|char|class|double|enum|float|fun|def|int|interface|long|short|var|auto|attr)\b,
|
||||||
|
name: storage.type.chai}
|
||||||
|
- {match: \b(break|case|catch|continue|default|do|else|finally|else if|for|goto|if|return|switch|throw|try|while)\b,
|
||||||
|
name: keyword.control.chai}
|
||||||
|
- {match: \b(delete|in|instanceof|new|typeof|with)\b, name: keyword.operator.chai}
|
||||||
|
- {match: \btrue\b, name: constant.language.boolean.true.chai}
|
||||||
|
- {match: \bfalse\b, name: constant.language.boolean.false.chai}
|
||||||
|
- {match: \bnull\b, name: constant.language.null.chai}
|
||||||
|
- {match: \b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\b,
|
||||||
|
name: support.class.chai}
|
||||||
|
- {match: '\b(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))\b(?=\()',
|
||||||
|
name: support.function.chai}
|
||||||
|
- {match: '\b(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)\b(?=\()',
|
||||||
|
name: support.function.dom.chai}
|
||||||
|
- {match: '(?<=\.)(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))\b',
|
||||||
|
name: support.constant.chai}
|
||||||
|
- {match: '(?<=\.)(s(hape|ystemId|c(heme|ope|rolling)|ta(ndby|rt)|ize|ummary|pecified|e(ctionRowIndex|lected(Index)?)|rc)|h(space|t(tpEquiv|mlFor)|e(ight|aders)|ref(lang)?)|n(o(Resize|tation(s|Name)|Shade|Href|de(Name|Type|Value)|Wrap)|extSibling|ame)|c(h(ildNodes|Off|ecked|arset)?|ite|o(ntent|o(kie|rds)|de(Base|Type)?|l(s|Span|or)|mpact)|ell(s|Spacing|Padding)|l(ear|assName)|aption)|t(ype|Bodies|itle|Head|ext|a(rget|gName)|Foot)|i(sMap|ndex|d|m(plementation|ages))|o(ptions|wnerDocument|bject)|d(i(sabled|r)|o(c(type|umentElement)|main)|e(clare|f(er|ault(Selected|Checked|Value)))|at(eTime|a))|useMap|p(ublicId|arentNode|r(o(file|mpt)|eviousSibling))|e(n(ctype|tities)|vent|lements)|v(space|ersion|alue(Type)?|Link|Align)|URL|f(irstChild|orm(s)?|ace|rame(Border)?)|width|l(ink(s)?|o(ngDesc|wSrc)|a(stChild|ng|bel))|a(nchors|c(ce(ssKey|pt(Charset)?)|tion)|ttributes|pplets|l(t|ign)|r(chive|eas)|xis|Link|bbr)|r(ow(s|Span|Index)|ules|e(v|ferrer|l|adOnly))|m(ultiple|e(thod|dia)|a(rgin(Height|Width)|xLength))|b(o(dy|rder)|ackground|gColor))\b',
|
||||||
|
name: support.constant.dom.chai}
|
||||||
|
- {match: \b(ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|INDEX_SIZE_ERR|DOMSTRING_SIZE_ERR|HIERARCHY_REQUEST_ERR|WRONG_DOCUMENT_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR|NOT_SUPPORTED_ERR|INUSE_ATTRIBUTE_ERR)\b,
|
||||||
|
name: support.constant.dom.chai}
|
||||||
|
- {match: '\bon(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))\b',
|
||||||
|
name: support.function.event-handler.chai}
|
||||||
|
- {match: '!|\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(in|instanceof|new|delete|typeof|void)\b',
|
||||||
|
name: keyword.operator.chai}
|
||||||
|
- {match: \b(Infinity|NaN|undefined)\b, name: constant.language.chai}
|
||||||
|
- begin: (?<=[=(:]|^|return|&&|\|\||!)\s*(/)(?![/*+{}?])
|
||||||
|
beginCaptures:
|
||||||
|
'1': {name: punctuation.definition.string.begin.chai}
|
||||||
|
end: (/)[igm]*
|
||||||
|
endCaptures:
|
||||||
|
'1': {name: punctuation.definition.string.end.chai}
|
||||||
|
name: string.regexp.chai
|
||||||
|
patterns:
|
||||||
|
- {match: \\., name: constant.character.escape.chai}
|
||||||
|
- {match: \;, name: punctuation.terminator.statement.chai}
|
||||||
|
- {match: ',[ |\t]*', name: meta.delimiter.object.comma.chai}
|
||||||
|
- {match: \., name: meta.delimiter.method.period.chai}
|
||||||
|
- {match: '\{|\}', name: meta.brace.curly.chai}
|
||||||
|
- {match: \(|\), name: meta.brace.round.chai}
|
||||||
|
- {match: '\[|\]', name: meta.brace.square.chai}
|
||||||
|
scopeName: source.chai
|
||||||
|
uuid: 93E017CC-6F27-11D9-90EB-000D93589AF6
|
||||||
|
|
||||||
|
...
|
||||||
333
contrib/sublimetext/ChaiScript.tmLanguage
Normal file
333
contrib/sublimetext/ChaiScript.tmLanguage
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>comment</key>
|
||||||
|
<string>ChaiScript Syntax: version 2.0</string>
|
||||||
|
<key>fileTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>chai</string>
|
||||||
|
</array>
|
||||||
|
<key>firstLineMatch</key>
|
||||||
|
<string>^#!/usr/bin/env node</string>
|
||||||
|
<key>foldingStartMarker</key>
|
||||||
|
<string>^.*\bdef\s*(\w+\s*)?\([^\)]*\)(\s*\{[^\}]*)?\s*$</string>
|
||||||
|
<key>foldingStopMarker</key>
|
||||||
|
<string>^\s*\}</string>
|
||||||
|
<key>keyEquivalent</key>
|
||||||
|
<string>^~J</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>ChaiScript</string>
|
||||||
|
<key>patterns</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>comment</key>
|
||||||
|
<string>chaiscript shebang</string>
|
||||||
|
<key>match</key>
|
||||||
|
<string>^#</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>comment.line.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?))\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.numeric.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>begin</key>
|
||||||
|
<string>'</string>
|
||||||
|
<key>beginCaptures</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.string.begin.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>end</key>
|
||||||
|
<string>'</string>
|
||||||
|
<key>endCaptures</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.string.end.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>string.quoted.single.chai</string>
|
||||||
|
<key>patterns</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.character.escape.chai</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>begin</key>
|
||||||
|
<string>"</string>
|
||||||
|
<key>beginCaptures</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.string.begin.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>end</key>
|
||||||
|
<string>"</string>
|
||||||
|
<key>endCaptures</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.string.end.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>string.quoted.double.chai</string>
|
||||||
|
<key>patterns</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.character.escape.chai</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>begin</key>
|
||||||
|
<string>/\*\*(?!/)</string>
|
||||||
|
<key>captures</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.comment.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>end</key>
|
||||||
|
<string>\*/</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>comment.block.documentation.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>begin</key>
|
||||||
|
<string>/\*</string>
|
||||||
|
<key>captures</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.comment.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>end</key>
|
||||||
|
<string>\*/</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>comment.block.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>captures</key>
|
||||||
|
<dict>
|
||||||
|
<key>1</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.comment.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>(//).*$\n?</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>comment.line.double-slash.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>captures</key>
|
||||||
|
<dict>
|
||||||
|
<key>0</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.comment.html.chai</string>
|
||||||
|
</dict>
|
||||||
|
<key>2</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.comment.html.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>(<!--|-->)</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>comment.block.html.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(boolean|byte|char|class|double|enum|float|fun|def|int|interface|long|short|var|auto|attr)\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>storage.type.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(break|case|catch|continue|default|do|else|finally|else if|for|goto|if|return|switch|throw|try|while)\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>keyword.control.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(delete|in|instanceof|new|typeof|with)\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>keyword.operator.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\btrue\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.language.boolean.true.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\bfalse\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.language.boolean.false.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\bnull\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.language.null.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(Anchor|Applet|Area|Array|Boolean|Button|Checkbox|Date|document|event|FileUpload|Form|Frame|Function|Hidden|History|Image|JavaArray|JavaClass|JavaObject|JavaPackage|java|Layer|Link|Location|Math|MimeType|Number|navigator|netscape|Object|Option|Packages|Password|Plugin|Radio|RegExp|Reset|Select|String|Style|Submit|screen|sun|Text|Textarea|window|XMLHttpRequest)\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>support.class.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(s(h(ift|ow(Mod(elessDialog|alDialog)|Help))|croll(X|By(Pages|Lines)?|Y|To)?|t(op|rike)|i(n|zeToContent|debar|gnText)|ort|u(p|b(str(ing)?)?)|pli(ce|t)|e(nd|t(Re(sizable|questHeader)|M(i(nutes|lliseconds)|onth)|Seconds|Ho(tKeys|urs)|Year|Cursor|Time(out)?|Interval|ZOptions|Date|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(ome|andleEvent)|navigate|c(har(CodeAt|At)|o(s|n(cat|textual|firm)|mpile)|eil|lear(Timeout|Interval)?|a(ptureEvents|ll)|reate(StyleSheet|Popup|EventObject))|t(o(GMTString|S(tring|ource)|U(TCString|pperCase)|Lo(caleString|werCase))|est|a(n|int(Enabled)?))|i(s(NaN|Finite)|ndexOf|talics)|d(isableExternalCapture|ump|etachEvent)|u(n(shift|taint|escape|watch)|pdateCommands)|j(oin|avaEnabled)|p(o(p|w)|ush|lugins.refresh|a(ddings|rse(Int|Float)?)|r(int|ompt|eference))|e(scape|nableExternalCapture|val|lementFromPoint|x(p|ec(Script|Command)?))|valueOf|UTC|queryCommand(State|Indeterm|Enabled|Value)|f(i(nd|le(ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(nt(size|color)|rward)|loor|romCharCode)|watch|l(ink|o(ad|g)|astIndexOf)|a(sin|nchor|cos|t(tachEvent|ob|an(2)?)|pply|lert|b(s|ort))|r(ou(nd|teEvents)|e(size(By|To)|calc|turnValue|place|verse|l(oad|ease(Capture|Events)))|andom)|g(o|et(ResponseHeader|M(i(nutes|lliseconds)|onth)|Se(conds|lection)|Hours|Year|Time(zoneOffset)?|Da(y|te)|UTC(M(i(nutes|lliseconds)|onth)|Seconds|Hours|Da(y|te)|FullYear)|FullYear|A(ttention|llResponseHeaders)))|m(in|ove(B(y|elow)|To(Absolute)?|Above)|ergeAttributes|a(tch|rgins|x))|b(toa|ig|o(ld|rderWidths)|link|ack))\b(?=\()</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>support.function.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(s(ub(stringData|mit)|plitText|e(t(NamedItem|Attribute(Node)?)|lect))|has(ChildNodes|Feature)|namedItem|c(l(ick|o(se|neNode))|reate(C(omment|DATASection|aption)|T(Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(ntityReference|lement)|Attribute))|tabIndex|i(nsert(Row|Before|Cell|Data)|tem)|open|delete(Row|C(ell|aption)|T(Head|Foot)|Data)|focus|write(ln)?|a(dd|ppend(Child|Data))|re(set|place(Child|Data)|move(NamedItem|Child|Attribute(Node)?)?)|get(NamedItem|Element(sBy(Name|TagName)|ById)|Attribute(Node)?)|blur)\b(?=\()</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>support.function.dom.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>(?<=\.)(s(ystemLanguage|cr(ipts|ollbars|een(X|Y|Top|Left))|t(yle(Sheets)?|atus(Text|bar)?)|ibling(Below|Above)|ource|uffixes|e(curity(Policy)?|l(ection|f)))|h(istory|ost(name)?|as(h|Focus))|y|X(MLDocument|SLDocument)|n(ext|ame(space(s|URI)|Prop))|M(IN_VALUE|AX_VALUE)|c(haracterSet|o(n(structor|trollers)|okieEnabled|lorDepth|mp(onents|lete))|urrent|puClass|l(i(p(boardData)?|entInformation)|osed|asses)|alle(e|r)|rypto)|t(o(olbar|p)|ext(Transform|Indent|Decoration|Align)|ags)|SQRT(1_2|2)|i(n(ner(Height|Width)|put)|ds|gnoreCase)|zIndex|o(scpu|n(readystatechange|Line)|uter(Height|Width)|p(sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(i(splay|alog(Height|Top|Width|Left|Arguments)|rectories)|e(scription|fault(Status|Ch(ecked|arset)|View)))|u(ser(Profile|Language|Agent)|n(iqueID|defined)|pdateInterval)|_content|p(ixelDepth|ort|ersonalbar|kcs11|l(ugins|atform)|a(thname|dding(Right|Bottom|Top|Left)|rent(Window|Layer)?|ge(X(Offset)?|Y(Offset)?))|r(o(to(col|type)|duct(Sub)?|mpter)|e(vious|fix)))|e(n(coding|abledPlugin)|x(ternal|pando)|mbeds)|v(isibility|endor(Sub)?|Linkcolor)|URLUnencoded|P(I|OSITIVE_INFINITY)|f(ilename|o(nt(Size|Family|Weight)|rmName)|rame(s|Element)|gColor)|E|whiteSpace|l(i(stStyleType|n(eHeight|kColor))|o(ca(tion(bar)?|lName)|wsrc)|e(ngth|ft(Context)?)|a(st(M(odified|atch)|Index|Paren)|yer(s|X)|nguage))|a(pp(MinorVersion|Name|Co(deName|re)|Version)|vail(Height|Top|Width|Left)|ll|r(ity|guments)|Linkcolor|bove)|r(ight(Context)?|e(sponse(XML|Text)|adyState))|global|x|m(imeTypes|ultiline|enubar|argin(Right|Bottom|Top|Left))|L(N(10|2)|OG(10E|2E))|b(o(ttom|rder(Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(Color|Image)))\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>support.constant.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>(?<=\.)(s(hape|ystemId|c(heme|ope|rolling)|ta(ndby|rt)|ize|ummary|pecified|e(ctionRowIndex|lected(Index)?)|rc)|h(space|t(tpEquiv|mlFor)|e(ight|aders)|ref(lang)?)|n(o(Resize|tation(s|Name)|Shade|Href|de(Name|Type|Value)|Wrap)|extSibling|ame)|c(h(ildNodes|Off|ecked|arset)?|ite|o(ntent|o(kie|rds)|de(Base|Type)?|l(s|Span|or)|mpact)|ell(s|Spacing|Padding)|l(ear|assName)|aption)|t(ype|Bodies|itle|Head|ext|a(rget|gName)|Foot)|i(sMap|ndex|d|m(plementation|ages))|o(ptions|wnerDocument|bject)|d(i(sabled|r)|o(c(type|umentElement)|main)|e(clare|f(er|ault(Selected|Checked|Value)))|at(eTime|a))|useMap|p(ublicId|arentNode|r(o(file|mpt)|eviousSibling))|e(n(ctype|tities)|vent|lements)|v(space|ersion|alue(Type)?|Link|Align)|URL|f(irstChild|orm(s)?|ace|rame(Border)?)|width|l(ink(s)?|o(ngDesc|wSrc)|a(stChild|ng|bel))|a(nchors|c(ce(ssKey|pt(Charset)?)|tion)|ttributes|pplets|l(t|ign)|r(chive|eas)|xis|Link|bbr)|r(ow(s|Span|Index)|ules|e(v|ferrer|l|adOnly))|m(ultiple|e(thod|dia)|a(rgin(Height|Width)|xLength))|b(o(dy|rder)|ackground|gColor))\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>support.constant.dom.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFERENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|NOTATION_NODE|INDEX_SIZE_ERR|DOMSTRING_SIZE_ERR|HIERARCHY_REQUEST_ERR|WRONG_DOCUMENT_ERR|INVALID_CHARACTER_ERR|NO_DATA_ALLOWED_ERR|NO_MODIFICATION_ALLOWED_ERR|NOT_FOUND_ERR|NOT_SUPPORTED_ERR|INUSE_ATTRIBUTE_ERR)\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>support.constant.dom.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\bon(R(ow(s(inserted|delete)|e(nter|xit))|e(s(ize(start|end)?|et)|adystatechange))|Mouse(o(ut|ver)|down|up|move)|B(efore(cut|deactivate|u(nload|pdate)|p(aste|rint)|editfocus|activate)|lur)|S(croll|top|ubmit|elect(start|ionchange)?)|H(over|elp)|C(hange|ont(extmenu|rolselect)|ut|ellchange|l(ick|ose))|D(eactivate|ata(setc(hanged|omplete)|available)|r(op|ag(start|over|drop|en(ter|d)|leave)?)|blclick)|Unload|P(aste|ropertychange)|Error(update)?|Key(down|up|press)|Focus|Load|A(ctivate|fter(update|print)|bort))\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>support.function.event-handler.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>!|\$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\b(in|instanceof|new|delete|typeof|void)\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>keyword.operator.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\b(Infinity|NaN|undefined)\b</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.language.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>begin</key>
|
||||||
|
<string>(?<=[=(:]|^|return|&&|\|\||!)\s*(/)(?![/*+{}?])</string>
|
||||||
|
<key>beginCaptures</key>
|
||||||
|
<dict>
|
||||||
|
<key>1</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.string.begin.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>end</key>
|
||||||
|
<string>(/)[igm]*</string>
|
||||||
|
<key>endCaptures</key>
|
||||||
|
<dict>
|
||||||
|
<key>1</key>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.definition.string.end.chai</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>string.regexp.chai</string>
|
||||||
|
<key>patterns</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\\.</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>constant.character.escape.chai</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\;</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>punctuation.terminator.statement.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>,[ |\t]*</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>meta.delimiter.object.comma.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\.</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>meta.delimiter.method.period.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\{|\}</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>meta.brace.curly.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\(|\)</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>meta.brace.round.chai</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>match</key>
|
||||||
|
<string>\[|\]</string>
|
||||||
|
<key>name</key>
|
||||||
|
<string>meta.brace.square.chai</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>scopeName</key>
|
||||||
|
<string>source.chai</string>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>93E017CC-6F27-11D9-90EB-000D93589AF6</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -1 +0,0 @@
|
|||||||
vim support can be found at https://github.com/ChaiScript/vim-chaiscript
|
|
||||||
7
contrib/vim/README.txt
Normal file
7
contrib/vim/README.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Install ftdetect, indent and syntax subdirectories to:
|
||||||
|
|
||||||
|
~/.vim/
|
||||||
|
|
||||||
|
See the vim documentation on this:
|
||||||
|
|
||||||
|
http://vimdoc.sourceforge.net/htmldoc/syntax.html#mysyntaxfile
|
||||||
2
contrib/vim/ftdetect/chaiscript.vim
Normal file
2
contrib/vim/ftdetect/chaiscript.vim
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
au BufRead,BufNewFile *.chai set filetype=chaiscript
|
||||||
|
|
||||||
50
contrib/vim/indent/chaiscript.vim
Normal file
50
contrib/vim/indent/chaiscript.vim
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
" Vim indent file
|
||||||
|
" Language: ChaiScript
|
||||||
|
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
||||||
|
|
||||||
|
" Only load this indent file when no other was loaded.
|
||||||
|
if exists("b:did_indent")
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let b:did_indent = 1
|
||||||
|
|
||||||
|
setlocal indentexpr=GetChaiScriptIndent()
|
||||||
|
setlocal autoindent
|
||||||
|
|
||||||
|
" Only define the function once.
|
||||||
|
if exists("*GetChaiScriptIndent")
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! GetChaiScriptIndent()
|
||||||
|
" Find a non-blank line above the current line.
|
||||||
|
let lnum = prevnonblank(v:lnum - 1)
|
||||||
|
|
||||||
|
" Hit the start of the file, use zero indent.
|
||||||
|
if lnum == 0
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Add a 'shiftwidth' after lines that start a block:
|
||||||
|
" lines containing a {
|
||||||
|
let ind = indent(lnum)
|
||||||
|
let flag = 0
|
||||||
|
let prevline = getline(lnum)
|
||||||
|
if prevline =~ '^.*{.*'
|
||||||
|
let ind = ind + &shiftwidth
|
||||||
|
let flag = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Subtract a 'shiftwidth' after lines containing a { followed by a }
|
||||||
|
" to keep it balanced
|
||||||
|
if flag == 1 && prevline =~ '.*{.*}.*'
|
||||||
|
let ind = ind - &shiftwidth
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Subtract a 'shiftwidth' on lines ending with }
|
||||||
|
if getline(v:lnum) =~ '^\s*\%(}\)'
|
||||||
|
let ind = ind - &shiftwidth
|
||||||
|
endif
|
||||||
|
|
||||||
|
return ind
|
||||||
|
endfunction
|
||||||
99
contrib/vim/syntax/chaiscript.vim
Normal file
99
contrib/vim/syntax/chaiscript.vim
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
" Vim syntax file
|
||||||
|
" Language: ChaiScript
|
||||||
|
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
||||||
|
|
||||||
|
" Quit when a (custom) syntax file was already loaded
|
||||||
|
if exists("b:current_syntax")
|
||||||
|
finish
|
||||||
|
end
|
||||||
|
|
||||||
|
let s:cpo_save = &cpo
|
||||||
|
set cpo&vim
|
||||||
|
|
||||||
|
syn case match
|
||||||
|
|
||||||
|
" syncing method
|
||||||
|
syn sync fromstart
|
||||||
|
|
||||||
|
" Strings
|
||||||
|
syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell
|
||||||
|
|
||||||
|
" Escape characters
|
||||||
|
syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}"
|
||||||
|
|
||||||
|
" String evals
|
||||||
|
syn region chaiscriptEval contained start="${" end="}"
|
||||||
|
|
||||||
|
" integer number
|
||||||
|
syn match chaiscriptNumber "\<\d\+\>"
|
||||||
|
|
||||||
|
" floating point number, with dot, optional exponent
|
||||||
|
syn match chaiscriptFloat "\<\d\+\.\d*\%(e[-+]\=\d\+\)\=\>"
|
||||||
|
|
||||||
|
" floating point number, starting with a dot, optional exponent
|
||||||
|
syn match chaiscriptFloat "\.\d\+\%(e[-+]\=\d\+\)\=\>"
|
||||||
|
|
||||||
|
" floating point number, without dot, with exponent
|
||||||
|
syn match chaiscriptFloat "\<\d\+e[-+]\=\d\+\>"
|
||||||
|
|
||||||
|
" Hex strings
|
||||||
|
syn match chaiscriptNumber "\<0x\x\+\>"
|
||||||
|
|
||||||
|
" Binary strings
|
||||||
|
syn match chaiscriptNumber "\<0b[01]\+\>"
|
||||||
|
|
||||||
|
" Various language features
|
||||||
|
syn keyword chaiscriptCond if else
|
||||||
|
syn keyword chaiscriptRepeat while for do
|
||||||
|
syn keyword chaiscriptStatement break continue return switch case default
|
||||||
|
syn keyword chaiscriptExceptions try catch throw
|
||||||
|
|
||||||
|
"Keyword
|
||||||
|
syn keyword chaiscriptKeyword def true false attr
|
||||||
|
|
||||||
|
"Built in types
|
||||||
|
syn keyword chaiscriptType fun var auto
|
||||||
|
|
||||||
|
"Built in funcs, keep it simple
|
||||||
|
syn keyword chaiscriptFunc eval throw
|
||||||
|
|
||||||
|
"Let's treat all backtick operator function lookups as built in too
|
||||||
|
syn region chaiscriptFunc matchgroup=chaiscriptFunc start="`" end="`"
|
||||||
|
|
||||||
|
" Account for the "[1..10]" syntax, treating it as an operator
|
||||||
|
" Intentionally leaving out all of the normal, well known operators
|
||||||
|
syn match chaiscriptOperator "\.\."
|
||||||
|
|
||||||
|
" Guard seperator as an operator
|
||||||
|
syn match chaiscriptOperator ":"
|
||||||
|
|
||||||
|
" Comments
|
||||||
|
syn match chaiscriptComment "//.*$" contains=@Spell
|
||||||
|
syn region chaiscriptComment matchgroup=chaiscriptComment start="/\*" end="\*/" contains=@Spell
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
hi def link chaiscriptExceptions Exception
|
||||||
|
hi def link chaiscriptKeyword Keyword
|
||||||
|
hi def link chaiscriptStatement Statement
|
||||||
|
hi def link chaiscriptRepeat Repeat
|
||||||
|
hi def link chaiscriptString String
|
||||||
|
hi def link chaiscriptNumber Number
|
||||||
|
hi def link chaiscriptFloat Float
|
||||||
|
hi def link chaiscriptOperator Operator
|
||||||
|
hi def link chaiscriptConstant Constant
|
||||||
|
hi def link chaiscriptCond Conditional
|
||||||
|
hi def link chaiscriptFunction Function
|
||||||
|
hi def link chaiscriptComment Comment
|
||||||
|
hi def link chaiscriptTodo Todo
|
||||||
|
hi def link chaiscriptError Error
|
||||||
|
hi def link chaiscriptSpecial SpecialChar
|
||||||
|
hi def link chaiscriptFunc Identifier
|
||||||
|
hi def link chaiscriptType Type
|
||||||
|
hi def link chaiscriptEval Special
|
||||||
|
|
||||||
|
let b:current_syntax = "chaiscript"
|
||||||
|
|
||||||
|
let &cpo = s:cpo_save
|
||||||
|
unlet s:cpo_save
|
||||||
|
" vim: nowrap sw=2 sts=2 ts=8 noet
|
||||||
@ -1,40 +0,0 @@
|
|||||||
# Emscripten/WebAssembly build for ChaiScript
|
|
||||||
# Based on work by Rob Loach: https://github.com/RobLoach/ChaiScript.js
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# emcmake cmake -B build-em -S emscripten
|
|
||||||
# cmake --build build-em
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.12)
|
|
||||||
project(chaiscript_em)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
# Emscripten-specific compiler/linker flags
|
|
||||||
add_definitions(-DCHAISCRIPT_NO_THREADS -DCHAISCRIPT_NO_DYNLOAD)
|
|
||||||
|
|
||||||
add_executable(chaiscript chaiscript_em.cpp)
|
|
||||||
target_include_directories(chaiscript PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
|
||||||
|
|
||||||
# Enable WASM exception handling — ChaiScript relies on C++ exceptions for
|
|
||||||
# error propagation; without this flag exceptions cause an abort in WASM.
|
|
||||||
target_compile_options(chaiscript PRIVATE -fwasm-exceptions)
|
|
||||||
|
|
||||||
# Emscripten link flags: enable embind, allow memory growth, export as ES module-compatible
|
|
||||||
target_link_options(chaiscript PRIVATE
|
|
||||||
--bind
|
|
||||||
-fwasm-exceptions
|
|
||||||
-sALLOW_MEMORY_GROWTH=1
|
|
||||||
-sEXPORT_ES6=0
|
|
||||||
-sMODULARIZE=0
|
|
||||||
-sINVOKE_RUN=0
|
|
||||||
)
|
|
||||||
|
|
||||||
# Copy the HTML shell to the build output directory
|
|
||||||
add_custom_command(TARGET chaiscript POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/chaiscript.html
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/chaiscript.html
|
|
||||||
COMMENT "Copying HTML frontend to build directory"
|
|
||||||
)
|
|
||||||
@ -1,240 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<!--
|
|
||||||
ChaiScript Emscripten Frontend
|
|
||||||
Based on work by Rob Loach: https://github.com/RobLoach/ChaiScript.js
|
|
||||||
Copyright 2019, Rob Loach
|
|
||||||
Copyright 2009-2018, Jason Turner
|
|
||||||
Licensed under the BSD License. See "license.txt" for details.
|
|
||||||
-->
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>ChaiScript</title>
|
|
||||||
<style>
|
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
||||||
background: #1a1a2e;
|
|
||||||
color: #e0e0e0;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
header {
|
|
||||||
background: #16213e;
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
border-bottom: 2px solid #0f3460;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
header h1 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
color: #e94560;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
header span {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
#status {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
padding: 0.3rem 0.8rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: #0f3460;
|
|
||||||
}
|
|
||||||
#status.ready { color: #4ecca3; }
|
|
||||||
#status.loading { color: #e9c46a; }
|
|
||||||
#status.error { color: #e94560; }
|
|
||||||
main {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
gap: 0;
|
|
||||||
}
|
|
||||||
.panel {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
.panel-header {
|
|
||||||
background: #16213e;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.1em;
|
|
||||||
color: #888;
|
|
||||||
border-bottom: 1px solid #0f3460;
|
|
||||||
}
|
|
||||||
#input {
|
|
||||||
flex: 1;
|
|
||||||
background: #0d1117;
|
|
||||||
color: #c9d1d9;
|
|
||||||
border: none;
|
|
||||||
padding: 1rem;
|
|
||||||
font-family: "SF Mono", "Fira Code", "Fira Mono", Menlo, Consolas, monospace;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
line-height: 1.6;
|
|
||||||
resize: none;
|
|
||||||
outline: none;
|
|
||||||
tab-size: 2;
|
|
||||||
}
|
|
||||||
.divider {
|
|
||||||
width: 2px;
|
|
||||||
background: #0f3460;
|
|
||||||
}
|
|
||||||
#output {
|
|
||||||
flex: 1;
|
|
||||||
background: #0d1117;
|
|
||||||
padding: 1rem;
|
|
||||||
font-family: "SF Mono", "Fira Code", "Fira Mono", Menlo, Consolas, monospace;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
line-height: 1.6;
|
|
||||||
overflow-y: auto;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
.output-line { color: #c9d1d9; }
|
|
||||||
.output-error { color: #e94560; }
|
|
||||||
footer {
|
|
||||||
background: #16213e;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
align-items: center;
|
|
||||||
border-top: 2px solid #0f3460;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background: #e94560;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
padding: 0.4rem 1.2rem;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
button:hover { background: #c73652; }
|
|
||||||
button:disabled { background: #555; cursor: not-allowed; }
|
|
||||||
#btn-clear {
|
|
||||||
background: #0f3460;
|
|
||||||
}
|
|
||||||
#btn-clear:hover { background: #1a4a8a; }
|
|
||||||
.hint {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<h1>ChaiScript</h1>
|
|
||||||
<span>Interactive Playground</span>
|
|
||||||
<div id="status" class="loading">Loading...</div>
|
|
||||||
</header>
|
|
||||||
<main>
|
|
||||||
<div class="panel">
|
|
||||||
<div class="panel-header">Input</div>
|
|
||||||
<textarea id="input" spellcheck="false">// Welcome to ChaiScript!
|
|
||||||
// Write your code here and click Run (or press Ctrl+Enter).
|
|
||||||
|
|
||||||
def greet(name) {
|
|
||||||
return "Hello, " + name + "!"
|
|
||||||
}
|
|
||||||
|
|
||||||
print(greet("World"))
|
|
||||||
print(greet("ChaiScript"))
|
|
||||||
|
|
||||||
// Math example
|
|
||||||
def factorial(n) {
|
|
||||||
if (n <= 1) { return 1 }
|
|
||||||
return n * factorial(n - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
print("5! = " + to_string(factorial(5)))
|
|
||||||
print("10! = " + to_string(factorial(10)))
|
|
||||||
</textarea>
|
|
||||||
</div>
|
|
||||||
<div class="divider"></div>
|
|
||||||
<div class="panel">
|
|
||||||
<div class="panel-header">Output</div>
|
|
||||||
<div id="output"></div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<footer>
|
|
||||||
<button id="btn-run" disabled>Run</button>
|
|
||||||
<button id="btn-clear">Clear</button>
|
|
||||||
<span class="hint">Ctrl+Enter to run</span>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
var outputEl = document.getElementById('output');
|
|
||||||
var inputEl = document.getElementById('input');
|
|
||||||
var btnRun = document.getElementById('btn-run');
|
|
||||||
var btnClear = document.getElementById('btn-clear');
|
|
||||||
var statusEl = document.getElementById('status');
|
|
||||||
|
|
||||||
function appendOutput(text, className) {
|
|
||||||
var line = document.createElement('div');
|
|
||||||
line.className = className || 'output-line';
|
|
||||||
line.textContent = text;
|
|
||||||
outputEl.appendChild(line);
|
|
||||||
outputEl.scrollTop = outputEl.scrollHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
var chaiHandle = 0;
|
|
||||||
|
|
||||||
var Module = {
|
|
||||||
print: function(text) {
|
|
||||||
appendOutput(text);
|
|
||||||
},
|
|
||||||
printErr: function(text) {
|
|
||||||
appendOutput(text, 'output-error');
|
|
||||||
},
|
|
||||||
onRuntimeInitialized: function() {
|
|
||||||
chaiHandle = Module.create();
|
|
||||||
statusEl.textContent = 'Ready';
|
|
||||||
statusEl.className = 'ready';
|
|
||||||
btnRun.disabled = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function runCode() {
|
|
||||||
var code = inputEl.value;
|
|
||||||
if (!code.trim()) return;
|
|
||||||
|
|
||||||
appendOutput('> Running...', 'output-line');
|
|
||||||
try {
|
|
||||||
Module.eval(chaiHandle, code);
|
|
||||||
} catch (e) {
|
|
||||||
appendOutput('Error: ' + e.message, 'output-error');
|
|
||||||
}
|
|
||||||
appendOutput('', 'output-line');
|
|
||||||
}
|
|
||||||
|
|
||||||
btnRun.addEventListener('click', runCode);
|
|
||||||
btnClear.addEventListener('click', function() {
|
|
||||||
outputEl.innerHTML = '';
|
|
||||||
});
|
|
||||||
|
|
||||||
inputEl.addEventListener('keydown', function(e) {
|
|
||||||
if (e.ctrlKey && e.key === 'Enter') {
|
|
||||||
e.preventDefault();
|
|
||||||
runCode();
|
|
||||||
}
|
|
||||||
// Tab key inserts spaces
|
|
||||||
if (e.key === 'Tab') {
|
|
||||||
e.preventDefault();
|
|
||||||
var start = this.selectionStart;
|
|
||||||
var end = this.selectionEnd;
|
|
||||||
this.value = this.value.substring(0, start) + ' ' + this.value.substring(end);
|
|
||||||
this.selectionStart = this.selectionEnd = start + 2;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script src="chaiscript.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
// This file is distributed under the BSD License.
|
|
||||||
// See "license.txt" for details.
|
|
||||||
// Copyright 2019, Rob Loach (https://github.com/RobLoach/ChaiScript.js)
|
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
|
||||||
// http://www.chaiscript.com
|
|
||||||
//
|
|
||||||
// Emscripten/WebAssembly wrapper for ChaiScript.
|
|
||||||
// Based on work by Rob Loach: https://github.com/RobLoach/ChaiScript.js
|
|
||||||
|
|
||||||
#include "chaiscript_eval.hpp"
|
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
#include <emscripten/bind.h>
|
|
||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(chaiscript) {
|
|
||||||
emscripten::function("create", &chaiscript_create);
|
|
||||||
emscripten::function("destroy", &chaiscript_destroy);
|
|
||||||
emscripten::function("eval", &chaiscript_eval);
|
|
||||||
emscripten::function("evalString", &chaiscript_eval_string);
|
|
||||||
emscripten::function("evalBool", &chaiscript_eval_bool);
|
|
||||||
emscripten::function("evalInt", &chaiscript_eval_int);
|
|
||||||
emscripten::function("evalFloat", &chaiscript_eval_float);
|
|
||||||
emscripten::function("evalDouble", &chaiscript_eval_double);
|
|
||||||
emscripten::function("saveState", &chaiscript_save_state);
|
|
||||||
emscripten::function("restoreState", &chaiscript_restore_state);
|
|
||||||
emscripten::function("releaseState", &chaiscript_release_state);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
// This file is distributed under the BSD License.
|
|
||||||
// See "license.txt" for details.
|
|
||||||
// Copyright 2019, Rob Loach (https://github.com/RobLoach/ChaiScript.js)
|
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
|
||||||
// http://www.chaiscript.com
|
|
||||||
|
|
||||||
// Shared eval helper functions for the ChaiScript Emscripten wrapper.
|
|
||||||
// These functions provide typed evaluation of ChaiScript expressions,
|
|
||||||
// used by both the Emscripten/WebAssembly build and native tests.
|
|
||||||
//
|
|
||||||
// The interface is opaque and handle-based: JS callers create one or more
|
|
||||||
// engines via chaiscript_create(), pass the resulting handle to the eval and
|
|
||||||
// state helpers, and release the engine with chaiscript_destroy() when done.
|
|
||||||
// State snapshots are themselves opaque handles produced by
|
|
||||||
// chaiscript_save_state() and consumed by chaiscript_restore_state() /
|
|
||||||
// chaiscript_release_state(). Hiding ChaiScript and ChaiScript::State behind
|
|
||||||
// integer handles keeps embind from having to manage their lifetimes and
|
|
||||||
// avoids forcing a static singleton on the C++ side.
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_EMSCRIPTEN_EVAL_HPP_
|
|
||||||
#define CHAISCRIPT_EMSCRIPTEN_EVAL_HPP_
|
|
||||||
|
|
||||||
#include <chaiscript/chaiscript.hpp>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
// ChaiScript::State captures globals/functions/types but not the top-level
|
|
||||||
// scripting locals (variables created by `var x = ...` at the script's
|
|
||||||
// outermost scope). The playground's reset-between-runs use case needs both,
|
|
||||||
// so the snapshot pairs the engine state with the locals map.
|
|
||||||
struct Snapshot {
|
|
||||||
chaiscript::ChaiScript::State engine_state;
|
|
||||||
std::map<std::string, chaiscript::Boxed_Value> locals;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::unordered_map<int, std::unique_ptr<chaiscript::ChaiScript>> &chai_registry() {
|
|
||||||
static std::unordered_map<int, std::unique_ptr<chaiscript::ChaiScript>> registry;
|
|
||||||
return registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::unordered_map<int, Snapshot> &state_registry() {
|
|
||||||
static std::unordered_map<int, Snapshot> registry;
|
|
||||||
return registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int next_handle() {
|
|
||||||
static int handle = 0;
|
|
||||||
return ++handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline chaiscript::ChaiScript &get_chai(const int handle) {
|
|
||||||
return *chai_registry().at(handle);
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// Construct a fresh ChaiScript engine and return an opaque handle. The handle
|
|
||||||
// is owned by the caller and must be released with chaiscript_destroy().
|
|
||||||
inline int chaiscript_create() {
|
|
||||||
const int handle = detail::next_handle();
|
|
||||||
detail::chai_registry().emplace(handle, std::make_unique<chaiscript::ChaiScript>());
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy an engine handle. Unknown handles are silently ignored so JS callers
|
|
||||||
// do not need to track validity defensively.
|
|
||||||
inline void chaiscript_destroy(const int handle) {
|
|
||||||
detail::chai_registry().erase(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void chaiscript_eval(const int handle, const std::string &input) {
|
|
||||||
detail::get_chai(handle).eval(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string chaiscript_eval_string(const int handle, const std::string &input) {
|
|
||||||
return detail::get_chai(handle).eval<std::string>(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool chaiscript_eval_bool(const int handle, const std::string &input) {
|
|
||||||
return detail::get_chai(handle).eval<bool>(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int chaiscript_eval_int(const int handle, const std::string &input) {
|
|
||||||
return detail::get_chai(handle).eval<int>(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float chaiscript_eval_float(const int handle, const std::string &input) {
|
|
||||||
return detail::get_chai(handle).eval<float>(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double chaiscript_eval_double(const int handle, const std::string &input) {
|
|
||||||
return detail::get_chai(handle).eval<double>(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Snapshot the engine identified by chai_handle and return a fresh opaque
|
|
||||||
// state handle. Release it with chaiscript_release_state() when no longer
|
|
||||||
// needed.
|
|
||||||
inline int chaiscript_save_state(const int chai_handle) {
|
|
||||||
const int state_handle = detail::next_handle();
|
|
||||||
auto &chai = detail::get_chai(chai_handle);
|
|
||||||
detail::state_registry().emplace(state_handle, detail::Snapshot{chai.get_state(), chai.get_locals()});
|
|
||||||
return state_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore a previously snapshotted state onto the engine identified by
|
|
||||||
// chai_handle. Unknown state handles are silently ignored.
|
|
||||||
inline void chaiscript_restore_state(const int chai_handle, const int state_handle) {
|
|
||||||
const auto it = detail::state_registry().find(state_handle);
|
|
||||||
if (it != detail::state_registry().end()) {
|
|
||||||
auto &chai = detail::get_chai(chai_handle);
|
|
||||||
chai.set_state(it->second.engine_state);
|
|
||||||
chai.set_locals(it->second.locals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release a state handle returned by chaiscript_save_state. Releasing an
|
|
||||||
// unknown handle is a no-op.
|
|
||||||
inline void chaiscript_release_state(const int state_handle) {
|
|
||||||
detail::state_registry().erase(state_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CHAISCRIPT_EMSCRIPTEN_EVAL_HPP_ */
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
/*
|
|
||||||
* ChaiScript Grammar — EBNF for Railroad Diagram Generation
|
|
||||||
*
|
|
||||||
* View as navigable railroad diagrams at:
|
|
||||||
* https://www.bottlecaps.de/rr/ui (IPv6)
|
|
||||||
* https://rr.red-dove.com/ui (IPv4)
|
|
||||||
*
|
|
||||||
* Copy and paste this file into the 'Edit Grammar' tab, then
|
|
||||||
* click 'View Diagram'.
|
|
||||||
*
|
|
||||||
* This grammar uses the notation accepted by
|
|
||||||
* https://github.com/GuntherRademacher/rr :
|
|
||||||
* - "::=" as rule separator
|
|
||||||
* - no semicolon at end of rule
|
|
||||||
* - "?" "+" "*" for repetition
|
|
||||||
* - C comments
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ---- Top-level ---- */
|
|
||||||
|
|
||||||
statements ::= ( def | try | if | while | class | enum
|
|
||||||
| for | switch | return | break | continue
|
|
||||||
| equation | block | eol )+
|
|
||||||
|
|
||||||
/* ---- Functions ---- */
|
|
||||||
|
|
||||||
def ::= "def" id ( "::" id )? "(" decl_arg_list ")" eol*
|
|
||||||
( ":" guard )? eol* block
|
|
||||||
|
|
||||||
lambda ::= "fun" ( "[" id_arg_list "]" )? "(" decl_arg_list ")" eol* block
|
|
||||||
|
|
||||||
guard ::= operator
|
|
||||||
|
|
||||||
/* ---- Exception handling ---- */
|
|
||||||
|
|
||||||
try ::= "try" eol* block catch* finally?
|
|
||||||
catch ::= "catch" ( "(" arg ")" )? eol* block
|
|
||||||
finally ::= "finally" eol* block
|
|
||||||
|
|
||||||
/* ---- Control flow ---- */
|
|
||||||
|
|
||||||
if ::= "if" "(" equation ( eol equation )? ")" eol* block
|
|
||||||
( "else" ( if | eol* block ) )*
|
|
||||||
|
|
||||||
while ::= "while" "(" operator ")" eol* block
|
|
||||||
|
|
||||||
for ::= "for" "(" ( for_guards | equation ":" equation ) ")" eol* block
|
|
||||||
for_guards ::= equation eol equation eol equation
|
|
||||||
|
|
||||||
switch ::= "switch" "(" operator ")" eol* "{" ( case | default )+ "}"
|
|
||||||
case ::= "case" "(" operator ")" eol* block
|
|
||||||
default ::= "default" eol* block
|
|
||||||
|
|
||||||
/* ---- Classes ---- */
|
|
||||||
|
|
||||||
class ::= "class" id ( ":" id )? eol* class_block
|
|
||||||
class_block ::= "{" class_statements* "}"
|
|
||||||
class_statements ::= def | var_decl | eol
|
|
||||||
|
|
||||||
/* ---- Enums ---- */
|
|
||||||
|
|
||||||
enum ::= "enum" ( "class" | "struct" ) id ( ":" underlying_type )?
|
|
||||||
"{" enum_entries? "}"
|
|
||||||
|
|
||||||
enum_entries ::= enum_entry ( "," enum_entry )*
|
|
||||||
|
|
||||||
enum_entry ::= id ( "=" integer )?
|
|
||||||
|
|
||||||
underlying_type ::= id
|
|
||||||
|
|
||||||
|
|
||||||
/* ---- Blocks & flow keywords ---- */
|
|
||||||
|
|
||||||
block ::= "{" statements* "}"
|
|
||||||
return ::= "return" operator?
|
|
||||||
break ::= "break"
|
|
||||||
continue ::= "continue"
|
|
||||||
|
|
||||||
/* ---- Line termination ---- */
|
|
||||||
|
|
||||||
eol ::= "\n" | "\r\n" | ";"
|
|
||||||
|
|
||||||
/* ---- Equations & operators ---- */
|
|
||||||
|
|
||||||
equation ::= operator ( ( "=" | ":=" | "+=" | "-=" | "*=" | "/="
|
|
||||||
| "%=" | "<<=" | ">>=" | "&=" | "^=" | "|=" )
|
|
||||||
equation )?
|
|
||||||
|
|
||||||
operator ::= prefix
|
|
||||||
| value
|
|
||||||
| operator binary_operator operator
|
|
||||||
| operator "?" operator ":" operator
|
|
||||||
|
|
||||||
prefix ::= ( "++" | "--" | "-" | "+" | "!" | "~" ) operator
|
|
||||||
|
|
||||||
binary_operator ::= "||" | "&&"
|
|
||||||
| "|" | "^" | "&"
|
|
||||||
| "==" | "!="
|
|
||||||
| "<" | "<=" | ">" | ">="
|
|
||||||
| "<<" | ">>"
|
|
||||||
| "+" | "-"
|
|
||||||
| "*" | "/" | "%"
|
|
||||||
|
|
||||||
/* ---- Values & access ---- */
|
|
||||||
|
|
||||||
value ::= var_decl | dot_fun_array | prefix
|
|
||||||
|
|
||||||
dot_fun_array ::= ( lambda | num | quoted_string
|
|
||||||
| single_quoted_string | raw_string
|
|
||||||
| paren_expression | inline_container
|
|
||||||
| id )
|
|
||||||
( fun_call | array_call | dot_access )*
|
|
||||||
|
|
||||||
fun_call ::= "(" arg_list ")"
|
|
||||||
array_call ::= "[" operator "]"
|
|
||||||
dot_access ::= "." id
|
|
||||||
|
|
||||||
/* ---- Variable declarations ---- */
|
|
||||||
|
|
||||||
var_decl ::= ( "auto" | "var" | "const" ) ( reference | id )
|
|
||||||
| "global" ( reference | id )
|
|
||||||
| "attr" id ( "::" id )?
|
|
||||||
|
|
||||||
reference ::= "&" id
|
|
||||||
|
|
||||||
/* ---- Parenthesised & inline containers ---- */
|
|
||||||
|
|
||||||
paren_expression ::= "(" operator ")"
|
|
||||||
|
|
||||||
inline_container ::= "[" container_arg_list "]"
|
|
||||||
container_arg_list ::= value_range
|
|
||||||
| map_pair ( "," map_pair )*
|
|
||||||
| operator ( "," operator )*
|
|
||||||
|
|
||||||
value_range ::= operator ".." operator
|
|
||||||
map_pair ::= operator ":" operator
|
|
||||||
|
|
||||||
/* ---- String literals ---- */
|
|
||||||
|
|
||||||
quoted_string ::= '"' ( char | escape | interpolation )* '"'
|
|
||||||
single_quoted_string ::= "'" ( char | escape ) "'"
|
|
||||||
raw_string ::= 'R"' delimiter? "(" char* ")" delimiter? '"'
|
|
||||||
delimiter ::= [a-zA-Z0-9_]+
|
|
||||||
interpolation ::= "${" equation "}"
|
|
||||||
|
|
||||||
/* ---- Escape sequences ---- */
|
|
||||||
|
|
||||||
escape ::= "\" ( "'" | '"' | "?" | "\" | "a" | "b"
|
|
||||||
| "f" | "n" | "r" | "t" | "v" | "$"
|
|
||||||
| "0"
|
|
||||||
| "x" hex_digit+
|
|
||||||
| "u" hex_digit hex_digit hex_digit hex_digit
|
|
||||||
| "U" hex_digit hex_digit hex_digit hex_digit
|
|
||||||
hex_digit hex_digit hex_digit hex_digit
|
|
||||||
| octal_digit+ )
|
|
||||||
|
|
||||||
/* ---- Argument lists ---- */
|
|
||||||
|
|
||||||
id_arg_list ::= id ( "," id )*
|
|
||||||
decl_arg_list ::= ( arg ( "," arg )* )?
|
|
||||||
arg_list ::= ( equation ( "," equation )* )?
|
|
||||||
arg ::= id id?
|
|
||||||
|
|
||||||
/* ---- Identifiers ---- */
|
|
||||||
|
|
||||||
id ::= ( [a-zA-Z_] [a-zA-Z0-9_]* )
|
|
||||||
| ( "`" [^`]+ "`" )
|
|
||||||
| "true" | "false"
|
|
||||||
| "Infinity" | "NaN"
|
|
||||||
| "_"
|
|
||||||
| "__LINE__" | "__FILE__" | "__FUNC__" | "__CLASS__"
|
|
||||||
|
|
||||||
/* ---- Numeric literals ---- */
|
|
||||||
|
|
||||||
num ::= hex | binary | float | integer
|
|
||||||
|
|
||||||
hex ::= "0" ( "x" | "X" ) [0-9a-fA-F]+ int_suffix*
|
|
||||||
binary ::= "0" ( "b" | "B" ) [01]+ int_suffix*
|
|
||||||
float ::= [0-9]+ "." [0-9]+ ( ( "e" | "E" ) ( "+" | "-" )? [0-9]+ )? float_suffix?
|
|
||||||
integer ::= [0-9]+ int_suffix*
|
|
||||||
|
|
||||||
int_suffix ::= "l" | "L" | "ll" | "LL" | "u" | "U"
|
|
||||||
float_suffix ::= "l" | "L" | "f" | "F"
|
|
||||||
|
|
||||||
/* ---- Character classes ---- */
|
|
||||||
|
|
||||||
octal_digit ::= [0-7]
|
|
||||||
hex_digit ::= [0-9a-fA-F]
|
|
||||||
char ::= [^"\]
|
|
||||||
@ -1,15 +1,14 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_HPP_
|
#ifndef CHAISCRIPT_HPP_
|
||||||
#define CHAISCRIPT_HPP_
|
#define CHAISCRIPT_HPP_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @mainpage
|
/// @mainpage
|
||||||
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
|
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
|
||||||
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
|
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
|
||||||
@ -19,8 +18,7 @@
|
|||||||
///
|
///
|
||||||
/// The end user parts of the API are extremely simple both in size and ease of use.
|
/// The end user parts of the API are extremely simple both in size and ease of use.
|
||||||
///
|
///
|
||||||
/// Currently, all source control and project management aspects of ChaiScript occur on
|
/// Currently, all source control and project management aspects of ChaiScript occur on [github](http://www.github.com/ChaiScript/ChaiScript").
|
||||||
/// [github](http://www.github.com/ChaiScript/ChaiScript").
|
|
||||||
///
|
///
|
||||||
/// ------------------------------------------------------------
|
/// ------------------------------------------------------------
|
||||||
///
|
///
|
||||||
@ -67,7 +65,7 @@
|
|||||||
/// int main()
|
/// int main()
|
||||||
/// {
|
/// {
|
||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
/// chai.add(chaiscript::fun(&function), "function");
|
/// chai.add(&function, "function");
|
||||||
///
|
///
|
||||||
/// double d = chai.eval<double>("function(3, 4.75);");
|
/// double d = chai.eval<double>("function(3, 4.75);");
|
||||||
/// }
|
/// }
|
||||||
@ -313,8 +311,8 @@
|
|||||||
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
|
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
|
||||||
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
|
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
|
||||||
///
|
///
|
||||||
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference
|
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting).
|
||||||
/// counting). Const may be added, but never removed.
|
/// Const may be added, but never removed.
|
||||||
///
|
///
|
||||||
/// The take away is that you can pretty much expect function calls to Just Work when you need them to.
|
/// The take away is that you can pretty much expect function calls to Just Work when you need them to.
|
||||||
///
|
///
|
||||||
@ -468,8 +466,7 @@
|
|||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
///
|
///
|
||||||
/// try {
|
/// try {
|
||||||
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const
|
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||||
/// std::exception &>());
|
|
||||||
/// } catch (const double e) {
|
/// } catch (const double e) {
|
||||||
/// } catch (int) {
|
/// } catch (int) {
|
||||||
/// } catch (float) {
|
/// } catch (float) {
|
||||||
@ -482,6 +479,8 @@
|
|||||||
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
|
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
|
||||||
/// @sa chaiscript::exception_specification
|
/// @sa chaiscript::exception_specification
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference
|
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
@ -649,6 +648,7 @@
|
|||||||
/// @sa @ref LangKeywordRef
|
/// @sa @ref LangKeywordRef
|
||||||
/// @sa ChaiScript_Language for Built in Functions
|
/// @sa ChaiScript_Language for Built in Functions
|
||||||
|
|
||||||
|
|
||||||
/// @page LangKeywordRef ChaiScript Language Keyword Reference
|
/// @page LangKeywordRef ChaiScript Language Keyword Reference
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
@ -695,10 +695,11 @@
|
|||||||
/// Begins a function or method definition
|
/// Begins a function or method definition
|
||||||
///
|
///
|
||||||
/// ~~~~~~~~
|
/// ~~~~~~~~
|
||||||
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||||
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||||
/// ~~~~~~~~
|
/// ~~~~~~~~
|
||||||
///
|
///
|
||||||
|
/// annotation: meta-annotation on function, currently used as documentation. Optional.
|
||||||
/// identifier: name of function. Required.
|
/// identifier: name of function. Required.
|
||||||
/// args: comma-delimited list of parameter names with optional type specifiers. Optional.
|
/// args: comma-delimited list of parameter names with optional type specifiers. Optional.
|
||||||
/// guards: guarding statement that act as a prerequisite for the function. Optional.
|
/// guards: guarding statement that act as a prerequisite for the function. Optional.
|
||||||
@ -809,31 +810,23 @@
|
|||||||
///
|
///
|
||||||
/// Synonym for @ref keywordauto
|
/// Synonym for @ref keywordauto
|
||||||
|
|
||||||
|
|
||||||
/// @namespace chaiscript
|
/// @namespace chaiscript
|
||||||
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
|
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
|
||||||
|
|
||||||
/// @namespace chaiscript::detail
|
/// @namespace chaiscript::detail
|
||||||
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
|
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
|
||||||
|
|
||||||
#include "chaiscript_basic.hpp"
|
#include "chaiscript_defines.hpp"
|
||||||
#include "chaiscript_stdlib.hpp"
|
|
||||||
#include "language/chaiscript_parser.hpp"
|
#include "dispatchkit/dispatchkit.hpp"
|
||||||
|
#include "dispatchkit/function_call.hpp"
|
||||||
|
#include "dispatchkit/dynamic_object.hpp"
|
||||||
|
#include "dispatchkit/boxed_number.hpp"
|
||||||
|
|
||||||
|
#include "language/chaiscript_eval.hpp"
|
||||||
|
#include "language/chaiscript_engine.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace chaiscript {
|
|
||||||
class ChaiScript : public ChaiScript_Basic {
|
|
||||||
public:
|
|
||||||
ChaiScript(std::vector<std::string> t_modulepaths = {},
|
|
||||||
std::vector<std::string> t_usepaths = {},
|
|
||||||
std::vector<Options> t_opts = chaiscript::default_options(),
|
|
||||||
std::vector<Library_Options> t_lib_opts = {})
|
|
||||||
: ChaiScript_Basic(chaiscript::Std_Lib::library(t_lib_opts),
|
|
||||||
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
|
|
||||||
std::move(t_modulepaths),
|
|
||||||
std::move(t_usepaths),
|
|
||||||
std::move(t_opts),
|
|
||||||
std::find(t_lib_opts.begin(), t_lib_opts.end(), Library_Options::No_IO) != t_lib_opts.end()) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace chaiscript
|
|
||||||
|
|
||||||
#endif /* CHAISCRIPT_HPP_ */
|
#endif /* CHAISCRIPT_HPP_ */
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
// This file is distributed under the BSD License.
|
|
||||||
// See "license.txt" for details.
|
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
|
||||||
// http://www.chaiscript.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BASIC_HPP_
|
|
||||||
#define CHAISCRIPT_BASIC_HPP_
|
|
||||||
|
|
||||||
#include "chaiscript_defines.hpp"
|
|
||||||
|
|
||||||
#include "dispatchkit/boxed_number.hpp"
|
|
||||||
#include "dispatchkit/dispatchkit.hpp"
|
|
||||||
#include "dispatchkit/dynamic_object.hpp"
|
|
||||||
#include "dispatchkit/function_call.hpp"
|
|
||||||
|
|
||||||
#include "language/chaiscript_engine.hpp"
|
|
||||||
#include "language/chaiscript_eval.hpp"
|
|
||||||
|
|
||||||
// This file includes all of the basic requirements for ChaiScript,
|
|
||||||
// to use, you might do something like:
|
|
||||||
//
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
#include "chaiscript_stdlib.hpp"
|
|
||||||
#include "language/chaiscript_parser.hpp"
|
|
||||||
|
|
||||||
ChaiScript_Basic chai(
|
|
||||||
chaiscript::Std_Lib::library(),
|
|
||||||
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>());
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
|
|
||||||
|
|
||||||
#endif /* CHAISCRIPT_BASIC_HPP_ */
|
|
||||||
@ -1,36 +1,24 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_DEFINES_HPP_
|
#ifndef CHAISCRIPT_DEFINES_HPP_
|
||||||
#define CHAISCRIPT_DEFINES_HPP_
|
#define CHAISCRIPT_DEFINES_HPP_
|
||||||
|
|
||||||
// MacOSX Fix: std::get/std::get_if/std::visit for std::variant are annotated
|
|
||||||
// __attribute__((availability(macos,strict,introduced=10.14))) in Apple libc++.
|
|
||||||
// Defining this macro before any libc++ header strips those annotations so
|
|
||||||
// ChaiScript can be built against older MacOSX deployment targets.
|
|
||||||
#if defined(__APPLE__) && defined(__clang__)
|
|
||||||
#ifndef _LIBCPP_DISABLE_AVAILABILITY
|
|
||||||
#define _LIBCPP_DISABLE_AVAILABILITY
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define CHAISCRIPT_STRINGIZE(x) "" #x
|
|
||||||
#define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x)
|
|
||||||
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
|
|
||||||
#define CHAISCRIPT_MSVC _MSC_VER
|
#define CHAISCRIPT_MSVC _MSC_VER
|
||||||
#define CHAISCRIPT_HAS_DECLSPEC
|
#define CHAISCRIPT_HAS_DECLSPEC
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
|
#define CHAISCRIPT_MSVC_12
|
||||||
|
#endif
|
||||||
#else
|
#endif
|
||||||
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
|
|
||||||
|
#ifndef CHAISCRIPT_MSVC_12
|
||||||
|
#define CHAISCRIPT_HAS_MAGIC_STATICS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#if defined( _LIBCPP_VERSION )
|
#if defined( _LIBCPP_VERSION )
|
||||||
@ -41,76 +29,47 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req
|
|||||||
#define CHAISCRIPT_WINDOWS
|
#define CHAISCRIPT_WINDOWS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || (defined(__llvm__) && !defined(CHAISCRIPT_LIBCPP))
|
||||||
#if defined(__llvm__)
|
/// Currently only g++>=4.8 supports this natively
|
||||||
#define CHAISCRIPT_COMPILER_NAME "clang(windows)"
|
/// \todo Make this support other compilers when possible
|
||||||
#elif defined(__GNUC__)
|
#define CHAISCRIPT_HAS_THREAD_LOCAL
|
||||||
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
|
|
||||||
#else
|
|
||||||
#define CHAISCRIPT_COMPILER_NAME "msvc"
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if defined(__llvm__)
|
|
||||||
#define CHAISCRIPT_COMPILER_NAME "clang"
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
#define CHAISCRIPT_COMPILER_NAME "gcc"
|
|
||||||
#else
|
|
||||||
#define CHAISCRIPT_COMPILER_NAME "unknown"
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__llvm__)
|
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
|
||||||
#define CHAISCRIPT_CLANG
|
#define CHAISCRIPT_GCC_4_6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) && __GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || defined(CHAISCRIPT_MSVC) || defined(__llvm__)
|
||||||
|
#define CHAISCRIPT_OVERRIDE override
|
||||||
|
#else
|
||||||
|
#define CHAISCRIPT_OVERRIDE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef CHAISCRIPT_HAS_DECLSPEC
|
#ifdef CHAISCRIPT_HAS_DECLSPEC
|
||||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef CHAISCRIPT_MSVC_12
|
||||||
#define CHAISCRIPT_DEBUG true
|
#define CHAISCRIPT_NOEXCEPT throw()
|
||||||
|
#define CHAISCRIPT_CONSTEXPR
|
||||||
#else
|
#else
|
||||||
#define CHAISCRIPT_DEBUG false
|
#define CHAISCRIPT_NOEXCEPT noexcept
|
||||||
|
#define CHAISCRIPT_CONSTEXPR constexpr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Upper bound on the depth of nested ChaiScript function calls. Hitting it
|
|
||||||
// causes the dispatcher to throw chaiscript::exception::stack_overflow_error
|
|
||||||
// instead of letting the native call stack overflow. Defining the macro on
|
|
||||||
// the command line overrides the default.
|
|
||||||
//
|
|
||||||
// MSVC Debug builds emit very large per-frame native stack usage (no inlining,
|
|
||||||
// /RTC, buffer security checks) and Windows defaults to a 1 MiB thread stack,
|
|
||||||
// so the same ChaiScript depth that fits comfortably on Linux/macOS or in an
|
|
||||||
// MSVC Release build overflows the native stack before the depth check fires.
|
|
||||||
// We pick a tighter default in that configuration to keep the throw reachable.
|
|
||||||
#ifndef CHAISCRIPT_MAX_CALL_DEPTH
|
|
||||||
#if defined(CHAISCRIPT_MSVC) && CHAISCRIPT_DEBUG
|
|
||||||
#define CHAISCRIPT_MAX_CALL_DEPTH 32
|
|
||||||
#else
|
|
||||||
#define CHAISCRIPT_MAX_CALL_DEPTH 256
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
constexpr static const int version_major = 7;
|
static const int version_major = 5;
|
||||||
constexpr static const int version_minor = 0;
|
static const int version_minor = 7;
|
||||||
constexpr static const int version_patch = 0;
|
static const int version_patch = 2;
|
||||||
|
|
||||||
constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
|
|
||||||
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
|
|
||||||
constexpr static const bool debug_build = CHAISCRIPT_DEBUG;
|
|
||||||
|
|
||||||
constexpr static const int max_call_depth = CHAISCRIPT_MAX_CALL_DEPTH;
|
|
||||||
static_assert(max_call_depth > 0, "CHAISCRIPT_MAX_CALL_DEPTH must be a positive integer");
|
|
||||||
|
|
||||||
template<typename B, typename D, typename ...Arg>
|
template<typename B, typename D, typename ...Arg>
|
||||||
inline std::shared_ptr<B> make_shared(Arg &&...arg) {
|
inline std::shared_ptr<B> make_shared(Arg && ... arg)
|
||||||
|
{
|
||||||
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
|
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
|
||||||
return std::make_shared<D>(std::forward<Arg>(arg)...);
|
return std::make_shared<D>(std::forward<Arg>(arg)...);
|
||||||
#else
|
#else
|
||||||
@ -118,161 +77,6 @@ namespace chaiscript {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename B, typename D, typename... Arg>
|
}
|
||||||
inline std::unique_ptr<B> make_unique(Arg &&...arg) {
|
|
||||||
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
|
|
||||||
return std::make_unique<D>(std::forward<Arg>(arg)...);
|
|
||||||
#else
|
|
||||||
return std::unique_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
struct Build_Info {
|
|
||||||
[[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
|
|
||||||
|
|
||||||
[[nodiscard]] static std::string version() {
|
|
||||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
|
|
||||||
|
|
||||||
[[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
|
|
||||||
|
|
||||||
[[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
|
|
||||||
|
|
||||||
[[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type {
|
|
||||||
T t = 0;
|
|
||||||
for (const auto c : t_str) {
|
|
||||||
if (c < '0' || c > '9') {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
t *= 10;
|
|
||||||
t += c - '0';
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type {
|
|
||||||
T t = 0;
|
|
||||||
T base{};
|
|
||||||
T decimal_place = 0;
|
|
||||||
int exponent = 0;
|
|
||||||
|
|
||||||
for (const auto c : t_str) {
|
|
||||||
switch (c) {
|
|
||||||
case '.':
|
|
||||||
decimal_place = 10;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
case 'E':
|
|
||||||
exponent = 1;
|
|
||||||
decimal_place = 0;
|
|
||||||
base = t;
|
|
||||||
t = 0;
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
exponent = -1;
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
break;
|
|
||||||
case '0':
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
if (decimal_place < 10) {
|
|
||||||
t *= 10;
|
|
||||||
t += static_cast<T>(c - '0');
|
|
||||||
} else {
|
|
||||||
t += static_cast<T>(c - '0') / decimal_place;
|
|
||||||
decimal_place *= 10;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct str_equal {
|
|
||||||
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs == t_rhs; }
|
|
||||||
template<typename LHS, typename RHS>
|
|
||||||
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
|
|
||||||
return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
|
|
||||||
}
|
|
||||||
struct is_transparent {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct str_less {
|
|
||||||
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; }
|
|
||||||
template<typename LHS, typename RHS>
|
|
||||||
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
|
|
||||||
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
|
|
||||||
}
|
|
||||||
struct is_transparent {
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Options {
|
|
||||||
No_Load_Modules,
|
|
||||||
Load_Modules,
|
|
||||||
No_External_Scripts,
|
|
||||||
External_Scripts
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Library_Options {
|
|
||||||
No_Stdlib,
|
|
||||||
No_IO,
|
|
||||||
No_Prelude,
|
|
||||||
No_JSON
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename From, typename To>
|
|
||||||
struct is_nothrow_forward_constructible : std::bool_constant<noexcept(To{std::declval<From>()})> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class From, class To>
|
|
||||||
static inline constexpr bool is_nothrow_forward_constructible_v = is_nothrow_forward_constructible<From, To>::value;
|
|
||||||
|
|
||||||
template<typename Container, typename... T>
|
|
||||||
[[nodiscard]] constexpr auto make_container(T &&...t) {
|
|
||||||
Container c;
|
|
||||||
c.reserve(sizeof...(t));
|
|
||||||
(c.push_back(std::forward<T>(t)), ...);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... T>
|
|
||||||
[[nodiscard]] auto make_vector(T &&...t) -> std::vector<std::common_type_t<std::decay_t<T>...>> {
|
|
||||||
using container_type = std::vector<std::common_type_t<std::decay_t<T>...>>;
|
|
||||||
|
|
||||||
return make_container<container_type>(std::forward<T>(t)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] inline std::vector<Options> default_options() {
|
|
||||||
#ifdef CHAISCRIPT_NO_DYNLOAD
|
|
||||||
return {Options::No_Load_Modules, Options::External_Scripts};
|
|
||||||
#else
|
|
||||||
return {Options::Load_Modules, Options::External_Scripts};
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} // namespace chaiscript
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -10,74 +10,57 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "chaiscript_defines.hpp"
|
#include "chaiscript_defines.hpp"
|
||||||
#include "language/chaiscript_common.hpp"
|
#include "dispatchkit/dispatchkit.hpp"
|
||||||
|
|
||||||
#include "dispatchkit/function_call.hpp"
|
|
||||||
|
|
||||||
// #include "dispatchkit/dispatchkit.hpp"
|
|
||||||
#include "dispatchkit/bootstrap.hpp"
|
#include "dispatchkit/bootstrap.hpp"
|
||||||
#include "dispatchkit/bootstrap_stl.hpp"
|
#include "dispatchkit/bootstrap_stl.hpp"
|
||||||
#include "dispatchkit/operators.hpp"
|
#include "dispatchkit/boxed_value.hpp"
|
||||||
// #include "dispatchkit/boxed_value.hpp"
|
#include "language/chaiscript_prelude.chai"
|
||||||
#include "dispatchkit/register_function.hpp"
|
|
||||||
#include "language/chaiscript_prelude.hpp"
|
|
||||||
#include "utility/json_wrap.hpp"
|
#include "utility/json_wrap.hpp"
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
#include <future>
|
#include <future>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/// @file
|
/// @file
|
||||||
///
|
///
|
||||||
/// This file generates the standard library that normal ChaiScript usage requires.
|
/// This file generates the standard library that normal ChaiScript usage requires.
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
class Std_Lib {
|
{
|
||||||
|
class Std_Lib
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static ModulePtr library(const std::vector<Library_Options> &t_opts = {}) {
|
|
||||||
if (std::find(t_opts.begin(), t_opts.end(), Library_Options::No_Stdlib) != t_opts.end()) {
|
|
||||||
return std::make_shared<Module>();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lib = std::make_shared<Module>();
|
static ModulePtr library()
|
||||||
|
{
|
||||||
|
using namespace bootstrap;
|
||||||
|
|
||||||
const bool no_prelude = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_Prelude) != t_opts.end();
|
ModulePtr lib = Bootstrap::bootstrap();
|
||||||
const bool no_json = std::find(t_opts.begin(), t_opts.end(), Library_Options::No_JSON) != t_opts.end();
|
|
||||||
|
|
||||||
bootstrap::Bootstrap::bootstrap(*lib);
|
lib->add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
|
||||||
|
lib->add(standard_library::string_type<std::string>("string"));
|
||||||
bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
|
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
|
||||||
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
|
||||||
bootstrap::standard_library::string_view_type<std::string_view, std::string>("string_view", *lib);
|
|
||||||
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value>>("Map", *lib);
|
|
||||||
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value>>("Pair", *lib);
|
|
||||||
|
|
||||||
// Allow explicit conversion from std::string_view back to std::string,
|
|
||||||
// e.g. `string(sv)` in ChaiScript.
|
|
||||||
lib->add(fun([](const std::string_view sv) { return std::string{sv}; }), "string");
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
|
lib->add(standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future"));
|
||||||
// Note: async() is registered in ChaiScript_Basic::build_eval_system()
|
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||||
// with thread tracking to prevent heap-use-after-free on engine destruction.
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!no_json) {
|
lib->add(json_wrap::library());
|
||||||
json_wrap::library(*lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!no_prelude) {
|
|
||||||
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
||||||
}
|
|
||||||
|
|
||||||
return lib;
|
return lib;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +1,18 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_THREADING_HPP_
|
#ifndef CHAISCRIPT_THREADING_HPP_
|
||||||
#define CHAISCRIPT_THREADING_HPP_
|
#define CHAISCRIPT_THREADING_HPP_
|
||||||
|
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
#include <mutex>
|
|
||||||
#include <shared_mutex>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
#else
|
#else
|
||||||
#ifndef CHAISCRIPT_NO_THREADS_WARNING
|
#ifndef CHAISCRIPT_NO_THREADS_WARNING
|
||||||
#pragma message ("ChaiScript is compiling without thread safety.")
|
#pragma message ("ChaiScript is compiling without thread safety.")
|
||||||
@ -32,102 +29,213 @@
|
|||||||
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
|
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
|
||||||
/// one thread simultaneously.
|
/// one thread simultaneously.
|
||||||
|
|
||||||
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
/// If threading is enabled, then this namespace contains std thread classes.
|
/// If threading is enabled, then this namespace contains std thread classes.
|
||||||
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
|
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
|
||||||
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
|
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
|
||||||
namespace chaiscript::detail::threading {
|
namespace threading
|
||||||
|
{
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using unique_lock = std::unique_lock<T>;
|
class unique_lock : public std::unique_lock<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
unique_lock(T &t) : std::unique_lock<T>(t) {}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using shared_lock = std::shared_lock<T>;
|
class shared_lock : public std::unique_lock<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
shared_lock(T &t) : std::unique_lock<T>(t) {}
|
||||||
|
void unlock() {}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using lock_guard = std::lock_guard<T>;
|
class lock_guard : public std::lock_guard<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
lock_guard(T &t) : std::lock_guard<T>(t) {}
|
||||||
|
};
|
||||||
|
|
||||||
using std::shared_mutex;
|
class shared_mutex : public std::mutex { };
|
||||||
|
|
||||||
using std::mutex;
|
using std::mutex;
|
||||||
|
|
||||||
using std::recursive_mutex;
|
using std::recursive_mutex;
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_HAS_THREAD_LOCAL
|
||||||
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
|
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
|
||||||
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
|
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Thread_Storage {
|
class Thread_Storage
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Thread_Storage() = default;
|
|
||||||
Thread_Storage(const Thread_Storage &) = delete;
|
|
||||||
Thread_Storage(Thread_Storage &&) = delete;
|
|
||||||
Thread_Storage &operator=(const Thread_Storage &) = delete;
|
|
||||||
Thread_Storage &operator=(Thread_Storage &&) = delete;
|
|
||||||
|
|
||||||
~Thread_Storage() { t().erase(this); }
|
Thread_Storage(void *t_key)
|
||||||
|
: m_key(t_key)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
inline const T *operator->() const noexcept { return &(t()[this]); }
|
~Thread_Storage()
|
||||||
|
{
|
||||||
|
t().erase(m_key);
|
||||||
|
}
|
||||||
|
|
||||||
inline const T &operator*() const noexcept { return t()[this]; }
|
inline const T *operator->() const
|
||||||
|
{
|
||||||
|
return &(t()[m_key]);
|
||||||
|
}
|
||||||
|
|
||||||
inline T *operator->() noexcept { return &(t()[this]); }
|
inline const T &operator*() const
|
||||||
|
{
|
||||||
|
return t()[m_key];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T *operator->()
|
||||||
|
{
|
||||||
|
return &(t()[m_key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T &operator*()
|
||||||
|
{
|
||||||
|
return t()[m_key];
|
||||||
|
}
|
||||||
|
|
||||||
inline T &operator*() noexcept { return t()[this]; }
|
|
||||||
|
|
||||||
void *m_key;
|
void *m_key;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// todo: is it valid to make this noexcept? The allocation could fail, but if it
|
static std::unordered_map<void*, T> &t()
|
||||||
/// does there is no possible way to recover
|
{
|
||||||
static std::unordered_map<const void *, T> &t() noexcept {
|
thread_local static std::unordered_map<void *, T> my_t;
|
||||||
static thread_local std::unordered_map<const void *, T> my_t;
|
|
||||||
return my_t;
|
return my_t;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
|
||||||
|
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
|
||||||
|
///
|
||||||
|
/// This version is used if the compiler does not support thread_local
|
||||||
|
template<typename T>
|
||||||
|
class Thread_Storage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Thread_Storage(void *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T *operator->() const
|
||||||
|
{
|
||||||
|
return get_tls().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const T &operator*() const
|
||||||
|
{
|
||||||
|
return *get_tls();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T *operator->()
|
||||||
|
{
|
||||||
|
return get_tls().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T &operator*()
|
||||||
|
{
|
||||||
|
return *get_tls();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// \todo this leaks thread instances. It needs to be culled from time to time
|
||||||
|
std::shared_ptr<T> get_tls() const
|
||||||
|
{
|
||||||
|
unique_lock<mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
auto itr = m_instances.find(std::this_thread::get_id());
|
||||||
|
|
||||||
|
if (itr != m_instances.end()) { return itr->second; }
|
||||||
|
|
||||||
|
std::shared_ptr<T> new_instance(std::make_shared<T>());
|
||||||
|
|
||||||
|
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
|
||||||
|
|
||||||
|
return new_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mutable mutex m_mutex;
|
||||||
|
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
|
||||||
|
};
|
||||||
|
#endif // threading enabled but no tls
|
||||||
|
|
||||||
#else // threading disabled
|
#else // threading disabled
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class unique_lock {
|
class unique_lock
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
constexpr explicit unique_lock(T &) noexcept {}
|
unique_lock(T &) {}
|
||||||
constexpr void lock() noexcept {}
|
void lock() {}
|
||||||
constexpr void unlock() noexcept {}
|
void unlock() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class shared_lock {
|
class shared_lock
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
constexpr explicit shared_lock(T &) noexcept {}
|
shared_lock(T &) {}
|
||||||
constexpr void lock() noexcept {}
|
void lock() {}
|
||||||
constexpr void unlock() noexcept {}
|
void unlock() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class lock_guard {
|
class lock_guard
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
constexpr explicit lock_guard(T &) noexcept {}
|
lock_guard(T &) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class shared_mutex {
|
class shared_mutex { };
|
||||||
};
|
|
||||||
|
class recursive_mutex {};
|
||||||
|
|
||||||
class recursive_mutex {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Thread_Storage {
|
class Thread_Storage
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
constexpr explicit Thread_Storage() noexcept {}
|
Thread_Storage(void *)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
constexpr inline T *operator->() const noexcept { return &obj; }
|
inline T *operator->() const
|
||||||
|
{
|
||||||
|
return &obj;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr inline T &operator*() const noexcept { return obj; }
|
inline T &operator*() const
|
||||||
|
{
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable T obj;
|
mutable T obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
} // namespace chaiscript::detail::threading
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -11,48 +11,80 @@
|
|||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace exception {
|
namespace exception
|
||||||
|
{
|
||||||
/// \brief Thrown in the event that an Any cannot be cast to the desired type
|
/// \brief Thrown in the event that an Any cannot be cast to the desired type
|
||||||
///
|
///
|
||||||
/// It is used internally during function dispatch.
|
/// It is used internally during function dispatch.
|
||||||
///
|
///
|
||||||
/// \sa chaiscript::detail::Any
|
/// \sa chaiscript::detail::Any
|
||||||
class bad_any_cast : public std::bad_cast {
|
class bad_any_cast : public std::bad_cast
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
|
bad_any_cast() CHAISCRIPT_NOEXCEPT
|
||||||
|
: m_what("bad any cast")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bad_any_cast(const bad_any_cast &) = default;
|
||||||
|
|
||||||
|
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
|
||||||
/// \brief Description of what error occurred
|
/// \brief Description of what error occurred
|
||||||
const char *what() const noexcept override { return "bad any cast"; }
|
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return m_what.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_what;
|
||||||
};
|
};
|
||||||
} // namespace exception
|
}
|
||||||
|
|
||||||
|
|
||||||
class Any {
|
class Any {
|
||||||
private:
|
private:
|
||||||
struct Data {
|
struct Data
|
||||||
constexpr explicit Data(const std::type_info &t_type) noexcept
|
{
|
||||||
: m_type(t_type) {
|
Data(const std::type_info &t_type)
|
||||||
|
: m_type(t_type)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Data &operator=(const Data &) = delete;
|
Data &operator=(const Data &) = delete;
|
||||||
|
|
||||||
virtual ~Data() noexcept = default;
|
virtual ~Data() {}
|
||||||
|
|
||||||
virtual void *data() noexcept = 0;
|
virtual void *data() = 0;
|
||||||
|
const std::type_info &type() const
|
||||||
const std::type_info &type() const noexcept { return m_type; }
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::unique_ptr<Data> clone() const = 0;
|
virtual std::unique_ptr<Data> clone() const = 0;
|
||||||
const std::type_info &m_type;
|
const std::type_info &m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Data_Impl : Data {
|
struct Data_Impl : Data
|
||||||
|
{
|
||||||
explicit Data_Impl(T t_type)
|
explicit Data_Impl(T t_type)
|
||||||
: Data(typeid(T))
|
: Data(typeid(T)),
|
||||||
, m_data(std::move(t_type)) {
|
m_data(std::move(t_type))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void *data() noexcept override { return &m_data; }
|
virtual ~Data_Impl() {}
|
||||||
|
|
||||||
std::unique_ptr<Data> clone() const override { return std::make_unique<Data_Impl<T>>(m_data); }
|
virtual void *data() CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return &m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Data> clone() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
|
||||||
|
}
|
||||||
|
|
||||||
Data_Impl &operator=(const Data_Impl&) = delete;
|
Data_Impl &operator=(const Data_Impl&) = delete;
|
||||||
|
|
||||||
@ -63,45 +95,71 @@ namespace chaiscript {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// construct/copy/destruct
|
// construct/copy/destruct
|
||||||
constexpr Any() noexcept = default;
|
Any() = default;
|
||||||
Any(Any &&) noexcept = default;
|
|
||||||
Any &operator=(Any &&t_any) = default;
|
|
||||||
|
|
||||||
Any(const Any &t_any)
|
Any(const Any &t_any)
|
||||||
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) {
|
{
|
||||||
|
if (!t_any.empty())
|
||||||
|
{
|
||||||
|
m_data = t_any.m_data->clone();
|
||||||
|
} else {
|
||||||
|
m_data.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ValueType, typename = std::enable_if_t<!std::is_same_v<Any, std::decay_t<ValueType>>>>
|
#if !defined(_MSC_VER) || _MSC_VER != 1800
|
||||||
|
Any(Any &&) = default;
|
||||||
|
Any &operator=(Any &&t_any) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename ValueType,
|
||||||
|
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
|
||||||
explicit Any(ValueType &&t_value)
|
explicit Any(ValueType &&t_value)
|
||||||
: m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(std::forward<ValueType>(t_value))) {
|
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Any &operator=(const Any &t_any) {
|
|
||||||
|
Any & operator=(const Any &t_any)
|
||||||
|
{
|
||||||
Any copy(t_any);
|
Any copy(t_any);
|
||||||
swap(copy);
|
swap(copy);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ToType>
|
template<typename ToType>
|
||||||
ToType &cast() const {
|
ToType &cast() const
|
||||||
if (m_data && typeid(ToType) == m_data->type()) {
|
{
|
||||||
|
if (m_data && typeid(ToType) == m_data->type())
|
||||||
|
{
|
||||||
return *static_cast<ToType *>(m_data->data());
|
return *static_cast<ToType *>(m_data->data());
|
||||||
} else {
|
} else {
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
~Any()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// modifiers
|
// modifiers
|
||||||
Any &swap(Any &t_other) {
|
Any & swap(Any &t_other)
|
||||||
|
{
|
||||||
std::swap(t_other.m_data, m_data);
|
std::swap(t_other.m_data, m_data);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// queries
|
// queries
|
||||||
bool empty() const noexcept { return !static_cast<bool>(m_data); }
|
bool empty() const
|
||||||
|
{
|
||||||
|
return !bool(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
const std::type_info &type() const noexcept {
|
const std::type_info & type() const
|
||||||
if (m_data) {
|
{
|
||||||
|
if (m_data)
|
||||||
|
{
|
||||||
return m_data->type();
|
return m_data->type();
|
||||||
} else {
|
} else {
|
||||||
return typeid(void);
|
return typeid(void);
|
||||||
@ -109,7 +167,9 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
}
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||||
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||||
|
|
||||||
@ -14,51 +11,59 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#include "../chaiscript_defines.hpp"
|
#include "../chaiscript_defines.hpp"
|
||||||
#include "../utility/static_string.hpp"
|
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
class Type_Info;
|
class Type_Info;
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace exception {
|
{
|
||||||
|
namespace exception
|
||||||
|
{
|
||||||
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
|
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
|
||||||
///
|
///
|
||||||
/// It is used internally during function dispatch and may be used by the end user.
|
/// It is used internally during function dispatch and may be used by the end user.
|
||||||
///
|
///
|
||||||
/// \sa chaiscript::boxed_cast
|
/// \sa chaiscript::boxed_cast
|
||||||
class bad_boxed_cast : public std::bad_cast {
|
class bad_boxed_cast : public std::bad_cast
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, utility::Static_String t_what) noexcept
|
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
|
||||||
: from(t_from)
|
std::string t_what) CHAISCRIPT_NOEXCEPT
|
||||||
, to(&t_to)
|
: from(std::move(t_from)), to(&t_to), m_what(std::move(t_what))
|
||||||
, m_what(std::move(t_what)) {
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept
|
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
|
||||||
: from(t_from)
|
: from(std::move(t_from)), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
|
||||||
, to(&t_to)
|
{
|
||||||
, m_what("Cannot perform boxed_cast") {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit bad_boxed_cast(utility::Static_String t_what) noexcept
|
bad_boxed_cast(std::string t_what) CHAISCRIPT_NOEXCEPT
|
||||||
: m_what(std::move(t_what)) {
|
: to(nullptr), m_what(std::move(t_what))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
|
bad_boxed_cast(const bad_boxed_cast &) = default;
|
||||||
~bad_boxed_cast() noexcept override = default;
|
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
|
||||||
/// \brief Description of what error occurred
|
/// \brief Description of what error occurred
|
||||||
const char *what() const noexcept override { return m_what.c_str(); }
|
virtual const char * what() const CHAISCRIPT_NOEXCEPT CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return m_what.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
Type_Info from; ///< Type_Info contained in the Boxed_Value
|
Type_Info from; ///< Type_Info contained in the Boxed_Value
|
||||||
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
|
const std::type_info *to; ///< std::type_info of the desired (but failed) result type
|
||||||
|
|
||||||
private:
|
private:
|
||||||
utility::Static_String m_what;
|
std::string m_what;
|
||||||
};
|
};
|
||||||
} // namespace exception
|
}
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,60 +1,74 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
|
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
|
||||||
#define CHAISCRIPT_BIND_FIRST_HPP_
|
#define CHAISCRIPT_BIND_FIRST_HPP_
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace detail {
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T *get_pointer(T *t) noexcept {
|
T* get_pointer(T *t)
|
||||||
|
{
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
|
T* get_pointer(const std::reference_wrapper<T> &t)
|
||||||
|
{
|
||||||
return &t.get();
|
return &t.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||||
constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) {
|
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O&& o)
|
||||||
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
|
{
|
||||||
|
return std::function<Ret (Param...)>(
|
||||||
|
[f, o](Param...param) -> Ret {
|
||||||
|
return f(std::forward<O>(o), std::forward<Param>(param)...);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||||
constexpr auto bind_first(Ret (Class::*f)(Param...), O &&o) {
|
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O&& o)
|
||||||
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
|
{
|
||||||
|
return std::function<Ret (Param...)>(
|
||||||
|
[f, o](Param...param) -> Ret {
|
||||||
|
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||||
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) {
|
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O&& o)
|
||||||
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
|
{
|
||||||
|
return std::function<Ret (Param...)>(
|
||||||
|
[f, o](Param...param) -> Ret {
|
||||||
|
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||||
auto bind_first(const std::function<Ret(P1, Param...)> &f, O &&o) {
|
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
|
||||||
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
|
{
|
||||||
|
return std::function<Ret (Param...)>(
|
||||||
|
[f, o](Param...param) -> Ret {
|
||||||
|
return f(o, std::forward<Param>(param)...);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename O, typename Ret, typename Class, typename P1, typename... Param>
|
|
||||||
constexpr auto bind_first(const F &fo, O &&o, Ret (Class::*f)(P1, Param...) const) {
|
}
|
||||||
return [fo, o = std::forward<O>(o), f](Param... param) -> Ret { return (fo.*f)(o, std::forward<Param>(param)...); };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename O>
|
|
||||||
constexpr auto bind_first(const F &f, O &&o) {
|
|
||||||
return bind_first(f, std::forward<O>(o), &F::operator());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
} // namespace chaiscript
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,85 +1,136 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
||||||
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
||||||
|
|
||||||
#include "../utility/utility.hpp"
|
#include <cstdint>
|
||||||
|
#include <exception>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include "bad_boxed_cast.hpp"
|
||||||
|
#include "boxed_cast.hpp"
|
||||||
|
#include "boxed_number.hpp"
|
||||||
|
#include "boxed_value.hpp"
|
||||||
|
#include "dispatchkit.hpp"
|
||||||
|
#include "type_conversions.hpp"
|
||||||
|
#include "dynamic_object.hpp"
|
||||||
|
#include "operators.hpp"
|
||||||
|
#include "proxy_constructors.hpp"
|
||||||
|
#include "proxy_functions.hpp"
|
||||||
|
#include "proxy_functions_detail.hpp"
|
||||||
#include "register_function.hpp"
|
#include "register_function.hpp"
|
||||||
|
#include "type_info.hpp"
|
||||||
|
#include "../utility/utility.hpp"
|
||||||
|
#include "../language/chaiscript_common.hpp"
|
||||||
|
|
||||||
|
namespace chaiscript
|
||||||
|
{
|
||||||
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
|
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
|
||||||
namespace chaiscript::bootstrap {
|
namespace bootstrap
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
/// \brief Constructs a new POD value object from a Boxed_Number
|
||||||
|
/// \param[in] v Boxed_Number to copy into the new object
|
||||||
|
/// \returns The newly created object.
|
||||||
|
template<typename P1>
|
||||||
|
std::shared_ptr<P1> construct_pod(const Boxed_Number &v)
|
||||||
|
{
|
||||||
|
return std::make_shared<P1>(v.get_as<P1>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
|
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
|
||||||
void array(const std::string &type, Module &m) {
|
ModulePtr array(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
using ReturnType = typename std::remove_extent<T>::type;
|
{
|
||||||
|
typedef typename std::remove_extent<T>::type ReturnType;
|
||||||
m.add(user_type<T>(), type);
|
const auto extent = std::extent<T>::value;
|
||||||
m.add(fun([](T &t, size_t index) -> ReturnType & {
|
m->add(user_type<T>(), type);
|
||||||
constexpr const auto extent = std::extent<T>::value;
|
m->add(fun(
|
||||||
|
[extent](T& t, size_t index)->ReturnType &{
|
||||||
if (extent > 0 && index >= extent) {
|
if (extent > 0 && index >= extent) {
|
||||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||||
+ std::to_string(extent));
|
|
||||||
} else {
|
} else {
|
||||||
return *std::next(t, static_cast<std::ptrdiff_t>(index));
|
return t[index];
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
"[]");
|
), "[]"
|
||||||
|
);
|
||||||
|
|
||||||
m.add(fun([](const T &t, size_t index) -> const ReturnType & {
|
m->add(fun(
|
||||||
constexpr const auto extent = std::extent<T>::value;
|
[extent](const T &t, size_t index)->const ReturnType &{
|
||||||
if (extent > 0 && index >= extent) {
|
if (extent > 0 && index >= extent) {
|
||||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||||
+ std::to_string(extent));
|
|
||||||
} else {
|
} else {
|
||||||
return *std::next(t, static_cast<std::ptrdiff_t>(index));
|
return t[index];
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
"[]");
|
), "[]"
|
||||||
|
);
|
||||||
|
|
||||||
m.add(fun([](const T &) { return std::extent<T>::value; }), "size");
|
m->add(fun(
|
||||||
|
[extent](const T &) {
|
||||||
|
return extent;
|
||||||
|
}), "size");
|
||||||
|
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Adds a copy constructor for the given type to the given Model
|
/// \brief Adds a copy constructor for the given type to the given Model
|
||||||
/// \param[in] type The name of the type. The copy constructor will be named "type".
|
/// \param[in] type The name of the type. The copy constructor will be named "type".
|
||||||
/// \param[in,out] m The Module to add the copy constructor to
|
/// \param[in,out] m The Module to add the copy constructor to
|
||||||
/// \tparam T The type to add a copy constructor for
|
/// \tparam T The type to add a copy constructor for
|
||||||
/// \returns The passed in Module
|
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void copy_constructor(const std::string &type, Module &m) {
|
ModulePtr copy_constructor(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(constructor<T(const T &)>(), type);
|
{
|
||||||
|
m->add(constructor<T (const T &)>(), type);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
|
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
|
||||||
/// \tparam T Type to create comparison operators for
|
/// \tparam T Type to create comparison operators for
|
||||||
/// \param[in,out] m module to add comparison operators to
|
/// \param[in,out] m module to add comparison operators to
|
||||||
/// \returns the passed in Module.
|
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void opers_comparison(Module &m) {
|
ModulePtr opers_comparison(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
operators::equal<T>(m);
|
operators::equal<T>(m);
|
||||||
operators::greater_than<T>(m);
|
operators::greater_than<T>(m);
|
||||||
operators::greater_than_equal<T>(m);
|
operators::greater_than_equal<T>(m);
|
||||||
operators::less_than<T>(m);
|
operators::less_than<T>(m);
|
||||||
operators::less_than_equal<T>(m);
|
operators::less_than_equal<T>(m);
|
||||||
operators::not_equal<T>(m);
|
operators::not_equal<T>(m);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// \brief Adds default and copy constructors for the given type
|
/// \brief Adds default and copy constructors for the given type
|
||||||
/// \param[in] type The name of the type to add the constructors for.
|
/// \param[in] type The name of the type to add the constructors for.
|
||||||
/// \param[in,out] m The Module to add the basic constructors to
|
/// \param[in,out] m The Module to add the basic constructors to
|
||||||
/// \tparam T Type to generate basic constructors for
|
/// \tparam T Type to generate basic constructors for
|
||||||
/// \returns The passed in Module
|
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
||||||
/// \sa copy_constructor
|
/// \sa copy_constructor
|
||||||
/// \sa constructor
|
/// \sa constructor
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void basic_constructors(const std::string &type, Module &m) {
|
ModulePtr basic_constructors(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(constructor<T()>(), type);
|
{
|
||||||
|
m->add(constructor<T ()>(), type);
|
||||||
copy_constructor<T>(type, m);
|
copy_constructor<T>(type, m);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Adds a constructor for a POD type
|
/// \brief Adds a constructor for a POD type
|
||||||
@ -87,60 +138,94 @@ namespace chaiscript::bootstrap {
|
|||||||
/// \param[in] type The name of the type
|
/// \param[in] type The name of the type
|
||||||
/// \param[in,out] m The Module to add the constructor to
|
/// \param[in,out] m The Module to add the constructor to
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void construct_pod(const std::string &type, Module &m) {
|
ModulePtr construct_pod(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
|
{
|
||||||
|
m->add(fun(&detail::construct_pod<T>), type);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// to_string function for internal use. Uses ostream operator<<
|
||||||
|
template<typename Input>
|
||||||
|
std::string to_string(Input i)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << i;
|
||||||
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal function for converting from a string to a value
|
/// Internal function for converting from a string to a value
|
||||||
/// uses ostream operator >> to perform the conversion
|
/// uses ostream operator >> to perform the conversion
|
||||||
template<typename Input>
|
template<typename Input>
|
||||||
Input parse_string(const std::string &i) {
|
auto parse_string(const std::string &i)
|
||||||
if constexpr (!std::is_same<Input, wchar_t>::value && !std::is_same<Input, char16_t>::value && !std::is_same<Input, char32_t>::value) {
|
-> typename std::enable_if<
|
||||||
|
!std::is_same<Input, wchar_t>::value
|
||||||
|
&& !std::is_same<Input, char16_t>::value
|
||||||
|
&& !std::is_same<Input, char32_t>::value,
|
||||||
|
Input>::type
|
||||||
|
{
|
||||||
std::stringstream ss(i);
|
std::stringstream ss(i);
|
||||||
Input t;
|
Input t;
|
||||||
ss >> t;
|
ss >> t;
|
||||||
return t;
|
return t;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
template<typename Input>
|
||||||
|
auto parse_string(const std::string &)
|
||||||
|
-> typename std::enable_if<
|
||||||
|
std::is_same<Input, wchar_t>::value
|
||||||
|
|| std::is_same<Input, char16_t>::value
|
||||||
|
|| std::is_same<Input, char32_t>::value,
|
||||||
|
Input>::type
|
||||||
|
{
|
||||||
throw std::runtime_error("Parsing of wide characters is not yet supported");
|
throw std::runtime_error("Parsing of wide characters is not yet supported");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Add all common functions for a POD type. All operators, and
|
/// Add all common functions for a POD type. All operators, and
|
||||||
/// common conversions
|
/// common conversions
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void bootstrap_pod_type(const std::string &name, Module &m) {
|
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<T>(), name);
|
{
|
||||||
m.add(constructor<T()>(), name);
|
m->add(user_type<T>(), name);
|
||||||
|
m->add(constructor<T()>(), name);
|
||||||
construct_pod<T>(name, m);
|
construct_pod<T>(name, m);
|
||||||
|
|
||||||
m.add(fun(&parse_string<T>), "to_" + name);
|
m->add(fun(&parse_string<T>), "to_" + name);
|
||||||
m.add(fun([](const T t) { return t; }), "to_" + name);
|
return m;
|
||||||
m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), "to_" + name);
|
|
||||||
m.add(fun(&parse_string<T>), name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// "clone" function for a shared_ptr type. This is used in the case
|
/// "clone" function for a shared_ptr type. This is used in the case
|
||||||
/// where you do not want to make a deep copy of an object during cloning
|
/// where you do not want to make a deep copy of an object during cloning
|
||||||
/// but want to instead maintain the shared_ptr. It is needed internally
|
/// but want to instead maintain the shared_ptr. It is needed internally
|
||||||
/// for handling of Proxy_Function object (that is,
|
/// for handling of Proxy_Function object (that is,
|
||||||
/// function variables.
|
/// function variables.
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
|
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
|
||||||
|
{
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specific version of shared_ptr_clone just for Proxy_Functions
|
/// Specific version of shared_ptr_clone just for Proxy_Functions
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<Type>> &p) {
|
std::shared_ptr<typename std::remove_const<Type>::type>
|
||||||
|
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
|
||||||
|
{
|
||||||
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
|
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Assignment function for shared_ptr objects, does not perform a copy of the
|
/// Assignment function for shared_ptr objects, does not perform a copy of the
|
||||||
/// object pointed to, instead maintains the shared_ptr concept.
|
/// object pointed to, instead maintains the shared_ptr concept.
|
||||||
/// Similar to shared_ptr_clone. Used for Proxy_Function.
|
/// Similar to shared_ptr_clone. Used for Proxy_Function.
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) {
|
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
|
||||||
if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) {
|
{
|
||||||
|
if (lhs.is_undef()
|
||||||
|
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
|
||||||
|
{
|
||||||
lhs.assign(Boxed_Value(rhs));
|
lhs.assign(Boxed_Value(rhs));
|
||||||
return lhs;
|
return lhs;
|
||||||
} else {
|
} else {
|
||||||
@ -150,110 +235,156 @@ namespace chaiscript::bootstrap {
|
|||||||
|
|
||||||
/// Class consisting of only static functions. All default bootstrapping occurs
|
/// Class consisting of only static functions. All default bootstrapping occurs
|
||||||
/// from this class.
|
/// from this class.
|
||||||
class Bootstrap {
|
class Bootstrap
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
/// Function allowing for assignment of an unknown type to any other value
|
/// Function allowing for assignment of an unknown type to any other value
|
||||||
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) {
|
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
|
||||||
if (lhs.is_undef()) {
|
{
|
||||||
|
if (lhs.is_undef())
|
||||||
|
{
|
||||||
return (lhs.assign(rhs));
|
return (lhs.assign(rhs));
|
||||||
} else {
|
} else {
|
||||||
throw exception::bad_boxed_cast("boxed_value has a set type already");
|
throw exception::bad_boxed_cast("boxed_value has a set type already");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); }
|
static void print(const std::string &s)
|
||||||
|
{
|
||||||
|
fwrite(s.c_str(), 1, s.size(), stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void println(const std::string &s)
|
||||||
|
{
|
||||||
|
puts(s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
static void println(const std::string &s) noexcept { puts(s.c_str()); }
|
|
||||||
|
|
||||||
/// Add all arithmetic operators for PODs
|
/// Add all arithmetic operators for PODs
|
||||||
static void opers_arithmetic_pod(Module &m) {
|
static void opers_arithmetic_pod(ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(fun(&Boxed_Number::equals), "==");
|
{
|
||||||
m.add(fun(&Boxed_Number::less_than), "<");
|
m->add(fun(&Boxed_Number::equals), "==");
|
||||||
m.add(fun(&Boxed_Number::greater_than), ">");
|
m->add(fun(&Boxed_Number::less_than), "<");
|
||||||
m.add(fun(&Boxed_Number::greater_than_equal), ">=");
|
m->add(fun(&Boxed_Number::greater_than), ">");
|
||||||
m.add(fun(&Boxed_Number::less_than_equal), "<=");
|
m->add(fun(&Boxed_Number::greater_than_equal), ">=");
|
||||||
m.add(fun(&Boxed_Number::not_equal), "!=");
|
m->add(fun(&Boxed_Number::less_than_equal), "<=");
|
||||||
|
m->add(fun(&Boxed_Number::not_equal), "!=");
|
||||||
|
|
||||||
|
m->add(fun(&Boxed_Number::pre_decrement), "--");
|
||||||
|
m->add(fun(&Boxed_Number::pre_increment), "++");
|
||||||
|
m->add(fun(&Boxed_Number::sum), "+");
|
||||||
|
m->add(fun(&Boxed_Number::unary_plus), "+");
|
||||||
|
m->add(fun(&Boxed_Number::unary_minus), "-");
|
||||||
|
m->add(fun(&Boxed_Number::difference), "-");
|
||||||
|
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
|
||||||
|
m->add(fun(&Boxed_Number::assign), "=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_remainder), "%=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
|
||||||
|
m->add(fun(&Boxed_Number::bitwise_and), "&");
|
||||||
|
m->add(fun(&Boxed_Number::bitwise_complement), "~");
|
||||||
|
m->add(fun(&Boxed_Number::bitwise_xor), "^");
|
||||||
|
m->add(fun(&Boxed_Number::bitwise_or), "|");
|
||||||
|
m->add(fun(&Boxed_Number::assign_product), "*=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_quotient), "/=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_sum), "+=");
|
||||||
|
m->add(fun(&Boxed_Number::assign_difference), "-=");
|
||||||
|
m->add(fun(&Boxed_Number::quotient), "/");
|
||||||
|
m->add(fun(&Boxed_Number::shift_left), "<<");
|
||||||
|
m->add(fun(&Boxed_Number::product), "*");
|
||||||
|
m->add(fun(&Boxed_Number::remainder), "%");
|
||||||
|
m->add(fun(&Boxed_Number::shift_right), ">>");
|
||||||
|
|
||||||
|
|
||||||
m.add(fun(&Boxed_Number::pre_decrement), "--");
|
|
||||||
m.add(fun(&Boxed_Number::pre_increment), "++");
|
|
||||||
m.add(fun(&Boxed_Number::sum), "+");
|
|
||||||
m.add(fun(&Boxed_Number::unary_plus), "+");
|
|
||||||
m.add(fun(&Boxed_Number::unary_minus), "-");
|
|
||||||
m.add(fun(&Boxed_Number::difference), "-");
|
|
||||||
m.add(fun(&Boxed_Number::assign_bitwise_and), "&=");
|
|
||||||
m.add(fun(&Boxed_Number::assign), "=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_bitwise_or), "|=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_remainder), "%=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_shift_left), "<<=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_shift_right), ">>=");
|
|
||||||
m.add(fun(&Boxed_Number::bitwise_and), "&");
|
|
||||||
m.add(fun(&Boxed_Number::bitwise_complement), "~");
|
|
||||||
m.add(fun(&Boxed_Number::bitwise_xor), "^");
|
|
||||||
m.add(fun(&Boxed_Number::bitwise_or), "|");
|
|
||||||
m.add(fun(&Boxed_Number::assign_product), "*=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_quotient), "/=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_sum), "+=");
|
|
||||||
m.add(fun(&Boxed_Number::assign_difference), "-=");
|
|
||||||
m.add(fun(&Boxed_Number::quotient), "/");
|
|
||||||
m.add(fun(&Boxed_Number::shift_left), "<<");
|
|
||||||
m.add(fun(&Boxed_Number::product), "*");
|
|
||||||
m.add(fun(&Boxed_Number::remainder), "%");
|
|
||||||
m.add(fun(&Boxed_Number::shift_right), ">>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a bound function object. The first param is the function to bind
|
/// Create a bound function object. The first param is the function to bind
|
||||||
/// the remaining parameters are the args to bind into the result
|
/// the remaining parameters are the args to bind into the result
|
||||||
static Boxed_Value bind_function(const Function_Params ¶ms) {
|
static Boxed_Value bind_function(const std::vector<Boxed_Value> ¶ms)
|
||||||
|
{
|
||||||
if (params.empty()) {
|
if (params.empty()) {
|
||||||
throw exception::arity_error(0, 1);
|
throw exception::arity_error(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||||
|
|
||||||
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1) {
|
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1)
|
||||||
|
{
|
||||||
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
|
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boxed_Value(Const_Proxy_Function(
|
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f),
|
||||||
std::make_shared<dispatch::Bound_Function>(std::move(f), std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept {
|
|
||||||
|
static bool has_guard(const Const_Proxy_Function &t_pf)
|
||||||
|
{
|
||||||
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
return pf && pf->has_guard();
|
return pf && pf->get_guard();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) {
|
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
|
||||||
|
{
|
||||||
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
if (pf && pf->get_guard()) {
|
if (pf && pf->get_guard())
|
||||||
|
{
|
||||||
return pf->get_guard();
|
return pf->get_guard();
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Function does not have a guard");
|
throw std::runtime_error("Function does not have a guard");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void throw_exception(const Boxed_Value &bv) {
|
||||||
|
throw bv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string what(const std::exception &e)
|
||||||
|
{
|
||||||
|
return e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Boolean specialization of internal to_string function
|
||||||
|
static std::string bool_to_string(bool b)
|
||||||
|
{
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
return "true";
|
||||||
|
} else {
|
||||||
|
return "false";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename FunctionType>
|
template<typename FunctionType>
|
||||||
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) {
|
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
|
||||||
|
const dispatch::Proxy_Function_Base *b)
|
||||||
|
{
|
||||||
auto v = (b->*f)();
|
auto v = (b->*f)();
|
||||||
|
|
||||||
std::vector<Boxed_Value> vbv;
|
std::vector<Boxed_Value> vbv;
|
||||||
|
|
||||||
for (const auto &o : v) {
|
for (const auto &o: v)
|
||||||
|
{
|
||||||
vbv.push_back(const_var(o));
|
vbv.push_back(const_var(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
return vbv;
|
return vbv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept {
|
|
||||||
|
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||||
|
{
|
||||||
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
return bool(pf);
|
return pf && pf->get_parse_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const chaiscript::AST_Node &get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) {
|
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||||
|
{
|
||||||
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
if (pf) {
|
if (pf && pf->get_parse_tree())
|
||||||
|
{
|
||||||
return pf->get_parse_tree();
|
return pf->get_parse_tree();
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Function does not have a parse tree");
|
throw std::runtime_error("Function does not have a parse tree");
|
||||||
@ -261,145 +392,120 @@ namespace chaiscript::bootstrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Function>
|
template<typename Function>
|
||||||
static auto return_boxed_value_vector(const Function &f) {
|
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
|
||||||
return [f](const dispatch::Proxy_Function_Base *b) { return do_return_boxed_value_vector(f, b); };
|
{
|
||||||
|
return [f](const dispatch::Proxy_Function_Base *b) {
|
||||||
|
return do_return_boxed_value_vector(f, b);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \brief perform all common bootstrap functions for std::string, void and POD types
|
/// \brief perform all common bootstrap functions for std::string, void and POD types
|
||||||
/// \param[in,out] m Module to add bootstrapped functions to
|
/// \param[in,out] m Module to add bootstrapped functions to
|
||||||
/// \param[in] t_no_io If true, skip registering print_string and println_string
|
/// \returns passed in ModulePtr, or newly created one if default argument is used
|
||||||
static void bootstrap(Module &m) {
|
static ModulePtr bootstrap(ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<void>(), "void");
|
{
|
||||||
m.add(user_type<bool>(), "bool");
|
m->add(user_type<void>(), "void");
|
||||||
m.add(user_type<Boxed_Value>(), "Object");
|
m->add(user_type<bool>(), "bool");
|
||||||
m.add(user_type<Boxed_Number>(), "Number");
|
m->add(user_type<Boxed_Value>(), "Object");
|
||||||
m.add(user_type<Proxy_Function>(), "Function");
|
m->add(user_type<Boxed_Number>(), "Number");
|
||||||
m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
|
m->add(user_type<Proxy_Function>(), "Function");
|
||||||
m.add(user_type<std::exception>(), "exception");
|
m->add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
|
||||||
|
m->add(user_type<std::exception>(), "exception");
|
||||||
|
|
||||||
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
|
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
|
||||||
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
|
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
|
||||||
|
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
|
||||||
|
|
||||||
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
|
|
||||||
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
|
||||||
|
|
||||||
m.add(fun([](const std::exception &e) { return std::string(e.what()); }), "what");
|
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
|
||||||
|
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
||||||
|
|
||||||
m.add(user_type<std::out_of_range>(), "out_of_range");
|
|
||||||
m.add(user_type<std::logic_error>(), "logic_error");
|
|
||||||
m.add(chaiscript::base_class<std::exception, std::logic_error>());
|
|
||||||
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
|
|
||||||
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
|
|
||||||
|
|
||||||
m.add(user_type<std::runtime_error>(), "runtime_error");
|
m->add(user_type<std::out_of_range>(), "out_of_range");
|
||||||
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
|
m->add(user_type<std::logic_error>(), "logic_error");
|
||||||
|
m->add(chaiscript::base_class<std::exception, std::logic_error>());
|
||||||
|
m->add(chaiscript::base_class<std::logic_error, std::out_of_range>());
|
||||||
|
m->add(chaiscript::base_class<std::exception, std::out_of_range>());
|
||||||
|
|
||||||
m.add(constructor<std::runtime_error(const std::string &)>(), "runtime_error");
|
m->add(user_type<std::runtime_error>(), "runtime_error");
|
||||||
|
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||||
|
|
||||||
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
|
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||||
m.add(constructor<dispatch::Dynamic_Object(const std::string &)>(), "Dynamic_Object");
|
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
|
||||||
m.add(constructor<dispatch::Dynamic_Object()>(), "Dynamic_Object");
|
|
||||||
m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
|
||||||
m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
|
||||||
m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
|
|
||||||
m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
|
|
||||||
m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr");
|
|
||||||
|
|
||||||
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
|
||||||
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
|
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
|
||||||
"get_attr");
|
m->add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
|
||||||
|
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
||||||
|
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
||||||
|
m->add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
|
||||||
|
m->add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
|
||||||
|
|
||||||
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)),
|
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||||
"method_missing");
|
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||||
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(
|
|
||||||
&dispatch::Dynamic_Object::method_missing)),
|
|
||||||
"method_missing");
|
|
||||||
|
|
||||||
m.add(fun(static_cast<Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
|
||||||
m.add(fun(static_cast<const Boxed_Value &(dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)),
|
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
|
||||||
"[]");
|
|
||||||
|
|
||||||
m.eval(R"chaiscript(
|
m->add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||||
|
m->add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||||
|
|
||||||
|
m->eval(R""(
|
||||||
def Dynamic_Object::clone() {
|
def Dynamic_Object::clone() {
|
||||||
auto &new_o = Dynamic_Object(this.get_type_name());
|
auto &new_o = Dynamic_Object(this.get_type_name());
|
||||||
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
|
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
|
||||||
new_o;
|
new_o;
|
||||||
}
|
}
|
||||||
|
)"");
|
||||||
|
|
||||||
def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
|
m->add(fun(&has_guard), "has_guard");
|
||||||
{
|
m->add(fun(&get_guard), "get_guard");
|
||||||
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
|
m->add(fun(&Boxed_Value::is_undef), "is_var_undef");
|
||||||
{
|
m->add(fun(&Boxed_Value::is_null), "is_var_null");
|
||||||
var rhs_attrs := rhs.get_attrs();
|
m->add(fun(&Boxed_Value::is_const), "is_var_const");
|
||||||
var lhs_attrs := lhs.get_attrs();
|
m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
|
||||||
|
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
|
||||||
|
m->add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
|
||||||
|
m->add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
|
||||||
|
m->add(fun(&Boxed_Value::is_type), "is_type");
|
||||||
|
m->add(fun(&Boxed_Value::get_attr), "get_var_attr");
|
||||||
|
m->add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
|
||||||
|
m->add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
|
||||||
|
|
||||||
if (rhs_attrs.size() != lhs_attrs.size()) {
|
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
||||||
true;
|
m->add(user_type<Type_Info>(), "Type_Info");
|
||||||
} else {
|
m->add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
|
||||||
return any_of(rhs_attrs, fun[lhs](x) { !lhs.has_attr(x.first) || lhs.get_attr(x.first) != x.second; } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def `==`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
|
|
||||||
{
|
|
||||||
var rhs_attrs := rhs.get_attrs();
|
|
||||||
var lhs_attrs := lhs.get_attrs();
|
|
||||||
|
|
||||||
if (rhs_attrs.size() != lhs_attrs.size()) {
|
|
||||||
false;
|
|
||||||
} else {
|
|
||||||
return all_of(rhs_attrs, fun[lhs](x) { lhs.has_attr(x.first) && lhs.get_attr(x.first) == x.second; } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)chaiscript");
|
|
||||||
|
|
||||||
m.add(fun(&has_guard), "has_guard");
|
|
||||||
m.add(fun(&get_guard), "get_guard");
|
|
||||||
|
|
||||||
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
|
|
||||||
m.add(fun(&Boxed_Value::is_null), "is_var_null");
|
|
||||||
m.add(fun(&Boxed_Value::is_const), "is_var_const");
|
|
||||||
m.add(fun(&Boxed_Value::is_ref), "is_var_reference");
|
|
||||||
m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
|
|
||||||
m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
|
|
||||||
m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
|
|
||||||
m.add(fun(&Boxed_Value::is_type), "is_type");
|
|
||||||
m.add(fun(&Boxed_Value::get_attr), "get_var_attr");
|
|
||||||
m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
|
|
||||||
m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
|
|
||||||
|
|
||||||
m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
|
||||||
m.add(user_type<Type_Info>(), "Type_Info");
|
|
||||||
m.add(constructor<Type_Info(const Type_Info &)>(), "Type_Info");
|
|
||||||
|
|
||||||
operators::equal<Type_Info>(m);
|
operators::equal<Type_Info>(m);
|
||||||
|
|
||||||
m.add(fun(&Type_Info::is_const), "is_type_const");
|
m->add(fun(&Type_Info::is_const), "is_type_const");
|
||||||
m.add(fun(&Type_Info::is_reference), "is_type_reference");
|
m->add(fun(&Type_Info::is_reference), "is_type_reference");
|
||||||
m.add(fun(&Type_Info::is_void), "is_type_void");
|
m->add(fun(&Type_Info::is_void), "is_type_void");
|
||||||
m.add(fun(&Type_Info::is_undef), "is_type_undef");
|
m->add(fun(&Type_Info::is_undef), "is_type_undef");
|
||||||
m.add(fun(&Type_Info::is_pointer), "is_type_pointer");
|
m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
|
||||||
m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
|
m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
|
||||||
m.add(fun(&Type_Info::name), "cpp_name");
|
m->add(fun(&Type_Info::name), "cpp_name");
|
||||||
m.add(fun(&Type_Info::bare_name), "cpp_bare_name");
|
m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
|
||||||
m.add(fun(&Type_Info::bare_equal), "bare_equal");
|
m->add(fun(&Type_Info::bare_equal), "bare_equal");
|
||||||
|
|
||||||
|
|
||||||
basic_constructors<bool>("bool", m);
|
basic_constructors<bool>("bool", m);
|
||||||
operators::assign<bool>(m);
|
operators::assign<bool>(m);
|
||||||
operators::equal<bool>(m);
|
operators::equal<bool>(m);
|
||||||
operators::not_equal<bool>(m);
|
operators::not_equal<bool>(m);
|
||||||
|
|
||||||
m.add(fun([](const std::string &s) { return s; }), "to_string");
|
m->add(fun([](const std::string &s) -> std::string { return s; }), "to_string");
|
||||||
m.add(fun([](const bool b) { return std::string(b ? "true" : "false"); }), "to_string");
|
m->add(fun(&Bootstrap::bool_to_string), "to_string");
|
||||||
m.add(fun(&unknown_assign), "=");
|
m->add(fun(&unknown_assign), "=");
|
||||||
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
|
m->add(fun(&throw_exception), "throw");
|
||||||
|
m->add(fun(&what), "what");
|
||||||
|
|
||||||
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
|
m->add(fun(&to_string<char>), "to_string");
|
||||||
m.add(fun(&Boxed_Number::to_string), "to_string");
|
m->add(fun(&Boxed_Number::to_string), "to_string");
|
||||||
|
|
||||||
bootstrap_pod_type<double>("double", m);
|
bootstrap_pod_type<double>("double", m);
|
||||||
bootstrap_pod_type<long double>("long_double", m);
|
bootstrap_pod_type<long double>("long_double", m);
|
||||||
@ -428,63 +534,63 @@ namespace chaiscript::bootstrap {
|
|||||||
|
|
||||||
opers_arithmetic_pod(m);
|
opers_arithmetic_pod(m);
|
||||||
|
|
||||||
m.add(fun(&Build_Info::version_major), "version_major");
|
|
||||||
m.add(fun(&Build_Info::version_minor), "version_minor");
|
|
||||||
m.add(fun(&Build_Info::version_patch), "version_patch");
|
|
||||||
m.add(fun(&Build_Info::version), "version");
|
|
||||||
m.add(fun(&Build_Info::compiler_version), "compiler_version");
|
|
||||||
m.add(fun(&Build_Info::compiler_name), "compiler_name");
|
|
||||||
m.add(fun(&Build_Info::compiler_id), "compiler_id");
|
|
||||||
m.add(fun(&Build_Info::debug_build), "debug_build");
|
|
||||||
|
|
||||||
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
m->add(fun(&print), "print_string");
|
||||||
|
m->add(fun(&println), "println_string");
|
||||||
|
|
||||||
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
m->add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
||||||
m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
|
|
||||||
m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
|
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
||||||
m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
|
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||||
m.add(fun([](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
|
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||||
|
m->add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
|
||||||
|
m->add(fun(
|
||||||
|
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
|
||||||
t_lhs.assign(t_rhs);
|
t_lhs.assign(t_rhs);
|
||||||
}),
|
}
|
||||||
"=");
|
), "="
|
||||||
|
);
|
||||||
|
|
||||||
m.add(fun(&Boxed_Value::type_match), "type_match");
|
m->add(fun(&Boxed_Value::type_match), "type_match");
|
||||||
|
|
||||||
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
|
|
||||||
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
|
||||||
|
|
||||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
|
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
|
||||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
|
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
||||||
|
|
||||||
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
|
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
|
||||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
|
|
||||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
|
|
||||||
|
|
||||||
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> >
|
m->add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
|
||||||
// >("AST_NodeVector", m);
|
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
|
||||||
|
|
||||||
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
|
|
||||||
|
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||||
|
|
||||||
|
|
||||||
|
chaiscript::utility::add_class<chaiscript::exception::eval_error>(*m,
|
||||||
"eval_error",
|
"eval_error",
|
||||||
{ },
|
{ },
|
||||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||||
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||||
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
|
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::exception::eval_error &t_eval_error)>([](const chaiscript::exception::eval_error &t_eval_error) -> std::vector<Boxed_Value> {
|
||||||
std::vector<Boxed_Value> retval;
|
std::vector<Boxed_Value> retval;
|
||||||
std::transform(t_eval_error.call_stack.begin(),
|
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||||
t_eval_error.call_stack.end(),
|
|
||||||
std::back_inserter(retval),
|
std::back_inserter(retval),
|
||||||
&chaiscript::var<const chaiscript::AST_Node_Trace &>);
|
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
||||||
return retval;
|
return retval;
|
||||||
}),
|
})), "call_stack"} }
|
||||||
"call_stack"}});
|
);
|
||||||
|
|
||||||
chaiscript::utility::add_class<chaiscript::File_Position>(m,
|
|
||||||
|
chaiscript::utility::add_class<chaiscript::File_Position>(*m,
|
||||||
"File_Position",
|
"File_Position",
|
||||||
{constructor<File_Position()>(), constructor<File_Position(int, int)>()},
|
{ constructor<File_Position()>(),
|
||||||
|
constructor<File_Position(int, int)>() },
|
||||||
{ {fun(&File_Position::line), "line"},
|
{ {fun(&File_Position::line), "line"},
|
||||||
{fun(&File_Position::column), "column"}});
|
{fun(&File_Position::column), "column"} }
|
||||||
|
);
|
||||||
|
|
||||||
chaiscript::utility::add_class<AST_Node>(m,
|
|
||||||
|
chaiscript::utility::add_class<AST_Node>(*m,
|
||||||
"AST_Node",
|
"AST_Node",
|
||||||
{ },
|
{ },
|
||||||
{ {fun(&AST_Node::text), "text"},
|
{ {fun(&AST_Node::text), "text"},
|
||||||
@ -493,18 +599,32 @@ namespace chaiscript::bootstrap {
|
|||||||
{fun(&AST_Node::start), "start"},
|
{fun(&AST_Node::start), "start"},
|
||||||
{fun(&AST_Node::end), "end"},
|
{fun(&AST_Node::end), "end"},
|
||||||
{fun(&AST_Node::to_string), "to_string"},
|
{fun(&AST_Node::to_string), "to_string"},
|
||||||
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
|
{fun(std::function<std::vector<Boxed_Value> (const chaiscript::AST_Node &t_node)>([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
|
||||||
std::vector<Boxed_Value> retval;
|
std::vector<Boxed_Value> retval;
|
||||||
const auto children = t_node.get_children();
|
std::transform(t_node.children.begin(), t_node.children.end(),
|
||||||
std::transform(children.begin(),
|
|
||||||
children.end(),
|
|
||||||
std::back_inserter(retval),
|
std::back_inserter(retval),
|
||||||
&chaiscript::var<const std::reference_wrapper<chaiscript::AST_Node> &>);
|
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
||||||
return retval;
|
return retval;
|
||||||
}),
|
})), "children"},
|
||||||
"children"}});
|
{fun(&AST_Node::replace_child), "replace_child"}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
chaiscript::utility::add_class<parser::ChaiScript_Parser>(*m,
|
||||||
|
"ChaiScript_Parser",
|
||||||
|
{ constructor<parser::ChaiScript_Parser ()>() },
|
||||||
|
{ {fun(&parser::ChaiScript_Parser::parse), "parse"},
|
||||||
|
{fun(&parser::ChaiScript_Parser::ast), "ast"} }
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace chaiscript::bootstrap
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +1,21 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
/// \file
|
/// \file
|
||||||
/// This file contains utility functions for registration of STL container
|
/// This file contains utility functions for registration of STL container
|
||||||
/// classes. The methodology used is based on the SGI STL concepts.
|
/// classes. The methodology used is based on the SGI STL concepts.
|
||||||
/// http://www.sgi.com/tech/stl/table_of_contents.html
|
/// http://www.sgi.com/tech/stl/table_of_contents.html
|
||||||
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
||||||
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <type_traits>
|
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -30,103 +27,183 @@
|
|||||||
#include "register_function.hpp"
|
#include "register_function.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
namespace chaiscript::bootstrap::standard_library {
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
namespace bootstrap
|
||||||
|
{
|
||||||
|
namespace standard_library
|
||||||
|
{
|
||||||
|
|
||||||
/// Bidir_Range, based on the D concept of ranges.
|
/// Bidir_Range, based on the D concept of ranges.
|
||||||
/// \todo Update the Range code to base its capabilities on
|
/// \todo Update the Range code to base its capabilities on
|
||||||
/// the user_typetraits of the iterator passed in
|
/// the user_typetraits of the iterator passed in
|
||||||
template<typename Container, typename IterType>
|
template<typename Container>
|
||||||
struct Bidir_Range {
|
struct Bidir_Range
|
||||||
using container_type = Container;
|
{
|
||||||
|
typedef Container container_type;
|
||||||
|
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
|
||||||
|
|
||||||
constexpr Bidir_Range(Container &c)
|
Bidir_Range(Container &c)
|
||||||
: m_begin(c.begin())
|
: m_begin(c.begin()), m_end(c.end())
|
||||||
, m_end(c.end()) {
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool empty() const noexcept { return m_begin == m_end; }
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_begin == m_end;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void pop_front() {
|
void pop_front()
|
||||||
if (empty()) {
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
throw std::range_error("Range empty");
|
throw std::range_error("Range empty");
|
||||||
}
|
}
|
||||||
++m_begin;
|
++m_begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void pop_back() {
|
void pop_back()
|
||||||
if (empty()) {
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
throw std::range_error("Range empty");
|
throw std::range_error("Range empty");
|
||||||
}
|
}
|
||||||
--m_end;
|
--m_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr decltype(auto) front() const {
|
reference_type front() const
|
||||||
if (empty()) {
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
throw std::range_error("Range empty");
|
throw std::range_error("Range empty");
|
||||||
}
|
}
|
||||||
return (*m_begin);
|
return *m_begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr decltype(auto) back() const {
|
reference_type back() const
|
||||||
if (empty()) {
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
throw std::range_error("Range empty");
|
throw std::range_error("Range empty");
|
||||||
}
|
}
|
||||||
auto pos = m_end;
|
typename Container::iterator pos = m_end;
|
||||||
--pos;
|
--pos;
|
||||||
return (*(pos));
|
return *(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
IterType m_begin;
|
typename Container::iterator m_begin;
|
||||||
IterType m_end;
|
typename Container::iterator m_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
struct Const_Bidir_Range
|
||||||
|
{
|
||||||
|
typedef const Container container_type;
|
||||||
|
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
|
||||||
|
|
||||||
|
Const_Bidir_Range(const Container &c)
|
||||||
|
: m_begin(c.begin()), m_end(c.end())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_begin == m_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_front()
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
throw std::range_error("Range empty");
|
||||||
|
}
|
||||||
|
++m_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
throw std::range_error("Range empty");
|
||||||
|
}
|
||||||
|
--m_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_reference_type front() const
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
throw std::range_error("Range empty");
|
||||||
|
}
|
||||||
|
return *m_begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_reference_type back() const
|
||||||
|
{
|
||||||
|
if (empty())
|
||||||
|
{
|
||||||
|
throw std::range_error("Range empty");
|
||||||
|
}
|
||||||
|
typename Container::const_iterator pos = m_end;
|
||||||
|
--pos;
|
||||||
|
return *(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename Container::const_iterator m_begin;
|
||||||
|
typename Container::const_iterator m_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
size_t count(const T &t_target, const typename T::key_type &t_key) {
|
size_t count(const T &t_target, const typename T::key_type &t_key)
|
||||||
|
{
|
||||||
return t_target.count(t_key);
|
return t_target.count(t_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value find(const T &t_target, const typename T::key_type &t_key) {
|
void insert(T &t_target, const T &t_other)
|
||||||
const auto itr = t_target.find(t_key);
|
{
|
||||||
if (itr != t_target.end()) {
|
|
||||||
return Boxed_Value(itr->second);
|
|
||||||
}
|
|
||||||
return Boxed_Value();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void insert(T &t_target, const T &t_other) {
|
|
||||||
t_target.insert(t_other.begin(), t_other.end());
|
t_target.insert(t_other.begin(), t_other.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void insert_ref(T &t_target, const typename T::value_type &t_val) {
|
void insert_ref(T &t_target, const typename T::value_type &t_val)
|
||||||
|
{
|
||||||
t_target.insert(t_val);
|
t_target.insert(t_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Add Bidir_Range support for the given ContainerType
|
/// Add Bidir_Range support for the given ContainerType
|
||||||
template<typename Bidir_Type>
|
template<typename Bidir_Type>
|
||||||
void input_range_type_impl(const std::string &type, Module &m) {
|
ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<Bidir_Type>(), type + "_Range");
|
{
|
||||||
|
m->add(user_type<Bidir_Type>(), type + "_Range");
|
||||||
|
|
||||||
copy_constructor<Bidir_Type>(type + "_Range", m);
|
copy_constructor<Bidir_Type>(type + "_Range", m);
|
||||||
|
|
||||||
m.add(constructor<Bidir_Type(typename Bidir_Type::container_type &)>(), "range_internal");
|
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
|
||||||
|
|
||||||
m.add(fun(&Bidir_Type::empty), "empty");
|
m->add(fun(&Bidir_Type::empty), "empty");
|
||||||
m.add(fun(&Bidir_Type::pop_front), "pop_front");
|
m->add(fun(&Bidir_Type::pop_front), "pop_front");
|
||||||
m.add(fun(&Bidir_Type::front), "front");
|
m->add(fun(&Bidir_Type::front), "front");
|
||||||
m.add(fun(&Bidir_Type::pop_back), "pop_back");
|
m->add(fun(&Bidir_Type::pop_back), "pop_back");
|
||||||
m.add(fun(&Bidir_Type::back), "back");
|
m->add(fun(&Bidir_Type::back), "back");
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Algorithm for inserting at a specific position into a container
|
/// Algorithm for inserting at a specific position into a container
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
void insert_at(Type &container, int pos, const typename Type::value_type &v) {
|
void insert_at(Type &container, int pos, const typename Type::value_type &v)
|
||||||
|
{
|
||||||
auto itr = container.begin();
|
auto itr = container.begin();
|
||||||
auto end = container.end();
|
auto end = container.end();
|
||||||
|
|
||||||
if (pos < 0 || std::distance(itr, end) < pos) {
|
if (pos < 0 || std::distance(itr, end) < pos)
|
||||||
|
{
|
||||||
throw std::range_error("Cannot insert past end of range");
|
throw std::range_error("Cannot insert past end of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,141 +211,128 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
container.insert(itr, v);
|
container.insert(itr, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Algorithm for erasing a specific position from a container
|
/// Algorithm for erasing a specific position from a container
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
void erase_at(Type &container, int pos) {
|
void erase_at(Type &container, int pos)
|
||||||
|
{
|
||||||
auto itr = container.begin();
|
auto itr = container.begin();
|
||||||
auto end = container.end();
|
auto end = container.end();
|
||||||
|
|
||||||
if (pos < 0 || std::distance(itr, end) <= pos) {
|
if (pos < 0 || std::distance(itr, end) < (pos-1))
|
||||||
|
{
|
||||||
throw std::range_error("Cannot erase past end of range");
|
throw std::range_error("Cannot erase past end of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::advance(itr, pos);
|
std::advance(itr, pos);
|
||||||
container.erase(itr);
|
container.erase(itr);
|
||||||
}
|
}
|
||||||
} // namespace detail
|
}
|
||||||
|
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void input_range_type(const std::string &type, Module &m) {
|
ModulePtr input_range_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator>>(type, m);
|
{
|
||||||
detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator>>("Const_" + type, m);
|
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m);
|
||||||
|
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Add random_access_container concept to the given ContainerType
|
/// Add random_access_container concept to the given ContainerType
|
||||||
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html
|
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void random_access_container_type(const std::string & /*type*/, Module &m) {
|
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
||||||
//to throw an exception in an out of bounds condition.
|
//to throw an exception in an out of bounds condition.
|
||||||
m.add(fun([](ContainerType &c, int index) -> typename ContainerType::reference {
|
m->add(
|
||||||
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
|
fun(
|
||||||
/// during dispatch. reevaluate
|
[](ContainerType &c, int index) -> typename ContainerType::reference {
|
||||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
return c.at(index);
|
||||||
}),
|
}), "[]");
|
||||||
"[]");
|
|
||||||
|
|
||||||
m.add(fun([](const ContainerType &c, int index) -> typename ContainerType::const_reference {
|
m->add(
|
||||||
/// \todo we are preferring to keep the key as 'int' to avoid runtime conversions
|
fun(
|
||||||
/// during dispatch. reevaluate
|
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
|
||||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
return c.at(index);
|
||||||
}),
|
}), "[]");
|
||||||
"[]");
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Add assignable concept to the given ContainerType
|
/// Add assignable concept to the given ContainerType
|
||||||
/// http://www.sgi.com/tech/stl/Assignable.html
|
/// http://www.sgi.com/tech/stl/Assignable.html
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void assignable_type(const std::string &type, Module &m) {
|
ModulePtr assignable_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
if constexpr (std::is_copy_constructible_v<typename ContainerType::value_type>) {
|
{
|
||||||
copy_constructor<ContainerType>(type, m);
|
copy_constructor<ContainerType>(type, m);
|
||||||
operators::assign<ContainerType>(m);
|
operators::assign<ContainerType>(m);
|
||||||
}
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add container resize concept to the given ContainerType
|
|
||||||
/// http://www.cplusplus.com/reference/stl/
|
|
||||||
template<typename ContainerType>
|
|
||||||
void resizable_type(const std::string & /*type*/, Module &m) {
|
|
||||||
if constexpr (std::is_copy_constructible_v<typename ContainerType::value_type>) {
|
|
||||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type &val) {
|
|
||||||
return a->resize(n, val);
|
|
||||||
}),
|
|
||||||
"resize");
|
|
||||||
}
|
|
||||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); }), "resize");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add container reserve concept to the given ContainerType
|
|
||||||
/// http://www.cplusplus.com/reference/stl/
|
|
||||||
template<typename ContainerType>
|
|
||||||
void reservable_type(const std::string & /*type*/, Module &m) {
|
|
||||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); }), "reserve");
|
|
||||||
m.add(fun([](const ContainerType *a) { return a->capacity(); }), "capacity");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add container concept to the given ContainerType
|
/// Add container concept to the given ContainerType
|
||||||
/// http://www.sgi.com/tech/stl/Container.html
|
/// http://www.sgi.com/tech/stl/Container.html
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void container_type(const std::string & /*type*/, Module &m) {
|
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(fun([](const ContainerType *a) { return a->size(); }), "size");
|
{
|
||||||
m.add(fun([](const ContainerType *a) { return a->empty(); }), "empty");
|
m->add(fun([](const ContainerType *a) { return a->size(); } ), "size");
|
||||||
m.add(fun([](ContainerType *a) { a->clear(); }), "clear");
|
m->add(fun([](const ContainerType *a) { return a->empty(); } ), "empty");
|
||||||
|
m->add(fun([](ContainerType *a) { a->clear(); } ), "clear");
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Add default constructable concept to the given Type
|
/// Add default constructable concept to the given Type
|
||||||
/// http://www.sgi.com/tech/stl/DefaultConstructible.html
|
/// http://www.sgi.com/tech/stl/DefaultConstructible.html
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
void default_constructible_type(const std::string &type, Module &m) {
|
ModulePtr default_constructible_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(constructor<Type()>(), type);
|
{
|
||||||
|
m->add(constructor<Type ()>(), type);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Add sequence concept to the given ContainerType
|
/// Add sequence concept to the given ContainerType
|
||||||
/// http://www.sgi.com/tech/stl/Sequence.html
|
/// http://www.sgi.com/tech/stl/Sequence.html
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void sequence_type(const std::string & /*type*/, Module &m) {
|
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||||
if constexpr (std::is_copy_constructible_v<typename ContainerType::value_type>) {
|
{
|
||||||
m.add(fun(&detail::insert_at<ContainerType>), []() -> std::string {
|
m->add(fun(&detail::insert_at<ContainerType>),
|
||||||
|
[]()->std::string{
|
||||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||||
return "insert_ref_at";
|
return "insert_ref_at";
|
||||||
} else {
|
} else {
|
||||||
return "insert_at";
|
return "insert_at";
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
m->add(fun(&detail::erase_at<ContainerType>), "erase_at");
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
m.add(fun(&detail::erase_at<ContainerType>), "erase_at");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add back insertion sequence concept to the given ContainerType
|
/// Add back insertion sequence concept to the given ContainerType
|
||||||
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
|
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void back_insertion_sequence_type(const std::string &type, Module &m) {
|
ModulePtr back_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(fun([](ContainerType &container) -> decltype(auto) {
|
{
|
||||||
if (container.empty()) {
|
typedef typename ContainerType::reference (ContainerType::*backptr)();
|
||||||
throw std::range_error("Container empty");
|
|
||||||
} else {
|
|
||||||
return (container.back());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
"back");
|
|
||||||
m.add(fun([](const ContainerType &container) -> decltype(auto) {
|
|
||||||
if (container.empty()) {
|
|
||||||
throw std::range_error("Container empty");
|
|
||||||
} else {
|
|
||||||
return (container.back());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
"back");
|
|
||||||
|
|
||||||
if constexpr (std::is_copy_constructible_v<typename ContainerType::value_type>) {
|
m->add(fun(static_cast<backptr>(&ContainerType::back)), "back");
|
||||||
using push_back = void (ContainerType::*)(const typename ContainerType::value_type &);
|
|
||||||
m.add(fun(static_cast<push_back>(&ContainerType::push_back)), [&]() -> std::string {
|
|
||||||
|
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||||
|
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
||||||
|
[&]()->std::string{
|
||||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||||
m.eval("# Pushes the second value onto the container while making a clone of the value\n"
|
m->eval(
|
||||||
"def push_back("
|
"# Pushes the second value onto the container while making a clone of the value\n"
|
||||||
+ type
|
"def push_back(" + type + " container, x)\n"
|
||||||
+ " container, x)\n"
|
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" if (x.is_var_return_value()) {\n"
|
" if (x.is_var_return_value()) {\n"
|
||||||
" x.reset_var_return_value() \n"
|
" x.reset_var_return_value() \n"
|
||||||
@ -276,50 +340,40 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
" } else { \n"
|
" } else { \n"
|
||||||
" container.push_back_ref(clone(x)); \n"
|
" container.push_back_ref(clone(x)); \n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"} \n");
|
"} \n"
|
||||||
|
);
|
||||||
|
|
||||||
return "push_back_ref";
|
return "push_back_ref";
|
||||||
} else {
|
} else {
|
||||||
return "push_back";
|
return "push_back";
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
m->add(fun(&ContainerType::pop_back), "pop_back");
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
m.add(fun(&ContainerType::pop_back), "pop_back");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Front insertion sequence
|
/// Front insertion sequence
|
||||||
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
|
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void front_insertion_sequence_type(const std::string &type, Module &m) {
|
ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference);
|
{
|
||||||
using pop_ptr = void (ContainerType::*)();
|
typedef typename ContainerType::reference (ContainerType::*front_ptr)();
|
||||||
|
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
|
||||||
|
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
|
||||||
|
typedef void (ContainerType::*pop_ptr)();
|
||||||
|
|
||||||
m.add(fun([](ContainerType &container) -> decltype(auto) {
|
m->add(fun(static_cast<front_ptr>(&ContainerType::front)), "front");
|
||||||
if (container.empty()) {
|
m->add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
|
||||||
throw std::range_error("Container empty");
|
|
||||||
} else {
|
|
||||||
return (container.front());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
"front");
|
|
||||||
|
|
||||||
m.add(fun([](const ContainerType &container) -> decltype(auto) {
|
m->add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
|
||||||
if (container.empty()) {
|
[&]()->std::string{
|
||||||
throw std::range_error("Container empty");
|
|
||||||
} else {
|
|
||||||
return (container.front());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
"front");
|
|
||||||
|
|
||||||
if constexpr (std::is_copy_constructible_v<typename ContainerType::value_type>) {
|
|
||||||
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)), [&]() -> std::string {
|
|
||||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||||
m.eval("# Pushes the second value onto the front of container while making a clone of the value\n"
|
m->eval(
|
||||||
"def push_front("
|
"# Pushes the second value onto the front of container while making a clone of the value\n"
|
||||||
+ type
|
"def push_front(" + type + " container, x)\n"
|
||||||
+ " container, x)\n"
|
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" if (x.is_var_return_value()) {\n"
|
" if (x.is_var_return_value()) {\n"
|
||||||
" x.reset_var_return_value() \n"
|
" x.reset_var_return_value() \n"
|
||||||
@ -327,76 +381,98 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
" } else { \n"
|
" } else { \n"
|
||||||
" container.push_front_ref(clone(x)); \n"
|
" container.push_front_ref(clone(x)); \n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"} \n");
|
"} \n"
|
||||||
|
);
|
||||||
return "push_front_ref";
|
return "push_front_ref";
|
||||||
} else {
|
} else {
|
||||||
return "push_front";
|
return "push_front";
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
m->add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// bootstrap a given PairType
|
/// bootstrap a given PairType
|
||||||
/// http://www.sgi.com/tech/stl/pair.html
|
/// http://www.sgi.com/tech/stl/pair.html
|
||||||
template<typename PairType>
|
template<typename PairType>
|
||||||
void pair_type(const std::string &type, Module &m) {
|
ModulePtr pair_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<PairType>(), type);
|
{
|
||||||
|
m->add(user_type<PairType>(), type);
|
||||||
|
|
||||||
m.add(fun(&PairType::first), "first");
|
|
||||||
m.add(fun(&PairType::second), "second");
|
typename PairType::first_type PairType::* f = &PairType::first;
|
||||||
|
typename PairType::second_type PairType::* s = &PairType::second;
|
||||||
|
|
||||||
|
m->add(fun(f), "first");
|
||||||
|
m->add(fun(s), "second");
|
||||||
|
|
||||||
basic_constructors<PairType>(type, m);
|
basic_constructors<PairType>(type, m);
|
||||||
m.add(constructor<PairType(const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
|
m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Add pair associative container concept to the given ContainerType
|
/// Add pair associative container concept to the given ContainerType
|
||||||
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
|
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
|
||||||
|
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void pair_associative_container_type(const std::string &type, Module &m) {
|
ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
|
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Add unique associative container concept to the given ContainerType
|
/// Add unique associative container concept to the given ContainerType
|
||||||
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
|
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
|
||||||
template<typename ContainerType>
|
template<typename ContainerType>
|
||||||
void unique_associative_container_type(const std::string & /*type*/, Module &m) {
|
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(fun(detail::count<ContainerType>), "count");
|
{
|
||||||
m.add(fun(detail::find<ContainerType>), "find");
|
m->add(fun(detail::count<ContainerType>), "count");
|
||||||
|
|
||||||
using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &);
|
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
|
||||||
|
|
||||||
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
|
m->add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
|
||||||
|
|
||||||
m.add(fun(&detail::insert<ContainerType>), "insert");
|
m->add(fun(&detail::insert<ContainerType>), "insert");
|
||||||
|
|
||||||
m.add(fun(&detail::insert_ref<ContainerType>), []() -> std::string {
|
m->add(fun(&detail::insert_ref<ContainerType>),
|
||||||
|
[]()->std::string{
|
||||||
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
|
||||||
return "insert_ref";
|
return "insert_ref";
|
||||||
} else {
|
} else {
|
||||||
return "insert";
|
return "insert";
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Add a MapType container
|
/// Add a MapType container
|
||||||
/// http://www.sgi.com/tech/stl/Map.html
|
/// http://www.sgi.com/tech/stl/Map.html
|
||||||
template<typename MapType>
|
template<typename MapType>
|
||||||
void map_type(const std::string &type, Module &m) {
|
ModulePtr map_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<MapType>(), type);
|
{
|
||||||
|
m->add(user_type<MapType>(), type);
|
||||||
|
|
||||||
using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &);
|
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &);
|
||||||
using const_elem_access = const typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &) const;
|
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const;
|
||||||
|
|
||||||
m.add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
|
m->add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
|
||||||
|
|
||||||
m.add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
m->add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
||||||
m.add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
m->add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
||||||
|
|
||||||
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>)) {
|
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>))
|
||||||
m.eval(R"(
|
{
|
||||||
|
m->eval(R"(
|
||||||
def Map::`==`(Map rhs) {
|
def Map::`==`(Map rhs) {
|
||||||
if ( rhs.size() != this.size() ) {
|
if ( rhs.size() != this.size() ) {
|
||||||
return false;
|
return false;
|
||||||
@ -414,7 +490,8 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
}
|
}
|
||||||
true;
|
true;
|
||||||
}
|
}
|
||||||
} )");
|
} )"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
container_type<MapType>(type, m);
|
container_type<MapType>(type, m);
|
||||||
@ -423,59 +500,55 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
unique_associative_container_type<MapType>(type, m);
|
unique_associative_container_type<MapType>(type, m);
|
||||||
pair_associative_container_type<MapType>(type, m);
|
pair_associative_container_type<MapType>(type, m);
|
||||||
input_range_type<MapType>(type, m);
|
input_range_type<MapType>(type, m);
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// hopefully working List type
|
||||||
/// http://www.sgi.com/tech/stl/List.html
|
/// http://www.sgi.com/tech/stl/List.html
|
||||||
template<typename ListType>
|
template<typename ListType>
|
||||||
void list_type(const std::string &type, Module &m) {
|
ModulePtr list_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<ListType>(), type);
|
{
|
||||||
|
m->add(user_type<ListType>(), type);
|
||||||
|
|
||||||
front_insertion_sequence_type<ListType>(type, m);
|
front_insertion_sequence_type<ListType>(type, m);
|
||||||
back_insertion_sequence_type<ListType>(type, m);
|
back_insertion_sequence_type<ListType>(type, m);
|
||||||
sequence_type<ListType>(type, m);
|
sequence_type<ListType>(type, m);
|
||||||
resizable_type<ListType>(type, m);
|
|
||||||
container_type<ListType>(type, m);
|
container_type<ListType>(type, m);
|
||||||
default_constructible_type<ListType>(type, m);
|
default_constructible_type<ListType>(type, m);
|
||||||
assignable_type<ListType>(type, m);
|
assignable_type<ListType>(type, m);
|
||||||
input_range_type<ListType>(type, m);
|
input_range_type<ListType>(type, m);
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Create a vector type with associated concepts
|
/// Create a vector type with associated concepts
|
||||||
/// http://www.sgi.com/tech/stl/Vector.html
|
/// http://www.sgi.com/tech/stl/Vector.html
|
||||||
template<typename VectorType>
|
template<typename VectorType>
|
||||||
void vector_type(const std::string &type, Module &m) {
|
ModulePtr vector_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<VectorType>(), type);
|
{
|
||||||
|
m->add(user_type<VectorType>(), type);
|
||||||
|
|
||||||
m.add(fun([](VectorType &container) -> decltype(auto) {
|
typedef typename VectorType::reference (VectorType::*frontptr)();
|
||||||
if (container.empty()) {
|
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
|
||||||
throw std::range_error("Container empty");
|
|
||||||
} else {
|
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
|
||||||
return (container.front());
|
m->add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
|
||||||
}
|
|
||||||
}),
|
|
||||||
"front");
|
|
||||||
|
|
||||||
m.add(fun([](const VectorType &container) -> decltype(auto) {
|
|
||||||
if (container.empty()) {
|
|
||||||
throw std::range_error("Container empty");
|
|
||||||
} else {
|
|
||||||
return (container.front());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
"front");
|
|
||||||
|
|
||||||
back_insertion_sequence_type<VectorType>(type, m);
|
back_insertion_sequence_type<VectorType>(type, m);
|
||||||
sequence_type<VectorType>(type, m);
|
sequence_type<VectorType>(type, m);
|
||||||
random_access_container_type<VectorType>(type, m);
|
random_access_container_type<VectorType>(type, m);
|
||||||
resizable_type<VectorType>(type, m);
|
|
||||||
reservable_type<VectorType>(type, m);
|
|
||||||
container_type<VectorType>(type, m);
|
container_type<VectorType>(type, m);
|
||||||
default_constructible_type<VectorType>(type, m);
|
default_constructible_type<VectorType>(type, m);
|
||||||
assignable_type<VectorType>(type, m);
|
assignable_type<VectorType>(type, m);
|
||||||
input_range_type<VectorType>(type, m);
|
input_range_type<VectorType>(type, m);
|
||||||
|
|
||||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>)) {
|
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
||||||
m.eval(R"(
|
{
|
||||||
|
m->eval(R"(
|
||||||
def Vector::`==`(Vector rhs) {
|
def Vector::`==`(Vector rhs) {
|
||||||
if ( rhs.size() != this.size() ) {
|
if ( rhs.size() != this.size() ) {
|
||||||
return false;
|
return false;
|
||||||
@ -493,15 +566,19 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
}
|
}
|
||||||
true;
|
true;
|
||||||
}
|
}
|
||||||
} )");
|
} )"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a String container
|
/// Add a String container
|
||||||
/// http://www.sgi.com/tech/stl/basic_string.html
|
/// http://www.sgi.com/tech/stl/basic_string.html
|
||||||
template<typename String>
|
template<typename String>
|
||||||
void string_type(const std::string &type, Module &m) {
|
ModulePtr string_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<String>(), type);
|
{
|
||||||
|
m->add(user_type<String>(), type);
|
||||||
operators::addition<String>(m);
|
operators::addition<String>(m);
|
||||||
operators::assign_sum<String>(m);
|
operators::assign_sum<String>(m);
|
||||||
opers_comparison<String>(m);
|
opers_comparison<String>(m);
|
||||||
@ -513,7 +590,8 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
input_range_type<String>(type, m);
|
input_range_type<String>(type, m);
|
||||||
|
|
||||||
//Special case: add push_back to string (which doesn't support other back_insertion operations
|
//Special case: add push_back to string (which doesn't support other back_insertion operations
|
||||||
m.add(fun(&String::push_back), []() -> std::string {
|
m->add(fun(&String::push_back),
|
||||||
|
[]()->std::string{
|
||||||
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
|
||||||
return "push_back_ref";
|
return "push_back_ref";
|
||||||
} else {
|
} else {
|
||||||
@ -521,89 +599,45 @@ namespace chaiscript::bootstrap::standard_library {
|
|||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); }), "find");
|
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); }), "rfind");
|
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); }), "find_first_of");
|
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); }), "find_last_of");
|
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); }), "find_last_not_of");
|
|
||||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); }), "find_first_not_of");
|
|
||||||
|
|
||||||
m.add(fun([](String *s, typename String::value_type c) -> decltype(auto) { return (*s += c); }), "+=");
|
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find");
|
||||||
|
m->add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind");
|
||||||
|
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of");
|
||||||
|
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
|
||||||
|
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
|
||||||
|
m->add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
|
||||||
|
|
||||||
m.add(fun([](String *s) { s->clear(); }), "clear");
|
m->add(fun([](String *s) { s->clear(); } ), "clear");
|
||||||
m.add(fun([](const String *s) { return s->empty(); }), "empty");
|
m->add(fun([](const String *s) { return s->empty(); } ), "empty");
|
||||||
m.add(fun([](const String *s) { return s->size(); }), "size");
|
m->add(fun([](const String *s) { return s->size(); } ), "size");
|
||||||
|
|
||||||
m.add(fun([](const String *s) { return s->c_str(); }), "c_str");
|
m->add(fun([](const String *s) { return s->c_str(); } ), "c_str");
|
||||||
m.add(fun([](const String *s) { return s->data(); }), "data");
|
m->add(fun([](const String *s) { return s->data(); } ), "data");
|
||||||
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); }), "substr");
|
m->add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a String_View type (e.g. std::string_view), with conversions to and from
|
|
||||||
/// the matching owning String type (e.g. std::string).
|
|
||||||
///
|
|
||||||
/// Mirrors the search/substring surface of string_type so that scripts can
|
|
||||||
/// traverse a buffer through StringView without allocating. Sharing method
|
|
||||||
/// names with the owning String type is safe: dispatch deprioritizes any
|
|
||||||
/// candidate whose first/receiver argument requires a type conversion (see
|
|
||||||
/// dispatch() in proxy_functions.hpp), so myString.substr(1, 2) still
|
|
||||||
/// resolves to String::substr while mySV.substr(1, 2) resolves to
|
|
||||||
/// StringView::substr (returning a StringView).
|
|
||||||
///
|
|
||||||
/// \note A String_View is a non-owning reference. Constructing one from a
|
|
||||||
/// temporary owning String yields a dangling reference once that temporary
|
|
||||||
/// is destroyed; the same lifetime caveats as in C++ apply here.
|
|
||||||
template<typename StringView, typename String>
|
|
||||||
void string_view_type(const std::string &type, Module &m) {
|
|
||||||
m.add(user_type<StringView>(), type);
|
|
||||||
m.add(constructor<StringView()>(), type);
|
|
||||||
m.add(constructor<StringView(const StringView &)>(), type);
|
|
||||||
m.add(fun([](const String &s) { return StringView{s}; }), type);
|
|
||||||
|
|
||||||
opers_comparison<StringView>(m);
|
|
||||||
|
|
||||||
m.add(fun([](const StringView *s) { return s->size(); }), "size");
|
|
||||||
m.add(fun([](const StringView *s) { return s->length(); }), "length");
|
|
||||||
m.add(fun([](const StringView *s) { return s->empty(); }), "empty");
|
|
||||||
m.add(fun([](const StringView *s) { return s->data(); }), "data");
|
|
||||||
|
|
||||||
// Random-access via [] / at, returning const_reference; StringView is read-only.
|
|
||||||
m.add(fun([](const StringView &sv, int index) -> typename StringView::const_reference {
|
|
||||||
return sv.at(static_cast<typename StringView::size_type>(index));
|
|
||||||
}),
|
|
||||||
"[]");
|
|
||||||
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f, size_t pos) { return s->find(f, pos); }), "find");
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f, size_t pos) { return s->rfind(f, pos); }), "rfind");
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f, size_t pos) { return s->find_first_of(f, pos); }), "find_first_of");
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f, size_t pos) { return s->find_last_of(f, pos); }), "find_last_of");
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f, size_t pos) { return s->find_last_not_of(f, pos); }), "find_last_not_of");
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f, size_t pos) { return s->find_first_not_of(f, pos); }), "find_first_not_of");
|
|
||||||
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f) { return s->starts_with(f); }), "starts_with");
|
|
||||||
m.add(fun([](const StringView *s, const StringView &f) { return s->ends_with(f); }), "ends_with");
|
|
||||||
|
|
||||||
m.add(fun([](const StringView *s, size_t pos, size_t len) { return s->substr(pos, len); }), "substr");
|
|
||||||
|
|
||||||
// Built-in implicit conversion from owning String to non-owning StringView.
|
|
||||||
m.add(type_conversion<const String &, StringView>());
|
|
||||||
|
|
||||||
// Explicit conversion from StringView back to owning String, registered as
|
|
||||||
// to_string(sv); the call site can also register it under the owning type's
|
|
||||||
// name (e.g. string(sv)) when desired.
|
|
||||||
m.add(fun([](const StringView sv) { return String{sv}; }), "to_string");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a MapType container
|
/// Add a MapType container
|
||||||
/// http://www.sgi.com/tech/stl/Map.html
|
/// http://www.sgi.com/tech/stl/Map.html
|
||||||
template<typename FutureType>
|
template<typename FutureType>
|
||||||
void future_type(const std::string &type, Module &m) {
|
ModulePtr future_type(const std::string &type, ModulePtr m = std::make_shared<Module>())
|
||||||
m.add(user_type<FutureType>(), type);
|
{
|
||||||
|
m->add(user_type<FutureType>(), type);
|
||||||
|
|
||||||
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
|
m->add(fun([](const FutureType &t) { return t.valid(); }), "valid");
|
||||||
m.add(fun([](FutureType &t) { return t.get(); }), "get");
|
m->add(fun(&FutureType::get), "get");
|
||||||
m.add(fun(&FutureType::wait), "wait");
|
m->add(fun(&FutureType::wait), "wait");
|
||||||
|
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
} // namespace chaiscript::bootstrap::standard_library
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
|
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
|
||||||
#define CHAISCRIPT_BOXED_CAST_HPP_
|
#define CHAISCRIPT_BOXED_CAST_HPP_
|
||||||
|
|
||||||
@ -19,12 +16,16 @@
|
|||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
class Type_Conversions;
|
class Type_Conversions;
|
||||||
}
|
namespace detail {
|
||||||
namespace chaiscript::detail::exception {
|
namespace exception {
|
||||||
class bad_any_cast;
|
class bad_any_cast;
|
||||||
} // namespace chaiscript::detail::exception
|
} // namespace exception
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
|
||||||
namespace chaiscript {
|
|
||||||
/// \brief Function for extracting a value stored in a Boxed_Value object
|
/// \brief Function for extracting a value stored in a Boxed_Value object
|
||||||
/// \tparam Type The type to extract from the Boxed_Value
|
/// \tparam Type The type to extract from the Boxed_Value
|
||||||
/// \param[in] bv The Boxed_Value to extract a typed value from
|
/// \param[in] bv The Boxed_Value to extract a typed value from
|
||||||
@ -68,35 +69,43 @@ namespace chaiscript {
|
|||||||
/// assert(i == 5);
|
/// assert(i == 5);
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) {
|
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
|
||||||
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
|
{
|
||||||
|
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !t_conversions->convertable_type<Type>())) {
|
||||||
try {
|
try {
|
||||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t_conversions && (*t_conversions)->convertable_type<Type>()) {
|
|
||||||
|
if (t_conversions && t_conversions->convertable_type<Type>())
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
|
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
|
||||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||||
// either way, we are not responsible if it doesn't work
|
// either way, we are not responsible if it doesn't work
|
||||||
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
try {
|
try {
|
||||||
// try going the other way
|
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
|
||||||
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv),
|
// try going the other way - down the inheritance graph
|
||||||
t_conversions));
|
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
|
||||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If it's not convertable, just throw the error, don't waste the time on the
|
// If it's not polymorphic, just throw the error, don't waste the time on the
|
||||||
// attempted dynamic_cast
|
// attempted dynamic_cast
|
||||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||||
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||||
|
|
||||||
@ -16,154 +13,125 @@
|
|||||||
#include "boxed_value.hpp"
|
#include "boxed_value.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
|
||||||
class Type_Conversions_State;
|
|
||||||
|
|
||||||
namespace detail {
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
class Type_Conversions;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
// Cast_Helper_Inner helper classes
|
// Cast_Helper_Inner helper classes
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T *throw_if_null(T *t) {
|
T* throw_if_null(T *t)
|
||||||
if (t) {
|
{
|
||||||
return t;
|
if (t) return t;
|
||||||
}
|
|
||||||
throw std::runtime_error("Attempted to dereference null Boxed_Value");
|
throw std::runtime_error("Attempted to dereference null Boxed_Value");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
|
|
||||||
if (ob.get_type_info() == ti) {
|
|
||||||
return ptr;
|
|
||||||
} else {
|
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
|
||||||
if (!ob.is_const() && ob.get_type_info() == ti) {
|
|
||||||
return ptr;
|
|
||||||
} else {
|
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
|
|
||||||
if (ob.get_type_info().bare_equal_type_info(ti)) {
|
|
||||||
return throw_if_null(ptr);
|
|
||||||
} else {
|
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
|
||||||
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
|
|
||||||
return throw_if_null(ptr);
|
|
||||||
} else {
|
|
||||||
throw chaiscript::detail::exception::bad_any_cast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generic Cast_Helper_Inner, for casting to any type
|
/// Generic Cast_Helper_Inner, for casting to any type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner {
|
struct Cast_Helper_Inner
|
||||||
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
{
|
||||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
typedef std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
|
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||||
|
{
|
||||||
|
auto p = throw_if_null(ob.get_const_ptr());
|
||||||
|
return std::cref(*static_cast<const Result *>(p));
|
||||||
|
} else {
|
||||||
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result> {
|
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Cast_Helper_Inner for casting to a const & type
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a const * type
|
/// Cast_Helper_Inner for casting to a const * type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const Result *> {
|
struct Cast_Helper_Inner<const Result *>
|
||||||
static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
{
|
||||||
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
|
typedef const Result * Result_Type;
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
|
if (ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||||
|
{
|
||||||
|
return static_cast<const Result *>(throw_if_null(ob.get_const_ptr()));
|
||||||
|
} else {
|
||||||
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a * type
|
/// Cast_Helper_Inner for casting to a * type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<Result *> {
|
struct Cast_Helper_Inner<Result *>
|
||||||
static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
{
|
||||||
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
|
typedef Result * Result_Type;
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
|
if (!ob.get_type_info().is_const() && ob.get_type_info() == typeid(Result))
|
||||||
|
{
|
||||||
|
return static_cast<Result *>(throw_if_null(ob.get_ptr()));
|
||||||
|
} else {
|
||||||
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<Result *const &> : public Cast_Helper_Inner<Result *> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const Result *const &> : public Cast_Helper_Inner<const Result *> {
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a & type
|
/// Cast_Helper_Inner for casting to a & type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const Result &> {
|
struct Cast_Helper_Inner<Result &>
|
||||||
static const Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
{
|
||||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
typedef Result& Result_Type;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a & type
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
template<typename Result>
|
{
|
||||||
struct Cast_Helper_Inner<Result &> {
|
if (!ob.get_type_info().is_const() && ob.get_type_info().bare_equal_type_info(typeid(Result)))
|
||||||
static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
{
|
||||||
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
|
return *(static_cast<Result *>(throw_if_null(ob.get_ptr())));
|
||||||
|
} else {
|
||||||
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a && type
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<Result &&> {
|
|
||||||
static Result &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
|
||||||
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
|
|
||||||
/// \todo Fix the fact that this has to be in a shared_ptr for now
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<std::unique_ptr<Result> &&> {
|
|
||||||
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
|
||||||
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
|
|
||||||
/// \todo Fix the fact that this has to be in a shared_ptr for now
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<std::unique_ptr<Result> &> {
|
|
||||||
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
|
||||||
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
|
|
||||||
/// \todo Fix the fact that this has to be in a shared_ptr for now
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const std::unique_ptr<Result> &> {
|
|
||||||
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
|
||||||
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type
|
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<std::shared_ptr<Result>> {
|
struct Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob.get().cast<std::shared_ptr<Result>>(); }
|
{
|
||||||
|
typedef std::shared_ptr<Result> Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
|
return ob.get().cast<std::shared_ptr<Result> >();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
|
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
{
|
||||||
if (!ob.get_type_info().is_const()) {
|
typedef std::shared_ptr<const Result> Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
|
if (!ob.get_type_info().is_const())
|
||||||
|
{
|
||||||
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
|
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
|
||||||
} else {
|
} else {
|
||||||
return ob.get().cast<std::shared_ptr<const Result> >();
|
return ob.get().cast<std::shared_ptr<const Result> >();
|
||||||
@ -173,88 +141,108 @@ namespace chaiscript {
|
|||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
|
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::shared_ptr<Result>> : Cast_Helper_Inner<std::shared_ptr<Result>> {
|
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result>> {
|
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||||
};
|
{
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<std::shared_ptr<Result> &> {
|
|
||||||
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
|
|
||||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
|
||||||
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result>>();
|
|
||||||
return ob.pointer_sentinel(res);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a Boxed_Value type
|
/// Cast_Helper_Inner for casting to a Boxed_Value type
|
||||||
template<>
|
template<>
|
||||||
struct Cast_Helper_Inner<Boxed_Value> {
|
struct Cast_Helper_Inner<Boxed_Value>
|
||||||
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; }
|
{
|
||||||
|
typedef Boxed_Value Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
|
return ob;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a Boxed_Value & type
|
/// Cast_Helper_Inner for casting to a Boxed_Value & type
|
||||||
template<>
|
template<>
|
||||||
struct Cast_Helper_Inner<Boxed_Value &> {
|
struct Cast_Helper_Inner<Boxed_Value &>
|
||||||
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
{
|
||||||
|
typedef std::reference_wrapper<Boxed_Value> Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *)
|
||||||
|
{
|
||||||
return std::ref(const_cast<Boxed_Value &>(ob));
|
return std::ref(const_cast<Boxed_Value &>(ob));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
|
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
|
||||||
template<>
|
template<>
|
||||||
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value> {
|
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> {
|
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Cast_Helper_Inner for casting to a std::reference_wrapper type
|
/// Cast_Helper_Inner for casting to a std::reference_wrapper type
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
|
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
|
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &> {
|
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
|
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
|
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Result>
|
template<typename Result>
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> &> : Cast_Helper_Inner<const Result &> {
|
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
|
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Cast_Helper {
|
struct Cast_Helper
|
||||||
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
{
|
||||||
return (Cast_Helper_Inner<T>::cast(ob, t_conversions));
|
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
|
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace detail
|
}
|
||||||
|
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
|
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
|
||||||
#define CHAISCRIPT_BOXED_VALUE_HPP_
|
#define CHAISCRIPT_BOXED_VALUE_HPP_
|
||||||
|
|
||||||
@ -18,29 +15,36 @@
|
|||||||
#include "any.hpp"
|
#include "any.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
|
||||||
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
|
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
|
||||||
/// \sa chaiscript::boxed_cast
|
/// \sa chaiscript::boxed_cast
|
||||||
class Boxed_Value {
|
class Boxed_Value
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
/// used for explicitly creating a "void" object
|
/// used for explicitly creating a "void" object
|
||||||
struct Void_Type {
|
struct Void_Type
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// structure which holds the internal state of a Boxed_Value
|
/// structure which holds the internal state of a Boxed_Value
|
||||||
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
|
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
|
||||||
struct Data {
|
struct Data
|
||||||
Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value) noexcept
|
{
|
||||||
: m_type_info(ti)
|
Data(const Type_Info &ti,
|
||||||
, m_obj(std::move(to))
|
chaiscript::detail::Any to,
|
||||||
, m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr))
|
bool tr,
|
||||||
, m_const_data_ptr(t_void_ptr)
|
const void *t_void_ptr,
|
||||||
, m_is_ref(is_ref)
|
bool t_return_value)
|
||||||
, m_return_value(t_return_value) {
|
: m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
|
||||||
|
m_is_ref(tr), m_return_value(t_return_value)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Data &operator=(const Data &rhs) {
|
Data &operator=(const Data &rhs)
|
||||||
|
{
|
||||||
m_type_info = rhs.m_type_info;
|
m_type_info = rhs.m_type_info;
|
||||||
m_obj = rhs.m_obj;
|
m_obj = rhs.m_obj;
|
||||||
m_is_ref = rhs.m_is_ref;
|
m_is_ref = rhs.m_is_ref;
|
||||||
@ -48,8 +52,9 @@ namespace chaiscript {
|
|||||||
m_const_data_ptr = rhs.m_const_data_ptr;
|
m_const_data_ptr = rhs.m_const_data_ptr;
|
||||||
m_return_value = rhs.m_return_value;
|
m_return_value = rhs.m_return_value;
|
||||||
|
|
||||||
if (rhs.m_attrs) {
|
if (rhs.m_attrs)
|
||||||
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
|
{
|
||||||
|
m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*rhs.m_attrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -57,8 +62,11 @@ namespace chaiscript {
|
|||||||
|
|
||||||
Data(const Data &) = delete;
|
Data(const Data &) = delete;
|
||||||
|
|
||||||
|
#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER != 1800)
|
||||||
Data(Data &&) = default;
|
Data(Data &&) = default;
|
||||||
Data &operator=(Data &&rhs) = default;
|
Data &operator=(Data &&rhs) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Type_Info m_type_info;
|
Type_Info m_type_info;
|
||||||
chaiscript::detail::Any m_obj;
|
chaiscript::detail::Any m_obj;
|
||||||
@ -69,151 +77,205 @@ namespace chaiscript {
|
|||||||
bool m_return_value;
|
bool m_return_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Object_Data {
|
struct Object_Data
|
||||||
static auto get(Boxed_Value::Void_Type, bool t_return_value) {
|
{
|
||||||
return std::make_shared<Data>(detail::Get_Type_Info<void>::get(), chaiscript::detail::Any(), false, nullptr, t_return_value);
|
static std::shared_ptr<Data> get(Boxed_Value::Void_Type, bool t_return_value)
|
||||||
|
{
|
||||||
|
return std::make_shared<Data>(
|
||||||
|
detail::Get_Type_Info<void>::get(),
|
||||||
|
chaiscript::detail::Any(),
|
||||||
|
false,
|
||||||
|
nullptr,
|
||||||
|
t_return_value)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
|
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj, bool t_return_value)
|
||||||
|
{
|
||||||
return get(*obj, t_return_value);
|
return get(*obj, t_return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static auto get(const std::shared_ptr<T> &obj, bool t_return_value) {
|
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj, bool t_return_value)
|
||||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(obj), false, obj.get(), t_return_value);
|
{
|
||||||
|
return std::make_shared<Data>(
|
||||||
|
detail::Get_Type_Info<T>::get(),
|
||||||
|
chaiscript::detail::Any(obj),
|
||||||
|
false,
|
||||||
|
obj.get(),
|
||||||
|
t_return_value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static auto get(std::shared_ptr<T> &&obj, bool t_return_value) {
|
static std::shared_ptr<Data> get(std::shared_ptr<T> &&obj, bool t_return_value)
|
||||||
|
{
|
||||||
auto ptr = obj.get();
|
auto ptr = obj.get();
|
||||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), false, ptr, t_return_value);
|
return std::make_shared<Data>(
|
||||||
|
detail::Get_Type_Info<T>::get(),
|
||||||
|
chaiscript::detail::Any(std::move(obj)),
|
||||||
|
false,
|
||||||
|
ptr,
|
||||||
|
t_return_value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static auto get(T *t, bool t_return_value) {
|
static std::shared_ptr<Data> get(T *t, bool t_return_value)
|
||||||
|
{
|
||||||
return get(std::ref(*t), t_return_value);
|
return get(std::ref(*t), t_return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static auto get(const T *t, bool t_return_value) {
|
static std::shared_ptr<Data> get(const T *t, bool t_return_value)
|
||||||
|
{
|
||||||
return get(std::cref(*t), t_return_value);
|
return get(std::cref(*t), t_return_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static auto get(std::reference_wrapper<T> obj, bool t_return_value) {
|
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj, bool t_return_value)
|
||||||
|
{
|
||||||
auto p = &obj.get();
|
auto p = &obj.get();
|
||||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(obj)), true, p, t_return_value);
|
return std::make_shared<Data>(
|
||||||
}
|
detail::Get_Type_Info<T>::get(),
|
||||||
|
chaiscript::detail::Any(std::move(obj)),
|
||||||
template<typename T>
|
|
||||||
static auto get(std::unique_ptr<T> &&obj, bool t_return_value) {
|
|
||||||
auto ptr = obj.get();
|
|
||||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(),
|
|
||||||
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
|
|
||||||
true,
|
true,
|
||||||
ptr,
|
p,
|
||||||
t_return_value);
|
t_return_value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static auto get(T t, bool t_return_value) {
|
static std::shared_ptr<Data> get(T t, bool t_return_value)
|
||||||
|
{
|
||||||
auto p = std::make_shared<T>(std::move(t));
|
auto p = std::make_shared<T>(std::move(t));
|
||||||
auto ptr = p.get();
|
auto ptr = p.get();
|
||||||
return std::make_shared<Data>(detail::Get_Type_Info<T>::get(), chaiscript::detail::Any(std::move(p)), false, ptr, t_return_value);
|
return std::make_shared<Data>(
|
||||||
|
detail::Get_Type_Info<T>::get(),
|
||||||
|
chaiscript::detail::Any(std::move(p)),
|
||||||
|
false,
|
||||||
|
ptr,
|
||||||
|
t_return_value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<Data> get()
|
||||||
|
{
|
||||||
|
return std::make_shared<Data>(
|
||||||
|
Type_Info(),
|
||||||
|
chaiscript::detail::Any(),
|
||||||
|
false,
|
||||||
|
nullptr,
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Basic Boxed_Value constructor
|
/// Basic Boxed_Value constructor
|
||||||
template<typename T, typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
|
template<typename T,
|
||||||
|
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
|
||||||
explicit Boxed_Value(T &&t, bool t_return_value = false)
|
explicit Boxed_Value(T &&t, bool t_return_value = false)
|
||||||
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) {
|
: m_data(Object_Data::get(std::forward<T>(t), t_return_value))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unknown-type constructor
|
/// Unknown-type constructor
|
||||||
Boxed_Value() = default;
|
Boxed_Value()
|
||||||
|
: m_data(Object_Data::get())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(_MSC_VER) || _MSC_VER != 1800
|
||||||
Boxed_Value(Boxed_Value&&) = default;
|
Boxed_Value(Boxed_Value&&) = default;
|
||||||
Boxed_Value& operator=(Boxed_Value&&) = default;
|
Boxed_Value& operator=(Boxed_Value&&) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
Boxed_Value(const Boxed_Value&) = default;
|
Boxed_Value(const Boxed_Value&) = default;
|
||||||
Boxed_Value& operator=(const Boxed_Value&) = default;
|
Boxed_Value& operator=(const Boxed_Value&) = default;
|
||||||
|
|
||||||
void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); }
|
void swap(Boxed_Value &rhs)
|
||||||
|
{
|
||||||
|
std::swap(m_data, rhs.m_data);
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy the values stored in rhs.m_data to m_data.
|
/// Copy the values stored in rhs.m_data to m_data.
|
||||||
/// m_data pointers are not shared in this case
|
/// m_data pointers are not shared in this case
|
||||||
Boxed_Value assign(const Boxed_Value &rhs) noexcept {
|
Boxed_Value assign(const Boxed_Value &rhs)
|
||||||
|
{
|
||||||
(*m_data) = (*rhs.m_data);
|
(*m_data) = (*rhs.m_data);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type_Info &get_type_info() const noexcept { return m_data->m_type_info; }
|
const Type_Info &get_type_info() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_data->m_type_info;
|
||||||
|
}
|
||||||
|
|
||||||
/// return true if the object is uninitialized
|
/// return true if the object is uninitialized
|
||||||
bool is_undef() const noexcept { return m_data->m_type_info.is_undef(); }
|
bool is_undef() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
bool is_const() const noexcept { return m_data->m_type_info.is_const(); }
|
return m_data->m_type_info.is_undef();
|
||||||
|
|
||||||
/// Mark this Boxed_Value as const (used for script-level const declarations)
|
|
||||||
void make_const() noexcept {
|
|
||||||
m_data->m_type_info.make_const();
|
|
||||||
m_data->m_data_ptr = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_type(const Type_Info &ti) const noexcept { return m_data->m_type_info.bare_equal(ti); }
|
bool is_const() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
template<typename T>
|
return m_data->m_type_info.is_const();
|
||||||
auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept {
|
|
||||||
struct Sentinel {
|
|
||||||
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
|
|
||||||
: m_ptr(t_ptr)
|
|
||||||
, m_data(data) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Sentinel() {
|
bool is_type(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
|
||||||
// save new pointer data
|
{
|
||||||
const auto ptr_ = m_ptr.get().get();
|
return m_data->m_type_info.bare_equal(ti);
|
||||||
m_data.get().m_data_ptr = ptr_;
|
|
||||||
m_data.get().m_const_data_ptr = ptr_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sentinel &operator=(Sentinel &&s) = default;
|
bool is_null() const CHAISCRIPT_NOEXCEPT
|
||||||
Sentinel(Sentinel &&s) = default;
|
{
|
||||||
|
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
|
||||||
operator std::shared_ptr<T> &() const noexcept { return m_ptr.get(); }
|
|
||||||
|
|
||||||
Sentinel &operator=(const Sentinel &) = delete;
|
|
||||||
Sentinel(Sentinel &) = delete;
|
|
||||||
|
|
||||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
|
||||||
std::reference_wrapper<Data> m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
return Sentinel(ptr, *(m_data.get()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_null() const noexcept { return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr); }
|
const chaiscript::detail::Any & get() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_data->m_obj;
|
||||||
|
}
|
||||||
|
|
||||||
const chaiscript::detail::Any &get() const noexcept { return m_data->m_obj; }
|
bool is_ref() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_data->m_is_ref;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_ref() const noexcept { return m_data->m_is_ref; }
|
bool is_return_value() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_data->m_return_value;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_return_value() const noexcept { return m_data->m_return_value; }
|
void reset_return_value() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
m_data->m_return_value = false;
|
||||||
|
}
|
||||||
|
|
||||||
void reset_return_value() const noexcept { m_data->m_return_value = false; }
|
bool is_pointer() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return !is_ref();
|
||||||
|
}
|
||||||
|
|
||||||
bool is_pointer() const noexcept { return !is_ref(); }
|
void *get_ptr() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_data->m_data_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
void *get_ptr() const noexcept { return m_data->m_data_ptr; }
|
const void *get_const_ptr() const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_data->m_const_data_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
const void *get_const_ptr() const noexcept { return m_data->m_const_data_ptr; }
|
Boxed_Value get_attr(const std::string &t_name)
|
||||||
|
{
|
||||||
Boxed_Value get_attr(const std::string &t_name) {
|
if (!m_data->m_attrs)
|
||||||
if (!m_data->m_attrs) {
|
{
|
||||||
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
|
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &attr = (*m_data->m_attrs)[t_name];
|
auto &attr = (*m_data->m_attrs)[t_name];
|
||||||
@ -226,36 +288,41 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value ©_attrs(const Boxed_Value &t_obj) {
|
Boxed_Value ©_attrs(const Boxed_Value &t_obj)
|
||||||
if (t_obj.m_data->m_attrs) {
|
{
|
||||||
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
|
if (t_obj.m_data->m_attrs)
|
||||||
|
{
|
||||||
|
m_data->m_attrs = std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>>(new std::map<std::string, std::shared_ptr<Data>>(*t_obj.m_data->m_attrs));
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) {
|
Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
|
||||||
|
{
|
||||||
copy_attrs(t_obj);
|
copy_attrs(t_obj);
|
||||||
reset_return_value();
|
reset_return_value();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// \returns true if the two Boxed_Values share the same internal type
|
/// \returns true if the two Boxed_Values share the same internal type
|
||||||
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); }
|
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return l.get_type_info() == r.get_type_info();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// necessary to avoid hitting the templated && constructor of Boxed_Value
|
// necessary to avoid hitting the templated && constructor of Boxed_Value
|
||||||
struct Internal_Construction {
|
struct Internal_Construction{};
|
||||||
};
|
|
||||||
|
|
||||||
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
|
Boxed_Value(const std::shared_ptr<Data> &t_data, Internal_Construction)
|
||||||
: m_data(std::move(t_data)) {
|
: m_data(t_data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Data> m_data = Object_Data::get();
|
std::shared_ptr<Data> m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or
|
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
|
||||||
/// std::reference_type
|
|
||||||
/// a copy is not made.
|
/// a copy is not made.
|
||||||
/// @param t The value to box
|
/// @param t The value to box
|
||||||
///
|
///
|
||||||
@ -270,7 +337,8 @@ namespace chaiscript {
|
|||||||
///
|
///
|
||||||
/// @sa @ref adding_objects
|
/// @sa @ref adding_objects
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value var(T &&t) {
|
Boxed_Value var(T &&t)
|
||||||
|
{
|
||||||
return Boxed_Value(std::forward<T>(t));
|
return Boxed_Value(std::forward<T>(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +348,8 @@ namespace chaiscript {
|
|||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(const T &t) {
|
Boxed_Value const_var_impl(const T &t)
|
||||||
|
{
|
||||||
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
|
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +359,8 @@ namespace chaiscript {
|
|||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(T *t) {
|
Boxed_Value const_var_impl(T *t)
|
||||||
|
{
|
||||||
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
|
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,7 +370,8 @@ namespace chaiscript {
|
|||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(const std::shared_ptr<T> &t) {
|
Boxed_Value const_var_impl(const std::shared_ptr<T> &t)
|
||||||
|
{
|
||||||
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
|
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,10 +381,11 @@ namespace chaiscript {
|
|||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) {
|
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t)
|
||||||
|
{
|
||||||
return Boxed_Value( std::cref(t.get()) );
|
return Boxed_Value( std::cref(t.get()) );
|
||||||
}
|
}
|
||||||
} // namespace detail
|
}
|
||||||
|
|
||||||
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
|
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
|
||||||
/// the value is not copied. If it is an object type, it is copied.
|
/// the value is not copied. If it is an object type, it is copied.
|
||||||
@ -339,18 +411,15 @@ namespace chaiscript {
|
|||||||
/// \todo support C++11 strongly typed enums
|
/// \todo support C++11 strongly typed enums
|
||||||
/// \sa \ref adding_objects
|
/// \sa \ref adding_objects
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var(const T &t) {
|
Boxed_Value const_var(const T &t)
|
||||||
|
{
|
||||||
return detail::const_var_impl(t);
|
return detail::const_var_impl(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Boxed_Value void_var() {
|
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
||||||
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Boxed_Value const_var(bool b) {
|
inline Boxed_Value const_var(bool b) {
|
||||||
static const auto t = detail::const_var_impl(true);
|
static auto t = detail::const_var_impl(true);
|
||||||
static const auto f = detail::const_var_impl(false);
|
static auto f = detail::const_var_impl(false);
|
||||||
|
|
||||||
if (b) {
|
if (b) {
|
||||||
return t;
|
return t;
|
||||||
@ -358,7 +427,9 @@ namespace chaiscript {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||||
@ -12,8 +12,10 @@
|
|||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
namespace dispatch {
|
namespace dispatch {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<typename Class, typename ... Param>
|
template<typename Class, typename ... Param>
|
||||||
struct Constructor {
|
struct Constructor
|
||||||
|
{
|
||||||
template<typename ... Inner>
|
template<typename ... Inner>
|
||||||
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
|
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
|
||||||
return std::make_shared<Class>(std::forward<Inner>(inner)...);
|
return std::make_shared<Class>(std::forward<Inner>(inner)...);
|
||||||
@ -21,10 +23,9 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename ... Param>
|
template<typename Ret, typename Class, typename ... Param>
|
||||||
struct Const_Caller {
|
struct Const_Caller
|
||||||
explicit Const_Caller(Ret (Class::*t_func)(Param...) const)
|
{
|
||||||
: m_func(t_func) {
|
Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ... Inner>
|
template<typename ... Inner>
|
||||||
Ret operator()(const Class &o, Inner&& ... inner) const {
|
Ret operator()(const Class &o, Inner&& ... inner) const {
|
||||||
@ -35,10 +36,9 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename ... Param>
|
template<typename Ret, typename ... Param>
|
||||||
struct Fun_Caller {
|
struct Fun_Caller
|
||||||
explicit Fun_Caller(Ret (*t_func)(Param...))
|
{
|
||||||
: m_func(t_func) {
|
Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ... Inner>
|
template<typename ... Inner>
|
||||||
Ret operator()(Inner&& ... inner) const {
|
Ret operator()(Inner&& ... inner) const {
|
||||||
@ -49,10 +49,9 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename ... Param>
|
template<typename Ret, typename Class, typename ... Param>
|
||||||
struct Caller {
|
struct Caller
|
||||||
explicit Caller(Ret (Class::*t_func)(Param...))
|
{
|
||||||
: m_func(t_func) {
|
Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ... Inner>
|
template<typename ... Inner>
|
||||||
Ret operator()(Class &o, Inner&& ... inner) const {
|
Ret operator()(Class &o, Inner&& ... inner) const {
|
||||||
@ -63,37 +62,46 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Arity {
|
struct Arity
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename ... Params>
|
template<typename Ret, typename ... Params>
|
||||||
struct Arity<Ret(Params...)> {
|
struct Arity<Ret (Params...)>
|
||||||
|
{
|
||||||
static const size_t arity = sizeof...(Params);
|
static const size_t arity = sizeof...(Params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Function_Signature {
|
struct Function_Signature
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename ... Params>
|
template<typename Ret, typename ... Params>
|
||||||
struct Function_Signature<Ret(Params...)> {
|
struct Function_Signature<Ret (Params...)>
|
||||||
using Return_Type = Ret;
|
{
|
||||||
using Signature = Ret()(Params...);
|
typedef Ret Return_Type;
|
||||||
|
typedef Ret (Signature)(Params...);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename T, typename ... Params>
|
template<typename Ret, typename T, typename ... Params>
|
||||||
struct Function_Signature<Ret (T::*)(Params...) const> {
|
struct Function_Signature<Ret (T::*)(Params...) const>
|
||||||
using Return_Type = Ret;
|
{
|
||||||
using Signature = Ret()(Params...);
|
typedef Ret Return_Type;
|
||||||
|
typedef Ret (Signature)(Params...);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Callable_Traits {
|
struct Callable_Traits
|
||||||
using Signature = typename Function_Signature<decltype(&T::operator())>::Signature;
|
{
|
||||||
using Return_Type = typename Function_Signature<decltype(&T::operator())>::Return_Type;
|
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
|
||||||
|
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
|
||||||
};
|
};
|
||||||
} // namespace detail
|
}
|
||||||
} // namespace dispatch
|
}
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||||
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||||
|
|
||||||
@ -23,59 +20,59 @@ namespace chaiscript {
|
|||||||
} // namespace dispatch
|
} // namespace dispatch
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace dispatch {
|
{
|
||||||
|
namespace dispatch
|
||||||
|
{
|
||||||
struct option_explicit_set : std::runtime_error {
|
struct option_explicit_set : std::runtime_error {
|
||||||
explicit option_explicit_set(const std::string &t_param_name)
|
option_explicit_set(const std::string &t_param_name)
|
||||||
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist") {
|
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
option_explicit_set(const option_explicit_set &) = default;
|
virtual ~option_explicit_set() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
|
||||||
~option_explicit_set() noexcept override = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Dynamic_Object {
|
class Dynamic_Object
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
explicit Dynamic_Object(std::string t_type_name)
|
Dynamic_Object(std::string t_type_name)
|
||||||
: m_type_name(std::move(t_type_name))
|
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
|
||||||
, m_option_explicit(false) {
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Dynamic_Object() = default;
|
Dynamic_Object() : m_type_name(""), m_option_explicit(false)
|
||||||
|
{
|
||||||
/// Register that derived_name inherits from base_name
|
|
||||||
static void register_inheritance(const std::string &derived_name, const std::string &base_name) {
|
|
||||||
inheritance_map()[derived_name] = base_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if type_name is, or inherits from, base_name
|
bool is_explicit() const
|
||||||
static bool type_matches(const std::string &type_name, const std::string &base_name) noexcept {
|
{
|
||||||
if (type_name == base_name) {
|
return m_option_explicit;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const auto &m = inheritance_map();
|
|
||||||
auto it = m.find(type_name);
|
|
||||||
while (it != m.end()) {
|
|
||||||
if (it->second == base_name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
it = m.find(it->second);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_explicit() const noexcept { return m_option_explicit; }
|
void set_explicit(const bool t_explicit)
|
||||||
|
{
|
||||||
|
m_option_explicit = t_explicit;
|
||||||
|
}
|
||||||
|
|
||||||
void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
|
std::string get_type_name() const
|
||||||
|
{
|
||||||
|
return m_type_name;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string &get_type_name() const noexcept { return m_type_name; }
|
const Boxed_Value &operator[](const std::string &t_attr_name) const
|
||||||
|
{
|
||||||
|
return get_attr(t_attr_name);
|
||||||
|
}
|
||||||
|
|
||||||
const Boxed_Value &operator[](const std::string &t_attr_name) const { return get_attr(t_attr_name); }
|
Boxed_Value &operator[](const std::string &t_attr_name)
|
||||||
|
{
|
||||||
|
return get_attr(t_attr_name);
|
||||||
|
}
|
||||||
|
|
||||||
Boxed_Value &operator[](const std::string &t_attr_name) { return get_attr(t_attr_name); }
|
const Boxed_Value &get_attr(const std::string &t_attr_name) const
|
||||||
|
{
|
||||||
const Boxed_Value &get_attr(const std::string &t_attr_name) const {
|
|
||||||
auto a = m_attrs.find(t_attr_name);
|
auto a = m_attrs.find(t_attr_name);
|
||||||
|
|
||||||
if (a != m_attrs.end()) {
|
if (a != m_attrs.end()) {
|
||||||
@ -85,11 +82,13 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_attr(const std::string &t_attr_name) const { return m_attrs.find(t_attr_name) != m_attrs.end(); }
|
Boxed_Value &get_attr(const std::string &t_attr_name)
|
||||||
|
{
|
||||||
|
return m_attrs[t_attr_name];
|
||||||
|
}
|
||||||
|
|
||||||
Boxed_Value &get_attr(const std::string &t_attr_name) { return m_attrs[t_attr_name]; }
|
Boxed_Value &method_missing(const std::string &t_method_name)
|
||||||
|
{
|
||||||
Boxed_Value &method_missing(const std::string &t_method_name) {
|
|
||||||
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||||
throw option_explicit_set(t_method_name);
|
throw option_explicit_set(t_method_name);
|
||||||
}
|
}
|
||||||
@ -97,7 +96,8 @@ namespace chaiscript {
|
|||||||
return get_attr(t_method_name);
|
return get_attr(t_method_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Boxed_Value &method_missing(const std::string &t_method_name) const {
|
const Boxed_Value &method_missing(const std::string &t_method_name) const
|
||||||
|
{
|
||||||
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||||
throw option_explicit_set(t_method_name);
|
throw option_explicit_set(t_method_name);
|
||||||
}
|
}
|
||||||
@ -105,20 +105,20 @@ namespace chaiscript {
|
|||||||
return get_attr(t_method_name);
|
return get_attr(t_method_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; }
|
|
||||||
|
std::map<std::string, Boxed_Value> get_attrs() const
|
||||||
|
{
|
||||||
|
return m_attrs;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::map<std::string, std::string> &inheritance_map() {
|
std::string m_type_name;
|
||||||
static std::map<std::string, std::string> s_map;
|
bool m_option_explicit;
|
||||||
return s_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string m_type_name = "";
|
|
||||||
bool m_option_explicit = false;
|
|
||||||
|
|
||||||
std::map<std::string, Boxed_Value> m_attrs;
|
std::map<std::string, Boxed_Value> m_attrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dispatch
|
}
|
||||||
} // namespace chaiscript
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||||
@ -19,9 +19,9 @@
|
|||||||
#include "boxed_cast.hpp"
|
#include "boxed_cast.hpp"
|
||||||
#include "boxed_cast_helper.hpp"
|
#include "boxed_cast_helper.hpp"
|
||||||
#include "boxed_value.hpp"
|
#include "boxed_value.hpp"
|
||||||
#include "dynamic_object.hpp"
|
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
#include "dynamic_object.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
class Type_Conversions;
|
class Type_Conversions;
|
||||||
@ -30,110 +30,136 @@ namespace chaiscript {
|
|||||||
} // namespace dispatch
|
} // namespace dispatch
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace dispatch {
|
{
|
||||||
namespace detail {
|
namespace dispatch
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
/// A Proxy_Function implementation designed for calling a function
|
/// A Proxy_Function implementation designed for calling a function
|
||||||
/// that is automatically guarded based on the first param based on the
|
/// that is automatically guarded based on the first param based on the
|
||||||
/// param's type name
|
/// param's type name
|
||||||
class Dynamic_Object_Function final : public Proxy_Function_Base {
|
class Dynamic_Object_Function : public Proxy_Function_Base
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, bool t_is_attribute = false)
|
Dynamic_Object_Function(
|
||||||
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity())
|
std::string t_type_name,
|
||||||
, m_type_name(std::move(t_type_name))
|
const Proxy_Function &t_func,
|
||||||
, m_func(t_func)
|
bool t_is_attribute = false)
|
||||||
, m_doti(user_type<Dynamic_Object>())
|
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
|
||||||
, m_is_attribute(t_is_attribute) {
|
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()),
|
||||||
|
m_is_attribute(t_is_attribute)
|
||||||
|
{
|
||||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||||
}
|
}
|
||||||
|
|
||||||
Dynamic_Object_Function(std::string t_type_name, const Proxy_Function &t_func, const Type_Info &t_ti, bool t_is_attribute = false)
|
Dynamic_Object_Function(
|
||||||
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity())
|
std::string t_type_name,
|
||||||
, m_type_name(std::move(t_type_name))
|
const Proxy_Function &t_func,
|
||||||
, m_func(t_func)
|
const Type_Info &t_ti,
|
||||||
, m_ti(t_ti.is_undef() ? nullptr : new Type_Info(t_ti))
|
bool t_is_attribute = false)
|
||||||
, m_doti(user_type<Dynamic_Object>())
|
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
|
||||||
, m_is_attribute(t_is_attribute) {
|
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>()),
|
||||||
|
m_is_attribute(t_is_attribute)
|
||||||
|
{
|
||||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual ~Dynamic_Object_Function() {}
|
||||||
|
|
||||||
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
||||||
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
||||||
|
|
||||||
bool operator==(const Proxy_Function_Base &f) const noexcept override {
|
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||||
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f)) {
|
{
|
||||||
|
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
||||||
|
{
|
||||||
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
|
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_attribute_function() const noexcept override { return m_is_attribute; }
|
virtual bool is_attribute_function() const CHAISCRIPT_OVERRIDE { return m_is_attribute; }
|
||||||
|
|
||||||
const std::string &dynamic_object_type_name() const noexcept override { return m_type_name; }
|
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept override {
|
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
||||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) {
|
{
|
||||||
return m_func->call_match(vals, t_conversions);
|
return m_func->call_match(vals, t_conversions);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Const_Proxy_Function> get_contained_functions() const override { return {m_func}; }
|
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return {m_func};
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return m_func->annotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override {
|
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions)) {
|
{
|
||||||
|
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
||||||
|
{
|
||||||
return (*m_func)(params, t_conversions);
|
return (*m_func)(params, t_conversions);
|
||||||
} else {
|
} else {
|
||||||
throw exception::guard_error();
|
throw exception::guard_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept override {
|
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
|
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::vector<Type_Info> build_param_types(const std::vector<Type_Info> &t_inner_types, const Type_Info &t_objectti) {
|
static std::vector<Type_Info> build_param_types(
|
||||||
|
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
|
||||||
|
{
|
||||||
std::vector<Type_Info> types(t_inner_types);
|
std::vector<Type_Info> types(t_inner_types);
|
||||||
|
|
||||||
assert(types.size() > 1);
|
assert(types.size() > 1);
|
||||||
//assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
//assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
||||||
// When the object type_info is undefined (ChaiScript-defined class), use
|
types[1] = t_objectti;
|
||||||
// Dynamic_Object so that dispatch priority scoring works correctly.
|
|
||||||
types[1] = t_objectti.is_undef() ? user_type<Dynamic_Object>() : t_objectti;
|
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dynamic_object_typename_match(const Boxed_Value &bv,
|
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||||
const std::string &name,
|
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||||
const std::unique_ptr<Type_Info> &ti,
|
{
|
||||||
const Type_Conversions_State &t_conversions) const noexcept {
|
if (bv.get_type_info().bare_equal(m_doti))
|
||||||
if (bv.get_type_info().bare_equal(m_doti)) {
|
{
|
||||||
try {
|
try {
|
||||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
||||||
return name == "Dynamic_Object" || Dynamic_Object::type_matches(d.get_type_name(), name);
|
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||||
} catch (const std::bad_cast &) {
|
} catch (const std::bad_cast &) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ti) {
|
if (ti)
|
||||||
|
{
|
||||||
return bv.get_type_info().bare_equal(*ti);
|
return bv.get_type_info().bare_equal(*ti);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dynamic_object_typename_match(const chaiscript::Function_Params &bvs,
|
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||||
const std::string &name,
|
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||||
const std::unique_ptr<Type_Info> &ti,
|
{
|
||||||
const Type_Conversions_State &t_conversions) const noexcept {
|
if (bvs.size() > 0)
|
||||||
if (!bvs.empty()) {
|
{
|
||||||
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
|
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -144,64 +170,84 @@ namespace chaiscript {
|
|||||||
Proxy_Function m_func;
|
Proxy_Function m_func;
|
||||||
std::unique_ptr<Type_Info> m_ti;
|
std::unique_ptr<Type_Info> m_ti;
|
||||||
const Type_Info m_doti;
|
const Type_Info m_doti;
|
||||||
const bool m_is_attribute;
|
bool m_is_attribute;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Proxy_Function implementation designed for creating a new
|
* A Proxy_Function implementation designed for creating a new
|
||||||
* Dynamic_Object
|
* Dynamic_Object
|
||||||
* that is automatically guarded based on the first param based on the
|
* that is automatically guarded based on the first param based on the
|
||||||
* param's type name
|
* param's type name
|
||||||
*/
|
*/
|
||||||
class Dynamic_Object_Constructor final : public Proxy_Function_Base {
|
class Dynamic_Object_Constructor : public Proxy_Function_Base
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Object_Constructor(std::string t_type_name, const Proxy_Function &t_func)
|
Dynamic_Object_Constructor(
|
||||||
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1)
|
std::string t_type_name,
|
||||||
, m_type_name(std::move(t_type_name))
|
const Proxy_Function &t_func)
|
||||||
, m_func(t_func) {
|
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
|
||||||
|
m_type_name(std::move(t_type_name)), m_func(t_func)
|
||||||
|
{
|
||||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl) {
|
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
|
||||||
|
{
|
||||||
auto begin = tl.begin();
|
auto begin = tl.begin();
|
||||||
auto end = tl.end();
|
auto end = tl.end();
|
||||||
|
|
||||||
if (begin != end) {
|
if (begin != end)
|
||||||
|
{
|
||||||
++begin;
|
++begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::vector<Type_Info>(begin, end);
|
return std::vector<Type_Info>(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Proxy_Function_Base &f) const noexcept override {
|
virtual ~Dynamic_Object_Constructor() {}
|
||||||
|
|
||||||
|
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||||
return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
return dc && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const override {
|
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
|
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
|
||||||
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
|
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
|
||||||
|
|
||||||
return m_func->call_match(chaiscript::Function_Params{new_vals}, t_conversions);
|
return m_func->call_match(new_vals, t_conversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return m_func->annotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Boxed_Value do_call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) const override {
|
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
||||||
std::vector<Boxed_Value> new_params{bv};
|
std::vector<Boxed_Value> new_params{bv};
|
||||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||||
|
|
||||||
(*m_func)(chaiscript::Function_Params{new_params}, t_conversions);
|
(*m_func)(new_params, t_conversions);
|
||||||
|
|
||||||
return bv;
|
return bv;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string m_type_name;
|
std::string m_type_name;
|
||||||
const Proxy_Function m_func;
|
Proxy_Function m_func;
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace detail
|
}
|
||||||
} // namespace dispatch
|
}
|
||||||
} // namespace chaiscript
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||||
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||||
|
|
||||||
@ -16,28 +13,93 @@
|
|||||||
#include "boxed_cast.hpp"
|
#include "boxed_cast.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
namespace detail {
|
class Boxed_Value;
|
||||||
struct Exception_Handler_Base {
|
namespace exception {
|
||||||
|
class bad_boxed_cast;
|
||||||
|
} // namespace exception
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
/// \todo make this a variadic template
|
||||||
|
struct Exception_Handler_Base
|
||||||
|
{
|
||||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
|
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
|
||||||
|
|
||||||
virtual ~Exception_Handler_Base() = default;
|
virtual ~Exception_Handler_Base() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) {
|
void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
||||||
try {
|
{
|
||||||
T t = t_engine.boxed_cast<T>(bv);
|
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
|
||||||
throw t;
|
|
||||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... T>
|
template<typename T1>
|
||||||
struct Exception_Handler_Impl : Exception_Handler_Base {
|
struct Exception_Handler_Impl1 : Exception_Handler_Base
|
||||||
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type<T>(bv, t_engine), ...); }
|
{
|
||||||
|
virtual ~Exception_Handler_Impl1() {}
|
||||||
|
|
||||||
|
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
throw_type<T1>(bv, t_engine);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace detail
|
template<typename T1, typename T2>
|
||||||
|
struct Exception_Handler_Impl2 : Exception_Handler_Base
|
||||||
|
{
|
||||||
|
virtual ~Exception_Handler_Impl2() {}
|
||||||
|
|
||||||
|
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
throw_type<T1>(bv, t_engine);
|
||||||
|
throw_type<T2>(bv, t_engine);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2, typename T3>
|
||||||
|
struct Exception_Handler_Impl3 : Exception_Handler_Base
|
||||||
|
{
|
||||||
|
virtual ~Exception_Handler_Impl3() {}
|
||||||
|
|
||||||
|
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
throw_type<T1>(bv, t_engine);
|
||||||
|
throw_type<T2>(bv, t_engine);
|
||||||
|
throw_type<T3>(bv, t_engine);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename T1, typename T2, typename T3, typename T4>
|
||||||
|
struct Exception_Handler_Impl4 : Exception_Handler_Base
|
||||||
|
{
|
||||||
|
virtual ~Exception_Handler_Impl4() {}
|
||||||
|
|
||||||
|
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
throw_type<T1>(bv, t_engine);
|
||||||
|
throw_type<T2>(bv, t_engine);
|
||||||
|
throw_type<T3>(bv, t_engine);
|
||||||
|
throw_type<T4>(bv, t_engine);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||||
|
struct Exception_Handler_Impl5 : Exception_Handler_Base
|
||||||
|
{
|
||||||
|
virtual ~Exception_Handler_Impl5() {}
|
||||||
|
|
||||||
|
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
throw_type<T1>(bv, t_engine);
|
||||||
|
throw_type<T2>(bv, t_engine);
|
||||||
|
throw_type<T3>(bv, t_engine);
|
||||||
|
throw_type<T4>(bv, t_engine);
|
||||||
|
throw_type<T5>(bv, t_engine);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
|
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
|
||||||
///
|
///
|
||||||
@ -49,8 +111,7 @@ namespace chaiscript {
|
|||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
///
|
///
|
||||||
/// try {
|
/// try {
|
||||||
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const
|
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||||
/// std::exception &>());
|
|
||||||
/// } catch (const double e) {
|
/// } catch (const double e) {
|
||||||
/// } catch (int) {
|
/// } catch (int) {
|
||||||
/// } catch (float) {
|
/// } catch (float) {
|
||||||
@ -90,14 +151,49 @@ namespace chaiscript {
|
|||||||
///
|
///
|
||||||
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
|
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
|
||||||
/// \sa \ref exceptions
|
/// \sa \ref exceptions
|
||||||
using Exception_Handler = std::shared_ptr<detail::Exception_Handler_Base>;
|
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
|
||||||
|
|
||||||
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
|
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
|
||||||
/// \sa \ref exceptions
|
/// \sa \ref exceptions
|
||||||
template<typename... T>
|
template<typename T1>
|
||||||
Exception_Handler exception_specification() {
|
Exception_Handler exception_specification()
|
||||||
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
|
{
|
||||||
|
return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
|
||||||
}
|
}
|
||||||
} // namespace chaiscript
|
|
||||||
|
/// \brief creates a chaiscript::Exception_Handler which handles two types of exception unboxing
|
||||||
|
/// \sa \ref exceptions
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
Exception_Handler exception_specification()
|
||||||
|
{
|
||||||
|
return Exception_Handler(new detail::Exception_Handler_Impl2<T1, T2>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief creates a chaiscript::Exception_Handler which handles three types of exception unboxing
|
||||||
|
/// \sa \ref exceptions
|
||||||
|
template<typename T1, typename T2, typename T3>
|
||||||
|
Exception_Handler exception_specification()
|
||||||
|
{
|
||||||
|
return Exception_Handler(new detail::Exception_Handler_Impl3<T1, T2, T3>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief creates a chaiscript::Exception_Handler which handles four types of exception unboxing
|
||||||
|
/// \sa \ref exceptions
|
||||||
|
template<typename T1, typename T2, typename T3, typename T4>
|
||||||
|
Exception_Handler exception_specification()
|
||||||
|
{
|
||||||
|
return Exception_Handler(new detail::Exception_Handler_Impl4<T1, T2, T3, T4>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief creates a chaiscript::Exception_Handler which handles five types of exception unboxing
|
||||||
|
/// \sa \ref exceptions
|
||||||
|
template<typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||||
|
Exception_Handler exception_specification()
|
||||||
|
{
|
||||||
|
return Exception_Handler(new detail::Exception_Handler_Impl5<T1, T2, T3, T4, T5>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
|
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||||
#define CHAISCRIPT_FUNCTION_CALL_HPP_
|
#define CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||||
|
|
||||||
@ -17,25 +14,20 @@
|
|||||||
#include "boxed_cast.hpp"
|
#include "boxed_cast.hpp"
|
||||||
#include "function_call_detail.hpp"
|
#include "function_call_detail.hpp"
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
|
#include "callable_traits.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
class Boxed_Value;
|
class Boxed_Value;
|
||||||
class Type_Conversions_State;
|
class Type_Conversions;
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T>
|
template <typename T> struct Cast_Helper;
|
||||||
struct Cast_Helper;
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace dispatch {
|
{
|
||||||
namespace detail {
|
namespace dispatch
|
||||||
template<typename Ret, typename... Param>
|
{
|
||||||
constexpr auto arity(Ret (*)(Param...)) noexcept {
|
|
||||||
return sizeof...(Param);
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/// Build a function caller that knows how to dispatch on a set of functions
|
/// Build a function caller that knows how to dispatch on a set of functions
|
||||||
/// example:
|
/// example:
|
||||||
/// std::function<void (int)> f =
|
/// std::function<void (int)> f =
|
||||||
@ -43,9 +35,12 @@ namespace chaiscript {
|
|||||||
/// \returns A std::function object for dispatching
|
/// \returns A std::function object for dispatching
|
||||||
/// \param[in] funcs the set of functions to dispatch on.
|
/// \param[in] funcs the set of functions to dispatch on.
|
||||||
template<typename FunctionType>
|
template<typename FunctionType>
|
||||||
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
|
std::function<FunctionType>
|
||||||
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) {
|
functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
|
||||||
return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast<FunctionType *>(nullptr));
|
{
|
||||||
|
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
|
||||||
|
[](const Const_Proxy_Function &f) {
|
||||||
|
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!has_arity_match) {
|
if (!has_arity_match) {
|
||||||
@ -68,24 +63,33 @@ namespace chaiscript {
|
|||||||
/// \returns A std::function object for dispatching
|
/// \returns A std::function object for dispatching
|
||||||
/// \param[in] func A function to execute.
|
/// \param[in] func A function to execute.
|
||||||
template<typename FunctionType>
|
template<typename FunctionType>
|
||||||
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) {
|
std::function<FunctionType>
|
||||||
|
functor(Const_Proxy_Function func, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
|
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for automatically unboxing a Boxed_Value that contains a function object
|
/// Helper for automatically unboxing a Boxed_Value that contains a function object
|
||||||
/// and creating a typesafe C++ function caller from it.
|
/// and creating a typesafe C++ function caller from it.
|
||||||
template<typename FunctionType>
|
template<typename FunctionType>
|
||||||
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) {
|
std::function<FunctionType>
|
||||||
|
functor(const Boxed_Value &bv, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
|
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
|
||||||
}
|
}
|
||||||
} // namespace dispatch
|
}
|
||||||
|
|
||||||
namespace detail{
|
namespace detail{
|
||||||
/// Cast helper to handle automatic casting to const std::function &
|
/// Cast helper to handle automatic casting to const std::function &
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct Cast_Helper<const std::function<Signature> &> {
|
struct Cast_Helper<const std::function<Signature> &>
|
||||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
{
|
||||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
|
typedef std::function<Signature> Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
|
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||||
|
{
|
||||||
return dispatch::functor<Signature>(ob, t_conversions);
|
return dispatch::functor<Signature>(ob, t_conversions);
|
||||||
} else {
|
} else {
|
||||||
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
|
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
|
||||||
@ -95,9 +99,14 @@ namespace chaiscript {
|
|||||||
|
|
||||||
/// Cast helper to handle automatic casting to std::function
|
/// Cast helper to handle automatic casting to std::function
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct Cast_Helper<std::function<Signature>> {
|
struct Cast_Helper<std::function<Signature> >
|
||||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
{
|
||||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
|
typedef std::function<Signature> Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
|
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||||
|
{
|
||||||
return dispatch::functor<Signature>(ob, t_conversions);
|
return dispatch::functor<Signature>(ob, t_conversions);
|
||||||
} else {
|
} else {
|
||||||
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions);
|
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions);
|
||||||
@ -107,16 +116,22 @@ namespace chaiscript {
|
|||||||
|
|
||||||
/// Cast helper to handle automatic casting to const std::function
|
/// Cast helper to handle automatic casting to const std::function
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct Cast_Helper<const std::function<Signature>> {
|
struct Cast_Helper<const std::function<Signature> >
|
||||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
{
|
||||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
|
typedef std::function<Signature> Result_Type;
|
||||||
|
|
||||||
|
static Result_Type cast(const Boxed_Value &ob, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
|
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||||
|
{
|
||||||
return dispatch::functor<Signature>(ob, t_conversions);
|
return dispatch::functor<Signature>(ob, t_conversions);
|
||||||
} else {
|
} else {
|
||||||
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions);
|
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace detail
|
}
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||||
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||||
|
|
||||||
@ -19,74 +16,106 @@
|
|||||||
#include "boxed_cast.hpp"
|
#include "boxed_cast.hpp"
|
||||||
#include "boxed_number.hpp"
|
#include "boxed_number.hpp"
|
||||||
#include "boxed_value.hpp"
|
#include "boxed_value.hpp"
|
||||||
#include "proxy_functions.hpp"
|
|
||||||
#include "type_conversions.hpp"
|
#include "type_conversions.hpp"
|
||||||
|
#include "proxy_functions.hpp"
|
||||||
|
|
||||||
namespace chaiscript::dispatch::detail {
|
namespace chaiscript
|
||||||
/// used internally for unwrapping a function call's types
|
{
|
||||||
|
namespace dispatch
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
/// Internal helper class for handling the return
|
||||||
|
/// value of a build_function_caller
|
||||||
|
template<typename Ret, bool is_arithmetic>
|
||||||
|
struct Function_Caller_Ret
|
||||||
|
{
|
||||||
|
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
|
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions()), t_conversions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for arithmetic return types
|
||||||
|
*/
|
||||||
|
template<typename Ret>
|
||||||
|
struct Function_Caller_Ret<Ret, true>
|
||||||
|
{
|
||||||
|
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
|
return Boxed_Number(dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions())).get_as<Ret>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization for void return types
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
struct Function_Caller_Ret<void, false>
|
||||||
|
{
|
||||||
|
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions *t_conversions)
|
||||||
|
{
|
||||||
|
dispatch::dispatch(t_funcs, params, t_conversions?*t_conversions:Type_Conversions());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used internally for unwrapping a function call's types
|
||||||
|
*/
|
||||||
template<typename Ret, typename ... Param>
|
template<typename Ret, typename ... Param>
|
||||||
struct Build_Function_Caller_Helper {
|
struct Build_Function_Caller_Helper
|
||||||
|
{
|
||||||
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
|
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
|
||||||
: m_funcs(std::move(t_funcs))
|
: m_funcs(std::move(t_funcs)),
|
||||||
, m_conversions(t_conversions) {
|
m_conversions(t_conversions)
|
||||||
}
|
{
|
||||||
|
|
||||||
Ret call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_state) {
|
|
||||||
if constexpr (std::is_arithmetic_v<Ret> && !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ret>>, bool>) {
|
|
||||||
return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>();
|
|
||||||
} else if constexpr (std::is_same_v<void, Ret>) {
|
|
||||||
dispatch::dispatch(m_funcs, params, t_state);
|
|
||||||
} else {
|
|
||||||
return boxed_cast<Ret>(dispatch::dispatch(m_funcs, params, t_state), &t_state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ... P>
|
template<typename ... P>
|
||||||
Ret operator()(P &&...param) {
|
Ret operator()(P&& ... param)
|
||||||
std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...};
|
{
|
||||||
|
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||||
|
box<P>(std::forward<P>(param))...
|
||||||
|
}, m_conversions
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
if (m_conversions) {
|
|
||||||
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
|
|
||||||
return call(chaiscript::Function_Params{params}, state);
|
|
||||||
} else {
|
|
||||||
Type_Conversions conv;
|
|
||||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
|
||||||
return call(chaiscript::Function_Params{params}, state);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct is_shared_ptr : std::false_type {};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
|
|
||||||
|
|
||||||
template<typename P, typename Q>
|
template<typename P, typename Q>
|
||||||
static Boxed_Value box(Q &&q) {
|
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||||
using bare_p = std::remove_cv_t<std::remove_reference_t<P>>;
|
{
|
||||||
if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) {
|
|
||||||
return std::forward<Q>(q);
|
|
||||||
} else if constexpr (is_shared_ptr<bare_p>::value) {
|
|
||||||
// Pass shared_ptr arguments through by value rather than wrapping a
|
|
||||||
// reference. Boxed_Value's shared_ptr-aware overloads then record the
|
|
||||||
// bare type as the pointee, allowing dispatch to a C++ function that
|
|
||||||
// takes the same shared_ptr<T> on the other side.
|
|
||||||
return Boxed_Value(bare_p(std::forward<Q>(q)));
|
|
||||||
} else if constexpr (std::is_reference_v<P>) {
|
|
||||||
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
template<typename P, typename Q>
|
||||||
|
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||||
|
{
|
||||||
return Boxed_Value(std::forward<Q>(q));
|
return Boxed_Value(std::forward<Q>(q));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename P>
|
||||||
|
static Boxed_Value box(Boxed_Value bv)
|
||||||
|
{
|
||||||
|
return bv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<Const_Proxy_Function> m_funcs;
|
std::vector<Const_Proxy_Function> m_funcs;
|
||||||
const Type_Conversions *m_conversions;
|
const Type_Conversions *m_conversions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// \todo what happens if t_conversions is deleted out from under us?!
|
/// \todo what happens if t_conversions is deleted out from under us?!
|
||||||
template<typename Ret, typename ... Params>
|
template<typename Ret, typename ... Params>
|
||||||
std::function<Ret(Params...)>
|
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions *t_conversions)
|
||||||
build_function_caller_helper(Ret(Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
|
{
|
||||||
/*
|
/*
|
||||||
if (funcs.size() == 1)
|
if (funcs.size() == 1)
|
||||||
{
|
{
|
||||||
@ -103,8 +132,11 @@ namespace chaiscript::dispatch::detail {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return std::function<Ret(Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions ? t_conversions->get() : nullptr));
|
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace chaiscript::dispatch::detail
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
// This file is distributed under the BSD License.
|
|
||||||
// See "license.txt" for details.
|
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
|
||||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
|
||||||
// http://www.chaiscript.com
|
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_FUNCTION_PARAMS_HPP
|
|
||||||
#define CHAISCRIPT_FUNCTION_PARAMS_HPP
|
|
||||||
|
|
||||||
#include "boxed_value.hpp"
|
|
||||||
|
|
||||||
#include <span>
|
|
||||||
|
|
||||||
namespace chaiscript {
|
|
||||||
|
|
||||||
using Function_Params = std::span<const Boxed_Value>;
|
|
||||||
|
|
||||||
} // namespace chaiscript
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,149 +0,0 @@
|
|||||||
#ifndef CHAISCRIPT_FUNCTION_SIGNATURE_HPP
|
|
||||||
#define CHAISCRIPT_FUNCTION_SIGNATURE_HPP
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace chaiscript::dispatch::detail {
|
|
||||||
template<typename... Param>
|
|
||||||
struct Function_Params {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret, typename Params, bool IsNoExcept = false, bool IsMember = false, bool IsMemberObject = false, bool IsObject = false>
|
|
||||||
struct Function_Signature {
|
|
||||||
using Param_Types = Params;
|
|
||||||
using Return_Type = Ret;
|
|
||||||
constexpr static const bool is_object = IsObject;
|
|
||||||
constexpr static const bool is_member_object = IsMemberObject;
|
|
||||||
constexpr static const bool is_noexcept = IsNoExcept;
|
|
||||||
template<typename T>
|
|
||||||
constexpr Function_Signature(T &&) noexcept {
|
|
||||||
}
|
|
||||||
constexpr Function_Signature() noexcept = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Free functions
|
|
||||||
|
|
||||||
template<typename Ret, typename... Param>
|
|
||||||
Function_Signature(Ret (*f)(Param...)) -> Function_Signature<Ret, Function_Params<Param...>>;
|
|
||||||
|
|
||||||
template<typename Ret, typename... Param>
|
|
||||||
Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Param...>, true>;
|
|
||||||
|
|
||||||
// no reference specifier
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile noexcept)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile const)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...)) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) const) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) const noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
// & reference specifier
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile &) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile & noexcept)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile const &)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile const & noexcept)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) &) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) & noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) const &) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) const & noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
|
|
||||||
|
|
||||||
// && reference specifier
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile &&) -> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile && noexcept)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile const &&)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) volatile const && noexcept)
|
|
||||||
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) &&) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) && noexcept) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) const &&) -> Function_Signature<Ret, Function_Params<const Class &&, Param...>, false, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Param>
|
|
||||||
Function_Signature(Ret (Class::*f)(Param...) const && noexcept)
|
|
||||||
-> Function_Signature<Ret, Function_Params<const Class &&, Param...>, true, true>;
|
|
||||||
|
|
||||||
template<typename Ret, typename Class>
|
|
||||||
Function_Signature(Ret Class::*f) -> Function_Signature<Ret, Function_Params<Class &>, true, true, true>;
|
|
||||||
|
|
||||||
// primary template handles types that have no nested ::type member:
|
|
||||||
template<class, class = std::void_t<>>
|
|
||||||
struct has_call_operator : std::false_type {
|
|
||||||
};
|
|
||||||
|
|
||||||
// specialization recognizes types that do have a nested ::type member:
|
|
||||||
template<class T>
|
|
||||||
struct has_call_operator<T, std::void_t<decltype(&T::operator())>> : std::true_type {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Func>
|
|
||||||
auto function_signature(const Func &f) {
|
|
||||||
if constexpr (has_call_operator<Func>::value) {
|
|
||||||
return Function_Signature<typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Return_Type,
|
|
||||||
typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Param_Types,
|
|
||||||
decltype(Function_Signature{&std::decay_t<Func>::operator()})::is_noexcept,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true>{};
|
|
||||||
} else {
|
|
||||||
return Function_Signature{f};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace chaiscript::dispatch::detail
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
|
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||||
#define CHAISCRIPT_HANDLE_RETURN_HPP_
|
#define CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||||
|
|
||||||
@ -21,175 +18,261 @@ namespace chaiscript {
|
|||||||
class Boxed_Number;
|
class Boxed_Number;
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace dispatch {
|
{
|
||||||
template<class T, class U>
|
namespace dispatch
|
||||||
class Proxy_Function_Callable_Impl;
|
{
|
||||||
template<class T>
|
template<class T, class U> class Proxy_Function_Callable_Impl;
|
||||||
class Assignable_Proxy_Function_Impl;
|
template<class T> class Assignable_Proxy_Function_Impl;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail
|
||||||
/// Used internally for handling a return value from a Proxy_Function call
|
{
|
||||||
|
/**
|
||||||
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
|
*/
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return {
|
struct Handle_Return
|
||||||
template<typename T, typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>>
|
{
|
||||||
static Boxed_Value handle(T r) {
|
template<typename T,
|
||||||
|
typename = typename std::enable_if<std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||||
|
static Boxed_Value handle(T r)
|
||||||
|
{
|
||||||
return Boxed_Value(std::move(r), true);
|
return Boxed_Value(std::move(r), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>>
|
template<typename T,
|
||||||
static Boxed_Value handle(T &&r) {
|
typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||||
|
static Boxed_Value handle(T &&r)
|
||||||
|
{
|
||||||
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
|
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const std::function<Ret> &> {
|
struct Handle_Return<const std::function<Ret> &>
|
||||||
|
{
|
||||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||||
return Boxed_Value(
|
return Boxed_Value(
|
||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> {
|
struct Handle_Return<std::function<Ret>>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||||
|
return Boxed_Value(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const std::shared_ptr<std::function<Ret>>> {
|
struct Handle_Return<const std::shared_ptr<std::function<Ret>>>
|
||||||
|
{
|
||||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||||
return Boxed_Value(
|
return Boxed_Value(
|
||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f));
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
|
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||||
|
return Boxed_Value(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
|
struct Handle_Return<std::shared_ptr<std::function<Ret>>>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||||
|
return Boxed_Value(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<std::function<Ret> &> {
|
struct Handle_Return<std::function<Ret> &>
|
||||||
|
{
|
||||||
static Boxed_Value handle(std::function<Ret> &f) {
|
static Boxed_Value handle(std::function<Ret> &f) {
|
||||||
return Boxed_Value(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(
|
return Boxed_Value(
|
||||||
std::ref(f), std::shared_ptr<std::function<Ret>>()));
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f),
|
||||||
|
std::shared_ptr<std::function<Ret>>())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||||
return Boxed_Value(
|
return Boxed_Value(
|
||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<Ret *&> {
|
struct Handle_Return<Ret *>
|
||||||
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
|
{
|
||||||
};
|
static Boxed_Value handle(Ret *p)
|
||||||
|
{
|
||||||
template<typename Ret>
|
return Boxed_Value(p, true);
|
||||||
struct Handle_Return<const Ret *&> {
|
|
||||||
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
|
||||||
struct Handle_Return<Ret *> {
|
|
||||||
static Boxed_Value handle(Ret *p) { return Boxed_Value(p, true); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
|
||||||
struct Handle_Return<const Ret *> {
|
|
||||||
static Boxed_Value handle(const Ret *p) { return Boxed_Value(p, true); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
|
||||||
struct Handle_Return<std::shared_ptr<Ret> &> {
|
|
||||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r) { return Boxed_Value(r, true); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
|
||||||
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
|
||||||
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
|
||||||
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &> {
|
|
||||||
static Boxed_Value handle(std::unique_ptr<Ret> &&r) { return Boxed_Value(std::move(r), true); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret, bool Ptr>
|
|
||||||
struct Handle_Return_Ref {
|
|
||||||
template<typename T>
|
|
||||||
static Boxed_Value handle(T &&r) {
|
|
||||||
return Boxed_Value(std::cref(r), false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return_Ref<Ret, true> {
|
struct Handle_Return<const Ret *>
|
||||||
template<typename T>
|
{
|
||||||
static Boxed_Value handle(T &&r) {
|
static Boxed_Value handle(const Ret *p)
|
||||||
return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
|
{
|
||||||
|
return Boxed_Value(p, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
|
struct Handle_Return<std::shared_ptr<Ret> &>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||||
|
{
|
||||||
|
return Boxed_Value(r, true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const Ret> {
|
struct Handle_Return<std::shared_ptr<Ret> >
|
||||||
static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); }
|
{
|
||||||
|
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||||
|
{
|
||||||
|
return Boxed_Value(r, true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<Ret &> {
|
struct Handle_Return<const std::shared_ptr<Ret> &>
|
||||||
static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); }
|
{
|
||||||
|
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||||
|
{
|
||||||
|
return Boxed_Value(r, true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<typename Ret>
|
||||||
struct Handle_Return<Boxed_Value> {
|
struct Handle_Return<const Ret &>
|
||||||
static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; }
|
{
|
||||||
|
static Boxed_Value handle(const Ret &r)
|
||||||
|
{
|
||||||
|
return Boxed_Value(std::cref(r), true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
|
||||||
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
/**
|
||||||
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
};
|
*/
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return<Ret &>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(Ret &r)
|
||||||
|
{
|
||||||
|
return Boxed_Value(std::ref(r));
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
static Boxed_Value handle(const Ret &r)
|
||||||
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> {
|
{
|
||||||
|
return Boxed_Value(std::cref(r));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used internally for handling a return value from a Proxy_Function call
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
*/
|
*/
|
||||||
template<>
|
template<>
|
||||||
struct Handle_Return<Boxed_Number> {
|
struct Handle_Return<Boxed_Value>
|
||||||
static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; }
|
{
|
||||||
};
|
static Boxed_Value handle(const Boxed_Value &r)
|
||||||
|
{
|
||||||
template<>
|
return r;
|
||||||
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> {
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used internally for handling a return value from a Proxy_Function call
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
*/
|
*/
|
||||||
template<>
|
template<>
|
||||||
struct Handle_Return<void> {
|
struct Handle_Return<const Boxed_Value>
|
||||||
static Boxed_Value handle() { return void_var(); }
|
{
|
||||||
|
static Boxed_Value handle(const Boxed_Value &r)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace detail
|
|
||||||
} // namespace dispatch
|
/**
|
||||||
} // namespace chaiscript
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<Boxed_Value &>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const Boxed_Value &r)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<const Boxed_Value &>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const Boxed_Value &r)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<Boxed_Number>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const Boxed_Number &r)
|
||||||
|
{
|
||||||
|
return r.bv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<const Boxed_Number>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle(const Boxed_Number &r)
|
||||||
|
{
|
||||||
|
return r.bv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally for handling a return value from a Proxy_Function call
|
||||||
|
*/
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<void>
|
||||||
|
{
|
||||||
|
static Boxed_Value handle()
|
||||||
|
{
|
||||||
|
return Boxed_Value(Boxed_Value::Void_Type());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,184 +1,465 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_OPERATORS_HPP_
|
#ifndef CHAISCRIPT_OPERATORS_HPP_
|
||||||
#define CHAISCRIPT_OPERATORS_HPP_
|
#define CHAISCRIPT_OPERATORS_HPP_
|
||||||
|
|
||||||
#include "../chaiscript_defines.hpp"
|
#include "../chaiscript_defines.hpp"
|
||||||
#include "../dispatchkit/dispatchkit.hpp"
|
|
||||||
#include "register_function.hpp"
|
#include "register_function.hpp"
|
||||||
|
|
||||||
namespace chaiscript::bootstrap::operators {
|
namespace chaiscript
|
||||||
template<typename T, typename ModuleType>
|
{
|
||||||
void assign(ModuleType &m) {
|
namespace bootstrap
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "=");
|
{
|
||||||
|
namespace operators
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
/// \todo make this return a decltype once we drop gcc 4.6
|
||||||
|
template<typename L, typename R>
|
||||||
|
auto assign(L l, R r) -> L&
|
||||||
|
{
|
||||||
|
return (l = r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_bitwise_and(ModuleType &m) {
|
auto assign_bitwise_and(L l, R r) -> decltype((l &= r))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&=");
|
{
|
||||||
|
return (l &= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_xor(ModuleType &m) {
|
auto assign_xor(L l, R r) -> decltype((l^=r))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^=");
|
{
|
||||||
|
return (l ^= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_bitwise_or(ModuleType &m) {
|
auto assign_bitwise_or(L l, R r) -> decltype((l |= r))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|=");
|
{
|
||||||
|
return (l |= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_difference(ModuleType &m) {
|
auto assign_difference(L l, R r) -> decltype(( l -= r))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-=");
|
{
|
||||||
|
return (l -= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_left_shift(ModuleType &m) {
|
auto assign_left_shift(L l, R r) -> decltype(( l <<= r))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<=");
|
{
|
||||||
|
return (l <<= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_product(ModuleType &m) {
|
auto assign_product(L l, R r) -> decltype(( l *= r ))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*=");
|
{
|
||||||
|
return (l *= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_quotient(ModuleType &m) {
|
auto assign_quotient(L l, R r) -> decltype(( l /= r ))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/=");
|
{
|
||||||
|
return (l /= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_remainder(ModuleType &m) {
|
auto assign_remainder(L l, R r) -> decltype(( l %= r ))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%=");
|
{
|
||||||
|
return (l %= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void assign_right_shift(ModuleType &m) {
|
auto assign_right_shift(L l, R r) -> decltype(( l >>= r))
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>=");
|
{
|
||||||
|
return (l >>= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
/// \todo make this return a decltype once we drop gcc 4.6
|
||||||
void assign_sum(ModuleType &m) {
|
template<typename L, typename R>
|
||||||
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+=");
|
auto assign_sum(L l, R r) -> L&
|
||||||
|
{
|
||||||
|
return (l += r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L>
|
||||||
void prefix_decrement(ModuleType &m) {
|
auto prefix_decrement(L l) -> decltype(( --l ))
|
||||||
m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--");
|
{
|
||||||
|
return (--l);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L>
|
||||||
void prefix_increment(ModuleType &m) {
|
auto prefix_increment(L l) -> decltype(( ++l ))
|
||||||
m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++");
|
{
|
||||||
|
return (++l);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void equal(ModuleType &m) {
|
auto equal(L l, R r) -> decltype(( l == r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "==");
|
{
|
||||||
|
return (l == r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void greater_than(ModuleType &m) {
|
auto greater_than(L l, R r) -> decltype(( l > r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">");
|
{
|
||||||
|
return (l > r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void greater_than_equal(ModuleType &m) {
|
auto greater_than_equal(L l, R r) -> decltype(( l >= r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">=");
|
{
|
||||||
|
return (l >= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void less_than(ModuleType &m) {
|
auto less_than(L l, R r) -> decltype(( l < r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<");
|
{
|
||||||
|
return (l < r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void less_than_equal(ModuleType &m) {
|
auto less_than_equal(L l, R r) -> decltype(( l <= r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<=");
|
{
|
||||||
|
return (l <= r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L>
|
||||||
void logical_compliment(ModuleType &m) {
|
auto logical_compliment(L l) -> decltype(( !l ))
|
||||||
m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!");
|
{
|
||||||
|
return (!l);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void not_equal(ModuleType &m) {
|
auto not_equal(L l, R r) -> decltype(( l != r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!=");
|
{
|
||||||
|
return (l != r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void addition(ModuleType &m) {
|
auto addition(L l, R r) -> decltype(( l + r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+");
|
{
|
||||||
|
return (l + r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L>
|
||||||
void unary_plus(ModuleType &m) {
|
auto unary_plus(L l) -> decltype(( +l ))
|
||||||
m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+");
|
{
|
||||||
|
return (+l);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void subtraction(ModuleType &m) {
|
auto subtraction(L l, R r) -> decltype(( l - r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-");
|
{
|
||||||
|
return (l - r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L>
|
||||||
void unary_minus(ModuleType &m) {
|
auto unary_minus(L l) -> decltype(( -l ))
|
||||||
m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-");
|
{
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4146)
|
||||||
|
return (-l);
|
||||||
|
#pragma warning(pop)
|
||||||
|
#else
|
||||||
|
return (-l);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void bitwise_and(ModuleType &m) {
|
auto bitwise_and(L l, R r) -> decltype(( l & r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&");
|
{
|
||||||
|
return (l & r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L>
|
||||||
void bitwise_compliment(ModuleType &m) {
|
auto bitwise_compliment(L l) -> decltype(( ~l ))
|
||||||
m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~");
|
{
|
||||||
|
return (~l);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void bitwise_xor(ModuleType &m) {
|
auto bitwise_xor(L l, R r) -> decltype(( l ^ r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^");
|
{
|
||||||
|
return (l ^ r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void bitwise_or(ModuleType &m) {
|
auto bitwise_or(L l, R r) -> decltype(( l | r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|");
|
{
|
||||||
|
return (l | r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void division(ModuleType &m) {
|
auto division(L l, R r) -> decltype(( l / r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/");
|
{
|
||||||
|
return (l / r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void left_shift(ModuleType &m) {
|
auto left_shift(L l, R r) -> decltype(( l << r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<");
|
{
|
||||||
|
return l << r;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void multiplication(ModuleType &m) {
|
auto multiplication(L l, R r) -> decltype(( l * r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*");
|
{
|
||||||
|
return l * r;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void remainder(ModuleType &m) {
|
auto remainder(L l, R r) -> decltype(( l % r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%");
|
{
|
||||||
|
return (l % r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ModuleType>
|
template<typename L, typename R>
|
||||||
void right_shift(ModuleType &m) {
|
auto right_shift(L l, R r) -> decltype(( l >> r ))
|
||||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>");
|
{
|
||||||
|
return (l >> r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign<T &, const T&>), "=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_bitwise_and(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_bitwise_and<T &, const T&>), "&=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_xor(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_xor<T &, const T&>), "^=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_bitwise_or(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_bitwise_or<T &, const T&>), "|=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_difference(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_difference<T &, const T&>), "-=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_left_shift(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_left_shift<T &, const T&>), "<<=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_product(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_product<T &, const T&>), "*=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_quotient(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_quotient<T &, const T&>), "/=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_remainder(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_remainder<T &, const T&>), "%=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_right_shift(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_right_shift<T &, const T&>), ">>=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr assign_sum(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::assign_sum<T &, const T&>), "+=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr prefix_decrement(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::prefix_decrement<T &>), "--");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr prefix_increment(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::prefix_increment<T &>), "++");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr equal(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::equal<const T&, const T&>), "==");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr greater_than(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::greater_than<const T&, const T&>), ">");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr greater_than_equal(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::greater_than_equal<const T&, const T&>), ">=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr less_than(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::less_than<const T&, const T&>), "<");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr less_than_equal(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::less_than_equal<const T&, const T&>), "<=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr logical_compliment(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::logical_compliment<const T &>), "!");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr not_equal(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::not_equal<const T &, const T &>), "!=");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr addition(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::addition<const T &, const T &>), "+");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr unary_plus(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::unary_plus<const T &>), "+");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr subtraction(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::subtraction<const T &, const T &>), "-");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr unary_minus(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::unary_minus<const T &>), "-");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr bitwise_and(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::bitwise_and<const T &, const T &>), "&");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr bitwise_compliment(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::bitwise_compliment<const T &>), "~");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr bitwise_xor(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::bitwise_xor<const T &, const T &>), "^");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr bitwise_or(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::bitwise_or<const T &, const T &>), "|");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr division(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::division<const T &, const T &>), "/");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr left_shift(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::left_shift<const T &, const T &>), "<<");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr multiplication(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::multiplication<const T &, const T &>), "*");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr remainder(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::remainder<const T &, const T &>), "%");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ModulePtr right_shift(ModulePtr m = std::make_shared<Module>())
|
||||||
|
{
|
||||||
|
m->add(chaiscript::fun(&detail::right_shift<const T &, const T &>), ">>");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace chaiscript::bootstrap::operators
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,37 +1,34 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||||
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||||
|
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
|
|
||||||
namespace chaiscript::dispatch::detail {
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
namespace dispatch
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
template<typename Class, typename ... Params >
|
template<typename Class, typename ... Params >
|
||||||
Proxy_Function build_constructor_(Class (*)(Params...)) {
|
Proxy_Function build_constructor_(Class (*)(Params...))
|
||||||
if constexpr (!std::is_copy_constructible_v<Class>) {
|
{
|
||||||
auto call = [](auto &&...param) { return std::make_shared<Class>(std::forward<decltype(param)>(param)...); };
|
auto call = dispatch::detail::Constructor<Class, Params...>();
|
||||||
|
|
||||||
return Proxy_Function(
|
return Proxy_Function(
|
||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base,
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
|
||||||
dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class>(Params...), decltype(call)>>(call));
|
}
|
||||||
} else if constexpr (true) {
|
|
||||||
auto call = [](auto &&...param) { return Class(std::forward<decltype(param)>(param)...); };
|
|
||||||
|
|
||||||
return Proxy_Function(
|
|
||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class(Params...), decltype(call)>>(
|
|
||||||
call));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace chaiscript::dispatch::detail
|
|
||||||
|
|
||||||
namespace chaiscript {
|
|
||||||
/// \brief Generates a constructor function for use with ChaiScript
|
/// \brief Generates a constructor function for use with ChaiScript
|
||||||
///
|
///
|
||||||
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
|
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
|
||||||
@ -44,10 +41,13 @@ namespace chaiscript {
|
|||||||
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
|
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Proxy_Function constructor() {
|
Proxy_Function constructor()
|
||||||
|
{
|
||||||
T *f = nullptr;
|
T *f = nullptr;
|
||||||
return (dispatch::detail::build_constructor_(f));
|
return (dispatch::detail::build_constructor_(f));
|
||||||
}
|
}
|
||||||
} // namespace chaiscript
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,12 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||||
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -18,104 +14,262 @@
|
|||||||
#include "../chaiscript_defines.hpp"
|
#include "../chaiscript_defines.hpp"
|
||||||
#include "boxed_cast.hpp"
|
#include "boxed_cast.hpp"
|
||||||
#include "boxed_value.hpp"
|
#include "boxed_value.hpp"
|
||||||
#include "function_params.hpp"
|
|
||||||
#include "handle_return.hpp"
|
#include "handle_return.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
#include "callable_traits.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
class Type_Conversions_State;
|
class Type_Conversions;
|
||||||
namespace exception {
|
namespace exception {
|
||||||
class bad_boxed_cast;
|
class bad_boxed_cast;
|
||||||
} // namespace exception
|
} // namespace exception
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace exception {
|
{
|
||||||
|
namespace exception
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Exception thrown when there is a mismatch in number of
|
* Exception thrown when there is a mismatch in number of
|
||||||
* parameters during Proxy_Function execution
|
* parameters during Proxy_Function execution
|
||||||
*/
|
*/
|
||||||
struct arity_error : std::range_error {
|
struct arity_error : std::range_error
|
||||||
|
{
|
||||||
arity_error(int t_got, int t_expected)
|
arity_error(int t_got, int t_expected)
|
||||||
: std::range_error("Function dispatch arity mismatch")
|
: std::range_error("Function dispatch arity mismatch"),
|
||||||
, got(t_got)
|
got(t_got), expected(t_expected)
|
||||||
, expected(t_expected) {
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
arity_error(const arity_error &) = default;
|
arity_error(const arity_error &) = default;
|
||||||
|
|
||||||
~arity_error() noexcept override = default;
|
virtual ~arity_error() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
|
||||||
int got;
|
int got;
|
||||||
int expected;
|
int expected;
|
||||||
};
|
};
|
||||||
} // namespace exception
|
}
|
||||||
|
|
||||||
namespace dispatch {
|
namespace dispatch
|
||||||
namespace detail {
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Used by Proxy_Function_Impl to return a list of all param types
|
* Used by Proxy_Function_Impl to return a list of all param types
|
||||||
* it contains.
|
* it contains.
|
||||||
*/
|
*/
|
||||||
template<typename Ret, typename ... Params>
|
template<typename Ret, typename ... Params>
|
||||||
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) {
|
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
|
||||||
|
{
|
||||||
/// \note somehow this is responsible for a large part of the code generation
|
/// \note somehow this is responsible for a large part of the code generation
|
||||||
return { user_type<Ret>(), user_type<Params>()... };
|
return { user_type<Ret>(), user_type<Params>()... };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_GCC_4_6
|
||||||
|
/// \todo REMOVE THIS WHEN WE DROP G++4.6
|
||||||
|
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
template<typename ... Rest>
|
||||||
|
struct Try_Cast;
|
||||||
|
|
||||||
|
template<typename Param, typename ... Rest>
|
||||||
|
struct Try_Cast<Param, Rest...>
|
||||||
|
{
|
||||||
|
static void do_try(const std::vector<Boxed_Value> ¶ms, size_t generation, const Type_Conversions &t_conversions)
|
||||||
|
{
|
||||||
|
boxed_cast<Param>(params[generation], &t_conversions);
|
||||||
|
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 0th case
|
||||||
|
template<>
|
||||||
|
struct Try_Cast<>
|
||||||
|
{
|
||||||
|
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||||
* Proxy_Function_Impl object. This function is primarily used to prevent
|
* Proxy_Function_Impl object. This function is primarily used to prevent
|
||||||
* registration of two functions with the exact same signatures
|
* registration of two functions with the exact same signatures
|
||||||
*/
|
*/
|
||||||
template<typename Ret, typename ... Params>
|
template<typename Ret, typename ... Params>
|
||||||
bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) noexcept {
|
bool compare_types_cast(Ret (*)(Params...),
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
std::vector<Boxed_Value>::size_type i = 0;
|
Try_Cast<Params...>::do_try(params, 0, t_conversions);
|
||||||
(boxed_cast<Params>(params[i++], &t_conversions), ...);
|
} catch (const exception::bad_boxed_cast &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ret, int count, typename ... Params>
|
||||||
|
struct Call_Func
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename Callable, typename ... InnerParams>
|
||||||
|
static Ret do_call(const Callable &f,
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
|
||||||
|
{
|
||||||
|
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, typename ... Params>
|
||||||
|
struct Call_Func<Ret, 0, Params...>
|
||||||
|
{
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
|
||||||
|
#endif
|
||||||
|
template<typename Callable, typename ... InnerParams>
|
||||||
|
static Ret do_call(const Callable &f,
|
||||||
|
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
|
||||||
|
{
|
||||||
|
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
|
||||||
|
}
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||||
|
* The function attempts to unbox each parameter to the expected type.
|
||||||
|
* if any unboxing fails the execution of the function fails and
|
||||||
|
* the bad_boxed_cast is passed up to the caller.
|
||||||
|
*/
|
||||||
|
template<typename Callable, typename Ret, typename ... Params>
|
||||||
|
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, const Callable &f,
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
|
{
|
||||||
|
if (params.size() == sizeof...(Params))
|
||||||
|
{
|
||||||
|
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params, t_conversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template<size_t ... I>
|
||||||
|
struct Indexes
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t S, size_t ... I>
|
||||||
|
struct Make_Indexes
|
||||||
|
{
|
||||||
|
typedef typename Make_Indexes<S-1, I..., sizeof...(I)>::indexes indexes;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t ... I>
|
||||||
|
struct Make_Indexes<0, I...>
|
||||||
|
{
|
||||||
|
typedef Indexes<I...> indexes;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||||
|
* Proxy_Function_Impl object. This function is primarily used to prevent
|
||||||
|
* registration of two functions with the exact same signatures
|
||||||
|
*/
|
||||||
|
template<typename Ret, typename ... Params, size_t ... I>
|
||||||
|
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
(void)params; (void)t_conversions;
|
||||||
|
(void)std::initializer_list<int>{(boxed_cast<Params>(params[I], &t_conversions), 0)...};
|
||||||
return true;
|
return true;
|
||||||
} catch (const exception::bad_boxed_cast &) {
|
} catch (const exception::bad_boxed_cast &) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Ret, typename ... Params>
|
||||||
|
bool compare_types_cast(Ret (*f)(Params...),
|
||||||
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
|
{
|
||||||
|
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
|
||||||
|
return compare_types_cast(indexes(), f, params, t_conversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
|
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
|
||||||
Ret call_func_impl(Ret (*)(Params...),
|
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &, Indexes<I...>, const Callable &f,
|
||||||
std::index_sequence<I...>,
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
const Callable &f,
|
{
|
||||||
[[maybe_unused]] const chaiscript::Function_Params ¶ms,
|
(void)params; (void)t_conversions;
|
||||||
[[maybe_unused]] const Type_Conversions_State &t_conversions) {
|
|
||||||
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
|
||||||
/// The function attempts to unbox each parameter to the expected type.
|
/**
|
||||||
/// if any unboxing fails the execution of the function fails and
|
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||||
/// the bad_boxed_cast is passed up to the caller.
|
* The function attempts to unbox each parameter to the expected type.
|
||||||
|
* if any unboxing fails the execution of the function fails and
|
||||||
|
* the bad_boxed_cast is passed up to the caller.
|
||||||
|
*/
|
||||||
template<typename Callable, typename Ret, typename ... Params>
|
template<typename Callable, typename Ret, typename ... Params>
|
||||||
Boxed_Value
|
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||||
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) {
|
const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
return Handle_Return<Ret>::handle(call_func_impl(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
{
|
||||||
|
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
|
||||||
|
return call_func(sig, indexes(), f, params, t_conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSVC has a broken warning for unreachable code in this block
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable : 4702)
|
|
||||||
#endif
|
#endif
|
||||||
template<typename Callable, typename... Params>
|
|
||||||
Boxed_Value
|
}
|
||||||
call_func(void (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) {
|
}
|
||||||
call_func_impl(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
namespace dispatch
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template<typename Ret>
|
||||||
|
struct Do_Call
|
||||||
|
{
|
||||||
|
template<typename Signature, typename Callable>
|
||||||
|
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
|
{
|
||||||
|
return Handle_Return<Ret>::handle(call_func(Function_Signature<Signature>(), fun, params, t_conversions));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Do_Call<void>
|
||||||
|
{
|
||||||
|
template<typename Signature, typename Callable>
|
||||||
|
static Boxed_Value go(const Callable &fun, const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions)
|
||||||
|
{
|
||||||
|
call_func(Function_Signature<Signature>(), fun, params, t_conversions);
|
||||||
return Handle_Return<void>::handle();
|
return Handle_Return<void>::handle();
|
||||||
}
|
}
|
||||||
#ifdef _MSC_VER
|
};
|
||||||
#pragma warning(pop)
|
}
|
||||||
#endif
|
}
|
||||||
|
}
|
||||||
} // namespace detail
|
|
||||||
} // namespace dispatch
|
|
||||||
|
|
||||||
} // namespace chaiscript
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,61 +1,19 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||||
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "bind_first.hpp"
|
#include "bind_first.hpp"
|
||||||
#include "function_signature.hpp"
|
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace dispatch::detail {
|
{
|
||||||
template<typename Obj, typename Param1, typename... Rest>
|
|
||||||
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj) {
|
|
||||||
return static_cast<Param1>(std::forward<Obj>(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename... Param>
|
|
||||||
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) {
|
|
||||||
if constexpr (Is_MemberObject) {
|
|
||||||
// we now that the Param pack will have only one element, so we are safe expanding it here
|
|
||||||
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(
|
|
||||||
std::forward<Func>(func)));
|
|
||||||
} else if constexpr (Is_Member) {
|
|
||||||
// TODO some kind of bug is preventing forwarding of this noexcept for the lambda
|
|
||||||
auto call = [func = std::forward<Func>(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) {
|
|
||||||
return ((get_first_param(Function_Params<Param...>{}, obj).*func)(std::forward<decltype(param)>(param)...));
|
|
||||||
};
|
|
||||||
return Proxy_Function(
|
|
||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), decltype(call)>>(
|
|
||||||
std::move(call)));
|
|
||||||
} else {
|
|
||||||
return Proxy_Function(
|
|
||||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), std::decay_t<Func>>>(
|
|
||||||
std::forward<Func>(func)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this version peels off the function object itself from the function signature, when used
|
|
||||||
// on a callable object
|
|
||||||
template<typename Func, typename Ret, typename Object, typename... Param, bool Is_Noexcept>
|
|
||||||
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) {
|
|
||||||
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Func, typename Ret, typename... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
|
|
||||||
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) {
|
|
||||||
return make_callable_impl(std::forward<Func>(func), fs);
|
|
||||||
}
|
|
||||||
} // namespace dispatch::detail
|
|
||||||
|
|
||||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
||||||
/// \param[in] t Function / member to expose
|
/// \param[in] t Function / member to expose
|
||||||
@ -78,47 +36,53 @@ namespace chaiscript {
|
|||||||
///
|
///
|
||||||
/// \sa \ref adding_functions
|
/// \sa \ref adding_functions
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Proxy_Function fun(T &&t) {
|
Proxy_Function fun(const T &t)
|
||||||
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
|
{
|
||||||
|
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
|
||||||
|
|
||||||
|
return Proxy_Function(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Creates a new Proxy_Function object from an overloaded free function, with the
|
template<typename Ret, typename ... Param>
|
||||||
/// signature specified explicitly to disambiguate the overload.
|
Proxy_Function fun(Ret (*func)(Param...))
|
||||||
///
|
{
|
||||||
/// \b Example:
|
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
|
||||||
/// \code
|
|
||||||
/// int overloaded(int);
|
return Proxy_Function(
|
||||||
/// double overloaded(double);
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
|
||||||
///
|
|
||||||
/// chai.add(chaiscript::fun<int(int)>(&overloaded), "overloaded");
|
|
||||||
/// chai.add(chaiscript::fun<double(double)>(&overloaded), "overloaded");
|
|
||||||
/// \endcode
|
|
||||||
template<typename Sig, std::enable_if_t<std::is_function_v<Sig>, int> = 0>
|
|
||||||
Proxy_Function fun(std::type_identity_t<Sig> *f) {
|
|
||||||
return dispatch::detail::make_callable(f, dispatch::detail::function_signature(f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Creates a new Proxy_Function object from an overloaded member function, with the
|
template<typename Ret, typename Class, typename ... Param>
|
||||||
/// signature specified explicitly to disambiguate the overload.
|
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
|
||||||
///
|
{
|
||||||
/// \b Example:
|
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
|
||||||
/// \code
|
|
||||||
/// class MyClass {
|
return Proxy_Function(
|
||||||
/// public:
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
|
||||||
/// int overloaded(int);
|
|
||||||
/// double overloaded(double);
|
|
||||||
/// int const_overloaded() const;
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// chai.add(chaiscript::fun<int(int)>(&MyClass::overloaded), "overloaded");
|
|
||||||
/// chai.add(chaiscript::fun<double(double)>(&MyClass::overloaded), "overloaded");
|
|
||||||
/// chai.add(chaiscript::fun<int() const>(&MyClass::const_overloaded), "const_overloaded");
|
|
||||||
/// \endcode
|
|
||||||
template<typename Sig, typename Class, std::enable_if_t<std::is_function_v<Sig>, int> = 0>
|
|
||||||
Proxy_Function fun(std::type_identity_t<Sig> Class::*f) {
|
|
||||||
return dispatch::detail::make_callable(f, dispatch::detail::function_signature(f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename ... Param>
|
||||||
|
Proxy_Function fun(Ret (Class::*t_func)(Param...))
|
||||||
|
{
|
||||||
|
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
|
||||||
|
|
||||||
|
return Proxy_Function(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
|
||||||
|
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
|
||||||
|
{
|
||||||
|
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<T, Class>>(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
||||||
/// \param[in] t Function / member to expose
|
/// \param[in] t Function / member to expose
|
||||||
/// \param[in] q Value to bind to first parameter
|
/// \param[in] q Value to bind to first parameter
|
||||||
@ -138,10 +102,39 @@ namespace chaiscript {
|
|||||||
///
|
///
|
||||||
/// \sa \ref adding_functions
|
/// \sa \ref adding_functions
|
||||||
template<typename T, typename Q>
|
template<typename T, typename Q>
|
||||||
Proxy_Function fun(T &&t, const Q &q) {
|
Proxy_Function fun(T &&t, const Q &q)
|
||||||
|
{
|
||||||
return fun(detail::bind_first(std::forward<T>(t), q));
|
return fun(detail::bind_first(std::forward<T>(t), q));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chaiscript
|
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
|
||||||
|
/// \param[in] t Function / member to expose
|
||||||
|
/// \param[in] q Value to bind to first parameter
|
||||||
|
/// \param[in] r Value to bind to second parameter
|
||||||
|
///
|
||||||
|
/// \b Example:
|
||||||
|
/// \code
|
||||||
|
/// struct MyClass
|
||||||
|
/// {
|
||||||
|
/// void memberfunction(int);
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// MyClass obj;
|
||||||
|
/// chaiscript::ChaiScript chai;
|
||||||
|
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
|
||||||
|
/// // memberfunction() will be equivalent to obj.memberfunction(1)
|
||||||
|
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// \sa \ref adding_functions
|
||||||
|
template<typename T, typename Q, typename R>
|
||||||
|
Proxy_Function fun(T &&t, Q &&q, R &&r)
|
||||||
|
{
|
||||||
|
return fun(detail::bind_first(detail::bind_first(std::forward<T>(t), std::forward<Q>(q)), std::forward<R>(r)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||||
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -20,116 +16,141 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#include "../chaiscript_threading.hpp"
|
#include "../chaiscript_threading.hpp"
|
||||||
#include "../utility/static_string.hpp"
|
|
||||||
#include "bad_boxed_cast.hpp"
|
#include "bad_boxed_cast.hpp"
|
||||||
#include "boxed_cast_helper.hpp"
|
#include "boxed_cast_helper.hpp"
|
||||||
#include "boxed_value.hpp"
|
#include "boxed_value.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace exception {
|
{
|
||||||
/// \brief Error thrown when there's a problem with type conversion
|
namespace exception
|
||||||
class conversion_error : public bad_boxed_cast {
|
{
|
||||||
|
class bad_boxed_dynamic_cast : public bad_boxed_cast
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
conversion_error(const Type_Info t_to, const Type_Info t_from, const utility::Static_String what) noexcept
|
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||||
: bad_boxed_cast(t_from, (*t_to.bare_type_info()), what)
|
const std::string &t_what) CHAISCRIPT_NOEXCEPT
|
||||||
, type_to(t_to) {
|
: bad_boxed_cast(t_from, t_to, t_what)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Info type_to;
|
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
|
||||||
};
|
: bad_boxed_cast(t_from, t_to)
|
||||||
|
{
|
||||||
class bad_boxed_dynamic_cast : public bad_boxed_cast {
|
|
||||||
public:
|
|
||||||
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
|
|
||||||
: bad_boxed_cast(t_from, t_to, t_what) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
|
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
|
||||||
: bad_boxed_cast(t_from, t_to) {
|
: bad_boxed_cast(w)
|
||||||
}
|
{
|
||||||
|
|
||||||
explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept
|
|
||||||
: bad_boxed_cast(w) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
|
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
|
||||||
|
|
||||||
~bad_boxed_dynamic_cast() noexcept override = default;
|
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class bad_boxed_type_cast : public bad_boxed_cast {
|
class bad_boxed_type_cast : public bad_boxed_cast
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, const utility::Static_String &t_what) noexcept
|
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||||
: bad_boxed_cast(t_from, t_to, t_what) {
|
const std::string &t_what) CHAISCRIPT_NOEXCEPT
|
||||||
|
: bad_boxed_cast(t_from, t_to, t_what)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
|
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
|
||||||
: bad_boxed_cast(t_from, t_to) {
|
: bad_boxed_cast(t_from, t_to)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept
|
bad_boxed_type_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
|
||||||
: bad_boxed_cast(w) {
|
: bad_boxed_cast(w)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
|
bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
|
||||||
|
|
||||||
~bad_boxed_type_cast() noexcept override = default;
|
virtual ~bad_boxed_type_cast() CHAISCRIPT_NOEXCEPT {}
|
||||||
};
|
};
|
||||||
} // namespace exception
|
}
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
class Type_Conversion_Base {
|
namespace detail
|
||||||
|
{
|
||||||
|
class Type_Conversion_Base
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
|
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
|
||||||
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
|
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
|
||||||
|
|
||||||
const Type_Info &to() const noexcept { return m_to; }
|
const Type_Info &to() const
|
||||||
const Type_Info &from() const noexcept { return m_from; }
|
{
|
||||||
|
return m_to;
|
||||||
virtual bool bidir() const noexcept { return true; }
|
}
|
||||||
|
const Type_Info &from() const
|
||||||
virtual ~Type_Conversion_Base() = default;
|
{
|
||||||
|
return m_from;
|
||||||
protected:
|
|
||||||
Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
|
|
||||||
: m_to(std::move(t_to))
|
|
||||||
, m_from(std::move(t_from)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool bidir() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Type_Conversion_Base() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Type_Conversion_Base(const Type_Info &t_to, const Type_Info &t_from)
|
||||||
|
: m_to(t_to), m_from(t_from)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Type_Info m_to;
|
Type_Info m_to;
|
||||||
const Type_Info m_from;
|
Type_Info m_from;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
class Static_Caster {
|
class Static_Caster
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
static Boxed_Value cast(const Boxed_Value &t_from) {
|
static Boxed_Value cast(const Boxed_Value &t_from)
|
||||||
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
|
{
|
||||||
if (t_from.is_pointer()) {
|
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
|
||||||
|
{
|
||||||
|
if (t_from.is_pointer())
|
||||||
|
{
|
||||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||||
if (t_from.is_const()) {
|
if (t_from.is_const())
|
||||||
return Boxed_Value([&]() {
|
{
|
||||||
if (auto data
|
return Boxed_Value(
|
||||||
= std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
|
[&]()->std::shared_ptr<const To>{
|
||||||
|
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
|
||||||
|
{
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
throw std::bad_cast();
|
throw std::bad_cast();
|
||||||
}
|
}
|
||||||
}());
|
}()
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return Boxed_Value([&]() {
|
return Boxed_Value(
|
||||||
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
|
[&]()->std::shared_ptr<To>{
|
||||||
|
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
|
||||||
|
{
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
throw std::bad_cast();
|
throw std::bad_cast();
|
||||||
}
|
}
|
||||||
}());
|
}()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Pull the reference out of the contained boxed value, which we know is the type we want
|
// Pull the reference out of the contained boxed value, which we know is the type we want
|
||||||
if (t_from.is_const()) {
|
if (t_from.is_const())
|
||||||
|
{
|
||||||
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
|
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
|
||||||
const To &data = static_cast<const To &>(d);
|
const To &data = static_cast<const To &>(d);
|
||||||
return Boxed_Value(std::cref(data));
|
return Boxed_Value(std::cref(data));
|
||||||
@ -143,27 +164,38 @@ namespace chaiscript {
|
|||||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
class Dynamic_Caster {
|
class Dynamic_Caster
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
static Boxed_Value cast(const Boxed_Value &t_from) {
|
static Boxed_Value cast(const Boxed_Value &t_from)
|
||||||
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>())) {
|
{
|
||||||
if (t_from.is_pointer()) {
|
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
|
||||||
|
{
|
||||||
|
if (t_from.is_pointer())
|
||||||
|
{
|
||||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||||
if (t_from.is_const()) {
|
if (t_from.is_const())
|
||||||
return Boxed_Value([&]() {
|
{
|
||||||
if (auto data
|
return Boxed_Value(
|
||||||
= std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From>>::cast(t_from, nullptr))) {
|
[&]()->std::shared_ptr<const To>{
|
||||||
|
if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
|
||||||
|
{
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
throw std::bad_cast();
|
throw std::bad_cast();
|
||||||
}
|
}
|
||||||
}());
|
}()
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return Boxed_Value([&]() {
|
return Boxed_Value(
|
||||||
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From>>::cast(t_from, nullptr))) {
|
[&]()->std::shared_ptr<To>{
|
||||||
|
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
|
||||||
|
{
|
||||||
return data;
|
return data;
|
||||||
} else {
|
} else {
|
||||||
#ifdef CHAISCRIPT_LIBCPP
|
#ifdef CHAISCRIPT_LIBCPP
|
||||||
@ -177,11 +209,13 @@ namespace chaiscript {
|
|||||||
#endif
|
#endif
|
||||||
throw std::bad_cast();
|
throw std::bad_cast();
|
||||||
}
|
}
|
||||||
}());
|
}()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Pull the reference out of the contained boxed value, which we know is the type we want
|
// Pull the reference out of the contained boxed value, which we know is the type we want
|
||||||
if (t_from.is_const()) {
|
if (t_from.is_const())
|
||||||
|
{
|
||||||
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
|
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
|
||||||
const To &data = dynamic_cast<const To &>(d);
|
const To &data = dynamic_cast<const To &>(d);
|
||||||
return Boxed_Value(std::cref(data));
|
return Boxed_Value(std::cref(data));
|
||||||
@ -195,91 +229,127 @@ namespace chaiscript {
|
|||||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename Base, typename Derived>
|
template<typename Base, typename Derived>
|
||||||
class Dynamic_Conversion_Impl : public Type_Conversion_Base {
|
class Dynamic_Conversion_Impl : public Type_Conversion_Base
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Conversion_Impl()
|
Dynamic_Conversion_Impl()
|
||||||
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
|
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value convert_down(const Boxed_Value &t_base) const override { return Dynamic_Caster<Base, Derived>::cast(t_base); }
|
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return Dynamic_Caster<Base, Derived>::cast(t_base);
|
||||||
|
}
|
||||||
|
|
||||||
Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
|
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Base, typename Derived>
|
template<typename Base, typename Derived>
|
||||||
class Static_Conversion_Impl : public Type_Conversion_Base {
|
class Static_Conversion_Impl : public Type_Conversion_Base
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Static_Conversion_Impl()
|
Static_Conversion_Impl()
|
||||||
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>()) {
|
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value convert_down(const Boxed_Value &t_base) const override {
|
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const CHAISCRIPT_OVERRIDE
|
||||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(),
|
{
|
||||||
typeid(Derived),
|
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), "Unable to cast down inheritance hierarchy with non-polymorphic types");
|
||||||
"Unable to cast down inheritance hierarchy with non-polymorphic types");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bidir() const noexcept override { return false; }
|
virtual bool bidir() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Boxed_Value convert(const Boxed_Value &t_derived) const override { return Static_Caster<Derived, Base>::cast(t_derived); }
|
virtual Boxed_Value convert(const Boxed_Value &t_derived) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Callable>
|
template<typename Callable>
|
||||||
class Type_Conversion_Impl : public Type_Conversion_Base {
|
class Type_Conversion_Impl : public Type_Conversion_Base
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
|
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
|
||||||
: Type_Conversion_Base(t_to, t_from)
|
: Type_Conversion_Base(std::move(t_to), std::move(t_from)),
|
||||||
, m_func(std::move(t_func)) {
|
m_func(std::move(t_func))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value convert_down(const Boxed_Value &) const override {
|
virtual Boxed_Value convert_down(const Boxed_Value &) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
|
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value convert(const Boxed_Value &t_from) const override {
|
virtual Boxed_Value convert(const Boxed_Value &t_from) const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
/// \todo better handling of errors from the conversion function
|
/// \todo better handling of errors from the conversion function
|
||||||
return m_func(t_from);
|
return m_func(t_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bidir() const noexcept override { return false; }
|
virtual bool bidir() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Callable m_func;
|
Callable m_func;
|
||||||
};
|
};
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
class Type_Conversions {
|
}
|
||||||
|
|
||||||
|
class Type_Conversions
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
struct Conversion_Saves {
|
struct Less_Than
|
||||||
bool enabled = false;
|
{
|
||||||
std::vector<Boxed_Value> saves;
|
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
|
||||||
};
|
{
|
||||||
|
|
||||||
struct Less_Than {
|
|
||||||
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept {
|
|
||||||
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
|
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Type_Conversions()
|
Type_Conversions()
|
||||||
: m_mutex()
|
: m_mutex(),
|
||||||
, m_conversions()
|
m_conversions(),
|
||||||
, m_convertableTypes()
|
m_convertableTypes(),
|
||||||
, m_num_types(0) {
|
m_num_types(0),
|
||||||
|
m_thread_cache(this),
|
||||||
|
m_conversion_saves(this)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Conversions(const Type_Conversions &t_other) = delete;
|
Type_Conversions(const Type_Conversions &t_other)
|
||||||
Type_Conversions(Type_Conversions &&) = delete;
|
: m_mutex(),
|
||||||
|
m_conversions(t_other.get_conversions()),
|
||||||
|
m_convertableTypes(t_other.m_convertableTypes),
|
||||||
|
m_num_types(m_conversions.size()),
|
||||||
|
m_thread_cache(this),
|
||||||
|
m_conversion_saves(this)
|
||||||
|
|
||||||
Type_Conversions &operator=(const Type_Conversions &) = delete;
|
{
|
||||||
Type_Conversions &operator=(Type_Conversions &&) = delete;
|
}
|
||||||
|
|
||||||
const std::set<const std::type_info *, Less_Than> &thread_cache() const {
|
const std::set<const std::type_info *, Less_Than> &thread_cache() const
|
||||||
|
{
|
||||||
auto &cache = *m_thread_cache;
|
auto &cache = *m_thread_cache;
|
||||||
if (cache.size() != m_num_types) {
|
if (cache.size() != m_num_types)
|
||||||
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
cache = m_convertableTypes;
|
cache = m_convertableTypes;
|
||||||
}
|
}
|
||||||
@ -287,125 +357,142 @@ namespace chaiscript {
|
|||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
|
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
|
||||||
|
{
|
||||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) {
|
/// \todo error if a conversion already exists
|
||||||
throw exception::conversion_error(conversion->to(), conversion->from(), "Trying to re-insert an existing conversion!");
|
|
||||||
}
|
|
||||||
m_conversions.insert(conversion);
|
m_conversions.insert(conversion);
|
||||||
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
|
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
|
||||||
m_num_types = m_convertableTypes.size();
|
m_num_types = m_convertableTypes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool convertable_type() const noexcept {
|
bool convertable_type() const
|
||||||
const auto type = user_type<T>().bare_type_info();
|
{
|
||||||
return thread_cache().count(type) != 0;
|
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename To, typename From>
|
template<typename To, typename From>
|
||||||
bool converts() const noexcept {
|
bool converts() const
|
||||||
|
{
|
||||||
return converts(user_type<To>(), user_type<From>());
|
return converts(user_type<To>(), user_type<From>());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool converts(const Type_Info &to, const Type_Info &from) const noexcept {
|
bool converts(const Type_Info &to, const Type_Info &from) const
|
||||||
|
{
|
||||||
const auto &types = thread_cache();
|
const auto &types = thread_cache();
|
||||||
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) {
|
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
|
||||||
|
{
|
||||||
return has_conversion(to, from);
|
return has_conversion(to, from);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename To>
|
template<typename To>
|
||||||
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const {
|
Boxed_Value boxed_type_conversion(const Boxed_Value &from) const
|
||||||
return boxed_type_conversion(user_type<To>(), t_saves, from);
|
{
|
||||||
|
try {
|
||||||
|
Boxed_Value ret = get_conversion(user_type<To>(), from.get_type_info())->convert(from);
|
||||||
|
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
|
||||||
|
return ret;
|
||||||
|
} catch (const std::out_of_range &) {
|
||||||
|
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "No known conversion");
|
||||||
|
} catch (const std::bad_cast &) {
|
||||||
|
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), typeid(To), "Unable to perform dynamic_cast operation");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename From>
|
template<typename From>
|
||||||
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const {
|
Boxed_Value boxed_type_down_conversion(const Boxed_Value &to) const
|
||||||
return boxed_type_down_conversion(user_type<From>(), t_saves, to);
|
{
|
||||||
}
|
|
||||||
|
|
||||||
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const {
|
|
||||||
try {
|
try {
|
||||||
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
|
Boxed_Value ret = get_conversion(to.get_type_info(), user_type<From>())->convert_down(to);
|
||||||
if (t_saves.enabled) {
|
if (m_conversion_saves->enabled) m_conversion_saves->saves.push_back(ret);
|
||||||
t_saves.saves.push_back(ret);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) {
|
||||||
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
|
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "No known conversion");
|
||||||
} catch (const std::bad_cast &) {
|
} catch (const std::bad_cast &) {
|
||||||
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
|
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), typeid(From), "Unable to perform dynamic_cast operation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const {
|
void enable_conversion_saves(bool t_val)
|
||||||
try {
|
{
|
||||||
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
|
m_conversion_saves->enabled = t_val;
|
||||||
if (t_saves.enabled) {
|
|
||||||
t_saves.saves.push_back(ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
} catch (const std::out_of_range &) {
|
|
||||||
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
|
|
||||||
} catch (const std::bad_cast &) {
|
|
||||||
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) { t_saves.enabled = t_val; }
|
std::vector<Boxed_Value> take_saves()
|
||||||
|
{
|
||||||
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves) {
|
|
||||||
std::vector<Boxed_Value> ret;
|
std::vector<Boxed_Value> ret;
|
||||||
std::swap(ret, t_saves.saves);
|
std::swap(ret, m_conversion_saves->saves);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_conversion(const Type_Info &to, const Type_Info &from) const {
|
bool has_conversion(const Type_Info &to, const Type_Info &from) const
|
||||||
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
return find_bidir(to, from) != m_conversions.end();
|
return find_bidir(to, from) != m_conversions.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const {
|
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
|
||||||
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
const auto itr = find(to, from);
|
auto itr = find(to, from);
|
||||||
|
|
||||||
if (itr != m_conversions.end()) {
|
if (itr != m_conversions.end())
|
||||||
|
{
|
||||||
return *itr;
|
return *itr;
|
||||||
} else {
|
} else {
|
||||||
throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
|
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Conversion_Saves &conversion_saves() const noexcept { return *m_conversion_saves; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find_bidir(const Type_Info &to, const Type_Info &from) const {
|
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
|
||||||
return std::find_if(m_conversions.begin(),
|
const Type_Info &to, const Type_Info &from) const
|
||||||
m_conversions.end(),
|
{
|
||||||
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool {
|
return std::find_if(m_conversions.begin(), m_conversions.end(),
|
||||||
|
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
|
||||||
|
{
|
||||||
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|
||||||
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
|
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
|
||||||
});
|
;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::shared_ptr<detail::Type_Conversion_Base>>::const_iterator find(const Type_Info &to, const Type_Info &from) const {
|
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
|
||||||
return std::find_if(m_conversions.begin(),
|
const Type_Info &to, const Type_Info &from) const
|
||||||
m_conversions.end(),
|
{
|
||||||
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) {
|
return std::find_if(m_conversions.begin(), m_conversions.end(),
|
||||||
|
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
|
||||||
|
{
|
||||||
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
|
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const {
|
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
|
||||||
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
return m_conversions;
|
return m_conversions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Conversion_Saves
|
||||||
|
{
|
||||||
|
Conversion_Saves()
|
||||||
|
: enabled(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
std::vector<Boxed_Value> saves;
|
||||||
|
};
|
||||||
|
|
||||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||||
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
|
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
|
||||||
std::set<const std::type_info *, Less_Than> m_convertableTypes;
|
std::set<const std::type_info *, Less_Than> m_convertableTypes;
|
||||||
@ -414,25 +501,7 @@ namespace chaiscript {
|
|||||||
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
|
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Type_Conversions_State {
|
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
|
||||||
public:
|
|
||||||
Type_Conversions_State(const Type_Conversions &t_conversions, Type_Conversions::Conversion_Saves &t_saves)
|
|
||||||
: m_conversions(t_conversions)
|
|
||||||
, m_saves(t_saves) {
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type_Conversions *operator->() const noexcept { return &m_conversions.get(); }
|
|
||||||
|
|
||||||
const Type_Conversions *get() const noexcept { return &m_conversions.get(); }
|
|
||||||
|
|
||||||
Type_Conversions::Conversion_Saves &saves() const noexcept { return m_saves; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::reference_wrapper<const Type_Conversions> m_conversions;
|
|
||||||
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
|
|
||||||
};
|
|
||||||
|
|
||||||
using Type_Conversion = std::shared_ptr<chaiscript::detail::Type_Conversion_Base>;
|
|
||||||
|
|
||||||
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
|
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
|
||||||
/// want automatic conversions up your inheritance hierarchy.
|
/// want automatic conversions up your inheritance hierarchy.
|
||||||
@ -456,124 +525,75 @@ namespace chaiscript {
|
|||||||
/// \endcode
|
/// \endcode
|
||||||
///
|
///
|
||||||
template<typename Base, typename Derived>
|
template<typename Base, typename Derived>
|
||||||
Type_Conversion base_class() {
|
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||||
|
{
|
||||||
//Can only be used with related polymorphic types
|
//Can only be used with related polymorphic types
|
||||||
//may be expanded some day to support conversions other than child -> parent
|
//may be expanded some day to support conversions other than child -> parent
|
||||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||||
|
|
||||||
if constexpr (std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
|
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
|
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
|
||||||
} else {
|
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Base, typename Derived>
|
||||||
|
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||||
|
{
|
||||||
|
//Can only be used with related polymorphic types
|
||||||
|
//may be expanded some day to support conversions other than child -> parent
|
||||||
|
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||||
|
|
||||||
|
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Callable>
|
template<typename Callable>
|
||||||
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, const Callable &t_func) {
|
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
|
||||||
|
const Callable &t_func)
|
||||||
|
{
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
|
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename From, typename To, typename Callable>
|
template<typename From, typename To, typename Callable>
|
||||||
Type_Conversion type_conversion(const Callable &t_function) {
|
Type_Conversion type_conversion(const Callable &t_function)
|
||||||
|
{
|
||||||
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
|
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||||
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
|
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
|
||||||
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
|
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
|
||||||
};
|
};
|
||||||
|
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
|
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
|
||||||
user_type<To>(),
|
|
||||||
func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename From, typename To>
|
template<typename From, typename To>
|
||||||
Type_Conversion type_conversion() {
|
Type_Conversion type_conversion()
|
||||||
|
{
|
||||||
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
|
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
|
||||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||||
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
|
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
|
||||||
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
|
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
|
||||||
};
|
};
|
||||||
|
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(),
|
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
|
||||||
user_type<To>(),
|
|
||||||
func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename T>
|
|
||||||
struct is_std_vector : std::false_type {};
|
|
||||||
|
|
||||||
template<typename T, typename A>
|
|
||||||
struct is_std_vector<std::vector<T, A>> : std::true_type {};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T convert_vector_element(const Boxed_Value &bv) {
|
|
||||||
if constexpr (is_std_vector<T>::value) {
|
|
||||||
const auto &inner = Cast_Helper<const std::vector<Boxed_Value> &>::cast(bv, nullptr);
|
|
||||||
T result;
|
|
||||||
result.reserve(inner.size());
|
|
||||||
for (const Boxed_Value &elem : inner) {
|
|
||||||
result.push_back(convert_vector_element<typename T::value_type>(elem));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return Cast_Helper<T>::cast(bv, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<typename To>
|
template<typename To>
|
||||||
Type_Conversion vector_conversion() {
|
Type_Conversion vector_conversion()
|
||||||
|
{
|
||||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||||
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
|
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
|
||||||
|
|
||||||
To vec;
|
To vec;
|
||||||
vec.reserve(from_vec.size());
|
|
||||||
for (const Boxed_Value &bv : from_vec) {
|
for (const Boxed_Value &bv : from_vec) {
|
||||||
vec.push_back(detail::convert_vector_element<typename To::value_type>(bv));
|
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boxed_Value(std::move(vec));
|
return Boxed_Value(std::move(vec));
|
||||||
};
|
};
|
||||||
|
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(),
|
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
|
||||||
user_type<To>(),
|
|
||||||
func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename To>
|
|
||||||
Type_Conversion map_conversion() {
|
|
||||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
|
||||||
const std::map<std::string, Boxed_Value> &from_map
|
|
||||||
= detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
|
|
||||||
|
|
||||||
To map;
|
|
||||||
for (const std::pair<const std::string, Boxed_Value> &p : from_map) {
|
|
||||||
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boxed_Value(std::move(map));
|
|
||||||
};
|
|
||||||
|
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(
|
|
||||||
user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Left, typename Right>
|
|
||||||
Type_Conversion pair_conversion() {
|
|
||||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
|
||||||
const std::pair<Boxed_Value, Boxed_Value> &from_pair
|
|
||||||
= detail::Cast_Helper<const std::pair<Boxed_Value, Boxed_Value> &>::cast(t_bv, nullptr);
|
|
||||||
|
|
||||||
auto pair = std::make_pair(
|
|
||||||
detail::Cast_Helper<Left>::cast(from_pair.first, nullptr),
|
|
||||||
detail::Cast_Helper<Right>::cast(from_pair.second, nullptr));
|
|
||||||
|
|
||||||
return Boxed_Value(std::move(pair));
|
|
||||||
};
|
|
||||||
|
|
||||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(
|
|
||||||
user_type<std::pair<Boxed_Value, Boxed_Value>>(), user_type<std::pair<Left, Right>>(), func);
|
|
||||||
}
|
|
||||||
} // namespace chaiscript
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,115 +1,143 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
|
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
|
||||||
#define CHAISCRIPT_TYPE_INFO_HPP_
|
#define CHAISCRIPT_TYPE_INFO_HPP_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
namespace detail {
|
{
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Bare_Type {
|
struct Bare_Type
|
||||||
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
|
{
|
||||||
|
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
|
||||||
};
|
};
|
||||||
} // namespace detail
|
}
|
||||||
|
|
||||||
|
|
||||||
/// \brief Compile time deduced information about a type
|
/// \brief Compile time deduced information about a type
|
||||||
class Type_Info {
|
class Type_Info
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
constexpr Type_Info(const bool t_is_const,
|
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||||
const bool t_is_reference,
|
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
||||||
const bool t_is_pointer,
|
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
|
||||||
const bool t_is_void,
|
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
||||||
const bool t_is_arithmetic,
|
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
|
||||||
const std::type_info *t_ti,
|
m_is_undef(false)
|
||||||
const std::type_info *t_bare_ti) noexcept
|
{
|
||||||
: m_type_info(t_ti)
|
|
||||||
, m_bare_type_info(t_bare_ti)
|
|
||||||
, m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag) + (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
|
|
||||||
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag) + (static_cast<unsigned int>(t_is_void) << is_void_flag)
|
|
||||||
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Type_Info() noexcept = default;
|
CHAISCRIPT_CONSTEXPR Type_Info()
|
||||||
|
: m_type_info(nullptr), m_bare_type_info(nullptr),
|
||||||
bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
|
m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
||||||
|
m_is_void(false), m_is_arithmetic(false),
|
||||||
constexpr bool operator!=(const Type_Info &ti) const noexcept { return !(operator==(ti)); }
|
m_is_undef(true)
|
||||||
|
{
|
||||||
constexpr bool operator!=(const std::type_info &ti) const noexcept { return !(operator==(ti)); }
|
|
||||||
|
|
||||||
constexpr bool operator==(const Type_Info &ti) const noexcept {
|
|
||||||
return ti.m_type_info == m_type_info || *ti.m_type_info == *m_type_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
|
#if !defined(_MSC_VER) || _MSC_VER != 1800
|
||||||
|
Type_Info(Type_Info&&) = default;
|
||||||
|
Type_Info& operator=(Type_Info&&) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
constexpr bool bare_equal(const Type_Info &ti) const noexcept {
|
Type_Info(const Type_Info&) = default;
|
||||||
return ti.m_bare_type_info == m_bare_type_info || *ti.m_bare_type_info == *m_bare_type_info;
|
Type_Info& operator=(const Type_Info&) = default;
|
||||||
|
|
||||||
|
|
||||||
|
CHAISCRIPT_CONSTEXPR bool operator<(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_type_info < ti.m_type_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept { return !is_undef() && (*m_bare_type_info) == ti; }
|
CHAISCRIPT_CONSTEXPR bool operator==(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return ti.m_type_info == m_type_info
|
||||||
|
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
|
CHAISCRIPT_CONSTEXPR bool operator==(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
|
||||||
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
|
{
|
||||||
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; }
|
return m_type_info != nullptr && (*m_type_info) == ti;
|
||||||
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
|
}
|
||||||
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
|
|
||||||
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
|
|
||||||
|
|
||||||
const char *name() const noexcept {
|
CHAISCRIPT_CONSTEXPR bool bare_equal(const Type_Info &ti) const CHAISCRIPT_NOEXCEPT
|
||||||
if (!is_undef()) {
|
{
|
||||||
|
return ti.m_bare_type_info == m_bare_type_info
|
||||||
|
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAISCRIPT_CONSTEXPR bool bare_equal_type_info(const std::type_info &ti) const CHAISCRIPT_NOEXCEPT
|
||||||
|
{
|
||||||
|
return m_bare_type_info != nullptr
|
||||||
|
&& (*m_bare_type_info) == ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAISCRIPT_CONSTEXPR bool is_const() const CHAISCRIPT_NOEXCEPT { return m_is_const; }
|
||||||
|
CHAISCRIPT_CONSTEXPR bool is_reference() const CHAISCRIPT_NOEXCEPT { return m_is_reference; }
|
||||||
|
CHAISCRIPT_CONSTEXPR bool is_void() const CHAISCRIPT_NOEXCEPT { return m_is_void; }
|
||||||
|
CHAISCRIPT_CONSTEXPR bool is_arithmetic() const CHAISCRIPT_NOEXCEPT { return m_is_arithmetic; }
|
||||||
|
CHAISCRIPT_CONSTEXPR bool is_undef() const CHAISCRIPT_NOEXCEPT { return m_is_undef; }
|
||||||
|
CHAISCRIPT_CONSTEXPR bool is_pointer() const CHAISCRIPT_NOEXCEPT { return m_is_pointer; }
|
||||||
|
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
if (m_type_info)
|
||||||
|
{
|
||||||
return m_type_info->name();
|
return m_type_info->name();
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *bare_name() const noexcept {
|
std::string bare_name() const
|
||||||
if (!is_undef()) {
|
{
|
||||||
|
if (m_bare_type_info)
|
||||||
|
{
|
||||||
return m_bare_type_info->name();
|
return m_bare_type_info->name();
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
|
CHAISCRIPT_CONSTEXPR const std::type_info *bare_type_info() const
|
||||||
|
{
|
||||||
void make_const() noexcept { m_flags |= (1 << is_const_flag); }
|
return m_bare_type_info;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Unknown_Type {
|
const std::type_info *m_type_info;
|
||||||
|
const std::type_info *m_bare_type_info;
|
||||||
|
bool m_is_const;
|
||||||
|
bool m_is_reference;
|
||||||
|
bool m_is_pointer;
|
||||||
|
bool m_is_void;
|
||||||
|
bool m_is_arithmetic;
|
||||||
|
bool m_is_undef;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::type_info *m_type_info = &typeid(Unknown_Type);
|
namespace detail
|
||||||
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
|
{
|
||||||
static const int is_const_flag = 0;
|
|
||||||
static const int is_reference_flag = 1;
|
|
||||||
static const int is_pointer_flag = 2;
|
|
||||||
static const int is_void_flag = 3;
|
|
||||||
static const int is_arithmetic_flag = 4;
|
|
||||||
static const int is_undef_flag = 5;
|
|
||||||
unsigned int m_flags = (1 << is_undef_flag);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
/// Helper used to create a Type_Info object
|
/// Helper used to create a Type_Info object
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info {
|
struct Get_Type_Info
|
||||||
constexpr static Type_Info get() noexcept {
|
{
|
||||||
|
typedef T type;
|
||||||
|
|
||||||
|
static Type_Info get()
|
||||||
|
{
|
||||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||||
std::is_reference<T>::value,
|
std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||||
std::is_pointer<T>::value,
|
|
||||||
std::is_void<T>::value,
|
std::is_void<T>::value,
|
||||||
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
|
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
|
||||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
@ -119,66 +147,66 @@ namespace chaiscript {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<std::shared_ptr<T>> {
|
struct Get_Type_Info<std::shared_ptr<T> >
|
||||||
constexpr static Type_Info get() noexcept {
|
{
|
||||||
return Type_Info(std::is_const<T>::value,
|
typedef T type;
|
||||||
std::is_reference<T>::value,
|
|
||||||
std::is_pointer<T>::value,
|
static Type_Info get()
|
||||||
|
{
|
||||||
|
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||||
std::is_void<T>::value,
|
std::is_void<T>::value,
|
||||||
std::is_arithmetic<T>::value
|
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
|
||||||
&typeid(std::shared_ptr<T> ),
|
&typeid(std::shared_ptr<T> ),
|
||||||
&typeid(typename Bare_Type<T>::type));
|
&typeid(typename Bare_Type<T>::type));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> {
|
struct Get_Type_Info<const std::shared_ptr<T> &>
|
||||||
};
|
{
|
||||||
|
typedef T type;
|
||||||
|
|
||||||
template<typename T>
|
static Type_Info get()
|
||||||
struct Get_Type_Info<const std::shared_ptr<T> &> {
|
{
|
||||||
constexpr static Type_Info get() noexcept {
|
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||||
return Type_Info(std::is_const<T>::value,
|
|
||||||
std::is_reference<T>::value,
|
|
||||||
std::is_pointer<T>::value,
|
|
||||||
std::is_void<T>::value,
|
std::is_void<T>::value,
|
||||||
std::is_arithmetic<T>::value
|
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
|
||||||
&typeid(const std::shared_ptr<T> &),
|
&typeid(const std::shared_ptr<T> &),
|
||||||
&typeid(typename Bare_Type<T>::type));
|
&typeid(typename Bare_Type<T>::type));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<std::reference_wrapper<T>> {
|
struct Get_Type_Info<std::reference_wrapper<T> >
|
||||||
constexpr static Type_Info get() noexcept {
|
{
|
||||||
return Type_Info(std::is_const<T>::value,
|
typedef T type;
|
||||||
std::is_reference<T>::value,
|
|
||||||
std::is_pointer<T>::value,
|
static Type_Info get()
|
||||||
|
{
|
||||||
|
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||||
std::is_void<T>::value,
|
std::is_void<T>::value,
|
||||||
std::is_arithmetic<T>::value
|
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
|
||||||
&typeid(std::reference_wrapper<T> ),
|
&typeid(std::reference_wrapper<T> ),
|
||||||
&typeid(typename Bare_Type<T>::type));
|
&typeid(typename Bare_Type<T>::type));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<const std::reference_wrapper<T> &> {
|
struct Get_Type_Info<const std::reference_wrapper<T> &>
|
||||||
constexpr static Type_Info get() noexcept {
|
{
|
||||||
return Type_Info(std::is_const<T>::value,
|
typedef T type;
|
||||||
std::is_reference<T>::value,
|
|
||||||
std::is_pointer<T>::value,
|
static Type_Info get()
|
||||||
|
{
|
||||||
|
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||||
std::is_void<T>::value,
|
std::is_void<T>::value,
|
||||||
std::is_arithmetic<T>::value
|
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
|
||||||
&typeid(const std::reference_wrapper<T> &),
|
&typeid(const std::reference_wrapper<T> &),
|
||||||
&typeid(typename Bare_Type<T>::type));
|
&typeid(typename Bare_Type<T>::type));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
}
|
||||||
|
|
||||||
/// \brief Creates a Type_Info object representing the type passed in
|
/// \brief Creates a Type_Info object representing the type passed in
|
||||||
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
|
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
|
||||||
@ -190,10 +218,12 @@ namespace chaiscript {
|
|||||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Type_Info user_type(const T & /*t*/) noexcept {
|
Type_Info user_type(const T &/*t*/)
|
||||||
|
{
|
||||||
return detail::Get_Type_Info<T>::get();
|
return detail::Get_Type_Info<T>::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// \brief Creates a Type_Info object representing the templated type
|
/// \brief Creates a Type_Info object representing the templated type
|
||||||
/// \tparam T Type of object to get a Type_Info for
|
/// \tparam T Type of object to get a Type_Info for
|
||||||
/// \return Type_Info for T
|
/// \return Type_Info for T
|
||||||
@ -203,10 +233,12 @@ namespace chaiscript {
|
|||||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Type_Info user_type() noexcept {
|
Type_Info user_type()
|
||||||
|
{
|
||||||
return detail::Get_Type_Info<T>::get();
|
return detail::Get_Type_Info<T>::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,168 +1,130 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
|
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
|
||||||
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
||||||
|
|
||||||
#include "../utility/hash.hpp"
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
|
{
|
||||||
|
|
||||||
struct Operators {
|
struct Operators {
|
||||||
enum class Opers {
|
enum Opers
|
||||||
equals,
|
{
|
||||||
less_than,
|
boolean_flag,
|
||||||
greater_than,
|
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
|
||||||
less_than_equal,
|
non_const_flag,
|
||||||
greater_than_equal,
|
assign, pre_increment, pre_decrement, assign_product, assign_sum,
|
||||||
not_equal,
|
assign_quotient, assign_difference,
|
||||||
assign,
|
non_const_int_flag,
|
||||||
pre_increment,
|
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
|
||||||
pre_decrement,
|
assign_remainder, assign_bitwise_xor,
|
||||||
assign_product,
|
const_int_flag,
|
||||||
assign_sum,
|
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
|
||||||
assign_quotient,
|
const_flag,
|
||||||
assign_difference,
|
sum, quotient, product, difference, unary_plus, unary_minus,
|
||||||
assign_bitwise_and,
|
|
||||||
assign_bitwise_or,
|
|
||||||
assign_shift_left,
|
|
||||||
assign_shift_right,
|
|
||||||
assign_remainder,
|
|
||||||
assign_bitwise_xor,
|
|
||||||
shift_left,
|
|
||||||
shift_right,
|
|
||||||
remainder,
|
|
||||||
bitwise_and,
|
|
||||||
bitwise_or,
|
|
||||||
bitwise_xor,
|
|
||||||
bitwise_complement,
|
|
||||||
sum,
|
|
||||||
quotient,
|
|
||||||
product,
|
|
||||||
difference,
|
|
||||||
unary_plus,
|
|
||||||
unary_minus,
|
|
||||||
invalid
|
invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr static std::string_view to_string(Opers t_oper) noexcept {
|
static const char *to_string(Opers t_oper) {
|
||||||
constexpr const std::array opers
|
const char *opers[] = {
|
||||||
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
|
"",
|
||||||
return opers[static_cast<std::size_t>(t_oper)];
|
"==", "<", ">", "<=", ">=", "!=",
|
||||||
}
|
"",
|
||||||
|
"=", "++", "--", "*=", "+=",
|
||||||
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept {
|
"/=", "-=",
|
||||||
#ifdef CHAISCRIPT_MSVC
|
"",
|
||||||
#pragma warning(push)
|
"&=", "|=", "<<=", ">>=",
|
||||||
#pragma warning(disable : 4307)
|
"%=", "^=",
|
||||||
#endif
|
"",
|
||||||
|
"<<", ">>", "%", "&", "|", "^", "~",
|
||||||
const auto op_hash = utility::hash(t_str);
|
"",
|
||||||
switch (op_hash) {
|
"+", "/", "*", "-", "+", "-",
|
||||||
case utility::hash("=="): {
|
""
|
||||||
return Opers::equals;
|
|
||||||
}
|
|
||||||
case utility::hash("<"): {
|
|
||||||
return Opers::less_than;
|
|
||||||
}
|
|
||||||
case utility::hash(">"): {
|
|
||||||
return Opers::greater_than;
|
|
||||||
}
|
|
||||||
case utility::hash("<="): {
|
|
||||||
return Opers::less_than_equal;
|
|
||||||
}
|
|
||||||
case utility::hash(">="): {
|
|
||||||
return Opers::greater_than_equal;
|
|
||||||
}
|
|
||||||
case utility::hash("!="): {
|
|
||||||
return Opers::not_equal;
|
|
||||||
}
|
|
||||||
case utility::hash("="): {
|
|
||||||
return Opers::assign;
|
|
||||||
}
|
|
||||||
case utility::hash("++"): {
|
|
||||||
return Opers::pre_increment;
|
|
||||||
}
|
|
||||||
case utility::hash("--"): {
|
|
||||||
return Opers::pre_decrement;
|
|
||||||
}
|
|
||||||
case utility::hash("*="): {
|
|
||||||
return Opers::assign_product;
|
|
||||||
}
|
|
||||||
case utility::hash("+="): {
|
|
||||||
return Opers::assign_sum;
|
|
||||||
}
|
|
||||||
case utility::hash("-="): {
|
|
||||||
return Opers::assign_difference;
|
|
||||||
}
|
|
||||||
case utility::hash("&="): {
|
|
||||||
return Opers::assign_bitwise_and;
|
|
||||||
}
|
|
||||||
case utility::hash("|="): {
|
|
||||||
return Opers::assign_bitwise_or;
|
|
||||||
}
|
|
||||||
case utility::hash("<<="): {
|
|
||||||
return Opers::assign_shift_left;
|
|
||||||
}
|
|
||||||
case utility::hash(">>="): {
|
|
||||||
return Opers::assign_shift_right;
|
|
||||||
}
|
|
||||||
case utility::hash("%="): {
|
|
||||||
return Opers::assign_remainder;
|
|
||||||
}
|
|
||||||
case utility::hash("^="): {
|
|
||||||
return Opers::assign_bitwise_xor;
|
|
||||||
}
|
|
||||||
case utility::hash("<<"): {
|
|
||||||
return Opers::shift_left;
|
|
||||||
}
|
|
||||||
case utility::hash(">>"): {
|
|
||||||
return Opers::shift_right;
|
|
||||||
}
|
|
||||||
case utility::hash("%"): {
|
|
||||||
return Opers::remainder;
|
|
||||||
}
|
|
||||||
case utility::hash("&"): {
|
|
||||||
return Opers::bitwise_and;
|
|
||||||
}
|
|
||||||
case utility::hash("|"): {
|
|
||||||
return Opers::bitwise_or;
|
|
||||||
}
|
|
||||||
case utility::hash("^"): {
|
|
||||||
return Opers::bitwise_xor;
|
|
||||||
}
|
|
||||||
case utility::hash("~"): {
|
|
||||||
return Opers::bitwise_complement;
|
|
||||||
}
|
|
||||||
case utility::hash("+"): {
|
|
||||||
return t_is_unary ? Opers::unary_plus : Opers::sum;
|
|
||||||
}
|
|
||||||
case utility::hash("-"): {
|
|
||||||
return t_is_unary ? Opers::unary_minus : Opers::difference;
|
|
||||||
}
|
|
||||||
case utility::hash("/"): {
|
|
||||||
return Opers::quotient;
|
|
||||||
}
|
|
||||||
case utility::hash("*"): {
|
|
||||||
return Opers::product;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return Opers::invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef CHAISCRIPT_MSVC
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // namespace chaiscript
|
return opers[t_oper];
|
||||||
|
}
|
||||||
|
|
||||||
|
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
|
||||||
|
{
|
||||||
|
if (t_str == "==")
|
||||||
|
{
|
||||||
|
return equals;
|
||||||
|
} else if (t_str == "<") {
|
||||||
|
return less_than;
|
||||||
|
} else if (t_str == ">") {
|
||||||
|
return greater_than;
|
||||||
|
} else if (t_str == "<=") {
|
||||||
|
return less_than_equal;
|
||||||
|
} else if (t_str == ">=") {
|
||||||
|
return greater_than_equal;
|
||||||
|
} else if (t_str == "!=") {
|
||||||
|
return not_equal;
|
||||||
|
} else if (t_str == "=") {
|
||||||
|
return assign;
|
||||||
|
} else if (t_str == "++") {
|
||||||
|
return pre_increment;
|
||||||
|
} else if (t_str == "--") {
|
||||||
|
return pre_decrement;
|
||||||
|
} else if (t_str == "*=") {
|
||||||
|
return assign_product;
|
||||||
|
} else if (t_str == "+=") {
|
||||||
|
return assign_sum;
|
||||||
|
} else if (t_str == "-=") {
|
||||||
|
return assign_difference;
|
||||||
|
} else if (t_str == "&=") {
|
||||||
|
return assign_bitwise_and;
|
||||||
|
} else if (t_str == "|=") {
|
||||||
|
return assign_bitwise_or;
|
||||||
|
} else if (t_str == "<<=") {
|
||||||
|
return assign_shift_left;
|
||||||
|
} else if (t_str == ">>=") {
|
||||||
|
return assign_shift_right;
|
||||||
|
} else if (t_str == "%=") {
|
||||||
|
return assign_remainder;
|
||||||
|
} else if (t_str == "^=") {
|
||||||
|
return assign_bitwise_xor;
|
||||||
|
} else if (t_str == "<<") {
|
||||||
|
return shift_left;
|
||||||
|
} else if (t_str == ">>") {
|
||||||
|
return shift_right;
|
||||||
|
} else if (t_str == "%") {
|
||||||
|
return remainder;
|
||||||
|
} else if (t_str == "&") {
|
||||||
|
return bitwise_and;
|
||||||
|
} else if (t_str == "|") {
|
||||||
|
return bitwise_or;
|
||||||
|
} else if (t_str == "^") {
|
||||||
|
return bitwise_xor;
|
||||||
|
} else if (t_str == "~") {
|
||||||
|
return bitwise_complement;
|
||||||
|
} else if (t_str == "+") {
|
||||||
|
if (t_is_unary) {
|
||||||
|
return unary_plus;
|
||||||
|
} else {
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
} else if (t_str == "-") {
|
||||||
|
if (t_is_unary) {
|
||||||
|
return unary_minus;
|
||||||
|
} else {
|
||||||
|
return difference;
|
||||||
|
}
|
||||||
|
} else if (t_str == "/") {
|
||||||
|
return quotient;
|
||||||
|
} else if (t_str == "*") {
|
||||||
|
return product;
|
||||||
|
} else {
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2015, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
||||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_COMMON_HPP_
|
#ifndef CHAISCRIPT_COMMON_HPP_
|
||||||
#define CHAISCRIPT_COMMON_HPP_
|
#define CHAISCRIPT_COMMON_HPP_
|
||||||
|
|
||||||
@ -22,281 +19,88 @@
|
|||||||
#include "../dispatchkit/dispatchkit.hpp"
|
#include "../dispatchkit/dispatchkit.hpp"
|
||||||
#include "../dispatchkit/proxy_functions.hpp"
|
#include "../dispatchkit/proxy_functions.hpp"
|
||||||
#include "../dispatchkit/type_info.hpp"
|
#include "../dispatchkit/type_info.hpp"
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
struct AST_Node;
|
struct AST_Node;
|
||||||
} // namespace chaiscript
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript
|
||||||
struct Name_Validator {
|
{
|
||||||
template<typename T>
|
|
||||||
static bool is_reserved_word(const T &s) noexcept {
|
|
||||||
const static std::unordered_set<std::uint32_t>
|
|
||||||
words{utility::hash("def"), utility::hash("fun"), utility::hash("while"), utility::hash("for"), utility::hash("if"), utility::hash("else"), utility::hash("&&"), utility::hash("||"), utility::hash(","), utility::hash("auto"), utility::hash("return"), utility::hash("break"), utility::hash("true"), utility::hash("false"), utility::hash("class"), utility::hash("attr"), utility::hash("var"), utility::hash("global"), utility::hash("GLOBAL"), utility::hash("_"), utility::hash("__LINE__"), utility::hash("__FILE__"), utility::hash("__FUNC__"), utility::hash("__CLASS__"), utility::hash("const"), utility::hash("using"), utility::hash("enum")};
|
|
||||||
|
|
||||||
return words.count(utility::hash(s)) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static bool valid_object_name(const T &name) noexcept {
|
|
||||||
return name.find("::") == std::string::npos && !is_reserved_word(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static void validate_object_name(const T &name) {
|
|
||||||
if (is_reserved_word(name)) {
|
|
||||||
throw exception::reserved_word_error(std::string(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name.find("::") != std::string::npos) {
|
|
||||||
throw exception::illegal_name_error(std::string(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Signature of module entry point that all binary loadable modules must implement.
|
/// Signature of module entry point that all binary loadable modules must implement.
|
||||||
using Create_Module_Func = ModulePtr (*)();
|
typedef ModulePtr (*Create_Module_Func)();
|
||||||
|
|
||||||
|
|
||||||
/// Types of AST nodes available to the parser and eval
|
/// Types of AST nodes available to the parser and eval
|
||||||
enum class AST_Node_Type {
|
class AST_Node_Type {
|
||||||
Id,
|
public:
|
||||||
Fun_Call,
|
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||||
Unused_Return_Fun_Call,
|
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||||
Arg_List,
|
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||||
Equation,
|
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||||
Var_Decl,
|
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl
|
||||||
Assign_Decl,
|
};
|
||||||
Array_Call,
|
|
||||||
Dot_Access,
|
|
||||||
Lambda,
|
|
||||||
Block,
|
|
||||||
Scopeless_Block,
|
|
||||||
Def,
|
|
||||||
While,
|
|
||||||
If,
|
|
||||||
For,
|
|
||||||
Ranged_For,
|
|
||||||
Inline_Array,
|
|
||||||
Inline_Map,
|
|
||||||
Return,
|
|
||||||
File,
|
|
||||||
Prefix,
|
|
||||||
Break,
|
|
||||||
Continue,
|
|
||||||
Map_Pair,
|
|
||||||
Value_Range,
|
|
||||||
Inline_Range,
|
|
||||||
Try,
|
|
||||||
Catch,
|
|
||||||
Finally,
|
|
||||||
Method,
|
|
||||||
Attr_Decl,
|
|
||||||
Logical_And,
|
|
||||||
Logical_Or,
|
|
||||||
Reference,
|
|
||||||
Switch,
|
|
||||||
Case,
|
|
||||||
Default,
|
|
||||||
Noop,
|
|
||||||
Class,
|
|
||||||
Binary,
|
|
||||||
Arg,
|
|
||||||
Global_Decl,
|
|
||||||
Constant,
|
|
||||||
Compiled,
|
|
||||||
Const_Var_Decl,
|
|
||||||
Const_Assign_Decl,
|
|
||||||
Using,
|
|
||||||
Enum,
|
|
||||||
Namespace_Block
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Operator_Precedence {
|
namespace
|
||||||
Ternary_Cond,
|
{
|
||||||
Logical_Or,
|
|
||||||
Logical_And,
|
|
||||||
Bitwise_Or,
|
|
||||||
Bitwise_Xor,
|
|
||||||
Bitwise_And,
|
|
||||||
Equality,
|
|
||||||
Comparison,
|
|
||||||
Shift,
|
|
||||||
Addition,
|
|
||||||
Multiplication,
|
|
||||||
Prefix
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
/// Helper lookup to get the name of each node type
|
/// Helper lookup to get the name of each node type
|
||||||
constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept {
|
const char *ast_node_type_to_string(int ast_node_type) {
|
||||||
constexpr std::array ast_node_types = {"Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled", "Const_Var_Decl", "Const_Assign_Decl", "Using", "Enum", "Namespace_Block"};
|
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||||
|
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||||
|
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
||||||
|
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||||
|
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
|
||||||
|
|
||||||
return ast_node_types[static_cast<std::size_t>(ast_node_type)];
|
return ast_node_types[ast_node_type];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
/// \brief Convenience type for file positions
|
/// \brief Convenience type for file positions
|
||||||
struct File_Position {
|
struct File_Position {
|
||||||
int line = 0;
|
int line;
|
||||||
int column = 0;
|
int column;
|
||||||
|
|
||||||
constexpr File_Position(int t_file_line, int t_file_column) noexcept
|
File_Position(int t_file_line, int t_file_column)
|
||||||
: line(t_file_line)
|
: line(t_file_line), column(t_file_column) { }
|
||||||
, column(t_file_column) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr File_Position() noexcept = default;
|
File_Position() : line(0), column(0) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Parse_Location {
|
struct Parse_Location {
|
||||||
Parse_Location(std::string t_fname = "", const int t_start_line = 0, const int t_start_col = 0, const int t_end_line = 0, const int t_end_col = 0)
|
Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0,
|
||||||
: start(t_start_line, t_start_col)
|
const int t_end_line=0, const int t_end_col=0)
|
||||||
, end(t_end_line, t_end_col)
|
: start(t_start_line, t_start_col),
|
||||||
, filename(std::make_shared<std::string>(std::move(t_fname))) {
|
end(t_end_line, t_end_col),
|
||||||
|
filename(std::make_shared<std::string>(std::move(t_fname)))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Parse_Location(std::shared_ptr<std::string> t_fname,
|
Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0,
|
||||||
const int t_start_line = 0,
|
const int t_end_line=0, const int t_end_col=0)
|
||||||
const int t_start_col = 0,
|
: start(t_start_line, t_start_col),
|
||||||
const int t_end_line = 0,
|
end(t_end_line, t_end_col),
|
||||||
const int t_end_col = 0)
|
filename(std::move(t_fname))
|
||||||
: start(t_start_line, t_start_col)
|
{
|
||||||
, end(t_end_line, t_end_col)
|
|
||||||
, filename(std::move(t_fname)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
File_Position start;
|
File_Position start;
|
||||||
File_Position end;
|
File_Position end;
|
||||||
std::shared_ptr<std::string> filename;
|
std::shared_ptr<std::string> filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
|
||||||
struct AST_Node {
|
|
||||||
public:
|
|
||||||
const AST_Node_Type identifier;
|
|
||||||
const std::string text;
|
|
||||||
Parse_Location location;
|
|
||||||
|
|
||||||
const std::string &filename() const noexcept { return *location.filename; }
|
|
||||||
|
|
||||||
const File_Position &start() const noexcept { return location.start; }
|
|
||||||
|
|
||||||
const File_Position &end() const noexcept { return location.end; }
|
|
||||||
|
|
||||||
std::string pretty_print() const {
|
|
||||||
std::ostringstream oss;
|
|
||||||
|
|
||||||
oss << text;
|
|
||||||
|
|
||||||
for (auto &elem : get_children()) {
|
|
||||||
oss << elem.get().pretty_print() << ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::vector<std::reference_wrapper<AST_Node>> get_children() const = 0;
|
|
||||||
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
|
|
||||||
|
|
||||||
/// Prints the contents of an AST node, including its children, recursively
|
|
||||||
std::string to_string(const std::string &t_prepend = "") const {
|
|
||||||
std::ostringstream oss;
|
|
||||||
|
|
||||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") " << this->text << " : " << this->location.start.line
|
|
||||||
<< ", " << this->location.start.column << '\n';
|
|
||||||
|
|
||||||
for (auto &elem : get_children()) {
|
|
||||||
oss << elem.get().to_string(t_prepend + " ");
|
|
||||||
}
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss);
|
|
||||||
|
|
||||||
virtual ~AST_Node() noexcept = default;
|
|
||||||
AST_Node(AST_Node &&) = default;
|
|
||||||
AST_Node &operator=(AST_Node &&) = delete;
|
|
||||||
AST_Node(const AST_Node &) = delete;
|
|
||||||
AST_Node &operator=(const AST_Node &) = delete;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
|
|
||||||
: identifier(t_id)
|
|
||||||
, text(std::move(t_ast_node_text))
|
|
||||||
, location(std::move(t_loc)) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
|
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
|
||||||
using AST_NodePtr = std::unique_ptr<AST_Node>;
|
typedef std::shared_ptr<AST_Node> AST_NodePtr;
|
||||||
using AST_NodePtr_Const = std::unique_ptr<const AST_Node>;
|
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
|
||||||
|
|
||||||
struct AST_Node_Trace {
|
|
||||||
const AST_Node_Type identifier;
|
|
||||||
const std::string text;
|
|
||||||
Parse_Location location;
|
|
||||||
|
|
||||||
const std::string &filename() const noexcept { return *location.filename; }
|
|
||||||
|
|
||||||
const File_Position &start() const noexcept { return location.start; }
|
|
||||||
|
|
||||||
const File_Position &end() const noexcept { return location.end; }
|
|
||||||
|
|
||||||
std::string pretty_print() const {
|
|
||||||
std::ostringstream oss;
|
|
||||||
|
|
||||||
oss << text;
|
|
||||||
|
|
||||||
for (const auto &elem : children) {
|
|
||||||
oss << elem.pretty_print() << ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<AST_Node_Trace> get_children(const AST_Node &node) {
|
|
||||||
const auto node_children = node.get_children();
|
|
||||||
return std::vector<AST_Node_Trace>(node_children.begin(), node_children.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
AST_Node_Trace(const AST_Node &node)
|
|
||||||
: identifier(node.identifier)
|
|
||||||
, text(node.text)
|
|
||||||
, location(node.location)
|
|
||||||
, children(get_children(node)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<AST_Node_Trace> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
||||||
namespace exception {
|
namespace exception
|
||||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
{
|
||||||
struct load_module_error : std::runtime_error {
|
|
||||||
explicit load_module_error(const std::string &t_reason)
|
|
||||||
: std::runtime_error(t_reason) {
|
|
||||||
}
|
|
||||||
|
|
||||||
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
|
|
||||||
: std::runtime_error(format_error(t_name, t_errors)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
load_module_error(const load_module_error &) = default;
|
|
||||||
~load_module_error() noexcept override = default;
|
|
||||||
|
|
||||||
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors) {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "Error loading module '" << t_name << "'\n"
|
|
||||||
<< " The following locations were searched:\n";
|
|
||||||
|
|
||||||
for (const auto &err : t_errors) {
|
|
||||||
ss << " " << err.what() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Errors generated during parsing or evaluation
|
/// Errors generated during parsing or evaluation
|
||||||
struct eval_error : std::runtime_error {
|
struct eval_error : std::runtime_error {
|
||||||
@ -304,57 +108,50 @@ namespace chaiscript {
|
|||||||
File_Position start_position;
|
File_Position start_position;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string detail;
|
std::string detail;
|
||||||
std::vector<AST_Node_Trace> call_stack;
|
std::vector<AST_NodePtr_Const> call_stack;
|
||||||
|
|
||||||
|
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
||||||
|
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||||
|
bool t_dot_notation,
|
||||||
|
const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
|
||||||
|
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
|
||||||
|
reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
|
||||||
|
{}
|
||||||
|
|
||||||
eval_error(const std::string &t_why,
|
eval_error(const std::string &t_why,
|
||||||
const File_Position &t_where,
|
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||||
const std::string &t_fname,
|
|
||||||
const std::vector<Boxed_Value> &t_parameters,
|
|
||||||
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
|
||||||
bool t_dot_notation,
|
bool t_dot_notation,
|
||||||
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
|
const chaiscript::detail::Dispatch_Engine &t_ss) CHAISCRIPT_NOEXCEPT :
|
||||||
: std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss))
|
std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss)),
|
||||||
, reason(t_why)
|
reason(t_why), detail(format_detail(t_functions, t_dot_notation, t_ss))
|
||||||
, start_position(t_where)
|
{}
|
||||||
, filename(t_fname)
|
|
||||||
, detail(format_detail(t_functions, t_dot_notation, t_ss)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
eval_error(const std::string &t_why,
|
|
||||||
const std::vector<Boxed_Value> &t_parameters,
|
|
||||||
const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
|
||||||
bool t_dot_notation,
|
|
||||||
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept
|
|
||||||
: std::runtime_error(format(t_why, t_parameters, t_dot_notation, t_ss))
|
|
||||||
, reason(t_why)
|
|
||||||
, detail(format_detail(t_functions, t_dot_notation, t_ss)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept
|
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) CHAISCRIPT_NOEXCEPT :
|
||||||
: std::runtime_error(format(t_why, t_where, t_fname))
|
std::runtime_error(format(t_why, t_where, t_fname)),
|
||||||
, reason(t_why)
|
reason(t_why), start_position(t_where), filename(t_fname)
|
||||||
, start_position(t_where)
|
{}
|
||||||
, filename(t_fname) {
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit eval_error(const std::string &t_why) noexcept
|
eval_error(const std::string &t_why) CHAISCRIPT_NOEXCEPT
|
||||||
: std::runtime_error("Error: \"" + t_why + "\" ")
|
: std::runtime_error("Error: \"" + t_why + "\" "),
|
||||||
, reason(t_why) {
|
reason(t_why)
|
||||||
}
|
{}
|
||||||
|
|
||||||
eval_error(const eval_error &) = default;
|
eval_error(const eval_error &) = default;
|
||||||
|
|
||||||
std::string pretty_print() const {
|
std::string pretty_print() const
|
||||||
|
{
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
||||||
ss << what();
|
ss << what();
|
||||||
if (!call_stack.empty()) {
|
if (call_stack.size() > 0) {
|
||||||
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
|
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
|
||||||
ss << '\n'
|
ss << '\n' << detail << '\n';
|
||||||
<< detail << '\n';
|
|
||||||
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
|
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
|
||||||
for (size_t j = 1; j < call_stack.size(); ++j) {
|
for (size_t j = 1; j < call_stack.size(); ++j) {
|
||||||
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block && id(call_stack[j]) != chaiscript::AST_Node_Type::File) {
|
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
|
||||||
|
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
|
||||||
|
{
|
||||||
ss << '\n';
|
ss << '\n';
|
||||||
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
|
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
|
||||||
}
|
}
|
||||||
@ -364,42 +161,54 @@ namespace chaiscript {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
~eval_error() noexcept override = default;
|
virtual ~eval_error() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static AST_Node_Type id(const T &t) noexcept {
|
static int id(const T& t)
|
||||||
return t.identifier;
|
{
|
||||||
|
return t->identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string pretty(const T &t) {
|
static std::string pretty(const T& t)
|
||||||
return t.pretty_print();
|
{
|
||||||
|
return t->pretty_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static const std::string &fname(const T &t) noexcept {
|
static const std::string &fname(const T& t)
|
||||||
return t.filename();
|
{
|
||||||
|
return t->filename();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string startpos(const T &t) {
|
static std::string startpos(const T& t)
|
||||||
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << t.start().line << ", " << t.start().column;
|
oss << t->start().line << ", " << t->start().column;
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format_why(const std::string &t_why) { return "Error: \"" + t_why + "\""; }
|
static std::string format_why(const std::string &t_why)
|
||||||
|
{
|
||||||
|
return "Error: \"" + t_why + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
static std::string format_types(const Const_Proxy_Function &t_func, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) {
|
static std::string format_types(const Const_Proxy_Function &t_func,
|
||||||
assert(t_func);
|
bool t_dot_notation,
|
||||||
|
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||||
|
{
|
||||||
int arity = t_func->get_arity();
|
int arity = t_func->get_arity();
|
||||||
std::vector<Type_Info> types = t_func->get_param_types();
|
std::vector<Type_Info> types = t_func->get_param_types();
|
||||||
|
|
||||||
std::string retval;
|
std::string retval;
|
||||||
if (arity == -1) {
|
if (arity == -1)
|
||||||
|
{
|
||||||
retval = "(...)";
|
retval = "(...)";
|
||||||
if (t_dot_notation) {
|
if (t_dot_notation)
|
||||||
|
{
|
||||||
retval = "(Object)." + retval;
|
retval = "(Object)." + retval;
|
||||||
}
|
}
|
||||||
} else if (types.size() <= 1) {
|
} else if (types.size() <= 1) {
|
||||||
@ -410,13 +219,18 @@ namespace chaiscript {
|
|||||||
|
|
||||||
std::string paramstr;
|
std::string paramstr;
|
||||||
|
|
||||||
for (size_t index = 1; index != types.size(); ++index) {
|
for (size_t index = 1;
|
||||||
|
index != types.size();
|
||||||
|
++index)
|
||||||
|
{
|
||||||
paramstr += (types[index].is_const()?"const ":"");
|
paramstr += (types[index].is_const()?"const ":"");
|
||||||
paramstr += t_ss.get_type_name(types[index]);
|
paramstr += t_ss.get_type_name(types[index]);
|
||||||
|
|
||||||
if (index == 1 && t_dot_notation) {
|
if (index == 1 && t_dot_notation)
|
||||||
|
{
|
||||||
paramstr += ").(";
|
paramstr += ").(";
|
||||||
if (types.size() == 2) {
|
if (types.size() == 2)
|
||||||
|
{
|
||||||
paramstr += ", ";
|
paramstr += ", ";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -430,15 +244,19 @@ namespace chaiscript {
|
|||||||
retval = ss.str();
|
retval = ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
|
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfun
|
||||||
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
|
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_func);
|
||||||
|
|
||||||
if (dynfun && dynfun->has_parse_tree()) {
|
if (dynfun)
|
||||||
|
{
|
||||||
Proxy_Function f = dynfun->get_guard();
|
Proxy_Function f = dynfun->get_guard();
|
||||||
|
|
||||||
if (f) {
|
if (f)
|
||||||
|
{
|
||||||
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
||||||
if (dynfunguard && dynfunguard->has_parse_tree()) {
|
if (dynfunguard)
|
||||||
|
{
|
||||||
retval += " : " + format_guard(dynfunguard->get_parse_tree());
|
retval += " : " + format_guard(dynfunguard->get_parse_tree());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -450,50 +268,69 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string format_guard(const T &t) {
|
static std::string format_guard(const T &t)
|
||||||
return t.pretty_print();
|
{
|
||||||
|
return t->pretty_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static std::string format_location(const T &t) {
|
static std::string format_location(const T &t)
|
||||||
|
{
|
||||||
|
if (t) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "(" << t.filename() << " " << t.start().line << ", " << t.start().column << ")";
|
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
|
} else {
|
||||||
|
return "(internal)";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
static std::string format_detail(const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||||
bool t_dot_notation,
|
bool t_dot_notation,
|
||||||
const chaiscript::detail::Dispatch_Engine &t_ss) {
|
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||||
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
if (t_functions.size() == 1) {
|
if (t_functions.size() == 1)
|
||||||
assert(t_functions[0]);
|
{
|
||||||
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
|
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
|
||||||
} else {
|
} else {
|
||||||
ss << " " << t_functions.size() << " overloads available:\n";
|
ss << " " << t_functions.size() << " overloads available:\n";
|
||||||
|
|
||||||
for (const auto &t_function : t_functions) {
|
for (const auto & t_function : t_functions)
|
||||||
|
{
|
||||||
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
|
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string
|
static std::string format_parameters(const std::vector<Boxed_Value> &t_parameters,
|
||||||
format_parameters(const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss) {
|
bool t_dot_notation,
|
||||||
|
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||||
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "(";
|
ss << "(";
|
||||||
|
|
||||||
if (!t_parameters.empty()) {
|
if (!t_parameters.empty())
|
||||||
|
{
|
||||||
std::string paramstr;
|
std::string paramstr;
|
||||||
|
|
||||||
for (auto itr = t_parameters.begin(); itr != t_parameters.end(); ++itr) {
|
for (auto itr = t_parameters.begin();
|
||||||
|
itr != t_parameters.end();
|
||||||
|
++itr)
|
||||||
|
{
|
||||||
paramstr += (itr->is_const()?"const ":"");
|
paramstr += (itr->is_const()?"const ":"");
|
||||||
paramstr += t_ss.type_name(*itr);
|
paramstr += t_ss.type_name(*itr);
|
||||||
|
|
||||||
if (itr == t_parameters.begin() && t_dot_notation) {
|
if (itr == t_parameters.begin() && t_dot_notation)
|
||||||
|
{
|
||||||
paramstr += ").(";
|
paramstr += ").(";
|
||||||
if (t_parameters.size() == 1) {
|
if (t_parameters.size() == 1)
|
||||||
|
{
|
||||||
paramstr += ", ";
|
paramstr += ", ";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -508,10 +345,12 @@ namespace chaiscript {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format_filename(const std::string &t_fname) {
|
static std::string format_filename(const std::string &t_fname)
|
||||||
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
if (t_fname != "__EVAL__") {
|
if (t_fname != "__EVAL__")
|
||||||
|
{
|
||||||
ss << "in '" << t_fname << "' ";
|
ss << "in '" << t_fname << "' ";
|
||||||
} else {
|
} else {
|
||||||
ss << "during evaluation ";
|
ss << "during evaluation ";
|
||||||
@ -520,18 +359,16 @@ namespace chaiscript {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format_location(const File_Position &t_where) {
|
static std::string format_location(const File_Position &t_where)
|
||||||
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "at (" << t_where.line << ", " << t_where.column << ")";
|
ss << "at (" << t_where.line << ", " << t_where.column << ")";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format(const std::string &t_why,
|
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
||||||
const File_Position &t_where,
|
const std::vector<Boxed_Value> &t_parameters, bool t_dot_notation, const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||||
const std::string &t_fname,
|
{
|
||||||
const std::vector<Boxed_Value> &t_parameters,
|
|
||||||
bool t_dot_notation,
|
|
||||||
const chaiscript::detail::Dispatch_Engine &t_ss) {
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
ss << format_why(t_why);
|
ss << format_why(t_why);
|
||||||
@ -551,7 +388,8 @@ namespace chaiscript {
|
|||||||
static std::string format(const std::string &t_why,
|
static std::string format(const std::string &t_why,
|
||||||
const std::vector<Boxed_Value> &t_parameters,
|
const std::vector<Boxed_Value> &t_parameters,
|
||||||
bool t_dot_notation,
|
bool t_dot_notation,
|
||||||
const chaiscript::detail::Dispatch_Engine &t_ss) {
|
const chaiscript::detail::Dispatch_Engine &t_ss)
|
||||||
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
ss << format_why(t_why);
|
ss << format_why(t_why);
|
||||||
@ -563,7 +401,8 @@ namespace chaiscript {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) {
|
static std::string format(const std::string &t_why, const File_Position &t_where, const std::string &t_fname)
|
||||||
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
ss << format_why(t_why);
|
ss << format_why(t_why);
|
||||||
@ -578,125 +417,218 @@ namespace chaiscript {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Errors generated when loading a file
|
/// Errors generated when loading a file
|
||||||
struct file_not_found_error : std::runtime_error {
|
struct file_not_found_error : std::runtime_error {
|
||||||
explicit file_not_found_error(const std::string &t_filename)
|
file_not_found_error(const std::string &t_filename) CHAISCRIPT_NOEXCEPT
|
||||||
: std::runtime_error("File Not Found: " + t_filename)
|
: std::runtime_error("File Not Found: " + t_filename)
|
||||||
, filename(t_filename) {
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
file_not_found_error(const file_not_found_error &) = default;
|
file_not_found_error(const file_not_found_error &) = default;
|
||||||
~file_not_found_error() noexcept override = default;
|
virtual ~file_not_found_error() CHAISCRIPT_NOEXCEPT {}
|
||||||
|
|
||||||
std::string filename;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace exception
|
}
|
||||||
|
|
||||||
// static
|
|
||||||
bool AST_Node::get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
|
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||||
|
struct AST_Node : std::enable_shared_from_this<AST_Node> {
|
||||||
|
public:
|
||||||
|
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
|
||||||
|
const std::string text;
|
||||||
|
Parse_Location location;
|
||||||
|
std::vector<AST_NodePtr> children;
|
||||||
|
AST_NodePtr annotation;
|
||||||
|
|
||||||
|
const std::string &filename() const {
|
||||||
|
return *location.filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
const File_Position &start() const {
|
||||||
|
return location.start;
|
||||||
|
}
|
||||||
|
|
||||||
|
const File_Position &end() const {
|
||||||
|
return location.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string pretty_print() const
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
|
||||||
|
oss << text;
|
||||||
|
|
||||||
|
for (auto & elem : this->children) {
|
||||||
|
oss << elem->pretty_print();
|
||||||
|
}
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Prints the contents of an AST node, including its children, recursively
|
||||||
|
std::string to_string(const std::string &t_prepend = "") const {
|
||||||
|
std::ostringstream oss;
|
||||||
|
|
||||||
|
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||||
|
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
|
||||||
|
|
||||||
|
for (auto & elem : this->children) {
|
||||||
|
oss << elem->to_string(t_prepend + " ");
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
return t_ss->boxed_cast<bool>(t_bv);
|
return eval_internal(t_e);
|
||||||
} catch (const exception::bad_boxed_cast &) {
|
} catch (exception::eval_error &ee) {
|
||||||
|
ee.call_stack.push_back(shared_from_this());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_bool_condition(const Boxed_Value &t_bv) {
|
||||||
|
try {
|
||||||
|
return boxed_cast<bool>(t_bv);
|
||||||
|
}
|
||||||
|
catch (const exception::bad_boxed_cast &) {
|
||||||
throw exception::eval_error("Condition not boolean");
|
throw exception::eval_error("Condition not boolean");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace parser {
|
|
||||||
class ChaiScript_Parser_Base {
|
|
||||||
public:
|
|
||||||
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
|
|
||||||
virtual void debug_print(const AST_Node &t, std::string prepend = "") const = 0;
|
|
||||||
virtual void *get_tracer_ptr() = 0;
|
|
||||||
virtual ~ChaiScript_Parser_Base() = default;
|
|
||||||
ChaiScript_Parser_Base() = default;
|
|
||||||
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
|
|
||||||
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
|
|
||||||
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
|
|
||||||
|
|
||||||
template<typename T>
|
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
|
||||||
T &get_tracer() noexcept {
|
{
|
||||||
// to do type check this somehow?
|
std::replace(children.begin(), children.end(), t_child, t_new_child);
|
||||||
return *static_cast<T *>(get_tracer_ptr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
virtual ~AST_Node() {}
|
||||||
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
|
|
||||||
};
|
|
||||||
} // namespace parser
|
|
||||||
|
|
||||||
namespace eval {
|
protected:
|
||||||
namespace detail {
|
AST_Node(std::string t_ast_node_text, int t_id, Parse_Location t_loc,
|
||||||
|
std::vector<AST_NodePtr> t_children = std::vector<AST_NodePtr>()) :
|
||||||
|
identifier(t_id), text(std::move(t_ast_node_text)),
|
||||||
|
location(std::move(t_loc)),
|
||||||
|
children(std::move(t_children))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Undispatched ast_node (internal error)");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Copy and assignment explicitly unimplemented
|
||||||
|
AST_Node(const AST_Node &) = delete;
|
||||||
|
AST_Node& operator=(const AST_Node &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace eval
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
/// Special type for returned values
|
/// Special type for returned values
|
||||||
struct Return_Value {
|
struct Return_Value {
|
||||||
Boxed_Value retval;
|
Boxed_Value retval;
|
||||||
|
|
||||||
|
Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Special type indicating a call to 'break'
|
/// Special type indicating a call to 'break'
|
||||||
struct Break_Loop {
|
struct Break_Loop {
|
||||||
|
Break_Loop() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Special type indicating a call to 'continue'
|
/// Special type indicating a call to 'continue'
|
||||||
struct Continue_Loop {
|
struct Continue_Loop {
|
||||||
|
Continue_Loop() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Creates a new scope then pops it on destruction
|
/// Creates a new scope then pops it on destruction
|
||||||
struct Scope_Push_Pop {
|
struct Scope_Push_Pop
|
||||||
Scope_Push_Pop(Scope_Push_Pop &&) = default;
|
{
|
||||||
Scope_Push_Pop &operator=(Scope_Push_Pop &&) = delete;
|
|
||||||
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
||||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
||||||
|
|
||||||
explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||||
: m_ds(t_ds) {
|
: m_ds(t_ds)
|
||||||
m_ds->new_scope(m_ds.stack_holder());
|
{
|
||||||
|
m_ds.get()->new_scope(m_ds.get().stack_holder());
|
||||||
|
}
|
||||||
|
|
||||||
|
~Scope_Push_Pop()
|
||||||
|
{
|
||||||
|
m_ds.get()->pop_scope(m_ds.get().stack_holder());
|
||||||
}
|
}
|
||||||
|
|
||||||
~Scope_Push_Pop() { m_ds->pop_scope(m_ds.stack_holder()); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const chaiscript::detail::Dispatch_State &m_ds;
|
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates a new function call and pops it on destruction
|
/// Creates a new function call and pops it on destruction
|
||||||
struct Function_Push_Pop {
|
struct Function_Push_Pop
|
||||||
Function_Push_Pop(Function_Push_Pop &&) = default;
|
{
|
||||||
Function_Push_Pop &operator=(Function_Push_Pop &&) = delete;
|
|
||||||
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
||||||
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
||||||
|
|
||||||
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||||
: m_ds(t_ds) {
|
: m_ds(t_ds)
|
||||||
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
{
|
||||||
|
m_ds.get()->new_function_call(m_ds.get().stack_holder());
|
||||||
}
|
}
|
||||||
|
|
||||||
~Function_Push_Pop() { m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves()); }
|
~Function_Push_Pop()
|
||||||
|
{
|
||||||
|
m_ds.get()->pop_function_call(m_ds.get().stack_holder());
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||||
|
{
|
||||||
|
m_ds.get()->save_function_params(t_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||||
|
{
|
||||||
|
m_ds.get()->save_function_params(std::move(t_params));
|
||||||
|
}
|
||||||
|
|
||||||
void save_params(const Function_Params &t_params) { m_ds->save_function_params(t_params); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const chaiscript::detail::Dispatch_State &m_ds;
|
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates a new scope then pops it on destruction
|
/// Creates a new scope then pops it on destruction
|
||||||
struct Stack_Push_Pop {
|
struct Stack_Push_Pop
|
||||||
Stack_Push_Pop(Stack_Push_Pop &&) = default;
|
{
|
||||||
Stack_Push_Pop &operator=(Stack_Push_Pop &&) = delete;
|
|
||||||
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
||||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
||||||
|
|
||||||
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||||
: m_ds(t_ds) {
|
: m_ds(t_ds)
|
||||||
m_ds->new_stack(m_ds.stack_holder());
|
{
|
||||||
|
m_ds.get()->new_stack(m_ds.get().stack_holder());
|
||||||
|
}
|
||||||
|
|
||||||
|
~Stack_Push_Pop()
|
||||||
|
{
|
||||||
|
m_ds.get()->pop_stack(m_ds.get().stack_holder());
|
||||||
}
|
}
|
||||||
|
|
||||||
~Stack_Push_Pop() { m_ds->pop_stack(m_ds.stack_holder()); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const chaiscript::detail::Dispatch_State &m_ds;
|
std::reference_wrapper<const chaiscript::detail::Dispatch_State> m_ds;
|
||||||
};
|
};
|
||||||
} // namespace detail
|
}
|
||||||
} // namespace eval
|
}
|
||||||
} // namespace chaiscript
|
}
|
||||||
|
|
||||||
#endif /* _CHAISCRIPT_COMMON_HPP */
|
#endif /* _CHAISCRIPT_COMMON_HPP */
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,443 +0,0 @@
|
|||||||
// This file is distributed under the BSD License.
|
|
||||||
// See "license.txt" for details.
|
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
|
||||||
// http://www.chaiscript.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
|
|
||||||
#define CHAISCRIPT_OPTIMIZER_HPP_
|
|
||||||
|
|
||||||
#include "chaiscript_eval.hpp"
|
|
||||||
|
|
||||||
namespace chaiscript {
|
|
||||||
namespace optimizer {
|
|
||||||
template<typename... T>
|
|
||||||
struct Optimizer : T... {
|
|
||||||
Optimizer() = default;
|
|
||||||
explicit Optimizer(T... t)
|
|
||||||
: T(std::move(t))... {
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Tracer>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
|
|
||||||
((p = static_cast<T &>(*this).optimize(std::move(p))), ...);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
|
|
||||||
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
|
|
||||||
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
|
|
||||||
} else {
|
|
||||||
return *node.children[offset];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
|
|
||||||
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
|
|
||||||
return *(dynamic_cast<const eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
|
|
||||||
} else {
|
|
||||||
return *node.children[offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (node->identifier == AST_Node_Type::Compiled) {
|
|
||||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
|
|
||||||
} else {
|
|
||||||
return node->children[offset];
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
auto child_count(const eval::AST_Node_Impl<T> &node) noexcept {
|
|
||||||
if (node.identifier == AST_Node_Type::Compiled) {
|
|
||||||
return dynamic_cast<const eval::Compiled_AST_Node<T> &>(node).m_original_node->children.size();
|
|
||||||
} else {
|
|
||||||
return node.children.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename Callable>
|
|
||||||
auto make_compiled_node(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable) {
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(original_node),
|
|
||||||
std::move(children),
|
|
||||||
std::move(callable));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Return {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> p) {
|
|
||||||
if ((p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda) && !p->children.empty()) {
|
|
||||||
auto &last_child = p->children.back();
|
|
||||||
if (last_child->identifier == AST_Node_Type::Block) {
|
|
||||||
auto &block_last_child = last_child->children.back();
|
|
||||||
if (block_last_child->identifier == AST_Node_Type::Return) {
|
|
||||||
if (block_last_child->children.size() == 1) {
|
|
||||||
last_child->children.back() = std::move(block_last_child->children[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept {
|
|
||||||
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl
|
|
||||||
|| node.identifier == AST_Node_Type::Const_Var_Decl || node.identifier == AST_Node_Type::Const_Assign_Decl
|
|
||||||
|| node.identifier == AST_Node_Type::Reference) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto num = child_count(node);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < num; ++i) {
|
|
||||||
const auto &child = child_at(node, i);
|
|
||||||
if (child.identifier != AST_Node_Type::Block && child.identifier != AST_Node_Type::For
|
|
||||||
&& child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Block {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
|
||||||
if (node->identifier == AST_Node_Type::Block) {
|
|
||||||
if (!contains_var_decl_in_scope(*node)) {
|
|
||||||
if (node->children.size() == 1) {
|
|
||||||
return std::move(node->children[0]);
|
|
||||||
} else {
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text,
|
|
||||||
node->location,
|
|
||||||
std::move(node->children));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Dead_Code {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
|
||||||
if (node->identifier == AST_Node_Type::Block) {
|
|
||||||
std::vector<size_t> keepers;
|
|
||||||
const auto num_children = node->children.size();
|
|
||||||
keepers.reserve(num_children);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < num_children; ++i) {
|
|
||||||
const auto &child = *node->children[i];
|
|
||||||
if ((child.identifier != AST_Node_Type::Id && child.identifier != AST_Node_Type::Constant
|
|
||||||
&& child.identifier != AST_Node_Type::Noop)
|
|
||||||
|| i == num_children - 1) {
|
|
||||||
keepers.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keepers.size() == num_children) {
|
|
||||||
return node;
|
|
||||||
} else {
|
|
||||||
const auto new_children = [&]() {
|
|
||||||
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
|
|
||||||
for (const auto x : keepers) {
|
|
||||||
retval.push_back(std::move(node->children[x]));
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
};
|
|
||||||
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Unused_Return {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
|
||||||
if ((node->identifier == AST_Node_Type::Block || node->identifier == AST_Node_Type::Scopeless_Block) && !node->children.empty()) {
|
|
||||||
for (size_t i = 0; i < node->children.size() - 1; ++i) {
|
|
||||||
auto child = node->children[i].get();
|
|
||||||
if (child->identifier == AST_Node_Type::Fun_Call) {
|
|
||||||
node->children[i]
|
|
||||||
= chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text,
|
|
||||||
child->location,
|
|
||||||
std::move(child->children));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ((node->identifier == AST_Node_Type::For || node->identifier == AST_Node_Type::While) && child_count(*node) > 0) {
|
|
||||||
auto &child = child_at(*node, child_count(*node) - 1);
|
|
||||||
if (child.identifier == AST_Node_Type::Block || child.identifier == AST_Node_Type::Scopeless_Block) {
|
|
||||||
auto num_sub_children = child_count(child);
|
|
||||||
for (size_t i = 0; i < num_sub_children; ++i) {
|
|
||||||
auto &sub_child = child_at(child, i);
|
|
||||||
if (sub_child.identifier == AST_Node_Type::Fun_Call) {
|
|
||||||
child.children[i] = chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(
|
|
||||||
sub_child.text, sub_child.location, std::move(sub_child.children));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Assign_Decl {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
|
||||||
if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2
|
|
||||||
&& node->children[0]->identifier == AST_Node_Type::Var_Decl) {
|
|
||||||
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
|
|
||||||
new_children.push_back(std::move(node->children[0]->children[0]));
|
|
||||||
new_children.push_back(std::move(node->children[1]));
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
|
|
||||||
node->location,
|
|
||||||
std::move(new_children));
|
|
||||||
} else if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2
|
|
||||||
&& node->children[0]->identifier == AST_Node_Type::Const_Var_Decl) {
|
|
||||||
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
|
|
||||||
new_children.push_back(std::move(node->children[0]->children[0]));
|
|
||||||
new_children.push_back(std::move(node->children[1]));
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Const_Assign_Decl_AST_Node<T>>(node->text,
|
|
||||||
node->location,
|
|
||||||
std::move(new_children));
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct If {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
|
||||||
if ((node->identifier == AST_Node_Type::If) && node->children.size() >= 2 && node->children[0]->identifier == AST_Node_Type::Constant) {
|
|
||||||
const auto condition = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
|
|
||||||
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
|
|
||||||
if (boxed_cast<bool>(condition)) {
|
|
||||||
return std::move(node->children[1]);
|
|
||||||
} else if (node->children.size() == 3) {
|
|
||||||
return std::move(node->children[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Partial_Fold {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
|
||||||
// Fold right side
|
|
||||||
if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2
|
|
||||||
&& node->children[0]->identifier != AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) {
|
|
||||||
try {
|
|
||||||
const auto &oper = node->text;
|
|
||||||
const auto parsed = Operators::to_operator(oper);
|
|
||||||
if (parsed != Operators::Opers::invalid) {
|
|
||||||
const auto rhs = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->m_value;
|
|
||||||
if (rhs.get_type_info().is_arithmetic()) {
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(
|
|
||||||
node->text, node->location, std::move(node->children), rhs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const std::exception &) {
|
|
||||||
// failure to fold, that's OK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Constant_Fold {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
|
||||||
if (node->identifier == AST_Node_Type::Prefix && node->children.size() == 1 && node->children[0]->identifier == AST_Node_Type::Constant) {
|
|
||||||
try {
|
|
||||||
const auto &oper = node->text;
|
|
||||||
const auto parsed = Operators::to_operator(oper, true);
|
|
||||||
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
|
|
||||||
const auto match = oper + node->children[0]->text;
|
|
||||||
|
|
||||||
if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) {
|
|
||||||
const auto val = Boxed_Number::do_oper(parsed, lhs);
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
|
|
||||||
node->location,
|
|
||||||
std::move(val));
|
|
||||||
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
|
|
||||||
node->location,
|
|
||||||
Boxed_Value(!boxed_cast<bool>(lhs)));
|
|
||||||
}
|
|
||||||
} catch (const std::exception &) {
|
|
||||||
// failure to fold, that's OK
|
|
||||||
}
|
|
||||||
} else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or)
|
|
||||||
&& node->children.size() == 2 && node->children[0]->identifier == AST_Node_Type::Constant
|
|
||||||
&& node->children[1]->identifier == AST_Node_Type::Constant) {
|
|
||||||
try {
|
|
||||||
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
|
|
||||||
const auto rhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]).m_value;
|
|
||||||
if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) {
|
|
||||||
const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text;
|
|
||||||
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
|
|
||||||
if (id == AST_Node_Type::Logical_And) {
|
|
||||||
return Boxed_Value(lhs_val && rhs_val);
|
|
||||||
} else {
|
|
||||||
return Boxed_Value(lhs_val || rhs_val);
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
|
|
||||||
node->location,
|
|
||||||
std::move(val));
|
|
||||||
}
|
|
||||||
} catch (const std::exception &) {
|
|
||||||
// failure to fold, that's OK
|
|
||||||
}
|
|
||||||
} else if (node->identifier == AST_Node_Type::Binary && node->children.size() == 2
|
|
||||||
&& node->children[0]->identifier == AST_Node_Type::Constant && node->children[1]->identifier == AST_Node_Type::Constant) {
|
|
||||||
try {
|
|
||||||
const auto &oper = node->text;
|
|
||||||
const auto parsed = Operators::to_operator(oper);
|
|
||||||
if (parsed != Operators::Opers::invalid) {
|
|
||||||
const auto lhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
|
|
||||||
const auto rhs = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]).m_value;
|
|
||||||
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
|
|
||||||
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
|
|
||||||
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
|
|
||||||
node->location,
|
|
||||||
std::move(val));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const std::exception &) {
|
|
||||||
// failure to fold, that's OK
|
|
||||||
}
|
|
||||||
} else if (node->identifier == AST_Node_Type::Fun_Call && node->children.size() == 2
|
|
||||||
&& node->children[0]->identifier == AST_Node_Type::Id && node->children[1]->identifier == AST_Node_Type::Arg_List
|
|
||||||
&& node->children[1]->children.size() == 1 && node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
|
|
||||||
const auto arg = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[1]->children[0]).m_value;
|
|
||||||
if (arg.get_type_info().is_arithmetic()) {
|
|
||||||
const auto &fun_name = node->children[0]->text;
|
|
||||||
|
|
||||||
const auto make_constant = [&node, &fun_name](auto val) {
|
|
||||||
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
|
|
||||||
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
|
|
||||||
node->location,
|
|
||||||
const_var(val));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (fun_name == "double") {
|
|
||||||
return make_constant(Boxed_Number(arg).get_as<double>());
|
|
||||||
} else if (fun_name == "int") {
|
|
||||||
return make_constant(Boxed_Number(arg).get_as<int>());
|
|
||||||
} else if (fun_name == "float") {
|
|
||||||
return make_constant(Boxed_Number(arg).get_as<float>());
|
|
||||||
} else if (fun_name == "long") {
|
|
||||||
return make_constant(Boxed_Number(arg).get_as<long>());
|
|
||||||
} else if (fun_name == "size_t") {
|
|
||||||
return make_constant(Boxed_Number(arg).get_as<size_t>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct For_Loop {
|
|
||||||
template<typename T>
|
|
||||||
auto optimize(eval::AST_Node_Impl_Ptr<T> for_node) {
|
|
||||||
if (for_node->identifier != AST_Node_Type::For) {
|
|
||||||
return for_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto &eq_node = child_at(*for_node, 0);
|
|
||||||
const auto &binary_node = child_at(*for_node, 1);
|
|
||||||
const auto &prefix_node = child_at(*for_node, 2);
|
|
||||||
|
|
||||||
if (child_count(*for_node) == 4 && eq_node.identifier == AST_Node_Type::Assign_Decl && child_count(eq_node) == 2
|
|
||||||
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id && child_at(eq_node, 1).identifier == AST_Node_Type::Constant
|
|
||||||
&& binary_node.identifier == AST_Node_Type::Binary && binary_node.text == "<" && child_count(binary_node) == 2
|
|
||||||
&& child_at(binary_node, 0).identifier == AST_Node_Type::Id && child_at(binary_node, 0).text == child_at(eq_node, 0).text
|
|
||||||
&& child_at(binary_node, 1).identifier == AST_Node_Type::Constant && prefix_node.identifier == AST_Node_Type::Prefix
|
|
||||||
&& prefix_node.text == "++" && child_count(prefix_node) == 1 && child_at(prefix_node, 0).identifier == AST_Node_Type::Id
|
|
||||||
&& child_at(prefix_node, 0).text == child_at(eq_node, 0).text) {
|
|
||||||
const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value;
|
|
||||||
const Boxed_Value &end = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(binary_node, 1)).m_value;
|
|
||||||
const std::string &id = child_at(prefix_node, 0).text;
|
|
||||||
|
|
||||||
if (begin.get_type_info().bare_equal(user_type<int>()) && end.get_type_info().bare_equal(user_type<int>())) {
|
|
||||||
const auto start_int = boxed_cast<int>(begin);
|
|
||||||
const auto end_int = boxed_cast<int>(end);
|
|
||||||
|
|
||||||
// note that we are moving the last element out, then popping the empty shared_ptr
|
|
||||||
// from the vector
|
|
||||||
std::vector<eval::AST_Node_Impl_Ptr<T>> body_vector;
|
|
||||||
auto body_child = std::move(for_node->children[3]);
|
|
||||||
for_node->children.pop_back();
|
|
||||||
body_vector.emplace_back(std::move(body_child));
|
|
||||||
|
|
||||||
return make_compiled_node(std::move(for_node),
|
|
||||||
std::move(body_vector),
|
|
||||||
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children,
|
|
||||||
const chaiscript::detail::Dispatch_State &t_ss) {
|
|
||||||
assert(children.size() == 1);
|
|
||||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
|
||||||
|
|
||||||
Boxed_Value bv_i(start_int);
|
|
||||||
auto &i = *static_cast<int *>(bv_i.get_ptr());
|
|
||||||
t_ss.add_object(id, bv_i);
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (; i < end_int; ++i) {
|
|
||||||
try {
|
|
||||||
// Body of Loop
|
|
||||||
children[0]->eval(t_ss);
|
|
||||||
} catch (eval::detail::Continue_Loop &) {
|
|
||||||
// we got a continue exception, which means all of the remaining
|
|
||||||
// loop implementation is skipped and we just need to continue to
|
|
||||||
// the next iteration step
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (eval::detail::Break_Loop &) {
|
|
||||||
// loop broken
|
|
||||||
}
|
|
||||||
|
|
||||||
return void_var();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return for_node;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return for_node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using Optimizer_Default = Optimizer<optimizer::Partial_Fold,
|
|
||||||
optimizer::Unused_Return,
|
|
||||||
optimizer::Constant_Fold,
|
|
||||||
optimizer::If,
|
|
||||||
optimizer::Return,
|
|
||||||
optimizer::Dead_Code,
|
|
||||||
optimizer::Block,
|
|
||||||
optimizer::For_Loop,
|
|
||||||
optimizer::Assign_Decl>;
|
|
||||||
|
|
||||||
} // namespace optimizer
|
|
||||||
} // namespace chaiscript
|
|
||||||
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,53 +0,0 @@
|
|||||||
// This file is distributed under the BSD License.
|
|
||||||
// See "license.txt" for details.
|
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
|
||||||
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
|
||||||
// http://www.chaiscript.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_POSIX_HPP_
|
|
||||||
#define CHAISCRIPT_POSIX_HPP_
|
|
||||||
|
|
||||||
namespace chaiscript::detail {
|
|
||||||
struct Loadable_Module {
|
|
||||||
struct DLModule {
|
|
||||||
explicit DLModule(const std::string &t_filename)
|
|
||||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW)) {
|
|
||||||
if (m_data == nullptr) {
|
|
||||||
throw chaiscript::exception::load_module_error(dlerror());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DLModule(DLModule &&) = default;
|
|
||||||
DLModule &operator=(DLModule &&) = default;
|
|
||||||
DLModule(const DLModule &) = delete;
|
|
||||||
DLModule &operator=(const DLModule &) = delete;
|
|
||||||
|
|
||||||
~DLModule() { dlclose(m_data); }
|
|
||||||
|
|
||||||
void *m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct DLSym {
|
|
||||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
|
||||||
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) {
|
|
||||||
if (!m_symbol) {
|
|
||||||
throw chaiscript::exception::load_module_error(dlerror());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
T m_symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
|
||||||
: m_dlmodule(t_filename)
|
|
||||||
, m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
|
|
||||||
, m_moduleptr(m_func.m_symbol()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
DLModule m_dlmodule;
|
|
||||||
DLSym<Create_Module_Func> m_func;
|
|
||||||
ModulePtr m_moduleptr;
|
|
||||||
};
|
|
||||||
} // namespace chaiscript::detail
|
|
||||||
#endif
|
|
||||||
539
include/chaiscript/language/chaiscript_prelude.chai
Normal file
539
include/chaiscript/language/chaiscript_prelude.chai
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// and Jason Turner (jason@emptycrate.com)
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_PRELUDE_HPP_
|
||||||
|
#define CHAISCRIPT_PRELUDE_HPP_
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
struct ChaiScript_Prelude {
|
||||||
|
static std::string chaiscript_prelude() { return R""(
|
||||||
|
|
||||||
|
def lt(l, r) {
|
||||||
|
if (call_exists(`<`, l, r)) {
|
||||||
|
l < r
|
||||||
|
} else {
|
||||||
|
type_name(l) < type_name(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def gt(l, r) {
|
||||||
|
if (call_exists(`>`, l, r)) {
|
||||||
|
l > r
|
||||||
|
} else {
|
||||||
|
type_name(l) > type_name(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def eq(l, r) {
|
||||||
|
if (call_exists(`==`, l, r)) {
|
||||||
|
l == r
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def new(x) {
|
||||||
|
eval(type_name(x))();
|
||||||
|
}
|
||||||
|
|
||||||
|
def clone(double x) {
|
||||||
|
double(x).clone_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
def clone(string x) {
|
||||||
|
string(x).clone_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
def clone(vector x) {
|
||||||
|
vector(x).clone_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def clone(int x) {
|
||||||
|
int(x).clone_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
||||||
|
{
|
||||||
|
eval(type_name(x))(x).clone_var_attrs(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# to_string for Pair()
|
||||||
|
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
|
||||||
|
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
# to_string for containers
|
||||||
|
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
|
||||||
|
"[" + x.join(", ") + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prints to console with no carriage return
|
||||||
|
def puts(x) {
|
||||||
|
print_string(x.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prints to console with carriage return
|
||||||
|
def print(x) {
|
||||||
|
println_string(x.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the maximum value of two numbers
|
||||||
|
def max(a, b) {
|
||||||
|
if (a>b) {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the minimum value of two numbers
|
||||||
|
def min(a, b)
|
||||||
|
{
|
||||||
|
if (a<b)
|
||||||
|
{
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns true if the value is odd
|
||||||
|
def odd(x) {
|
||||||
|
if (x % 2 == 1)
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns true if the value is even
|
||||||
|
def even(x)
|
||||||
|
{
|
||||||
|
if (x % 2 == 0)
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Inserts the third value at the position of the second value into the container of the first
|
||||||
|
# while making a clone.
|
||||||
|
def insert_at(container, pos, x)
|
||||||
|
{
|
||||||
|
container.insert_ref_at(pos, clone(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the reverse of the given container
|
||||||
|
def reverse(container) {
|
||||||
|
auto retval := new(container);
|
||||||
|
auto r := range(container);
|
||||||
|
while (!r.empty()) {
|
||||||
|
retval.push_back(r.back());
|
||||||
|
r.pop_back();
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def range(r) : call_exists(range_internal, r)
|
||||||
|
{
|
||||||
|
var ri := range_internal(r);
|
||||||
|
ri.get_var_attr("internal_obj") := r;
|
||||||
|
ri;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return a range from a range
|
||||||
|
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
|
||||||
|
{
|
||||||
|
clone(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# The retro attribute that contains the underlying range
|
||||||
|
attr retro::m_range;
|
||||||
|
|
||||||
|
# Creates a retro from a retro by returning the original range
|
||||||
|
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
|
||||||
|
{
|
||||||
|
clone(r.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Creates a retro range from a range
|
||||||
|
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
|
||||||
|
{
|
||||||
|
this.m_range = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the first value of a retro
|
||||||
|
def retro::front()
|
||||||
|
{
|
||||||
|
back(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the last value of a retro
|
||||||
|
def retro::back()
|
||||||
|
{
|
||||||
|
front(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Moves the back iterator of a retro towards the front by one
|
||||||
|
def retro::pop_back()
|
||||||
|
{
|
||||||
|
pop_front(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Moves the front iterator of a retro towards the back by one
|
||||||
|
def retro::pop_front()
|
||||||
|
{
|
||||||
|
pop_back(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns true if the retro is out of elements
|
||||||
|
def retro::empty()
|
||||||
|
{
|
||||||
|
empty(this.m_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Performs the second value function over the container first value
|
||||||
|
def for_each(container, func) : call_exists(range, container) {
|
||||||
|
var t_range := range(container);
|
||||||
|
while (!t_range.empty()) {
|
||||||
|
func(t_range.front());
|
||||||
|
t_range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def back_inserter(container) {
|
||||||
|
bind(push_back, container, _);
|
||||||
|
}
|
||||||
|
|
||||||
|
def contains(container, item, compare_func) : call_exists(range, container) {
|
||||||
|
auto t_range := range(container);
|
||||||
|
while (!t_range.empty()) {
|
||||||
|
if ( compare_func(t_range.front(), item) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_range.pop_front();
|
||||||
|
}
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
def contains(container, item) {
|
||||||
|
contains(container, item, eq)
|
||||||
|
}
|
||||||
|
|
||||||
|
def map(container, func, inserter) : call_exists(range, container) {
|
||||||
|
auto range := range(container);
|
||||||
|
while (!range.empty()) {
|
||||||
|
inserter(func(range.front()));
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Performs the second value function over the container first value. Creates a new container with the results
|
||||||
|
def map(container, func) {
|
||||||
|
auto retval := new(container);
|
||||||
|
map(container, func, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Performs the second value function over the container first value. Starts with initial and continues with each element.
|
||||||
|
def foldl(container, func, initial) : call_exists(range, container){
|
||||||
|
auto retval = initial;
|
||||||
|
auto range := range(container);
|
||||||
|
while (!range.empty()) {
|
||||||
|
retval = (func(range.front(), retval));
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the sum of the elements of the given value
|
||||||
|
def sum(container) {
|
||||||
|
foldl(container, `+`, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the product of the elements of the given value
|
||||||
|
def product(container) {
|
||||||
|
foldl(container, `*`, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns a new container with the elements of the first value concatenated with the elements of the second value
|
||||||
|
def concat(x, y) : call_exists(clone, x) {
|
||||||
|
auto retval = x;
|
||||||
|
auto inserter := back_inserter(retval);
|
||||||
|
auto range := range(y);
|
||||||
|
while (!range.empty()) {
|
||||||
|
inserter(range.front());
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def take(container, num, inserter) : call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
auto i = num;
|
||||||
|
while ((i > 0) && (!r.empty())) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given number of elements taken from the container
|
||||||
|
def take(container, num) {
|
||||||
|
auto retval := new(container);
|
||||||
|
take(container, num, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def take_while(container, f, inserter) : call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
while ((!r.empty()) && f(r.front())) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given elements match the second value function
|
||||||
|
def take_while(container, f) {
|
||||||
|
auto retval := new(container);
|
||||||
|
take_while(container, f, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def drop(container, num, inserter) : call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
auto i = num;
|
||||||
|
while ((i > 0) && (!r.empty())) {
|
||||||
|
r.pop_front();
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
while (!r.empty()) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given number of elements dropped from the given container
|
||||||
|
def drop(container, num) {
|
||||||
|
auto retval := new(container);
|
||||||
|
drop(container, num, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def drop_while(container, f, inserter) : call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
while ((!r.empty())&& f(r.front())) {
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
while (!r.empty()) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given elements dropped that match the second value function
|
||||||
|
def drop_while(container, f) {
|
||||||
|
auto retval := new(container);
|
||||||
|
drop_while(container, f, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
|
||||||
|
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
auto retval = r.front();
|
||||||
|
r.pop_front();
|
||||||
|
retval = func(retval, r.front());
|
||||||
|
r.pop_front();
|
||||||
|
while (!r.empty()) {
|
||||||
|
retval = func(retval, r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a string of the elements in container delimited by the second value string
|
||||||
|
def join(container, delim) {
|
||||||
|
auto retval = "";
|
||||||
|
auto range := range(container);
|
||||||
|
if (!range.empty()) {
|
||||||
|
retval += to_string(range.front());
|
||||||
|
range.pop_front();
|
||||||
|
while (!range.empty()) {
|
||||||
|
retval += delim;
|
||||||
|
retval += to_string(range.front());
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def filter(container, f, inserter) : call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
while (!r.empty()) {
|
||||||
|
if (f(r.front())) {
|
||||||
|
inserter(r.front());
|
||||||
|
}
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector which match the second value function
|
||||||
|
def filter(container, f) {
|
||||||
|
auto retval := new(container);
|
||||||
|
filter(container, f, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def generate_range(x, y, inserter) {
|
||||||
|
auto i = x;
|
||||||
|
while (i <= y) {
|
||||||
|
inserter(i);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector which represents the range from the first value to the second value
|
||||||
|
def generate_range(x, y) {
|
||||||
|
auto retval := Vector();
|
||||||
|
generate_range(x,y,back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector with the first value to the second value as its elements
|
||||||
|
def collate(x, y) {
|
||||||
|
return [x, y];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
|
||||||
|
auto r_x := range(x);
|
||||||
|
auto r_y := range(y);
|
||||||
|
while (!r_x.empty() && !r_y.empty()) {
|
||||||
|
inserter(f(r_x.front(), r_y.front()));
|
||||||
|
r_x.pop_front();
|
||||||
|
r_y.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector which joins matching elements of the second and third value with the first value function
|
||||||
|
def zip_with(f, x, y) {
|
||||||
|
auto retval := Vector();
|
||||||
|
zip_with(f,x,y,back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector which joins matching elements of the first and second
|
||||||
|
def zip(x, y) {
|
||||||
|
zip_with(collate, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the position of the second value string in the first value string
|
||||||
|
def string::find(string substr) {
|
||||||
|
find(this, substr, size_t(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the position of last match of the second value string in the first value string
|
||||||
|
def string::rfind(string substr) {
|
||||||
|
rfind(this, substr, size_t(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the position of the first match of elements in the second value string in the first value string
|
||||||
|
def string::find_first_of(string list) {
|
||||||
|
find_first_of(this, list, size_t(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the position of the last match of elements in the second value string in the first value string
|
||||||
|
def string::find_last_of(string list) {
|
||||||
|
find_last_of(this, list, size_t(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the position of the first non-matching element in the second value string in the first value string
|
||||||
|
def string::find_first_not_of(string list) {
|
||||||
|
find_first_not_of(this, list, size_t(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the position of the last non-matching element in the second value string in the first value string
|
||||||
|
def string::find_last_not_of(string list) {
|
||||||
|
find_last_not_of(this, list, size_t(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def string::ltrim() {
|
||||||
|
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def string::rtrim() {
|
||||||
|
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def string::trim() {
|
||||||
|
ltrim(rtrim(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def find(container, value, Function compare_func) : call_exists(range, container) {
|
||||||
|
auto range := range(container);
|
||||||
|
while (!range.empty()) {
|
||||||
|
if (compare_func(range.front(), value)) {
|
||||||
|
return range;
|
||||||
|
} else {
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
range;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def find(container, value) {
|
||||||
|
find(container, value, eq)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
)"";
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CHAISCRIPT_PRELUDE_HPP_ */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user