diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 1722bf4..a1e0bdd 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -190,6 +190,9 @@ target_include_directories(step65_test PRIVATE src) add_executable(step66_test tests/step66_test.cpp) target_include_directories(step66_test PRIVATE src) +add_executable(step67_test tests/step67_test.cpp) +target_include_directories(step67_test PRIVATE src) + add_executable(whetstone_editor src/main.cpp) target_include_directories(whetstone_editor PRIVATE src) # find_package(SDL2 REQUIRED) # Commented out for now to avoid build issues diff --git a/editor/tests/step67_test.cpp b/editor/tests/step67_test.cpp new file mode 100644 index 0000000..899222d --- /dev/null +++ b/editor/tests/step67_test.cpp @@ -0,0 +1,203 @@ +// Step 67 TDD Test: Optimization annotations +// +// Tests optimization annotation classes and their C++ code generation: +// 1. @Hot → C++ __attribute__((hot)) +// 2. @Cold → C++ __attribute__((cold)) +// 3. @Inline(Always) → C++ [[gnu::always_inline]] +// 4. @Pure → C++ [[nodiscard]] +// 5. @ConstExpr → C++ constexpr +// 6. All optimization annotation classes exist and inherit from Annotation +// +// Will fail until optimization annotation classes are created and +// CppGenerator handles them. + +#include +#include +#include +#include "ast/Generator.h" + +static bool contains(const std::string& haystack, const std::string& needle) { + return haystack.find(needle) != std::string::npos; +} + +int main() { + int passed = 0; + int failed = 0; + + // --- Test 1: HotColdAnnotation exists --- + { + HotColdAnnotation anno; + anno.hint = "Hot"; + Annotation* base = &anno; + (void)base; + assert(anno.hint == "Hot" && "Should store hint"); + + std::cout << "Test 1 PASS: HotColdAnnotation exists" << std::endl; + ++passed; + } + + // --- Test 2: InlineAnnotation exists --- + { + InlineAnnotation anno; + anno.mode = "Always"; + Annotation* base = &anno; + (void)base; + assert(anno.mode == "Always" && "Should store mode"); + + std::cout << "Test 2 PASS: InlineAnnotation exists" << std::endl; + ++passed; + } + + // --- Test 3: PureAnnotation exists --- + { + PureAnnotation anno; + Annotation* base = &anno; + (void)base; + + std::cout << "Test 3 PASS: PureAnnotation exists" << std::endl; + ++passed; + } + + // --- Test 4: ConstExprAnnotation exists --- + { + ConstExprAnnotation anno; + Annotation* base = &anno; + (void)base; + + std::cout << "Test 4 PASS: ConstExprAnnotation exists" << std::endl; + ++passed; + } + + // --- Test 5: @Hot function → C++ __attribute__((hot)) --- + { + Module mod("m1", "Perf", "cpp"); + Function* fn = new Function("f1", "hotPath"); + PrimitiveType* retType = new PrimitiveType("t1", "void"); + fn->setChild("returnType", retType); + + HotColdAnnotation* anno = new HotColdAnnotation(); + anno->hint = "Hot"; + fn->addChild("annotations", anno); + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert((contains(output, "__attribute__((hot))") || contains(output, "[[likely]]")) && + "@Hot should produce __attribute__((hot)) or [[likely]]"); + + std::cout << "Test 5 PASS: @Hot → C++ hot attribute" << std::endl; + ++passed; + + delete anno; + delete retType; + delete fn; + } + + // --- Test 6: @Cold function → C++ __attribute__((cold)) --- + { + Module mod("m1", "Perf", "cpp"); + Function* fn = new Function("f1", "errorHandler"); + PrimitiveType* retType = new PrimitiveType("t1", "void"); + fn->setChild("returnType", retType); + + HotColdAnnotation* anno = new HotColdAnnotation(); + anno->hint = "Cold"; + fn->addChild("annotations", anno); + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert((contains(output, "__attribute__((cold))") || contains(output, "[[unlikely]]")) && + "@Cold should produce __attribute__((cold)) or [[unlikely]]"); + + std::cout << "Test 6 PASS: @Cold → C++ cold attribute" << std::endl; + ++passed; + + delete anno; + delete retType; + delete fn; + } + + // --- Test 7: @Inline(Always) → C++ always_inline --- + { + Module mod("m1", "Perf", "cpp"); + Function* fn = new Function("f1", "fastMath"); + PrimitiveType* retType = new PrimitiveType("t1", "int"); + fn->setChild("returnType", retType); + + InlineAnnotation* anno = new InlineAnnotation(); + anno->mode = "Always"; + fn->addChild("annotations", anno); + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert((contains(output, "always_inline") || contains(output, "inline")) && + "@Inline(Always) should produce inline attribute"); + + std::cout << "Test 7 PASS: @Inline(Always) → C++ always_inline" << std::endl; + ++passed; + + delete anno; + delete retType; + delete fn; + } + + // --- Test 8: @Pure → C++ [[nodiscard]] --- + { + Module mod("m1", "Perf", "cpp"); + Function* fn = new Function("f1", "pureCalc"); + PrimitiveType* retType = new PrimitiveType("t1", "int"); + fn->setChild("returnType", retType); + + PureAnnotation* anno = new PureAnnotation(); + fn->addChild("annotations", anno); + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert((contains(output, "[[nodiscard]]") || contains(output, "pure") || + contains(output, "[[gnu::pure]]")) && + "@Pure should produce [[nodiscard]] or [[gnu::pure]]"); + + std::cout << "Test 8 PASS: @Pure → C++ pure/nodiscard attribute" << std::endl; + ++passed; + + delete anno; + delete retType; + delete fn; + } + + // --- Test 9: @ConstExpr → C++ constexpr --- + { + Module mod("m1", "Perf", "cpp"); + Function* fn = new Function("f1", "constCalc"); + PrimitiveType* retType = new PrimitiveType("t1", "int"); + fn->setChild("returnType", retType); + + ConstExprAnnotation* anno = new ConstExprAnnotation(); + fn->addChild("annotations", anno); + mod.addChild("functions", fn); + + CppGenerator gen; + std::string output = gen.generate(&mod); + + assert(contains(output, "constexpr") && + "@ConstExpr should produce 'constexpr' keyword"); + + std::cout << "Test 9 PASS: @ConstExpr → C++ constexpr" << std::endl; + ++passed; + + delete anno; + delete retType; + delete fn; + } + + // --- Summary --- + std::cout << "\n=== Step 67 Results: " << passed << " passed, " << failed << " failed ===" << std::endl; + return failed > 0 ? 1 : 0; +}