Skip to main content

molpack/script/
error.rs

1//! Error type for the script loader.
2
3use std::fmt;
4use std::path::PathBuf;
5
6use crate::error::PackError;
7
8/// Errors produced by the script module — from parsing, file loading, or
9/// the downstream `pack()` call invoked by a script-driven run.
10#[derive(Debug)]
11pub enum ScriptError {
12    /// Parse error with line number and diagnostic message.
13    Parse { line: usize, message: String },
14    /// An unrecognised keyword appeared where a known one was expected.
15    /// Unlike a generic parse error, this carries the offending token and
16    /// the context block so error messages can suggest fixes.
17    UnknownKeyword {
18        line: usize,
19        keyword: String,
20        context: &'static str,
21    },
22    /// Script is missing a required `output` keyword.
23    MissingOutput,
24    /// Script contains zero `structure` blocks.
25    NoStructures,
26    /// A `structure` or `atoms` block was not closed with `end …`.
27    UnclosedBlock(&'static str),
28    /// Reading or writing a molecular frame failed.
29    Io { path: PathBuf, message: String },
30    /// The packer itself returned an error.
31    Pack(PackError),
32}
33
34impl fmt::Display for ScriptError {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            Self::Parse { line, message } => write!(f, "line {line}: {message}"),
38            Self::UnknownKeyword {
39                line,
40                keyword,
41                context,
42            } => write!(
43                f,
44                "line {line}: unknown keyword `{keyword}` in {context}. \
45                 Silently dropping it risks wrong semantics (e.g. \
46                 `pbc` that was ignored blew the cell grid); if this \
47                 keyword should be accepted, add it to the parser",
48            ),
49            Self::MissingOutput => write!(f, "missing required `output` keyword"),
50            Self::NoStructures => write!(f, "no `structure` blocks found in script"),
51            Self::UnclosedBlock(kind) => write!(f, "unexpected EOF: unclosed `{kind}` block"),
52            Self::Io { path, message } => write!(f, "{}: {message}", path.display()),
53            Self::Pack(err) => write!(f, "packing failed: {err}"),
54        }
55    }
56}
57
58impl std::error::Error for ScriptError {
59    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
60        match self {
61            Self::Pack(err) => Some(err),
62            _ => None,
63        }
64    }
65}
66
67impl From<PackError> for ScriptError {
68    fn from(err: PackError) -> Self {
69        Self::Pack(err)
70    }
71}