xschem_parser/lib.rs
1//! [Xschem] schematic and symbol parser.
2//!
3//! This library supports up to Xschem file version 1.2.
4//! See Xschem [developer info] for more information on the file format.
5//!
6//! # Usage
7//!
8//! Use [`from_str`] or [`from_slice`] to parse a [`token::Schematic`] from a
9//! string or byte slice. The parser is zero-copy so the resulting data
10//! structure contains references to the input.
11//!
12//! The parse error result [`Error`] implements [`std::fmt::Display`] to convert
13//! the error to a nice human readable format.
14//!
15//! # Examples
16//!
17//! ## Parse from string
18//!
19//! ```
20//! use nom::Input;
21//! use xschem_parser::Span;
22//! use xschem_parser::token::{Flip, Objects, Property, Rotation, Schematic, Text, Version};
23//!
24//! let input = "\
25//! v {xschem version=3.4.5 file_version=1.2}
26//! K {type=regulator}
27//! T {@name} -17.5 -15 0 0 0.2 0.2 {}
28//! ";
29//!
30//! // Get a span so we can reference to locations in the input string.
31//! // The parsed schematic contains references with column and line in
32//! // the input string.
33//! let span = Span::new(input);
34//!
35//! let expected = Schematic {
36//! version: Version(Property {
37//! prop: span.take_from(3).take(37),
38//! attrs: [
39//! (span.take_from(10).take(7), span.take_from(18).take(5)),
40//! (span.take_from(24).take(12), span.take_from(37).take(3)),
41//! ].into(),
42//! }),
43//! spice_property: None,
44//! verilog_property: None,
45//! vhdl_property: None,
46//! tedax_property: None,
47//! symbol_property: Some(Property {
48//! prop: span.take_from(45).take(14).into(),
49//! attrs: [
50//! (span.take_from(45).take(4), span.take_from(50).take(9)),
51//! ].into(),
52//! }.into()),
53//! texts: vec![Text {
54//! text: span.take_from(64).take(5),
55//! position: (-17.5, -15.0).try_into().unwrap(),
56//! rotation: Rotation::Zero,
57//! flip: Flip::Unflipped,
58//! size: (0.2, 0.2).try_into().unwrap(),
59//! property: Property {
60//! prop: span.take_from(94).take(0),
61//! attrs: [].into(),
62//! },
63//! }].into(),
64//! lines: Objects::default(),
65//! rectangles: Objects::default(),
66//! polygons: Objects::default(),
67//! arcs: Objects::default(),
68//! wires: Objects::default(),
69//! components: Objects::default(),
70//! };
71//!
72//! let result = xschem_parser::from_str(input);
73//!
74//! assert_eq!(result, Ok(expected));
75//! ```
76//!
77//! ## Parse from invalid string
78//!
79//! ```
80//! // invalid input, wrong brackets
81//! let input = "v []";
82//!
83//! let expected = "\
84//! error: expected '{'
85//! --> :1:3
86//! |
87//! 1 | v []
88//! | ^
89//! |
90//! in version
91//! --> :1:1
92//! |
93//! 1 | v []
94//! | ^
95//! |";
96//!
97//! let result = xschem_parser::from_str(input);
98//!
99//! assert!(result.is_err());
100//! assert_eq!(result.unwrap_err().to_string(), expected);
101//! ```
102//!
103//! ## Parse from file
104//!
105//! Since a parsed schematic contains references to the input, this library
106//! cannot provide an implementation of parsing from file, since that would
107//! require copying the contents of the file contents to make the lifetimes work
108//! out.
109//!
110//! ```no_run
111//! use std::path::Path;
112//!
113//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
114//! let path = Path::new("test.sch");
115//! let contents = std::fs::read_to_string(path)?;
116//! match xschem_parser::from_str_file(&contents, path) {
117//! Ok(schematic) => println!("{schematic}"),
118//! Err(e) => eprintln!("{e}"),
119//! }
120//! # Ok(())
121//! # }
122//! ```
123//!
124//! [Xschem]: https://xschem.sourceforge.io/stefan/index.html
125//! [developer info]: https://xschem.sourceforge.io/stefan/xschem_man/developer_info.html
126
127use std::path::Path;
128
129use nom_locate::LocatedSpan;
130
131use crate::error::Error;
132use crate::token::Schematic;
133
134pub mod error;
135pub mod parse;
136pub mod token;
137
138#[cfg(test)]
139mod test;
140
141/// String reference with location.
142pub type Span<'a, X = ()> = LocatedSpan<&'a str, X>;
143/// String reference with location in file.
144pub type FileSpan<'a, 'b> = Span<'a, &'b Path>;
145/// Bytes reference with location.
146pub type ByteSpan<'a, X = ()> = LocatedSpan<&'a [u8], X>;
147/// Bytes reference with location in file.
148pub type ByteFileSpan<'a, 'b> = ByteSpan<'a, &'b Path>;
149
150/// Parse a [`Schematic`] from a [`str`].
151pub fn from_str(s: &str) -> Result<Schematic<Span<'_>>, Error<Span<'_>>> {
152 Schematic::parse_str(s)
153}
154
155/// Parse a [`Schematic`] from a byte slice.
156pub fn from_slice(s: &[u8]) -> Result<Schematic<ByteSpan<'_>>, Error<ByteSpan<'_>>> {
157 Schematic::parse_slice(s)
158}
159
160/// Parse a [`Schematic`] from a [`str`] with [`Path`] info.
161pub fn from_str_file<'a, 'b>(
162 s: &'a str,
163 path: &'b Path,
164) -> Result<Schematic<FileSpan<'a, 'b>>, Error<FileSpan<'a, 'b>>> {
165 Schematic::parse_str_with_extra(s, path)
166}
167
168/// Parse a [`Schematic`] from a byte slice with [`Path`] info.
169pub fn from_slice_file<'a, 'b>(
170 s: &'a [u8],
171 path: &'b Path,
172) -> Result<Schematic<ByteFileSpan<'a, 'b>>, Error<ByteFileSpan<'a, 'b>>> {
173 Schematic::parse_slice_with_extra(s, path)
174}