1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::any::Any;
use std::any::type_name;
use std::clone;
use std::fmt::Display;
use std::fmt::Debug;
use std::fmt::format;
use std::iter::FromIterator;
use std::ops::Range;
use std::str::Chars;
use std::usize;

use crate::*;

/// Is used to parse things.
#[derive(Clone, Debug)]
pub struct Parser<'a> {

	input: &'a str,
	pub(crate)iterator: Chars<'a>,
	strict_mode: bool

}

impl<'a> From<&'a str> for Parser<'a> {

	fn from(input: &'a str) -> Self {
		
		Parser {

			input,
			iterator: input.chars(),
			strict_mode: true

		}

	}

}


impl<'a> Parser<'a> {

	/// Parses `T : FromStr` from the given input.
	pub fn parse<T: Parse>(&mut self) -> Result<T::Target> {

		type Spaces = Many<Either<"\t\n\r ">>;

		let ref mut cloned_parser = self.clone();

		if !(self.strict_mode) { let _ = Maybe::<Spaces>::parse_from(cloned_parser); }
		
		let result = T::parse_from(cloned_parser);
		
		if !(self.strict_mode) { let _ = Maybe::<Spaces>::parse_from(cloned_parser); }
		
		if result.is_ok() { self.clone_from(cloned_parser); } 
		
		result

	}

	/// Returns the entire input string.
	pub fn input(&self) -> &'a str {

		self.input

	}

	/// Returns the current index of this `Parser`.
	pub fn index(&self) -> usize {

 		self.iterator.clone().rev().count()

	}

	/// Returns the current line number.
	pub fn line(&self) -> usize {
		
		let enumerated = self.input.char_indices();

		let mut result = 0;

		for (i, character) in enumerated {

			if character == '\n' { result += 1; }
			
			if i > self.index() { break; }

		}

		if result == 0 { result } else { result - 1 }

	}

	/// The current position within the current line.
	pub fn column(&self) -> usize {

		let beginning_reversed = self.input.clone().split_at(self.index()).1.chars().rev().collect::<String>();

		beginning_reversed.chars().position(|c| c == '\n').unwrap_or(0)
		
	}

	pub fn enable_strict_mode(&mut self) {
		
		self.strict_mode = true;
		
	} 

	pub fn disable_strict_mode(&mut self) {

		self.strict_mode = false;

	}


}