diff --git a/.github/workflows/release-package.yml b/.github/workflows/release-package.yml deleted file mode 100644 index 01b82f6..0000000 --- a/.github/workflows/release-package.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Build - -on: - push: - branches: - - feature/* - - dev - - main - tags: - - '[0-9]+.[0-9]+.[0-9]+' - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - # Set up Emscripten - - name: Set up Emscripten - uses: mymindstorm/setup-emsdk@v14 - - # Build your project with CMake - - name: Build - run: | - npm run build - - # Upload build artifacts - - name: Upload build artifacts - uses: actions/upload-artifact@v2 - with: - name: build-artifacts - path: dist - - publish: - needs: build - if: github.ref_type == 'tag' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Download build artifacts - uses: actions/download-artifact@v2 - with: - name: build-artifacts - path: dist - - # Publish to GitHub Packages (adjust for your packaging tool) - - name: Publish - run: | - # Assuming you're generating a npm package - git config --global user.name "${{ github.actor }}" - git config --global user.email "github-action-${{ github.actor }}@users.noreply.github.com" - npm version ${{ github.ref_name }} - npm publish --access public - env: - NPM_CONFIG_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index dc30f00..16c5d53 100644 --- a/.gitignore +++ b/.gitignore @@ -57,5 +57,5 @@ cmake-build-*/ # Added by cargo - /target +/lib diff --git a/.gitmodules b/.gitmodules index 5c96a90..7f610be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,3 @@ -[submodule "dependencies/fmtlib"] - path = dependencies/fmtlib - url = https://github.com/fmtlib/fmt.git [submodule "dependencies/winflexbison"] path = dependencies/winflexbison url = https://github.com/lexxmark/winflexbison.git -[submodule "dependencies/emsdk"] - path = dependencies/emsdk - url = https://github.com/emscripten-core/emsdk.git diff --git a/.npmrc b/.npmrc deleted file mode 100644 index b9eae83..0000000 --- a/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -//npm.pkg.github.com/:_authToken=${NPM_CONFIG_TOKEN} -@xtjoeytx:registry=https://npm.pkg.github.com -always-auth=true \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b11e05..48ac233 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,35 +1,29 @@ cmake_minimum_required(VERSION 3.10) project(gs2test VERSION 1.0) -set(CMAKE_DEBUG_POSTFIX _d) +# Enable verbose makefile for debugging purposes +set(CMAKE_VERBOSE_MAKEFILE ON) -set(BIN_DIR "bin" CACHE STRING "Binary output directory") +# Set debug postfix for binaries +set(CMAKE_DEBUG_POSTFIX _d) -# specify the C++ standard +# Specify the C++ standard set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_POSITION_INDEPENDENT_CODE ON) -# Set up output directories -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/${BIN_DIR}) - -# Second, for multi-config builds (e.g. msvc) -foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) - string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) - set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_SOURCE_DIR}/lib ) - set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_SOURCE_DIR}/lib ) - set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_SOURCE_DIR}/${BIN_DIR} ) -endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) - -link_directories(${PROJECT_SOURCE_DIR}/lib) +# Include necessary directories +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + src +) +# Adjust library prefixes for specific platforms if(WIN32 OR APPLE) - set(CMAKE_SHARED_LIBRARY_PREFIX "") - set(CMAKE_STATIC_LIBRARY_PREFIX "lib") + set(CMAKE_SHARED_LIBRARY_PREFIX "") + set(CMAKE_STATIC_LIBRARY_PREFIX "lib") endif() +# Handle winflexbison setup on Windows (not MinGW) if(WIN32 AND NOT MINGW) execute_process(COMMAND ${CMAKE_COMMAND} -S${CMAKE_CURRENT_SOURCE_DIR}/dependencies/winflexbison -B${CMAKE_CURRENT_SOURCE_DIR}/dependencies/winflexbison/build-winflex-bison -GNinja -DCMAKE_BUILD_TYPE=Release) execute_process(COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_SOURCE_DIR}/dependencies/winflexbison/build-winflex-bison --parallel 8) @@ -40,76 +34,83 @@ endif(WIN32 AND NOT MINGW) find_package(BISON 3.4 REQUIRED) find_package(FLEX REQUIRED) +# Check for Bison and Flex availability +if(NOT BISON_EXECUTABLE AND (WIN32 AND NOT MINGW)) + message(FATAL_ERROR "Bison not found. Please ensure winflexbison is available.") +endif() + +if(NOT FLEX_EXECUTABLE AND (WIN32 AND NOT MINGW)) + message(FATAL_ERROR "Flex not found. Please ensure winflexbison is available.") +endif() + +# Add Flex compatibility flags for Windows +if(WIN32 AND NOT MINGW) + set(FLEX_FLAGS "--wincompat") +endif() + +# Generate parser and scanner with Bison/Flex BISON_TARGET(GS2Parser generator/gs2parser.y ${CMAKE_CURRENT_BINARY_DIR}/gs2parser.tab.cc) -FLEX_TARGET(GS2Scanner generator/gs2scanner.l ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.cc DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.h COMPILE_FLAGS "${FLEX_FLAGS}") +FLEX_TARGET(GS2Scanner generator/gs2scanner.l ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.cc + DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.h + COMPILE_FLAGS "${FLEX_FLAGS}") ADD_FLEX_BISON_DEPENDENCY(GS2Scanner GS2Parser) -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - src +# List source files +set(SOURCES_ALL + src/ast/ast.cpp + src/encoding/buffer.cpp + src/visitors/GS2CompilerVisitor.cpp + src/GS2BuiltInFunctions.cpp + src/GS2Bytecode.cpp + src/GS2Context.cpp + src/Parser.cpp + src/c_interface.cpp + + src/ast/ast.h + src/ast/astvisitor.h + src/ast/astnodevisitor.h + src/ast/expressiontypes.h + src/encoding/buffer.h + src/encoding/graalencoding.h + src/utils/EventHandler.h + src/exceptions/GS2CompilerError.h + src/utils/ContextThreadPool.h + src/utils/format_string.h + src/visitors/FunctionInspectVisitor.h + src/visitors/GS2CompilerVisitor.h + src/visitors/GS2SourceVisitor.h + src/CompilerThreadJob.h + src/GS2BuiltInFunctions.h + src/GS2Bytecode.h + src/GS2Context.h + src/opcodes.h + src/Parser.h + + ${BISON_GS2Parser_INPUT} + ${FLEX_GS2Scanner_INPUT} + ${BISON_GS2Parser_OUTPUTS} + ${FLEX_GS2Scanner_OUTPUTS} ) -set(SOURCES_ALL - src/ast/ast.cpp - src/encoding/buffer.cpp - src/visitors/GS2CompilerVisitor.cpp - src/GS2BuiltInFunctions.cpp - src/GS2Bytecode.cpp - src/GS2Context.cpp - src/Parser.cpp - src/c_interface.cpp - - src/ast/ast.h - src/ast/astvisitor.h - src/ast/astnodevisitor.h - src/ast/expressiontypes.h - src/encoding/buffer.h - src/encoding/graalencoding.h - src/utils/EventHandler.h - src/exceptions/GS2CompilerError.h - src/utils/ContextThreadPool.h - src/visitors/FunctionInspectVisitor.h - src/visitors/GS2CompilerVisitor.h - src/visitors/GS2SourceVisitor.h - src/CompilerThreadJob.h - src/GS2BuiltInFunctions.h - src/GS2Bytecode.h - src/GS2Context.h - src/opcodes.h - src/Parser.h - - ${BISON_GS2Parser_INPUT} - ${FLEX_GS2Scanner_INPUT} - ${BISON_GS2Parser_OUTPUTS} - ${FLEX_GS2Scanner_OUTPUTS}) - -add_subdirectory(${PROJECT_SOURCE_DIR}/dependencies/fmtlib EXCLUDE_FROM_ALL) - -if (DEFINED EMSCRIPTEN) - add_executable(gs2test ${SOURCES_ALL} src/js_interface.cpp) - set_target_properties(gs2test PROPERTIES LINK_FLAGS "--embind-emit-tsd gs2test.d.ts -s ENVIRONMENT=web -s DYNAMIC_EXECUTION=0 -s SINGLE_FILE=1 -s MODULARIZE -s 'EXPORT_NAME=GS2Compiler' --bind") -else() - add_executable(gs2test ${SOURCES_ALL} src/main.cpp) -endif() +# Create executable target +add_executable(gs2test ${SOURCES_ALL} src/main.cpp) -if (STATIC) - add_library(gs2compiler STATIC ${SOURCES_ALL}) +# Add library target +if(STATIC) + add_library(gs2compiler STATIC ${SOURCES_ALL}) else() - add_library(gs2compiler SHARED ${SOURCES_ALL}) + add_library(gs2compiler SHARED ${SOURCES_ALL}) endif() +# Set special compile options for MinGW if(WIN32 AND MINGW) - target_compile_options(gs2compiler PRIVATE "-fno-rtti") + target_compile_options(gs2compiler PRIVATE "-fno-rtti") endif() -set_property(TARGET gs2test PROPERTY CXX_STANDARD 23) -set_property(TARGET gs2compiler PROPERTY CXX_STANDARD 23) - -target_link_libraries(gs2test fmt::fmt) -target_link_libraries(gs2compiler fmt::fmt) - +# Export include directory for use by other projects set(GS2COMPILER_INCLUDE_DIRECTORY - "${PROJECT_SOURCE_DIR}/include" - "${PROJECT_BINARY_DIR}/include" - "${PROJECT_SOURCE_DIR}/src" - PARENT_SCOPE) + "${PROJECT_SOURCE_DIR}/include" + "${PROJECT_BINARY_DIR}/include" + "${PROJECT_SOURCE_DIR}/src" + PARENT_SCOPE +) diff --git a/Cargo.lock b/Cargo.lock index caafe12..74b18bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,25 +1,28 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "cc" -version = "1.1.7" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +dependencies = [ + "shlex", +] [[package]] name = "cmake" -version = "0.1.50" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" dependencies = [ "cc", ] [[package]] name = "gs2compiler" -version = "0.1.0" +version = "0.2.3" dependencies = [ "cmake", "libc", @@ -27,6 +30,12 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.168" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" + +[[package]] +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" diff --git a/Cargo.toml b/Cargo.toml index f4417ba..a012cad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,10 @@ [package] name = "gs2compiler" -version = "0.1.0" +version = "0.2.3" edition = "2021" build = "build.rs" +description = "Compiles GS2 source code into GS2 bytecode." +license = "GPL-3.0-only" [dependencies] libc = "0.2.155" diff --git a/Jenkinsfile b/Jenkinsfile index 90dcdc4..94a8f39 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -62,20 +62,18 @@ def buildStep(dockerImage, generator, os, osdir, defines) { } + sh("rm -rf build"); sh("mkdir -p build/"); - sh("mkdir -p lib/"); - sh("rm -rfv build/*"); - sh("rm -rfv lib/*"); discordSend(description: "", footer: "", link: env.BUILD_URL, result: currentBuild.currentResult, title: "[${split_job_name[0]}] Starting ${os} build target...", webhookURL: env.GS2EMU_WEBHOOK); dir("build") { - sh("cmake -G\"${generator}\" -DCMAKE_BUILD_TYPE=Release ${defines} -DVER_EXTRA=\"-${fixed_os}-${fixed_job_name}\" .. || true"); // Temporary fix for Windows MingW builds + sh("cmake -G\"${generator}\" -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=bin -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=lib -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=lib -DCMAKE_BUILD_TYPE=Release ${defines} -DVER_EXTRA=\"-${fixed_os}-${fixed_job_name}\" .. || true"); // Temporary fix for Windows MingW builds sh("cmake --build . --config Release --target all -- -j `nproc`"); } - archiveArtifacts(artifacts: 'lib/*.dylib,lib/*.so,bin/*.dll', allowEmptyArchive: true); - stash(name: osdir, includes: 'lib/*.dylib,lib/*.so,bin/*.dll', allowEmpty: true); + archiveArtifacts(artifacts: 'build/lib/*.dylib,build/lib/*.so,build/bin/*.dll', allowEmptyArchive: true); + stash(name: osdir, includes: 'build/lib/*.dylib,build/lib/*.so,build/bin/*.dll', allowEmpty: true); discordSend(description: "", footer: "", link: env.BUILD_URL, result: currentBuild.currentResult, title: "[${split_job_name[0]}] Build ${fixed_job_name} #${env.BUILD_NUMBER} Target: ${os} successful!", webhookURL: env.GS2EMU_WEBHOOK); } @@ -256,7 +254,7 @@ killall_jobs(); project.builds.each { v -> branches["Build ${v.DockerRoot}/${v.DockerImage}:${v.DockerTag}"] = { - node { + node("amd64") { buildStep(v.DockerImage, v.Generator, v.OS, v.OSDir, v.Defines); } } @@ -273,12 +271,12 @@ killall_jobs(); dir("bindings/dotnet/cross-compile/${v.OSDir}/") { unstash(name: v.OSDir); try { - sh("mv -fv bin/* ."); - sh("rm -rf bin") + sh("mv -fv build/bin/* ."); + sh("rm -rf build/bin") } catch(err) { } try { - sh("mv -fv lib/* ."); - sh("rm -rf lib") + sh("mv -fv build/lib/* ."); + sh("rm -rf build/lib") } catch(err) { } } } diff --git a/README.md b/README.md index 2169018..7b500ec 100644 --- a/README.md +++ b/README.md @@ -21,22 +21,9 @@ cmake .. make -j $(nproc) ``` -# Building (Wasm) - -First, ensure you have Emscripten installed. Then, you can build the project using CMake: - -```sh -mkdir build -cd build -emcmake cmake .. -make -j $(nproc) -``` - -The resulting `gs2test.js` file can be imported into a webpage. - # Running -The non-wasm build can be run using the following command: +You can use the following command: ```sh $ ./gs2test ../scripts/asd2.txt diff --git a/build.rs b/build.rs index bba0957..54dc3d6 100644 --- a/build.rs +++ b/build.rs @@ -4,8 +4,6 @@ use cmake::Config; // Constants for common library names const DEBUG_SUFFIX_GS2: &str = "_d"; -const DEBUG_SUFFIX_FMT: &str = "d"; -const STATIC_LIB_DIR: &str = "lib"; fn main() { let profile = env::var("PROFILE").unwrap_or_else(|_| "release".to_string()); @@ -13,14 +11,24 @@ fn main() { // Determine the appropriate library names based on the profile and platform let gs2_compiler_lib = library_name("gs2compiler", &profile, DEBUG_SUFFIX_GS2, &target); - let fmt_lib = library_name("fmt", &profile, DEBUG_SUFFIX_FMT, &target); let mut cmake_config = Config::new("."); cmake_config.build_target("gs2compiler").define("STATIC", "ON"); let cpp_lib = configure_platform_specifics(&target, &mut cmake_config); - link_libraries(cmake_config.build(), cpp_lib, &gs2_compiler_lib, &fmt_lib); + let lib_path = cmake_config.build(); + + // Add the appropriate subdirectory (e.g., Debug or Release) + let build_subdir = if profile == "debug" { + "build/Debug" + } else { + "build/Release" + }; + + let full_lib_path = lib_path.join(build_subdir); + + link_libraries(full_lib_path, cpp_lib, &gs2_compiler_lib); } fn library_name(base: &str, profile: &str, debug_suffix: &str, target: &str) -> String { @@ -49,13 +57,8 @@ fn configure_platform_specifics(target: &str, cmake_config: &mut Config) -> &'st } } -fn link_libraries(lib_path: PathBuf, cpp_lib: &str, gs2_lib: &str, fmt_lib: &str) { - let lib_dir = env::current_dir().unwrap().join(STATIC_LIB_DIR); - +fn link_libraries(lib_path: PathBuf, cpp_lib: &str, gs2_lib: &str) { println!("cargo:rustc-link-lib=dylib={}", cpp_lib); println!("cargo:rustc-link-search=native={}", lib_path.display()); - println!("cargo:rustc-link-search=native={}", lib_dir.display()); - println!("cargo:rustc-link-lib=static={}", gs2_lib); - println!("cargo:rustc-link-lib=static={}", fmt_lib); } diff --git a/dependencies/emsdk b/dependencies/emsdk deleted file mode 160000 index 476dc4e..0000000 --- a/dependencies/emsdk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 476dc4e01fce997b540d9a507241f136256344e3 diff --git a/dependencies/fmtlib b/dependencies/fmtlib deleted file mode 160000 index 34caecd..0000000 --- a/dependencies/fmtlib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 34caecd6b6850adb3e57218dc28f14eaafd5cf0e diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 28094aa..0000000 --- a/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@xtjoeytx/gs2-parser", - "version": "0.0.2", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@xtjoeytx/gs2-parser", - "version": "0.0.2", - "license": "GPL-3.0-only" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index d92005f..0000000 --- a/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "@xtjoeytx/gs2-parser", - "version": "0.0.2", - "description": "This is a compiler for the Graal Script 2 (GS2) language.", - "main": "dist/gs2test.js", - "types": "dist/gs2test.d.ts", - "scripts": { - "build": "mkdir -p dist && emcmake cmake -S. -Bbuild/ && cmake --build build/ -j$(nproc) && mv -fv ./bin/* ./dist/" - }, - "keywords": [], - "author": "xtjoeytx", - "license": "GPL-3.0-only", - "publishConfig": { - "registry": "https://npm.pkg.github.com" - } -} diff --git a/src/GS2Context.cpp b/src/GS2Context.cpp index 5d201cb..1033cfc 100644 --- a/src/GS2Context.cpp +++ b/src/GS2Context.cpp @@ -1,4 +1,3 @@ -#include #include "GS2Context.h" #include "encoding/graalencoding.h" #include "visitors/GS2CompilerVisitor.h" diff --git a/src/Parser.cpp b/src/Parser.cpp index 26ac66f..d0a7dc8 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -106,7 +106,7 @@ std::string* ParserContext::saveString(const char* str, int length, bool unquote std::string * ParserContext::generateLambdaFuncName() { - std::string fnName = fmt::format("function_{}_1", 100 + lambdaFunctionCount); + std::string fnName = printf_format_string("function_%d_1", 100 + lambdaFunctionCount); lambdaFunctionCount++; return saveString(fnName.c_str(), int(fnName.length())); } @@ -139,7 +139,7 @@ void ParserContext::addConstant(const std::string& ident, ExpressionIdentifierNo if (constant) { // report error - redefining constant - addParserError(fmt::format("redefinition of constant {}", ident)); + addParserError(printf_format_string("redefinition of constant %s", ident.c_str())); return; } @@ -168,7 +168,7 @@ void ParserContext::addConstant(const std::string& ident, ExpressionIdentifierNo else { // report error - constant does not exist - addParserError(fmt::format("constant {} is undefined", ident)); + addParserError(printf_format_string("constant %s is undefined", ident.c_str())); return; } } @@ -187,7 +187,7 @@ void ParserContext::addConstant(const std::string& ident, ExpressionNode *node) auto constant = getConstant(ident); if (constant) { - addParserError(fmt::format("redefinition of constant {}", ident)); + addParserError(printf_format_string("redefinition of constant %s", ident.c_str())); return; } @@ -205,11 +205,11 @@ void ParserContext::addParserError(const std::string& errmsg) std::string msg; if (lineText.empty()) { - msg = fmt::format("parser error occurred near line {}: {}", lineNumber, errmsg); + msg = printf_format_string("parser error occurred near line %d: %s", lineNumber, errmsg.c_str()); } else { - msg = fmt::format("{} at line {}: {}", errmsg, lineNumber, lineText); + msg = printf_format_string("%s at line %d: %s", errmsg.c_str(), lineNumber, lineText.c_str()); } addError({ ErrorLevel::E_ERROR, GS2CompilerError::ErrorCategory::Parser, std::move(msg) }); diff --git a/src/Parser.h b/src/Parser.h index c9d08fc..f2715d8 100644 --- a/src/Parser.h +++ b/src/Parser.h @@ -12,8 +12,8 @@ #include #include -#include #include "ast/ast.h" +#include "utils/format_string.h" #include "exceptions/GS2CompilerError.h" typedef void* yyscan_t; diff --git a/src/js_interface.cpp b/src/js_interface.cpp deleted file mode 100644 index 2fa39b8..0000000 --- a/src/js_interface.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "GS2Context.h" -using namespace emscripten; - -EMSCRIPTEN_BINDINGS(module) { - register_vector("VectorString"); -} - -EMSCRIPTEN_BINDINGS(GS2Context_bindings) { - class_("GS2Context") - .constructor<>() - .function("compile", select_overload(&GS2Context::compile), emscripten::return_value_policy::take_ownership()) - .function("compile", select_overload(&GS2Context::compile), emscripten::return_value_policy::take_ownership()); -} - -emscripten::val getBytecodeFromBuffer(const CompilerResponse &response) { - const Buffer &buf = response.bytecode; - return emscripten::val(emscripten::typed_memory_view(buf.size(), buf.buffer())); -} - -/* getErrors is simply a list of strings for now */ -std::vector getErrors(const CompilerResponse &response) { - std::vector errors; - for (const GS2CompilerError &error : response.errors) { - errors.push_back(error.msg()); - } - - return errors; -} - -EMSCRIPTEN_BINDINGS(CompilerResponse_bindings) { - /* For now, let's just have a test property set to 1 */ - class_("CompilerResponse") - .property("success", &CompilerResponse::success) - .function("getBytecode", &getBytecodeFromBuffer, emscripten::return_value_policy::take_ownership()) - .function("getErrors", &getErrors, emscripten::return_value_policy::take_ownership()); -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index edddeaa..6adef3d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -87,7 +87,7 @@ int main(int argc, const char *argv[]) { // yydebug = 1; #endif -// auto ret = fmt::format("Test {}", 42); +// auto ret = std::format("Test {}", 42); // printf("Test: %s\n", ret.c_str()); //auto ret = std::format("test {}", 3); //printf("Test: %s\n", ret.c_str()); diff --git a/src/utils/format_string.h b/src/utils/format_string.h new file mode 100644 index 0000000..7d17580 --- /dev/null +++ b/src/utils/format_string.h @@ -0,0 +1,55 @@ +#ifndef FORMAT_STRING_H +#define FORMAT_STRING_H + +#include +#include +#include +#include +#include // for std::vsnprintf + +/** + * @brief Formats a string using a printf-style format string and variadic arguments. + * + * Remove the dependency on std::format by using std::vsnprintf to format a string + * + * @param fmt The printf-style format string. + * @param ... Variadic arguments matching the format string specifiers. + * @return A formatted std::string. + * @throws std::runtime_error If an error occurs during formatting. + * + * @note This function supports standard printf-style formatting specifiers (e.g., + * `%d`, `%s`, `%f`, etc.). Ensure that the number and types of arguments match + * the format specifiers to avoid undefined behavior. + * + * @example + * ```cpp + * std::string result = printf_format_string("Hello, %s! You have %d new messages.", "Alice", 5); + * std::cout << result; // Output: Hello, Alice! You have 5 new messages. + * ``` + */ +inline std::string printf_format_string(const char* fmt, ...) { + // Start variable arguments processing + va_list args; + va_start(args, fmt); + + // Estimate required buffer size + size_t size = std::vsnprintf(nullptr, 0, fmt, args) + 1; // +1 for null terminator + va_end(args); + + if (size <= 0) { + throw std::runtime_error("Error during formatting."); + } + + // Allocate the required size + std::vector buffer(size); + + // Format the string + va_start(args, fmt); + std::vsnprintf(buffer.data(), size, fmt, args); + va_end(args); + + // Return the formatted string + return std::string(buffer.data()); +} + +#endif // FORMAT_STRING_H diff --git a/src/visitors/GS2CompilerVisitor.cpp b/src/visitors/GS2CompilerVisitor.cpp index f471614..11f8b3e 100644 --- a/src/visitors/GS2CompilerVisitor.cpp +++ b/src/visitors/GS2CompilerVisitor.cpp @@ -86,7 +86,7 @@ void GS2CompilerVisitor::writeLabels() void GS2CompilerVisitor::Visit(Node *node) { - std::string errorMsg = fmt::format("unimplemented node type {}", node->NodeType()); + std::string errorMsg = printf_format_string("unimplemented node type %s", node->NodeType()); parserContext.addError({ ErrorLevel::E_ERROR, GS2CompilerError::ErrorCategory::Compiler, errorMsg }); #ifdef DBGEMITTERS @@ -470,7 +470,7 @@ void GS2CompilerVisitor::Visit(ExpressionBinaryOpNode *node) } } - std::string errorMsg = fmt::format("Undefined opcode in BinaryExpression {}: {} {}", node->op, ExpressionOpToString(node->op), node->toString()); + std::string errorMsg = printf_format_string("Undefined opcode in BinaryExpression %d: %s %s", static_cast(node->op), ExpressionOpToString(node->op), node->toString().c_str()); parserContext.addError({ ErrorLevel::E_ERROR, GS2CompilerError::ErrorCategory::Compiler, std::move(errorMsg) }); } @@ -599,7 +599,7 @@ void GS2CompilerVisitor::Visit(ExpressionUnaryOpNode* node) } } - std::string errorMsg = fmt::format("Undefined opcode in UnaryExpression {}: {}", node->op, ExpressionOpToString(node->op)); + std::string errorMsg = printf_format_string("Undefined opcode in UnaryExpression %d: %s", static_cast(node->op), ExpressionOpToString(node->op)); parserContext.addError({ ErrorLevel::E_ERROR, GS2CompilerError::ErrorCategory::Compiler, std::move(errorMsg) }); } @@ -1172,7 +1172,7 @@ void GS2CompilerVisitor::Visit(StatementBreakNode* node) { if (break_label <= 0) { - std::string errorMsg = fmt::format("`break` outside loop detected"); + std::string errorMsg = printf_format_string("`break` outside loop detected"); parserContext.addError({ ErrorLevel::E_WARNING, GS2CompilerError::ErrorCategory::Compiler, std::move(errorMsg) }); return; } @@ -1188,7 +1188,7 @@ void GS2CompilerVisitor::Visit(StatementContinueNode* node) { if (continue_label <= 0) { - std::string errorMsg = fmt::format("`continue` outside loop detected"); + std::string errorMsg = printf_format_string("`continue` outside loop detected"); parserContext.addError({ ErrorLevel::E_WARNING, GS2CompilerError::ErrorCategory::Compiler, std::move(errorMsg) }); return; } diff --git a/src/visitors/GS2CompilerVisitor.h b/src/visitors/GS2CompilerVisitor.h index efd9eb4..1eab0c3 100644 --- a/src/visitors/GS2CompilerVisitor.h +++ b/src/visitors/GS2CompilerVisitor.h @@ -9,6 +9,7 @@ #include #include "ast/astvisitor.h" #include "GS2Bytecode.h" +#include "utils/format_string.h" #include "GS2BuiltInFunctions.h" class ParserContext;