pine/src/main.rs

146 lines
3.0 KiB
Rust

#![feature(box_syntax)]
#[derive(Debug, Copy, Clone)]
enum Token<'a> {
IntegerLiteral(&'a str),
Plus,
Semicolon,
}
impl Token<'_> {
pub fn len(&self) -> usize {
return match self {
Token::IntegerLiteral(s) => s.len(),
Token::Plus | Token::Semicolon => 1,
};
}
}
impl std::fmt::Display for Token<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return match self {
Token::IntegerLiteral(i) => write!(f, "{}", i),
Token::Plus => write!(f, "+"),
_ => unreachable!(),
};
}
}
struct Source<'a> {
source: &'a str,
cursor: usize,
last: Option<Token<'a>>,
}
impl<'a> Source<'a> {
pub fn new(source: &'a str) -> Self {
return Self {
source,
cursor: 0,
last: None,
};
}
fn skip_whitespace(&mut self) {
let mut chars = self.source[self.cursor..].chars();
while let Some(c) = chars.next() {
if c.is_whitespace() {
self.cursor += c.len_utf8();
} else {
return;
}
}
}
fn get_next(&mut self) -> Option<Token<'a>> {
self.skip_whitespace();
let mut chars = self.source[self.cursor..].chars();
let token = match chars.next()? {
'+' => Token::Plus,
';' => Token::Semicolon,
c if c.is_ascii_digit() => {
let start = self.cursor;
let mut length = c.len_utf8();
loop {
match chars.next()? {
c if c.is_ascii_digit() => length += c.len_utf8(),
_ => break,
};
};
Token::IntegerLiteral(&self.source[start..start + length])
},
c => todo!("invalid character `{:?}`", c)
};
return Some(token);
}
pub fn next(&mut self) -> Option<Token<'a>> {
let token = match self.last {
Some(t) => t,
None => self.get_next()?,
};
self.last = None;
self.cursor += token.len();
return Some(token);
}
pub fn peek(&mut self) -> Option<Token<'a>> {
self.last = Some(self.get_next()?);
return self.last;
}
}
#[derive(Debug)]
enum Statement<'a> {
Expression(Expression<'a>),
}
// statement = expression ';' .
fn parse_statement<'a>(source: &mut Source<'a>) -> Option<Statement<'a>> {
let expression = match source.peek()? {
Token::IntegerLiteral(_) => parse_expression(source)?,
_ => return None,
};
return match source.next()? {
Token::Semicolon => Some(Statement::Expression(expression)),
_ => None,
};
}
#[derive(Debug)]
enum Expression<'a> {
Literal(&'a str),
Binary(Token<'a>, Box<Expression<'a>>, Box<Expression<'a>>),
}
// expression = literal | expression '+' expression .
fn parse_expression<'a>(source: &mut Source<'a>) -> Option<Expression<'a>> {
let lhs = match source.next()? {
Token::IntegerLiteral(i) => Expression::Literal(i),
_ => return None,
};
let operator = match source.peek()? {
token @ Token::Plus => token,
Token::Semicolon => return Some(lhs),
_ => return None,
};
source.next();
let rhs = parse_expression(source)?;
return Some(Expression::Binary(operator, box lhs, box rhs));
}
fn main() {
let inline_source = "3 + 5 + 7;";
let mut source = Source::new(inline_source);
eprintln!("{:?}", parse_statement(&mut source));
}