Skip to main content

litex/parse/
parse_obj.rs

1use crate::prelude::*;
2use std::collections::HashMap;
3
4impl Runtime {
5    pub fn parse_obj(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
6        self.parse_obj_hierarchy0(tb)
7    }
8
9    /// Infix `name` (one backtick before the function name) is loosest; then `+-`, `*/%`, `^`, `[]`, `...`, primary.
10    fn parse_obj_hierarchy0(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
11        let left = self.parse_obj_hierarchy1(tb)?;
12        if tb.exceed_end_of_head() {
13            return Ok(left);
14        }
15        if tb.current_token_is_equal_to(INFIX_FN_NAME_SIGN) {
16            tb.skip()?; // consume the infix delimiter, then read the name
17            let fn_name = self.parse_identifier_or_identifier_with_mod(tb)?;
18            let right = self.parse_obj(tb)?;
19
20            if is_key_symbol_or_keyword(&fn_name.to_string()) {
21                return match fn_name.to_string().as_str() {
22                    UNION => Ok(Union::new(left, right).into()),
23                    INTERSECT => Ok(Intersect::new(left, right).into()),
24                    SET_MINUS => Ok(SetMinus::new(left, right).into()),
25                    SET_DIFF => Ok(SetDiff::new(left, right).into()),
26                    RANGE => Ok(Range::new(left, right).into()),
27                    CLOSED_RANGE => Ok(ClosedRange::new(left, right).into()),
28                    PROJ => Ok(Proj::new(left, right).into()),
29                    _ => Err(RuntimeError::from(ParseRuntimeError(
30                        RuntimeErrorStruct::new_with_msg_and_line_file(
31                            format!("{} does not support infix function syntax", fn_name),
32                            tb.line_file.clone(),
33                        ),
34                    ))),
35                };
36            }
37
38            let body = vec![vec![Box::new(left), Box::new(right)]];
39
40            let head = FnObjHead::given_an_atom_return_a_fn_obj_head(fn_name).ok_or_else(|| {
41                RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file("infix (backtick) expects an identifier or single field-access name for the function"
42                        .to_string(), tb.line_file.clone())))
43            })?;
44            Ok(FnObj::new(head, body).into())
45        } else {
46            Ok(left)
47        }
48    }
49
50    /// + - 优先级最低,左结合,可连续 2 + 3 - 4
51    fn parse_obj_hierarchy1(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
52        let mut left = self.parse_obj_hierarchy2(tb)?;
53        loop {
54            if tb.exceed_end_of_head() {
55                return Ok(left);
56            }
57            if tb.current_token_is_equal_to(ADD) {
58                tb.skip()?;
59                let right = self.parse_obj_hierarchy2(tb)?;
60
61                left = Add::new(left, right).into();
62            } else if tb.current_token_is_equal_to(SUB) {
63                tb.skip()?;
64                let right = self.parse_obj_hierarchy2(tb)?;
65                left = Sub::new(left, right).into();
66            } else {
67                return Ok(left);
68            }
69        }
70    }
71
72    /// * / % 高于 + -,左结合
73    fn parse_obj_hierarchy2(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
74        let mut left = self.parse_obj_hierarchy3(tb)?;
75        loop {
76            if tb.exceed_end_of_head() {
77                return Ok(left);
78            }
79            if tb.current_token_is_equal_to(MUL) {
80                tb.skip()?;
81                let right = self.parse_obj_hierarchy3(tb)?;
82                left = Mul::new(left, right).into();
83            } else if tb.current_token_is_equal_to(DIV) {
84                tb.skip()?;
85                let right = self.parse_obj_hierarchy3(tb)?;
86                left = Div::new(left, right).into();
87            } else if tb.current_token_is_equal_to(MOD) {
88                tb.skip()?;
89                let right = self.parse_obj_hierarchy3(tb)?;
90                left = Mod::new(left, right).into();
91            } else if tb.current_token_is_equal_to(MATRIX_SCALAR_MUL) {
92                tb.skip()?;
93                let right = self.parse_obj_hierarchy3(tb)?;
94                left = MatrixScalarMul::new(left, right).into();
95            } else {
96                return Ok(left);
97            }
98        }
99    }
100
101    /// ^ 高于 * / %,右结合:2^3^2 = 2^(3^2)
102    fn parse_obj_hierarchy3(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
103        let left = self.parse_obj_hierarchy4(tb)?;
104        if tb.exceed_end_of_head() {
105            return Ok(left);
106        }
107        if tb.current_token_is_equal_to(POW) {
108            tb.skip()?;
109            let right = self.parse_obj_hierarchy3(tb)?; // 右结合:右侧可继续接 ^
110            Ok(Pow::new(left, right).into())
111        } else if tb.current_token_is_equal_to(MATRIX_POW) {
112            tb.skip()?;
113            let right = self.parse_obj_hierarchy3(tb)?;
114            Ok(MatrixPow::new(left, right).into())
115        } else if tb.current_token_is_equal_to(MATRIX_MUL) {
116            tb.skip()?;
117            let right = self.parse_obj_hierarchy3(tb)?;
118            Ok(MatrixMul::new(left, right).into())
119        } else if tb.current_token_is_equal_to(MATRIX_SUB) {
120            tb.skip()?;
121            let right = self.parse_obj_hierarchy3(tb)?;
122            Ok(MatrixSub::new(left, right).into())
123        } else if tb.current_token_is_equal_to(MATRIX_ADD) {
124            tb.skip()?;
125            let right = self.parse_obj_hierarchy3(tb)?;
126            Ok(MatrixAdd::new(left, right).into())
127        } else {
128            Ok(left)
129        }
130    }
131
132    /// Subscript `[]`, tighter than `^`.
133    fn parse_obj_hierarchy4(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
134        let mut left = self.parse_obj_hierarchy5(tb)?;
135        loop {
136            if tb.current_token_is_equal_to(LEFT_BRACKET) {
137                tb.skip_token(LEFT_BRACKET)?;
138                let obj = self.parse_obj(tb)?;
139                tb.skip_token(RIGHT_BRACKET)?;
140                left = ObjAtIndex::new(left, obj).into();
141            } else {
142                return Ok(left);
143            }
144        }
145    }
146
147    /// Infix closed interval `...` (`closed_range`); same band as `[]`, applied after subscripts.
148    fn parse_obj_hierarchy5(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
149        let left = self.parse_obj_hierarchy6(tb)?;
150
151        if tb.current_token_is_equal_to(DOT_DOT_DOT) {
152            tb.skip_token(DOT_DOT_DOT)?;
153            let right = self.parse_obj_hierarchy1(tb)?;
154            Ok(ClosedRange::new(left, right).into())
155        } else {
156            Ok(left)
157        }
158    }
159
160    /// Primary: `{ }`, `fn`, numbers, `()`, keywords, atoms.
161    fn parse_obj_hierarchy6(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
162        if tb.current_token_is_equal_to(LEFT_CURLY_BRACE) {
163            self.parse_set_builder_or_set_list(tb)
164        } else if tb.current_token_is_equal_to(LEFT_BRACKET) {
165            tb.skip_token(LEFT_BRACKET)?;
166            if tb.current_token_is_equal_to(LEFT_BRACKET) {
167                let mut rows: Vec<Vec<Obj>> = vec![];
168                loop {
169                    tb.skip_token(LEFT_BRACKET)?;
170                    let mut row: Vec<Obj> = vec![];
171                    if !tb.current_token_is_equal_to(RIGHT_BRACKET) {
172                        row.push(self.parse_obj(tb)?);
173                        while tb.current_token_is_equal_to(COMMA) {
174                            tb.skip_token(COMMA)?;
175                            row.push(self.parse_obj(tb)?);
176                        }
177                    }
178                    tb.skip_token(RIGHT_BRACKET)?;
179                    rows.push(row);
180                    if tb.current_token_is_equal_to(COMMA) {
181                        tb.skip_token(COMMA)?;
182                        if !tb.current_token_is_equal_to(LEFT_BRACKET) {
183                            return Err(RuntimeError::from(ParseRuntimeError(
184                                RuntimeErrorStruct::new_with_msg_and_line_file(
185                                    "matrix literal: expected `[` after `,` between rows"
186                                        .to_string(),
187                                    tb.line_file.clone(),
188                                ),
189                            )));
190                        }
191                    } else if tb.current_token_is_equal_to(RIGHT_BRACKET) {
192                        tb.skip_token(RIGHT_BRACKET)?;
193                        return Ok(MatrixListObj::new(rows).into());
194                    } else {
195                        return Err(RuntimeError::from(ParseRuntimeError(
196                            RuntimeErrorStruct::new_with_msg_and_line_file(
197                                "matrix literal: expected `,` or closing `]`".to_string(),
198                                tb.line_file.clone(),
199                            ),
200                        )));
201                    }
202                }
203            } else if tb.current_token_is_equal_to(RIGHT_BRACKET) {
204                tb.skip_token(RIGHT_BRACKET)?;
205                Ok(FiniteSeqListObj::new(vec![]).into())
206            } else {
207                let mut objs = vec![self.parse_obj(tb)?];
208                while tb.current_token_is_equal_to(COMMA) {
209                    tb.skip_token(COMMA)?;
210                    objs.push(self.parse_obj(tb)?);
211                }
212                tb.skip_token(RIGHT_BRACKET)?;
213                Ok(FiniteSeqListObj::new(objs).into())
214            }
215        } else if tb.current_token_is_equal_to(FN_LOWER_CASE) {
216            tb.skip_token(FN_LOWER_CASE)?;
217            Ok(self.parse_fn_set(tb)?.into())
218        } else if tb.current_token_is_equal_to(ANONYMOUS_FN_PREFIX) {
219            let mut result = self.parse_anonymous_fn(tb)?;
220            if let Obj::AnonymousFn(anon) = &result {
221                let mut body_vectors: Vec<Vec<Box<Obj>>> = vec![];
222                while !tb.exceed_end_of_head() && tb.current()? == LEFT_BRACE {
223                    let args = self.parse_braced_objs(tb)?;
224                    let group: Vec<Box<Obj>> = args.into_iter().map(Box::new).collect();
225                    body_vectors.push(group);
226                }
227                if !body_vectors.is_empty() {
228                    let head = FnObjHead::AnonymousFnLiteral(Box::new(anon.clone()));
229                    result = FnObj::new(head, body_vectors).into();
230                }
231            }
232            Ok(result)
233        } else {
234            self.parse_number_or_primary_obj_or_fn_obj_with_minus_prefix(tb)
235        }
236    }
237
238    /// `'` + `(param sets [: dom])` + return set + `{ body }`, or `'` + set + `(names)` + `{ body }`.
239    ///
240    /// After a comma-separated name list, if the next token is `:` (domain facts) rather than a set
241    /// expression, parameters are taken to be in `R` (same as writing `x, y R : ...`).
242    pub fn parse_anonymous_fn(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
243        tb.skip_token(ANONYMOUS_FN_PREFIX)?;
244        if tb.current_token_is_equal_to(LEFT_BRACE) {
245            let built = self.run_in_local_parsing_time_name_scope(|this| {
246                tb.skip_token(LEFT_BRACE)?;
247                let mut params_def_with_set: Vec<ParamGroupWithSet> = vec![];
248                loop {
249                    let param = parse_synthetically_correct_identifier_string(tb)?;
250                    let mut current_params = vec![param];
251
252                    while tb.current_token_is_equal_to(COMMA) {
253                        tb.skip_token(COMMA)?;
254                        current_params.push(parse_synthetically_correct_identifier_string(tb)?);
255                    }
256
257                    this.parsing_free_param_collection.begin_scope(
258                        ParamObjType::FnSet,
259                        &current_params,
260                        tb.line_file.clone(),
261                    )?;
262
263                    let set = if tb.current_token_is_equal_to(COLON) {
264                        StandardSet::R.into()
265                    } else {
266                        this.parse_obj(tb)?
267                    };
268
269                    params_def_with_set.push(ParamGroupWithSet::new(current_params, set));
270
271                    if tb.current_token_is_equal_to(COMMA) {
272                        tb.skip_token(COMMA)?;
273                        continue;
274                    } else if tb.current_token_is_equal_to(COLON) {
275                        break;
276                    } else if tb.current_token_is_equal_to(RIGHT_BRACE) {
277                        break;
278                    } else {
279                        return Err(RuntimeError::from(ParseRuntimeError(
280                            RuntimeErrorStruct::new_with_msg_and_line_file("anonymous fn: expected `,`, `:`, or closing `)` after parameter group"
281                                    .to_string(), tb.line_file.clone()),
282                        )));
283                    }
284                }
285
286                let all_fn_names = ParamGroupWithSet::collect_param_names(&params_def_with_set);
287
288                let mut dom_facts = vec![];
289                if tb.current_token_is_equal_to(COLON) {
290                    tb.skip_token(COLON)?;
291                    let cur = this.parse_or_and_chain_atomic_fact(tb)?;
292                    dom_facts.push(cur);
293                    while tb.current_token_is_equal_to(COMMA) {
294                        tb.skip_token(COMMA)?;
295                        let cur = this.parse_or_and_chain_atomic_fact(tb)?;
296                        dom_facts.push(cur);
297                    }
298                }
299
300                tb.skip_token(RIGHT_BRACE)?;
301                let ret_set_parsed = this.parse_obj(tb)?;
302                tb.skip_token(LEFT_CURLY_BRACE)?;
303                let equal_to = this.parse_obj(tb)?;
304                tb.skip_token(RIGHT_CURLY_BRACE)?;
305                let built =
306                    this.new_anonymous_fn(params_def_with_set, dom_facts, ret_set_parsed, equal_to)?;
307                this.parsing_free_param_collection
308                    .end_scope(ParamObjType::FnSet, &all_fn_names);
309                Ok(built)
310            })?;
311            Ok(built.into())
312        } else {
313            let set_obj = self.parse_and_reclassify_atom_as_free_param_obj(tb)?;
314            let built = self.run_in_local_parsing_time_name_scope(|this| {
315                tb.skip_token(LEFT_BRACE)?;
316                let mut params = vec![parse_synthetically_correct_identifier_string(tb)?];
317                while tb.current_token_is_equal_to(COMMA) {
318                    tb.skip_token(COMMA)?;
319                    params.push(parse_synthetically_correct_identifier_string(tb)?);
320                }
321                tb.skip_token(RIGHT_BRACE)?;
322                let param_group = ParamGroupWithSet::new(params, set_obj.clone());
323                let param_groups = vec![param_group.clone()];
324                let all_names = ParamGroupWithSet::collect_param_names(&param_groups);
325                this.parsing_free_param_collection.begin_scope(
326                    ParamObjType::FnSet,
327                    &all_names,
328                    tb.line_file.clone(),
329                )?;
330                tb.skip_token(LEFT_CURLY_BRACE)?;
331                let equal_to = this.parse_obj(tb)?;
332                tb.skip_token(RIGHT_CURLY_BRACE)?;
333                this.parsing_free_param_collection
334                    .end_scope(ParamObjType::FnSet, &all_names);
335                this.new_anonymous_fn(vec![param_group], vec![], set_obj, equal_to)
336            })?;
337            Ok(built.into())
338        }
339    }
340
341    pub fn parse_fn_set(&mut self, tb: &mut TokenBlock) -> Result<FnSet, RuntimeError> {
342        let fn_set = self.run_in_local_parsing_time_name_scope(|this| {
343            tb.skip_token(LEFT_BRACE)?;
344            let mut params_def_with_set: Vec<ParamGroupWithSet> = vec![];
345            loop {
346                let param = parse_synthetically_correct_identifier_string(tb)?;
347                let mut current_params = vec![param];
348
349                while tb.current_token_is_equal_to(COMMA) {
350                    tb.skip_token(COMMA)?;
351                    current_params.push(parse_synthetically_correct_identifier_string(tb)?);
352                }
353
354                this.parsing_free_param_collection.begin_scope(
355                    ParamObjType::FnSet,
356                    &current_params,
357                    tb.line_file.clone(),
358                )?;
359
360                let set = this.parse_obj(tb)?;
361
362                params_def_with_set.push(ParamGroupWithSet::new(current_params, set));
363
364                if tb.current_token_is_equal_to(COMMA) {
365                    tb.skip_token(COMMA)?;
366                    continue;
367                } else if tb.current_token_is_equal_to(COLON) {
368                    break;
369                } else if tb.current_token_is_equal_to(RIGHT_BRACE) {
370                    break;
371                } else {
372                    return Err(RuntimeError::from(ParseRuntimeError(
373                        RuntimeErrorStruct::new_with_msg_and_line_file(
374                            "Expected comma or colon".to_string(),
375                            tb.line_file.clone(),
376                        ),
377                    )));
378                }
379            }
380
381            let all_fn_names = ParamGroupWithSet::collect_param_names(&params_def_with_set);
382
383            let mut dom_facts = vec![];
384            if tb.current_token_is_equal_to(COLON) {
385                tb.skip_token(COLON)?;
386                let cur = this.parse_or_and_chain_atomic_fact(tb)?;
387                dom_facts.push(cur);
388                while tb.current_token_is_equal_to(COMMA) {
389                    tb.skip_token(COMMA)?;
390                    let cur = this.parse_or_and_chain_atomic_fact(tb)?;
391                    dom_facts.push(cur);
392                }
393            }
394
395            tb.skip_token(RIGHT_BRACE)?;
396            let ret_set_parsed = this.parse_obj(tb)?;
397            let built = this.new_fn_set(params_def_with_set, dom_facts, ret_set_parsed);
398            this.parsing_free_param_collection
399                .end_scope(ParamObjType::FnSet, &all_fn_names);
400            Ok(FnSetOrFnSetClause::FnSet(built?))
401        });
402        match fn_set {
403            Ok(fn_set) => match fn_set {
404                FnSetOrFnSetClause::FnSet(fn_set) => Ok(fn_set),
405                FnSetOrFnSetClause::FnSetClause(_) => {
406                    panic!("FnSetOrFnSetClause::FnSetClause should not be returned");
407                }
408            },
409            Err(e) => Err(e),
410        }
411    }
412
413    pub fn parse_fn_set_clause(
414        &mut self,
415        tb: &mut TokenBlock,
416    ) -> Result<FnSetClause, RuntimeError> {
417        let clause = self.run_in_local_parsing_time_name_scope(|this| {
418            tb.skip_token(LEFT_BRACE)?;
419            let mut params_def_with_set: Vec<ParamGroupWithSet> = vec![];
420            loop {
421                let param = parse_synthetically_correct_identifier_string(tb)?;
422                let mut current_params = vec![param];
423
424                while tb.current_token_is_equal_to(COMMA) {
425                    tb.skip_token(COMMA)?;
426                    current_params.push(parse_synthetically_correct_identifier_string(tb)?);
427                }
428
429                let set = this.parse_obj(tb)?;
430
431                params_def_with_set.push(ParamGroupWithSet::new(current_params, set));
432
433                if tb.current_token_is_equal_to(COMMA) {
434                    tb.skip_token(COMMA)?;
435                    continue;
436                } else if tb.current_token_is_equal_to(COLON) {
437                    break;
438                } else if tb.current_token_is_equal_to(RIGHT_BRACE) {
439                    break;
440                } else {
441                    return Err(RuntimeError::from(ParseRuntimeError(
442                        RuntimeErrorStruct::new_with_msg_and_line_file(
443                            "Expected comma or colon".to_string(),
444                            tb.line_file.clone(),
445                        ),
446                    )));
447                }
448            }
449
450            let all_fn_names = ParamGroupWithSet::collect_param_names(&params_def_with_set);
451            this.parsing_free_param_collection.begin_scope(
452                ParamObjType::FnSet,
453                &all_fn_names,
454                tb.line_file.clone(),
455            )?;
456
457            let mut dom_facts = vec![];
458            if tb.current_token_is_equal_to(COLON) {
459                tb.skip_token(COLON)?;
460                let cur = this.parse_or_and_chain_atomic_fact(tb)?;
461                dom_facts.push(cur);
462                while tb.current_token_is_equal_to(COMMA) {
463                    tb.skip_token(COMMA)?;
464                    let cur = this.parse_or_and_chain_atomic_fact(tb)?;
465                    dom_facts.push(cur);
466                }
467            }
468
469            tb.skip_token(RIGHT_BRACE)?;
470            let ret_set_parsed = this.parse_obj(tb)?;
471            let clause_ok = FnSetClause::new(params_def_with_set, dom_facts, ret_set_parsed);
472            this.parsing_free_param_collection
473                .end_scope(ParamObjType::FnSet, &all_fn_names);
474            Ok(FnSetOrFnSetClause::FnSetClause(clause_ok))
475        });
476        match clause {
477            Ok(clause) => match clause {
478                FnSetOrFnSetClause::FnSetClause(clause) => Ok(clause),
479                FnSetOrFnSetClause::FnSet(_) => {
480                    panic!("FnSetOrFnSetClause::FnSet should not be returned");
481                }
482            },
483            Err(e) => Err(e),
484        }
485    }
486
487    pub fn parse_number_or_primary_obj_or_fn_obj_with_minus_prefix(
488        &mut self,
489        tb: &mut TokenBlock,
490    ) -> Result<Obj, RuntimeError> {
491        if tb.current_token_is_equal_to(SUB) {
492            tb.skip()?;
493            let obj = self.parse_number_or_primary_obj_or_fn_obj(tb)?;
494            Ok(Mul::new(Number::new("-1".to_string()).into(), obj).into())
495        } else {
496            self.parse_number_or_primary_obj_or_fn_obj(tb)
497        }
498    }
499
500    /// 若得到 atom,调用方再给其接若干 (args) 变成 FnObj。
501    fn parse_number_or_primary_obj_or_fn_obj(
502        &mut self,
503        tb: &mut TokenBlock,
504    ) -> Result<Obj, RuntimeError> {
505        let token = tb.current()?;
506
507        // 0. (obj) 或 (obj, obj, ...)
508        if token == LEFT_BRACE {
509            tb.skip()?;
510            let obj = self.parse_obj(tb)?;
511
512            if tb.current_token_is_equal_to(COMMA) {
513                let mut args = vec![obj];
514                while tb.current_token_is_equal_to(COMMA) {
515                    tb.skip_token(COMMA)?;
516
517                    args.push(self.parse_obj(tb)?);
518                }
519                tb.skip_token(RIGHT_BRACE)?;
520                return Ok(Tuple::new(args).into());
521            } else {
522                tb.skip_token(RIGHT_BRACE)?;
523                return Ok(obj);
524            }
525        }
526
527        // 1. 数字
528        if starts_with_digit(token) {
529            let number = tb.advance()?;
530            // 若已经到行尾,则直接检查并返回
531            if tb.exceed_end_of_head() {
532                if !is_number(&number) {
533                    return Err(RuntimeError::from(ParseRuntimeError(
534                        RuntimeErrorStruct::new_with_msg_and_line_file(
535                            format!("Invalid number: {}", number),
536                            tb.line_file.clone(),
537                        ),
538                    )));
539                }
540                return Ok(Number::new(number).into());
541            }
542
543            if tb.current()? == DOT_AKA_FIELD_ACCESS_SIGN {
544                tb.skip()?;
545                let fraction = tb.advance()?;
546                let number = format!("{}{}{}", number, DOT_AKA_FIELD_ACCESS_SIGN, fraction);
547                if !is_number(&number) {
548                    return Err(RuntimeError::from(ParseRuntimeError(
549                        RuntimeErrorStruct::new_with_msg_and_line_file(
550                            format!("Invalid number: {}", number),
551                            tb.line_file.clone(),
552                        ),
553                    )));
554                }
555                return Ok(Number::new(number).into());
556            } else {
557                if !is_number(&number) {
558                    return Err(RuntimeError::from(ParseRuntimeError(
559                        RuntimeErrorStruct::new_with_msg_and_line_file(
560                            format!("Invalid number: {}", number),
561                            tb.line_file.clone(),
562                        ),
563                    )));
564                }
565                return Ok(Number::new(number).into());
566            }
567        }
568
569        // 2. 多元关键字、或 atom(内建 `StandardSet` 名在 reclassify 中处理)
570        let mut result = self.parse_primary_obj(tb)?;
571
572        // 3. 若是 atom,后面可以接多组 (args),每组一个 Vec<Obj>,合起来 body: Vec<Vec<Box<Obj>>>
573        let (head, mut body_vectors) = match &result {
574            Obj::Atom(AtomObj::Identifier(i)) => (FnObjHead::Identifier(i.clone()), vec![]),
575            Obj::Atom(AtomObj::IdentifierWithMod(m)) => {
576                (FnObjHead::IdentifierWithMod(m.clone()), vec![])
577            }
578            Obj::Atom(AtomObj::Forall(p)) => (FnObjHead::Forall(p.clone()), vec![]),
579            Obj::Atom(AtomObj::Exist(p)) => (FnObjHead::Exist(p.clone()), vec![]),
580            Obj::Atom(AtomObj::Def(p)) => (FnObjHead::DefHeader(p.clone()), vec![]),
581            Obj::Atom(AtomObj::SetBuilder(p)) => (FnObjHead::SetBuilder(p.clone()), vec![]),
582            Obj::Atom(AtomObj::FnSet(p)) => (FnObjHead::FnSet(p.clone()), vec![]),
583            Obj::Atom(AtomObj::Induc(p)) => (FnObjHead::Induc(p.clone()), vec![]),
584            Obj::Atom(AtomObj::DefAlgo(p)) => (FnObjHead::DefAlgo(p.clone()), vec![]),
585            Obj::AnonymousFn(anon) => (
586                FnObjHead::AnonymousFnLiteral(Box::new(anon.clone())),
587                vec![],
588            ),
589            _ => return Ok(result),
590        };
591        while !tb.exceed_end_of_head() && tb.current()? == LEFT_BRACE {
592            let args = self.parse_braced_objs(tb)?;
593            let group: Vec<Box<Obj>> = args.into_iter().map(Box::new).collect();
594            body_vectors.push(group);
595        }
596        if !body_vectors.is_empty() {
597            result = FnObj::new(head, body_vectors).into();
598        }
599        Ok(result)
600    }
601
602    /// 解析「主元」:当前 token 必须是多元关键字、或普通标识符 (atom)(内建 `StandardSet` 名走 atom 路径)。
603    fn parse_primary_obj(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
604        let tok = tb.current()?;
605
606        if tok == FAMILY_OBJ_PREFIX {
607            let family = self.parse_family_obj(tb)?;
608            return Ok(Obj::FamilyObj(family));
609        }
610        if tok == ABS {
611            tb.skip()?;
612            tb.skip_token(LEFT_BRACE)?;
613            let arg = self.parse_obj(tb)?;
614            tb.skip_token(RIGHT_BRACE)?;
615            return Ok(Abs::new(arg).into());
616        }
617        if tok == MAX {
618            tb.skip()?;
619            let args = self.parse_braced_objs(tb)?;
620            if args.len() != 2 {
621                return Err(RuntimeError::from(ParseRuntimeError(
622                    RuntimeErrorStruct::new_with_msg_and_line_file(
623                        "max expects 2 arguments".to_string(),
624                        tb.line_file.clone(),
625                    ),
626                )));
627            }
628            let mut it = args.into_iter();
629            let left = it.next().ok_or_else(|| {
630                RuntimeError::from(ParseRuntimeError(
631                    RuntimeErrorStruct::new_with_msg_and_line_file(
632                        "max expects 2 arguments".to_string(),
633                        tb.line_file.clone(),
634                    ),
635                ))
636            })?;
637            let right = it.next().ok_or_else(|| {
638                RuntimeError::from(ParseRuntimeError(
639                    RuntimeErrorStruct::new_with_msg_and_line_file(
640                        "max expects 2 arguments".to_string(),
641                        tb.line_file.clone(),
642                    ),
643                ))
644            })?;
645            return Ok(Max::new(left, right).into());
646        }
647        if tok == MIN {
648            tb.skip()?;
649            let args = self.parse_braced_objs(tb)?;
650            if args.len() != 2 {
651                return Err(RuntimeError::from(ParseRuntimeError(
652                    RuntimeErrorStruct::new_with_msg_and_line_file(
653                        "min expects 2 arguments".to_string(),
654                        tb.line_file.clone(),
655                    ),
656                )));
657            }
658            let mut it = args.into_iter();
659            let left = it.next().ok_or_else(|| {
660                RuntimeError::from(ParseRuntimeError(
661                    RuntimeErrorStruct::new_with_msg_and_line_file(
662                        "min expects 2 arguments".to_string(),
663                        tb.line_file.clone(),
664                    ),
665                ))
666            })?;
667            let right = it.next().ok_or_else(|| {
668                RuntimeError::from(ParseRuntimeError(
669                    RuntimeErrorStruct::new_with_msg_and_line_file(
670                        "min expects 2 arguments".to_string(),
671                        tb.line_file.clone(),
672                    ),
673                ))
674            })?;
675            return Ok(Min::new(left, right).into());
676        }
677        if tok == LOG {
678            tb.skip()?;
679            let args = self.parse_braced_objs(tb)?;
680            if args.len() != 2 {
681                return Err(RuntimeError::from(ParseRuntimeError(
682                    RuntimeErrorStruct::new_with_msg_and_line_file(
683                        "log expects 2 arguments (base, argument)".to_string(),
684                        tb.line_file.clone(),
685                    ),
686                )));
687            }
688            let mut it = args.into_iter();
689            let base = it.next().ok_or_else(|| {
690                RuntimeError::from(ParseRuntimeError(
691                    RuntimeErrorStruct::new_with_msg_and_line_file(
692                        "log expects 2 arguments (base, argument)".to_string(),
693                        tb.line_file.clone(),
694                    ),
695                ))
696            })?;
697            let arg = it.next().ok_or_else(|| {
698                RuntimeError::from(ParseRuntimeError(
699                    RuntimeErrorStruct::new_with_msg_and_line_file(
700                        "log expects 2 arguments (base, argument)".to_string(),
701                        tb.line_file.clone(),
702                    ),
703                ))
704            })?;
705            return Ok(Log::new(base, arg).into());
706        }
707
708        // 多元关键字:吃关键字 + 括号里若干 obj
709        if tok == UNION {
710            tb.skip()?;
711            let args = self.parse_braced_objs(tb)?;
712            if args.len() != 2 {
713                return Err(RuntimeError::from(ParseRuntimeError(
714                    RuntimeErrorStruct::new_with_msg_and_line_file(
715                        "union expects 2 arguments".to_string(),
716                        tb.line_file.clone(),
717                    ),
718                )));
719            }
720            let mut it = args.into_iter();
721            let left = it.next().ok_or_else(|| {
722                RuntimeError::from(ParseRuntimeError(
723                    RuntimeErrorStruct::new_with_msg_and_line_file(
724                        "union expects 2 arguments".to_string(),
725                        tb.line_file.clone(),
726                    ),
727                ))
728            })?;
729            let right = it.next().ok_or_else(|| {
730                RuntimeError::from(ParseRuntimeError(
731                    RuntimeErrorStruct::new_with_msg_and_line_file(
732                        "union expects 2 arguments".to_string(),
733                        tb.line_file.clone(),
734                    ),
735                ))
736            })?;
737            return Ok(Union::new(left, right).into());
738        }
739        if tok == INTERSECT {
740            tb.skip()?;
741            let args = self.parse_braced_objs(tb)?;
742            if args.len() != 2 {
743                return Err(RuntimeError::from(ParseRuntimeError(
744                    RuntimeErrorStruct::new_with_msg_and_line_file(
745                        "intersect expects 2 arguments".to_string(),
746                        tb.line_file.clone(),
747                    ),
748                )));
749            }
750            let mut it = args.into_iter();
751            let left = it.next().ok_or_else(|| {
752                RuntimeError::from(ParseRuntimeError(
753                    RuntimeErrorStruct::new_with_msg_and_line_file(
754                        "intersect expects 2 arguments".to_string(),
755                        tb.line_file.clone(),
756                    ),
757                ))
758            })?;
759            let right = it.next().ok_or_else(|| {
760                RuntimeError::from(ParseRuntimeError(
761                    RuntimeErrorStruct::new_with_msg_and_line_file(
762                        "intersect expects 2 arguments".to_string(),
763                        tb.line_file.clone(),
764                    ),
765                ))
766            })?;
767            return Ok(Intersect::new(left, right).into());
768        }
769        if tok == SET_MINUS {
770            tb.skip()?;
771            let args = self.parse_braced_objs(tb)?;
772            if args.len() != 2 {
773                return Err(RuntimeError::from(ParseRuntimeError(
774                    RuntimeErrorStruct::new_with_msg_and_line_file(
775                        "set_minus expects 2 arguments".to_string(),
776                        tb.line_file.clone(),
777                    ),
778                )));
779            }
780            let mut it = args.into_iter();
781            let left = it.next().ok_or_else(|| {
782                RuntimeError::from(ParseRuntimeError(
783                    RuntimeErrorStruct::new_with_msg_and_line_file(
784                        "set_minus expects 2 arguments".to_string(),
785                        tb.line_file.clone(),
786                    ),
787                ))
788            })?;
789            let right = it.next().ok_or_else(|| {
790                RuntimeError::from(ParseRuntimeError(
791                    RuntimeErrorStruct::new_with_msg_and_line_file(
792                        "set_minus expects 2 arguments".to_string(),
793                        tb.line_file.clone(),
794                    ),
795                ))
796            })?;
797            return Ok(SetMinus::new(left, right).into());
798        }
799        if tok == SET_DIFF {
800            tb.skip()?;
801            let args = self.parse_braced_objs(tb)?;
802            if args.len() != 2 {
803                return Err(RuntimeError::from(ParseRuntimeError(
804                    RuntimeErrorStruct::new_with_msg_and_line_file(
805                        "disjoint_union expects 2 arguments".to_string(),
806                        tb.line_file.clone(),
807                    ),
808                )));
809            }
810            let mut it = args.into_iter();
811            let left = it.next().ok_or_else(|| {
812                RuntimeError::from(ParseRuntimeError(
813                    RuntimeErrorStruct::new_with_msg_and_line_file(
814                        "disjoint_union expects 2 arguments".to_string(),
815                        tb.line_file.clone(),
816                    ),
817                ))
818            })?;
819            let right = it.next().ok_or_else(|| {
820                RuntimeError::from(ParseRuntimeError(
821                    RuntimeErrorStruct::new_with_msg_and_line_file(
822                        "disjoint_union expects 2 arguments".to_string(),
823                        tb.line_file.clone(),
824                    ),
825                ))
826            })?;
827            return Ok(SetDiff::new(left, right).into());
828        }
829        if tok == CAP {
830            tb.skip()?;
831            let args = self.parse_braced_objs(tb)?;
832            if args.len() != 1 {
833                return Err(RuntimeError::from(ParseRuntimeError(
834                    RuntimeErrorStruct::new_with_msg_and_line_file(
835                        "cap expects 1 argument".to_string(),
836                        tb.line_file.clone(),
837                    ),
838                )));
839            }
840            let mut it = args.into_iter();
841            let value = it.next().ok_or_else(|| {
842                RuntimeError::from(ParseRuntimeError(
843                    RuntimeErrorStruct::new_with_msg_and_line_file(
844                        "cap expects 1 argument".to_string(),
845                        tb.line_file.clone(),
846                    ),
847                ))
848            })?;
849            return Ok(Cap::new(value).into());
850        }
851        if tok == CUP {
852            tb.skip()?;
853            let args = self.parse_braced_objs(tb)?;
854            if args.len() != 1 {
855                return Err(RuntimeError::from(ParseRuntimeError(
856                    RuntimeErrorStruct::new_with_msg_and_line_file(
857                        "cup expects 1 argument".to_string(),
858                        tb.line_file.clone(),
859                    ),
860                )));
861            }
862            let mut it = args.into_iter();
863            let value = it.next().ok_or_else(|| {
864                RuntimeError::from(ParseRuntimeError(
865                    RuntimeErrorStruct::new_with_msg_and_line_file(
866                        "cup expects 1 argument".to_string(),
867                        tb.line_file.clone(),
868                    ),
869                ))
870            })?;
871            return Ok(Cup::new(value).into());
872        }
873        if tok == CHOOSE {
874            tb.skip()?;
875            let args = self.parse_braced_objs(tb)?;
876            if args.len() != 1 {
877                return Err(RuntimeError::from(ParseRuntimeError(
878                    RuntimeErrorStruct::new_with_msg_and_line_file(
879                        "choice expects 1 argument".to_string(),
880                        tb.line_file.clone(),
881                    ),
882                )));
883            }
884            let mut it = args.into_iter();
885            let value = it.next().ok_or_else(|| {
886                RuntimeError::from(ParseRuntimeError(
887                    RuntimeErrorStruct::new_with_msg_and_line_file(
888                        "choice expects 1 argument".to_string(),
889                        tb.line_file.clone(),
890                    ),
891                ))
892            })?;
893            return Ok(Choose::new(value).into());
894        }
895        if tok == PROJ {
896            tb.skip()?;
897            let args = self.parse_braced_objs(tb)?;
898            if args.len() != 2 {
899                return Err(RuntimeError::from(ParseRuntimeError(
900                    RuntimeErrorStruct::new_with_msg_and_line_file(
901                        "proj expects 2 arguments".to_string(),
902                        tb.line_file.clone(),
903                    ),
904                )));
905            }
906            let mut it = args.into_iter();
907            let left = it.next().ok_or_else(|| {
908                RuntimeError::from(ParseRuntimeError(
909                    RuntimeErrorStruct::new_with_msg_and_line_file(
910                        "proj expects 2 arguments".to_string(),
911                        tb.line_file.clone(),
912                    ),
913                ))
914            })?;
915            let right = it.next().ok_or_else(|| {
916                RuntimeError::from(ParseRuntimeError(
917                    RuntimeErrorStruct::new_with_msg_and_line_file(
918                        "proj expects 2 arguments".to_string(),
919                        tb.line_file.clone(),
920                    ),
921                ))
922            })?;
923            return Ok(Proj::new(left, right).into());
924        }
925        if tok == RANGE {
926            tb.skip()?;
927            let args = self.parse_braced_objs(tb)?;
928            if args.len() != 2 {
929                return Err(RuntimeError::from(ParseRuntimeError(
930                    RuntimeErrorStruct::new_with_msg_and_line_file(
931                        "range expects 2 arguments".to_string(),
932                        tb.line_file.clone(),
933                    ),
934                )));
935            }
936            let mut it = args.into_iter();
937            let left = it.next().ok_or_else(|| {
938                RuntimeError::from(ParseRuntimeError(
939                    RuntimeErrorStruct::new_with_msg_and_line_file(
940                        "range expects 2 arguments".to_string(),
941                        tb.line_file.clone(),
942                    ),
943                ))
944            })?;
945            let right = it.next().ok_or_else(|| {
946                RuntimeError::from(ParseRuntimeError(
947                    RuntimeErrorStruct::new_with_msg_and_line_file(
948                        "range expects 2 arguments".to_string(),
949                        tb.line_file.clone(),
950                    ),
951                ))
952            })?;
953            return Ok(Range::new(left, right).into());
954        }
955        if tok == CLOSED_RANGE {
956            tb.skip()?;
957            let args = self.parse_braced_objs(tb)?;
958            if args.len() != 2 {
959                return Err(RuntimeError::from(ParseRuntimeError(
960                    RuntimeErrorStruct::new_with_msg_and_line_file(
961                        "closed_range expects 2 arguments".to_string(),
962                        tb.line_file.clone(),
963                    ),
964                )));
965            }
966            let mut it = args.into_iter();
967            let left = it.next().ok_or_else(|| {
968                RuntimeError::from(ParseRuntimeError(
969                    RuntimeErrorStruct::new_with_msg_and_line_file(
970                        "closed_range expects 2 arguments".to_string(),
971                        tb.line_file.clone(),
972                    ),
973                ))
974            })?;
975            let right = it.next().ok_or_else(|| {
976                RuntimeError::from(ParseRuntimeError(
977                    RuntimeErrorStruct::new_with_msg_and_line_file(
978                        "closed_range expects 2 arguments".to_string(),
979                        tb.line_file.clone(),
980                    ),
981                ))
982            })?;
983            return Ok(ClosedRange::new(left, right).into());
984        }
985        if tok == FINITE_SEQ {
986            tb.skip()?;
987            let args = self.parse_braced_objs(tb)?;
988            if args.len() != 2 {
989                return Err(RuntimeError::from(ParseRuntimeError(
990                    RuntimeErrorStruct::new_with_msg_and_line_file(
991                        "finite_seq expects 2 arguments".to_string(),
992                        tb.line_file.clone(),
993                    ),
994                )));
995            }
996            let mut it = args.into_iter();
997            let set = it.next().ok_or_else(|| {
998                RuntimeError::from(ParseRuntimeError(
999                    RuntimeErrorStruct::new_with_msg_and_line_file(
1000                        "finite_seq expects 2 arguments".to_string(),
1001                        tb.line_file.clone(),
1002                    ),
1003                ))
1004            })?;
1005            let n = it.next().ok_or_else(|| {
1006                RuntimeError::from(ParseRuntimeError(
1007                    RuntimeErrorStruct::new_with_msg_and_line_file(
1008                        "finite_seq expects 2 arguments".to_string(),
1009                        tb.line_file.clone(),
1010                    ),
1011                ))
1012            })?;
1013            return Ok(FiniteSeqSet::new(set, n).into());
1014        }
1015        if tok == SEQ {
1016            tb.skip()?;
1017            let args = self.parse_braced_objs(tb)?;
1018            if args.len() != 1 {
1019                return Err(RuntimeError::from(ParseRuntimeError(
1020                    RuntimeErrorStruct::new_with_msg_and_line_file(
1021                        "seq expects 1 argument".to_string(),
1022                        tb.line_file.clone(),
1023                    ),
1024                )));
1025            }
1026            let set = args.into_iter().next().ok_or_else(|| {
1027                RuntimeError::from(ParseRuntimeError(
1028                    RuntimeErrorStruct::new_with_msg_and_line_file(
1029                        "seq expects 1 argument".to_string(),
1030                        tb.line_file.clone(),
1031                    ),
1032                ))
1033            })?;
1034            return Ok(SeqSet::new(set).into());
1035        }
1036        if tok == MATRIX {
1037            tb.skip()?;
1038            let args = self.parse_braced_objs(tb)?;
1039            if args.len() != 3 {
1040                return Err(RuntimeError::from(ParseRuntimeError(
1041                    RuntimeErrorStruct::new_with_msg_and_line_file(
1042                        "matrix expects 3 arguments".to_string(),
1043                        tb.line_file.clone(),
1044                    ),
1045                )));
1046            }
1047            let mut it = args.into_iter();
1048            let set = it.next().ok_or_else(|| {
1049                RuntimeError::from(ParseRuntimeError(
1050                    RuntimeErrorStruct::new_with_msg_and_line_file(
1051                        "matrix expects 3 arguments".to_string(),
1052                        tb.line_file.clone(),
1053                    ),
1054                ))
1055            })?;
1056            let row_len = it.next().ok_or_else(|| {
1057                RuntimeError::from(ParseRuntimeError(
1058                    RuntimeErrorStruct::new_with_msg_and_line_file(
1059                        "matrix expects 3 arguments".to_string(),
1060                        tb.line_file.clone(),
1061                    ),
1062                ))
1063            })?;
1064            let col_len = it.next().ok_or_else(|| {
1065                RuntimeError::from(ParseRuntimeError(
1066                    RuntimeErrorStruct::new_with_msg_and_line_file(
1067                        "matrix expects 3 arguments".to_string(),
1068                        tb.line_file.clone(),
1069                    ),
1070                ))
1071            })?;
1072            return Ok(MatrixSet::new(set, row_len, col_len).into());
1073        }
1074
1075        if tok == CUP {
1076            tb.skip()?;
1077            let args = self.parse_braced_objs(tb)?;
1078            if args.len() != 1 {
1079                return Err(RuntimeError::from(ParseRuntimeError(
1080                    RuntimeErrorStruct::new_with_msg_and_line_file(
1081                        "cup expects 1 argument".to_string(),
1082                        tb.line_file.clone(),
1083                    ),
1084                )));
1085            }
1086            let mut it = args.into_iter();
1087            let value = it.next().ok_or_else(|| {
1088                RuntimeError::from(ParseRuntimeError(
1089                    RuntimeErrorStruct::new_with_msg_and_line_file(
1090                        "cup expects 1 argument".to_string(),
1091                        tb.line_file.clone(),
1092                    ),
1093                ))
1094            })?;
1095            return Ok(Cup::new(value).into());
1096        }
1097        if tok == POWER_SET {
1098            tb.skip()?;
1099            let args = self.parse_braced_objs(tb)?;
1100            if args.len() != 1 {
1101                return Err(RuntimeError::from(ParseRuntimeError(
1102                    RuntimeErrorStruct::new_with_msg_and_line_file(
1103                        "power_set expects 1 argument".to_string(),
1104                        tb.line_file.clone(),
1105                    ),
1106                )));
1107            }
1108            let mut it = args.into_iter();
1109            let value = it.next().ok_or_else(|| {
1110                RuntimeError::from(ParseRuntimeError(
1111                    RuntimeErrorStruct::new_with_msg_and_line_file(
1112                        "power_set expects 1 argument".to_string(),
1113                        tb.line_file.clone(),
1114                    ),
1115                ))
1116            })?;
1117            return Ok(PowerSet::new(value).into());
1118        }
1119        if tok == CART_DIM {
1120            tb.skip()?;
1121            let args = self.parse_braced_objs(tb)?;
1122            if args.len() != 1 {
1123                return Err(RuntimeError::from(ParseRuntimeError(
1124                    RuntimeErrorStruct::new_with_msg_and_line_file(
1125                        "set_dim expects 1 argument".to_string(),
1126                        tb.line_file.clone(),
1127                    ),
1128                )));
1129            }
1130            let mut it = args.into_iter();
1131            let value = it.next().ok_or_else(|| {
1132                RuntimeError::from(ParseRuntimeError(
1133                    RuntimeErrorStruct::new_with_msg_and_line_file(
1134                        "set_dim expects 1 argument".to_string(),
1135                        tb.line_file.clone(),
1136                    ),
1137                ))
1138            })?;
1139            return Ok(CartDim::new(value).into());
1140        }
1141        if tok == COUNT {
1142            tb.skip()?;
1143            let args = self.parse_braced_objs(tb)?;
1144            if args.len() != 1 {
1145                return Err(RuntimeError::from(ParseRuntimeError(
1146                    RuntimeErrorStruct::new_with_msg_and_line_file(
1147                        "count expects 1 argument".to_string(),
1148                        tb.line_file.clone(),
1149                    ),
1150                )));
1151            }
1152            let mut it = args.into_iter();
1153            let value = it.next().ok_or_else(|| {
1154                RuntimeError::from(ParseRuntimeError(
1155                    RuntimeErrorStruct::new_with_msg_and_line_file(
1156                        "count expects 1 argument".to_string(),
1157                        tb.line_file.clone(),
1158                    ),
1159                ))
1160            })?;
1161            return Ok(Count::new(value).into());
1162        }
1163        if tok == SUM {
1164            tb.skip()?;
1165            let args = self.parse_braced_objs(tb)?;
1166            if args.len() != 3 {
1167                return Err(RuntimeError::from(ParseRuntimeError(
1168                    RuntimeErrorStruct::new_with_msg_and_line_file(
1169                        "sum expects 3 arguments (start, end, function)".to_string(),
1170                        tb.line_file.clone(),
1171                    ),
1172                )));
1173            }
1174            let mut it = args.into_iter();
1175            let start = it.next().ok_or_else(|| {
1176                RuntimeError::from(ParseRuntimeError(
1177                    RuntimeErrorStruct::new_with_msg_and_line_file(
1178                        "sum expects 3 arguments (start, end, function)".to_string(),
1179                        tb.line_file.clone(),
1180                    ),
1181                ))
1182            })?;
1183            let end = it.next().ok_or_else(|| {
1184                RuntimeError::from(ParseRuntimeError(
1185                    RuntimeErrorStruct::new_with_msg_and_line_file(
1186                        "sum expects 3 arguments (start, end, function)".to_string(),
1187                        tb.line_file.clone(),
1188                    ),
1189                ))
1190            })?;
1191            let func = it.next().ok_or_else(|| {
1192                RuntimeError::from(ParseRuntimeError(
1193                    RuntimeErrorStruct::new_with_msg_and_line_file(
1194                        "sum expects 3 arguments (start, end, function)".to_string(),
1195                        tb.line_file.clone(),
1196                    ),
1197                ))
1198            })?;
1199            return Ok(Sum::new(start, end, func).into());
1200        }
1201        if tok == PRODUCT {
1202            tb.skip()?;
1203            let args = self.parse_braced_objs(tb)?;
1204            if args.len() != 3 {
1205                return Err(RuntimeError::from(ParseRuntimeError(
1206                    RuntimeErrorStruct::new_with_msg_and_line_file(
1207                        "product expects 3 arguments (start, end, function)".to_string(),
1208                        tb.line_file.clone(),
1209                    ),
1210                )));
1211            }
1212            let mut it = args.into_iter();
1213            let start = it.next().ok_or_else(|| {
1214                RuntimeError::from(ParseRuntimeError(
1215                    RuntimeErrorStruct::new_with_msg_and_line_file(
1216                        "product expects 3 arguments (start, end, function)".to_string(),
1217                        tb.line_file.clone(),
1218                    ),
1219                ))
1220            })?;
1221            let end = it.next().ok_or_else(|| {
1222                RuntimeError::from(ParseRuntimeError(
1223                    RuntimeErrorStruct::new_with_msg_and_line_file(
1224                        "product expects 3 arguments (start, end, function)".to_string(),
1225                        tb.line_file.clone(),
1226                    ),
1227                ))
1228            })?;
1229            let func = it.next().ok_or_else(|| {
1230                RuntimeError::from(ParseRuntimeError(
1231                    RuntimeErrorStruct::new_with_msg_and_line_file(
1232                        "product expects 3 arguments (start, end, function)".to_string(),
1233                        tb.line_file.clone(),
1234                    ),
1235                ))
1236            })?;
1237            return Ok(Product::new(start, end, func).into());
1238        }
1239        if tok == CART {
1240            tb.skip()?;
1241            let args = self.parse_braced_objs(tb)?;
1242            if args.len() < 2 {
1243                return Err(RuntimeError::from(ParseRuntimeError(
1244                    RuntimeErrorStruct::new_with_msg_and_line_file(
1245                        "cart expects at least 2 arguments".to_string(),
1246                        tb.line_file.clone(),
1247                    ),
1248                )));
1249            }
1250            return Ok(Cart::new(args).into());
1251        }
1252
1253        if tok == TUPLE_DIM {
1254            tb.skip()?;
1255            let args = self.parse_braced_obj(tb)?;
1256            return Ok(TupleDim::new(args).into());
1257        }
1258
1259        if tok == CART_DIM {
1260            tb.skip()?;
1261            let args = self.parse_braced_obj(tb)?;
1262            return Ok(CartDim::new(args).into());
1263        }
1264
1265        // Bare `ident` or `mod::ident`: built-in single-token `StandardSet` names, else free params.
1266        self.parse_and_reclassify_atom_as_free_param_obj(tb)
1267    }
1268
1269    // parse_identifier_or_identifier_with_mod + reclassify (std sets + free params).
1270    fn parse_and_reclassify_atom_as_free_param_obj(
1271        &mut self,
1272        tb: &mut TokenBlock,
1273    ) -> Result<Obj, RuntimeError> {
1274        let atom = self.parse_identifier_or_identifier_with_mod(tb)?;
1275        self.reclassify_atom_as_free_param_obj(atom)
1276    }
1277
1278    fn reclassify_atom_as_free_param_obj(&self, obj: Obj) -> Result<Obj, RuntimeError> {
1279        match obj {
1280            Obj::Atom(AtomObj::Identifier(id)) => {
1281                if let Some(standard) = standard_set_from_bare_identifier_name(&id.name) {
1282                    return Ok(standard);
1283                }
1284                Ok(self
1285                    .parsing_free_param_collection
1286                    .resolve_identifier_to_free_param_obj(&id.name))
1287            }
1288            Obj::Atom(AtomObj::IdentifierWithMod(m)) => {
1289                Ok(Obj::Atom(AtomObj::IdentifierWithMod(m)))
1290            }
1291            _ => Err(RuntimeError::from(ParseRuntimeError(
1292                RuntimeErrorStruct::new_with_just_msg(
1293                    "internal: atom position was not a name form".to_string(),
1294                ),
1295            ))),
1296        }
1297    }
1298
1299    pub fn parse_braced_objs(&mut self, tb: &mut TokenBlock) -> Result<Vec<Obj>, RuntimeError> {
1300        tb.skip_token(LEFT_BRACE)?;
1301        if tb.current_token_is_equal_to(RIGHT_BRACE) {
1302            tb.skip_token(RIGHT_BRACE)?;
1303            return Ok(vec![]);
1304        }
1305        let mut objs = vec![self.parse_obj(tb)?];
1306        while tb.current_token_is_equal_to(COMMA) {
1307            tb.skip_token(COMMA)?;
1308            objs.push(self.parse_obj(tb)?);
1309        }
1310        tb.skip_token(RIGHT_BRACE)?;
1311        Ok(objs)
1312    }
1313
1314    pub fn parse_braced_obj(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
1315        let mut parsed_args = self.parse_braced_objs(tb)?;
1316        if parsed_args.len() != 1 {
1317            return Err(RuntimeError::from(ParseRuntimeError(
1318                RuntimeErrorStruct::new_with_msg_and_line_file(
1319                    "expected exactly 1 argument".to_string(),
1320                    tb.line_file.clone(),
1321                ),
1322            )));
1323        }
1324        let parsed_obj = parsed_args.remove(0);
1325        Ok(parsed_obj)
1326    }
1327
1328    /// 解析逗号分隔的 obj 列表,直到遇到非 COMMA 的 token(如 COLON)。
1329    pub fn parse_obj_list(&mut self, tb: &mut TokenBlock) -> Result<Vec<Obj>, RuntimeError> {
1330        let mut objs = vec![self.parse_obj(tb)?];
1331        while tb.current_token_is_equal_to(COMMA) {
1332            tb.skip_token(COMMA)?;
1333            objs.push(self.parse_obj(tb)?);
1334        }
1335        Ok(objs)
1336    }
1337
1338    fn parse_set_builder_or_set_list(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
1339        tb.skip_token(LEFT_CURLY_BRACE)?;
1340        if tb.current_token_is_equal_to(RIGHT_CURLY_BRACE) {
1341            tb.skip_token(RIGHT_CURLY_BRACE)?;
1342            return Ok(ListSet::new(vec![]).into());
1343        }
1344
1345        let left = self.parse_obj(tb)?;
1346        // Plain identifiers and parsing-time free-param atoms (e.g. forall-bound `x`) must both
1347        // allow `{ x S : ... }` set-builder syntax; only `Identifier` was handled originally.
1348        let name_for_set_builder = match &left {
1349            Obj::Atom(AtomObj::Identifier(a)) => Some(a.name.as_str()),
1350            Obj::Atom(AtomObj::IdentifierWithMod(m)) => Some(m.name.as_str()),
1351            Obj::Atom(AtomObj::Forall(p)) => Some(p.name.as_str()),
1352            Obj::Atom(AtomObj::Def(p)) => Some(p.name.as_str()),
1353            Obj::Atom(AtomObj::Exist(p)) => Some(p.name.as_str()),
1354            Obj::Atom(AtomObj::SetBuilder(p)) => Some(p.name.as_str()),
1355            Obj::Atom(AtomObj::FnSet(p)) => Some(p.name.as_str()),
1356            Obj::Atom(AtomObj::Induc(p)) => Some(p.name.as_str()),
1357            Obj::Atom(AtomObj::DefAlgo(p)) => Some(p.name.as_str()),
1358            _ => None,
1359        };
1360        if let Some(name) = name_for_set_builder {
1361            if tb.current_token_is_equal_to(COMMA) || tb.current()? == RIGHT_CURLY_BRACE {
1362                self.parse_list_set_obj_with_leftmost_obj(tb, left)
1363            } else {
1364                self.parse_set_builder(tb, Identifier::new(name.to_string()))
1365            }
1366        } else {
1367            self.parse_list_set_obj_with_leftmost_obj(tb, left)
1368        }
1369    }
1370
1371    /// Parse set builder or list set after the first identifier; wraps body in a name block for the bound variable.
1372    fn parse_set_builder(
1373        &mut self,
1374        tb: &mut TokenBlock,
1375        a: Identifier,
1376    ) -> Result<Obj, RuntimeError> {
1377        self.run_in_local_parsing_time_name_scope(|this| {
1378            let set_builder_param = [a.name.clone()];
1379            this.parsing_free_param_collection.begin_scope(
1380                ParamObjType::SetBuilder,
1381                &set_builder_param,
1382                tb.line_file.clone(),
1383            )?;
1384            let parsed = (|| -> Result<Obj, RuntimeError> {
1385                let second = this.parse_obj(tb)?;
1386                if tb.current()? == COLON {
1387                    tb.skip_token(COLON)?;
1388
1389                    let user_names = vec![a.name.clone()];
1390                    this.validate_user_fn_param_names_for_parse(&user_names, tb.line_file.clone())?;
1391                    let empty: HashMap<String, Obj> = HashMap::new();
1392                    let second_inst = this.inst_obj(&second, &empty, ParamObjType::SetBuilder)?;
1393
1394                    let mut facts_inst = Vec::new();
1395                    while tb.current()? != RIGHT_CURLY_BRACE {
1396                        let f = this.parse_or_and_chain_atomic_fact(tb)?;
1397                        facts_inst.push(this.inst_or_and_chain_atomic_fact(
1398                            &f,
1399                            &empty,
1400                            ParamObjType::SetBuilder,
1401                            None,
1402                        )?);
1403                    }
1404                    tb.skip_token(RIGHT_CURLY_BRACE)?;
1405
1406                    Ok(SetBuilder::new(a.name.clone(), second_inst, facts_inst)?.into())
1407                } else {
1408                    Err(RuntimeError::from(ParseRuntimeError(
1409                        RuntimeErrorStruct::new_with_msg_and_line_file(
1410                            "expected colon after first argument".to_string(),
1411                            tb.line_file.clone(),
1412                        ),
1413                    )))
1414                }
1415            })();
1416            this.parsing_free_param_collection
1417                .end_scope(ParamObjType::SetBuilder, &set_builder_param);
1418            parsed
1419        })
1420    }
1421
1422    /// ListSet: { a b c } 或 { 1, 0, 2 };遇逗号先 skip 再解析下一项
1423    fn parse_list_set_obj_with_leftmost_obj(
1424        &mut self,
1425        tb: &mut TokenBlock,
1426        left_most_obj: Obj,
1427    ) -> Result<Obj, RuntimeError> {
1428        let mut objs = vec![left_most_obj];
1429        while tb.current()? != RIGHT_CURLY_BRACE {
1430            if tb.current_token_is_equal_to(COMMA) {
1431                tb.skip_token(COMMA)?;
1432            }
1433            objs.push(self.parse_obj(tb)?);
1434        }
1435        tb.skip_token(RIGHT_CURLY_BRACE)?;
1436        Ok(ListSet::new(objs).into())
1437    }
1438
1439    pub fn parse_list_set_obj(&mut self, tb: &mut TokenBlock) -> Result<ListSet, RuntimeError> {
1440        let mut objs = vec![];
1441        tb.skip_token(LEFT_CURLY_BRACE)?;
1442        while tb.current()? != RIGHT_CURLY_BRACE {
1443            objs.push(self.parse_obj(tb)?);
1444            if tb.current_token_is_equal_to(COMMA) {
1445                tb.skip_token(COMMA)?;
1446            }
1447        }
1448        tb.skip_token(RIGHT_CURLY_BRACE)?;
1449        Ok(ListSet::new(objs))
1450    }
1451
1452    /// Unqualified name-shaped atom. Field access (`name.field`) is not supported.
1453    pub fn parse_identifier_or_field_access(
1454        &mut self,
1455        tb: &mut TokenBlock,
1456    ) -> Result<Obj, RuntimeError> {
1457        let left = parse_synthetically_correct_identifier_string(tb)?;
1458        if !tb.exceed_end_of_head() && tb.current()? == DOT_AKA_FIELD_ACCESS_SIGN {
1459            return Err(RuntimeError::from(ParseRuntimeError(
1460                RuntimeErrorStruct::new_with_msg_and_line_file(
1461                    "field access (`name.field`) is not supported in this version".to_string(),
1462                    tb.line_file.clone(),
1463                ),
1464            )));
1465        }
1466        Ok(Identifier::new(left).into())
1467    }
1468
1469    fn parse_mod_qualified_atom(&mut self, tb: &mut TokenBlock) -> Result<Obj, RuntimeError> {
1470        let left = parse_synthetically_correct_identifier_string(tb)?;
1471        tb.skip_token(MOD_SIGN)?;
1472        let right = parse_synthetically_correct_identifier_string(tb)?;
1473        if !tb.exceed_end_of_head() && tb.current()? == DOT_AKA_FIELD_ACCESS_SIGN {
1474            return Err(RuntimeError::from(ParseRuntimeError(
1475                RuntimeErrorStruct::new_with_msg_and_line_file(
1476                    "field access on module-qualified names is not supported in this version"
1477                        .to_string(),
1478                    tb.line_file.clone(),
1479                ),
1480            )));
1481        }
1482        Ok(IdentifierWithMod::new(left, right).into())
1483    }
1484
1485    /// Unqualified or `::`-qualified name / field name; returns a name-shaped [`Obj`].
1486    pub fn parse_identifier_or_identifier_with_mod(
1487        &mut self,
1488        tb: &mut TokenBlock,
1489    ) -> Result<Obj, RuntimeError> {
1490        let next_is_mod = tb.token_at_add_index(1) == MOD_SIGN;
1491        if next_is_mod {
1492            self.parse_mod_qualified_atom(tb)
1493        } else {
1494            self.parse_identifier_or_field_access(tb)
1495        }
1496    }
1497
1498    pub fn parse_predicate(&mut self, tb: &mut TokenBlock) -> Result<AtomicName, RuntimeError> {
1499        self.parse_atomic_name(tb)
1500    }
1501
1502    pub fn parse_family_obj(&mut self, tb: &mut TokenBlock) -> Result<FamilyObj, RuntimeError> {
1503        tb.skip_token(FAMILY_OBJ_PREFIX)?;
1504        let name = self.parse_atomic_name(tb)?;
1505        let params = self.parse_braced_objs(tb)?;
1506        Ok(FamilyObj::new(name, params))
1507    }
1508
1509    /// `ident` or `mod::ident` as a predicate/atomic name in parse position.
1510    pub fn parse_atomic_name(&mut self, tb: &mut TokenBlock) -> Result<AtomicName, RuntimeError> {
1511        let left = parse_synthetically_correct_identifier_string(tb)?;
1512        if !tb.exceed_end_of_head() && tb.current()? == MOD_SIGN {
1513            tb.skip()?;
1514            let right = parse_synthetically_correct_identifier_string(tb)?;
1515            Ok(AtomicName::WithMod(left, right))
1516        } else {
1517            Ok(AtomicName::WithoutMod(left))
1518        }
1519    }
1520}
1521
1522fn starts_with_digit(s: &str) -> bool {
1523    s.chars()
1524        .next()
1525        .map(|c| c.is_ascii_digit())
1526        .unwrap_or(false)
1527}
1528
1529fn is_number(s: &str) -> bool {
1530    if s.is_empty() {
1531        return false;
1532    }
1533
1534    let mut dot_count = 0;
1535
1536    for c in s.chars() {
1537        if c == '.' {
1538            dot_count += 1;
1539            if dot_count > 1 {
1540                return false;
1541            }
1542        } else if !c.is_ascii_digit() {
1543            return false;
1544        }
1545    }
1546
1547    s != "."
1548}
1549
1550enum FnSetOrFnSetClause {
1551    FnSet(FnSet),
1552    FnSetClause(FnSetClause),
1553}
1554
1555fn parse_synthetically_correct_identifier_string(
1556    tb: &mut TokenBlock,
1557) -> Result<String, RuntimeError> {
1558    let cur = tb.advance()?;
1559
1560    if cur == SET || cur == NONEMPTY_SET || cur == FINITE_SET {
1561        return Err(RuntimeError::from(ParseRuntimeError(
1562            RuntimeErrorStruct::new_with_msg_and_line_file(
1563                format!("{} is not a valid identifier", cur),
1564                tb.line_file.clone(),
1565            ),
1566        )));
1567    }
1568
1569    Ok(cur)
1570}
1571
1572// Maps a built-in one-token standard-set symbol to Obj::StandardSet; see reclassify_atom_as_free_param_obj.
1573fn standard_set_from_bare_identifier_name(name: &str) -> Option<Obj> {
1574    match name {
1575        N_POS => Some(StandardSet::NPos.into()),
1576        N => Some(StandardSet::N.into()),
1577        Q => Some(StandardSet::Q.into()),
1578        Z => Some(StandardSet::Z.into()),
1579        R => Some(StandardSet::R.into()),
1580        Q_POS => Some(StandardSet::QPos.into()),
1581        R_POS => Some(StandardSet::RPos.into()),
1582        Q_NEG => Some(StandardSet::QNeg.into()),
1583        Z_NEG => Some(StandardSet::ZNeg.into()),
1584        R_NEG => Some(StandardSet::RNeg.into()),
1585        Q_NZ => Some(StandardSet::QNz.into()),
1586        Z_NZ => Some(StandardSet::ZNz.into()),
1587        R_NZ => Some(StandardSet::RNz.into()),
1588        _ => None,
1589    }
1590}