1use itertools::Itertools;
2use ruleset::{Rule, RuleSet};
3
4use crate::utils::{interner::Interner, Result};
5
6pub mod ruleset;
7
8#[derive(PartialEq, Eq)]
9pub enum State {
10 Left,
11 Right,
12}
13
14pub fn parse(code: &str, interner: &mut Interner<String>) -> Result<RuleSet> {
16 let mut buffer = String::new();
17 let mut left: Vec<(usize, usize)> = vec![];
18 let mut right: Vec<(usize, usize)> = vec![];
19 let mut state = State::Right;
20
21 let hash = interner.intern("#");
22 let comment = interner.intern("--");
23 let string = interner.intern("string");
24 let variables = interner.intern("variables");
25
26 let mut delimiter = '|';
30
31 let mut ruleset: Vec<Rule> = Vec::new();
32
33 for c in code.chars() {
34 if c.is_whitespace() {
35 continue;
36 }
37 delimiter = c;
38 break;
39 }
40
41 for c in code.chars() {
42 if c == delimiter || c == ',' {
43 add_tuple(
44 &mut buffer,
45 if state == State::Left {
46 &mut left
47 } else {
48 &mut right
49 },
50 interner,
51 );
52 if c == delimiter {
53 if state == State::Left {
54 state = State::Right
55 } else {
56 if left.is_empty() && right.is_empty() {
61 } else {
62 if left == [(hash, 1)] {
63 make_variable_rules(
64 &right,
65 string,
66 interner,
67 delimiter,
68 &mut ruleset,
69 variables,
70 );
71 } else if left == [(comment, 1)] {
72 } else {
73 ruleset.push(Rule {
74 conditions: left.clone().into_boxed_slice(),
75 multiplicities: right.clone().into_boxed_slice(),
76 });
77 }
78
79 right.clear();
81 left.clear();
82 }
83
84 state = State::Left;
85 }
86 }
87 } else {
88 buffer.push(c);
89 }
90 }
91
92 add_tuple(
93 &mut buffer,
94 if state == State::Left {
95 &mut left
96 } else {
97 &mut right
98 },
99 interner,
100 );
101
102 ruleset.push(Rule {
103 conditions: left.into_boxed_slice(),
104 multiplicities: right.into_boxed_slice(),
105 });
106
107 let (facts, rules): (Vec<Rule>, Vec<Rule>) = ruleset.iter().cloned().partition(|r| r.is_fact());
108
109 Ok(RuleSet { facts, rules })
110}
111
112fn make_variable_rules(
113 right: &[(usize, usize)],
114 string: usize,
115 interner: &mut Interner<String>,
116 delimiter: char,
117 ruleset: &mut Vec<Rule>,
118 variables: usize,
119) {
120 if let Some(&(tuple, _)) = right.first() {
121 if tuple == string {
122 let name_interned = right.get(1).unwrap().0;
123 let name = interner.lookup(name_interned).unwrap().clone();
124
125 let str = right
126 .iter()
127 .skip(2)
128 .map(|s| interner.lookup(s.0).unwrap().clone())
129 .map(|s| {
130 if let Some(s) = s.strip_prefix("#") {
131 match s {
132 "COMMA" | "comma" => ",".to_string(),
133 "SPACE" | "space" => " ".to_string(),
134 "DELIM" | "delim" => delimiter.to_string(),
135 "HASH" | "hash" => "#".to_string(),
136 "CR" | "cr" => "\r".to_string(),
137 "NL" | "nl" => "\n".to_string(),
138 other => format!("#{other}"),
139 }
140 } else {
141 s
142 }
143 })
144 .collect::<Vec<String>>()
145 .join("");
146
147 let name_load = interner.intern(format!("{name}.load"));
148 let name_pointer = interner.intern(format!("{name}.pointer"));
149 let name_length = interner.intern(format!("{name}.length"));
150
151 let length = str.len();
152 let str_interned = interner.intern(str);
153 let ptr = interner.lookup(str_interned).unwrap().as_ptr() as usize;
154
155 ruleset.push(Rule {
156 conditions: vec![(name_load, 1)].into_boxed_slice(),
157 multiplicities: vec![(name_pointer, ptr), (name_length, length)].into_boxed_slice(),
158 });
159 } else if tuple == variables {
160 for (a, b) in right.iter().tuple_combinations().unique() {
161 make_copy(a, interner, b, ruleset);
162 make_copy(b, interner, a, ruleset);
163 }
164 }
165 }
166}
167
168fn make_copy(
169 left: &(usize, usize),
170 interner: &mut Interner<String>,
171 right: &(usize, usize),
172 ruleset: &mut Vec<Rule>,
173) {
174 let src_i = right.0;
175 let src = interner.lookup(src_i).unwrap().clone();
176 let dest_i = left.0;
177 let dest = interner.lookup(dest_i).unwrap().clone();
178
179 let copy = interner.intern(format!("{dest} = {src}"));
180 let r#move = interner.intern(format!("{src} -> {dest}"));
181 let src_backup = interner.intern(format!("*{dest} = {src} src backup"));
182
183 ruleset.push(Rule {
184 conditions: vec![(copy, 1), (src_i, 1)].into_boxed_slice(),
185 multiplicities: vec![(src_backup, 1), (dest_i, 1), (copy, usize::MAX)].into_boxed_slice(),
186 });
187
188 ruleset.push(Rule {
189 conditions: vec![(copy, 1)].into_boxed_slice(),
190 multiplicities: vec![].into_boxed_slice(),
191 });
192
193 ruleset.push(Rule {
194 conditions: vec![(src_backup, 1)].into_boxed_slice(),
195 multiplicities: vec![(src_i, 1)].into_boxed_slice(),
196 });
197
198 ruleset.push(Rule {
199 conditions: vec![(r#move, 1), (src_i, 1)].into_boxed_slice(),
200 multiplicities: vec![(dest_i, 1), (r#move, usize::MAX)].into_boxed_slice(),
201 });
202
203 ruleset.push(Rule {
204 conditions: vec![(r#move, 1)].into_boxed_slice(),
205 multiplicities: vec![].into_boxed_slice(),
206 });
207}
208
209#[inline]
210fn add_tuple(buffer: &mut String, side: &mut Vec<(usize, usize)>, interner: &mut Interner<String>) {
211 if !buffer.trim().is_empty() {
212 let (fact, multiplicity) = parse_multiplicity(buffer).expect("there should be a fact");
213
214 side.push((interner.intern(fact.trim().to_string()), multiplicity));
215 }
216
217 buffer.clear();
218}
219
220fn parse_multiplicity(buffer: &mut str) -> Option<(&str, usize)> {
221 let mut split = buffer.split(':');
222
223 let fact = split.next()?;
224
225 split.next().map_or(Some((buffer, 1)), |multiplicity| {
226 if let Ok(multiplicity) = str::parse(multiplicity.trim()) {
227 Some((fact, multiplicity))
228 } else {
229 Some((buffer, 1))
230 }
231 })
232}