├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── ci.yml │ └── container.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake ├── GetGitRevisionDescription.cmake ├── GetGitRevisionDescription.cmake.in └── git_sha1.cpp.in ├── context.h ├── docker └── Dockerfile ├── docs ├── Debugger │ ├── README.MD │ ├── control.md │ ├── do-preprocess.md │ ├── error.md │ ├── get-callstack.json │ ├── get-callstack.md │ ├── get-status.json │ ├── get-status.md │ ├── get-variables.json │ ├── get-variables.md │ ├── load-sqf.md │ ├── message.md │ ├── parse-sqf.md │ ├── position.md │ └── set-breakpoint.md ├── PreProcessor │ └── pp.xnf └── config.xbnf ├── icon.png ├── include └── tclap-1.2.2 │ ├── AUTHORS │ ├── COPYING │ ├── INSTALL │ └── include │ ├── Makefile.am │ ├── Makefile.in │ └── tclap │ ├── Arg.h │ ├── ArgException.h │ ├── ArgTraits.h │ ├── CmdLine.h │ ├── CmdLineInterface.h │ ├── CmdLineOutput.h │ ├── Constraint.h │ ├── DocBookOutput.h │ ├── HelpVisitor.h │ ├── IgnoreRestVisitor.h │ ├── Makefile.am │ ├── Makefile.in │ ├── MultiArg.h │ ├── MultiSwitchArg.h │ ├── OptionalUnlabeledTracker.h │ ├── StandardTraits.h │ ├── StdOutput.h │ ├── SwitchArg.h │ ├── UnlabeledMultiArg.h │ ├── UnlabeledValueArg.h │ ├── ValueArg.h │ ├── ValuesConstraint.h │ ├── VersionVisitor.h │ ├── Visitor.h │ ├── XorHandler.h │ ├── ZshCompletionOutput.h │ └── sstream.h ├── sqf-dummy-check ├── delta.sqf ├── gen.sqf └── ops.sqf ├── src ├── ReadMe.md ├── cli │ ├── ReadMe.md │ ├── cli.cpp │ ├── cli.hpp │ ├── colors.h │ ├── interactive_helper.cpp │ ├── interactive_helper.h │ ├── main.cpp │ └── main.h ├── export │ ├── ReadMe.md │ ├── sqfvm.cpp │ └── sqfvm.h ├── fileio │ ├── ReadMe.md │ ├── default.cpp │ └── default.h ├── opcodes │ ├── assign_to.h │ ├── assign_to_local.h │ ├── call_binary.h │ ├── call_nular.h │ ├── call_unary.h │ ├── common.h │ ├── end_statement.h │ ├── get_variable.h │ ├── make_array.h │ └── push.h ├── operators │ ├── ReadMe.md │ ├── d_config.h │ ├── d_group.h │ ├── d_object.h │ ├── d_side.h │ ├── d_text.h │ ├── dlops.cpp │ ├── dlops.h │ ├── dlops_storage.h │ ├── group.cpp │ ├── group.h │ ├── object.cpp │ ├── object.h │ ├── ops.h │ ├── ops_config.cpp │ ├── ops_config.h │ ├── ops_diag.cpp │ ├── ops_diag.h │ ├── ops_dummy_binary.cpp │ ├── ops_dummy_binary.h │ ├── ops_dummy_nular.cpp │ ├── ops_dummy_nular.h │ ├── ops_dummy_unary.cpp │ ├── ops_dummy_unary.h │ ├── ops_generic.cpp │ ├── ops_generic.h │ ├── ops_group.cpp │ ├── ops_group.h │ ├── ops_hashmap.cpp │ ├── ops_hashmap.h │ ├── ops_logic.cpp │ ├── ops_logic.h │ ├── ops_markers.cpp │ ├── ops_markers.h │ ├── ops_math.cpp │ ├── ops_math.h │ ├── ops_namespace.cpp │ ├── ops_namespace.h │ ├── ops_object.cpp │ ├── ops_object.h │ ├── ops_osspecific.cpp │ ├── ops_osspecific.h │ ├── ops_sqfvm.cpp │ ├── ops_sqfvm.h │ ├── ops_string.cpp │ ├── ops_string.h │ ├── ops_text.cpp │ └── ops_text.h ├── parser │ ├── ReadMe.md │ ├── assembly │ │ ├── assembly_parser.cpp │ │ ├── assembly_parser.h │ │ ├── astnode.h │ │ ├── location.hh │ │ ├── parser.output │ │ ├── parser.tab.cc │ │ ├── parser.tab.hh │ │ ├── parser.y │ │ ├── position.hh │ │ ├── stack.hh │ │ └── tokenizer.hpp │ ├── config │ │ ├── config_parser.cpp │ │ ├── config_parser.hpp │ │ ├── location.hh │ │ ├── parser.output │ │ ├── parser.tab.cc │ │ ├── parser.tab.hh │ │ ├── parser.y │ │ ├── position.hh │ │ ├── stack.hh │ │ └── tokenizer.hpp │ ├── pbo │ │ ├── parsepbo.cpp │ │ └── parsepbo.h │ ├── preprocessor │ │ ├── default.cpp │ │ └── default.h │ └── sqf │ │ ├── astnode.hpp │ │ ├── location.hh │ │ ├── parser.output │ │ ├── parser.tab.cc │ │ ├── parser.tab.hh │ │ ├── parser.y │ │ ├── position.hh │ │ ├── sqf_formatter.cpp │ │ ├── sqf_formatter.h │ │ ├── sqf_parser.cpp │ │ ├── sqf_parser.hpp │ │ ├── stack.hh │ │ └── tokenizer.hpp ├── runtime │ ├── ReadMe.md │ ├── confighost.h │ ├── context.h │ ├── d_array.cpp │ ├── d_array.h │ ├── d_boolean.h │ ├── d_code.h │ ├── d_scalar.cpp │ ├── d_scalar.h │ ├── d_string.h │ ├── data.h │ ├── diagnostics │ │ ├── breakpoint.h │ │ ├── d_stacktrace.h │ │ ├── diag_info.h │ │ ├── stacktrace.cpp │ │ └── stacktrace.h │ ├── fileio.cpp │ ├── fileio.h │ ├── frame.cpp │ ├── frame.h │ ├── git_sha1.h │ ├── instruction.h │ ├── instruction_set.h │ ├── logging.cpp │ ├── logging.h │ ├── parser │ │ ├── config.h │ │ ├── preprocessor.cpp │ │ ├── preprocessor.h │ │ └── sqf.h │ ├── runtime.cpp │ ├── runtime.h │ ├── sqfop.h │ ├── type.h │ ├── util.h │ ├── value.h │ ├── value_scope.h │ ├── vec.h │ └── version.h ├── rvutils │ └── pbofile.hpp ├── sqc │ ├── ReadMe.md │ ├── location.hh │ ├── parser.tab.cc │ ├── parser.tab.hh │ ├── parser.y │ ├── position.hh │ ├── sqc_parser.cpp │ ├── sqc_parser.h │ ├── stack.hh │ └── tokenizer.h └── unused │ ├── ReadMe.md │ ├── linting.cpp │ ├── linting.h │ ├── netserver.cpp │ ├── netserver.h │ ├── networking.c │ ├── networking.h │ ├── networking │ ├── messages │ │ └── net_message.h │ ├── nethelper.h │ ├── network_client.cpp │ ├── network_client.h │ ├── network_server.cpp │ ├── network_server.h │ └── streamable.h │ ├── parseassembly.cpp │ ├── parseassembly.h │ ├── parsepbo.cpp │ └── parsepbo.h └── tests ├── CMakeLists.txt ├── ReadMe.md ├── cba ├── .gitignore ├── CMakeLists.txt ├── cba_a3.py └── cba_a3.sqf ├── config.cpp ├── framework.sqf ├── preprocess ├── CMakeLists.txt ├── ReadMe.md ├── backslash.sqf ├── backslash.txt ├── define_macro_callable_0.sqf ├── define_macro_callable_0.txt ├── define_macro_callable_1.sqf └── define_macro_callable_1.txt ├── runTests.sqf └── sqf ├── CMakeLists.txt ├── alive.sqf ├── append.sqf ├── apply.sqf ├── boolean.sqf ├── breakOut.sqf ├── compilation.sqf ├── config.sqf ├── count.sqf ├── deleteAt.sqf ├── deleteRange.sqf ├── diag.sqf ├── distance.sqf ├── distance2d.sqf ├── findIf.sqf ├── forEach.sqf ├── forStep.sqf ├── format.sqf ├── if.sqf ├── in.sqf ├── isEqualTo.sqf ├── isEqualType.sqf ├── isNil.sqf ├── isNotEqualTo.sqf ├── math.sqf ├── matrix.sqf ├── misc.sqf ├── namespace.sqf ├── params.sqf ├── private.sqf ├── select.sqf ├── selectLeader.sqf ├── set.sqf ├── side.sqf ├── splitString.sqf ├── switch.sqf ├── text.sqf ├── trycatchthrow.sqf └── while.sqf /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] Brief Description Of The Bug" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/container.yml: -------------------------------------------------------------------------------- 1 | name: Build Docker container 2 | 3 | on: [ workflow_dispatch ] 4 | 5 | jobs: 6 | build_container: 7 | name: Build container 8 | runs-on: ubuntu-18.04 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - id: string 13 | uses: ASzc/change-string-case-action@v2 14 | with: 15 | string: ${{ github.repository_owner }} 16 | 17 | - name: Build x64 binary 18 | run: mkdir build && cd build && cmake .. && cmake --build . --parallel 2 --target sqfvm 19 | env: 20 | CC: clang 21 | CXX: clang++ 22 | 23 | - name: Sanity check 24 | run: build/sqfvm --version 25 | 26 | - name: Move binary to docker directory 27 | run: mv build/sqfvm docker/ 28 | 29 | - name: Login to GitHub Container Registry 30 | uses: docker/login-action@v1 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GITHUB_TOKEN }} 35 | 36 | - name: Build & push 37 | uses: docker/build-push-action@v2 38 | with: 39 | context: docker 40 | push: true 41 | tags: ghcr.io/${{ steps.string.outputs.lowercase }}/sqfvm:latest 42 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: gcc 3 | 4 | matrix: 5 | include: 6 | - os: linux 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | - gcc-8 13 | - g++-8 14 | env: 15 | - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" 16 | - os: linux 17 | addons: 18 | apt: 19 | sources: 20 | - ubuntu-toolchain-r-test 21 | - llvm-toolchain-trusty-8 22 | packages: 23 | - gcc-8 24 | - g++-8 25 | - clang-8 26 | - lldb-8 27 | - lld-8 28 | - libc++-8-dev 29 | env: 30 | - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" 31 | - os: osx 32 | osx_image: xcode11.6 33 | 34 | before_install: 35 | - eval "${MATRIX_EVAL}" 36 | script: 37 | - cmake . 38 | - make -j4 39 | - ./sqfvm -a --no-execute-print -i tests/runTests.sqf 40 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | * Be excellent to each other 4 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | branches: 3 | only: 4 | - master 5 | clone_folder: c:\projects\vm 6 | image: 7 | - Visual Studio 2017 8 | configuration: 9 | - Release 10 | platform: 11 | - Win32 12 | - x64 13 | skip_tags: true 14 | matrix: 15 | fast_finish: true 16 | 17 | # skip unsupported combinations 18 | init: 19 | - set arch= 20 | - if "%PLATFORM%"=="x64" ( set arch= Win64) 21 | - echo %arch% 22 | - echo %APPVEYOR_BUILD_WORKER_IMAGE% 23 | - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set generator="Visual Studio 15 2017%arch%" ) 24 | - echo %generator% 25 | 26 | before_build: 27 | - cmd: |- 28 | cmake --version 29 | cmake -G %generator% -S . -B build 30 | install: 31 | - git submodule update --init --recursive 32 | build: 33 | project: c:\projects\vm\build\sqfvm.sln 34 | verbosity: minimal 35 | parallel: true 36 | cache: 37 | - build 38 | only_commits: 39 | files: 40 | - CMakeLists.txt 41 | - appveyor.yml 42 | - src/ 43 | - tests/ 44 | test_script: 45 | - cmd: |- 46 | cd c:\projects\vm 47 | .\build\Release\sqfvm.exe -a --no-execute-print -i tests\runTests.sqf 48 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | else() 27 | configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) 28 | file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) 29 | if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") 30 | set(HEAD_HASH "${CMAKE_MATCH_1}") 31 | endif() 32 | endif() 33 | else() 34 | # detached HEAD 35 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 36 | endif() 37 | 38 | if(NOT HEAD_HASH) 39 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 40 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 41 | endif() 42 | -------------------------------------------------------------------------------- /cmake/git_sha1.cpp.in: -------------------------------------------------------------------------------- 1 | #define GIT_SHA1 "@GIT_SHA1@" 2 | extern const char g_GIT_SHA1[] = GIT_SHA1; -------------------------------------------------------------------------------- /context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include ".h" 6 | 7 | namespace sqf::runtime 8 | { 9 | class context 10 | { 11 | private: 12 | sqf::runtime::instruction_set m_instruction_set; 13 | sqf::runtime::instruction_set::iterator m_iterator; 14 | public: 15 | frame(sqf::runtime::instruction_set instruction_set) : m_instruction_set(instruction_set), m_iterator(instruction_set.begin()) {} 16 | }; 17 | } -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | LABEL org.opencontainers.image.source=https://github.com/SQFvm/runtime 3 | WORKDIR /tmp 4 | COPY sqfvm /usr/bin/sqfvm 5 | ENTRYPOINT ["/usr/bin/sqfvm", "--automated", "--suppress-welcome", "--no-execute-print"] 6 | -------------------------------------------------------------------------------- /docs/Debugger/README.MD: -------------------------------------------------------------------------------- 1 | # Client-Modes 2 | * [get-callstack](get-callstack.md) 3 | * [get-status](get-status.md) 4 | * [get-variables](get-variables.md) 5 | * [control](control.md) 6 | * [set-breakpoint](set-breakpoint.md) 7 | * [parse-sqf](parse-sqf.md) 8 | * [load-sqf](load-sqf.md) 9 | * [do-preprocess](do-preprocess.md) 10 | 11 | # Server-Modes 12 | * [callstack](get-callstack.md) 13 | * [message](message.md) 14 | * [error](error.md) 15 | * [status](get-status.md) 16 | * [variables](get-variables.md) 17 | * [position](position.md) 18 | * [preprocess](do-preprocess.md) 19 | -------------------------------------------------------------------------------- /docs/Debugger/control.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "control", 4 | "data": { "status": "string" } 5 | } 6 | - **mode** - `control` - always required, tells the debugger that this is a control request. 7 | - **data** - `OBJECT` - always required, object containing the field `status` that needs to be one of the following enum values: `[stop, pause, resume, quit]`. 8 | 9 | 10 | No response will be send. -------------------------------------------------------------------------------- /docs/Debugger/do-preprocess.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "do-preprocess", 4 | "data": { "path": "string", "content": "string" } 5 | } 6 | * **mode** - `do-preprocess` - always set, tells the receiving end that this is a do-preprocess action in the `data` field 7 | * **data** - `STRING` - always set, contains either the `path` to an existing file or a `content` field. If both are provided, path takes priority. 8 | ## Response Schema 9 | { 10 | "mode": "preprocess", 11 | "data": "string" 12 | } 13 | * **mode** - `preprocess` - always set, tells the receiving end that this is a preprocess-string in the `data` field 14 | * **data** - `STRING` - always set, contains the preprocessed data from the server. 15 | 16 | Tells the server to preprocess a file or contents. -------------------------------------------------------------------------------- /docs/Debugger/error.md: -------------------------------------------------------------------------------- 1 | ## Response Schema 2 | { 3 | "mode": "error", 4 | "data": "string" 5 | } 6 | * **mode** - `error` - always set, tells the receiving end that this is a error-string in the `data` field 7 | * **data** - `STRING` - always set, contains the actual error comming from the server. 8 | 9 | This response will be send whenever some error is generated on the server. -------------------------------------------------------------------------------- /docs/Debugger/get-callstack.json: -------------------------------------------------------------------------------- 1 | /* REQUEST */ 2 | { 3 | "mode": "get-callstack", 4 | "data": null 5 | } 6 | /* RESPONSE */ 7 | { 8 | "mode": "callstack", 9 | "data": [ 10 | { 11 | "lvl": 0, 12 | "scopename": "string", 13 | "namespace": "string", 14 | "variables": [ 15 | { "name": "string", "value", "string" } 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /docs/Debugger/get-callstack.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "get-callstack", 4 | "data": null 5 | } 6 | - **mode** - `get-callstack` - always required, tells the debugger that this is a get-callstack request. 7 | - **data** - `null` - always required, null as the get-callstack request does not has any further data requirements. 8 | 9 | ## Response Schema 10 | { 11 | "mode": "callstack", 12 | "data": [ 13 | { 14 | "lvl": 0, 15 | "scopename": "string", 16 | "namespace": "string", 17 | "options": { "line": 0, "column": 0, "file": 0, "available": false } 18 | "variables": [ 19 | { "name": "string", "value", "string" } 20 | ] 21 | } 22 | ] 23 | } 24 | * **mode** - `callstack` - always set, tells the receiving end that this is a callstack-object in the `data` field 25 | * **data** - `ARRAY` - always set, contains the actual callstack `scope` objects as they are present on the sqf-end. 26 | 27 | #### The Scope Object 28 | { 29 | "lvl": 0, 30 | "scopename": "string", 31 | "namespace": "string", 32 | "variables": [ 33 | { "name": "string", "value", "string" } 34 | ] 35 | } 36 | * **lvl** - `NUMBER` - the level of the current scope object. 0 is the most-outter-scope. 37 | * **scopename** - `STRING` - the name of the current scope object. May be an empty string if the `scopeName` command never was used or scope was created without a scope name. 38 | * **namespace** - `STRING` - the namespace this scope lives in. Most of the time, this will be missionNamespace. May change with eg. `with NAMESPACE do {...}` operators. 39 | * **options** - `OBEJCT` - Simple object containing informations about the current position that gets executed. Information may not be available, which is when `available` will be false. 40 | * **variables** - `ARRAY` - Simple key-value array containing the private variables (those starting with underscore `_`) as object with the fields `name` for the key and `value` for the value. -------------------------------------------------------------------------------- /docs/Debugger/get-status.json: -------------------------------------------------------------------------------- 1 | /* REQUEST */ 2 | { 3 | "mode": "get-status", 4 | "data": null 5 | } 6 | /* RESPONSE */ 7 | { 8 | "mode": "status", 9 | "data": "string" /* HALT | RUNNING | DONE | NA */ 10 | } -------------------------------------------------------------------------------- /docs/Debugger/get-status.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "get-status", 4 | "data": null 5 | } 6 | - **mode** - `get-status` - always required, tells the debugger that this is a get-status request. 7 | - **data** - `null` - always required, null as the get-status request does not has any further data requirements. 8 | 9 | ## Response Schema 10 | { 11 | "mode": "status", 12 | "data": "string" 13 | } 14 | * **mode** - `callstack` - always set, tells the receiving end that this is a callstack-object in the `data` field 15 | * **data** - `STRING` - always set, either `HALT`, `RUNNING`, `DONE` or `NA`. 16 | 17 | 18 | #### HALT 19 | Halt means that the server currently is in breakmode. 20 | 21 | #### RUNNING 22 | Server currently executes code. 23 | 24 | #### DONE 25 | Same as `HALT` but with different meaning. 26 | Always set when the server ran out of code it may run. 27 | 28 | #### NA 29 | Set when the server could not determine the exact status of the current execution. -------------------------------------------------------------------------------- /docs/Debugger/get-variables.json: -------------------------------------------------------------------------------- 1 | /* REQUEST */ 2 | { 3 | "mode": "get-variables", 4 | "data": [ 5 | { 6 | "name": "varname", /* Variablename */ 7 | "scope": "string" /* Required to be one of the following: [missionNamespace, uiNamespace, profileNamespace, parsingNamespace] */ 8 | }, 9 | { 10 | "name": "_varname", /* Variablename */ 11 | "scope": -1 /* Stack Location (determines starting point, 0 is top most, -N is N levels lower) */ 12 | } 13 | ] 14 | } 15 | /* RESPONSE */ 16 | { 17 | "mode": "variables", 18 | "data": [ 19 | { "name": "string", "value": "string" } 20 | ] 21 | } -------------------------------------------------------------------------------- /docs/Debugger/get-variables.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "get-variables", 4 | "data": [ 5 | { 6 | "name": "varname", 7 | "scope": "global" 8 | }, 9 | { 10 | "name": "_varname", 11 | "scope": -1 12 | } 13 | ] 14 | } 15 | - **mode** - `get-variables` - always required, tells the debugger that this is a get-variables request. 16 | - **data** - `ARRAY` - always required, contains all variables you want to receive as VariableRequest objects. 17 | 18 | ## Response Schema 19 | { 20 | "mode": "variables", 21 | "data": [ 22 | { "name": "string", "value": "string" } 23 | ] 24 | } 25 | * **mode** - `variables` - always set, tells the receiving end that this is a variables-response in the `data` field 26 | * **data** - `ARRAY` - always set, simple key-value array containing the private variables (those starting with underscore `_`) as object with the fields `name` for the key and `value` for the value. 27 | 28 | #### The VariableRequest Object 29 | { 30 | "name": "varname", 31 | "scope": "string" 32 | } 33 | /* OR */ 34 | { 35 | "name": "_varname", 36 | "scope": -1 37 | } 38 | * **name** - `STRING` - The name of the variable requested. 39 | * **scope** - `STRING` - The scope this is requesting from. Needs to be one of the following enum values: [missionNamespace, uiNamespace, profileNamespace, parsingNamespace] 40 | * **scope** - `NUMBER` - Stack Location. Telling the debugger where to start the variable search. 0 is the most inner scope, -N is N levels outter. -------------------------------------------------------------------------------- /docs/Debugger/load-sqf.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "load-sqf", 4 | "data": { "path": "string", "name": "string" } 5 | } 6 | - **mode** - `load-sqf` - always required, tells the debugger that this is a load-sqf request. 7 | - **data** - `OBJECT` - always required, object containing the field `path` being the path to the file to parse local to the VM and the field `name` containing file name. 8 | 9 | 10 | No response will be send. -------------------------------------------------------------------------------- /docs/Debugger/message.md: -------------------------------------------------------------------------------- 1 | ## Response Schema 2 | { 3 | "mode": "message", 4 | "data": "string" 5 | } 6 | * **mode** - `message` - always set, tells the receiving end that this is a message-string in the `data` field 7 | * **data** - `STRING` - always set, contains the actual message comming from the server. 8 | 9 | This response will be send whenever some output is generated on the server. -------------------------------------------------------------------------------- /docs/Debugger/parse-sqf.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "parse-sqf", 4 | "data": { "sqf": "string", "file": "string" } 5 | } 6 | - **mode** - `parse-sqf` - always required, tells the debugger that this is a parse-sqf request. 7 | - **data** - `OBJECT` - always required, object containing the field `sqf` being the code to parse and the field `file` containing file informations. 8 | 9 | 10 | No response will be send. -------------------------------------------------------------------------------- /docs/Debugger/position.md: -------------------------------------------------------------------------------- 1 | ## Response Schema 2 | { 3 | "mode": "position", 4 | "data": { "line": 0, "col": 0, "file": "string" } 5 | } 6 | * **mode** - `position` - always set, tells the receiving end that this is a position-object in the `data` field 7 | * **data** - `STRING` - always set, contains the current line, column and file where the vm currently is at. 8 | 9 | This response will be send whenever a breakpoint is hit or an error is raised. -------------------------------------------------------------------------------- /docs/Debugger/set-breakpoint.md: -------------------------------------------------------------------------------- 1 | ## Request Schema 2 | { 3 | "mode": "set-breakpoint", 4 | "data": { 5 | "line": 0, 6 | "file": "string" 7 | } 8 | } 9 | - **mode** - `set-breakpoint` - always required, tells the debugger that this is a set-breakpoint request. 10 | - **data** - `OBJECT` - always required, object containing the field `line` for the line to break on, and field `file` for file specific stuff. 11 | 12 | 13 | No response will be send. -------------------------------------------------------------------------------- /docs/PreProcessor/pp.xnf: -------------------------------------------------------------------------------- 1 | @SKIP \ \r\t\n 2 | @CASESENSITIVE true 3 | @LINECOMMENTSTART \/\/ 4 | @BLOCKCOMMENTSTART \/\* 5 | @BLOCKCOMMENTEND \*\/ 6 | 7 | hash = "#" > \#; 8 | ifdef => ifdef; 9 | else => else; 10 | endif => endif; 11 | define => define; 12 | undefine => undefine; 13 | include => include; 14 | string => \"(.)+\"; 15 | identifier => (a-zA-Z)(a-zA-Z0-9\_)+; 16 | ro = "(" > \(; 17 | rc = ")" > \); 18 | comma = "," > \,; 19 | anytext => (.)+; 20 | content =? 0; 21 | 22 | 23 | ROOT = { identifier [ PARAMLIST ] | PP | anytext }; 24 | PP = hash ( IFDEF | ELSE | ENDIF | DEFINE | UNDEFINE | INCLUDE ); 25 | IFDEF = ifdef identifier; 26 | ELSE = else; 27 | ENDIF = endif; 28 | DEFINE = define [ PARAMLIST ] identifier content; 29 | PARAMLIST = ro [ identifier { comma identifier } ] rc; 30 | ARGLIST = ro [ anytext { comma anytext } ] rc; 31 | UNDEFINE = undefine identifier; 32 | INCLUDE = include string; -------------------------------------------------------------------------------- /docs/config.xbnf: -------------------------------------------------------------------------------- 1 | @SKIP \ \r\n\t 2 | @CASESENSITIVE true 3 | @LINECOMMENTSTART \/\/ 4 | @BLOCKCOMMENTSTART \/\* 5 | @BLOCKCOMMENTEND \*\/ 6 | 7 | 8 | class => class ? notoken; 9 | ident => (a-zA-Z0-9\_)+; 10 | curlyo = "{" > \{ ? notoken; 11 | curlyc = "}" > \} ? notoken; 12 | roundo = "(" > \( ? notoken; 13 | roundc = ")" > \) ? notoken; 14 | squareo = "[" > \[ ? notoken; 15 | squarec = "]" > \] ? notoken; 16 | colon = ":" > \: ? notoken; 17 | semicolon = ";" > \; ? notoken; 18 | equalsign = "=" > \=; 19 | plusequal = "+=" > \+\=; 20 | comma = "," > \, ? notoken; 21 | dot = "." > \. ? notoken; 22 | minus = "-" > \. ? notoken; 23 | number => (0-9)+; 24 | string =? 0; 25 | true => true; 26 | false => false; 27 | delete => delete; 28 | 29 | CONFIGROOT = { CLASS }; 30 | CLASS = class ident [ colon ident ] [ curlyo { CLASS | VARIABLE | DELETE } curlyc ] semicolon; 31 | DELETE = delete ident semicolon; 32 | VARIABLE = ident ( curlyo curlyc ( equalsign | plusequal ) ARRAY | equalsign VALUE ) semicolon; 33 | VALUE = STRING | NUMBER | BOOLEAN; 34 | ARRAY = curlyo [ ( ARRAY | VALUE ) { comma ( ARRAY | VALUE ) } ] curlyc; 35 | STRING = string; 36 | NUMBER = [ minus ] number [ dot number ]; 37 | BOOLEAN = true | false; -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQFvm/runtime/ea66b8afc04951004b83f7d746168415baeef9c0/icon.png -------------------------------------------------------------------------------- /include/tclap-1.2.2/AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | original author: Michael E. Smoot 3 | invaluable contributions: Daniel Aarno 4 | more contributions: Erik Zeek 5 | more contributions: Fabien Carmagnac (Tinbergen-AM) 6 | outstanding editing: Carol Smoot 7 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/COPYING: -------------------------------------------------------------------------------- 1 | 2 | 3 | Copyright (c) 2003 Michael E. Smoot 4 | Copyright (c) 2004 Daniel Aarno 5 | Copyright (c) 2017 Google Inc. 6 | 7 | Permission is hereby granted, free of charge, to any person 8 | obtaining a copy of this software and associated documentation 9 | files (the "Software"), to deal in the Software without restriction, 10 | including without limitation the rights to use, copy, modify, merge, 11 | publish, distribute, sublicense, and/or sell copies of the Software, 12 | and to permit persons to whom the Software is furnished to do so, 13 | subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 22 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = tclap 2 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/ArgTraits.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- 2 | 3 | /****************************************************************************** 4 | * 5 | * file: ArgTraits.h 6 | * 7 | * Copyright (c) 2007, Daniel Aarno, Michael E. Smoot . 8 | * All rights reserved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | // This is an internal tclap file, you should probably not have to 24 | // include this directly 25 | 26 | #ifndef TCLAP_ARGTRAITS_H 27 | #define TCLAP_ARGTRAITS_H 28 | 29 | namespace TCLAP { 30 | 31 | // We use two empty structs to get compile type specialization 32 | // function to work 33 | 34 | /** 35 | * A value like argument value type is a value that can be set using 36 | * operator>>. This is the default value type. 37 | */ 38 | struct ValueLike { 39 | typedef ValueLike ValueCategory; 40 | virtual ~ValueLike() {} 41 | }; 42 | 43 | /** 44 | * A string like argument value type is a value that can be set using 45 | * operator=(string). Useful if the value type contains spaces which 46 | * will be broken up into individual tokens by operator>>. 47 | */ 48 | struct StringLike { 49 | virtual ~StringLike() {} 50 | }; 51 | 52 | /** 53 | * A class can inherit from this object to make it have string like 54 | * traits. This is a compile time thing and does not add any overhead 55 | * to the inherenting class. 56 | */ 57 | struct StringLikeTrait { 58 | typedef StringLike ValueCategory; 59 | virtual ~StringLikeTrait() {} 60 | }; 61 | 62 | /** 63 | * A class can inherit from this object to make it have value like 64 | * traits. This is a compile time thing and does not add any overhead 65 | * to the inherenting class. 66 | */ 67 | struct ValueLikeTrait { 68 | typedef ValueLike ValueCategory; 69 | virtual ~ValueLikeTrait() {} 70 | }; 71 | 72 | /** 73 | * Arg traits are used to get compile type specialization when parsing 74 | * argument values. Using an ArgTraits you can specify the way that 75 | * values gets assigned to any particular type during parsing. The two 76 | * supported types are StringLike and ValueLike. 77 | */ 78 | template 79 | struct ArgTraits { 80 | typedef typename T::ValueCategory ValueCategory; 81 | virtual ~ArgTraits() {} 82 | //typedef ValueLike ValueCategory; 83 | }; 84 | 85 | } // namespace 86 | 87 | #endif 88 | 89 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/CmdLineOutput.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /****************************************************************************** 4 | * 5 | * file: CmdLineOutput.h 6 | * 7 | * Copyright (c) 2004, Michael E. Smoot 8 | * All rights reserved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | #ifndef TCLAP_CMDLINEOUTPUT_H 24 | #define TCLAP_CMDLINEOUTPUT_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace TCLAP { 34 | 35 | class CmdLineInterface; 36 | class ArgException; 37 | 38 | /** 39 | * The interface that any output object must implement. 40 | */ 41 | class CmdLineOutput 42 | { 43 | 44 | public: 45 | 46 | /** 47 | * Virtual destructor. 48 | */ 49 | virtual ~CmdLineOutput() {} 50 | 51 | /** 52 | * Generates some sort of output for the USAGE. 53 | * \param c - The CmdLine object the output is generated for. 54 | */ 55 | virtual void usage(CmdLineInterface& c)=0; 56 | 57 | /** 58 | * Generates some sort of output for the version. 59 | * \param c - The CmdLine object the output is generated for. 60 | */ 61 | virtual void version(CmdLineInterface& c)=0; 62 | 63 | /** 64 | * Generates some sort of output for a failure. 65 | * \param c - The CmdLine object the output is generated for. 66 | * \param e - The ArgException that caused the failure. 67 | */ 68 | virtual void failure( CmdLineInterface& c, 69 | ArgException& e )=0; 70 | 71 | }; 72 | 73 | } //namespace TCLAP 74 | #endif 75 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/Constraint.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: Constraint.h 5 | * 6 | * Copyright (c) 2005, Michael E. Smoot 7 | * All rights reserved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | #ifndef TCLAP_CONSTRAINT_H 23 | #define TCLAP_CONSTRAINT_H 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace TCLAP { 33 | 34 | /** 35 | * The interface that defines the interaction between the Arg and Constraint. 36 | */ 37 | template 38 | class Constraint 39 | { 40 | 41 | public: 42 | /** 43 | * Returns a description of the Constraint. 44 | */ 45 | virtual std::string description() const =0; 46 | 47 | /** 48 | * Returns the short ID for the Constraint. 49 | */ 50 | virtual std::string shortID() const =0; 51 | 52 | /** 53 | * The method used to verify that the value parsed from the command 54 | * line meets the constraint. 55 | * \param value - The value that will be checked. 56 | */ 57 | virtual bool check(const T& value) const =0; 58 | 59 | /** 60 | * Destructor. 61 | * Silences warnings about Constraint being a base class with virtual 62 | * functions but without a virtual destructor. 63 | */ 64 | virtual ~Constraint() { ; } 65 | }; 66 | 67 | } //namespace TCLAP 68 | #endif 69 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/HelpVisitor.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: HelpVisitor.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * All rights reserved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | #ifndef TCLAP_HELP_VISITOR_H 23 | #define TCLAP_HELP_VISITOR_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace TCLAP { 30 | 31 | /** 32 | * A Visitor object that calls the usage method of the given CmdLineOutput 33 | * object for the specified CmdLine object. 34 | */ 35 | class HelpVisitor: public Visitor 36 | { 37 | private: 38 | /** 39 | * Prevent accidental copying. 40 | */ 41 | HelpVisitor(const HelpVisitor& rhs); 42 | HelpVisitor& operator=(const HelpVisitor& rhs); 43 | 44 | protected: 45 | 46 | /** 47 | * The CmdLine the output will be generated for. 48 | */ 49 | CmdLineInterface* _cmd; 50 | 51 | /** 52 | * The output object. 53 | */ 54 | CmdLineOutput** _out; 55 | 56 | public: 57 | 58 | /** 59 | * Constructor. 60 | * \param cmd - The CmdLine the output will be generated for. 61 | * \param out - The type of output. 62 | */ 63 | HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) 64 | : Visitor(), _cmd( cmd ), _out( out ) { } 65 | 66 | /** 67 | * Calls the usage method of the CmdLineOutput for the 68 | * specified CmdLine. 69 | */ 70 | void visit() { (*_out)->usage(*_cmd); throw ExitException(0); } 71 | 72 | }; 73 | 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/IgnoreRestVisitor.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: IgnoreRestVisitor.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * All rights reserved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | 23 | #ifndef TCLAP_IGNORE_REST_VISITOR_H 24 | #define TCLAP_IGNORE_REST_VISITOR_H 25 | 26 | #include 27 | #include 28 | 29 | namespace TCLAP { 30 | 31 | /** 32 | * A Visitor that tells the CmdLine to begin ignoring arguments after 33 | * this one is parsed. 34 | */ 35 | class IgnoreRestVisitor: public Visitor 36 | { 37 | public: 38 | 39 | /** 40 | * Constructor. 41 | */ 42 | IgnoreRestVisitor() : Visitor() {} 43 | 44 | /** 45 | * Sets Arg::_ignoreRest. 46 | */ 47 | void visit() { Arg::beginIgnoring(); } 48 | }; 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | libtclapincludedir = $(includedir)/tclap 3 | 4 | libtclapinclude_HEADERS = \ 5 | CmdLineInterface.h \ 6 | ArgException.h \ 7 | CmdLine.h \ 8 | XorHandler.h \ 9 | MultiArg.h \ 10 | UnlabeledMultiArg.h \ 11 | ValueArg.h \ 12 | UnlabeledValueArg.h \ 13 | Visitor.h Arg.h \ 14 | HelpVisitor.h \ 15 | SwitchArg.h \ 16 | MultiSwitchArg.h \ 17 | VersionVisitor.h \ 18 | IgnoreRestVisitor.h \ 19 | CmdLineOutput.h \ 20 | StdOutput.h \ 21 | DocBookOutput.h \ 22 | ZshCompletionOutput.h \ 23 | OptionalUnlabeledTracker.h \ 24 | Constraint.h \ 25 | ValuesConstraint.h \ 26 | ArgTraits.h \ 27 | StandardTraits.h \ 28 | sstream.h 29 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/OptionalUnlabeledTracker.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /****************************************************************************** 4 | * 5 | * file: OptionalUnlabeledTracker.h 6 | * 7 | * Copyright (c) 2005, Michael E. Smoot . 8 | * All rights reserved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | 24 | #ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H 25 | #define TCLAP_OPTIONAL_UNLABELED_TRACKER_H 26 | 27 | #include 28 | 29 | namespace TCLAP { 30 | 31 | class OptionalUnlabeledTracker 32 | { 33 | 34 | public: 35 | 36 | static void check( bool req, const std::string& argName ); 37 | 38 | static void gotOptional() { alreadyOptionalRef() = true; } 39 | 40 | static bool& alreadyOptional() { return alreadyOptionalRef(); } 41 | 42 | private: 43 | 44 | static bool& alreadyOptionalRef() { static bool ct = false; return ct; } 45 | }; 46 | 47 | 48 | inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName ) 49 | { 50 | if ( OptionalUnlabeledTracker::alreadyOptional() ) 51 | throw( SpecificationException( 52 | "You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg", 53 | argName ) ); 54 | 55 | if ( !req ) 56 | OptionalUnlabeledTracker::gotOptional(); 57 | } 58 | 59 | 60 | } // namespace TCLAP 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/VersionVisitor.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- 2 | 3 | /****************************************************************************** 4 | * 5 | * file: VersionVisitor.h 6 | * 7 | * Copyright (c) 2003, Michael E. Smoot . 8 | * All rights reserved. 9 | * 10 | * See the file COPYING in the top directory of this distribution for 11 | * more information. 12 | * 13 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 14 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 16 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | * DEALINGS IN THE SOFTWARE. 20 | * 21 | *****************************************************************************/ 22 | 23 | 24 | #ifndef TCLAP_VERSION_VISITOR_H 25 | #define TCLAP_VERSION_VISITOR_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace TCLAP { 32 | 33 | /** 34 | * A Visitor that will call the version method of the given CmdLineOutput 35 | * for the specified CmdLine object and then exit. 36 | */ 37 | class VersionVisitor: public Visitor 38 | { 39 | private: 40 | /** 41 | * Prevent accidental copying 42 | */ 43 | VersionVisitor(const VersionVisitor& rhs); 44 | VersionVisitor& operator=(const VersionVisitor& rhs); 45 | 46 | protected: 47 | 48 | /** 49 | * The CmdLine of interest. 50 | */ 51 | CmdLineInterface* _cmd; 52 | 53 | /** 54 | * The output object. 55 | */ 56 | CmdLineOutput** _out; 57 | 58 | public: 59 | 60 | /** 61 | * Constructor. 62 | * \param cmd - The CmdLine the output is generated for. 63 | * \param out - The type of output. 64 | */ 65 | VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) 66 | : Visitor(), _cmd( cmd ), _out( out ) { } 67 | 68 | /** 69 | * Calls the version method of the output object using the 70 | * specified CmdLine. 71 | */ 72 | void visit() { 73 | (*_out)->version(*_cmd); 74 | throw ExitException(0); 75 | } 76 | 77 | }; 78 | 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/Visitor.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * 4 | * file: Visitor.h 5 | * 6 | * Copyright (c) 2003, Michael E. Smoot . 7 | * All rights reserved. 8 | * 9 | * See the file COPYING in the top directory of this distribution for 10 | * more information. 11 | * 12 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 13 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 | * DEALINGS IN THE SOFTWARE. 19 | * 20 | *****************************************************************************/ 21 | 22 | 23 | #ifndef TCLAP_VISITOR_H 24 | #define TCLAP_VISITOR_H 25 | 26 | namespace TCLAP { 27 | 28 | /** 29 | * A base class that defines the interface for visitors. 30 | */ 31 | class Visitor 32 | { 33 | public: 34 | 35 | /** 36 | * Constructor. Does nothing. 37 | */ 38 | Visitor() { } 39 | 40 | /** 41 | * Destructor. Does nothing. 42 | */ 43 | virtual ~Visitor() { } 44 | 45 | /** 46 | * Does nothing. Should be overridden by child. 47 | */ 48 | virtual void visit() { } 49 | }; 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /include/tclap-1.2.2/include/tclap/sstream.h: -------------------------------------------------------------------------------- 1 | // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- 2 | 3 | /****************************************************************************** 4 | * 5 | * file: sstream.h 6 | * 7 | * Copyright (c) 2003, Michael E. Smoot . 8 | * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno . 9 | * Copyright (c) 2017 Google Inc. 10 | * All rights reserved. 11 | * 12 | * See the file COPYING in the top directory of this distribution for 13 | * more information. 14 | * 15 | * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | * DEALINGS IN THE SOFTWARE. 22 | * 23 | *****************************************************************************/ 24 | 25 | #ifndef TCLAP_SSTREAM_H 26 | #define TCLAP_SSTREAM_H 27 | 28 | #if !defined(HAVE_STRSTREAM) 29 | // Assume sstream is available if strstream is not specified 30 | // (https://sourceforge.net/p/tclap/bugs/23/) 31 | #define HAVE_SSTREAM 32 | #endif 33 | 34 | #if defined(HAVE_SSTREAM) 35 | #include 36 | namespace TCLAP { 37 | typedef std::istringstream istringstream; 38 | typedef std::ostringstream ostringstream; 39 | } 40 | #elif defined(HAVE_STRSTREAM) 41 | #include 42 | namespace TCLAP { 43 | typedef std::istrstream istringstream; 44 | typedef std::ostrstream ostringstream; 45 | } 46 | #else 47 | #error "Need a stringstream (sstream or strstream) to compile!" 48 | #endif 49 | 50 | #endif // TCLAP_SSTREAM_H 51 | -------------------------------------------------------------------------------- /sqf-dummy-check/delta.sqf: -------------------------------------------------------------------------------- 1 | private _ops_list = 2 | #include "ops.sqf" 3 | ; 4 | private _ops_existing = cmds__ apply { 5 | switch (_x select 0) do 6 | { 7 | case "n": { ["n", _x select 1] }; 8 | case "u": { ["u", _x select 1] }; 9 | case "b": { ["b", _x select 2] }; 10 | }; 11 | }; 12 | private _ops_missing = []; 13 | 14 | { 15 | _x params ["_kind", "_name", "_precedence"]; 16 | private _index = -1; 17 | switch _kind do 18 | { 19 | case "n": { 20 | private _index = _ops_existing find ["n",_name]; 21 | if (_index == -1) then { 22 | diag_log format["MISSING NULAR '%1'", _name]; 23 | _ops_missing pushBack format [ 24 | "runtime.register_sqfop(nular(""%1"", """"," + 25 | "[](sqf::runtime::runtime& runtime) -> value" + 26 | "{ runtime.__logmsg(logmessage::runtime::ErrorMessage(runtime.context_active()" + 27 | ".current_frame().diag_info_from_position(), ""NOT IMPLEMENTED"", ""%1"")); return {}; }));", 28 | _name 29 | ]; 30 | } else { 31 | diag_log format["FOUND NULAR '%1'", _name]; 32 | } 33 | }; 34 | case "u": { 35 | private _index = _ops_existing find ["u",_name]; 36 | if (_index == -1) then { 37 | diag_log format["MISSING UNARY '%1'", _name]; 38 | _ops_missing pushBack format [ 39 | "runtime.register_sqfop(unary(""%1"", t_any(), """"," + 40 | "[](sqf::runtime::runtime& runtime, value::cref r) -> value" + 41 | "{ runtime.__logmsg(logmessage::runtime::ErrorMessage(runtime.context_active()" + 42 | ".current_frame().diag_info_from_position(), ""NOT IMPLEMENTED"", ""%1"")); return {}; }));", 43 | _name 44 | ]; 45 | } else { 46 | diag_log format["FOUND UNARY '%1'", _name]; 47 | } 48 | }; 49 | case "b": { 50 | private _index = _ops_existing find ["b",_name]; 51 | if (_index == -1) then { 52 | diag_log format["MISSING BINARY '%1'", _name]; 53 | _ops_missing pushBack format [ 54 | "runtime.register_sqfop(binary(%1, ""%2"", t_any(), t_any(), """"," + 55 | "[](sqf::runtime::runtime& runtime, value::cref l, value::cref r) -> value" + 56 | "{ runtime.__logmsg(logmessage::runtime::ErrorMessage(runtime.context_active()" + 57 | ".current_frame().diag_info_from_position(), ""NOT IMPLEMENTED"", ""%2"")); return {}; }));", 58 | _precedence, 59 | _name 60 | ]; 61 | } else { 62 | diag_log format["FOUND BINARY '%1'", _name]; 63 | } 64 | }; 65 | }; 66 | } foreach _ops_list; 67 | 68 | diag_log "Copying generated list to clipboard"; 69 | copyToClipboard (_ops_missing joinString endl); -------------------------------------------------------------------------------- /sqf-dummy-check/gen.sqf: -------------------------------------------------------------------------------- 1 | // call compileScript ["gen.sqf"]; 2 | // ..\build\Release\sqfvm.exe --input-sqf .\delta.sqf 3 | 4 | private _ops_list = 5 | #include "ops.sqf" 6 | ; 7 | 8 | private _toAdd = []; 9 | (supportInfo "") apply { 10 | if (_x == "b:SWITCH : CODE") then { continue }; 11 | if (_x == "b:SWITCH do CODE") then { continue }; 12 | _x splitString ":" params ["_t", "_x"]; 13 | if (_t != "t") then { 14 | _x = _x splitString " "; 15 | private _cmd = switch count _x do { 16 | case 1: { ["n", (_x # 0)] }; 17 | case 2: { ["u", (_x # 0)] }; 18 | case 3: { ["b", (_x # 1), 4] }; 19 | }; 20 | if ((_ops_list findIf {(_x select [0,2]) isEqualTo (_cmd select [0,2])}) == -1) then { 21 | _toAdd pushBackUnique str _cmd; 22 | }; 23 | }; 24 | }; 25 | copyToClipboard (_toAdd apply {format ["%1,", _x]} joinString endl); 26 | format ["found %1", count _toAdd]; -------------------------------------------------------------------------------- /src/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Implementation Requirements for classes 2 | 3 | | Level | Applies To | Requirement | 4 | | ------ | -------------------- | ------------------------------------------------------------ | 5 | | MUST | `sqf::runtime::type` | MUST reside in namespace `sqf::types` or lower | 6 | | | `sqf::runtime::data` | | 7 | | SHOULD | * | SHOULD be declared in-header as much as possible and viable. | 8 | | MUST | `sqf::runtime::type` | MUST be prefixed with `t_` | 9 | | MUST | `sqf::runtime::data` | MUST be prefixed with `d_` | 10 | | MUST | `sqf::runtime::data` | MUST be contained with a corresponding `sqf::runtime::type` | 11 | | SHOULD | `sqf::runtime::data` | SHOULD provide operator overloads for `sqf::runtime::value` | -------------------------------------------------------------------------------- /src/cli/ReadMe.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQFvm/runtime/ea66b8afc04951004b83f7d746168415baeef9c0/src/cli/ReadMe.md -------------------------------------------------------------------------------- /src/cli/cli.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/logging.h" 3 | #include "../runtime/runtime.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace TCLAP 13 | { 14 | class CmdLine; 15 | } 16 | 17 | class cli 18 | { 19 | StdOutLogger m_logger; 20 | sqf::runtime::runtime m_runtime; 21 | bool m_cli_file; 22 | bool m_parse_only; 23 | bool m_good; 24 | bool m_automated; 25 | std::unordered_map()>>> m_files; 26 | 27 | void handle_files(); 28 | void mount_filesystem(const std::vector& mappings); 29 | int cli_from_file(const char* arg0, std::filesystem::path path); 30 | public: 31 | cli(); 32 | int run(size_t argc, const char** argv); 33 | 34 | bool verbose() const { return m_logger.isEnabled(loglevel::verbose); } 35 | }; -------------------------------------------------------------------------------- /src/cli/colors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | namespace console 4 | { 5 | class color 6 | { 7 | private: 8 | constexpr color(const char* view) : data(view) {} 9 | public: 10 | const char* data; 11 | static constexpr color foreground_black() { return color("\u001b[30m"); } 12 | static constexpr color foreground_red() { return color("\u001b[31m"); } 13 | static constexpr color foreground_green() { return color("\u001b[32m"); } 14 | static constexpr color foreground_yellow() { return color("\u001b[33m"); } 15 | static constexpr color foreground_blue() { return color("\u001b[34m"); } 16 | static constexpr color foreground_magenta() { return color("\u001b[35m"); } 17 | static constexpr color foreground_cyan() { return color("\u001b[36m"); } 18 | static constexpr color foreground_white() { return color("\u001b[37m"); } 19 | static constexpr color reset() { return color("\u001b[0m"); } 20 | static constexpr color foreground_bright_black() { return color("\u001b[30;1m"); } 21 | static constexpr color foreground_bright_red() { return color("\u001b[31;1m"); } 22 | static constexpr color foreground_bright_green() { return color("\u001b[32;1m"); } 23 | static constexpr color foreground_bright_yellow() { return color("\u001b[33;1m"); } 24 | static constexpr color foreground_bright_blue() { return color("\u001b[34;1m"); } 25 | static constexpr color foreground_bright_magenta() { return color("\u001b[35;1m"); } 26 | static constexpr color foreground_bright_cyan() { return color("\u001b[36;1m"); } 27 | static constexpr color foreground_bright_white() { return color("\u001b[37;1m"); } 28 | static constexpr color background_black() { return color("\u001b[40m"); } 29 | static constexpr color background_red() { return color("\u001b[41m"); } 30 | static constexpr color background_green() { return color("\u001b[42m"); } 31 | static constexpr color background_yellow() { return color("\u001b[43m"); } 32 | static constexpr color background_blue() { return color("\u001b[44m"); } 33 | static constexpr color background_magenta() { return color("\u001b[45m"); } 34 | static constexpr color background_cyan() { return color("\u001b[46m"); } 35 | static constexpr color background_white() { return color("\u001b[47m"); } 36 | static constexpr color background_bright_black() { return color("\u001b[40;1m"); } 37 | static constexpr color background_bright_red() { return color("\u001b[41;1m"); } 38 | static constexpr color background_bright_green() { return color("\u001b[42;1m"); } 39 | static constexpr color background_bright_yellow() { return color("\u001b[43;1m"); } 40 | static constexpr color background_bright_blue() { return color("\u001b[44;1m"); } 41 | static constexpr color background_bright_magenta() { return color("\u001b[45;1m"); } 42 | static constexpr color background_bright_cyan() { return color("\u001b[46;1m"); } 43 | static constexpr color background_bright_white() { return color("\u001b[47;1m"); } 44 | }; 45 | } 46 | inline std::ostream& operator<<(std::ostream& os, const console::color& c) 47 | { 48 | os << c.data; 49 | return os; 50 | } -------------------------------------------------------------------------------- /src/cli/interactive_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/runtime.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace sqf::runtime 9 | { 10 | class context; 11 | } 12 | class interactive_helper 13 | { 14 | typedef void (*interactive_callback)(interactive_helper&, std::string_view); 15 | struct command 16 | { 17 | std::vector names; 18 | interactive_callback callback; 19 | std::string description; 20 | }; 21 | std::vector m_commands; 22 | 23 | 24 | sqf::runtime::runtime& m_runtime; 25 | sqf::runtime::runtime::action m_runtime_apply_action; 26 | bool m_thread_die; 27 | bool m_exit; 28 | std::weak_ptr m_context_selected; 29 | 30 | static const size_t buffer_size = 16384; 31 | char* m_buffer; 32 | 33 | void virtualmachine_thread(); 34 | public: 35 | template 36 | void register_command(std::array names, std::string description, interactive_callback callback) 37 | { 38 | m_commands.push_back({ std::vector(names.begin(), names.end()), callback, description }); 39 | } 40 | interactive_helper(sqf::runtime::runtime& vm) : 41 | m_commands(), 42 | m_runtime(vm), 43 | m_runtime_apply_action(sqf::runtime::runtime::action::invalid), 44 | m_thread_die(false), 45 | m_exit(false), 46 | m_context_selected(), 47 | m_buffer(new char[buffer_size]) 48 | { 49 | } 50 | ~interactive_helper() 51 | { 52 | delete[] m_buffer; 53 | } 54 | 55 | void init(); 56 | void run(); 57 | 58 | std::vector::const_iterator commands_begin() const { return m_commands.begin(); } 59 | std::vector::const_iterator commands_end() const { return m_commands.end(); } 60 | sqf::runtime::runtime& runtime() const { return m_runtime; } 61 | 62 | void context_selected(std::shared_ptr sptr) { m_context_selected = sptr; } 63 | std::shared_ptr context_selected() const { return m_context_selected.lock(); } 64 | void print_welcome(); 65 | 66 | bool execute_next(sqf::runtime::runtime::action action) 67 | { 68 | if (m_runtime_apply_action == sqf::runtime::runtime::action::invalid) 69 | { 70 | m_runtime_apply_action = action; 71 | return true; 72 | } 73 | else 74 | { 75 | return false; 76 | } 77 | } 78 | }; 79 | -------------------------------------------------------------------------------- /src/cli/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifndef CONCAT_ 5 | #define CONCAT_(L, R) L ## R 6 | #endif // !CONCAT_ 7 | #ifndef CONCAT 8 | #define CONCAT(L, R) CONCAT_(L, R) 9 | #endif // !CONCAT 10 | #ifndef STR_ 11 | #define STR_(IN) # IN 12 | #endif // !STR_ 13 | #ifndef STR 14 | #define STR(IN) STR_(IN) 15 | #endif // !STR 16 | 17 | 18 | #define VERSION_MAJOR 2 19 | #define VERSION_MINOR 0 20 | #define VERSION_REVISION 0 21 | #define VERSION STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) 22 | #define VERSION_FULL VERSION " - " __DATE__ " " __TIME__ 23 | #define VERSION_MAJORMINOR CONCAT(VERSION_MAJOR, VERSION_MINOR) 24 | 25 | 26 | 27 | // Check windows 28 | #if defined(_WIN32) || defined(_WIN64) 29 | #if defined(_WIN64) 30 | #define ENVIRONMENT x64 31 | #define ENVIRONMENT64 ENVIRONMENT 32 | #else 33 | #define ENVIRONMENT x86 34 | #define ENVIRONMENT32 ENVIRONMENT 35 | #endif 36 | #endif 37 | 38 | // Check GCC 39 | #if defined(__GNUC__) 40 | #if defined(__x86_64__) || defined(__ppc64__) 41 | #define ENVIRONMENT x64 42 | #define ENVIRONMENT64 ENVIRONMENT 43 | #else 44 | #define ENVIRONMENT x86 45 | #define ENVIRONMENT32 ENVIRONMENT 46 | #endif 47 | #endif 48 | 49 | #if !defined(ENVIRONMENT) 50 | #define ENVIRONMENT NA 51 | #endif 52 | 53 | #define ENVIRONMENTSTR STR(ENVIRONMENT) 54 | 55 | 56 | void strcpy_safe(char* const dest, size_t len, const char* const src); 57 | char* const copy_str(const std::string& str); 58 | 59 | int console_width(); 60 | int main_actual(int argc, char** argv); 61 | int main(int argc, char** argv); 62 | -------------------------------------------------------------------------------- /src/export/ReadMe.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQFvm/runtime/ea66b8afc04951004b83f7d746168415baeef9c0/src/export/ReadMe.md -------------------------------------------------------------------------------- /src/fileio/ReadMe.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQFvm/runtime/ea66b8afc04951004b83f7d746168415baeef9c0/src/fileio/ReadMe.md -------------------------------------------------------------------------------- /src/opcodes/assign_to.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/value.h" 4 | #include "../runtime/data.h" 5 | #include "../runtime/runtime.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace sqf::opcodes 11 | { 12 | class assign_to : public sqf::runtime::instruction 13 | { 14 | private: 15 | #if _DEBUG 16 | std::string ___TYPE = "assign_to"; 17 | #endif 18 | std::string m_variable_name; 19 | 20 | public: 21 | assign_to(std::string value) : m_variable_name(value) {} 22 | assign_to(std::string_view value) : m_variable_name(value.begin(), value.end()) {} 23 | virtual void execute(sqf::runtime::runtime& vm) const override 24 | { 25 | auto& context = vm.context_active(); 26 | 27 | auto value = vm.context_active().pop_value(); 28 | if (!value.has_value()) 29 | { 30 | if (context.weak_error_handling()) 31 | { 32 | vm.__logmsg(logmessage::runtime::FoundNoValueWeak(diag_info())); 33 | } 34 | else 35 | { 36 | vm.__logmsg(logmessage::runtime::FoundNoValue(diag_info())); 37 | } 38 | return; 39 | } 40 | else if (value->is()) 41 | { 42 | vm.__logmsg(logmessage::runtime::AssigningNilValue(diag_info(), m_variable_name)); 43 | } 44 | if (m_variable_name.empty()) { return; } 45 | if (m_variable_name[0] == '_') 46 | { 47 | for (auto it = context.frames_rbegin(); it != context.frames_rend(); ++it) 48 | { 49 | if (it->contains(m_variable_name)) 50 | { 51 | (*it)[m_variable_name] = *value; 52 | return; 53 | } 54 | } 55 | context.current_frame()[m_variable_name] = *value; 56 | } 57 | else 58 | { 59 | context.current_frame().globals_value_scope()->at(m_variable_name) = *value; 60 | } 61 | } 62 | virtual std::string to_string() const override { return std::string("ASSIGNTO ") + m_variable_name; } 63 | std::string_view variable_name() const { return m_variable_name; } 64 | 65 | virtual std::optional reconstruct( 66 | std::vector::const_reverse_iterator& current, 67 | std::vector::const_reverse_iterator end, 68 | short parent_precedence, bool left_from_binary) const override 69 | { 70 | if (++current == end) 71 | { 72 | return {}; 73 | } 74 | auto exp = (*current)->reconstruct(current, end, 10, false); 75 | if (!exp.has_value()) 76 | { 77 | return {}; 78 | } 79 | return m_variable_name + " = " + *exp; 80 | } 81 | 82 | virtual bool equals(const instruction* p_other) const override 83 | { 84 | auto casted = dynamic_cast(p_other); 85 | return casted != nullptr && casted->m_variable_name == m_variable_name; 86 | } 87 | }; 88 | } -------------------------------------------------------------------------------- /src/opcodes/assign_to_local.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/value.h" 4 | #include "../runtime/data.h" 5 | #include "../runtime/runtime.h" 6 | 7 | namespace sqf::opcodes 8 | { 9 | class assign_to_local : public sqf::runtime::instruction 10 | { 11 | private: 12 | #if _DEBUG 13 | std::string ___TYPE = "assign_to_local"; 14 | #endif 15 | std::string m_variable_name; 16 | 17 | public: 18 | assign_to_local(std::string value) : m_variable_name(value) {} 19 | assign_to_local(std::string_view value) : m_variable_name(value.begin(), value.end()) {} 20 | virtual void execute(sqf::runtime::runtime& vm) const override 21 | { 22 | auto& context = vm.context_active(); 23 | 24 | auto value = vm.context_active().pop_value(); 25 | if (m_variable_name.empty()) { return; } 26 | if (!value.has_value()) 27 | { 28 | if (context.weak_error_handling()) 29 | { 30 | vm.__logmsg(logmessage::runtime::FoundNoValueWeak(diag_info())); 31 | } 32 | else 33 | { 34 | vm.__logmsg(logmessage::runtime::FoundNoValue(diag_info())); 35 | } 36 | return; 37 | } 38 | else if (value->is()) 39 | { 40 | vm.__logmsg(logmessage::runtime::AssigningNilValue(diag_info(), m_variable_name)); 41 | } 42 | 43 | context.current_frame()[m_variable_name] = *value; 44 | } 45 | virtual std::string to_string() const override { return std::string("ASSIGNTOLOCAL ") + m_variable_name; } 46 | std::string_view variable_name() const { return m_variable_name; } 47 | 48 | virtual std::optional reconstruct( 49 | std::vector::const_reverse_iterator& current, 50 | std::vector::const_reverse_iterator end, 51 | short parent_precedence, bool left_from_binary) const override 52 | { 53 | if (++current == end) 54 | { 55 | return {}; 56 | } 57 | auto exp = (*current)->reconstruct(current, end, 10, false); 58 | if (!exp.has_value()) 59 | { 60 | return {}; 61 | } 62 | #if defined(SQFVM_ARMA2_SYNTAX) 63 | return "local " + m_variable_name + " = " + *exp; 64 | #else 65 | return "private " + m_variable_name + " = " + *exp; 66 | #endif 67 | } 68 | 69 | virtual bool equals(const instruction* p_other) const override 70 | { 71 | auto casted = dynamic_cast(p_other); 72 | return casted != nullptr && casted->m_variable_name == m_variable_name; 73 | } 74 | }; 75 | } -------------------------------------------------------------------------------- /src/opcodes/call_nular.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/value.h" 4 | #include "../runtime/data.h" 5 | #include "../runtime/runtime.h" 6 | #include "../runtime/sqfop.h" 7 | 8 | #ifdef DF__SQF_RUNTIME__ASSEMBLY_DEBUG_ON_EXECUTE 9 | 10 | #include 11 | 12 | #endif // DF__SQF_RUNTIME__ASSEMBLY_DEBUG_ON_EXECUTE 13 | 14 | namespace sqf::opcodes 15 | { 16 | class call_nular : public sqf::runtime::instruction 17 | { 18 | #if _DEBUG 19 | std::string ___TYPE = "call_nular"; 20 | #endif 21 | private: 22 | std::string m_operator_name; 23 | 24 | public: 25 | call_nular(std::string key) : m_operator_name(key) {} 26 | virtual void execute(sqf::runtime::runtime& vm) const override 27 | { 28 | auto& context = vm.context_active(); 29 | sqf::runtime::sqfop_nular::key key = { m_operator_name }; 30 | if (!vm.sqfop_exists(key)) 31 | { 32 | vm.__logmsg(logmessage::runtime::UnknownInputTypeCombinationNular(diag_info(), key.name)); 33 | return; 34 | } 35 | auto op = vm.sqfop_at(key); 36 | auto return_value = op.execute(vm); 37 | 38 | context.push_value(return_value); 39 | } 40 | virtual std::string to_string() const override { return std::string("CALLNULAR ") + m_operator_name; } 41 | std::string_view operator_name() const { return m_operator_name; } 42 | virtual std::optional reconstruct( 43 | std::vector::const_reverse_iterator& current, 44 | std::vector::const_reverse_iterator end, 45 | short parent_precedence, bool left_from_binary) const override 46 | { 47 | return m_operator_name; 48 | } 49 | 50 | virtual bool equals(const instruction* p_other) const override 51 | { 52 | auto casted = dynamic_cast(p_other); 53 | return casted != nullptr && casted->m_operator_name == m_operator_name; 54 | } 55 | }; 56 | } -------------------------------------------------------------------------------- /src/opcodes/call_unary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/value.h" 4 | #include "../runtime/data.h" 5 | #include "../runtime/runtime.h" 6 | #include "../runtime/sqfop.h" 7 | 8 | 9 | namespace sqf::opcodes 10 | { 11 | class call_unary : public sqf::runtime::instruction 12 | { 13 | #if _DEBUG 14 | std::string ___TYPE = "call_unary"; 15 | #endif 16 | private: 17 | std::string m_operator_name; 18 | 19 | public: 20 | call_unary(std::string key) : m_operator_name(key) {} 21 | virtual void execute(sqf::runtime::runtime& vm) const override 22 | { 23 | auto& context = vm.context_active(); 24 | 25 | auto right_value = vm.context_active().pop_value(); 26 | if (!right_value.has_value()) 27 | { 28 | if (context.weak_error_handling()) 29 | { 30 | vm.__logmsg(logmessage::runtime::NoValueFoundForRightArgumentWeak(diag_info())); 31 | } 32 | else 33 | { 34 | vm.__logmsg(logmessage::runtime::NoValueFoundForRightArgument(diag_info())); 35 | } 36 | return; 37 | } 38 | else if (right_value->is()) 39 | { 40 | vm.__logmsg(logmessage::runtime::NilValueFoundForRightArgumentWeak(diag_info())); 41 | return; 42 | } 43 | 44 | auto tright = right_value->operator sqf::runtime::type(); 45 | sqf::runtime::sqfop_unary::key key = { m_operator_name, tright }; 46 | if (!vm.sqfop_exists(key)) 47 | { 48 | key = { m_operator_name, sqf::types::t_any() }; 49 | if (!vm.sqfop_exists(key)) 50 | { 51 | vm.__logmsg(logmessage::runtime::UnknownInputTypeCombinationUnary(diag_info(), key.name, tright)); 52 | return; 53 | } 54 | } 55 | auto op = vm.sqfop_at(key); 56 | auto return_value = op.execute(vm, *right_value); 57 | 58 | context.push_value(return_value); 59 | } 60 | virtual std::string to_string() const override { return std::string("CALLUNARY ") + m_operator_name; } 61 | std::string_view operator_name() const { return m_operator_name; } 62 | virtual std::optional reconstruct( 63 | std::vector::const_reverse_iterator& current, 64 | std::vector::const_reverse_iterator end, 65 | short parent_precedence, bool left_from_binary) const override 66 | { 67 | if (++current == end) 68 | { 69 | return {}; 70 | } 71 | auto exp = (*current)->reconstruct(current, end, 10, false); 72 | if (!exp.has_value()) 73 | { 74 | return {}; 75 | } 76 | return m_operator_name + " " + *exp; 77 | } 78 | 79 | virtual bool equals(const instruction* p_other) const override 80 | { 81 | auto casted = dynamic_cast(p_other); 82 | return casted != nullptr && casted->m_operator_name == m_operator_name; 83 | } 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /src/opcodes/common.h: -------------------------------------------------------------------------------- 1 | #include "../opcodes/assign_to.h" 2 | #include "../opcodes/assign_to_local.h" 3 | #include "../opcodes/call_binary.h" 4 | #include "../opcodes/call_unary.h" 5 | #include "../opcodes/call_nular.h" 6 | #include "../opcodes/end_statement.h" 7 | #include "../opcodes/get_variable.h" 8 | #include "../opcodes/make_array.h" 9 | #include "../opcodes/push.h" -------------------------------------------------------------------------------- /src/opcodes/end_statement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/runtime.h" 4 | 5 | namespace sqf::opcodes 6 | { 7 | class end_statement : public sqf::runtime::instruction 8 | { 9 | #if _DEBUG 10 | std::string ___TYPE = "end_statement"; 11 | #endif 12 | public: 13 | virtual void execute(sqf::runtime::runtime& vm) const override { vm.context_active().clear_values(); } 14 | virtual std::string to_string() const override { return "ENDSTATEMENT"; } 15 | virtual std::optional reconstruct( 16 | std::vector::const_reverse_iterator& current, 17 | std::vector::const_reverse_iterator end, 18 | short parent_precedence, bool left_from_binary) const override 19 | { 20 | return ""; 21 | } 22 | 23 | virtual bool equals(const instruction* p_other) const override 24 | { 25 | auto casted = dynamic_cast(p_other); 26 | return casted != nullptr; 27 | } 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/opcodes/get_variable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/runtime.h" 4 | #include "../runtime/value.h" 5 | #include "../runtime/value_scope.h" 6 | 7 | #include 8 | 9 | namespace sqf::runtime 10 | { 11 | class runtime; 12 | } 13 | namespace sqf::opcodes 14 | { 15 | class get_variable : public sqf::runtime::instruction 16 | { 17 | private: 18 | #if _DEBUG 19 | std::string ___TYPE = "get_variable"; 20 | #endif 21 | std::string m_variable_name; 22 | public: 23 | get_variable(std::string variable_name) : m_variable_name(variable_name) {} 24 | get_variable(std::string_view value) : m_variable_name(value.begin(), value.end()) {} 25 | virtual void execute(sqf::runtime::runtime& vm) const override 26 | { 27 | if (m_variable_name[0] == '_') 28 | { // local variable 29 | auto opt = vm.context_active().get_variable(m_variable_name); 30 | if (opt.has_value()) 31 | { 32 | vm.context_active().push_value(*opt); 33 | } 34 | else 35 | { 36 | vm.__logmsg(logmessage::runtime::VariableNotFound(diag_info(), m_variable_name)); 37 | vm.context_active().push_value({}); 38 | } 39 | } 40 | else 41 | { // global variable 42 | auto global_scope = vm.context_active().current_frame().globals_value_scope(); 43 | if (global_scope->contains(m_variable_name)) 44 | { 45 | vm.context_active().push_value(global_scope->at(m_variable_name)); 46 | } 47 | else 48 | { 49 | vm.__logmsg(logmessage::runtime::VariableNotFound(diag_info(), m_variable_name)); 50 | vm.context_active().push_value({}); 51 | } 52 | } 53 | } 54 | std::string to_string() const override { return "GETVARIABLE " + m_variable_name; } 55 | std::string variable_name() const { return m_variable_name; } 56 | 57 | virtual std::optional reconstruct( 58 | std::vector::const_reverse_iterator& current, 59 | std::vector::const_reverse_iterator end, 60 | short parent_precedence, bool left_from_binary) const override 61 | { 62 | return m_variable_name; 63 | } 64 | 65 | virtual bool equals(const instruction* p_other) const override 66 | { 67 | auto casted = dynamic_cast(p_other); 68 | return casted != nullptr && casted->m_variable_name == m_variable_name; 69 | } 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /src/opcodes/make_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/value.h" 4 | #include "../runtime/data.h" 5 | #include "../runtime/runtime.h" 6 | #include "../runtime/logging.h" 7 | #include "../runtime/d_array.h" 8 | 9 | #include 10 | 11 | namespace sqf::runtime 12 | { 13 | class runtime; 14 | } 15 | namespace sqf::opcodes 16 | { 17 | class make_array : public sqf::runtime::instruction 18 | { 19 | #if _DEBUG 20 | std::string ___TYPE = "make_array"; 21 | #endif 22 | private: 23 | size_t m_array_size; 24 | 25 | public: 26 | make_array(size_t array_size) : m_array_size(array_size) {} 27 | virtual void execute(sqf::runtime::runtime& vm) const override 28 | { 29 | auto vec = std::vector(m_array_size); 30 | for (size_t i = m_array_size - 1; i != (size_t)~0; i--) 31 | { 32 | auto opt = vm.context_active().pop_value(); 33 | if (!opt.has_value()) 34 | { 35 | vm.__logmsg(logmessage::runtime::StackCorruptionMissingValues(diag_info(), m_array_size, i)); 36 | break; 37 | } 38 | else 39 | { 40 | vec[i] = *opt; 41 | } 42 | } 43 | vm.context_active().push_value(std::make_shared(vec)); 44 | } 45 | virtual std::string to_string() const override { return std::string("MAKEARRAY ") + std::to_string(m_array_size); } 46 | size_t array_size() const { return m_array_size; } 47 | 48 | virtual std::optional reconstruct( 49 | std::vector::const_reverse_iterator& current, 50 | std::vector::const_reverse_iterator end, 51 | short parent_precedence, bool left_from_binary) const override 52 | { 53 | std::stringstream sstream; 54 | auto strvec = std::vector(array_size()); 55 | sstream << "["; 56 | for (size_t i = 0; i < array_size(); i++) 57 | { 58 | if (++current == end) 59 | { 60 | return {}; 61 | } 62 | auto exp = (*current)->reconstruct(current, end, 0, false); 63 | if (!exp.has_value()) 64 | { 65 | return {}; 66 | } 67 | strvec[i] = *exp; 68 | } 69 | for (auto it = strvec.rbegin(); it != strvec.rend(); it++) 70 | { 71 | if (it != strvec.rbegin()) 72 | { 73 | sstream << ", "; 74 | } 75 | sstream << *it; 76 | } 77 | sstream << "]"; 78 | return sstream.str(); 79 | } 80 | 81 | virtual bool equals(const instruction* p_other) const override 82 | { 83 | auto casted = dynamic_cast(p_other); 84 | return casted != nullptr && casted->m_array_size == m_array_size; 85 | } 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /src/opcodes/push.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/instruction.h" 3 | #include "../runtime/value.h" 4 | #include "../runtime/data.h" 5 | #include "../runtime/runtime.h" 6 | 7 | namespace sqf::opcodes 8 | { 9 | class push : public sqf::runtime::instruction 10 | { 11 | private: 12 | #if _DEBUG 13 | std::string ___TYPE = "push"; 14 | #endif 15 | sqf::runtime::value m_value; 16 | 17 | public: 18 | push(sqf::runtime::value value) : m_value(value) {} 19 | virtual void execute(sqf::runtime::runtime& vm) const override { vm.context_active().push_value(m_value); } 20 | virtual std::string to_string() const override { return std::string("PUSH ") + m_value.to_string_sqf(); } 21 | sqf::runtime::value::cref value() const { return m_value; } 22 | virtual std::optional reconstruct( 23 | std::vector::const_reverse_iterator& current, 24 | std::vector::const_reverse_iterator end, 25 | short parent_precedence, bool left_from_binary) const override 26 | { 27 | if (!m_value.empty()) 28 | { 29 | return m_value.data<::sqf::runtime::data>()->to_string_sqf(); 30 | } 31 | else 32 | { 33 | return "nil"; 34 | } 35 | } 36 | 37 | virtual bool equals(const instruction* p_other) const override 38 | { 39 | auto casted = dynamic_cast(p_other); 40 | return casted != nullptr && casted->m_value == m_value; 41 | } 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/operators/ReadMe.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQFvm/runtime/ea66b8afc04951004b83f7d746168415baeef9c0/src/operators/ReadMe.md -------------------------------------------------------------------------------- /src/operators/d_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../runtime/data.h" 8 | #include "../runtime/type.h" 9 | #include "../runtime/value.h" 10 | #include "../runtime/confighost.h" 11 | 12 | 13 | namespace sqf 14 | { 15 | namespace runtime 16 | { 17 | struct t_config : public type::extend { t_config() : extend() {} static const std::string name() { return "CONFIG"; } }; 18 | } 19 | namespace types 20 | { 21 | class d_config : public sqf::runtime::data 22 | { 23 | public: 24 | using data_type = sqf::runtime::t_config; 25 | private: 26 | sqf::runtime::config m_value; 27 | protected: 28 | bool do_equals(std::shared_ptr other, bool invariant) const override 29 | { 30 | auto other_config = std::static_pointer_cast(other)->m_value; 31 | return other_config == m_value; 32 | } 33 | public: 34 | d_config() = default; 35 | d_config(sqf::runtime::config conf) : m_value(conf) {} 36 | 37 | std::string to_string_sqf() const override 38 | { 39 | return std::string(m_value.name()); 40 | } 41 | std::string to_string() const override 42 | { 43 | return std::string(m_value.name()); 44 | } 45 | sqf::runtime::type type() const override { return data_type(); } 46 | virtual std::size_t hash() const override { return std::hash()(m_value.container_id()); } 47 | sqf::runtime::config value() const { return m_value; } 48 | void value(sqf::runtime::config conf) { m_value = conf; } 49 | 50 | operator sqf::runtime::config() { return m_value; } 51 | }; 52 | 53 | template<> 54 | inline std::shared_ptr to_data(sqf::runtime::config conf) 55 | { 56 | return std::make_shared(conf); 57 | } 58 | template<> 59 | inline std::shared_ptr to_data(sqf::runtime::confignav confignav) 60 | { 61 | return std::make_shared(*confignav); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/operators/d_group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/data.h" 3 | #include "../runtime/type.h" 4 | #include "../runtime/value.h" 5 | #include "group.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | namespace sqf 13 | { 14 | namespace runtime 15 | { 16 | struct t_group : public type::extend { t_group() : extend() {} static const std::string name() { return "GROUP"; } }; 17 | } 18 | namespace types 19 | { 20 | class d_group : public sqf::runtime::data 21 | { 22 | public: 23 | using data_type = sqf::runtime::t_group; 24 | private: 25 | std::weak_ptr m_value; 26 | protected: 27 | bool do_equals(std::shared_ptr other, bool invariant) const override 28 | { 29 | return value().get() == std::static_pointer_cast(other)->value().get(); 30 | } 31 | public: 32 | d_group() = default; 33 | d_group(std::weak_ptr value) : m_value(value) {} 34 | d_group(std::shared_ptr value) : m_value(value) {} 35 | 36 | 37 | std::string to_string_sqf() const override 38 | { 39 | auto obj = value(); 40 | if (!obj) 41 | { 42 | return "NULL"; 43 | } 44 | if (obj->group_id().empty()) 45 | { 46 | std::stringstream sstream; 47 | sstream << static_cast(obj.get()) << "# " << obj->netid() << ": " << d_side::to_string(obj->side()); 48 | return sstream.str(); 49 | } 50 | else 51 | { 52 | return std::string(obj->group_id()); 53 | } 54 | } 55 | std::string to_string() const override { return to_string_sqf(); } 56 | 57 | sqf::runtime::type type() const override { return data_type(); } 58 | virtual std::size_t hash() const override { return 0; } 59 | 60 | bool is_null() const { return m_value.expired(); } 61 | 62 | std::shared_ptr<::sqf::types::group> value() const 63 | { 64 | if (m_value.expired()) 65 | { 66 | return {}; 67 | } 68 | return m_value.lock(); 69 | } 70 | void value(std::shared_ptr<::sqf::types::group> val) { m_value = val; } 71 | 72 | operator std::shared_ptr<::sqf::types::group>() { return value(); } 73 | }; 74 | 75 | inline bool operator==(const std::shared_ptr left, const std::shared_ptr right) 76 | { 77 | if (left->is_null()) { return false; } 78 | return left->value() == right; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/operators/d_object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/data.h" 3 | #include "../runtime/type.h" 4 | #include "../runtime/value.h" 5 | #include "object.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | namespace sqf 13 | { 14 | namespace runtime 15 | { 16 | struct t_object : public type::extend { t_object() : extend() {} static const std::string name() { return "OBJECT"; } }; 17 | } 18 | namespace types 19 | { 20 | class d_object : public sqf::runtime::data 21 | { 22 | public: 23 | using data_type = sqf::runtime::t_object; 24 | private: 25 | std::weak_ptr m_value; 26 | protected: 27 | bool do_equals(std::shared_ptr other, bool invariant) const override 28 | { 29 | return value().get() == std::static_pointer_cast(other)->value().get(); 30 | } 31 | public: 32 | d_object() = default; 33 | d_object(std::weak_ptr value) : m_value(value) {} 34 | 35 | 36 | std::string to_string_sqf() const override 37 | { 38 | auto obj = value(); 39 | if (!obj) 40 | { 41 | return "NULL"; 42 | } 43 | if (obj->varname().empty()) 44 | { 45 | std::stringstream sstream; 46 | sstream << static_cast(obj.get()) << "# " << obj->netid() << ": " << obj->config().name(); 47 | return sstream.str(); 48 | } 49 | else 50 | { 51 | return std::string(obj->varname()); 52 | } 53 | } 54 | std::string to_string() const override { return to_string_sqf(); } 55 | 56 | sqf::runtime::type type() const override { return data_type(); } 57 | virtual std::size_t hash() const override { return 0; } 58 | 59 | bool is_null() const { return m_value.expired(); } 60 | 61 | std::shared_ptr<::sqf::types::object> value() const 62 | { 63 | if (m_value.expired()) 64 | { 65 | return {}; 66 | } 67 | return m_value.lock(); 68 | } 69 | void value(std::shared_ptr<::sqf::types::object> val) { m_value = val; } 70 | 71 | operator std::shared_ptr<::sqf::types::object>() { return value(); } 72 | }; 73 | template<> 74 | inline std::shared_ptr to_data>(std::shared_ptr value) 75 | { 76 | return std::make_shared(value); 77 | } 78 | 79 | inline bool operator==(const std::shared_ptr left, const std::shared_ptr right) 80 | { 81 | if (left->is_null()) { return false; } 82 | return left->value() == right; 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/operators/d_text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../runtime/data.h" 7 | #include "../runtime/type.h" 8 | #include "../runtime/value.h" 9 | 10 | 11 | namespace sqf 12 | { 13 | namespace runtime 14 | { 15 | struct t_text : public type::extend { t_text() : extend() {} static const std::string name() { return "TEXT"; } }; 16 | } 17 | namespace types 18 | { 19 | class d_text : public sqf::runtime::data 20 | { 21 | public: 22 | using data_type = sqf::runtime::t_text; 23 | private: 24 | std::string m_value; 25 | protected: 26 | bool do_equals(std::shared_ptr other, bool invariant) const override 27 | { 28 | auto other_text = std::static_pointer_cast(other)->m_value; 29 | return other_text == m_value; 30 | } 31 | public: 32 | d_text() = default; 33 | d_text(std::string str) : m_value(str) {} 34 | 35 | std::string to_string_sqf() const override 36 | { 37 | return m_value; 38 | } 39 | std::string to_string() const override 40 | { 41 | return m_value; 42 | } 43 | sqf::runtime::type type() const override { return data_type(); } 44 | virtual std::size_t hash() const override { return std::hash()(m_value); } 45 | std::string value() const { return m_value; } 46 | void value(std::string str) { m_value = str; } 47 | 48 | operator std::string() { return m_value; } 49 | operator std::string_view() { return m_value; } 50 | }; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/operators/dlops.cpp: -------------------------------------------------------------------------------- 1 | #include "dlops.h" 2 | #include 3 | #include 4 | 5 | #if defined(__linux__) || defined(__APPLE__) || defined(__unix__) 6 | #include 7 | #define DLOPS_LIB_OPEN(P) dlopen(P, RTLD_LAZY) 8 | #define DLOPS_LIB_CLOSE(H) dlclose(H) 9 | #define DLOPS_LIB_SYM(H, N) dlsym(H, N) 10 | #define DLOPS_LIB_GETLASTERROR() dlerror() 11 | #define DLOPS_LIB_HANDLE void* 12 | #elif defined(_WIN32) 13 | #include 14 | #define DLOPS_LIB_OPEN(P) LoadLibraryA(P) 15 | #define DLOPS_LIB_CLOSE(H) FreeLibrary(H) 16 | #define DLOPS_LIB_SYM(H, N) GetProcAddress(H, N) 17 | #define DLOPS_LIB_GETLASTERROR() std::to_string(GetLastError()) 18 | #define DLOPS_LIB_HANDLE HMODULE 19 | #else 20 | #define DLOPS_LIB_OPEN(P) 21 | #define DLOPS_LIB_CLOSE(H) 22 | #define DLOPS_LIB_SYM(H, N) 23 | #define DLOPS_LIB_GETLASTERROR() 24 | #define DLOPS_LIB_HANDLE 25 | #error UNSUPPORTED PLATFORM 26 | #endif 27 | 28 | dlops::dlops(std::string path) 29 | { 30 | handle = DLOPS_LIB_OPEN(path.c_str()); 31 | if (nullptr == handle) 32 | { 33 | std::stringstream sstream; 34 | sstream << "Loading Library failed with error code '" << DLOPS_LIB_GETLASTERROR() << "'"; 35 | throw std::runtime_error(sstream.str()); 36 | } 37 | mpath = path; 38 | } 39 | 40 | void* dlops::resolve(std::string name) 41 | { 42 | if (nullptr == handle) 43 | return nullptr; 44 | auto res = DLOPS_LIB_SYM(static_cast(handle), name.c_str()); 45 | if (nullptr == res) 46 | { 47 | std::stringstream sstream; 48 | sstream << "Receiving symbol failed with error '" << DLOPS_LIB_GETLASTERROR() << "'"; 49 | throw std::runtime_error(sstream.str()); 50 | } 51 | else 52 | { 53 | return res; 54 | } 55 | }; 56 | 57 | bool dlops::try_resolve(std::string name, void** outptr) 58 | { 59 | if (nullptr == handle) 60 | return false; 61 | *outptr = DLOPS_LIB_SYM(static_cast(handle), name.c_str()); 62 | return *outptr; 63 | } 64 | 65 | void dlops::close() 66 | { 67 | if (nullptr == handle) 68 | return; 69 | #if defined(__linux__) 70 | if (DLOPS_LIB_CLOSE(handle)) 71 | #elif defined(_WIN32) 72 | if (!DLOPS_LIB_CLOSE(static_cast(handle))) 73 | #else 74 | if (DLOPS_LIB_CLOSE(handle)) 75 | #endif 76 | { 77 | std::stringstream sstream; 78 | sstream << "Closing library failed with error code '" << DLOPS_LIB_GETLASTERROR() << "'"; 79 | throw std::runtime_error(sstream.str()); 80 | } 81 | } 82 | 83 | 84 | 85 | #undef DLOPS_LIB_OPEN 86 | #undef DLOPS_LIB_CLOSE 87 | #undef DLOPS_LIB_SYM 88 | #undef DLOPS_LIB_GETLASTERROR 89 | #undef DLOPS_LIB_HANDLE 90 | -------------------------------------------------------------------------------- /src/operators/dlops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | class dlops 7 | { 8 | private: 9 | void* handle; 10 | std::string mpath; 11 | public: 12 | //Prevent copy 13 | dlops(const dlops&) = delete; 14 | void operator=(dlops const &x) = delete; 15 | 16 | 17 | dlops(std::string path); 18 | ~dlops() 19 | { 20 | close(); 21 | } 22 | std::string path() { return mpath; } 23 | 24 | void* resolve(std::string name); 25 | bool try_resolve(std::string name, void** outptr); 26 | void close(); 27 | }; 28 | -------------------------------------------------------------------------------- /src/operators/dlops_storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/runtime.h" 3 | #include "dlops.h" 4 | 5 | #include 6 | namespace sqf::operators 7 | { 8 | class dlops_storage : public ::sqf::runtime::runtime::datastorage 9 | { 10 | private: 11 | std::vector> m_dlops; 12 | public: 13 | virtual ~dlops_storage() override {} 14 | void push_back(std::shared_ptr dl) { m_dlops.push_back(dl); } 15 | std::vector>::iterator begin() { return m_dlops.begin(); } 16 | std::vector>::iterator end() { return m_dlops.end(); } 17 | }; 18 | } -------------------------------------------------------------------------------- /src/operators/group.cpp: -------------------------------------------------------------------------------- 1 | #include "group.h" 2 | 3 | std::shared_ptr sqf::types::group::create(::sqf::runtime::runtime& runtime) 4 | { 5 | auto& storage = runtime.storage(); 6 | auto sp_obj = std::shared_ptr(new sqf::types::group()); 7 | auto net_id = storage.push_back(sp_obj); 8 | sp_obj->m_netid = net_id; 9 | return sp_obj; 10 | } 11 | 12 | void sqf::types::group::destroy(::sqf::runtime::runtime& runtime) 13 | { 14 | auto& storage = runtime.storage(); 15 | storage.erase(shared_from_this()); 16 | } -------------------------------------------------------------------------------- /src/operators/ops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ops_config.h" 3 | #include "ops_diag.h" 4 | #include "ops_generic.h" 5 | #include "ops_group.h" 6 | #include "ops_logic.h" 7 | #include "ops_markers.h" 8 | #include "ops_math.h" 9 | #include "ops_namespace.h" 10 | #include "ops_object.h" 11 | #include "ops_sqfvm.h" 12 | #include "ops_string.h" 13 | #include "ops_text.h" 14 | #include "ops_dummy_nular.h" 15 | #include "ops_dummy_unary.h" 16 | #include "ops_dummy_binary.h" 17 | #include "ops_osspecific.h" 18 | #include "ops_hashmap.h" 19 | 20 | namespace sqf 21 | { 22 | namespace runtime 23 | { 24 | class runtime; 25 | } 26 | 27 | namespace operators 28 | { 29 | inline void ops(::sqf::runtime::runtime& runtime) 30 | { 31 | sqf::operators::ops_config(runtime); 32 | sqf::operators::ops_diag(runtime); 33 | sqf::operators::ops_generic(runtime); 34 | sqf::operators::ops_group(runtime); 35 | sqf::operators::ops_logic(runtime); 36 | sqf::operators::ops_markers(runtime); 37 | sqf::operators::ops_math(runtime); 38 | sqf::operators::ops_namespace(runtime); 39 | sqf::operators::ops_object(runtime); 40 | sqf::operators::ops_sqfvm(runtime); 41 | sqf::operators::ops_string(runtime); 42 | sqf::operators::ops_text(runtime); 43 | sqf::operators::ops_dummy_nular(runtime); 44 | sqf::operators::ops_dummy_unary(runtime); 45 | sqf::operators::ops_dummy_binary(runtime); 46 | sqf::operators::ops_osspecific(runtime); 47 | sqf::operators::ops_hashmap(runtime); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/operators/ops_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace sqf::runtime 5 | { 6 | class runtime; 7 | } 8 | namespace sqf::operators 9 | { 10 | void ops_config(::sqf::runtime::runtime& runtime); 11 | } -------------------------------------------------------------------------------- /src/operators/ops_diag.cpp: -------------------------------------------------------------------------------- 1 | #include "ops_diag.h" 2 | #include "../runtime/value.h" 3 | #include "../runtime/runtime.h" 4 | #include "../runtime/sqfop.h" 5 | 6 | #include "../runtime/d_string.h" 7 | #include "../runtime/d_scalar.h" 8 | #include "../runtime/d_boolean.h" 9 | 10 | #include 11 | 12 | namespace err = logmessage::runtime; 13 | using namespace sqf::runtime; 14 | using namespace sqf::types; 15 | namespace 16 | { 17 | value diag_log_any(runtime& runtime, value::cref right) 18 | { 19 | auto r = right.to_string(); 20 | runtime.__logmsg(err::InfoMessage(runtime.context_active().current_frame().diag_info_from_position(), "DIAG_LOG", r)); 21 | return {}; 22 | } 23 | value diag_tickTime_(runtime& runtime) 24 | { 25 | auto curtime = std::chrono::system_clock::now().time_since_epoch(); 26 | auto starttime = runtime.runtime_timestamp().time_since_epoch(); 27 | // Time is since beginning of game so long is fine. 28 | long long r = static_cast(std::chrono::duration_cast(curtime - starttime).count()); 29 | double d = r * 0.001; 30 | float f = (float)d; 31 | return { f }; 32 | } 33 | value assert_bool(runtime& runtime, value::cref right) 34 | { 35 | auto r = right.data()->value(); 36 | if (!r) 37 | { 38 | runtime.__logmsg(err::AssertFailed(runtime.context_active().current_frame().diag_info_from_position())); 39 | } 40 | return right; 41 | } 42 | value halt_(runtime& runtime) 43 | { 44 | runtime.execute(sqf::runtime::runtime::action::stop); 45 | return {}; 46 | } 47 | } 48 | void sqf::operators::ops_diag(::sqf::runtime::runtime& runtime) 49 | { 50 | runtime.register_sqfop(sqfop::unary("diag_log", t_any(), "Dumps the argument's value to the report file. Each call creates a new line in the file.", diag_log_any)); 51 | runtime.register_sqfop(sqfop::nular("diag_tickTime", "Real time spent from the start of the runtime. Expressed in fractions of second. Resolution of 1 tick is 1 ms.", diag_tickTime_)); 52 | runtime.register_sqfop(sqfop::unary("assert", t_boolean(), "Tests a condition and if the condition is false, displays error on screen.", assert_bool)); 53 | runtime.register_sqfop(sqfop::nular("halt", "Halts the execution if a debugger is attached. If not, warning is logged and execution continues.", halt_)); 54 | } -------------------------------------------------------------------------------- /src/operators/ops_diag.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace sqf::runtime 5 | { 6 | class runtime; 7 | } 8 | namespace sqf::operators 9 | { 10 | void ops_diag(::sqf::runtime::runtime& runtime); 11 | } -------------------------------------------------------------------------------- /src/operators/ops_dummy_binary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_dummy_binary(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_dummy_nular.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_dummy_nular(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_dummy_unary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_dummy_unary(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_group(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_hashmap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/data.h" 3 | #include "../runtime/type.h" 4 | #include "../runtime/value.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | namespace sqf 14 | { 15 | namespace runtime 16 | { 17 | struct t_hashmap : public type::extend { t_hashmap() : extend() {} static const std::string name() { return "HASHMAP"; } }; 18 | class runtime; 19 | } 20 | namespace types 21 | { 22 | class d_hashmap : public sqf::runtime::data 23 | { 24 | private: 25 | std::unordered_map m_map; 26 | public: 27 | using data_type = sqf::runtime::t_hashmap; 28 | protected: 29 | virtual bool do_equals(std::shared_ptr other, bool invariant) const 30 | { 31 | auto& other_map = std::static_pointer_cast(other)->map(); 32 | auto& self_map = m_map; 33 | 34 | return other_map == self_map; 35 | } 36 | public: 37 | d_hashmap() = default; 38 | d_hashmap(std::unordered_map map) : m_map(map) {} 39 | 40 | sqf::runtime::type type() const override { return data_type(); } 41 | virtual std::size_t hash() const override 42 | { 43 | size_t hash = 0x9e3779b9; 44 | for (auto& it : m_map) 45 | { 46 | hash ^= std::hash()(it.first) + 0x9e3779b9 + (hash << 6) + (hash >> 2); 47 | hash ^= std::hash()(it.second) + 0x9e3779b9 + (hash << 6) + (hash >> 2); 48 | } 49 | return hash; 50 | } 51 | 52 | std::string to_string_sqf() const override 53 | { 54 | std::stringstream sstream; 55 | sstream << "["; 56 | if (m_map.size() > 0) 57 | { 58 | for (auto it : m_map) 59 | { 60 | sstream << "[" << it.first.to_string_sqf() << "," << it.second.to_string_sqf() << "]" << ","; 61 | } 62 | sstream.seekp(-1, std::ios_base::end); 63 | } 64 | sstream << "]"; 65 | return sstream.str(); 66 | } 67 | std::string to_string() const override 68 | { 69 | std::stringstream sstream; 70 | sstream << "["; 71 | if (m_map.size() > 0) 72 | { 73 | for (auto it : m_map) 74 | { 75 | sstream << it.first.to_string() << ": " << it.second.to_string() << ","; 76 | } 77 | sstream.seekp(-1, std::ios_base::end); 78 | } 79 | sstream << "}"; 80 | return sstream.str(); 81 | } 82 | 83 | std::unordered_map& map() { return m_map; } 84 | }; 85 | } 86 | 87 | namespace operators 88 | { 89 | void ops_hashmap(::sqf::runtime::runtime& runtime); 90 | } 91 | } -------------------------------------------------------------------------------- /src/operators/ops_logic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_logic(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace sqf::runtime 5 | { 6 | class runtime; 7 | } 8 | namespace sqf::operators 9 | { 10 | void ops_math(::sqf::runtime::runtime& runtime); 11 | } -------------------------------------------------------------------------------- /src/operators/ops_namespace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/data.h" 3 | #include "../runtime/type.h" 4 | #include "../runtime/value.h" 5 | #include "../runtime/value_scope.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace sqf 11 | { 12 | namespace runtime 13 | { 14 | inline static const std::string missionNamespace = "missionNamespace"; 15 | inline static const std::string profileNamespace = "profileNamespace"; 16 | inline static const std::string uiNamespace = "uiNamespace"; 17 | inline static const std::string parsingNamespace = "parsingNamespace"; 18 | inline static const std::string localNamespace = "localNamespace"; 19 | 20 | struct t_with : public sqf::runtime::type::extend { t_with() : extend() {} static const std::string name() { return "WITH"; } }; 21 | struct t_namespace : public sqf::runtime::type::extend { t_namespace() : extend() {} static const std::string name() { return "NAMESPACE"; } }; 22 | class runtime; 23 | class context; 24 | class instruction_set; 25 | } 26 | namespace types 27 | { 28 | class d_namespace : public sqf::runtime::data 29 | { 30 | public: 31 | using data_type = sqf::runtime::t_namespace; 32 | private: 33 | std::weak_ptr m_scope; 34 | protected: 35 | bool do_equals(std::shared_ptr other, bool ignoreCase) const override 36 | { 37 | auto otherNs = std::static_pointer_cast(other); 38 | if (!m_scope.expired() && !otherNs->m_scope.expired()) 39 | { 40 | return m_scope.lock() == otherNs->m_scope.lock(); 41 | } 42 | else if (m_scope.expired() && otherNs->m_scope.expired()) 43 | { 44 | return true; 45 | } 46 | else 47 | { 48 | return false; 49 | } 50 | } 51 | public: 52 | d_namespace() = default; 53 | d_namespace(std::shared_ptr scope) : m_scope(scope) {} 54 | 55 | virtual std::string to_string_sqf() const override 56 | { 57 | if (m_scope.expired()) 58 | { 59 | return "nil"; 60 | } 61 | else 62 | { 63 | return std::string(m_scope.lock()->scope_name()); 64 | } 65 | } 66 | 67 | virtual std::string to_string() const override { return to_string_sqf(); } 68 | sqf::runtime::type type() const override { return data_type(); } 69 | virtual std::size_t hash() const override { return 0; } 70 | 71 | std::shared_ptr value() { return m_scope.lock(); } 72 | operator std::shared_ptr() { return m_scope.lock(); } 73 | }; 74 | class d_with : public sqf::types::d_namespace 75 | { 76 | public: 77 | using data_type = sqf::runtime::t_with; 78 | public: 79 | d_with() = default; 80 | d_with(std::shared_ptr scope) : d_namespace(scope) {} 81 | 82 | sqf::runtime::type type() const override { return data_type(); } 83 | }; 84 | } 85 | 86 | namespace operators 87 | { 88 | void ops_namespace(::sqf::runtime::runtime& runtime); 89 | } 90 | } -------------------------------------------------------------------------------- /src/operators/ops_object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_object(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_osspecific.cpp: -------------------------------------------------------------------------------- 1 | #include "ops_osspecific.h" 2 | #include "../runtime/runtime.h" 3 | #include "../runtime/value.h" 4 | #include "../runtime/d_string.h" 5 | 6 | #ifdef _WIN32 7 | // Required due to some headers using WinSock2.h 8 | // & some headers requiring windows.h 9 | // If this was not here, a link conflict would emerge due to 10 | // windows.h including winsock1 11 | #include 12 | #endif 13 | 14 | namespace err = logmessage::runtime; 15 | using namespace sqf::runtime; 16 | using namespace sqf::types; 17 | namespace 18 | { 19 | sqf::runtime::value copytoclipboard_string(sqf::runtime::runtime& runtime, sqf::runtime::value::cref right) 20 | { 21 | #if defined(_WIN32) & !defined(DISABLE_CLIPBOARD) 22 | auto data = right.data(); 23 | if (!OpenClipboard(NULL)) 24 | { 25 | //vm->wrn() << "Failed to access clipboard." << std::endl; 26 | runtime.__logmsg(err::FailedToCopyToClipboard(runtime.context_active().current_frame().diag_info_from_position())); 27 | return {}; 28 | } 29 | EmptyClipboard(); 30 | HGLOBAL hClipboardData = GlobalAlloc(GMEM_DDESHARE, data.length() + 1); 31 | if (hClipboardData == NULL) 32 | { 33 | //vm->wrn() << "Failed to allocate clipboard." << std::endl; 34 | runtime.__logmsg(err::FailedToCopyToClipboard(runtime.context_active().current_frame().diag_info_from_position())); 35 | return {}; 36 | } 37 | char* pchData = (char*)GlobalLock(hClipboardData); 38 | strcpy(pchData, data.c_str()); 39 | GlobalUnlock(hClipboardData); 40 | SetClipboardData(CF_TEXT, hClipboardData); 41 | CloseClipboard(); 42 | 43 | #else 44 | runtime.__logmsg(err::ClipboardDisabled(runtime.context_active().current_frame().diag_info_from_position())); 45 | #endif 46 | return {}; 47 | 48 | } 49 | } 50 | void sqf::operators::ops_osspecific(sqf::runtime::runtime& runtime) 51 | { 52 | using namespace sqf::runtime::sqfop; 53 | runtime.register_sqfop(unary("copyToClipboard", t_string(), "Copy text string to the clipboard.", copytoclipboard_string)); /* STRING */ 54 | } -------------------------------------------------------------------------------- /src/operators/ops_osspecific.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_osspecific(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_sqfvm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace sqf::runtime 5 | { 6 | class runtime; 7 | } 8 | namespace sqf::operators 9 | { 10 | void ops_sqfvm(::sqf::runtime::runtime& runtime); 11 | } -------------------------------------------------------------------------------- /src/operators/ops_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_string(::sqf::runtime::runtime& runtime); 13 | } 14 | } -------------------------------------------------------------------------------- /src/operators/ops_text.cpp: -------------------------------------------------------------------------------- 1 | #include "ops_text.h" 2 | #include "../runtime/value.h" 3 | #include "../runtime/logging.h" 4 | #include "../runtime/runtime.h" 5 | 6 | #include "../runtime/d_string.h" 7 | #include "../runtime/d_array.h" 8 | #include "d_text.h" 9 | 10 | namespace err = logmessage::runtime; 11 | using namespace sqf::runtime; 12 | using namespace sqf::types; 13 | using namespace std::string_literals; 14 | 15 | namespace 16 | { 17 | value composetext_array(runtime& runtime, value::cref right) 18 | { 19 | auto r = right.data(); 20 | std::stringstream sstream; 21 | for (auto& it : *r) 22 | { 23 | sstream << it.data(); 24 | } 25 | return std::make_shared(sstream.str()); 26 | } 27 | value linebreak_(runtime& runtime) 28 | { 29 | return std::make_shared("\r\n"s); 30 | } 31 | value parsetext_string(runtime& runtime, value::cref right) 32 | { 33 | return std::make_shared(right.data()); 34 | } 35 | value text_string(runtime& runtime, value::cref right) 36 | { 37 | return std::make_shared(right.data()); 38 | } 39 | } 40 | void sqf::operators::ops_text(sqf::runtime::runtime& runtime) 41 | { 42 | using namespace sqf::runtime::sqfop; 43 | 44 | runtime.register_sqfop(unary("composeText", t_array(), "Creates a structured text containing a line break.", composetext_array)); 45 | runtime.register_sqfop(nular("lineBreak", "Creates a structured text containing a line break.", linebreak_)); 46 | runtime.register_sqfop(unary("parseText", t_string(), "Creates a structured text by parsing the given XML description.", parsetext_string)); 47 | runtime.register_sqfop(unary("text", t_string(), "Creates a structured text containing the given plain text if argument is String.", text_string)); 48 | } 49 | -------------------------------------------------------------------------------- /src/operators/ops_text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf 4 | { 5 | namespace runtime 6 | { 7 | class runtime; 8 | } 9 | 10 | namespace operators 11 | { 12 | void ops_text(::sqf::runtime::runtime& runtime); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/parser/ReadMe.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQFvm/runtime/ea66b8afc04951004b83f7d746168415baeef9c0/src/parser/ReadMe.md -------------------------------------------------------------------------------- /src/parser/assembly/assembly_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../runtime/parser/sqf.h" 3 | #include "../../runtime/logging.h" 4 | #include "../../runtime/diagnostics/diag_info.h" 5 | #include "../../runtime/fileio.h" 6 | #include "../../runtime/util.h" 7 | #include "../../runtime/value.h" 8 | #include "../../runtime/instruction_set.h" 9 | #include "tokenizer.hpp" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | 17 | namespace sqf::parser::assembly::bison 18 | { 19 | struct astnode; 20 | } 21 | namespace sqf::parser::assembly 22 | { 23 | class parser : public ::sqf::runtime::parser::sqf, public CanLog 24 | { 25 | private: 26 | ::sqf::runtime::value get_value(::sqf::runtime::runtime& runtime, std::string_view contents, const ::sqf::parser::assembly::bison::astnode& node); 27 | void to_assembly(::sqf::runtime::runtime& runtime, std::string_view contents, const ::sqf::parser::assembly::bison::astnode& node, std::vector<::sqf::runtime::instruction::sptr>& set); 28 | public: 29 | parser(Logger& logger) : CanLog(logger) 30 | { 31 | } 32 | void __log(LogMessageBase&& msg) const 33 | { 34 | log(msg); 35 | } 36 | bool get_tree(::sqf::runtime::runtime& runtime, tokenizer& t, bison::astnode* out); 37 | virtual ~parser() override { }; 38 | virtual bool check_syntax(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override; 39 | virtual std::optional<::sqf::runtime::instruction_set> parse(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/parser/assembly/astnode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf::parser::assembly::bison 4 | { 5 | enum class astkind 6 | { 7 | ENDOFFILE = -3, 8 | INVALID = -2, 9 | __TOKEN = -1, 10 | NA = 0, 11 | STATEMENTS, 12 | STATEMENT, 13 | IDENT, 14 | NUMBER, 15 | HEXNUMBER, 16 | STRING, 17 | BOOLEAN_TRUE, 18 | BOOLEAN_FALSE, 19 | EXPRESSION_LIST, 20 | CODE, 21 | ARRAY, 22 | ASSIGN_TO, 23 | ASSIGN_TO_LOCAL, 24 | GET_VARIABLE, 25 | CALL_UNARY, 26 | CALL_NULAR, 27 | CALL_BINARY, 28 | PUSH, 29 | END_STATEMENT, 30 | }; 31 | struct astnode 32 | { 33 | ::sqf::parser::assembly::tokenizer::token token; 34 | astkind kind; 35 | std::vector children; 36 | 37 | astnode() : token(), kind(astkind::NA) { } 38 | astnode(astkind kind) : token(), kind(kind) { } 39 | astnode(::sqf::parser::assembly::tokenizer::token t) : token(t), kind(astkind::__TOKEN) { } 40 | astnode(astkind kind, ::sqf::parser::assembly::tokenizer::token t) : token(t), kind(kind) { } 41 | 42 | void append(astnode node) 43 | { 44 | children.push_back(node); 45 | } 46 | void append_children(const astnode& other) 47 | { 48 | for (auto node : other.children) 49 | { 50 | append(node); 51 | } 52 | } 53 | }; 54 | } -------------------------------------------------------------------------------- /src/parser/config/config_parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../runtime/parser/config.h" 3 | #include "../../runtime/logging.h" 4 | #include "../../runtime/diagnostics/diag_info.h" 5 | #include "../../runtime/fileio.h" 6 | #include "../../runtime/util.h" 7 | #include "../../runtime/instruction_set.h" 8 | #include "tokenizer.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | 17 | namespace sqf::parser::config::bison 18 | { 19 | struct astnode; 20 | } 21 | namespace sqf::parser::config 22 | { 23 | class parser : public ::sqf::runtime::parser::config, public CanLog 24 | { 25 | private: 26 | bool apply_to_confighost(::sqf::parser::config::bison::astnode& node, ::sqf::runtime::confighost& confighost, ::sqf::runtime::confignav parent); 27 | public: 28 | parser(Logger& logger) : CanLog(logger) 29 | { 30 | } 31 | void __log(LogMessageBase&& msg) const 32 | { 33 | log(msg); 34 | } 35 | bool get_tree(::sqf::runtime::runtime& runtime, tokenizer& t, bison::astnode* out); 36 | virtual ~parser() override { }; 37 | virtual bool check_syntax(std::string contents, ::sqf::runtime::fileio::pathinfo pathinfo) override; 38 | virtual bool parse(::sqf::runtime::confighost& target, std::string contents, ::sqf::runtime::fileio::pathinfo pathinfo) override; 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/parser/pbo/parsepbo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | class PboProperty { 10 | public: 11 | PboProperty() {} 12 | PboProperty(std::string k, std::string v): key(std::move(k)), value(std::move(v)) {} 13 | 14 | std::string key; 15 | std::string value; 16 | 17 | bool read(std::istream& in); 18 | }; 19 | 20 | enum class PboEntryPackingMethod { 21 | none, 22 | version, 23 | compressed, 24 | encrypted 25 | }; 26 | 27 | class PboEntry { 28 | public: 29 | std::string name; 30 | 31 | uint32_t original_size = 0; 32 | uint32_t data_size = 0; 33 | uint32_t startOffset = 0; 34 | PboEntryPackingMethod method = PboEntryPackingMethod::none; 35 | 36 | void read(std::istream& in); 37 | }; 38 | 39 | class PboReader; 40 | class PboEntryBuffer : public std::streambuf { 41 | std::vector buffer; 42 | const PboEntry& file; 43 | const PboReader& reader; 44 | //What position the character after the last character that's currently in our buffer, corresponds to in the pbofile 45 | //Meaning on next read, the first character read is that pos 46 | size_t bufferEndFilePos{0}; 47 | public: 48 | PboEntryBuffer(const PboReader& rd, const PboEntry& ent, uint32_t bufferSize = 4096u); 49 | 50 | void setBufferSize(size_t newSize); 51 | int underflow() override; 52 | std::streamsize xsgetn(char* _Ptr, std::streamsize _Count) override; 53 | pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) override; 54 | pos_type seekpos(pos_type, std::ios_base::openmode) override; 55 | std::streamsize showmanyc() override; 56 | 57 | void setBuffersize(size_t newSize) { 58 | buffer.resize(newSize); 59 | } 60 | }; 61 | 62 | class PboReader { 63 | friend class PboEntryBuffer; 64 | 65 | std::vector files; 66 | std::vector properties; 67 | uint32_t propertiesEnd{0}; 68 | uint32_t headerEnd{0}; 69 | std::istream& input; 70 | std::array hash; 71 | bool badHeader{false}; 72 | public: 73 | PboReader(std::istream &input) : input(input) {} 74 | void readHeaders(); 75 | const auto& getFiles() const noexcept { return files; } 76 | PboEntryBuffer getFileBuffer(const PboEntry& ent) const { 77 | return PboEntryBuffer(*this, ent); 78 | } 79 | const auto& getProperties() const { return properties; } 80 | const auto& getHash() const { return hash; } 81 | //Broken 3DEN exported pbo with no header 82 | bool isBadHeader() const{ return badHeader; } 83 | }; 84 | 85 | -------------------------------------------------------------------------------- /src/parser/sqf/astnode.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf::parser::sqf::bison 4 | { 5 | enum class astkind 6 | { 7 | ENDOFFILE = -3, 8 | INVALID = -2, 9 | __TOKEN = -1, 10 | NA = 0, 11 | STATEMENTS, 12 | STATEMENT, 13 | IDENT, 14 | NUMBER, 15 | HEXNUMBER, 16 | STRING, 17 | BOOLEAN_TRUE, 18 | BOOLEAN_FALSE, 19 | EXPRESSION_LIST, 20 | CODE, 21 | ARRAY, 22 | ASSIGNMENT, 23 | ASSIGNMENT_LOCAL, 24 | EXPN, 25 | EXP0, 26 | EXP1, 27 | EXP2, 28 | EXP3, 29 | EXP4, 30 | EXP5, 31 | EXP6, 32 | EXP7, 33 | EXP8, 34 | EXP9, 35 | EXPU 36 | }; 37 | struct astnode 38 | { 39 | ::sqf::parser::sqf::tokenizer::token token; 40 | astkind kind; 41 | std::vector children; 42 | 43 | astnode() : token(), kind(astkind::NA) { } 44 | astnode(astkind kind) : token(), kind(kind) { } 45 | astnode(::sqf::parser::sqf::tokenizer::token t) : token(t), kind(astkind::__TOKEN) { } 46 | astnode(astkind kind, ::sqf::parser::sqf::tokenizer::token t) : token(t), kind(kind) { } 47 | 48 | void append(astnode node) 49 | { 50 | children.push_back(node); 51 | } 52 | void append_children(const astnode& other) 53 | { 54 | for (auto node : other.children) 55 | { 56 | append(node); 57 | } 58 | } 59 | }; 60 | } -------------------------------------------------------------------------------- /src/parser/sqf/sqf_formatter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tokenizer.hpp" 3 | #include "parser.tab.hh" 4 | #include "../../runtime/fileio.h" 5 | #include "../../runtime/runtime.h" 6 | #include "sqf_parser.hpp" 7 | 8 | #include 9 | #include 10 | 11 | namespace sqf::parser::sqf { 12 | class formatter { 13 | private: 14 | bool hasError = false; 15 | ::sqf::runtime::runtime& runtime; 16 | std::string contents; 17 | ::sqf::runtime::fileio::pathinfo file; 18 | ::sqf::parser::sqf::bison::astnode res; 19 | public: 20 | formatter(::sqf::runtime::runtime& r, std::string c, ::sqf::runtime::fileio::pathinfo f); 21 | ::sqf::parser::sqf::bison::astnode& getRes() { return this->res; } 22 | void prettify(const ::sqf::parser::sqf::bison::astnode& node, size_t depth, std::ostringstream& buff); 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/parser/sqf/sqf_parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../../runtime/parser/sqf.h" 3 | #include "../../runtime/logging.h" 4 | #include "../../runtime/diagnostics/diag_info.h" 5 | #include "../../runtime/fileio.h" 6 | #include "../../runtime/util.h" 7 | #include "../../runtime/instruction_set.h" 8 | #include "tokenizer.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | 16 | namespace sqf::parser::sqf::bison 17 | { 18 | struct astnode; 19 | } 20 | namespace sqf::parser::sqf 21 | { 22 | class parser : public ::sqf::runtime::parser::sqf, public CanLog 23 | { 24 | private: 25 | void to_assembly(std::string_view contents, const ::sqf::parser::sqf::bison::astnode& node, std::vector<::sqf::runtime::instruction::sptr>& set); 26 | public: 27 | parser(Logger& logger) : CanLog(logger) 28 | { 29 | } 30 | void __log(LogMessageBase&& msg) const 31 | { 32 | log(msg); 33 | } 34 | bool get_tree(::sqf::runtime::runtime& runtime, tokenizer& t, bison::astnode* out); 35 | virtual ~parser() override { }; 36 | virtual bool check_syntax(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override; 37 | virtual std::optional<::sqf::runtime::instruction_set> parse(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/runtime/ReadMe.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQFvm/runtime/ea66b8afc04951004b83f7d746168415baeef9c0/src/runtime/ReadMe.md -------------------------------------------------------------------------------- /src/runtime/d_boolean.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "data.h" 3 | #include "type.h" 4 | #include "value.h" 5 | 6 | 7 | #include 8 | #include 9 | 10 | namespace sqf 11 | { 12 | namespace runtime 13 | { 14 | struct t_boolean : public type::extend { t_boolean() : extend() {} static const std::string name() { return "BOOL"; } }; 15 | } 16 | namespace types 17 | { 18 | class d_boolean : public sqf::runtime::data 19 | { 20 | public: 21 | using data_type = sqf::runtime::t_boolean; 22 | private: 23 | bool m_value; 24 | protected: 25 | bool do_equals(std::shared_ptr other, bool invariant) const override 26 | { 27 | return m_value == std::static_pointer_cast(other)->m_value; 28 | } 29 | public: 30 | d_boolean() = default; 31 | d_boolean(bool flag) : m_value(flag) {} 32 | 33 | std::string to_string_sqf() const override 34 | { 35 | return m_value ? "true" : "false"; 36 | } 37 | std::string to_string() const override 38 | { 39 | return m_value ? "true" : "false"; 40 | } 41 | 42 | sqf::runtime::type type() const override { return data_type(); } 43 | virtual std::size_t hash() const override { return std::hash()(m_value); } 44 | 45 | bool value() const { return m_value; } 46 | void value(bool flag) { m_value = flag; } 47 | 48 | operator bool() 49 | { 50 | return m_value; 51 | } 52 | }; 53 | template<> 54 | inline std::shared_ptr to_data(bool flag) 55 | { 56 | return std::make_shared(flag); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/runtime/d_scalar.cpp: -------------------------------------------------------------------------------- 1 | #include "d_scalar.h" 2 | #include 3 | #include 4 | 5 | 6 | std::string sqf::types::d_scalar::to_string_sqf() const 7 | { 8 | if (s_decimals == -1) 9 | { 10 | auto bufflen = std::snprintf(nullptr, 0, "%g", m_value) + 1; 11 | auto buff = new char[bufflen]; 12 | std::snprintf(buff, bufflen, "%g", m_value); 13 | auto str = std::string(buff, bufflen - 1); 14 | delete[] buff; 15 | return str; 16 | } 17 | else 18 | { 19 | auto bufflen = std::snprintf(nullptr, 0, "%0.*f", s_decimals, m_value) + 1; 20 | auto buff = new char[bufflen]; 21 | std::snprintf(buff, bufflen, "%0.*f", s_decimals, m_value); 22 | auto str = std::string(buff, bufflen - 1); 23 | delete[] buff; 24 | return str; 25 | } 26 | } 27 | 28 | std::string sqf::types::d_scalar::to_string() const 29 | { 30 | if (s_decimals == -1) 31 | { 32 | auto bufflen = std::snprintf(nullptr, 0, "%g", m_value) + 1; 33 | auto buff = new char[bufflen]; 34 | std::snprintf(buff, bufflen, "%g", m_value); 35 | auto str = std::string(buff, bufflen - 1); 36 | delete[] buff; 37 | return str; 38 | } 39 | else 40 | { 41 | auto bufflen = std::snprintf(nullptr, 0, "%0.*f", s_decimals, m_value) + 1; 42 | auto buff = new char[bufflen]; 43 | std::snprintf(buff, bufflen, "%0.*f", s_decimals, m_value); 44 | auto str = std::string(buff, bufflen - 1); 45 | delete[] buff; 46 | return str; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/runtime/data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "type.h" 6 | 7 | namespace sqf::runtime 8 | { 9 | class runtime; 10 | class data 11 | { 12 | template 13 | struct empty_delete 14 | { 15 | empty_delete() /* noexcept */ 16 | { 17 | } 18 | 19 | template 20 | empty_delete(const empty_delete&, 21 | typename std::enable_if< 22 | std::is_convertible::value 23 | >::type* = nullptr) /* noexcept */ 24 | { 25 | } 26 | 27 | void operator()(T* const) const /* noexcept */ 28 | { 29 | // do nothing 30 | } 31 | }; 32 | protected: 33 | /// 34 | /// Performs the actual comparison. 35 | /// Compares this value against the other value and returns 36 | /// true if they are equivalent. 37 | /// If invariant false, comparison should be case-sensitive. 38 | /// 39 | /// The other value 40 | /// Wether operation should be case sensitive (false) or not (true) 41 | /// The result of the comparison 42 | virtual bool do_equals(std::shared_ptr other, bool invariant) const = 0; 43 | 44 | public: 45 | 46 | /// 47 | /// Returns the SQF representation of this datatype. 48 | /// SQF-representation here means that this could get printed 49 | /// out to file directly and parsed again. 50 | /// 51 | /// 52 | /// Valid instance of runtime the current runtime, 53 | /// requesting the SQF representation. 54 | /// 55 | /// SQF-Representation of this data. 56 | virtual std::string to_string_sqf() const = 0; 57 | 58 | /// 59 | /// Returns a string representation of this datatype. 60 | /// 61 | /// String representing this datatype. 62 | virtual std::string to_string() const = 0; 63 | 64 | /// 65 | /// Compares this value against the other value and returns 66 | /// true if they are equivalent. 67 | /// If invariant false, comparison should be case-sensitive. 68 | /// 69 | /// The other value 70 | /// Wether operation should be case sensitive (false) or not (true) 71 | /// The result of the comparison 72 | bool equals(std::shared_ptr other, bool invariant = false) const 73 | { 74 | if (other->type() != type()) { return false; } 75 | if (other.get() == this) { return true; } 76 | return do_equals(other, invariant); 77 | } 78 | 79 | /// 80 | /// Actual type of this. 81 | /// 82 | /// 83 | virtual ::sqf::runtime::type type() const = 0; 84 | 85 | virtual std::size_t hash() const = 0; 86 | }; 87 | } 88 | namespace std 89 | { 90 | template<> struct hash 91 | { 92 | std::size_t operator()(sqf::runtime::data const& s) const noexcept 93 | { 94 | return s.hash(); 95 | } 96 | }; 97 | } -------------------------------------------------------------------------------- /src/runtime/diagnostics/breakpoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace sqf::runtime::diagnostics 6 | { 7 | class breakpoint 8 | { 9 | std::size_t m_line; 10 | std::string m_file; 11 | std::string m_condition; 12 | bool m_enabled; 13 | public: 14 | breakpoint(std::size_t line, std::string_view file) : m_line(line), m_file(file), m_condition(), m_enabled(true) {} 15 | //breakpoint(std::size_t line, std::string_view file, std::string_view condition) : m_line(line), m_file(file), m_condition(condition), m_enabled(true) {} 16 | 17 | void disable() { m_enabled = false; } 18 | void enable() { m_enabled = true; } 19 | bool is_enabled() const { return m_enabled; } 20 | 21 | std::size_t line() const { return m_line; } 22 | void line(std::size_t value) { m_line = value; } 23 | 24 | std::string_view file() const { return m_file; } 25 | void file(std::string value) { m_file = value; } 26 | 27 | // std::string condition() const { return m_condition; } 28 | // void condition(std::string value) { m_condition = value; } 29 | }; 30 | } -------------------------------------------------------------------------------- /src/runtime/diagnostics/d_stacktrace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../data.h" 3 | #include "../type.h" 4 | #include "../value.h" 5 | #include "stacktrace.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace sqf 11 | { 12 | namespace runtime 13 | { 14 | struct t_stacktrace : public type::extend { t_stacktrace() : extend() {} static const std::string name() { return "VM-STACKTRACE"; } }; 15 | } 16 | namespace types 17 | { 18 | class d_stacktrace : public sqf::runtime::data 19 | { 20 | public: 21 | using data_type = sqf::runtime::t_stacktrace; 22 | private: 23 | sqf::runtime::diagnostics::stacktrace m_value; 24 | protected: 25 | bool do_equals(std::shared_ptr other, bool invariant) const override 26 | { 27 | // A stacktrace is never equal to another stacktrace 28 | return false; 29 | } 30 | public: 31 | d_stacktrace() = default; 32 | d_stacktrace(sqf::runtime::diagnostics::stacktrace stacktrace) : m_value(stacktrace) {} 33 | 34 | std::string to_string_sqf() const override 35 | { 36 | return "'" + m_value.to_string() + "'"; 37 | } 38 | std::string to_string() const override 39 | { 40 | return m_value.to_string(); 41 | } 42 | 43 | sqf::runtime::type type() const override { return data_type(); } 44 | 45 | sqf::runtime::diagnostics::stacktrace value() const { return m_value; } 46 | void value(sqf::runtime::diagnostics::stacktrace stacktrace) { m_value = stacktrace; } 47 | 48 | operator sqf::runtime::diagnostics::stacktrace() 49 | { 50 | return m_value; 51 | } 52 | virtual std::size_t hash() const override { return std::hash()(to_string_sqf()); } 53 | }; 54 | 55 | template<> 56 | inline std::shared_ptr to_data(sqf::runtime::diagnostics::stacktrace str) 57 | { 58 | return std::make_shared(str); 59 | } 60 | 61 | 62 | } 63 | } -------------------------------------------------------------------------------- /src/runtime/diagnostics/diag_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../fileio.h" 3 | 4 | #include 5 | #include 6 | 7 | 8 | namespace sqf::runtime::diagnostics 9 | { 10 | class diag_info 11 | { 12 | public: 13 | // The line this diag_info was created at 14 | size_t line; 15 | // The column this diag_info was created at 16 | size_t column; 17 | // The adjusted file offset, after preprocessing, this diag_info was created at 18 | size_t adjusted_offset; 19 | // The original file offset, before preprocessing, this diag_info was created at. 20 | size_t file_offset; 21 | // The original file offset, before preprocessing, this diag_info was created at. 22 | size_t length; 23 | // The path of this diag_info 24 | sqf::runtime::fileio::pathinfo path; 25 | // A view from the file, that can be used for diagnostics 26 | std::string code_segment; 27 | 28 | bool operator==(const diag_info& b) const { return line == b.line && column == b.column && file_offset == b.file_offset && path == b.path && code_segment == b.code_segment; } 29 | bool operator!=(const diag_info& b) const { return line != b.line || column != b.column || file_offset != b.file_offset || path != b.path || code_segment != b.code_segment; } 30 | 31 | diag_info() : diag_info(0, 0, 0, 0, {}, "") {} 32 | diag_info( 33 | size_t line, 34 | size_t column, 35 | size_t file_offset, 36 | sqf::runtime::fileio::pathinfo path, 37 | std::string code_segment) : 38 | line(line), 39 | column(column), 40 | adjusted_offset(file_offset), 41 | file_offset(file_offset), 42 | length(0), 43 | path(path), 44 | code_segment(code_segment) 45 | { 46 | } 47 | diag_info( 48 | size_t line, 49 | size_t column, 50 | size_t adjusted_offset, 51 | size_t file_offset, 52 | sqf::runtime::fileio::pathinfo path, 53 | std::string code_segment) : 54 | line(line), 55 | column(column), 56 | adjusted_offset(adjusted_offset), 57 | file_offset(file_offset), 58 | length(0), 59 | path(path), 60 | code_segment(code_segment) 61 | { 62 | } 63 | 64 | operator sqf::runtime::fileio::pathinfo() const { return path; } 65 | }; 66 | } -------------------------------------------------------------------------------- /src/runtime/diagnostics/stacktrace.cpp: -------------------------------------------------------------------------------- 1 | #include "stacktrace.h" 2 | #include "../logging.h" 3 | 4 | #include 5 | 6 | std::string sqf::runtime::diagnostics::stacktrace::to_string() const 7 | { 8 | std::stringstream sstream; 9 | int i = 0; 10 | if (!value.empty()) 11 | { 12 | sstream << value.to_string_sqf() << std::endl; 13 | } 14 | for (auto& frame : frames) 15 | { 16 | sstream << 17 | "<" << std::setw(3) << ++i << " of " << frames.size() << "> " << 18 | LogLocationInfo((*frame.current())->diag_info()).format() << 19 | "[" << (frame.globals_value_scope()->scope_name().empty() ? "SCOPENAME-NA" : frame.globals_value_scope()->scope_name()) << "] " << 20 | "[" << (frame.scope_name().empty() ? "SCOPENAME-EMPTY" : frame.scope_name()) << "]" << std::endl << 21 | (*frame.current())->diag_info().code_segment << std::endl; 22 | } 23 | return sstream.str(); 24 | } -------------------------------------------------------------------------------- /src/runtime/diagnostics/stacktrace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../frame.h" 3 | #include "../value.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sqf::runtime::diagnostics 10 | { 11 | struct stacktrace 12 | { 13 | std::vector frames; 14 | sqf::runtime::value value; 15 | 16 | stacktrace() {} 17 | stacktrace(std::vector f) : frames(f) {} 18 | 19 | std::string to_string() const; 20 | }; 21 | } -------------------------------------------------------------------------------- /src/runtime/frame.cpp: -------------------------------------------------------------------------------- 1 | #include "frame.h" 2 | #include "runtime.h" 3 | #include "context.h" 4 | 5 | void sqf::runtime::frame::clear_values_helper(runtime& runtime) 6 | { 7 | 8 | runtime.context_active().clear_values(); 9 | } 10 | -------------------------------------------------------------------------------- /src/runtime/git_sha1.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | extern const char g_GIT_SHA1[]; -------------------------------------------------------------------------------- /src/runtime/instruction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "diagnostics/diag_info.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sqf::runtime 10 | { 11 | class runtime; 12 | class instruction 13 | { 14 | public: 15 | using sptr = std::shared_ptr; 16 | private: 17 | sqf::runtime::diagnostics::diag_info m_diag_info; 18 | public: 19 | virtual ~instruction() {}; 20 | virtual void execute(runtime& runtime) const = 0; 21 | virtual std::string to_string() const = 0; 22 | virtual std::optional reconstruct( 23 | std::vector::const_reverse_iterator& current, 24 | std::vector::const_reverse_iterator end, 25 | short parent_precedence, bool left_from_binary) const = 0; 26 | virtual bool equals(const instruction* p_other) const = 0; 27 | 28 | sqf::runtime::diagnostics::diag_info diag_info() const { return m_diag_info; } 29 | void diag_info(sqf::runtime::diagnostics::diag_info dinf) { m_diag_info = dinf; } 30 | }; 31 | } -------------------------------------------------------------------------------- /src/runtime/instruction_set.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "instruction.h" 3 | 4 | #include 5 | #include 6 | 7 | namespace sqf::runtime 8 | { 9 | /// 10 | /// A way to represent a "immutable" instruction set. 11 | /// 12 | class instruction_set final 13 | { 14 | public: 15 | using iterator = std::vector::const_iterator; 16 | using reverse_iterator = std::vector::const_reverse_iterator; 17 | private: 18 | std::vector m_instructions; 19 | public: 20 | instruction_set() {} 21 | instruction_set(std::initializer_list initializer) : m_instructions(initializer.begin(), initializer.end()) {} 22 | instruction_set(std::vector instructions) : m_instructions(std::move(instructions)) {} 23 | 24 | iterator begin() const { return m_instructions.begin(); } 25 | iterator end() const { return m_instructions.end(); } 26 | reverse_iterator rbegin() const { return m_instructions.rbegin(); } 27 | reverse_iterator rend() const { return m_instructions.rend(); } 28 | bool empty() const { return m_instructions.empty(); } 29 | size_t size() const { return m_instructions.size(); } 30 | }; 31 | } -------------------------------------------------------------------------------- /src/runtime/parser/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../fileio.h" 3 | #include "../instruction_set.h" 4 | 5 | namespace sqf 6 | { 7 | namespace runtime 8 | { 9 | class runtime; 10 | class confighost; 11 | namespace parser 12 | { 13 | class config 14 | { 15 | public: 16 | virtual ~config() {} 17 | /// Checks the syntax of the given contents. 18 | /// @param contents The actual file contents. 19 | /// @param pathinfo The path to the file. 20 | /// @returns True on success. False on Failure. 21 | virtual bool check_syntax(std::string contents, ::sqf::runtime::fileio::pathinfo pathinfo) = 0; 22 | /// Parses the given contents. 23 | /// @param target The targeted confighost, the config should be parsed into. 24 | /// @param contents The actual file contents. 25 | /// @param pathinfo The path to the file. 26 | /// @returns True on success. False on Failure. 27 | virtual bool parse(::sqf::runtime::confighost& target, std::string contents, ::sqf::runtime::fileio::pathinfo pathinfo) = 0; 28 | }; 29 | } 30 | } 31 | namespace parser::config 32 | { 33 | class disabled : public ::sqf::runtime::parser::config 34 | { 35 | public: 36 | virtual ~disabled() override { return; } 37 | virtual bool check_syntax(std::string contents, ::sqf::runtime::fileio::pathinfo pathinfo) override { return false; } 38 | virtual bool parse(::sqf::runtime::confighost& target, std::string contents, ::sqf::runtime::fileio::pathinfo pathinfo) override { return false; } 39 | }; 40 | } 41 | } -------------------------------------------------------------------------------- /src/runtime/parser/preprocessor.cpp: -------------------------------------------------------------------------------- 1 | #include "preprocessor.h" 2 | #include "../runtime.h" 3 | 4 | std::optional sqf::parser::preprocessor::passthrough::preprocess(::sqf::runtime::runtime& runtime, std::string_view view, ::sqf::runtime::fileio::pathinfo pathinfo) 5 | { 6 | return std::string(view); 7 | } 8 | 9 | std::optional sqf::runtime::parser::preprocessor::preprocess(::sqf::runtime::runtime& runtime, ::sqf::runtime::fileio::pathinfo pathinfo) 10 | { 11 | auto contents = runtime.fileio().read_file(pathinfo); 12 | return preprocess(runtime, contents, pathinfo); 13 | } 14 | -------------------------------------------------------------------------------- /src/runtime/parser/sqf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../fileio.h" 3 | #include "../instruction_set.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace sqf 10 | { 11 | namespace runtime 12 | { 13 | class runtime; 14 | namespace parser 15 | { 16 | class sqf 17 | { 18 | public: 19 | virtual ~sqf() {}; 20 | virtual bool check_syntax(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) = 0; 21 | virtual std::optional<::sqf::runtime::instruction_set> parse(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) = 0; 22 | static std::string create_code_segment(std::string_view view, size_t off, size_t length) 23 | { 24 | size_t i = off < 15 ? 0 : off - 15; 25 | size_t len = 30 + length; 26 | if (i < 0) 27 | { 28 | len += i; 29 | i = 0; 30 | } 31 | for (size_t j = i; j < i + len && j < view.length(); j++) 32 | { 33 | char wc = view[j]; 34 | if (wc == '\n') 35 | { 36 | if (j < off) 37 | { 38 | i = j + 1; 39 | } 40 | else 41 | { 42 | len = j - i; 43 | break; 44 | } 45 | } 46 | } 47 | 48 | std::string spacing(off - i, ' '); 49 | std::string postfix(std::max(1, length), '^'); 50 | 51 | std::string txt; 52 | txt.reserve(len + 1 + spacing.length() + postfix.length() + 1); 53 | txt.append(view.substr(i, len)); 54 | txt.append("\n"); 55 | txt.append(spacing); 56 | txt.append(postfix); 57 | txt.append("\n"); 58 | return txt; 59 | } 60 | }; 61 | } 62 | } 63 | namespace parser::sqf 64 | { 65 | class disabled : public ::sqf::runtime::parser::sqf 66 | { 67 | public: 68 | virtual ~disabled() override { return; }; 69 | virtual bool check_syntax(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override { return false; } 70 | virtual std::optional<::sqf::runtime::instruction_set> parse(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override { return {}; } 71 | }; 72 | } 73 | } -------------------------------------------------------------------------------- /src/runtime/value_scope.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "value.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 12 | #include 13 | #endif // DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 14 | 15 | namespace sqf::runtime 16 | { 17 | class value_scope 18 | { 19 | private: 20 | std::string m_scope_name; 21 | std::unordered_map m_map; 22 | public: 23 | value_scope() = default; 24 | 25 | sqf::runtime::value operator[](const std::string& index) const { return at(index); } 26 | sqf::runtime::value& operator[](const std::string& index) { return at(index); } 27 | 28 | bool contains(std::string variable_name) const 29 | { 30 | std::transform(variable_name.begin(), variable_name.end(), variable_name.begin(), [](char& c) { return (char)std::tolower((int)c); }); 31 | auto res = m_map.find(variable_name) != m_map.end(); 32 | #ifdef DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 33 | std::cout << "\x1B[33m[VALUE-SCOPE-DBG]\033[0m" << 34 | " " << 35 | " " << 36 | " " << " " << "contains(\"" << variable_name << "\") const := " << res << std::endl; 37 | #endif // DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 38 | return res; 39 | } 40 | sqf::runtime::value at(std::string variable_name) const 41 | { 42 | std::transform(variable_name.begin(), variable_name.end(), variable_name.begin(), [](char& c) { return (char)std::tolower((int)c); }); 43 | auto res = m_map.find(variable_name); 44 | #ifdef DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 45 | std::cout << "\x1B[33m[VALUE-SCOPE-DBG]\033[0m" << 46 | " " << 47 | " " << 48 | " " << " " << "at(\"" << variable_name << "\") const := { " << (res == m_map.end() ? "" : res->second.to_string_sqf()) << " }" << std::endl; 49 | #endif // DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 50 | return res == m_map.end() ? value() : res->second; 51 | } 52 | sqf::runtime::value& at(std::string variable_name) 53 | { 54 | std::transform(variable_name.begin(), variable_name.end(), variable_name.begin(), [](char& c) { return (char)std::tolower((int)c); }); 55 | #ifdef DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 56 | auto res = m_map.find(variable_name); 57 | std::cout << "\x1B[33m[VALUE-SCOPE-DBG]\033[0m" << 58 | " " << 59 | " " << 60 | " " << " " << "at(\"" << variable_name << "\") := { " << (res == m_map.end() ? "" : res->second.to_string_sqf()) << " }" << std::endl; 61 | #endif // DF__SQF_RUNTIME__VALUE_SCOPE_DEBUG 62 | return m_map[variable_name]; 63 | } 64 | std::string_view scope_name() const { return m_scope_name; } 65 | void scope_name(std::string value) { m_scope_name = value; } 66 | void clear_value_scope() { m_map.clear(); } 67 | std::optional try_get(std::string variable_name) { if (contains(variable_name)) { return at(variable_name); } return {}; } 68 | 69 | std::unordered_map::iterator begin() { return m_map.begin(); } 70 | std::unordered_map::iterator end() { return m_map.end(); } 71 | }; 72 | } -------------------------------------------------------------------------------- /src/runtime/vec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace sqf::runtime 4 | { 5 | struct vec3 6 | { 7 | float x; 8 | float y; 9 | float z; 10 | 11 | vec3() : x(0), y(0), z(0) {} 12 | vec3(float x, float y, float z) : x(x), y(y), z(z) {} 13 | vec3(float x, float y) : x(x), y(y), z(0) {} 14 | }; 15 | } -------------------------------------------------------------------------------- /src/runtime/version.h: -------------------------------------------------------------------------------- 1 | #ifndef SQFVM_RUNTIME_VERSION_H_ 2 | #define SQFVM_RUNTIME_VERSION_H_ 3 | 4 | #ifndef CONCAT_ 5 | #define CONCAT_(L, R) L ## R 6 | #endif // !CONCAT_ 7 | #ifndef CONCAT 8 | #define CONCAT(L, R) CONCAT_(L, R) 9 | #endif // !CONCAT 10 | #ifndef STR_ 11 | #define STR_(IN) # IN 12 | #endif // !STR_ 13 | #ifndef STR 14 | #define STR(IN) STR_(IN) 15 | #endif // !STR 16 | 17 | #define SQFVM_RUNTIME_VERSION_MAJOR 2 18 | #define SQFVM_RUNTIME_VERSION_MINOR 1 19 | #define SQFVM_RUNTIME_VERSION_REVISION 0 20 | #define SQFVM_RUNTIME_VERSION STR(SQFVM_RUNTIME_VERSION_MAJOR) "." STR(SQFVM_RUNTIME_VERSION_MINOR) "." STR(SQFVM_RUNTIME_VERSION_REVISION) 21 | #define SQFVM_RUNTIME_VERSION_FULL SQFVM_RUNTIME_VERSION " - " __DATE__ " " __TIME__ 22 | 23 | 24 | #endif // !SQFVM_RUNTIME_VERSION_H_ 25 | -------------------------------------------------------------------------------- /src/sqc/sqc_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../runtime/parser/sqf.h" 3 | #include "../runtime/logging.h" 4 | #include "../runtime/diagnostics/diag_info.h" 5 | #include "../runtime/fileio.h" 6 | #include "../runtime/util.h" 7 | #include "../runtime/instruction_set.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace sqf::sqc::bison 15 | { 16 | struct astnode; 17 | } 18 | namespace sqf::sqc 19 | { 20 | namespace util 21 | { 22 | class setbuilder; 23 | } 24 | class parser : public ::sqf::runtime::parser::sqf, public CanLog 25 | { 26 | private: 27 | struct emplace 28 | { 29 | std::string ident; 30 | std::string replace; 31 | }; 32 | constexpr static const char* key_scopename_function = "___sqc_func"; 33 | constexpr static const char* key_self = "___self"; 34 | void to_assembly(::sqf::runtime::runtime& runtime, util::setbuilder& set, std::vector& locals, const ::sqf::sqc::bison::astnode& current_node); 35 | public: 36 | parser(Logger& logger) : CanLog(logger) 37 | { 38 | } 39 | void __log(LogMessageBase&& msg) const 40 | { 41 | log(msg); 42 | } 43 | virtual ~parser() override { }; 44 | virtual bool check_syntax(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override; 45 | virtual std::optional<::sqf::runtime::instruction_set> parse(::sqf::runtime::runtime& runtime, std::string contents, ::sqf::runtime::fileio::pathinfo file) override; 46 | 47 | static std::string to_sqc(const ::sqf::runtime::instruction_set& set); 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/unused/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Components inside of here are ready-to-integrate for SQF-VM. -------------------------------------------------------------------------------- /src/unused/linting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "parsing/astnode.h" 3 | #include 4 | #include 5 | namespace sqf 6 | { 7 | class virtualmachine; 8 | namespace linting 9 | { 10 | enum check 11 | { 12 | private_var_usage 13 | }; 14 | void add_to(virtualmachine* vm, check type); 15 | } 16 | } -------------------------------------------------------------------------------- /src/unused/netserver.cpp: -------------------------------------------------------------------------------- 1 | #include "netserver.h" 2 | 3 | void netserver::THREAD_METHOD(netserver* srv) 4 | { 5 | while (!srv->_die) 6 | { 7 | SOCKET sclient; 8 | SOCKETADDR aclient; 9 | if (!networking_server_accept_block(&srv->_socket, &sclient, &aclient)) 10 | { 11 | bool flag = true; 12 | srv->_accept = true; 13 | while (!srv->_die && flag) 14 | { 15 | if (networking_poll(&sclient, 100)) 16 | { 17 | srv->_inLock.lock(); 18 | try { srv->poll_queue(sclient); } 19 | catch (const std::runtime_error& /*err*/) {} 20 | srv->_inLock.unlock(); 21 | } 22 | 23 | srv->_outLock.lock(); 24 | try { flag = srv->send_queue(sclient); } 25 | catch (const std::runtime_error& /*err*/) { flag = false; } 26 | srv->_outLock.unlock(); 27 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 28 | } 29 | srv->_outLock.lock(); 30 | try 31 | { 32 | while (!srv->_messageQueueOut.empty()) 33 | { 34 | srv->_messageQueueOut.pop(); 35 | } 36 | } 37 | catch (const std::runtime_error& /*err*/) {} 38 | srv->_outLock.unlock(); 39 | networking_close(sclient); 40 | srv->_accept = false; 41 | } 42 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 43 | } 44 | } 45 | bool netserver::poll_queue(SOCKET client) 46 | { 47 | auto bytecount = recv(client, buffer, BUFFSIZE, 0); 48 | bool flag = false; 49 | for (int i = 0; i < bytecount; i++) 50 | { 51 | if (buffer[i] == '\0') 52 | { 53 | flag = true; 54 | auto msg = builder.str(); 55 | builder.str(std::string()); 56 | _messageQueueIn.push(msg); 57 | } 58 | else 59 | { 60 | builder << buffer[i]; 61 | } 62 | } 63 | return flag; 64 | } 65 | bool netserver::send_queue(SOCKET client) 66 | { 67 | bool flag = true; 68 | while (!_messageQueueOut.empty()) 69 | { 70 | auto msg = _messageQueueOut.front(); 71 | _messageQueueOut.pop(); 72 | int res = send(client, msg.c_str(), static_cast(msg.length()) + 1, 0); 73 | flag = res >= 0; 74 | } 75 | return flag; 76 | } 77 | 78 | netserver::netserver(unsigned short port) : _port(port), _die(false), _accept(false) 79 | { 80 | if (networking_create_server(&_socket)) 81 | { 82 | throw std::runtime_error("Coult not create server-socket."); 83 | } 84 | if (networking_server_bind(&_socket, port)) 85 | { 86 | networking_close(_socket); 87 | throw std::runtime_error("Coult not bind to provided port."); 88 | } 89 | if (networking_server_listen(&_socket, 3)) 90 | { 91 | networking_close(_socket); 92 | throw std::runtime_error("Coult not bind to provided port."); 93 | } 94 | _currentThread = std::thread([this]() { THREAD_METHOD(this); }); 95 | //_currentThread.detach(); 96 | } 97 | netserver::~netserver() 98 | { 99 | force_close(); 100 | } 101 | 102 | 103 | void netserver::force_close() { 104 | _die = true; 105 | networking_close(_socket); 106 | _currentThread.join(); 107 | } 108 | void netserver::wait_accept() { 109 | while (!_accept) 110 | { 111 | if (_die) 112 | { 113 | throw std::runtime_error("server died"); 114 | } 115 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/unused/netserver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "networking.h" 9 | 10 | #if defined(_WIN32) 11 | #elif defined(_linux) 12 | #endif 13 | 14 | class netserver 15 | { 16 | private: 17 | const unsigned short _port; 18 | SOCKET _socket; 19 | std::stringstream builder; 20 | std::thread _currentThread; 21 | std::queue _messageQueueIn; 22 | std::queue _messageQueueOut; 23 | bool _die; 24 | bool _accept; 25 | std::mutex _inLock; 26 | std::mutex _outLock; 27 | 28 | #define BUFFSIZE 2048 29 | char buffer[BUFFSIZE]; 30 | 31 | static void THREAD_METHOD(netserver* srv); 32 | bool poll_queue(SOCKET client); 33 | bool send_queue(SOCKET client); 34 | 35 | public: 36 | netserver(unsigned short port); 37 | ~netserver(); 38 | 39 | std::string next_message() { _inLock.lock(); auto str = _messageQueueIn.back(); _messageQueueIn.pop(); _inLock.unlock(); return str; } 40 | bool has_message() { return !_messageQueueIn.empty(); } 41 | void request_close() { _die = true; } 42 | void force_close(); 43 | void wait_accept(); 44 | bool is_accept() { return _accept; } 45 | 46 | void push_message(std::string str) { _outLock.lock(); _messageQueueOut.push(str); _outLock.unlock(); } 47 | }; -------------------------------------------------------------------------------- /src/unused/networking.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif // __cplusplus 7 | 8 | #if defined(_WIN32) 9 | /* See http://stackoverflow.com/questions/12765743/getaddrinfo-on-win32 */ 10 | #include 11 | #include 12 | #pragma comment(lib,"WS2_32") 13 | #else 14 | /* Assume that any non-Windows platform uses POSIX-style sockets instead. */ 15 | #include 16 | #include 17 | #include /* Needed for getaddrinfo() and freeaddrinfo() */ 18 | #include /* Needed for close() */ 19 | #define INVALID_SOCKET -1 20 | typedef int SOCKET; 21 | #endif 22 | typedef struct sockaddr_in SOCKETADDR; 23 | 24 | 25 | //https://stackoverflow.com/questions/28027937/cross-platform-sockets 26 | 27 | int networking_init(void); 28 | int networking_cleanup(void); 29 | 30 | int networking_initialized(int doinit, int uninit); 31 | int networking_close(SOCKET); 32 | // param1: The IP Address 33 | // param2: The PORT 34 | // param3: OUT parameter, the resulting socket 35 | // return: 0 (false) if everything is fine, 1 (true) if some error happened. 36 | int networking_create_client(const char*, const char*, SOCKET*); 37 | int networking_create_server(SOCKET *); 38 | int networking_server_bind(SOCKET*, unsigned short); 39 | int networking_server_listen(SOCKET*, int); 40 | int networking_poll(SOCKET* s, int timeoutms); 41 | int networking_server_accept_block(SOCKET*, SOCKET*, SOCKETADDR*); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif // __cplusplus 46 | -------------------------------------------------------------------------------- /src/unused/networking/messages/net_message.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | typename char net_message_id; 6 | 7 | class net_message 8 | { 9 | public: 10 | class payload 11 | { 12 | public: 13 | std::tuple serialize() = 0; 14 | void deserialize(char* data, size_t data_length) = 0; 15 | }; 16 | private: 17 | net_message_id m_id; 18 | char * m_data; 19 | size_t m_data_length; 20 | public: 21 | net_message(char id, char * data, size_t data_length) : m_id(id), m_data(data), m_data_length(m_data_length) {} 22 | 23 | net_message_id id() const { return m_id; } 24 | std::tuple data() const { return std::make_tuple(m_data, m_data_length); } 25 | 26 | template 27 | T get_payload() 28 | { 29 | static_assert(std::is_base_of::value, "net_message::get_payload() can only convert to net_message::payload types"); 30 | T p; 31 | static_cast(p).deserialize(m_data, m_data_length); 32 | return p; 33 | } 34 | }; -------------------------------------------------------------------------------- /src/unused/networking/nethelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../networking.h" 9 | 10 | namespace sqf 11 | { 12 | namespace networking 13 | { 14 | class nethelper 15 | { 16 | 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/unused/networking/network_client.cpp: -------------------------------------------------------------------------------- 1 | #include "network_client.h" 2 | #include "../networking.h" 3 | 4 | bool sqf::networking::client::poll_queue() 5 | { 6 | std::lock_guard guard(m_mutex_in); 7 | auto bytecount = recv(m_socket, m_buffer, buffersize, 0); 8 | bool flag = false; 9 | for (int i = 0; i < bytecount; i++) 10 | { 11 | if (m_buffer[i] == '\0') 12 | { 13 | flag = true; 14 | auto msg = m_builder.str(); 15 | m_builder.str(std::string()); 16 | m_messages_in.push(msg); 17 | } 18 | else 19 | { 20 | m_builder << m_buffer[i]; 21 | } 22 | } 23 | return flag; 24 | } 25 | 26 | bool sqf::networking::client::send_queue() 27 | { 28 | std::lock_guard guard(m_mutex_out); 29 | bool flag = true; 30 | while (!m_messages_out.empty()) 31 | { 32 | auto msg = m_messages_out.front(); 33 | m_messages_out.pop(); 34 | int res = send(m_socket, msg.c_str(), msg.length() + 1, 0); 35 | flag = res >= 0; 36 | } 37 | return flag; 38 | } 39 | 40 | void sqf::networking::client::THREAD_CLIENT_HANDLE(client* clnt) 41 | { 42 | clnt->m_alive = true; 43 | bool flag = true; 44 | while (!clnt->m_die && flag) 45 | { 46 | if (networking_poll(&(clnt->m_socket), 100)) 47 | { 48 | try { clnt->poll_queue(); } 49 | catch (const std::exception & err) {} 50 | } 51 | 52 | try { flag = clnt->send_queue(); } 53 | catch (const std::exception & err) { flag = false; } 54 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 55 | } 56 | try 57 | { 58 | std::lock_guard guard(clnt->m_mutex_out); 59 | while (!clnt->m_messages_out.empty()) 60 | { 61 | clnt->m_messages_out.pop(); 62 | } 63 | } 64 | catch (const std::exception & err) {} 65 | networking_close(clnt->m_socket); 66 | clnt->m_alive = false; 67 | } 68 | 69 | void sqf::networking::client::stop() 70 | { 71 | m_die = true; 72 | networking_close(m_socket); 73 | m_thread.join(); 74 | } 75 | -------------------------------------------------------------------------------- /src/unused/networking/network_client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "networking.h" 10 | #include "network_server.h" 11 | 12 | namespace sqf 13 | { 14 | namespace networking 15 | { 16 | class client 17 | { 18 | const size_t buffersize = 2024; 19 | char m_buffer[2024]; 20 | bool m_die; 21 | 22 | SOCKET m_socket; 23 | std::stringstream m_builder; 24 | std::queue m_messages_in; 25 | std::queue m_messages_out; 26 | std::mutex m_mutex_in; 27 | std::mutex m_mutex_out; 28 | std::thread m_thread; 29 | bool m_alive; 30 | 31 | bool poll_queue(); 32 | bool send_queue(); 33 | static void THREAD_CLIENT_HANDLE(client* clnt); 34 | public: 35 | client(SOCKET socket) 36 | : m_die(false), 37 | m_socket(socket), 38 | m_builder(std::stringstream::out | std::stringstream::in | std::stringstream::binary), 39 | m_alive(false) 40 | { 41 | m_thread = std::thread([this]() { THREAD_CLIENT_HANDLE(this); }); 42 | } 43 | ~client() { stop(); } 44 | void stop(); 45 | 46 | void send_message(const char* cstr) { send_message(std::string(cstr)); } 47 | void send_message(const std::string s) 48 | { 49 | std::lock_guard guard(m_mutex_out); 50 | this->m_messages_out.push(s); 51 | } 52 | std::optional read_message(const std::string) 53 | { 54 | std::lock_guard guard(m_mutex_in); 55 | if (this->m_messages_in.size() == 0) 56 | { 57 | return {}; 58 | } 59 | auto res = this->m_messages_in.front(); 60 | this->m_messages_in.pop(); 61 | return res; 62 | } 63 | }; 64 | } 65 | } -------------------------------------------------------------------------------- /src/unused/networking/network_server.cpp: -------------------------------------------------------------------------------- 1 | #include "network_server.h" 2 | #include "network_client.h" 3 | #include "../networking.h" 4 | #include 5 | 6 | 7 | 8 | void sqf::networking::server::THREAD_SERVER_ACCEPT(server * srv) 9 | { 10 | while (!srv->m_die) 11 | { 12 | SOCKET sclient; 13 | SOCKETADDR aclient; 14 | if (!networking_server_accept_block(&srv->m_socket, &sclient, &aclient)) 15 | { 16 | srv->push_client(std::make_shared(sclient)); 17 | } 18 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 19 | } 20 | } 21 | 22 | 23 | void sqf::networking::server::push_client(std::shared_ptr c) 24 | { 25 | std::lock_guard guard(m_clients_mutex); 26 | m_clients.push_back(c); 27 | } 28 | 29 | void sqf::networking::server::remove_client(std::shared_ptr c) 30 | { 31 | std::lock_guard guard(m_clients_mutex); 32 | auto res = std::find_if(m_clients.begin(), m_clients.end(), [c](std::shared_ptr it) -> bool { return it.get() == c.get(); }); 33 | if (res == m_clients.end()) 34 | { 35 | return; 36 | } 37 | m_clients.erase(res); 38 | } 39 | 40 | sqf::networking::server::server(unsigned short port) : m_die(false) 41 | { 42 | if (networking_create_server(&m_socket)) 43 | { 44 | throw std::runtime_error("Coult not create server-socket."); 45 | } 46 | if (networking_server_bind(&m_socket, port)) 47 | { 48 | networking_close(m_socket); 49 | throw std::runtime_error("Coult not bind to provided port."); 50 | } 51 | if (networking_server_listen(&m_socket, 3)) 52 | { 53 | networking_close(m_socket); 54 | throw std::runtime_error("Coult not start listening."); 55 | } 56 | m_thread = std::thread([this]() { THREAD_SERVER_ACCEPT(this); }); 57 | //_currentThread.detach(); 58 | } 59 | 60 | void sqf::networking::server::stop() 61 | { 62 | m_die = true; 63 | networking_close(m_socket); 64 | for (auto& c : m_clients) 65 | { 66 | c->stop(); 67 | } 68 | m_thread.join(); 69 | } 70 | 71 | void sqf::networking::server::send_message(const std::string s) 72 | { 73 | for (auto it : m_clients) 74 | { 75 | it->send_message(s); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/unused/networking/network_server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "networking.h" 10 | 11 | namespace sqf 12 | { 13 | namespace networking 14 | { 15 | class client; 16 | class server 17 | { 18 | private: 19 | static void THREAD_SERVER_ACCEPT(server* srv); 20 | 21 | SOCKET m_socket; 22 | std::thread m_thread; 23 | bool m_die; 24 | std::mutex m_clients_mutex; 25 | std::vector> m_clients; 26 | 27 | void push_client(std::shared_ptr c); 28 | void remove_client(std::shared_ptr c); 29 | public: 30 | server(unsigned short port); 31 | ~server() { stop(); } 32 | 33 | std::vector> clients() 34 | { 35 | std::lock_guard guard(m_clients_mutex); 36 | auto copy = std::vector>(m_clients); 37 | return m_clients; 38 | } 39 | void stop(); 40 | 41 | void send_message(const char* cstr) { send_message(std::string(cstr)); } 42 | void send_message(const std::string s); 43 | }; 44 | } 45 | } -------------------------------------------------------------------------------- /src/unused/parsepbo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | class PboProperty { 9 | public: 10 | PboProperty() {} 11 | PboProperty(std::string k, std::string v): key(std::move(k)), value(std::move(v)) {} 12 | 13 | std::string key; 14 | std::string value; 15 | 16 | bool read(std::istream& in); 17 | }; 18 | 19 | enum class PboEntryPackingMethod { 20 | none, 21 | version, 22 | compressed, 23 | encrypted 24 | }; 25 | 26 | class PboEntry { 27 | public: 28 | std::string name; 29 | 30 | uint32_t original_size = 0; 31 | uint32_t data_size = 0; 32 | uint32_t startOffset = 0; 33 | PboEntryPackingMethod method = PboEntryPackingMethod::none; 34 | 35 | void read(std::istream& in); 36 | }; 37 | 38 | class PboReader; 39 | class PboEntryBuffer : public std::streambuf { 40 | std::vector buffer; 41 | const PboEntry& file; 42 | const PboReader& reader; 43 | //What position the character after the last character that's currently in our buffer, corresponds to in the pbofile 44 | //Meaning on next read, the first character read is that pos 45 | size_t bufferEndFilePos{0}; 46 | public: 47 | PboEntryBuffer(const PboReader& rd, const PboEntry& ent, uint32_t bufferSize = 4096u); 48 | 49 | void setBufferSize(size_t newSize); 50 | int underflow() override; 51 | std::streamsize xsgetn(char* _Ptr, std::streamsize _Count) override; 52 | pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) override; 53 | pos_type seekpos(pos_type, std::ios_base::openmode) override; 54 | std::streamsize showmanyc() override; 55 | 56 | void setBuffersize(size_t newSize) { 57 | buffer.resize(newSize); 58 | } 59 | }; 60 | 61 | class PboReader { 62 | friend class PboEntryBuffer; 63 | 64 | std::vector files; 65 | std::vector properties; 66 | uint32_t propertiesEnd{0}; 67 | uint32_t headerEnd{0}; 68 | std::istream& input; 69 | std::array hash; 70 | bool badHeader{false}; 71 | public: 72 | PboReader(std::istream &input) : input(input) {} 73 | void readHeaders(); 74 | const auto& getFiles() const noexcept { return files; } 75 | PboEntryBuffer getFileBuffer(const PboEntry& ent) const { 76 | return PboEntryBuffer(*this, ent); 77 | } 78 | const auto& getProperties() const { return properties; } 79 | const auto& getHash() const { return hash; } 80 | //Broken 3DEN exported pbo with no header 81 | bool isBadHeader() const{ return badHeader; } 82 | }; 83 | 84 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Register all .sqf tests 2 | 3 | set(TEST_ROOT_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}) 4 | 5 | function(add_sqf_run_test test_full_path) 6 | get_filename_component(test_name ${test_full_path} NAME_WE) 7 | file(RELATIVE_PATH test_relative_path ${TEST_ROOT_LOCATION} ${test_full_path}) 8 | set(test_full_name run.${test_name}) 9 | 10 | message(VERBOSE "Registering test " ${test_full_path} " as " ${test_full_name}) 11 | add_test( 12 | NAME "${test_full_name}" 13 | COMMAND sqfvm -a -V --no-execute-print --max-runtime 1000 14 | --input-sqf "framework.sqf" --input-config ${TEST_ROOT_LOCATION}/config.cpp 15 | --sqf "\"${test_relative_path}\" call test_fnc_run_from_file;" 16 | WORKING_DIRECTORY ${TEST_ROOT_LOCATION} 17 | ) 18 | set_tests_properties(${test_full_name} PROPERTIES TIMEOUT 11) 19 | endfunction() 20 | 21 | function(add_sqf_preprocess_test test_full_path) 22 | get_filename_component(test_name ${test_full_path} NAME_WE) 23 | set(test_full_name preprocess.${test_name}) 24 | 25 | message(VERBOSE "Registering test " ${test_full_path} " as " ${test_full_name}) 26 | add_test( 27 | NAME "${test_full_name}" 28 | COMMAND sqfvm -a -V --no-execute-print --preprocess-file ${test_full_path} --input-config ${TEST_ROOT_LOCATION}/config.cpp --max-runtime 10000 29 | WORKING_DIRECTORY ${TEST_ROOT_LOCATION} 30 | ) 31 | endfunction() 32 | 33 | add_subdirectory(sqf) 34 | add_subdirectory(preprocess) 35 | add_subdirectory(cba) 36 | -------------------------------------------------------------------------------- /tests/cba/.gitignore: -------------------------------------------------------------------------------- 1 | cba_a3 2 | -------------------------------------------------------------------------------- /tests/cba/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # add_sqf_run_test(${CMAKE_CURRENT_SOURCE_DIR}/cba_a3.sqf) 2 | -------------------------------------------------------------------------------- /tests/cba/cba_a3.sqf: -------------------------------------------------------------------------------- 1 | private _addons = ["accessorys", "ai", "arrays", "common", "diagnostic", "disposable", "ee", "events", "hashes", "help", "jam", "jr", "keybinding", "main", "main_a3", "modules", "music", "network", "optics", "settings", "statemachine", "strings", "ui", "vectors", "versioning", "xeh"]; 2 | private _tests = ["arrays", "common", "diagnostic", "events", "hashes", "network", "strings", "vectors"]; // "jam" disabled, "main" is all tests 3 | private _functions = []; 4 | 5 | { 6 | private _addons = _x; 7 | private _addonPath = format ["\x\cba\addons\%1", _x]; 8 | private _addonSqfFiles = allFiles__ [".sqf"]; 9 | { 10 | private _addonFunctionPrefix = format ["%1/fnc_", _addons]; 11 | if (_x find _addonFunctionPrefix > 0) then { 12 | private _splitStr = _x splitString "/"; 13 | private _filename = _splitStr select (count _splitStr - 1); 14 | private _filePath = format ["%1\%2", _addonPath, _filename]; 15 | 16 | if (not (_filePath in _functions)) then { 17 | private _functionName = "CBA_fnc_" + (_filename select [4, count _filename - 8]); 18 | missionNamespace setVariable [_functionName, compile preprocessFileLineNumbers _filePath]; 19 | _functions pushBackUnique _filePath; 20 | }; 21 | }; 22 | } forEach _addonSqfFiles; 23 | } forEach _addons; 24 | 25 | { 26 | call compile preprocessFileLineNumbers format ["\x\cba\addons\%1\test.sqf", _x]; 27 | } forEach _tests; 28 | 29 | nil; 30 | -------------------------------------------------------------------------------- /tests/config.cpp: -------------------------------------------------------------------------------- 1 | class nested_tests 2 | { 3 | node = "0"; 4 | class nested1 5 | { 6 | node = "1"; 7 | class nested2 8 | { 9 | node = "2"; 10 | class nested3 11 | { 12 | node = "3"; 13 | class nested4 14 | { 15 | node = "4"; 16 | }; 17 | }; 18 | }; 19 | }; 20 | }; 21 | class type_tests 22 | { 23 | type_array[] = { 1, "test", { 1, 2, 3 } }; 24 | type_string = "test"; 25 | type_anytext = any fancy text should be accepted; 26 | type_anytext_array[] = { any, fancy, text, should, be, accepted }; 27 | type_scalar = 1; 28 | class type_class {}; 29 | }; 30 | class flat_tests { 31 | class A { key = 1; }; 32 | class B { key = 2; }; 33 | class C: A {}; 34 | class D: C { key = 4; }; 35 | class E: B { key = 5; }; 36 | }; 37 | class test_select_selects_addon 38 | { 39 | class addon {}; 40 | }; 41 | 42 | class test_config_classes_only_returns_config_entries 43 | { 44 | property = 0; 45 | class TestSub 46 | { 47 | subProperty = 0; 48 | }; 49 | }; -------------------------------------------------------------------------------- /tests/preprocess/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB_RECURSE test_script_files "*.sqf") 2 | foreach(test_full_path ${test_script_files}) 3 | add_sqf_preprocess_test(${test_full_path}) 4 | endforeach() 5 | -------------------------------------------------------------------------------- /tests/preprocess/ReadMe.md: -------------------------------------------------------------------------------- 1 | Dear Reader, 2 | 3 | please ensure that the test-cases are: 4 | 5 | * **Contain no pathing informations** Sadly this for the time being makes testing `#include` unless explicitly adjusted on every system the tests run in. 6 | * **Double Checked with Arma** The arma preprocessor is not the same as (for example) the one included in GCC. Thus please assure that you tested your result, using arma. 7 | 8 | thanks. 9 | 10 | ----- 11 | 12 | Tests work by preprocessing a `.sqf` file, loading the related `.txt` file (same name, different extension). and performing a `isEqualTo` on them. -------------------------------------------------------------------------------- /tests/preprocess/backslash.sqf: -------------------------------------------------------------------------------- 1 | foo\ 2 | bar -------------------------------------------------------------------------------- /tests/preprocess/backslash.txt: -------------------------------------------------------------------------------- 1 | #line 0 "" 2 | foobar -------------------------------------------------------------------------------- /tests/preprocess/define_macro_callable_0.sqf: -------------------------------------------------------------------------------- 1 | #define TEST() abc 2 | #define EMPTY() 3 | #define OTHER() TEST() 4 | TEST 5 | TEST() 6 | EMPTY 7 | EMPTY() 8 | OTHER 9 | OTHER() -------------------------------------------------------------------------------- /tests/preprocess/define_macro_callable_0.txt: -------------------------------------------------------------------------------- 1 | #line 0 "" 2 | 3 | 4 | 5 | TEST 6 | abc 7 | EMPTY 8 | 9 | OTHER 10 | abc -------------------------------------------------------------------------------- /tests/preprocess/define_macro_callable_1.sqf: -------------------------------------------------------------------------------- 1 | #define TEST(ARG1) ARG1 ARG1 ARG1 2 | #define EMPTY(ARG1) 3 | #define OTHER(ARG1) ARG1: TEST(ARG1) 4 | TEST 5 | TEST(something-1) 6 | EMPTY 7 | EMPTY(something-1) 8 | OTHER 9 | OTHER(something-1) -------------------------------------------------------------------------------- /tests/preprocess/define_macro_callable_1.txt: -------------------------------------------------------------------------------- 1 | #line 0 "" 2 | 3 | 4 | 5 | TEST 6 | something-1 something-1 something-1 7 | EMPTY 8 | 9 | OTHER 10 | something-1: something-1 something-1 something-1 -------------------------------------------------------------------------------- /tests/sqf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB_RECURSE test_script_files "*.sqf") 2 | foreach(test_full_path ${test_script_files}) 3 | add_sqf_run_test(${test_full_path}) 4 | endforeach() 5 | -------------------------------------------------------------------------------- /tests/sqf/alive.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertTrue", { alive player }], 2 | ["assertFalse", { alive objNull }] 3 | ] -------------------------------------------------------------------------------- /tests/sqf/append.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { private _arr = []; _arr append [1]; _arr; }, [1]], 2 | ["assertEqual", { private _arr = [1]; _arr append []; _arr; }, [1]], 3 | ["assertEqual", { private _arr = [1]; _arr append [2]; _arr; }, [1, 2]], 4 | ["assertEqual", { private _arr = [1]; _arr append [2]; _arr append [3]; _arr; }, [1, 2, 3]], 5 | ["assertEqual", { private _arr = [1, 2]; _arr append [3, 4]; _arr; }, [1, 2, 3, 4]] 6 | ] 7 | -------------------------------------------------------------------------------- /tests/sqf/apply.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { private _arr = [1,0,1]; [_arr, _arr apply { _arr set [_x, 0]; 9 }]}, [[0,0,1], [9,9,9]]], 2 | ["assertException", { private _i = 0; private _arr = [1,2,3]; { _i = _i + 1; if (_i > 3) then { throw "Abort Endless Loop" }; _arr pushBack _x; 0 } apply _arr }], 3 | ["assertEqual", 4 | [ 5 | "Frame-Variables Cleared before each repetition.", 6 | { 7 | private _out = []; 8 | [1, 2] apply 9 | { 10 | if !isNil "_something" then 11 | { 12 | _out pushBack _something; 13 | }; 14 | _something = 1; 15 | false 16 | }; 17 | _out 18 | } 19 | ], []] 20 | ] -------------------------------------------------------------------------------- /tests/sqf/boolean.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertTrue", { true }], // BOOL 2 | ["assertFalse", { false }], // BOOL 3 | ["assertTrue", { true == true }], // BOOL op BOOL 4 | ["assertTrue", { false == false }], // BOOL op BOOL 5 | ["assertTrue", { true isEqualTo true }], // BOOL isEqualTo BOOL 6 | ["assertTrue", { false isEqualTo false }], // BOOL isEqualTo BOOL 7 | ["assertFalse", { true isEqualTo false }], // BOOL isEqualTo BOOL 8 | ["assertFalse", { false isEqualTo true }], // BOOL isEqualTo BOOL 9 | ["assertTrue", { true && true }], // BOOL && BOOL 10 | ["assertFalse", { true && false }], // BOOL && BOOL 11 | ["assertFalse", { false && true }], // BOOL && BOOL 12 | ["assertFalse", { false && { true } }], // BOOL && CODE 13 | ["assertTrue", { false || true }], // BOOL || BOOL 14 | ["assertTrue", { false || { true } }], // BOOL || CODE 15 | ["assertTrue", { !false }], // BOOL || CODE 16 | ["assertFalse", { !true }], // BOOL || CODE 17 | ["assertTrue", { not false }], // BOOL || CODE 18 | ["assertFalse", { not true }], // BOOL || CODE 19 | ["assertFalse", { false isEqualTo true }] // BOOL isEqualTo BOOL 20 | ] 21 | -------------------------------------------------------------------------------- /tests/sqf/breakOut.sqf: -------------------------------------------------------------------------------- 1 | [ 2 | ["assertException", 3 | [ 4 | "Unknown scope errors", 5 | { 6 | private _arr = []; 7 | [] call { 8 | _arr pushBack 1; 9 | [] call { 10 | _arr pushBack 2; 11 | [] call { 12 | _arr pushBack 3; 13 | breakOut "someunknowngiberishstuffyscope"; 14 | _arr pushBack 3; 15 | }; 16 | _arr pushBack 2; 17 | }; 18 | _arr pushBack 1; 19 | }; 20 | _arr 21 | } 22 | ], 23 | [1, 2, 3] 24 | ], 25 | ["assertEqual", 26 | [ 27 | "Empty scope leaves current scope", 28 | { 29 | private _arr = []; 30 | [] call { 31 | _arr pushBack 1; 32 | [] call { 33 | _arr pushBack 2; 34 | [] call { 35 | _arr pushBack 3; 36 | breakOut ""; 37 | _arr pushBack 3; 38 | }; 39 | _arr pushBack 2; 40 | }; 41 | _arr pushBack 1; 42 | }; 43 | _arr 44 | } 45 | ], 46 | [1, 2, 3, 2, 1] 47 | ], 48 | ["assertEqual", 49 | [ 50 | "breakOut actually works", 51 | { 52 | private _arr = []; 53 | [] call { 54 | _arr pushBack 1; 55 | [] call { 56 | _arr pushBack 2; 57 | scopeName "test-scope"; 58 | [] call { 59 | _arr pushBack 3; 60 | breakOut "test-scope"; 61 | _arr pushBack 3; 62 | }; 63 | _arr pushBack 2; 64 | }; 65 | _arr pushBack 1; 66 | }; 67 | _arr 68 | } 69 | ], 70 | [1, 2, 3, 1] 71 | ], 72 | ["assertEqual", 73 | [ 74 | "breakOut works with value", 75 | { 76 | private _arr = []; 77 | [] call { 78 | _arr pushBack 1; 79 | _arr pushBack ([] call { 80 | _arr pushBack 2; 81 | scopeName "test-scope"; 82 | [] call { 83 | _arr pushBack 3; 84 | true breakOut "test-scope"; 85 | _arr pushBack 3; 86 | false 87 | }; 88 | _arr pushBack 2; 89 | false 90 | }); 91 | _arr pushBack 1; 92 | false 93 | }; 94 | _arr 95 | } 96 | ], 97 | [1, 2, 3, true, 1] 98 | ] 99 | ] -------------------------------------------------------------------------------- /tests/sqf/compilation.sqf: -------------------------------------------------------------------------------- 1 | // Contains parse tests that should not crash and should parse 2 | [ ["assert", { compile """unclosed string" }], 3 | ["assert", { compile "'unclosed string" }], 4 | ["assertExcept", { compile "." }], 5 | ["assert", { compile "1" }], 6 | ["assert", { compile ";" }], 7 | ["assert", { compile "1E7" }], 8 | ["assert", { compile "1e7" }], 9 | ["assert", { compile "-1E7" }], 10 | ["assert", { compile "-1e7" }], 11 | ["assert", { compile "1E-7" }], 12 | ["assert", { compile "1e-7" }], 13 | ["assert", { compile "-1E-7" }], 14 | ["assert", { compile "-1e-7" }], 15 | ["assert", { compile "0x1" }], 16 | ["assert", { compile "$1" }], 17 | ["assertExcept", { compile "[1,2,3" }], 18 | ["assert", { compile "fa" }], 19 | ["assertExcept", { compile "!" }], 20 | ["assertExcept", { compile "+" }], 21 | ["assertExcept", { compile "-" }], 22 | ["assert", { compile "" }], 23 | ["assertExcept", { compile "(1" }], 24 | ["assertExcept", { compile "{" }], 25 | ["assert", { compile "1" }], 26 | ["assert", { compile ".1" }], 27 | ["assertExcept", { compile "." }], 28 | ["assert", { compile "private _test = 1+1, _test == 2" }] 29 | ] -------------------------------------------------------------------------------- /tests/sqf/count.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { count [] }, 0], // count ARRAY 2 | ["assertEqual", { count [1, 2, 3] }, 3], // count ARRAY 3 | ["assertEqual", { count [[1, 1, 1], [2, 2, 2]] }, 2], // count ARRAY 4 | ["assertEqual", { count "123" }, 3], // count STRING 5 | ["assertEqual", { count "" }, 0], // count STRING 6 | ["assertEqual", { count "123456789" }, 9], // count STRING 7 | ["assertEqual", { { _x == 0 } count [1, 2, 3] }, 0], // CODE count ARRAY 8 | ["assertEqual", { { _x == 1 } count [1, 2, 3] }, 1], // CODE count ARRAY 9 | ["assertEqual", { { _x == 1 } count [] }, 0], // CODE count ARRAY 10 | ["assertEqual", { { nil } count [1, 2, 3] }, 0], // CODE count ARRAY 11 | ["assertEqual", { { _x == 0 } count [] }, 0], // CODE count ARRAY 12 | ["assertEqual", { { _x == 0 } count [1, 2, 3] }, 0], // CODE count ARRAY 13 | ["assertEqual", { { _x == 0 } count [0] }, 1], // CODE count ARRAY 14 | ["assertEqual", { { _x == 0 } count [0, 0] }, 2], // CODE count ARRAY 15 | ["assertEqual", { {} count [0] }, 0], // CODE count ARRAY 16 | ["assertException", { { 1 } count [0] }], // CODE count ARRAY 17 | ["assertException", { { {} } count [0] }], // CODE count ARRAY 18 | ["assertException", { { [] } count [0] }], // CODE count ARRAY 19 | ["assertException", { {""} count [0] }], // CODE count ARRAY 20 | ["assertEqual", { { _x > 1 } count [1, 2, 3] }, 2], // CODE count ARRAY 21 | ["assertEqual", { { _x > 1 } count [] }, 0], // CODE count ARRAY 22 | ["assertException", { private _i = 0; private _arr = [1,2,3]; { _i = _i + 1; if (_i > 3) then { throw "Abort Endless Loop" }; _arr pushBack _x; false } count _arr }], 23 | ["assertEqual", 24 | [ 25 | "Frame-Variables Cleared before each repetition.", 26 | { 27 | private _out = []; 28 | { 29 | if !isNil "_something" then 30 | { 31 | _out pushBack _i; 32 | }; 33 | _something = 1; 34 | false 35 | } 36 | count [1, 2]; 37 | _out 38 | } 39 | ], [] 40 | ] 41 | ] -------------------------------------------------------------------------------- /tests/sqf/deleteAt.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", ["Returns deleted value", { private _arr = [1,2,3]; _arr deleteAt 1 } ], 2], // ARRAY deleteAt SCALAR: Returns deleted value 2 | ["assertIsNil", ["Positive Out Of Bounds returns nil", { private _arr = [1,2,3]; _arr deleteAt 10 } ] ], // ARRAY deleteAt SCALAR: Positive Out Of Bounds returns nil 3 | ["assertIsNil", ["Negative Out Of Bounds returns nil", { private _arr = [1,2,3]; _arr deleteAt -1 } ] ] // ARRAY deleteAt SCALAR: Negative Out Of Bounds returns nil 4 | ] -------------------------------------------------------------------------------- /tests/sqf/deleteRange.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { private _arr = [0,1,2,3,4,5,6]; _arr deleteRange [0.6, 2.4]; _arr; }, [0,3,4,5,6]], 2 | ["assertEqual", { private _arr = [0,1,2,3,4,5,6]; _arr deleteRange [2, 1]; _arr; }, [0,1,3,4,5,6]], 3 | ["assertEqual", { private _arr = [0,1,2,3,4,5,6]; _arr deleteRange [1, 1]; _arr; }, [0,2,3,4,5,6]], 4 | ["assertEqual", { private _arr = [0,1,2,3,4,5,6]; _arr deleteRange [-1, 1]; _arr; }, [0,1,2,3,4,5,6]], 5 | ["assertEqual", { private _arr = [0,1,2,3,4,5,6]; _arr deleteRange [1, 10]; _arr; }, [0]] 6 | ] -------------------------------------------------------------------------------- /tests/sqf/diag.sqf: -------------------------------------------------------------------------------- 1 | [ 2 | ["assertTrue", { diag_tickTime > 0 }], 3 | ["assertTrue", { assert(true) }], 4 | ["assertException", { assert(false) }], 5 | ["assertEqual", { productVersion }, productVersion], 6 | ["assertEqual", { typename "" }, "STRING"], 7 | ["assertEqual", { typename 1 }, "SCALAR"], 8 | ["assertEqual", { typename player }, "OBJECT"], 9 | ["assertEqual", { typename missionNamespace }, "NAMESPACE"], 10 | ["assertEqual", { typename grpNull }, "GROUP"], //#TODO add the other types 11 | ["assertNil", { comment "hah!" }], 12 | ["assertException", { if (true) then [0,0] }, "STRING"], 13 | ["assertException", { if (false) then [0,0] }, "STRING"], 14 | ["assertNil", { if (false) exitWith {false} }, "STRING"], 15 | ["assertTrue", { if (true) exitWith {true} }, "STRING"], 16 | ["assertTrue", { if (true) then {true} else {false} }, "STRING"], 17 | ["assertFalse", { if (true) then {false} else {true} }, "STRING"] 18 | ] -------------------------------------------------------------------------------- /tests/sqf/distance2d.sqf: -------------------------------------------------------------------------------- 1 | [ ["setup", { private _obj1 = "CAManBase" createVehicle [0,0,0]; private _obj2 = "CAManBase" createVehicle [0,0,0]; [] call _this; deleteVehicle _obj1; deleteVehicle _obj2; }, 1], 2 | ["assertEqual", { [0,0,4] distance2d [0,1,1] }, 1], 3 | ["assertEqual", { [0,0,3] distance2d [2,0,2] }, 2], 4 | ["assertEqual", { [0,3,2] distance2d [0,0,3] }, 3], 5 | ["assertEqual", { [4,0,1] distance2d [0,0,4] }, 4], 6 | ["assertEqual", { _obj1 setPos [0,0,4]; private _res = _obj1 distance2d [0,1,1]; _res }, 1], 7 | ["assertEqual", { _obj1 setPos [0,0,3]; private _res = _obj1 distance2d [2,0,2]; _res }, 2], 8 | ["assertEqual", { _obj1 setPos [0,3,2]; private _res = _obj1 distance2d [0,0,3]; _res }, 3], 9 | ["assertEqual", { _obj1 setPos [4,0,1]; private _res = _obj1 distance2d [0,0,4]; _res }, 4], 10 | ["assertEqual", { _obj1 setPos [0,0,4]; private _res = [0,1,1] distance2d _obj1; _res }, 1], 11 | ["assertEqual", { _obj1 setPos [0,0,3]; private _res = [2,0,2] distance2d _obj1; _res }, 2], 12 | ["assertEqual", { _obj1 setPos [0,3,2]; private _res = [0,0,3] distance2d _obj1; _res }, 3], 13 | ["assertEqual", { _obj1 setPos [4,0,1]; private _res = [0,0,4] distance2d _obj1; _res }, 4], 14 | ["assertEqual", { _obj1 setPos [0,0,4]; _obj2 setPos [0,1,1]; private _res = _obj1 distance2d _obj2; _res }, 1], 15 | ["assertEqual", { _obj1 setPos [0,0,3]; _obj2 setPos [2,0,2]; private _res = _obj1 distance2d _obj2; _res }, 2], 16 | ["assertEqual", { _obj1 setPos [0,3,2]; _obj2 setPos [0,0,3]; private _res = _obj1 distance2d _obj2; _res }, 3], 17 | ["assertEqual", { _obj1 setPos [4,0,1]; _obj2 setPos [0,0,4]; private _res = _obj1 distance2d _obj2; _res }, 4] 18 | ] -------------------------------------------------------------------------------- /tests/sqf/findIf.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { [1, 2, 3] findIf { _x == 1 } }, 0], 2 | ["assertEqual", { [1, 2, 3] findIf { _x == 2 } }, 1], 3 | ["assertEqual", { [1, 2, 3] findIf { _x == 3 } }, 2], 4 | ["assertEqual", { [1, 2, 3] findIf { _x > 5 } }, -1], 5 | ["assertEqual", { [] findIf {_x > 1} }, -1], 6 | ["assertException", { private _i = 0; private _arr = [1, 2, 3]; _arr findIf { _i = _i + 1; if (_i > 3) then { throw "Abort Endless Loop" }; _arr pushBack _x; false } }], 7 | ["assertEqual", 8 | [ 9 | "Frame-Variables Cleared before each repetition.", 10 | { 11 | private _out = []; 12 | [1, 2] findIf 13 | { 14 | if !isNil "_something" then { 15 | _out pushBack _i; 16 | }; 17 | _something = 1; 18 | false 19 | }; 20 | _out 21 | } 22 | ], [] 23 | ] 24 | ] -------------------------------------------------------------------------------- /tests/sqf/forEach.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { private _arr2 = [0,1,2,3,4,5]; { _arr2 deleteAt _x; } forEach _arr2; _arr2 }, [1,2,4,5]], // CODE forEach ARRAY 2 | ["assertEqual", { private _arr2 = [5,4,3,2,1,0]; { _arr2 deleteAt _x; } forEach _arr2; _arr2 }, [5,4,3]], // CODE forEach ARRAY 3 | ["assertException", { private _i = 0; private _arr = [1,2,3]; { _i = _i + 1; if (_i > 3) then { throw "Abort Endless Loop" }; _arr pushBack _x; } forEach _arr }], 4 | ["assertEqual", 5 | [ 6 | "Frame-Variables Cleared before each repetition.", 7 | { 8 | private _arr = []; 9 | { 10 | if !isNil "_i" then 11 | { 12 | _arr pushBack _i; 13 | }; 14 | _i = 1; 15 | } forEach [1,2,3]; 16 | _arr 17 | } 18 | ], [] 19 | ], 20 | ["assertEqual", 21 | [ 22 | "Frame iterates all values.", 23 | { 24 | private _arr = []; 25 | { 26 | _arr pushBack _x; 27 | } forEach [1,2,3]; 28 | _arr 29 | } 30 | ], [1, 2, 3] 31 | ] 32 | ] -------------------------------------------------------------------------------- /tests/sqf/forStep.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { for "_i" from 1 to 10 do { _i }; }, 10], 2 | ["assertEqual", { private _arr = []; for "_i" from 1 to 3 do { _arr pushBack _i; }; _arr }, [1, 2, 3]], 3 | ["assertEqual", { private _arr = []; for "_i" from 0 to 5 step 2 do { _arr pushBack _i; }; _arr }, [0, 2, 4]], 4 | ["assertEqual", { for "_i" from -1 to -10 step -1 do { _i }; }, -10], 5 | ["assertEqual", { private _arr = []; for "_i" from (-1) to (-3) step -1 do { _arr pushBack _i; }; _arr }, [-1, -2, -3]], 6 | ["assertEqual", { private _arr = []; for "_i" from 0 to (-5) step (-2) do { _arr pushBack _i; }; _arr }, [0, -2, -4]], 7 | ["assert", { for "_i" from 0 to -1 do { assert false }; }], 8 | ["assert", { for "_i" from -1 to 0 step -1 do { assert false }; }], 9 | ["assertEqual", 10 | [ 11 | "Frame-Variables Cleared before each repetition.", 12 | { 13 | private _out = []; 14 | for "_i" from 0 to 2 do 15 | { 16 | _i = _i + 1; 17 | if !isNil "_something" then 18 | { 19 | _out pushBack _i; 20 | }; 21 | _something = 1; 22 | false 23 | }; 24 | _out 25 | } 26 | ], [] 27 | ], 28 | ["assert", 29 | [ 30 | "Loop with step=0 loops endless.", 31 | { 32 | private _i = 0; 33 | for "_" from 0 to 1 step 0 do 34 | { 35 | _i = _i + 1; 36 | if (_i == 2) exitWith {}; 37 | }; 38 | assert (_i == 2); 39 | } 40 | ] 41 | ] 42 | ] -------------------------------------------------------------------------------- /tests/sqf/format.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { format ["%"]; }, ""], 2 | ["assertEqual", { format ["%1"]; }, ""], 3 | ["assertEqual", { format ["%2", 1]; }, ""], 4 | ["assertEqual", { format ["%%"]; }, ""], 5 | ["assertEqual", { format ["%%%"]; }, ""], 6 | ["assertEqual", { format ["%1", true]; }, "true"], 7 | ["assertEqual", { format ["%1", false]; }, "false"], 8 | ["assertEqual", { format ["%1", 1]; }, "1"], 9 | ["assertEqual", { format ["%1", []]; }, "[]"], 10 | ["assertEqual", { format ["%1", [1,2,3]]; }, "[1,2,3]"], 11 | ["assertEqual", { format ["%1", [[]]]; }, "[[]]"], 12 | ["assertEqual", { format ["%1", "test"]; }, "test"], 13 | ["assertEqual", { format [] }, ""], 14 | ["assertEqual", { format [true] }, ""], 15 | ["assertEqual", { format ["%a"] }, ""], 16 | ["assertEqual", { format ["%5"] }, ""], 17 | ["assertEqual", { format ["%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }, "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10"] 18 | ] -------------------------------------------------------------------------------- /tests/sqf/if.sqf: -------------------------------------------------------------------------------- 1 | [ 2 | ["assert", { for "_i" from 0 to 3 do { assert (_i == 0); if true exitWith {}; }; }], 3 | ["assert", { private _i = -1; while { _i = _i + 1; _i < 3 } do { assert (_i == 0); if true exitWith {}; }; }] 4 | ] -------------------------------------------------------------------------------- /tests/sqf/in.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertTrue", { [] in [[],1,2,3] }], 2 | ["assertFalse", { [] in [] }], 3 | ["assertFalse", { [] in [[123]] }], 4 | ["assertFalse", { [] in [1] }], 5 | ["assertTrue", { 1 in [1,2,3] }], 6 | ["assertFalse", { 1 in [2,3,4] }], 7 | ["assertFalse", { 1 in [[1]] }], 8 | ["assertFalse", { 1 in [] }], 9 | ["assertTrue", { false in [false] }], 10 | ["assertFalse", { false in [true] }], 11 | ["assertFalse", { false in [1,2,3] }], 12 | ["assertFalse", { false in [[false]] }], 13 | ["assertFalse", { false in [] }], 14 | ["assertTrue", { "abc" in ["abc",1,2,3] }], 15 | ["assertFalse", { "abc" in ["ABC",1,2,3] }], 16 | ["assertFalse", { "abc" in ["",1,2,3] }], 17 | ["assertFalse", { "abc" in [["abc"]] }], 18 | ["assertFalse", { "abc" in [] }], 19 | ["assertTrue", { player in [player, 1, 2, "", []] }], 20 | ["assertTrue", { player in [objNull, player, 1, 2, "", []] }], 21 | ["assertTrue", { player in [objNull, 1, 2, "", [], player] }], 22 | ["assertFalse", { player in [objNull, 1, 2, "", []] }], 23 | ["assertFalse", { player in ["",1,objNull,2,3] }], 24 | ["assertFalse", { player in [[player]] }], 25 | ["assertFalse", { player in [] }], 26 | ["assertTrue", { "abc" in "abc" }], 27 | ["assertTrue", { "abc" in "zzzabc" }], 28 | ["assertTrue", { "abc" in "zzzabczzz" }], 29 | ["assertTrue", { "abc" in "abczzz" }], 30 | ["assertFalse", { "abc" in "ABC" }], 31 | ["assertFalse", { "abc" in "zzzABC" }], 32 | ["assertFalse", { "abc" in "zzzABCzzz" }], 33 | ["assertFalse", { "abc" in "ABCzzz" }], 34 | ["assertFalse", { "abc" in "" }] 35 | ] -------------------------------------------------------------------------------- /tests/sqf/isEqualTo.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertTrue", { true isEqualTo true }], 2 | ["assertFalse", { true isEqualTo false }], 3 | ["assertFalse", { false isEqualTo true }], 4 | ["assertTrue", { false isEqualTo false }], 5 | ["assertFalse", { 1 isEqualTo 2 }], 6 | ["assertFalse", { 2 isEqualTo 1 }], 7 | ["assertTrue", { 1 isEqualTo 1 }], 8 | ["assertTrue", { [] isEqualTo [] }], 9 | ["assertTrue", { [1] isEqualTo [1] }], 10 | ["assertTrue", { [true] isEqualTo [true] }], 11 | ["assertFalse", { [true] isEqualTo [false] }], 12 | ["assertFalse", { [false] isEqualTo [true] }], 13 | ["assertTrue", { [false] isEqualTo [false] }], 14 | ["assertTrue", { [[1,2,3],[1,2,3]] isEqualTo [[1,2,3],[1,2,3]] }], 15 | ["assertFalse", { [[1,2,3]] isEqualTo [[1,2,3],[1,2,3]] }], 16 | ["assertFalse", { [nil] isEqualTo [nil] }], 17 | ["assertTrue", { private _arr = [nil]; _arr isEqualTo _arr }], 18 | ["assertTrue", { [player] isEqualTo [player] }], 19 | ["assertTrue", { ["test"] isEqualTo ["test"] }], 20 | ["assertFalse", { ["test"] isEqualTo ["TEST"] }] 21 | ] -------------------------------------------------------------------------------- /tests/sqf/isNil.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertTrue", { private _test = nil; isNil "_test"; }], 2 | ["assertFalse", { private _test = 1; isNil "_test"; }], 3 | ["assertTrue", { isNil { nil } }], 4 | ["assertFalse", { isNil { 1 } }] 5 | ] -------------------------------------------------------------------------------- /tests/sqf/isNotEqualTo.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertFalse", { true isNotEqualTo true }], 2 | ["assertTrue", { true isNotEqualTo false }], 3 | ["assertTrue", { false isNotEqualTo true }], 4 | ["assertFalse", { false isNotEqualTo false }], 5 | ["assertTrue", { 1 isNotEqualTo 2 }], 6 | ["assertTrue", { 2 isNotEqualTo 1 }], 7 | ["assertFalse", { 1 isNotEqualTo 1 }], 8 | ["assertFalse", { [] isNotEqualTo [] }], 9 | ["assertFalse", { [1] isNotEqualTo [1] }], 10 | ["assertFalse", { [true] isNotEqualTo [true] }], 11 | ["assertTrue", { [true] isNotEqualTo [false] }], 12 | ["assertTrue", { [false] isNotEqualTo [true] }], 13 | ["assertFalse", { [false] isNotEqualTo [false] }], 14 | ["assertFalse", { [[1,2,3],[1,2,3]] isNotEqualTo [[1,2,3],[1,2,3]] }], 15 | ["assertTrue", { [[1,2,3]] isNotEqualTo [[1,2,3],[1,2,3]] }], 16 | ["assertTrue", { [nil] isNotEqualTo [nil] }], 17 | ["assertFalse", { private _arr = [nil]; _arr isNotEqualTo _arr }], 18 | ["assertFalse", { [player] isNotEqualTo [player] }], 19 | ["assertFalse", { ["test"] isNotEqualTo ["test"] }], 20 | ["assertTrue", { ["test"] isNotEqualTo ["TEST"] }] 21 | ] -------------------------------------------------------------------------------- /tests/sqf/matrix.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { [[2], [2]] matrixMultiply [[3]] }, [[6], [6]]], 2 | ["assertEqual", { [[-1,0,0], [0,-1,0]] matrixMultiply [[1,2], [3,1], [2,3]] }, [[-1,-2], [-3,-1]]], 3 | ["assertEqual", { [[-1,0,0], [0,-1,0], [0,0,-1]] matrixMultiply [1, 2, 3] }, []], 4 | ["assertEqual", { [[-1,0,0], [0,-1,0], [0,0,-1]] matrixMultiply [[1, 2, 3]] }, []], 5 | ["assertEqual", { [[-1,0,0], [0,-1,0], [0,0,-1]] matrixMultiply [[1], [2], [3]] }, [[-1], [-2], [-3]]], 6 | ["assertEqual", { matrixTranspose [[1,2,3]] }, [[1], [2], [3]]], 7 | ["assertEqual", { matrixTranspose [[1], [2], [3]] }, [[1,2,3]]], 8 | ["assertEqual", { matrixTranspose [[1,2,3], [3,1,2], [2,3,1]] }, [[1,3,2], [2,1,3], [3,2,1]]] 9 | ] 10 | -------------------------------------------------------------------------------- /tests/sqf/misc.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { compile "1+1+1" }, {1+1+1}], 2 | ["assertEqual", { [1, 2, 3] apply { 0x1 } }, [1, 1, 1]], 3 | ["assertEqual", { [] apply {+1} }, []], 4 | ["assertNil", { comment "this is a comment" }], 5 | ["assertNil", { nil }], 6 | ["assertTrue", { true }], 7 | ["assertFalse", { false }], 8 | ["assertTrue", { 1 <= 1 }], 9 | ["assertEqual", { str 0.5 }, "0.5"], 10 | ["assertEqual", { toLower "UPPER" }, "upper"], 11 | ["assertEqual", { toUpper "lower" }, "LOWER"], 12 | ["assertEqual", { toArray "123" }, [49,50,51]], 13 | ["assertEqual", { toString [49,50,51] }, "123"], 14 | ["assertEqual", { ["1","2","3"] joinString "-" }, "1-2-3"], 15 | ["assertEqual", { [1,2,3] joinString "-" }, "1-2-3"], 16 | ["assertEqual", { "a"+"b" }, "ab"], 17 | ["assert", { nil isEqualTo nil }], 18 | ["assertFalse", { [nil] isEqualTo [nil] }], 19 | ["assertTrue", { isNil "_some_Non_Existing_Variable_" }], 20 | ["assertFalse", { private _var = 0; isNil "_var" }], 21 | ["assertTrue", { isNil { nil } }], 22 | ["assertFalse", { isNil { "a"+"b" } }], 23 | //["assertEqual", { for [{ _i = 0 }, { _i < 10 }, { _i = _i + 1 }] do { _i }; }, 10] //not implemented 24 | ["assertEqual", { str (switch (true)) }, "true"] 25 | ] -------------------------------------------------------------------------------- /tests/sqf/namespace.sqf: -------------------------------------------------------------------------------- 1 | [ 2 | ["assertEqual", { private _ns = customNamespace__ "custom"; _ns setVariable ["test", 0]; allVariables _ns }, ["test"]], 3 | ["assertEqual", { private _ns = customNamespace__ "custom"; _ns setVariable ["test", 0]; with _ns do { allVariables currentNamespace } }, ["test"]], 4 | ["assertNil", { missionNamespace getVariable "don'texist" }], 5 | ["assertNil", { missionNamespace setVariable ["nstest", true] }], 6 | ["assertEqual", { missionNamespace getVariable "nstest" }, true], 7 | ["assertEqual", { missionNamespace getVariable ["nstest", false] }, true], 8 | ["assertEqual", { missionNamespace getVariable ["don'texist", false] }, false], 9 | ["assertEqual", { allVariables player }, []], 10 | ["assertNil", { player getVariable "don'texist" }], 11 | ["assertNil", { player setVariable ["nstest", true] }], 12 | ["assertEqual", { player getVariable "nstest" }, true], 13 | ["assertEqual", { player getVariable ["nstest", false] }, true], 14 | ["assertEqual", { player getVariable ["don'texist", false] }, false], 15 | ["assertException", { player getVariable [false] }, []], 16 | ["assertException", { player setVariable [false] }, []], 17 | ["assertException", { player setVariable ["test"] }, []], 18 | ["assertException", { player setVariable [true, "test"] }, []], 19 | ["assertException", { player getVariable [true, "test"] }, []], 20 | ["assertEqual", { allVariables objNull }, []], 21 | ["assertNil", { objNull getVariable "don'texist" }], 22 | ["assertNil", { objNull setVariable ["nstest", true] }], 23 | ["assertNil", { objNull getVariable "nstest" }], 24 | ["assertNil", { objNull getVariable ["nstest", false] }], 25 | ["assertNil", { objNull getVariable ["don'texist", false] }], 26 | ["assertNil", { objNull getVariable [false] }], 27 | ["assertNil", { objNull setVariable [false] }], 28 | ["assertNil", { objNull setVariable ["test"] }] 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ] 38 | -------------------------------------------------------------------------------- /tests/sqf/params.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { 1 call { params ["_test"]; _test } }, 1], 2 | ["assertEqual", { true call { params ["_test"]; _test } }, true], 3 | ["assertEqual", { "" call { params ["_test"]; _test } }, ""], 4 | ["assertEqual", { [1,2,3] params [["_array", [], [[]]], ["_inPlace", false, [false]]]; [_array, _inPlace] }, [[], false]] 5 | ] -------------------------------------------------------------------------------- /tests/sqf/private.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", ["private STRING no override test", { private _arr = []; { private "_x"; _arr pushBack _x; } foreach [1,2,3]; _arr }], [1,2,3] ], // private STRING 2 | ["assertEqual", ["private ARRAY no override test", { private _arr = []; { private ["_x"]; _arr pushBack _x; } foreach [1,2,3]; _arr }], [1,2,3] ], // while CODE do CODE: condition false 3 | ["assertEqual", { private _private = 0; [] call { private "_private"; _private = 1; }; _private }, 0], 4 | ["assertIsNil", { [] call { private "_private"; _private = 1; }; _private }], 5 | ["assertEqual", { private _private = 0; [] call { private ["_private"]; _private = 1; }; _private }, 0], 6 | ["assertIsNil", { [] call { private ["_private"]; _private = 1; }; _private }] 7 | ] -------------------------------------------------------------------------------- /tests/sqf/selectLeader.sqf: -------------------------------------------------------------------------------- 1 | [ ["setup", { private _group = grpNull; private _unitA = objNull; private _unitB = objNull; [] call _this; /* todo: delete */}], 2 | ["assert", { grpNull selectLeader objNull; }, ""], 3 | ["assert", { grpNull selectLeader player; }, ""], 4 | ["assert", { grpNull selectLeader objNull; }, ""] 5 | ] -------------------------------------------------------------------------------- /tests/sqf/set.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { private _arr = []; _arr set [0,1]; _arr }, [1]], // ARRAY set ARRAY 2 | ["assertEqual", { private _arr = [0]; _arr set [0,1]; _arr }, [1]], // ARRAY set ARRAY 3 | ["assertEqual", { private _arr = [0]; _arr set [0,""]; _arr }, [""]], // ARRAY set ARRAY 4 | ["assertEqual", { private _arr = [0]; _arr set [1,1]; _arr }, [0,1]], // ARRAY set ARRAY 5 | ["assertEqual", { private _arr = [0]; _arr set [1,""]; _arr }, [0,""]], // ARRAY set ARRAY 6 | ["assertIsNil", { private _arr = []; _arr set [1,1]; _arr#0 }], // ARRAY set ARRAY 7 | ["assertEqual", { private _arr = [0]; _arr set [count _arr,1]; _arr }, [0,1]], // ARRAY set ARRAY 8 | ["assertEqual", { private _arr = [0]; _arr set [count _arr - 1, 1]; _arr }, [1]], // ARRAY set ARRAY 9 | ["assertException", { [] set [-1,1] }] // ARRAY set ARRAY 10 | ] -------------------------------------------------------------------------------- /tests/sqf/side.sqf: -------------------------------------------------------------------------------- 1 | [ 2 | ["assert", { side objectNull }] 3 | ] -------------------------------------------------------------------------------- /tests/sqf/splitString.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { ".,a,.b.,c,.d.,e,.f.," splitString ",." }, ["a","b","c","d", "e","f"]], 2 | ["assertEqual", { "abc.,.,.,.,.,.def," splitString ",." }, ["abc","def"]], 3 | ["assertEqual", { "abcdef," splitString ",." }, ["abcdef"]], 4 | ["assertEqual", { ",." splitString ",." }, []], 5 | ["assertEqual", { "" splitString ",." }, []], 6 | ["assertEqual", { "abcdef" splitString "" }, ["a","b","c","d","e","f"]] 7 | ] -------------------------------------------------------------------------------- /tests/sqf/switch.sqf: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "assertEqual", 4 | [ 5 | "switch cases from call", 6 | { 7 | private _arr = []; 8 | private _cases = { 9 | case 1: {_arr pushBack "inside 1"; "a"}; 10 | _arr pushBack "past case 1"; 11 | case 2: {_arr pushBack "inside 2"; "b"}; 12 | _arr pushBack "past case 2"; 13 | case 3: {_arr pushBack "inside 3"; "c"}; 14 | _arr pushBack "past case 3"; 15 | default {_arr pushBack "inside default"; "default"}; 16 | _arr pushBack "past default"; 17 | }; 18 | private _res = switch 2 do { 19 | [] call { 20 | [] call _cases; 21 | _arr pushBack "past cases inner" 22 | }; 23 | _arr pushBack "past cases call outter"; 24 | }; 25 | _arr pushBack _res; 26 | _arr 27 | } 28 | ], 29 | ["past case 1","past cases inner","past cases call outter","inside 2","b"] 30 | ], 31 | [ 32 | "assertEqual", 33 | { 34 | private _arr = []; 35 | switch (1) do 36 | { 37 | private _case = case 1; 38 | switch (2) do 39 | { 40 | case 2: { _arr pushBack "empty"; }; 41 | _case: { _arr pushBack "arg"; }; 42 | }; 43 | default { _arr pushBack "magic"; }; 44 | }; 45 | _arr 46 | }, 47 | ["empty", "magic"] 48 | ], 49 | ["assert", { switch(2) do { case 1: {}; }; }] 50 | ] -------------------------------------------------------------------------------- /tests/sqf/text.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { str composeText ["hello", " ", "world"] }, "hello world"], 2 | ["assertEqual", { typeName composeText ["hello", " ", "world"] }, "TEXT"], 3 | ["assertEqual", { str lineBreak }, toString [13, 10]], // \r\n 4 | ["assertEqual", { typeName lineBreak }, "TEXT"], 5 | ["assertEqual", { str parseText "hello world" }, "hello world"], 6 | ["assertEqual", { typeName parseText "hello world" }, "TEXT"], 7 | ["assertEqual", { str text "hello world" }, "hello world"], 8 | ["assertEqual", { typeName text "hello world" }, "TEXT"] 9 | ] 10 | -------------------------------------------------------------------------------- /tests/sqf/trycatchthrow.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertException", { throw "test"; }], 2 | ["assertEqual", { private "_val"; try { throw true; } catch { _val = _exception; }; _val }, true], 3 | ["assertEqual", { private "_val"; try { throw "string"; } catch { _val = _exception; }; _val }, "string"], 4 | ["assertEqual", { private "_val"; try { throw 1; } catch { _val = _exception; }; _val }, 1], 5 | ["assertEqual", { private "_val"; try { throw [1,2,3]; } catch { _val = _exception; }; _val }, [1,2,3]], 6 | ["assertEqual", { private "_val"; try { throw {1+1}; } catch { _val = _exception; }; _val }, {1+1}], 7 | ["assertEqual", { private _exception = 1; try { throw "string"; } catch { private _val = _exception; }; _exception }, 1] 8 | ] -------------------------------------------------------------------------------- /tests/sqf/while.sqf: -------------------------------------------------------------------------------- 1 | [ ["assertEqual", { private _i = 0; while { false } do { _i = 1 }; _i }, 0], // while CODE do CODE: condition false 2 | ["assertIsNil", { while { false } do {} } ], // while CODE do CODE: condition false 3 | ["assertException", { while { } do {} } ], // while CODE do CODE: condition empty 4 | ["assertException", { while { "" } do {} } ], // while CODE do CODE: condition not BOOL 5 | ["assertIsNil", { while { nil } do {} } ], // while CODE do CODE: condition nil 6 | ["assertEqual", { private _i = 0; while { _i == 0 } do { _i = 1 }; _i }, 1], // while CODE do CODE: condition true before body executed 7 | ["assertEqual", { private _i = 0; while { _i = _i + 1; _i < 5 } do {}; _i }, 5], // while CODE do CODE: empty body 8 | ["assertEqual", { private _i = 0; while { _i = _i + 1; _i < 5 } do { nil }; _i }, 5], // while CODE do CODE: nil body 9 | ["assertEqual", { private _i = 0; while { _i < 5 } do { _i = _i + 1; }; _i }, 5], // while CODE do CODE: normal body 10 | ["assertEqual", ["while loop limit of 10000 in unscheduled", { private _iterations = 0; while { _iterations < 10001 } do { _iterations = _iterations + 1; }; _iterations }], 10000], // while CODE do CODE: normal body 11 | ["assertEqual", 12 | [ 13 | "Frame-Variables Cleared before each repetition.", 14 | { 15 | private _arr = []; 16 | private _i = 0; 17 | while { _i < 2 } do 18 | { 19 | _i = _i + 1; 20 | if !isNil "_something" then 21 | { 22 | _arr pushBack _i; 23 | }; 24 | _something = 1; 25 | }; 26 | _arr 27 | } 28 | ], [] 29 | ] 30 | ] --------------------------------------------------------------------------------