cel_rs/lib.rs
1//! cel-rs provides a stack-based runtime for developing domain specific languages, including
2//! concatenative languages to describe concurrent processes.
3//!
4//! This crate exposes two main components:
5//!
6//! - **cel-runtime**: The core stack-based runtime and CEL parser
7//! - **cel-rs-macros**: Procedural macros for CEL expressions
8//!
9//! For **Adam** — the property-model DSL built on top of this runtime (`adam-lang`,
10//! `adam-rs`) — see [*The Adam Programming Language*](../book/index.html), a tutorial and
11//! reference manual for that language specifically.
12//!
13//! # Examples
14//!
15//! ## Using the Runtime
16//!
17//! ```rust
18//! use cel_rs::cel_runtime::*;
19//!
20//! // Create a segment that takes a u32 and &str as arguments
21//! let segment = Segment::<(u32, &str)>::new()
22//! .op1r(|s| {
23//! let r = s.parse::<u32>()?;
24//! Ok(r)
25//! })
26//! .op2(|a, b| a + b)
27//! .op1(|r| r.to_string());
28//! assert_eq!(segment.call((1u32, "2")).unwrap(), "3");
29//! ```
30//!
31//! ## Using the Parser
32//!
33//! ```rust
34//! use cel_rs::cel_parser::{CELParser, OpLookup};
35//! use proc_macro2::TokenStream;
36//! use std::str::FromStr;
37//!
38//! let input = TokenStream::from_str("10").unwrap();
39//! let mut parser = CELParser::new(OpLookup::new());
40//! parser.set_tokens(input.into_iter());
41//! let result = parser.is_expression();
42//! assert!(result.is_ok());
43//! ```
44//!
45//! ## Parsing an Array Literal
46//!
47//! CEL array literals use canonical [`Array`](cel_runtime::Array) storage.
48//! A checked host call returns [`OwnedValue`](cel_runtime::OwnedValue). Bind its complete
49//! shape to recover typed storage without moving or reallocating array elements.
50//! Prepared calls use [`DynSegment::prepare`](cel_runtime::DynSegment::prepare) directly:
51//!
52//! ```rust
53//! use cel_rs::parser::{CELParser, OpLookup};
54//! use cel_rs::runtime::{ArrayOf, Leaf, Nil, IntoCStackList};
55//!
56//! let segment = CELParser::new(OpLookup::new()).parse_str("[0, 1, 2]").unwrap();
57//! let mut prepared = segment.prepare::<Nil, ArrayOf<Leaf<i32>>>().unwrap();
58//! let array = prepared.call(&().into_c_stack_list()).unwrap();
59//! assert_eq!(array.into_vec(), vec![0, 1, 2]);
60//! ```
61//!
62//! ## Using the Macros
63//!
64//! ```rust
65//! use cel_rs::cel_rs_macros::expression;
66//!
67//! expression! {
68//! 54 + 25 * (11 + 6 * 6)
69//! };
70//! ```
71
72pub use cel_parser;
73pub use cel_rs_macros;
74pub use cel_runtime;
75
76// Re-export commonly used items for convenience
77/// Re-exports from the cel-runtime crate for convenient access.
78pub mod runtime {
79 pub use cel_runtime::*;
80}
81
82/// Re-exports for the CEL parser.
83pub mod parser {
84 pub use cel_parser::{CELParser, op_table::OpLookup};
85}
86
87/// Re-exports from the cel-rs-macros crate for convenient access.
88pub mod macros {
89 pub use cel_rs_macros::*;
90}
91#[cfg(all(test, feature = "playground"))]
92mod playground {
93 struct Experiment {
94 a: u32,
95 }
96
97 struct Segment<T, F: Fn(&mut T) -> String> {
98 context: T,
99 f: F,
100 }
101
102 impl<T, F: Fn(&mut T) -> String> Segment<T, F> {
103 fn new(context: T, f: F) -> Self {
104 Self { context, f }
105 }
106
107 fn call(&mut self) -> String {
108 (self.f)(&mut self.context)
109 }
110 }
111
112 #[test]
113 fn context_segment() {
114 let experiment = Experiment { a: 1 };
115 let mut segment = Segment::new(experiment, |e| e.a.to_string());
116 println!("{}", segment.call());
117 }
118
119 /*
120 #[test]
121 fn expression_macro_error() {
122 let result = cel_rs_macros::expression! {
123 "Hello" + "World" + 32.0;
124 };
125 }
126
127 #[test]
128 fn expression_macro_error2() {
129 let result = cel_rs_macros::expression! {
130 "Hello" + "World" + 32.0
131 };
132 }
133 */
134}