Last active
February 28, 2019 16:49
-
-
Save mbillingr/196076b4f5f3c308c339d7ae7400d1f7 to your computer and use it in GitHub Desktop.
Deriving Stack Effects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from functools import cmp_to_key | |
| class StackItem: pass | |
| class Row(StackItem): | |
| def __init__(self, name=''): | |
| self.name = name | |
| def __repr__(self): | |
| return '..' + self.name | |
| class Item(StackItem): | |
| def __init__(self, name): | |
| self.name = name | |
| def __repr__(self): | |
| return self.name | |
| class Quot(StackItem): | |
| def __init__(self, name, inputs, outputs): | |
| self.name = name | |
| self.inputs = Sequence(inputs) | |
| self.outputs = Sequence(outputs) | |
| def __repr__(self): | |
| return '{}({} -- {})'.format(self.name, self.inputs, self.outputs) | |
| def substitute(self, a, b): | |
| self.inputs.substitute(a, b) | |
| self.inputs.flatten() | |
| self.outputs.substitute(a, b) | |
| self.outputs.flatten() | |
| def match(self, other): | |
| substitutions = [] | |
| substitutions += self.inputs.match(other.inputs) | |
| substitutions += self.outputs.match(other.outputs) | |
| return substitutions | |
| class Sequence: | |
| def __init__(self, values=None): | |
| if values is None: | |
| self.values = [] | |
| elif isinstance(values, Sequence): | |
| self.values = values.values | |
| else: | |
| self.values = list(values) | |
| def len(self): | |
| return len(self.values) | |
| def contains(self, item): | |
| return item in self.values | |
| def top(self): | |
| return self.values[-1] | |
| def pop(self): | |
| return self.values.pop() | |
| def insert(self, i, x): | |
| assert isinstance(x, StackItem) | |
| self.values.insert(i, x) | |
| def grow(self, item_or_items): | |
| try: | |
| assert all(isinstance(x, StackItem) for x in item_or_items.values) | |
| self.values.extend(item_or_items.values) | |
| return | |
| except AttributeError: | |
| pass | |
| try: | |
| assert all(isinstance(x, StackItem) for x in item_or_items) | |
| self.values.extend(item_or_items) | |
| except TypeError: | |
| pass | |
| assert isinstance(item_or_items, StackItem) | |
| self.values.append(item_or_items) | |
| def substitute(self, a, b): | |
| for i in range(len(self.values)): | |
| if self.values[i] == a: | |
| self.values[i] = b | |
| elif isinstance(self.values[i], Quot): | |
| self.values[i].substitute(a, b) | |
| self.flatten() | |
| def match(self, other): | |
| substitutions = [] | |
| for i, j in zip(range(self.len())[::-1], range(other.len())[::-1]): | |
| a, b = self.values[i], other.values[j] | |
| if isinstance(a, Item) and isinstance(b, Item): | |
| substitutions += [(a, b)] | |
| elif isinstance(a, Row): | |
| substitutions += [(a, Sequence(other.values[:j+1]))] | |
| break | |
| elif isinstance(b, Row): | |
| substitutions += [(b, Sequence(self.values[:i+1]))] | |
| break | |
| else: | |
| raise NotImplementedError('match {} with {}'.format(type(a).__name__, type(b).__name__)) | |
| return substitutions | |
| def flatten(self): | |
| flat = [] | |
| for x in self.values: | |
| try: | |
| flat.extend(x.values) | |
| except AttributeError: | |
| flat.append(x) | |
| self.values = flat | |
| def cmp(self, other): | |
| for i, j in zip(range(self.len())[::-1], range(other.len())[::-1]): | |
| a, b = self.values[i], other.values[j] | |
| if isinstance(a, Item) and isinstance(b, Item): | |
| continue | |
| elif isinstance(a, Row) and isinstance(b, Row): | |
| return 0 | |
| elif isinstance(a, Row): | |
| return -1 | |
| elif isinstance(b, Row): | |
| return 1 | |
| else: | |
| raise NotImplementedError('compare {} with {}'.format(type(a).__name__, type(b).__name__)) | |
| def __repr__(self): | |
| return ' '.join(str(i) for i in self.values) | |
| def cmp_items(a, b): | |
| if isinstance(a, Row) and isinstance(b, Row): | |
| return 0 | |
| if isinstance(a, Item) and isinstance(b, Item): | |
| return 0 | |
| if isinstance(a, Quot) and isinstance(b, Quot): | |
| a.inputs.cmp(b.inputs) | |
| a.outputs.cmp(b.outputs) | |
| return 0 | |
| if isinstance(a, Item) and isinstance(b, Quot): | |
| return -1 | |
| if isinstance(a, Sequence) and isinstance(b, Row): | |
| return 1 | |
| if isinstance(a, Sequence) and isinstance(b, Sequence): | |
| return a.cmp(b) | |
| raise NotImplementedError('compare {} with {}'.format(type(a).__name__, type(b).__name__)) | |
| class AbstractStack: | |
| def __init__(self): | |
| r = Row('a') | |
| self.inputs = Sequence([r]) | |
| self.values = Sequence([r]) | |
| self.substitutions = Substitutions() | |
| def __repr__(self): | |
| return '{} -- {} ... with {}'.format(self.inputs, self.values, self.substitutions) | |
| def pop(self, targets): | |
| #targets = self.substitutions.check(targets) | |
| try: | |
| iter(targets) | |
| except TypeError: | |
| target = targets | |
| return self._pop(target) | |
| return [self._pop(t) for t in targets[::-1]][::-1] | |
| def _pop(self, target): | |
| top = self.values.top() | |
| if isinstance(target, Row): | |
| x, self.values = self.values, Sequence() | |
| self.substitute(target, x) | |
| return x | |
| elif isinstance(top, Item): | |
| self.substitute(target, top) | |
| self.values.pop() | |
| return target | |
| elif isinstance(top, Row): | |
| self.add_input(target) | |
| return target | |
| elif isinstance(top, Quot) and isinstance(target, Quot): | |
| for a, b in top.match(target): | |
| self.substitute(a, b) | |
| target.substitute(a, b) | |
| self.values.pop() | |
| self.substitute(target, top) | |
| return target | |
| else: | |
| raise NotImplementedError('pop {} from {}'.format(type(target).__name__, type(top).__name__)) | |
| def add_input(self, x): | |
| self.inputs.insert(1, x) | |
| def push(self, item): | |
| item = self.substitutions.check(item) | |
| self.values.grow(item) | |
| def substitute(self, a, b): | |
| for a, b in self.substitutions.add(a, b): | |
| self.inputs.substitute(a, b) | |
| self.values.substitute(a, b) | |
| self.inputs.flatten() | |
| self.values.flatten() | |
| class Substitutions: | |
| def __init__(self): | |
| self.subs = {} | |
| def add(self, a, b): | |
| items = [a, b] | |
| if a in self.subs: | |
| items.append(self.subs[a]) | |
| if b in self.subs: | |
| items.append(self.subs[b]) | |
| items.sort(key=cmp_to_key(cmp_items)) | |
| b = items[-1] | |
| try: | |
| iter(b) | |
| b = Sequence(b) | |
| except TypeError: | |
| if a == b: [] | |
| b = Sequence([b]) | |
| b.flatten() | |
| resubs = [] | |
| for a in items[:-1]: | |
| if isinstance(a, Sequence): | |
| if a.len() > 1: | |
| raise TypeError("cannot substitute for sequence") | |
| a = a.values[0] | |
| if b.contains(a): | |
| raise RuntimeError("Invalid Substitution") | |
| self.subs[a] = b | |
| resubs.append((a, b)) | |
| return resubs | |
| def check(self, x): | |
| try: | |
| try: | |
| return Sequence([self.subs[i] for i in x.values]) | |
| except AttributeError: | |
| return self.subs[x] | |
| except KeyError: | |
| return x | |
| def __repr__(self): | |
| return str(self.subs) | |
| def test4(): | |
| astack = AbstractStack() | |
| # [ + ] (..b -- ..b g(..e x -- ..e z)) | |
| e = Row('e') | |
| g = astack.push(Quot('g', [e, Item('x')], [e, Item('z')])) | |
| # (..c f(..d i j -- ..d k) - ..c) | |
| try: | |
| d = Row('d') | |
| f = astack.pop(Quot('f', [d, Item('i'), Item('j')], [d, Item('k')])) | |
| c = astack.pop(Row('c')) | |
| astack.push(c) | |
| print("Should have failed:", astack) | |
| except RuntimeError: | |
| print("OK") | |
| def test3(): | |
| astack = AbstractStack() | |
| # [ + ] (..b -- ..b g(..e x y -- ..e z)) | |
| e = Row('e') | |
| g = astack.push(Quot('g', [e, Item('x'), Item('y')], [e, Item('z')])) | |
| # CALL (..c f(..c -- ..d) - ..d) | |
| c = Row('c') | |
| d = Row('d') | |
| f = astack.pop(Quot('f', [c], [d])) | |
| c = astack.pop(c) | |
| astack.push(d) | |
| print(astack) | |
| def test2(): | |
| astack = AbstractStack() | |
| # SWAP (..a x y -- ..a y x) | |
| y = astack.pop(Item('y')) | |
| x = astack.pop(Item('x')) | |
| r = astack.pop(Row('a')) | |
| astack.push(r) | |
| astack.push(y) | |
| astack.push(x) | |
| # CALL (..a f(..a -- ..b) - ..b) | |
| a = Row('a') | |
| b = Row('b') | |
| f = astack.pop(Quot('f', [a], [b])) | |
| a = astack.pop(a) | |
| astack.push(b) | |
| print(astack) | |
| def test1(): | |
| astack = AbstractStack() | |
| # SWAP (..a x y -- ..a y x) | |
| y = astack.pop(Item('y')) | |
| x = astack.pop(Item('x')) | |
| r = astack.pop(Row('a')) | |
| astack.push(r) | |
| astack.push(y) | |
| astack.push(x) | |
| # DROP (..b z -- ..b) | |
| z = astack.pop(Item('z')) | |
| r = astack.pop(Row('b')) | |
| astack.push(r) | |
| # DROP (..b z -- ..b) | |
| z = astack.pop(Item('z')) | |
| r = astack.pop(Row('b')) | |
| astack.push(r) | |
| # DROP (..b z -- ..b) | |
| z = astack.pop(Item('z')) | |
| r = astack.pop(Row('b')) | |
| astack.push(r) | |
| print(astack) | |
| test1() | |
| test2() | |
| test3() | |
| test4() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::cell::RefCell; | |
| use std::collections::HashMap; | |
| use std::hash::{Hash, Hasher}; | |
| use std::iter::FromIterator; | |
| use std::rc::Rc; | |
| use std::mem::replace; | |
| type ItemRef = RefHash<StackItem>; | |
| enum StackItem { | |
| Row(String), | |
| Item(String), | |
| Quotation(String, RefCell<Sequence>, RefCell<Sequence>), | |
| } | |
| impl StackItem { | |
| fn anonymous_row() -> ItemRef { | |
| RefHash::new(Rc::new(StackItem::Row(String::new()))) | |
| } | |
| fn item(name: &str) -> ItemRef { | |
| RefHash::new(Rc::new(StackItem::Item(name.to_string()))) | |
| } | |
| fn row(name: &str) -> ItemRef { | |
| RefHash::new(Rc::new(StackItem::Row(name.to_string()))) | |
| } | |
| fn quot(name: &str, inputs: &[ItemRef], outputs: &[ItemRef]) -> ItemRef { | |
| RefHash::new(Rc::new(StackItem::Quotation(name.to_string(), | |
| RefCell::new(inputs.iter().cloned().collect()), | |
| RefCell::new(outputs.iter().cloned().collect())))) | |
| } | |
| fn compare(&self, other: &Self) -> ItemOrd { | |
| use StackItem::*; | |
| use ItemOrd::*; | |
| match (self, other) { | |
| (Row(_), Row(_)) => Equivalent, | |
| (Item(_), Item(_)) => Equivalent, | |
| (Quotation(_, ia, oa), Quotation(_, ib, ob)) => { | |
| // try to catch incompatible quotations | |
| if let Invalid = ia.borrow().compare(&ib.borrow()) { return Invalid } | |
| if let Invalid = oa.borrow().compare(&ob.borrow()) { return Invalid } | |
| // but consider them equivalent in general. | |
| Equivalent | |
| } | |
| (Item(_), Quotation(_, _, _)) => MoreGeneral, | |
| (Quotation(_, _, _), Item(_)) => MoreSpecific, | |
| (Row(_), _) => MoreGeneral, | |
| (_, Row(_)) => MoreSpecific, | |
| } | |
| } | |
| fn substitute(&self, a: &ItemRef, b: &Sequence) { | |
| match self { | |
| StackItem::Row(_) => {}, | |
| StackItem::Item(_) => {} | |
| StackItem::Quotation(_, inps, outs) => { | |
| inps.borrow_mut().substitute(a, b); | |
| outs.borrow_mut().substitute(a, b); | |
| } | |
| } | |
| } | |
| } | |
| enum ItemOrd { | |
| MoreGeneral, | |
| Equivalent, | |
| MoreSpecific, | |
| Invalid, | |
| } | |
| impl From<ItemOrd> for std::cmp::Ordering { | |
| fn from(io: ItemOrd) -> Self { | |
| match io { | |
| ItemOrd::MoreGeneral => std::cmp::Ordering::Less, | |
| ItemOrd::Equivalent => std::cmp::Ordering::Equal, | |
| ItemOrd::MoreSpecific => std::cmp::Ordering::Greater, | |
| ItemOrd::Invalid => panic!("Invalid something somewhere"), | |
| } | |
| } | |
| } | |
| #[derive(Default, Clone)] | |
| struct Sequence { | |
| values: Vec<ItemRef>, | |
| } | |
| impl Sequence { | |
| fn new() -> Self { | |
| Sequence::default() | |
| } | |
| fn single(item: ItemRef) -> Self { | |
| Sequence { | |
| values: vec![item], | |
| } | |
| } | |
| fn len(&self) -> usize { | |
| self.values.len() | |
| } | |
| fn contains(&self, item: &ItemRef) -> bool { | |
| self.values.contains(item) | |
| } | |
| fn extend(&mut self, other: Sequence) { | |
| self.values.extend(other.values) | |
| } | |
| fn insert(&mut self, idx: usize, item: ItemRef) { | |
| self.values.insert(idx, item) | |
| } | |
| fn pop(&mut self) -> Option<ItemRef> { | |
| self.values.pop() | |
| } | |
| fn into_item(self) -> ItemRef { | |
| assert_eq!(self.len(), 1); | |
| self.values.into_iter().next().unwrap() | |
| } | |
| fn substitute(&mut self, a: &ItemRef, b: &Sequence) { | |
| let mut i = 0; | |
| while i < self.len() { | |
| if &self.values[i] == a { | |
| let mut tmp = Vec::from(&self.values[..i]); | |
| tmp.extend(b.values.clone()); | |
| tmp.extend(self.values[i+1..].iter().cloned()); | |
| self.values = tmp; | |
| i += b.len(); | |
| } else { | |
| self.values[i].substitute(a, b); | |
| i += 1; | |
| } | |
| } | |
| } | |
| fn compare(&self, other: &Sequence) -> ItemOrd { | |
| use ItemOrd::*; | |
| let av = self.values.iter().rev(); | |
| let bv = other.values.iter().rev(); | |
| for (a, b) in av.zip(bv) { | |
| match a.compare(b) { | |
| Equivalent => {}, | |
| other => return other | |
| } | |
| } | |
| if self.len() == other.len() { | |
| Equivalent | |
| } else { | |
| Invalid | |
| } | |
| } | |
| fn match_effects(&self, other: &Sequence) -> Vec<(ItemRef, Sequence)> { | |
| use StackItem::*; | |
| let mut subs = vec![]; | |
| for (i, j) in (0..self.len()).rev().zip((0..other.len()).rev()) { | |
| let a = &self.values[i]; | |
| let b = &other.values[j]; | |
| match (&**a, &**b) { | |
| (Item(_), Item(_)) => subs.push((a.clone(), Sequence::single(b.clone()))), | |
| (Item(_), Quotation(_, _, _)) => subs.push((a.clone(), Sequence::single(b.clone()))), | |
| (Quotation(_, _, _), Item(_)) => subs.push((b.clone(), Sequence::single(a.clone()))), | |
| (Quotation(_, ref ia, ref oa), Quotation(_, ref ib, ref ob)) => { | |
| subs.extend(ia.borrow().match_effects(&ib.borrow())); | |
| subs.extend(oa.borrow().match_effects(&ob.borrow())); | |
| }, | |
| (Row(_), _) => { | |
| subs.push((a.clone(), Sequence::from_iter(&other.values[..=j]))); | |
| break | |
| } | |
| (_, Row(_)) => { | |
| subs.push((b.clone(), Sequence::from_iter(&self.values[..=i]))); | |
| break | |
| } | |
| } | |
| } | |
| subs | |
| } | |
| } | |
| impl std::iter::FromIterator<ItemRef> for Sequence { | |
| fn from_iter<I: IntoIterator<Item=ItemRef>>(input: I) -> Self { | |
| Sequence { | |
| values: input.into_iter().collect(), | |
| } | |
| } | |
| } | |
| impl<'a> std::iter::FromIterator<&'a ItemRef> for Sequence { | |
| fn from_iter<I: IntoIterator<Item=&'a ItemRef>>(input: I) -> Self { | |
| Sequence { | |
| values: input.into_iter().cloned().collect(), | |
| } | |
| } | |
| } | |
| impl From<ItemRef> for Sequence { | |
| fn from(item: ItemRef) -> Self { | |
| Sequence { | |
| values: vec![item] | |
| } | |
| } | |
| } | |
| struct Substitutions { | |
| subs: HashMap<ItemRef, Sequence>, | |
| } | |
| impl Substitutions { | |
| fn new() -> Self { | |
| Substitutions { | |
| subs: HashMap::new(), | |
| } | |
| } | |
| fn find(&self, item: ItemRef) -> Sequence { | |
| self.subs.get(&item).cloned().unwrap_or(Sequence::single(item)) | |
| } | |
| fn add_sequence(&mut self, a: ItemRef, b: Sequence) -> Vec<(ItemRef, Sequence)> { | |
| let mut items = vec![]; | |
| if let Some(item) = self.subs.get(&a) { | |
| items.push(item.clone()); | |
| } | |
| items.push(Sequence::single(a)); | |
| items.push(b); | |
| items.sort_unstable_by(|x, y|{ | |
| x.compare(y).into() | |
| }); | |
| let b = items.pop().unwrap(); | |
| let mut subs = vec![]; | |
| for a in items.into_iter().map(Sequence::into_item) { | |
| if b.contains(&a) { | |
| panic!("Invalid Substitution") | |
| } | |
| self.subs.insert(a.clone(), b.clone()); | |
| subs.push((a, b.clone())); | |
| } | |
| subs | |
| } | |
| } | |
| struct AbstractStack { | |
| inputs: Sequence, | |
| values: Sequence, | |
| subs: Substitutions, | |
| } | |
| impl AbstractStack { | |
| fn new() -> Self { | |
| let r = [StackItem::anonymous_row()]; | |
| AbstractStack { | |
| inputs: Sequence::from_iter(&r), | |
| values: Sequence::from_iter(&r), | |
| subs: Substitutions::new(), | |
| } | |
| } | |
| fn pop<T: Into<Sequence>>(&mut self, x: T) -> Sequence { | |
| self.pop_sequence(x.into()) | |
| } | |
| fn push<T: Into<Sequence>>(&mut self, x: T) { | |
| self.push_sequence(x.into()) | |
| } | |
| fn pop_sequence(&mut self, mut targets: Sequence) -> Sequence { | |
| let mut result = Sequence::new(); | |
| while let Some(target) = targets.pop() { | |
| result.extend(self.pop_item(target)); | |
| } | |
| result | |
| } | |
| fn pop_item(&mut self, target: ItemRef) -> Sequence { | |
| if let StackItem::Row(_) = *target { | |
| let x = replace(&mut self.values, Sequence::new()); | |
| self.substitute(&target, &x); | |
| return x | |
| } | |
| match self.values.pop() { | |
| None => panic!("Abstract Stack Underflow"), | |
| Some(top) => match *top { | |
| StackItem::Item(_) => { | |
| self.substitute(&target, &Sequence::single(top.clone())); | |
| return Sequence::single(top) | |
| } | |
| StackItem::Row(_) => { | |
| self.add_input(target.clone()); | |
| self.push_item(top); | |
| return Sequence::single(target); | |
| } | |
| StackItem::Quotation(_, ref ia, ref oa) => { | |
| if let StackItem::Quotation(_, ref ib, ref ob) = *target { | |
| let mut subs = vec![]; | |
| subs.extend(ia.borrow().match_effects(&ib.borrow())); | |
| subs.extend(oa.borrow().match_effects(&ob.borrow())); | |
| for (a, b) in subs { | |
| self.substitute(&a, &b); | |
| target.substitute(&a, &b); | |
| } | |
| return Sequence::single(target) | |
| } else { | |
| unimplemented!() | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fn push_item(&mut self, item: ItemRef) { | |
| self.values.extend(self.subs.find(item)); | |
| } | |
| fn push_sequence(&mut self, items: Sequence) { | |
| if items.len() == 1 { | |
| self.push_item(items.into_item()); | |
| } else { | |
| self.values.extend(items); | |
| } | |
| } | |
| fn add_input(&mut self, item: ItemRef) { | |
| self.inputs.insert(1, item); | |
| } | |
| fn substitute(&mut self, a: &ItemRef, b: &Sequence) { | |
| for (a, b) in self.subs.add_sequence(a.clone(), b.clone()) { | |
| self.inputs.substitute(&a, &b); | |
| self.values.substitute(&a, &b); | |
| } | |
| } | |
| } | |
| impl std::fmt::Debug for AbstractStack { | |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
| write!(f, "{:?} -- {:?} ...with {:?}", self.inputs, self.values, self.subs) | |
| } | |
| } | |
| impl std::fmt::Debug for Sequence { | |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
| let names: Vec<_> = self.values.iter().map(|x| format!("{:?}", x)).collect(); | |
| write!(f, "{}", names.join(" ")) | |
| } | |
| } | |
| impl std::fmt::Debug for Substitutions { | |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
| write!(f, "{:?}", self.subs) | |
| } | |
| } | |
| impl std::fmt::Debug for StackItem { | |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
| match self { | |
| StackItem::Row(name) => write!(f, "..{}", name), | |
| StackItem::Item(name) => write!(f, "{}", name), | |
| StackItem::Quotation(name, a, b) => write!(f, "{}({:?} -- {:?})", name, a.borrow(), b.borrow()), | |
| } | |
| } | |
| } | |
| /// Helper for hashing by Rc identity | |
| pub struct RefHash<T>{ | |
| inner: Rc<T>, | |
| } | |
| impl<T> RefHash<T>{ | |
| pub fn new(inner: Rc<T>) -> Self{ | |
| return RefHash{inner} | |
| } | |
| } | |
| impl<T> Hash for RefHash<T> { | |
| fn hash<H: Hasher>(&self, state: &mut H) { | |
| let ptr = Rc::into_raw(self.inner.clone()); | |
| ptr.hash(state); | |
| let _ = unsafe{ Rc::from_raw(ptr) }; | |
| } | |
| } | |
| impl<T> PartialEq for RefHash<T> { | |
| fn eq(&self, other: &Self) -> bool { | |
| return Rc::ptr_eq(&self.inner, &other.inner); | |
| } | |
| } | |
| impl<T> Eq for RefHash<T> {} | |
| impl<T> Clone for RefHash<T> { | |
| fn clone(&self) -> Self { | |
| RefHash { | |
| inner: self.inner.clone() | |
| } | |
| } | |
| } | |
| impl<T> std::ops::Deref for RefHash<T> { | |
| type Target = T; | |
| fn deref(&self) -> &T { | |
| &*self.inner | |
| } | |
| } | |
| impl<T: std::fmt::Debug> std::fmt::Debug for RefHash<T> { | |
| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
| write!(f, "{:?}", self.inner) | |
| } | |
| } | |
| fn main() { | |
| //////////////////////////////////////////////////////////////////////////// | |
| let mut astack = AbstractStack::new(); | |
| println!("{:?}", astack); | |
| // SWAP (..a x y -- ..a y x) | |
| let y = astack.pop(StackItem::item("y")); | |
| let x = astack.pop(StackItem::item("x")); | |
| let r = astack.pop(StackItem::row("a")); | |
| astack.push(r); | |
| astack.push(y); | |
| astack.push(x); | |
| println!("{:?}", astack); | |
| // DROP (..b z -- ..b) | |
| astack.pop(StackItem::item("z")); | |
| let b = astack.pop(StackItem::row("b")); | |
| astack.push(b); | |
| // DROP (z -- ) | |
| astack.pop(StackItem::item("z")); | |
| // DROP (z -- ) | |
| astack.pop(StackItem::item("z")); | |
| println!("{:?}", astack); | |
| //////////////////////////////////////////////////////////////////////////// | |
| println!("--------------------------------------------------------"); | |
| let mut astack = AbstractStack::new(); | |
| // SWAP (x y -- y x) | |
| let y = astack.pop(StackItem::item("y")); | |
| let x = astack.pop(StackItem::item("x")); | |
| astack.push(y); | |
| astack.push(x); | |
| println!("{:?}", astack); | |
| // CALL (..a f(..a -- ..b) - ..b) | |
| let a = StackItem::row("a"); | |
| let b = StackItem::row("b"); | |
| astack.pop(StackItem::quot("f", &[a.clone()], &[b.clone()])); | |
| astack.pop(a); | |
| astack.push(b); | |
| println!("{:?}", astack); | |
| //////////////////////////////////////////////////////////////////////////// | |
| println!("--------------------------------------------------------"); | |
| let mut astack = AbstractStack::new(); | |
| // [ + ] (-- g(..e x y -- ..e z)) | |
| let e = StackItem::row("e"); | |
| astack.push(StackItem::quot("g", &[e.clone(), StackItem::item("x"), StackItem::item("y")], &[e, StackItem::item("z")])); | |
| // CALL (..c f(..c -- ..d) - ..d) | |
| let c = StackItem::row("c"); | |
| let d = StackItem::row("d"); | |
| astack.pop(StackItem::quot("f", &[c.clone()], &[d.clone()])); | |
| astack.pop(c); | |
| astack.push(d); | |
| println!("{:?}", astack); | |
| //////////////////////////////////////////////////////////////////////////// | |
| println!("--------------------------------------------------------"); | |
| let mut astack = AbstractStack::new(); | |
| // [ + ] (-- g(..e y -- ..e z)) | |
| let e = StackItem::row("e"); | |
| astack.push(StackItem::quot("g", &[e.clone(), StackItem::item("y")], &[e, StackItem::item("z")])); | |
| // CALL (..c f(..c i j -- ..d k) - ..d) | |
| let c = StackItem::row("c"); | |
| astack.pop(StackItem::quot("f", &[c.clone(), StackItem::item("i"), StackItem::item("j")], &[c.clone(), StackItem::item("k")])); | |
| let c = astack.pop(c); | |
| astack.push(c); | |
| println!("{:?}", astack); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment