dendi/src/dendi.md

2.3 KiB

Dendi

fn main() {
    println!("Hello, Rust!");
}
use ndm::RollSet;
use std::str::FromStr;

<<sheetentry>>
<<sheetentry-methods>>
<<entryvalue>>
<<entryvalue-fromstr>>
#[derive(Debug, PartialEq, Clone)]
struct SheetEntry {
    description: String,
    display_name: String,
    unique_name: String,
    value: EntryValue,
    value_text: Option<String>,
}

EntryValue

An EntryValue can either be a flat number, a roll formula, a calculated constant (which is just a flat number), not yet calculated, or simply not present.

#[derive(Debug, PartialEq, Clone)]
enum EntryValue {
    Num(i32),
    Roll(RollSet),
    CalculateMe,
    None,
}

Parsing EntryValue

On first pass, parsing an EntryValue is pretty simple. If it parses as a number, it's a Num(i32). Otherwise, if it parses as a RollSet, then that's what it is. Otherwise, it's something special that we'll have to determine later, once all of the other EntryValues have been parsed.

TODO

It's possible that something requiring additional processing will parse as a RollSet, due to ndm's permissive approach to allowing plaintext comments in roll strings. As a result, we should check if the string contains any valid value-reference tokens (with the format $unique_name), and take that as a sign that further work is needed to get at the value.

#[derive(Debug, PartialEq)]
enum EntryValueError {
    NoValue(SheetEntry),
    InvalidFormula(String),
}

impl FromStr for EntryValue {
    type Err = EntryValueError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.is_empty() {
            Ok(Self::None)
        } else if let Ok(n) = s.parse::<i32>() {
            Ok(Self::Num(n))
        } else if let Ok(rs) = s.parse::<RollSet>() {
            Ok(Self::Roll(rs))
        } else {
            Ok(Self::CalculateMe)
        }
    }
}
impl SheetEntry {
    fn evaluate(&self) -> Result<String, EntryValueError> {
        match &self.value {
            EntryValue::Num(n) => Ok(n.to_string()),
            EntryValue::Roll(r) => Ok(r.to_string()),
            EntryValue::None => Err(EntryValueError::NoValue(self.clone())),
            _ => todo!(),
        }
    }
}