1use crate::prelude::*;
2use crate::verify::number_is_in_z;
3
4impl Runtime {
5 pub fn parse_def_prop_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
6 let stmt = self.run_in_local_parsing_time_name_scope(|this| {
7 tb.skip_token(PROP)?;
8 let name = this.parse_name_and_insert_into_top_parsing_time_name_scope(tb)?;
9 let param_defs = this.parse_def_braced_param_groups_with_param_type(tb)?;
10 let def_param_names = param_defs.collect_param_names();
11
12 if tb.current_token_is_equal_to(COLON) {
13 tb.skip_token(COLON)?;
14 } else {
15 if !tb.exceed_end_of_head() {
16 return Err(RuntimeError::from(ParseRuntimeError(
17 RuntimeErrorStruct::new_with_msg_and_line_file(
18 "expect `:` or end of line after `)` in prop statement".to_string(),
19 tb.line_file.clone(),
20 ),
21 )));
22 } else {
23 this.parsing_free_param_collection
24 .end_scope(ParamObjType::DefHeader, &def_param_names);
25 return Ok(DefPropStmt::new(
26 name,
27 param_defs,
28 vec![],
29 tb.line_file.clone(),
30 ));
31 }
32 }
33
34 let facts_result = this.parse_facts_in_body(tb);
35 this.parsing_free_param_collection
36 .end_scope(ParamObjType::DefHeader, &def_param_names);
37 let facts = facts_result?;
38 Ok(DefPropStmt::new(
39 name,
40 param_defs,
41 facts,
42 tb.line_file.clone(),
43 ))
44 });
45
46 let stmt_ok = stmt?;
47 self.insert_parsed_name_into_top_parsing_time_name_scope(
48 &stmt_ok.name,
49 tb.line_file.clone(),
50 )?;
51
52 Ok(stmt_ok.into())
53 }
54
55 pub fn parse_def_abstract_prop_stmt(
56 &mut self,
57 tb: &mut TokenBlock,
58 ) -> Result<Stmt, RuntimeError> {
59 let stmt: Result<DefAbstractPropStmt, RuntimeError> = self
60 .run_in_local_parsing_time_name_scope(|this| {
61 tb.skip_token(ABSTRACT_PROP)?;
62 let name = this.parse_name_and_insert_into_top_parsing_time_name_scope(tb)?;
63 tb.skip_token(LEFT_BRACE)?;
64 let mut params = vec![];
65 while tb.current()? != RIGHT_BRACE {
66 params.push(tb.advance()?);
67 if !tb.current_token_is_equal_to(RIGHT_BRACE) {
68 tb.skip_token(COMMA)?;
69 }
70 }
71 tb.skip_token(RIGHT_BRACE)?;
72
73 this.register_collected_param_names_for_def_parse(¶ms, tb.line_file.clone())?;
74
75 Ok(DefAbstractPropStmt::new(name, params, tb.line_file.clone()))
76 });
77
78 let stmt_ok = stmt?;
79 self.insert_parsed_name_into_top_parsing_time_name_scope(
80 &stmt_ok.name,
81 tb.line_file.clone(),
82 )?;
83 Ok(stmt_ok.into())
84 }
85
86 pub fn parse_def_let_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
87 tb.skip_token(LET)?;
88 let mut param_def: Vec<ParamGroupWithParamType> = vec![];
89 loop {
90 match tb.current() {
91 Ok(t) if t == COLON => break,
92 Err(_) => break,
93 Ok(_) => {}
94 }
95 param_def.push(
96 self.parse_param_def_with_param_type_and_skip_comma(tb, ParamObjType::Identifier)?,
97 );
98 }
99 let param_def = ParamDefWithType::new(param_def);
100 let all_param_names = param_def.collect_param_names();
101 self.register_collected_param_names_for_def_parse(&all_param_names, tb.line_file.clone())?;
102
103 let facts = if tb.current_token_is_equal_to(COLON) {
104 tb.skip_token(COLON)?;
105
106 let facts_result: Result<Vec<Fact>, RuntimeError> = if tb.exceed_end_of_head() {
107 self.parse_facts_in_body(tb)
108 } else {
109 let mut facts = Vec::new();
110 let parse_result = (|| {
111 loop {
112 facts.push(self.parse_fact(tb)?);
113 if tb.exceed_end_of_head() {
114 break;
115 }
116 tb.skip_token(COMMA)?;
117 if tb.exceed_end_of_head() {
118 return Err(RuntimeError::from(ParseRuntimeError(
119 RuntimeErrorStruct::new_with_msg_and_line_file(
120 "expected fact after comma in inline let statement".to_string(),
121 tb.line_file.clone(),
122 ),
123 )));
124 }
125 }
126 if !tb.body.is_empty() {
127 return Err(RuntimeError::from(ParseRuntimeError(
128 RuntimeErrorStruct::new_with_msg_and_line_file(
129 "inline let statement cannot also have an indented body"
130 .to_string(),
131 tb.line_file.clone(),
132 ),
133 )));
134 }
135 Ok(())
136 })();
137 parse_result.map(|_| facts)
138 };
139 if facts_result.is_err() && !all_param_names.is_empty() {
140 self.parsing_free_param_collection
141 .end_scope(ParamObjType::Identifier, &all_param_names);
142 }
143 let facts = facts_result?;
144 self.parsing_free_param_collection
145 .end_scope(ParamObjType::Identifier, &all_param_names);
146 facts
147 } else {
148 if !all_param_names.is_empty() {
149 self.parsing_free_param_collection
150 .end_scope(ParamObjType::Identifier, &all_param_names);
151 }
152 vec![]
153 };
154 Ok(DefLetStmt::new(param_def, facts, tb.line_file.clone()).into())
155 }
156
157 pub fn parse_have_obj_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
159 tb.skip_token(HAVE)?;
160 let mut param_defs: Vec<ParamGroupWithParamType> = vec![];
161 loop {
162 param_defs.push(
163 self.parse_param_def_with_param_type_and_skip_comma(tb, ParamObjType::Identifier)?,
164 );
165 match tb.current() {
166 Ok(t) if t == EQUAL => break,
167 Err(_) => break,
168 Ok(_) => {}
169 }
170 }
171 if param_defs.is_empty() {
172 return Err(RuntimeError::from(ParseRuntimeError(
173 RuntimeErrorStruct::new_with_msg_and_line_file(
174 "have expects at least one param type pair".to_string(),
175 tb.line_file.clone(),
176 ),
177 )));
178 }
179 let param_defs = ParamDefWithType::new(param_defs);
180 let have_param_names = param_defs.collect_param_names();
181 self.register_collected_param_names_for_def_parse(&have_param_names, tb.line_file.clone())?;
182
183 if tb.current().map(|t| t != EQUAL).unwrap_or(true) {
184 if !have_param_names.is_empty() {
185 self.parsing_free_param_collection
186 .end_scope(ParamObjType::Identifier, &have_param_names);
187 }
188 Ok(HaveObjInNonemptySetOrParamTypeStmt::new(param_defs, tb.line_file.clone()).into())
189 } else {
190 tb.skip_token(EQUAL)?;
191 let objs_result = (|| -> Result<Vec<Obj>, RuntimeError> {
192 let mut objs_equal_to = vec![self.parse_obj(tb)?];
193 while matches!(tb.current(), Ok(t) if t == COMMA) {
194 tb.skip_token(COMMA)?;
195 objs_equal_to.push(self.parse_obj(tb)?);
196 }
197 Ok(objs_equal_to)
198 })();
199 self.parsing_free_param_collection
200 .end_scope(ParamObjType::Identifier, &have_param_names);
201 let objs_equal_to = objs_result?;
202 Ok(HaveObjEqualStmt::new(param_defs, objs_equal_to, tb.line_file.clone()).into())
203 }
204 }
205
206 pub fn parse_have_fn_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
207 tb.skip_token(HAVE)?;
208 tb.skip_token(FN_LOWER_CASE)?;
209 if tb.current_token_is_equal_to(BY) {
210 tb.skip_token(BY)?;
211 self.parse_have_fn_by_induc_stmt(tb)
212 } else {
213 let name = self.parse_name_and_insert_into_top_parsing_time_name_scope(tb)?;
214 if tb.current_token_is_equal_to(BY) {
215 tb.skip_token(BY)?;
216 let lf = tb.line_file.clone();
217 let fact = self.parse_fact(tb)?;
218 let forall = match fact {
219 Fact::ForallFact(ff) => ff,
220 _ => {
221 return Err(RuntimeError::from(ParseRuntimeError(
222 RuntimeErrorStruct::new_with_msg_and_line_file(
223 "have fn <name> by ... expects a `forall` fact".to_string(),
224 lf,
225 ),
226 )));
227 }
228 };
229 if !tb.exceed_end_of_head() {
230 return Err(RuntimeError::from(ParseRuntimeError(
231 RuntimeErrorStruct::new_with_msg_and_line_file(
232 "unexpected token after `have fn` `by` `forall` fact".to_string(),
233 tb.line_file.clone(),
234 ),
235 )));
236 }
237 return Ok(HaveFnByForallExistUniqueStmt::new(name, forall, lf).into());
238 }
239
240 let fs = self.parse_fn_set_clause(tb)?;
241 let fn_param_names = fs.collect_all_param_names_including_nested_ret_fn_sets();
242
243 if tb.current_token_is_equal_to(COLON) {
244 tb.skip_token(COLON)?;
245 let case_block_count = tb.body.len();
246 let mut cases: Vec<AndChainAtomicFact> = Vec::with_capacity(case_block_count);
247 let mut equal_tos: Vec<Obj> = Vec::with_capacity(case_block_count);
248 for block in tb.body.iter_mut() {
249 block.skip_token(CASE)?;
250 let case_lf = block.line_file.clone();
251 cases.push(self.with_optional_free_param_scope(
252 ParamObjType::FnSet,
253 &fn_param_names,
254 case_lf,
255 |this| this.parse_and_chain_atomic_fact(block),
256 )?);
257 block.skip_token(COLON)?;
258 let rhs_lf = block.line_file.clone();
259 equal_tos.push(self.with_optional_free_param_scope(
260 ParamObjType::FnSet,
261 &fn_param_names,
262 rhs_lf,
263 |this| this.parse_obj(block),
264 )?);
265 }
266 Ok(
267 HaveFnEqualCaseByCaseStmt::new(
268 name,
269 fs,
270 cases,
271 equal_tos,
272 tb.line_file.clone(),
273 )
274 .into(),
275 )
276 } else {
277 tb.skip_token(EQUAL)?;
278
279 let lf = tb.line_file.clone();
280 let equal_to = self.with_optional_free_param_scope(
281 ParamObjType::FnSet,
282 &fn_param_names,
283 lf,
284 |this| this.parse_obj(tb),
285 )?;
286 let equal_to_anonymous_fn = AnonymousFn::new(
287 fs.params_def_with_set.clone(),
288 fs.dom_facts.clone(),
289 fs.ret_set.clone(),
290 equal_to,
291 )?;
292 Ok(HaveFnEqualStmt::new(name, equal_to_anonymous_fn, tb.line_file.clone()).into())
293 }
294 }
295 }
296
297 fn parse_have_fn_by_induc_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
301 tb.skip_token(INDUC)?;
302 tb.skip_token(FROM)?;
303 let induc_from = self.parse_obj(tb)?;
304 tb.skip_token(COLON)?;
305 let name = self.parse_name_and_insert_into_top_parsing_time_name_scope(tb)?;
306
307 tb.skip_token(LEFT_BRACE)?;
308 let param = tb.advance()?;
309 if !tb.current_token_is_equal_to(Z) {
310 return Err(RuntimeError::from(ParseRuntimeError(
311 RuntimeErrorStruct::new_with_msg_and_line_file(
312 "have fn by induc from: expected `Z` after parameter name".to_string(),
313 tb.line_file.clone(),
314 ),
315 )));
316 }
317 tb.skip_token(Z)?;
318 tb.skip_token(COLON)?;
319
320 self.run_in_local_parsing_time_name_scope(|this| {
321 this.parse_have_fn_by_induc_stmt_after_param_scope(tb, name, param, induc_from)
322 })
323 }
324
325 fn parse_have_fn_by_induc_stmt_after_param_scope(
326 &mut self,
327 tb: &mut TokenBlock,
328 name: String,
329 param: String,
330 induc_from: Obj,
331 ) -> Result<Stmt, RuntimeError> {
332 self.validate_user_fn_param_names_for_parse(&[param.clone()], tb.line_file.clone())?;
333 let dom_and_chain = self.parse_and_chain_atomic_fact(tb)?;
334 Self::verify_have_fn_by_induc_dom_matches_induc_from(
335 &dom_and_chain,
336 ¶m,
337 &induc_from,
338 tb.line_file.clone(),
339 )?;
340 tb.skip_token(RIGHT_BRACE)?;
341 let ret_set = self.parse_obj(tb)?;
342
343 if !tb.current_token_is_equal_to(COLON) {
344 return Err(RuntimeError::from(ParseRuntimeError(
345 RuntimeErrorStruct::new_with_msg_and_line_file(
346 "have fn by induc from: expected `:` before case blocks".to_string(),
347 tb.line_file.clone(),
348 ),
349 )));
350 }
351 tb.skip_token(COLON)?;
352
353 let num_blocks = tb.body.len();
354 if num_blocks <= 1 {
355 return Err(RuntimeError::from(ParseRuntimeError(
356 RuntimeErrorStruct::new_with_msg_and_line_file(
357 "have fn by induc from: expected at least two case blocks".to_string(),
358 tb.line_file.clone(),
359 ),
360 )));
361 }
362
363 let num_special = num_blocks - 1;
364 let mut special_cases_equal_tos: Vec<Obj> = Vec::with_capacity(num_special);
365
366 let induc_from_is_number_obj = matches!(induc_from, Obj::Number(_));
367 if induc_from_is_number_obj {
368 if let Obj::Number(n) = &induc_from {
369 if !number_is_in_z(n) {
370 return Err(
371 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file(format!(
372 "have fn by induc from: when `from` is a number literal, it must be an integer, got {}",
373 induc_from.to_string()
374 ), tb.line_file.clone()))));
375 }
376 }
377 }
378
379 for i in 0..num_special {
380 let block = &mut tb.body[i];
381 block.skip_token(CASE)?;
382
383 block.skip_token(¶m)?;
384
385 block.skip_token(EQUAL)?;
386
387 let slot_label = self.parse_obj(block)?;
388 Self::verify_have_fn_by_induc_special_case_slot_label(
389 &slot_label,
390 i,
391 block.line_file.clone(),
392 )?;
393
394 if induc_from_is_number_obj {
395 let induc_from_add_i: Obj = Add::new(
396 induc_from.clone(),
397 Into::<Obj>::into(Number::new(i.to_string())),
398 )
399 .into();
400
401 if !induc_from_add_i
402 .two_objs_can_be_calculated_and_equal_by_calculation(&slot_label)
403 {
404 return Err(
405 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file(format!(
406 "have fn by induc from: when `from` is a number literal, special case must be `case {} = {}:` (`from` + {}), got {}",
407 param, induc_from_add_i.to_string(), i, slot_label.to_string()
408 ), block.line_file.clone()))));
409 }
410 } else {
411 let induc_from_add_i: Obj = Add::new(
412 induc_from.clone(),
413 Into::<Obj>::into(Number::new(i.to_string())),
414 )
415 .into();
416
417 if induc_from_add_i.to_string() != slot_label.to_string() {
418 return Err(
419 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file(format!(
420 "have fn by induc from: when `from` is not a number literal, special case must be `case {} = {}:`, got {}",
421 param, induc_from_add_i.to_string(), slot_label.to_string()
422 ), block.line_file.clone()))));
423 }
424 }
425
426 block.skip_token(COLON)?;
427 if !block.exceed_end_of_head() {
428 special_cases_equal_tos.push(self.parse_obj(block)?);
429 } else {
430 return Err(
431 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file("have fn by induc from: special case must be `case <index>: <obj>` on one line"
432 .to_string(), block.line_file.clone()))));
433 }
434 }
435
436 let induc_names_last = [param.clone()];
437 let last_case_line = tb.body[num_blocks - 1].line_file.clone();
438 let last_case = self.parse_in_local_free_param_scope(
439 ParamObjType::Induc,
440 &induc_names_last,
441 last_case_line,
442 |this| {
443 let last_block = &mut tb.body[num_blocks - 1];
444 last_block.skip_token(CASE)?;
445 last_block.skip_token(¶m)?;
446 last_block.skip_token(GREATER_EQUAL)?;
447 let last_bound = this.parse_obj(last_block)?;
448
449 if induc_from_is_number_obj {
450 let induc_from_add_n: Obj = Add::new(
451 induc_from.clone(),
452 Into::<Obj>::into(Number::new(num_special.to_string())),
453 )
454 .into();
455 if !induc_from_add_n
456 .two_objs_can_be_calculated_and_equal_by_calculation(&last_bound)
457 {
458 return Err(
459 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file(format!(
460 "have fn by induc from: when `from` is a number literal, last case must be `case >= {}:` (`from` + {}), got {}",
461 induc_from_add_n.to_string(), num_special, last_bound.to_string()
462 ), last_block.line_file.clone()))));
463 }
464 } else {
465 let induc_from_add_n: Obj = Add::new(
466 induc_from.clone(),
467 Into::<Obj>::into(Number::new(num_special.to_string())),
468 )
469 .into();
470 if induc_from_add_n.to_string() != last_bound.to_string() {
471 return Err(
472 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file(format!(
473 "have fn by induc from: when `from` is not a number literal, last case must be `case >= {}:`, got {}",
474 induc_from_add_n.to_string(), last_bound.to_string()
475 ), last_block.line_file.clone()))));
476 }
477 }
478
479 last_block.skip_token(COLON)?;
480
481 if !last_block.exceed_end_of_head() {
482 let last_obj = this.parse_obj(last_block)?;
483 if !last_block.exceed_end_of_head() {
484 return Err(
485 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file("have fn by induc from: unexpected tokens after `obj` in last case"
486 .to_string(), last_block.line_file.clone()))));
487 }
488 if !last_block.body.is_empty() {
489 return Err(
490 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file("have fn by induc from: if last case has `:` and an object on the same line, it must not have a nested body"
491 .to_string(), last_block.line_file.clone()))));
492 }
493 Ok(HaveFnByInducLastCase::EqualTo(last_obj))
494 } else if !last_block.body.is_empty() {
495 let mut nested: Vec<HaveFnByInducNestedCase> =
496 Vec::with_capacity(last_block.body.len());
497 for sub in last_block.body.iter_mut() {
498 sub.skip_token(CASE)?;
499 let w = this.parse_and_chain_atomic_fact(sub)?;
500 sub.skip_token(COLON)?;
501 if sub.exceed_end_of_head() {
502 return Err(
503 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file("have fn by induc from: nested case must be `case <when>: <obj>`"
504 .to_string(), sub.line_file.clone()))));
505 }
506 let o = this.parse_obj(sub)?;
507 if !sub.body.is_empty() {
508 return Err(
509 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file("have fn by induc from: nested case must not have further indentation"
510 .to_string(), sub.line_file.clone()))));
511 }
512 nested.push(HaveFnByInducNestedCase {
513 case_fact: w,
514 equal_to: o,
515 });
516 }
517 Ok(HaveFnByInducLastCase::NestedCases(nested))
518 } else {
519 Err(RuntimeError::from(ParseRuntimeError(
520 RuntimeErrorStruct::new_with_msg_and_line_file("have fn by induc from: last case must end with `: <obj>` or `:` with nested `case` blocks"
521 .to_string(), last_block.line_file.clone()),
522 )))
523 }
524 },
525 )?;
526
527 Ok(HaveFnByInducStmt::new(
528 name,
529 param,
530 ret_set,
531 induc_from,
532 special_cases_equal_tos,
533 last_case,
534 tb.line_file.clone(),
535 )
536 .into())
537 }
538
539 fn verify_have_fn_by_induc_dom_matches_induc_from(
540 when: &AndChainAtomicFact,
541 param_name: &str,
542 induc_from: &Obj,
543 line_file: LineFile,
544 ) -> Result<(), RuntimeError> {
545 let ge = match when {
546 AndChainAtomicFact::AtomicFact(AtomicFact::GreaterEqualFact(ge)) => ge,
547 _ => {
548 return Err(RuntimeError::from(ParseRuntimeError(
549 RuntimeErrorStruct::new_with_msg_and_line_file(
550 "have fn by induc from: dom fact must be a single `>=` fact".to_string(),
551 line_file,
552 ),
553 )));
554 }
555 };
556 match &ge.left {
557 Obj::Atom(AtomObj::Identifier(id)) if id.name == param_name => {}
558 _ => {
559 return Err(RuntimeError::from(ParseRuntimeError(
560 RuntimeErrorStruct::new_with_msg_and_line_file(
561 "have fn by induc from: `>=` left must be the parameter name".to_string(),
562 line_file,
563 ),
564 )));
565 }
566 }
567 if ge.right.to_string() != induc_from.to_string() {
568 return Err(RuntimeError::from(ParseRuntimeError(
569 RuntimeErrorStruct::new_with_msg_and_line_file(
570 "have fn by induc from: `>=` right must match the object after `from`"
571 .to_string(),
572 line_file,
573 ),
574 )));
575 }
576 Ok(())
577 }
578
579 fn verify_have_fn_by_induc_special_case_slot_label(
581 slot: &Obj,
582 expected_index: usize,
583 line_file: LineFile,
584 ) -> Result<(), RuntimeError> {
585 match slot {
586 Obj::Number(n) => {
587 if n.normalized_value == expected_index.to_string() {
588 Ok(())
589 } else {
590 Err(
591 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file(format!(
592 "have fn by induc from: special case label must be `{}` (0-based index for this row), got {}",
593 expected_index, n.normalized_value
594 ), line_file))))
595 }
596 }
597 _ => Err(
598 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file("have fn by induc from: special case must be `case <natural>: <obj>` where <natural> is the 0-based index (0, 1, …)"
599 .to_string(), line_file)))),
600 }
601 }
602
603 pub fn parse_have_exist(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
604 tb.skip_token(HAVE)?;
605 tb.skip_token(BY)?;
606
607 let true_fact = self.parse_exist_fact(tb)?;
608
609 tb.skip_token(COLON)?;
610
611 let mut equal_tos = vec![];
612 while !tb.exceed_end_of_head() {
613 equal_tos.push(tb.advance()?);
614 if tb.current_token_is_equal_to(COMMA) {
615 tb.skip_token(COMMA)?;
616 }
617 }
618
619 self.register_collected_param_names_for_def_parse(&equal_tos, tb.line_file.clone())?;
620
621 Ok(HaveByExistStmt::new(equal_tos, true_fact, tb.line_file.clone()).into())
622 }
623
624 fn parse_braced_params_and_optional_dom_facts(
627 &mut self,
628 tb: &mut TokenBlock,
629 ) -> Result<(ParamDefWithType, Vec<OrAndChainAtomicFact>), RuntimeError> {
630 tb.skip_token(LEFT_BRACE)?;
631 let params_def_with_type =
632 self.parse_def_param_type_groups_until_colon_or_right_brace(tb)?;
633 let scope_names = params_def_with_type.collect_param_names();
634 let dom_facts = if tb.current_token_is_equal_to(COLON) {
635 tb.skip_token(COLON)?;
636 let mut facts = vec![];
637 let dom_result = loop {
638 if tb.current()? == RIGHT_BRACE {
639 break Ok(facts);
640 }
641 match self.parse_or_and_chain_atomic_fact(tb) {
642 Ok(f) => facts.push(f),
643 Err(e) => {
644 self.parsing_free_param_collection
645 .end_scope(ParamObjType::DefHeader, &scope_names);
646 break Err(e);
647 }
648 }
649 if tb.current_token_is_equal_to(COMMA) {
650 tb.skip_token(COMMA)?;
651 }
652 };
653 dom_result?
654 } else {
655 vec![]
656 };
657 if let Err(e) = tb.skip_token(RIGHT_BRACE) {
658 self.parsing_free_param_collection
659 .end_scope(ParamObjType::DefHeader, &scope_names);
660 return Err(e);
661 }
662 Ok((params_def_with_type, dom_facts))
663 }
664
665 pub fn parse_def_family_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
666 tb.skip_token(FAMILY)?;
667 let name = self.parse_name_and_insert_into_top_parsing_time_name_scope(tb)?;
668
669 self.run_in_local_parsing_time_name_scope(move |this| {
670 let (params_def_with_type, dom_facts) =
671 this.parse_braced_params_and_optional_dom_facts(tb)?;
672 let family_def_scope_names = params_def_with_type.collect_param_names();
673 let stmt_result = (|| -> Result<Stmt, RuntimeError> {
674 if !tb.current_token_is_equal_to(EQUAL) {
675 return Err(RuntimeError::from(ParseRuntimeError(
676 RuntimeErrorStruct::new_with_msg_and_line_file(
677 "family definition expects `=` after `}`".to_string(),
678 tb.line_file.clone(),
679 ),
680 )));
681 }
682 tb.skip_token(EQUAL)?;
683 let equal_to = this.parse_obj(tb)?;
684 Ok(DefFamilyStmt::new(
685 name,
686 params_def_with_type,
687 dom_facts,
688 equal_to,
689 tb.line_file.clone(),
690 )
691 .into())
692 })();
693 this.parsing_free_param_collection
694 .end_scope(ParamObjType::DefHeader, &family_def_scope_names);
695 stmt_result
696 })
697 }
698
699 pub fn parse_def_algorithm_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
700 tb.skip_token(ALGO)?;
701 let name = tb.advance()?;
702 self.run_in_local_parsing_time_name_scope(move |this| {
703 tb.skip_token(LEFT_BRACE)?;
704 let mut params: Vec<String> = vec![];
705 while tb.current()? != RIGHT_BRACE {
706 params.push(tb.advance()?);
707 if tb.current_token_is_equal_to(COMMA) {
708 tb.skip_token(COMMA)?;
709 }
710 }
711 tb.skip_token(RIGHT_BRACE)?;
712 this.register_collected_param_names_for_def_parse(¶ms, tb.line_file.clone())?;
713 tb.skip_token(COLON)?;
714 this.parsing_free_param_collection.begin_scope(
715 ParamObjType::DefAlgo,
716 ¶ms,
717 tb.line_file.clone(),
718 )?;
719 let params_for_end = params.clone();
720 let algo_result = (|| -> Result<DefAlgoStmt, RuntimeError> {
721 let mut algo_cases: Vec<AlgoCase> = vec![];
722 let mut default_return: Option<AlgoReturn> = None;
723 match tb.body.split_last_mut() {
724 None => {}
725 Some((last_block, leading_blocks)) => {
726 for block in leading_blocks.iter_mut() {
727 algo_cases.push(this.parse_algo_case(block)?);
728 }
729 if last_block.current_token_empty_if_exceed_end_of_head() == CASE {
730 algo_cases.push(this.parse_algo_case(last_block)?);
731 } else {
732 default_return = Some(this.parse_algo_return(last_block)?);
733 }
734 }
735 }
736 Ok(DefAlgoStmt::new(
737 name,
738 params,
739 algo_cases,
740 default_return,
741 tb.line_file.clone(),
742 ))
743 })();
744 this.parsing_free_param_collection
745 .end_scope(ParamObjType::DefAlgo, ¶ms_for_end);
746 Ok(algo_result?.into())
747 })
748 }
749
750 fn parse_algo_case(&mut self, block: &mut TokenBlock) -> Result<AlgoCase, RuntimeError> {
752 block.skip_token(CASE)?;
753 let condition = self.parse_atomic_fact(block, true)?;
754 block.skip_token(COLON)?;
755
756 let return_stmt = self.parse_algo_return(block)?;
757 Ok(AlgoCase::new(
758 condition,
759 return_stmt,
760 block.line_file.clone(),
761 ))
762 }
763
764 fn parse_algo_return(&mut self, block: &mut TokenBlock) -> Result<AlgoReturn, RuntimeError> {
766 let value = self.parse_obj(block)?;
767 Ok(AlgoReturn::new(value, block.line_file.clone()))
768 }
769}
770
771impl Runtime {
772 pub fn register_collected_param_names_for_def_parse(
773 &mut self,
774 names: &Vec<String>,
775 line_file: LineFile,
776 ) -> Result<(), RuntimeError> {
777 self.validate_names_and_insert_into_top_parsing_time_name_scope(names, line_file.clone())
778 .map_err(|e| {
779 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new(
780 None,
781 String::new(),
782 line_file,
783 Some(e),
784 vec![],
785 )))
786 })
787 }
788
789 fn parse_def_braced_param_groups_with_param_type(
791 &mut self,
792 tb: &mut TokenBlock,
793 ) -> Result<ParamDefWithType, RuntimeError> {
794 tb.skip_token(LEFT_BRACE)?;
795 let mut groups = Vec::new();
796 while tb.current()? != RIGHT_BRACE {
797 groups.push(
798 self.parse_param_def_with_param_type_and_skip_comma(tb, ParamObjType::DefHeader)?,
799 );
800 }
801 tb.skip_token(RIGHT_BRACE)?;
802 let param_defs = ParamDefWithType::new(groups);
803 let names = param_defs.collect_param_names();
804 self.register_collected_param_names_for_def_parse(&names, tb.line_file.clone())?;
805 Ok(param_defs)
806 }
807
808 fn parse_def_param_type_groups_until_colon_or_right_brace(
810 &mut self,
811 tb: &mut TokenBlock,
812 ) -> Result<ParamDefWithType, RuntimeError> {
813 let mut groups = vec![];
814 while tb.current()? != COLON && tb.current()? != RIGHT_BRACE {
815 groups.push(
816 self.parse_param_def_with_param_type_and_skip_comma(tb, ParamObjType::DefHeader)?,
817 );
818 }
819 let params_def_with_type = ParamDefWithType::new(groups);
820 let param_names = params_def_with_type.collect_param_names();
821 self.register_collected_param_names_for_def_parse(¶m_names, tb.line_file.clone())?;
822 Ok(params_def_with_type)
823 }
824
825 pub fn insert_parsed_name_into_top_parsing_time_name_scope(
826 &mut self,
827 name: &str,
828 line_file: LineFile,
829 ) -> Result<(), RuntimeError> {
830 self.validate_name_and_insert_into_top_parsing_time_name_scope(name, line_file.clone())
831 .map_err(|e| {
832 RuntimeError::from(ParseRuntimeError(RuntimeErrorStruct::new(
833 None,
834 String::new(),
835 line_file,
836 Some(e),
837 vec![],
838 )))
839 })
840 }
841
842 pub fn parse_name_and_insert_into_top_parsing_time_name_scope(
843 &mut self,
844 tb: &mut TokenBlock,
845 ) -> Result<String, RuntimeError> {
846 let name = tb.advance()?;
847 self.insert_parsed_name_into_top_parsing_time_name_scope(&name, tb.line_file.clone())?;
848 Ok(name)
849 }
850}