Feature/split serialize#2460
Conversation
There was a problem hiding this comment.
Pull request overview
Refactors AST expression serialization by removing per-node serialize(AstSerializer&) virtual methods from Expression subclasses and replacing them with a visitor-based serialization path driven by a new Expression::dispatch(Visitor&) shim.
Changes:
- Replace
Expression::serialize/ExprXxx::serializewithExpression::dispatch/ExprXxx::dispatchand route expression serialization throughSerializeVisitor. - Add
src/ast/ast_dispatch.cppimplementingdispatchfor expression classes. - Wire the new dispatch TU into the build and update headers accordingly.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/builtin/module_builtin_ast_serialize.cpp | Moves expression serialization into SerializeVisitor and updates AstSerializer::operator<<(ExpressionPtr&) to use dispatch. |
| src/ast/ast_dispatch.cpp | Adds per-class dispatch shims to call the correct Visitor::preVisit(...) overloads. |
| include/daScript/ast/ast_expressions.h | Replaces serialize overrides with dispatch declarations for expression types. |
| include/daScript/ast/ast.h | Replaces Expression::serialize with Expression::dispatch and forward-declares Visitor. |
| CMakeLists.txt | Adds src/ast/ast_dispatch.cpp to AST_SRC. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
c9af88f to
cfd618d
Compare
Now we can reuse visitor to just visit one node, not recursively. It will be used in following commit to extract serialize from Expression.
cfd618d to
c6385f9
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Ast should not know anything about serialization. Now serializer is separate visitor declared in src/builtin/module_builtin_ast_serialize.cpp
c6385f9 to
e85bcc5
Compare
We need to skip expected failures in serialization. To do so their naming should be unified.
Fix module leaks. Now this all memory ownership is confusing and error-prone. To supress leak we should manually release module.
e85bcc5 to
9f33ea7
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 22 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/builtin/module_builtin_ast_serialize.cpp:900
serializeSmartPtris still keyed onuint64_t, butgetSerializeId(obj.get())now returnsSerializeNodeId. As written this won’t compile (type mismatch) and also doesn’t match the updatedsmart*Mapmember key types. UpdateserializeSmartPtr(both declaration and definition) to useSerializeNodeIdforidand for theobjMapkey type, and adjust the null check accordingly (e.g.,id.ptr == nullptr).
// This method creates concrete (i.e. non-polymorphic types without duplications)
template<typename T>
void AstSerializer::serializeSmartPtr( smart_ptr<T> & obj, das_hash_map<uint64_t, smart_ptr<T>> & objMap) {
uint64_t id = getSerializeId(obj.get());
*this << id;
if ( id == 0 ) {
if ( !writing ) obj = nullptr;
return;
}
We should never use print() inside daslib/. And we should always prefer to_log everywhere, not only in daslib. Also made logs in serialize more clear.
6fb5aba to
bf75106
Compare
Valid, removed this method at all. It's unused. |
bf75106 to
683c8d2
Compare
Make ids unique and stable. Enable serialization in dastest and added to CI.
683c8d2 to
98cb658
Compare
PR #2460 — feature/split-serialize
Summary
This PR fixes AST serialization roundtrip correctness and re-enables
--ser/--deserCI testing.Architectural changes
Virtual dispatch for AST nodes (
compiler: add virtual dispatch)Added
Expression::dispatch(Visitor&)— a non-recursive virtual shim that routes a single node to the most-specific visitor overload for its concrete type. Previously the only way to drive visitor logic was the full recursivevisit()traversal; now a single node can be processed in isolation.Serialize extracted from AST (
compiler: extract serialize from ast)Expression::serialize(and relatedserializemethods on expression subclasses) moved out ofast_expressions.h/ast.hintosrc/builtin/module_builtin_ast_serialize.cppas aSerializeVisitorthat uses the new dispatch shim. AST types no longer include serialization headers or carry serialization logic — the compiler core is now independent of the serializer.Correctness fixes
Stable node IDs (
serialization: stable id in serialization)The dedup maps in
AstSerializerpreviously keyed on rawuintptr_t(ptr). Pointer addresses are reused acrossProgramlifetimes and during short-lived AST construction, causing two logically-distinct nodes to collide on the same key — the writer deduped them into one, the reader reconstructed only one, andtag()tripped on a misaligned hash word. Maps now key onSerializeNodeId{ptr, epoch}(raw pointer + per-serialize-call epoch), which eliminates cross-call collisions.g_Programstale pointer after deserializationfinalizeModulesetsg_Programto a temporaryProgramthen callsthisModule.release(), leavingg_Programpointing at a program with nullthisModule. Fixed by saving/restoringg_Programaround the block invocation inrtti_ast_serializer_deserialize_programso thatcompiling_module()sees the correct module during simulate and test execution.Function::fromGenericnow serializedfromGenericwas commented out inFunction::serialize. After deserialization,qm_call_name_matchesindaslib/ast_matchcouldn't match generic call names because the fallbackcall.func.fromGeneric.namepath was always null.fromGenericis now serialized via the existingFunctionPtrdedup path.Macro module context leak
Non-promoted
[call_macro]modules get amacroContext(smart_ptr, rc=1) duringfinalizeModule.Program::libraryis plainModuleLibrarywhose destructor does not delete modules, so those modules and their contexts were abandoned. Fixed by callingprog->thisModule.release()+prog->library.reset()after the block invocation returns.Test infrastructure
Expected-failure file naming unified (
serialization: unify failed tests naming)Nine test files that were expected to fail compilation but didn't follow the
failed_/cant_/invalid_prefix convention were renamed.dastest's--serpass now skips files with these prefixes (nothing to serialize for a program that doesn't compile). Naming convention documented intests/README.md.CI re-enabled (
serialization: stable id in serialization)extended_checks.ymlgains aTest ser/deserstep that serializes the full test suite then deserializes and re-runs it. Previously dropped because--desercrashed insideAstSerializer::tag.