Skip to main content

zz_validator/
parser.rs

1use crate::{
2    ast::{Constraint, Constraints, FieldRule, FieldType, Value},
3    token::{Token, tokenize},
4};
5
6/// -----------------------------
7/// Parser
8/// -----------------------------
9pub struct Parser {
10    tokens: Vec<Token>,
11    pos: usize,
12}
13
14impl Parser {
15    pub fn new(tokens: Vec<Token>) -> Self {
16        Self { tokens, pos: 0 }
17    }
18    fn peek(&self) -> Option<&Token> {
19        self.tokens.get(self.pos)
20    }
21    fn next(&mut self) -> Option<Token> {
22        let t = self.tokens.get(self.pos).cloned();
23        self.pos += 1;
24        t
25    }
26    fn expect(&mut self, expected: &Token) -> Result<(), String> {
27        let t = self.next().ok_or("Unexpected EOF")?;
28        if &t != expected {
29            return Err(format!("Expected {:?}, got {:?}", expected, t));
30        }
31        Ok(())
32    }
33
34    // parse_program 修正版
35    pub fn parse_program(&mut self) -> Result<Vec<FieldRule>, String> {
36        self.expect(&Token::LParen)?;
37        let mut rules = Vec::new();
38        loop {
39            if matches!(self.peek(), Some(Token::RParen)) {
40                self.next();
41                break;
42            }
43            let field = self.parse_field(false)?;
44            rules.push(field);
45
46            match self.peek() {
47                Some(Token::Comma) => {
48                    self.next();
49                }
50                Some(Token::RParen) => {}
51                _ => {
52                    return Err("Expected ',' or ')'".into());
53                }
54            }
55        }
56        Ok(rules)
57    }
58
59    pub fn parse_field(&mut self, nameless: bool) -> Result<FieldRule, String> {
60        // -----------------------------
61        // 1️⃣ 字段名 + optional
62        // -----------------------------
63        let (name, optional) = if nameless {
64            (String::new(), false)
65        } else {
66            let name = match self.next() {
67                Some(Token::Ident(s)) => s,
68                t => {
69                    return Err(format!("Expected field name, got {:?}", t));
70                }
71            };
72
73            let optional = matches!(self.peek(), Some(Token::Question));
74            if optional {
75                self.next();
76            }
77
78            (name, optional)
79        };
80
81        if !nameless {
82            self.expect(&Token::Colon)?;
83        }
84
85        // -----------------------------
86        // 2️⃣ 解析 union 类型
87        // -----------------------------
88        let mut union_types = Vec::new();
89        loop {
90            let ty = match self.next() {
91                Some(Token::Ident(s)) => match s.as_str() {
92                    "string" => FieldType::String,
93                    "int" => FieldType::Int,
94                    "float" => FieldType::Float,
95                    "bool" => FieldType::Bool,
96                    "object" => FieldType::Object,
97                    "array" => FieldType::Array,
98                    "email" => FieldType::Email,
99                    "uri" => FieldType::Uri,
100                    "uuid" => FieldType::Uuid,
101                    "ip" => FieldType::Ip,
102                    "mac" => FieldType::Mac,
103                    "date" => FieldType::Date,
104                    "datetime" => FieldType::DateTime,
105                    "time" => FieldType::Time,
106                    "timestamp" => FieldType::Timestamp,
107                    "color" => FieldType::Color,
108                    "hostname" => FieldType::Hostname,
109                    "slug" => FieldType::Slug,
110                    "hex" => FieldType::Hex,
111                    "base64" => FieldType::Base64,
112                    "password" => FieldType::Password,
113                    "token" => FieldType::Token,
114
115                    t => {
116                        return Err(format!("Unknown type {}", t));
117                    }
118                },
119                t => {
120                    return Err(format!("Expected type, got {:?}", t));
121                }
122            };
123
124            union_types.push(ty);
125
126            if matches!(self.peek(), Some(Token::Pipe)) {
127                self.next();
128            } else {
129                break;
130            }
131        }
132
133        let field_type = union_types[0].clone();
134
135        let mut sub_rule = None;
136        let mut children = None;
137        let mut constraints = Vec::new();
138        let mut enum_values = None;
139        let mut default = None;
140        let is_array = field_type == FieldType::Array;
141
142        //
143        // 3️⃣ array<sub_rule>
144        //
145        // 修正版 array 解析,确保 sub_rule 不被丢弃
146        if is_array && matches!(self.peek(), Some(Token::Lt)) {
147            self.next(); // consume '<'
148            // 使用 nameless=true 避免重复解析字段名,但保留 FieldType、constraints 等
149            let sub = self.parse_field(true)?;
150            // 父级 array 的 rule 指向这个子规则
151            sub_rule = Some(Box::new(FieldRule {
152                field: String::new(), // nameless
153                field_type: sub.field_type,
154                required: sub.required,
155                default: sub.default,
156                enum_values: sub.enum_values,
157                union_types: sub.union_types,
158                constraints: sub.constraints,
159                rule: sub.rule,
160                children: sub.children,
161                is_array: sub.is_array,
162            }));
163            self.expect(&Token::Gt)?;
164        }
165
166        //
167        // 4️⃣ object(...)
168        //
169        if field_type == FieldType::Object && matches!(self.peek(), Some(Token::LParen)) {
170            self.next(); // consume '('
171            let mut inner = Vec::new();
172
173            loop {
174                if matches!(self.peek(), Some(Token::RParen)) {
175                    self.next(); // consume ')'
176                    break;
177                }
178
179                inner.push(self.parse_field(false)?);
180
181                match self.peek() {
182                    Some(Token::Comma) => {
183                        self.next();
184                    }
185                    Some(Token::RParen) => {}
186                    _ => {
187                        return Err("Expected ',' or ')' in object".into());
188                    }
189                }
190            }
191
192            children = Some(inner);
193        }
194
195        //
196        // 5️⃣ 约束 / regex / enum / default
197        //
198        loop {
199            match self.peek() {
200                // range
201                Some(Token::LBracket) => {
202                    constraints.push(self.parse_range(&field_type)?);
203                }
204
205                Some(Token::LParen) => {
206                    if field_type == FieldType::Object {
207                        return Err("Unexpected '(' after object definition".into());
208                    }
209                    constraints.push(self.parse_range(&field_type)?);
210                }
211
212                // regex
213                Some(Token::Ident(s)) if s == "regex" => {
214                    self.next();
215                    self.expect(&Token::LParen)?;
216                    let pattern = match self.next() {
217                        Some(Token::Ident(p)) => p,
218                        t => {
219                            return Err(format!("Expected pattern, got {:?}", t));
220                        }
221                    };
222                    self.expect(&Token::RParen)?;
223                    constraints.push(Constraint::Regex(pattern));
224                }
225
226                // enum
227                Some(Token::Ident(s)) if s == "enum" => {
228                    self.next();
229                    self.expect(&Token::LParen)?;
230                    let mut vals = Vec::new();
231
232                    loop {
233                        match self.next() {
234                            Some(Token::Number(s)) => {
235                                // 根据当前的 field_type 转换数字
236                                let v = self
237                                    .parse_token_number_as_type(&Token::Number(s), &field_type)?;
238                                vals.push(v);
239                            }
240                            Some(Token::Ident(v)) => {
241                                // 如果是 bool 类型,特殊处理
242                                if field_type == FieldType::Bool {
243                                    match v.as_str() {
244                                        "true" => vals.push(Value::Bool(true)),
245                                        "false" => vals.push(Value::Bool(false)),
246                                        _ => vals.push(Value::String(v)),
247                                    }
248                                } else {
249                                    vals.push(Value::String(v));
250                                }
251                            }
252                            t => {
253                                return Err(format!("Expected enum value, got {:?}", t));
254                            }
255                        }
256
257                        match self.peek() {
258                            Some(Token::Comma) => {
259                                self.next();
260                            }
261                            Some(Token::RParen) => {
262                                self.next();
263                                break;
264                            }
265                            _ => {
266                                return Err("Expected ',' or ')' in enum".into());
267                            }
268                        }
269                    }
270
271                    enum_values = Some(vals);
272                }
273
274                // default
275                Some(Token::Equal) => {
276                    self.next();
277                    let token = self.next().ok_or("Expected default value")?;
278
279let val = match token {
280                        Token::Number(s) => {
281                            // 关键修正:如果字段是 string,默认值直接存为 Value::String
282                            if field_type == FieldType::String {
283                                Value::String(s)
284                            } else {
285                                // 只有非 string 类型(如 int/float)才走数值解析
286                                self.parse_token_number_as_type(&Token::Number(s), &field_type)?
287                            }
288                        }
289                        Token::Ident(s) => {
290                            if field_type == FieldType::Bool {
291                                match s.as_str() {
292                                    "true" => Value::Bool(true),
293                                    "false" => Value::Bool(false),
294                                    _ => {
295                                        return Err(format!("Invalid bool '{}'", s));
296                                    }
297                                }
298                            } else {
299                                // 字段是 string 时,Ident 也是字符串
300                                Value::String(s)
301                            }
302                        }
303                        t => {
304                            return Err(format!("Unexpected default value {:?}", t));
305                        }
306                    };
307
308                    default = Some(val);
309                }
310
311                _ => {
312                    break;
313                }
314            }
315        }
316
317        Ok(FieldRule {
318            field: name,
319            field_type,
320            required: if nameless { true } else { !optional },
321            default,
322            enum_values,
323            union_types: if union_types.len() > 1 {
324                Some(union_types)
325            } else {
326                None
327            },
328            constraints: if constraints.is_empty() {
329                None
330            } else {
331                Some(Constraints { items: constraints })
332            },
333            rule: sub_rule,
334            children,
335            is_array,
336        })
337    }
338
339    /// 根据 FieldType 解析 Token::Number 为 Value
340    fn parse_token_number_as_type(
341        &self,
342        token: &Token,
343        field_type: &FieldType,
344    ) -> Result<Value, String> {
345        match token {
346            Token::Number(s) => {
347                match field_type {
348                    // 如果目标是 Int,允许输入浮点字符串,先解析为 f64
349                    FieldType::Int => {
350                        if let Ok(i) = s.parse::<i64>() {
351                            Ok(Value::Int(i))
352                        } else if let Ok(f) = s.parse::<f64>() {
353                            // 暂时返回 Float,由 parse_range 进行后续的 ceil/floor 处理
354                            Ok(Value::Float(f))
355                        } else {
356                            Err(format!("Invalid integer '{}'", s))
357                        }
358                    }
359                    FieldType::Float => s
360                        .parse::<f64>()
361                        .map(Value::Float)
362                        .map_err(|_| format!("Invalid float '{}'", s)),
363                    // 如果是 String 类型,Range 通常代表长度,所以也支持数字解析
364                    FieldType::String => s
365                        .parse::<i64>()
366                        .map(Value::Int)
367                        .map_err(|_| format!("Invalid length number '{}'", s)),
368                    _ => Err(format!(
369                        "Range only supports int/float/string, got {:?}",
370                        field_type
371                    )),
372                }
373            }
374            _ => Err("Expected a number token".into()),
375        }
376    }
377
378    /// Range 解析,支持 int/float 并对 int 类型进行向内取整
379    fn parse_range(&mut self, field_type: &FieldType) -> Result<Constraint, String> {
380        let min_inclusive = matches!(self.peek(), Some(Token::LBracket));
381        self.next(); // 消耗 [ 或 (
382
383        let min_token = self.next().ok_or("Expected min number")?;
384        let mut min = self.parse_token_number_as_type(&min_token, field_type)?;
385
386        self.expect(&Token::Comma)?;
387
388        let max_token = self.next().ok_or("Expected max number")?;
389        let mut max = self.parse_token_number_as_type(&max_token, field_type)?;
390
391        // --- 逻辑核心:如果字段是 Int,将边界向内取整 ---
392        if let FieldType::Int = field_type {
393            if let Value::Float(f) = min {
394                min = Value::Int(f.ceil() as i64); // 1.2 -> 2
395            }
396            if let Value::Float(f) = max {
397                max = Value::Int(f.floor() as i64); // 5.8 -> 5
398            }
399        }
400        // ------------------------------------------
401
402        let max_inclusive = match self.next() {
403            Some(Token::RBracket) => true,
404            Some(Token::RParen) => false,
405            t => {
406                return Err(format!("Expected closing bracket or paren, got {:?}", t));
407            }
408        };
409
410        Ok(Constraint::Range {
411            min,
412            max,
413            min_inclusive,
414            max_inclusive,
415        })
416    }
417
418    pub fn parse_rules(input: &str) -> Result<Vec<FieldRule>, String> {
419        let tokens = tokenize(input)?;
420        let mut parser = Parser::new(tokens);
421        parser.parse_program()
422    }
423}