From 4b13ceadd16145ddd813c1ddcbcd3cb0231c14d0 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Tue, 24 Jun 2025 15:16:44 +0300 Subject: [PATCH 01/31] feat: (wip) ArcscriptTranspiler initial cmake project --- Cpp/.gitignore | 3 +- Cpp/CMakeLists.txt | 70 +++++ Cpp/cmake/ExternalAntlr4Cpp.cmake | 177 +++++++++++ Cpp/cmake/FindANTLR.cmake | 124 ++++++++ Cpp/cmake/antlr4-generator.cmake.in | 181 +++++++++++ Cpp/cmake/antlr4-runtime.cmake.in | 13 + Cpp/src/ArcscriptErrorExceptions.h | 54 ++++ Cpp/src/ArcscriptErrorListener.cpp | 12 + Cpp/src/ArcscriptErrorListener.h | 14 + Cpp/src/ArcscriptExpression.cpp | 312 +++++++++++++++++++ Cpp/src/ArcscriptExpression.h | 81 +++++ Cpp/src/ArcscriptFunctions.cpp | 206 +++++++++++++ Cpp/src/ArcscriptFunctions.h | 40 +++ Cpp/src/ArcscriptHelpers.h | 109 +++++++ Cpp/src/ArcscriptOutputs.cpp | 79 +++++ Cpp/src/ArcscriptOutputs.h | 96 ++++++ Cpp/src/ArcscriptParserBase.cpp | 99 ++++++ Cpp/src/ArcscriptParserBase.h | 19 ++ Cpp/src/ArcscriptTranspiler.cpp | 172 +++++++++++ Cpp/src/ArcscriptTranspiler.h | 164 ++++++++++ Cpp/src/ArcscriptVisitor.cpp | 461 ++++++++++++++++++++++++++++ Cpp/src/ArcscriptVisitor.h | 52 ++++ 22 files changed, 2537 insertions(+), 1 deletion(-) create mode 100755 Cpp/CMakeLists.txt create mode 100755 Cpp/cmake/ExternalAntlr4Cpp.cmake create mode 100755 Cpp/cmake/FindANTLR.cmake create mode 100755 Cpp/cmake/antlr4-generator.cmake.in create mode 100755 Cpp/cmake/antlr4-runtime.cmake.in create mode 100755 Cpp/src/ArcscriptErrorExceptions.h create mode 100755 Cpp/src/ArcscriptErrorListener.cpp create mode 100755 Cpp/src/ArcscriptErrorListener.h create mode 100755 Cpp/src/ArcscriptExpression.cpp create mode 100755 Cpp/src/ArcscriptExpression.h create mode 100755 Cpp/src/ArcscriptFunctions.cpp create mode 100755 Cpp/src/ArcscriptFunctions.h create mode 100755 Cpp/src/ArcscriptHelpers.h create mode 100755 Cpp/src/ArcscriptOutputs.cpp create mode 100755 Cpp/src/ArcscriptOutputs.h create mode 100755 Cpp/src/ArcscriptParserBase.cpp create mode 100755 Cpp/src/ArcscriptParserBase.h create mode 100755 Cpp/src/ArcscriptTranspiler.cpp create mode 100755 Cpp/src/ArcscriptTranspiler.h create mode 100755 Cpp/src/ArcscriptVisitor.cpp create mode 100755 Cpp/src/ArcscriptVisitor.h diff --git a/Cpp/.gitignore b/Cpp/.gitignore index 21bc544..817844d 100644 --- a/Cpp/.gitignore +++ b/Cpp/.gitignore @@ -1 +1,2 @@ -src/Generated \ No newline at end of file +src/Generated +build \ No newline at end of file diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt new file mode 100755 index 0000000..25096c9 --- /dev/null +++ b/Cpp/CMakeLists.txt @@ -0,0 +1,70 @@ +# minimum required CMAKE version +CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR) + +set(PROJECT_VERSION "0.1.0") +project(ArcscriptTranspiler VERSION ${PROJECT_VERSION}) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +message(CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) +# 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 4.13.1) +# 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}) + +## set variable pointing to the antlr tool that supports C++ +## this is not required if the jar file can be found under PATH environment +#set(ANTLR_EXECUTABLE /home/user/antlr-4.13.2-complete.jar) +## add macros to generate ANTLR Cpp code from grammar +#find_package(ANTLR REQUIRED) +# +## Call macro to add lexer and grammar to your build dependencies. +#antlr_target(SampleGrammarLexer TLexer.g4 LEXER +# PACKAGE antlrcpptest) +#antlr_target(SampleGrammarParser TParser.g4 PARSER +# PACKAGE antlrcpptest +# DEPENDS_ANTLR SampleGrammarLexer +# COMPILE_FLAGS -lib ${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) + +# include generated files in project environment +#include_directories(${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) +#include_directories(${ANTLR_SampleGrammarParser_OUTPUT_DIR}) + +include_directories(src/Generated/ArcscriptLexer) +include_directories(src/Generated/ArcscriptParser) +include_directories(src) +# add generated grammar to demo binary target +#add_executable(demo main.cpp +# src/Generated/ArcscriptLexer +# src/Generated/ArcscriptParser) + +add_library(ArcscriptTranspiler SHARED) + +target_sources(ArcscriptTranspiler PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.cpp) + +set_target_properties(ArcscriptTranspiler PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION}) + +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 antlr4_shared) \ No newline at end of file diff --git a/Cpp/cmake/ExternalAntlr4Cpp.cmake b/Cpp/cmake/ExternalAntlr4Cpp.cmake new file mode 100755 index 0000000..678bf8b --- /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..0c10d9d --- /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..4cfd908 --- /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..04f5252 --- /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/src/ArcscriptErrorExceptions.h b/Cpp/src/ArcscriptErrorExceptions.h new file mode 100755 index 0000000..95e634d --- /dev/null +++ b/Cpp/src/ArcscriptErrorExceptions.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include + +namespace Arcweave { + class RuntimeErrorException : public std::exception { + public: + std::string message; + int line = -1; + int charPositionInLine = -1; + RuntimeErrorException(std::string msg) { + message = msg; + }; + RuntimeErrorException(std::string msg, size_t _line, size_t _charPositionInLine) { + message = msg; + line = _line; + charPositionInLine = _charPositionInLine; + }; + char const* what() const noexcept override { + if (line > -1) { + std::ostringstream oss; + oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; + return oss.str().c_str(); + } + return message.c_str(); + } + }; + + class ParseErrorException : public std::exception { + public: + std::string message; + int line = -1; + int charPositionInLine = -1; + ParseErrorException(std::string msg) { + message = msg; + }; + ParseErrorException(std::string msg, size_t _line, size_t _charPositionInLine) { + message = msg; + line = _line; + charPositionInLine = _charPositionInLine; + }; + char const* what() const noexcept override { + if (line > -1) { + std::ostringstream oss; + oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; + return oss.str().c_str(); + } + return message.c_str(); + } + }; +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptErrorListener.cpp b/Cpp/src/ArcscriptErrorListener.cpp new file mode 100755 index 0000000..6cf0c84 --- /dev/null +++ b/Cpp/src/ArcscriptErrorListener.cpp @@ -0,0 +1,12 @@ +#include "ArcscriptErrorListener.h" +#include "ArcscriptErrorExceptions.h" + +using namespace antlr4; +using namespace Arcweave; + +ErrorListener ErrorListener::INSTANCE; + +void ErrorListener::syntaxError(Recognizer * /*recognizer*/, Token * /*offendingSymbol*/, + size_t line, size_t charPositionInLine, const std::string &msg, std::exception_ptr /*e*/) { + throw ParseErrorException(msg, line, charPositionInLine); +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptErrorListener.h b/Cpp/src/ArcscriptErrorListener.h new file mode 100755 index 0000000..5bf81bb --- /dev/null +++ b/Cpp/src/ArcscriptErrorListener.h @@ -0,0 +1,14 @@ +#pragma once + +#include "BaseErrorListener.h" + +using namespace antlr4; + +namespace Arcweave { + class ErrorListener : public BaseErrorListener { + public: + static ErrorListener INSTANCE; + void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, + size_t charPositionInLine, const std::string &msg, std::exception_ptr e); + }; +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptExpression.cpp b/Cpp/src/ArcscriptExpression.cpp new file mode 100755 index 0000000..4064338 --- /dev/null +++ b/Cpp/src/ArcscriptExpression.cpp @@ -0,0 +1,312 @@ +#include "ArcscriptExpression.h" +#include + +namespace Arcweave { + +std::string Expression::valueToString(std::any value) +{ + if (value.type() == typeid(std::string)) + { + return std::any_cast(value); + } + if (value.type() == typeid(bool)) + { + return std::any_cast(value) ? "true" : "false"; + } + if (value.type() == typeid(int)) + { + return std::to_string(std::any_cast(value)); + } + if (value.type() == typeid(double)) + { + std::stringstream ss; + ss << std::any_cast(value); + return ss.str(); + } + + return NULL; +} + + +Expression::NumberValues Expression::doubleValues(std::any value1, std::any value2) { + int intValue1, intValue2; + double dblValue1, dblValue2; + bool isDouble = false; + if (value1.type() == typeid(int)) { + intValue1 = std::any_cast(value1); + dblValue1 = intValue1; + } else if (value1.type() == typeid(double)){ // type double; + isDouble = true; + dblValue1 = std::any_cast(value1); + } else if (value1.type() == typeid(bool)) { + bool boolVal = std::any_cast(value1); + if (boolVal) { + dblValue1 = 1; + } else { + dblValue1 = 0; + } + } + if (value2.type() == typeid(int)) { + intValue2 = std::any_cast(value2); + dblValue2 = intValue2; + } else if (value2.type() == typeid(double)) { + isDouble = true; + dblValue2 = std::any_cast(value2); + } else if (value2.type() == typeid(bool)) { + bool boolVal = std::any_cast(value1); + if (boolVal) { + dblValue2 = 1; + } else { + dblValue2 = 0; + } + } + NumberValues returnVal; + returnVal.value1 = dblValue1; + returnVal.value2 = dblValue2; + returnVal.hasDoubles = isDouble; + return returnVal; +} + +bool Expression::valueToBool(std::any value) { + if (value.type() == typeid(int)) { + return (std::any_cast(value) > 0); + } + if (value.type() == typeid(double)) { + return (std::any_cast(value) > 0); + } + if (value.type() == typeid(std::string)) { + return (std::any_cast(value) != ""); + } + return (std::any_cast(value)); +} + +Expression Expression::operator+ (const Expression &other) { + if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) + { + return new Expression(valueToString(value) + valueToString(other.value)); + } + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 + values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 + values.value2); + } + return *result; +} + +Expression Expression::operator- (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 - values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 - values.value2); + } + return *result; +} + +Expression Expression::operator* (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 * values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 * values.value2); + } + return *result; +} + +Expression Expression::operator* (const int other) { + NumberValues values = doubleValues(value, other); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 * values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 * values.value2); + } + return *result; +} + +Expression Expression::operator/ (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 / values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 / values.value2); + } + return *result; +} + +Expression Expression::operator+= (const Expression &other) { + if (value.type() == typeid(int) || value.type() == typeid(double)) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 + values.value2; + value = intValue; + } else { + value = values.value1 + values.value2; + } + } + if (value.type() == typeid(std::string)) { + value = std::any_cast(value) + std::any_cast(other.value); + } + return *this; +} + +Expression Expression::operator-= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 - values.value2; + value = intValue; + } else { + value = values.value1 - values.value2; + } + return *this; +} + +Expression Expression::operator*= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 * values.value2; + value = intValue; + } else { + value = values.value1 * values.value2; + } + return *this; +} + +Expression Expression::operator/= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 / values.value2; + value = intValue; + } else { + value = values.value1 / values.value2; + } + return *this; +} + +bool Expression::operator== (const Expression &other) { + if (value.type() == typeid(int) || value.type() == typeid(double)) { + NumberValues values = doubleValues(value, other.value); + return values.value1 == values.value2; + } + if (value.type() == typeid(bool)) { + return std::any_cast(value) == std::any_cast(other.value); + } + return std::any_cast(value) == std::any_cast(other.value); +} + +bool Expression::operator== (double other) { + NumberValues values = doubleValues(value, other); + return values.value1 == values.value2; +} + +bool Expression::operator== (int other) { + NumberValues values = doubleValues(value, other); + return values.value1 == values.value2; +} + +bool Expression::operator== (std::string other) { + return std::any_cast(value) == other; +} + +bool Expression::operator== (bool other) { + return valueToBool(value) == other; +} + +bool Expression::operator!= (const Expression &other) { + if (value.type() == typeid(int) || value.type() == typeid(double)) { + NumberValues values = doubleValues(value, other.value); + return values.value1 != values.value2; + } + if (value.type() == typeid(bool)) { + return std::any_cast(value) != std::any_cast(other.value); + } + return std::any_cast(value) != std::any_cast(other.value); +} + +bool Expression::operator!= (double other) { + NumberValues values = doubleValues(value, other); + return values.value1 != values.value2; +} + +bool Expression::operator!= (int other) { + NumberValues values = doubleValues(value, other); + return values.value1 != values.value2; +} + +bool Expression::operator!= (std::string other) { + return std::any_cast(value) != other; +} + +bool Expression::operator!= (const char other[]) { + return strcmp(std::any_cast(value).c_str(), other) == 0; +} + +bool Expression::operator> (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 > values.value2; +} + +bool Expression::operator> (int other) { + NumberValues values = doubleValues(value, other); + return values.value1 > values.value2; +} + +bool Expression::operator> (double other) { + NumberValues values = doubleValues(value, other); + return values.value1 > values.value2; +} + +bool Expression::operator>= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 >= values.value2; +} + +bool Expression::operator< (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 < values.value2; +} + +bool Expression::operator<= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 <= values.value2; +} + +bool Expression::operator! () { + return !(valueToBool(value)); +} + +bool Expression::operator&& (const Expression &other) { + return valueToBool(value) && valueToBool(other.value); +} + +bool Expression::operator|| (const Expression &other) { + return valueToBool(value) || valueToBool(other.value); +} +} + +std::ostream& operator<< (std::ostream& out, const Arcweave::Expression &e) { + std::any value = e.value; + if (value.type() == typeid(int)) { + return out << std::any_cast(value); + } + if (value.type() == typeid(double)) { + return out << std::any_cast(value); + } + if (value.type() == typeid(std::string)) { + return out << std::any_cast(value); + } + if (value.type() == typeid(bool)) { + return out << std::any_cast(value); + } + return out; +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptExpression.h b/Cpp/src/ArcscriptExpression.h new file mode 100755 index 0000000..0a7c715 --- /dev/null +++ b/Cpp/src/ArcscriptExpression.h @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +namespace Arcweave { + +class Expression { +private: + struct NumberValues { + double value1; + double value2; + bool hasDoubles = false; + }; + + static NumberValues doubleValues(std::any value1, std::any value2) ; + + static std::string valueToString(std::any value); + static bool valueToBool(std::any value); +public: + std::any value; + Expression() { + value = std::any(); + } + Expression(std::string _value) { + value = _value; + } + Expression(bool _value) { + value = _value; + } + Expression(int _value) { + value = _value; + } + Expression(double _value) { + value = _value; + } + Expression(const Expression &e) { + value = e.value; + } + + void setValue(std::any _value) { + value = _value; + } + + const std::type_info& type() { + return value.type(); + } + + Expression operator+ (const Expression &other); + Expression operator- (const Expression &other); + Expression operator* (const Expression &other); + Expression operator* (const int other); + Expression operator/ (const Expression &other); + Expression operator+= (const Expression &other); + Expression operator-= (const Expression &other); + Expression operator*= (const Expression &other); + Expression operator/= (const Expression &other); + + bool operator== (const Expression &other); + bool operator== (double other); + bool operator== (int other); + bool operator== (std::string other); + bool operator== (bool other); + bool operator!= (const Expression &other); + bool operator!= (double other); + bool operator!= (int other); + bool operator!= (std::string other); + bool operator!= (const char other[]); + bool operator> (const Expression &other); + bool operator> (int other); + bool operator> (double other); + bool operator>= (const Expression &other); + bool operator< (const Expression &other); + bool operator<= (const Expression &other); + bool operator! (); + bool operator&& (const Expression &other); + bool operator|| (const Expression &other); +}; + +} +std::ostream& operator<< (std::ostream& out, const Arcweave::Expression &e); \ No newline at end of file diff --git a/Cpp/src/ArcscriptFunctions.cpp b/Cpp/src/ArcscriptFunctions.cpp new file mode 100755 index 0000000..98cbea5 --- /dev/null +++ b/Cpp/src/ArcscriptFunctions.cpp @@ -0,0 +1,206 @@ +#include "ArcscriptFunctions.h" +#include +#include +#include +#include + +namespace Arcweave { + std::map ArcscriptFunctions::functions = { + { "abs", { 1, 1 } }, + { "max", { 2, -1 }}, + { "min", { 2, -1 }}, + { "random", { 0, 0 }}, + { "reset", { 1, -1 }}, + { "resetAll", { 0, -1} }, + { "roll", { 1, 2 } }, + { "round", { 1, 1} }, + { "show", { 1, -1 } }, + { "sqr", { 1, 1 } }, + { "sqrt", { 1, 1 } }, + { "visits", { 0, 1 } }, + }; + + std::any ArcscriptFunctions::Call(std::string functionName, std::vector _args) { + std::vector args; + for (std::any arg : _args) { + if (arg.type() == typeid(Expression)) { + args.push_back(std::any_cast(arg).value); + } + else { + args.push_back(arg); + } + } + std::any result; + if (functionName == "sqrt") { + result = this->Sqrt(args); + } + else if (functionName == "sqr") { + result = this->Sqr(args); + } + else if (functionName == "abs") { + result = this->Abs(args); + } + else if (functionName == "random") { + result = this->Random(args); + } + else if (functionName == "roll") { + result = this->Roll(args); + } + else if (functionName == "show") { + result = this->Show(args); + } + else if (functionName == "reset") { + result = this->Reset(args); + } + else if (functionName == "resetAll") { + result = this->ResetAll(args); + } + else if (functionName == "round") { + result = this->Round(args); + } + else if (functionName == "min") { + result = this->Min(args); + } + else if (functionName == "max") { + result = this->Max(args); + } + else if (functionName == "visits") { + result = this->Visits(args); + } + return result; + } + + std::any ArcscriptFunctions::Sqrt(std::vector args) { + + if (args[0].type() == typeid(int)) { + return sqrt(std::any_cast(args[0])); + } + return sqrt(std::any_cast(args[0])); + } + + std::any ArcscriptFunctions::Sqr(std::vector args) { + if (args[0].type() == typeid(int)) { + int n = std::any_cast(args[0]); + return n * n; + } + double n = std::any_cast(args[0]); + return n * n; + } + + std::any ArcscriptFunctions::Abs(std::vector args) { + if (args[0].type() == typeid(int)) { + return abs(std::any_cast(args[0])); + } + double n = std::any_cast(args[0]); + return abs(n); + } + + std::any ArcscriptFunctions::Random(std::vector args) { + srand(time(NULL)); + return ((double)rand() / (RAND_MAX)); + } + + std::any ArcscriptFunctions::Roll(std::vector args) { + int maxRoll = std::any_cast(args[0]); + int numRolls = 1; + if (args.size() == 2) { + numRolls = std::any_cast(args[1]); + } + int sum = 0; + for (int i = 0; i < numRolls; i++) { + int oneRoll = rand() % maxRoll + 1; + sum += oneRoll; + } + return sum; + } + + std::any ArcscriptFunctions::Show(std::vector args) { + std::string result; + for (int i = 0; i < args.size(); i++) { + std::any arg = args[i]; + if (arg.type() == typeid(int)) { + result += std::to_string(std::any_cast(arg)); + } + else if (arg.type() == typeid(double)) { + result += std::to_string(std::any_cast(arg)); + } + else if (arg.type() == typeid(bool)) { + result += std::to_string(std::any_cast(arg)); + } + else if (arg.type() == typeid(std::string)) { + result += std::any_cast(arg); + } + } + _state->outputs.AddScriptOutput(result); + return std::any(); + } + + std::any ArcscriptFunctions::Round(std::vector args) { + if (args[0].type() == typeid(int)) { + return round(std::any_cast(args[0])); + } + double n = std::any_cast(args[0]); + return round(n); + } + + std::any ArcscriptFunctions::Min(std::vector args) { + std::vector casted; + for (std::any arg : args) { + double val; + if (arg.type() == typeid(int)) { + val = std::any_cast(arg); + } + else { + val = std::any_cast(arg); + } + casted.push_back(val); + } + return *min_element(casted.begin(), casted.end()); + } + + std::any ArcscriptFunctions::Max(std::vector args) { + std::vector casted; + for (std::any arg : args) { + double val; + if (arg.type() == typeid(int)) { + val = std::any_cast(arg); + } + else { + val = std::any_cast(arg); + } + casted.push_back(val); + } + return *max_element(casted.begin(), casted.end()); + } + + std::any ArcscriptFunctions::Reset(std::vector args) { + std::vector variables; + for (std::any arg : args) { + variables.push_back(std::any_cast(arg)); + } + _state->resetVars(variables); + return std::any(); + } + + std::any ArcscriptFunctions::ResetAll(std::vector args) { + std::vector except; + for (std::any arg : args) { + except.push_back(std::any_cast(arg)); + } + _state->resetAllVars(except); + return std::any(); + } + + std::any ArcscriptFunctions::Visits(std::vector args) { + std::string nodeId = _state->currentElement; + if (args.size() > 0) { + Mention mention = std::any_cast(args[0]); + + if (mention.attrs.count("data-id")) { + nodeId = mention.attrs["data-id"]; + } + } + + return _state->visits[nodeId]; + } +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptFunctions.h b/Cpp/src/ArcscriptFunctions.h new file mode 100755 index 0000000..1647409 --- /dev/null +++ b/Cpp/src/ArcscriptFunctions.h @@ -0,0 +1,40 @@ +#pragma once + +#include "ArcscriptHelpers.h" +#include +#include +#include + +namespace Arcweave { +class ArcscriptFunctions { +private: + ArcscriptState *_state; + +public: + struct FunctionInfo { + int minArgs; + int maxArgs; + }; + + static std::map functions; + + ArcscriptFunctions(ArcscriptState* state) : _state(state) { + + } + + std::any Call(std::string functionName, std::vector args); + + std::any Abs(std::vector args); + std::any Max(std::vector args); + std::any Min(std::vector args); + std::any Random(std::vector args); + std::any Reset(std::vector args); + std::any ResetAll(std::vector args); + std::any Roll(std::vector args); + std::any Round(std::vector args); + std::any Show(std::vector args); + std::any Sqr(std::vector args); + std::any Sqrt(std::vector args); + std::any Visits(std::vector args); +}; +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptHelpers.h b/Cpp/src/ArcscriptHelpers.h new file mode 100755 index 0000000..878691d --- /dev/null +++ b/Cpp/src/ArcscriptHelpers.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "ArcscriptExpression.h" +#include "ArcscriptErrorExceptions.h" +#include "ArcscriptOutputs.h" + +namespace Arcweave { + +enum VariableType { + AW_STRING, + AW_INTEGER, + AW_DOUBLE, + AW_BOOLEAN, + AW_ANY +}; + +struct Variable { + std::string id; + std::string name; + VariableType type; + std::any value; +}; + +class ArcscriptState { +public: + std::map variableChanges; + std::map variableValues; + std::map varNameToID; + ArcscriptOutputs outputs; + std::string currentElement; + std::map visits; + + ArcscriptState(std::string elementId, std::map varValues, std::map _visits) { + currentElement = elementId; + variableValues = varValues; + for(const auto var : variableValues) { + varNameToID[var.second.name] = var.first; + } + visits = _visits; + }; + + inline Variable getVar(std::string name) { + std::string varId = varNameToID[name]; + return variableValues[varId]; + } + + inline std::any getVarValue(std::string name) { + std::string varId = varNameToID[name]; + if(variableChanges.count(varId)) { + return variableChanges[varId]; + } + return variableValues[varId].value; + } + inline VariableType getVarType(std::string name) { + return variableValues[varNameToID[name]].type; + } + inline void setVarValue(std::string name, std::any value) { + std::string varId = varNameToID[name]; + variableChanges[varId] = value; + } + inline void setVarValues(std::vector names, std::vector values) { + for (int i = 0; i < names.size(); i++) { + variableChanges[names[i]] = values[i]; + } + } + + inline void resetVars(std::vector vars) { + for (Variable var : vars) { + variableChanges[var.id] = var.value; + } + } + + inline void resetAllVars(std::vector except) { + std::set exceptVariableIds; + for (Variable var : except) { + exceptVariableIds.insert(var.id); + } + std::map::iterator it = variableValues.begin(); + while (it != variableValues.end()) + { + if (exceptVariableIds.find(it->first) == exceptVariableIds.end()) { // not in except vars + variableChanges[it->first] = it->second.value; + } + it++; + } + } +}; + +class Mention { +public: + std::string label; + std::map attrs; + Mention(std::string _label, std::map _attrs) { + label = _label; + attrs = _attrs; + } + Mention(const Mention &m) { + label = m.label; + attrs = m.attrs; + } +}; +} diff --git a/Cpp/src/ArcscriptOutputs.cpp b/Cpp/src/ArcscriptOutputs.cpp new file mode 100755 index 0000000..77ec05a --- /dev/null +++ b/Cpp/src/ArcscriptOutputs.cpp @@ -0,0 +1,79 @@ +#include "ArcscriptOutputs.h" + +void Arcweave::ArcscriptOutputs::AppendParagraph(std::string text) +{ + outputs_.push_back(std::make_unique(text)); +} + +void Arcweave::ArcscriptOutputs::AddParagraph(std::string text) +{ + if (current_node_ == nullptr) + { + current_node_ = this; + } + + if (added_script_) + { + if (!outputs_.empty() && dynamic_cast(outputs_.back().get()) && dynamic_cast(current_node_) == nullptr) + { + AppendParagraph(text); + } else + { + AddScriptOutput(text); + } + added_script_ = false; + return; + } + current_node_->AppendParagraph(text); +} + +void Arcweave::ArcscriptOutputs::AddBlockquote() +{ + if (added_script_ && !outputs_.empty()) + { + IOutputNode* n = outputs_.back().get(); + if (dynamic_cast(n)) + { + current_node_ = dynamic_cast(n); + return; + } + } + Blockquote* b = new Blockquote(); + outputs_.push_back(std::unique_ptr(b)); + current_node_ = b; +} + +void Arcweave::ArcscriptOutputs::AddScript() +{ + added_script_ = true; +} + + +void Arcweave::ArcscriptOutputs::AddScriptOutput(std::string text) +{ + added_script_ = true; + if (outputs_.empty()) + { + outputs_.push_back(std::make_unique(text)); + return; + } + outputs_.back()->MergeScriptOutput(text); +} + +void Arcweave::ArcscriptOutputs::ExitBlockquote() +{ + current_node_ = this; +} + +std::string Arcweave::ArcscriptOutputs::GetText() +{ + std::string output; + for (const auto& value : outputs_) + { + output += value->GetText(); + } + + return output; +} + + diff --git a/Cpp/src/ArcscriptOutputs.h b/Cpp/src/ArcscriptOutputs.h new file mode 100755 index 0000000..e47e69a --- /dev/null +++ b/Cpp/src/ArcscriptOutputs.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include +#include + +namespace Arcweave +{ + class IOutputNode + { + public: + virtual std::string GetText() = 0; + virtual void MergeScriptOutput(std::string text) = 0; + }; + + class IHasParagraphs + { + public: + virtual void AppendParagraph(std::string text) = 0; + }; + + class Paragraph: public IOutputNode + { + private: + std::string text_; + + public: + + Paragraph(std::string text) + { + text_ = text; + } + + inline void MergeScriptOutput(std::string text) override + { + if (text.length() > 0) + { + text_ += ' ' + text; + } + } + + inline std::string GetText() override + { + return "

" + text_ + "

