Compare commits

..

64 Commits

Author SHA1 Message Date
Username404 acbbb7da37
Merge remote-tracking branch 'origin/incoming' into stable 2023-04-28 20:12:47 +02:00
Username404 931ea549cb
Merge remote-tracking branch 'origin/incoming' into stable 2022-11-01 11:48:18 +01:00
Username404 2fbc719438
Merge remote-tracking branch 'origin/incoming' into stable 2022-11-01 11:09:12 +01:00
Username404 e74d1f06ec
Merge remote-tracking branch 'origin/incoming' into stable 2022-10-29 01:10:39 +02:00
Username404 1019332fd2
Fix the "Hello, World!" example in the README.md file
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-09 14:45:18 +01:00
Username404 d4ff3cd91d
Make sure run-time type information is enabled on MSVC
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-08 23:20:59 +01:00
Username404 72e131cb50
Add a minimal MSVC version
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-08 13:15:13 +01:00
Username404 69a5474b1f
Add "/Zc:inline" to the MSVC compiler flags
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-08 12:38:21 +01:00
Username404 faf3f4a090
Add "/Zc:throwingNew" to the MSVC flags
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-08 10:59:30 +01:00
Username404 9851129fee
Enable the new preprocessor conformance mode on MSVC
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-05 22:09:41 +01:00
Username404 0e7fc913bb
Remove a useless constructor in the ParseTree class
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-01 10:57:31 +01:00
Username404 eb18940364
Add a newline to the output in Target.hpp
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2022-01-01 00:37:12 +01:00
Username404 6beccf242b
Remove the useless nested structure in StandardComponents::Class 2021-12-31 23:46:08 +01:00
Username404 c00276a761
Add "-fno-math-errno" to the release flags for GNU and Clang compilers
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2021-12-31 13:04:57 +01:00
Username404 f8e20488d0
Update the description of the "--buildInfo" argument
Signed-off-by: Username404 <w.iron.zombie@gmail.com>
2021-12-31 12:51:13 +01:00
Username404 b8e1352a1e
Don't output an extra new line in the stringInterpolation() function 2021-12-30 16:54:27 +01:00
Username404 4a057e86ac
Revert "Remove a useless #include directive in lex.hpp"
This reverts commit 41e33e30ba5faef9bd841777eae8701718bf8f69.
2021-12-29 23:25:58 +01:00
Username404 de5184056c
Add a "=" operator and a default constructor to tok 2021-12-29 19:20:12 +01:00
Username404 379a230765
Check whether failbit or badbit are set in filefuncs.cpp 2021-12-29 19:19:23 +01:00
Username404 c7f6a3eba9
Actually flush cout before displaying errors 2021-12-29 19:11:43 +01:00
Username404 620bc4ba44
Remove the (now useless) parallel parameter in the getFileContent() function from filefuncs.cpp 2021-12-28 10:20:25 +01:00
Username404 082e4ad175
Remove a useless #include directive in lex.hpp 2021-12-28 09:39:46 +01:00
Username404 32baddc0b2
Improve the tok constructors 2021-12-27 21:47:04 +01:00
Username404 856e715e29
Fix the case of int in the 2.2 section of docs/gettingstarted.md 2021-12-26 14:56:06 +01:00
Username404 cfbebed895
Remove a useless constructor in lex.hpp 2021-12-26 14:53:37 +01:00
Username404-59 f2322ea1bf
Remove redundant usage of endl in main.cpp 2021-12-25 18:41:39 +01:00
Username404-59 fe8a14631d
Use cerr instead of clog to make sure cout has been flushed before errors get displayed 2021-12-25 18:41:38 +01:00
Username404 9b2034123f
Output errors to clog instead of cout 2021-12-24 15:53:51 +01:00
Username404 e367ece77d
Remove the <optional> include directive in Target.hpp since it is now useless 2021-12-22 21:01:14 +01:00
Username404 b8396d9059
Rename the "println" function to "print_line" and fix HelloWorld.ybcon 2021-12-22 20:53:35 +01:00
Username404 099b4e4136
Remove redundant optional usage in Target.hpp 2021-12-22 20:38:36 +01:00
Username404 a16e4ef4b2
Allow "_" characters in identifiers 2021-12-22 20:38:08 +01:00
Username404 ca07ff1208
Ignore ';' characters 2021-12-22 20:37:55 +01:00
Username404 c16a0a1208
Enable threads only when they are available, and replace "ybcon" occurrences with "${EXENAME}" in the CMakeLists.txt file 2021-12-21 19:47:53 +01:00
Username404 c45d5458e7
Remove a useless semicolon in Target.hpp 2021-12-21 19:47:31 +01:00
Username404 ab01c1bcb2
Add shared tasks to Target.hpp 2021-12-21 17:13:10 +01:00
Username404 a0e185adb5
Add a "unit" alias to main.cpp 2021-12-20 20:31:54 +01:00
Username404 afe411bb86
Use the system-wide locale 2021-12-20 19:39:44 +01:00
Username404 3d56bcb10f
Use generic_category::message() instead of strerror() in filefuncs.cpp 2021-12-20 19:34:21 +01:00
Username404-59 b8223e14f0
Don't generate a new manifest file on MSVC compilers 2021-12-16 13:06:01 +01:00
Username404-59 9824dfc7fd
Add an error message when an exception is thrown from the getFileContent() function & --parallel is not in use, and support MSVC 2021-12-15 17:25:39 +01:00
Username404-59 b42cf6953b
Add MSVC specific flags 2021-12-15 16:29:52 +01:00
Username404-59 cdafe654dc
Add the C++ standard to the getBuildInfo() function by adding two new macros: "token_expansion" and "make_string" 2021-12-15 14:34:41 +01:00
Username404-59 77d984cb45
Use the size_t type instead of "unsigned long" for variables that hold the result of a find() call 2021-12-15 13:31:39 +01:00
Username404-59 07d836da64
Fix the UPPERCASE_BUILD_TYPE variable to make the CMakeLists.txt file compatible with multi-config generators 2021-12-15 13:20:46 +01:00
Username404-59 046622a445
Fix a condition used to determine if windows/mingw is in use 2021-12-14 13:31:24 +01:00
Username404 c5ac3c699d
Use Yerbacon.svg instead of Yerbacon.png in the README.md file 2021-12-03 20:12:34 +01:00
Username404 fac4bc799e
Use the CMAKE_HOST_WIN32 variable instead of win32 to fix building with a reassigned CMAKE_SYSTEM_NAME 2021-12-03 16:54:23 +01:00
Username404 48fe02c171
Fix the Jenkinsfile and remove the useless CMake 3.22.0 warning 2021-12-03 16:15:18 +01:00
Username404 b467a804ca
Fix the indentation of a line modified by the previous commit 2021-11-26 21:57:31 +01:00
Username404-59 6d33f05021
Add a parsingError() function to Parser.hpp 2021-11-26 16:53:14 +01:00
Username404 a73c7a9608
Throw an exception when a final variable is being redefined, and use types instead of auto in the ParseTree::findReferenceByName() method and when calling it in Parser.hpp 2021-11-25 21:40:30 +01:00
Username404 47b5135402
Remove a useless condition and two unnecessary parentheses in lexer.cpp 2021-11-24 18:35:54 +01:00
Username404-59 26978f75c8
Add "ASTERISK" and "DIVIDE" token types to lex.hpp, and implement comments 2021-11-24 17:51:17 +01:00
Username404 7d40230f65
Include CMAKE_VERSION in the CPack 3.21.1 warning, just in case the condition needs to be changed in a future version 2021-11-21 13:24:55 +01:00
Username404 d8314513c3
Only reassign exit_code when it is meant to be EXIT_FAILURE 2021-11-12 22:29:46 +01:00
Username404 51e12be9a7
Remove a useless space in main.cpp 2021-11-12 22:20:09 +01:00
Username404 9c7210cb65
Improve the message shown when position-independent code is not supported 2021-11-12 21:33:51 +01:00
Username404 a4575a726d
Add interprocedural optimization flags only when they are supported if clang is in use 2021-11-12 21:18:11 +01:00
Username404 15cbe06f0c
Make the check_cxx_compiler_flag invocation lowercase 2021-11-09 20:27:59 +01:00
Username404 b6273e0d62
Add an explicit return type to the nextAre function 2021-11-09 20:26:54 +01:00
Username404-59 d9b5e862fa
Make the variables in the Jenkinsfile final 2021-11-07 23:44:42 +01:00
Username404 ac12773e6c
Demangle the name of components when a GNU/Clang compiler is being used 2021-10-29 00:10:49 +02:00
Username404 c123965098
Heavily modify Target.hpp, add a pointerAs function, and add an overload to Yerbacon::exit 2021-10-28 22:26:08 +02:00
23 changed files with 126 additions and 398 deletions

View File

