diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml
new file mode 100644
index 0000000..0538a65
--- /dev/null
+++ b/.github/workflows/cpp-build-test.yml
@@ -0,0 +1,56 @@
+name: Cpp Build and Test
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - "Cpp/**"
+ - "grammar/*.g4"
+ pull_request:
+ branches: [main]
+ paths:
+ - "Cpp/**"
+ - "grammar/*.g4"
+
+jobs:
+ build-and-test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [macos-latest, windows-latest]
+ fail-fast: false
+ env:
+ DEMO_DIR: demo/${{ matrix.os == 'windows-latest' && 'Win32/Debug' || 'Mac' }}
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ - name: Setup cmake
+ uses: jwlawson/actions-setup-cmake@v2
+ with:
+ cmake-version: "3.x"
+
+ - name: Generate ANTLR4 files (Windows)
+ if: matrix.os == 'windows-latest'
+ run: .\generate.ps1
+
+ - name: Generate ANTLR4 files (macOS)
+ if: matrix.os == 'macos-latest'
+ run: sh ./generate.sh
+ shell: bash
+
+ - name: Configure CMake
+ run: |
+ mkdir -p Cpp/build
+ cd Cpp/build
+ cmake .. -DWITH_TEST=true
+
+ - name: Build
+ run: |
+ cd Cpp/build
+ cmake --build .
+
+ - name: Run tests
+ run: |
+ cd Cpp/build/${{ env.DEMO_DIR }}
+ ls
+ ./ArcscriptTest
diff --git a/.gitignore b/.gitignore
index 413023d..7e2e3c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
.DS_Store
-
+.idea
/grammar/**/.antlr
!/grammar/*.g4
diff --git a/Cpp/.gitignore b/Cpp/.gitignore
index 21bc544..d1860aa 100644
--- a/Cpp/.gitignore
+++ b/Cpp/.gitignore
@@ -1 +1,7 @@
-src/Generated
\ No newline at end of file
+src/Generated
+.idea
+build
+cmake-build-debug-visual-studio
+cmake-build-debug
+cmake-build-release-visual-studio
+cmake-build-release
diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt
new file mode 100755
index 0000000..72bbd5c
--- /dev/null
+++ b/Cpp/CMakeLists.txt
@@ -0,0 +1,175 @@
+# minimum required CMAKE version
+CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR)
+
+message(STATUS "CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}")
+message(STATUS "CMake version: ${CMAKE_VERSION}")
+
+set(PROJECT_VERSION "0.1.0")
+project(ArcscriptTranspiler VERSION ${PROJECT_VERSION})
+
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+
+message(STATUS "Generator: ${CMAKE_GENERATOR}")
+message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
+message(STATUS "CMAKE_CONFIGURATION_TYPES: ${CMAKE_CONFIGURATION_TYPES}")
+
+# compiler must be 17
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+# required if linking to static library
+#add_definitions(-DANTLR4CPP_STATIC)
+
+# using /MD flag for antlr4_runtime (for Visual C++ compilers only)
+set(ANTLR4_WITH_STATIC_CRT OFF)
+
+# Specify the version of the antlr4 library needed for this project.
+# By default the latest version of antlr4 will be used. You can specify a
+# specific, stable version by setting a repository tag value or a link
+# to a zip file containing the libary source.
+ set(ANTLR4_TAG 8e6fd91)
+# set(ANTLR4_ZIP_REPOSITORY https://github.com/antlr/antlr4/archive/refs/tags/4.13.2.zip)
+
+# add external build for antlrcpp
+include(ExternalAntlr4Cpp)
+# add antlr4cpp artifacts to project environment
+include_directories(${ANTLR4_INCLUDE_DIRS})
+
+include_directories(src/Generated/ArcscriptLexer)
+include_directories(src/Generated/ArcscriptParser)
+include_directories(src)
+
+add_library(ArcscriptTranspiler SHARED)
+
+target_sources(ArcscriptTranspiler PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptParserBase.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptVisitor.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptOutputs.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptFunctions.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptExpression.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptErrorListener.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/Generated/ArcscriptLexer/ArcscriptLexer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/Generated/ArcscriptParser/ArcscriptParser.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/Generated/ArcscriptParser/ArcscriptParserBaseVisitor.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/Generated/ArcscriptParser/ArcscriptParserVisitor.cpp
+)
+
+target_sources(ArcscriptTranspiler PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.h)
+
+set(ARCSCRIPT_INCLUDE_HEADERS
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptHelpers.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptErrorExceptions.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptOutputs.h
+)
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ # For MSVC, we need to link against the shared library
+ target_compile_options(ArcscriptTranspiler PRIVATE -Wall -Wextra)
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ # For other compilers, we can link against the static library
+ target_compile_definitions(ArcscriptTranspiler PRIVATE WIN_EXPORT)
+endif()
+
+target_link_libraries(ArcscriptTranspiler PRIVATE antlr4_shared)
+
+if (WIN32 OR WIN64)
+ set(LIBRARY_NAME "${PROJECT_NAME}.lib")
+ set(DLL_NAME "${PROJECT_NAME}.dll")
+ if (WIN64)
+ set(PLATFORM "Win64")
+ else()
+ set(PLATFORM "Win32")
+ endif()
+elseif (APPLE)
+ set(DLL_NAME "lib${PROJECT_NAME}.dylib")
+ set(PLATFORM "Mac")
+elseif (UNIX)
+ set(DLL_NAME "lib${PROJECT_NAME}.so")
+ set(PLATFORM "Linux")
+endif()
+
+set_target_properties(ArcscriptTranspiler PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/${PLATFORM}"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/${PLATFORM}"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/${PLATFORM}"
+ OUTPUT_NAME ${PROJECT_NAME}
+)
+
+if (APPLE)
+ add_custom_command(TARGET ArcscriptTranspiler PRE_BUILD
+ COMMAND install_name_tool -id @rpath/libantlr4-runtime.dylib ${ANTLR4_RUNTIME_LIBRARIES})
+endif ()
+
+# Copy the antlr4 runtime library to the output directory
+add_custom_command(TARGET ArcscriptTranspiler PRE_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -E copy ${ANTLR4_RUNTIME_LIBRARIES} "$"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+# Copy the generated headers to the output directory
+if (NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/lib/include")
+ add_custom_command(TARGET ArcscriptTranspiler POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/lib/include")
+endif()
+
+add_custom_command(TARGET ArcscriptTranspiler POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -E copy ${ARCSCRIPT_INCLUDE_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/lib/include"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+if (WITH_TEST)
+ add_executable(ArcscriptTest ${CMAKE_CURRENT_SOURCE_DIR}/demo/ArcscriptTest.cpp)
+
+ include(FetchContent)
+ FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz)
+ FetchContent_MakeAvailable(json)
+
+ target_link_libraries(ArcscriptTest PRIVATE nlohmann_json::nlohmann_json)
+ target_link_libraries(ArcscriptTest PRIVATE ArcscriptTranspiler)
+
+ set_target_properties(ArcscriptTest PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/demo/${PLATFORM}"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/demo/${PLATFORM}"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/demo/${PLATFORM}"
+ OUTPUT_NAME ArcscriptTest
+ )
+
+ file(GLOB TEST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/demo/tests/*.json")
+
+ if (NOT EXISTS "$/tests")
+ add_custom_command(TARGET ArcscriptTest POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -E make_directory "$/tests")
+ endif()
+
+ add_custom_command(TARGET ArcscriptTest POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -E copy ${TEST_SOURCES} "$/tests"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+ if (WIN32 OR WIN64)
+ set(ARCSCRIPT_TRANSPILER_LIB_FILES
+ "$/${DLL_NAME}"
+ "$/${LIBRARY_NAME}"
+ "$/${PROJECT_NAME}.exp"
+ "$/${PROJECT_NAME}.pdb"
+ )
+ elseif (APPLE)
+ set(ARCSCRIPT_TRANSPILER_LIB_FILES
+ "$/${DLL_NAME}"
+ "$/${LIBRARY_NAME}"
+ )
+ endif()
+
+ add_custom_command(TARGET ArcscriptTest POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -E copy ${ANTLR4_RUNTIME_LIBRARIES} "$"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+ add_custom_command(TARGET ArcscriptTest POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ -E copy ${ARCSCRIPT_TRANSPILER_LIB_FILES} "$"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+endif (WITH_TEST)
\ No newline at end of file
diff --git a/Cpp/README.md b/Cpp/README.md
new file mode 100644
index 0000000..2418ce5
--- /dev/null
+++ b/Cpp/README.md
@@ -0,0 +1,20 @@
+# Arcscript C++ Transpiler
+
+## Prerequisites
+
+- CMake 3.10 or higher
+- A C++ compiler that supports C++17 or higher
+
+## Building the Project
+
+### Windows & Linux
+
+1. After generating the ANTLR4 parser files from the top root folder of this repository, run the following commands to build the project:
+
+ ```bash
+ mkdir build
+ cd build
+ cmake ..
+ cmake --build .
+ ```
+2. The generated libraries will be located in the `build/Debug` or `build/Release` directory, depending on your build configuration. The folder also includes the `include` directory with the header files needed to use the transpiler.
\ No newline at end of file
diff --git a/Cpp/cmake/ExternalAntlr4Cpp.cmake b/Cpp/cmake/ExternalAntlr4Cpp.cmake
new file mode 100755
index 0000000..620b2c8
--- /dev/null
+++ b/Cpp/cmake/ExternalAntlr4Cpp.cmake
@@ -0,0 +1,177 @@
+cmake_minimum_required(VERSION 3.10)
+
+if(POLICY CMP0114)
+ cmake_policy(SET CMP0114 NEW)
+endif()
+
+include(ExternalProject)
+
+set(ANTLR4_ROOT ${CMAKE_CURRENT_BINARY_DIR}/antlr4_runtime/src/antlr4_runtime)
+set(ANTLR4_INCLUDE_DIRS ${ANTLR4_ROOT}/runtime/Cpp/runtime/src)
+set(ANTLR4_GIT_REPOSITORY https://github.com/antlr/antlr4.git)
+if(NOT DEFINED ANTLR4_TAG)
+ # Set to branch name to keep library updated at the cost of needing to rebuild after 'clean'
+ # Set to commit hash to keep the build stable and does not need to rebuild after 'clean'
+ set(ANTLR4_TAG master)
+endif()
+
+# Ensure that the include dir already exists at configure time (to avoid cmake erroring
+# on non-existent include dirs)
+file(MAKE_DIRECTORY "${ANTLR4_INCLUDE_DIRS}")
+
+if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*")
+ set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/runtime/$(Configuration))
+elseif(${CMAKE_GENERATOR} MATCHES "Xcode.*")
+ set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/runtime/$(CONFIGURATION))
+else()
+ set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/runtime)
+endif()
+
+if(MSVC)
+ set(ANTLR4_STATIC_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/antlr4-runtime-static.lib)
+ set(ANTLR4_SHARED_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/antlr4-runtime.lib)
+ set(ANTLR4_RUNTIME_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/antlr4-runtime.dll)
+else()
+ set(ANTLR4_STATIC_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.a)
+ if(MINGW)
+ set(ANTLR4_SHARED_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a)
+ set(ANTLR4_RUNTIME_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll)
+ elseif(CYGWIN)
+ set(ANTLR4_SHARED_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a)
+ set(ANTLR4_RUNTIME_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/cygantlr4-runtime-4.13.2.dll)
+ elseif(APPLE)
+ set(ANTLR4_RUNTIME_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dylib)
+ else()
+ set(ANTLR4_RUNTIME_LIBRARIES
+ ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.so)
+ endif()
+endif()
+
+if(${CMAKE_GENERATOR} MATCHES ".* Makefiles")
+ # This avoids
+ # 'warning: jobserver unavailable: using -j1. Add '+' to parent make rule.'
+ set(ANTLR4_BUILD_COMMAND $(MAKE))
+elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio.*")
+ set(ANTLR4_BUILD_COMMAND
+ ${CMAKE_COMMAND}
+ --build .
+ --config $(Configuration)
+ --target)
+elseif(${CMAKE_GENERATOR} MATCHES "Xcode.*")
+ set(ANTLR4_BUILD_COMMAND
+ ${CMAKE_COMMAND}
+ --build .
+ --config $(CONFIGURATION)
+ --target)
+else()
+ set(ANTLR4_BUILD_COMMAND
+ ${CMAKE_COMMAND}
+ --build .
+ --target)
+endif()
+
+if(NOT DEFINED ANTLR4_WITH_STATIC_CRT)
+ set(ANTLR4_WITH_STATIC_CRT ON)
+endif()
+
+if(ANTLR4_ZIP_REPOSITORY)
+ ExternalProject_Add(
+ antlr4_runtime
+ PREFIX antlr4_runtime
+ URL ${ANTLR4_ZIP_REPOSITORY}
+ DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}
+ BUILD_COMMAND ""
+ BUILD_IN_SOURCE 1
+ SOURCE_DIR ${ANTLR4_ROOT}
+ SOURCE_SUBDIR runtime/Cpp
+ CMAKE_CACHE_ARGS
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DWITH_STATIC_CRT:BOOL=${ANTLR4_WITH_STATIC_CRT}
+ -DDISABLE_WARNINGS:BOOL=ON
+ # -DCMAKE_CXX_STANDARD:STRING=17 # if desired, compile the runtime with a different C++ standard
+ # -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} # alternatively, compile the runtime with the same C++ standard as the outer project
+ INSTALL_COMMAND ""
+ EXCLUDE_FROM_ALL 1)
+else()
+ ExternalProject_Add(
+ antlr4_runtime
+ PREFIX antlr4_runtime
+ GIT_REPOSITORY ${ANTLR4_GIT_REPOSITORY}
+ GIT_TAG ${ANTLR4_TAG}
+ DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR}
+ BUILD_COMMAND ""
+ BUILD_IN_SOURCE 1
+ SOURCE_DIR ${ANTLR4_ROOT}
+ SOURCE_SUBDIR runtime/Cpp
+ CMAKE_CACHE_ARGS
+ -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+ -DWITH_STATIC_CRT:BOOL=${ANTLR4_WITH_STATIC_CRT}
+ -DDISABLE_WARNINGS:BOOL=ON
+ # -DCMAKE_CXX_STANDARD:STRING=17 # if desired, compile the runtime with a different C++ standard
+ # -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} # alternatively, compile the runtime with the same C++ standard as the outer project
+ INSTALL_COMMAND ""
+ EXCLUDE_FROM_ALL 1)
+endif()
+
+# Separate build step as rarely people want both
+set(ANTLR4_BUILD_DIR ${ANTLR4_ROOT})
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0")
+ # CMake 3.14 builds in above's SOURCE_SUBDIR when BUILD_IN_SOURCE is true
+ set(ANTLR4_BUILD_DIR ${ANTLR4_ROOT}/runtime/Cpp)
+endif()
+
+ExternalProject_Add_Step(
+ antlr4_runtime
+ build_static
+ COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_static
+ # Depend on target instead of step (a custom command)
+ # to avoid running dependent steps concurrently
+ DEPENDS antlr4_runtime
+ BYPRODUCTS ${ANTLR4_STATIC_LIBRARIES}
+ EXCLUDE_FROM_MAIN 1
+ WORKING_DIRECTORY ${ANTLR4_BUILD_DIR})
+ExternalProject_Add_StepTargets(antlr4_runtime build_static)
+
+add_library(antlr4_static STATIC IMPORTED)
+add_dependencies(antlr4_static antlr4_runtime-build_static)
+set_target_properties(antlr4_static PROPERTIES
+ IMPORTED_LOCATION ${ANTLR4_STATIC_LIBRARIES})
+target_include_directories(antlr4_static
+ INTERFACE
+ ${ANTLR4_INCLUDE_DIRS}
+)
+
+ExternalProject_Add_Step(
+ antlr4_runtime
+ build_shared
+ COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_shared
+ # Depend on target instead of step (a custom command)
+ # to avoid running dependent steps concurrently
+ DEPENDS antlr4_runtime
+ BYPRODUCTS ${ANTLR4_SHARED_LIBRARIES} ${ANTLR4_RUNTIME_LIBRARIES}
+ EXCLUDE_FROM_MAIN 1
+ WORKING_DIRECTORY ${ANTLR4_BUILD_DIR})
+ExternalProject_Add_StepTargets(antlr4_runtime build_shared)
+
+add_library(antlr4_shared SHARED IMPORTED)
+add_dependencies(antlr4_shared antlr4_runtime-build_shared)
+set_target_properties(antlr4_shared PROPERTIES
+ IMPORTED_LOCATION ${ANTLR4_RUNTIME_LIBRARIES})
+target_include_directories(antlr4_shared
+ INTERFACE
+ ${ANTLR4_INCLUDE_DIRS}
+)
+
+if(ANTLR4_SHARED_LIBRARIES)
+ set_target_properties(antlr4_shared PROPERTIES
+ IMPORTED_IMPLIB ${ANTLR4_SHARED_LIBRARIES})
+endif()
\ No newline at end of file
diff --git a/Cpp/cmake/FindANTLR.cmake b/Cpp/cmake/FindANTLR.cmake
new file mode 100755
index 0000000..77f4f7b
--- /dev/null
+++ b/Cpp/cmake/FindANTLR.cmake
@@ -0,0 +1,124 @@
+find_package(Java QUIET COMPONENTS Runtime)
+
+if(NOT ANTLR_EXECUTABLE)
+ find_program(ANTLR_EXECUTABLE
+ NAMES antlr.jar antlr4.jar antlr-4.jar antlr-4.13.2-complete.jar)
+endif()
+
+if(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE)
+ execute_process(
+ COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}
+ OUTPUT_VARIABLE ANTLR_COMMAND_OUTPUT
+ ERROR_VARIABLE ANTLR_COMMAND_ERROR
+ RESULT_VARIABLE ANTLR_COMMAND_RESULT
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(ANTLR_COMMAND_RESULT EQUAL 0)
+ string(REGEX MATCH "Version [0-9]+(\\.[0-9]+)*" ANTLR_VERSION ${ANTLR_COMMAND_OUTPUT})
+ string(REPLACE "Version " "" ANTLR_VERSION ${ANTLR_VERSION})
+ else()
+ message(
+ SEND_ERROR
+ "Command '${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}' "
+ "failed with the output '${ANTLR_COMMAND_ERROR}'")
+ endif()
+
+ macro(ANTLR_TARGET Name InputFile)
+ set(ANTLR_OPTIONS LEXER PARSER LISTENER VISITOR)
+ set(ANTLR_ONE_VALUE_ARGS PACKAGE OUTPUT_DIRECTORY DEPENDS_ANTLR)
+ set(ANTLR_MULTI_VALUE_ARGS COMPILE_FLAGS DEPENDS)
+ cmake_parse_arguments(ANTLR_TARGET
+ "${ANTLR_OPTIONS}"
+ "${ANTLR_ONE_VALUE_ARGS}"
+ "${ANTLR_MULTI_VALUE_ARGS}"
+ ${ARGN})
+
+ set(ANTLR_${Name}_INPUT ${InputFile})
+
+ get_filename_component(ANTLR_INPUT ${InputFile} NAME_WE)
+
+ if(ANTLR_TARGET_OUTPUT_DIRECTORY)
+ set(ANTLR_${Name}_OUTPUT_DIR ${ANTLR_TARGET_OUTPUT_DIRECTORY})
+ else()
+ set(ANTLR_${Name}_OUTPUT_DIR
+ ${CMAKE_CURRENT_BINARY_DIR}/antlr4cpp_generated_src/${ANTLR_INPUT})
+ endif()
+
+ unset(ANTLR_${Name}_CXX_OUTPUTS)
+
+ if((ANTLR_TARGET_LEXER AND NOT ANTLR_TARGET_PARSER) OR
+ (ANTLR_TARGET_PARSER AND NOT ANTLR_TARGET_LEXER))
+ list(APPEND ANTLR_${Name}_CXX_OUTPUTS
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.h
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.cpp)
+ set(ANTLR_${Name}_OUTPUTS
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.interp
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.tokens)
+ else()
+ list(APPEND ANTLR_${Name}_CXX_OUTPUTS
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.h
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.cpp
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.h
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.cpp)
+ list(APPEND ANTLR_${Name}_OUTPUTS
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.interp
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.tokens)
+ endif()
+
+ if(ANTLR_TARGET_LISTENER)
+ list(APPEND ANTLR_${Name}_CXX_OUTPUTS
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.h
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.cpp
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.h
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.cpp)
+ list(APPEND ANTLR_TARGET_COMPILE_FLAGS -listener)
+ endif()
+
+ if(ANTLR_TARGET_VISITOR)
+ list(APPEND ANTLR_${Name}_CXX_OUTPUTS
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.h
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.cpp
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.h
+ ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.cpp)
+ list(APPEND ANTLR_TARGET_COMPILE_FLAGS -visitor)
+ endif()
+
+ if(ANTLR_TARGET_PACKAGE)
+ list(APPEND ANTLR_TARGET_COMPILE_FLAGS -package ${ANTLR_TARGET_PACKAGE})
+ endif()
+
+ list(APPEND ANTLR_${Name}_OUTPUTS ${ANTLR_${Name}_CXX_OUTPUTS})
+
+ if(ANTLR_TARGET_DEPENDS_ANTLR)
+ if(ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT)
+ list(APPEND ANTLR_TARGET_DEPENDS
+ ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT})
+ list(APPEND ANTLR_TARGET_DEPENDS
+ ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_OUTPUTS})
+ else()
+ message(SEND_ERROR
+ "ANTLR target '${ANTLR_TARGET_DEPENDS_ANTLR}' not found")
+ endif()
+ endif()
+
+ add_custom_command(
+ OUTPUT ${ANTLR_${Name}_OUTPUTS}
+ COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}
+ ${InputFile}
+ -o ${ANTLR_${Name}_OUTPUT_DIR}
+ -no-listener
+ -Dlanguage=Cpp
+ ${ANTLR_TARGET_COMPILE_FLAGS}
+ DEPENDS ${InputFile}
+ ${ANTLR_TARGET_DEPENDS}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Building ${Name} with ANTLR ${ANTLR_VERSION}")
+ endmacro(ANTLR_TARGET)
+
+endif(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+ ANTLR
+ REQUIRED_VARS ANTLR_EXECUTABLE Java_JAVA_EXECUTABLE
+ VERSION_VAR ANTLR_VERSION)
\ No newline at end of file
diff --git a/Cpp/cmake/antlr4-generator.cmake.in b/Cpp/cmake/antlr4-generator.cmake.in
new file mode 100755
index 0000000..9672d58
--- /dev/null
+++ b/Cpp/cmake/antlr4-generator.cmake.in
@@ -0,0 +1,181 @@
+set(ANTLR_VERSION @ANTLR_VERSION@)
+
+@PACKAGE_INIT@
+
+if (NOT ANTLR4_CPP_GENERATED_SRC_DIR)
+ set(ANTLR4_GENERATED_SRC_DIR ${CMAKE_BINARY_DIR}/antlr4_generated_src)
+endif()
+
+FIND_PACKAGE(Java COMPONENTS Runtime REQUIRED)
+
+#
+# The ANTLR generator will output the following files given the input file f.g4
+#
+# Input -> f.g4
+# Output -> f.h
+# -> f.cpp
+#
+# the following files will only be produced if there is a parser contained
+# Flag -visitor active
+# Output -> BaseVisitor.h
+# -> BaseVisitor.cpp
+# -> Visitor.h
+# -> Visitor.cpp
+#
+# Flag -listener active
+# Output -> BaseListener.h
+# -> BaseListener.cpp
+# -> Listener.h
+# -> Listener.cpp
+#
+# See documentation in markup
+#
+function(antlr4_generate
+ Antlr4_ProjectTarget
+ Antlr4_InputFile
+ Antlr4_GeneratorType
+ )
+
+ set( Antlr4_GeneratedSrcDir ${ANTLR4_GENERATED_SRC_DIR}/${Antlr4_ProjectTarget} )
+
+ get_filename_component(Antlr4_InputFileBaseName ${Antlr4_InputFile} NAME_WE )
+
+ list( APPEND Antlr4_GeneratorStatusMessage "Common Include-, Source- and Tokenfiles" )
+
+ if ( ${Antlr4_GeneratorType} STREQUAL "LEXER")
+ set(Antlr4_LexerBaseName "${Antlr4_InputFileBaseName}")
+ set(Antlr4_ParserBaseName "")
+ else()
+ if ( ${Antlr4_GeneratorType} STREQUAL "PARSER")
+ set(Antlr4_LexerBaseName "")
+ set(Antlr4_ParserBaseName "${Antlr4_InputFileBaseName}")
+ else()
+ if ( ${Antlr4_GeneratorType} STREQUAL "BOTH")
+ set(Antlr4_LexerBaseName "${Antlr4_InputFileBaseName}Lexer")
+ set(Antlr4_ParserBaseName "${Antlr4_InputFileBaseName}Parser")
+ else()
+ message(FATAL_ERROR "The third parameter must be LEXER, PARSER or BOTH")
+ endif ()
+ endif ()
+ endif ()
+
+ # Prepare list of generated targets
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}.tokens" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}.interp" )
+ list( APPEND DependentTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}.tokens" )
+
+ if ( NOT ${Antlr4_LexerBaseName} STREQUAL "" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_LexerBaseName}.h" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_LexerBaseName}.cpp" )
+ endif ()
+
+ if ( NOT ${Antlr4_ParserBaseName} STREQUAL "" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_ParserBaseName}.h" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_ParserBaseName}.cpp" )
+ endif ()
+
+ # process optional arguments ...
+
+ if ( ( ARGC GREATER_EQUAL 4 ) AND ARGV3 )
+ set(Antlr4_BuildListenerOption "-listener")
+
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseListener.h" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseListener.cpp" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Listener.h" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Listener.cpp" )
+
+ list( APPEND Antlr4_GeneratorStatusMessage ", Listener Include- and Sourcefiles" )
+ else()
+ set(Antlr4_BuildListenerOption "-no-listener")
+ endif ()
+
+ if ( ( ARGC GREATER_EQUAL 5 ) AND ARGV4 )
+ set(Antlr4_BuildVisitorOption "-visitor")
+
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseVisitor.h" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseVisitor.cpp" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Visitor.h" )
+ list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Visitor.cpp" )
+
+ list( APPEND Antlr4_GeneratorStatusMessage ", Visitor Include- and Sourcefiles" )
+ else()
+ set(Antlr4_BuildVisitorOption "-no-visitor")
+ endif ()
+
+ if ( (ARGC GREATER_EQUAL 6 ) AND (NOT ${ARGV5} STREQUAL "") )
+ set(Antlr4_NamespaceOption "-package;${ARGV5}")
+
+ list( APPEND Antlr4_GeneratorStatusMessage " in Namespace ${ARGV5}" )
+ else()
+ set(Antlr4_NamespaceOption "")
+ endif ()
+
+ if ( (ARGC GREATER_EQUAL 7 ) AND (NOT ${ARGV6} STREQUAL "") )
+ set(Antlr4_AdditionalDependencies ${ARGV6})
+ else()
+ set(Antlr4_AdditionalDependencies "")
+ endif ()
+
+ if ( (ARGC GREATER_EQUAL 8 ) AND (NOT ${ARGV7} STREQUAL "") )
+ set(Antlr4_LibOption "-lib;${ARGV7}")
+
+ list( APPEND Antlr4_GeneratorStatusMessage " using Library ${ARGV7}" )
+ else()
+ set(Antlr4_LibOption "")
+ endif ()
+
+ if(NOT Java_FOUND)
+ message(FATAL_ERROR "Java is required to process grammar or lexer files! - Use 'FIND_PACKAGE(Java COMPONENTS Runtime REQUIRED)'")
+ endif()
+
+ if(NOT EXISTS "${ANTLR4_JAR_LOCATION}")
+ message(FATAL_ERROR "Unable to find antlr tool. ANTLR4_JAR_LOCATION:${ANTLR4_JAR_LOCATION}")
+ endif()
+
+ # The call to generate the files
+ add_custom_command(
+ OUTPUT ${Antlr4_GeneratedTargets}
+ # Remove target directory
+ COMMAND
+ ${CMAKE_COMMAND} -E remove_directory ${Antlr4_GeneratedSrcDir}
+ # Create target directory
+ COMMAND
+ ${CMAKE_COMMAND} -E make_directory ${Antlr4_GeneratedSrcDir}
+ COMMAND
+ # Generate files
+ "${Java_JAVA_EXECUTABLE}" -jar "${ANTLR4_JAR_LOCATION}" -Werror -Dlanguage=Cpp ${Antlr4_BuildListenerOption} ${Antlr4_BuildVisitorOption} ${Antlr4_LibOption} ${ANTLR4_GENERATED_OPTIONS} -o "${Antlr4_GeneratedSrcDir}" ${Antlr4_NamespaceOption} "${Antlr4_InputFile}"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ MAIN_DEPENDENCY "${Antlr4_InputFile}"
+ DEPENDS ${Antlr4_AdditionalDependencies}
+ )
+
+ # set output variables in parent scope
+ set( ANTLR4_INCLUDE_DIR_${Antlr4_ProjectTarget} ${Antlr4_GeneratedSrcDir} PARENT_SCOPE)
+ set( ANTLR4_SRC_FILES_${Antlr4_ProjectTarget} ${Antlr4_GeneratedTargets} PARENT_SCOPE)
+ set( ANTLR4_TOKEN_FILES_${Antlr4_ProjectTarget} ${DependentTargets} PARENT_SCOPE)
+ set( ANTLR4_TOKEN_DIRECTORY_${Antlr4_ProjectTarget} ${Antlr4_GeneratedSrcDir} PARENT_SCOPE)
+
+ # export generated cpp files into list
+ foreach(generated_file ${Antlr4_GeneratedTargets})
+
+ if (NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ set_source_files_properties(
+ ${generated_file}
+ PROPERTIES
+ COMPILE_FLAGS -Wno-overloaded-virtual
+ )
+ endif ()
+
+ if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ set_source_files_properties(
+ ${generated_file}
+ PROPERTIES
+ COMPILE_FLAGS -wd4251
+ )
+ endif ()
+
+ endforeach(generated_file)
+
+message(STATUS "Antlr4 ${Antlr4_ProjectTarget} - Building " ${Antlr4_GeneratorStatusMessage} )
+
+endfunction()
\ No newline at end of file
diff --git a/Cpp/cmake/antlr4-runtime.cmake.in b/Cpp/cmake/antlr4-runtime.cmake.in
new file mode 100755
index 0000000..c120494
--- /dev/null
+++ b/Cpp/cmake/antlr4-runtime.cmake.in
@@ -0,0 +1,13 @@
+set(ANTLR_VERSION @ANTLR_VERSION@)
+
+@PACKAGE_INIT@
+
+set_and_check(ANTLR4_INCLUDE_DIR "@PACKAGE_ANTLR4_INCLUDE_DIR@")
+set_and_check(ANTLR4_LIB_DIR "@PACKAGE_ANTLR4_LIB_DIR@")
+
+include(CMakeFindDependencyMacro)
+find_dependency(Threads)
+
+include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake)
+
+check_required_components(antlr)
\ No newline at end of file
diff --git a/Cpp/demo/ArcscriptTest.cpp b/Cpp/demo/ArcscriptTest.cpp
new file mode 100644
index 0000000..7fd8f53
--- /dev/null
+++ b/Cpp/demo/ArcscriptTest.cpp
@@ -0,0 +1,330 @@
+// ArcscriptTranspilerTest.cpp: This file contains the 'main' function. Program execution begins and ends there.
+//
+
+#include
+#include
+#include
+#include
"
+ state->outputs.AddParagraph(paragraph_content);
+ return context->getText();
+}
+
+
+std::any ArcscriptVisitor::visitAssignment_segment(ArcscriptParser::Assignment_segmentContext *ctx) {
+ state->outputs.AddScript();
+ return visitStatement_assignment(ctx->statement_assignment());
+}
+
+std::any ArcscriptVisitor::visitFunction_call_segment(ArcscriptParser::Function_call_segmentContext *ctx) {
+ state->outputs.AddScript();
+ return visitStatement_function_call(ctx->statement_function_call());
+}
+
+std::any ArcscriptVisitor::visitConditional_section(ArcscriptParser::Conditional_sectionContext *ctx) {
+ state->outputs.AddScript();
+ ConditionalSection ifSection = std::any_cast(visitIf_section(ctx->if_section()));
+ if (ifSection.clause) {
+ state->outputs.AddScript();
+ return ifSection.script;
+ }
+ for (ArcscriptParser::Else_if_sectionContext *else_if_section : ctx->else_if_section()) {
+ ConditionalSection elif_section = std::any_cast(visitElse_if_section(else_if_section));
+ if (elif_section.clause) {
+ return elif_section.script;
+ }
+ }
+ if (ctx->else_section() != NULL) {
+ ConditionalSection elseSection = std::any_cast(visitElse_section(ctx->else_section()));
+ state->outputs.AddScript();
+ return elseSection.script;
+ }
+ state->outputs.AddScript();
+ return std::any();
+}
+
+std::any ArcscriptVisitor::visitIf_section(ArcscriptParser::If_sectionContext *ctx) {
+ Expression result = std::any_cast(visitIf_clause(ctx->if_clause()));
+ ConditionalSection ifSection;
+ ifSection.clause = false;
+ if (result == true) {
+ ifSection.clause = true;
+ ifSection.script = visitScript(ctx->script());
+ }
+ return ifSection;
+}
+
+std::any ArcscriptVisitor::visitElse_if_section(ArcscriptParser::Else_if_sectionContext *ctx) {
+ Expression result = std::any_cast(visitElse_if_clause(ctx->else_if_clause()));
+ ConditionalSection elseSection;
+ elseSection.clause = false;
+ if (result == true) {
+ elseSection.clause = true;
+ elseSection.script = visitScript(ctx->script());
+ }
+
+ return elseSection;
+}
+
+std::any ArcscriptVisitor::visitElse_section(ArcscriptParser::Else_sectionContext *ctx) {
+ ConditionalSection elseIfSection;
+ elseIfSection.clause = true;
+ elseIfSection.script = visitScript(ctx->script());
+ return elseIfSection;
+}
+
+std::any ArcscriptVisitor::visitIf_clause(ArcscriptParser::If_clauseContext *ctx) {
+ return visitCompound_condition_or(ctx->compound_condition_or());
+}
+
+std::any ArcscriptVisitor::visitElse_if_clause(ArcscriptParser::Else_if_clauseContext *ctx) {
+ return visitCompound_condition_or(ctx->compound_condition_or());
+}
+
+std::any ArcscriptVisitor::visitStatement_assignment(ArcscriptParser::Statement_assignmentContext *ctx) {
+ std::string variableName = ctx->VARIABLE()->getText();
+ Expression compound_condition_or = std::any_cast(visitCompound_condition_or(ctx->compound_condition_or()));
+ if (ctx->ASSIGN() != NULL) {
+ state->setVarValue(variableName, compound_condition_or.value);
+ return std::any();
+ }
+
+ Expression varValue;
+ varValue.setValue(state->getVarValue(variableName));
+
+ if (ctx->ASSIGNADD() != NULL) {
+ varValue += compound_condition_or;
+ }
+ if (ctx->ASSIGNSUB() != NULL) {
+ varValue -= compound_condition_or;
+ }
+ if (ctx->ASSIGNMUL() != NULL) {
+ varValue *= compound_condition_or;
+ }
+ if (ctx->ASSIGNDIV() != NULL) {
+ varValue /= compound_condition_or;
+ }
+
+ state->setVarValue(variableName, varValue.value);
+ return std::any();
+}
+
+std::any ArcscriptVisitor::visitCompound_condition_or(ArcscriptParser::Compound_condition_orContext *ctx) {
+ std::any cond_any = visitCompound_condition_and(ctx->compound_condition_and());
+ Expression compound_condition_and = std::any_cast(cond_any);
+ if (ctx->compound_condition_or() != NULL) {
+ Expression compound_condition_or = std::any_cast(visitCompound_condition_or(ctx->compound_condition_or()));
+ Expression result(compound_condition_and || compound_condition_or);
+ return result;
+ }
+ return compound_condition_and;
+}
+
+std::any ArcscriptVisitor::visitCompound_condition_and(ArcscriptParser::Compound_condition_andContext *ctx) {
+ std::any cond_any = visitNegated_unary_condition(ctx->negated_unary_condition());
+ Expression negated_unary_condition = std::any_cast(cond_any);
+ if (ctx->compound_condition_and() != NULL) {
+ Expression compound_condition_and = std::any_cast(visitCompound_condition_and(ctx->compound_condition_and()));
+ Expression result(negated_unary_condition && compound_condition_and);
+ return result;
+ }
+ return negated_unary_condition;
+}
+
+std::any ArcscriptVisitor::visitNegated_unary_condition(ArcscriptParser::Negated_unary_conditionContext *ctx) {
+ Expression unary_condition = std::any_cast(visitUnary_condition(ctx->unary_condition()));
+ if (ctx->NEG() != NULL || ctx->NOTKEYWORD() != NULL) {
+ return Expression(!unary_condition);
+ }
+ return unary_condition;
+}
+
+std::any ArcscriptVisitor::visitCondition(ArcscriptParser::ConditionContext *ctx) {
+ if (ctx->expression().size() == 1) {
+ return visitExpression(ctx->expression()[0]);
+
+ // Expression expr = std::any_cast(exprAny);
+ // if (expr.type() == typeid(double)) {
+ // return expr > 0.0;
+ // }
+ // else if (expr.type() == typeid(int)) {
+ // return expr > 0;
+ // }
+ // else if (expr.type() == typeid(std::string)) {
+ // return expr != "";
+ // }
+ // return std::any_cast(expr.value);
+ }
+
+ ArcscriptParser::Conditional_operatorContext *cond_operator_ctx = ctx->conditional_operator();
+ Expression exp0 = std::any_cast(visitExpression(ctx->expression()[0]));
+ Expression exp1 = std::any_cast(visitExpression(ctx->expression()[1]));
+ bool result = false;
+ if (cond_operator_ctx->GT() != NULL) {
+ result = exp0 > exp1;
+ }
+ else if (cond_operator_ctx->GE() != NULL) {
+ result = exp0 >= exp1;
+ }
+ else if (cond_operator_ctx->LT() != NULL) {
+ result = exp0 < exp1;
+ }
+ else if (cond_operator_ctx->LE() != NULL) {
+ result = exp0 <= exp1;
+ }
+ else if (cond_operator_ctx->EQ() != NULL) {
+ result = exp0 == exp1;
+ }
+ else if (cond_operator_ctx->NE() != NULL) {
+ result = exp0 != exp1;
+ }
+ else if (cond_operator_ctx->ISKEYWORD() != NULL) {
+ if (cond_operator_ctx->NOTKEYWORD() != NULL) {
+ result = exp0 != exp1;
+ } else {
+ result = exp0 == exp1;
+ }
+ }
+ return Expression(result);
+}
+
+std::any ArcscriptVisitor::visitExpression(ArcscriptParser::ExpressionContext *ctx) {
+ if (ctx->STRING() != NULL) {
+ std::string result = ctx->STRING()->getText();
+ result = result.substr(1, result.size() - 2);
+ return Expression(result);
+ }
+ if (ctx->BOOLEAN() != NULL) {
+ return Expression(ctx->BOOLEAN()->getText() == "true");
+ }
+
+ return visitAdditive_numeric_expression(ctx->additive_numeric_expression());
+}
+
+std::any ArcscriptVisitor::visitAdditive_numeric_expression(ArcscriptParser::Additive_numeric_expressionContext *ctx) {
+ if (ctx->additive_numeric_expression() != NULL) {
+ Expression result = std::any_cast(visitAdditive_numeric_expression(ctx->additive_numeric_expression()));
+ Expression mult_num_expr = std::any_cast(visitMultiplicative_numeric_expression(ctx->multiplicative_numeric_expression()));
+
+ if (ctx->ADD() != NULL) {
+ mult_num_expr = result + mult_num_expr;
+ }
+ else if (ctx->SUB() != NULL) {
+ mult_num_expr = result - mult_num_expr;
+ }
+ return mult_num_expr;
+ }
+ return std::any_cast(visitMultiplicative_numeric_expression(ctx->multiplicative_numeric_expression()));
+}
+
+std::any ArcscriptVisitor::visitMultiplicative_numeric_expression(ArcscriptParser::Multiplicative_numeric_expressionContext *ctx) {
+ if (ctx->multiplicative_numeric_expression() != NULL) {
+ Expression result = std::any_cast(visitMultiplicative_numeric_expression(ctx->multiplicative_numeric_expression()));
+ Expression signed_unary_num_expr = std::any_cast(visitSigned_unary_numeric_expression(ctx->signed_unary_numeric_expression()));
+
+ if (ctx->MUL() != NULL) {
+ signed_unary_num_expr = result * signed_unary_num_expr;
+ }
+ else if (ctx->DIV() != NULL) {
+ signed_unary_num_expr = result / signed_unary_num_expr;
+ }
+ return signed_unary_num_expr;
+ }
+
+ return std::any_cast(visitSigned_unary_numeric_expression(ctx->signed_unary_numeric_expression()));
+}
+
+std::any ArcscriptVisitor::visitSigned_unary_numeric_expression(ArcscriptParser::Signed_unary_numeric_expressionContext *ctx) {
+ std::any expr_any = visitUnary_numeric_expression(ctx->unary_numeric_expression());
+ Expression unary_num_expr = std::any_cast(expr_any);
+ ArcscriptParser::SignContext *sign = ctx->sign();
+
+ if (sign != NULL) {
+ if (sign->ADD() != NULL) {
+ return unary_num_expr;
+ }
+ // Else MINUS
+ unary_num_expr = unary_num_expr * (-1);
+ }
+ return unary_num_expr;
+}
+
+std::any ArcscriptVisitor::visitUnary_numeric_expression(ArcscriptParser::Unary_numeric_expressionContext *ctx) {
+ if (ctx->FLOAT() != NULL) {
+ Expression result(std::stod(ctx->FLOAT()->getText()));
+ return result;
+ }
+ if (ctx->INTEGER() != NULL) {
+ Expression result(std::stoi(ctx->INTEGER()->getText()));
+ return result;
+ }
+ if (ctx->STRING() != NULL) {
+ std::string result = ctx->STRING()->getText();
+ result = result.substr(1, result.size() - 2);
+ return Expression(result);
+ }
+ if (ctx->BOOLEAN() != NULL) {
+ return Expression(ctx->BOOLEAN()->getText() == "true");
+ }
+ if (ctx->VARIABLE() != NULL) {
+ std::string variableName = ctx->VARIABLE()->getText();
+ std::any varValue = state->getVarValue(variableName);
+ if (varValue.type() == typeid(std::string)) {
+ Expression result(std::any_cast(varValue));
+ return result;
+ }
+ if (varValue.type() == typeid(bool)) {
+ Expression result(std::any_cast(varValue));
+ return result;
+ }
+ if (varValue.type() == typeid(int)) {
+ Expression result(std::any_cast(varValue));
+ return result;
+ }
+ if (varValue.type() == typeid(double)) {
+ Expression result(std::any_cast(varValue));
+ return result;
+ }
+ }
+ if (ctx->function_call() != NULL) {
+ std::any resultValue = visitFunction_call(ctx->function_call());
+ if (resultValue.type() == typeid(std::string)) {
+ Expression result(std::any_cast(resultValue));
+ return result;
+ }
+ if (resultValue.type() == typeid(bool)) {
+ Expression result(std::any_cast(resultValue));
+ return result;
+ }
+ if (resultValue.type() == typeid(int)) {
+ Expression result(std::any_cast(resultValue));
+ return result;
+ }
+ if (resultValue.type() == typeid(double)) {
+ Expression result(std::any_cast(resultValue));
+ return result;
+ }
+ throw Arcweave::RuntimeErrorException("Unknown result type from function call: " + ctx->function_call()->getText() + "\nType: " + resultValue.type().name());
+ }
+ return visitCompound_condition_or(ctx->compound_condition_or());
+}
+
+std::any ArcscriptVisitor::visitVoid_function_call(ArcscriptParser::Void_function_callContext *ctx) {
+ std::string fname = "";
+ std::any result;
+ if (ctx->VFNAME() != NULL) {
+ fname = ctx->VFNAME()->getText();
+ std::vector argument_list_result;
+ if (ctx->argument_list() != NULL) {
+ argument_list_result = std::any_cast>(visitArgument_list(ctx->argument_list()));
+ }
+ result = functions->Call(fname, argument_list_result);
+ }
+
+ if (ctx->VFNAMEVARS() != NULL) {
+ fname = ctx->VFNAMEVARS()->getText();
+ std::vector variable_list_result;
+
+ if (ctx->variable_list() != NULL) {
+ variable_list_result = std::any_cast>(visitVariable_list(ctx->variable_list()));
+ }
+ result = functions->Call(fname, variable_list_result);
+ }
+ // std::any result = std::invoke(functions->functions[fname], functions, argument_list_result);
+
+ return result;
+}
+
+std::any ArcscriptVisitor::visitFunction_call(ArcscriptParser::Function_callContext *ctx) {
+ std::vector argument_list_result;
+ if (ctx->argument_list() != NULL) {
+ argument_list_result = std::any_cast>(visitArgument_list(ctx->argument_list()));
+ }
+ std::string fname = ctx->FNAME()->getText();
+
+ // std::any result = std::invoke(functions->functions[fname], functions, argument_list_result);
+ std::any result = functions->Call(fname, argument_list_result);
+ return result;
+}
+
+std::any ArcscriptVisitor::visitVariable_list(ArcscriptParser::Variable_listContext *ctx) {
+ std::vector variables;
+ for (antlr4::tree::TerminalNode *variable : ctx->VARIABLE()) {
+ variables.push_back(state->getVar(variable->getText()));
+ }
+ return variables;
+}
+
+std::any ArcscriptVisitor::visitArgument_list(ArcscriptParser::Argument_listContext *ctx) {
+ std::vector arguments;
+ for (ArcscriptParser::ArgumentContext *argument : ctx->argument()) {
+ arguments.push_back(visitArgument(argument));
+ }
+ return arguments;
+}
+
+std::any ArcscriptVisitor::visitArgument(ArcscriptParser::ArgumentContext *ctx) {
+ if (ctx->STRING() != NULL) {
+ std::string result = ctx->STRING()->getText();
+ result = result.substr(1, result.size() - 2);
+ return Expression(result);
+ }
+ if (ctx->mention() != NULL) {
+ Mention mention_result = std::any_cast(visitMention(ctx->mention()));
+ return mention_result;
+ }
+
+ return visitAdditive_numeric_expression(ctx->additive_numeric_expression());
+}
+
+std::any ArcscriptVisitor::visitMention(ArcscriptParser::MentionContext *ctx) {
+ std::map attrs;
+ for (ArcscriptParser::Mention_attributesContext *attr : ctx->mention_attributes()) {
+ std::map res = std::any_cast>(visitMention_attributes(attr));
+ attrs[res["name"]] = res["value"];
+ }
+ std::string label = "";
+ if (ctx->MENTION_LABEL() != NULL) {
+ label = ctx->MENTION_LABEL()->getText();
+ }
+ Mention mention(label, attrs);
+ return mention;
+}
+
+inline bool ends_with(std::string const & value, std::string const & ending)
+{
+ if (ending.size() > value.size()) return false;
+ return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
+}
+
+std::any ArcscriptVisitor::visitMention_attributes(ArcscriptParser::Mention_attributesContext *ctx) {
+ std::string name = ctx->ATTR_NAME()->getText();
+ antlr4::tree::TerminalNode *valueNode = ctx->ATTR_VALUE();
+ std::string value(name);
+
+ if (valueNode != NULL) {
+ std::string strvalue = valueNode->getText();
+ if ((strvalue.rfind("\"", 0) == 0 && ends_with(strvalue, "\"")) ||
+ strvalue.rfind("'", 0) == 0 && ends_with(strvalue, "'")) {
+
+ strvalue = strvalue.substr(1, strvalue.size() - 2);
+
+ }
+ value = strvalue;
+ }
+ return std::map { {"name", name }, {"value", value } };
+}
diff --git a/Cpp/src/ArcscriptVisitor.h b/Cpp/src/ArcscriptVisitor.h
new file mode 100755
index 0000000..2b07166
--- /dev/null
+++ b/Cpp/src/ArcscriptVisitor.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "ArcscriptParserBaseVisitor.h"
+#include "ArcscriptFunctions.h"
+
+using namespace Arcweave;
+
+class ArcscriptVisitor : public ArcscriptParserBaseVisitor {
+public:
+ struct ConditionalSection {
+ bool clause;
+ std::any script;
+ };
+
+ ArcscriptState *state;
+ ArcscriptFunctions *functions;
+
+ ArcscriptVisitor(ArcscriptState* _state) : state(_state) {
+ functions = new ArcscriptFunctions(state);
+ }
+
+ std::any visitInput(ArcscriptParser::InputContext *ctx) override;
+ std::any visitScript_section(ArcscriptParser::Script_sectionContext *ctx) override;
+ std::any visitAssignment_segment(ArcscriptParser::Assignment_segmentContext *ctx) override;
+ std::any visitFunction_call_segment(ArcscriptParser::Function_call_segmentContext * ctx) override;
+ std::any visitConditional_section(ArcscriptParser::Conditional_sectionContext *ctx) override;
+ std::any visitIf_section(ArcscriptParser::If_sectionContext *ctx) override;
+ std::any visitElse_if_section(ArcscriptParser::Else_if_sectionContext *ctx) override;
+ std::any visitElse_section(ArcscriptParser::Else_sectionContext *ctx) override;
+ std::any visitIf_clause(ArcscriptParser::If_clauseContext *ctx) override;
+ std::any visitElse_if_clause(ArcscriptParser::Else_if_clauseContext *ctx) override;
+ std::any visitStatement_assignment(ArcscriptParser::Statement_assignmentContext *ctx) override;
+ std::any visitCompound_condition_or(ArcscriptParser::Compound_condition_orContext *ctx) override;
+ std::any visitCompound_condition_and(ArcscriptParser::Compound_condition_andContext *ctx) override;
+ std::any visitNegated_unary_condition(ArcscriptParser::Negated_unary_conditionContext *ctx) override;
+ std::any visitCondition(ArcscriptParser::ConditionContext *ctx) override;
+ std::any visitExpression(ArcscriptParser::ExpressionContext *ctx) override;
+ std::any visitAdditive_numeric_expression(ArcscriptParser::Additive_numeric_expressionContext *ctx) override;
+ std::any visitMultiplicative_numeric_expression(ArcscriptParser::Multiplicative_numeric_expressionContext *ctx) override;
+ std::any visitSigned_unary_numeric_expression(ArcscriptParser::Signed_unary_numeric_expressionContext *ctx) override;
+ std::any visitUnary_numeric_expression(ArcscriptParser::Unary_numeric_expressionContext *ctx) override;
+ std::any visitVoid_function_call(ArcscriptParser::Void_function_callContext *ctx) override;
+ std::any visitFunction_call(ArcscriptParser::Function_callContext *ctx) override;
+ std::any visitVariable_list(ArcscriptParser::Variable_listContext *ctx) override;
+ std::any visitArgument_list(ArcscriptParser::Argument_listContext *ctx) override;
+ std::any visitArgument(ArcscriptParser::ArgumentContext *ctx) override;
+ std::any visitMention(ArcscriptParser::MentionContext *ctx) override;
+ std::any visitMention_attributes(ArcscriptParser::Mention_attributesContext *ctx) override;
+ std::any visitParagraph(ArcscriptParser::ParagraphContext* context) override;
+ std::any visitBlockquote(ArcscriptParser::BlockquoteContext* context) override;
+};
diff --git a/README.md b/README.md
index 4351dfc..8e82f34 100644
--- a/README.md
+++ b/README.md
@@ -42,9 +42,16 @@ We are using the JavaScript parser to interpret arcscript in our arcweave app. W
You can find more info in [JavaScript](JavaScript) folder.
-### C# & C++
+### C#
-The implementation on these two languages are not yet ready to be published.
+Use the C# code along with the antlr4 NuGet package in your project.
+
+Find more info in the [CSharp](CSharp) folder.
+
+### C++
+
+Building the C++ solution will create the include headers and the shared libaries (.dll for Windows and .dylib for macOS) to be included in your project
+Find more info in the [Cpp](Cpp) folder.
## Links & References
diff --git a/generate.ps1 b/generate.ps1
index 593c942..d325749 100644
--- a/generate.ps1
+++ b/generate.ps1
@@ -28,6 +28,6 @@ Set-Location ..
# CSharp generation
java -Xmx500M -cp ../antlr4.jar org.antlr.v4.Tool -Dlanguage=CSharp ArcscriptLexer.g4 ArcscriptParser.g4 -visitor -no-listener -o ./CSharp -package Arcweave.Interpreter
-New-Item -ItemType Directory -Force -Path ../CSharp/src/Generated | Out-Null
-Copy-Item CSharp\*.cs ../CSharp/src/Generated\
+New-Item -ItemType Directory -Force -Path ../CSharp/Interpreter/Generated | Out-Null
+Copy-Item CSharp\*.cs ../CSharp/Interpreter/Generated\
Remove-Item -Recurse -Force ./CSharp
\ No newline at end of file
diff --git a/generate.sh b/generate.sh
index 5c253ec..e76b1ac 100644
--- a/generate.sh
+++ b/generate.sh
@@ -1,3 +1,6 @@
+#!/usr/bin/env bash
+cd "$(dirname "$0")"
+
if [ ! -f ./antlr4.jar ]
then
curl https://www.antlr.org/download/antlr-4.13.1-complete.jar -o antlr4.jar