Reid/src/parser.rs

337 lines
9.1 KiB
Rust

use super::errors::CompilerError;
use std::fmt;
use std::fmt::Display;
type Ident = String;
const ALLOWED_IDENT_CHARS: [char; 38] = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_', '-',
];
const ALLOWED_IDENT_BEGIN_CHARS: [char; 26] = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't', 'u', 'v', 'w', 'x', 'y', 'z',
];
pub struct Parser {
text: Vec<char>,
cursor: usize,
line_number: usize,
character_number: usize,
}
impl Parser {
pub fn from(text: String) -> Self {
Parser {
text: text.chars().collect(),
cursor: 0,
line_number: 0,
character_number: 0,
}
}
pub fn parse(mut self) -> Result<ParsedReid, CompilerError> {
let mut exp_list = Vec::new();
let mut error = None;
while {
self.skip_whitespace();
if self.remaining() > 0 {
match Expression::parse(&mut self) {
Ok(exp) => {
exp_list.push(exp);
true
}
Err(err) => {
error = Some(err);
false
}
}
} else {
false
}
} {}
if let Some(error) = error {
Err(error)
} else {
Ok(ParsedReid(Expression::BlockExpr(Position(0, 0), exp_list)))
}
}
pub fn remaining(&self) -> usize {
self.text.len() - self.cursor
}
pub fn peek(&mut self, index: usize) -> Option<char> {
if self.remaining() < (index + 1) {
None
} else {
Some(self.text[self.cursor + index])
}
}
pub fn expect<T: Into<String>>(&mut self, expected: T) -> Expect {
let expected = expected.into();
self.skip_whitespace();
let mut result = Some(expected.clone());
for (idx, c) in expected.chars().enumerate() {
if let Some(peek) = self.peek(idx) {
if peek != c {
result = None;
}
} else {
result = None;
break;
}
}
Expect {
text: result,
len: expected.len(),
parser: self,
}
}
pub fn expect_ident(&mut self) -> Expect {
self.skip_whitespace();
let mut ident: Option<String> = None;
let mut len = 0;
while {
if let Some(peek) = self.peek(len) {
let lowercase = &peek.to_ascii_lowercase();
if let Some(id) = &mut ident {
if ALLOWED_IDENT_CHARS.contains(lowercase) {
id.push(peek);
len += 1;
true
} else {
false
}
} else {
if ALLOWED_IDENT_BEGIN_CHARS.contains(lowercase) {
ident = Some(peek.to_string());
len += 1;
true
} else {
false
}
}
} else {
false
}
} {}
Expect {
text: ident,
len: len,
parser: self,
}
}
pub fn expect_string_lit(&mut self) -> Expect {
self.skip_whitespace();
let mut content: Option<String> = None;
let mut len = 0;
while {
if let Some(peek) = self.peek(len) {
if let Some(cont) = &mut content {
if peek == '"' {
len += 1;
false
} else {
cont.push(peek);
len += 1;
true
}
} else {
if peek == '"' {
content = Some(String::new());
len += 1;
true
} else {
false
}
}
} else {
false
}
} {}
Expect {
text: content,
len: len,
parser: self,
}
}
pub fn move_cursor(&mut self) {
let curr = self.peek(0).unwrap();
self.cursor += 1;
self.character_number += 1;
if curr == '\n' {
self.character_number = 0;
self.line_number += 1;
}
}
pub fn move_cursor_multiple(&mut self, amount: usize) {
for _ in 0..amount {
self.move_cursor();
}
}
pub fn pos(&self) -> Position {
Position(self.line_number, self.character_number)
}
fn skip_whitespace(&mut self) {
let mut next = ' ';
while self.remaining() > 0 && {
next = self.peek(0).unwrap();
next == ' ' || next == '\n' || next == '\r' || next == '\t'
} {
self.move_cursor();
}
}
fn empty() -> Parser {
Parser {
text: Vec::new(),
cursor: 0,
character_number: 0,
line_number: 0,
}
}
}
#[derive(Debug)]
pub struct ParsedReid(Expression);
#[derive(Debug)]
pub enum Expression {
BlockExpr(Position, Vec<Expression>),
StatementExpr(Position, Statement),
EmptyExpr,
}
impl Expression {
pub fn parse(parser: &mut Parser) -> Result<Expression, CompilerError> {
let begin_pos = parser.pos();
let expect = parser.expect("{");
if let Some(_) = expect.get() {
let mut exp_list = Vec::new();
while {
match Expression::parse(parser) {
Ok(exp) => {
exp_list.push(exp);
true
}
Err(_) => false,
}
} {}
if let Some(_) = parser.expect("}").get() {
Ok(Expression::BlockExpr(begin_pos, exp_list))
} else {
Err(CompilerError::ExpectedToken(parser.pos(), '}'))
}
} else {
match Statement::parse(parser) {
Ok(statement) => Ok(Expression::StatementExpr(begin_pos, statement)),
Err(err) => Err(CompilerError::ExpectedExpression(begin_pos, Box::new(err))),
}
}
}
}
#[derive(Debug)]
pub enum Statement {
LetStatement(Position, Ident, Box<Expression>),
ValueRef(Position, Pattern),
}
impl Statement {
pub fn parse(parser: &mut Parser) -> Result<Statement, CompilerError> {
let pos = parser.pos();
if let Some(_) = parser.expect("let").get() {
let ident = parser
.expect_ident()
.get_or(CompilerError::ExpectedIdent(pos))?;
parser
.expect("=")
.get_or(CompilerError::ExpectedToken(pos, '='))?;
match Expression::parse(parser) {
Ok(expr) => {
parser
.expect(";")
.get_or(CompilerError::ExpectedToken(pos, ';'))?;
Ok(Statement::LetStatement(pos, ident, Box::new(expr)))
}
Err(err) => Err(CompilerError::ExpectedExpression(pos, Box::new(err))),
}
} else if let Ok(pattern) = Pattern::parse(parser) {
Ok(Statement::ValueRef(pos, pattern))
} else {
Err(CompilerError::ExpectedStatement(pos))
}
}
}
#[derive(Debug)]
pub enum Pattern {
IdentPattern(Position, Ident),
LiteralPattern(Position, LiteralPattern),
}
impl Pattern {
fn parse(parser: &mut Parser) -> Result<Pattern, CompilerError> {
let pos = parser.pos();
if let Some(string) = parser.expect_string_lit().get() {
Ok(Pattern::LiteralPattern(
pos,
LiteralPattern::StringLit(string),
))
} else if let Some(ident) = parser.expect_ident().get() {
Ok(Pattern::IdentPattern(pos, ident))
} else {
Err(CompilerError::ExpectedPattern(pos))
}
}
}
#[derive(Debug)]
pub enum LiteralPattern {
StringLit(String),
}
pub struct Expect<'a> {
text: Option<String>,
len: usize,
parser: &'a mut Parser,
}
impl Expect<'_> {
pub fn get(mut self) -> Option<String> {
if self.text.is_some() {
self.parser.move_cursor_multiple(self.len);
}
self.text
}
pub fn get_or(mut self, error: CompilerError) -> Result<String, CompilerError> {
match self.get() {
Some(text) => Ok(text),
None => Err(error),
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct Position(usize, usize);
impl Display for Position {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "line {}, column {}", self.0, self.1)
}
}