ERR/E0.1: error-set decls + ! / !Named type exprs (parser)
Parser-only first step of the error-handling stream. No sema/codegen.
- token: `kw_error` keyword (`!` reuses existing `.bang`).
- ast: `ErrorSetDecl { name, tag_names }` + `ErrorTypeExpr { name: ?[] }`
(null = inferred `!`, non-null = `!Named`); wired into Node.Data and
declName.
- parser: `parseErrorSetDecl` (comma-separated tags, optional trailing
comma/`;`) dispatched from parseConstBinding; `!` / `!Named` parsed in
parseTypeExpr; result-list loop enforces error type as trailing-only;
hasFnBodyAfterArrow skips `.bang` so failable-return fns are recognised.
- print: new focused AST round-trip printer (decls + type exprs); loud
`error.UnsupportedNode` otherwise. Registered in root.zig.
- sema/lsp: exhaustive switch arms for the two new nodes.
- tests: 11 inline parser unit tests (shapes + 3 round-trip prints + 2
trailing-position rejections).
zig build, zig build test, and 254/254 examples green.
This commit is contained in:
70
src/print.zig
Normal file
70
src/print.zig
Normal file
@@ -0,0 +1,70 @@
|
||||
//! Focused AST round-trip printer.
|
||||
//!
|
||||
//! Reconstructs sx source text from AST nodes. The scope is intentionally
|
||||
//! narrow: it covers the declaration and type-expression node kinds the
|
||||
//! error-handling (ERR) stream's parser tests round-trip, and bails loudly
|
||||
//! (`error.UnsupportedNode`) on anything it does not yet handle — so an
|
||||
//! unsupported node can never be silently mis-printed (CLAUDE.md REJECTED
|
||||
//! PATTERNS: no silent arms). Later ERR steps extend it as new surface
|
||||
//! syntax lands.
|
||||
|
||||
const std = @import("std");
|
||||
const ast = @import("ast.zig");
|
||||
|
||||
const Node = ast.Node;
|
||||
const Writer = *std.Io.Writer;
|
||||
|
||||
/// Print a declaration node back to source text. Currently handles
|
||||
/// `error { ... }` set declarations; falls through to `printType` for
|
||||
/// type-expression nodes.
|
||||
pub fn printNode(node: *const Node, writer: Writer) !void {
|
||||
switch (node.data) {
|
||||
.error_set_decl => |d| {
|
||||
try writer.writeAll(d.name);
|
||||
try writer.writeAll(" :: error {");
|
||||
for (d.tag_names, 0..) |tag, i| {
|
||||
try writer.writeAll(if (i == 0) " " else ", ");
|
||||
try writer.writeAll(tag);
|
||||
}
|
||||
if (d.tag_names.len > 0) try writer.writeByte(' ');
|
||||
try writer.writeByte('}');
|
||||
},
|
||||
else => try printType(node, writer),
|
||||
}
|
||||
}
|
||||
|
||||
/// Print a type-expression node back to source text.
|
||||
pub fn printType(node: *const Node, writer: Writer) !void {
|
||||
switch (node.data) {
|
||||
.type_expr => |t| try writer.writeAll(t.name),
|
||||
.error_type_expr => |e| {
|
||||
try writer.writeByte('!');
|
||||
if (e.name) |n| try writer.writeAll(n);
|
||||
},
|
||||
.pointer_type_expr => |p| {
|
||||
try writer.writeByte('*');
|
||||
try printType(p.pointee_type, writer);
|
||||
},
|
||||
.optional_type_expr => |o| {
|
||||
try writer.writeByte('?');
|
||||
try printType(o.inner_type, writer);
|
||||
},
|
||||
.slice_type_expr => |s| {
|
||||
try writer.writeAll("[]");
|
||||
try printType(s.element_type, writer);
|
||||
},
|
||||
.many_pointer_type_expr => |m| {
|
||||
try writer.writeAll("[*]");
|
||||
try printType(m.element_type, writer);
|
||||
},
|
||||
.tuple_type_expr => |t| {
|
||||
try writer.writeByte('(');
|
||||
for (t.field_types, 0..) |ft, i| {
|
||||
if (i > 0) try writer.writeAll(", ");
|
||||
try printType(ft, writer);
|
||||
}
|
||||
try writer.writeByte(')');
|
||||
},
|
||||
else => return error.UnsupportedNode,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user