1use crate::uris::{ContentURI, DocumentElementURI, Name, URIOrRefTrait, URIRef};
2use crate::{oma, oms, omsp};
3use flams_utils::prelude::{DFSContinuation, Indentor, TreeChild, TreeChildIter, TreeLike};
4use std::fmt::{Debug, Display, Formatter, Write};
5use std::str::FromStr;
6
7#[derive(Clone, Debug, Hash, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
10#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
11pub enum Term {
12 OMID(ContentURI),
13 OMV(Var),
14 OMA {
15 head: Box<Term>,
16 args: Box<[Arg]>,
17 },
18 Field {
19 record: Box<Term>,
20 key: Name,
21 owner: Option<Box<Term>>,
22 },
23 OML {
24 name: Name,
25 df: Option<Box<Term>>,
26 tp: Option<Box<Term>>,
27 },
28 Informal {
29 tag: String,
30 attributes: Box<[(Box<str>, Box<str>)]>,
31 children: Box<[Informal]>,
32 terms: Box<[Term]>,
33 },
34}
35
36impl Term {
37 #[inline]
39 pub fn present(
40 &self,
41 presenter: &mut impl crate::narration::notations::Presenter,
42 ) -> Result<(), crate::narration::notations::PresentationError> {
43 crate::narration::notations::Notation::present_term(self, presenter)
45 }
46
47 pub fn term_list(i: impl Iterator<Item = Self>) -> Self {
48 oma!(oms!(ftml:SEQUENCE_EXPRESSION),I@N:i)
49 }
50
51 #[must_use]
52 pub fn as_list(&self) -> Option<&[Arg]> {
53 match self {
54 Self::OMA {
55 head, args,
57 } if matches!(&**head,Self::OMID(ContentURI::Symbol(s)) if *s == *crate::metatheory::SEQUENCE_EXPRESSION) => {
58 Some(&**args)
59 } _ => None,
61 }
62 }
63
64 #[must_use]
65 #[allow(clippy::result_large_err)]
66 pub fn is_record_field(&self) -> bool {
67 matches!(self,oma!(hd,args) if matches!(&**hd,omsp!(fp) if *fp == *crate::metatheory::FIELD_PROJECTION) && args.len() == 2)
68 }
69
70 #[allow(clippy::result_large_err)]
72 pub fn into_record_field(self) -> Result<(Self, Name), Self> {
73 match self {
74 oma!(hd, args)
75 if matches!(&*hd,omsp!(fp) if *fp == *crate::metatheory::FIELD_PROJECTION)
76 && args.len() == 2 =>
77 {
78 let mut args = args.into_vec().into_iter();
79 let [a, b] = [
80 args.next().unwrap_or_else(|| unreachable!()),
81 args.next().unwrap_or_else(|| unreachable!()),
82 ];
83 match b {
84 Arg {
85 term:
86 Self::OML {
87 name,
88 df: None,
89 tp: None,
90 },
91 mode: ArgMode::Normal,
92 } => Ok((a.term, name)),
93 b => Err(oma!(*hd, [a, b])),
94 }
95 }
96 _ => Err(self),
97 }
98 }
99 fn display_top<const SHORT: bool>(
115 &self,
116 f: &mut Formatter<'_>,
117 indent: Option<Indentor>,
118 ) -> std::fmt::Result {
119 if let Some(i) = &indent {
120 i.skip_next();
121 };
122 Self::display_children(
123 TermChildrenIter::One(self),
124 f,
125 |t, i, f| t.display_start::<true>(i, f),
126 |t, f| t.display_short_end(f),
127 indent,
128 )
129 }
130 fn display_start<const SHORT: bool>(
131 &self,
132 ind: &mut Indentor,
133 f: &mut Formatter<'_>,
134 ) -> Result<DFSContinuation<()>, std::fmt::Error> {
135 macro_rules! cont {
136 ($t:expr) => {
137 $t.display_top::<SHORT>(f, Some(ind.clone()))
138 };
139 }
140 match self {
141 Self::OMID(uri) => if SHORT {
142 Display::fmt(uri.name(), f)
143 } else {
144 Display::fmt(uri, f)
145 }
146 .map(|()| DFSContinuation::Continue),
147 Self::OMV(v) => Display::fmt(v, f).map(|()| DFSContinuation::Continue),
148 Self::OMA { head, .. } => {
149 cont!(head)?;
150 f.write_char('(')?;
151 Ok(DFSContinuation::SkipNextAndClose(()))
152 }
153 Self::Field { record, key, owner } => {
154 cont!(record)?;
155 f.write_char('.')?;
156 Display::fmt(key, f)?;
157 if let Some(owner) = owner {
158 f.write_char('(')?;
159 cont!(owner)?;
160 f.write_char(')')?;
161 }
162 Ok(DFSContinuation::SkipChildren)
163 }
164 Self::OML { name, df, tp } => {
165 write!(f, "\"{name}\"")?;
166 if let Some(tp) = tp {
167 write!(f, "{ind} : ")?;
168 cont!(tp)?;
169 }
170 if let Some(df) = df {
171 write!(f, "{ind} := ")?;
172 cont!(df)?;
173 }
174 Ok(DFSContinuation::SkipChildren)
175 }
176 Self::Informal { .. } => {
177 write!(f, "TODO: Display for Term::Informal")?;
178 Ok(DFSContinuation::SkipChildren)
179 }
180 }
181 }
182 fn display_short_end(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
183 match self {
184 Self::OMID(_) | Self::OMV(_) | Self::Field { .. } => unreachable!(),
185 Self::OMA { .. } => f.write_char(')'),
186 Self::OML { .. } => f.write_char('>'),
187 Self::Informal { .. } => todo!(),
188 }
189 }
190
191 #[inline]
192 pub fn subterm_iter(&self) -> impl Iterator<Item = &'_ Self> {
193 <TermChildrenIter as TreeChildIter<Self>>::dfs(TermChildrenIter::One(self))
194 }
195
196 #[inline]
197 pub fn uri_iter(&self) -> impl Iterator<Item = URIRef<'_>> {
198 self.subterm_iter().filter_map(|t| match t {
199 Self::OMID(uri) => Some(uri.as_uri()),
200 Self::OMV(Var::Ref { declaration, .. }) => Some(declaration.as_uri()),
201 _ => None,
202 })
203 }
204}
205
206impl Display for Term {
207 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
208 self.display_top::<true>(f, None)
209 }
210}
211
212pub enum TermChildrenIter<'a> {
213 Slice(std::slice::Iter<'a, Term>),
214 Args(std::slice::Iter<'a, Arg>),
215 One(&'a Term),
216 Two(&'a Term, &'a Term),
217 WithHead(&'a Term, &'a [Arg]),
218 Empty,
219}
220impl<'a> Iterator for TermChildrenIter<'a> {
221 type Item = &'a Term;
222 fn next(&mut self) -> Option<Self::Item> {
223 match self {
224 Self::Slice(i) => i.next(),
225 Self::Args(i) => i.next().map(|a| &a.term),
226 Self::One(t) => {
227 let t = *t;
228 *self = Self::Empty;
229 Some(t)
230 }
231 Self::Two(t1, t2) => {
232 let t1 = *t1;
233 *self = Self::One(t2);
234 Some(t1)
235 }
236 Self::WithHead(head, args) => {
237 let head = *head;
238 *self = Self::Args(args.iter());
239 Some(head)
240 }
241 Self::Empty => None,
242 }
243 }
244}
245
246impl TreeLike for Term {
247 type Child<'a> = &'a Self;
248 type RefIter<'a> = TermChildrenIter<'a>;
249 #[allow(clippy::enum_glob_use)]
250 fn children(&self) -> Option<Self::RefIter<'_>> {
251 use Term::*;
252 match self {
253 OMID(_)
254 | OMV(_)
255 | OML {
256 tp: None, df: None, ..
257 } => None,
258 Field { record, owner, .. } => Some(
259 owner
260 .as_ref()
261 .map_or(TermChildrenIter::One(record), |owner| {
262 TermChildrenIter::Two(record, owner)
263 }),
264 ),
265 OMA { head, args } => Some(TermChildrenIter::WithHead(head, args)),
266 OML {
268 df: Some(df),
269 tp: Some(tp),
270 ..
271 } => Some(TermChildrenIter::Two(tp, df)),
272 OML {
273 df: None,
274 tp: Some(tp),
275 ..
276 } => Some(TermChildrenIter::One(tp)),
277 OML {
278 df: Some(df),
279 tp: None,
280 ..
281 } => Some(TermChildrenIter::One(df)),
282 Informal { terms, .. } => Some(TermChildrenIter::Slice(terms.iter())),
283 }
284 }
285}
286impl TreeChild<Term> for &Term {
287 fn children<'b>(&self) -> Option<<Term as TreeLike>::RefIter<'b>>
288 where
289 Self: 'b,
290 {
291 <Term as TreeLike>::children(self)
292 }
293}
294
295#[derive(Debug, Clone, Hash, PartialEq, Eq)]
296#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
297#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
298#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
299pub struct Arg {
300 pub term: Term,
301 pub mode: ArgMode,
302}
303impl From<(Term, ArgMode)> for Arg {
304 fn from((term, mode): (Term, ArgMode)) -> Self {
305 Self { term, mode }
306 }
307}
308
309#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
310#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
311#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
312#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
313pub enum ArgMode {
314 #[default]
315 Normal,
316 Sequence,
317 Binding,
318 BindingSequence,
319}
320impl ArgMode {
321 #[inline]
322 #[must_use]
323 pub const fn as_char(self) -> char {
324 match self {
325 Self::Normal => 'i',
326 Self::Sequence => 'a',
327 Self::Binding => 'b',
328 Self::BindingSequence => 'B',
329 }
330 }
331}
332impl std::fmt::Display for ArgMode {
333 #[inline]
334 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
335 f.write_char(self.as_char())
336 }
337}
338impl TryFrom<u8> for ArgMode {
339 type Error = ();
340 fn try_from(c: u8) -> Result<Self, Self::Error> {
341 match c {
342 b'i' => Ok(Self::Normal),
343 b'a' => Ok(Self::Sequence),
344 b'b' => Ok(Self::Binding),
345 b'B' => Ok(Self::BindingSequence),
346 _ => Err(()),
347 }
348 }
349}
350impl FromStr for ArgMode {
351 type Err = ();
352 #[inline]
353 fn from_str(s: &str) -> Result<Self, Self::Err> {
354 if s.len() != 1 {
355 return Err(());
356 }
357 s.as_bytes()[0].try_into()
358 }
359}
360
361#[derive(Clone, PartialEq, Eq, Hash)]
362#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
363#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
364#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
365pub enum Var {
366 Name(Name),
367 Ref {
368 declaration: DocumentElementURI,
369 is_sequence: Option<bool>,
370 },
371}
372impl Display for Var {
373 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
374 match self {
375 Self::Name(n) => Display::fmt(n, f),
376 Self::Ref { declaration, .. } => Display::fmt(declaration.name().last_name(), f),
377 }
378 }
379}
380impl Debug for Var {
381 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
382 match self {
383 Self::Name(n) => Debug::fmt(n, f),
384 Self::Ref { declaration, .. } => Debug::fmt(declaration, f),
385 }
386 }
387}
388
389#[derive(Clone, Debug, Hash, PartialEq, Eq)]
390#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
391#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
392#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
393pub enum Informal {
394 Term(u8),
395 Node {
396 tag: String,
397 attributes: Box<[(Box<str>, Box<str>)]>,
398 children: Box<[Informal]>,
399 },
400 Text(Box<str>),
401}
402
403impl Informal {
404 #[must_use]
405 pub fn iter_opt(&self) -> Option<impl Iterator<Item = &Self>> {
406 match self {
407 Self::Term(_) | Self::Text(_) => None,
408 Self::Node { children, .. } => Some(InformalIter {
409 curr: children.iter(),
410 stack: Vec::new(),
411 }),
412 }
413 }
414 #[must_use]
415 pub fn iter_mut_opt(&mut self) -> Option<impl Iterator<Item = &mut Self>> {
416 match self {
417 Self::Term(_) | Self::Text(_) => None,
418 Self::Node { children, .. } => Some(InformalIterMut {
419 curr: children.iter_mut(),
420 stack: Vec::new(),
421 }),
422 }
423 }
424}
425
426struct InformalIter<'a> {
427 curr: std::slice::Iter<'a, Informal>,
428 stack: Vec<std::slice::Iter<'a, Informal>>,
429}
430impl<'a> Iterator for InformalIter<'a> {
431 type Item = &'a Informal;
432 fn next(&mut self) -> Option<Self::Item> {
433 let r = self.curr.next().or_else(|| {
434 self.curr = self.stack.pop()?;
435 self.curr.next()
436 });
437 if let Some(Informal::Node { children, .. }) = r {
438 self.stack
439 .push(std::mem::replace(&mut self.curr, children.iter()));
440 }
441 r
442 }
443}
444struct InformalIterMut<'a> {
445 curr: std::slice::IterMut<'a, Informal>,
446 stack: Vec<std::slice::IterMut<'a, Informal>>,
447}
448impl<'a> Iterator for InformalIterMut<'a> {
449 type Item = &'a mut Informal;
450 fn next(&mut self) -> Option<Self::Item> {
451 loop {
452 let r = self.curr.next().or_else(|| {
453 self.curr = self.stack.pop()?;
454 self.curr.next()
455 });
456 if let Some(Informal::Node { children, .. }) = r {
457 self.stack
458 .push(std::mem::replace(&mut self.curr, children.iter_mut()));
459 } else {
460 return r;
461 }
462 }
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use crate::uris::{ArchiveURI, BaseURI, ModuleURI, SymbolURI};
469 use crate::{content::terms::Term, oma, oml, oms, omv};
470 use lazy_static::lazy_static;
471 lazy_static! {
472 static ref NAMESPACE: BaseURI = BaseURI::new_unchecked("http://example.com/");
473 static ref ARCHIVE1: ArchiveURI = NAMESPACE.clone() & "some/archive";
474 static ref ARCHIVE2: ArchiveURI = NAMESPACE.clone() & "some/other/archive";
475 static ref MODULE1: ModuleURI = (ARCHIVE1.clone() | "some/module").expect("impossible");
476 static ref MODULE2: ModuleURI = (ARCHIVE2.clone() | "some/module").expect("impossible");
477 static ref SYM1: SymbolURI = (MODULE1.clone() | "some symbol").expect("impossible");
478 static ref SYM2: SymbolURI = (MODULE2.clone() | "other symbol").expect("impossible");
479 static ref FUNC1: SymbolURI = (MODULE1.clone() | "some function").expect("impossible");
480 static ref FUNC2: SymbolURI = (MODULE2.clone() | "other function").expect("impossible");
481 static ref TERM: Term = oma!(oms!(FUNC1.clone()),[
482 {N:oma!(oms!(FUNC2.clone()),[
483 {N:oms!(SYM1.clone())},
484 {N:oms!(SYM2.clone())}
485 ])},
486 {N:oma!(oms!(FUNC1.clone()),[
487 {N:oml!("some name".parse().expect("impossible"); := oms!(SYM2.clone()))},
488 {N:oms!(SYM1.clone())},
489 {N:omv!("some var".parse().expect("impossible");)}
490 ])}
491 ]);
492 }
493
494 #[test]
495 fn test_term_display() {
496 let term = &*TERM;
497 let s = format!("{term}");
498 let refs = r#"some function(
499 other function(
500 some symbol
501 other symbol
502 )
503 some function(
504 "some name"
505 := other symbol
506 some symbol
507 some var
508 )
509)"#;
510 assert_eq!(s, refs);
511 }
512}