brooks_lib/verifying/mel/
verify.rs1use crate::{
21 cdni::{
22 gmd::spec::TypedGenericMetadata,
23 mel::spec::{SetVariable, TypedSetVariable},
24 },
25 common::TextLocation,
26 mel::{
27 self, MEL_USER_SET_VARIABLE_STRUCT_NAME,
28 analysis::{self, Analyzed},
29 ast::Expr,
30 compiler::{self, error::CompilerLocatableError},
31 types::{
32 self,
33 Type::{self, Struct},
34 },
35 },
36 verifying::verify::{
37 AnalysisResult, CdniVerificationKey, MetadataAnalysisContext, MetadataVerificationError,
38 Verifier,
39 },
40};
41use std::fmt::{Debug, Display};
42
43#[derive(Debug, Clone, Default)]
44pub struct SetVariableVerificationKey {
45 pub value: Option<()>,
46 pub expression: Option<Expr<Analyzed>>,
47}
48
49#[derive(Debug, Clone)]
50pub enum MelVerificationError {
51 CompilationError(Box<CompilerLocatableError>),
52 AnalysisError(Box<mel::error::AnalysisLocatableError>),
53}
54
55impl Display for MelVerificationError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 MelVerificationError::CompilationError(mel_compiler_locatable_error) => {
59 write!(f, "Compilation error: {mel_compiler_locatable_error}")
60 }
61 MelVerificationError::AnalysisError(mel_analysis_locatable_error) => {
62 write!(f, "Analysis error: {mel_analysis_locatable_error}")
63 }
64 }
65 }
66}
67
68#[derive(Debug)]
69pub struct SetVariableMetadataAnalyzer {}
70
71impl Verifier<MetadataAnalysisContext, MetadataVerificationError> for SetVariableMetadataAnalyzer {
72 fn analyze(
73 &self,
74 v: &TypedGenericMetadata<()>,
75 mut input: MetadataAnalysisContext,
76 ) -> AnalysisResult<MetadataAnalysisContext, MetadataVerificationError> {
77 let typed_set_variable = serde_json::from_value::<TypedSetVariable<()>>(
78 serde_json::to_value(v)
79 .map_err(|e| MetadataVerificationError::JsonError(e.to_string()))?,
80 )
81 .map_err(|e| MetadataVerificationError::JsonError(e.to_string()))?;
82
83 let mut verification_key = SetVariableVerificationKey::default();
84
85 let expression = if let Some(value_is_expression) =
86 typed_set_variable.value.value_is_expression
87 && value_is_expression
88 {
89 let parsed =
90 compiler::compile(&typed_set_variable.value.variable_value).map_err(|e| {
91 MetadataVerificationError::MelVerificationError(
92 MelVerificationError::CompilationError(e.into()).into(),
93 )
94 })?;
95
96 analysis::analyze(&parsed, &input.scopes).map_err(|e| {
97 MetadataVerificationError::MelVerificationError(
98 MelVerificationError::AnalysisError(e).into(),
99 )
100 })?
101 } else {
102 todo!()
103 };
104
105 verification_key.expression = Some(expression.clone());
106
107 let res = TypedSetVariable {
108 tpe: TypedSetVariable::<()>::typed_cdni_metadata_name(),
109 value: SetVariable {
110 aug: verification_key.clone(),
111 variable_name: typed_set_variable.value.variable_name.clone(),
112 variable_value: typed_set_variable.value.variable_value,
113 value_is_expression: typed_set_variable.value.value_is_expression,
114 },
115 };
116
117 let var = input
119 .scopes
120 .lookup(MEL_USER_SET_VARIABLE_STRUCT_NAME)
121 .ok_or(MetadataVerificationError::MelVerificationError(
122 MelVerificationError::AnalysisError(
123 mel::error::AnalysisLocatableError {
124 error: mel::error::AnalysisError::UnknownIdentifier(
125 MEL_USER_SET_VARIABLE_STRUCT_NAME.to_string(),
126 )
127 .into(),
128 location: TextLocation {
129 start: 0,
130 extent: 0,
131 },
132 }
133 .into(),
134 )
135 .into(),
136 ))?;
137
138 let mut var_type = match var {
139 Type::Struct(s) => s,
140 it => {
141 return Err(MetadataVerificationError::MelVerificationError(
142 MelVerificationError::AnalysisError(
143 mel::error::AnalysisLocatableError {
144 error: mel::error::AnalysisError::InvalidType(
145 vec![Struct(types::Struct::new(
146 MEL_USER_SET_VARIABLE_STRUCT_NAME,
147 ))],
148 it,
149 )
150 .into(),
151 location: TextLocation {
152 start: 0,
153 extent: 0,
154 },
155 }
156 .into(),
157 )
158 .into(),
159 )
160 .into());
161 }
162 };
163
164 var_type.insert_field(&typed_set_variable.value.variable_name, expression.tipe());
165
166 input.scopes = input
167 .scopes
168 .insert(MEL_USER_SET_VARIABLE_STRUCT_NAME, Type::Struct(var_type));
169
170 Ok((input, CdniVerificationKey::SetVariable(Box::new(res))))
171 }
172
173 fn type_name(&self, candidate: &str) -> bool {
174 candidate == TypedSetVariable::<()>::typed_cdni_metadata_name()
175 }
176}
177
178#[cfg(test)]
179mod test {
180 use std::assert_matches;
181
182 use crate::{
183 cdni::{
184 mel::spec::TypedSetVariable,
185 tests::test_helpers::{generic_metadata, set_variable},
186 },
187 mel::types::{builtin_function_types, minimal_core_variable_types},
188 verifying::{
189 mel::verify::SetVariableMetadataAnalyzer,
190 verify::{CdniVerificationKey, MetadataAnalysisContext, Verifier},
191 },
192 };
193
194 #[test]
195 fn verify_test() {
196 let variable = set_variable("is_bad".to_string(), "true".to_string(), Some(true));
197
198 let json = generic_metadata(
199 &TypedSetVariable::<()>::typed_cdni_metadata_name(),
200 Some(serde_json::to_value(variable.value).expect("TODO")),
201 );
202
203 let svma = SetVariableMetadataAnalyzer {};
204
205 let result = svma.analyze(
206 &json,
207 MetadataAnalysisContext {
208 scopes: (&builtin_function_types() + &minimal_core_variable_types()).into(),
209 },
210 );
211
212 assert_matches!(result, Ok((_, CdniVerificationKey::SetVariable(e))) if e.value.aug.expression.is_some());
213 }
214}