Step 338: EnumDeclaration + NamespaceDeclaration (12/12 tests)

Added EnumDeclaration, EnumMember, NamespaceDeclaration, TypeAlias AST nodes with
full serialization roundtrip and CompactAST support. Enums support scoped/unscoped,
underlying type, member values. Namespaces support nesting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill
2026-02-16 00:38:34 -07:00
parent 96799dd51f
commit ca01fc6744
6 changed files with 352 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
#pragma once
#include "ASTNode.h"
#include <string>
// Enum, namespace, and type alias AST nodes — statement-level.
class EnumMember : public ASTNode {
public:
std::string name;
std::string value; // Optional explicit value ("1", "0xFF")
EnumMember() { conceptType = "EnumMember"; }
EnumMember(const std::string& id, const std::string& n, const std::string& v = "")
: name(n), value(v) {
this->id = id;
conceptType = "EnumMember";
}
};
class EnumDeclaration : public ASTNode {
public:
std::string name;
bool isScoped = false; // enum class (true) vs plain enum (false)
std::string underlyingType; // Optional: "int", "uint8_t", etc.
// Children role "members": vector of EnumMember nodes
EnumDeclaration() { conceptType = "EnumDeclaration"; }
EnumDeclaration(const std::string& id, const std::string& n, bool scoped = false)
: name(n), isScoped(scoped) {
this->id = id;
conceptType = "EnumDeclaration";
}
};
class NamespaceDeclaration : public ASTNode {
public:
std::string name; // Empty for anonymous namespaces
// Children role "body": statements/declarations inside
NamespaceDeclaration() { conceptType = "NamespaceDeclaration"; }
NamespaceDeclaration(const std::string& id, const std::string& n)
: name(n) {
this->id = id;
conceptType = "NamespaceDeclaration";
}
};
class TypeAlias : public ASTNode {
public:
std::string aliasName; // The new name
std::string targetType; // What it aliases
bool isUsing = true; // using (true) vs typedef (false)
TypeAlias() { conceptType = "TypeAlias"; }
TypeAlias(const std::string& id, const std::string& alias, const std::string& target, bool usingStyle = true)
: aliasName(alias), targetType(target), isUsing(usingStyle) {
this->id = id;
conceptType = "TypeAlias";
}
};

View File

@@ -18,6 +18,7 @@
#include "GenericType.h"
#include "AsyncNodes.h"
#include "PreprocessorNodes.h"
#include "EnumNamespaceNodes.h"
using json = nlohmann::json;
@@ -523,6 +524,28 @@ inline json propertiesToJson(const ASTNode* node) {
if (n->isFunctionLike) props["isFunctionLike"] = n->isFunctionLike;
if (!n->parameters.empty()) props["parameters"] = n->parameters;
}
// Enum/Namespace/TypeAlias nodes (Step 338)
else if (ct == "EnumDeclaration") {
auto* n = static_cast<const EnumDeclaration*>(node);
props["name"] = n->name;
if (n->isScoped) props["isScoped"] = n->isScoped;
if (!n->underlyingType.empty()) props["underlyingType"] = n->underlyingType;
}
else if (ct == "EnumMember") {
auto* n = static_cast<const EnumMember*>(node);
props["name"] = n->name;
if (!n->value.empty()) props["value"] = n->value;
}
else if (ct == "NamespaceDeclaration") {
auto* n = static_cast<const NamespaceDeclaration*>(node);
props["name"] = n->name;
}
else if (ct == "TypeAlias") {
auto* n = static_cast<const TypeAlias*>(node);
props["aliasName"] = n->aliasName;
props["targetType"] = n->targetType;
if (!n->isUsing) props["isUsing"] = n->isUsing;
}
// NullLiteral, ListLiteral, IndexAccess, Block, Assignment, IfStatement,
// WhileLoop, Return, ExpressionStatement, ListType, SetType, MapType,
// TupleType, ArrayType, OptionalType — no extra properties
@@ -689,6 +712,10 @@ inline ASTNode* createNode(const std::string& conceptName) {
if (conceptName == "IncludeDirective") return new IncludeDirective();
if (conceptName == "PragmaDirective") return new PragmaDirective();
if (conceptName == "MacroDefinition") return new MacroDefinition();
if (conceptName == "EnumDeclaration") return new EnumDeclaration();
if (conceptName == "EnumMember") return new EnumMember();
if (conceptName == "NamespaceDeclaration") return new NamespaceDeclaration();
if (conceptName == "TypeAlias") return new TypeAlias();
return nullptr;
}
@@ -1230,6 +1257,28 @@ inline void setPropertiesFromJson(ASTNode* node, const json& props) {
if (p.is_string()) n->parameters.push_back(p.get<std::string>());
}
}
// Enum/Namespace/TypeAlias nodes (Step 338)
else if (ct == "EnumDeclaration") {
auto* n = static_cast<EnumDeclaration*>(node);
if (props.contains("name")) n->name = props["name"].get<std::string>();
if (props.contains("isScoped")) n->isScoped = props["isScoped"].get<bool>();
if (props.contains("underlyingType")) n->underlyingType = props["underlyingType"].get<std::string>();
}
else if (ct == "EnumMember") {
auto* n = static_cast<EnumMember*>(node);
if (props.contains("name")) n->name = props["name"].get<std::string>();
if (props.contains("value")) n->value = props["value"].get<std::string>();
}
else if (ct == "NamespaceDeclaration") {
auto* n = static_cast<NamespaceDeclaration*>(node);
if (props.contains("name")) n->name = props["name"].get<std::string>();
}
else if (ct == "TypeAlias") {
auto* n = static_cast<TypeAlias*>(node);
if (props.contains("aliasName")) n->aliasName = props["aliasName"].get<std::string>();
if (props.contains("targetType")) n->targetType = props["targetType"].get<std::string>();
if (props.contains("isUsing")) n->isUsing = props["isUsing"].get<bool>();
}
}
inline std::string generateNodeId() {