From 2dba7fbda6849818c2ea1f785a0c8a138f3da3c5 Mon Sep 17 00:00:00 2001 From: Username404 Date: Sat, 28 Aug 2021 00:06:21 +0200 Subject: [PATCH] Add experimental string transpilation with interpolation --- CMakeLists.txt | 2 +- README.md | 2 +- src/headers/transpiler/Target.hpp | 45 ++++++++++++++++++- src/headers/transpiler/implementations/Js.hpp | 3 ++ .../transpiler/implementations/Lua.hpp | 25 +---------- src/headers/transpiler/implementations/Py.hpp | 3 ++ 6 files changed, 53 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8899969..5bf32ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU) if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${MINIMAL_GNU}) message(FATAL_ERROR "G++ ${MINIMAL_GNU} or higher is required.") endif() - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fsched-pressure -flive-range-shrinkage -fpredictive-commoning -ftree-partial-pre -fira-loop-pressure -ftree-loop-distribution -floop-interchange -fsplit-paths -fgcse-las -fgcse-sm -fipa-pta -fstdarg-opt -fivopts -s") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -foptimize-strlen -fsched-pressure -flive-range-shrinkage -fpredictive-commoning -ftree-partial-pre -fira-loop-pressure -ftree-loop-distribution -floop-interchange -fsplit-paths -fgcse-las -fgcse-sm -fipa-pta -fstdarg-opt -fivopts -s") set(CMAKE_CXX_FLAGS "-fno-use-linker-plugin -fwhole-program ${CMAKE_CXX_FLAGS}") elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang) if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${MINIMAL_CLANG}) diff --git a/README.md b/README.md index 1a0772a..5dfe333 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Yerbacon logo Aka Yer Bacon, -- #### A language that transpiles into lua, javascript or python code. +- #### A language that transpiles into lua, javascript (ES6) or python code. ``` main #=> { println "Hello, World!" diff --git a/src/headers/transpiler/Target.hpp b/src/headers/transpiler/Target.hpp index 39a753a..138ecc2 100644 --- a/src/headers/transpiler/Target.hpp +++ b/src/headers/transpiler/Target.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../parsing/ParseComponents.hpp" @@ -14,7 +15,49 @@ class Target { protected: std::stringstream output; INCLUDECOMPONENT(StandardComponents::Define); - INCLUDECOMPONENT(StandardComponents::types::String) + INCLUDECOMPONENT(StandardComponents::types::String); + void stringInterpolation(string view, const char* openMultiline = "", const char* closeMultiline = "", const char* concatenationCharacters = "+") { + vector interpolationVector; + const string interpolationString = "${"; + unsigned long occurence_position = view.find(interpolationString); + while (occurence_position != string::npos) { + interpolationVector.push_back(occurence_position); + occurence_position = view.find(interpolationString, occurence_position + interpolationString.size()); + } + const bool noMultiline = not (strcmp(openMultiline, "") != 0 && strcmp(closeMultiline, openMultiline) != 0); + const bool multiline = view.find('\n') != string::npos && not noMultiline; + if (noMultiline) { + unsigned long newLine = view.find('\n'); + while (newLine != string::npos) { + view.erase(newLine, 1); + view.insert(newLine, "\\n"); + newLine = view.find('\n', newLine); + } + } + const char* const openCharacters = multiline ? openMultiline : "\""; + decltype(openCharacters) closeCharacters = multiline ? closeMultiline : openCharacters; + if (not interpolationVector.empty()) { + unsigned long closingBrace = 0; + for (unsigned long i = 0; i < interpolationVector.size(); ++i) { + const auto& occurence = interpolationVector[i]; + const bool hasNext = (i + 1) < interpolationVector.size(); + const bool oldClosingBraceIsFar = closingBrace >= occurence; + if (i > 0) output << concatenationCharacters; + output << openCharacters << view.substr(closingBrace + (i > 0), (occurence - closingBrace) - (i > 0)); + closingBrace = view.find_first_of('}', occurence); + const bool closingBraceIsNPOS = closingBrace == string::npos; + const bool wrongClosingBrace = !closingBraceIsNPOS && ((hasNext && closingBrace > interpolationVector[i + 1])); + if (closingBraceIsNPOS || wrongClosingBrace) { + output << view.substr(occurence - 1, (hasNext ? interpolationVector[i + 1] - (occurence - 1) : 0)); + } + output << closeCharacters; + if (not closingBraceIsNPOS && not wrongClosingBrace) { + output << concatenationCharacters; + output << view.substr(occurence + interpolationString.size(), (closingBrace - occurence) - interpolationString.size()); + } + } + } else output << openCharacters << view << closeCharacters << '\n'; + } INCLUDECOMPONENT(StandardComponents::Reference); INCLUDECOMPONENT(StandardComponents::Class); public: diff --git a/src/headers/transpiler/implementations/Js.hpp b/src/headers/transpiler/implementations/Js.hpp index f850a20..4ad2054 100644 --- a/src/headers/transpiler/implementations/Js.hpp +++ b/src/headers/transpiler/implementations/Js.hpp @@ -5,6 +5,9 @@ struct JsTarget: Target { void on(const StandardComponents::Define &parseComponent) override { output << (parseComponent.final ? "const " : "let ") << parseComponent.name << " = "; } + void on(const StandardComponents::types::String &parseComponent) override { + stringInterpolation(parseComponent.content); + } }; #endif \ No newline at end of file diff --git a/src/headers/transpiler/implementations/Lua.hpp b/src/headers/transpiler/implementations/Lua.hpp index dba5e4b..66d68cd 100644 --- a/src/headers/transpiler/implementations/Lua.hpp +++ b/src/headers/transpiler/implementations/Lua.hpp @@ -9,30 +9,7 @@ struct LuaTarget: Target { output << " = "; } void on(const StandardComponents::types::String &parseComponent) override { - const string_view view (parseComponent.content); - vector interpolationVector; - const string interpolationString = "${"; - unsigned long occurence_position = view.find(interpolationString); - while (occurence_position != string_view::npos) { - interpolationVector.push_back(occurence_position); - occurence_position = view.find(interpolationString, occurence_position + interpolationString.size()); - } - const bool multiline = view.find('\n') != string_view::npos; - const char* openCharacters = multiline ? "[[" : "\""; - decltype(openCharacters) closeCharacters = multiline ? "]]" : "\""; - if (not interpolationVector.empty()) { - unsigned long closingBrace = 0; - for (unsigned long i = 0; cmp_less(i, interpolationVector.size()); ++i) { - const auto& occurence = interpolationVector[i]; - if (i > 0) output << ".."; - output << openCharacters << view.substr((i > 0) ? closingBrace + 1 : 0, occurence - (closingBrace + 1)) << closeCharacters; - closingBrace = view.find_first_of('}', occurence); - if (closingBrace == string_view::npos) { - throw Yerbacon::Exception("Closing brace missing in a string"); - } - output << ".." << view.substr(occurence + interpolationString.size(), (closingBrace - occurence) - interpolationString.size()); - } - } else output << openCharacters << view << closeCharacters << '\n'; + stringInterpolation(parseComponent.content, "[[", "]]", ".."); } }; diff --git a/src/headers/transpiler/implementations/Py.hpp b/src/headers/transpiler/implementations/Py.hpp index 5e81c71..2bbdb4c 100644 --- a/src/headers/transpiler/implementations/Py.hpp +++ b/src/headers/transpiler/implementations/Py.hpp @@ -5,6 +5,9 @@ struct PyTarget: Target { void on(const StandardComponents::Define &parseComponent) override { output << parseComponent.name << " = "; } + void on(const StandardComponents::types::String &parseComponent) override { + stringInterpolation(parseComponent.content, "\"\"\"", "\"\"\""); + } }; #endif \ No newline at end of file