summaryrefslogtreecommitdiffstatshomepage
path: root/src/parser.rs
blob: 8f4633ebfcfbcccba41d0191373fecd7668f68cc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use crate::errors::DiceError;
use crate::types::{DiceModifier, DiceRoll, Expression};

mod oneroll {
    include!(concat!(env!("OUT_DIR"), "/oneroll_grammar.rs"));
}

use oneroll::{Grammar, Rule};
use pest::Parser;

pub struct DiceParser;

impl DiceParser {
    pub fn parse_expression(input: &str) -> Result<Expression, DiceError> {
        let pairs = Grammar::parse(Rule::main, input)
            .map_err(|e| DiceError::ParseError(e.to_string()))?;
        
        let pair = pairs.peek().unwrap();
        Self::parse_dice_expr(pair)
    }

    fn parse_dice_expr(pair: pest::iterators::Pair<Rule>) -> Result<Expression, DiceError> {
        match pair.as_rule() {
            Rule::main => {
                // main 规则包含 dice_expr
                let inner = pair.into_inner().next().unwrap();
                Self::parse_dice_expr(inner)
            }
            Rule::dice_expr => {
                let mut pairs = pair.into_inner();
                let mut expr = Self::parse_dice_term(pairs.next().unwrap())?;
                
                while let Some(pair) = pairs.next() {
                    match pair.as_rule() {
                        Rule::op => {
                            let op = pair.as_str();
                            let right = Self::parse_dice_term(pairs.next().unwrap())?;
                            
                            expr = match op {
                                "+" => Expression::Add(Box::new(expr), Box::new(right)),
                                "-" => Expression::Subtract(Box::new(expr), Box::new(right)),
                                "*" => Expression::Multiply(Box::new(expr), Box::new(right)),
                                "/" => Expression::Divide(Box::new(expr), Box::new(right)),
                                "^" => Expression::Power(Box::new(expr), Box::new(right)),
                                _ => return Err(DiceError::ParseError(format!("未知操作符: {}", op))),
                            };
                        }
                        Rule::comment => {
                            let comment = Self::parse_comment(pair)?;
                            if let Some(comment_text) = comment {
                                expr = Expression::WithComment(Box::new(expr), Some(comment_text));
                            }
                        }
                        _ => {}
                    }
                }
                Ok(expr)
            }
            _ => Err(DiceError::ParseError(format!("期望骰子表达式,得到: {:?}", pair.as_rule()))),
        }
    }

    fn parse_dice_term(pair: pest::iterators::Pair<Rule>) -> Result<Expression, DiceError> {
        match pair.as_rule() {
            Rule::dice_term => {
                let inner = pair.into_inner().next().unwrap();
                match inner.as_rule() {
                    Rule::dice_roll => Self::parse_dice_roll(inner),
                    Rule::paren_expr => {
                        let expr = Self::parse_dice_expr(inner.into_inner().next().unwrap())?;
                        Ok(Expression::Paren(Box::new(expr)))
                    }
                    Rule::number => {
                        let num = inner.as_str().parse::<i32>()
                            .map_err(|_| DiceError::ParseError("无效数字".to_string()))?;
                        Ok(Expression::Number(num))
                    }
                    _ => Err(DiceError::ParseError("无效的骰子项".to_string())),
                }
            }
            _ => Err(DiceError::ParseError("期望骰子项".to_string())),
        }
    }

    fn parse_dice_roll(pair: pest::iterators::Pair<Rule>) -> Result<Expression, DiceError> {
        let mut pairs = pair.into_inner();
        let count = pairs.next().unwrap().as_str().parse::<i32>()
            .map_err(|_| DiceError::ParseError("无效的骰子数量".to_string()))?;
        let sides = pairs.next().unwrap().as_str().parse::<i32>()
            .map_err(|_| DiceError::ParseError("无效的骰子面数".to_string()))?;
        
        let mut modifiers = Vec::new();
        if let Some(modifiers_pair) = pairs.next() {
            for modifier_pair in modifiers_pair.into_inner() {
                let modifier = Self::parse_modifier(modifier_pair)?;
                modifiers.push(modifier);
            }
        }
        
        Ok(Expression::DiceRoll(DiceRoll {
            count,
            sides,
            modifiers,
        }))
    }

    fn parse_modifier(pair: pest::iterators::Pair<Rule>) -> Result<DiceModifier, DiceError> {
        match pair.as_rule() {
            Rule::modifier => {
                let inner = pair.into_inner().next().unwrap();
                match inner.as_rule() {
                    Rule::explode => Ok(DiceModifier::Explode),
                    Rule::reroll => {
                        let num = inner.into_inner().next().unwrap().as_str().parse::<i32>()
                            .map_err(|_| DiceError::ParseError("无效的重投数值".to_string()))?;
                        Ok(DiceModifier::Reroll(num))
                    }
                    Rule::reroll_once => {
                        let num = inner.into_inner().next().unwrap().as_str().parse::<i32>()
                            .map_err(|_| DiceError::ParseError("无效的条件重投数值".to_string()))?;
                        Ok(DiceModifier::RerollOnce(num))
                    }
                    Rule::keep_high => {
                        let num = inner.into_inner().next().unwrap().as_str().parse::<i32>()
                            .map_err(|_| DiceError::ParseError("无效的取高数值".to_string()))?;
                        Ok(DiceModifier::KeepHigh(num))
                    }
                    Rule::keep_low => {
                        let num = inner.into_inner().next().unwrap().as_str().parse::<i32>()
                            .map_err(|_| DiceError::ParseError("无效的取低数值".to_string()))?;
                        Ok(DiceModifier::KeepLow(num))
                    }
                    Rule::drop_high => {
                        let num = inner.into_inner().next().unwrap().as_str().parse::<i32>()
                            .map_err(|_| DiceError::ParseError("无效的丢弃高数值".to_string()))?;
                        Ok(DiceModifier::DropHigh(num))
                    }
                    Rule::drop_low => {
                        let num = inner.into_inner().next().unwrap().as_str().parse::<i32>()
                            .map_err(|_| DiceError::ParseError("无效的丢弃低数值".to_string()))?;
                        Ok(DiceModifier::DropLow(num))
                    }
                    _ => Err(DiceError::ParseError("未知的修饰符".to_string())),
                }
            }
            _ => Err(DiceError::ParseError("期望修饰符".to_string())),
        }
    }

    fn parse_comment(pair: pest::iterators::Pair<Rule>) -> Result<Option<String>, DiceError> {
        match pair.as_rule() {
            Rule::comment => {
                let comment = pair.as_str().trim_start_matches('#').trim();
                Ok(if comment.is_empty() { None } else { Some(comment.to_string()) })
            }
            _ => Ok(None),
        }
    }


}