Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Printing

This section is a work-in-progress experiment about making the book executable.

These printers turn the AST back into Rust syntax.

AI disclaimer: this section is LLM-generated.

pub fn print_program(program: &Program) -> String {
    let mut printer = Printer::new();
    printer.program(program);
    printer.finish()
}

fn write_tuple<T: Display>(f: &mut Formatter<'_>, elements: &[T]) -> fmt::Result {
    f.write_str("(")?;
    write!(f, "{}", elements.iter().format(", "))?;
    if elements.len() == 1 {
        f.write_str(",")?;
    }
    f.write_str(")")
}

struct Printer {
    output: String,
    indent: usize,
    at_line_start: bool,
}

impl Printer {
    fn new() -> Self {
        Self {
            output: String::new(),
            indent: 0,
            at_line_start: true,
        }
    }

    fn finish(mut self) -> String {
        self.newline();
        self.output
    }

    fn token(&mut self, token: impl AsRef<str>) {
        if self.at_line_start {
            for _ in 0..self.indent {
                self.output.push_str("    ");
            }
            self.at_line_start = false;
        }
        self.output.push_str(token.as_ref());
    }

    fn display(&mut self, value: impl Display) {
        self.token(value.to_string());
    }

    fn space(&mut self) {
        self.output.push(' ');
    }

