diff --git a/src/parser/cxx/external_name_encoder.cc b/src/parser/cxx/external_name_encoder.cc new file mode 100644 index 00000000..65dbd688 --- /dev/null +++ b/src/parser/cxx/external_name_encoder.cc @@ -0,0 +1,206 @@ +// Copyright (c) 2025 Roberto Raggi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include + +#include + +namespace cxx { + +struct ExternalNameEncoder::NameVisitor { + ExternalNameEncoder& encoder; + + void operator()(const Identifier* name) {} + + void operator()(const OperatorId* name) {} + + void operator()(const DestructorId* name) {} + + void operator()(const LiteralOperatorId* name) {} + + void operator()(const ConversionFunctionId* name) {} + + void operator()(const TemplateId* name) {} +}; + +struct ExternalNameEncoder::TypeVisitor { + ExternalNameEncoder& encoder; + + void operator()(const VoidType* type) { encoder.out("v"); } + + void operator()(const NullptrType* type) { encoder.out("Dn"); } + + void operator()(const DecltypeAutoType* type) { encoder.out("Dc"); } + + void operator()(const AutoType* type) { encoder.out("Da"); } + + void operator()(const BoolType* type) { encoder.out("b"); } + + void operator()(const SignedCharType* type) { encoder.out("a"); } + + void operator()(const ShortIntType* type) { encoder.out("s"); } + + void operator()(const IntType* type) { encoder.out("i"); } + + void operator()(const LongIntType* type) { encoder.out("l"); } + + void operator()(const LongLongIntType* type) { encoder.out("x"); } + + void operator()(const UnsignedCharType* type) { encoder.out("h"); } + + void operator()(const UnsignedShortIntType* type) { encoder.out("t"); } + + void operator()(const UnsignedIntType* type) { encoder.out("j"); } + + void operator()(const UnsignedLongIntType* type) { encoder.out("m"); } + + void operator()(const UnsignedLongLongIntType* type) { encoder.out("y"); } + + void operator()(const CharType* type) { encoder.out("c"); } + + void operator()(const Char8Type* type) { encoder.out("Du"); } + + void operator()(const Char16Type* type) { encoder.out("Ds"); } + + void operator()(const Char32Type* type) { encoder.out("Di"); } + + void operator()(const WideCharType* type) { encoder.out("w"); } + + void operator()(const FloatType* type) { encoder.out("f"); } + + void operator()(const DoubleType* type) { encoder.out("d"); } + + void operator()(const LongDoubleType* type) { encoder.out("e"); } + + void operator()(const QualType* type) {} + + void operator()(const BoundedArrayType* type) {} + + void operator()(const UnboundedArrayType* type) {} + + void operator()(const PointerType* type) {} + + void operator()(const LvalueReferenceType* type) {} + + void operator()(const RvalueReferenceType* type) {} + + void operator()(const FunctionType* type) {} + + void operator()(const ClassType* type) {} + + void operator()(const EnumType* type) {} + + void operator()(const ScopedEnumType* type) {} + + void operator()(const MemberObjectPointerType* type) {} + + void operator()(const MemberFunctionPointerType* type) {} + + void operator()(const NamespaceType* type) {} + + void operator()(const TypeParameterType* type) {} + + void operator()(const TemplateTypeParameterType* type) {} + + void operator()(const UnresolvedNameType* type) {} + + void operator()(const UnresolvedBoundedArrayType* type) {} + + void operator()(const UnresolvedUnderlyingType* type) {} + + void operator()(const OverloadSetType* type) {} + + void operator()(const BuiltinVaListType* type) {} +}; + +struct ExternalNameEncoder::SymbolVisitor { + ExternalNameEncoder& encoder; + + void operator()(NamespaceSymbol* symbol) {} + + void operator()(ConceptSymbol* symbol) {} + + void operator()(ClassSymbol* symbol) {} + + void operator()(EnumSymbol* symbol) {} + + void operator()(ScopedEnumSymbol* symbol) {} + + void operator()(FunctionSymbol* symbol) {} + + void operator()(TypeAliasSymbol* symbol) {} + + void operator()(VariableSymbol* symbol) {} + + void operator()(FieldSymbol* symbol) {} + + void operator()(ParameterSymbol* symbol) {} + + void operator()(EnumeratorSymbol* symbol) {} + + void operator()(FunctionParametersSymbol* symbol) {} + + void operator()(TemplateParametersSymbol* symbol) {} + + void operator()(BlockSymbol* symbol) {} + + void operator()(LambdaSymbol* symbol) {} + + void operator()(TypeParameterSymbol* symbol) {} + + void operator()(NonTypeParameterSymbol* symbol) {} + + void operator()(TemplateTypeParameterSymbol* symbol) {} + + void operator()(ConstraintTypeParameterSymbol* symbol) {} + + void operator()(OverloadSetSymbol* symbol) {} + + void operator()(BaseClassSymbol* symbol) {} +}; + +ExternalNameEncoder::ExternalNameEncoder() {} + +void ExternalNameEncoder::out(std::string_view s) { externalName_.append(s); } + +auto ExternalNameEncoder::encode(Symbol* symbol) -> std::string { + std::string externalName; + if (symbol) { + std::swap(externalName, externalName_); + visit(SymbolVisitor{*this}, symbol); + std::swap(externalName, externalName_); + } + return externalName; +} + +auto ExternalNameEncoder::encode(const Type* type) -> std::string { + std::string externalName; + if (type) { + std::swap(externalName, externalName_); + visit(TypeVisitor{*this}, type); + std::swap(externalName, externalName_); + } + return externalName; +} + +} // namespace cxx \ No newline at end of file diff --git a/src/parser/cxx/external_name_encoder.h b/src/parser/cxx/external_name_encoder.h new file mode 100644 index 00000000..96724d85 --- /dev/null +++ b/src/parser/cxx/external_name_encoder.h @@ -0,0 +1,49 @@ +// Copyright (c) 2025 Roberto Raggi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include +#include +#include + +#include + +namespace cxx { + +class ExternalNameEncoder { + public: + ExternalNameEncoder(); + + [[nodiscard]] auto encode(Symbol* symbol) -> std::string; + [[nodiscard]] auto encode(const Type* type) -> std::string; + + private: + void out(std::string_view s); + + struct NameVisitor; + struct TypeVisitor; + struct SymbolVisitor; + + private: + std::string externalName_; +}; + +} // namespace cxx \ No newline at end of file diff --git a/tests/api_tests/CMakeLists.txt b/tests/api_tests/CMakeLists.txt index 97e8e345..f80daf57 100644 --- a/tests/api_tests/CMakeLists.txt +++ b/tests/api_tests/CMakeLists.txt @@ -1,3 +1,22 @@ +# Copyright (c) 2025 Roberto Raggi +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. if (CMAKE_SYSTEM_NAME STREQUAL "WASI") return() diff --git a/tests/api_tests/test_control.cc b/tests/api_tests/test_control.cc index ed5d8e64..0b468a29 100644 --- a/tests/api_tests/test_control.cc +++ b/tests/api_tests/test_control.cc @@ -1,3 +1,22 @@ +// Copyright (c) 2025 Roberto Raggi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. #include #include diff --git a/tests/api_tests/test_external_names.cc b/tests/api_tests/test_external_names.cc new file mode 100644 index 00000000..92d0f5e8 --- /dev/null +++ b/tests/api_tests/test_external_names.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2025 Roberto Raggi +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include +#include +#include +#include +#include + +using namespace cxx; + +TEST(ExternalNames, BuiltinTypes) { + Control control; + ExternalNameEncoder encoder; + + ASSERT_EQ("v", encoder.encode(control.getVoidType())); + ASSERT_EQ("w", encoder.encode(control.getWideCharType())); + ASSERT_EQ("b", encoder.encode(control.getBoolType())); + ASSERT_EQ("c", encoder.encode(control.getCharType())); + ASSERT_EQ("a", encoder.encode(control.getSignedCharType())); + ASSERT_EQ("h", encoder.encode(control.getUnsignedCharType())); + ASSERT_EQ("s", encoder.encode(control.getShortIntType())); + ASSERT_EQ("t", encoder.encode(control.getUnsignedShortIntType())); + ASSERT_EQ("i", encoder.encode(control.getIntType())); + ASSERT_EQ("j", encoder.encode(control.getUnsignedIntType())); + ASSERT_EQ("l", encoder.encode(control.getLongIntType())); + ASSERT_EQ("m", encoder.encode(control.getUnsignedLongIntType())); + ASSERT_EQ("x", encoder.encode(control.getLongLongIntType())); + ASSERT_EQ("y", encoder.encode(control.getUnsignedLongLongIntType())); + // ASSERT_EQ("n", encoder.encode(control.getInt128Type())); + // ASSERT_EQ("o", encoder.encode(control.getUnsignedInt128Type())); + ASSERT_EQ("f", encoder.encode(control.getFloatType())); + ASSERT_EQ("d", encoder.encode(control.getDoubleType())); + ASSERT_EQ("e", encoder.encode(control.getLongDoubleType())); + // ASSERT_EQ("g", encoder.encode(control.getFloat128Type())); + // ASSERT_EQ("z", encoder.encode(control.getEllipsisType())); + ASSERT_EQ("Di", encoder.encode(control.getChar32Type())); + ASSERT_EQ("Ds", encoder.encode(control.getChar16Type())); + ASSERT_EQ("Du", encoder.encode(control.getChar8Type())); + ASSERT_EQ("Da", encoder.encode(control.getAutoType())); + ASSERT_EQ("Dc", encoder.encode(control.getDecltypeAutoType())); + ASSERT_EQ("Dn", encoder.encode(control.getNullptrType())); +} \ No newline at end of file