add reverse, snippet for prepend implementation

This commit is contained in:
Ava Hahn 2023-03-08 20:59:22 -08:00
parent 6961fcc9fa
commit 928c9b91ed
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
6 changed files with 288 additions and 25 deletions

View file

@ -126,6 +126,20 @@ impl Seg {
}
}
/* applies a function across a list in standard form
* recurs before applying function to go in reverse
* function must take a Ctr and return a bool
* short circuits on the first false returned.
* also returns false on a non standard form list
*/
pub fn circuit_reverse<F: FnMut(&Ctr) -> bool>(&self, func: &mut F) -> bool {
match &*self.cdr {
Ctr::None => func(&self.car),
Ctr::Seg(l) => l.circuit_reverse(func) && func(&self.car),
_ => false,
}
}
pub fn from_mono(arg: Box<Ctr>) -> Seg {
Seg {
car: arg,

View file

@ -338,6 +338,39 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
},
);
syms.insert(
"pop".to_string(),
Symbol {
name: String::from("pop"),
args: Args::Strict(vec![Type::Seg]),
conditional_branches: false,
docs: append::POP_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(append::pop_callback)),
},
);
syms.insert(
"dq".to_string(),
Symbol {
name: String::from("dequeue"),
args: Args::Strict(vec![Type::Seg]),
conditional_branches: false,
docs: append::DEQUEUE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(append::dequeue_callback)),
},
);
syms.insert(
"reverse".to_string(),
Symbol {
name: String::from("reverse"),
args: Args::Strict(vec![Type::Seg]),
conditional_branches: false,
docs: append::REVERSE_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(append::reverse_callback)),
},
);
syms.insert(
"exp".to_string(),
Symbol {

View file

@ -103,3 +103,84 @@ pub fn cdr_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
Err("impossible condition: argument to cdr not a list".to_string())
}
}
pub const POP_DOCSTRING: &str = "Takes a single argument, expected to be a list.
Returns a list containing the first element, and the rest of the elements.
Example: (pop (1 2 3)) -> (1 (2 3)).
The head can then be accessed by car and the rest can be accessed by cdr.";
pub fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
if let Ctr::Seg(ref s) = *ast.car {
if s.len() < 1 {
return Err("cannot pop from empty list".to_string());
}
let mut ret = Seg::new();
ret.append(s.car.clone());
if let Ctr::Seg(ref s2) = *s.cdr {
ret.append(Box::new(Ctr::Seg(s2.clone())));
} else {
ret.append(Box::new(Ctr::Seg(Seg::new())));
}
Ok(Ctr::Seg(ret))
} else {
Err("Impossible condition: arg not a list".to_string())
}
}
pub const DEQUEUE_DOCSTRING: &str = "Takes a single argument, expected to be a list.
Returns a list containing the last element, and the rest of the elements.
Example: (dq (1 2 3)) -> (3 (1 2)).
The last element can then be accessed by car and the rest can be accessed by cdr.";
pub fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
if let Ctr::Seg(ref s) = *ast.car {
if s.len() < 1 {
return Err("cannot dequeue from empty list".to_string());
}
let mut rest = Seg::new();
let mut iter = s;
while *iter.cdr != Ctr::None {
rest.append(Box::new(*iter.car.clone()));
if let Ctr::Seg(ref next) = *iter.cdr {
iter = next;
} else {
break;
}
}
let mut ret = Seg::new();
match *iter.car {
Ctr::Seg(ref s) => {
ret.append(s.car.clone());
}
_ => ret.append(iter.car.clone()),
}
ret.append(Box::new(Ctr::Seg(rest)));
Ok(Ctr::Seg(ret))
} else {
Err("Impossible condition: arg not a list".to_string())
}
}
pub const REVERSE_DOCSTRING: &str = "Takes a single argument, expected to be a list.
Returns the same list, but in reverse order.";
pub fn reverse_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, String> {
if let Ctr::Seg(ref s) = *ast.car {
let mut ret = Seg::new();
s.circuit_reverse(&mut |arg: &Ctr| -> bool {
ret.append(Box::new(arg.clone()));
true
});
Ok(Ctr::Seg(ret))
} else {
Err("Impossible condition: arg not a list".to_string())
}
}