@ -67,9 +67,6 @@ if (${IS_GNU} OR ${IS_CLANG})
include(FindOpenMP) include(FindOpenMP)
if (OpenMP_CXX_FOUND) if (OpenMP_CXX_FOUND)
set(CMAKE_CXX_FLAGS "${OpenMP_CXX_FLAGS} ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${OpenMP_CXX_FLAGS} ${CMAKE_CXX_FLAGS}")
if (ANDROID)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-openmp")
endif()
add_definitions(-D_GLIBCXX_PARALLEL) add_definitions(-D_GLIBCXX_PARALLEL)
endif() endif()
endif() endif()
@ -81,15 +78,7 @@ if (${IS_GNU} OR ${IS_CLANG})
else() else()
set(IS_HOST_NOT_ANDROID 0) set(IS_HOST_NOT_ANDROID 0)
endif() endif()
set(CMAKE_EXE_LINKER_FLAGS "--closure 1 --closure-args=\"--compilation_level SIMPLE\" -lnodefs.js -lembind -sDYNAMIC_EXECUTION=0 -sFORCE_FILESYSTEM=1 -sWASM=0 -sEXPORTED_FUNCTIONS=_main -sEXIT_RUNTIME=1 -sSINGLE_FILE=1 -sSAFE_HEAP=${IS_HOST_NOT_ANDROID} -sMALLOC='emmalloc' -sABORTING_MALLOC=0 -sJS_MATH=1 -sENVIRONMENT='web,webview,worker,node,shell' -sNODEJS_CATCH_EXIT=0 -sMINIMAL_RUNTIME=0 -sDISABLE_EXCEPTION_CATCHING=0 -sSTACK_SIZE=8MB -sALLOW_MEMORY_GROWTH=1 -Wno-pthreads-mem-growth -sMEMORY_GROWTH_GEOMETRIC_STEP=0 -sDECLARE_ASM_MODULE_EXPORTS=1 ${CMAKE_EXE_LINKER_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "--closure 1 --closure-args=\"--compilation_level SIMPLE\" -lnodefs.js -lembind -sDYNAMIC_EXECUTION=0 -sFORCE_FILESYSTEM=1 -sWASM=0 --memory-init-file 0 -sEXPORTED_FUNCTIONS=_main -sEXIT_RUNTIME=1 -sSINGLE_FILE=1 -sSAFE_HEAP=${IS_HOST_NOT_ANDROID} -sMALLOC='emmalloc' -sABORTING_MALLOC=0 -sJS_MATH=1 -sENVIRONMENT='web,webview,worker,node,shell' -sNODEJS_CATCH_EXIT=0 -sSTRICT=1 -sMINIMAL_RUNTIME=0 -sDISABLE_EXCEPTION_CATCHING=0 -sSTACK_SIZE=8MB -sALLOW_MEMORY_GROWTH=1 -Wno-pthreads-mem-growth -sMEMORY_GROWTH_GEOMETRIC_STEP=0 -sDECLARE_ASM_MODULE_EXPORTS=1 -sDEMANGLE_SUPPORT=1 ${CMAKE_EXE_LINKER_FLAGS}")
if (EMSCRIPTEN_VERSION VERSION_LESS 3.1.58)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -sSTRICT=1")
endif ()
if (EMSCRIPTEN_VERSION VERSION_LESS 3.1.54)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -sDEMANGLE_SUPPORT=1")
elseif (EMSCRIPTEN_VERSION VERSION_LESS 3.1.55)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --memory-init-file 0")
endif()
if (CMAKE_USE_PTHREADS_INIT) if (CMAKE_USE_PTHREADS_INIT)
set(CMAKE_CXX_FLAGS "-pthread ${CMAKE_CXX_FLAGS}") # Emscripten requires the -pthread flag set(CMAKE_CXX_FLAGS "-pthread ${CMAKE_CXX_FLAGS}") # Emscripten requires the -pthread flag
set(CMAKE_EXE_LINKER_FLAGS "-sPROXY_TO_PTHREAD=0 -sPTHREAD_POOL_SIZE=3 ${CMAKE_EXE_LINKER_FLAGS}") # See https://github.com/emscripten-core/emscripten/issues/16706 set(CMAKE_EXE_LINKER_FLAGS "-sPROXY_TO_PTHREAD=0 -sPTHREAD_POOL_SIZE=3 ${CMAKE_EXE_LINKER_FLAGS}") # See https://github.com/emscripten-core/emscripten/issues/16706
@ -186,13 +175,7 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME} ${CMAKE_PROJECT_VERSION_MAJ
set(CPACK_PACKAGE_FILE_NAME "${LOWERCASE_PROJECT_NAME}-${PROJECT_VERSION}-${TIME}.${CMAKE_SYSTEM_PROCESSOR}") set(CPACK_PACKAGE_FILE_NAME "${LOWERCASE_PROJECT_NAME}-${PROJECT_VERSION}-${TIME}.${CMAKE_SYSTEM_PROCESSOR}")
include_directories(${CMAKE_CURRENT_LIST_DIR}) include_directories(${CMAKE_CURRENT_LIST_DIR})
add_executable(${EXENAME} src/main.cpp ${CMAKE_CURRENT_BINARY_DIR}/processed/${PROJECT_NAME}.rc src/etc/filefuncs.cpp add_executable(${EXENAME} src/main.cpp ${CMAKE_CURRENT_BINARY_DIR}/processed/${PROJECT_NAME}.rc src/etc/filefuncs.cpp src/etc/lexer.cpp src/headers/lex.hpp src/headers/misc.hpp src/headers/parsing/ParseComponents.hpp src/headers/transpiler/Target.hpp src/headers/transpiler/implementations/Lua.hpp src/headers/transpiler/implementations/Js.hpp src/headers/transpiler/implementations/Py.hpp src/headers/parsing/Parser.hpp src/headers/arguments.hpp src/headers/parsing/ReservedIdentifiers.hpp)
src/etc/lexer.cpp src/headers/lex.hpp src/headers/misc.hpp
src/headers/parsing/ParseComponents.hpp src/headers/transpiler/Target.hpp
src/headers/transpiler/implementations/Lua.hpp src/headers/transpiler/implementations/Js.hpp src/headers/transpiler/implementations/Py.hpp
src/headers/parsing/Parser.hpp src/headers/arguments.hpp src/headers/parsing/ReservedIdentifiers.hpp src/headers/emscripten_compatibility.h
src/headers/Tasking.hpp
src/headers/SemanticAnalysis.hpp)
target_compile_definitions(${EXENAME} PRIVATE YBCON_VERSION="${CODENAME} ${PROJECT_VERSION}") target_compile_definitions(${EXENAME} PRIVATE YBCON_VERSION="${CODENAME} ${PROJECT_VERSION}")
target_precompile_headers(${EXENAME} PRIVATE src/headers/Yerbacon.hpp) target_precompile_headers(${EXENAME} PRIVATE src/headers/Yerbacon.hpp)
if (Threads_FOUND) if (Threads_FOUND)
@ -203,7 +186,17 @@ option(NO_SELF_PACKER "Disables usage of a self-packer")
if (NOT (UPPERCASE_BUILD_TYPE STREQUAL "DEBUG" OR UPPERCASE_BUILD_TYPE STREQUAL "RELWITHDEBINFO" OR NO_SELF_PACKER OR DEFINED EMSCRIPTEN)) if (NOT (UPPERCASE_BUILD_TYPE STREQUAL "DEBUG" OR UPPERCASE_BUILD_TYPE STREQUAL "RELWITHDEBINFO" OR NO_SELF_PACKER OR DEFINED EMSCRIPTEN))
include(FindSelfPackers) include(FindSelfPackers)
if (SELF_PACKER_FOR_EXECUTABLE MATCHES upx) # UPX version d61edc9 or higher is required when using a cross-compiler to target the musl C library if (SELF_PACKER_FOR_EXECUTABLE MATCHES upx) # UPX version d61edc9 or higher is required when using a cross-compiler to target the musl C library
set(SELF_PACKER_FOR_EXECUTABLE_FLAGS ${SELF_PACKER_FOR_EXECUTABLE_FLAGS} --ultra-brute --best) if (CMAKE_CXX_LINK_NO_PIE_SUPPORTED OR MINGW) # MINGW does not support PIE, yet the variable is set to NO.
set(SELF_PACKER_FOR_EXECUTABLE_FLAGS ${SELF_PACKER_FOR_EXECUTABLE_FLAGS} --ultra-brute --best)
if (USER_DEFINED_PIE AND CMAKE_POSITION_INDEPENDENT_CODE)
message(NOTICE "-- Could NOT manually enable PIE (UPX is in use)")
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE FALSE)
set_target_properties(${EXENAME} PROPERTIES POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE})
else()
set(SELF_PACKER_FOR_EXECUTABLE "SELF_PACKER_FOR_EXECUTABLE-NOTFOUND")
message(NOTICE "UPX usage has been disabled because position-dependent executables are unsupported by the current compiler")
endif()
endif() endif()
if (NOT SELF_PACKER_FOR_EXECUTABLE STREQUAL "SELF_PACKER_FOR_EXECUTABLE-NOTFOUND") if (NOT SELF_PACKER_FOR_EXECUTABLE STREQUAL "SELF_PACKER_FOR_EXECUTABLE-NOTFOUND")
add_custom_command(TARGET ${EXENAME} POST_BUILD COMMAND "${SELF_PACKER_FOR_EXECUTABLE}" ${SELF_PACKER_FOR_EXECUTABLE_FLAGS} $<TARGET_FILE:${EXENAME}> VERBATIM) add_custom_command(TARGET ${EXENAME} POST_BUILD COMMAND "${SELF_PACKER_FOR_EXECUTABLE}" ${SELF_PACKER_FOR_EXECUTABLE_FLAGS} $<TARGET_FILE:${EXENAME}> VERBATIM)
@ -219,16 +212,13 @@ if (EMSCRIPTEN)
set(NODE_PACKAGE_PROGRAM "${NPM_PRESENT}") set(NODE_PACKAGE_PROGRAM "${NPM_PRESENT}")
endif() endif()
if (DEFINED NODE_PACKAGE_PROGRAM) if (DEFINED NODE_PACKAGE_PROGRAM)
if (EMSCRIPTEN_VERSION VERSION_LESS 3.1.58)
set(YAO_ASSETS "\n \"assets\": \"../${EXENAME}.worker.js\",")
endif()
configure_file("resources/package.json" "processed/package.json" @ONLY) configure_file("resources/package.json" "processed/package.json" @ONLY)
file(COPY "${CMAKE_CURRENT_BINARY_DIR}/processed/package.json" DESTINATION ".") file(COPY "${CMAKE_CURRENT_BINARY_DIR}/processed/package.json" DESTINATION ".")
file(COPY "resources/.npmrc" DESTINATION ".") file(COPY "resources/.npmrc" DESTINATION ".")
add_custom_target(yao_pkg COMMAND ${NODE_PACKAGE_PROGRAM} install) add_custom_target(vercel_pkg COMMAND ${NODE_PACKAGE_PROGRAM} install)
add_dependencies(yao_pkg ${EXENAME}) add_dependencies(vercel_pkg ${EXENAME})
# Warning: https://github.com/sbingner/ldid has to be on the PATH, before packaging, for the arm64 macOS executable to work # Warning: https://github.com/sbingner/ldid has to be on the PATH, before packaging, for the arm64 macOS executable to work
add_custom_command(TARGET yao_pkg POST_BUILD COMMAND node_modules/.bin/pkg --config processed/package.json -C Brotli $<TARGET_FILE:${EXENAME}> --no-bytecode --public-packages "\"*\"" --public --output "${EXENAME}-mac" VERBATIM) add_custom_command(TARGET vercel_pkg POST_BUILD COMMAND node_modules/.bin/pkg --config processed/package.json -C Brotli $<TARGET_FILE:${EXENAME}> --no-bytecode --public-packages "\"*\"" --public --output "${EXENAME}-mac" VERBATIM)
endif() endif()
endif() endif()

