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