mirror of
https://github.com/TheM1Stery/izanami.git
synced 2025-04-20 08:51:12 +00:00
Compare commits
2 Commits
2bac50ecba
...
4df4107b77
Author | SHA1 | Date | |
---|---|---|---|
4df4107b77 | |||
cd5fae595c |
32
src/lib.rs
32
src/lib.rs
@ -4,6 +4,7 @@ use std::{
|
|||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use scanner::Scanner;
|
||||||
use token::Token;
|
use token::Token;
|
||||||
|
|
||||||
mod scanner;
|
mod scanner;
|
||||||
@ -13,24 +14,37 @@ mod utils;
|
|||||||
pub fn run_file(path: &str) -> Result<(), Box<dyn Error>> {
|
pub fn run_file(path: &str) -> Result<(), Box<dyn Error>> {
|
||||||
let file = fs::read_to_string(path)?;
|
let file = fs::read_to_string(path)?;
|
||||||
|
|
||||||
|
run(&file);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(src: &str) {
|
pub fn run(src: &str) {
|
||||||
let tokens: Vec<Token> = Vec::new();
|
let mut scanner = Scanner::new(src.to_string());
|
||||||
|
let tokens = scanner.scan_tokens();
|
||||||
|
|
||||||
|
match tokens {
|
||||||
|
Err(ref errors) => {
|
||||||
|
for err in errors {
|
||||||
|
report(err.line, "", &err.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(tokens) => {
|
||||||
|
for token in tokens {
|
||||||
|
println!("{}", token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_prompt() -> Result<(), Box<dyn Error>> {
|
pub fn run_prompt() -> Result<(), Box<dyn Error>> {
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let input = &mut String::new();
|
let input = &mut String::new();
|
||||||
print!("> ");
|
|
||||||
io::stdout().flush()?;
|
|
||||||
loop {
|
loop {
|
||||||
input.clear();
|
input.clear();
|
||||||
let _ = stdin.read_line(input)?;
|
|
||||||
|
|
||||||
print!("> ");
|
print!("> ");
|
||||||
io::stdout().flush()?;
|
io::stdout().flush()?;
|
||||||
|
stdin.read_line(input)?;
|
||||||
|
run(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,12 +54,6 @@ pub struct RloxError {
|
|||||||
line: usize,
|
line: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RloxError {
|
pub fn report(line: usize, location: &str, message: &str) {
|
||||||
pub fn error(line: i32, message: &str) {
|
|
||||||
report(line, "", message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn report(line: i32, location: &str, message: &str) {
|
|
||||||
eprintln!("[line {line}] Error {location}: {message}");
|
eprintln!("[line {line}] Error {location}: {message}");
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ pub struct Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Scanner {
|
impl Scanner {
|
||||||
fn new(source: String) -> Self {
|
pub fn new(source: String) -> Self {
|
||||||
// the reason for using unsafe here is to have the ability to use utf-8 symbols
|
// the reason for using unsafe here is to have the ability to use utf-8 symbols
|
||||||
// rust doesn't allow having both the iterator and iterable inside one
|
// rust doesn't allow having both the iterator and iterable inside one
|
||||||
// structure(understandably so bcs of reference invalidation)
|
// structure(understandably so bcs of reference invalidation)
|
||||||
@ -35,7 +35,7 @@ impl Scanner {
|
|||||||
|
|
||||||
// this is so awful for me to write. This function needs to be not mutable in theory and it
|
// this is so awful for me to write. This function needs to be not mutable in theory and it
|
||||||
// could be accomplished. TODO!
|
// could be accomplished. TODO!
|
||||||
fn scan_tokens(&mut self) -> Result<&Vec<Token>, Vec<RloxError>> {
|
pub fn scan_tokens(&mut self) -> Result<&Vec<Token>, Vec<RloxError>> {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
while self.peek().is_some() {
|
while self.peek().is_some() {
|
||||||
self.start = self.current;
|
self.start = self.current;
|
||||||
@ -94,10 +94,11 @@ impl Scanner {
|
|||||||
}
|
}
|
||||||
'/' => self.add_token(TokenType::Slash),
|
'/' => self.add_token(TokenType::Slash),
|
||||||
'"' => error = self.string(),
|
'"' => error = self.string(),
|
||||||
'0'..='9' => self.number(),
|
|
||||||
' ' | '\r' | '\t' => (),
|
' ' | '\r' | '\t' => (),
|
||||||
'\n' => self.line += 1,
|
'\n' => self.line += 1,
|
||||||
|
|
||||||
|
'0'..='9' => self.number(),
|
||||||
|
'a'..='z' | 'A'..='Z' | '_' => self.identifier(),
|
||||||
_ => {
|
_ => {
|
||||||
error = Err(RloxError {
|
error = Err(RloxError {
|
||||||
msg: "Unexpected character".to_string(),
|
msg: "Unexpected character".to_string(),
|
||||||
@ -200,6 +201,45 @@ impl Scanner {
|
|||||||
|
|
||||||
self.add_token_literal(TokenType::Number, Some(LiteralType::Number(number)));
|
self.add_token_literal(TokenType::Number, Some(LiteralType::Number(number)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn identifier(&mut self) {
|
||||||
|
while self.peek().is_some_and(is_alpha_numeric) {
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
let text_value = self.source.slice(self.start..self.current);
|
||||||
|
if let Some(identified_token) = get_identified_keyword(text_value) {
|
||||||
|
return self.add_token(identified_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.add_token(TokenType::Identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_alpha_numeric(chr: char) -> bool {
|
||||||
|
matches!(chr ,'0'..='9'| '_' | 'a'..='z'|'A'..='Z')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_identified_keyword(identifier: &str) -> Option<TokenType> {
|
||||||
|
match identifier {
|
||||||
|
"and" => Some(TokenType::And),
|
||||||
|
"class" => Some(TokenType::Class),
|
||||||
|
"else" => Some(TokenType::Else),
|
||||||
|
"false" => Some(TokenType::False),
|
||||||
|
"for" => Some(TokenType::For),
|
||||||
|
"fun" => Some(TokenType::Fun),
|
||||||
|
"if" => Some(TokenType::If),
|
||||||
|
"nil" => Some(TokenType::Nil),
|
||||||
|
"or" => Some(TokenType::OR),
|
||||||
|
"print" => Some(TokenType::Print),
|
||||||
|
"return" => Some(TokenType::Return),
|
||||||
|
"super" => Some(TokenType::Super),
|
||||||
|
"this" => Some(TokenType::This),
|
||||||
|
"true" => Some(TokenType::True),
|
||||||
|
"var" => Some(TokenType::Var),
|
||||||
|
"while" => Some(TokenType::While),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -312,7 +352,7 @@ mod tests {
|
|||||||
fn correct_fractional_number_scan() {
|
fn correct_fractional_number_scan() {
|
||||||
let value = r#"
|
let value = r#"
|
||||||
// number test
|
// number test
|
||||||
123.456"#
|
123.aaa"#
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let mut scanner = Scanner::new(value);
|
let mut scanner = Scanner::new(value);
|
||||||
|
Loading…
Reference in New Issue
Block a user