OSDN Git Service

Bring in the Rust implementation.
authorSimon Forman <sforman@hushmail.com>
Sun, 16 Jan 2022 01:28:31 +0000 (17:28 -0800)
committerSimon Forman <sforman@hushmail.com>
Sun, 16 Jan 2022 01:28:31 +0000 (17:28 -0800)
implementations/Rust/.gitignore [new file with mode: 0644]
implementations/Rust/Cargo.lock [new file with mode: 0644]
implementations/Rust/Cargo.toml [new file with mode: 0644]
implementations/Rust/src/main.rs [new file with mode: 0644]
implementations/Rust/src/stack.rs [new file with mode: 0644]

diff --git a/implementations/Rust/.gitignore b/implementations/Rust/.gitignore
new file mode 100644 (file)
index 0000000..ea8c4bf
--- /dev/null
@@ -0,0 +1 @@
+/target
diff --git a/implementations/Rust/Cargo.lock b/implementations/Rust/Cargo.lock
new file mode 100644 (file)
index 0000000..c9cd6a3
--- /dev/null
@@ -0,0 +1,49 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "crust"
+version = "0.1.0"
+dependencies = [
+ "lazy_static",
+ "regex",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
diff --git a/implementations/Rust/Cargo.toml b/implementations/Rust/Cargo.toml
new file mode 100644 (file)
index 0000000..8dad137
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name = "crust"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+regex = "1"
+lazy_static = "1"
+
diff --git a/implementations/Rust/src/main.rs b/implementations/Rust/src/main.rs
new file mode 100644 (file)
index 0000000..968165f
--- /dev/null
@@ -0,0 +1,86 @@
+mod stack;
+use lazy_static::lazy_static;
+use regex::Regex;
+use std::io;
+
+#[derive(Debug)]
+enum JoyVal {
+    True,
+    False,
+    List(stack::List<JoyVal>),
+    Int(i64),
+    Sym(String),
+}
+
+fn tokenize(str: &str) -> JoyVal {
+    lazy_static! {
+        static ref RE: Regex = Regex::new(
+            r"(?x)
+              (?P<true>true)\b
+            | (?P<false>false)\b
+            | (?P<lbracket>\[)
+            | (?P<rbracket>\])
+            | (?P<int>\d+)
+            | (?P<atom>[^\s+\[\]]+) "
+        )
+        .unwrap();
+    }
+
+    let mut frame = vec![];
+    let mut stack = vec![];
+    for cap in RE.captures_iter(str) {
+        // Is this better than the if/elif/else chain below?
+        // More importantly, how would I go about figuring that out?
+        match cap.name("true") {
+            Some(_) => {
+                frame.push(JoyVal::True);
+                continue;
+            }
+            None => {}
+        }
+        // Is there a better way to do this?
+        //if cap.name("true") != None {
+        //    println!("T");
+        //} else
+        if cap.name("false") != None {
+            frame.push(JoyVal::False);
+        } else if cap.name("lbracket") != None {
+            stack.push(frame);
+            frame = vec![];
+        } else if cap.name("rbracket") != None {
+            let v = frame;
+            frame = stack.pop().expect("Extra closing bracket.");
+            frame.push(JoyVal::List(stack::List::vec_to_list(v)));
+        } else if cap.name("int") != None {
+            frame.push(JoyVal::Int(cap[0].parse().unwrap()));
+        } else if cap.name("atom") != None {
+            frame.push(JoyVal::Sym(String::from(&cap[0])));
+        } else {
+            println!("wtf");
+        }
+    }
+    JoyVal::List(stack::List::vec_to_list(frame))
+}
+
+fn joy(mut s: stack::List<JoyVal>, mut e: stack::List<JoyVal>) -> stack::List<JoyVal> {
+    while !e.empty() {
+        let term = e.head().expect("How!?");
+        e = e.tail();
+        match term {
+            JoyVal::True => { s = s.push(JoyVal::True) }
+            JoyVal::False => { s = s.push(JoyVal::False) }
+            JoyVal::List(_) => { s = s.push(term) }
+            JoyVal::Int(_) => { s = s.push(term) }
+            JoyVal::Sym(_) => { s = s.push(term) }
+        }
+    }
+    s
+}
+
+fn main() {
+    println!("Enter a number:");
+    let mut n = String::new();
+    let m = io::stdin().read_line(&mut n).expect("WTF?");
+    println!("{:?}", tokenize(&n));
+    println!("Entered: {} {}", m, n);
+}
diff --git a/implementations/Rust/src/stack.rs b/implementations/Rust/src/stack.rs
new file mode 100644 (file)
index 0000000..75fd9ef
--- /dev/null
@@ -0,0 +1,133 @@
+// https://rust-unofficial.github.io/too-many-lists/third.html
+use std::rc::Rc;
+
+#[derive(Debug)]
+pub struct List<T> {
+    head: Link<T>,
+}
+
+type Link<T> = Option<Rc<Node<T>>>;
+
+#[derive(Debug)]
+struct Node<T> {
+    elem: T,
+    next: Link<T>,
+}
+
+impl<T> List<T> {
+    pub fn new() -> Self {
+        List { head: None }
+    }
+    pub fn push(&self, elem: T) -> List<T> {
+        List {
+            head: Some(Rc::new(Node {
+                elem: elem,
+                next: self.head.clone(),
+            })),
+        }
+    }
+    pub fn tail(&self) -> List<T> {
+        List {
+            head: self.head.as_ref().and_then(|node| node.next.clone()),
+        }
+    }
+    pub fn head(&self) -> Option<&T> {
+        self.head.as_ref().map(|node| &node.elem)
+    }
+    pub fn iter(&self) -> Iter<'_, T> {
+        Iter {
+            next: self.head.as_deref(),
+        }
+    }
+    pub fn vec_to_list(v: Vec<T>) -> List<T> {
+        let mut list = List::new();
+        for t in v.into_iter().rev() {
+            list = list.push(t);
+        }
+        list
+    }
+    pub fn empty(&self) -> bool {
+        match self.head {
+            Some(_) => false,
+            None => true
+        }
+    }
+}
+
+impl<T> Drop for List<T> {
+    fn drop(&mut self) {
+        let mut head = self.head.take();
+        while let Some(node) = head {
+            if let Ok(mut node) = Rc::try_unwrap(node) {
+                head = node.next.take();
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+pub struct Iter<'a, T> {
+    next: Option<&'a Node<T>>,
+}
+
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.next.map(|node| {
+            self.next = node.next.as_deref();
+            &node.elem
+        })
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::List;
+
+    #[test]
+    fn basics() {
+        let list = List::new();
+        assert_eq!(list.head(), None);
+        assert_eq!(list.empty(), true);
+
+        let list = list.push(1).push(2).push(3);
+        assert_eq!(list.empty(), false);
+        assert_eq!(list.head(), Some(&3));
+
+        let list = list.tail();
+        assert_eq!(list.head(), Some(&2));
+
+        let list = list.tail();
+        assert_eq!(list.head(), Some(&1));
+
+        let list = list.tail();
+        assert_eq!(list.head(), None);
+
+        // Make sure empty tail works
+        let list = list.tail();
+        assert_eq!(list.head(), None);
+    }
+
+    #[test]
+    fn iter() {
+        let list = List::new().push(1).push(2).push(3);
+
+        let mut iter = list.iter();
+        assert_eq!(iter.next(), Some(&3));
+        assert_eq!(iter.next(), Some(&2));
+        assert_eq!(iter.next(), Some(&1));
+    }
+
+    #[test]
+    fn v2l() {
+        let v = vec![1, 2, 3];
+        let list = List::vec_to_list(v);
+
+        let mut iter = list.iter();
+        assert_eq!(iter.next(), Some(&1));
+        assert_eq!(iter.next(), Some(&2));
+        assert_eq!(iter.next(), Some(&3));
+    }
+}