1use std::{collections::BTreeMap, ops::Deref};
2use std::sync::Arc;
3
4use crate::{
5 ser_de::{SerDict, SerWord},
6 std_rt::{
7 new_runtime, ser_srw, BuiltinToken, NamedStdRuntimeWord, SerContext, StdFuncSeq,
8 StdRuntime, StdRuntimeWord, StdVecStack,
9 },
10 Error, RuntimeWord, StepResult, VerbSeqInner,
11};
12
13pub struct Dict {
14 pub bis: BTreeMap<String, BuiltinToken>,
15 pub data: BTreeMap<String, StdFuncSeq>,
16 pub(crate) shame_idx: usize,
17}
18
19impl Dict {
20 pub fn new() -> Self {
21 Self {
22 bis: BTreeMap::new(),
23 data: BTreeMap::new(),
24 shame_idx: 0,
25 }
26 }
27
28 pub fn serialize(&self) -> SerDict {
29 let mut out: BTreeMap<String, Vec<SerWord>> = BTreeMap::new();
30 let mut ctxt = SerContext::new();
31
32 for (word, val) in self.data.iter() {
33 out.insert(word.to_string(), ser_srw(&mut ctxt, &word, val));
34 }
35
36 let mut data = Vec::new();
37 for word in ctxt.seqs {
38 data.push(out.get(&word).unwrap().clone());
39 }
40
41 SerDict {
42 data,
43 bis: ctxt.bis,
44 }
45 }
46}
47
48pub struct Context {
49 pub rt: StdRuntime,
50 pub dict: Dict,
51}
52
53impl Context {
54
55
56 #[allow(dead_code)]
57 fn compile2(&mut self, data: &[String]) -> Result<Vec<NamedStdRuntimeWord>, Error> {
58 let mut vd_data: VecDeque<String> = data.iter().map(String::as_str).map(str::to_lowercase).collect();
59
60 let munched = muncher(&mut vd_data);
61 assert!(vd_data.is_empty());
62
63 let conv: Vec<NamedStdRuntimeWord> = munched.into_iter().map(|m| m.to_named_rt_words(&mut self.dict)).flatten().collect();
64
65 Ok(conv)
66 }
67
68 pub fn evaluate(&mut self, data: Vec<String>) -> Result<(), Error> {
69 match (data.first(), data.last()) {
70 (Some(f), Some(l)) if f == ":" && l == ";" => {
71 assert!(data.len() >= 3);
73
74 let name = data[1].to_lowercase();
75
76 let relevant = &data[2..][..data.len() - 3];
78
79 let compiled = Arc::new(self.compile2(relevant).unwrap());
81
82 self.dict.data.insert(name, StdFuncSeq { inner: compiled });
83 }
84 _ => {
85 if !data.is_empty() {
89 let name = format!("__{}", self.dict.shame_idx);
90 let comp = self.compile2(&data).unwrap();
92 self.dict.data.insert(
93 name.clone(),
94 StdFuncSeq {
95 inner: Arc::new(comp),
96 },
97 );
98 self.dict.shame_idx += 1;
99 let temp_compiled = RuntimeWord::VerbSeq(VerbSeqInner::from_word(name));
100 self.push_exec(temp_compiled);
101 }
102 }
103 }
104
105 Ok(())
106 }
107
108
109
110 pub fn serialize(&self) -> SerDict {
111 self.dict.serialize()
112 }
113
114 pub fn step(&mut self) -> Result<StepResult<BuiltinToken, String>, Error> {
115 self.rt.step()
116 }
117
118 pub fn data_stack(&self) -> &StdVecStack<i32> {
119 &self.rt.data_stk
120 }
121
122 pub fn return_stack(&self) -> &StdVecStack<i32> {
123 &self.rt.ret_stk
124 }
125
126 pub fn flow_stack(&self) -> &StdVecStack<RuntimeWord<BuiltinToken, String>> {
127 &self.rt.flow_stk
128 }
129
130 pub fn with_builtins(bi: &[(&'static str, fn(&mut StdRuntime) -> Result<(), Error>)]) -> Self {
131 let mut new = Context {
132 rt: new_runtime(),
133 dict: Dict::new(),
134 };
135
136 for (word, func) in bi {
137 new.dict
138 .bis
139 .insert(word.to_string(), BuiltinToken::new(*func));
140 }
141
142 new
143 }
144
145 pub fn output(&mut self) -> String {
146 self.rt.exchange_output()
147 }
148
149 pub fn push_exec(&mut self, word: StdRuntimeWord) {
150 self.rt.push_exec(word)
151 }
152}
153
154fn parse_num(input: &str) -> Option<i32> {
161 input.parse::<i32>().ok()
162}
163
164
165#[derive(Debug)]
167enum Chunk {
168 IfThen {
169 if_body: Vec<Chunk>,
170 },
171 IfElseThen {
172 if_body: Vec<Chunk>,
173 else_body: Vec<Chunk>,
174 },
175 DoLoop {
176 do_body: Vec<Chunk>,
177 },
178 Token(String),
179}
180
181impl Chunk {
182 fn to_named_rt_words(self, dict: &mut Dict) -> Vec<NamedStdRuntimeWord> {
184 let mut ret = vec![];
185
186 match self {
187 Chunk::IfThen { if_body } => {
188 let mut conv: VecDeque<NamedStdRuntimeWord> = if_body
190 .into_iter()
191 .map(|m| m.to_named_rt_words(dict))
192 .flatten()
193 .collect();
194
195 conv.push_front(NamedStdRuntimeWord {
196 name: "CRJ".into(),
197 word: RuntimeWord::CondRelativeJump { offset: conv.len() as i32, jump_on: false },
198 });
199
200 let conv: Vec<NamedStdRuntimeWord> = conv.into_iter().collect();
201 ret.extend(conv);
202 },
203 Chunk::IfElseThen { if_body, else_body } => {
204 let mut if_conv: VecDeque<NamedStdRuntimeWord> = if_body
205 .into_iter()
206 .map(|m| m.to_named_rt_words(dict))
207 .flatten()
208 .collect();
209
210 let else_conv: Vec<NamedStdRuntimeWord> = else_body
211 .into_iter()
212 .map(|m| m.to_named_rt_words(dict))
213 .flatten()
214 .collect();
215
216 if_conv.push_back(NamedStdRuntimeWord {
217 name: "UCRJ".into(),
218 word: RuntimeWord::UncondRelativeJump { offset: else_conv.len() as i32 },
219 });
220
221 if_conv.push_front(NamedStdRuntimeWord {
222 name: "CRJ".into(),
223 word: RuntimeWord::CondRelativeJump { offset: if_conv.len() as i32, jump_on: false },
224 });
225
226 let conv: Vec<NamedStdRuntimeWord> = if_conv.into_iter().chain(else_conv.into_iter()).collect();
227 ret.extend(conv);
228 },
229 Chunk::DoLoop { do_body } => {
230 let mut conv: VecDeque<NamedStdRuntimeWord> = do_body
232 .into_iter()
233 .map(|m| m.to_named_rt_words(dict))
234 .flatten()
235 .collect();
236
237 conv.push_back(NamedStdRuntimeWord {
238 word: RuntimeWord::Verb(BuiltinToken::new(crate::builtins::bi_priv_loop)),
239 name: "PRIV_LOOP".into(),
240 });
241
242 let len = conv.len();
243
244 conv.push_front(NamedStdRuntimeWord {
245 word: RuntimeWord::Verb(BuiltinToken::new(crate::builtins::bi_retstk_push)),
246 name: ">r".into(),
247 });
248 conv.push_front(NamedStdRuntimeWord {
249 word: RuntimeWord::Verb(BuiltinToken::new(crate::builtins::bi_retstk_push)),
250 name: ">r".into(),
251 });
252
253 conv.push_back(NamedStdRuntimeWord {
256 word: RuntimeWord::CondRelativeJump { offset: -1 * len as i32 - 1, jump_on: false },
257 name: "CRJ".into(),
258 });
259
260 let conv: Vec<NamedStdRuntimeWord> = conv.into_iter().collect();
261 ret.extend(conv);
262 },
263 Chunk::Token(tok) => {
264 ret.push(if let Some(bi) = dict.bis.get(&tok).cloned() {
265 NamedStdRuntimeWord {
266 name: tok,
267 word: RuntimeWord::Verb(bi.clone()),
268 }
269 } else if dict.data.contains_key(&tok) {
270 NamedStdRuntimeWord {
271 word: RuntimeWord::VerbSeq(VerbSeqInner::from_word(tok.clone())),
272 name: tok,
273 }
274 } else if let Some(num) = parse_num(&tok) {
275 NamedStdRuntimeWord {
276 word: RuntimeWord::LiteralVal(num),
277 name: format!("LIT({})", num),
278 }
279 } else {
280 panic!()
281 });
283 },
284 }
285
286 ret
287 }
288}
289
290use std::collections::VecDeque;
291
292fn muncher(data: &mut VecDeque<String>) -> Vec<Chunk> {
293 let mut chunks = vec![];
294 loop {
295 let next = if let Some(t) = data.pop_front() {
296 t
297 } else {
298 break;
299 };
300
301 match next.as_str() {
302 "do" => {
303 chunks.push(munch_do(data));
304 }
305 "if" => {
306 chunks.push(munch_if(data));
307 }
308 _ => chunks.push(Chunk::Token(next)),
309 }
310 }
311
312 chunks
313}
314
315fn munch_do(data: &mut VecDeque<String>) -> Chunk {
316 let mut chunks = vec![];
317 loop {
318 let next = if let Some(t) = data.pop_front() {
319 t
320 } else {
321 break;
322 };
323
324 match next.as_str() {
325 "do" => {
326 chunks.push(munch_do(data));
327 }
328 "if" => {
329 chunks.push(munch_if(data));
330 }
331 "loop" => {
332 return Chunk::DoLoop {
333 do_body: chunks,
334 }
335 }
336 _ => chunks.push(Chunk::Token(next)),
337 }
338 }
339
340 todo!()
342}
343
344fn munch_if(data: &mut VecDeque<String>) -> Chunk {
345 let mut chunks = vec![];
346 loop {
347 let next = if let Some(t) = data.pop_front() {
348 t
349 } else {
350 break;
351 };
352
353 match next.as_str() {
354 "do" => {
355 chunks.push(munch_do(data));
356 }
357 "if" => {
358 chunks.push(munch_if(data));
359 }
360 "then" => {
361 return Chunk::IfThen {
362 if_body: chunks,
363 }
364 }
365 "else" => {
366 return munch_else(data, chunks);
367 }
368 _ => chunks.push(Chunk::Token(next)),
369 }
370 }
371
372 todo!()
374}
375
376fn munch_else(data: &mut VecDeque<String>, if_body: Vec<Chunk>) -> Chunk {
377 let mut chunks = vec![];
378 loop {
379 let next = if let Some(t) = data.pop_front() {
380 t
381 } else {
382 break;
383 };
384
385 match next.as_str() {
386 "do" => {
387 chunks.push(munch_do(data));
388 }
389 "if" => {
390 chunks.push(munch_if(data));
391 }
392 "then" => {
393 return Chunk::IfElseThen {
394 if_body,
395 else_body: chunks,
396 }
397 }
398 _ => chunks.push(Chunk::Token(next)),
399 }
400 }
401
402 todo!()
404}