glang_core 0.1.0

Scripting language built with Rust
Documentation
// Copyright 2022 the GLanguage authors. All rights reserved. MIT license.

use crate::token::{Kind, Token};

pub struct Lexer {
	source_code: String,
	position: usize,
	current: Option<Token>,
	errors: Vec<String>,
}

impl Lexer {
	pub fn new(source_code: String) -> Self {
		Self {
			source_code,
			position: 0,
			current: None,
			errors: Vec::new(),
		}
	}

	fn current_char(&self) -> Option<char> {
		self.source_code.chars().nth(self.position)
	}

	fn current_token(&self) -> Option<Token> {
		self.current.clone()
	}

	fn advance_token(&mut self) {
		self.current = self.next();
	}

	pub fn check_source_code(&mut self) -> Result<(), String> {
		loop {
			match self.consume() {
				Ok(token) => {
					if let Some(token) = token {
						if token.kind == Kind::EOF {
							break;
						}
					}
				}
				Err(err) => return Err(err),
			}
		}

		Ok(())
	}

	pub fn consume(&mut self) -> Result<Option<Token>, String> {
		self.advance_token();
		if self.errors.len() > 0 {
			return Err(format!("{}", self.errors.first().unwrap()));
		}
		Ok(self.current_token())
	}
}

impl Iterator for Lexer {
	type Item = Token;

	fn next(&mut self) -> Option<Self::Item> {
		let current: Option<char> = self.current_char();
		let kind: Result<Kind, String> = Kind::classify(current.clone());
		self.position += 1;

		match kind {
			Ok(k) => match k {
				Kind::EOF => Some(Token::new(k, format!("eof"))),
				Kind::String => {
					let mut string: Vec<char> = Vec::new();
					loop {
						let cc: Option<char> = self.current_char();
						self.position += 1;
						let kc: Result<Kind, String> = Kind::classify(cc.clone());

						if let Ok(Kind::EOF) = kc {
							self.errors
								.push(format!("unterminated double quote string"));
							break None;
						} else if let Ok(Kind::String) = kc {
							break Some(Token::new(k, string.into_iter().collect()));
						} else {
							string.push(cc.unwrap())
						}
					}
				}
				_ => Some(Token::new(k, current.unwrap().to_string())),
			},
			Err(err) => {
				self.errors.push(err);
				None
			}
		}
	}
}