Skip to main content

stav/check/
schema.rs

1//! The declared structs and sum types of a checked program, for tooling.
2
3use super::Checked;
4use super::load::FileId;
5use super::types::{FieldDef, ParamDef};
6
7/// Every struct and sum type a checked program declares, with the doc
8/// comments of the declarations, their fields and their variants.
9#[derive(Debug, Clone, Default, PartialEq, Eq)]
10pub struct SchemaIndex {
11    /// The structs, in the order they were declared.
12    pub structs: Vec<SchemaStruct>,
13    /// The sum types, in the order they were declared.
14    pub sums: Vec<SchemaSum>,
15}
16
17/// A declared struct.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct SchemaStruct {
20    /// The name of the struct.
21    pub name: String,
22    /// The file that declares it.
23    pub file: FileId,
24    /// The doc comment, without the `##` markers.
25    pub doc: Option<String>,
26    /// The fields in declaration order.
27    pub fields: Vec<SchemaField>,
28}
29
30/// A field of a struct or a payload field of a variant.
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct SchemaField {
33    /// The name of the field.
34    pub name: String,
35    /// The type as it is written, refinements included.
36    pub ty: String,
37    /// The doc comment, without the `##` markers.
38    pub doc: Option<String>,
39    /// Whether a value must set the field: it has neither a default nor an
40    /// `Option` type.
41    pub required: bool,
42    /// The block kind of a `block kind` clause.
43    pub block: Option<String>,
44}
45
46/// A declared sum type.
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct SchemaSum {
49    /// The name of the sum type.
50    pub name: String,
51    /// The file that declares it.
52    pub file: FileId,
53    /// The doc comment, without the `##` markers.
54    pub doc: Option<String>,
55    /// The variants in declaration order.
56    pub variants: Vec<SchemaVariant>,
57}
58
59/// A variant of a sum type.
60#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct SchemaVariant {
62    /// The name of the variant.
63    pub name: String,
64    /// The doc comment, without the `##` markers.
65    pub doc: Option<String>,
66    /// The payload fields, or `None` for a variant without payload.
67    pub fields: Option<Vec<SchemaField>>,
68}
69
70impl Checked {
71    /// Returns every declared struct field and sum variant with its doc
72    /// comment, for tooling such as completion and documentation.
73    pub fn schema(&self) -> SchemaIndex {
74        let text = |file: FileId, span: crate::Span| {
75            self.source(file)
76                .and_then(|source| source.get(span.range()))
77                .unwrap_or_default()
78                .to_owned()
79        };
80        let field = |file: FileId, f: &FieldDef| SchemaField {
81            name: f.name.clone(),
82            ty: text(file, f.ty_span),
83            doc: f.doc.clone(),
84            required: f.is_required(&self.types),
85            block: f.block.clone(),
86        };
87        let param = |file: FileId, p: &ParamDef| SchemaField {
88            name: p.name.clone(),
89            ty: text(file, p.ty_span),
90            doc: None,
91            required: p.default.is_none() && self.types.unwrap_option(p.ty).is_none(),
92            block: None,
93        };
94        SchemaIndex {
95            structs: self
96                .types
97                .structs
98                .iter()
99                .map(|s| SchemaStruct {
100                    name: s.name.clone(),
101                    file: s.file,
102                    doc: s.doc.clone(),
103                    fields: s.fields.iter().map(|f| field(s.file, f)).collect(),
104                })
105                .collect(),
106            sums: self
107                .types
108                .sums
109                .iter()
110                .map(|s| SchemaSum {
111                    name: s.name.clone(),
112                    file: s.file,
113                    doc: s.doc.clone(),
114                    variants: s
115                        .variants
116                        .iter()
117                        .map(|v| SchemaVariant {
118                            name: v.name.clone(),
119                            doc: v.doc.clone(),
120                            fields: v
121                                .fields
122                                .as_ref()
123                                .map(|fields| fields.iter().map(|p| param(s.file, p)).collect()),
124                        })
125                        .collect(),
126                })
127                .collect(),
128        }
129    }
130}