Skip to content

Instantly share code, notes, and snippets.

@tanner00
Created August 13, 2018 19:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tanner00/9a766c2d4985356609d3c9e3d5205f29 to your computer and use it in GitHub Desktop.
Save tanner00/9a766c2d4985356609d3c9e3d5205f29 to your computer and use it in GitHub Desktop.
A lisp parser in Rust
#[derive(Debug)]
pub enum Node {
Id(String),
List(Box<Option<Node>>, Vec<Node>),
}
pub struct Parser {
input: String,
position: usize,
}
impl Parser {
pub fn new(program: String) -> Parser {
Parser {
input: program,
position: 0,
}
}
fn peek(&self) -> Option<char> {
self.input.chars().nth(self.position)
}
fn consume(&mut self) -> Option<char> {
let c = self.peek();
self.position += 1;
c
}
fn consume_while(&mut self, pred: fn(char) -> bool) -> String {
let mut s = String::new();
while !self.done() && pred(self.peek().unwrap()) {
s.push(self.consume().unwrap());
}
s
}
fn discard_whitespace(&mut self) {
while !self.done() && char::is_whitespace(self.peek().unwrap()) {
self.position += 1
}
}
fn done(&self) -> bool {
self.position >= self.input.len()
}
fn parse_id(&mut self) -> Node {
Node::Id(self.consume_while(char::is_alphanumeric))
}
fn parse_list(&mut self) -> Node {
self.discard_whitespace();
assert_eq!(self.consume(), Some('('));
let mut nodes = Vec::new();
while self.peek() != Some(')') {
if let Some(n) = self.parse_node() {
nodes.push(n);
}
}
assert_eq!(self.consume(), Some(')'));
let mut nodes = nodes.into_iter();
let n = Node::List(box nodes.next(), nodes.collect());
self.discard_whitespace();
n
}
fn parse_node(&mut self) -> Option<Node> {
self.discard_whitespace();
let n = match self.peek() {
Some('(') => Some(self.parse_list()),
Some(')') => None,
Some(c) if char::is_alphanumeric(c) => Some(self.parse_id()),
None | Some(_) => panic!(format!("Unrecognized: {}", self.peek().unwrap())),
};
self.discard_whitespace();
n
}
pub fn parse_nodes(&mut self) -> Vec<Node> {
let mut nodes = Vec::new();
while !self.done() {
nodes.push(self.parse_list());
}
nodes
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment