Skip to main content

pharmsol_dsl/
lib.rs

1//! Backend-neutral frontend crate for the pharmsol DSL.
2//!
3//! Use this crate when you need the DSL frontend as an engineering API: parse
4//! model source, inspect diagnostics, analyze names and types, and lower a
5//! validated model into the execution representation that backends consume.
6//!
7//! Do not use this crate when you already know you want JIT compilation,
8//! native AoT artifacts, WASM artifacts, or `Subject`-based prediction
9//! helpers. Those runtime-facing workflows stay in the main `pharmsol` crate
10//! under `pharmsol::dsl`.
11//!
12//! Main entrypoints:
13//!
14//! - [`parse_model`] and [`parse_module`] for turning DSL source text into the
15//!   syntax tree in [`ast`].
16//! - [`analyze_model`] and [`analyze_module`] for semantic validation and the
17//!   typed IR in [`ir`].
18//! - [`lower_typed_model`] and [`lower_typed_module`] for lowering typed models
19//!   into the execution representation in [`execution`].
20//!
21//! The frontend pipeline is intentionally simple:
22//!
23//! 1. Parse source text into syntax.
24//! 2. Analyze the syntax into a typed model.
25//! 3. Lower the typed model into an [`ExecutionModel`] or [`ExecutionModule`].
26//!
27//! This crate accepts both canonical `model { ... }` source and the authoring
28//! shorthand used by the `pharmsol` examples. The returned diagnostics carry
29//! source spans, rendered messages, and structured data for editor or UI use.
30//!
31//! Main modules:
32//!
33//! - [`ast`] for syntax-level nodes.
34//! - [`diagnostic`] for spans, diagnostic codes, and rendered reports.
35//! - [`ir`] for the typed intermediate representation.
36//! - [`execution`] for the lowered execution model shared by JIT, AoT, and
37//!   WASM backends.
38//!
39//! Smallest parse-analyze-lower example:
40//!
41//! ```rust
42//! use pharmsol_dsl::{analyze_model, lower_typed_model, parse_model};
43//!
44//! let source = r#"
45//! name = bimodal_ke
46//! kind = ode
47//!
48//! params = ke, v
49//! states = central
50//! outputs = cp
51//!
52//! infusion(iv) -> central
53//!
54//! dx(central) = -ke * central
55//! out(cp) = central / v
56//! "#;
57//!
58//! let syntax = parse_model(source).expect("model parses");
59//! let typed = analyze_model(&syntax).expect("model analyzes");
60//! let execution = lower_typed_model(&typed).expect("model lowers");
61//!
62//! assert_eq!(execution.name, "bimodal_ke");
63//! assert_eq!(execution.metadata.routes.len(), 1);
64//! assert_eq!(execution.metadata.outputs.len(), 1);
65//! ```
66//!
67//! If you are building an authoring tool, custom compiler, or diagnostics UI,
68//! stay in this crate. If you want a complete source-to-runtime workflow,
69//! switch to `pharmsol::dsl` in the main crate.
70
71pub mod ast;
72mod authoring;
73pub mod diagnostic;
74pub mod execution;
75pub mod ir;
76mod lexer;
77mod name_match;
78mod parser;
79mod semantic;
80#[cfg(test)]
81mod test_fixtures;
82
83/// Canonical prefix for numeric route labels such as `input_1`.
84pub const NUMERIC_ROUTE_PREFIX: &str = "input_";
85/// Canonical prefix for numeric output labels such as `outeq_1`.
86pub const NUMERIC_OUTPUT_PREFIX: &str = "outeq_";
87pub(crate) const RATE_FUNCTION_NAME: &str = "rate";
88
89pub use ast::*;
90pub use diagnostic::*;
91pub use execution::{
92    lower_typed_model, lower_typed_module, ExecutionModel, ExecutionModule, LoweringError,
93};
94pub use ir::*;
95pub use parser::{parse_model, parse_module};
96pub use semantic::{analyze_model, analyze_module, SemanticError};