    fn newline(&mut self) {
        if !self.output.ends_with('\n') {
            self.output.push('\n');
        }
        self.at_line_start = true;
    }

    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
        self.indent += 1;
        f(self);
        self.indent -= 1;
    }

    fn comma_separated<T>(&mut self, elements: &[T], mut print: impl FnMut(&mut Self, &T)) {
        for (index, element) in elements.iter().enumerate() {
            if index > 0 {
                self.token(", ");
            }
            print(self, element);
        }
    }

    fn program(&mut self, program: &Program) {
        for (index, item) in program.items.iter().enumerate() {
            if index > 0 {
                self.newline();
                self.newline();
            }
            self.item(item);
        }
    }

    fn item(&mut self, item: &Item) {
        self.attrs(&item.attrs);
        if let Some(visibility) = &item.visibility {
            self.display(visibility);
            self.space();
        }
        match &item.kind {
            ItemKind::Function(function) => self.function(function),
        }
    }

    fn attrs(&mut self, attrs: &[OuterAttribute]) {
        for attr in attrs {
            self.display(attr);
            self.space();
        }
    }

    fn function(&mut self, function: &Function) {
        self.function_qualifiers(&function.qualifiers);
        self.token("fn ");
        self.token(&function.name);
        self.display(&function.generic_params);
        self.token("(");
        self.comma_separated(&function.parameters, |printer, parameter| {
            printer.display(parameter);
        });
        self.token(")");
        if let Some(return_type) = &function.return_type {
            self.token(" -> ");
            self.display(return_type);
        }
        self.display(&function.where_clauses);
        match &function.body {
            FunctionBody::Block(block) => {
                self.space();
                self.block(block);
            }
            FunctionBody::Missing => self.token(";"),
        }
    }

    fn function_qualifiers(&mut self, qualifiers: &FunctionQualifiers) {
        let mut parts = Vec::new();
        if qualifiers.is_const {
            parts.push("const".to_owned());
        }
        if qualifiers.is_async {
            parts.push("async".to_owned());
        }
        if let Some(safety) = &qualifiers.safety {
            parts.push(safety.to_string());
        }
        if let Some(extern_abi) = &qualifiers.extern_abi {
            parts.push(extern_abi.to_string());
        }
        if !parts.is_empty() {
            self.display(parts.iter().format(" "));
            self.space();
        }
    }

    fn block(&mut self, block: &BlockExpression) {
        if let Some(label) = &block.label {
            self.display(label);
            self.token(": ");
        }
        if block.statements.is_empty() && block.tail.is_none() {
            self.token("{}");
            return;
        }

        self.token("{");
        self.indented(|printer| {
            for statement in &block.statements {
                printer.newline();
                printer.statement(statement);
            }
            if let Some(tail) = &block.tail {
                printer.newline();
                printer.expression(tail);
            }
        });
        self.newline();
        self.token("}");
    }

    fn statement(&mut self, statement: &Statement) {
        match statement {
            Statement::Empty => self.token(";"),
            Statement::Item(item) => self.item(item),
            Statement::Let {
                attrs,
                scope,
                pattern,
                ty,
                initial_value,
                else_branch,
            } => {
                self.attrs(attrs);
                self.token("let");
                if let Some(scope) = scope {
                    self.token("(in ");
                    self.display(scope);
                    self.token(")");
                }
                self.space();
                self.display(pattern);
                if let Some(ty) = ty {
                    self.token(": ");
                    self.display(ty);
                }
                if let Some(initial_value) = initial_value {
                    self.token(" = ");
                    self.expression(initial_value);
                }
                if let Some(else_branch) = else_branch {
                    self.token(" else ");
                    self.block(else_branch);
                }
                self.token(";");
            }
            Statement::Expr(expression) => {
                self.expression(expression);
                if !expression.is_with_block() {
                    self.token(";");
                }
            }
        }
    }

    fn expression(&mut self, expression: &Expression) {
        self.attrs(&expression.attrs);
        match &expression.kind {
            ExpressionKind::Literal(literal) => self.display(literal),
            ExpressionKind::Path(path) => self.token(path),
            ExpressionKind::Operator(operator) => self.operator_expression(operator),
            ExpressionKind::Virtual(virtual_expression) => {
                self.virtual_expression(virtual_expression)
            }
            ExpressionKind::Grouped(grouped) => {
                self.token("(");
                self.expression(grouped);
                self.token(")");
            }
            ExpressionKind::Block(block) => self.block(block),
            ExpressionKind::If(if_expression) => self.if_expression(if_expression),
            ExpressionKind::Tuple(elements) => self.tuple(elements),
            ExpressionKind::TupleIndexing(tuple_indexing) => {
                self.expression(&tuple_indexing.expression);
                self.token(".");
                self.token(tuple_indexing.index.to_string());
            }
            ExpressionKind::Call(call) => {
                self.expression(&call.callee);
                self.token("(");
                self.comma_separated(&call.args, |printer, argument| {
                    printer.expression(argument);
                });
                self.token(")");
            }
        }
    }

    fn tuple(&mut self, elements: &[Expression]) {
        self.token("(");
        self.comma_separated(elements, |printer, element| {
            printer.expression(element);
        });
        if elements.len() == 1 {
            self.token(",");
        }
        self.token(")");
    }

    fn if_expression(&mut self, if_expression: &IfExpression) {
        self.token("if ");
        self.expression(&if_expression.condition);
        self.space();
        self.expression(&if_expression.then_branch);
        if let Some(else_branch) = &if_expression.else_branch {
            match &else_branch.kind {
                ExpressionKind::If(nested) if else_branch.attrs.is_empty() => {
                    self.token(" else ");
                    self.if_expression(nested);
                }
                ExpressionKind::Block(block) if else_branch.attrs.is_empty() => {
                    self.token(" else ");
                    self.block(block);
                }
                _ => {
                    self.token(" else ");
                    self.expression(else_branch);
                }
            }
        }
    }

    fn operator_expression(&mut self, operator: &OperatorExpression) {
        match operator {
            OperatorExpression::Borrow(borrow) => {
                self.token("&");
                self.display(borrow.mutability);
                self.expression(&borrow.expression);
            }
            OperatorExpression::Dereference(dereference) => {
                self.token("*");
                self.expression(&dereference.expression);
            }
            OperatorExpression::Add(left, right) => {
                self.expression(left);
                self.token(" + ");
                self.expression(right);
            }
            OperatorExpression::Assignment(left, right) => {
                self.expression(left);
                self.token(" = ");
                self.expression(right);
            }
        }
    }

    fn virtual_expression(&mut self, virtual_expression: &VirtualExpression) {
        match virtual_expression {
            VirtualExpression::ValueToPlaceCoercion(expression) => {
                self.token("value_to_place!(");
                self.expression(expression);
                self.token(")");
            }
            VirtualExpression::PlaceToValueCoercion(expression) => {
                self.token("place_to_value!(");
                self.expression(expression);
                self.token(")");
            }
        }
    }
}

impl Display for Program {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.items.iter().format("\n\n"))
    }
}

