1use num_bigint::BigInt;
2
3use std::cmp::Reverse;
4use std::rc::Rc;
5use std::ops::Range;
6use std::collections::HashMap;
7
8use crate::label::Label;
9
10pub use crate::Program;
11
12#[derive(Debug, Clone)]
13pub struct SourceLoc {
14 pub line: usize,
15 pub column: usize,
16 pub span: Range<usize>,
17 pub label: Option<Rc<Label>>
18}
19
20#[derive(Debug, Clone)]
21pub enum Command {
22 Push {value: Integer},
23 PushBig {value: BigInteger},
24 Duplicate,
25 Copy {index: usize},
26 Swap,
27 Discard,
28 Slide {amount: usize},
29 Add,
30 Subtract,
31 Multiply,
32 Divide,
33 Modulo,
34 Set,
35 Get,
36 Label,
37 Call {index: usize},
38 Jump {index: usize},
39 JumpIfZero {index: usize},
40 JumpIfNegative {index: usize},
41 EndSubroutine,
42 EndProgram,
43 PrintChar,
44 PrintNum,
45 InputChar,
46 InputNum
47}
48
49pub type Integer = isize;
50
51pub type BigInteger = BigInt;
52
53#[derive(Debug, Clone)]
54pub enum SizedInteger {
55 Big(BigInteger),
56 Small(Integer)
57}
58
59impl Program {
60 pub fn strip(&mut self) {
62 self.source = None;
63 self.locs = None;
64 }
65
66 pub fn minify(&mut self) {
68 let locs = if let Some(ref mut locs) = self.locs {
70 locs
71 } else {
72 self.locs = Some(self.commands.iter().map(|_| SourceLoc {line: 0, column: 0, span: 0..0, label: None}).collect());
73 self.locs.as_mut().unwrap()
74 };
75
76 let mut label_count = HashMap::<usize, usize>::new();
78 for (i, op) in self.commands.iter().enumerate() {
79 match *op {
80 Command::Label => *label_count.entry(i + 1).or_insert(0) += 1,
81 Command::Call {index}
82 | Command::Jump {index}
83 | Command::JumpIfZero {index}
84 | Command::JumpIfNegative {index} => *label_count.entry(index).or_insert(0) += 1,
85 _ => ()
86 }
87 }
88
89 let mut label_count: Vec<_> = label_count.into_iter().collect();
92 label_count.sort_by_key(|&(index, count)| (Reverse(count), index));
93
94 let mut length = 0usize;
96 let mut value = 0usize;
97 let mut new_label = || {
98 let mut label = Label::new();
100 for i in (0..length).rev() {
101 label.push(value & (1 << i) != 0);
102 }
103 value += 1;
105 if value == (1 << length) {
106 length += 1;
107 value = 0;
108 }
109 Rc::new(label)
110 };
111
112 let label_map: HashMap<_, _> = label_count.iter().map(|&(i, _)| (i, new_label())).collect();
114
115 for ((i, op), loc) in self.commands.iter().enumerate().zip(locs) {
117 match *op {
118 Command::Label => loc.label = Some(label_map[&(i + 1)].clone()),
119 Command::Call {index}
120 | Command::Jump {index}
121 | Command::JumpIfZero {index}
122 | Command::JumpIfNegative {index} => loc.label = Some(label_map[&index].clone()),
123 _ => ()
124 }
125 }
126 }
127}