Skip to main content

polydat_grammar/comprehension/spec/
mod.rs

1// Copyright 2024-2026 Jonathan Shook
2// SPDX-License-Identifier: Apache-2.0
3
4//! Comprehension specification surface — author-friendly input
5//! form for YAML / JSON consumers.
6//!
7//! Polydat owns the conversion from a YAML/JSON-native
8//! structural form into the algebra-layer `Comprehension`
9//! AST. Consumers (nb-workload, REPL, tooling) deserialize
10//! into [`ComprehensionSpec`] via serde and call
11//! [`ComprehensionSpec::into_algebra`]; text-block consumers
12//! call [`parse_text`] which routes through serde for them.
13//!
14//! ## Single `for` verb
15//!
16//! The surface has one keyword (comprehension_forms.md §8.1). The RHS shape
17//! disambiguates which constructor:
18//!
19//! ```yaml
20//! # Single clause
21//! for: "k in 1..10"
22//!
23//! # Multi-clause cartesian (one inline string)
24//! for: "k in 1..10, limit in [10, 100, 1000]"
25//!
26//! # Multi-clause cartesian (list of strings)
27//! for:
28//!   - "k in 1..10"
29//!   - "limit in [10, 100, 1000]"
30//!
31//! # Union of sub-spaces (list of clause lists)
32//! for:
33//!   - ["k in 10",  "limit in 1..50"]
34//!   - ["k in 100", "limit in 1..500"]
35//! ```
36//!
37//! With optional modifiers:
38//!
39//! ```yaml
40//! for: "k in 1..10, limit in 1..100"
41//! where: "{k} * {limit} <= 1000"
42//! order: "halton/50"
43//! ```
44//!
45//! ## Architecture
46//!
47//! The friendly surface delegates **structural parsing** to
48//! the crate-internal text parser --
49//! `parse_clause_list`,
50//! `parse_comprehension_text`, `parse_order_spec`. Those
51//! parsers produce the flat form with raw
52//! string sources. The [`from_clauses`] module then walks
53//! that form and assembles the algebra-layer AST,
54//! using [`source_parser::parse_source`] for typed-source
55//! classification of each clause's RHS string.
56//!
57//! This is the **single bridge**: every conversion of a
58//! polydat-grammar input to the algebra layer funnels through
59//! [`from_clauses::clauses_to_algebra`].
60
61pub mod algebra_text;
62pub mod from_clauses;
63pub mod serde_form;
64pub mod source_parser;
65pub mod text;
66
67pub use algebra_text::parse_comprehension_algebra;
68pub use from_clauses::ConvertError;
69pub use serde_form::{ComprehensionSpec, ForSpec, SpecConvertError, parse_inline};
70pub use source_parser::{SourceParseError, parse_source};
71pub use text::{TextParseError, parse_text};
72
73/// An `order` specification on its own — `halton/5`, `lex`,
74/// `shuffle(seed=7)` — as the algebra's strategy, truncation, and
75/// seed, read by the parser's order-spec entry point without parsing
76/// a comprehension around it.
77pub fn parse_order(
78    spec: &str,
79) -> Result<
80    (
81        crate::comprehension::strategy::StrategyName,
82        Option<u64>,
83        Option<u64>,
84    ),
85    String,
86> {
87    let form = crate::comprehension::parse::parse_order_spec(spec)?;
88    from_clauses::convert_order(&form).map_err(|e| e.to_string())
89}
90
91// The flat parse form (`crate::comprehension::clause_ast`) and the
92// text parser that produces it are crate-internal: they exist to be
93// lowered here (comprehension_forms.md §14.8). Text reaches the
94// canonical tree through [`parse_comprehension_algebra`], a spec
95// document through [`ComprehensionSpec::into_algebra`] or
96// [`parse_text`], and a source expression through [`parse_source`].
97
98// Leaf grammar utilities — re-exported here so consumers reach
99// them through one module. The implementations live in
100// `crate::comprehension::parse`, which is also public as the full
101// parser.
102//
103// What's re-exported (leaf utilities, no comprehension-build
104// pipeline):
105// - `parse_clause` — one `var in expr` clause text → `Clause`
106// - `parse_clause_list` — comma-separated clauses → `Vec<Clause>`
107// - `parse_order_spec` — order-spec text → `TraversalOrder`
108// - `parse_comprehension_text` — full `for ... where ... order`
109//   text → the flat clause `Comprehension` (used for inline-text shapes
110//   where the where/order are not separate keys).
111//
112// Not re-exported here (comprehension-build pipeline — callers
113// route through [`ComprehensionSpec`]; reach them at
114// `crate::comprehension::parse` if needed):
115// - `comprehension_from_subspaces` — used by
116//   `ComprehensionSpec::into_legacy` / `into_algebra`.
117// - `split_at_order`, `split_at_where`, `split_respecting_parens` —
118//   parser helpers.