use std::collections::BTreeMap;
use std::sync::Arc;
use crate::{
ser_de::{SerDict, SerWord},
std_rt::{
new_runtime, ser_srw, BuiltinToken, NamedStdRuntimeWord, SerContext, StdFuncSeq,
StdRuntime, StdRuntimeWord, StdVecStack,
},
Error, RuntimeWord, StepResult, VerbSeqInner,
};
pub struct Dict {
pub bis: BTreeMap<String, BuiltinToken>,
pub data: BTreeMap<String, StdFuncSeq>,
pub(crate) shame_idx: usize,
}
impl Dict {
pub fn new() -> Self {
Self {
bis: BTreeMap::new(),
data: BTreeMap::new(),
shame_idx: 0,
}
}
pub fn serialize(&self) -> SerDict {
let mut out: BTreeMap<String, Vec<SerWord>> = BTreeMap::new();
let mut data_map: Vec<String> = Vec::new();
let mut ctxt = SerContext::new();
for (word, val) in self.data.iter() {
out.insert(word.to_string(), ser_srw(&mut ctxt, &word, val));
}
let mut data = Vec::new();
for word in ctxt.seqs {
data.push(out.get(&word).unwrap().clone());
data_map.push(word.clone());
}
SerDict {
data,
data_map: Some(data_map),
bis: ctxt.bis,
}
}
}
pub struct Context {
pub rt: StdRuntime,
pub dict: Dict,
}
impl Context {
pub fn load_ser_dict(&mut self, data: &SerDict) {
let data_map = if let Some(dm) = data.data_map.as_ref() {
dm.clone()
} else {
eprintln!("Error: dict has no name map! Refusing to load.");
return;
};
if !data.bis.iter().all(|bi| self.dict.bis.contains_key(bi)) {
eprintln!("Missing builtins! Refusing to load.");
return;
}
if data_map.len() != data.data.len() {
eprintln!("Data map size mismatch! Refusing to load.");
return;
}
for (name, word) in data_map.iter().zip(data.data.iter()) {
let cword = word
.iter()
.map(|x| match x {
SerWord::LiteralVal(v) => NamedStdRuntimeWord {
name: format!("LIT({})", v),
word: RuntimeWord::LiteralVal(*v),
},
SerWord::Verb(i) => {
let txt = data.bis.get(*i as usize).unwrap();
NamedStdRuntimeWord {
name: txt.clone(),
word: RuntimeWord::Verb(self.dict.bis.get(txt).unwrap().clone()),
}
}
SerWord::VerbSeq(i) => {
let txt = data_map.get(*i as usize).unwrap();
NamedStdRuntimeWord {
name: txt.clone(),
word: RuntimeWord::VerbSeq(VerbSeqInner::from_word(txt.to_string())),
}
}
SerWord::UncondRelativeJump { offset } => NamedStdRuntimeWord {
name: format!("UCRJ({})", offset),
word: RuntimeWord::UncondRelativeJump { offset: *offset },
},
SerWord::CondRelativeJump { offset, jump_on } => NamedStdRuntimeWord {
name: format!("CRJ({})", offset),
word: RuntimeWord::CondRelativeJump {
offset: *offset,
jump_on: *jump_on,
},
},
})
.collect::<Vec<_>>();
self.dict.data.insert(
name.clone(),
StdFuncSeq {
inner: Arc::new(cword),
},
);
}
}
fn compile(&mut self, data: &[String]) -> Result<Vec<NamedStdRuntimeWord>, Error> {
let mut vd_data: VecDeque<String> = data
.iter()
.map(String::as_str)
.map(str::to_lowercase)
.collect();
let munched = muncher(&mut vd_data);
assert!(vd_data.is_empty());
let conv: Vec<NamedStdRuntimeWord> = munched
.into_iter()
.map(|m| m.to_named_rt_words(&mut self.dict))
.flatten()
.collect();
Ok(conv)
}
pub fn evaluate(&mut self, data: Vec<String>) -> Result<(), Error> {
match (data.first(), data.last()) {
(Some(f), Some(l)) if f == ":" && l == ";" => {
assert!(data.len() >= 3);
let name = data[1].to_lowercase();
let relevant = &data[2..][..data.len() - 3];
let compiled = Arc::new(self.compile(relevant).unwrap());
self.dict.data.insert(name, StdFuncSeq { inner: compiled });
}
_ => {
if !data.is_empty() {
let name = format!("__{}", self.dict.shame_idx);
let comp = self.compile(&data).unwrap();
self.dict.data.insert(
name.clone(),
StdFuncSeq {
inner: Arc::new(comp),
},
);
self.dict.shame_idx += 1;
let temp_compiled = RuntimeWord::VerbSeq(VerbSeqInner::from_word(name));
self.push_exec(temp_compiled);
}
}
}
Ok(())
}
pub fn serialize(&self) -> SerDict {
self.dict.serialize()
}
pub fn step(&mut self) -> Result<StepResult<BuiltinToken, String>, Error> {
self.rt.step()
}
pub fn data_stack(&self) -> &StdVecStack<i32> {
&self.rt.data_stk
}
pub fn return_stack(&self) -> &StdVecStack<i32> {
&self.rt.ret_stk
}
pub fn flow_stack(&self) -> &StdVecStack<RuntimeWord<BuiltinToken, String>> {
&self.rt.flow_stk
}
pub fn with_builtins(bi: &[(&'static str, fn(&mut StdRuntime) -> Result<(), Error>)]) -> Self {
let mut new = Context {
rt: new_runtime(),
dict: Dict::new(),
};
for (word, func) in bi {
new.dict
.bis
.insert(word.to_string(), BuiltinToken::new(*func));
}
new
}
pub fn output(&mut self) -> String {
self.rt.exchange_output()
}
pub fn push_exec(&mut self, word: StdRuntimeWord) {
self.rt.push_exec(word)
}
}
fn parse_num(input: &str) -> Option<i32> {
input.parse::<i32>().ok()
}
#[derive(Debug)]
enum Chunk {
IfThen {
if_body: Vec<Chunk>,
},
IfElseThen {
if_body: Vec<Chunk>,
else_body: Vec<Chunk>,
},
DoLoop {
do_body: Vec<Chunk>,
},
Token(String),
Comment {
contents: Vec<String>,
}
}
impl Chunk {
fn to_named_rt_words(self, dict: &mut Dict) -> Vec<NamedStdRuntimeWord> {
let mut ret = vec![];
match self {
Chunk::IfThen { if_body } => {
let mut conv: VecDeque<NamedStdRuntimeWord> = if_body
.into_iter()
.map(|m| m.to_named_rt_words(dict))
.flatten()
.collect();
conv.push_front(NamedStdRuntimeWord {
name: "CRJ".into(),
word: RuntimeWord::CondRelativeJump {
offset: conv.len() as i32,
jump_on: false,
},
});
let conv: Vec<NamedStdRuntimeWord> = conv.into_iter().collect();
ret.extend(conv);
}
Chunk::IfElseThen { if_body, else_body } => {
let mut if_conv: VecDeque<NamedStdRuntimeWord> = if_body
.into_iter()
.map(|m| m.to_named_rt_words(dict))
.flatten()
.collect();
let else_conv: Vec<NamedStdRuntimeWord> = else_body
.into_iter()
.map(|m| m.to_named_rt_words(dict))
.flatten()
.collect();
if_conv.push_back(NamedStdRuntimeWord {
name: "UCRJ".into(),
word: RuntimeWord::UncondRelativeJump {
offset: else_conv.len() as i32,
},
});
if_conv.push_front(NamedStdRuntimeWord {
name: "CRJ".into(),
word: RuntimeWord::CondRelativeJump {
offset: if_conv.len() as i32,
jump_on: false,
},
});
let conv: Vec<NamedStdRuntimeWord> =
if_conv.into_iter().chain(else_conv.into_iter()).collect();
ret.extend(conv);
}
Chunk::DoLoop { do_body } => {
let mut conv: VecDeque<NamedStdRuntimeWord> = do_body
.into_iter()
.map(|m| m.to_named_rt_words(dict))
.flatten()
.collect();
conv.push_back(NamedStdRuntimeWord {
word: RuntimeWord::Verb(BuiltinToken::new(crate::builtins::bi_priv_loop)),
name: "PRIV_LOOP".into(),
});
let len = conv.len();
conv.push_front(NamedStdRuntimeWord {
word: RuntimeWord::Verb(BuiltinToken::new(crate::builtins::bi_retstk_push)),
name: ">r".into(),
});
conv.push_front(NamedStdRuntimeWord {
word: RuntimeWord::Verb(BuiltinToken::new(crate::builtins::bi_retstk_push)),
name: ">r".into(),
});
conv.push_back(NamedStdRuntimeWord {
word: RuntimeWord::CondRelativeJump {
offset: -1 * len as i32 - 1,
jump_on: false,
},
name: "CRJ".into(),
});
let conv: Vec<NamedStdRuntimeWord> = conv.into_iter().collect();
ret.extend(conv);
}
Chunk::Token(tok) => {
ret.push(if let Some(bi) = dict.bis.get(&tok).cloned() {
NamedStdRuntimeWord {
name: tok,
word: RuntimeWord::Verb(bi.clone()),
}
} else if dict.data.contains_key(&tok) {
NamedStdRuntimeWord {
word: RuntimeWord::VerbSeq(VerbSeqInner::from_word(tok.clone())),
name: tok,
}
} else if let Some(num) = parse_num(&tok) {
NamedStdRuntimeWord {
word: RuntimeWord::LiteralVal(num),
name: format!("LIT({})", num),
}
} else {
panic!("{:?}", tok);
});
}
Chunk::Comment { .. } => {
}
}
ret
}
}
use std::collections::VecDeque;
fn muncher(data: &mut VecDeque<String>) -> Vec<Chunk> {
let mut chunks = vec![];
loop {
let next = if let Some(t) = data.pop_front() {
t
} else {
break;
};
match next.as_str() {
"do" => {
chunks.push(munch_do(data));
}
"if" => {
chunks.push(munch_if(data));
}
"(" => {
chunks.push(Chunk::Comment { contents: munch_comment(data) });
}
_ => chunks.push(Chunk::Token(next)),
}
}
chunks
}
fn munch_comment(data: &mut VecDeque<String>) -> Vec<String> {
let mut contents = vec![];
loop {
let next = if let Some(t) = data.pop_front() {
t
} else {
break;
};
match next.as_str() {
"(" => {
contents.extend(munch_comment(data));
}
")" => {
return contents;
}
_ => {
contents.push(next);
}
}
}
todo!()
}
fn munch_do(data: &mut VecDeque<String>) -> Chunk {
let mut chunks = vec![];
loop {
let next = if let Some(t) = data.pop_front() {
t
} else {
break;
};
match next.as_str() {
"do" => {
chunks.push(munch_do(data));
}
"if" => {
chunks.push(munch_if(data));
}
"loop" => return Chunk::DoLoop { do_body: chunks },
_ => chunks.push(Chunk::Token(next)),
}
}
todo!()
}
fn munch_if(data: &mut VecDeque<String>) -> Chunk {
let mut chunks = vec![];
loop {
let next = if let Some(t) = data.pop_front() {
t
} else {
break;
};
match next.as_str() {
"do" => {
chunks.push(munch_do(data));
}
"if" => {
chunks.push(munch_if(data));
}
"then" => return Chunk::IfThen { if_body: chunks },
"else" => {
return munch_else(data, chunks);
}
_ => chunks.push(Chunk::Token(next)),
}
}
todo!()
}
fn munch_else(data: &mut VecDeque<String>, if_body: Vec<Chunk>) -> Chunk {
let mut chunks = vec![];
loop {
let next = if let Some(t) = data.pop_front() {
t
} else {
break;
};
match next.as_str() {
"do" => {
chunks.push(munch_do(data));
}
"if" => {
chunks.push(munch_if(data));
}
"then" => {
return Chunk::IfElseThen {
if_body,
else_body: chunks,
}
}
_ => chunks.push(Chunk::Token(next)),
}
}
todo!()
}