rsleigh 0.3.0

SLEIGH (.slaspec) parser and Rust decoder/P-code emitter codegen — Ghidra-compatible disassembly in pure Rust
Documentation
use nom::combinator::{cut, map};
use nom::multi::many0;
use nom::sequence::{pair, preceded, terminated, tuple};
use nom::IResult;

use crate::preprocessor::token::Token;
use crate::syntax::parser::{ident, this_ident};
use crate::syntax::BitRangeLsbMsb;
use crate::{SleighError, Span};

use super::TokenFieldAttribute;

#[derive(Clone, Debug)]
pub struct Context {
    pub varnode_name: String,
    pub varnode_span: Span,
    pub fields: Vec<ContextField>,
}

impl Context {
    pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box<SleighError>> {
        map(
            preceded(
                this_ident("context"),
                cut(pair(ident, many0(ContextField::parse))),
            ),
            |((varnode_name, varnode_span), fields)| Context {
                varnode_name,
                varnode_span: varnode_span.clone(),
                fields,
            },
        )(input)
    }
}

#[derive(Clone, Debug)]
pub struct ContextField {
    pub src: Span,
    pub name: String,
    pub range: BitRangeLsbMsb,
    pub attributes: Vec<ContextFieldAttribute>,
}

impl ContextField {
    pub fn parse(input: &[Token]) -> IResult<&[Token], Self, Box<SleighError>> {
        map(
            tuple((
                terminated(ident, tag!("=")),
                BitRangeLsbMsb::parse,
                many0(ContextFieldAttribute::parse),
            )),
            |((name, name_src), range, attributes)| Self {
                src: name_src.clone(),
                name,
                range,
                attributes,
            },
        )(input)
    }
}

#[derive(Clone, Copy, Debug)]
pub enum ContextFieldAttribute {
    Token(TokenFieldAttribute),
    Noflow,
}

impl ContextFieldAttribute {
    pub(crate) fn from_str(name: &str) -> Option<Self> {
        TokenFieldAttribute::from_str(name)
            .map(Self::Token)
            .or(match name {
                "noflow" => Some(Self::Noflow),
                _ => None,
            })
    }
    fn parse(input_ori: &[Token]) -> IResult<&[Token], Self, Box<SleighError>> {
        let (input, (att, location)) = ident(input_ori)?;
        Self::from_str(&att)
            .map(|att| (input, att))
            .ok_or(nom::Err::Error(Box::new(SleighError::StatementInvalid(
                location.clone(),
            ))))
    }
}