"; + } + }; + + class Blockquote: public IOutputNode, public IHasParagraphs + { + public: + std::vector> paragraphs; + + inline void AppendParagraph(std::string text) override + { + paragraphs.push_back(std::make_unique(text)); + } + + inline void MergeScriptOutput(std::string text) override + { + if (paragraphs.empty()) + { + AppendParagraph(text); + return; + } + paragraphs.back()->MergeScriptOutput(text); + } + + inline std::string GetText() override + { + std::string output; + for (const auto& value : paragraphs) + { + output += value->GetText(); + } + + return "
" + output + "
"; + } + }; + + class ArcscriptOutputs: public IHasParagraphs + { + private: + std::vector> outputs_; + IHasParagraphs* current_node_ = nullptr; + bool added_script_ = false; + public: + void AppendParagraph(std::string text) override; + void AddParagraph(std::string text); + void AddBlockquote(); + void AddScript(); + void AddScriptOutput(std::string text); + void ExitBlockquote(); + std::string GetText(); + }; + +} diff --git a/Cpp/src/ArcscriptParserBase.cpp b/Cpp/src/ArcscriptParserBase.cpp new file mode 100755 index 0000000..c3acc17 --- /dev/null +++ b/Cpp/src/ArcscriptParserBase.cpp @@ -0,0 +1,99 @@ +#include "ArcscriptParser.h" +#include "ArcscriptLexer.h" +#include "ArcscriptParserBase.h" + +using namespace antlr4; + +bool ArcscriptParserBase::assertVariable(antlr4::Token *variable) { + std::string variableName = variable->getText(); + if (_state->varNameToID.count(variableName) > 0) { + return true; + } + throw Arcweave::ParseErrorException("Unknown variable \"" + variableName + "\""); + return false; +} + +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()); +} + +bool ArcscriptParserBase::assertMention(std::any attrCtxList) { + std::map attrs; + ParserRuleContext *ctx = this->getContext(); + std::vector ctxList = ctx->getRuleContexts(); + for (auto attrCtx : ctxList) { + tree::TerminalNode *nameNode = attrCtx->getToken(Arcweave::ArcscriptParser::ATTR_NAME, 0); + std::string attrName = ""; + if (nameNode) { + attrName = nameNode->getText(); + } + tree::TerminalNode *valueNode = attrCtx->getToken(Arcweave::ArcscriptParser::ATTR_VALUE, 0); + std::string attrValue = ""; + if (nameNode) { + attrValue = valueNode->getText(); + } + + if ((attrValue.rfind("\"", 0) == 0 && ends_with(attrValue, "\"")) || + attrValue.rfind("'", 0) == 0 && ends_with(attrValue, "'")) { + + attrValue = attrValue.substr(1, attrValue.size() - 2); + + } + attrs[attrName] = attrValue; + } + std::stringstream classList(attrs["class"]); + std::string className; + bool classFound = false; + while(classList >> className){ + if (className == "mention") { + classFound = true; + break; + } + } + if (!classFound) { + throw Arcweave::ParseErrorException("Invalid mention type"); + return false; + } + if (attrs["data-type"] != "element") { + throw Arcweave::ParseErrorException("Invalid mention type"); + return false; + } + if (_state->visits.count(attrs["data-id"]) == 0) { + throw Arcweave::ParseErrorException("Invalid element mention"); + } + + return true; +} + +bool ArcscriptParserBase::assertFunctionArguments(Token *fname, std::any argumentList) { + int argListLength = 0; + std::string functionName = fname->getText(); + int min = Arcweave::ArcscriptFunctions::functions[functionName].minArgs; + int max = Arcweave::ArcscriptFunctions::functions[functionName].maxArgs; + if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Argument_listContext*)) { + Arcweave::ArcscriptParser::Argument_listContext *argumentListCtx = std::any_cast(argumentList); + if (argumentListCtx != NULL) { + argListLength = argumentListCtx->argument().size(); + } + } + if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Variable_listContext*)) { + Arcweave::ArcscriptParser::Variable_listContext *variableListCtx = std::any_cast(argumentList); + if (variableListCtx != NULL) { + argListLength = variableListCtx->VARIABLE().size(); + } + } + + if ((min != -1 && argListLength < min) || (max != -1 && argListLength > max)) { + throw Arcweave::ParseErrorException("Wrong number of arguments in \""+ functionName + "\"."); + return false; + } + + return true; +} + +void ArcscriptParserBase::setLineStart(antlr4::Token* token) +{ + openTagEndPos = token->getStartIndex() + token->getText().length(); +} diff --git a/Cpp/src/ArcscriptParserBase.h b/Cpp/src/ArcscriptParserBase.h new file mode 100755 index 0000000..7d0d849 --- /dev/null +++ b/Cpp/src/ArcscriptParserBase.h @@ -0,0 +1,19 @@ +#pragma once + +#include "antlr4-runtime.h" +#include "ArcscriptHelpers.h" +#include "ArcscriptFunctions.h" + +class ArcscriptParserBase : public antlr4::Parser { +private: + Arcweave::ArcscriptState* _state; + int openTagEndPos; +public: + int currentLine = 0; + ArcscriptParserBase(antlr4::TokenStream *input) : Parser(input) { } + inline void setArcscriptState(Arcweave::ArcscriptState *state) { _state = state; }; + bool assertVariable(antlr4::Token *variable); + bool assertMention(std::any attrCtxList); + bool assertFunctionArguments(antlr4::Token *fname, std::any argumentList); + void setLineStart(antlr4::Token *token); +}; \ No newline at end of file diff --git a/Cpp/src/ArcscriptTranspiler.cpp b/Cpp/src/ArcscriptTranspiler.cpp new file mode 100755 index 0000000..2abc9bd --- /dev/null +++ b/Cpp/src/ArcscriptTranspiler.cpp @@ -0,0 +1,172 @@ +#include "ArcscriptTranspiler.h" +#include "ArcscriptErrorListener.h" +#include +#include + +#define _CRT_SECURE_NO_WARNINGS + +#ifdef _WIN64 +#define strdup _strdup +#endif + +using namespace Arcweave; +using namespace antlr4; + +TranspilerOutput ArcscriptTranspiler::runScript(std::string code) { + ANTLRInputStream input(code); + ArcscriptLexer lexer(&input); + + TranspilerOutput result; + + ErrorListener lexerErrorListener; + lexer.removeErrorListeners(); + lexer.addErrorListener(&lexerErrorListener); + + CommonTokenStream tokens(&lexer); + + // Run the lexer + tokens.fill(); + + ArcscriptParser parser(&tokens); + parser.setArcscriptState(&state); + ErrorListener parserErrorListener; + parser.removeErrorListeners(); + parser.addErrorListener(&parserErrorListener); + + ArcscriptParser::InputContext *tree; + + // Run the parser + tree = parser.input(); + + ArcscriptVisitor visitor(&state); + + // Run the visitor + std::any res(visitor.visitInput(tree)); + + result.changes = visitor.state->variableChanges; + + result.output = visitor.state->outputs.GetText(); + result.result = res; + + if (tree->script() != NULL) { + result.type = SCRIPT; + } else { + result.type = CONDITION; + } + + return result; +} + +UTranspilerOutput* runScriptExport(const char* code, const char* elId, UVariable* variables, size_t varLength, UVisit* visits, size_t visitsLength) +{ + Arcweave::TranspilerOutput transpilerOutput; + + transpilerOutput.type = InputType::CONDITION; + + std::string sCode(code); + std::string sElId(elId); + + std::map initVars; + for (size_t i = 0; i < varLength; i++) { + Variable var; + var.id = std::string(variables[i].id); + var.name = std::string(variables[i].name); + var.type = variables[i].type; + + if (var.type == VariableType::AW_STRING) { + var.value = std::string(variables[i].string_val); + } + else if (var.type == VariableType::AW_INTEGER) { + var.value = variables[i].int_val; + } + else if (var.type == VariableType::AW_DOUBLE) { + var.value = variables[i].double_val; + } + else if (var.type == VariableType::AW_BOOLEAN) { + var.value = variables[i].bool_val; + } + initVars[variables[i].id] = var; + } + + std::map initVisits; + for (size_t i = 0; i < visitsLength; i++) { + initVisits[std::string(visits[i].elId)] = visits[i].visits; + } + + Arcweave::ArcscriptTranspiler transpiler(sElId, initVars, initVisits); + transpilerOutput = transpiler.runScript(sCode); + + UTranspilerOutput* uTranspilerOutput = new UTranspilerOutput(); + uTranspilerOutput->output = strdup(transpilerOutput.output.c_str()); + uTranspilerOutput->type = transpilerOutput.type; + + if (transpilerOutput.type == InputType::CONDITION) { + uTranspilerOutput->conditionResult = std::any_cast(transpilerOutput.result); + } + + size_t changesLen = transpilerOutput.changes.size(); + + UVariableChange* variableChanges = new UVariableChange[changesLen]; + size_t i = 0; + for (auto change : transpilerOutput.changes) { + UVariableChange uChange; + uChange.varId = strdup(change.first.c_str()); + + if (change.second.type() == typeid(std::string)) { + uChange.type = VariableType::AW_STRING; + std::string string_result = std::any_cast(change.second); + uChange.string_result = strdup(string_result.c_str()); + } + else if (change.second.type() == typeid(int)) { + uChange.type = VariableType::AW_INTEGER; + uChange.int_result = std::any_cast(change.second); + } + else if (change.second.type() == typeid(double)) { + uChange.type = VariableType::AW_DOUBLE; + uChange.double_result = std::any_cast(change.second); + } + else if (change.second.type() == typeid(bool)) { + uChange.type = VariableType::AW_BOOLEAN; + uChange.bool_result = std::any_cast(change.second); + } + variableChanges[i] = uChange; + i++; + } + uTranspilerOutput->changes = variableChanges; + uTranspilerOutput->changesLen = changesLen; + + return uTranspilerOutput; + //std::cout << code << std::endl; + //std::cout << elId << std::endl; + //std::cout << _visits["test"] << std::endl; + /*try { + Arcweave::ArcscriptTranspiler transpiler(elId, initVars, _visits); + + try { + transpilerOutput = transpiler.runScript(code); + } + catch (std::exception& e) { + std::cerr << "Arcscript Transpiler failed during runScript: " << std::endl; + std::cerr << e.what() << std::endl; + return false; + } + } + catch (std::exception &e) { + std::cerr << "Arcscript Transpiler failed during init: " << std::endl; + std::cerr << e.what() << std::endl; + return false; + } + return true;*/ +} + +void deallocateOutput(UTranspilerOutput* output) { + for (size_t i = 0; i < output->changesLen; i++) { + free(output->changes[i].varId); + if (output->changes[i].type == VariableType::AW_STRING) { + free(output->changes[i].string_result); + } + } + delete[] output->changes; + free(output->output); + delete output; +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptTranspiler.h b/Cpp/src/ArcscriptTranspiler.h new file mode 100755 index 0000000..913a233 --- /dev/null +++ b/Cpp/src/ArcscriptTranspiler.h @@ -0,0 +1,164 @@ +#pragma once +#include "antlr4-runtime.h" +#include "ArcscriptLexer.h" +#include "ArcscriptParser.h" +#include "ArcscriptVisitor.h" + +#if defined _WIN64 + #ifdef WIN_EXPORT + #ifdef __GNUC__ + #define EXPORTED __attribute__ ((dllexport)) + #else + #define EXPORTED __declspec(dllexport) + #endif + #else + #ifdef __GNUC__ + #define EXPORTED __attribute__ ((dllimport)) + #else + #define EXPORTED __declspec(dllimport) + #endif + #endif + #define NOT_EXPORTED +#else + #if __GNUC__ >= 4 + #define EXPORTED __attribute__ ((visibility("default"))) + #define NOT_EXPORTED __attribute__ ((visibility("hidden"))) + #else + #define EXPORTED + #define NOT_EXPORTED + #endif +#endif + +// #ifdef ARCSCRIPTTRANSPILER_EXPORTS +// #define ARCSCRIPTTRANSPILER_API __declspec(dllexport) +// #else +// #define ARCSCRIPTTRANSPILER_API __declspec(dllimport) +// #endif +// #else +// #define ARCSCRIPTTRANSPILER_API +// #endif + +namespace Arcweave +{ + /** + * @enum InputType + * The arscript code types + */ + enum InputType { + /// @brief A condition (results to bool) code type + CONDITION, + /// @brief A script code type + SCRIPT + }; + + /** + * @struct TranspilerOutput + * @brief The structure contains info that the ArcscriptTranspiler returns + * @var TranspilerOutput::output + * Member 'output' contains the text output when a codeblock is run + * @var TranspilerOutput::changes + * Member 'changes' contains the variables that are going to be changed from the codeblock + * @var TranspilerOutput::result + * Member 'result' contains the result of the ArcscriptTranspiler code. Useful in condition blocks + * @var TranspilerOutput::type + * Member 'type' contains the type of the code block i.e. CONDITION or SCRIPT + */ + struct TranspilerOutput { + std::string output; + std::map changes; + std::any result; + InputType type; + }; + + + // The following types starting with a U* are the types that the exported DLL function accepts and returns + extern "C" struct UVariableChange { + char* varId; + VariableType type; + int int_result; + double double_result; + char* string_result; + bool bool_result; + UVariableChange() { + varId = nullptr; + type = VariableType::AW_ANY; + int_result = 0; + double_result = 0.0; + string_result = nullptr; + bool_result = false; + } + }; + + extern "C" struct UTranspilerOutput { + char* output; + InputType type; + UVariableChange* changes; + size_t changesLen = 0; + bool conditionResult = false; + + UTranspilerOutput() { + output = nullptr; + type = InputType::SCRIPT; + changes = nullptr; + changesLen = 0; + conditionResult = false; + } + }; + + + struct UVariable { + const char* id; + const char* name; + VariableType type; + int int_val; + double double_val; + const char* string_val; + bool bool_val; + + UVariable() { + id = nullptr; + name = nullptr; + type = VariableType::AW_ANY; + int_val = 0; + double_val = 0; + string_val = nullptr; + bool_val = false; + } + }; + + struct UVisit { + const char* elId; + int visits; + + UVisit() { + elId = nullptr; + visits = 0; + } + }; + + /** + * Implementation of the Arcscript Transpiler in C++. Uses the ANTLR4 runtime library + * to run the code and it needs the initial variables and the current element ID it is + * transpiling. + * + * + */ + class ArcscriptTranspiler { + public: + + ArcscriptState state; + + ArcscriptTranspiler(std::string elId, std::map initVars, std::map _visits) : state(elId, initVars, _visits) { }; + + /** + * Runs the arcscript code and returns it's results. + * @param code The code block that we need to parse + * @return The result of the ran script + */ + TranspilerOutput runScript(std::string code); + + //ARCSCRIPTTRANSPILER_API UTranspilerOutput URunScript(char* code); + }; +}; +EXPORTED UTranspilerOutput* runScriptExport(const char* code, const char* elId, UVariable* variables, size_t varLength, UVisit* visits, size_t visitsLength); +EXPORTED void deallocateOutput(UTranspilerOutput* output); \ No newline at end of file diff --git a/Cpp/src/ArcscriptVisitor.cpp b/Cpp/src/ArcscriptVisitor.cpp new file mode 100755 index 0000000..986efac --- /dev/null +++ b/Cpp/src/ArcscriptVisitor.cpp @@ -0,0 +1,461 @@ +#include "ArcscriptVisitor.h" +#include "ArcscriptParser.h" + +using namespace Arcweave; + +std::any ArcscriptVisitor::visitInput(ArcscriptParser::InputContext * ctx) +{ + if (ctx->script() != NULL) { + return visitScript(ctx->script()); + } + // Condition + Expression comp_cond = std::any_cast(visitCompound_condition_or(ctx->compound_condition_or())); + return comp_cond.value; +} + +std::any ArcscriptVisitor::visitScript_section(ArcscriptParser::Script_sectionContext *ctx) { + if (ctx == NULL) { + return std::any(); + } + + if (const auto blockquote_contexts = ctx->blockquote(); !blockquote_contexts.empty()) + { + std::vector result; + for (const auto blockquote_context : blockquote_contexts) + { + result.push_back(visitBlockquote(blockquote_context)); + } + return result; + } + + if (const auto paragraph_contexts = ctx->paragraph(); !paragraph_contexts.empty()) + { + std::vector result; + for (const auto paragraph_context : paragraph_contexts) + { + result.push_back(visitParagraph(paragraph_context)); + } + return result; + } + + return visitChildren(ctx); +} + +std::any ArcscriptVisitor::visitBlockquote(ArcscriptParser::BlockquoteContext* context) +{ + state->outputs.AddBlockquote(); + visitChildren(context); + state->outputs.ExitBlockquote(); + return context->getText(); +} + +std::any ArcscriptVisitor::visitParagraph(ArcscriptParser::ParagraphContext* context) +{ + auto paragraph_end = context->PARAGRAPHEND()->getText(); + auto paragraph_content = paragraph_end.substr(0, paragraph_end.size() - 4); // size of "

