Skip to content

Commit 8437278

Browse files
authored
Document some public functions and modify macros interface a bit (#63)
* Document some public functions and modify macros interface a bit
1 parent e0de366 commit 8437278

File tree

8 files changed

+272
-13
lines changed

8 files changed

+272
-13
lines changed

crates/cellang/src/env.rs

Lines changed: 198 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,47 @@ pub struct Env {
2121
}
2222

2323
impl Env {
24+
/// Creates a new environment builder.
2425
pub fn builder() -> EnvBuilder {
2526
EnvBuilder::default()
2627
}
2728

29+
/// Looks up an identifier declaration by name.
2830
pub fn lookup_ident(&self, name: &str) -> Option<&IdentDecl> {
2931
self.identifiers.get(name)
3032
}
3133

34+
/// Looks up a function declaration by name.
3235
pub fn lookup_function(&self, name: &str) -> Option<&FunctionDecl> {
3336
self.functions.get(name)
3437
}
3538

39+
/// Looks up a named type by its type name.
3640
pub fn lookup_type(&self, name: &TypeName) -> Option<&NamedType> {
3741
self.type_registry.get(name)
3842
}
3943

44+
/// Returns the type registry associated with the environment.
4045
pub fn types(&self) -> &TypeRegistry {
4146
&self.type_registry
4247
}
4348

49+
/// Returns all identifier declarations in the environment.
4450
pub fn idents(&self) -> &BTreeMap<String, IdentDecl> {
4551
&self.identifiers
4652
}
4753

54+
/// Returns all function declarations in the environment.
4855
pub fn functions(&self) -> &BTreeMap<String, FunctionDecl> {
4956
&self.functions
5057
}
5158

59+
/// Returns the macro registry associated with the environment.
5260
pub fn macros(&self) -> &MacroRegistry {
5361
&self.macros
5462
}
5563

64+
/// Compiles the given CEL source code into a typed AST using this environment.
5665
pub fn compile(&self, src: &str) -> Result<TypedExpr, CompileError> {
5766
let mut parser = Parser::new(src);
5867
let token_tree = parser.parse()?;
@@ -78,10 +87,11 @@ pub struct EnvBuilder {
7887

7988
impl Default for EnvBuilder {
8089
fn default() -> Self {
81-
let mut builder = EnvBuilder::new_empty();
90+
let mut builder = EnvBuilder::empty();
8291
builder
8392
.install_builtin_function_decls()
8493
.expect("builtin declarations must register");
94+
builder.install_builtin_macros();
8595
builder
8696
}
8797
}
@@ -98,26 +108,30 @@ impl CelTypeRegistrar for EnvBuilder {
98108
}
99109

100110
impl EnvBuilder {
111+
/// Creates a new environment builder, with built-in functions and macros.
101112
pub fn new() -> Self {
102113
Self::default()
103114
}
104115

105-
pub fn new_empty() -> Self {
116+
/// Creates a new empty environment builder without built-in functions or macros.
117+
pub fn empty() -> Self {
106118
Self {
107119
type_registry: TypeRegistry::new(),
108120
identifiers: BTreeMap::new(),
109121
functions: BTreeMap::new(),
110-
macros: MacroRegistry::standard(),
122+
macros: MacroRegistry::empty(),
111123
}
112124
}
113125

126+
/// Adds a named type to the environment being built.
114127
pub fn add_type(&mut self, ty: NamedType) -> Result<&mut Self, EnvError> {
115128
self.type_registry.register(ty).map_err(|e| {
116129
EnvError::new(format!("Type registration error: {}", e))
117130
})?;
118131
Ok(self)
119132
}
120133

134+
/// Adds an identifier declaration to the environment being built.
121135
pub fn add_ident(
122136
&mut self,
123137
decl: IdentDecl,
@@ -132,6 +146,7 @@ impl EnvBuilder {
132146
Ok(self)
133147
}
134148

149+
/// Adds a function declaration to the environment being built.
135150
pub fn add_function(
136151
&mut self,
137152
mut decl: FunctionDecl,
@@ -153,48 +168,66 @@ impl EnvBuilder {
153168
Ok(self)
154169
}
155170

171+
/// Returns the macro registry being built.
156172
pub fn macros(&self) -> &MacroRegistry {
157173
&self.macros
158174
}
159175

176+
/// Returns a mutable reference to the macro registry being built.
160177
pub fn macros_mut(&mut self) -> &mut MacroRegistry {
161178
&mut self.macros
162179
}
163180

181+
/// Looks up an identifier declaration by name.
164182
pub fn lookup_ident(&self, name: &str) -> Option<&IdentDecl> {
165183
self.identifiers.get(name)
166184
}
167185

186+
/// Looks up a function declaration by name.
168187
pub fn lookup_function(&self, name: &str) -> Option<&FunctionDecl> {
169188
self.functions.get(name)
170189
}
171190

191+
/// Sets the macro registry for the environment being built.
172192
pub fn set_macros(&mut self, registry: MacroRegistry) -> &mut Self {
173193
self.macros = registry;
174194
self
175195
}
176196

197+
/// Imports all types, identifiers and functions from the given environment.
177198
pub fn import_env(&mut self, env: &Env) -> Result<&mut Self, EnvError> {
178199
for (_, ty) in env.types().iter() {
179-
self.type_registry.register(ty.clone())?;
200+
self.add_type(ty.clone())?;
180201
}
181202
for decl in env.idents().values() {
182203
self.add_ident(decl.clone())?;
183204
}
184205
for decl in env.functions().values() {
185-
match self.functions.entry(decl.name.clone()) {
186-
Entry::Vacant(entry) => {
187-
entry.insert(decl.clone());
188-
}
189-
Entry::Occupied(mut entry) => {
190-
merge_function_decl(entry.get_mut(), decl)?;
191-
}
192-
}
206+
self.merge_function_shared(decl)?;
193207
}
194208
self.macros.merge(env.macros());
195209
Ok(self)
196210
}
197211

212+
/// Imports all entries from an owned environment, reusing allocations when possible.
213+
pub fn import_env_owned(
214+
&mut self,
215+
env: Env,
216+
) -> Result<&mut Self, EnvError> {
217+
let Env {
218+
type_registry,
219+
identifiers,
220+
functions,
221+
macros,
222+
} = env;
223+
self.absorb_type_registry(type_registry)?;
224+
self.absorb_identifiers(identifiers)?;
225+
self.absorb_functions(functions)?;
226+
self.absorb_macros(macros);
227+
Ok(self)
228+
}
229+
230+
/// Builds the environment.
198231
pub fn build(self) -> Env {
199232
Env {
200233
type_registry: Arc::new(self.type_registry),
@@ -204,12 +237,110 @@ impl EnvBuilder {
204237
}
205238
}
206239

240+
fn absorb_type_registry(
241+
&mut self,
242+
registry: Arc<TypeRegistry>,
243+
) -> Result<(), EnvError> {
244+
match Arc::try_unwrap(registry) {
245+
Ok(inner) => {
246+
for ty in inner.into_named_types() {
247+
self.add_type(ty)?;
248+
}
249+
}
250+
Err(shared) => {
251+
for (_, ty) in shared.as_ref().iter() {
252+
self.add_type(ty.clone())?;
253+
}
254+
}
255+
}
256+
Ok(())
257+
}
258+
259+
fn absorb_identifiers(
260+
&mut self,
261+
idents: Arc<BTreeMap<String, IdentDecl>>,
262+
) -> Result<(), EnvError> {
263+
match Arc::try_unwrap(idents) {
264+
Ok(map) => {
265+
for decl in map.into_values() {
266+
self.add_ident(decl)?;
267+
}
268+
}
269+
Err(shared) => {
270+
for decl in shared.as_ref().values() {
271+
self.add_ident(decl.clone())?;
272+
}
273+
}
274+
}
275+
Ok(())
276+
}
277+
278+
fn absorb_functions(
279+
&mut self,
280+
functions: Arc<BTreeMap<String, FunctionDecl>>,
281+
) -> Result<(), EnvError> {
282+
match Arc::try_unwrap(functions) {
283+
Ok(map) => {
284+
for decl in map.into_values() {
285+
self.merge_function_owned(decl)?;
286+
}
287+
}
288+
Err(shared) => {
289+
for decl in shared.as_ref().values() {
290+
self.merge_function_shared(decl)?;
291+
}
292+
}
293+
}
294+
Ok(())
295+
}
296+
297+
fn merge_function_shared(
298+
&mut self,
299+
decl: &FunctionDecl,
300+
) -> Result<(), EnvError> {
301+
match self.functions.entry(decl.name.clone()) {
302+
Entry::Vacant(entry) => {
303+
entry.insert(decl.clone());
304+
}
305+
Entry::Occupied(mut entry) => {
306+
merge_function_decl(entry.get_mut(), decl)?;
307+
}
308+
}
309+
Ok(())
310+
}
311+
312+
fn merge_function_owned(
313+
&mut self,
314+
decl: FunctionDecl,
315+
) -> Result<(), EnvError> {
316+
match self.functions.entry(decl.name.clone()) {
317+
Entry::Vacant(entry) => {
318+
entry.insert(decl);
319+
}
320+
Entry::Occupied(mut entry) => {
321+
merge_function_decl_owned(entry.get_mut(), decl)?;
322+
}
323+
}
324+
Ok(())
325+
}
326+
327+
fn absorb_macros(&mut self, macros: Arc<MacroRegistry>) {
328+
match Arc::try_unwrap(macros) {
329+
Ok(registry) => self.macros.merge(&registry),
330+
Err(shared) => self.macros.merge(shared.as_ref()),
331+
}
332+
}
333+
207334
fn install_builtin_function_decls(&mut self) -> Result<(), EnvError> {
208335
for decl in builtin_function_decls() {
209336
self.add_function(decl)?;
210337
}
211338
Ok(())
212339
}
340+
341+
fn install_builtin_macros(&mut self) {
342+
self.macros = MacroRegistry::new();
343+
}
213344
}
214345

215346
fn merge_function_decl(
@@ -238,6 +369,32 @@ fn merge_function_decl(
238369
Ok(())
239370
}
240371

372+
fn merge_function_decl_owned(
373+
existing: &mut FunctionDecl,
374+
mut incoming: FunctionDecl,
375+
) -> Result<(), EnvError> {
376+
if existing.doc.is_none() {
377+
existing.doc = incoming.doc.take();
378+
}
379+
for overload in incoming.overloads.drain(..) {
380+
if let Some(current) = existing
381+
.overloads
382+
.iter()
383+
.find(|item| item.id == overload.id)
384+
{
385+
if current != &overload {
386+
return Err(EnvError::new(format!(
387+
"Function '{}' overload id '{}' conflicts with existing declaration",
388+
existing.name, overload.id
389+
)));
390+
}
391+
continue;
392+
}
393+
existing.overloads.push(overload);
394+
}
395+
Ok(())
396+
}
397+
241398
fn builtin_function_decls() -> Vec<FunctionDecl> {
242399
vec![
243400
builtin_size_decl(),
@@ -490,6 +647,35 @@ mod tests {
490647
assert!(merged.lookup_type(&scan.name).is_some());
491648
}
492649

650+
#[test]
651+
fn merge_existing_env_owned() {
652+
let scan = build_scan_type();
653+
let mut base = Env::builder();
654+
base.add_type(NamedType::Struct(scan.clone())).unwrap();
655+
base.add_ident(IdentDecl::new("scan_total", Type::Int))
656+
.unwrap();
657+
base.add_function({
658+
let mut func = FunctionDecl::new("scan_owned_status");
659+
func.add_overload(OverloadDecl::new(
660+
"scan_owned_status_struct",
661+
vec![Type::struct_type(scan.name.clone())],
662+
Type::Bool,
663+
))
664+
.unwrap();
665+
func
666+
})
667+
.unwrap();
668+
let env = base.build();
669+
670+
let mut derived = Env::builder();
671+
derived.import_env_owned(env).unwrap();
672+
let merged = derived.build();
673+
674+
assert!(merged.lookup_type(&scan.name).is_some());
675+
assert!(merged.lookup_ident("scan_total").is_some());
676+
assert!(merged.lookup_function("scan_owned_status").is_some());
677+
}
678+
493679
#[test]
494680
fn compile_supports_standard_macros() {
495681
let mut builder = Env::builder();

crates/cellang/src/interpreter.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ use crate::runtime::{CallContext, Runtime};
55
use crate::value::{Key, ListValue, MapValue, TryFromValue, Value, ValueError};
66
use std::cmp::Ordering;
77

8+
/// Evaluates the given source string in the context of the provided runtime,
9+
/// returning the resulting value.
810
pub fn eval(runtime: &Runtime, source: &str) -> Result<Value, RuntimeError> {
911
let mut parser = Parser::new(source);
1012
let ast = parser.parse().map_err(RuntimeError::from)?;
1113
eval_ast(runtime, &ast)
1214
}
1315

16+
/// Evaluates the given AST node in the context of the provided runtime,
17+
/// returning the resulting value.
1418
pub fn eval_ast<'src>(
1519
runtime: &Runtime,
1620
node: &TokenTree<'src>,

0 commit comments

Comments
 (0)