use lazy_static::lazy_static;
use regex::Regex;
use crate::{
error::{ParserError, ParserErrorKind},
indention::Indention,
value::{PrimitiveValue, Value},
ParserResult,
};
pub struct LineParser<'a> {
line_number: usize,
line: &'a str,
left: &'a str,
i: usize,
recorded: Vec<(usize, &'a str)>,
}
impl<'a> LineParser<'a> {
pub fn new(line_number: usize, line: &'a str) -> Self {
Self {
line_number,
line,
left: line,
i: 0,
recorded: Vec::new(),
}
}
pub fn generate_error(&self, kind: ParserErrorKind) -> ParserError {
ParserError {
kind,
line_number: self.line_number,
column_number: self.i,
line: self.line.to_string(),
}
}
pub fn consume_rest(&mut self) -> &'a str {
let ret = self.left;
self.i = self.line.len();
self.left = &self.line[self.line.len()..self.line.len()];
ret
}
fn record(&mut self) {
self.recorded.push((self.i, self.left));
}
fn restore(&mut self) {
let (i, left) = self.recorded.pop().unwrap();
self.i = i;
self.left = left;
}
fn cancel_restore(&mut self) {
self.recorded.pop().unwrap();
}
pub fn reached_end(&self) -> bool {
self.left.len() == 0
}
pub fn see(&mut self, s: &str) -> bool {
self.left.starts_with(s)
}
pub fn have(&mut self, s: &str) -> bool {
if self.see(s) {
self.i += s.len();
self.left = &self.left[s.len()..];
true
} else {
false
}
}
pub fn see_any(&mut self, ss: &[&str]) -> bool {
for s in ss {
if self.see(s) {
return true;
}
}
return false;
}
pub fn see_end_or_comment(&self) -> bool {
let left = self.left.trim_start();
left.len() == 0 || left.starts_with("#")
}
pub fn advance(&mut self) {
self.left = &self.left[1..];
self.i += 1;
}
pub fn advance_by(&mut self, amount: usize) {
self.left = &self.left[amount..];
self.i += amount;
}
pub fn next_whitespaces(&mut self) -> (usize, usize) {
let mut tabs_count = 0;
let mut spaces_count = 0;
while self.left.len() > 0 {
if self.left.starts_with(" ") {
spaces_count += 1;
self.advance();
} else if self.left.starts_with("\t") {
tabs_count += 1;
self.advance();
} else {
break;
}
}
(tabs_count, spaces_count)
}
pub fn consume_whitespaces(&mut self) {
let start_len = self.left.len();
self.left = self.left.trim_start();
self.i += start_len - self.left.len();
}
fn parse_string_literal_with(&mut self, escape: &str) -> ParserResult<String> {
let start = self.i;
loop {
if self.reached_end() {
return Err(self.generate_error(ParserErrorKind::UnclosedString));
}
if self.see(escape) {
let s = self.line[start..self.i].to_string();
self.advance_by(escape.len());
return Ok(s);
}
self.advance();
}
}
pub fn parse_string_literal(&mut self) -> ParserResult<Option<String>> {
if self.see("'") {
let start = self.i;
while self.have("'") {}
let escape = &self.line[start..self.i];
self.parse_string_literal_with(escape).map(|x| Some(x))
} else if self.see("\"") {
let start = self.i;
while self.have("\"") {}
let escape = &self.line[start..self.i];
self.parse_string_literal_with(escape).map(|x| Some(x))
} else {
Ok(None)
}
}
pub fn parse_key(&mut self) -> ParserResult<String> {
if let Some(literal) = self.parse_string_literal()? {
Ok(literal.to_string())
} else {
let start_len = self.left.len();
let source = self.left;
while self.left.len() > 0 {
if !self.see_any(&[" ", "\t", ":", "#", ";"]) {
self.advance();
} else {
break;
}
}
Ok(source[..start_len - self.left.len()].to_string())
}
}
pub fn parse_key_with_colon(&mut self) -> ParserResult<String> {
self.record();
let key = self.parse_key()?;
self.consume_whitespaces();
if self.have(":") {
self.cancel_restore();
Ok(key)
} else {
self.restore();
Ok(String::new())
}
}
pub fn parse_numerical_literal(&mut self) -> Option<f32> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^-?[0-9]*(?:\.[0-9]+)?").unwrap();
}
if let Some(captures) = RE.captures(self.left) {
if let Some(m) = captures.get(0) {
let s = m.as_str();
if let Ok(value) = s.parse() {
self.advance_by(s.len());
return Some(value);
}
}
}
None
}
pub fn parse_boolean_literal(&mut self) -> Option<bool> {
if self.have("true") {
Some(true)
} else if self.have("false") {
Some(false)
} else {
None
}
}
pub fn parse_null_literal(&mut self) -> bool {
self.have("null")
}
fn next_inline_array(&mut self) -> ParserResult<Value> {
let mut values = Vec::new();
loop {
self.consume_whitespaces();
if self.have("]") {
break;
}
if self.have("[") {
values.push(self.next_inline_array()?);
continue;
}
if let Some(primitive) = self.parse_primitive()? {
values.push(Value::Primitive(primitive));
continue;
}
todo!("error");
}
Ok(Value::Array(values))
}
pub fn parse_inline_array(&mut self) -> ParserResult<Option<Value>> {
if self.have("[") {
Ok(Some(self.next_inline_array()?))
} else {
Ok(None)
}
}
pub fn parse_primitive(&mut self) -> ParserResult<Option<PrimitiveValue>> {
if let Some(value) = self.parse_string_literal()? {
Ok(Some(PrimitiveValue::String(value)))
} else if let Some(value) = self.parse_numerical_literal() {
Ok(Some(PrimitiveValue::Number(value)))
} else if let Some(value) = self.parse_boolean_literal() {
Ok(Some(PrimitiveValue::Boolean(value)))
} else if self.parse_null_literal() {
Ok(Some(PrimitiveValue::Null))
} else {
Ok(None)
}
}
fn have_indentions_helper(&mut self, indention: Indention, amount: usize) -> bool {
match indention {
Indention::Tabs => {
for _ in 0..amount {
if self.see(" ") {
return false;
}
if !self.have("\t") {
return false;
}
}
}
Indention::Spaces(spaces) => {
for _ in 0..amount {
for _ in 0..spaces {
if self.see("\t") {
return false;
}
if !self.have(" ") {
return false;
}
}
}
}
};
true
}
pub fn have_indentions(&mut self, indention: Indention, amount: usize) -> bool {
self.record();
if self.have_indentions_helper(indention, amount) {
self.cancel_restore();
true
} else {
self.restore();
false
}
}
}