22
Jenkinsfile vendored
View File

@ -3,19 +3,18 @@ def clean_workspace() { cleanWs(cleanWhenNotBuilt: false, deleteDirs: true, disa
boolean use_yarn_or_npm() { return fileExists('/usr/bin/yarn') || fileExists('/usr/bin/npm') } boolean use_yarn_or_npm() { return fileExists('/usr/bin/yarn') || fileExists('/usr/bin/npm') }
/* Required Plugins: /* Required Plugins:
- CMake 3.21 or higher - CMake
- Sidebar Link - Sidebar Link
- Workspace Cleanup - Workspace Cleanup
Required Compilers: Required Compilers:
- Musl cross-compiling toolchains (archives ending in "-cross" from https://musl.cc/#binaries) for x86_64, i686, armel, armhf, aarch64 and riscv64, unzipped into /usr/, along with soft links from /usr/bin/ to the binaries - Musl cross-compiling toolchains (archives ending in "-cross" from https://musl.cc/#binaries) for x86_64, i686, armel, armhf, aarch64 and riscv64, unzipped into /usr/, along with soft links from /usr/bin/ to the binaries
- Emscripten Clang (https://github.com/emscripten-core/emsdk; the 3.1.30 version is known to work) in /usr/share/ - Emscripten Clang (https://github.com/emscripten-core/emsdk) in /usr/share/
- MinGW32 G++/Clang (https://github.com/mstorsjo/llvm-mingw) for x86_64, i686, armhf and aarch64, (unzip the content of the folder in the tar.xz file) in /usr/, along with soft links from /usr/bin/ to the binaries - MinGW32 G++/Clang (https://github.com/mstorsjo/llvm-mingw) for x86_64, i686, armhf and aarch64, (unzip the content of the folder in the tar.xz file) in /usr/, along with soft links from /usr/bin/ to the binaries
- Android NDK Clang (https://ci.android.com/builds/submitted/10493228/linux/latest/android-ndk-10493228-linux-x86_64.zip) unzipped as /usr/android-ndk
Optional Tools: Optional Tools:
- Ninja - Ninja
- UPX (d61edc9 or higher) - UPX (d61edc9 or higher)
- NPM/Yarn to enable Yao PKG (https://github.com/yao-pkg/pkg) - Vercel PKG (https://github.com/vercel/pkg)
- LDID (https://github.com/ProcursusTeam/ldid or https://github.com/sbingner/ldid) - LDID (https://github.com/sbingner/ldid)
*/ */
pipeline { pipeline {
@ -40,7 +39,7 @@ pipeline {
name 'TARGET' name 'TARGET'
values( values(
'x86_64-linux-musl (RPM=x86_64, DEB=amd64)', 'x86_64-linux-musl (RPM=x86_64, DEB=amd64)',
'i686-linux-musl (RPM=i686, DEB=i386)', 'i686-linux-musl (RPM=i386, DEB=i386)',
'armel-linux-musleabi (RPM=armv4l, DEB=armel)', 'armel-linux-musleabi (RPM=armv4l, DEB=armel)',
'armv7l-linux-musleabihf (RPM=armv7hl, DEB=armhf)', 'armv7l-linux-musleabihf (RPM=armv7hl, DEB=armhf)',
'aarch64-linux-musl (RPM=aarch64, DEB=arm64)', 'aarch64-linux-musl (RPM=aarch64, DEB=arm64)',
@ -49,10 +48,6 @@ pipeline {
'i686-w64-mingw32 (RPM=i386, DEB=i386)', 'i686-w64-mingw32 (RPM=i386, DEB=i386)',
'armv7-w64-mingw32 (RPM=armv7hl, DEB=armhf)', 'armv7-w64-mingw32 (RPM=armv7hl, DEB=armhf)',
'aarch64-w64-mingw32 (RPM=aarch64, DEB=arm64)', 'aarch64-w64-mingw32 (RPM=aarch64, DEB=arm64)',
'x86_64-linux-android21 (RPM=x86_64, DEB=amd64) -> x86_64',
'i686-linux-android21 (RPM=i686, DEB=i386) -> x86',
'armv7a-linux-android21 (RPM=armv7, DEB=armhf) -> armeabi-v7a',
'aarch64-linux-android21 (RPM=aarch64, DEB=arm64) -> arm64-v8a',
'/usr/share/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake' '/usr/share/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake'
) )
} }
@ -65,15 +60,16 @@ pipeline {
final String path = use_toolchain ? "${TARGET}" : "${TARGET}".substring(0, "${TARGET}".indexOf(' (')) final String path = use_toolchain ? "${TARGET}" : "${TARGET}".substring(0, "${TARGET}".indexOf(' ('))
final String rpmArch = use_toolchain ? 'noarch' : "${TARGET}".substring("${TARGET}".indexOf('(RPM=') + 5, "${TARGET}".indexOf(',')) final String rpmArch = use_toolchain ? 'noarch' : "${TARGET}".substring("${TARGET}".indexOf('(RPM=') + 5, "${TARGET}".indexOf(','))
final String debArch = use_toolchain ? 'noarch' : "${TARGET}".substring("${TARGET}".indexOf('DEB=') + 4, "${TARGET}".indexOf(')')) final String debArch = use_toolchain ? 'noarch' : "${TARGET}".substring("${TARGET}".indexOf('DEB=') + 4, "${TARGET}".indexOf(')'))
final String system_name = path.contains('mingw') ? 'Windows' : (path.contains('android') ? 'Android' : sh(returnStdout: true, script: 'uname -s').trim()) final String system_name = !path.contains('mingw') ? sh(returnStdout: true, script: 'uname -s').trim() : 'Windows'
final String linker = "/usr/bin/${path}-ld" final String linker = "/usr/bin/${path}-ld"
final boolean not_packer_compatible = path.contains('riscv') || ((path.contains('aarch64') || path.contains('arm')) && path.contains('mingw')) final boolean not_packer_compatible = path.contains('riscv') || ((path.contains('aarch64') || path.contains('arm')) && path.contains('mingw'))
final String build_directory = "cmake-build-${use_toolchain ? path.substring(path.lastIndexOf('/') + 1, path.length() - 6) : path}".toLowerCase() final String build_directory = "cmake-build-${use_toolchain ? path.substring(path.lastIndexOf('/') + 1, path.length() - 6) : path}".toLowerCase()
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
// Note: CMake 3.20 or higher is needed
cmakeBuild buildDir: build_directory, buildType: 'release', cleanBuild: true, installation: 'Latest', cmakeBuild buildDir: build_directory, buildType: 'release', cleanBuild: true, installation: 'Latest',
cmakeArgs: "--no-warn-unused-cli ${use_toolchain ? "-DCMAKE_TOOLCHAIN_FILE=${path}" : "-DCMAKE_SYSTEM_NAME=\"${system_name}\" -DCXX_TARGET=\"${use_toolchain ? 'noarch' : debArch}\" -DCPACK_RPM_PACKAGE_ARCHITECTURE=${rpmArch} -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=${debArch} -DCMAKE_C_COMPILER=/usr/bin/${path}-gcc -DCMAKE_CXX_COMPILER=/usr/bin/${path}-g++ ${system_name == 'Android' ? "-DCMAKE_SYSTEM_VERSION=21 -DCMAKE_ANDROID_STL_TYPE=c++_static -DCMAKE_CXX_FLAGS=-static-openmp -DCMAKE_ANDROID_NDK=/usr/android-ndk -DCMAKE_ANDROID_ARCH_ABI=${"${TARGET}".substring("${TARGET}".indexOf(' -> ') + 4)}" : "-DCMAKE_SYSTEM_PROCESSOR=${path.substring(0, path.indexOf('-'))}"} -DCMAKE_LINKER=${fileExists("${linker}.gold") ? "${linker}.gold" : linker} -DCMAKE_AR=/usr/bin/${path}-ar -DCMAKE_RC_COMPILER=/usr/bin/${path}-windres -DCMAKE_EXE_LINKER_FLAGS=-static"} -DNO_SELF_PACKER=${!(not_packer_compatible || use_toolchain) ? "OFF" : "ON"} -DIGNORE_MINIMAL_COMPILER_VERSION=ON -DNO_CCACHE=ON -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON${path.endsWith('armv7-w64-mingw32') ? ' -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=NO' : ''}", cmakeArgs: "--no-warn-unused-cli ${use_toolchain ? "-DCMAKE_TOOLCHAIN_FILE=${path}" : "-DCMAKE_SYSTEM_NAME=\"${system_name}\" -DCXX_TARGET=\"${use_toolchain ? 'noarch' : debArch}\" -DCPACK_RPM_PACKAGE_ARCHITECTURE=${rpmArch} -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=${debArch} -DCMAKE_SYSTEM_PROCESSOR=\"${path.substring(0, path.indexOf('-'))}\" -DCMAKE_C_COMPILER=/usr/bin/${path}-gcc -DCMAKE_CXX_COMPILER=/usr/bin/${path}-g++ -DCMAKE_LINKER=${fileExists("${linker}.gold") ? "${linker}.gold" : linker} -DCMAKE_AR=/usr/bin/${path}-ar -DCMAKE_RC_COMPILER=/usr/bin/${path}-windres -DCMAKE_EXE_LINKER_FLAGS=-static"} -DNO_SELF_PACKER=${!(not_packer_compatible || use_toolchain) ? "OFF" : "ON"} -DIGNORE_MINIMAL_COMPILER_VERSION=ON -DNO_CCACHE=ON -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON${path.endsWith('armv7-w64-mingw32') ? ' -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=NO' : ''}",
generator: cmake_generator() generator: cmake_generator()
cmake arguments: "--build ./$build_directory --target ${!("${TARGET}".endsWith('Emscripten.cmake') && use_yarn_or_npm()) ? 'ybcon' : 'yao_pkg'}", installation: 'Latest' cmake arguments: "--build ./$build_directory --target ${!("${TARGET}".endsWith('Emscripten.cmake') && use_yarn_or_npm()) ? 'ybcon' : 'vercel_pkg'}", installation: 'Latest'
} }
} }
} }

