dftp 0.1.0

dft instructions parser
Documentation
pub mod types;

use nom::branch::alt;
use nom::bytes::complete::{tag, tag_no_case};
use nom::character::complete::{char, multispace0, space1};
use nom::combinator::map;
use nom::combinator::value;
use nom::multi::many0;
use nom::sequence::{pair, preceded, terminated};

use super::types::*;
use types::*;

pub fn program(input: &str) -> VResult<&str, Program> {
    map(
        pair(statement, many0(preceded(multispace0, statement))),
        |(first, rest): (Statement, Program)| {
            let mut result = vec![first];

            for item in rest {
                result.push(item);
            }

            return result;
        },
    )(input)
}

pub fn statement(input: &str) -> VResult<&str, Statement> {
    map(
        terminated(
            pair(
                directive_component,
                preceded(space1, connector_component_list),
            ),
            char(';'),
        ),
        |(dcomp, clist): (DirectiveComponent, ConnectorComponentList)| Statement {
            directive_component: dcomp,
            connector_components: clist,
        },
    )(input)
}

pub fn directive_component(input: &str) -> VResult<&str, DirectiveComponent> {
    map(
        pair(directive, preceded(space1, field_list)),
        |(dir, flist): (Directive, FieldList)| DirectiveComponent {
            directive: dir,
            fields: flist,
        },
    )(input)
}

pub fn connector_component_list(input: &str) -> VResult<&str, ConnectorComponentList> {
    map(
        pair(
            connector_component,
            many0(preceded(space1, connector_component)),
        ),
        |(first, rest): (ConnectorComponent, ConnectorComponentList)| {
            let mut result = vec![first];

            for item in rest {
                result.push(item);
            }

            return result;
        },
    )(input)
}

pub fn field_list(input: &str) -> VResult<&str, FieldList> {
    map(
        pair(field, many0(preceded(tag(","), field))),
        |(first, rest): (Field, FieldList)| {
            let mut result = vec![first];

            for item in rest {
                result.push(item);
            }

            return result;
        },
    )(input)
}

pub fn field(input: &str) -> VResult<&str, Field> {
    map(textchars1, |result: &str| result.into())(input)
}

pub fn connector_component(input: &str) -> VResult<&str, ConnectorComponent> {
    map(
        pair(connector, preceded(space1, target_component)),
        |(con, tar): (Connector, TargetComponent)| ConnectorComponent {
            connector: con,
            target: tar,
        },
    )(input)
}

pub fn target_component(input: &str) -> VResult<&str, TargetComponent> {
    alt((
        map(format, |result: Format| TargetComponent::Format(result)),
        map(action, |result: Action| TargetComponent::Action(result)),
        map(expression, |result: Expression| {
            TargetComponent::Expression(result)
        }),
        map(data_type, |result: DataType| {
            TargetComponent::DataType(result)
        }),
        map(data_value, |result: DataValue| {
            TargetComponent::DataValue(result)
        }),
    ))(input)
}

pub fn data_value(input: &str) -> VResult<&str, DataValue> {
    alt((
        map(float, |result: Float| DataValue::Float(result)),
        map(integer, |result: Integer| DataValue::Integer(result)),
        map(boolean, |result: Boolean| DataValue::Boolean(result)),
        map(text, |result: Text| DataValue::Text(result)),
    ))(input)
}

pub fn directive(input: &str) -> VResult<&str, Directive> {
    alt((
        value(Directive::SET, tag_no_case("set")),
        value(Directive::ADD, tag_no_case("add")),
        value(Directive::ALIAS, tag_no_case("alias")),
        value(Directive::MERGE, tag_no_case("merge")),
        value(Directive::IGNORE, tag_no_case("ignore")),
        value(Directive::RENAME, tag_no_case("rename")),
        value(Directive::FILTER, tag_no_case("filter")),
        value(Directive::COERCE, tag_no_case("coerce")),
        value(Directive::DISTINCT, tag_no_case("distinct")),
        value(Directive::VALIDATE, tag_no_case("validate")),
    ))(input)
}

pub fn connector(input: &str) -> VResult<&str, Connector> {
    alt((
        value(Connector::OR, tag_no_case("or")),
        value(Connector::TO, tag_no_case("to")),
        value(Connector::TYPED, tag_no_case("typed")),
        value(Connector::RESCUE, tag_no_case("rescue")),
        value(Connector::DEFAULT, tag_no_case("default")),
        value(Connector::MATCHING, tag_no_case("matching")),
    ))(input)
}

pub fn data_type(input: &str) -> VResult<&str, DataType> {
    alt((
        value(DataType::FLOAT, tag_no_case("float")),
        value(DataType::STRING, tag_no_case("string")),
        value(DataType::INTEGER, tag_no_case("integer")),
        value(DataType::BOOLEAN, tag_no_case("boolean")),
    ))(input)
}

pub fn format(input: &str) -> VResult<&str, Format> {
    alt((
        value(Format::URI, tag_no_case("uri")),
        value(Format::UUID, tag_no_case("uuid")),
        value(Format::DATE, tag_no_case("date")),
        value(Format::TIME, tag_no_case("time")),
        value(Format::EMAIL, tag_no_case("email")),
        value(Format::DATETIME, tag_no_case("datetime")),
    ))(input)
}

pub fn action(input: &str) -> VResult<&str, Action> {
    alt((
        value(Action::HALT, tag_no_case("halt")),
        value(Action::NOTIFY, tag_no_case("notify")),
        value(Action::DISCARD, tag_no_case("discard")),
    ))(input)
}

pub fn expression(input: &str) -> VResult<&str, Expression> {
    alt((
        value(Expression::EQUALS, tag_no_case("equals")),
        value(Expression::LESSER, tag_no_case("lesser")),
        value(Expression::DIFFERS, tag_no_case("differs")),
        value(Expression::GREATER, tag_no_case("greater")),
        value(Expression::EQLESSER, tag_no_case("eqlesser")),
        value(Expression::EQGREATER, tag_no_case("eqgreater")),
    ))(input)
}