sdc-parser 0.1.1

A parser library for Synopsys Design Constraints (sdc)
Documentation
use combine::char::{char, digit, string};
use combine::error::{ParseError, ParseResult};
use combine::parser::combinator::recognize;
use combine::{
    choice, eof, from_str, look_ahead, many, many1, none_of, not_followed_by, one_of, optional,
    parser, skip_many, skip_many1, token, Parser, Stream,
};

pub(crate) fn symbol<I>(name: &'static str) -> impl Parser<Input = I, Output = &'static str>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    lex(symbol_(name))
}

fn symbol_<I>(name: &'static str) -> impl Parser<Input = I, Output = &'static str>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    string(name)
        .and(look_ahead(
            one_of(" \t\n\\[]{}".chars()).or(eof().map(|_| ' ')),
        ))
        .map(|(x, _)| x)
}

pub(crate) fn float<I>() -> impl Parser<Input = I, Output = f64>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    lex(float_())
}

fn float_<I>() -> impl Parser<Input = I, Output = f64>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    from_str(recognize::<String, _>((
        optional(token('-')),
        (token('.').and(skip_many1(digit())).map(|_| '0')).or((
            token('0').skip(not_followed_by(digit())).or((
                one_of("123456789".chars()),
                skip_many(digit()),
            )
                .map(|_| '0')),
            optional((token('.'), skip_many(digit()))),
        )
            .map(|_| '0')),
        optional((
            (one_of("eE".chars()), optional(one_of("+-".chars()))),
            skip_many1(digit()),
        )),
    )))
    .expected("float")
}

pub(crate) fn item<I>() -> impl Parser<Input = I, Output = String>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    lex(item_())
}

fn item_<I>() -> impl Parser<Input = I, Output = String>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    item_literal()
        .or(item_literal_braces())
        .or(item_head()
            .and(many(parser(item_body)))
            .map(|(x, y): (_, Vec<String>)| {
                let mut ret = String::new();
                ret.push(x);
                for s in y {
                    ret.push_str(&s);
                }
                ret
            }))
}

fn item_literal<I>() -> impl Parser<Input = I, Output = String>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    between('\"', '\"', many(none_of("\"".chars())))
}

fn item_literal_braces<I>() -> impl Parser<Input = I, Output = String>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    between('{', '}', many(none_of("}".chars())))
}

fn item_head<I>() -> impl Parser<Input = I, Output = char>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    none_of(" -{}[]\r\n\t".chars())
}

fn item_body<I>(input: &mut I) -> ParseResult<String, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    many1(none_of(" -{}[]\r\n\t".chars()))
        .or(combine::between(char('['), char(']'), parser(item_body)).map(|x| format!("[{}]", x)))
        .parse_stream(input)
}

pub(crate) fn braces<I, O>(
    parser: impl Parser<Input = I, Output = O>,
) -> impl Parser<Input = I, Output = O>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    between('{', '}', parser)
}

pub(crate) fn brackets<I, O>(
    parser: impl Parser<Input = I, Output = O>,
) -> impl Parser<Input = I, Output = O>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    between('[', ']', parser)
}

fn between<I, O>(
    start: char,
    end: char,
    parser: impl Parser<Input = I, Output = O>,
) -> impl Parser<Input = I, Output = O>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    combine::between(lex(char(start)), lex(char(end)), parser)
}

pub(crate) fn lex<I, O>(
    parser: impl Parser<Input = I, Output = O>,
) -> impl Parser<Input = I, Output = O>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    parser
        .and(skip_many(one_of(" \t".chars()).or(
            char('\\').with(char('\n').or(string("\r\n").map(|_| ' '))),
        )))
        .map(|(x, _)| x)
}

pub(crate) fn braces_strings<I>(input: &mut I) -> ParseResult<Vec<String>, I>
where
    I: Stream<Item = char>,
    I::Error: ParseError<I::Item, I::Range, I::Position>,
{
    choice((braces(parser(braces_strings)), many1(item()))).parse_stream(input)
}