View File

@ -1,6 +1,6 @@
# Yerbacon # Yerbacon
<img title="Yer &#129363;" align="left" src="resources/Yerbacon.svg" alt="Yerbacon logo" width="192" height="192"> <img title="Yer &#129363;" align="left" src="/Username404-59/Yerbacon/raw/branch/stable/resources/Yerbacon.svg" alt="Yerbacon logo" width="192" height="192">
### &#9658; A language that transpiles into another programming language, like Lua, JavaScript (ES6) or Python. ### &#9658; A language that transpiles into another programming language, like Lua, JavaScript (ES6) or Python.
``` ```

View File

@ -2,8 +2,9 @@
"name": "@EXENAME@", "name": "@EXENAME@",
"bin": "@EXENAME@.js", "bin": "@EXENAME@.js",
"license": "@CPACK_RPM_PACKAGE_LICENSE@", "license": "@CPACK_RPM_PACKAGE_LICENSE@",
"devDependencies": { "@yao-pkg/pkg": "^5.9.0" }, "devDependencies": { "pkg": "^5.8.0" },
"pkg": {@YAO_ASSETS@ "pkg": {
"assets": "../@EXENAME@.worker.js",
"targets": [ "targets": [
"latest-macos-x64", "latest-macos-x64",
"latest-macos-arm64" "latest-macos-arm64"

View File

@ -8,7 +8,7 @@ _ybconAutoComplete() {
COMPREPLY=() COMPREPLY=()
current="${COMP_WORDS[COMP_CWORD]}" current="${COMP_WORDS[COMP_CWORD]}"
previous="${COMP_WORDS[COMP_CWORD-1]}" previous="${COMP_WORDS[COMP_CWORD-1]}"
options='-h -p -t -o --help --parallel --target= --newlines= --printresult --text --output --version --buildInfo' options='-h -p -t --help --parallel --target= --newlines= --printresult --text --version --buildInfo'
if [[ "${current}" == -* ]]; then if [[ "${current}" == -* ]]; then
YCompReply "$(compgen -W "$options" -- "$current")" YCompReply "$(compgen -W "$options" -- "$current")"
return 0 return 0

View File

@ -8,5 +8,4 @@ complete -c ybcon -l parallel -k -d "Transpile files in parallel mode"
complete -c ybcon -l target -k -f -a 'lua js py' -d "Set the transpilation target" complete -c ybcon -l target -k -f -a 'lua js py' -d "Set the transpilation target"
complete -c ybcon -l newlines -k -f -a 'on off' -d "Enable or disable new lines" complete -c ybcon -l newlines -k -f -a 'on off' -d "Enable or disable new lines"
complete -c ybcon -s p -l printresult -d "Enable printing the transpilation result to stdout" complete -c ybcon -s p -l printresult -d "Enable printing the transpilation result to stdout"
complete -c ybcon -x -s t -l text -d "Transpile text provided after this argument (implies -p)" complete -c ybcon -x -s t -l text -d "Transpile text provided after this argument (implies -p)"
complete -c ybcon -x -s o -l output -a '(__fish_complete_directories)' -d 'Output the transpiled file(s) to the specified directory'

View File

@ -10,7 +10,6 @@ _ybcon() {
--newlines='[Enable or disable new lines]:state:(on off)' \ --newlines='[Enable or disable new lines]:state:(on off)' \
{-p,--printresult}'[Enable printing the transpilation result to stdout]' \ {-p,--printresult}'[Enable printing the transpilation result to stdout]' \
{-t,--text}'[Transpile text provided after this argument (implies -p)]' \ {-t,--text}'[Transpile text provided after this argument (implies -p)]' \
{-o,--output}'[Output the transpiled file(s) to the specified directory]' \
"*:$completeyfile" "*:$completeyfile"
return 0 return 0
} }

View File

@ -21,7 +21,6 @@ usage() {
echo " --newlines=on/off Enable or disable new lines" echo " --newlines=on/off Enable or disable new lines"
echo " -p or --printresult Enable printing the transpilation result to stdout" echo " -p or --printresult Enable printing the transpilation result to stdout"
echo " -t or --text Transpile text provided after this argument (implies -p)" echo " -t or --text Transpile text provided after this argument (implies -p)"
echo " -o or --output Output the transpiled file(s) to the specified directory"
printf "\n" printf "\n"
fi fi
} }

View File

@ -17,4 +17,7 @@ string getFileContent(const string& file)
} else throw Yerbacon::Exception("Could not open \"" + file + "\" : " + generic_category().message(errno)); } else throw Yerbacon::Exception("Could not open \"" + file + "\" : " + generic_category().message(errno));
} }
void outputFileContent(const string& file, const string_view content) { ofstream(file, ofstream::out) << content;} void outputFileContent(const string& file, const string_view content) {
ofstream outputFile (file, ofstream::out);
outputFile << content;
}

View File

