Steps 266-268: Phase 10a — semantic annotation core + sidecar persistence (32/32 tests)
Step 266: 5 semantic annotation AST types (Intent, Complexity, Risk,
Contract, SemanticTag) with JSON roundtrip and compact AST integration.
Step 267: Sidecar AST persistence (.whetstone/<file>.ast.json) with
save/load/list RPC methods, MCP tools, and permission enforcement.
Step 268: Phase 10a integration tests — multi-file sidecar workflow,
all 5 types in compact view, idempotent roundtrip, source isolation.
Also includes Sprint 10 plan, GUI/installer polish, and Emacs integration fixes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 16:01:56 +00:00
|
|
|
#pragma once
|
|
|
|
|
// Step 267: Sidecar AST Persistence
|
|
|
|
|
//
|
|
|
|
|
// Save/load annotated ASTs as .whetstone/<path>.ast.json sidecar files.
|
|
|
|
|
// Annotations live alongside the codebase without polluting source code.
|
|
|
|
|
|
|
|
|
|
#include "ast/ASTNode.h"
|
|
|
|
|
#include "ast/Serialization.h"
|
|
|
|
|
#include "ast/Annotation.h"
|
2026-02-13 19:42:28 +00:00
|
|
|
#include "ASTUtils.h"
|
|
|
|
|
#include "CompactAST.h"
|
|
|
|
|
#include "SemannoSidecar.h"
|
Steps 266-268: Phase 10a — semantic annotation core + sidecar persistence (32/32 tests)
Step 266: 5 semantic annotation AST types (Intent, Complexity, Risk,
Contract, SemanticTag) with JSON roundtrip and compact AST integration.
Step 267: Sidecar AST persistence (.whetstone/<file>.ast.json) with
save/load/list RPC methods, MCP tools, and permission enforcement.
Step 268: Phase 10a integration tests — multi-file sidecar workflow,
all 5 types in compact view, idempotent roundtrip, source isolation.
Also includes Sprint 10 plan, GUI/installer polish, and Emacs integration fixes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 16:01:56 +00:00
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
|
|
using json = nlohmann::json;
|
|
|
|
|
|
|
|
|
|
// --- Sidecar path resolution ---
|
|
|
|
|
inline std::string sidecarPath(const std::string& workspaceRoot,
|
|
|
|
|
const std::string& filePath) {
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
fs::path base = fs::path(workspaceRoot) / ".whetstone";
|
|
|
|
|
return (base / (filePath + ".ast.json")).string();
|
|
|
|
|
}
|
|
|
|
|
|
Steps 272-277: Phase 10c — type system, concurrency & scope annotations (68/68 tests)
- Step 272: Type layout/constraints — BitWidth, Endian, Layout, Nullability, Variance (37 tests)
- Step 273: Type identity/mutability — Identity, Mut, TypeState (25 tests)
- Step 274: Concurrency primitives — Atomic, Sync, ThreadModel, MemoryBarrier (25 tests)
- Step 275: Async/error handling — Exec, Blocking, Parallel, Trap, Exception, Panic (36 tests)
- Step 276: Scope/namespace — Binding, Lookup, Capture, Visibility, Namespace, Scope (32 tests)
- Step 277: Integration tests — cross-subject workflows, sidecar roundtrip, RPC (16 tests)
- 24 new annotation classes with JSON roundtrip, compact AST, sidecar persistence
- Generic fallback in getSemanticAnnotations RPC for extensible annotation queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:15:21 +00:00
|
|
|
// --- Check if a node type is a semantic annotation ---
|
|
|
|
|
inline bool isSemanticAnnotation(const std::string& conceptType) {
|
|
|
|
|
return conceptType == "IntentAnnotation" ||
|
|
|
|
|
conceptType == "ComplexityAnnotation" ||
|
|
|
|
|
conceptType == "RiskAnnotation" ||
|
|
|
|
|
conceptType == "ContractAnnotation" ||
|
|
|
|
|
conceptType == "SemanticTagAnnotation" ||
|
|
|
|
|
// Type System (Steps 272-273)
|
|
|
|
|
conceptType == "BitWidthAnnotation" ||
|
|
|
|
|
conceptType == "EndianAnnotation" ||
|
|
|
|
|
conceptType == "LayoutAnnotation" ||
|
|
|
|
|
conceptType == "NullabilityAnnotation" ||
|
|
|
|
|
conceptType == "VarianceAnnotation" ||
|
|
|
|
|
conceptType == "IdentityAnnotation" ||
|
|
|
|
|
conceptType == "MutAnnotation" ||
|
|
|
|
|
conceptType == "TypeStateAnnotation" ||
|
|
|
|
|
// Concurrency (Step 274)
|
|
|
|
|
conceptType == "AtomicAnnotation" ||
|
|
|
|
|
conceptType == "SyncAnnotation" ||
|
|
|
|
|
conceptType == "ThreadModelAnnotation" ||
|
|
|
|
|
conceptType == "MemoryBarrierAnnotation" ||
|
|
|
|
|
// Async / Error Handling (Step 275)
|
|
|
|
|
conceptType == "ExecAnnotation" ||
|
|
|
|
|
conceptType == "BlockingAnnotation" ||
|
|
|
|
|
conceptType == "ParallelAnnotation" ||
|
|
|
|
|
conceptType == "TrapAnnotation" ||
|
|
|
|
|
conceptType == "ExceptionAnnotation" ||
|
|
|
|
|
conceptType == "PanicAnnotation" ||
|
|
|
|
|
// Scope & Namespace (Step 276)
|
|
|
|
|
conceptType == "BindingAnnotation" ||
|
|
|
|
|
conceptType == "LookupAnnotation" ||
|
|
|
|
|
conceptType == "CaptureAnnotation" ||
|
|
|
|
|
conceptType == "VisibilityAnnotation" ||
|
|
|
|
|
conceptType == "NamespaceAnnotation" ||
|
Steps 278-283: Phase 10d — shims, optimization, meta-programming & policy annotations (117/117 tests)
- Step 278: Shim/escape hatch — Intrinsic, Raw, CallingConv, Link, Shim, PointerArithmetic, Opaque (25 tests)
- Step 279: Platform/provenance — Target, Feature, Original, Mapping (19 tests)
- Step 280: Optimization completion — TailCall, Loop, Data, Align, Pack, BoundsCheck, Overflow (22 tests)
- Step 281: Meta-programming — Meta, Symbol, Evaluate, Template, Synthetic (20 tests)
- Step 282: Strategy/policy — Policy, Ambiguity, Candidate, Tradeoff, Choice, Decision (22 tests)
- Step 283: Integration tests — FFI workflow, sidecar roundtrip, RPC, taxonomy completeness (9 tests)
- 29 new annotation classes with JSON roundtrip, compact AST, sidecar persistence
- All 58 semantic annotation types recognized across 8 subjects
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:29:43 +00:00
|
|
|
conceptType == "ScopeAnnotation" ||
|
|
|
|
|
// Shim & Escape Hatch (Step 278)
|
|
|
|
|
conceptType == "IntrinsicAnnotation" ||
|
|
|
|
|
conceptType == "RawAnnotation" ||
|
|
|
|
|
conceptType == "CallingConvAnnotation" ||
|
|
|
|
|
conceptType == "LinkAnnotation" ||
|
|
|
|
|
conceptType == "ShimAnnotation" ||
|
|
|
|
|
conceptType == "PointerArithmeticAnnotation" ||
|
|
|
|
|
conceptType == "OpaqueAnnotation" ||
|
|
|
|
|
// Platform & Provenance (Step 279)
|
|
|
|
|
conceptType == "TargetAnnotation" ||
|
|
|
|
|
conceptType == "FeatureAnnotation" ||
|
|
|
|
|
conceptType == "OriginalAnnotation" ||
|
|
|
|
|
conceptType == "MappingAnnotation" ||
|
|
|
|
|
// Optimization Completion (Step 280)
|
|
|
|
|
conceptType == "TailCallAnnotation" ||
|
|
|
|
|
conceptType == "LoopAnnotation" ||
|
|
|
|
|
conceptType == "DataAnnotation" ||
|
|
|
|
|
conceptType == "AlignAnnotation" ||
|
|
|
|
|
conceptType == "PackAnnotation" ||
|
|
|
|
|
conceptType == "BoundsCheckAnnotation" ||
|
|
|
|
|
conceptType == "OverflowAnnotation" ||
|
|
|
|
|
// Meta-Programming (Step 281)
|
|
|
|
|
conceptType == "MetaAnnotation" ||
|
|
|
|
|
conceptType == "SymbolAnnotation" ||
|
|
|
|
|
conceptType == "EvaluateAnnotation" ||
|
|
|
|
|
conceptType == "TemplateAnnotation" ||
|
|
|
|
|
conceptType == "SyntheticAnnotation" ||
|
|
|
|
|
// Strategy & Policy (Step 282)
|
|
|
|
|
conceptType == "PolicyAnnotation" ||
|
|
|
|
|
conceptType == "AmbiguityAnnotation" ||
|
|
|
|
|
conceptType == "CandidateAnnotation" ||
|
|
|
|
|
conceptType == "TradeoffAnnotation" ||
|
|
|
|
|
conceptType == "ChoiceAnnotation" ||
|
Phase 10e WIP: environment layer core + host boundary nodes
EnvironmentSpec, CapabilityRequirement, HostCall, ScheduleTask, ModuleLoad
classes created. All wired through Serialization.h, CompactAST.h,
SidecarPersistence.h, HeadlessAgentRPCHandler.h (setEnvironment,
getEnvironment, validateEnvironment, getLoweringHints RPCs).
Tests for steps 284-285 written. Steps 286-289 tests remaining.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:41:16 +00:00
|
|
|
conceptType == "DecisionAnnotation" ||
|
Steps 309-319: Sprint 11 Phases 11d-e — Kotlin/C# languages + workflow annotation foundation
Phase 11d (Steps 309-313): Kotlin + C# parsers and generators
- KotlinParser (regex-based): fun, suspend fun, class, data class, val/var
- KotlinGenerator: idiomatic Kotlin output with type mappings
- CSharpParser (regex-based): methods, async, class, interface
- CSharpGenerator: Allman braces, foreach, Task async, LINQ types
- Pipeline integration for both languages, 10 parsers + 10 generators
Phase 11e (Steps 314-319): Workflow annotation foundation
- AnnotationInference: generalized multi-subject inference engine
- Subject 9 routing annotations: ContextWidth, Review, Ambiguity,
Automatability, Priority, ImplementationStatus
- SkeletonAST: project specification before code exists
- Architect tooling: createSkeleton, addSkeletonNode, getProjectModel,
inferAnnotations RPCs + 4 MCP tools (42+ total)
- Inference-to-routing bridge: complexity→ambiguity, getter→deterministic
- TrainingDataExporter + TrainingDataGenerator scaffolding
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:50:06 -07:00
|
|
|
// Subject 9: Workflow Routing (Step 315)
|
|
|
|
|
conceptType == "ContextWidthAnnotation" ||
|
|
|
|
|
conceptType == "ReviewAnnotation" ||
|
|
|
|
|
conceptType == "AutomatabilityAnnotation" ||
|
|
|
|
|
conceptType == "PriorityAnnotation" ||
|
|
|
|
|
conceptType == "ImplementationStatusAnnotation" ||
|
Phase 10e WIP: environment layer core + host boundary nodes
EnvironmentSpec, CapabilityRequirement, HostCall, ScheduleTask, ModuleLoad
classes created. All wired through Serialization.h, CompactAST.h,
SidecarPersistence.h, HeadlessAgentRPCHandler.h (setEnvironment,
getEnvironment, validateEnvironment, getLoweringHints RPCs).
Tests for steps 284-285 written. Steps 286-289 tests remaining.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:41:16 +00:00
|
|
|
// Environment Layer (Step 285)
|
|
|
|
|
conceptType == "CapabilityRequirement";
|
Steps 272-277: Phase 10c — type system, concurrency & scope annotations (68/68 tests)
- Step 272: Type layout/constraints — BitWidth, Endian, Layout, Nullability, Variance (37 tests)
- Step 273: Type identity/mutability — Identity, Mut, TypeState (25 tests)
- Step 274: Concurrency primitives — Atomic, Sync, ThreadModel, MemoryBarrier (25 tests)
- Step 275: Async/error handling — Exec, Blocking, Parallel, Trap, Exception, Panic (36 tests)
- Step 276: Scope/namespace — Binding, Lookup, Capture, Visibility, Namespace, Scope (32 tests)
- Step 277: Integration tests — cross-subject workflows, sidecar roundtrip, RPC (16 tests)
- 24 new annotation classes with JSON roundtrip, compact AST, sidecar persistence
- Generic fallback in getSemanticAnnotations RPC for extensible annotation queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:15:21 +00:00
|
|
|
}
|
|
|
|
|
|
Steps 266-268: Phase 10a — semantic annotation core + sidecar persistence (32/32 tests)
Step 266: 5 semantic annotation AST types (Intent, Complexity, Risk,
Contract, SemanticTag) with JSON roundtrip and compact AST integration.
Step 267: Sidecar AST persistence (.whetstone/<file>.ast.json) with
save/load/list RPC methods, MCP tools, and permission enforcement.
Step 268: Phase 10a integration tests — multi-file sidecar workflow,
all 5 types in compact view, idempotent roundtrip, source isolation.
Also includes Sprint 10 plan, GUI/installer polish, and Emacs integration fixes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 16:01:56 +00:00
|
|
|
// --- Count semantic annotations in an AST ---
|
|
|
|
|
inline int countSemanticAnnotations(const ASTNode* node) {
|
|
|
|
|
if (!node) return 0;
|
|
|
|
|
int count = 0;
|
|
|
|
|
auto annos = node->getChildren("annotations");
|
|
|
|
|
for (const auto* a : annos) {
|
Steps 272-277: Phase 10c — type system, concurrency & scope annotations (68/68 tests)
- Step 272: Type layout/constraints — BitWidth, Endian, Layout, Nullability, Variance (37 tests)
- Step 273: Type identity/mutability — Identity, Mut, TypeState (25 tests)
- Step 274: Concurrency primitives — Atomic, Sync, ThreadModel, MemoryBarrier (25 tests)
- Step 275: Async/error handling — Exec, Blocking, Parallel, Trap, Exception, Panic (36 tests)
- Step 276: Scope/namespace — Binding, Lookup, Capture, Visibility, Namespace, Scope (32 tests)
- Step 277: Integration tests — cross-subject workflows, sidecar roundtrip, RPC (16 tests)
- 24 new annotation classes with JSON roundtrip, compact AST, sidecar persistence
- Generic fallback in getSemanticAnnotations RPC for extensible annotation queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 18:15:21 +00:00
|
|
|
if (isSemanticAnnotation(a->conceptType))
|
Steps 266-268: Phase 10a — semantic annotation core + sidecar persistence (32/32 tests)
Step 266: 5 semantic annotation AST types (Intent, Complexity, Risk,
Contract, SemanticTag) with JSON roundtrip and compact AST integration.
Step 267: Sidecar AST persistence (.whetstone/<file>.ast.json) with
save/load/list RPC methods, MCP tools, and permission enforcement.
Step 268: Phase 10a integration tests — multi-file sidecar workflow,
all 5 types in compact view, idempotent roundtrip, source isolation.
Also includes Sprint 10 plan, GUI/installer polish, and Emacs integration fixes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 16:01:56 +00:00
|
|
|
++count;
|
|
|
|
|
}
|
|
|
|
|
for (const auto* child : node->allChildren()) {
|
|
|
|
|
count += countSemanticAnnotations(child);
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Save annotated AST to sidecar file ---
|
|
|
|
|
struct SidecarSaveResult {
|
|
|
|
|
bool success = false;
|
|
|
|
|
std::string sidecarPath;
|
|
|
|
|
int annotationCount = 0;
|
|
|
|
|
std::string error;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline SidecarSaveResult saveSidecarAST(const std::string& workspaceRoot,
|
|
|
|
|
const std::string& filePath,
|
|
|
|
|
Module* ast) {
|
|
|
|
|
SidecarSaveResult result;
|
|
|
|
|
if (!ast) {
|
|
|
|
|
result.error = "No AST to save";
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.sidecarPath = sidecarPath(workspaceRoot, filePath);
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
fs::create_directories(fs::path(result.sidecarPath).parent_path());
|
|
|
|
|
|
|
|
|
|
json astJson = toJson(ast);
|
|
|
|
|
std::ofstream out(result.sidecarPath);
|
|
|
|
|
if (!out.is_open()) {
|
|
|
|
|
result.error = "Cannot write to " + result.sidecarPath;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
out << astJson.dump(2);
|
|
|
|
|
out.close();
|
|
|
|
|
|
|
|
|
|
result.annotationCount = countSemanticAnnotations(ast);
|
|
|
|
|
result.success = true;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Find a matching node in the live AST ---
|
|
|
|
|
// Tries ID match first, then falls back to concept+name match
|
|
|
|
|
// (node IDs are ephemeral and change across re-parses).
|
|
|
|
|
inline ASTNode* findMatchingNode(ASTNode* liveRoot,
|
|
|
|
|
const ASTNode* sidecarNode) {
|
|
|
|
|
if (!liveRoot || !sidecarNode) return nullptr;
|
|
|
|
|
// Try exact ID match first
|
|
|
|
|
ASTNode* byId = findNodeById(liveRoot, sidecarNode->id);
|
|
|
|
|
if (byId) return byId;
|
|
|
|
|
// Fallback: match by concept type + name
|
|
|
|
|
std::string name = getNodeName(sidecarNode);
|
|
|
|
|
if (name.empty()) return nullptr;
|
|
|
|
|
for (auto* child : liveRoot->allChildren()) {
|
|
|
|
|
if (child->conceptType == sidecarNode->conceptType &&
|
|
|
|
|
getNodeName(child) == name)
|
|
|
|
|
return child;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Merge annotations from sidecar AST into live AST ---
|
|
|
|
|
// Matches nodes by ID or concept+name, copies semantic annotations.
|
|
|
|
|
struct SidecarMergeResult {
|
|
|
|
|
bool success = false;
|
|
|
|
|
int mergedCount = 0;
|
|
|
|
|
int staleCount = 0;
|
|
|
|
|
std::string error;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline void mergeAnnotationsRecursive(ASTNode* sidecarNode,
|
|
|
|
|
ASTNode* liveRoot,
|
|
|
|
|
int& mergedCount,
|
|
|
|
|
int& staleCount) {
|
|
|
|
|
if (!sidecarNode) return;
|
|
|
|
|
|
|
|
|
|
// Check if this sidecar node has semantic annotations to merge
|
|
|
|
|
auto annos = sidecarNode->getChildren("annotations");
|
|
|
|
|
for (auto* anno : annos) {
|
|
|
|
|
if (!isSemanticAnnotation(anno->conceptType)) continue;
|
|
|
|
|
|
|
|
|
|
// Find matching node in live AST
|
|
|
|
|
ASTNode* liveNode = findMatchingNode(liveRoot, sidecarNode);
|
|
|
|
|
if (liveNode) {
|
|
|
|
|
// Clone the annotation via JSON roundtrip
|
|
|
|
|
json annoJson = toJson(anno);
|
|
|
|
|
ASTNode* cloned = fromJson(annoJson);
|
|
|
|
|
if (cloned) {
|
|
|
|
|
liveNode->addChild("annotations", cloned);
|
|
|
|
|
++mergedCount;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
++staleCount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Recurse into children
|
|
|
|
|
for (auto* child : sidecarNode->allChildren()) {
|
|
|
|
|
// Skip annotation children themselves
|
|
|
|
|
if (isSemanticAnnotation(child->conceptType)) continue;
|
|
|
|
|
mergeAnnotationsRecursive(child, liveRoot, mergedCount, staleCount);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline SidecarMergeResult loadSidecarAST(const std::string& workspaceRoot,
|
|
|
|
|
const std::string& filePath,
|
|
|
|
|
Module* liveAST) {
|
|
|
|
|
SidecarMergeResult result;
|
|
|
|
|
if (!liveAST) {
|
|
|
|
|
result.error = "No live AST to merge into";
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string path = sidecarPath(workspaceRoot, filePath);
|
|
|
|
|
std::ifstream in(path);
|
|
|
|
|
if (!in.is_open()) {
|
|
|
|
|
result.error = "No sidecar file: " + path;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
json astJson;
|
|
|
|
|
try {
|
|
|
|
|
in >> astJson;
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
result.error = std::string("Failed to parse sidecar: ") + e.what();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
in.close();
|
|
|
|
|
|
|
|
|
|
ASTNode* sidecarAST = fromJson(astJson);
|
|
|
|
|
if (!sidecarAST) {
|
|
|
|
|
result.error = "Failed to deserialize sidecar AST";
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mergeAnnotationsRecursive(sidecarAST, liveAST,
|
|
|
|
|
result.mergedCount, result.staleCount);
|
|
|
|
|
|
|
|
|
|
// Clean up sidecar AST
|
|
|
|
|
delete sidecarAST;
|
|
|
|
|
|
|
|
|
|
result.success = true;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- List available sidecar files ---
|
|
|
|
|
inline std::vector<std::string> listSidecarFiles(
|
|
|
|
|
const std::string& workspaceRoot) {
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
std::vector<std::string> files;
|
|
|
|
|
fs::path dir = fs::path(workspaceRoot) / ".whetstone";
|
|
|
|
|
if (!fs::exists(dir)) return files;
|
|
|
|
|
|
|
|
|
|
for (const auto& entry : fs::directory_iterator(dir)) {
|
|
|
|
|
if (entry.is_regular_file()) {
|
|
|
|
|
std::string name = entry.path().filename().string();
|
|
|
|
|
// Remove .ast.json suffix to get original path
|
|
|
|
|
const std::string suffix = ".ast.json";
|
|
|
|
|
if (name.size() > suffix.size() &&
|
|
|
|
|
name.substr(name.size() - suffix.size()) == suffix) {
|
|
|
|
|
files.push_back(name.substr(0, name.size() - suffix.size()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return files;
|
|
|
|
|
}
|