feat: Add AST emitter and comment support

Introduces a new AST emitter module responsible for serializing AST
nodes back into Myc source code. This emitter preserves leading comments
and whitespace, enabling a round-trip guarantee for the parser and
emitter.

The documentation in `docs/BNF.md` has been updated to reflect the new
syntax rules for comments, including single-line comments (`;`) and
documentation comments (`;;`). The rules clarify that comments must be
whole lines and that inline comments are disallowed.

The lexer and AST node structures have been updated to accommodate
`CommentLine` variants, allowing for different types of comments
(regular, documentation, and blank lines) to be stored and processed.

A new test suite `tests/comment_roundtrip.rs` has been added to verify
the round-trip property of the parser and emitter across all example
`.myc` files. This test ensures that parsing source code, emitting it,
and then parsing the emitted code again results in the same output
string.

The `ast.rs` binary now includes a `--emit` flag that uses the new
emitter to output the parsed source code, facilitating debugging and
testing of the emitter itself.
This commit is contained in:
2026-03-25 19:15:40 +01:00
parent ee89d2330d
commit e757b453a4
10 changed files with 501 additions and 32 deletions
+15
View File
@@ -9,6 +9,21 @@ use std::rc::Rc;
use std::sync::Mutex; // Still needed for global keyword registry
use std::sync::OnceLock;
/// A single line within a leading comment block attached to an AST node.
///
/// Comment blocks are attached to the *next* expression in the source.
/// The first and last line of a block are never `Blank` (enforced by the lexer).
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CommentLine {
/// `; text` — regular comment, no semantic effect.
Comment(Rc<str>),
/// `;; text` — documentation comment.
/// When attached to a `def` or `macro` node, the text is registered in the symbol registry.
Doc(Rc<str>),
/// A blank separator line within a comment block (preserves visual spacing).
Blank,
}
/// Simple source location
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SourceLocation {