xschem_parser/
token.rs

1//! Parsed data structures.
2use std::collections::HashMap;
3use std::fmt;
4use std::fmt::Formatter;
5use std::hash::Hash;
6use std::vec::Vec;
7
8use derive_more::{Deref, DerefMut, Display, From, Into, TryFrom};
9
10use crate::error::Error;
11use crate::{ByteSpan, Span, parse};
12
13/// Xschem schematic (or symbol).
14#[derive(Clone, Debug, Default)]
15pub struct Schematic<I> {
16    pub version: Version<I>,
17    pub vhdl_property: Option<VhdlProperty<I>>,
18    pub symbol_property: Option<SymbolProperty<I>>,
19    pub verilog_property: Option<VerilogProperty<I>>,
20    pub spice_property: Option<SpiceProperty<I>>,
21    pub tedax_property: Option<TedaXProperty<I>>,
22    pub texts: Objects<Text<I>>,
23    pub lines: Objects<Line<I>>,
24    pub rectangles: Objects<Rectangle<I>>,
25    pub polygons: Objects<Polygon<I>>,
26    pub arcs: Objects<Arc<I>>,
27    pub wires: Objects<Wire<I>>,
28    pub components: Objects<Component<I>>,
29}
30
31/// Xschem property string with parsed attributes.
32#[derive(Clone, Debug, Default, Display)]
33#[display("{{{prop}}}")]
34pub struct Property<I> {
35    /// Full property input.
36    pub prop: I,
37    /// Parsed attributes from `prop`.
38    pub attrs: HashMap<I, I>,
39}
40
41/// Xschem schematic or symbol version specifiication.
42#[derive(Clone, Debug, Default, Display)]
43#[display("v {_0}")]
44pub struct Version<I>(pub Property<I>);
45
46#[derive(Clone, Debug, Default, Deref, Display, From)]
47#[display("G {_0}")]
48pub struct VhdlProperty<I>(pub Property<I>);
49
50#[derive(Clone, Debug, Default, Deref, Display, From)]
51#[display("K {_0}")]
52pub struct SymbolProperty<I>(pub Property<I>);
53
54#[derive(Clone, Debug, Default, Deref, Display, From)]
55#[display("V {_0}")]
56pub struct VerilogProperty<I>(pub Property<I>);
57
58#[derive(Clone, Debug, Default, Deref, Display, From)]
59#[display("S {_0}")]
60pub struct SpiceProperty<I>(pub Property<I>);
61
62#[derive(Clone, Debug, Default, Deref, Display, From)]
63#[display("E {_0}")]
64pub struct TedaXProperty<I>(pub Property<I>);
65
66#[derive(Clone, Debug, From)]
67#[from(forward)]
68#[allow(clippy::large_enum_variant)]
69pub enum Object<I> {
70    SpiceProperty(SpiceProperty<I>),
71    VerilogProperty(VerilogProperty<I>),
72    VhdlProperty(VhdlProperty<I>),
73    TedaXProperty(TedaXProperty<I>),
74    SymbolProperty(SymbolProperty<I>),
75
76    Arc(Arc<I>),
77    Component(Component<I>),
78    Line(Line<I>),
79    Polygon(Polygon<I>),
80    Rectangle(Rectangle<I>),
81    Text(Text<I>),
82    Wire(Wire<I>),
83}
84
85#[derive(Clone, Debug, Deref, DerefMut, From, Into, PartialEq)]
86pub struct Objects<O>(pub Vec<O>);
87
88/// Xschem arc object.
89#[derive(Clone, Debug, Default, Display)]
90#[display("A {layer} {center} {radius} {start_angle} {sweep_angle} {property}")]
91pub struct Arc<I> {
92    pub layer: u64,
93    pub center: Coordinate,
94    pub radius: FiniteDouble,
95    pub start_angle: FiniteDouble,
96    pub sweep_angle: FiniteDouble,
97    pub property: Property<I>,
98}
99
100/// Xschem component instance.
101#[derive(Clone, Debug, Default)]
102pub struct Component<I> {
103    pub reference: I,
104    pub position: Coordinate,
105    pub rotation: Rotation,
106    pub flip: Flip,
107    pub property: Property<I>,
108    pub embedding: Option<Embedding<I>>,
109}
110
111/// Xschem line object.
112#[derive(Clone, Debug, Default, Display)]
113#[display("L {layer} {start} {end} {property}")]
114pub struct Line<I> {
115    pub layer: u64,
116    pub start: Coordinate,
117    pub end: Coordinate,
118    pub property: Property<I>,
119}
120
121/// Xschem polygon object.
122#[derive(Clone, Debug, Default, Display)]
123#[display("P {layer} {npoints} {points} {property}", npoints = points.len())]
124pub struct Polygon<I> {
125    pub layer: u64,
126    pub points: Coordinates,
127    pub property: Property<I>,
128}
129
130/// Xschem rectangle object.
131#[derive(Clone, Debug, Default, Display)]
132#[display("B {layer} {start} {end} {property}")]
133pub struct Rectangle<I> {
134    pub layer: u64,
135    pub start: Coordinate,
136    pub end: Coordinate,
137    pub property: Property<I>,
138}
139
140/// Xschem text object.
141#[derive(Clone, Debug, Default, Display)]
142#[display("T {{{text}}} {position} {rotation} {flip} {size} {property}")]
143pub struct Text<I> {
144    pub text: I,
145    pub position: Coordinate,
146    pub rotation: Rotation,
147    pub flip: Flip,
148    pub size: Size,
149    pub property: Property<I>,
150}
151
152/// Xschem wire object.
153#[derive(Clone, Debug, Default, Display)]
154#[display("N {start} {end} {property}")]
155pub struct Wire<I> {
156    pub start: Coordinate,
157    pub end: Coordinate,
158    pub property: Property<I>,
159}
160
161#[derive(Clone, Debug, Default, Deref, Display, From, Into)]
162#[display("[\n{_0}\n]")]
163pub struct Embedding<I>(pub Schematic<I>);
164
165/// Finite double precision type.
166#[derive(Clone, Copy, Debug, Default, Deref, Display, Into, PartialEq, PartialOrd)]
167pub struct FiniteDouble(f64);
168
169#[derive(Clone, Copy, Debug, Default, Display, From, Into, PartialEq, PartialOrd)]
170#[from((FiniteDouble, FiniteDouble))]
171#[into((FiniteDouble, FiniteDouble))]
172#[display("{x} {y}")]
173pub struct Vec2 {
174    pub x: FiniteDouble,
175    pub y: FiniteDouble,
176}
177
178pub type Coordinate = Vec2;
179pub type Size = Vec2;
180
181#[derive(Clone, Debug, Default, Deref, DerefMut, From, Into, PartialEq)]
182pub struct Coordinates(pub Vec<Coordinate>);
183
184#[derive(Clone, Copy, Debug, Default, Display, PartialEq, Eq, PartialOrd, Ord, TryFrom)]
185#[try_from(repr)]
186#[repr(u8)]
187pub enum Rotation {
188    #[default]
189    #[display("0")]
190    Zero,
191    #[display("1")]
192    One,
193    #[display("2")]
194    Two,
195    #[display("3")]
196    Three,
197}
198
199#[derive(Clone, Copy, Debug, Default, Display, PartialEq, Eq, PartialOrd, Ord, TryFrom)]
200#[try_from(repr)]
201#[repr(u8)]
202pub enum Flip {
203    #[default]
204    #[display("0")]
205    Unflipped,
206    #[display("1")]
207    Flipped,
208}
209
210impl<'a, X: Clone + Default> TryFrom<&'a str> for Schematic<Span<'a, X>> {
211    type Error = Error<Span<'a, X>>;
212
213    /// Tries to parse a schematic from a `str`.
214    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
215        Self::try_from(Span::new_extra(value, X::default()))
216    }
217}
218
219impl<'a, X: Clone + Default> TryFrom<&'a [u8]> for Schematic<ByteSpan<'a, X>> {
220    type Error = Error<ByteSpan<'a, X>>;
221
222    /// Tries to parse a schematic from a slice.
223    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
224        Self::try_from(ByteSpan::new_extra(value, X::default()))
225    }
226}
227
228impl<'a, X: Clone> TryFrom<Span<'a, X>> for Schematic<Span<'a, X>> {
229    type Error = Error<Span<'a, X>>;
230
231    /// Tries to parse a schematic from a spanned `str`.
232    fn try_from(value: Span<'a, X>) -> Result<Self, Self::Error> {
233        parse::schematic_full(value)
234    }
235}
236
237impl<'a, X: Clone> TryFrom<ByteSpan<'a, X>> for Schematic<ByteSpan<'a, X>> {
238    type Error = Error<ByteSpan<'a, X>>;
239
240    /// Tries to parse a schematic from a spanned slice.
241    fn try_from(value: ByteSpan<'a, X>) -> Result<Self, Self::Error> {
242        parse::schematic_full(value)
243    }
244}
245
246impl<I> fmt::Display for Schematic<I>
247where
248    I: fmt::Display,
249{
250    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
251        write!(f, "{}", self.version)?;
252        if let Some(p) = &self.vhdl_property {
253            write!(f, "\n{p}")?;
254        }
255        if let Some(p) = &self.symbol_property {
256            write!(f, "\n{p}")?;
257        }
258        if let Some(p) = &self.verilog_property {
259            write!(f, "\n{p}")?;
260        }
261        if let Some(p) = &self.spice_property {
262            write!(f, "\n{p}")?;
263        }
264        if let Some(p) = &self.tedax_property {
265            write!(f, "\n{p}")?;
266        }
267        if !self.texts.is_empty() {
268            write!(f, "\n{}", self.texts)?;
269        }
270        if !self.lines.is_empty() {
271            write!(f, "\n{}", self.lines)?;
272        }
273        if !self.rectangles.is_empty() {
274            write!(f, "\n{}", self.rectangles)?;
275        }
276        if !self.polygons.is_empty() {
277            write!(f, "\n{}", self.polygons)?;
278        }
279        if !self.arcs.is_empty() {
280            write!(f, "\n{}", self.arcs)?;
281        }
282        if !self.wires.is_empty() {
283            write!(f, "\n{}", self.wires)?;
284        }
285        if !self.components.is_empty() {
286            write!(f, "\n{}", self.components)?;
287        }
288        Ok(())
289    }
290}
291
292impl<'a> Schematic<Span<'a>> {
293    /// Parses a string as a [`Schematic`].
294    pub fn parse_str<I: AsRef<str> + ?Sized>(input: &'a I) -> Result<Self, Error<Span<'a>>> {
295        Self::try_from(input.as_ref())
296    }
297}
298
299impl<'a, X: Clone> Schematic<Span<'a, X>> {
300    /// Parses a string as a [`Schematic`].
301    pub fn parse_str_with_extra<I: AsRef<str> + ?Sized>(
302        input: &'a I,
303        extra: X,
304    ) -> Result<Self, Error<Span<'a, X>>> {
305        Self::try_from(Span::new_extra(input.as_ref(), extra))
306    }
307}
308
309impl<'a> Schematic<ByteSpan<'a>> {
310    /// Parses bytes as a [`Schematic`].
311    pub fn parse_slice<I: AsRef<[u8]> + ?Sized>(input: &'a I) -> Result<Self, Error<ByteSpan<'a>>> {
312        Self::try_from(input.as_ref())
313    }
314}
315
316impl<'a, X: Clone> Schematic<ByteSpan<'a, X>> {
317    /// Parses a string as a [`Schematic`].
318    pub fn parse_slice_with_extra<I: AsRef<[u8]> + ?Sized>(
319        input: &'a I,
320        extra: X,
321    ) -> Result<Self, Error<ByteSpan<'a, X>>> {
322        Self::try_from(ByteSpan::new_extra(input.as_ref(), extra))
323    }
324}
325
326impl<'a, X: Clone> Schematic<Span<'a, X>> {
327    /// Parses a string span as a [`Schematic`].
328    pub fn parse_span(input: Span<'a, X>) -> Result<Self, Error<Span<'a, X>>> {
329        Self::try_from(input)
330    }
331}
332
333impl<'a, X: Clone> Schematic<ByteSpan<'a, X>> {
334    /// Parses a string span as a [`Schematic`].
335    pub fn parse_span(input: ByteSpan<'a, X>) -> Result<Self, Error<ByteSpan<'a, X>>> {
336        Self::try_from(input)
337    }
338}
339
340impl<I: PartialEq> PartialEq for Schematic<I>
341where
342    Property<I>: PartialEq,
343{
344    fn eq(&self, other: &Self) -> bool {
345        self.version == other.version
346            && self.vhdl_property == other.vhdl_property
347            && self.symbol_property == other.symbol_property
348            && self.verilog_property == other.verilog_property
349            && self.spice_property == other.spice_property
350            && self.tedax_property == other.tedax_property
351            && self.texts == other.texts
352            && self.lines == other.lines
353            && self.rectangles == other.rectangles
354            && self.polygons == other.polygons
355            && self.arcs == other.arcs
356            && self.wires == other.wires
357            && self.components == other.components
358    }
359}
360
361impl<I> Schematic<I> {
362    pub fn new(version: Version<I>) -> Self {
363        Self {
364            version,
365            vhdl_property: Option::default(),
366            symbol_property: Option::default(),
367            verilog_property: Option::default(),
368            spice_property: Option::default(),
369            tedax_property: Option::default(),
370            texts: Objects::default(),
371            lines: Objects::default(),
372            rectangles: Objects::default(),
373            polygons: Objects::default(),
374            arcs: Objects::default(),
375            wires: Objects::default(),
376            components: Objects::default(),
377        }
378    }
379
380    #[must_use]
381    pub fn add_object(mut self, object: Object<I>) -> Self {
382        match object {
383            Object::VhdlProperty(p) => {
384                self.vhdl_property.replace(p);
385            }
386            Object::SymbolProperty(p) => {
387                self.symbol_property.replace(p);
388            }
389            Object::VerilogProperty(p) => {
390                self.verilog_property.replace(p);
391            }
392            Object::SpiceProperty(p) => {
393                self.spice_property.replace(p);
394            }
395            Object::TedaXProperty(p) => {
396                self.tedax_property.replace(p);
397            }
398            Object::Arc(o) => {
399                self.arcs.push(o);
400            }
401            Object::Component(o) => {
402                self.components.push(o);
403            }
404            Object::Line(o) => {
405                self.lines.push(o);
406            }
407            Object::Polygon(o) => {
408                self.polygons.push(o);
409            }
410            Object::Rectangle(o) => {
411                self.rectangles.push(o);
412            }
413            Object::Text(o) => {
414                self.texts.push(o);
415            }
416            Object::Wire(o) => {
417                self.wires.push(o);
418            }
419        }
420
421        self
422    }
423}
424
425impl<I: Eq + Hash + PartialEq> PartialEq for Property<I> {
426    fn eq(&self, other: &Self) -> bool {
427        self.prop == other.prop && self.attrs == other.attrs
428    }
429}
430
431impl<I> PartialEq for Version<I>
432where
433    Property<I>: PartialEq,
434{
435    fn eq(&self, other: &Self) -> bool {
436        self.0 == other.0
437    }
438}
439
440impl<I> PartialEq for SpiceProperty<I>
441where
442    Property<I>: PartialEq,
443{
444    fn eq(&self, other: &Self) -> bool {
445        self.0 == other.0
446    }
447}
448
449impl<I> PartialEq for VerilogProperty<I>
450where
451    Property<I>: PartialEq,
452{
453    fn eq(&self, other: &Self) -> bool {
454        self.0 == other.0
455    }
456}
457
458impl<I> PartialEq for VhdlProperty<I>
459where
460    Property<I>: PartialEq,
461{
462    fn eq(&self, other: &Self) -> bool {
463        self.0 == other.0
464    }
465}
466
467impl<I> PartialEq for TedaXProperty<I>
468where
469    Property<I>: PartialEq,
470{
471    fn eq(&self, other: &Self) -> bool {
472        self.0 == other.0
473    }
474}
475
476impl<I> PartialEq for SymbolProperty<I>
477where
478    Property<I>: PartialEq,
479{
480    fn eq(&self, other: &Self) -> bool {
481        self.0 == other.0
482    }
483}
484
485impl<I> PartialEq for Arc<I>
486where
487    Property<I>: PartialEq,
488{
489    fn eq(&self, other: &Self) -> bool {
490        self.layer == other.layer
491            && self.center == other.center
492            && self.radius == other.radius
493            && self.start_angle == other.start_angle
494            && self.sweep_angle == other.sweep_angle
495            && self.property == other.property
496    }
497}
498
499impl<I> fmt::Display for Component<I>
500where
501    I: fmt::Display,
502{
503    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
504        let Self {
505            reference,
506            position,
507            rotation,
508            flip,
509            property,
510            embedding,
511        } = self;
512        write!(
513            f,
514            "C {{{reference}}} {position} {rotation} {flip} {property}"
515        )?;
516        if let Some(e) = embedding {
517            write!(f, "\n{e}")?;
518        }
519        Ok(())
520    }
521}
522
523impl<I: PartialEq> PartialEq for Component<I>
524where
525    Property<I>: PartialEq,
526{
527    fn eq(&self, other: &Self) -> bool {
528        self.reference == other.reference
529            && self.position == other.position
530            && self.rotation == other.rotation
531            && self.flip == other.flip
532            && self.property == other.property
533            && self.embedding == other.embedding
534    }
535}
536
537impl<I> PartialEq for Line<I>
538where
539    Property<I>: PartialEq,
540{
541    fn eq(&self, other: &Self) -> bool {
542        self.layer == other.layer
543            && self.start == other.start
544            && self.end == other.end
545            && self.property == other.property
546    }
547}
548
549impl<I> PartialEq for Polygon<I>
550where
551    Property<I>: PartialEq,
552{
553    fn eq(&self, other: &Self) -> bool {
554        self.layer == other.layer && self.points == other.points && self.property == other.property
555    }
556}
557
558impl<I> PartialEq for Rectangle<I>
559where
560    Property<I>: PartialEq,
561{
562    fn eq(&self, other: &Self) -> bool {
563        self.layer == other.layer
564            && self.start == other.start
565            && self.end == other.end
566            && self.property == other.property
567    }
568}
569
570impl<I: PartialEq> PartialEq for Text<I>
571where
572    Property<I>: PartialEq,
573{
574    fn eq(&self, other: &Self) -> bool {
575        self.text == other.text
576            && self.position == other.position
577            && self.rotation == other.rotation
578            && self.flip == other.flip
579            && self.size == other.size
580            && self.property == other.property
581    }
582}
583
584impl<I> PartialEq for Wire<I>
585where
586    Property<I>: PartialEq,
587{
588    fn eq(&self, other: &Self) -> bool {
589        self.start == other.start && self.end == other.end && self.property == other.property
590    }
591}
592
593impl<I: PartialEq> PartialEq for Embedding<I>
594where
595    Property<I>: PartialEq,
596{
597    fn eq(&self, other: &Self) -> bool {
598        self.0 == other.0
599    }
600}
601
602impl<O> Default for Objects<O> {
603    fn default() -> Self {
604        Self(Vec::default())
605    }
606}
607
608impl<O: fmt::Display> fmt::Display for Objects<O> {
609    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
610        self.iter().enumerate().try_for_each(
611            |(i, o)| {
612                if i == 0 { o.fmt(f) } else { write!(f, "\n{o}") }
613            },
614        )
615    }
616}
617
618impl fmt::Display for Coordinates {
619    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
620        self.iter().enumerate().try_for_each(
621            |(i, c)| {
622                if i == 0 { c.fmt(f) } else { write!(f, " {c}") }
623            },
624        )
625    }
626}
627
628impl TryFrom<f64> for FiniteDouble {
629    type Error = &'static str;
630
631    fn try_from(value: f64) -> Result<Self, Self::Error> {
632        if value.is_finite() {
633            Ok(Self(value))
634        } else {
635            Err("value is not finite")
636        }
637    }
638}
639
640impl Eq for FiniteDouble {}
641
642impl TryFrom<(f64, f64)> for Vec2 {
643    type Error = <FiniteDouble as TryFrom<f64>>::Error;
644
645    fn try_from(value: (f64, f64)) -> Result<Self, Self::Error> {
646        let (x, y) = value;
647        let x = x.try_into()?;
648        let y = y.try_into()?;
649        Ok(Self { x, y })
650    }
651}
652
653impl<T> From<Vec<(T, T)>> for Coordinates
654where
655    Vec2: From<(T, T)>,
656{
657    fn from(value: Vec<(T, T)>) -> Self {
658        Self(value.into_iter().map(Vec2::from).collect())
659    }
660}
661
662impl FromIterator<Vec2> for Coordinates {
663    fn from_iter<T: IntoIterator<Item = Vec2>>(iter: T) -> Self {
664        Self(iter.into_iter().collect())
665    }
666}
667
668impl TryFrom<Vec<(f64, f64)>> for Coordinates {
669    type Error = <Vec2 as TryFrom<(f64, f64)>>::Error;
670
671    fn try_from(value: Vec<(f64, f64)>) -> Result<Self, Self::Error> {
672        value.into_iter().map(Vec2::try_from).collect()
673    }
674}
675
676impl From<Rotation> for u8 {
677    fn from(value: Rotation) -> Self {
678        match value {
679            Rotation::Zero => 0,
680            Rotation::One => 1,
681            Rotation::Two => 2,
682            Rotation::Three => 3,
683        }
684    }
685}
686
687impl From<bool> for Flip {
688    fn from(value: bool) -> Self {
689        if value {
690            Flip::Flipped
691        } else {
692            Flip::Unflipped
693        }
694    }
695}
696
697impl From<Flip> for bool {
698    fn from(value: Flip) -> Self {
699        match value {
700            Flip::Unflipped => false,
701            Flip::Flipped => true,
702        }
703    }
704}