Complete step469 initializer list and STL pattern support with tests
This commit is contained in:
@@ -3100,4 +3100,13 @@ target_link_libraries(step468_test PRIVATE
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
add_executable(step469_test tests/step469_test.cpp)
|
||||
target_include_directories(step469_test PRIVATE src)
|
||||
target_link_libraries(step469_test PRIVATE
|
||||
nlohmann_json::nlohmann_json
|
||||
unofficial::tree-sitter::tree-sitter
|
||||
tree_sitter_python tree_sitter_cpp tree_sitter_elisp
|
||||
tree_sitter_javascript tree_sitter_typescript
|
||||
tree_sitter_java tree_sitter_rust tree_sitter_go)
|
||||
|
||||
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)
|
||||
|
||||
135
editor/src/ast/CppInitializerStl.h
Normal file
135
editor/src/ast/CppInitializerStl.h
Normal file
@@ -0,0 +1,135 @@
|
||||
#pragma once
|
||||
|
||||
// Step 469: Initializer Lists + STL Patterns
|
||||
// Focused helpers for parsing initializer-list expressions and recognizing
|
||||
// common STL/iterator loop patterns with lightweight annotations.
|
||||
|
||||
#include "ASTNode.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
class InitializerListExpression : public ASTNode {
|
||||
public:
|
||||
std::vector<std::string> elements;
|
||||
|
||||
InitializerListExpression() { conceptType = "InitializerListExpression"; }
|
||||
};
|
||||
|
||||
struct StlContainerInfo {
|
||||
std::string rawType; // std::vector<int>
|
||||
std::string containerKind; // vector/map/set/string/unknown
|
||||
std::string elementType; // int, pair<...>, ...
|
||||
std::vector<std::string> annotations;
|
||||
};
|
||||
|
||||
struct IteratorPatternInfo {
|
||||
bool isIteratorLoop = false;
|
||||
std::vector<std::string> annotations; // includes @Loop(...) when detected
|
||||
};
|
||||
|
||||
class CppInitializerStl {
|
||||
public:
|
||||
static bool parseInitializerList(const std::string& source, InitializerListExpression& out) {
|
||||
std::regex rx(R"(\{([^}]*)\})");
|
||||
std::smatch m;
|
||||
if (!std::regex_search(source, m, rx)) return false;
|
||||
out.elements = splitCsv(m[1].str());
|
||||
return true;
|
||||
}
|
||||
|
||||
static StlContainerInfo recognizeContainer(const std::string& declaration) {
|
||||
StlContainerInfo info;
|
||||
std::regex rx(R"((std::[A-Za-z_]\w*(?:\s*<[^>]+>)?)\s+[A-Za-z_]\w*)");
|
||||
std::smatch m;
|
||||
if (!std::regex_search(declaration, m, rx)) {
|
||||
info.containerKind = "unknown";
|
||||
info.rawType = "";
|
||||
return info;
|
||||
}
|
||||
|
||||
info.rawType = trim(m[1].str());
|
||||
auto lowered = toLower(info.rawType);
|
||||
if (lowered.find("std::vector") == 0) info.containerKind = "vector";
|
||||
else if (lowered.find("std::map") == 0) info.containerKind = "map";
|
||||
else if (lowered.find("std::set") == 0) info.containerKind = "set";
|
||||
else if (lowered.find("std::string") == 0) info.containerKind = "string";
|
||||
else info.containerKind = "unknown";
|
||||
|
||||
info.elementType = extractTemplateArg(info.rawType);
|
||||
info.annotations.push_back("@Container(" + info.containerKind + ")");
|
||||
if (!info.elementType.empty()) info.annotations.push_back("@ElementType(" + info.elementType + ")");
|
||||
return info;
|
||||
}
|
||||
|
||||
static IteratorPatternInfo detectIteratorPattern(const std::string& source) {
|
||||
IteratorPatternInfo info;
|
||||
std::string s = toLower(source);
|
||||
bool hasBeginEnd = s.find(".begin()") != std::string::npos && s.find(".end()") != std::string::npos;
|
||||
bool hasIteratorDecl = s.find("::iterator") != std::string::npos || s.find("auto it") != std::string::npos;
|
||||
bool hasIncrement = s.find("++it") != std::string::npos || s.find("it++") != std::string::npos;
|
||||
if (hasBeginEnd && hasIteratorDecl && hasIncrement) {
|
||||
info.isIteratorLoop = true;
|
||||
info.annotations.push_back("@Loop(iterator)");
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static json toJson(const InitializerListExpression& e) {
|
||||
return {
|
||||
{"concept", e.conceptType},
|
||||
{"elements", e.elements}
|
||||
};
|
||||
}
|
||||
|
||||
static InitializerListExpression fromJson(const json& j) {
|
||||
InitializerListExpression e;
|
||||
e.elements = j.value("elements", std::vector<std::string>{});
|
||||
return e;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string trim(const std::string& s) {
|
||||
size_t start = s.find_first_not_of(" \t\r\n");
|
||||
if (start == std::string::npos) return "";
|
||||
size_t end = s.find_last_not_of(" \t\r\n");
|
||||
return s.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
static std::string toLower(std::string s) {
|
||||
for (char& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::vector<std::string> splitCsv(const std::string& in) {
|
||||
std::vector<std::string> out;
|
||||
std::string cur;
|
||||
int depth = 0;
|
||||
for (char c : in) {
|
||||
if (c == '<') ++depth;
|
||||
if (c == '>') --depth;
|
||||
if (c == ',' && depth == 0) {
|
||||
auto t = trim(cur);
|
||||
if (!t.empty()) out.push_back(t);
|
||||
cur.clear();
|
||||
} else {
|
||||
cur.push_back(c);
|
||||
}
|
||||
}
|
||||
auto t = trim(cur);
|
||||
if (!t.empty()) out.push_back(t);
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::string extractTemplateArg(const std::string& type) {
|
||||
size_t lt = type.find('<');
|
||||
size_t gt = type.rfind('>');
|
||||
if (lt == std::string::npos || gt == std::string::npos || gt <= lt) return "";
|
||||
return trim(type.substr(lt + 1, gt - lt - 1));
|
||||
}
|
||||
};
|
||||
138
editor/tests/step469_test.cpp
Normal file
138
editor/tests/step469_test.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
// Step 469: Initializer Lists + STL Patterns Tests (12 tests)
|
||||
|
||||
#include "ast/CppInitializerStl.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static int passed = 0, failed = 0;
|
||||
#define TEST(name) { std::cout << " " << #name << "... "; }
|
||||
#define PASS() { std::cout << "PASS\n"; ++passed; }
|
||||
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
|
||||
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {}
|
||||
|
||||
void test_parse_initializer_list_simple_ints() {
|
||||
TEST(parse_initializer_list_simple_ints);
|
||||
InitializerListExpression e;
|
||||
bool ok = CppInitializerStl::parseInitializerList("{1, 2, 3}", e);
|
||||
CHECK(ok, "parse should succeed");
|
||||
CHECK(e.elements.size() == 3, "expected 3 elements");
|
||||
CHECK(e.elements[0] == "1" && e.elements[2] == "3", "wrong elements");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_parse_initializer_list_strings() {
|
||||
TEST(parse_initializer_list_strings);
|
||||
InitializerListExpression e;
|
||||
bool ok = CppInitializerStl::parseInitializerList("{\"a\", \"b\"}", e);
|
||||
CHECK(ok, "parse should succeed");
|
||||
CHECK(e.elements.size() == 2, "expected 2 elements");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_initializer_list_json_roundtrip() {
|
||||
TEST(initializer_list_json_roundtrip);
|
||||
InitializerListExpression e;
|
||||
e.elements = {"1", "2", "3"};
|
||||
auto j = CppInitializerStl::toJson(e);
|
||||
auto out = CppInitializerStl::fromJson(j);
|
||||
CHECK(out.elements.size() == 3, "roundtrip element count mismatch");
|
||||
CHECK(out.elements[1] == "2", "roundtrip element mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_recognize_std_vector_container() {
|
||||
TEST(recognize_std_vector_container);
|
||||
auto info = CppInitializerStl::recognizeContainer("std::vector<int> v = {1,2,3};");
|
||||
CHECK(info.containerKind == "vector", "expected vector kind");
|
||||
CHECK(info.elementType == "int", "expected int element type");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_recognize_std_map_container() {
|
||||
TEST(recognize_std_map_container);
|
||||
auto info = CppInitializerStl::recognizeContainer("std::map<std::string,int> m;");
|
||||
CHECK(info.containerKind == "map", "expected map kind");
|
||||
CHECK(info.elementType.find("std::string") != std::string::npos, "expected map template args");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_recognize_std_set_container() {
|
||||
TEST(recognize_std_set_container);
|
||||
auto info = CppInitializerStl::recognizeContainer("std::set<long> s;");
|
||||
CHECK(info.containerKind == "set", "expected set kind");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_recognize_std_string_container() {
|
||||
TEST(recognize_std_string_container);
|
||||
auto info = CppInitializerStl::recognizeContainer("std::string name;");
|
||||
CHECK(info.containerKind == "string", "expected string kind");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_unknown_container_fallback() {
|
||||
TEST(unknown_container_fallback);
|
||||
auto info = CppInitializerStl::recognizeContainer("CustomList<int> c;");
|
||||
CHECK(info.containerKind == "unknown", "expected unknown kind");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_container_annotations_include_type_info() {
|
||||
TEST(container_annotations_include_type_info);
|
||||
auto info = CppInitializerStl::recognizeContainer("std::vector<int> v;");
|
||||
bool hasContainer = false, hasElement = false;
|
||||
for (const auto& a : info.annotations) {
|
||||
if (a.find("@Container(") != std::string::npos) hasContainer = true;
|
||||
if (a.find("@ElementType(") != std::string::npos) hasElement = true;
|
||||
}
|
||||
CHECK(hasContainer, "missing container annotation");
|
||||
CHECK(hasElement, "missing element type annotation");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_detect_iterator_pattern_begin_end_loop() {
|
||||
TEST(detect_iterator_pattern_begin_end_loop);
|
||||
std::string src = "for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) { use(*it); }";
|
||||
auto info = CppInitializerStl::detectIteratorPattern(src);
|
||||
CHECK(info.isIteratorLoop, "expected iterator loop detection");
|
||||
CHECK(!info.annotations.empty(), "expected loop annotation");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_detect_iterator_pattern_auto_it_loop() {
|
||||
TEST(detect_iterator_pattern_auto_it_loop);
|
||||
std::string src = "for (auto it = values.begin(); it != values.end(); it++) { sum += *it; }";
|
||||
auto info = CppInitializerStl::detectIteratorPattern(src);
|
||||
CHECK(info.isIteratorLoop, "expected iterator loop detection");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void test_non_iterator_loop_not_annotated() {
|
||||
TEST(non_iterator_loop_not_annotated);
|
||||
std::string src = "for (int i = 0; i < n; ++i) { sum += i; }";
|
||||
auto info = CppInitializerStl::detectIteratorPattern(src);
|
||||
CHECK(!info.isIteratorLoop, "should not detect iterator loop");
|
||||
CHECK(info.annotations.empty(), "should not add loop annotations");
|
||||
PASS();
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Step 469: Initializer Lists + STL Patterns Tests\n";
|
||||
|
||||
test_parse_initializer_list_simple_ints(); // 1
|
||||
test_parse_initializer_list_strings(); // 2
|
||||
test_initializer_list_json_roundtrip(); // 3
|
||||
test_recognize_std_vector_container(); // 4
|
||||
test_recognize_std_map_container(); // 5
|
||||
test_recognize_std_set_container(); // 6
|
||||
test_recognize_std_string_container(); // 7
|
||||
test_unknown_container_fallback(); // 8
|
||||
test_container_annotations_include_type_info(); // 9
|
||||
test_detect_iterator_pattern_begin_end_loop(); // 10
|
||||
test_detect_iterator_pattern_auto_it_loop(); // 11
|
||||
test_non_iterator_loop_not_annotated(); // 12
|
||||
|
||||
std::cout << "\nResults: " << passed << "/" << (passed + failed)
|
||||
<< " passed\n";
|
||||
return failed == 0 ? 0 : 1;
|
||||
}
|
||||
30
progress.md
30
progress.md
@@ -6360,3 +6360,33 @@ named methods in Java/Python.
|
||||
**Architecture gate check:**
|
||||
- `editor/src/ast/CppOperators.h` within header-size limit (`129` <= `600`)
|
||||
- `editor/tests/step468_test.cpp` within test-file size guidance (`152` lines)
|
||||
|
||||
### Step 469: Initializer Lists + STL Patterns
|
||||
**Status:** PASS (12/12 tests)
|
||||
|
||||
Adds focused support for C++ initializer-list parsing plus STL container and
|
||||
iterator-loop pattern recognition with lightweight annotation outputs.
|
||||
|
||||
**Files added:**
|
||||
- `editor/src/ast/CppInitializerStl.h` — initializer/STL helpers:
|
||||
- `InitializerListExpression` model
|
||||
- initializer-list parser
|
||||
- STL container recognition (`vector`, `map`, `set`, `string`)
|
||||
- element-type extraction from template arguments
|
||||
- iterator-loop pattern detector with `@Loop(iterator)` annotation
|
||||
- JSON round-trip helpers for initializer-list node
|
||||
- `editor/tests/step469_test.cpp` — 12 tests covering:
|
||||
- initializer-list parsing and round-trip
|
||||
- STL container kind/type recognition
|
||||
- container annotation output checks
|
||||
- iterator-pattern detection (`begin/end`, `auto it`) and non-iterator negative case
|
||||
- `editor/CMakeLists.txt` — `step469_test` target
|
||||
|
||||
**Verification run:**
|
||||
- `cmake --build editor/build-native --target step469_test` — PASS
|
||||
- `./editor/build-native/step469_test` — PASS (12/12)
|
||||
- `./editor/build-native/step468_test` — PASS (12/12) regression coverage
|
||||
|
||||
**Architecture gate check:**
|
||||
- `editor/src/ast/CppInitializerStl.h` within header-size limit (`135` <= `600`)
|
||||
- `editor/tests/step469_test.cpp` within test-file size guidance (`138` lines)
|
||||
|
||||
Reference in New Issue
Block a user