Files
hakorune/src/runner/json_v0_bridge/lexer.rs

192 lines
5.3 KiB
Rust

use super::ast::{ExprV0, ProgramV0, StmtV0};
#[derive(Clone, Debug)]
enum Tok {
Int(i64),
Plus,
Minus,
Star,
Slash,
LParen,
RParen,
Return,
Eof,
}
fn lex(input: &str) -> Result<Vec<Tok>, String> {
let mut chars = input.chars().peekable();
let mut toks = Vec::new();
while let Some(&c) = chars.peek() {
match c {
' ' | '\n' | '\t' | '\r' => {
chars.next();
}
'+' => {
chars.next();
toks.push(Tok::Plus);
}
'-' => {
chars.next();
toks.push(Tok::Minus);
}
'*' => {
chars.next();
toks.push(Tok::Star);
}
'/' => {
chars.next();
toks.push(Tok::Slash);
}
'(' => {
chars.next();
toks.push(Tok::LParen);
}
')' => {
chars.next();
toks.push(Tok::RParen);
}
'0'..='9' => {
let mut n = 0i64;
while let Some(&d) = chars.peek() {
if d.is_ascii_digit() {
n = n * 10 + (d as i64 - '0' as i64);
chars.next();
} else {
break;
}
}
toks.push(Tok::Int(n));
}
'r' => {
let kw = "return";
let mut it = kw.chars();
let mut ok = true;
for _ in 0..kw.len() {
if Some(chars.next().unwrap_or('\0')) != it.next() {
ok = false;
break;
}
}
if ok {
toks.push(Tok::Return);
} else {
return Err("unexpected 'r'".into());
}
}
_ => return Err(format!("unexpected char '{}'", c)),
}
}
toks.push(Tok::Eof);
Ok(toks)
}
struct P {
toks: Vec<Tok>,
pos: usize,
}
impl P {
fn new(toks: Vec<Tok>) -> Self {
Self { toks, pos: 0 }
}
fn peek(&self) -> &Tok {
self.toks.get(self.pos).unwrap()
}
fn next(&mut self) -> Tok {
let t = self.toks.get(self.pos).unwrap().clone();
self.pos += 1;
t
}
fn expect_return(&mut self) -> Result<(), String> {
match self.next() {
Tok::Return => Ok(()),
_ => Err("expected 'return'".into()),
}
}
fn parse_program(&mut self) -> Result<ExprV0, String> {
self.expect_return()?;
self.parse_expr()
}
fn parse_expr(&mut self) -> Result<ExprV0, String> {
let mut left = self.parse_term()?;
loop {
match self.peek() {
Tok::Plus => {
self.next();
let r = self.parse_term()?;
left = ExprV0::Binary {
op: "+".into(),
lhs: Box::new(left),
rhs: Box::new(r),
};
}
Tok::Minus => {
self.next();
let r = self.parse_term()?;
left = ExprV0::Binary {
op: "-".into(),
lhs: Box::new(left),
rhs: Box::new(r),
};
}
_ => break,
}
}
Ok(left)
}
fn parse_term(&mut self) -> Result<ExprV0, String> {
let mut left = self.parse_factor()?;
loop {
match self.peek() {
Tok::Star => {
self.next();
let r = self.parse_factor()?;
left = ExprV0::Binary {
op: "*".into(),
lhs: Box::new(left),
rhs: Box::new(r),
};
}
Tok::Slash => {
self.next();
let r = self.parse_factor()?;
left = ExprV0::Binary {
op: "/".into(),
lhs: Box::new(left),
rhs: Box::new(r),
};
}
_ => break,
}
}
Ok(left)
}
fn parse_factor(&mut self) -> Result<ExprV0, String> {
match self.next() {
Tok::Int(v) => Ok(ExprV0::Int {
value: serde_json::Value::from(v),
}),
Tok::LParen => {
let e = self.parse_expr()?;
match self.next() {
Tok::RParen => Ok(e),
_ => Err(") expected".into()),
}
}
_ => Err("factor expected".into()),
}
}
}
pub(super) fn parse_source_v0_to_json(input: &str) -> Result<String, String> {
let toks = lex(input)?;
let mut p = P::new(toks);
let expr = p.parse_program()?;
let prog = ProgramV0 {
version: 0,
kind: "Program".into(),
body: vec![StmtV0::Return { expr }],
defs: vec![],
};
serde_json::to_string(&prog).map_err(|e| e.to_string())
}