diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..afbc995 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "Reid" +version = "0.1.0" diff --git a/reid_src/test.reid b/reid_src/test.reid new file mode 100644 index 0000000..4a9fbbd --- /dev/null +++ b/reid_src/test.reid @@ -0,0 +1 @@ +let otus = "gotus"; \ No newline at end of file diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..df68aaf --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,24 @@ +use super::parser::Position; +use std::io; + +#[derive(Debug)] +pub enum GenericError { + StdIOError(io::Error), +} + +impl From for GenericError { + fn from(error: io::Error) -> Self { + Self::StdIOError(error) + } +} + +#[derive(Debug)] +pub enum CompilerError { + Fatal, + PeekFailed, + ExpectedToken(Position, char), + ExpectedExpression(Position, Box), + ExpectedIdent(Position), + ExpectedStatement(Position), + ExpectedPattern(Position), +} diff --git a/src/file_io.rs b/src/file_io.rs new file mode 100644 index 0000000..e1b98d9 --- /dev/null +++ b/src/file_io.rs @@ -0,0 +1,14 @@ +use std::fs::File; +use std::io::prelude::*; +use std::io::BufReader; +use std::path::Path; + +use super::errors::GenericError; + +pub fn open_file(path: &Path) -> Result { + let file = File::open(path)?; + let mut reader = BufReader::new(file); + let mut text = String::new(); + reader.read_to_string(&mut text)?; + Ok(text) +} diff --git a/src/main.rs b/src/main.rs index e7a11a9..68cdd16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,13 @@ +mod errors; +mod file_io; +mod parser; + +use file_io::open_file; +use parser::{ParsedReid, Parser}; +use std::path::Path; + fn main() { - println!("Hello, world!"); + let path = Path::new("reid_src/test.reid"); + let reid = Parser::from(open_file(&path).ok().unwrap()).parse(); + println!("Parsed: {:?}", reid); } diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..2c45889 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,327 @@ +use super::errors::CompilerError; + +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, + 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 { + 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 { + if self.remaining() < (index + 1) { + None + } else { + Some(self.text[self.cursor + index]) + } + } + + pub fn expect>(&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 = 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 = 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), + StatementExpr(Position, Statement), + EmptyExpr, +} + +impl Expression { + pub fn parse(parser: &mut Parser) -> Result { + 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), + ValueRef(Position, Pattern), +} + +impl Statement { + pub fn parse(parser: &mut Parser) -> Result { + 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 { + 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, + len: usize, + parser: &'a mut Parser, +} + +impl Expect<'_> { + pub fn get(mut self) -> Option { + if self.text.is_some() { + self.parser.move_cursor_multiple(self.len); + } + self.text + } + pub fn get_or(mut self, error: CompilerError) -> Result { + match self.get() { + Some(text) => Ok(text), + None => Err(error), + } + } +} + +#[derive(Debug, Copy, Clone)] +pub struct Position(usize, usize);