Add basic parsing of let statements

This commit is contained in:
Sofia 2020-06-21 01:21:24 +03:00
parent 1b28558dd8
commit bea027d730
6 changed files with 382 additions and 1 deletions

5
Cargo.lock generated Normal file
View File

@ -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"

1
reid_src/test.reid Normal file
View File

@ -0,0 +1 @@
let otus = "gotus";

24
src/errors.rs Normal file
View File

@ -0,0 +1,24 @@
use super::parser::Position;
use std::io;
#[derive(Debug)]
pub enum GenericError {
StdIOError(io::Error),
}
impl From<io::Error> for GenericError {
fn from(error: io::Error) -> Self {
Self::StdIOError(error)
}
}
#[derive(Debug)]
pub enum CompilerError {
Fatal,
PeekFailed,
ExpectedToken(Position, char),
ExpectedExpression(Position, Box<CompilerError>),
ExpectedIdent(Position),
ExpectedStatement(Position),
ExpectedPattern(Position),
}

14
src/file_io.rs Normal file
View File

@ -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<String, GenericError> {
let file = File::open(path)?;
let mut reader = BufReader::new(file);
let mut text = String::new();
reader.read_to_string(&mut text)?;
Ok(text)
}

View File

@ -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);
}

327
src/parser.rs Normal file
View File

@ -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<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);