Skip to main content

microcad_lang/
doc.rs

1// Copyright © 2026 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Doc trait.
5
6use crate::{
7    builtin::Builtin,
8    symbol::{Symbol, SymbolDef},
9    syntax::*,
10};
11
12use microcad_lang_base::{Refer, SrcRef};
13
14/// Documentation trait to fetch documentation from a [Symbol].
15///
16/// The retrieved `DocBlock` struct can processed further to markdown.
17/// Depending on the `Symbol`, the returned DocBlock might be empty.
18pub trait Doc {
19    /// Return block of documentation.
20    fn doc(&self) -> DocBlock {
21        DocBlock::merge(&self.outer_doc(), &self.inner_doc())
22    }
23
24    /// Fetch inner documentation.
25    fn inner_doc(&self) -> DocBlock {
26        DocBlock::default()
27    }
28
29    /// Fetch outer documentation.
30    fn outer_doc(&self) -> DocBlock {
31        DocBlock::default()
32    }
33}
34
35impl Doc for DocBlock {
36    fn doc(&self) -> DocBlock {
37        self.clone()
38    }
39}
40
41impl Doc for InitDefinition {
42    fn outer_doc(&self) -> DocBlock {
43        self.doc.as_ref().cloned().unwrap_or_default()
44    }
45
46    fn inner_doc(&self) -> DocBlock {
47        self.body.inner_doc()
48    }
49}
50
51impl Doc for StatementList {
52    fn inner_doc(&self) -> DocBlock {
53        if self.is_empty() {
54            DocBlock::default()
55        } else {
56            let src_ref = SrcRef::merge_all(self.iter());
57
58            DocBlock(Refer::new(
59                self.iter()
60                    .filter_map(|s| match s {
61                        Statement::InnerDocComment(doc) => Some(doc.0.value.clone()),
62                        _ => None,
63                    })
64                    .collect::<Vec<_>>(),
65                src_ref,
66            ))
67        }
68    }
69}
70
71impl Doc for Body {
72    fn inner_doc(&self) -> DocBlock {
73        self.statements.inner_doc()
74    }
75}
76
77impl Doc for ModuleDefinition {
78    fn outer_doc(&self) -> DocBlock {
79        self.doc.as_ref().cloned().unwrap_or_default()
80    }
81
82    fn inner_doc(&self) -> DocBlock {
83        self.body
84            .as_ref()
85            .map(|body| body.inner_doc())
86            .unwrap_or_default()
87    }
88}
89
90impl Doc for FunctionDefinition {
91    fn outer_doc(&self) -> DocBlock {
92        self.doc.as_ref().cloned().unwrap_or_default()
93    }
94
95    fn inner_doc(&self) -> DocBlock {
96        self.body.inner_doc()
97    }
98}
99
100impl Doc for WorkbenchDefinition {
101    fn outer_doc(&self) -> DocBlock {
102        self.doc.as_ref().cloned().unwrap_or_default()
103    }
104
105    fn inner_doc(&self) -> DocBlock {
106        self.body.inner_doc()
107    }
108}
109
110impl Doc for SourceFile {
111    fn inner_doc(&self) -> DocBlock {
112        self.statements.inner_doc()
113    }
114}
115
116impl Doc for Assignment {
117    fn outer_doc(&self) -> DocBlock {
118        self.doc.as_ref().cloned().unwrap_or_default()
119    }
120}
121
122impl Doc for Builtin {
123    fn outer_doc(&self) -> DocBlock {
124        match self {
125            Builtin::Function(builtin_function) => builtin_function.doc.clone(),
126            Builtin::Workbench(builtin_workbench) => builtin_workbench.doc.clone(),
127            Builtin::Constant(builtin_constant) => builtin_constant.doc.clone(),
128        }
129        .unwrap_or_default()
130    }
131}
132
133impl Doc for SymbolDef {
134    fn inner_doc(&self) -> DocBlock {
135        match &self {
136            SymbolDef::SourceFile(source_file) => source_file.inner_doc(),
137            SymbolDef::Module(module_definition) => module_definition.inner_doc(),
138            SymbolDef::Workbench(workbench_definition) => workbench_definition.inner_doc(),
139            SymbolDef::Function(function_definition) => function_definition.inner_doc(),
140            _ => DocBlock::default(),
141        }
142    }
143
144    fn outer_doc(&self) -> DocBlock {
145        match &self {
146            SymbolDef::Module(module_definition) => module_definition.outer_doc(),
147            SymbolDef::Workbench(workbench_definition) => workbench_definition.outer_doc(),
148            SymbolDef::Function(function_definition) => function_definition.outer_doc(),
149            SymbolDef::Assignment(assignment) => assignment.outer_doc(),
150            SymbolDef::Builtin(builtin) => builtin.outer_doc(),
151            //SymbolDef::Constant(..) => todo!(),
152            //SymbolDef::Alias(..) => todo!(),
153            _ => DocBlock::default(),
154        }
155    }
156}
157
158impl Doc for Symbol {
159    fn inner_doc(&self) -> DocBlock {
160        self.with_def(|def| def.inner_doc())
161    }
162
163    fn outer_doc(&self) -> DocBlock {
164        self.with_def(|def| def.outer_doc())
165    }
166}