@ -64,9 +64,9 @@ vector<tok> lex(const string_view& in)
string formedString; string formedString;
for (;i < in.size(); ++i) { for (;i < in.size(); ++i) {
const tok::type currentCharType = getIdentifierCharType(in[i]); const tok::type currentCharType = getIdentifierCharType(in[i]);
const bool isStringDelimiter = currentCharType == STRING; const bool isString = currentCharType == STRING;
if (isTypeString && (i == in.size() - 1 && not isStringDelimiter)) throw tok::LexerException("A never ending string was found", lineNumber); if (isTypeString && (i == in.size() - 1 && not isString)) throw tok::LexerException("A never ending string was found", lineNumber);
if ((currentCharType == type || isTypeString) && !isStringDelimiter) { if ((currentCharType == type || isTypeString) && !isString) {
formedString += in[i]; formedString += in[i];
} else { } else {
if (not isTypeString) --i; if (not isTypeString) --i;
@ -81,5 +81,10 @@ vector<tok> lex(const string_view& in)
} }
} }
} }
/* Test
for (const auto& it : resVal) {
cout << it << ' ' << it.toktype << '\n';
}
*/
return resVal; return resVal;
} }

View File

@ -1,58 +0,0 @@
#ifndef YERBACON_SEMANTICANALYSIS_HPP
#define YERBACON_SEMANTICANALYSIS_HPP
#include "parsing/ParseComponents.hpp"
#include "Tasking.hpp"
using namespace StandardComponents;
struct SemanticAnalyser final: public Tasking {
typedef Yerbacon::Exception SemanticException;
static void error(const string_view& text, unsigned long line = 0) {
throw SemanticException(text, line);
}
const auto& analyseTree(const ParseTree& tree) {
const auto& task_map = getTaskMapInstance();
for (unsigned int i = 0; i < tree.size(); ++i) {
try {
task_map.at(tree[i]->getId())(tree, i);
} catch (const out_of_range&) {}
}
return tree;
}
private:
unordered_task_map getTaskMapInstance() final {
using namespace StandardComponents;
return {
make_nonlocal_task(Function,
if (index > 0 and any_of(parsedTree.cbegin(), parsedTree.cbegin() + index, [&parseComponent](const component_ptr& pointer){
if (pointer->getId() != typeid(Reference)) {
string_view ptr_name;
try {
ptr_name = dynamic_cast<NamedIdentifier<true>&>(*pointer).name;
} catch (const bad_cast&) {
try {
ptr_name = dynamic_cast<NamedIdentifier<false>&>(*pointer).name;
} catch (const bad_cast&) {
return false;
}
};
if (ptr_name == parseComponent.name) {
return true;
}
}
return false;
})) { error(parseComponent.name + " has already been defined previously", parseComponent.line); }
),
share_task(Function, Class),
share_task(Function, Define<true>),
make_nonlocal_task(Define<false>,
if (parsedTree.findReferenceByName<Define<true>>(parseComponent.name).has_value()) {
error(parseComponent.name + string(" cannot be redefined as it is final"), parseComponent.line);
}
)
};
};
};
#endif //YERBACON_SEMANTICANALYSIS_HPP

View File

@ -1,24 +0,0 @@
#ifndef YERBACON_TASKING_HPP
#define YERBACON_TASKING_HPP
#include <typeindex>
#include <unordered_map>
#include "parsing/ParseComponents.hpp"
#define make_task_base(start, type, captures, function_body) make_pair(type_index(typeid(type)), [captures](const ParseTree& parsedTree, unsigned int& index) { start; function_body })
#define make_task_base_R(T, C, F) make_task_base(const T& parseComponent = reinterpret_cast<T&>(*parsedTree[index]), T, C, F)
#define make_task(T, F) make_task_base_R(T, this, F)
#define make_task_noR(T, F) make_task_base(,T, this, F)
#define make_nonlocal_task(T, F) make_task_base_R(T, , F)
#define share_task(T, T2) make_task_noR(T2, this->getTaskMapInstance()[typeid(T)](parsedTree, index);)
class Tasking {
protected:
typedef function<void (const ParseTree& parsedTree, unsigned int& index)> task;
typedef unordered_map<type_index, task> unordered_task_map;
public:
virtual unordered_task_map getTaskMapInstance() = 0;
virtual ~Tasking() = default;
};
#endif //YERBACON_TASKING_HPP

View File

@ -23,10 +23,6 @@
#error "The current standard library is incomplete" #error "The current standard library is incomplete"
#endif #endif
#ifdef _OPENMP
#include <omp.h>
#endif
#define token_expansion(X) #X #define token_expansion(X) #X
#define make_string(X) token_expansion(X) #define make_string(X) token_expansion(X)

View File

@ -1,36 +0,0 @@
#ifndef YERBACON_EMSCRIPTEN_COMPATIBILITY_H
#define YERBACON_EMSCRIPTEN_COMPATIBILITY_H
#include <string_view>
#include <string>
#include <filesystem>
filesystem::path mount(const std::string_view& element_path) {
filesystem::path file_path = element_path;
#ifdef EMSCRIPTEN
if (element_path.size() >= 2 and element_path[1] == ':') {
auto path = string(element_path.begin() + 2, element_path.end());
replace(path.begin(), path.end(), '\\', '/');
file_path = path;
}
const string directory = filesystem::path(file_path).remove_filename();
cout << "Directory: " << directory << endl;
for (unsigned int character = 1; character < directory.size(); ++character) {
const string sub_directory = directory.substr(0, character);
if (is_node and (directory[character] == '/') and not filesystem::is_directory(sub_directory)) {
MAIN_THREAD_EM_ASM({
const sub_directory = UTF8ToString($0);
if (!FS.isMountpoint(sub_directory)) {
try {
FS.mkdir(sub_directory);
FS.mount(NODEFS, {root: sub_directory}, sub_directory);
} catch (exception) {}
};
}, sub_directory.c_str());
}
}
#endif
return file_path;
}
#endif //YERBACON_EMSCRIPTEN_COMPATIBILITY_H

View File