impl Display for Function {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{} ", self.qualifiers)?;
        write!(
            f,
            "fn {}{}({})",
            self.name,
            self.generic_params,
            self.parameters.iter().format(", ")
        )?;

        if let Some(return_type) = &self.return_type {
            write!(f, " -> {return_type}")?;
        }
        write!(f, " {}", self.where_clauses)?;
        match &self.body {
            FunctionBody::Block(block) => write!(f, " {block}"),
            FunctionBody::Missing => f.write_str(";"),
        }
    }
}

impl Display for Item {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if !self.attrs.is_empty() {
            write!(f, "{} ", self.attrs.iter().format(" "))?;
        }
        if let Some(visibility) = &self.visibility {
            write!(f, "{visibility} ")?;
        }
        write!(f, "{}", self.kind)
    }
}

impl Display for ItemKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            ItemKind::Function(function) => write!(f, "{function}"),
        }
    }
}

impl Display for FunctionQualifiers {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if self.is_const {
            f.write_str("const")?;
        }
        if self.is_async {
            f.write_str(" async")?;
        }
        if let Some(safety) = &self.safety {
            write!(f, " {safety}")?;
        }
        if let Some(extern_abi) = &self.extern_abi {
            write!(f, " {extern_abi}")?;
        }
        Ok(())
    }
}

impl Display for ItemSafety {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str(match self {
            ItemSafety::Safe => "safe",
            ItemSafety::Unsafe => "unsafe",
        })
    }
}

impl Display for Visibility {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Visibility::Pub => f.write_str("pub"),
            Visibility::PubCrate => f.write_str("pub(crate)"),
            Visibility::PubSelf => f.write_str("pub(self)"),
            Visibility::PubSuper => f.write_str("pub(super)"),
            Visibility::InPath(path) => write!(f, "pub(in {path})"),
        }
    }
}

impl Display for Mutability {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str(match self {
            Self::Mutable => "mut ",
            Self::Immutable => "",
        })
    }
}

impl Display for ExternAbi {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match &self.abi {
            Some(abi) => write!(f, "extern \"{abi}\""),
            None => f.write_str("extern"),
        }
    }
}

impl Display for FunctionParam {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if !self.attrs.is_empty() {
            write!(f, "{} ", self.attrs.iter().format(" "))?;
        }
        write!(f, "{}", self.kind)
    }
}

impl Display for FunctionParamKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            FunctionParamKind::Regular { pattern, ty } => {
                if let Some(pattern) = pattern {
                    write!(f, "{pattern}: ")?;
                }
                write!(f, "{ty}")
            }
            FunctionParamKind::RefSelfShorthand {
                lifetime,
                mutability,
            } => {
                write!(f, "&")?;
                if let Some(lifetime) = lifetime {
                    write!(f, "{lifetime} ")?;
                }
                write!(f, "{mutability}")?;
                f.write_str("self")
            }
            FunctionParamKind::SelfParam { mutability, ty } => {
                write!(f, "{mutability}")?;
                f.write_str("self")?;
                if let Some(ty) = ty {
                    write!(f, ": {ty}")?;
                }
                Ok(())
            }
        }
    }
}

impl Display for FunctionParamType {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            FunctionParamType::Type(ty) => write!(f, "{ty}"),
            FunctionParamType::Variadic => f.write_str("..."),
        }
    }
}

impl Display for Type {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Type::Tuple(types) => write_tuple(f, types),
            Type::Bool => write!(f, "bool"),
            Type::Str => write!(f, "str"),
            Type::TraitSelf => write!(f, "Self"),
            Type::Ref(lifetime, mutability, ty) => {
                f.write_str("&")?;
                if let Some(lifetime) = lifetime {
                    write!(f, "{lifetime} ")?;
                }
                write!(f, "{mutability}")?;
                write!(f, "{ty}")
            }
        }
    }
}

impl Display for BlockExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        if let Some(label) = &self.label {
            write!(f, "{label}: ")?;
        }
        f.write_str("{")?;
        for statement in &self.statements {
            write!(f, " {statement}")?;
        }
        if let Some(tail) = &self.tail {
            write!(f, " {tail}")?;
        }
        f.write_str(" }")
    }
}

