netlist-db 0.4.10

Concurrent/Parallel SPICE (HSPICE) parser, under building.
Documentation
use super::utils::{
    key_value, loss_sep, many0_dummyfirst, multiline_sep, name, name_char, name_str, ports_params,
    value,
};
use crate::{
    instance::{
        BJTBuilder, CapacitorBuilder, CurrentBuilder, CurrentSourceBuilder, DiodeBuilder,
        InductorBuilder, InstanceBuilder, InstanceCtxBuilder, MOSFETBuilder, PWLBuilder,
        ResistorBuilder, SubcktBuilder, TimeValuePointBuilder, VoltageBuilder,
        VoltageSourceBuilder,
    },
    span::LocatedSpan,
};
use nom::{
    IResult, Parser,
    branch::alt,
    character::char,
    combinator::{map, map_res},
    multi::many1,
};

#[inline]
pub(super) fn instance(mut i: LocatedSpan) -> IResult<LocatedSpan, InstanceBuilder> {
    let first_char;
    let name;
    (i, (first_char, name)) = name_char(i)?;
    let parser = match first_char.to_ascii_lowercase() {
        b'r' => _resistor,
        b'c' => _capacitor,
        b'l' => _inductor,
        b'v' => _voltage,
        b'i' => _current,
        b'm' => _mosfet,
        b'q' => _bjt,
        b'd' => _diode,
        b'x' => _subckt,
        r#type => {
            return map(ports_params, |(nodes, params)| InstanceBuilder {
                name,
                ctx: InstanceCtxBuilder::Unknown {
                    r#type,
                    nodes,
                    params,
                },
            })
            .parse_complete(i);
        }
    };
    map(parser, |ctx| InstanceBuilder { name, ctx }).parse_complete(i)
}

#[inline]
fn _resistor(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map(
        (
            multiline_sep(name),
            multiline_sep(name),
            multiline_sep(value),
        ),
        |(n1, n2, value)| InstanceCtxBuilder::Resistor(ResistorBuilder { n1, n2, value }),
    )
    .parse_complete(i)
}
#[inline]
fn _capacitor(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map(
        (
            multiline_sep(name),
            multiline_sep(name),
            multiline_sep(value),
        ),
        |(n1, n2, value)| InstanceCtxBuilder::Capacitor(CapacitorBuilder { n1, n2, value }),
    )
    .parse_complete(i)
}
#[inline]
fn _inductor(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map(
        (
            multiline_sep(name),
            multiline_sep(name),
            multiline_sep(value),
        ),
        |(n1, n2, value)| InstanceCtxBuilder::Inductor(InductorBuilder { n1, n2, value }),
    )
    .parse_complete(i)
}
#[inline]
fn _mosfet(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map_res(ports_params, |(ports, params)| match ports.len() {
        4 => Ok(InstanceCtxBuilder::MOSFET(MOSFETBuilder {
            nd: ports[0],
            ng: ports[1],
            ns: ports[2],
            nb: None,
            mname: ports[3],
            params,
        })),
        5 => Ok(InstanceCtxBuilder::MOSFET(MOSFETBuilder {
            nd: ports[0],
            ng: ports[1],
            ns: ports[2],
            nb: Some(ports[3]),
            mname: ports[4],
            params,
        })),
        0 => Err("There is no model name".to_string()),
        n => Err(format!(
            "MOSFET is 3/4 ports device, but found {} port(s)",
            n - 1
        )),
    })
    .parse_complete(i)
}
#[inline]
fn _bjt(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map_res(ports_params, |(ports, params)| match ports.len() {
        4 => Ok(InstanceCtxBuilder::BJT(BJTBuilder {
            nc: ports[0],
            nb: ports[1],
            ne: ports[2],
            ns: None,
            mname: ports[3],
            params,
        })),
        5 => Ok(InstanceCtxBuilder::BJT(BJTBuilder {
            nc: ports[0],
            nb: ports[1],
            ne: ports[2],
            ns: Some(ports[3]),
            mname: ports[4],
            params,
        })),
        0 => Err("There is no model name".to_string()),
        n => Err(format!(
            "BJT is 3/4 ports device, but found {} port(s)",
            n - 1
        )),
    })
    .parse_complete(i)
}
#[inline]
fn _diode(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map_res(ports_params, |(ports, params)| match ports.len() {
        3 => Ok(InstanceCtxBuilder::Diode(DiodeBuilder {
            nplus: ports[0],
            nminus: ports[1],
            mname: ports[2],
            params,
        })),
        0 => Err("There is no model name".to_string()),
        n => Err(format!(
            "Diode is 2 ports device, but found {} port(s)",
            n - 1
        )),
    })
    .parse_complete(i)
}
#[inline]
fn _subckt(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map_res(ports_params, |(mut nodes, params)| {
        if let Some(cktname) = nodes.pop() {
            Ok(InstanceCtxBuilder::Subckt(SubcktBuilder {
                nodes,
                cktname,
                params,
            }))
        } else {
            Err("There is no subckt name")
        }
    })
    .parse_complete(i)
}
#[inline]
fn _pwl(i: LocatedSpan) -> IResult<LocatedSpan, PWLBuilder> {
    map_res(
        (
            multiline_sep(name_str),
            loss_sep,
            char('('),
            loss_sep,
            value,
            many0_dummyfirst(multiline_sep(value)),
            loss_sep,
            char(')'),
        ),
        |((tag, _), _, _, _, first, mut points, _, _)| {
            if tag.to_ascii_uppercase().eq("PWL") {
                if let Some(dummy_first) = points.first_mut() {
                    *dummy_first = first;
                    if points.len() % 2 != 0 {
                        Err("points should be 2N numbers")
                    } else {
                        Ok(PWLBuilder {
                            points: points
                                .chunks_exact(2)
                                .map(|values| TimeValuePointBuilder {
                                    time: values[0],
                                    value: values[1],
                                })
                                .collect(),
                            ..Default::default()
                        })
                    }
                } else {
                    Err("points should at least 2")
                }
            } else {
                Err("Want PWL keyword")
            }
        },
    )
    .parse_complete(i)
}
#[inline]
fn _voltage(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map(
        (
            multiline_sep(name),
            multiline_sep(name),
            alt((
                map(many1(multiline_sep(key_value)), |params| {
                    VoltageSourceBuilder::Params(params)
                }),
                map(_pwl, VoltageSourceBuilder::PWL),
                map(multiline_sep(value), VoltageSourceBuilder::Value),
            )),
        ),
        |(n1, n2, source)| InstanceCtxBuilder::Voltage(VoltageBuilder { n1, n2, source }),
    )
    .parse_complete(i)
}
#[inline]
fn _current(i: LocatedSpan) -> IResult<LocatedSpan, InstanceCtxBuilder> {
    map(
        (
            multiline_sep(name),
            multiline_sep(name),
            alt((
                map(many1(multiline_sep(key_value)), |params| {
                    CurrentSourceBuilder::Params(params)
                }),
                map(_pwl, CurrentSourceBuilder::PWL),
                map(multiline_sep(value), CurrentSourceBuilder::Value),
            )),
        ),
        |(n1, n2, source)| InstanceCtxBuilder::Current(CurrentBuilder { n1, n2, source }),
    )
    .parse_complete(i)
}