Steps 290-294: Phase 11a — Semanno format, annotation codegen, visitor dispatch (60/60 tests)

Semanno comment format standard (@semanno:type(key=value)) with emitter/parser
covering all 67+ annotation types. SemannoAnnotationImpl CRTP mixin provides
default visitor implementations for all 56 extended annotation methods across
7 language generators. Virtual inheritance resolves diamond ambiguity between
ProjectionGenerator and SemannoAnnotationImpl.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill
2026-02-13 18:41:31 +00:00
parent 8cbeef5af4
commit d4a3609050
29 changed files with 2510 additions and 17 deletions

614
editor/src/SemannoFormat.h Normal file
View File

@@ -0,0 +1,614 @@
#pragma once
// SemannoFormat.h — Semanno inline comment format standard
//
// Format: @semanno:type(key=value,key2=value2)
//
// SemannoEmitter — converts annotation ASTNodes to Semanno comment strings
// SemannoParser — parses Semanno comment strings back to structured data
//
// Covers all 67+ annotation types defined in Annotation.h and EnvironmentSpec.h.
#include "ast/ASTNode.h"
#include "ast/Annotation.h"
#include "EnvironmentSpec.h"
#include <string>
#include <map>
#include <vector>
#include <sstream>
#include <algorithm>
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
namespace semanno_detail {
inline std::string escapeValue(const std::string& v) {
std::string out;
out.reserve(v.size() + 2);
for (char c : v) {
if (c == '"') out += "\\\"";
else if (c == '\\') out += "\\\\";
else out += c;
}
return out;
}
inline std::string unescapeValue(const std::string& v) {
std::string out;
out.reserve(v.size());
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] == '\\' && i + 1 < v.size()) {
if (v[i + 1] == '"') { out += '"'; ++i; }
else if (v[i + 1] == '\\') { out += '\\'; ++i; }
else out += v[i];
} else {
out += v[i];
}
}
return out;
}
inline std::string joinVec(const std::vector<std::string>& vec) {
std::string out;
for (size_t i = 0; i < vec.size(); ++i) {
if (i > 0) out += ";";
out += escapeValue(vec[i]);
}
return out;
}
inline std::vector<std::string> splitVec(const std::string& s) {
std::vector<std::string> out;
if (s.empty()) return out;
std::string cur;
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] == '\\' && i + 1 < s.size()) {
cur += s[i];
cur += s[i + 1];
++i;
} else if (s[i] == ';') {
out.push_back(unescapeValue(cur));
cur.clear();
} else {
cur += s[i];
}
}
out.push_back(unescapeValue(cur));
return out;
}
// Build "key=\"value\"" pair; omits the pair entirely when value is empty.
inline void appendProp(std::string& buf, const std::string& key,
const std::string& val, bool& first) {
if (val.empty()) return;
if (!first) buf += ",";
first = false;
buf += key + "=\"" + escapeValue(val) + "\"";
}
inline void appendInt(std::string& buf, const std::string& key,
int val, bool& first) {
if (!first) buf += ",";
first = false;
buf += key + "=" + std::to_string(val);
}
inline void appendBool(std::string& buf, const std::string& key,
bool val, bool& first) {
if (!first) buf += ",";
first = false;
buf += key + "=" + (val ? "true" : "false");
}
inline void appendVec(std::string& buf, const std::string& key,
const std::vector<std::string>& vec, bool& first) {
if (vec.empty()) return;
if (!first) buf += ",";
first = false;
buf += key + "=\"" + joinVec(vec) + "\"";
}
} // namespace semanno_detail
// ---------------------------------------------------------------------------
// SemannoEmitter
// ---------------------------------------------------------------------------
class SemannoEmitter {
public:
/// Returns "@semanno:type(key=value,...)" or empty string if unrecognised.
static std::string emit(const ASTNode* anno) {
if (!anno) return "";
const std::string& ct = anno->conceptType;
std::string tag;
std::string props;
bool first = true;
using namespace semanno_detail;
// --- Subject 1: Memory ---
if (ct == "DeallocateAnnotation") {
tag = "deallocate";
auto* a = static_cast<const DeallocateAnnotation*>(anno);
appendProp(props, "strategy", a->strategy, first);
appendProp(props, "deallocateLocation", a->deallocateLocation, first);
appendProp(props, "owner", a->owner, first);
} else if (ct == "LifetimeAnnotation") {
tag = "lifetime";
auto* a = static_cast<const LifetimeAnnotation*>(anno);
appendProp(props, "strategy", a->strategy, first);
appendProp(props, "lifetimeScope", a->lifetimeScope, first);
} else if (ct == "ReclaimAnnotation") {
tag = "reclaim";
auto* a = static_cast<const ReclaimAnnotation*>(anno);
appendProp(props, "strategy", a->strategy, first);
appendProp(props, "reclaimPattern", a->reclaimPattern, first);
} else if (ct == "OwnerAnnotation") {
tag = "owner";
auto* a = static_cast<const OwnerAnnotation*>(anno);
appendProp(props, "strategy", a->strategy, first);
appendProp(props, "ownerType", a->ownerType, first);
} else if (ct == "AllocateAnnotation") {
tag = "allocate";
auto* a = static_cast<const AllocateAnnotation*>(anno);
appendProp(props, "strategy", a->strategy, first);
appendProp(props, "allocationPattern", a->allocationPattern, first);
} else if (ct == "HotColdAnnotation") {
tag = "hotcold";
auto* a = static_cast<const HotColdAnnotation*>(anno);
appendProp(props, "hint", a->hint, first);
} else if (ct == "InlineAnnotation") {
tag = "inline";
auto* a = static_cast<const InlineAnnotation*>(anno);
appendProp(props, "mode", a->mode, first);
} else if (ct == "PureAnnotation") {
tag = "pure";
} else if (ct == "ConstExprAnnotation") {
tag = "constexpr";
} else if (ct == "DerefStrategy") {
tag = "deref";
auto* a = static_cast<const DerefStrategy*>(anno);
appendProp(props, "strategy", a->strategy, first);
} else if (ct == "OptimizationLock") {
tag = "optlock";
auto* a = static_cast<const OptimizationLock*>(anno);
appendProp(props, "lockedBy", a->lockedBy, first);
appendProp(props, "lockReason", a->lockReason, first);
appendProp(props, "lockLevel", a->lockLevel, first);
} else if (ct == "LangSpecific") {
tag = "langspecific";
auto* a = static_cast<const LangSpecific*>(anno);
appendProp(props, "language", a->language, first);
appendProp(props, "idiomType", a->idiomType, first);
// --- Subject 2: Type System ---
} else if (ct == "BitWidthAnnotation") {
tag = "bitwidth";
auto* a = static_cast<const BitWidthAnnotation*>(anno);
appendInt(props, "width", a->width, first);
} else if (ct == "EndianAnnotation") {
tag = "endian";
auto* a = static_cast<const EndianAnnotation*>(anno);
appendProp(props, "order", a->order, first);
} else if (ct == "LayoutAnnotation") {
tag = "layout";
auto* a = static_cast<const LayoutAnnotation*>(anno);
appendProp(props, "mode", a->mode, first);
appendInt(props, "alignment", a->alignment, first);
} else if (ct == "NullabilityAnnotation") {
tag = "nullability";
auto* a = static_cast<const NullabilityAnnotation*>(anno);
appendBool(props, "nullable", a->nullable, first);
appendProp(props, "strategy", a->strategy, first);
} else if (ct == "VarianceAnnotation") {
tag = "variance";
auto* a = static_cast<const VarianceAnnotation*>(anno);
appendProp(props, "variance", a->variance, first);
} else if (ct == "IdentityAnnotation") {
tag = "identity";
auto* a = static_cast<const IdentityAnnotation*>(anno);
appendProp(props, "mode", a->mode, first);
} else if (ct == "MutAnnotation") {
tag = "mut";
auto* a = static_cast<const MutAnnotation*>(anno);
appendProp(props, "depth", a->depth, first);
} else if (ct == "TypeStateAnnotation") {
tag = "typestate";
auto* a = static_cast<const TypeStateAnnotation*>(anno);
appendProp(props, "state", a->state, first);
// --- Subject 3: Concurrency ---
} else if (ct == "AtomicAnnotation") {
tag = "atomic";
auto* a = static_cast<const AtomicAnnotation*>(anno);
appendProp(props, "consistency", a->consistency, first);
} else if (ct == "SyncAnnotation") {
tag = "sync";
auto* a = static_cast<const SyncAnnotation*>(anno);
appendProp(props, "primitive", a->primitive, first);
} else if (ct == "ThreadModelAnnotation") {
tag = "threadmodel";
auto* a = static_cast<const ThreadModelAnnotation*>(anno);
appendProp(props, "model", a->model, first);
} else if (ct == "MemoryBarrierAnnotation") {
tag = "memorybarrier";
} else if (ct == "ExecAnnotation") {
tag = "exec";
auto* a = static_cast<const ExecAnnotation*>(anno);
appendProp(props, "mode", a->mode, first);
appendProp(props, "runtimeHint", a->runtimeHint, first);
} else if (ct == "BlockingAnnotation") {
tag = "blocking";
auto* a = static_cast<const BlockingAnnotation*>(anno);
appendProp(props, "kind", a->kind, first);
} else if (ct == "ParallelAnnotation") {
tag = "parallel";
auto* a = static_cast<const ParallelAnnotation*>(anno);
appendProp(props, "kind", a->kind, first);
} else if (ct == "TrapAnnotation") {
tag = "trap";
auto* a = static_cast<const TrapAnnotation*>(anno);
appendProp(props, "signal", a->signal, first);
} else if (ct == "ExceptionAnnotation") {
tag = "exception";
auto* a = static_cast<const ExceptionAnnotation*>(anno);
appendProp(props, "style", a->style, first);
} else if (ct == "PanicAnnotation") {
tag = "panic";
auto* a = static_cast<const PanicAnnotation*>(anno);
appendProp(props, "behavior", a->behavior, first);
// --- Subject 4: Scope ---
} else if (ct == "BindingAnnotation") {
tag = "binding";
auto* a = static_cast<const BindingAnnotation*>(anno);
appendProp(props, "time", a->time, first);
} else if (ct == "LookupAnnotation") {
tag = "lookup";
auto* a = static_cast<const LookupAnnotation*>(anno);
appendProp(props, "mode", a->mode, first);
} else if (ct == "CaptureAnnotation") {
tag = "capture";
auto* a = static_cast<const CaptureAnnotation*>(anno);
appendProp(props, "strategy", a->strategy, first);
} else if (ct == "VisibilityAnnotation") {
tag = "visibility";
auto* a = static_cast<const VisibilityAnnotation*>(anno);
appendProp(props, "level", a->level, first);
} else if (ct == "NamespaceAnnotation") {
tag = "namespace";
auto* a = static_cast<const NamespaceAnnotation*>(anno);
appendProp(props, "style", a->style, first);
} else if (ct == "ScopeAnnotation") {
tag = "scope";
auto* a = static_cast<const ScopeAnnotation*>(anno);
appendProp(props, "kind", a->kind, first);
// --- Subject 5: Shims ---
} else if (ct == "IntrinsicAnnotation") {
tag = "intrinsic";
auto* a = static_cast<const IntrinsicAnnotation*>(anno);
appendProp(props, "instruction", a->instruction, first);
appendProp(props, "arch", a->arch, first);
} else if (ct == "RawAnnotation") {
tag = "raw";
auto* a = static_cast<const RawAnnotation*>(anno);
appendProp(props, "language", a->language, first);
appendProp(props, "code", a->code, first);
} else if (ct == "CallingConvAnnotation") {
tag = "callingconv";
auto* a = static_cast<const CallingConvAnnotation*>(anno);
appendProp(props, "convention", a->convention, first);
} else if (ct == "LinkAnnotation") {
tag = "link";
auto* a = static_cast<const LinkAnnotation*>(anno);
appendProp(props, "symbolName", a->symbolName, first);
appendProp(props, "library", a->library, first);
} else if (ct == "ShimAnnotation") {
tag = "shim";
auto* a = static_cast<const ShimAnnotation*>(anno);
appendProp(props, "strategy", a->strategy, first);
} else if (ct == "PointerArithmeticAnnotation") {
tag = "pointerarith";
} else if (ct == "OpaqueAnnotation") {
tag = "opaque";
auto* a = static_cast<const OpaqueAnnotation*>(anno);
appendProp(props, "reason", a->reason, first);
} else if (ct == "TargetAnnotation") {
tag = "target";
auto* a = static_cast<const TargetAnnotation*>(anno);
appendProp(props, "platform", a->platform, first);
appendProp(props, "arch", a->arch, first);
} else if (ct == "FeatureAnnotation") {
tag = "feature";
auto* a = static_cast<const FeatureAnnotation*>(anno);
appendProp(props, "flag", a->flag, first);
appendBool(props, "enabled", a->enabled, first);
} else if (ct == "OriginalAnnotation") {
tag = "original";
auto* a = static_cast<const OriginalAnnotation*>(anno);
appendProp(props, "sourceCode", a->sourceCode, first);
appendProp(props, "sourceLanguage", a->sourceLanguage, first);
} else if (ct == "MappingAnnotation") {
tag = "mapping";
auto* a = static_cast<const MappingAnnotation*>(anno);
appendVec(props, "history", a->history, first);
// --- Subject 6: Optimization ---
} else if (ct == "TailCallAnnotation") {
tag = "tailcall";
} else if (ct == "LoopAnnotation") {
tag = "loop";
auto* a = static_cast<const LoopAnnotation*>(anno);
appendProp(props, "hint", a->hint, first);
appendInt(props, "factor", a->factor, first);
} else if (ct == "DataAnnotation") {
tag = "data";
auto* a = static_cast<const DataAnnotation*>(anno);
appendProp(props, "hint", a->hint, first);
} else if (ct == "AlignAnnotation") {
tag = "align";
auto* a = static_cast<const AlignAnnotation*>(anno);
appendInt(props, "bytes", a->bytes, first);
} else if (ct == "PackAnnotation") {
tag = "pack";
} else if (ct == "BoundsCheckAnnotation") {
tag = "boundscheck";
auto* a = static_cast<const BoundsCheckAnnotation*>(anno);
appendBool(props, "enabled", a->enabled, first);
} else if (ct == "OverflowAnnotation") {
tag = "overflow";
auto* a = static_cast<const OverflowAnnotation*>(anno);
appendProp(props, "behavior", a->behavior, first);
// --- Subject 7: Meta-Programming ---
} else if (ct == "MetaAnnotation") {
tag = "meta";
auto* a = static_cast<const MetaAnnotation*>(anno);
appendProp(props, "state", a->state, first);
appendProp(props, "phase", a->phase, first);
} else if (ct == "SymbolAnnotation") {
tag = "symbol";
auto* a = static_cast<const SymbolAnnotation*>(anno);
appendProp(props, "mode", a->mode, first);
} else if (ct == "EvaluateAnnotation") {
tag = "evaluate";
auto* a = static_cast<const EvaluateAnnotation*>(anno);
appendProp(props, "phase", a->phase, first);
} else if (ct == "TemplateAnnotation") {
tag = "template";
auto* a = static_cast<const TemplateAnnotation*>(anno);
appendProp(props, "specialization", a->specialization, first);
} else if (ct == "SyntheticAnnotation") {
tag = "synthetic";
auto* a = static_cast<const SyntheticAnnotation*>(anno);
appendProp(props, "generator", a->generator, first);
appendBool(props, "isStructuralRisk", a->isStructuralRisk, first);
// --- Subject 8: Policy ---
} else if (ct == "PolicyAnnotation") {
tag = "policy";
auto* a = static_cast<const PolicyAnnotation*>(anno);
appendProp(props, "strictness", a->strictness, first);
appendProp(props, "perf", a->perf, first);
appendProp(props, "style", a->style, first);
appendBool(props, "binaryStable", a->binaryStable, first);
} else if (ct == "AmbiguityAnnotation") {
tag = "ambiguity";
auto* a = static_cast<const AmbiguityAnnotation*>(anno);
appendProp(props, "intent", a->intent, first);
appendVec(props, "options", a->options, first);
} else if (ct == "CandidateAnnotation") {
tag = "candidate";
auto* a = static_cast<const CandidateAnnotation*>(anno);
appendVec(props, "inferredTypes", a->inferredTypes, first);
} else if (ct == "TradeoffAnnotation") {
tag = "tradeoff";
auto* a = static_cast<const TradeoffAnnotation*>(anno);
appendProp(props, "reason", a->reason, first);
appendProp(props, "safetyCost", a->safetyCost, first);
appendProp(props, "perfCost", a->perfCost, first);
} else if (ct == "ChoiceAnnotation") {
tag = "choice";
auto* a = static_cast<const ChoiceAnnotation*>(anno);
appendProp(props, "choiceId", a->choiceId, first);
appendVec(props, "options", a->options, first);
} else if (ct == "DecisionAnnotation") {
tag = "decision";
auto* a = static_cast<const DecisionAnnotation*>(anno);
appendProp(props, "choiceId", a->choiceId, first);
appendProp(props, "selection", a->selection, first);
appendProp(props, "author", a->author, first);
appendProp(props, "reason", a->reason, first);
// --- Semantic Core ---
} else if (ct == "IntentAnnotation") {
tag = "intent";
auto* a = static_cast<const IntentAnnotation*>(anno);
appendProp(props, "summary", a->summary, first);
appendProp(props, "category", a->category, first);
} else if (ct == "ComplexityAnnotation") {
tag = "complexity";
auto* a = static_cast<const ComplexityAnnotation*>(anno);
appendProp(props, "timeComplexity", a->timeComplexity, first);
appendInt(props, "cognitiveComplexity", a->cognitiveComplexity, first);
appendInt(props, "linesOfLogic", a->linesOfLogic, first);
} else if (ct == "RiskAnnotation") {
tag = "risk";
auto* a = static_cast<const RiskAnnotation*>(anno);
appendProp(props, "level", a->level, first);
appendProp(props, "reason", a->reason, first);
appendInt(props, "dependentCount", a->dependentCount, first);
} else if (ct == "ContractAnnotation") {
tag = "contract";
auto* a = static_cast<const ContractAnnotation*>(anno);
appendProp(props, "preconditions", a->preconditions, first);
appendProp(props, "postconditions", a->postconditions, first);
appendProp(props, "returnShape", a->returnShape, first);
appendProp(props, "sideEffects", a->sideEffects, first);
} else if (ct == "SemanticTagAnnotation") {
tag = "tags";
auto* a = static_cast<const SemanticTagAnnotation*>(anno);
appendVec(props, "tags", a->tags, first);
// --- Environment ---
} else if (ct == "CapabilityRequirement") {
tag = "capability";
auto* a = static_cast<const CapabilityRequirement*>(anno);
appendProp(props, "capability", a->capability, first);
appendBool(props, "required", a->required, first);
} else {
return ""; // unrecognised annotation type
}
// Assemble final string
if (props.empty())
return "@semanno:" + tag;
return "@semanno:" + tag + "(" + props + ")";
}
};
// ---------------------------------------------------------------------------
// SemannoParser
// ---------------------------------------------------------------------------
struct SemannoEntry {
std::string type; // e.g. "intent"
std::map<std::string, std::string> properties; // key→raw value string
};
class SemannoParser {
public:
/// Check whether a line contains a Semanno annotation.
static bool isSemannoComment(const std::string& line) {
return line.find("@semanno:") != std::string::npos;
}
/// Parse a single Semanno comment line.
/// Accepts lines with any comment prefix: "//", "#", "/*", "--", etc.
/// Returns a SemannoEntry with type and key-value properties.
static SemannoEntry parse(const std::string& line) {
SemannoEntry entry;
// Locate the "@semanno:" marker
auto pos = line.find("@semanno:");
if (pos == std::string::npos) return entry;
pos += 9; // skip past "@semanno:"
// Extract the type name (until '(' or end of relevant content)
size_t typeEnd = pos;
while (typeEnd < line.size() && line[typeEnd] != '(' &&
line[typeEnd] != ')' && line[typeEnd] != ' ' &&
line[typeEnd] != '\t' && line[typeEnd] != '\n' &&
line[typeEnd] != '\r') {
++typeEnd;
}
entry.type = line.substr(pos, typeEnd - pos);
// Strip any trailing comment close markers from type (e.g. "*/" )
while (!entry.type.empty() &&
(entry.type.back() == '*' || entry.type.back() == '/')) {
entry.type.pop_back();
}
// If there is no property block, we are done.
if (typeEnd >= line.size() || line[typeEnd] != '(') return entry;
// Find the matching closing paren (respecting escaped quotes).
size_t propStart = typeEnd + 1;
size_t propEnd = findMatchingParen(line, propStart);
if (propEnd == std::string::npos) propEnd = line.size();
std::string propBlock = line.substr(propStart, propEnd - propStart);
parseProperties(propBlock, entry.properties);
return entry;
}
private:
/// Find the closing ')' that matches an opening '(' at `start`,
/// respecting quoted strings.
static size_t findMatchingParen(const std::string& s, size_t start) {
bool inQuote = false;
for (size_t i = start; i < s.size(); ++i) {
if (s[i] == '\\' && i + 1 < s.size()) {
++i; // skip escaped char
continue;
}
if (s[i] == '"') {
inQuote = !inQuote;
} else if (s[i] == ')' && !inQuote) {
return i;
}
}
return std::string::npos;
}
/// Parse "key=\"value\",key2=value2,..." into a map.
static void parseProperties(const std::string& block,
std::map<std::string, std::string>& props) {
size_t i = 0;
while (i < block.size()) {
// Skip whitespace
while (i < block.size() && (block[i] == ' ' || block[i] == '\t'))
++i;
if (i >= block.size()) break;
// Read key (up to '=')
size_t keyStart = i;
while (i < block.size() && block[i] != '=') ++i;
if (i >= block.size()) break;
std::string key = block.substr(keyStart, i - keyStart);
// Trim trailing whitespace from key
while (!key.empty() && (key.back() == ' ' || key.back() == '\t'))
key.pop_back();
++i; // skip '='
// Skip whitespace after '='
while (i < block.size() && (block[i] == ' ' || block[i] == '\t'))
++i;
std::string value;
if (i < block.size() && block[i] == '"') {
// Quoted value — read until unescaped closing '"'
++i; // skip opening '"'
while (i < block.size()) {
if (block[i] == '\\' && i + 1 < block.size()) {
value += block[i];
value += block[i + 1];
i += 2;
} else if (block[i] == '"') {
++i; // skip closing '"'
break;
} else {
value += block[i];
++i;
}
}
// Unescape the value
value = semanno_detail::unescapeValue(value);
} else {
// Unquoted value — read until ',' or end
size_t valStart = i;
while (i < block.size() && block[i] != ',') ++i;
value = block.substr(valStart, i - valStart);
// Trim trailing whitespace
while (!value.empty() &&
(value.back() == ' ' || value.back() == '\t'))
value.pop_back();
}
props[key] = value;
// Skip comma separator
if (i < block.size() && block[i] == ',') ++i;
}
}
};
// end of SemannoFormat.h