2020-06-21 00:45:09 +02:00
|
|
|
mod parsed_reid;
|
2020-06-21 00:21:24 +02:00
|
|
|
|
2020-06-22 20:49:21 +02:00
|
|
|
use super::errors::SyntaxError;
|
|
|
|
pub use parsed_reid::*;
|
2020-06-21 00:37:56 +02:00
|
|
|
use std::fmt;
|
|
|
|
use std::fmt::Display;
|
|
|
|
|
2020-06-21 00:21:24 +02:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-22 20:49:21 +02:00
|
|
|
pub fn parse(mut self) -> Result<ParsedReid, SyntaxError> {
|
2020-06-22 15:58:42 +02:00
|
|
|
let mut statement_list = Vec::new();
|
2020-06-21 00:21:24 +02:00
|
|
|
|
|
|
|
let mut error = None;
|
|
|
|
|
|
|
|
while {
|
|
|
|
self.skip_whitespace();
|
|
|
|
if self.remaining() > 0 {
|
2020-06-22 15:58:42 +02:00
|
|
|
match Statement::parse(&mut self) {
|
2020-06-21 00:21:24 +02:00
|
|
|
Ok(exp) => {
|
2020-06-22 15:58:42 +02:00
|
|
|
statement_list.push(exp);
|
2020-06-21 00:21:24 +02:00
|
|
|
true
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
error = Some(err);
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
} {}
|
|
|
|
|
|
|
|
if let Some(error) = error {
|
|
|
|
Err(error)
|
|
|
|
} else {
|
2020-06-22 15:58:42 +02:00
|
|
|
Ok(ParsedReid(Expression::BlockExpr(
|
|
|
|
Position(0, 0),
|
|
|
|
statement_list,
|
|
|
|
)))
|
2020-06-21 00:21:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Expect<'a> {
|
|
|
|
text: Option<String>,
|
|
|
|
len: usize,
|
|
|
|
parser: &'a mut Parser,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Expect<'_> {
|
2020-06-21 00:40:00 +02:00
|
|
|
pub fn get(self) -> Option<String> {
|
2020-06-21 00:21:24 +02:00
|
|
|
if self.text.is_some() {
|
|
|
|
self.parser.move_cursor_multiple(self.len);
|
|
|
|
}
|
|
|
|
self.text
|
|
|
|
}
|
2020-06-22 20:49:21 +02:00
|
|
|
pub fn get_or(self, error: SyntaxError) -> Result<String, SyntaxError> {
|
2020-06-21 00:21:24 +02:00
|
|
|
match self.get() {
|
|
|
|
Some(text) => Ok(text),
|
|
|
|
None => Err(error),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
pub struct Position(usize, usize);
|
2020-06-21 00:37:56 +02:00
|
|
|
|
|
|
|
impl Display for Position {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "line {}, column {}", self.0, self.1)
|
|
|
|
}
|
|
|
|
}
|