lisp-8bit/src/parser.rs

144 lines
3.8 KiB
Rust
Raw Normal View History

2024-08-08 21:53:27 +02:00
use crate::*;
#[derive(Debug)]
pub struct Parser {
row: usize,
column: usize,
lines: Vec<Vec<char>>,
}
#[derive(Debug)]
pub(crate) struct Instruction {
name: String,
arguments: Vec<Value>,
}
#[derive(Debug)]
enum Value {
Instruction(Instruction),
StringLiteral(String),
IntegerLiteral(usize),
Identifier(String),
}
impl Parser {
pub fn parse(stream: String) -> Result<Instruction> {
let mut parser = Parser {
row: 0,
column: 0,
lines: stream
.split('\n')
.map(|a| a.chars().collect::<Vec<_>>())
.collect::<Vec<_>>(),
};
parser.instruction()
}
fn increment(&mut self) -> Option<()> {
self.column += 1;
if self.column == self.lines[self.row].len() {
self.row += 1;
if self.row == self.lines.len() {
self.row -= 1;
self.column -= 1;
return None;
}
self.column = 0;
}
return Some(());
}
fn jump_whitespace(&mut self) -> Option<()> {
self.increment()?;
while self.lines[self.row][self.column].is_whitespace() {
self.increment()?;
}
Some(())
}
fn instruction(&mut self) -> Result<Instruction> {
if self.lines[self.row][self.column] != '(' {
return Err(Error::SyntaxError(SyntaxError {
row: self.row,
column: self.column,
message: "SyntaxError: Expected '('".to_string(),
}));
}
self.jump_whitespace();
let name = self.identifier()?;
let mut arguments = Vec::new();
while self.lines[self.row][self.column] != ')' {
match self.lines[self.row][self.column] {
'\"' => arguments.push(Value::StringLiteral(self.string_literal()?)),
'(' => arguments.push(Value::Instruction(self.instruction()?)),
character => {
if character.is_numeric() {
arguments.push(Value::IntegerLiteral(self.integer_literal()?));
} else {
arguments.push(Value::Identifier(self.identifier()?));
}
}
}
}
self.jump_whitespace();
return Ok(Instruction { name, arguments });
}
fn string_literal(&mut self) -> Result<String> {
self.increment();
let mut accumulator = String::new();
while self.lines[self.row][self.column] != '"' {
accumulator.push(self.lines[self.row][self.column]);
self.increment();
}
self.jump_whitespace();
Ok(accumulator)
}
fn integer_literal(&mut self) -> Result<usize> {
let mut accumulator = String::new();
while self.lines[self.row][self.column].is_numeric() {
accumulator.push(self.lines[self.row][self.column]);
self.increment();
}
self.jump_whitespace();
match accumulator.parse::<usize>() {
Ok(v) => Ok(v),
Err(_e) => Err(Error::SyntaxError(SyntaxError {
row: self.row,
column: self.column,
message: "Couldn't parse integer literal".to_string(),
})),
}
}
fn identifier(&mut self) -> Result<String> {
let mut accumulator = String::new();
let mut current = self.lines[self.row][self.column];
while !"()\"".contains(current) && !current.is_whitespace() {
accumulator.push(self.lines[self.row][self.column]);
self.increment();
current = self.lines[self.row][self.column];
}
self.jump_whitespace();
Ok(accumulator)
}
}