" + 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 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 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 } }; +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptVisitor.h b/Cpp/src/ArcscriptVisitor.h new file mode 100755 index 0000000..c1e2500 --- /dev/null +++ b/Cpp/src/ArcscriptVisitor.h @@ -0,0 +1,52 @@ +#pragma once + +#include "antlr4-runtime.h" +#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; +}; \ No newline at end of file From ab8c007e37538944cdc056fe187c9998c2d0d400 Mon Sep 17 00:00:00 2001 From: Emmanouil Dermitzakis Date: Wed, 25 Jun 2025 14:07:20 +0300 Subject: [PATCH 02/31] fix: cpp transpiler library --- .gitignore | 2 +- Cpp/.gitignore | 7 +- Cpp/CMakeLists.txt | 164 ++--- Cpp/cmake/ExternalAntlr4Cpp.cmake | 352 +++++------ Cpp/cmake/FindANTLR.cmake | 246 ++++---- Cpp/cmake/antlr4-generator.cmake.in | 360 +++++------ Cpp/cmake/antlr4-runtime.cmake.in | 24 +- Cpp/demo/ArcscriptTest.cpp | 137 +++++ Cpp/demo/tests/stringConcat.json | 132 ++++ Cpp/src/ArcscriptErrorExceptions.h | 108 ++-- Cpp/src/ArcscriptErrorListener.cpp | 24 +- Cpp/src/ArcscriptErrorListener.h | 28 +- Cpp/src/ArcscriptExpression.cpp | 624 +++++++++---------- Cpp/src/ArcscriptExpression.h | 162 ++--- Cpp/src/ArcscriptFunctions.cpp | 412 ++++++------- Cpp/src/ArcscriptFunctions.h | 80 +-- Cpp/src/ArcscriptHelpers.h | 218 +++---- Cpp/src/ArcscriptOutputs.cpp | 158 ++--- Cpp/src/ArcscriptOutputs.h | 192 +++--- Cpp/src/ArcscriptParserBase.cpp | 198 +++--- Cpp/src/ArcscriptParserBase.h | 38 +- Cpp/src/ArcscriptTranspiler.cpp | 344 +++++------ Cpp/src/ArcscriptTranspiler.h | 328 +++++----- Cpp/src/ArcscriptVisitor.cpp | 922 ++++++++++++++-------------- Cpp/src/ArcscriptVisitor.h | 104 ++-- 25 files changed, 2831 insertions(+), 2533 deletions(-) create mode 100644 Cpp/demo/ArcscriptTest.cpp create mode 100644 Cpp/demo/tests/stringConcat.json 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 817844d..d1860aa 100644 --- a/Cpp/.gitignore +++ b/Cpp/.gitignore @@ -1,2 +1,7 @@ src/Generated -build \ No newline at end of file +.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 index 25096c9..ac74c43 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -1,70 +1,94 @@ -# minimum required CMAKE version -CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR) - -set(PROJECT_VERSION "0.1.0") -project(ArcscriptTranspiler VERSION ${PROJECT_VERSION}) - -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -message(CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) -# 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 4.13.1) -# 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}) - -## set variable pointing to the antlr tool that supports C++ -## this is not required if the jar file can be found under PATH environment -#set(ANTLR_EXECUTABLE /home/user/antlr-4.13.2-complete.jar) -## add macros to generate ANTLR Cpp code from grammar -#find_package(ANTLR REQUIRED) -# -## Call macro to add lexer and grammar to your build dependencies. -#antlr_target(SampleGrammarLexer TLexer.g4 LEXER -# PACKAGE antlrcpptest) -#antlr_target(SampleGrammarParser TParser.g4 PARSER -# PACKAGE antlrcpptest -# DEPENDS_ANTLR SampleGrammarLexer -# COMPILE_FLAGS -lib ${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) - -# include generated files in project environment -#include_directories(${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) -#include_directories(${ANTLR_SampleGrammarParser_OUTPUT_DIR}) - -include_directories(src/Generated/ArcscriptLexer) -include_directories(src/Generated/ArcscriptParser) -include_directories(src) -# add generated grammar to demo binary target -#add_executable(demo main.cpp -# src/Generated/ArcscriptLexer -# src/Generated/ArcscriptParser) - -add_library(ArcscriptTranspiler SHARED) - -target_sources(ArcscriptTranspiler PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.cpp) - -set_target_properties(ArcscriptTranspiler PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION}) - -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 antlr4_shared) \ No newline at end of file +# minimum required CMAKE version +CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR) + +set(PROJECT_VERSION "0.1.0") +project(ArcscriptTranspiler VERSION ${PROJECT_VERSION}) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +message(CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) +# 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 4.13.1) +# 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}) + +## set variable pointing to the antlr tool that supports C++ +## this is not required if the jar file can be found under PATH environment +#set(ANTLR_EXECUTABLE /home/user/antlr-4.13.2-complete.jar) +## add macros to generate ANTLR Cpp code from grammar +#find_package(ANTLR REQUIRED) +# +## Call macro to add lexer and grammar to your build dependencies. +#antlr_target(SampleGrammarLexer TLexer.g4 LEXER +# PACKAGE antlrcpptest) +#antlr_target(SampleGrammarParser TParser.g4 PARSER +# PACKAGE antlrcpptest +# DEPENDS_ANTLR SampleGrammarLexer +# COMPILE_FLAGS -lib ${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) + +# include generated files in project environment +#include_directories(${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) +#include_directories(${ANTLR_SampleGrammarParser_OUTPUT_DIR}) + +include_directories(src/Generated/ArcscriptLexer) +include_directories(src/Generated/ArcscriptParser) +include_directories(src) +# add generated grammar to demo binary target +#add_executable(demo main.cpp +# src/Generated/ArcscriptLexer +# src/Generated/ArcscriptParser) + +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_target_properties(ArcscriptTranspiler PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION}) + +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) + +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) diff --git a/Cpp/cmake/ExternalAntlr4Cpp.cmake b/Cpp/cmake/ExternalAntlr4Cpp.cmake index 678bf8b..620b2c8 100755 --- a/Cpp/cmake/ExternalAntlr4Cpp.cmake +++ b/Cpp/cmake/ExternalAntlr4Cpp.cmake @@ -1,177 +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}) +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 index 0c10d9d..77f4f7b 100755 --- a/Cpp/cmake/FindANTLR.cmake +++ b/Cpp/cmake/FindANTLR.cmake @@ -1,124 +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 +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 index 4cfd908..9672d58 100755 --- a/Cpp/cmake/antlr4-generator.cmake.in +++ b/Cpp/cmake/antlr4-generator.cmake.in @@ -1,181 +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} ) - +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 index 04f5252..c120494 100755 --- a/Cpp/cmake/antlr4-runtime.cmake.in +++ b/Cpp/cmake/antlr4-runtime.cmake.in @@ -1,13 +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) - +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..f4fe411 --- /dev/null +++ b/Cpp/demo/ArcscriptTest.cpp @@ -0,0 +1,137 @@ +// ArcscriptTranspilerTest.cpp : This file contains the 'main' function. Program execution begins and ends there. +// + +#include +#include +#include +#include +#include +#include +#include +#include "ArcscriptTranspiler.h" + +using json = nlohmann::json; + +using namespace Arcweave; + +UVariable* getInitialVars(json initialVarsJson) { + UVariable* initVars = new UVariable[initialVarsJson.size()]; + int i = 0; + for (json::iterator it = initialVarsJson.begin(); it != initialVarsJson.end(); ++it) { + std::string id = it.value()["id"].template get(); + std::string name = it.value()["name"].template get(); + std::string type = it.value()["type"].template get(); + + initVars[i].id = _strdup(id.c_str()); + initVars[i].name = _strdup(name.c_str()); + initVars[i].type = VariableType::AW_ANY; + if (type == "string") { + initVars[i].type = VariableType::AW_STRING; + } + else if (type == "integer") { + initVars[i].type = VariableType::AW_INTEGER; + } + else if (type == "double") { + initVars[i].type = VariableType::AW_DOUBLE; + } + else if (type == "boolean") { + initVars[i].type = VariableType::AW_BOOLEAN; + } + + if (initVars[i].type == VariableType::AW_STRING) { + initVars[i].string_val = _strdup(it.value()["value"].template get().c_str()); + } + else if (initVars[i].type == VariableType::AW_INTEGER) { + initVars[i].int_val = it.value()["value"].template get(); + } + else if (initVars[i].type == VariableType::AW_DOUBLE) { + initVars[i].double_val= it.value()["value"].template get(); + } + else if (initVars[i].type == VariableType::AW_BOOLEAN) { + initVars[i].bool_val = it.value()["value"].template get(); + } + i += 1; + } + + return initVars; +} + +UVisit* getVisits(json initVisits) { + if (initVisits.size() == 0) return nullptr; + UVisit* visits = new UVisit[initVisits.size()]; + int i = 0; + for (json::iterator it = initVisits.begin(); it != initVisits.end(); ++it) { + visits[i].elId = _strdup(it.key().c_str()); + visits[i].visits = it.value().template get(); + i += 1; + } + return visits; +} + +int testFile(std::filesystem::path path) { + std::ifstream f(path); + json data = json::parse(f); + // ssstd::cout << data << std::endl; + json initVarsJson = data["initialVars"]; + UVariable* initVars = getInitialVars(initVarsJson); + size_t initVarLen = initVarsJson.size(); + for (json::iterator it = data["cases"].begin(); it != data["cases"].end(); ++it) { + const char* code = _strdup((*it)["code"].template get().c_str()); + UVisit* visits = nullptr; + size_t visitsLen = 0; + const char* currentElement = nullptr; + if ((*it).contains("elementId")) { + currentElement = _strdup((*it)["elementId"].template get().c_str()); + } + else { + currentElement = _strdup("TestElement"); + } + if ((*it).contains("visits")) { + visits = getVisits((*it)["visits"]); + visitsLen = (*it)["visits"].size(); + } + bool hasError = false; + if ((*it).contains("error")) { + hasError = true; + } + + UTranspilerOutput* result = runScriptExport(code, currentElement, initVars, initVarLen, visits, visitsLen); + if ((*it).contains("output")) + { + std::string output = (*it)["output"].template get(); + if (output.compare(result->output) != 0) + { + std::cout << "DIFFERENT" << std::endl; + std::cout << "EXPECTED: \"" << output << "\"" << std::endl << "ACTUAL: \"" << result->output << "\"" << std::endl; + } + } + + deallocateOutput(result); + + /*for (int i = 0; i < visitsLen; i++) { + free((char*)visits[i].elId); + } + delete visits; + free((char*)currentElement); + free((char*)code);*/ + } + /*for (int j = 0; j < initVarLen; j++) { + free((char*)initVars[j].id); + free((char*)initVars[j].name); + if (initVars[j].type == VariableType::AW_STRING) { + free((char*)initVars[j].string_val); + } + } + delete initVars;*/ + return 0; +} + + + +int main() +{ + const std::filesystem::path path{ "./stringConcat.json" }; + testFile(path); + + system("pause"); +} \ No newline at end of file diff --git a/Cpp/demo/tests/stringConcat.json b/Cpp/demo/tests/stringConcat.json new file mode 100644 index 0000000..eea6992 --- /dev/null +++ b/Cpp/demo/tests/stringConcat.json @@ -0,0 +1,132 @@ +{ + "initialVars": { + "var1": { + "id": "var1", + "name": "x", + "type": "integer", + "value": 14 + }, + "var2": { + "id": "var2", + "name": "y", + "type": "integer", + "value": 15 + }, + "var3": { + "id": "var3", + "name": "z", + "type": "integer", + "value": 0 + }, + "var4": { + "id": "var4", + "name": "w", + "type": "string", + "value": "Dummy text" + }, + "var5": { + "id": "var5", + "name": "$c5", + "type": "integer", + "value": 0 + }, + "var6": { + "id": "var6", + "name": "_a", + "type": "boolean", + "value": false + }, + "var7": { + "id": "var7", + "name": "xy", + "type": "integer", + "value": -1 + }, + "var8": { + "id": "var8", + "name": "man", + "type": "string", + "value": "Different Text" + } + }, + "cases": [ + { + "code": "
w = \"test\"
w = w + \"ing\"
", + "changes": { + "var4": "testing" + } + }, + { + "code": "
w = \"test\" + \"ing\"
", + "changes": { + "var4": "testing" + } + }, + { + "code": "
w = 0.42 + \"ing\"
", + "changes": { + "var4": "0.42ing" + } + }, + { + "code": "
w = 0.42 + \"\"
", + "changes": { + "var4": "0.42" + } + }, + { + "code": "
w = \"test\" + 44
", + "changes": { + "var4": "test44" + } + }, + { + "code": "
w = \"test\" + false
", + "changes": { + "var4": "testfalse" + } + }, + { + "code": "
w = \"test\" + true + true
", + "changes": { + "var4": "testtruetrue" + } + }, + { + "code": "
w = true + true + \"test\"
", + "changes": { + "var4": "2test" + } + }, + { + "code": "
w += \" test\"
", + "changes": { + "var4": "Dummy text test" + } + }, + { + "code": "
x += \"test\"
", + "changes": { + "var1": "14test" + } + }, + { + "code": "
w += 42
", + "changes": { + "var4": "Dummy text42" + } + }, + { + "code": "
w += _a
", + "changes": { + "var4": "Dummy textfalse" + } + }, + { + "code": "
w += man
", + "changes": { + "var4": "Dummy textDifferent Text" + } + } + ] +} \ No newline at end of file diff --git a/Cpp/src/ArcscriptErrorExceptions.h b/Cpp/src/ArcscriptErrorExceptions.h index 95e634d..d73e98f 100755 --- a/Cpp/src/ArcscriptErrorExceptions.h +++ b/Cpp/src/ArcscriptErrorExceptions.h @@ -1,54 +1,54 @@ -#pragma once - -#include -#include -#include -#include - -namespace Arcweave { - class RuntimeErrorException : public std::exception { - public: - std::string message; - int line = -1; - int charPositionInLine = -1; - RuntimeErrorException(std::string msg) { - message = msg; - }; - RuntimeErrorException(std::string msg, size_t _line, size_t _charPositionInLine) { - message = msg; - line = _line; - charPositionInLine = _charPositionInLine; - }; - char const* what() const noexcept override { - if (line > -1) { - std::ostringstream oss; - oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; - return oss.str().c_str(); - } - return message.c_str(); - } - }; - - class ParseErrorException : public std::exception { - public: - std::string message; - int line = -1; - int charPositionInLine = -1; - ParseErrorException(std::string msg) { - message = msg; - }; - ParseErrorException(std::string msg, size_t _line, size_t _charPositionInLine) { - message = msg; - line = _line; - charPositionInLine = _charPositionInLine; - }; - char const* what() const noexcept override { - if (line > -1) { - std::ostringstream oss; - oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; - return oss.str().c_str(); - } - return message.c_str(); - } - }; -} \ No newline at end of file +#pragma once + +#include +#include +#include +#include + +namespace Arcweave { + class RuntimeErrorException : public std::exception { + public: + std::string message; + int line = -1; + int charPositionInLine = -1; + RuntimeErrorException(std::string msg) { + message = msg; + }; + RuntimeErrorException(std::string msg, size_t _line, size_t _charPositionInLine) { + message = msg; + line = _line; + charPositionInLine = _charPositionInLine; + }; + char const* what() const noexcept override { + if (line > -1) { + std::ostringstream oss; + oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; + return oss.str().c_str(); + } + return message.c_str(); + } + }; + + class ParseErrorException : public std::exception { + public: + std::string message; + int line = -1; + int charPositionInLine = -1; + ParseErrorException(std::string msg) { + message = msg; + }; + ParseErrorException(std::string msg, size_t _line, size_t _charPositionInLine) { + message = msg; + line = _line; + charPositionInLine = _charPositionInLine; + }; + char const* what() const noexcept override { + if (line > -1) { + std::ostringstream oss; + oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; + return oss.str().c_str(); + } + return message.c_str(); + } + }; +} diff --git a/Cpp/src/ArcscriptErrorListener.cpp b/Cpp/src/ArcscriptErrorListener.cpp index 6cf0c84..d6bf9fc 100755 --- a/Cpp/src/ArcscriptErrorListener.cpp +++ b/Cpp/src/ArcscriptErrorListener.cpp @@ -1,12 +1,12 @@ -#include "ArcscriptErrorListener.h" -#include "ArcscriptErrorExceptions.h" - -using namespace antlr4; -using namespace Arcweave; - -ErrorListener ErrorListener::INSTANCE; - -void ErrorListener::syntaxError(Recognizer * /*recognizer*/, Token * /*offendingSymbol*/, - size_t line, size_t charPositionInLine, const std::string &msg, std::exception_ptr /*e*/) { - throw ParseErrorException(msg, line, charPositionInLine); -} \ No newline at end of file +#include "ArcscriptErrorListener.h" +#include "ArcscriptErrorExceptions.h" + +using namespace antlr4; +using namespace Arcweave; + +ErrorListener ErrorListener::INSTANCE; + +void ErrorListener::syntaxError(Recognizer * /*recognizer*/, Token * /*offendingSymbol*/, + size_t line, size_t charPositionInLine, const std::string &msg, std::exception_ptr /*e*/) { + throw ParseErrorException(msg, line, charPositionInLine); +} diff --git a/Cpp/src/ArcscriptErrorListener.h b/Cpp/src/ArcscriptErrorListener.h index 5bf81bb..894a736 100755 --- a/Cpp/src/ArcscriptErrorListener.h +++ b/Cpp/src/ArcscriptErrorListener.h @@ -1,14 +1,14 @@ -#pragma once - -#include "BaseErrorListener.h" - -using namespace antlr4; - -namespace Arcweave { - class ErrorListener : public BaseErrorListener { - public: - static ErrorListener INSTANCE; - void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, - size_t charPositionInLine, const std::string &msg, std::exception_ptr e); - }; -} \ No newline at end of file +#pragma once + +#include "BaseErrorListener.h" + +using namespace antlr4; + +namespace Arcweave { + class ErrorListener : public BaseErrorListener { + public: + static ErrorListener INSTANCE; + void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, + size_t charPositionInLine, const std::string &msg, std::exception_ptr e); + }; +} diff --git a/Cpp/src/ArcscriptExpression.cpp b/Cpp/src/ArcscriptExpression.cpp index 4064338..9af610c 100755 --- a/Cpp/src/ArcscriptExpression.cpp +++ b/Cpp/src/ArcscriptExpression.cpp @@ -1,312 +1,312 @@ -#include "ArcscriptExpression.h" -#include - -namespace Arcweave { - -std::string Expression::valueToString(std::any value) -{ - if (value.type() == typeid(std::string)) - { - return std::any_cast(value); - } - if (value.type() == typeid(bool)) - { - return std::any_cast(value) ? "true" : "false"; - } - if (value.type() == typeid(int)) - { - return std::to_string(std::any_cast(value)); - } - if (value.type() == typeid(double)) - { - std::stringstream ss; - ss << std::any_cast(value); - return ss.str(); - } - - return NULL; -} - - -Expression::NumberValues Expression::doubleValues(std::any value1, std::any value2) { - int intValue1, intValue2; - double dblValue1, dblValue2; - bool isDouble = false; - if (value1.type() == typeid(int)) { - intValue1 = std::any_cast(value1); - dblValue1 = intValue1; - } else if (value1.type() == typeid(double)){ // type double; - isDouble = true; - dblValue1 = std::any_cast(value1); - } else if (value1.type() == typeid(bool)) { - bool boolVal = std::any_cast(value1); - if (boolVal) { - dblValue1 = 1; - } else { - dblValue1 = 0; - } - } - if (value2.type() == typeid(int)) { - intValue2 = std::any_cast(value2); - dblValue2 = intValue2; - } else if (value2.type() == typeid(double)) { - isDouble = true; - dblValue2 = std::any_cast(value2); - } else if (value2.type() == typeid(bool)) { - bool boolVal = std::any_cast(value1); - if (boolVal) { - dblValue2 = 1; - } else { - dblValue2 = 0; - } - } - NumberValues returnVal; - returnVal.value1 = dblValue1; - returnVal.value2 = dblValue2; - returnVal.hasDoubles = isDouble; - return returnVal; -} - -bool Expression::valueToBool(std::any value) { - if (value.type() == typeid(int)) { - return (std::any_cast(value) > 0); - } - if (value.type() == typeid(double)) { - return (std::any_cast(value) > 0); - } - if (value.type() == typeid(std::string)) { - return (std::any_cast(value) != ""); - } - return (std::any_cast(value)); -} - -Expression Expression::operator+ (const Expression &other) { - if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) - { - return new Expression(valueToString(value) + valueToString(other.value)); - } - NumberValues values = doubleValues(value, other.value); - Expression* result; - if (!values.hasDoubles) { - int intValue = values.value1 + values.value2; - result = new Expression(intValue); - } else { - result = new Expression(values.value1 + values.value2); - } - return *result; -} - -Expression Expression::operator- (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - Expression* result; - if (!values.hasDoubles) { - int intValue = values.value1 - values.value2; - result = new Expression(intValue); - } else { - result = new Expression(values.value1 - values.value2); - } - return *result; -} - -Expression Expression::operator* (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - Expression* result; - if (!values.hasDoubles) { - int intValue = values.value1 * values.value2; - result = new Expression(intValue); - } else { - result = new Expression(values.value1 * values.value2); - } - return *result; -} - -Expression Expression::operator* (const int other) { - NumberValues values = doubleValues(value, other); - Expression* result; - if (!values.hasDoubles) { - int intValue = values.value1 * values.value2; - result = new Expression(intValue); - } else { - result = new Expression(values.value1 * values.value2); - } - return *result; -} - -Expression Expression::operator/ (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - Expression* result; - if (!values.hasDoubles) { - int intValue = values.value1 / values.value2; - result = new Expression(intValue); - } else { - result = new Expression(values.value1 / values.value2); - } - return *result; -} - -Expression Expression::operator+= (const Expression &other) { - if (value.type() == typeid(int) || value.type() == typeid(double)) { - NumberValues values = doubleValues(value, other.value); - if (!values.hasDoubles) { - int intValue = values.value1 + values.value2; - value = intValue; - } else { - value = values.value1 + values.value2; - } - } - if (value.type() == typeid(std::string)) { - value = std::any_cast(value) + std::any_cast(other.value); - } - return *this; -} - -Expression Expression::operator-= (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - if (!values.hasDoubles) { - int intValue = values.value1 - values.value2; - value = intValue; - } else { - value = values.value1 - values.value2; - } - return *this; -} - -Expression Expression::operator*= (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - if (!values.hasDoubles) { - int intValue = values.value1 * values.value2; - value = intValue; - } else { - value = values.value1 * values.value2; - } - return *this; -} - -Expression Expression::operator/= (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - if (!values.hasDoubles) { - int intValue = values.value1 / values.value2; - value = intValue; - } else { - value = values.value1 / values.value2; - } - return *this; -} - -bool Expression::operator== (const Expression &other) { - if (value.type() == typeid(int) || value.type() == typeid(double)) { - NumberValues values = doubleValues(value, other.value); - return values.value1 == values.value2; - } - if (value.type() == typeid(bool)) { - return std::any_cast(value) == std::any_cast(other.value); - } - return std::any_cast(value) == std::any_cast(other.value); -} - -bool Expression::operator== (double other) { - NumberValues values = doubleValues(value, other); - return values.value1 == values.value2; -} - -bool Expression::operator== (int other) { - NumberValues values = doubleValues(value, other); - return values.value1 == values.value2; -} - -bool Expression::operator== (std::string other) { - return std::any_cast(value) == other; -} - -bool Expression::operator== (bool other) { - return valueToBool(value) == other; -} - -bool Expression::operator!= (const Expression &other) { - if (value.type() == typeid(int) || value.type() == typeid(double)) { - NumberValues values = doubleValues(value, other.value); - return values.value1 != values.value2; - } - if (value.type() == typeid(bool)) { - return std::any_cast(value) != std::any_cast(other.value); - } - return std::any_cast(value) != std::any_cast(other.value); -} - -bool Expression::operator!= (double other) { - NumberValues values = doubleValues(value, other); - return values.value1 != values.value2; -} - -bool Expression::operator!= (int other) { - NumberValues values = doubleValues(value, other); - return values.value1 != values.value2; -} - -bool Expression::operator!= (std::string other) { - return std::any_cast(value) != other; -} - -bool Expression::operator!= (const char other[]) { - return strcmp(std::any_cast(value).c_str(), other) == 0; -} - -bool Expression::operator> (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - return values.value1 > values.value2; -} - -bool Expression::operator> (int other) { - NumberValues values = doubleValues(value, other); - return values.value1 > values.value2; -} - -bool Expression::operator> (double other) { - NumberValues values = doubleValues(value, other); - return values.value1 > values.value2; -} - -bool Expression::operator>= (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - return values.value1 >= values.value2; -} - -bool Expression::operator< (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - return values.value1 < values.value2; -} - -bool Expression::operator<= (const Expression &other) { - NumberValues values = doubleValues(value, other.value); - return values.value1 <= values.value2; -} - -bool Expression::operator! () { - return !(valueToBool(value)); -} - -bool Expression::operator&& (const Expression &other) { - return valueToBool(value) && valueToBool(other.value); -} - -bool Expression::operator|| (const Expression &other) { - return valueToBool(value) || valueToBool(other.value); -} -} - -std::ostream& operator<< (std::ostream& out, const Arcweave::Expression &e) { - std::any value = e.value; - if (value.type() == typeid(int)) { - return out << std::any_cast(value); - } - if (value.type() == typeid(double)) { - return out << std::any_cast(value); - } - if (value.type() == typeid(std::string)) { - return out << std::any_cast(value); - } - if (value.type() == typeid(bool)) { - return out << std::any_cast(value); - } - return out; -} \ No newline at end of file +#include "ArcscriptExpression.h" +#include + +namespace Arcweave { + +std::string Expression::valueToString(std::any value) +{ + if (value.type() == typeid(std::string)) + { + return std::any_cast(value); + } + if (value.type() == typeid(bool)) + { + return std::any_cast(value) ? "true" : "false"; + } + if (value.type() == typeid(int)) + { + return std::to_string(std::any_cast(value)); + } + if (value.type() == typeid(double)) + { + std::stringstream ss; + ss << std::any_cast(value); + return ss.str(); + } + + return NULL; +} + + +Expression::NumberValues Expression::doubleValues(std::any value1, std::any value2) { + int intValue1, intValue2; + double dblValue1, dblValue2; + bool isDouble = false; + if (value1.type() == typeid(int)) { + intValue1 = std::any_cast(value1); + dblValue1 = intValue1; + } else if (value1.type() == typeid(double)){ // type double; + isDouble = true; + dblValue1 = std::any_cast(value1); + } else if (value1.type() == typeid(bool)) { + bool boolVal = std::any_cast(value1); + if (boolVal) { + dblValue1 = 1; + } else { + dblValue1 = 0; + } + } + if (value2.type() == typeid(int)) { + intValue2 = std::any_cast(value2); + dblValue2 = intValue2; + } else if (value2.type() == typeid(double)) { + isDouble = true; + dblValue2 = std::any_cast(value2); + } else if (value2.type() == typeid(bool)) { + bool boolVal = std::any_cast(value1); + if (boolVal) { + dblValue2 = 1; + } else { + dblValue2 = 0; + } + } + NumberValues returnVal; + returnVal.value1 = dblValue1; + returnVal.value2 = dblValue2; + returnVal.hasDoubles = isDouble; + return returnVal; +} + +bool Expression::valueToBool(std::any value) { + if (value.type() == typeid(int)) { + return (std::any_cast(value) > 0); + } + if (value.type() == typeid(double)) { + return (std::any_cast(value) > 0); + } + if (value.type() == typeid(std::string)) { + return (std::any_cast(value) != ""); + } + return (std::any_cast(value)); +} + +Expression Expression::operator+ (const Expression &other) { + if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) + { + return new Expression(valueToString(value) + valueToString(other.value)); + } + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 + values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 + values.value2); + } + return *result; +} + +Expression Expression::operator- (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 - values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 - values.value2); + } + return *result; +} + +Expression Expression::operator* (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 * values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 * values.value2); + } + return *result; +} + +Expression Expression::operator* (const int other) { + NumberValues values = doubleValues(value, other); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 * values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 * values.value2); + } + return *result; +} + +Expression Expression::operator/ (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + Expression* result; + if (!values.hasDoubles) { + int intValue = values.value1 / values.value2; + result = new Expression(intValue); + } else { + result = new Expression(values.value1 / values.value2); + } + return *result; +} + +Expression Expression::operator+= (const Expression &other) { + if (value.type() == typeid(int) || value.type() == typeid(double)) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 + values.value2; + value = intValue; + } else { + value = values.value1 + values.value2; + } + } + if (value.type() == typeid(std::string)) { + value = std::any_cast(value) + std::any_cast(other.value); + } + return *this; +} + +Expression Expression::operator-= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 - values.value2; + value = intValue; + } else { + value = values.value1 - values.value2; + } + return *this; +} + +Expression Expression::operator*= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 * values.value2; + value = intValue; + } else { + value = values.value1 * values.value2; + } + return *this; +} + +Expression Expression::operator/= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = values.value1 / values.value2; + value = intValue; + } else { + value = values.value1 / values.value2; + } + return *this; +} + +bool Expression::operator== (const Expression &other) { + if (value.type() == typeid(int) || value.type() == typeid(double)) { + NumberValues values = doubleValues(value, other.value); + return values.value1 == values.value2; + } + if (value.type() == typeid(bool)) { + return std::any_cast(value) == std::any_cast(other.value); + } + return std::any_cast(value) == std::any_cast(other.value); +} + +bool Expression::operator== (double other) { + NumberValues values = doubleValues(value, other); + return values.value1 == values.value2; +} + +bool Expression::operator== (int other) { + NumberValues values = doubleValues(value, other); + return values.value1 == values.value2; +} + +bool Expression::operator== (std::string other) { + return std::any_cast(value) == other; +} + +bool Expression::operator== (bool other) { + return valueToBool(value) == other; +} + +bool Expression::operator!= (const Expression &other) { + if (value.type() == typeid(int) || value.type() == typeid(double)) { + NumberValues values = doubleValues(value, other.value); + return values.value1 != values.value2; + } + if (value.type() == typeid(bool)) { + return std::any_cast(value) != std::any_cast(other.value); + } + return std::any_cast(value) != std::any_cast(other.value); +} + +bool Expression::operator!= (double other) { + NumberValues values = doubleValues(value, other); + return values.value1 != values.value2; +} + +bool Expression::operator!= (int other) { + NumberValues values = doubleValues(value, other); + return values.value1 != values.value2; +} + +bool Expression::operator!= (std::string other) { + return std::any_cast(value) != other; +} + +bool Expression::operator!= (const char other[]) { + return strcmp(std::any_cast(value).c_str(), other) == 0; +} + +bool Expression::operator> (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 > values.value2; +} + +bool Expression::operator> (int other) { + NumberValues values = doubleValues(value, other); + return values.value1 > values.value2; +} + +bool Expression::operator> (double other) { + NumberValues values = doubleValues(value, other); + return values.value1 > values.value2; +} + +bool Expression::operator>= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 >= values.value2; +} + +bool Expression::operator< (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 < values.value2; +} + +bool Expression::operator<= (const Expression &other) { + NumberValues values = doubleValues(value, other.value); + return values.value1 <= values.value2; +} + +bool Expression::operator! () { + return !(valueToBool(value)); +} + +bool Expression::operator&& (const Expression &other) { + return valueToBool(value) && valueToBool(other.value); +} + +bool Expression::operator|| (const Expression &other) { + return valueToBool(value) || valueToBool(other.value); +} +} + +std::ostream& operator<< (std::ostream& out, const Arcweave::Expression &e) { + std::any value = e.value; + if (value.type() == typeid(int)) { + return out << std::any_cast(value); + } + if (value.type() == typeid(double)) { + return out << std::any_cast(value); + } + if (value.type() == typeid(std::string)) { + return out << std::any_cast(value); + } + if (value.type() == typeid(bool)) { + return out << std::any_cast(value); + } + return out; +} diff --git a/Cpp/src/ArcscriptExpression.h b/Cpp/src/ArcscriptExpression.h index 0a7c715..09d5c00 100755 --- a/Cpp/src/ArcscriptExpression.h +++ b/Cpp/src/ArcscriptExpression.h @@ -1,81 +1,81 @@ -#include -#include -#include -#include - -namespace Arcweave { - -class Expression { -private: - struct NumberValues { - double value1; - double value2; - bool hasDoubles = false; - }; - - static NumberValues doubleValues(std::any value1, std::any value2) ; - - static std::string valueToString(std::any value); - static bool valueToBool(std::any value); -public: - std::any value; - Expression() { - value = std::any(); - } - Expression(std::string _value) { - value = _value; - } - Expression(bool _value) { - value = _value; - } - Expression(int _value) { - value = _value; - } - Expression(double _value) { - value = _value; - } - Expression(const Expression &e) { - value = e.value; - } - - void setValue(std::any _value) { - value = _value; - } - - const std::type_info& type() { - return value.type(); - } - - Expression operator+ (const Expression &other); - Expression operator- (const Expression &other); - Expression operator* (const Expression &other); - Expression operator* (const int other); - Expression operator/ (const Expression &other); - Expression operator+= (const Expression &other); - Expression operator-= (const Expression &other); - Expression operator*= (const Expression &other); - Expression operator/= (const Expression &other); - - bool operator== (const Expression &other); - bool operator== (double other); - bool operator== (int other); - bool operator== (std::string other); - bool operator== (bool other); - bool operator!= (const Expression &other); - bool operator!= (double other); - bool operator!= (int other); - bool operator!= (std::string other); - bool operator!= (const char other[]); - bool operator> (const Expression &other); - bool operator> (int other); - bool operator> (double other); - bool operator>= (const Expression &other); - bool operator< (const Expression &other); - bool operator<= (const Expression &other); - bool operator! (); - bool operator&& (const Expression &other); - bool operator|| (const Expression &other); -}; - -} -std::ostream& operator<< (std::ostream& out, const Arcweave::Expression &e); \ No newline at end of file +#include +#include +#include +#include + +namespace Arcweave { + +class Expression { +private: + struct NumberValues { + double value1; + double value2; + bool hasDoubles = false; + }; + + static NumberValues doubleValues(std::any value1, std::any value2) ; + + static std::string valueToString(std::any value); + static bool valueToBool(std::any value); +public: + std::any value; + Expression() { + value = std::any(); + } + Expression(std::string _value) { + value = _value; + } + Expression(bool _value) { + value = _value; + } + Expression(int _value) { + value = _value; + } + Expression(double _value) { + value = _value; + } + Expression(const Expression &e) { + value = e.value; + } + + void setValue(std::any _value) { + value = _value; + } + + const std::type_info& type() { + return value.type(); + } + + Expression operator+ (const Expression &other); + Expression operator- (const Expression &other); + Expression operator* (const Expression &other); + Expression operator* (const int other); + Expression operator/ (const Expression &other); + Expression operator+= (const Expression &other); + Expression operator-= (const Expression &other); + Expression operator*= (const Expression &other); + Expression operator/= (const Expression &other); + + bool operator== (const Expression &other); + bool operator== (double other); + bool operator== (int other); + bool operator== (std::string other); + bool operator== (bool other); + bool operator!= (const Expression &other); + bool operator!= (double other); + bool operator!= (int other); + bool operator!= (std::string other); + bool operator!= (const char other[]); + bool operator> (const Expression &other); + bool operator> (int other); + bool operator> (double other); + bool operator>= (const Expression &other); + bool operator< (const Expression &other); + bool operator<= (const Expression &other); + bool operator! (); + bool operator&& (const Expression &other); + bool operator|| (const Expression &other); +}; + +} +std::ostream& operator<< (std::ostream& out, const Arcweave::Expression &e); diff --git a/Cpp/src/ArcscriptFunctions.cpp b/Cpp/src/ArcscriptFunctions.cpp index 98cbea5..2bacfa7 100755 --- a/Cpp/src/ArcscriptFunctions.cpp +++ b/Cpp/src/ArcscriptFunctions.cpp @@ -1,206 +1,206 @@ -#include "ArcscriptFunctions.h" -#include -#include -#include -#include - -namespace Arcweave { - std::map ArcscriptFunctions::functions = { - { "abs", { 1, 1 } }, - { "max", { 2, -1 }}, - { "min", { 2, -1 }}, - { "random", { 0, 0 }}, - { "reset", { 1, -1 }}, - { "resetAll", { 0, -1} }, - { "roll", { 1, 2 } }, - { "round", { 1, 1} }, - { "show", { 1, -1 } }, - { "sqr", { 1, 1 } }, - { "sqrt", { 1, 1 } }, - { "visits", { 0, 1 } }, - }; - - std::any ArcscriptFunctions::Call(std::string functionName, std::vector _args) { - std::vector args; - for (std::any arg : _args) { - if (arg.type() == typeid(Expression)) { - args.push_back(std::any_cast(arg).value); - } - else { - args.push_back(arg); - } - } - std::any result; - if (functionName == "sqrt") { - result = this->Sqrt(args); - } - else if (functionName == "sqr") { - result = this->Sqr(args); - } - else if (functionName == "abs") { - result = this->Abs(args); - } - else if (functionName == "random") { - result = this->Random(args); - } - else if (functionName == "roll") { - result = this->Roll(args); - } - else if (functionName == "show") { - result = this->Show(args); - } - else if (functionName == "reset") { - result = this->Reset(args); - } - else if (functionName == "resetAll") { - result = this->ResetAll(args); - } - else if (functionName == "round") { - result = this->Round(args); - } - else if (functionName == "min") { - result = this->Min(args); - } - else if (functionName == "max") { - result = this->Max(args); - } - else if (functionName == "visits") { - result = this->Visits(args); - } - return result; - } - - std::any ArcscriptFunctions::Sqrt(std::vector args) { - - if (args[0].type() == typeid(int)) { - return sqrt(std::any_cast(args[0])); - } - return sqrt(std::any_cast(args[0])); - } - - std::any ArcscriptFunctions::Sqr(std::vector args) { - if (args[0].type() == typeid(int)) { - int n = std::any_cast(args[0]); - return n * n; - } - double n = std::any_cast(args[0]); - return n * n; - } - - std::any ArcscriptFunctions::Abs(std::vector args) { - if (args[0].type() == typeid(int)) { - return abs(std::any_cast(args[0])); - } - double n = std::any_cast(args[0]); - return abs(n); - } - - std::any ArcscriptFunctions::Random(std::vector args) { - srand(time(NULL)); - return ((double)rand() / (RAND_MAX)); - } - - std::any ArcscriptFunctions::Roll(std::vector args) { - int maxRoll = std::any_cast(args[0]); - int numRolls = 1; - if (args.size() == 2) { - numRolls = std::any_cast(args[1]); - } - int sum = 0; - for (int i = 0; i < numRolls; i++) { - int oneRoll = rand() % maxRoll + 1; - sum += oneRoll; - } - return sum; - } - - std::any ArcscriptFunctions::Show(std::vector args) { - std::string result; - for (int i = 0; i < args.size(); i++) { - std::any arg = args[i]; - if (arg.type() == typeid(int)) { - result += std::to_string(std::any_cast(arg)); - } - else if (arg.type() == typeid(double)) { - result += std::to_string(std::any_cast(arg)); - } - else if (arg.type() == typeid(bool)) { - result += std::to_string(std::any_cast(arg)); - } - else if (arg.type() == typeid(std::string)) { - result += std::any_cast(arg); - } - } - _state->outputs.AddScriptOutput(result); - return std::any(); - } - - std::any ArcscriptFunctions::Round(std::vector args) { - if (args[0].type() == typeid(int)) { - return round(std::any_cast(args[0])); - } - double n = std::any_cast(args[0]); - return round(n); - } - - std::any ArcscriptFunctions::Min(std::vector args) { - std::vector casted; - for (std::any arg : args) { - double val; - if (arg.type() == typeid(int)) { - val = std::any_cast(arg); - } - else { - val = std::any_cast(arg); - } - casted.push_back(val); - } - return *min_element(casted.begin(), casted.end()); - } - - std::any ArcscriptFunctions::Max(std::vector args) { - std::vector casted; - for (std::any arg : args) { - double val; - if (arg.type() == typeid(int)) { - val = std::any_cast(arg); - } - else { - val = std::any_cast(arg); - } - casted.push_back(val); - } - return *max_element(casted.begin(), casted.end()); - } - - std::any ArcscriptFunctions::Reset(std::vector args) { - std::vector variables; - for (std::any arg : args) { - variables.push_back(std::any_cast(arg)); - } - _state->resetVars(variables); - return std::any(); - } - - std::any ArcscriptFunctions::ResetAll(std::vector args) { - std::vector except; - for (std::any arg : args) { - except.push_back(std::any_cast(arg)); - } - _state->resetAllVars(except); - return std::any(); - } - - std::any ArcscriptFunctions::Visits(std::vector args) { - std::string nodeId = _state->currentElement; - if (args.size() > 0) { - Mention mention = std::any_cast(args[0]); - - if (mention.attrs.count("data-id")) { - nodeId = mention.attrs["data-id"]; - } - } - - return _state->visits[nodeId]; - } -} \ No newline at end of file +#include "ArcscriptFunctions.h" +#include +#include +#include +#include + +namespace Arcweave { + std::map ArcscriptFunctions::functions = { + { "abs", { 1, 1 } }, + { "max", { 2, -1 }}, + { "min", { 2, -1 }}, + { "random", { 0, 0 }}, + { "reset", { 1, -1 }}, + { "resetAll", { 0, -1} }, + { "roll", { 1, 2 } }, + { "round", { 1, 1} }, + { "show", { 1, -1 } }, + { "sqr", { 1, 1 } }, + { "sqrt", { 1, 1 } }, + { "visits", { 0, 1 } }, + }; + + std::any ArcscriptFunctions::Call(std::string functionName, std::vector _args) { + std::vector args; + for (std::any arg : _args) { + if (arg.type() == typeid(Expression)) { + args.push_back(std::any_cast(arg).value); + } + else { + args.push_back(arg); + } + } + std::any result; + if (functionName == "sqrt") { + result = this->Sqrt(args); + } + else if (functionName == "sqr") { + result = this->Sqr(args); + } + else if (functionName == "abs") { + result = this->Abs(args); + } + else if (functionName == "random") { + result = this->Random(args); + } + else if (functionName == "roll") { + result = this->Roll(args); + } + else if (functionName == "show") { + result = this->Show(args); + } + else if (functionName == "reset") { + result = this->Reset(args); + } + else if (functionName == "resetAll") { + result = this->ResetAll(args); + } + else if (functionName == "round") { + result = this->Round(args); + } + else if (functionName == "min") { + result = this->Min(args); + } + else if (functionName == "max") { + result = this->Max(args); + } + else if (functionName == "visits") { + result = this->Visits(args); + } + return result; + } + + std::any ArcscriptFunctions::Sqrt(std::vector args) { + + if (args[0].type() == typeid(int)) { + return sqrt(std::any_cast(args[0])); + } + return sqrt(std::any_cast(args[0])); + } + + std::any ArcscriptFunctions::Sqr(std::vector args) { + if (args[0].type() == typeid(int)) { + int n = std::any_cast(args[0]); + return n * n; + } + double n = std::any_cast(args[0]); + return n * n; + } + + std::any ArcscriptFunctions::Abs(std::vector args) { + if (args[0].type() == typeid(int)) { + return abs(std::any_cast(args[0])); + } + double n = std::any_cast(args[0]); + return abs(n); + } + + std::any ArcscriptFunctions::Random(std::vector args) { + srand(time(NULL)); + return ((double)rand() / (RAND_MAX)); + } + + std::any ArcscriptFunctions::Roll(std::vector args) { + int maxRoll = std::any_cast(args[0]); + int numRolls = 1; + if (args.size() == 2) { + numRolls = std::any_cast(args[1]); + } + int sum = 0; + for (int i = 0; i < numRolls; i++) { + int oneRoll = rand() % maxRoll + 1; + sum += oneRoll; + } + return sum; + } + + std::any ArcscriptFunctions::Show(std::vector args) { + std::string result; + for (int i = 0; i < args.size(); i++) { + std::any arg = args[i]; + if (arg.type() == typeid(int)) { + result += std::to_string(std::any_cast(arg)); + } + else if (arg.type() == typeid(double)) { + result += std::to_string(std::any_cast(arg)); + } + else if (arg.type() == typeid(bool)) { + result += std::to_string(std::any_cast(arg)); + } + else if (arg.type() == typeid(std::string)) { + result += std::any_cast(arg); + } + } + _state->outputs.AddScriptOutput(result); + return std::any(); + } + + std::any ArcscriptFunctions::Round(std::vector args) { + if (args[0].type() == typeid(int)) { + return round(std::any_cast(args[0])); + } + double n = std::any_cast(args[0]); + return round(n); + } + + std::any ArcscriptFunctions::Min(std::vector args) { + std::vector casted; + for (std::any arg : args) { + double val; + if (arg.type() == typeid(int)) { + val = std::any_cast(arg); + } + else { + val = std::any_cast(arg); + } + casted.push_back(val); + } + return *min_element(casted.begin(), casted.end()); + } + + std::any ArcscriptFunctions::Max(std::vector args) { + std::vector casted; + for (std::any arg : args) { + double val; + if (arg.type() == typeid(int)) { + val = std::any_cast(arg); + } + else { + val = std::any_cast(arg); + } + casted.push_back(val); + } + return *max_element(casted.begin(), casted.end()); + } + + std::any ArcscriptFunctions::Reset(std::vector args) { + std::vector variables; + for (std::any arg : args) { + variables.push_back(std::any_cast(arg)); + } + _state->resetVars(variables); + return std::any(); + } + + std::any ArcscriptFunctions::ResetAll(std::vector args) { + std::vector except; + for (std::any arg : args) { + except.push_back(std::any_cast(arg)); + } + _state->resetAllVars(except); + return std::any(); + } + + std::any ArcscriptFunctions::Visits(std::vector args) { + std::string nodeId = _state->currentElement; + if (args.size() > 0) { + Mention mention = std::any_cast(args[0]); + + if (mention.attrs.count("data-id")) { + nodeId = mention.attrs["data-id"]; + } + } + + return _state->visits[nodeId]; + } +} diff --git a/Cpp/src/ArcscriptFunctions.h b/Cpp/src/ArcscriptFunctions.h index 1647409..5886a07 100755 --- a/Cpp/src/ArcscriptFunctions.h +++ b/Cpp/src/ArcscriptFunctions.h @@ -1,40 +1,40 @@ -#pragma once - -#include "ArcscriptHelpers.h" -#include -#include -#include - -namespace Arcweave { -class ArcscriptFunctions { -private: - ArcscriptState *_state; - -public: - struct FunctionInfo { - int minArgs; - int maxArgs; - }; - - static std::map functions; - - ArcscriptFunctions(ArcscriptState* state) : _state(state) { - - } - - std::any Call(std::string functionName, std::vector args); - - std::any Abs(std::vector args); - std::any Max(std::vector args); - std::any Min(std::vector args); - std::any Random(std::vector args); - std::any Reset(std::vector args); - std::any ResetAll(std::vector args); - std::any Roll(std::vector args); - std::any Round(std::vector args); - std::any Show(std::vector args); - std::any Sqr(std::vector args); - std::any Sqrt(std::vector args); - std::any Visits(std::vector args); -}; -} \ No newline at end of file +#pragma once + +#include "ArcscriptHelpers.h" +#include +#include +#include + +namespace Arcweave { +class ArcscriptFunctions { +private: + ArcscriptState *_state; + +public: + struct FunctionInfo { + int minArgs; + int maxArgs; + }; + + static std::map functions; + + ArcscriptFunctions(ArcscriptState* state) : _state(state) { + + } + + std::any Call(std::string functionName, std::vector args); + + std::any Abs(std::vector args); + std::any Max(std::vector args); + std::any Min(std::vector args); + std::any Random(std::vector args); + std::any Reset(std::vector args); + std::any ResetAll(std::vector args); + std::any Roll(std::vector args); + std::any Round(std::vector args); + std::any Show(std::vector args); + std::any Sqr(std::vector args); + std::any Sqrt(std::vector args); + std::any Visits(std::vector args); +}; +} diff --git a/Cpp/src/ArcscriptHelpers.h b/Cpp/src/ArcscriptHelpers.h index 878691d..26e85ee 100755 --- a/Cpp/src/ArcscriptHelpers.h +++ b/Cpp/src/ArcscriptHelpers.h @@ -1,109 +1,109 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "ArcscriptExpression.h" -#include "ArcscriptErrorExceptions.h" -#include "ArcscriptOutputs.h" - -namespace Arcweave { - -enum VariableType { - AW_STRING, - AW_INTEGER, - AW_DOUBLE, - AW_BOOLEAN, - AW_ANY -}; - -struct Variable { - std::string id; - std::string name; - VariableType type; - std::any value; -}; - -class ArcscriptState { -public: - std::map variableChanges; - std::map variableValues; - std::map varNameToID; - ArcscriptOutputs outputs; - std::string currentElement; - std::map visits; - - ArcscriptState(std::string elementId, std::map varValues, std::map _visits) { - currentElement = elementId; - variableValues = varValues; - for(const auto var : variableValues) { - varNameToID[var.second.name] = var.first; - } - visits = _visits; - }; - - inline Variable getVar(std::string name) { - std::string varId = varNameToID[name]; - return variableValues[varId]; - } - - inline std::any getVarValue(std::string name) { - std::string varId = varNameToID[name]; - if(variableChanges.count(varId)) { - return variableChanges[varId]; - } - return variableValues[varId].value; - } - inline VariableType getVarType(std::string name) { - return variableValues[varNameToID[name]].type; - } - inline void setVarValue(std::string name, std::any value) { - std::string varId = varNameToID[name]; - variableChanges[varId] = value; - } - inline void setVarValues(std::vector names, std::vector values) { - for (int i = 0; i < names.size(); i++) { - variableChanges[names[i]] = values[i]; - } - } - - inline void resetVars(std::vector vars) { - for (Variable var : vars) { - variableChanges[var.id] = var.value; - } - } - - inline void resetAllVars(std::vector except) { - std::set exceptVariableIds; - for (Variable var : except) { - exceptVariableIds.insert(var.id); - } - std::map::iterator it = variableValues.begin(); - while (it != variableValues.end()) - { - if (exceptVariableIds.find(it->first) == exceptVariableIds.end()) { // not in except vars - variableChanges[it->first] = it->second.value; - } - it++; - } - } -}; - -class Mention { -public: - std::string label; - std::map attrs; - Mention(std::string _label, std::map _attrs) { - label = _label; - attrs = _attrs; - } - Mention(const Mention &m) { - label = m.label; - attrs = m.attrs; - } -}; -} +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "ArcscriptExpression.h" +#include "ArcscriptErrorExceptions.h" +#include "ArcscriptOutputs.h" + +namespace Arcweave { + +enum VariableType { + AW_STRING, + AW_INTEGER, + AW_DOUBLE, + AW_BOOLEAN, + AW_ANY +}; + +struct Variable { + std::string id; + std::string name; + VariableType type; + std::any value; +}; + +class ArcscriptState { +public: + std::map variableChanges; + std::map variableValues; + std::map varNameToID; + ArcscriptOutputs outputs; + std::string currentElement; + std::map visits; + + ArcscriptState(std::string elementId, std::map varValues, std::map _visits) { + currentElement = elementId; + variableValues = varValues; + for(const auto var : variableValues) { + varNameToID[var.second.name] = var.first; + } + visits = _visits; + }; + + inline Variable getVar(std::string name) { + std::string varId = varNameToID[name]; + return variableValues[varId]; + } + + inline std::any getVarValue(std::string name) { + std::string varId = varNameToID[name]; + if(variableChanges.count(varId)) { + return variableChanges[varId]; + } + return variableValues[varId].value; + } + inline VariableType getVarType(std::string name) { + return variableValues[varNameToID[name]].type; + } + inline void setVarValue(std::string name, std::any value) { + std::string varId = varNameToID[name]; + variableChanges[varId] = value; + } + inline void setVarValues(std::vector names, std::vector values) { + for (int i = 0; i < names.size(); i++) { + variableChanges[names[i]] = values[i]; + } + } + + inline void resetVars(std::vector vars) { + for (Variable var : vars) { + variableChanges[var.id] = var.value; + } + } + + inline void resetAllVars(std::vector except) { + std::set exceptVariableIds; + for (Variable var : except) { + exceptVariableIds.insert(var.id); + } + std::map::iterator it = variableValues.begin(); + while (it != variableValues.end()) + { + if (exceptVariableIds.find(it->first) == exceptVariableIds.end()) { // not in except vars + variableChanges[it->first] = it->second.value; + } + it++; + } + } +}; + +class Mention { +public: + std::string label; + std::map attrs; + Mention(std::string _label, std::map _attrs) { + label = _label; + attrs = _attrs; + } + Mention(const Mention &m) { + label = m.label; + attrs = m.attrs; + } +}; +} diff --git a/Cpp/src/ArcscriptOutputs.cpp b/Cpp/src/ArcscriptOutputs.cpp index 77ec05a..32845fe 100755 --- a/Cpp/src/ArcscriptOutputs.cpp +++ b/Cpp/src/ArcscriptOutputs.cpp @@ -1,79 +1,79 @@ -#include "ArcscriptOutputs.h" - -void Arcweave::ArcscriptOutputs::AppendParagraph(std::string text) -{ - outputs_.push_back(std::make_unique(text)); -} - -void Arcweave::ArcscriptOutputs::AddParagraph(std::string text) -{ - if (current_node_ == nullptr) - { - current_node_ = this; - } - - if (added_script_) - { - if (!outputs_.empty() && dynamic_cast(outputs_.back().get()) && dynamic_cast(current_node_) == nullptr) - { - AppendParagraph(text); - } else - { - AddScriptOutput(text); - } - added_script_ = false; - return; - } - current_node_->AppendParagraph(text); -} - -void Arcweave::ArcscriptOutputs::AddBlockquote() -{ - if (added_script_ && !outputs_.empty()) - { - IOutputNode* n = outputs_.back().get(); - if (dynamic_cast(n)) - { - current_node_ = dynamic_cast(n); - return; - } - } - Blockquote* b = new Blockquote(); - outputs_.push_back(std::unique_ptr(b)); - current_node_ = b; -} - -void Arcweave::ArcscriptOutputs::AddScript() -{ - added_script_ = true; -} - - -void Arcweave::ArcscriptOutputs::AddScriptOutput(std::string text) -{ - added_script_ = true; - if (outputs_.empty()) - { - outputs_.push_back(std::make_unique(text)); - return; - } - outputs_.back()->MergeScriptOutput(text); -} - -void Arcweave::ArcscriptOutputs::ExitBlockquote() -{ - current_node_ = this; -} - -std::string Arcweave::ArcscriptOutputs::GetText() -{ - std::string output; - for (const auto& value : outputs_) - { - output += value->GetText(); - } - - return output; -} - - +#include "ArcscriptOutputs.h" + +void Arcweave::ArcscriptOutputs::AppendParagraph(std::string text) +{ + outputs_.push_back(std::make_unique(text)); +} + +void Arcweave::ArcscriptOutputs::AddParagraph(std::string text) +{ + if (current_node_ == nullptr) + { + current_node_ = this; + } + + if (added_script_) + { + if (!outputs_.empty() && dynamic_cast(outputs_.back().get()) && dynamic_cast(current_node_) == nullptr) + { + AppendParagraph(text); + } else + { + AddScriptOutput(text); + } + added_script_ = false; + return; + } + current_node_->AppendParagraph(text); +} + +void Arcweave::ArcscriptOutputs::AddBlockquote() +{ + if (added_script_ && !outputs_.empty()) + { + IOutputNode* n = outputs_.back().get(); + if (dynamic_cast(n)) + { + current_node_ = dynamic_cast(n); + return; + } + } + Blockquote* b = new Blockquote(); + outputs_.push_back(std::unique_ptr(b)); + current_node_ = b; +} + +void Arcweave::ArcscriptOutputs::AddScript() +{ + added_script_ = true; +} + + +void Arcweave::ArcscriptOutputs::AddScriptOutput(std::string text) +{ + added_script_ = true; + if (outputs_.empty()) + { + outputs_.push_back(std::make_unique(text)); + return; + } + outputs_.back()->MergeScriptOutput(text); +} + +void Arcweave::ArcscriptOutputs::ExitBlockquote() +{ + current_node_ = this; +} + +std::string Arcweave::ArcscriptOutputs::GetText() +{ + std::string output; + for (const auto& value : outputs_) + { + output += value->GetText(); + } + + return output; +} + + diff --git a/Cpp/src/ArcscriptOutputs.h b/Cpp/src/ArcscriptOutputs.h index e47e69a..3949d28 100755 --- a/Cpp/src/ArcscriptOutputs.h +++ b/Cpp/src/ArcscriptOutputs.h @@ -1,96 +1,96 @@ -#pragma once - -#include -#include -#include - -namespace Arcweave -{ - class IOutputNode - { - public: - virtual std::string GetText() = 0; - virtual void MergeScriptOutput(std::string text) = 0; - }; - - class IHasParagraphs - { - public: - virtual void AppendParagraph(std::string text) = 0; - }; - - class Paragraph: public IOutputNode - { - private: - std::string text_; - - public: - - Paragraph(std::string text) - { - text_ = text; - } - - inline void MergeScriptOutput(std::string text) override - { - if (text.length() > 0) - { - text_ += ' ' + text; - } - } - - inline std::string GetText() override - { - return "

" + text_ + "

"; - } - }; - - class Blockquote: public IOutputNode, public IHasParagraphs - { - public: - std::vector> paragraphs; - - inline void AppendParagraph(std::string text) override - { - paragraphs.push_back(std::make_unique(text)); - } - - inline void MergeScriptOutput(std::string text) override - { - if (paragraphs.empty()) - { - AppendParagraph(text); - return; - } - paragraphs.back()->MergeScriptOutput(text); - } - - inline std::string GetText() override - { - std::string output; - for (const auto& value : paragraphs) - { - output += value->GetText(); - } - - return "
" + output + "
"; - } - }; - - class ArcscriptOutputs: public IHasParagraphs - { - private: - std::vector> outputs_; - IHasParagraphs* current_node_ = nullptr; - bool added_script_ = false; - public: - void AppendParagraph(std::string text) override; - void AddParagraph(std::string text); - void AddBlockquote(); - void AddScript(); - void AddScriptOutput(std::string text); - void ExitBlockquote(); - std::string GetText(); - }; - -} +#pragma once + +#include +#include +#include + +namespace Arcweave +{ + class IOutputNode + { + public: + virtual std::string GetText() = 0; + virtual void MergeScriptOutput(std::string text) = 0; + }; + + class IHasParagraphs + { + public: + virtual void AppendParagraph(std::string text) = 0; + }; + + class Paragraph: public IOutputNode + { + private: + std::string text_; + + public: + + Paragraph(std::string text) + { + text_ = text; + } + + inline void MergeScriptOutput(std::string text) override + { + if (text.length() > 0) + { + text_ += ' ' + text; + } + } + + inline std::string GetText() override + { + return "

" + text_ + "

"; + } + }; + + class Blockquote: public IOutputNode, public IHasParagraphs + { + public: + std::vector> paragraphs; + + inline void AppendParagraph(std::string text) override + { + paragraphs.push_back(std::make_unique(text)); + } + + inline void MergeScriptOutput(std::string text) override + { + if (paragraphs.empty()) + { + AppendParagraph(text); + return; + } + paragraphs.back()->MergeScriptOutput(text); + } + + inline std::string GetText() override + { + std::string output; + for (const auto& value : paragraphs) + { + output += value->GetText(); + } + + return "
" + output + "
"; + } + }; + + class ArcscriptOutputs: public IHasParagraphs + { + private: + std::vector> outputs_; + IHasParagraphs* current_node_ = nullptr; + bool added_script_ = false; + public: + void AppendParagraph(std::string text) override; + void AddParagraph(std::string text); + void AddBlockquote(); + void AddScript(); + void AddScriptOutput(std::string text); + void ExitBlockquote(); + std::string GetText(); + }; + +} diff --git a/Cpp/src/ArcscriptParserBase.cpp b/Cpp/src/ArcscriptParserBase.cpp index c3acc17..92e1d4b 100755 --- a/Cpp/src/ArcscriptParserBase.cpp +++ b/Cpp/src/ArcscriptParserBase.cpp @@ -1,99 +1,99 @@ -#include "ArcscriptParser.h" -#include "ArcscriptLexer.h" -#include "ArcscriptParserBase.h" - -using namespace antlr4; - -bool ArcscriptParserBase::assertVariable(antlr4::Token *variable) { - std::string variableName = variable->getText(); - if (_state->varNameToID.count(variableName) > 0) { - return true; - } - throw Arcweave::ParseErrorException("Unknown variable \"" + variableName + "\""); - return false; -} - -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()); -} - -bool ArcscriptParserBase::assertMention(std::any attrCtxList) { - std::map attrs; - ParserRuleContext *ctx = this->getContext(); - std::vector ctxList = ctx->getRuleContexts(); - for (auto attrCtx : ctxList) { - tree::TerminalNode *nameNode = attrCtx->getToken(Arcweave::ArcscriptParser::ATTR_NAME, 0); - std::string attrName = ""; - if (nameNode) { - attrName = nameNode->getText(); - } - tree::TerminalNode *valueNode = attrCtx->getToken(Arcweave::ArcscriptParser::ATTR_VALUE, 0); - std::string attrValue = ""; - if (nameNode) { - attrValue = valueNode->getText(); - } - - if ((attrValue.rfind("\"", 0) == 0 && ends_with(attrValue, "\"")) || - attrValue.rfind("'", 0) == 0 && ends_with(attrValue, "'")) { - - attrValue = attrValue.substr(1, attrValue.size() - 2); - - } - attrs[attrName] = attrValue; - } - std::stringstream classList(attrs["class"]); - std::string className; - bool classFound = false; - while(classList >> className){ - if (className == "mention") { - classFound = true; - break; - } - } - if (!classFound) { - throw Arcweave::ParseErrorException("Invalid mention type"); - return false; - } - if (attrs["data-type"] != "element") { - throw Arcweave::ParseErrorException("Invalid mention type"); - return false; - } - if (_state->visits.count(attrs["data-id"]) == 0) { - throw Arcweave::ParseErrorException("Invalid element mention"); - } - - return true; -} - -bool ArcscriptParserBase::assertFunctionArguments(Token *fname, std::any argumentList) { - int argListLength = 0; - std::string functionName = fname->getText(); - int min = Arcweave::ArcscriptFunctions::functions[functionName].minArgs; - int max = Arcweave::ArcscriptFunctions::functions[functionName].maxArgs; - if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Argument_listContext*)) { - Arcweave::ArcscriptParser::Argument_listContext *argumentListCtx = std::any_cast(argumentList); - if (argumentListCtx != NULL) { - argListLength = argumentListCtx->argument().size(); - } - } - if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Variable_listContext*)) { - Arcweave::ArcscriptParser::Variable_listContext *variableListCtx = std::any_cast(argumentList); - if (variableListCtx != NULL) { - argListLength = variableListCtx->VARIABLE().size(); - } - } - - if ((min != -1 && argListLength < min) || (max != -1 && argListLength > max)) { - throw Arcweave::ParseErrorException("Wrong number of arguments in \""+ functionName + "\"."); - return false; - } - - return true; -} - -void ArcscriptParserBase::setLineStart(antlr4::Token* token) -{ - openTagEndPos = token->getStartIndex() + token->getText().length(); -} +#include "ArcscriptParser.h" +#include "ArcscriptLexer.h" +#include "ArcscriptParserBase.h" + +using namespace antlr4; + +bool ArcscriptParserBase::assertVariable(antlr4::Token *variable) { + std::string variableName = variable->getText(); + if (_state->varNameToID.count(variableName) > 0) { + return true; + } + throw Arcweave::ParseErrorException("Unknown variable \"" + variableName + "\""); + return false; +} + +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()); +} + +bool ArcscriptParserBase::assertMention(std::any attrCtxList) { + std::map attrs; + ParserRuleContext *ctx = this->getContext(); + std::vector ctxList = ctx->getRuleContexts(); + for (auto attrCtx : ctxList) { + tree::TerminalNode *nameNode = attrCtx->getToken(Arcweave::ArcscriptParser::ATTR_NAME, 0); + std::string attrName = ""; + if (nameNode) { + attrName = nameNode->getText(); + } + tree::TerminalNode *valueNode = attrCtx->getToken(Arcweave::ArcscriptParser::ATTR_VALUE, 0); + std::string attrValue = ""; + if (nameNode) { + attrValue = valueNode->getText(); + } + + if ((attrValue.rfind("\"", 0) == 0 && ends_with(attrValue, "\"")) || + attrValue.rfind("'", 0) == 0 && ends_with(attrValue, "'")) { + + attrValue = attrValue.substr(1, attrValue.size() - 2); + + } + attrs[attrName] = attrValue; + } + std::stringstream classList(attrs["class"]); + std::string className; + bool classFound = false; + while(classList >> className){ + if (className == "mention") { + classFound = true; + break; + } + } + if (!classFound) { + throw Arcweave::ParseErrorException("Invalid mention type"); + return false; + } + if (attrs["data-type"] != "element") { + throw Arcweave::ParseErrorException("Invalid mention type"); + return false; + } + if (_state->visits.count(attrs["data-id"]) == 0) { + throw Arcweave::ParseErrorException("Invalid element mention"); + } + + return true; +} + +bool ArcscriptParserBase::assertFunctionArguments(Token *fname, std::any argumentList) { + int argListLength = 0; + std::string functionName = fname->getText(); + int min = Arcweave::ArcscriptFunctions::functions[functionName].minArgs; + int max = Arcweave::ArcscriptFunctions::functions[functionName].maxArgs; + if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Argument_listContext*)) { + Arcweave::ArcscriptParser::Argument_listContext *argumentListCtx = std::any_cast(argumentList); + if (argumentListCtx != NULL) { + argListLength = argumentListCtx->argument().size(); + } + } + if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Variable_listContext*)) { + Arcweave::ArcscriptParser::Variable_listContext *variableListCtx = std::any_cast(argumentList); + if (variableListCtx != NULL) { + argListLength = variableListCtx->VARIABLE().size(); + } + } + + if ((min != -1 && argListLength < min) || (max != -1 && argListLength > max)) { + throw Arcweave::ParseErrorException("Wrong number of arguments in \""+ functionName + "\"."); + return false; + } + + return true; +} + +void ArcscriptParserBase::setLineStart(antlr4::Token* token) +{ + openTagEndPos = token->getStartIndex() + token->getText().length(); +} diff --git a/Cpp/src/ArcscriptParserBase.h b/Cpp/src/ArcscriptParserBase.h index 7d0d849..919c893 100755 --- a/Cpp/src/ArcscriptParserBase.h +++ b/Cpp/src/ArcscriptParserBase.h @@ -1,19 +1,19 @@ -#pragma once - -#include "antlr4-runtime.h" -#include "ArcscriptHelpers.h" -#include "ArcscriptFunctions.h" - -class ArcscriptParserBase : public antlr4::Parser { -private: - Arcweave::ArcscriptState* _state; - int openTagEndPos; -public: - int currentLine = 0; - ArcscriptParserBase(antlr4::TokenStream *input) : Parser(input) { } - inline void setArcscriptState(Arcweave::ArcscriptState *state) { _state = state; }; - bool assertVariable(antlr4::Token *variable); - bool assertMention(std::any attrCtxList); - bool assertFunctionArguments(antlr4::Token *fname, std::any argumentList); - void setLineStart(antlr4::Token *token); -}; \ No newline at end of file +#pragma once + +#include "antlr4-runtime.h" +#include "ArcscriptHelpers.h" +#include "ArcscriptFunctions.h" + +class ArcscriptParserBase : public antlr4::Parser { +private: + Arcweave::ArcscriptState* _state; + int openTagEndPos; +public: + int currentLine = 0; + ArcscriptParserBase(antlr4::TokenStream *input) : Parser(input) { } + inline void setArcscriptState(Arcweave::ArcscriptState *state) { _state = state; }; + bool assertVariable(antlr4::Token *variable); + bool assertMention(std::any attrCtxList); + bool assertFunctionArguments(antlr4::Token *fname, std::any argumentList); + void setLineStart(antlr4::Token *token); +}; diff --git a/Cpp/src/ArcscriptTranspiler.cpp b/Cpp/src/ArcscriptTranspiler.cpp index 2abc9bd..2bffc86 100755 --- a/Cpp/src/ArcscriptTranspiler.cpp +++ b/Cpp/src/ArcscriptTranspiler.cpp @@ -1,172 +1,172 @@ -#include "ArcscriptTranspiler.h" -#include "ArcscriptErrorListener.h" -#include -#include - -#define _CRT_SECURE_NO_WARNINGS - -#ifdef _WIN64 -#define strdup _strdup -#endif - -using namespace Arcweave; -using namespace antlr4; - -TranspilerOutput ArcscriptTranspiler::runScript(std::string code) { - ANTLRInputStream input(code); - ArcscriptLexer lexer(&input); - - TranspilerOutput result; - - ErrorListener lexerErrorListener; - lexer.removeErrorListeners(); - lexer.addErrorListener(&lexerErrorListener); - - CommonTokenStream tokens(&lexer); - - // Run the lexer - tokens.fill(); - - ArcscriptParser parser(&tokens); - parser.setArcscriptState(&state); - ErrorListener parserErrorListener; - parser.removeErrorListeners(); - parser.addErrorListener(&parserErrorListener); - - ArcscriptParser::InputContext *tree; - - // Run the parser - tree = parser.input(); - - ArcscriptVisitor visitor(&state); - - // Run the visitor - std::any res(visitor.visitInput(tree)); - - result.changes = visitor.state->variableChanges; - - result.output = visitor.state->outputs.GetText(); - result.result = res; - - if (tree->script() != NULL) { - result.type = SCRIPT; - } else { - result.type = CONDITION; - } - - return result; -} - -UTranspilerOutput* runScriptExport(const char* code, const char* elId, UVariable* variables, size_t varLength, UVisit* visits, size_t visitsLength) -{ - Arcweave::TranspilerOutput transpilerOutput; - - transpilerOutput.type = InputType::CONDITION; - - std::string sCode(code); - std::string sElId(elId); - - std::map initVars; - for (size_t i = 0; i < varLength; i++) { - Variable var; - var.id = std::string(variables[i].id); - var.name = std::string(variables[i].name); - var.type = variables[i].type; - - if (var.type == VariableType::AW_STRING) { - var.value = std::string(variables[i].string_val); - } - else if (var.type == VariableType::AW_INTEGER) { - var.value = variables[i].int_val; - } - else if (var.type == VariableType::AW_DOUBLE) { - var.value = variables[i].double_val; - } - else if (var.type == VariableType::AW_BOOLEAN) { - var.value = variables[i].bool_val; - } - initVars[variables[i].id] = var; - } - - std::map initVisits; - for (size_t i = 0; i < visitsLength; i++) { - initVisits[std::string(visits[i].elId)] = visits[i].visits; - } - - Arcweave::ArcscriptTranspiler transpiler(sElId, initVars, initVisits); - transpilerOutput = transpiler.runScript(sCode); - - UTranspilerOutput* uTranspilerOutput = new UTranspilerOutput(); - uTranspilerOutput->output = strdup(transpilerOutput.output.c_str()); - uTranspilerOutput->type = transpilerOutput.type; - - if (transpilerOutput.type == InputType::CONDITION) { - uTranspilerOutput->conditionResult = std::any_cast(transpilerOutput.result); - } - - size_t changesLen = transpilerOutput.changes.size(); - - UVariableChange* variableChanges = new UVariableChange[changesLen]; - size_t i = 0; - for (auto change : transpilerOutput.changes) { - UVariableChange uChange; - uChange.varId = strdup(change.first.c_str()); - - if (change.second.type() == typeid(std::string)) { - uChange.type = VariableType::AW_STRING; - std::string string_result = std::any_cast(change.second); - uChange.string_result = strdup(string_result.c_str()); - } - else if (change.second.type() == typeid(int)) { - uChange.type = VariableType::AW_INTEGER; - uChange.int_result = std::any_cast(change.second); - } - else if (change.second.type() == typeid(double)) { - uChange.type = VariableType::AW_DOUBLE; - uChange.double_result = std::any_cast(change.second); - } - else if (change.second.type() == typeid(bool)) { - uChange.type = VariableType::AW_BOOLEAN; - uChange.bool_result = std::any_cast(change.second); - } - variableChanges[i] = uChange; - i++; - } - uTranspilerOutput->changes = variableChanges; - uTranspilerOutput->changesLen = changesLen; - - return uTranspilerOutput; - //std::cout << code << std::endl; - //std::cout << elId << std::endl; - //std::cout << _visits["test"] << std::endl; - /*try { - Arcweave::ArcscriptTranspiler transpiler(elId, initVars, _visits); - - try { - transpilerOutput = transpiler.runScript(code); - } - catch (std::exception& e) { - std::cerr << "Arcscript Transpiler failed during runScript: " << std::endl; - std::cerr << e.what() << std::endl; - return false; - } - } - catch (std::exception &e) { - std::cerr << "Arcscript Transpiler failed during init: " << std::endl; - std::cerr << e.what() << std::endl; - return false; - } - return true;*/ -} - -void deallocateOutput(UTranspilerOutput* output) { - for (size_t i = 0; i < output->changesLen; i++) { - free(output->changes[i].varId); - if (output->changes[i].type == VariableType::AW_STRING) { - free(output->changes[i].string_result); - } - } - delete[] output->changes; - free(output->output); - delete output; -} \ No newline at end of file +#include "ArcscriptTranspiler.h" +#include "ArcscriptErrorListener.h" +#include +#include + +#define _CRT_SECURE_NO_WARNINGS + +#ifdef _WIN64 +#define strdup _strdup +#endif + +using namespace Arcweave; +using namespace antlr4; + +TranspilerOutput ArcscriptTranspiler::runScript(std::string code) { + ANTLRInputStream input(code); + ArcscriptLexer lexer(&input); + + TranspilerOutput result; + + ErrorListener lexerErrorListener; + lexer.removeErrorListeners(); + lexer.addErrorListener(&lexerErrorListener); + + CommonTokenStream tokens(&lexer); + + // Run the lexer + tokens.fill(); + + ArcscriptParser parser(&tokens); + parser.setArcscriptState(&state); + ErrorListener parserErrorListener; + parser.removeErrorListeners(); + parser.addErrorListener(&parserErrorListener); + + ArcscriptParser::InputContext *tree; + + // Run the parser + tree = parser.input(); + + ArcscriptVisitor visitor(&state); + + // Run the visitor + std::any res(visitor.visitInput(tree)); + + result.changes = visitor.state->variableChanges; + + result.output = visitor.state->outputs.GetText(); + result.result = res; + + if (tree->script() != NULL) { + result.type = SCRIPT; + } else { + result.type = CONDITION; + } + + return result; +} + +UTranspilerOutput* runScriptExport(const char* code, const char* elId, UVariable* variables, size_t varLength, UVisit* visits, size_t visitsLength) +{ + Arcweave::TranspilerOutput transpilerOutput; + + transpilerOutput.type = InputType::CONDITION; + + std::string sCode(code); + std::string sElId(elId); + + std::map initVars; + for (size_t i = 0; i < varLength; i++) { + Variable var; + var.id = std::string(variables[i].id); + var.name = std::string(variables[i].name); + var.type = variables[i].type; + + if (var.type == VariableType::AW_STRING) { + var.value = std::string(variables[i].string_val); + } + else if (var.type == VariableType::AW_INTEGER) { + var.value = variables[i].int_val; + } + else if (var.type == VariableType::AW_DOUBLE) { + var.value = variables[i].double_val; + } + else if (var.type == VariableType::AW_BOOLEAN) { + var.value = variables[i].bool_val; + } + initVars[variables[i].id] = var; + } + + std::map initVisits; + for (size_t i = 0; i < visitsLength; i++) { + initVisits[std::string(visits[i].elId)] = visits[i].visits; + } + + Arcweave::ArcscriptTranspiler transpiler(sElId, initVars, initVisits); + transpilerOutput = transpiler.runScript(sCode); + + UTranspilerOutput* uTranspilerOutput = new UTranspilerOutput(); + uTranspilerOutput->output = strdup(transpilerOutput.output.c_str()); + uTranspilerOutput->type = transpilerOutput.type; + + if (transpilerOutput.type == InputType::CONDITION) { + uTranspilerOutput->conditionResult = std::any_cast(transpilerOutput.result); + } + + size_t changesLen = transpilerOutput.changes.size(); + + UVariableChange* variableChanges = new UVariableChange[changesLen]; + size_t i = 0; + for (auto change : transpilerOutput.changes) { + UVariableChange uChange; + uChange.varId = strdup(change.first.c_str()); + + if (change.second.type() == typeid(std::string)) { + uChange.type = VariableType::AW_STRING; + std::string string_result = std::any_cast(change.second); + uChange.string_result = strdup(string_result.c_str()); + } + else if (change.second.type() == typeid(int)) { + uChange.type = VariableType::AW_INTEGER; + uChange.int_result = std::any_cast(change.second); + } + else if (change.second.type() == typeid(double)) { + uChange.type = VariableType::AW_DOUBLE; + uChange.double_result = std::any_cast(change.second); + } + else if (change.second.type() == typeid(bool)) { + uChange.type = VariableType::AW_BOOLEAN; + uChange.bool_result = std::any_cast(change.second); + } + variableChanges[i] = uChange; + i++; + } + uTranspilerOutput->changes = variableChanges; + uTranspilerOutput->changesLen = changesLen; + + return uTranspilerOutput; + //std::cout << code << std::endl; + //std::cout << elId << std::endl; + //std::cout << _visits["test"] << std::endl; + /*try { + Arcweave::ArcscriptTranspiler transpiler(elId, initVars, _visits); + + try { + transpilerOutput = transpiler.runScript(code); + } + catch (std::exception& e) { + std::cerr << "Arcscript Transpiler failed during runScript: " << std::endl; + std::cerr << e.what() << std::endl; + return false; + } + } + catch (std::exception &e) { + std::cerr << "Arcscript Transpiler failed during init: " << std::endl; + std::cerr << e.what() << std::endl; + return false; + } + return true;*/ +} + +void deallocateOutput(UTranspilerOutput* output) { + for (size_t i = 0; i < output->changesLen; i++) { + free(output->changes[i].varId); + if (output->changes[i].type == VariableType::AW_STRING) { + free(output->changes[i].string_result); + } + } + delete[] output->changes; + free(output->output); + delete output; +} diff --git a/Cpp/src/ArcscriptTranspiler.h b/Cpp/src/ArcscriptTranspiler.h index 913a233..9cf3cea 100755 --- a/Cpp/src/ArcscriptTranspiler.h +++ b/Cpp/src/ArcscriptTranspiler.h @@ -1,164 +1,164 @@ -#pragma once -#include "antlr4-runtime.h" -#include "ArcscriptLexer.h" -#include "ArcscriptParser.h" -#include "ArcscriptVisitor.h" - -#if defined _WIN64 - #ifdef WIN_EXPORT - #ifdef __GNUC__ - #define EXPORTED __attribute__ ((dllexport)) - #else - #define EXPORTED __declspec(dllexport) - #endif - #else - #ifdef __GNUC__ - #define EXPORTED __attribute__ ((dllimport)) - #else - #define EXPORTED __declspec(dllimport) - #endif - #endif - #define NOT_EXPORTED -#else - #if __GNUC__ >= 4 - #define EXPORTED __attribute__ ((visibility("default"))) - #define NOT_EXPORTED __attribute__ ((visibility("hidden"))) - #else - #define EXPORTED - #define NOT_EXPORTED - #endif -#endif - -// #ifdef ARCSCRIPTTRANSPILER_EXPORTS -// #define ARCSCRIPTTRANSPILER_API __declspec(dllexport) -// #else -// #define ARCSCRIPTTRANSPILER_API __declspec(dllimport) -// #endif -// #else -// #define ARCSCRIPTTRANSPILER_API -// #endif - -namespace Arcweave -{ - /** - * @enum InputType - * The arscript code types - */ - enum InputType { - /// @brief A condition (results to bool) code type - CONDITION, - /// @brief A script code type - SCRIPT - }; - - /** - * @struct TranspilerOutput - * @brief The structure contains info that the ArcscriptTranspiler returns - * @var TranspilerOutput::output - * Member 'output' contains the text output when a codeblock is run - * @var TranspilerOutput::changes - * Member 'changes' contains the variables that are going to be changed from the codeblock - * @var TranspilerOutput::result - * Member 'result' contains the result of the ArcscriptTranspiler code. Useful in condition blocks - * @var TranspilerOutput::type - * Member 'type' contains the type of the code block i.e. CONDITION or SCRIPT - */ - struct TranspilerOutput { - std::string output; - std::map changes; - std::any result; - InputType type; - }; - - - // The following types starting with a U* are the types that the exported DLL function accepts and returns - extern "C" struct UVariableChange { - char* varId; - VariableType type; - int int_result; - double double_result; - char* string_result; - bool bool_result; - UVariableChange() { - varId = nullptr; - type = VariableType::AW_ANY; - int_result = 0; - double_result = 0.0; - string_result = nullptr; - bool_result = false; - } - }; - - extern "C" struct UTranspilerOutput { - char* output; - InputType type; - UVariableChange* changes; - size_t changesLen = 0; - bool conditionResult = false; - - UTranspilerOutput() { - output = nullptr; - type = InputType::SCRIPT; - changes = nullptr; - changesLen = 0; - conditionResult = false; - } - }; - - - struct UVariable { - const char* id; - const char* name; - VariableType type; - int int_val; - double double_val; - const char* string_val; - bool bool_val; - - UVariable() { - id = nullptr; - name = nullptr; - type = VariableType::AW_ANY; - int_val = 0; - double_val = 0; - string_val = nullptr; - bool_val = false; - } - }; - - struct UVisit { - const char* elId; - int visits; - - UVisit() { - elId = nullptr; - visits = 0; - } - }; - - /** - * Implementation of the Arcscript Transpiler in C++. Uses the ANTLR4 runtime library - * to run the code and it needs the initial variables and the current element ID it is - * transpiling. - * - * - */ - class ArcscriptTranspiler { - public: - - ArcscriptState state; - - ArcscriptTranspiler(std::string elId, std::map initVars, std::map _visits) : state(elId, initVars, _visits) { }; - - /** - * Runs the arcscript code and returns it's results. - * @param code The code block that we need to parse - * @return The result of the ran script - */ - TranspilerOutput runScript(std::string code); - - //ARCSCRIPTTRANSPILER_API UTranspilerOutput URunScript(char* code); - }; -}; -EXPORTED UTranspilerOutput* runScriptExport(const char* code, const char* elId, UVariable* variables, size_t varLength, UVisit* visits, size_t visitsLength); -EXPORTED void deallocateOutput(UTranspilerOutput* output); \ No newline at end of file +#pragma once +#include "antlr4-runtime.h" +#include "ArcscriptLexer.h" +#include "ArcscriptParser.h" +#include "ArcscriptVisitor.h" + +#if defined _WIN64 + #ifdef WIN_EXPORT + #ifdef __GNUC__ + #define EXPORTED __attribute__ ((dllexport)) + #else + #define EXPORTED __declspec(dllexport) + #endif + #else + #ifdef __GNUC__ + #define EXPORTED __attribute__ ((dllimport)) + #else + #define EXPORTED __declspec(dllimport) + #endif + #endif + #define NOT_EXPORTED +#else + #if __GNUC__ >= 4 + #define EXPORTED __attribute__ ((visibility("default"))) + #define NOT_EXPORTED __attribute__ ((visibility("hidden"))) + #else + #define EXPORTED + #define NOT_EXPORTED + #endif +#endif + +// #ifdef ARCSCRIPTTRANSPILER_EXPORTS +// #define ARCSCRIPTTRANSPILER_API __declspec(dllexport) +// #else +// #define ARCSCRIPTTRANSPILER_API __declspec(dllimport) +// #endif +// #else +// #define ARCSCRIPTTRANSPILER_API +// #endif + +namespace Arcweave +{ + /** + * @enum InputType + * The arscript code types + */ + enum InputType { + /// @brief A condition (results to bool) code type + CONDITION, + /// @brief A script code type + SCRIPT + }; + + /** + * @struct TranspilerOutput + * @brief The structure contains info that the ArcscriptTranspiler returns + * @var TranspilerOutput::output + * Member 'output' contains the text output when a codeblock is run + * @var TranspilerOutput::changes + * Member 'changes' contains the variables that are going to be changed from the codeblock + * @var TranspilerOutput::result + * Member 'result' contains the result of the ArcscriptTranspiler code. Useful in condition blocks + * @var TranspilerOutput::type + * Member 'type' contains the type of the code block i.e. CONDITION or SCRIPT + */ + struct TranspilerOutput { + std::string output; + std::map changes; + std::any result; + InputType type; + }; + + + // The following types starting with a U* are the types that the exported DLL function accepts and returns + extern "C" struct UVariableChange { + char* varId; + VariableType type; + int int_result; + double double_result; + char* string_result; + bool bool_result; + UVariableChange() { + varId = nullptr; + type = VariableType::AW_ANY; + int_result = 0; + double_result = 0.0; + string_result = nullptr; + bool_result = false; + } + }; + + extern "C" struct UTranspilerOutput { + char* output; + InputType type; + UVariableChange* changes; + size_t changesLen = 0; + bool conditionResult = false; + + UTranspilerOutput() { + output = nullptr; + type = InputType::SCRIPT; + changes = nullptr; + changesLen = 0; + conditionResult = false; + } + }; + + + struct UVariable { + const char* id; + const char* name; + VariableType type; + int int_val; + double double_val; + const char* string_val; + bool bool_val; + + UVariable() { + id = nullptr; + name = nullptr; + type = VariableType::AW_ANY; + int_val = 0; + double_val = 0; + string_val = nullptr; + bool_val = false; + } + }; + + struct UVisit { + const char* elId; + int visits; + + UVisit() { + elId = nullptr; + visits = 0; + } + }; + + /** + * Implementation of the Arcscript Transpiler in C++. Uses the ANTLR4 runtime library + * to run the code and it needs the initial variables and the current element ID it is + * transpiling. + * + * + */ + class ArcscriptTranspiler { + public: + + ArcscriptState state; + + ArcscriptTranspiler(std::string elId, std::map initVars, std::map _visits) : state(elId, initVars, _visits) { }; + + /** + * Runs the arcscript code and returns it's results. + * @param code The code block that we need to parse + * @return The result of the ran script + */ + TranspilerOutput runScript(std::string code); + + //ARCSCRIPTTRANSPILER_API UTranspilerOutput URunScript(char* code); + }; +}; +EXPORTED UTranspilerOutput* runScriptExport(const char* code, const char* elId, UVariable* variables, size_t varLength, UVisit* visits, size_t visitsLength); +EXPORTED void deallocateOutput(UTranspilerOutput* output); diff --git a/Cpp/src/ArcscriptVisitor.cpp b/Cpp/src/ArcscriptVisitor.cpp index 986efac..22eef00 100755 --- a/Cpp/src/ArcscriptVisitor.cpp +++ b/Cpp/src/ArcscriptVisitor.cpp @@ -1,461 +1,461 @@ -#include "ArcscriptVisitor.h" -#include "ArcscriptParser.h" - -using namespace Arcweave; - -std::any ArcscriptVisitor::visitInput(ArcscriptParser::InputContext * ctx) -{ - if (ctx->script() != NULL) { - return visitScript(ctx->script()); - } - // Condition - Expression comp_cond = std::any_cast(visitCompound_condition_or(ctx->compound_condition_or())); - return comp_cond.value; -} - -std::any ArcscriptVisitor::visitScript_section(ArcscriptParser::Script_sectionContext *ctx) { - if (ctx == NULL) { - return std::any(); - } - - if (const auto blockquote_contexts = ctx->blockquote(); !blockquote_contexts.empty()) - { - std::vector result; - for (const auto blockquote_context : blockquote_contexts) - { - result.push_back(visitBlockquote(blockquote_context)); - } - return result; - } - - if (const auto paragraph_contexts = ctx->paragraph(); !paragraph_contexts.empty()) - { - std::vector result; - for (const auto paragraph_context : paragraph_contexts) - { - result.push_back(visitParagraph(paragraph_context)); - } - return result; - } - - return visitChildren(ctx); -} - -std::any ArcscriptVisitor::visitBlockquote(ArcscriptParser::BlockquoteContext* context) -{ - state->outputs.AddBlockquote(); - visitChildren(context); - state->outputs.ExitBlockquote(); - return context->getText(); -} - -std::any ArcscriptVisitor::visitParagraph(ArcscriptParser::ParagraphContext* context) -{ - auto paragraph_end = context->PARAGRAPHEND()->getText(); - auto paragraph_content = paragraph_end.substr(0, paragraph_end.size() - 4); // size of "