@ -24,7 +24,6 @@ template<bool disallow_reserved>
struct NamedIdentifier: virtual ParseComponent { struct NamedIdentifier: virtual ParseComponent {
struct identifier_reserved_exception: exception {}; struct identifier_reserved_exception: exception {};
const string name; const string name;
unsigned long line = 0;
explicit NamedIdentifier(const string_view nameText): name(nameText) { explicit NamedIdentifier(const string_view nameText): name(nameText) {
if (disallow_reserved and reserved(name)) { if (disallow_reserved and reserved(name)) {
throw identifier_reserved_exception(); throw identifier_reserved_exception();
@ -42,7 +41,6 @@ class ParseTree: public virtual ParseComponent {
using array_type = decltype(subComponents); using array_type = decltype(subComponents);
using iterator = array_type::iterator; using iterator = array_type::iterator;
using constant_iterator = array_type::const_iterator; using constant_iterator = array_type::const_iterator;
mutable optional<reference_wrapper<const ParseTree>> parent;
protected: protected:
IS_PARSECOMPONENT IS_PARSECOMPONENT
void addComponent(const T& component) const { void addComponent(const T& component) const {
@ -52,9 +50,6 @@ protected:
static_assert(is_move_constructible_v<T>, "T is not copy-constructible or move-constructible"); static_assert(is_move_constructible_v<T>, "T is not copy-constructible or move-constructible");
subComponents.emplace_back(new T(move(const_cast<T&>(component)))); subComponents.emplace_back(new T(move(const_cast<T&>(component))));
} }
if constexpr(is_base_of_v<ParseTree, T>) {
reinterpret_cast<const ParseTree&>(*subComponents.back()).parent = cref(*this);
}
}; };
IS_PARSECOMPONENT IS_PARSECOMPONENT
void addAllComponents( void addAllComponents(
@ -67,19 +62,9 @@ public:
inline size_t size() const { return subComponents.size(); } inline size_t size() const { return subComponents.size(); }
inline bool empty() const { return size() == 0; } inline bool empty() const { return size() == 0; }
inline iterator begin() noexcept { return subComponents.begin(); } inline iterator begin() noexcept { return subComponents.begin(); }
inline constant_iterator begin() const noexcept { return cbegin(); }
inline constant_iterator cbegin() const noexcept { return subComponents.cbegin(); } inline constant_iterator cbegin() const noexcept { return subComponents.cbegin(); }
inline iterator end() noexcept { return subComponents.end(); } inline iterator end() noexcept { return subComponents.end(); }
inline constant_iterator end() const noexcept { return cend(); }
inline constant_iterator cend() const noexcept { return subComponents.cend(); } inline constant_iterator cend() const noexcept { return subComponents.cend(); }
const decltype(parent)& getParent() const { return parent; }
void traverse_parent(const auto& lambda) const
{ if (parent.has_value()) for_each(parent.value().get().begin(), parent.value().get().end(), lambda); }
bool any_parent(const auto& lambda) const
{ return parent.has_value() and any_of(parent.value().get().begin(), parent.value().get().end(), lambda); }
IS_PARSECOMPONENT IS_PARSECOMPONENT
vector<T*> findById() const { vector<T*> findById() const {
vector<T*> filteredComponents; vector<T*> filteredComponents;
@ -118,12 +103,12 @@ public:
#undef IS_PARSECOMPONENT #undef IS_PARSECOMPONENT
namespace StandardComponents { namespace StandardComponents {
template<bool BOOL>
struct Define: NamedIdentifier<true> { struct Define: NamedIdentifier<true> {
const bool final = BOOL; const bool final;
ParseTree content; ParseTree content;
explicit Define(string_view nameText, ParseTree&& content): NamedIdentifier(nameText), content(move(content)) {} explicit Define(const bool& isFinal, string_view nameText, ParseTree&& content): NamedIdentifier(nameText), final(isFinal), content(move(content)) {}
Define(Define&& define) noexcept: Define(define.name, move(define.content)) {} explicit Define(string_view nameText, ParseTree&& content): Define(false, nameText, move(content)) {}
Define(Define&& define) noexcept: Define(define.final, define.name, move(define.content)) {}
}; };
struct Reference: NamedIdentifier<false> { struct Reference: NamedIdentifier<false> {
using NamedIdentifier::NamedIdentifier; using NamedIdentifier::NamedIdentifier;
@ -143,42 +128,6 @@ namespace StandardComponents {
struct Call: ParseTree, Reference { struct Call: ParseTree, Reference {
using Reference::Reference; using Reference::Reference;
}; };
struct Operator: ParseComponent { // TODO Parse operators in Parser.hpp
tok::type operator_type;
Operator(const convertible_to<tok::type> auto& operator_token): operator_type() {
using enum tok::type;
static_assert((operator_token == PLUS or operator_token == HYPHEN or operator_token == ASTERISK or operator_token == DIVIDE or operator_token == LCOMP or operator_token == RCOMP));
operator_type = operator_token;
}
};
struct Condition: ParseTree {
Condition(const ParseTree left, const ParseTree right, const Operator& operator_token) {
*this << left << operator_token << right;
}
explicit Condition(const derived_from<ParseComponent> auto condition) { *this << condition; }
struct Statement;
protected:
Condition() = default;
};
struct Condition::Statement: ParseTree {
struct Branch;
Condition condition;
ParseTree else_branches;
bool is_last_branch_conditional() const;
Statement(Condition _condition): ParseTree(), condition(move(_condition)), else_branches() {}
protected:
Statement(): condition(), else_branches() {}
};
struct Condition::Statement::Branch: Condition::Statement {
inline bool is_conditional() const { return not condition.empty(); };
using Condition::Statement::Statement; Branch(): Condition::Statement() {};
private:
using Condition::Statement::is_last_branch_conditional;
};
bool Condition::Statement::is_last_branch_conditional() const {
const auto* last = (not else_branches.empty()) ? dynamic_cast<const Branch*>(else_branches[else_branches.size() - 1].get()) : nullptr;
return (last == nullptr and (not this->condition.empty())) or (last != nullptr and not last->condition.empty());
}
struct Function: NamedIdentifier<true>, ParseTree { struct Function: NamedIdentifier<true>, ParseTree {
ParseTree parameters; ParseTree parameters;

View File

@ -88,48 +88,14 @@ namespace Parser {
} else { } else {
unsigned int parametersDistance = 0; unsigned int parametersDistance = 0;
if (next.toktype == LPAR) { if (next.toktype == LPAR) {
const auto closing = find_corresponding(lexed.begin() + i + 2, lexed.end(), LPAR, RPAR); const auto closing = find_if(lexed.begin() + i, lexed.end(), [](const tok& token){ return token.toktype == RPAR; });
parametersDistance = distance(lexed.begin() + i, closing); parametersDistance = distance(lexed.begin() + i, closing);
i += parametersDistance; i += parametersDistance;
} }
const bool is_branch = current.toktext == ID(CONDITION_STATEMENT_BRANCH); if (nextAre({LCOMP, LCOMP, LBRACE})) {
const bool is_conditional_branch = (not is_branch) and current.toktext == ID(CONDITION_STATEMENT_CONDITIONAL_BRANCH);
if (current.toktext == ID(CONDITION_STATEMENT) or is_branch or is_conditional_branch) {
if (is_branch or is_conditional_branch) {
const auto& last_id = parseTree.at(parseTree.size() - 1)->getId();
if (last_id != typeid(Condition::Statement)) {
parsingError(current, "unexpected \"" + current.toktext + "\" without preceding if statement");
}
}
const bool has_condition = next.toktype == LPAR and ((lexed.begin() + i - parametersDistance) + 2) < lexed.begin() + i;
if (not has_condition and not is_branch) parsingError(current, "missing condition after an \"" + current.toktext + "\" statement");
if (*(lexed.begin() + i + 1) != tok::LBRACE) parsingError(*(lexed.begin() + i), "missing statement body");
const auto body_end = find_corresponding(lexed.begin() + i + 2, lexed.end(), LBRACE, RBRACE);
auto* statement = (is_branch or is_conditional_branch) ? dynamic_cast<Condition::Statement*>(parseTree[parseTree.size() - 1].get()) : nullptr;
auto& else_branches = statement->else_branches;
if ((is_conditional_branch or is_branch) and not statement->is_last_branch_conditional())
parsingError(current, "<- unexpected branch", true);
Condition condition ((ParseTree()));
// TODO Check that the condition is valid
if (has_condition)
condition = Condition(parse((lexed.begin() + i - parametersDistance) + 2, lexed.begin() + i));
if (has_condition or is_branch) {
if (is_conditional_branch or is_branch) {
auto branch = (has_condition ? (Condition::Statement::Branch(move(condition))) : Condition::Statement::Branch());
branch.ParseTree::operator=(parse(lexed.begin() + i + 2, body_end));
else_branches << branch;
} else {
Condition::Statement new_statement (move(condition));
new_statement.ParseTree::operator=(parse(lexed.begin() + i + 2, body_end));
parseTree << new_statement;
}
i += distance(lexed.begin() + i, body_end);
}
continue;
} else if (nextAre({LCOMP, LCOMP, LBRACE})) {
Function function(current.toktext); Function function(current.toktext);
if (parametersDistance > 2) if (parametersDistance > 2)
function.parameters = parse(filter_comma_list(lexed.begin() + ((i + 2) - parametersDistance), lexed.begin() + i)); // TODO Parse parameters correctly function.parameters = parse(filter_comma_list(lexed.begin() + ((i + 2) - parametersDistance), lexed.begin() + i));
parseTree << function; parseTree << function;
i += 2; i += 2;
break; break;
@ -137,16 +103,15 @@ namespace Parser {
bool isFinalDefine = nextAre({TAG, DEFINE}); bool isFinalDefine = nextAre({TAG, DEFINE});
if (isFinalDefine || next.toktype == DEFINE) { if (isFinalDefine || next.toktype == DEFINE) {
const optional previousDefinition = parseTree.template findReferenceByName<Define>(current.toktext);
if (previousDefinition.has_value() && (previousDefinition.value().get().final || isFinalDefine))
parsingError(current, previousDefinition->get().final ? " cannot be redefined as it is final" : " cannot be made final after it has been declared", true);
const unsigned increment = 2 + isFinalDefine; const unsigned increment = 2 + isFinalDefine;
const auto beginning = lexed.begin() + i + increment; const auto beginning = lexed.begin() + i + increment;
const auto end = find_if(beginning, lexed.end(), [&current](const tok& it){ const auto end = find_if(beginning, lexed.end(), [&current](const tok& it){
return it.toktype == SEMICOLON || it.line != current.line; return it.toktype == SEMICOLON || it.line != current.line;
}); });
auto&& body = parse(beginning, end); parseTree << Define(isFinalDefine, current.toktext, parse(beginning, end));
if (isFinalDefine)
parseTree << Define<true>(current.toktext, move(body));
else
parseTree << Define<false>(current.toktext, move(body));
i += 1 + isFinalDefine + distance(beginning, end); i += 1 + isFinalDefine + distance(beginning, end);
} else { } else {
const bool method = nextAre({DOT, IDENTIFIER, LPAR}); const bool method = nextAre({DOT, IDENTIFIER, LPAR});
@ -154,7 +119,7 @@ namespace Parser {
const string name = property or method ? current.toktext + '.' + lexed[i + 2].toktext : current.toktext; const string name = property or method ? current.toktext + '.' + lexed[i + 2].toktext : current.toktext;
if (method or next.toktype == LPAR) { if (method or next.toktype == LPAR) {
parseTree << Call(name); parseTree << Call(name);
} else { } else if (property) {
parseTree << Reference(name); parseTree << Reference(name);
} }
if (property or method) i += 2; if (property or method) i += 2;
@ -184,14 +149,20 @@ namespace Parser {
} catch (const NamedIdentifier<true>::identifier_reserved_exception&) { } catch (const NamedIdentifier<true>::identifier_reserved_exception&) {
parsingError(current, " is a reserved identifier", true); parsingError(current, " is a reserved identifier", true);
} }
if (!parseTree.empty()) { if (not parseTree.empty()) {
const component_ptr& last = parseTree[parseTree.size() - 1]; const auto& last = parseTree.cend() - 1;
try { const type_info& lastId = last->get()->getId();
dynamic_cast<NamedIdentifier<true>&>(*last).line = current.line; const auto* last_identifier = dynamic_cast<NamedIdentifier<true>*>(last->get());
} catch (const bad_cast&) { if (last_identifier != nullptr) {
try { if (lastId != typeid(Define) and
dynamic_cast<NamedIdentifier<false>&>(*last).line = current.line; any_of(parseTree.cbegin(), last, [&last_identifier](const component_ptr& pointer){
} catch (const bad_cast&) {} try {
return dynamic_cast<NamedIdentifier<true>&>(*pointer).name == last_identifier->name;
} catch (const bad_cast&) {
return false;
}
}))
{ parsingError(current, " has already been defined previously", true); }
} }
} }
} }

View File

@ -7,11 +7,11 @@
#include <string_view> #include <string_view>
static constinit const array identifiers { static constinit const array identifiers {
"class", "structure", "print", "print_line", "if", "else", "elseif" "class", "structure", "print", "print_line"
}; };
enum class ReservedIdentifier: size_t { enum class ReservedIdentifier: size_t {
CLASS, STRUCT, PRINT_FUNCTION, PRINT_LINE_FUNCTION, CONDITION_STATEMENT, CONDITION_STATEMENT_BRANCH, CONDITION_STATEMENT_CONDITIONAL_BRANCH CLASS, STRUCT, PRINT_FUNCTION, PRINT_LINE_FUNCTION
}; };
inline const char* ID(const ReservedIdentifier& identifier) { inline const char* ID(const ReservedIdentifier& identifier) {

View File

@ -15,9 +15,8 @@
#endif #endif
#include "../parsing/ParseComponents.hpp" #include "../parsing/ParseComponents.hpp"
#include "../Tasking.hpp"
class Target: protected Tasking { class Target {
constexpr static const char* const interpolationString = "${"; constexpr static const char* const interpolationString = "${";
constexpr static const char* const interpolationCloseString = "}"; constexpr static const char* const interpolationCloseString = "}";
protected: protected:
@ -66,6 +65,13 @@ protected:
} }
} else output << openCharacters << view << closeCharacters; } else output << openCharacters << view << closeCharacters;
} }
typedef function<void (const ParseTree& parsedTree, unsigned int& index)> task;
#define make_task_base(start, type, captures, function_body) make_pair(type_index(typeid(type)), [captures](const ParseTree& parsedTree, unsigned int& index) { start; function_body })
#define make_task_base_R(T, C, F) make_task_base(const T& parseComponent = reinterpret_cast<T&>(*parsedTree[index]), T, C, F)
#define make_task(T, F) make_task_base_R(T, this, F)
#define make_task_noR(T, F) make_task_base(,T, this, F)
#define make_nonlocal_task(T, F) make_task_base_R(T, , F)
typedef unordered_map<type_index, task> unordered_task_map;
typedef pair<const char*, const char*> print_functions_pair; typedef pair<const char*, const char*> print_functions_pair;
virtual unordered_task_map getTaskMap() = 0; virtual unordered_task_map getTaskMap() = 0;
virtual print_functions_pair printFunctions() = 0; virtual print_functions_pair printFunctions() = 0;
@ -87,7 +93,7 @@ protected:
} catch (const out_of_range&) { } catch (const out_of_range&) {
throw Yerbacon::Exception(string( throw Yerbacon::Exception(string(
#ifndef __GNUC__ #ifndef __GNUC__
id.name() // This is undefined behaviour but most other compilers should output the name id.name()
#else #else
abi::__cxa_demangle(id.name(), nullptr, nullptr, nullptr) abi::__cxa_demangle(id.name(), nullptr, nullptr, nullptr)
#endif #endif
@ -102,13 +108,13 @@ protected:
void separate_transpileTree(const T& parseTree, const unsigned short& indentationLevel = 0) { void separate_transpileTree(const T& parseTree, const unsigned short& indentationLevel = 0) {
transpileTree(parseTree, indentationLevel, [this, &parseTree](const auto& iterator){ transpileTree(parseTree, indentationLevel, [this, &parseTree](const auto& iterator){
if ((newLines || iterator + 1 == parseTree.cend()) && use_uniqueLineSeparator()) output << uniqueLineSeparator().value(); if ((newLines || iterator + 1 == parseTree.cend()) && use_uniqueLineSeparator()) output << uniqueLineSeparator().value();
if (iterator + 1 < parseTree.cend()) output << separator; if (iterator + 1 != parseTree.cend()) output << separator;
}); });
} }
IS(ParseTree) IS(ParseTree)
void separate_transpileTree(const T& parseTree, const string_view separation_characters) { void separate_transpileTree(const T& parseTree, const string_view separation_characters) {
transpileTree(parseTree, 0, [this, &parseTree, &separation_characters](const auto& iterator){ transpileTree(parseTree, 0, [this, &parseTree, &separation_characters](const auto& iterator){
if (iterator + 1 < parseTree.cend()) { output << separation_characters; } if (iterator + 1 != parseTree.cend()) { output << separation_characters; }
}); });
} }
typedef optional<const char*> optional_string; typedef optional<const char*> optional_string;
@ -118,7 +124,7 @@ protected:
string separator; string separator;
static constexpr const char* indentation = " "; static constexpr const char* indentation = " ";
public: public:
unordered_task_map getTaskMapInstance() final { unordered_task_map getTaskMapInstance() {
unordered_task_map fullMap = getTaskMap(); unordered_task_map fullMap = getTaskMap();
// Default / Shared tasks: // Default / Shared tasks:
fullMap.merge(unordered_task_map({ fullMap.merge(unordered_task_map({
@ -131,9 +137,7 @@ public:
separate_transpileTree(parseComponent, ", "); separate_transpileTree(parseComponent, ", ");
output << ')'; output << ')';
), ),
make_task(StandardComponents::types::Integer, output << setprecision(parseComponent.precision) << fixed << parseComponent.value;), make_task(StandardComponents::types::Integer, output << setprecision(parseComponent.precision) << fixed << parseComponent.value;)
make_task(StandardComponents::Condition, output << '('; transpileTree(parseComponent); output << ')';),
share_task(StandardComponents::Define<false>, StandardComponents::Define<true>)
})); }));
return fullMap; return fullMap;
}; };
@ -146,7 +150,7 @@ public:
}; };
explicit Target(const bool& newLines): output(), newLines(newLines), separator() {}; explicit Target(const bool& newLines): output(), newLines(newLines), separator() {};
Target() = delete; Target() = delete;
~Target() override = default; virtual ~Target() = default;
}; };
#include "implementations/Lua.hpp" #include "implementations/Lua.hpp"
@ -161,7 +165,12 @@ unique_ptr<Target> Target::forName(string_view name, const bool newLines = true)
ADDTARGET("py", PyTarget); ADDTARGET("py", PyTarget);
ADDTARGET("gd", GsTarget); ADDTARGET("gd", GsTarget);
#undef ADDTARGET #undef ADDTARGET
Yerbacon::fail({"\"", name.data(), "\" is not a valid target."}); #undef make_nonlocal_task
#undef make_task_noR
#undef make_task
#undef make_task_base_R
#undef make_task_base
Yerbacon::fail({"\"", string(1, (char) toupper(name.at(1))).data(), name.substr(2).data(), "\" is not a valid target."});
return nullptr; return nullptr;
} }

View File

@ -1,13 +1,12 @@
#ifndef GODOTSCRIPT_HPP #ifndef GODOTSCRIPT_HPP
#define GODOTSCRIPT_HPP #define GODOTSCRIPT_HPP
using namespace StandardComponents;
struct GsTarget: Target { struct GsTarget: Target {
print_functions_pair printFunctions() final { return make_pair("printraw", "print"); } print_functions_pair printFunctions() final { return make_pair("printraw", "print"); }
unordered_task_map getTaskMap() final { unordered_task_map getTaskMap() final {
return { return {
make_task(Define<false>, make_task(Define,
output << (parseComponent.final ? "const " : "var ") << parseComponent.name << " = "; // TODO Handle redefining GodotScript variables output << (parseComponent.final ? "const " : "var ") << parseComponent.name << " = ";
transpileTree(parseComponent.content); transpileTree(parseComponent.content);
), ),
make_task(types::String, stringInterpolation(R"(""")", parseComponent.content);), make_task(types::String, stringInterpolation(R"(""")", parseComponent.content);),
@ -17,23 +16,6 @@ struct GsTarget: Target {
output << "):" << separator << indentation; output << "):" << separator << indentation;
if (parseComponent.empty()) output << "pass"; if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << "):" << separator << indentation;
if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
output << separator;
separate_transpileTree(parseComponent.else_branches);
}
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << "elif ("; transpileTree(parseComponent.condition); output << ")";
} else output << "else";
output << ':' << separator << indentation;
separate_transpileTree(parseComponent, 1);
if (parseComponent.empty()) output << "pass";
) )
}; };
} }

View File

@ -7,7 +7,7 @@ struct JsTarget: Target {
bool use_uniqueLineSeparator() final { return true; } bool use_uniqueLineSeparator() final { return true; }
unordered_task_map getTaskMap() final { unordered_task_map getTaskMap() final {
return { return {
make_task(Define<false>, make_task(Define,
output << (parseComponent.final ? "const " : "let ") << parseComponent.name << " = "; output << (parseComponent.final ? "const " : "let ") << parseComponent.name << " = ";
transpileTree(parseComponent.content); transpileTree(parseComponent.content);
), ),
@ -20,27 +20,6 @@ struct JsTarget: Target {
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
if (newLines and not parseComponent.empty()) output << separator; if (newLines and not parseComponent.empty()) output << separator;
output << '}'; output << '}';
),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << ") {";
if (not parseComponent.empty()) {
if (newLines) output << separator << indentation; }
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
if (newLines) output << separator;
output << '}';
separate_transpileTree(parseComponent.else_branches, string((newLines) ? separator : "") + '}');
}
if (newLines) output << separator;
output << '}';
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << " else if ("; transpileTree(parseComponent.condition); output << ')';
} else output << " else";
output << " {";
if (newLines) output << separator << indentation;
separate_transpileTree(parseComponent, 1);
) )
}; };
} }

View File

@ -7,7 +7,7 @@ struct LuaTarget: Target {
optional_string uniqueLineSeparator() final { return " "; } optional_string uniqueLineSeparator() final { return " "; }
unordered_task_map getTaskMap() final { unordered_task_map getTaskMap() final {
return { return {
make_task(Define<false>, make_task(Define,
if (parseComponent.final) output << "local "; if (parseComponent.final) output << "local ";
output << parseComponent.name; output << parseComponent.name;
if (parseComponent.final) output << " <const>"; // TODO Find an alternative to <const> for lua <5.4 if (parseComponent.final) output << " <const>"; // TODO Find an alternative to <const> for lua <5.4
@ -26,25 +26,6 @@ struct LuaTarget: Target {
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
if (not parseComponent.empty()) output << separator; if (not parseComponent.empty()) output << separator;
output << "end"; output << "end";
),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << ") then";
if (not parseComponent.empty()) {
output << separator; if (newLines) output << indentation; }
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
output << separator;
separate_transpileTree(parseComponent.else_branches);
}
output << separator << "end";
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << "elseif ("; transpileTree(parseComponent.condition); output << ") then";
} else output << "else";
output << separator;
if (newLines) output << indentation;
separate_transpileTree(parseComponent, 1);
) )
}; };
} }

View File

@ -7,7 +7,7 @@ struct PyTarget: Target {
optional_string uniqueLineSeparator() final { return {}; } optional_string uniqueLineSeparator() final { return {}; }
unordered_task_map getTaskMap() final { unordered_task_map getTaskMap() final {
return { return {
make_task(Define<false>, output << parseComponent.name << " = "; transpileTree(parseComponent.content);), make_task(Define, output << parseComponent.name << " = "; transpileTree(parseComponent.content);),
make_task(types::String, stringInterpolation(R"(""")", parseComponent.content);), make_task(types::String, stringInterpolation(R"(""")", parseComponent.content);),
make_task(Function, make_task(Function,
output << "def " << parseComponent.name << '('; output << "def " << parseComponent.name << '(';
@ -16,28 +16,6 @@ struct PyTarget: Target {
if (parseComponent.empty()) output << "pass"; if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1); separate_transpileTree(parseComponent, 1);
), ),
make_task(Condition::Statement,
output << "if ("; transpileTree(parseComponent.condition); output << "):" << separator << indentation;
if (parseComponent.empty()) output << "pass";
separate_transpileTree(parseComponent, 1);
if (not parseComponent.else_branches.empty()) {
output << separator;
separate_transpileTree(parseComponent.else_branches);
}
),
make_task(Condition::Statement::Branch,
if (parseComponent.is_conditional()) {
output << "elif ("; transpileTree(parseComponent.condition); output << ")";
} else output << "else";
output << ':' << separator << indentation;
separate_transpileTree(parseComponent, 1);
if (parseComponent.empty()) output << "pass";
),
make_task(StandardComponents::Reference,
if (parseComponent.name == "true" or parseComponent.name == "false") {
output << (char) toupper(parseComponent.name.front()) << parseComponent.name.substr(1);
} else output << parseComponent.name;
)
}; };
} }
using Target::Target; using Target::Target;

View File

@ -7,9 +7,7 @@ using namespace std;
#include "headers/misc.hpp" #include "headers/misc.hpp"
#include "headers/arguments.hpp" #include "headers/arguments.hpp"
#include "headers/SemanticAnalysis.hpp"
#include "headers/transpiler/Target.hpp" #include "headers/transpiler/Target.hpp"
#include "headers/emscripten_compatibility.h"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
@ -21,7 +19,6 @@ int main(int argc, char* argv[]) {
using unit_result = pair<string, optional<Yerbacon::Exception>>; using unit_result = pair<string, optional<Yerbacon::Exception>>;
using unit = future<unit_result>; using unit = future<unit_result>;
map<string_view, unit> Units; map<string_view, unit> Units;
optional<filesystem::path> output_directory;
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
is_node = MAIN_THREAD_EM_ASM_INT({ return ENVIRONMENT_IS_NODE; }); is_node = MAIN_THREAD_EM_ASM_INT({ return ENVIRONMENT_IS_NODE; });
#endif #endif
@ -44,33 +41,45 @@ int main(int argc, char* argv[]) {
} else goto invalid_argument; } else goto invalid_argument;
} }
else if (currentArgument == ArgumentShort("text")) printResult = text_provided = true; else if (currentArgument == ArgumentShort("text")) printResult = text_provided = true;
else if (currentArgument == ArgumentShort("output"))
if ((not output_directory.has_value()) and Units.empty() and (i + 1) != argc) {
mount(argv[i + 1]);
output_directory = argv[i + 1]; ++i;
} else goto invalid_argument;
else if (text_provided || currentArgument.ends_with(".ybcon")) { else if (text_provided || currentArgument.ends_with(".ybcon")) {
#ifdef _OPENMP #ifdef _OPENMP
if (not parallel) omp_set_num_threads(1); if (not parallel) omp_set_num_threads(1);
#endif #endif
filesystem::path file_path; optional file_path = make_optional<filesystem::path>();
if (not text_provided) file_path = mount(currentArgument); if (not text_provided) {
Units.insert_or_assign(currentArgument, async(not parallel ? launch::deferred : launch::async, [&, currentArgument, file_path, index = Units.size() + 1]() { file_path = filesystem::path(currentArgument);
#ifdef EMSCRIPTEN
if (currentArgument.size() >= 2 and currentArgument[1] == ':') {
auto path = string(currentArgument).erase(0, 2);
replace(path.begin(), path.end(), '\\', '/');
file_path = path;
}
const string directory = filesystem::path(file_path.value()).remove_filename();
for (unsigned int character = 1; character < directory.size(); ++character) {
const string sub_directory = directory.substr(0, character);
if (is_node and (directory[character] == '/') and not filesystem::is_directory(sub_directory)) {
MAIN_THREAD_EM_ASM({
const sub_directory = UTF8ToString($0);
if (!FS.isMountpoint(sub_directory)) {
try {
FS.mkdir(sub_directory);
FS.mount(NODEFS, {root: sub_directory}, sub_directory);
} catch (exception) {}
};
}, sub_directory.c_str());
}
}
#endif
}
Units.insert_or_assign(currentArgument, async(not parallel ? launch::deferred : launch::async, [&, currentArgument, file_path]() {
unit_result resultingPair; unit_result resultingPair;
try { try {
resultingPair.first = Target::forName(target, newLines)->transpileWithTree( resultingPair.first = Target::forName(target, newLines)->transpileWithTree(
SemanticAnalyser().analyseTree( parseString(text_provided ? currentArgument : getFileContent(file_path->string()))
parseString(text_provided ? string(currentArgument) + '\n' : getFileContent(file_path.string(/* NOTE: This string is expected to finish with a line ending */)))
)
); );
if (!text_provided or output_directory.has_value()) if (not text_provided) outputFileContent(filesystem::path(file_path.value()).replace_extension(target).string(), resultingPair.first);
outputFileContent(
(not output_directory.has_value() ? filesystem::path(file_path)
: output_directory->append(
(not text_provided) ? file_path.filename().string() : to_string(index))
).replace_extension(target).string(), resultingPair.first);
} catch (const Yerbacon::Exception& error) { } catch (const Yerbacon::Exception& error) {
resultingPair.first = not text_provided ? file_path.filename().string() : string(); resultingPair.first = file_path.has_value() ? file_path->filename().string() : string();
resultingPair.second.emplace(error); resultingPair.second.emplace(error);
} }
return resultingPair; return resultingPair;