ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/

Getting started with parser

Changed files
+187 -28
dna2rna
+67 -27
dna2rna/src/dna.rs
···
use std::ops::Index;
use std::rc::Rc;
-
#[derive(Clone)]
+
#[derive(Copy, Clone, PartialEq, Debug)]
+
pub enum Base {
+
I,
+
C,
+
F,
+
P,
+
}
+
+
#[derive(Clone, Debug)]
pub enum Dna {
Empty,
-
Leaf(char),
+
Leaf(Base),
TwoNode(TwoNode),
ThreeNode(ThreeNode),
}
-
#[derive(Clone)]
+
#[derive(Clone, Debug)]
// Wrap Rc in a single-value enum so I can implement traits for it.
pub enum DnaRef {
DnaRef(Rc<Dna>),
}
-
#[derive(Clone)]
+
#[derive(Clone, Debug)]
pub struct TwoNode {
len: usize,
depth: usize,
children: (DnaRef, DnaRef),
}
-
#[derive(Clone)]
+
#[derive(Clone, Debug)]
pub struct ThreeNode {
len: usize,
depth: usize,
children: (DnaRef, DnaRef, DnaRef),
}
+
impl Base {
+
fn from_char(c: char) -> Option<Base> {
+
match c {
+
'I' => Some(Base::I),
+
'C' => Some(Base::C),
+
'F' => Some(Base::F),
+
'P' => Some(Base::P),
+
_ => None,
+
}
+
}
+
+
fn to_char(&self) -> char {
+
match self {
+
Base::I => 'I',
+
Base::C => 'C',
+
Base::F => 'F',
+
Base::P => 'P',
+
}
+
}
+
}
+
impl DnaRef {
pub fn new() -> Self {
Self::DnaRef(Rc::new(Dna::Empty))
}
-
fn from_char(c: char) -> Self {
-
Self::DnaRef(Rc::new(Dna::Leaf(c)))
+
fn from_base(b: Base) -> Self {
+
Self::DnaRef(Rc::new(Dna::Leaf(b)))
}
fn from_two_children(a: DnaRef, b: DnaRef) -> Self {
···
}
pub fn from_string(s: &str) -> Self {
-
s.chars().map(|c| DnaRef::from_char(c)).collect::<DnaRef>()
+
s.chars()
+
.filter_map(|c| Base::from_char(c))
+
.map(|b| DnaRef::from_base(b))
+
.collect::<DnaRef>()
}
pub fn len(&self) -> usize {
···
debug_assert!(n <= self.len());
match &**self {
Dna::Empty => (DnaRef::new(), DnaRef::new()),
-
Dna::Leaf(c) => {
+
Dna::Leaf(b) => {
if n == 0 {
-
(DnaRef::new(), DnaRef::from_char(*c))
+
(DnaRef::new(), DnaRef::from_base(*b))
} else {
-
(DnaRef::from_char(*c), DnaRef::new())
+
(DnaRef::from_base(*b), DnaRef::new())
}
}
Dna::TwoNode(node) => {
···
}
}
}
+
}
+
+
pub fn to_string(&self) -> String {
+
self.iter().map(|b| Base::to_char(&b)).collect::<String>()
}
}
···
cur = DnaRefIter::new(cur.into_iter()).collect();
}
-
return cur.pop().unwrap();
+
match cur.pop() {
+
Some(dna) => dna,
+
None => DnaRef::new(),
+
}
}
}
···
}
impl<'a> Iterator for DnaIterator<'a> {
-
type Item = char;
+
type Item = Base;
fn next(&mut self) -> Option<Self::Item> {
while let Some(node) = self.stack.pop() {
···
} else if lhs.depth() < rhs.depth() {
match &*rhs {
Dna::Empty => unreachable!(),
-
Dna::Leaf(_) => unreachable!(),
+
Dna::Leaf(_) => AddState::One(rhs),
Dna::TwoNode(node) => {
let (a, b) = &node.children;
match add_helper(lhs, a.clone()) {
···
} else {
match &*lhs {
Dna::Empty => unreachable!(),
-
Dna::Leaf(_) => unreachable!(),
+
Dna::Leaf(_) => AddState::One(lhs.clone()),
Dna::TwoNode(node) => {
let (a, b) = &node.children;
match add_helper(b.clone(), rhs) {
···
}
impl Index<usize> for DnaRef {
-
type Output = char;
+
type Output = Base;
fn index(&self, n: usize) -> &Self::Output {
debug_assert!(n < self.len());
···
#[test]
fn test_to_from_string() {
let dna: DnaRef = DnaRef::from_string("ICFP");
-
assert_eq!(dna.iter().collect::<String>(), "ICFP");
+
assert_eq!(dna.to_string(), "ICFP");
}
#[test]
fn test_index() {
let s = "ICFP";
let dna: DnaRef = DnaRef::from_string(s);
-
for (i, c) in s.chars().enumerate() {
-
assert_eq!(dna[i], c);
-
}
+
assert_eq!(dna[0], Base::I);
+
assert_eq!(dna[1], Base::C);
+
assert_eq!(dna[2], Base::F);
+
assert_eq!(dna[3], Base::P);
}
#[test]
-
fn test_concat() {
-
let lhs = DnaRef::from_string("ABCD");
-
let rhs = DnaRef::from_string("WXYZ");
-
assert_eq!((lhs + rhs).iter().collect::<String>(), "ABCDWXYZ");
+
fn test_add() {
+
let lhs = DnaRef::from_string("IIIC");
+
let rhs = DnaRef::from_string("PFFF");
+
assert_eq!((lhs + rhs).to_string(), "IIICPFFF");
}
#[test]
fn test_split() {
-
let dna = DnaRef::from_string("ABCDWXYZ");
+
let dna = DnaRef::from_string("IIICPFFF");
let (lhs, rhs) = dna.split(4);
-
assert_eq!(lhs.iter().collect::<String>(), "ABCD");
-
assert_eq!(rhs.iter().collect::<String>(), "WXYZ");
+
assert_eq!(lhs.to_string(), "IIIC");
+
assert_eq!(rhs.to_string(), "PFFF");
}
}
+2 -1
dna2rna/src/main.rs
···
mod dna;
+
mod parser;
use crate::dna::*;
fn main() {
let dna: DnaRef = DnaRef::from_string("ICFP");
-
println!("Back to string: {}", dna.iter().collect::<String>());
+
println!("Back to string: {}", dna.to_string());
}
+109
dna2rna/src/parser.rs
···
+
use crate::Base;
+
use crate::DnaRef;
+
+
struct Parser<'a> {
+
buf: &'a DnaRef,
+
index: usize,
+
}
+
+
impl<'a> Parser<'a> {
+
pub fn new(buf: &'a DnaRef) -> Parser<'a> {
+
Parser { buf: buf, index: 0 }
+
}
+
+
pub fn next_is(&mut self, next: &[Base]) -> bool {
+
if self.index + next.len() > self.buf.len() {
+
return false;
+
}
+
+
for i in 0..next.len() {
+
if self.buf[self.index + i] != next[i] {
+
return false;
+
}
+
}
+
+
return true;
+
}
+
+
pub fn nat(&mut self) -> Option<usize> {
+
let mut ret = 0;
+
let mut bit = 1;
+
loop {
+
if self.next_is(&[Base::P]) {
+
self.index += 1;
+
return Some(ret);
+
} else if self.next_is(&[Base::I]) || self.next_is(&[Base::F]) {
+
self.index += 1;
+
} else if self.next_is(&[Base::C]) {
+
ret += bit;
+
self.index += 1;
+
} else {
+
return None;
+
}
+
+
bit *= 2;
+
}
+
}
+
+
pub fn consts(&mut self) -> Vec<Base> {
+
let mut ret = Vec::new();
+
loop {
+
if self.next_is(&[Base::C]) {
+
self.index += 1;
+
ret.push(Base::I);
+
} else if self.next_is(&[Base::F]) {
+
self.index += 1;
+
ret.push(Base::C);
+
} else if self.next_is(&[Base::P]) {
+
self.index += 1;
+
ret.push(Base::F);
+
} else if self.next_is(&[Base::I, Base::C]) {
+
self.index += 2;
+
ret.push(Base::P);
+
} else {
+
return ret;
+
}
+
}
+
}
+
}
+
+
#[cfg(test)]
+
mod tests {
+
use super::*;
+
+
#[test]
+
fn test_base() {
+
let dna = DnaRef::from_string("ICFP");
+
let mut parser = Parser::new(&dna);
+
assert!(parser.next_is(&[Base::I]));
+
assert!(parser.next_is(&[Base::I, Base::C]));
+
assert!(parser.next_is(&[Base::I, Base::C, Base::F]));
+
assert!(parser.next_is(&[Base::I, Base::C, Base::F, Base::P]));
+
}
+
+
#[test]
+
fn test_nat() {
+
let dna = DnaRef::from_string("CP");
+
let mut parser = Parser::new(&dna);
+
assert_eq!(parser.nat(), Some(1));
+
assert_eq!(parser.index, 2);
+
+
let dna = DnaRef::from_string("ICICP");
+
let mut parser = Parser::new(&dna);
+
assert_eq!(parser.nat(), Some(10));
+
assert_eq!(parser.index, 5);
+
+
let dna = DnaRef::from_string("III");
+
let mut parser = Parser::new(&dna);
+
assert_eq!(parser.nat(), None);
+
assert_eq!(parser.index, 3);
+
}
+
+
#[test]
+
fn test_consts() {
+
let dna = DnaRef::from_string("CFPICIIC");
+
let mut parser = Parser::new(&dna);
+
assert_eq!(parser.consts(), &[Base::I, Base::C, Base::F, Base::P]);
+
assert_eq!(parser.index, 5);
+
}
+
}
+9
dna2rna/src/pattern.rs
···
+
use crate::Base;
+
+
pub enum PatternItem {
+
Base(char),
+
Skip(usize),
+
Search(Vec<Base>),
+
Open,
+
Close
+
}