" - 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 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 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 } }; -} \ No newline at end of file +#include "ArcscriptVisitor.h" +#include "ArcscriptParser.h" + +using namespace Arcweave; + +std::any ArcscriptVisitor::visitInput(ArcscriptParser::InputContext * ctx) +{ + if (ctx->script() != NULL) { + return visitScript(ctx->script()); + } + // Condition + Expression comp_cond = std::any_cast(visitCompound_condition_or(ctx->compound_condition_or())); + return comp_cond.value; +} + +std::any ArcscriptVisitor::visitScript_section(ArcscriptParser::Script_sectionContext *ctx) { + if (ctx == NULL) { + return std::any(); + } + + if (const auto blockquote_contexts = ctx->blockquote(); !blockquote_contexts.empty()) + { + std::vector result; + for (const auto blockquote_context : blockquote_contexts) + { + result.push_back(visitBlockquote(blockquote_context)); + } + return result; + } + + if (const auto paragraph_contexts = ctx->paragraph(); !paragraph_contexts.empty()) + { + std::vector result; + for (const auto paragraph_context : paragraph_contexts) + { + result.push_back(visitParagraph(paragraph_context)); + } + return result; + } + + return visitChildren(ctx); +} + +std::any ArcscriptVisitor::visitBlockquote(ArcscriptParser::BlockquoteContext* context) +{ + state->outputs.AddBlockquote(); + visitChildren(context); + state->outputs.ExitBlockquote(); + return context->getText(); +} + +std::any ArcscriptVisitor::visitParagraph(ArcscriptParser::ParagraphContext* context) +{ + auto paragraph_end = context->PARAGRAPHEND()->getText(); + auto paragraph_content = paragraph_end.substr(0, paragraph_end.size() - 4); // size of "

