Skip to main content

lemma/
lib.rs

1//! # Lemma Engine
2//!
3//! **Rules for man and machine**
4//!
5//! Consumer API: **`load`** → **`list`** → **`show`** / **`source`** → **`run`**.
6
7#[cfg(test)]
8mod tests;
9
10pub(crate) mod computation;
11pub(crate) mod engine;
12pub(crate) mod error;
13pub(crate) mod evaluation;
14pub(crate) mod formatting;
15pub(crate) mod limits;
16pub(crate) mod literals;
17pub(crate) mod parsing;
18pub(crate) mod planning;
19pub(crate) mod registry;
20pub mod result_value;
21pub(crate) mod spec_set_id;
22pub(crate) mod stdlib;
23
24#[cfg(not(target_arch = "wasm32"))]
25pub mod deps;
26
27#[cfg(target_arch = "wasm32")]
28pub mod wasm;
29
30pub use computation::{OperationResult, VetoType};
31pub use engine::{
32    resolve_effective, Engine, Errors, ListedSpec, ResolvedRepository, EMBEDDED_STDLIB_REPOSITORY,
33};
34pub use error::{Error, ErrorDetails, ErrorKind, RequestErrorKind};
35pub use evaluation::explanations::{format_explanation, Cause, Explanation, ExplanationNode};
36pub use evaluation::response::{Response, RuleResult};
37pub use evaluation::run_data::RunDataValue;
38pub use formatting::{format_parse_result, format_source, format_specs};
39pub use limits::{
40    ResourceLimits, MAX_DATA_NAME_LENGTH, MAX_RULE_NAME_LENGTH, MAX_SPEC_NAME_LENGTH,
41};
42pub use literals::{DateGranularity, MeasureUnit, MeasureUnits, RatioUnit, RatioUnits};
43pub use parsing::ast::DateTimeValue;
44pub use parsing::source::SourceType;
45pub use planning::execution_plan::type_detail_lines;
46pub use planning::execution_plan::{Show, ShowData, ShowVersion};
47pub use planning::explanation::{ConversionTraceRole, SerializedConversionTraceStep};
48pub use planning::semantics::{DataPath, LemmaType, LiteralValue, TypeSpecification, ValueKind};
49pub use result_value::{CalendarResult, RangeResult, RuleResultValue, RuleResultValueFailure};
50pub use spec_set_id::parse_spec_set_id;
51pub use stdlib::UNITS_LEMMA;
52
53/// Exact rational helpers for in-tree integration tests. Not a supported consumer API.
54#[doc(hidden)]
55pub mod __test_support {
56    pub use crate::computation::rational::{
57        checked_div, checked_mul, decimal_to_rational, rational_new,
58    };
59    pub use crate::literals::TimeValue;
60    pub use crate::planning::semantics::{SemanticDateTime, SemanticTime, SemanticTimezone};
61
62    /// Serializes an [`Error`](crate::Error) the way WASM/`JsError` does today.
63    /// API-contract tests assert the *target* shape against this until a single
64    /// derived error type replaces the three hand-built projections.
65    pub fn current_binding_error_json(error: &crate::Error) -> serde_json::Value {
66        use crate::parsing::source::Source;
67        use serde::Serialize;
68
69        #[derive(Serialize)]
70        struct JsSource {
71            attribute: String,
72            line: usize,
73            column: usize,
74            length: usize,
75        }
76
77        impl From<&Source> for JsSource {
78            fn from(s: &Source) -> Self {
79                Self {
80                    attribute: s.source_type.to_string(),
81                    line: s.span.line,
82                    column: s.span.col,
83                    length: s.span.end.saturating_sub(s.span.start),
84                }
85            }
86        }
87
88        #[derive(Serialize)]
89        struct JsError<'a> {
90            kind: crate::ErrorKind,
91            message: &'a str,
92            related_data: Option<&'a str>,
93            spec: Option<&'a str>,
94            related_spec: Option<&'a str>,
95            source: Option<JsSource>,
96            suggestion: Option<&'a str>,
97            repository: Option<&'a str>,
98            registry_kind: Option<crate::registry::RegistryErrorKind>,
99            request_kind: Option<crate::error::RequestErrorKind>,
100            limit_name: Option<&'a str>,
101            limit_value: Option<&'a str>,
102            actual_value: Option<&'a str>,
103        }
104
105        let shaped = JsError {
106            kind: error.kind(),
107            message: error.message(),
108            related_data: error.related_data(),
109            spec: error.spec_context_name(),
110            related_spec: error.related_spec(),
111            source: error.source_location().map(JsSource::from),
112            suggestion: error.suggestion(),
113            repository: error.repository(),
114            registry_kind: error.registry_kind(),
115            request_kind: error.request_kind(),
116            limit_name: error.limit_name(),
117            limit_value: error.limit_value(),
118            actual_value: error.actual_value(),
119        };
120        serde_json::to_value(shaped).expect("JsError-shaped JSON must serialize")
121    }
122}
123
124// Tier 1 — language surface (always)
125pub use parsing::ast::{
126    try_parse_type_constraint_command, DataValue, Span, SpecRef, TimezoneValue,
127};
128pub use parsing::lexer::{Lexer, TokenKind};
129pub use parsing::source::Source;
130pub use parsing::{parse, ParseResult};
131
132// Tier 2 — registry network (feature-gated)
133#[cfg(feature = "registry")]
134pub use engine::Context;
135#[cfg(feature = "registry")]
136pub use parsing::ast::{LemmaRepository, LemmaSpec};
137#[cfg(feature = "registry")]
138pub use planning::LemmaSpecSet;
139#[cfg(all(feature = "registry", not(target_arch = "wasm32")))]
140pub use registry::resolve_registry_references;
141#[cfg(feature = "registry")]
142pub use registry::{LemmaBase, Registry, RegistryBundle, RegistryError, RegistryErrorKind};