openinfer-dsl 0.1.3

Rust-embedded DSL for defining OpenInfer graphs with explicit control flow and memory semantics.
Documentation
use syn::parse::{ParseStream, Result};
use syn::{Ident, LitInt, LitStr, Token};

use crate::parsers::var::parse_indices;
use crate::types::{OpArg, OpAttrValue, OpSetting, VarRef};

pub(crate) fn parse_op_arg(input: ParseStream) -> Result<OpArg> {
    let name: Ident = input.parse()?;
    if input.peek(Token![=]) {
        input.parse::<Token![=]>()?;
        let value = parse_op_attr_value(input)?;
        Ok(OpArg::Setting(OpSetting { name, value }))
    } else if input.peek(syn::token::Bracket) {
        let indices = parse_indices(input)?;
        Ok(OpArg::Input(VarRef { name, indices }))
    } else {
        Ok(OpArg::Input(VarRef {
            name,
            indices: Vec::new(),
        }))
    }
}

pub(crate) fn parse_op_attr_value(input: ParseStream) -> Result<OpAttrValue> {
    if input.peek(syn::token::Bracket) {
        let content;
        syn::bracketed!(content in input);
        let mut values = Vec::new();
        while !content.is_empty() {
            let negative = if content.peek(Token![-]) {
                content.parse::<Token![-]>()?;
                true
            } else {
                false
            };
            let lit: LitInt = content.parse()?;
            let mut value: i64 = lit.base10_parse()?;
            if negative {
                value = -value;
            }
            values.push(value);
            if content.peek(Token![,]) {
                content.parse::<Token![,]>()?;
            }
        }
        return Ok(OpAttrValue::IntList(values));
    }
    let negative = if input.peek(Token![-]) {
        input.parse::<Token![-]>()?;
        true
    } else {
        false
    };

    if input.peek(syn::LitFloat) {
        let lit: syn::LitFloat = input.parse()?;
        let mut value: f64 = lit.base10_parse()?;
        if negative {
            value = -value;
        }
        return Ok(OpAttrValue::Double(value));
    }
    if input.peek(syn::LitBool) {
        let lit: syn::LitBool = input.parse()?;
        if negative {
            return Err(input.error("unexpected '-' before bool literal"));
        }
        return Ok(OpAttrValue::Bool(lit.value));
    }
    if input.peek(LitInt) {
        let lit: LitInt = input.parse()?;
        let mut value: i64 = lit.base10_parse()?;
        if negative {
            value = -value;
        }
        return Ok(OpAttrValue::Int(value));
    }
    if input.peek(LitStr) {
        let lit: LitStr = input.parse()?;
        if negative {
            return Err(input.error("unexpected '-' before string literal"));
        }
        return Ok(OpAttrValue::String(lit.value()));
    }
    if input.peek(Ident) {
        let ident: Ident = input.parse()?;
        if negative {
            return Err(input.error("unexpected '-' before identifier"));
        }
        let name = ident.to_string();
        if name == "true" {
            return Ok(OpAttrValue::Bool(true));
        }
        if name == "false" {
            return Ok(OpAttrValue::Bool(false));
        }
        if name == "inf" {
            return Ok(OpAttrValue::Double(f64::INFINITY));
        }
        return Ok(OpAttrValue::Var(ident));
    }

    Err(input.error("expected literal or identifier for op setting"))
}