1use std::{
2 borrow::Cow,
3 io::{BufReader, Read},
4 marker::PhantomData,
5};
6
7use flussab::{text::LineReader, DeferredReader, DeferredWriter, Parsed::Fallthrough};
8
9use crate::{
10 aig::{OrderedAig, OrderedAndGate, OrderedLatch, Symbol, SymbolTarget},
11 token::{self, eof, unexpected},
12 Lit, ParseError,
13};
14
15#[derive(Default)]
16#[non_exhaustive]
17pub struct Config {}
18
19#[derive(Clone, Debug)]
20pub struct Header {
21 pub max_var_index: usize,
22 pub input_count: usize,
23 pub latch_count: usize,
24 pub output_count: usize,
25 pub and_gate_count: usize,
26 pub bad_state_property_count: usize,
27 pub invariant_constraint_count: usize,
28 pub justice_property_count: usize,
29 pub fairness_constraint_count: usize,
30}
31
32impl Header {
33 fn parse<L: Lit>(reader: &mut LineReader) -> Result<Self, ParseError> {
34 token::fixed(reader, b"aig")
35 .or_give_up(|| token::unexpected(reader, "binary AIGER header \"aig\""))?;
36
37 token::required_space(reader)?;
38 let max_var_index = token::header_field(
39 reader,
40 "maximum variable index",
41 (L::MAX_CODE - 1) / 2,
42 true,
43 )?;
44
45 let mut limit = max_var_index;
46
47 token::required_space(reader)?;
48 let input_count = token::header_field(reader, "input count", limit, false)?;
49
50 limit -= input_count;
51
52 token::required_space(reader)?;
53 let latch_count = token::header_field(reader, "latch count", limit, false)?;
54
55 limit -= latch_count;
56
57 token::required_space(reader)?;
58 let output_count = token::header_field(reader, "output count", usize::MAX, true)?;
59
60 token::required_space(reader)?;
61 let and_gate_count = token::header_field(reader, "and gate count", limit, false)?;
62
63 let mut bad_state_property_count = 0;
64 let mut invariant_constraint_count = 0;
65 let mut justice_property_count = 0;
66 let mut fairness_constraint_count = 0;
67
68 #[allow(clippy::never_loop)]
69 loop {
70 if !token::required_newline_or_space(reader)? {
71 break;
72 }
73
74 bad_state_property_count =
75 token::header_field(reader, "bad state property count", limit, false)?;
76
77 if !token::required_newline_or_space(reader)? {
78 break;
79 }
80 invariant_constraint_count =
81 token::header_field(reader, "invariant constraint count", limit, false)?;
82
83 if !token::required_newline_or_space(reader)? {
84 break;
85 }
86 justice_property_count =
87 token::header_field(reader, "justice property count", limit, false)?;
88
89 if !token::required_newline_or_space(reader)? {
90 break;
91 }
92 fairness_constraint_count =
93 token::header_field(reader, "fairness constraint count", limit, false)?;
94
95 token::required_newline(reader)?;
96 break;
97 }
98
99 Ok(Header {
100 max_var_index,
101 input_count,
102 latch_count,
103 output_count,
104 and_gate_count,
105 bad_state_property_count,
106 invariant_constraint_count,
107 justice_property_count,
108 fairness_constraint_count,
109 })
110 }
111}
112
113pub struct Parser<'a, L> {
115 reader: LineReader<'a>,
116 header: Header,
117 max_lit: usize,
118 code: usize,
119 _lit_builder: std::marker::PhantomData<L>,
120}
121
122impl<'a, L> Parser<'a, L>
123where
124 L: Lit,
125{
126 pub fn from_buf_reader(
128 buf_reader: BufReader<impl Read + 'a>,
129 config: Config,
130 ) -> Result<Self, ParseError> {
131 Self::new(
132 LineReader::new(DeferredReader::from_buf_reader(buf_reader)),
133 config,
134 )
135 }
136
137 pub fn from_read(read: impl Read + 'a, config: Config) -> Result<Self, ParseError> {
143 Self::new(LineReader::new(DeferredReader::from_read(read)), config)
144 }
145
146 #[inline(never)]
152 pub fn from_boxed_dyn_read(
153 read: Box<dyn Read + 'a>,
154 config: Config,
155 ) -> Result<Self, ParseError> {
156 Self::new(
157 LineReader::new(DeferredReader::from_boxed_dyn_read(read)),
158 config,
159 )
160 }
161
162 pub fn new(mut reader: LineReader<'a>, _config: Config) -> Result<Self, ParseError> {
164 let header = Header::parse::<L>(&mut reader)?;
165
166 Ok(Self {
167 reader,
168 max_lit: header.max_var_index * 2 + 1,
169 code: (header.input_count + 1) * 2,
170 header,
171 _lit_builder: std::marker::PhantomData,
172 })
173 }
174
175 pub fn latches(self) -> Result<ParseLatches<'a, L>, ParseError> {
176 Ok(ParseLatches {
177 latches_left: self.header.latch_count,
178 parser: self,
179 })
180 }
181
182 pub fn header(&self) -> &Header {
183 &self.header
184 }
185
186 pub fn parse(self) -> Result<OrderedAig<L>, ParseError> {
187 let mut aig = OrderedAig {
188 max_var_index: self.header.max_var_index,
189 input_count: self.header.input_count,
190 ..OrderedAig::default()
191 };
192
193 aig.latches.reserve(self.header.latch_count);
194 aig.outputs.reserve(self.header.output_count);
195 aig.bad_state_properties
196 .reserve(self.header.bad_state_property_count);
197 aig.invariant_constraints
198 .reserve(self.header.invariant_constraint_count);
199 aig.justice_properties = (0..self.header.justice_property_count)
200 .map(|_| vec![])
201 .collect();
202 aig.fairness_constraints
203 .reserve(self.header.fairness_constraint_count);
204 aig.and_gates.reserve(self.header.and_gate_count);
205
206 let justice_property_count = self.header.justice_property_count;
207
208 let mut aag_reader = self.latches()?;
209 while let Some(latch) = aag_reader.next_latch()? {
210 aig.latches.push(latch);
211 }
212
213 let mut aag_reader = aag_reader.outputs()?;
214 while let Some(output) = aag_reader.next_output()? {
215 aig.outputs.push(output);
216 }
217
218 let mut aag_reader = aag_reader.bad_state_properties()?;
219 while let Some(bad_state_property) = aag_reader.next_bad_state_property()? {
220 aig.bad_state_properties.push(bad_state_property);
221 }
222
223 let mut aag_reader = aag_reader.invariant_constraints()?;
224 while let Some(invariant_constraint) = aag_reader.next_invariant_constraint()? {
225 aig.invariant_constraints.push(invariant_constraint);
226 }
227
228 let mut justice_property_sizes = Vec::with_capacity(justice_property_count);
229
230 let mut aag_reader = aag_reader.justice_properties()?;
231 while let Some(justice_property_size) = aag_reader.next_justice_property_size()? {
232 justice_property_sizes.push(justice_property_size);
233 }
234
235 let mut justice_property = 0;
236
237 let mut aag_reader = aag_reader.justice_property_local_fairness_constraints()?;
238 while let Some(justice_property_local_fairness_constraint) =
239 aag_reader.next_justice_property_local_fairness_constraint()?
240 {
241 while aig.justice_properties[justice_property].len()
242 == justice_property_sizes[justice_property]
243 {
244 justice_property += 1;
245 }
246 aig.justice_properties[justice_property]
247 .push(justice_property_local_fairness_constraint);
248 }
249
250 let mut aag_reader = aag_reader.fairness_constraints()?;
251 while let Some(fairness_constraint) = aag_reader.next_fairness_constraint()? {
252 aig.fairness_constraints.push(fairness_constraint);
253 }
254
255 let mut aag_reader = aag_reader.and_gates()?;
256 while let Some(and_gate) = aag_reader.next_and_gate()? {
257 aig.and_gates.push(and_gate);
258 }
259
260 let mut aag_reader = aag_reader.symbols()?;
261 while let Some(symbol) = aag_reader.next_symbol()? {
262 aig.symbols.push(symbol.into_owned_name());
263 }
264
265 if let Some(comment) = aag_reader.comment()? {
266 aig.comment = Some(comment.to_owned());
267 }
268
269 Ok(aig)
270 }
271}
272
273pub struct ParseInputs<'a, L> {
274 parser: Parser<'a, L>,
275 inputs_left: usize,
276}
277
278impl<'a, L> std::ops::Deref for ParseInputs<'a, L> {
279 type Target = Parser<'a, L>;
280
281 fn deref(&self) -> &Self::Target {
282 &self.parser
283 }
284}
285
286impl<'a, L> ParseInputs<'a, L>
287where
288 L: Lit,
289{
290 pub fn next_input(&mut self) -> Result<Option<L>, ParseError> {
291 if self.inputs_left == 0 {
292 return Ok(None);
293 }
294 self.inputs_left -= 1;
295 let lit = L::from_code(token::lit(
296 &mut self.parser.reader,
297 "input literal",
298 self.parser.max_lit,
299 true,
300 )?);
301 token::required_newline(&mut self.parser.reader)?;
302 Ok(Some(lit))
303 }
304
305 pub fn latches(mut self) -> Result<ParseLatches<'a, L>, ParseError> {
306 while self.inputs_left != 0 {
307 self.next_input()?;
308 }
309
310 Ok(ParseLatches {
311 latches_left: self.parser.header.latch_count,
312 parser: self.parser,
313 })
314 }
315}
316pub struct ParseLatches<'a, L> {
317 parser: Parser<'a, L>,
318 latches_left: usize,
319}
320
321impl<'a, L> ParseLatches<'a, L>
322where
323 L: Lit,
324{
325 pub fn next_latch(&mut self) -> Result<Option<OrderedLatch<L>>, ParseError> {
326 if self.latches_left == 0 {
327 return Ok(None);
328 }
329 self.latches_left -= 1;
330
331 let next_state = L::from_code(token::lit(
332 &mut self.parser.reader,
333 "latch next state literal",
334 self.parser.max_lit,
335 false,
336 )?);
337
338 let mut initialization = Some(false);
339
340 if token::required_newline_or_space(&mut self.parser.reader)? {
341 let initialization_code = token::lit(
342 &mut self.parser.reader,
343 "latch initialization literal",
344 self.parser.max_lit,
345 false,
346 )?;
347
348 if initialization_code < 2 {
349 initialization = Some(initialization_code != 0);
350 } else if initialization_code == self.parser.code {
351 initialization = None;
352 } else {
353 return Err(token::invalid_initialization(
354 &mut self.parser.reader,
355 initialization_code,
356 self.parser.code,
357 ));
358 }
359
360 token::required_newline(&mut self.parser.reader)?;
361 }
362 self.parser.code += 2;
363 Ok(Some(OrderedLatch {
364 next_state,
365 initialization,
366 }))
367 }
368
369 pub fn outputs(mut self) -> Result<ParseOutputs<'a, L>, ParseError> {
370 while self.latches_left != 0 {
371 self.next_latch()?;
372 }
373
374 Ok(ParseOutputs {
375 outputs_left: self.parser.header.output_count,
376 parser: self.parser,
377 })
378 }
379}
380
381pub struct ParseOutputs<'a, L> {
382 parser: Parser<'a, L>,
383 outputs_left: usize,
384}
385
386impl<'a, L> ParseOutputs<'a, L>
387where
388 L: Lit,
389{
390 pub fn next_output(&mut self) -> Result<Option<L>, ParseError> {
391 if self.outputs_left == 0 {
392 return Ok(None);
393 }
394 self.outputs_left -= 1;
395 let lit = L::from_code(token::lit(
396 &mut self.parser.reader,
397 "output literal",
398 self.parser.max_lit,
399 false,
400 )?);
401 token::required_newline(&mut self.parser.reader)?;
402 Ok(Some(lit))
403 }
404
405 pub fn bad_state_properties(mut self) -> Result<ParseBadStateProperties<'a, L>, ParseError> {
406 while self.outputs_left != 0 {
407 self.next_output()?;
408 }
409
410 Ok(ParseBadStateProperties {
411 bad_left: self.parser.header.bad_state_property_count,
412 parser: self.parser,
413 })
414 }
415}
416
417pub struct ParseBadStateProperties<'a, L> {
418 parser: Parser<'a, L>,
419 bad_left: usize,
420}
421
422impl<'a, L> ParseBadStateProperties<'a, L>
423where
424 L: Lit,
425{
426 pub fn next_bad_state_property(&mut self) -> Result<Option<L>, ParseError> {
427 if self.bad_left == 0 {
428 return Ok(None);
429 }
430 self.bad_left -= 1;
431 let lit = L::from_code(token::lit(
432 &mut self.parser.reader,
433 "bad state property literal",
434 self.parser.max_lit,
435 false,
436 )?);
437 token::required_newline(&mut self.parser.reader)?;
438 Ok(Some(lit))
439 }
440
441 pub fn invariant_constraints(mut self) -> Result<ParseInvariantConstraints<'a, L>, ParseError> {
442 while self.bad_left != 0 {
443 self.next_bad_state_property()?;
444 }
445
446 Ok(ParseInvariantConstraints {
447 constraints_left: self.parser.header.invariant_constraint_count,
448 parser: self.parser,
449 })
450 }
451}
452
453pub struct ParseInvariantConstraints<'a, L> {
454 parser: Parser<'a, L>,
455 constraints_left: usize,
456}
457
458impl<'a, L> ParseInvariantConstraints<'a, L>
459where
460 L: Lit,
461{
462 pub fn next_invariant_constraint(&mut self) -> Result<Option<L>, ParseError> {
463 if self.constraints_left == 0 {
464 return Ok(None);
465 }
466 self.constraints_left -= 1;
467 let lit = L::from_code(token::lit(
468 &mut self.parser.reader,
469 "invariant constraint literal",
470 self.parser.max_lit,
471 false,
472 )?);
473 token::required_newline(&mut self.parser.reader)?;
474 Ok(Some(lit))
475 }
476
477 pub fn justice_properties(mut self) -> Result<ParseJusticePropertySizes<'a, L>, ParseError> {
478 while self.constraints_left != 0 {
479 self.next_invariant_constraint()?;
480 }
481
482 Ok(ParseJusticePropertySizes {
483 justice_left: self.parser.header.justice_property_count,
484 parser: self.parser,
485 total_local_fairness_count: 0,
486 })
487 }
488}
489
490pub struct ParseJusticePropertySizes<'a, L: Lit> {
491 parser: Parser<'a, L>,
492 justice_left: usize,
493 total_local_fairness_count: usize,
494}
495
496impl<'a, L> ParseJusticePropertySizes<'a, L>
497where
498 L: Lit,
499{
500 pub fn next_justice_property_size(&mut self) -> Result<Option<usize>, ParseError> {
501 if self.justice_left == 0 {
502 return Ok(None);
503 }
504 self.justice_left -= 1;
505 let count = token::header_field(
506 &mut self.parser.reader,
507 "justice property local fairness constraint count",
508 usize::MAX - self.total_local_fairness_count,
509 true,
510 )?;
511 token::required_newline(&mut self.parser.reader)?;
512
513 self.total_local_fairness_count += count;
514
515 Ok(Some(count))
516 }
517
518 pub fn justice_property_local_fairness_constraints(
519 mut self,
520 ) -> Result<ParseJusticePropertyLocalFairnessConstraints<'a, L>, ParseError> {
521 while self.justice_left != 0 {
522 self.next_justice_property_size()?;
523 }
524
525 Ok(ParseJusticePropertyLocalFairnessConstraints {
526 local_fairness_left: self.total_local_fairness_count,
527 parser: self.parser,
528 })
529 }
530}
531
532pub struct ParseJusticePropertyLocalFairnessConstraints<'a, L: Lit> {
533 parser: Parser<'a, L>,
534 local_fairness_left: usize,
535}
536
537impl<'a, L> ParseJusticePropertyLocalFairnessConstraints<'a, L>
538where
539 L: Lit,
540{
541 pub fn next_justice_property_local_fairness_constraint(
542 &mut self,
543 ) -> Result<Option<L>, ParseError> {
544 if self.local_fairness_left == 0 {
545 return Ok(None);
546 }
547 self.local_fairness_left -= 1;
548 let lit = L::from_code(token::lit(
549 &mut self.parser.reader,
550 "justice property local fairness constraint literal",
551 self.parser.max_lit,
552 false,
553 )?);
554 token::required_newline(&mut self.parser.reader)?;
555
556 Ok(Some(lit))
557 }
558
559 pub fn fairness_constraints(mut self) -> Result<ParseFairnessConstraints<'a, L>, ParseError> {
560 while self.local_fairness_left != 0 {
561 self.next_justice_property_local_fairness_constraint()?;
562 }
563
564 Ok(ParseFairnessConstraints {
565 fairness_left: self.parser.header.fairness_constraint_count,
566 parser: self.parser,
567 })
568 }
569}
570
571pub struct ParseFairnessConstraints<'a, L> {
572 parser: Parser<'a, L>,
573 fairness_left: usize,
574}
575
576impl<'a, L> ParseFairnessConstraints<'a, L>
577where
578 L: Lit,
579{
580 pub fn next_fairness_constraint(&mut self) -> Result<Option<L>, ParseError> {
581 if self.fairness_left == 0 {
582 return Ok(None);
583 }
584 self.fairness_left -= 1;
585 let lit = L::from_code(token::lit(
586 &mut self.parser.reader,
587 "fairness constraint literal",
588 self.parser.max_lit,
589 false,
590 )?);
591 token::required_newline(&mut self.parser.reader)?;
592 Ok(Some(lit))
593 }
594
595 pub fn and_gates(mut self) -> Result<ParseAndGates<'a, L>, ParseError> {
596 while self.fairness_left != 0 {
597 self.next_fairness_constraint()?;
598 }
599
600 Ok(ParseAndGates {
601 ands_left: self.parser.header.and_gate_count,
602 parser: self.parser,
603 })
604 }
605}
606
607pub struct ParseAndGates<'a, L> {
608 parser: Parser<'a, L>,
609 ands_left: usize,
610}
611
612impl<'a, L> ParseAndGates<'a, L>
613where
614 L: Lit,
615{
616 pub fn next_and_gate(&mut self) -> Result<Option<OrderedAndGate<L>>, ParseError> {
617 if self.ands_left == 0 {
618 return Ok(None);
619 }
620
621 self.ands_left -= 1;
622
623 let output_code = self.parser.code;
624
625 let input_code_0: usize = token::delta_code(
626 &mut self.parser.reader,
627 output_code,
628 "first input",
629 "output code",
630 )?;
631
632 let input_code_1: usize = token::delta_code(
633 &mut self.parser.reader,
634 input_code_0,
635 "second input",
636 "first input code",
637 )?;
638
639 self.parser.code += 2;
640 Ok(Some(OrderedAndGate {
641 inputs: [L::from_code(input_code_0), L::from_code(input_code_1)],
642 }))
643 }
644
645 pub fn symbols(mut self) -> Result<ParseSymbols<'a, L>, ParseError> {
646 while self.ands_left != 0 {
647 self.next_and_gate()?;
648 }
649
650 Ok(ParseSymbols {
651 parser: self.parser,
652 })
653 }
654}
655
656pub struct ParseSymbols<'a, L> {
657 parser: Parser<'a, L>,
658}
659
660impl<'a, L> ParseSymbols<'a, L>
661where
662 L: Lit,
663{
664 pub fn next_symbol(&mut self) -> Result<Option<Symbol>, ParseError> {
665 let input = &mut self.parser.reader;
666 let target = if self.parser.header.input_count > 0 {
667 token::fixed(input, b"i")
668 } else {
669 Fallthrough
670 }
671 .and_then(|_| {
672 token::symbol_index(input, "input index", self.parser.header.input_count - 1)
673 .map(SymbolTarget::Input)
674 })
675 .or_parse(|| {
676 if self.parser.header.output_count > 0 {
677 token::fixed(input, b"o")
678 } else {
679 Fallthrough
680 }
681 .and_then(|_| {
682 token::symbol_index(input, "output index", self.parser.header.output_count - 1)
683 .map(SymbolTarget::Output)
684 })
685 })
686 .or_parse(|| {
687 if self.parser.header.latch_count > 0 {
688 token::fixed(input, b"l")
689 } else {
690 Fallthrough
691 }
692 .and_then(|_| {
693 token::symbol_index(input, "latch index", self.parser.header.latch_count - 1)
694 .map(SymbolTarget::Latch)
695 })
696 })
697 .or_parse(|| {
698 if self.parser.header.bad_state_property_count > 0 {
699 token::fixed(input, b"b")
700 } else {
701 Fallthrough
702 }
703 .and_then(|_| {
704 token::symbol_index(
705 input,
706 "bad state property index",
707 self.parser.header.latch_count - 1,
708 )
709 .map(SymbolTarget::BadStateProperty)
710 })
711 })
712 .or_parse(|| {
713 if self.parser.header.invariant_constraint_count > 0 {
714 token::fixed_not_eol(input, b"c")
715 } else {
716 Fallthrough
717 }
718 .and_then(|_| {
719 token::symbol_index(
720 input,
721 "invariant constraint index or newline", self.parser.header.latch_count - 1,
723 )
724 .map(SymbolTarget::InvariantConstraint)
725 })
726 })
727 .or_parse(|| {
728 if self.parser.header.justice_property_count > 0 {
729 token::fixed(input, b"j")
730 } else {
731 Fallthrough
732 }
733 .and_then(|_| {
734 token::symbol_index(
735 input,
736 "justice property index",
737 self.parser.header.latch_count - 1,
738 )
739 .map(SymbolTarget::JusticeProperty)
740 })
741 })
742 .or_parse(|| {
743 if self.parser.header.fairness_constraint_count > 0 {
744 token::fixed(input, b"f")
745 } else {
746 Fallthrough
747 }
748 .and_then(|_| {
749 token::symbol_index(
750 input,
751 "fairness constraint index",
752 self.parser.header.latch_count - 1,
753 )
754 .map(SymbolTarget::FairnessConstraint)
755 })
756 })
757 .optional()?;
758
759 if let Some(target) = target {
760 token::required_space(input)?;
761 let name = token::remaining_line_content(input)?;
762
763 Ok(Some(Symbol {
764 target,
765 name: Cow::Borrowed(name),
766 }))
767 } else {
768 Ok(None)
769 }
770 }
771
772 pub fn comment(&mut self) -> Result<Option<&str>, ParseError> {
773 while self.next_symbol()?.is_some() {}
774 let input = &mut self.parser.reader;
775
776 if token::fixed(input, b"c").optional()?.is_some() {
777 token::required_newline(input)?;
778 let comment = token::remaining_file_content(input)?;
779
780 Ok(Some(comment))
781 } else {
782 eof(input).or_give_up(|| unexpected(input, "symbol, comment or end of file"))?;
783
784 Ok(None)
785 }
786 }
787}
788
789pub struct Writer<'a, L> {
790 pub writer: DeferredWriter<'a>,
791 pub code: usize,
792 codec: PhantomData<L>,
793}
794
795impl<'a, L> std::ops::Deref for Writer<'a, L> {
796 type Target = DeferredWriter<'a>;
797
798 fn deref(&self) -> &Self::Target {
799 &self.writer
800 }
801}
802
803impl<'a, L> std::ops::DerefMut for Writer<'a, L> {
804 fn deref_mut(&mut self) -> &mut Self::Target {
805 &mut self.writer
806 }
807}
808
809impl<'a, L> Writer<'a, L>
810where
811 L: Lit,
812{
813 pub fn new(writer: DeferredWriter<'a>) -> Self {
814 Self {
815 writer,
816 code: 0,
817 codec: PhantomData,
818 }
819 }
820
821 pub fn write_header(&mut self, header: &Header) {
822 let fields = [
823 header.max_var_index,
824 header.input_count,
825 header.latch_count,
826 header.output_count,
827 header.and_gate_count,
828 header.bad_state_property_count,
829 header.invariant_constraint_count,
830 header.justice_property_count,
831 header.fairness_constraint_count,
832 ];
833
834 self.code = (header.input_count + 1) * 2;
835
836 let mut fields = fields.as_slice();
837
838 while let Some((0, rest)) = fields.split_last() {
839 if rest.len() >= 5 {
840 fields = rest;
841 } else {
842 break;
843 }
844 }
845
846 self.writer.write_all_defer_err(b"aig");
847
848 for &field in fields {
849 self.writer.write_all_defer_err(b" ");
850 flussab::write::text::ascii_digits(&mut self.writer, field);
851 }
852 self.writer.write_all_defer_err(b"\n");
853 }
854
855 pub fn write_lit(&mut self, lit: L) {
856 flussab::write::text::ascii_digits(&mut self.writer, lit.code());
857 self.writer.write_all_defer_err(b"\n");
858 }
859
860 pub fn write_latch(&mut self, latch: OrderedLatch<L>) {
861 flussab::write::text::ascii_digits(&mut self.writer, latch.next_state.code());
862
863 match latch.initialization {
864 Some(true) => self.writer.write_all_defer_err(b" 1\n"),
865 Some(false) => self.writer.write_all_defer_err(b"\n"),
866 None => {
867 self.writer.write_all_defer_err(b" ");
868 flussab::write::text::ascii_digits(&mut self.writer, self.code);
869 self.writer.write_all_defer_err(b"\n");
870 }
871 }
872 self.code += 2;
873 }
874
875 pub fn write_count(&mut self, count: usize) {
876 flussab::write::text::ascii_digits(&mut self.writer, count);
877 self.writer.write_all_defer_err(b"\n");
878 }
879
880 pub fn write_and_gate(&mut self, mut and_gate: OrderedAndGate<L>) {
881 if and_gate.inputs[0].code() < and_gate.inputs[1].code() {
882 and_gate.inputs.swap(0, 1);
883 }
884 let code_0 = and_gate.inputs[0].code();
885 let code_1 = and_gate.inputs[1].code();
886 assert!(code_0 <= self.code);
887 let delta_0 = self.code - code_0;
888 let delta_1 = code_0 - code_1;
889
890 self.write_binary_uint(delta_0);
891 self.write_binary_uint(delta_1);
892 self.code += 2;
893 }
894
895 fn write_binary_uint(&mut self, mut code: usize) {
896 let mut bytes = [0u8; (usize::BITS as usize + 6) / 7];
898 let mut len = 0;
899 loop {
900 bytes[len] = (code as u8) | 0x80;
901 code >>= 7;
902
903 len += 1;
904 if code == 0 {
905 break;
906 }
907 }
908
909 bytes[len - 1] &= 0x7f;
910
911 self.writer.write_all_defer_err(&bytes[..len]);
912 }
913
914 pub fn write_symbol(&mut self, symbol: &Symbol) {
915 let (prefix, index) = match symbol.target {
916 SymbolTarget::Input(index) => (b"i", index),
917 SymbolTarget::Output(index) => (b"o", index),
918 SymbolTarget::Latch(index) => (b"l", index),
919 SymbolTarget::BadStateProperty(index) => (b"b", index),
920 SymbolTarget::InvariantConstraint(index) => (b"c", index),
921 SymbolTarget::JusticeProperty(index) => (b"j", index),
922 SymbolTarget::FairnessConstraint(index) => (b"f", index),
923 };
924
925 self.writer.write_all_defer_err(prefix);
926 flussab::write::text::ascii_digits(&mut self.writer, index);
927 self.writer.write_all_defer_err(b" ");
928 self.writer.write_all_defer_err(symbol.name.as_bytes());
929 self.writer.write_all_defer_err(b"\n");
930 }
931
932 pub fn write_comment(&mut self, comment: &str) {
933 self.writer.write_all_defer_err(b"c\n");
934 self.writer.write_all_defer_err(comment.as_bytes());
935 self.writer.write_all_defer_err(b"\n");
936 }
937
938 pub fn write_ordered_aig(&mut self, aig: &OrderedAig<L>) {
939 self.write_header(&Header {
940 max_var_index: aig.max_var_index,
941 input_count: aig.input_count,
942 latch_count: aig.latches.len(),
943 output_count: aig.outputs.len(),
944 and_gate_count: aig.and_gates.len(),
945 bad_state_property_count: aig.bad_state_properties.len(),
946 invariant_constraint_count: aig.invariant_constraints.len(),
947 justice_property_count: aig.justice_properties.len(),
948 fairness_constraint_count: aig.fairness_constraints.len(),
949 });
950
951 for &latch in &aig.latches {
952 self.write_latch(latch);
953 }
954
955 for &output in &aig.outputs {
956 self.write_lit(output);
957 }
958
959 for &bad_state_property in &aig.bad_state_properties {
960 self.write_lit(bad_state_property);
961 }
962
963 for &invariant_constraint in &aig.invariant_constraints {
964 self.write_lit(invariant_constraint);
965 }
966
967 for justice_property in &aig.justice_properties {
968 self.write_count(justice_property.len());
969 }
970
971 for justice_property in &aig.justice_properties {
972 for &justice_property_local_fairness_constraint in justice_property {
973 self.write_lit(justice_property_local_fairness_constraint);
974 }
975 }
976
977 for &fairness_constraint in &aig.fairness_constraints {
978 self.write_lit(fairness_constraint);
979 }
980
981 for &and_gate in &aig.and_gates {
982 self.write_and_gate(and_gate);
983 }
984
985 for symbol in &aig.symbols {
986 self.write_symbol(symbol);
987 }
988
989 if let Some(comment) = &aig.comment {
990 self.write_comment(comment);
991 }
992 }
993}