impl Display for Statement {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Statement::Empty => f.write_str(";"),
            Statement::Item(item) => write!(f, "{item}"),
            Statement::Let {
                attrs,
                scope,
                pattern,
                ty,
                initial_value,
                else_branch,
            } => {
                write!(f, "{} ", attrs.iter().format(" "))?;
                f.write_str("let")?;
                if let Some(scope) = scope {
                    write!(f, "(in {scope})")?;
                }
                write!(f, " {pattern}")?;
                if let Some(ty) = ty {
                    write!(f, ": {ty}")?;
                }
                if let Some(initial_value) = initial_value {
                    write!(f, " = {initial_value}")?;
                }
                if let Some(else_branch) = else_branch {
                    write!(f, " else {else_branch}")?;
                }
                f.write_str(";")
            }
            Statement::Expr(expression) if expression.is_with_block() => write!(f, "{expression}"),
            Statement::Expr(expression) => write!(f, "{expression};"),
        }
    }
}

impl Expression {
    fn is_with_block(&self) -> bool {
        matches!(self.kind, ExpressionKind::Block(_) | ExpressionKind::If(_))
    }
}

impl Display for Expression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{} ", self.attrs.iter().format(" "))?;
        write!(f, "{}", self.kind)
    }
}

impl Display for ExpressionKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            ExpressionKind::Literal(literal) => write!(f, "{literal}"),
            ExpressionKind::Path(path) => write!(f, "{path}"),
            ExpressionKind::Operator(operator) => write!(f, "{operator}"),
            ExpressionKind::Virtual(virtual_expression) => write!(f, "{virtual_expression}"),
            ExpressionKind::Grouped(grouped) => write!(f, "({grouped})"),
            ExpressionKind::Block(block) => write!(f, "{block}"),
            ExpressionKind::If(if_expression) => write!(f, "{if_expression}"),
            ExpressionKind::Tuple(elements) => write_tuple(f, elements),
            ExpressionKind::Call(call) => write!(f, "{call}"),
            ExpressionKind::TupleIndexing(tuple_indexing) => write!(f, "{tuple_indexing}"),
        }
    }
}

impl Display for LiteralExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            LiteralExpression::String(value) => write!(f, "\"{value}\""),
            LiteralExpression::Integer(value) => write!(f, "{value}"),
            LiteralExpression::Bool(value) => write!(f, "{value}"),
        }
    }
}

impl Display for IfExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "if{}{}", self.condition, self.then_branch)?;
        if let Some(else_branch) = &self.else_branch {
            match &else_branch.kind {
                ExpressionKind::If(if_expression) if else_branch.attrs.is_empty() => {
                    write!(f, " else {if_expression}")?;
                }
                ExpressionKind::Block(block) if else_branch.attrs.is_empty() => {
                    write!(f, " else {block}")?;
                }
                _ => write!(f, " else {else_branch}")?,
            }
        }
        Ok(())
    }
}

impl Display for TupleIndexingExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}.{}", self.expression, self.index)
    }
}

impl Display for CallExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}({})", self.callee, self.args.iter().format(", "))
    }
}

impl Display for VirtualExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            VirtualExpression::ValueToPlaceCoercion(expression) => {
                write!(f, "value_to_place!({expression})")
            }
            VirtualExpression::PlaceToValueCoercion(expression) => {
                write!(f, "place_to_value!({expression})")
            }
        }
    }
}

impl Display for OperatorExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            OperatorExpression::Borrow(borrow) => write!(f, "{borrow}"),
            OperatorExpression::Dereference(dereference) => write!(f, "{dereference}"),
            OperatorExpression::Add(left, right) => write!(f, "{left} + {right}"),
            OperatorExpression::Assignment(left, right) => write!(f, "{left} = {right}"),
        }
    }
}

impl Display for BorrowExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "&{}{}", self.mutability, self.expression)
    }
}

impl Display for DereferenceExpression {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "*{}", self.expression)
    }
}

impl Display for GenericParams {
    fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
        Ok(())
    }
}

impl Display for WhereClauses {
    fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
        Ok(())
    }
}

impl Display for OuterAttribute {
    fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
        Ok(())
    }
}

impl Display for Lifetime {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.write_str("'_")
    }
}

impl Display for Pattern {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Pattern::Identifier(name) => f.write_str(name),
            Pattern::Wildcard => f.write_str("_"),
        }
    }
}