" + 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 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 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 index c1e2500..4ec0d1e 100755 --- a/Cpp/src/ArcscriptVisitor.h +++ b/Cpp/src/ArcscriptVisitor.h @@ -1,52 +1,52 @@ -#pragma once - -#include "antlr4-runtime.h" -#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; -}; \ No newline at end of file +#pragma once + +#include "antlr4-runtime.h" +#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; +}; From fba09d536c393243bc92918b1f9e42eac00a7c02 Mon Sep 17 00:00:00 2001 From: Emmanouil Dermitzakis Date: Thu, 26 Jun 2025 20:31:42 +0300 Subject: [PATCH 03/31] fix: refactor header includes --- Cpp/src/ArcscriptFunctions.cpp | 1 + Cpp/src/ArcscriptFunctions.h | 2 -- Cpp/src/ArcscriptHelpers.h | 4 ---- Cpp/src/ArcscriptParserBase.cpp | 3 +++ Cpp/src/ArcscriptParserBase.h | 1 - Cpp/src/ArcscriptTranspiler.cpp | 5 ++++- Cpp/src/ArcscriptTranspiler.h | 19 ++++--------------- Cpp/src/ArcscriptVisitor.cpp | 3 +++ Cpp/src/ArcscriptVisitor.h | 1 - 9 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Cpp/src/ArcscriptFunctions.cpp b/Cpp/src/ArcscriptFunctions.cpp index 2bacfa7..83960a4 100755 --- a/Cpp/src/ArcscriptFunctions.cpp +++ b/Cpp/src/ArcscriptFunctions.cpp @@ -1,4 +1,5 @@ #include "ArcscriptFunctions.h" +#include "ArcscriptExpression.h" #include #include #include diff --git a/Cpp/src/ArcscriptFunctions.h b/Cpp/src/ArcscriptFunctions.h index 5886a07..cc2dc59 100755 --- a/Cpp/src/ArcscriptFunctions.h +++ b/Cpp/src/ArcscriptFunctions.h @@ -1,9 +1,7 @@ #pragma once #include "ArcscriptHelpers.h" -#include #include -#include namespace Arcweave { class ArcscriptFunctions { diff --git a/Cpp/src/ArcscriptHelpers.h b/Cpp/src/ArcscriptHelpers.h index 26e85ee..be5576c 100755 --- a/Cpp/src/ArcscriptHelpers.h +++ b/Cpp/src/ArcscriptHelpers.h @@ -1,14 +1,10 @@ #pragma once -#include #include #include -#include #include #include #include -#include "ArcscriptExpression.h" -#include "ArcscriptErrorExceptions.h" #include "ArcscriptOutputs.h" namespace Arcweave { diff --git a/Cpp/src/ArcscriptParserBase.cpp b/Cpp/src/ArcscriptParserBase.cpp index 92e1d4b..50ed267 100755 --- a/Cpp/src/ArcscriptParserBase.cpp +++ b/Cpp/src/ArcscriptParserBase.cpp @@ -1,6 +1,9 @@ #include "ArcscriptParser.h" #include "ArcscriptLexer.h" #include "ArcscriptParserBase.h" +#include "ArcscriptExpression.h" +#include "ArcscriptErrorExceptions.h" +#include "ArcscriptFunctions.h" using namespace antlr4; diff --git a/Cpp/src/ArcscriptParserBase.h b/Cpp/src/ArcscriptParserBase.h index 919c893..bc33945 100755 --- a/Cpp/src/ArcscriptParserBase.h +++ b/Cpp/src/ArcscriptParserBase.h @@ -2,7 +2,6 @@ #include "antlr4-runtime.h" #include "ArcscriptHelpers.h" -#include "ArcscriptFunctions.h" class ArcscriptParserBase : public antlr4::Parser { private: diff --git a/Cpp/src/ArcscriptTranspiler.cpp b/Cpp/src/ArcscriptTranspiler.cpp index 2bffc86..55cb545 100755 --- a/Cpp/src/ArcscriptTranspiler.cpp +++ b/Cpp/src/ArcscriptTranspiler.cpp @@ -1,6 +1,9 @@ #include "ArcscriptTranspiler.h" #include "ArcscriptErrorListener.h" -#include +#include "antlr4-runtime.h" +#include "ArcscriptVisitor.h" +#include "ArcscriptLexer.h" +#include "ArcscriptParser.h" #include #define _CRT_SECURE_NO_WARNINGS diff --git a/Cpp/src/ArcscriptTranspiler.h b/Cpp/src/ArcscriptTranspiler.h index 9cf3cea..0aebda6 100755 --- a/Cpp/src/ArcscriptTranspiler.h +++ b/Cpp/src/ArcscriptTranspiler.h @@ -1,8 +1,6 @@ #pragma once -#include "antlr4-runtime.h" -#include "ArcscriptLexer.h" -#include "ArcscriptParser.h" -#include "ArcscriptVisitor.h" +#include "ArcscriptHelpers.h" +#include "ArcscriptErrorExceptions.h" #if defined _WIN64 #ifdef WIN_EXPORT @@ -29,15 +27,6 @@ #endif #endif -// #ifdef ARCSCRIPTTRANSPILER_EXPORTS -// #define ARCSCRIPTTRANSPILER_API __declspec(dllexport) -// #else -// #define ARCSCRIPTTRANSPILER_API __declspec(dllimport) -// #endif -// #else -// #define ARCSCRIPTTRANSPILER_API -// #endif - namespace Arcweave { /** @@ -160,5 +149,5 @@ namespace Arcweave //ARCSCRIPTTRANSPILER_API UTranspilerOutput URunScript(char* code); }; }; -EXPORTED UTranspilerOutput* runScriptExport(const char* code, const char* elId, UVariable* variables, size_t varLength, UVisit* visits, size_t visitsLength); -EXPORTED void deallocateOutput(UTranspilerOutput* output); +EXPORTED Arcweave::UTranspilerOutput* runScriptExport(const char* code, const char* elId, Arcweave::UVariable* variables, size_t varLength, Arcweave::UVisit* visits, size_t visitsLength); +EXPORTED void deallocateOutput(Arcweave::UTranspilerOutput* output); diff --git a/Cpp/src/ArcscriptVisitor.cpp b/Cpp/src/ArcscriptVisitor.cpp index 22eef00..068ca9c 100755 --- a/Cpp/src/ArcscriptVisitor.cpp +++ b/Cpp/src/ArcscriptVisitor.cpp @@ -1,5 +1,8 @@ +#include "antlr4-runtime.h" #include "ArcscriptVisitor.h" #include "ArcscriptParser.h" +#include "ArcscriptExpression.h" +#include "ArcscriptErrorExceptions.h" using namespace Arcweave; diff --git a/Cpp/src/ArcscriptVisitor.h b/Cpp/src/ArcscriptVisitor.h index 4ec0d1e..2b07166 100755 --- a/Cpp/src/ArcscriptVisitor.h +++ b/Cpp/src/ArcscriptVisitor.h @@ -1,6 +1,5 @@ #pragma once -#include "antlr4-runtime.h" #include "ArcscriptParserBaseVisitor.h" #include "ArcscriptFunctions.h" From 4d1efc2086443f35801a05e84ad6f56297e4b0f7 Mon Sep 17 00:00:00 2001 From: Emmanouil Dermitzakis Date: Tue, 1 Jul 2025 13:49:19 +0300 Subject: [PATCH 04/31] (cpp) fix: library outputs --- Cpp/CMakeLists.txt | 59 +++- Cpp/README.md | 20 ++ Cpp/demo/ArcscriptTest.cpp | 6 +- Cpp/demo/tests/stringConcat.json | 132 --------- Cpp/demo/tests/valid.json | 466 +++++++++++++++++++++++++++++++ 5 files changed, 543 insertions(+), 140 deletions(-) create mode 100644 Cpp/README.md delete mode 100644 Cpp/demo/tests/stringConcat.json create mode 100644 Cpp/demo/tests/valid.json diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index ac74c43..911f827 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -6,6 +6,11 @@ project(ArcscriptTranspiler VERSION ${PROJECT_VERSION}) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) message(CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) + +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) @@ -71,7 +76,17 @@ target_sources(ArcscriptTranspiler PRIVATE target_sources(ArcscriptTranspiler PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.h) -set_target_properties(ArcscriptTranspiler PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION}) +set_target_properties(ArcscriptTranspiler PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION} +) + +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 @@ -83,12 +98,42 @@ endif() target_link_libraries(ArcscriptTranspiler PRIVATE antlr4_shared) -add_executable(ArcscriptTest ${CMAKE_CURRENT_SOURCE_DIR}/demo/ArcscriptTest.cpp) +add_custom_command(TARGET ArcscriptTranspiler POST_BUILD + COMMAND ${CMAKE_COMMAND} + -E copy ${ANTLR4_RUNTIME_LIBRARIES} "$" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +if (NOT EXISTS "$/include") + add_custom_command(TARGET ArcscriptTranspiler POST_BUILD + COMMAND ${CMAKE_COMMAND} + -E make_directory "$/include") +endif() + +add_custom_command(TARGET ArcscriptTranspiler POST_BUILD + COMMAND ${CMAKE_COMMAND} + -E copy ${ARCSCRIPT_INCLUDE_HEADERS} "$/include" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +if (WITH_DEMO) + 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) -include(FetchContent) + file(GLOB TEST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/demo/tests/*.json") -FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz) -FetchContent_MakeAvailable(json) + if (NOT EXISTS "$/tests") + add_custom_command(TARGET ArcscriptTest POST_BUILD + COMMAND ${CMAKE_COMMAND} + -E make_directory "$/tests") + endif() -target_link_libraries(ArcscriptTest PRIVATE nlohmann_json::nlohmann_json) -target_link_libraries(ArcscriptTest PRIVATE ArcscriptTranspiler) + add_custom_command(TARGET ArcscriptTest POST_BUILD + COMMAND ${CMAKE_COMMAND} + -E copy ${TEST_SOURCES} "$/tests" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +endif (WITH_DEMO) \ 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/demo/ArcscriptTest.cpp b/Cpp/demo/ArcscriptTest.cpp index f4fe411..db93908 100644 --- a/Cpp/demo/ArcscriptTest.cpp +++ b/Cpp/demo/ArcscriptTest.cpp @@ -130,7 +130,11 @@ int testFile(std::filesystem::path path) { int main() { - const std::filesystem::path path{ "./stringConcat.json" }; + const std::filesystem::path path{ "./tests/valid.json" }; + if (!std::filesystem::exists(path)) { + std::cout << "File not found: " << path << std::endl; + return 1; + } testFile(path); system("pause"); diff --git a/Cpp/demo/tests/stringConcat.json b/Cpp/demo/tests/stringConcat.json deleted file mode 100644 index eea6992..0000000 --- a/Cpp/demo/tests/stringConcat.json +++ /dev/null @@ -1,132 +0,0 @@ -{ - "initialVars": { - "var1": { - "id": "var1", - "name": "x", - "type": "integer", - "value": 14 - }, - "var2": { - "id": "var2", - "name": "y", - "type": "integer", - "value": 15 - }, - "var3": { - "id": "var3", - "name": "z", - "type": "integer", - "value": 0 - }, - "var4": { - "id": "var4", - "name": "w", - "type": "string", - "value": "Dummy text" - }, - "var5": { - "id": "var5", - "name": "$c5", - "type": "integer", - "value": 0 - }, - "var6": { - "id": "var6", - "name": "_a", - "type": "boolean", - "value": false - }, - "var7": { - "id": "var7", - "name": "xy", - "type": "integer", - "value": -1 - }, - "var8": { - "id": "var8", - "name": "man", - "type": "string", - "value": "Different Text" - } - }, - "cases": [ - { - "code": "
w = \"test\"
w = w + \"ing\"
", - "changes": { - "var4": "testing" - } - }, - { - "code": "
w = \"test\" + \"ing\"
", - "changes": { - "var4": "testing" - } - }, - { - "code": "
w = 0.42 + \"ing\"
", - "changes": { - "var4": "0.42ing" - } - }, - { - "code": "
w = 0.42 + \"\"
", - "changes": { - "var4": "0.42" - } - }, - { - "code": "
w = \"test\" + 44
", - "changes": { - "var4": "test44" - } - }, - { - "code": "
w = \"test\" + false
", - "changes": { - "var4": "testfalse" - } - }, - { - "code": "
w = \"test\" + true + true
", - "changes": { - "var4": "testtruetrue" - } - }, - { - "code": "
w = true + true + \"test\"
", - "changes": { - "var4": "2test" - } - }, - { - "code": "
w += \" test\"
", - "changes": { - "var4": "Dummy text test" - } - }, - { - "code": "
x += \"test\"
", - "changes": { - "var1": "14test" - } - }, - { - "code": "
w += 42
", - "changes": { - "var4": "Dummy text42" - } - }, - { - "code": "
w += _a
", - "changes": { - "var4": "Dummy textfalse" - } - }, - { - "code": "
w += man
", - "changes": { - "var4": "Dummy textDifferent Text" - } - } - ] -} \ No newline at end of file diff --git a/Cpp/demo/tests/valid.json b/Cpp/demo/tests/valid.json new file mode 100644 index 0000000..86ea21a --- /dev/null +++ b/Cpp/demo/tests/valid.json @@ -0,0 +1,466 @@ +{ + "initialVars": { + "var1": { + "id": "var1", + "name": "x", + "type": "integer", + "value": 14 + }, + "var2": { + "id": "var2", + "name": "y", + "type": "integer", + "value": 15 + }, + "var3": { + "id": "var3", + "name": "z", + "type": "integer", + "value": 0 + }, + "var4": { + "id": "var4", + "name": "w", + "type": "string", + "value": "Dummy text" + }, + "var5": { + "id": "var5", + "name": "$c5", + "type": "integer", + "value": 0 + }, + "var6": { + "id": "var6", + "name": "_a", + "type": "boolean", + "value": false + }, + "var7": { + "id": "var7", + "name": "xy", + "type": "integer", + "value": -1 + }, + "var8": { + "id": "var8", + "name": "man", + "type": "string", + "value": "Different Text" + } + }, + "cases": [ + { + "code": "
x=5
", + "changes": { + "var1": 5 + } + }, + { + "code": "
x=-5
", + "changes": { + "var1": -5 + } + }, + { + "code": "
x=5.23
", + "changes": { + "var1": 5.23 + } + }, + { + "code": "
x=3
y=2
", + "changes": { + "var1": 3, + "var2": 2 + } + }, + { + "code": "
x=\"test\"
", + "changes": { + "var1": "test" + } + }, + { + "code": "
x=true
", + "changes": { + "var1": true + } + }, + { + "code": "
x = y
", + "changes": { + "var1": 15 + } + }, + { + "code": "
x = 5 + 3
", + "changes": { + "var1": 8 + } + }, + { + "code": "
x = 3 / 4 * 5
", + "changes": { + "var1": 3.75 + } + }, + { + "code": "
x = 3 / 4 / 5
", + "changes": { + "var1": 0.15 + } + }, + { + "code": "
x = sqr(2)
", + "changes": { + "var1": 4 + } + }, + { + "code": "
x = 3 > 2
", + "changes": { + "var1": true + } + }, + { + "code": "
x = 3 >= 2
", + "changes": { + "var1": true + } + }, + { + "code": "
x = 3 < 2
", + "changes": { + "var1": false + } + }, + { + "code": "
x = 3 <= 2
", + "changes": { + "var1": false + } + }, + { + "code": "
x = 3 == 2
", + "changes": { + "var1": false + } + }, + { + "code": "
x = 3 != 2
", + "changes": { + "var1": true + } + }, + { + "code": "
_a = !(3 == 2)
", + "changes": { + "var6": true + } + }, + { + "code": "
_a = not (3 == 2)
", + "changes": { + "var6": true + } + }, + { + "code": "
x = !0
", + "changes": { + "var1": true + } + }, + { + "code": "
x = true || false
", + "changes": { + "var1": true + } + }, + { + "code": "
x = true && false
", + "changes": { + "var1": false + } + }, + { + "code": "
x = -3
y = y + 3
z = sqr(x)
", + "changes": { + "var1": -3, + "var2": 18, + "var3": 9 + } + }, + { + "code": "
x = sqrt(y + 2)
", + "changes": { + "var1": 4.123105625617661 + } + }, + { + "code": "
x = z + 12 == 4 * 3
", + "changes": { + "var1": true + } + }, + { + "code": "
x = y == 15 && !(z == 1)
", + "changes": { + "var1": true + } + }, + { + "code": "
x = (x*x + 3)/y
", + "changes": { + "var1": 13.266666666666667 + } + }, + { + "code": "
x = x*(x + 1)/y
", + "changes": { + "var1": 14 + } + }, + { + "code": "
x += 2
", + "changes": { + "var1": 16 + } + }, + { + "code": "
x -= 2
", + "changes": { + "var1": 12 + } + }, + { + "code": "
x *= 2
", + "changes": { + "var1": 28 + } + }, + { + "code": "
x /= 2
", + "changes": { + "var1": 7 + } + }, + { + "code": "
x = abs(-6)
", + "changes": { + "var1": 6 + } + }, + { + "code": "
x = min(5, -y, 2.3)
", + "changes": { + "var1": -15 + } + }, + { + "code": "
x = max(5, -y, 2.3)
", + "changes": { + "var1": 5 + } + }, + { + "code": "
x = random()
", + "changes": {} + }, + { + "code": "
x = roll(6)
", + "changes": {} + }, + { + "code": "
x = roll(6, 5)
", + "changes": {} + }, + { + "code": "
x = roll(y)
", + "changes": {} + }, + { + "code": "
x = round(2.65)
", + "changes": { + "var1": 3 + } + }, + { + "code": "
show(\"x is \", x)
", + "changes": {}, + "output": "

x is 14

" + }, + { + "code": "
y = 33
reset(y)
", + "changes": { + "var2": 15 + } + }, + { + "code": "
x = 16
y = 33
resetAll(y)
", + "changes": { + "var1": 14, + "var2": 33, + "var3": 0, + "var4": "Dummy text", + "var5": 0, + "var6": false, + "var7": -1, + "var8": "Different Text" + } + }, + { + "code": "
$c5 = x
", + "changes": { + "var5": 14 + } + }, + { + "code": "
if (x==14) 
x=5
endif
", + "changes": { + "var1": 5 + } + }, + { + "code": "
if (x==11)
x=5
else
x=7
endif
", + "changes": { + "var1": 7 + } + }, + { + "code": "
if x==3
x=5
elseif x==14
x=2
else
x = 0
endif
", + "changes": { + "var1": 2 + } + }, + { + "code": "

Mein gott!

x = 1

What is that?

", + "changes": { + "var1": 1 + }, + "output": "

Mein gott! What is that?

" + }, + { + "code": "

Hello my dear

if x == 1

We might ride to the mountains.

endif
", + "changes": {}, + "output": "

Hello my dear

" + }, + { + "code": "

You carry

if x == 12

a small knife

elseif y == 12

a large sword

elseif z == 1

just a rotten tomato

else

nothing really

endif
", + "changes": {}, + "output": "

You carry nothing really

" + }, + { + "code": "

How are you?

x = 1

I am fine, thank you.

", + "changes": {}, + "output": "

How are you?

I am fine, thank you.

" + }, + { + "code": "
show(\"Hello friends:\", x)
", + "changes": {}, + "output": "

Hello friends:14

" + }, + { + "code": "
_a = true
if (((_a)))
x = 1
endif
", + "changes": { + "var1": 1, + "var6": true + } + }, + { + "code": "
visits() == 1
", + "visits": { + "a": 1, + "b": 1, + "c": 0 + }, + "elementId": "b", + "result": true + }, + { + "code": "
visits(Untitled Comp) == 9
", + "visits": { + "a": 1, + "b": 1, + "c": 0 + }, + "elementId": "b", + "result": false + }, + { + "code": "

this

text

must

not

be

in

one

paragraph

", + "output": "

this

text

must

not

be

in

one

paragraph

" + }, + { + "code": "

three

separate

lines

just

show(\"one\")
show(\"and\")
show(\"single\")

line

three

more

lines

", + "output": "

three

separate

lines

just one and single line

three

more

lines

" + }, + { + "code": "

This is a blockquote

if x

This is a separate line

endif

This is another blockquote

", + "output": "

This is a blockquote

This is a separate line

This is another blockquote

" + }, + { + "code": "

This is a blockquote

show(x)

test

", + "output": "

This is a blockquote 14

test

" + }, + { + "code": "

This is a blockquote

show(x)

test

", + "output": "

This is a blockquote 14 test

" + }, + { + "code": "

one

if true

two

endif

three

", + "output": "

one

two

three

" + }, + { + "code": "

one

if true

two

endif

three

", + "output": "

one two

three

" + }, + { + "code": "

one

if true

two

endif

three

", + "output": "

one two

three

" + }, + { + "code": "

one

if true
show(x)
endif

three

", + "output": "

one 14

three

" + }, + { + "code": "

one

if true

two

test

four

endif

three

", + "output": "

one two

test

four

three

" + }, + { + "code": "

one

if true

two

test

show(\"four\")
endif

three

", + "output": "

one two

test four

three

" + }, + { + "code": "

one

if false

two

endif

three

", + "output": "

one

three

" + }, + { + "code": "

This is a blockquote

if true

Second blockquote

Separate Line

endif

Outside blockquote

", + "output": "

This is a blockquote

Second blockquote

Separate Line

Outside blockquote

" + }, + { + "code": "

Test

_a = true

this

", + "output": "

Test this

", + "changes": { + "var6": true + } + }, + { + "code": "

Test

show(x)

this

", + "output": "

Test 14 this

" + }, + { + "code": "

this is a test

show(x)

continue

testing

", + "output": "

this is a test

14 continue

testing

" + }, + { + "code": "

This is a test

Manolis

inside blockquotes

if true

John

endif
", + "output": "

This is a test

Manolis

inside blockquotes

John

" + }, + { + "code": "
w = \"String with \\\"quotes\\\" \\t tabs and \\n new lines\"
show(w)
", + "output": "

String with \"quotes\" \t tabs and \n new lines

" + } + ] +} \ No newline at end of file From 7aac76be14d90c18bf14171952005d07e484641b Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Tue, 1 Jul 2025 14:05:01 +0300 Subject: [PATCH 05/31] (cpp) fix: strdup imports --- Cpp/demo/ArcscriptTest.cpp | 21 +++++++++++++-------- Cpp/src/ArcscriptErrorExceptions.h | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Cpp/demo/ArcscriptTest.cpp b/Cpp/demo/ArcscriptTest.cpp index db93908..63f54eb 100644 --- a/Cpp/demo/ArcscriptTest.cpp +++ b/Cpp/demo/ArcscriptTest.cpp @@ -10,6 +10,10 @@ #include #include "ArcscriptTranspiler.h" +#ifdef _WIN64 +#define strdup _strdup +#endif + using json = nlohmann::json; using namespace Arcweave; @@ -22,8 +26,8 @@ UVariable* getInitialVars(json initialVarsJson) { std::string name = it.value()["name"].template get(); std::string type = it.value()["type"].template get(); - initVars[i].id = _strdup(id.c_str()); - initVars[i].name = _strdup(name.c_str()); + initVars[i].id = strdup(id.c_str()); + initVars[i].name = strdup(name.c_str()); initVars[i].type = VariableType::AW_ANY; if (type == "string") { initVars[i].type = VariableType::AW_STRING; @@ -39,7 +43,7 @@ UVariable* getInitialVars(json initialVarsJson) { } if (initVars[i].type == VariableType::AW_STRING) { - initVars[i].string_val = _strdup(it.value()["value"].template get().c_str()); + initVars[i].string_val = strdup(it.value()["value"].template get().c_str()); } else if (initVars[i].type == VariableType::AW_INTEGER) { initVars[i].int_val = it.value()["value"].template get(); @@ -61,7 +65,7 @@ UVisit* getVisits(json initVisits) { UVisit* visits = new UVisit[initVisits.size()]; int i = 0; for (json::iterator it = initVisits.begin(); it != initVisits.end(); ++it) { - visits[i].elId = _strdup(it.key().c_str()); + visits[i].elId = strdup(it.key().c_str()); visits[i].visits = it.value().template get(); i += 1; } @@ -76,15 +80,15 @@ int testFile(std::filesystem::path path) { UVariable* initVars = getInitialVars(initVarsJson); size_t initVarLen = initVarsJson.size(); for (json::iterator it = data["cases"].begin(); it != data["cases"].end(); ++it) { - const char* code = _strdup((*it)["code"].template get().c_str()); + const char* code = strdup((*it)["code"].template get().c_str()); UVisit* visits = nullptr; size_t visitsLen = 0; const char* currentElement = nullptr; if ((*it).contains("elementId")) { - currentElement = _strdup((*it)["elementId"].template get().c_str()); + currentElement = strdup((*it)["elementId"].template get().c_str()); } else { - currentElement = _strdup("TestElement"); + currentElement = strdup("TestElement"); } if ((*it).contains("visits")) { visits = getVisits((*it)["visits"]); @@ -137,5 +141,6 @@ int main() } testFile(path); - system("pause"); + system( "read -n 1 -s -p \"Press any key to continue...\"" ); + } \ No newline at end of file diff --git a/Cpp/src/ArcscriptErrorExceptions.h b/Cpp/src/ArcscriptErrorExceptions.h index d73e98f..058d112 100755 --- a/Cpp/src/ArcscriptErrorExceptions.h +++ b/Cpp/src/ArcscriptErrorExceptions.h @@ -46,7 +46,7 @@ namespace Arcweave { if (line > -1) { std::ostringstream oss; oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; - return oss.str().c_str(); + return strdup(oss.str().c_str()); } return message.c_str(); } From b2a15d699445810404f48e9234ec781b3c2e5944 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Tue, 1 Jul 2025 20:45:00 +0300 Subject: [PATCH 06/31] (cpp) fix: mac build --- Cpp/CMakeLists.txt | 74 +++++++++++++++++------------- Cpp/src/ArcscriptErrorExceptions.h | 2 +- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index 911f827..5eac8fa 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -32,31 +32,9 @@ include(ExternalAntlr4Cpp) # add antlr4cpp artifacts to project environment include_directories(${ANTLR4_INCLUDE_DIRS}) -## set variable pointing to the antlr tool that supports C++ -## this is not required if the jar file can be found under PATH environment -#set(ANTLR_EXECUTABLE /home/user/antlr-4.13.2-complete.jar) -## add macros to generate ANTLR Cpp code from grammar -#find_package(ANTLR REQUIRED) -# -## Call macro to add lexer and grammar to your build dependencies. -#antlr_target(SampleGrammarLexer TLexer.g4 LEXER -# PACKAGE antlrcpptest) -#antlr_target(SampleGrammarParser TParser.g4 PARSER -# PACKAGE antlrcpptest -# DEPENDS_ANTLR SampleGrammarLexer -# COMPILE_FLAGS -lib ${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) - -# include generated files in project environment -#include_directories(${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) -#include_directories(${ANTLR_SampleGrammarParser_OUTPUT_DIR}) - include_directories(src/Generated/ArcscriptLexer) include_directories(src/Generated/ArcscriptParser) include_directories(src) -# add generated grammar to demo binary target -#add_executable(demo main.cpp -# src/Generated/ArcscriptLexer -# src/Generated/ArcscriptParser) add_library(ArcscriptTranspiler SHARED) @@ -76,11 +54,6 @@ target_sources(ArcscriptTranspiler PRIVATE target_sources(ArcscriptTranspiler PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.h) -set_target_properties(ArcscriptTranspiler PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION} -) - set(ARCSCRIPT_INCLUDE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptTranspiler.h ${CMAKE_CURRENT_SOURCE_DIR}/src/ArcscriptHelpers.h @@ -98,20 +71,50 @@ endif() target_link_libraries(ArcscriptTranspiler PRIVATE antlr4_shared) -add_custom_command(TARGET ArcscriptTranspiler POST_BUILD +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}/bin/${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} "$" + -E copy ${ANTLR4_RUNTIME_LIBRARIES} "$" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -if (NOT EXISTS "$/include") +# 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 "$/include") + -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} "$/include" + -E copy ${ARCSCRIPT_INCLUDE_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/lib/include" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) if (WITH_DEMO) @@ -124,6 +127,13 @@ if (WITH_DEMO) 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") diff --git a/Cpp/src/ArcscriptErrorExceptions.h b/Cpp/src/ArcscriptErrorExceptions.h index 058d112..d3f3bf4 100755 --- a/Cpp/src/ArcscriptErrorExceptions.h +++ b/Cpp/src/ArcscriptErrorExceptions.h @@ -23,7 +23,7 @@ namespace Arcweave { if (line > -1) { std::ostringstream oss; oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; - return oss.str().c_str(); + return strdup(oss.str().c_str()); } return message.c_str(); } From 3295ff116ef772c4236ae01398ed9972440264b4 Mon Sep 17 00:00:00 2001 From: Emmanouil Dermitzakis Date: Fri, 4 Jul 2025 15:08:04 +0300 Subject: [PATCH 07/31] (cpp) fix: transpiler expression evaluation & tests --- Cpp/CMakeLists.txt | 19 ++- Cpp/demo/ArcscriptTest.cpp | 264 ++++++++++++++++++++++++----- Cpp/demo/tests/conditions.json | 100 +++++++++++ Cpp/demo/tests/parseErrors.json | 96 +++++++++++ Cpp/demo/tests/runtimeErrors.json | 72 ++++++++ Cpp/demo/tests/stringConcat.json | 132 +++++++++++++++ Cpp/demo/tests/valid.json | 12 ++ Cpp/src/ArcscriptErrorExceptions.h | 13 +- Cpp/src/ArcscriptExpression.cpp | 72 +++++--- Cpp/src/ArcscriptFunctions.cpp | 69 +++++++- Cpp/src/ArcscriptOutputs.h | 10 +- Cpp/src/ArcscriptParserBase.cpp | 4 +- Cpp/src/ArcscriptParserBase.h | 2 +- Cpp/src/ArcscriptVisitor.cpp | 2 + 14 files changed, 785 insertions(+), 82 deletions(-) create mode 100644 Cpp/demo/tests/conditions.json create mode 100644 Cpp/demo/tests/parseErrors.json create mode 100644 Cpp/demo/tests/runtimeErrors.json create mode 100644 Cpp/demo/tests/stringConcat.json diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index 5eac8fa..82f6447 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -90,7 +90,7 @@ 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}/bin/${PLATFORM}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/${PLATFORM}" OUTPUT_NAME ${PROJECT_NAME} ) @@ -146,4 +146,21 @@ if (WITH_DEMO) COMMAND ${CMAKE_COMMAND} -E copy ${TEST_SOURCES} "$/tests" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + set(ARCSCRIPT_TRANSPILER_LIB_FILES + "$/${DLL_NAME}" + "$/${LIBRARY_NAME}" + "$/${PROJECT_NAME}.exp" + "$/${PROJECT_NAME}.pdb" + ) + + 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_DEMO) \ No newline at end of file diff --git a/Cpp/demo/ArcscriptTest.cpp b/Cpp/demo/ArcscriptTest.cpp index 63f54eb..93c869d 100644 --- a/Cpp/demo/ArcscriptTest.cpp +++ b/Cpp/demo/ArcscriptTest.cpp @@ -60,6 +60,26 @@ UVariable* getInitialVars(json initialVarsJson) { return initVars; } +std::map getExpectedChanges(json changes) { + std::map expectedChanges; + + for (json::iterator it = changes.begin(); it != changes.end(); ++it) { + std::string varId = it.key(); + json value = it.value(); + + if (value.type() == json::value_t::string) { + expectedChanges[varId] = value.template get(); + } + else if (value.type() == json::value_t::number_float || value.type() == json::value_t::number_integer) { + expectedChanges[varId] = value.template get(); + } + else if (value.type() == json::value_t::boolean) { + expectedChanges[varId] = value.template get(); + } + } + return expectedChanges; +} + UVisit* getVisits(json initVisits) { if (initVisits.size() == 0) return nullptr; UVisit* visits = new UVisit[initVisits.size()]; @@ -72,75 +92,231 @@ UVisit* getVisits(json initVisits) { return visits; } -int testFile(std::filesystem::path path) { - std::ifstream f(path); - json data = json::parse(f); - // ssstd::cout << data << std::endl; - json initVarsJson = data["initialVars"]; - UVariable* initVars = getInitialVars(initVarsJson); - size_t initVarLen = initVarsJson.size(); - for (json::iterator it = data["cases"].begin(); it != data["cases"].end(); ++it) { - const char* code = strdup((*it)["code"].template get().c_str()); - UVisit* visits = nullptr; - size_t visitsLen = 0; - const char* currentElement = nullptr; - if ((*it).contains("elementId")) { - currentElement = strdup((*it)["elementId"].template get().c_str()); +std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t initVarLen) { + std::stringstream errorOutput; + + const char* code = strdup(testCase["code"].template get().c_str()); + UVisit* visits = nullptr; + size_t visitsLen = 0; + const char* currentElement = nullptr; + if (testCase.contains("elementId")) { + currentElement = strdup(testCase["elementId"].template get().c_str()); + } + else { + currentElement = strdup("TestElement"); + } + if (testCase.contains("visits")) { + visits = getVisits(testCase["visits"]); + visitsLen = testCase["visits"].size(); + } + + bool hasError = false; + std::string errorType = ""; + if (testCase.contains("error")) { + hasError = true; + errorType = testCase["error"].template get(); + } + UTranspilerOutput* result = nullptr; + try { + result = runScriptExport(code, currentElement, initVars, initVarLen, visits, visitsLen); + } catch (RuntimeErrorException &e) { + if (!hasError) { + errorOutput << "Unexpected Runtime Error: " << e.what() << std::endl; + } else { + if (errorType != "runtime") { + errorOutput << "Received Runtime Error: " << e.what() << std::endl; + } } - else { - currentElement = strdup("TestElement"); + } catch (ParseErrorException &e) { + if (!hasError) { + errorOutput << "Unexpected Parse Error: " << e.what() << std::endl; + } else { + if (errorType != "parse") { + errorOutput << "Received Parse Error: " << e.what() << std::endl; + } } - if ((*it).contains("visits")) { - visits = getVisits((*it)["visits"]); - visitsLen = (*it)["visits"].size(); + } catch (std::exception &e) { + if (!hasError) { + errorOutput << "Unexpected Exception: " << e.what() << std::endl; + } else { + if (errorType != "exception") { + errorOutput << "Received Exception: " << e.what() << std::endl; + } } - bool hasError = false; - if ((*it).contains("error")) { - hasError = true; + } + + if (result == nullptr) { + std::stringstream temp; + + if (errorOutput.str().length() > 0) { + temp << "Test case " << caseIndex << " failed: \"" << code << "\"" << std::endl << errorOutput.rdbuf(); + errorOutput.swap(temp); } + return errorOutput.str(); + } - UTranspilerOutput* result = runScriptExport(code, currentElement, initVars, initVarLen, visits, visitsLen); - if ((*it).contains("output")) + if (hasError) { + errorOutput << "Test case " << caseIndex << " failed: \"" << code << "\"" << std::endl; + errorOutput << "Expected error of type: " << errorType << " but no error thrown." << std::endl; + + return errorOutput.str(); + } + + if (testCase.contains("output")) + { + std::string output = testCase["output"].template get(); + if (output.compare(result->output) != 0) { - std::string output = (*it)["output"].template get(); - if (output.compare(result->output) != 0) - { - std::cout << "DIFFERENT" << std::endl; - std::cout << "EXPECTED: \"" << output << "\"" << std::endl << "ACTUAL: \"" << result->output << "\"" << std::endl; + errorOutput << "Different Text Output" << std::endl; + errorOutput << "EXPECTED:\t\"" << output << "\"" << std::endl << "ACTUAL:\t\t\"" << result->output << "\"" << std::endl; + } + } + + if (testCase.contains("changes")) { + json changes = testCase["changes"]; + + for (json::iterator it = changes.begin(); it != changes.end(); ++it) { + std::string expectedChangeKey = it.key(); + json expectedChangeValue = it.value(); + UVariableChange change; + bool found = false; + for (int i = 0; i < result->changesLen; i++) { + if (result->changes[i].varId == expectedChangeKey) { + change = result->changes[i]; + found = true; + break; + } + } + if (!found) { + errorOutput << "Variable change not found: " << expectedChangeKey << ": " << expectedChangeValue << std::endl; + continue; + } + + if (change.type == VariableType::AW_STRING) { + std::string expectedValue = expectedChangeValue.template get(); + if (expectedValue.compare(change.string_result) != 0) { + errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected \"" << expectedValue << "\", got \"" << change.string_result << "\"" << std::endl; + } + } else if (change.type == VariableType::AW_INTEGER) { + int expectedValue = expectedChangeValue.template get(); + if (expectedValue != change.int_result) { + errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected " << expectedValue << ", got " << change.int_result << std::endl; + } + } else if (change.type == VariableType::AW_DOUBLE) { + double expectedValue = expectedChangeValue.template get(); + if (expectedValue != change.double_result) { + errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected " << expectedValue << ", got " << change.double_result << std::endl; + } + } else if (change.type == VariableType::AW_BOOLEAN) { + bool expectedValue = expectedChangeValue.template get(); + if (expectedValue != change.bool_result) { + errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected " << expectedValue << ", got " << change.bool_result << std::endl; + } } } + } - deallocateOutput(result); + if (testCase.contains("result")) { + bool expectedResult = testCase["result"].template get(); + if (result->conditionResult != expectedResult) { + errorOutput << "Condition result mismatch: expected " << expectedResult << ", got " << result->conditionResult << std::endl; + } + } - /*for (int i = 0; i < visitsLen; i++) { + if (visits != nullptr) { + for (int i = 0; i < visitsLen; i++) { free((char*)visits[i].elId); } delete visits; - free((char*)currentElement); - free((char*)code);*/ } - /*for (int j = 0; j < initVarLen; j++) { + free(const_cast(currentElement)); + free(const_cast(code)); + + deallocateOutput(result); + + std::stringstream temp; + + if (errorOutput.str().length() > 0) { + temp << "Test case " << caseIndex << " failed: \"" << code << "\"" << std::endl << errorOutput.rdbuf(); + errorOutput.swap(temp); + } + + return errorOutput.str(); +} + +int testFile(std::filesystem::path path, int testIndex = -1) { + std::ifstream f(path); + json data = json::parse(f); + + std::cout << "Testing file: " << path; + + json initVarsJson = data["initialVars"]; + UVariable* initVars = getInitialVars(initVarsJson); + size_t initVarLen = initVarsJson.size(); + size_t casesLen = data["cases"].size(); + size_t caseIndex = 0; + + if (testIndex >= 0) { + std::string errorOutput = test(data["cases"][testIndex], testIndex, initVars, initVarLen); + + if (errorOutput.length() > 0) { + std::cout << errorOutput << std::endl; + } + + return 0; + } + + bool fileError = false; + for (json::iterator it = data["cases"].begin(); it != data["cases"].end(); ++it) { + + json testCase = *it; + + std::string errorOutput = test(testCase, caseIndex, initVars, initVarLen); + + if (errorOutput.length() > 0) { + fileError = true; + std::cout << std::endl << errorOutput; + } + caseIndex += 1; + } + + if (!fileError) { + std::cout << "\t\t\tSuccess" << std::endl; + } else { + std::cout << std::endl; + } + + + + for (int j = 0; j < initVarLen; j++) { free((char*)initVars[j].id); free((char*)initVars[j].name); if (initVars[j].type == VariableType::AW_STRING) { free((char*)initVars[j].string_val); } } - delete initVars;*/ + delete initVars; return 0; } -int main() +int main(int argc, char* argv[]) { - const std::filesystem::path path{ "./tests/valid.json" }; - if (!std::filesystem::exists(path)) { - std::cout << "File not found: " << path << std::endl; - return 1; - } - testFile(path); - - system( "read -n 1 -s -p \"Press any key to continue...\"" ); + // Create an array of the test path files + std::vector testPaths = { + "./tests/valid.json", + "./tests/conditions.json", + "./tests/stringConcat.json", + "./tests/runtimeErrors.json", + "./tests/parseErrors.json", + }; + for (auto path : testPaths) { + if (!std::filesystem::exists(path)) { + std::cout << "File not found: " << path << std::endl; + continue; + } + testFile(path); + } } \ No newline at end of file diff --git a/Cpp/demo/tests/conditions.json b/Cpp/demo/tests/conditions.json new file mode 100644 index 0000000..88331f1 --- /dev/null +++ b/Cpp/demo/tests/conditions.json @@ -0,0 +1,100 @@ +{ + "initialVars": { + "var1": { + "id": "var1", + "name": "x", + "type": "integer", + "value": 14 + }, + "var2": { + "id": "var2", + "name": "y", + "type": "integer", + "value": 15 + }, + "var3": { + "id": "var3", + "name": "z", + "type": "integer", + "value": 0 + }, + "var4": { + "id": "var4", + "name": "w", + "type": "string", + "value": "Dummy text" + }, + "var5": { + "id": "var5", + "name": "$c5", + "type": "integer", + "value": 0 + }, + "var6": { + "id": "var6", + "name": "_a", + "type": "boolean", + "value": false + }, + "var7": { + "id": "var7", + "name": "xy", + "type": "integer", + "value": -1 + } + }, + "cases": [ + { + "code": "
x >= 14
", + "result": true + }, + { + "code": "
x == 14
", + "result": true + }, + { + "code": "
x is 14
", + "result": true + }, + { + "code": "
x == 45
", + "result": false + }, + { + "code": "
x is 45
", + "result": false + }, + { + "code": "
x == 14 && y == 15
", + "result": true + }, + { + "code": "
x == 14 and y == 15
", + "result": true + }, + { + "code": "
x == 3 || y != 0
", + "result": true + }, + { + "code": "
x == 3 or y != 0
", + "result": true + }, + { + "code": "
w == \"Dummy text\"
", + "result": true + }, + { + "code": "
w != \"Dummy text\"
", + "result": false + }, + { + "code": "
w is not \"Dummy text\"
", + "result": false + }, + { + "code": "
x is not \"Dummy text\"
", + "result": true + } + ] +} \ No newline at end of file diff --git a/Cpp/demo/tests/parseErrors.json b/Cpp/demo/tests/parseErrors.json new file mode 100644 index 0000000..07d79d9 --- /dev/null +++ b/Cpp/demo/tests/parseErrors.json @@ -0,0 +1,96 @@ +{ + "initialVars": { + "var1": { + "id": "var1", + "name": "x", + "type": "integer", + "value": 14 + }, + "var2": { + "id": "var2", + "name": "y", + "type": "integer", + "value": 15 + }, + "var3": { + "id": "var3", + "name": "z", + "type": "integer", + "value": 0 + }, + "var4": { + "id": "var4", + "name": "w", + "type": "string", + "value": "Dummy text" + }, + "var5": { + "id": "var5", + "name": "$c5", + "type": "integer", + "value": 0 + }, + "var6": { + "id": "var6", + "name": "_a", + "type": "boolean", + "value": false + }, + "var7": { + "id": "var7", + "name": "xy", + "type": "integer", + "value": -1 + } + }, + "cases": [ + { + "code": "
p = 1
", + "error": "parse" + }, + { + "code": "
x = p
", + "error": "parse" + }, + { + "code": "
show(x, y, z, abc)
", + "error": "parse" + }, + { + "code": "
testFunction(x, y)
", + "error": "parse" + }, + { + "code": "
x = 1;
", + "error": "parse" + }, + { + "code": "
We want to be friends
", + "error": "parse" + }, + { + "code": "
x = sqr()
", + "error": "parse" + }, + { + "code": "
x = random(2)
", + "error": "parse" + }, + { + "code": "
y = 33
reset(13)
", + "error": "parse" + }, + { + "code": "
ελληνικά
", + "error": "parse" + }, + { + "code": "
visits(Untitled Comp) == 9
", + "error": "parse" + }, + { + "code": "

Test

if true

inside

endif

this

", + "error": "parse" + } + ] +} \ No newline at end of file diff --git a/Cpp/demo/tests/runtimeErrors.json b/Cpp/demo/tests/runtimeErrors.json new file mode 100644 index 0000000..2f4924a --- /dev/null +++ b/Cpp/demo/tests/runtimeErrors.json @@ -0,0 +1,72 @@ +{ + "initialVars": { + "var1": { + "id": "var1", + "name": "x", + "type": "integer", + "value": 14 + }, + "var2": { + "id": "var2", + "name": "y", + "type": "integer", + "value": 15 + }, + "var3": { + "id": "var3", + "name": "z", + "type": "integer", + "value": 0 + }, + "var4": { + "id": "var4", + "name": "w", + "type": "string", + "value": "Dummy text" + }, + "var5": { + "id": "var5", + "name": "$c5", + "type": "integer", + "value": 0 + }, + "var6": { + "id": "var6", + "name": "_a", + "type": "boolean", + "value": false + }, + "var7": { + "id": "var7", + "name": "xy", + "type": "integer", + "value": -1 + } + }, + "cases": [ + { + "code": "
x = sqrt(-3)
", + "error": "runtime" + }, + { + "code": "
x = 3 / 0
", + "error": "runtime" + }, + { + "code": "
x = roll(\"2\")
", + "error": "runtime" + }, + { + "code": "
w = \"2\" - \"test\"
", + "error": "runtime" + }, + { + "code": "
w = w - \"test\"
", + "error": "runtime" + }, + { + "code": "
w -= _a
", + "error": "runtime" + } + ] +} \ No newline at end of file diff --git a/Cpp/demo/tests/stringConcat.json b/Cpp/demo/tests/stringConcat.json new file mode 100644 index 0000000..d9b3503 --- /dev/null +++ b/Cpp/demo/tests/stringConcat.json @@ -0,0 +1,132 @@ +{ + "initialVars": { + "var1": { + "id": "var1", + "name": "x", + "type": "integer", + "value": 14 + }, + "var2": { + "id": "var2", + "name": "y", + "type": "integer", + "value": 15 + }, + "var3": { + "id": "var3", + "name": "z", + "type": "integer", + "value": 0 + }, + "var4": { + "id": "var4", + "name": "w", + "type": "string", + "value": "Dummy text" + }, + "var5": { + "id": "var5", + "name": "$c5", + "type": "integer", + "value": 0 + }, + "var6": { + "id": "var6", + "name": "_a", + "type": "boolean", + "value": false + }, + "var7": { + "id": "var7", + "name": "xy", + "type": "integer", + "value": -1 + }, + "var8": { + "id": "var8", + "name": "man", + "type": "string", + "value": "Different Text" + } + }, + "cases": [ + { + "code": "
w = \"test\"
w = w + \"ing\"
", + "changes": { + "var4": "testing" + } + }, + { + "code": "
w = \"test\" + \"ing\"
", + "changes": { + "var4": "testing" + } + }, + { + "code": "
w = 0.42 + \"ing\"
", + "changes": { + "var4": "0.42ing" + } + }, + { + "code": "
w = 0.42 + \"\"
", + "changes": { + "var4": "0.42" + } + }, + { + "code": "
w = \"test\" + 44
", + "changes": { + "var4": "test44" + } + }, + { + "code": "
w = \"test\" + false
", + "changes": { + "var4": "testfalse" + } + }, + { + "code": "
w = \"test\" + true + true
", + "changes": { + "var4": "testtruetrue" + } + }, + { + "code": "
w = true + true + \"test\"
", + "changes": { + "var4": "2test" + } + }, + { + "code": "
w += \" test\"
", + "changes": { + "var4": "Dummy text test" + } + }, + { + "code": "
x += \"test\"
", + "changes": { + "var1": "14test" + } + }, + { + "code": "
w += 42
", + "changes": { + "var4": "Dummy text42" + } + }, + { + "code": "
w += _a
", + "changes": { + "var4": "Dummy textfalse" + } + }, + { + "code": "
w += man
", + "changes": { + "var4": "Dummy textDifferent Text" + } + } + ] +} \ No newline at end of file diff --git a/Cpp/demo/tests/valid.json b/Cpp/demo/tests/valid.json index 86ea21a..6df3bb8 100644 --- a/Cpp/demo/tests/valid.json +++ b/Cpp/demo/tests/valid.json @@ -105,6 +105,18 @@ "var1": 3.75 } }, + { + "code": "
x = 3 + 4 * 5
", + "changes": { + "var1": 23 + } + }, + { + "code": "
x = 3 * 4 + 5
", + "changes": { + "var1": 17 + } + }, { "code": "
x = 3 / 4 / 5
", "changes": { diff --git a/Cpp/src/ArcscriptErrorExceptions.h b/Cpp/src/ArcscriptErrorExceptions.h index d3f3bf4..76cd04d 100755 --- a/Cpp/src/ArcscriptErrorExceptions.h +++ b/Cpp/src/ArcscriptErrorExceptions.h @@ -9,8 +9,8 @@ namespace Arcweave { class RuntimeErrorException : public std::exception { public: std::string message; - int line = -1; - int charPositionInLine = -1; + size_t line = 0; + size_t charPositionInLine = 0; RuntimeErrorException(std::string msg) { message = msg; }; @@ -20,7 +20,7 @@ namespace Arcweave { charPositionInLine = _charPositionInLine; }; char const* what() const noexcept override { - if (line > -1) { + if (line > 0) { std::ostringstream oss; oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; return strdup(oss.str().c_str()); @@ -32,8 +32,8 @@ namespace Arcweave { class ParseErrorException : public std::exception { public: std::string message; - int line = -1; - int charPositionInLine = -1; + size_t line = 0; + size_t charPositionInLine = 0; ParseErrorException(std::string msg) { message = msg; }; @@ -43,7 +43,7 @@ namespace Arcweave { charPositionInLine = _charPositionInLine; }; char const* what() const noexcept override { - if (line > -1) { + if (line > 0) { std::ostringstream oss; oss << "line " << line << ":" << charPositionInLine << " " << message << std::endl; return strdup(oss.str().c_str()); @@ -52,3 +52,4 @@ namespace Arcweave { } }; } + diff --git a/Cpp/src/ArcscriptExpression.cpp b/Cpp/src/ArcscriptExpression.cpp index 9af610c..f04e685 100755 --- a/Cpp/src/ArcscriptExpression.cpp +++ b/Cpp/src/ArcscriptExpression.cpp @@ -1,6 +1,8 @@ #include "ArcscriptExpression.h" #include +#include "../build/lib/include/ArcscriptErrorExceptions.h" + namespace Arcweave { std::string Expression::valueToString(std::any value) @@ -83,12 +85,12 @@ bool Expression::valueToBool(std::any value) { Expression Expression::operator+ (const Expression &other) { if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) { - return new Expression(valueToString(value) + valueToString(other.value)); + return Expression(valueToString(value) + valueToString(other.value)); } NumberValues values = doubleValues(value, other.value); Expression* result; if (!values.hasDoubles) { - int intValue = values.value1 + values.value2; + int intValue = static_cast(values.value1 + values.value2); result = new Expression(intValue); } else { result = new Expression(values.value1 + values.value2); @@ -97,10 +99,13 @@ Expression Expression::operator+ (const Expression &other) { } Expression Expression::operator- (const Expression &other) { + if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) { + throw RuntimeErrorException("Cannot subtract strings"); + } NumberValues values = doubleValues(value, other.value); Expression* result; if (!values.hasDoubles) { - int intValue = values.value1 - values.value2; + int intValue = static_cast(values.value1 - values.value2); result = new Expression(intValue); } else { result = new Expression(values.value1 - values.value2); @@ -112,7 +117,7 @@ Expression Expression::operator* (const Expression &other) { NumberValues values = doubleValues(value, other.value); Expression* result; if (!values.hasDoubles) { - int intValue = values.value1 * values.value2; + int intValue = static_cast(values.value1 * values.value2); result = new Expression(intValue); } else { result = new Expression(values.value1 * values.value2); @@ -124,7 +129,7 @@ Expression Expression::operator* (const int other) { NumberValues values = doubleValues(value, other); Expression* result; if (!values.hasDoubles) { - int intValue = values.value1 * values.value2; + int intValue = static_cast(values.value1 * values.value2); result = new Expression(intValue); } else { result = new Expression(values.value1 * values.value2); @@ -135,35 +140,50 @@ Expression Expression::operator* (const int other) { Expression Expression::operator/ (const Expression &other) { NumberValues values = doubleValues(value, other.value); Expression* result; - if (!values.hasDoubles) { - int intValue = values.value1 / values.value2; - result = new Expression(intValue); - } else { - result = new Expression(values.value1 / values.value2); + + if (values.value2 == 0) { + throw RuntimeErrorException("Division by zero is not allowed."); } + + result = new Expression(values.value1 / values.value2); + return *result; } Expression Expression::operator+= (const Expression &other) { - if (value.type() == typeid(int) || value.type() == typeid(double)) { - NumberValues values = doubleValues(value, other.value); - if (!values.hasDoubles) { - int intValue = values.value1 + values.value2; - value = intValue; + if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) { + auto val1 = valueToString(value); + auto val2 = valueToString(other.value); + if (val1.empty() && val2.empty()) { + value = std::string(); + } else if (val1.empty()) { + value = val2; + } else if (val2.empty()) { + value = val1; } else { - value = values.value1 + values.value2; + value = val1 + val2; } + return *this; } - if (value.type() == typeid(std::string)) { - value = std::any_cast(value) + std::any_cast(other.value); + + NumberValues values = doubleValues(value, other.value); + if (!values.hasDoubles) { + int intValue = static_cast(values.value1 + values.value2); + value = intValue; + } else { + value = values.value1 + values.value2; } + return *this; } Expression Expression::operator-= (const Expression &other) { + if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) { + throw RuntimeErrorException("Cannot subtract strings"); + } NumberValues values = doubleValues(value, other.value); if (!values.hasDoubles) { - int intValue = values.value1 - values.value2; + int intValue = static_cast(values.value1 - values.value2); value = intValue; } else { value = values.value1 - values.value2; @@ -174,7 +194,7 @@ Expression Expression::operator-= (const Expression &other) { Expression Expression::operator*= (const Expression &other) { NumberValues values = doubleValues(value, other.value); if (!values.hasDoubles) { - int intValue = values.value1 * values.value2; + int intValue = static_cast(values.value1 * values.value2); value = intValue; } else { value = values.value1 * values.value2; @@ -184,8 +204,11 @@ Expression Expression::operator*= (const Expression &other) { Expression Expression::operator/= (const Expression &other) { NumberValues values = doubleValues(value, other.value); + if (values.value2 == 0) { + throw RuntimeErrorException("Division by zero is not allowed."); + } if (!values.hasDoubles) { - int intValue = values.value1 / values.value2; + int intValue = static_cast(values.value1 / values.value2); value = intValue; } else { value = values.value1 / values.value2; @@ -223,6 +246,13 @@ bool Expression::operator== (bool other) { } bool Expression::operator!= (const Expression &other) { + if (value.type() == typeid(std::string) || other.value.type() == typeid(std::string)) { + if (value.type() != other.value.type()) { + return true; // Different types, cannot be equal + } else { + return std::any_cast(value) != std::any_cast(other.value); + } + } if (value.type() == typeid(int) || value.type() == typeid(double)) { NumberValues values = doubleValues(value, other.value); return values.value1 != values.value2; diff --git a/Cpp/src/ArcscriptFunctions.cpp b/Cpp/src/ArcscriptFunctions.cpp index 83960a4..d8cea19 100755 --- a/Cpp/src/ArcscriptFunctions.cpp +++ b/Cpp/src/ArcscriptFunctions.cpp @@ -5,7 +5,54 @@ #include #include +#include "../build/lib/include/ArcscriptErrorExceptions.h" + namespace Arcweave { + std::string replaceEscapes(std::string str) { + std::string result; + for (size_t i = 0; i < str.length(); i++) { + if (str[i] == '\\' && i + 1 < str.length()) { + switch (str[i + 1]) { + case 'a': + result += '\x07'; + break; + case 'b': + result += '\b'; + break; + case 'f': + result += '\f'; + case 'n': + result += '\n'; + break; + case 'r': + result += '\r'; + break; + case 't': + result += '\t'; + break; + case 'v': + result += '\v'; + break; + case '\'': + result += '\''; + break; + case '\\': + result += '\\'; + break; + case '"': + result += '"'; + break; + default: + result += str[i]; + } + i++; + } else { + result += str[i]; + } + } + return result; + } + std::map ArcscriptFunctions::functions = { { "abs", { 1, 1 } }, { "max", { 2, -1 }}, @@ -72,11 +119,21 @@ namespace Arcweave { } std::any ArcscriptFunctions::Sqrt(std::vector args) { - if (args[0].type() == typeid(int)) { - return sqrt(std::any_cast(args[0])); + const int arg = std::any_cast(args[0]); + if (arg < 0) { + throw RuntimeErrorException("Cannot calculate square root of a negative number."); + } + return sqrt(arg); } - return sqrt(std::any_cast(args[0])); + if (args[0].type() != typeid(double)) { + throw RuntimeErrorException("The argument of sqrt must be a number."); + } + const double arg = std::any_cast(args[0]); + if (arg < 0) { + throw RuntimeErrorException("Cannot calculate square root of a negative number."); + } + return sqrt(arg); } std::any ArcscriptFunctions::Sqr(std::vector args) { @@ -97,11 +154,14 @@ namespace Arcweave { } std::any ArcscriptFunctions::Random(std::vector args) { - srand(time(NULL)); + srand(static_cast(time(NULL))); return ((double)rand() / (RAND_MAX)); } std::any ArcscriptFunctions::Roll(std::vector args) { + if (args[0].type() != typeid(int)) { + throw RuntimeErrorException("The argument of roll must be an integer."); + } int maxRoll = std::any_cast(args[0]); int numRolls = 1; if (args.size() == 2) { @@ -132,6 +192,7 @@ namespace Arcweave { result += std::any_cast(arg); } } + result = replaceEscapes(result); _state->outputs.AddScriptOutput(result); return std::any(); } diff --git a/Cpp/src/ArcscriptOutputs.h b/Cpp/src/ArcscriptOutputs.h index 3949d28..090e077 100755 --- a/Cpp/src/ArcscriptOutputs.h +++ b/Cpp/src/ArcscriptOutputs.h @@ -33,9 +33,13 @@ namespace Arcweave inline void MergeScriptOutput(std::string text) override { - if (text.length() > 0) - { - text_ += ' ' + text; + if (text.length() > 0) { + if (text_.length() > 0) + { + text_ += ' ' + text; + } else { + text_ = text; + } } } diff --git a/Cpp/src/ArcscriptParserBase.cpp b/Cpp/src/ArcscriptParserBase.cpp index 50ed267..1ae9582 100755 --- a/Cpp/src/ArcscriptParserBase.cpp +++ b/Cpp/src/ArcscriptParserBase.cpp @@ -78,13 +78,13 @@ bool ArcscriptParserBase::assertFunctionArguments(Token *fname, std::any argumen if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Argument_listContext*)) { Arcweave::ArcscriptParser::Argument_listContext *argumentListCtx = std::any_cast(argumentList); if (argumentListCtx != NULL) { - argListLength = argumentListCtx->argument().size(); + argListLength = static_cast(argumentListCtx->argument().size()); } } if (argumentList.type() == typeid(Arcweave::ArcscriptParser::Variable_listContext*)) { Arcweave::ArcscriptParser::Variable_listContext *variableListCtx = std::any_cast(argumentList); if (variableListCtx != NULL) { - argListLength = variableListCtx->VARIABLE().size(); + argListLength = static_cast(variableListCtx->VARIABLE().size()); } } diff --git a/Cpp/src/ArcscriptParserBase.h b/Cpp/src/ArcscriptParserBase.h index bc33945..83e0af4 100755 --- a/Cpp/src/ArcscriptParserBase.h +++ b/Cpp/src/ArcscriptParserBase.h @@ -6,7 +6,7 @@ class ArcscriptParserBase : public antlr4::Parser { private: Arcweave::ArcscriptState* _state; - int openTagEndPos; + size_t openTagEndPos; public: int currentLine = 0; ArcscriptParserBase(antlr4::TokenStream *input) : Parser(input) { } diff --git a/Cpp/src/ArcscriptVisitor.cpp b/Cpp/src/ArcscriptVisitor.cpp index 068ca9c..f849517 100755 --- a/Cpp/src/ArcscriptVisitor.cpp +++ b/Cpp/src/ArcscriptVisitor.cpp @@ -262,6 +262,7 @@ std::any ArcscriptVisitor::visitAdditive_numeric_expression(ArcscriptParser::Add 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())); } @@ -277,6 +278,7 @@ std::any ArcscriptVisitor::visitMultiplicative_numeric_expression(ArcscriptParse 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())); From d437bfdf78b3091451f8fa6130cbf47592418584 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Fri, 4 Jul 2025 15:13:27 +0300 Subject: [PATCH 08/31] (cpp) fix: CMakeLists.txt for mac --- Cpp/CMakeLists.txt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index 82f6447..0821d4f 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -147,12 +147,19 @@ if (WITH_DEMO) -E copy ${TEST_SOURCES} "$/tests" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set(ARCSCRIPT_TRANSPILER_LIB_FILES - "$/${DLL_NAME}" - "$/${LIBRARY_NAME}" - "$/${PROJECT_NAME}.exp" - "$/${PROJECT_NAME}.pdb" - ) + 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} From 97abd94cd18fead91033e9dda450407e0eeb0c0f Mon Sep 17 00:00:00 2001 From: Emmanouil Dermitzakis Date: Mon, 7 Jul 2025 14:21:46 +0300 Subject: [PATCH 09/31] (cpp) fix: include paths --- Cpp/src/ArcscriptExpression.cpp | 2 +- Cpp/src/ArcscriptFunctions.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cpp/src/ArcscriptExpression.cpp b/Cpp/src/ArcscriptExpression.cpp index f04e685..ca13bfb 100755 --- a/Cpp/src/ArcscriptExpression.cpp +++ b/Cpp/src/ArcscriptExpression.cpp @@ -1,7 +1,7 @@ #include "ArcscriptExpression.h" #include -#include "../build/lib/include/ArcscriptErrorExceptions.h" +#include "ArcscriptErrorExceptions.h" namespace Arcweave { diff --git a/Cpp/src/ArcscriptFunctions.cpp b/Cpp/src/ArcscriptFunctions.cpp index d8cea19..476c153 100755 --- a/Cpp/src/ArcscriptFunctions.cpp +++ b/Cpp/src/ArcscriptFunctions.cpp @@ -5,7 +5,7 @@ #include #include -#include "../build/lib/include/ArcscriptErrorExceptions.h" +#include "ArcscriptErrorExceptions.h" namespace Arcweave { std::string replaceEscapes(std::string str) { From c739d2a3385c6a3dde9f17131c7296806e64e03f Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Sat, 24 Jan 2026 16:05:26 +0200 Subject: [PATCH 10/31] fix: generate folder --- generate.sh | 3 +++ 1 file changed, 3 insertions(+) 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 From 106498117c5d7d5250f4962f0b82f32947a71973 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Sat, 24 Jan 2026 16:18:13 +0200 Subject: [PATCH 11/31] feat: github CI for CPP --- .github/workflows/cpp-build-test.yml | 44 ++++++++++++++++++++++++++++ generate.ps1 | 4 +-- 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/cpp-build-test.yml diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml new file mode 100644 index 0000000..adef127 --- /dev/null +++ b/.github/workflows/cpp-build-test.yml @@ -0,0 +1,44 @@ +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] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Generate ANTLR4 files (based on runner OS) + run: | + if [[ "${{ matrix.os }}" == "windows-latest" ]]; then + .\generate.ps1 + else + sh generate.sh + fi + + - name: Configure CMake + run: | + mkdir -p Cpp/build + cd Cpp/build + cmake -DWITH_DEMO=true .. + + - name: Build + run: cmake --build . + + - name: Run tests + run: cd demo + ./ArcscriptTest 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 From 92bdb92a15dc956b105dc89a66e627bb6abcf276 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Sat, 24 Jan 2026 16:21:25 +0200 Subject: [PATCH 12/31] fix: github CI for cpp --- .github/workflows/cpp-build-test.yml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index adef127..d7b7c85 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -22,13 +22,14 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Generate ANTLR4 files (based on runner OS) - run: | - if [[ "${{ matrix.os }}" == "windows-latest" ]]; then - .\generate.ps1 - else - sh generate.sh - fi + - 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: | @@ -37,8 +38,11 @@ jobs: cmake -DWITH_DEMO=true .. - name: Build - run: cmake --build . + run: | + cd Cpp/build + cmake --build . - name: Run tests - run: cd demo + run: | + cd Cpp/build/demo ./ArcscriptTest From 5a2dd9a40d4b14680f6acfbe00feab90267ed022 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 09:58:05 +0200 Subject: [PATCH 13/31] chore: print cmake version --- Cpp/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index 0821d4f..70fba64 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -5,7 +5,8 @@ set(PROJECT_VERSION "0.1.0") project(ArcscriptTranspiler VERSION ${PROJECT_VERSION}) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) -message(CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) +message(STATUS "CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}") +message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "Generator: ${CMAKE_GENERATOR}") message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") From d7ee53fe62f65c0cd101d6ad30f8845fa8153838 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 10:12:24 +0200 Subject: [PATCH 14/31] fix: setup cmake 3 --- .github/workflows/cpp-build-test.yml | 5 +++++ Cpp/CMakeLists.txt | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index d7b7c85..b605de4 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -22,6 +22,11 @@ jobs: - 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 diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index 70fba64..fec03e8 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -1,12 +1,13 @@ # 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 "CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}") -message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "Generator: ${CMAKE_GENERATOR}") message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") From 81c3fa3f8e1c9c5266d599706d2498008e1a79de Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 10:26:07 +0200 Subject: [PATCH 15/31] fix: mac tests --- .github/workflows/cpp-build-test.yml | 6 ++++-- Cpp/CMakeLists.txt | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index b605de4..9695052 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -18,6 +18,8 @@ jobs: strategy: matrix: os: [macos-latest, windows-latest] + env: + PLATFORM: ${{ matrix.os == 'windows-latest' && 'Windows' || 'Mac' }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -40,7 +42,7 @@ jobs: run: | mkdir -p Cpp/build cd Cpp/build - cmake -DWITH_DEMO=true .. + cmake .. --DWITH_TEST=true - name: Build run: | @@ -49,5 +51,5 @@ jobs: - name: Run tests run: | - cd Cpp/build/demo + cd Cpp/build/demo/${{ env.PLATFORM }} ./ArcscriptTest diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index fec03e8..b35a3bc 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -119,7 +119,7 @@ add_custom_command(TARGET ArcscriptTranspiler POST_BUILD -E copy ${ARCSCRIPT_INCLUDE_HEADERS} "${CMAKE_CURRENT_BINARY_DIR}/lib/include" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -if (WITH_DEMO) +if (WITH_TEST) add_executable(ArcscriptTest ${CMAKE_CURRENT_SOURCE_DIR}/demo/ArcscriptTest.cpp) include(FetchContent) @@ -172,4 +172,4 @@ if (WITH_DEMO) COMMAND ${CMAKE_COMMAND} -E copy ${ARCSCRIPT_TRANSPILER_LIB_FILES} "$" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -endif (WITH_DEMO) \ No newline at end of file +endif (WITH_TEST) \ No newline at end of file From 2dff8c8690bdd8167b8f9400a6c4a2b1c749bea2 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 10:27:14 +0200 Subject: [PATCH 16/31] chore: typo --- .github/workflows/cpp-build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index 9695052..ead89b1 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -42,7 +42,7 @@ jobs: run: | mkdir -p Cpp/build cd Cpp/build - cmake .. --DWITH_TEST=true + cmake .. -DWITH_TEST=true - name: Build run: | From 52c5b476739a6bcf9742a7e8f2b949c168250b4a Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 11:56:43 +0200 Subject: [PATCH 17/31] fix: test runs --- Cpp/demo/ArcscriptTest.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Cpp/demo/ArcscriptTest.cpp b/Cpp/demo/ArcscriptTest.cpp index 93c869d..19ed1b2 100644 --- a/Cpp/demo/ArcscriptTest.cpp +++ b/Cpp/demo/ArcscriptTest.cpp @@ -19,7 +19,7 @@ using json = nlohmann::json; using namespace Arcweave; UVariable* getInitialVars(json initialVarsJson) { - UVariable* initVars = new UVariable[initialVarsJson.size()]; + auto initVars = new UVariable[initialVarsJson.size()]; int i = 0; for (json::iterator it = initialVarsJson.begin(); it != initialVarsJson.end(); ++it) { std::string id = it.value()["id"].template get(); @@ -82,7 +82,7 @@ std::map getExpectedChanges(json changes) { UVisit* getVisits(json initVisits) { if (initVisits.size() == 0) return nullptr; - UVisit* visits = new UVisit[initVisits.size()]; + auto visits = new UVisit[initVisits.size()]; int i = 0; for (json::iterator it = initVisits.begin(); it != initVisits.end(); ++it) { visits[i].elId = strdup(it.key().c_str()); @@ -230,7 +230,6 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in delete visits; } free(const_cast(currentElement)); - free(const_cast(code)); deallocateOutput(result); @@ -241,6 +240,8 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in errorOutput.swap(temp); } + free(const_cast(code)); + return errorOutput.str(); } @@ -296,6 +297,11 @@ int testFile(std::filesystem::path path, int testIndex = -1) { } } delete initVars; + + if (fileError) { + return 1; + } + return 0; } @@ -311,12 +317,18 @@ int main(int argc, char* argv[]) "./tests/runtimeErrors.json", "./tests/parseErrors.json", }; - + bool hasErrors = false; for (auto path : testPaths) { if (!std::filesystem::exists(path)) { std::cout << "File not found: " << path << std::endl; continue; } - testFile(path); + auto result = testFile(path); + if (result != 0) { + hasErrors = true; + } } -} \ No newline at end of file + if (hasErrors) { + return 1; + } +} From e897fd42a63147c513d2320f19753da2264e877b Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 12:53:49 +0200 Subject: [PATCH 18/31] fix: arcscript single test --- Cpp/demo/ArcscriptTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Cpp/demo/ArcscriptTest.cpp b/Cpp/demo/ArcscriptTest.cpp index 19ed1b2..1094a02 100644 --- a/Cpp/demo/ArcscriptTest.cpp +++ b/Cpp/demo/ArcscriptTest.cpp @@ -262,6 +262,7 @@ int testFile(std::filesystem::path path, int testIndex = -1) { if (errorOutput.length() > 0) { std::cout << errorOutput << std::endl; + return 1; } return 0; From 357f0e8796bc96ccf13ab92eac186ac3c66772f6 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 16:35:30 +0200 Subject: [PATCH 19/31] fix: use specific antlr4 commit --- Cpp/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cpp/CMakeLists.txt b/Cpp/CMakeLists.txt index b35a3bc..72bbd5c 100755 --- a/Cpp/CMakeLists.txt +++ b/Cpp/CMakeLists.txt @@ -26,7 +26,7 @@ set(ANTLR4_WITH_STATIC_CRT OFF) # 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 4.13.1) + 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 From 772afb7d29ab18d8e90cc73bd950bd4d60e363c4 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:01:59 +0200 Subject: [PATCH 20/31] fix: windows runner --- .github/workflows/cpp-build-test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index ead89b1..d360dbd 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -19,11 +19,10 @@ jobs: matrix: os: [macos-latest, windows-latest] env: - PLATFORM: ${{ matrix.os == 'windows-latest' && 'Windows' || 'Mac' }} + PLATFORM: ${{ matrix.os == 'windows-latest' && 'Win32' || 'Mac' }} steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 with: From 9c4541aec94a2389389688abe16fbd396b5ae746 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:06:49 +0200 Subject: [PATCH 21/31] fix: test runs dont fail --- .github/workflows/cpp-build-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index d360dbd..b4475de 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -18,6 +18,7 @@ jobs: strategy: matrix: os: [macos-latest, windows-latest] + fail-fast: false env: PLATFORM: ${{ matrix.os == 'windows-latest' && 'Win32' || 'Mac' }} steps: @@ -51,4 +52,5 @@ jobs: - name: Run tests run: | cd Cpp/build/demo/${{ env.PLATFORM }} + ls ./ArcscriptTest From 8be5615f6b8850577432a27f61d8847a6767c593 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:10:43 +0200 Subject: [PATCH 22/31] fix: windows demo directory --- .github/workflows/cpp-build-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index b4475de..58683bc 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -20,7 +20,7 @@ jobs: os: [macos-latest, windows-latest] fail-fast: false env: - PLATFORM: ${{ matrix.os == 'windows-latest' && 'Win32' || 'Mac' }} + DEMO_DIR: ${{ matrix.os == 'windows-latest' && 'Win32/Debug' || 'Mac' }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -51,6 +51,6 @@ jobs: - name: Run tests run: | - cd Cpp/build/demo/${{ env.PLATFORM }} + cd Cpp/build/${{ env.DEMO_DIR }} ls ./ArcscriptTest From b381ec42bec7ddcf78147d3b63213b74ee08dcb2 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:14:04 +0200 Subject: [PATCH 23/31] fix: demo dir again --- .github/workflows/cpp-build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index 58683bc..0538a65 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -20,7 +20,7 @@ jobs: os: [macos-latest, windows-latest] fail-fast: false env: - DEMO_DIR: ${{ matrix.os == 'windows-latest' && 'Win32/Debug' || 'Mac' }} + DEMO_DIR: demo/${{ matrix.os == 'windows-latest' && 'Win32/Debug' || 'Mac' }} steps: - name: Checkout repository uses: actions/checkout@v4 From ee38becef5bea9fb9d4ffe8e3da81e09fc665228 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:19:49 +0200 Subject: [PATCH 24/31] chore: use cache for antlr4 runtime --- .github/workflows/cpp-build-test.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index 0538a65..a3349b0 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -29,6 +29,14 @@ jobs: with: cmake-version: "3.x" + - name: Cache CMake packages + uses: actions/cache@v3 + with: + path: | + Cpp/build/_deps + Cpp/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp + key: ${{ runner.os }}-cmake-deps-${{ hashFiles('grammar/*.g4', 'Cpp/CMakeLists.txt', 'Cpp/cmake/ExternalAntlr4Cpp.cmake') }} + - name: Generate ANTLR4 files (Windows) if: matrix.os == 'windows-latest' run: .\generate.ps1 From e28ddfc5990e6381128edd4b3272d1d6995a6232 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:22:30 +0200 Subject: [PATCH 25/31] chore: use actions/cache@v5 --- .github/workflows/cpp-build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index a3349b0..b7c9d76 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -30,7 +30,7 @@ jobs: cmake-version: "3.x" - name: Cache CMake packages - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: | Cpp/build/_deps From 4aff241f7efad99ad29af2ef3f42e0a151cfd763 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:26:58 +0200 Subject: [PATCH 26/31] fix: github cache save/restore --- .github/workflows/cpp-build-test.yml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index b7c9d76..068c120 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -29,14 +29,6 @@ jobs: with: cmake-version: "3.x" - - name: Cache CMake packages - uses: actions/cache@v5 - with: - path: | - Cpp/build/_deps - Cpp/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp - key: ${{ runner.os }}-cmake-deps-${{ hashFiles('grammar/*.g4', 'Cpp/CMakeLists.txt', 'Cpp/cmake/ExternalAntlr4Cpp.cmake') }} - - name: Generate ANTLR4 files (Windows) if: matrix.os == 'windows-latest' run: .\generate.ps1 @@ -52,11 +44,27 @@ jobs: cd Cpp/build cmake .. -DWITH_TEST=true + - name: Restore Cache + uses: actions/cache/restore@v5 + with: + path: | + Cpp/build/_deps + Cpp/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp + key: ${{ runner.os }}-cmake-deps-${{ hashFiles('grammar/*.g4', 'Cpp/CMakeLists.txt', 'Cpp/cmake/ExternalAntlr4Cpp.cmake') }} + - name: Build run: | cd Cpp/build cmake --build . + - name: Save Cache + uses: actions/cache/save@v5 + with: + path: | + Cpp/build/_deps + Cpp/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp + key: ${{ runner.os }}-cmake-deps-${{ hashFiles('grammar/*.g4', 'Cpp/CMakeLists.txt', 'Cpp/cmake/ExternalAntlr4Cpp.cmake') }} + - name: Run tests run: | cd Cpp/build/${{ env.DEMO_DIR }} From 9eb5706008bfd237028c64cad9144cdc8572a507 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:30:32 +0200 Subject: [PATCH 27/31] chore: use cache primary key on save --- .github/workflows/cpp-build-test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index 068c120..61468ab 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -45,6 +45,7 @@ jobs: cmake .. -DWITH_TEST=true - name: Restore Cache + id: cache-deps-restore uses: actions/cache/restore@v5 with: path: | @@ -63,7 +64,7 @@ jobs: path: | Cpp/build/_deps Cpp/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp - key: ${{ runner.os }}-cmake-deps-${{ hashFiles('grammar/*.g4', 'Cpp/CMakeLists.txt', 'Cpp/cmake/ExternalAntlr4Cpp.cmake') }} + key: ${{ steps.cache-deps-restore.outputs.cache-primary-key }} - name: Run tests run: | From d86aa5dcc3d917384b751ece896c4f754175cf4f Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 17:35:53 +0200 Subject: [PATCH 28/31] chore: remove actions/cache --- .github/workflows/cpp-build-test.yml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.github/workflows/cpp-build-test.yml b/.github/workflows/cpp-build-test.yml index 61468ab..0538a65 100644 --- a/.github/workflows/cpp-build-test.yml +++ b/.github/workflows/cpp-build-test.yml @@ -44,28 +44,11 @@ jobs: cd Cpp/build cmake .. -DWITH_TEST=true - - name: Restore Cache - id: cache-deps-restore - uses: actions/cache/restore@v5 - with: - path: | - Cpp/build/_deps - Cpp/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp - key: ${{ runner.os }}-cmake-deps-${{ hashFiles('grammar/*.g4', 'Cpp/CMakeLists.txt', 'Cpp/cmake/ExternalAntlr4Cpp.cmake') }} - - name: Build run: | cd Cpp/build cmake --build . - - name: Save Cache - uses: actions/cache/save@v5 - with: - path: | - Cpp/build/_deps - Cpp/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp - key: ${{ steps.cache-deps-restore.outputs.cache-primary-key }} - - name: Run tests run: | cd Cpp/build/${{ env.DEMO_DIR }} From f4b812ecb72312282657d52687395cb533d27d6e Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 18:44:25 +0200 Subject: [PATCH 29/31] fix: c++ warnings --- Cpp/demo/ArcscriptTest.cpp | 89 ++++++++++++++++++-------------------- Cpp/src/ArcscriptOutputs.h | 10 +++-- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/Cpp/demo/ArcscriptTest.cpp b/Cpp/demo/ArcscriptTest.cpp index 1094a02..7fd8f53 100644 --- a/Cpp/demo/ArcscriptTest.cpp +++ b/Cpp/demo/ArcscriptTest.cpp @@ -1,4 +1,4 @@ -// ArcscriptTranspilerTest.cpp : This file contains the 'main' function. Program execution begins and ends there. +// ArcscriptTranspilerTest.cpp: This file contains the 'main' function. Program execution begins and ends there. // #include @@ -22,9 +22,9 @@ UVariable* getInitialVars(json initialVarsJson) { auto initVars = new UVariable[initialVarsJson.size()]; int i = 0; for (json::iterator it = initialVarsJson.begin(); it != initialVarsJson.end(); ++it) { - std::string id = it.value()["id"].template get(); - std::string name = it.value()["name"].template get(); - std::string type = it.value()["type"].template get(); + std::string id = it.value()["id"].get(); + std::string name = it.value()["name"].get(); + std::string type = it.value()["type"].get(); initVars[i].id = strdup(id.c_str()); initVars[i].name = strdup(name.c_str()); @@ -43,16 +43,16 @@ UVariable* getInitialVars(json initialVarsJson) { } if (initVars[i].type == VariableType::AW_STRING) { - initVars[i].string_val = strdup(it.value()["value"].template get().c_str()); + initVars[i].string_val = strdup(it.value()["value"].get().c_str()); } else if (initVars[i].type == VariableType::AW_INTEGER) { - initVars[i].int_val = it.value()["value"].template get(); + initVars[i].int_val = it.value()["value"].get(); } else if (initVars[i].type == VariableType::AW_DOUBLE) { - initVars[i].double_val= it.value()["value"].template get(); + initVars[i].double_val= it.value()["value"].get(); } else if (initVars[i].type == VariableType::AW_BOOLEAN) { - initVars[i].bool_val = it.value()["value"].template get(); + initVars[i].bool_val = it.value()["value"].get(); } i += 1; } @@ -64,29 +64,29 @@ std::map getExpectedChanges(json changes) { std::map expectedChanges; for (json::iterator it = changes.begin(); it != changes.end(); ++it) { - std::string varId = it.key(); - json value = it.value(); + const std::string& varId = it.key(); + const json& value = it.value(); if (value.type() == json::value_t::string) { - expectedChanges[varId] = value.template get(); + expectedChanges[varId] = value.get(); } else if (value.type() == json::value_t::number_float || value.type() == json::value_t::number_integer) { - expectedChanges[varId] = value.template get(); + expectedChanges[varId] = value.get(); } else if (value.type() == json::value_t::boolean) { - expectedChanges[varId] = value.template get(); + expectedChanges[varId] = value.get(); } } return expectedChanges; } UVisit* getVisits(json initVisits) { - if (initVisits.size() == 0) return nullptr; + if (initVisits.empty()) return nullptr; auto visits = new UVisit[initVisits.size()]; int i = 0; for (json::iterator it = initVisits.begin(); it != initVisits.end(); ++it) { visits[i].elId = strdup(it.key().c_str()); - visits[i].visits = it.value().template get(); + visits[i].visits = it.value().get(); i += 1; } return visits; @@ -95,12 +95,12 @@ UVisit* getVisits(json initVisits) { std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t initVarLen) { std::stringstream errorOutput; - const char* code = strdup(testCase["code"].template get().c_str()); + const char* code = strdup(testCase["code"].get().c_str()); UVisit* visits = nullptr; size_t visitsLen = 0; const char* currentElement = nullptr; if (testCase.contains("elementId")) { - currentElement = strdup(testCase["elementId"].template get().c_str()); + currentElement = strdup(testCase["elementId"].get().c_str()); } else { currentElement = strdup("TestElement"); @@ -111,10 +111,10 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in } bool hasError = false; - std::string errorType = ""; + std::string errorType; if (testCase.contains("error")) { hasError = true; - errorType = testCase["error"].template get(); + errorType = testCase["error"].get(); } UTranspilerOutput* result = nullptr; try { @@ -146,9 +146,8 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in } if (result == nullptr) { - std::stringstream temp; - - if (errorOutput.str().length() > 0) { + if (!errorOutput.str().empty()) { + std::stringstream temp; temp << "Test case " << caseIndex << " failed: \"" << code << "\"" << std::endl << errorOutput.rdbuf(); errorOutput.swap(temp); } @@ -164,8 +163,8 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in if (testCase.contains("output")) { - std::string output = testCase["output"].template get(); - if (output.compare(result->output) != 0) + std::string output = testCase["output"].get(); + if (output != result->output) { errorOutput << "Different Text Output" << std::endl; errorOutput << "EXPECTED:\t\"" << output << "\"" << std::endl << "ACTUAL:\t\t\"" << result->output << "\"" << std::endl; @@ -176,8 +175,8 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in json changes = testCase["changes"]; for (json::iterator it = changes.begin(); it != changes.end(); ++it) { - std::string expectedChangeKey = it.key(); - json expectedChangeValue = it.value(); + const std::string& expectedChangeKey = it.key(); + const json& expectedChangeValue = it.value(); UVariableChange change; bool found = false; for (int i = 0; i < result->changesLen; i++) { @@ -193,22 +192,22 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in } if (change.type == VariableType::AW_STRING) { - std::string expectedValue = expectedChangeValue.template get(); - if (expectedValue.compare(change.string_result) != 0) { + std::string expectedValue = expectedChangeValue.get(); + if (expectedValue != change.string_result) { errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected \"" << expectedValue << "\", got \"" << change.string_result << "\"" << std::endl; } } else if (change.type == VariableType::AW_INTEGER) { - int expectedValue = expectedChangeValue.template get(); + int expectedValue = expectedChangeValue.get(); if (expectedValue != change.int_result) { errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected " << expectedValue << ", got " << change.int_result << std::endl; } } else if (change.type == VariableType::AW_DOUBLE) { - double expectedValue = expectedChangeValue.template get(); + double expectedValue = expectedChangeValue.get(); if (expectedValue != change.double_result) { errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected " << expectedValue << ", got " << change.double_result << std::endl; } } else if (change.type == VariableType::AW_BOOLEAN) { - bool expectedValue = expectedChangeValue.template get(); + bool expectedValue = expectedChangeValue.get(); if (expectedValue != change.bool_result) { errorOutput << "Variable change mismatch for " << expectedChangeKey << ": expected " << expectedValue << ", got " << change.bool_result << std::endl; } @@ -217,7 +216,7 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in } if (testCase.contains("result")) { - bool expectedResult = testCase["result"].template get(); + bool expectedResult = testCase["result"].get(); if (result->conditionResult != expectedResult) { errorOutput << "Condition result mismatch: expected " << expectedResult << ", got " << result->conditionResult << std::endl; } @@ -225,7 +224,7 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in if (visits != nullptr) { for (int i = 0; i < visitsLen; i++) { - free((char*)visits[i].elId); + free(const_cast(visits[i].elId)); } delete visits; } @@ -233,9 +232,8 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in deallocateOutput(result); - std::stringstream temp; - - if (errorOutput.str().length() > 0) { + if (!errorOutput.str().empty()) { + std::stringstream temp; temp << "Test case " << caseIndex << " failed: \"" << code << "\"" << std::endl << errorOutput.rdbuf(); errorOutput.swap(temp); } @@ -245,7 +243,7 @@ std::string test(json testCase, size_t caseIndex, UVariable* initVars, size_t in return errorOutput.str(); } -int testFile(std::filesystem::path path, int testIndex = -1) { +int testFile(const std::filesystem::path& path, int testIndex = -1) { std::ifstream f(path); json data = json::parse(f); @@ -254,13 +252,12 @@ int testFile(std::filesystem::path path, int testIndex = -1) { json initVarsJson = data["initialVars"]; UVariable* initVars = getInitialVars(initVarsJson); size_t initVarLen = initVarsJson.size(); - size_t casesLen = data["cases"].size(); size_t caseIndex = 0; if (testIndex >= 0) { std::string errorOutput = test(data["cases"][testIndex], testIndex, initVars, initVarLen); - if (errorOutput.length() > 0) { + if (!errorOutput.empty()) { std::cout << errorOutput << std::endl; return 1; } @@ -269,13 +266,11 @@ int testFile(std::filesystem::path path, int testIndex = -1) { } bool fileError = false; - for (json::iterator it = data["cases"].begin(); it != data["cases"].end(); ++it) { - - json testCase = *it; + for (const auto& testCase : data["cases"]) { std::string errorOutput = test(testCase, caseIndex, initVars, initVarLen); - if (errorOutput.length() > 0) { + if (!errorOutput.empty()) { fileError = true; std::cout << std::endl << errorOutput; } @@ -291,10 +286,10 @@ int testFile(std::filesystem::path path, int testIndex = -1) { for (int j = 0; j < initVarLen; j++) { - free((char*)initVars[j].id); - free((char*)initVars[j].name); + free(const_cast(initVars[j].id)); + free(const_cast(initVars[j].name)); if (initVars[j].type == VariableType::AW_STRING) { - free((char*)initVars[j].string_val); + free(const_cast(initVars[j].string_val)); } } delete initVars; @@ -319,7 +314,7 @@ int main(int argc, char* argv[]) "./tests/parseErrors.json", }; bool hasErrors = false; - for (auto path : testPaths) { + for (const auto& path : testPaths) { if (!std::filesystem::exists(path)) { std::cout << "File not found: " << path << std::endl; continue; diff --git a/Cpp/src/ArcscriptOutputs.h b/Cpp/src/ArcscriptOutputs.h index 090e077..42edc19 100755 --- a/Cpp/src/ArcscriptOutputs.h +++ b/Cpp/src/ArcscriptOutputs.h @@ -9,6 +9,8 @@ namespace Arcweave class IOutputNode { public: + virtual ~IOutputNode() = default; + virtual std::string GetText() = 0; virtual void MergeScriptOutput(std::string text) = 0; }; @@ -16,6 +18,8 @@ namespace Arcweave class IHasParagraphs { public: + virtual ~IHasParagraphs() = default; + virtual void AppendParagraph(std::string text) = 0; }; @@ -26,15 +30,15 @@ namespace Arcweave public: - Paragraph(std::string text) + explicit Paragraph(const std::string &text) { text_ = text; } inline void MergeScriptOutput(std::string text) override { - if (text.length() > 0) { - if (text_.length() > 0) + if (!text.empty()) { + if (!text_.empty()) { text_ += ' ' + text; } else { From c715f3d508efb8ca78ed412c7e1cf2ce660f2e1b Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 18:49:10 +0200 Subject: [PATCH 30/31] fix: strdup windows warning --- Cpp/src/ArcscriptErrorExceptions.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cpp/src/ArcscriptErrorExceptions.h b/Cpp/src/ArcscriptErrorExceptions.h index 76cd04d..8e5c559 100755 --- a/Cpp/src/ArcscriptErrorExceptions.h +++ b/Cpp/src/ArcscriptErrorExceptions.h @@ -5,6 +5,10 @@ #include #include +#ifdef _WIN64 +#define strdup _strdup +#endif + namespace Arcweave { class RuntimeErrorException : public std::exception { public: From 63bef6788b3a903a827998ffef212b591a671ec7 Mon Sep 17 00:00:00 2001 From: Manolis Dermitzakis Date: Mon, 26 Jan 2026 18:56:04 +0200 Subject: [PATCH 31/31] chore: update readme --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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