Begin scanner impl

This commit is contained in:
2025-02-03 19:24:16 -05:00
parent 32bfb07574
commit 57aeabece8
5 changed files with 155 additions and 18 deletions

7
src/lexer/mod.rs Normal file
View File

@@ -0,0 +1,7 @@
mod token;
pub mod scanner;
pub mod tokenize;
pub use token::*;
pub use tokenize::*;

35
src/lexer/scanner.rs Normal file
View File

@@ -0,0 +1,35 @@
use super::LoxToken;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum LexerError {
#[error("Unexpected symbol encountered on line {0}, col {1}: {2}")]
UnexpectedSymbol(usize, usize, String),
#[error("Unexpected EOF reached.")]
EarlyEOF,
}
pub struct LoxScanner<'a> {
source: &'a str,
current_line: usize,
current_column: usize,
}
impl<'a> LoxScanner<'a> {
pub fn from_str(source: &'a str) -> Self {
Self {
source,
current_line: 0,
current_column: 0,
}
}
}
impl Iterator for LoxScanner<'_> {
type Item = Result<LoxToken, LexerError>;
fn next(&mut self) -> Option<Self::Item> {
Some(Err(LexerError::EarlyEOF))
}
}

65
src/lexer/token.rs Normal file
View File

@@ -0,0 +1,65 @@
#[derive(Debug, Copy, Clone)]
enum NumberValue {
Integer(usize),
Real(usize, usize),
}
#[derive(Debug, Copy, Clone)]
enum TokenType {
// Single-character tokens
LeftParen,
RightParen,
LeftBrace,
RightBrace,
Comma,
Dot,
Minux,
Plus,
Semicolon,
Slash,
Star,
// One or two character tokens
Bang,
BangEqual,
Equal,
EqualEqual,
Greater,
GreaterEqual,
Less,
LessEqual,
// Literals.
Identifier,
String,
Number(NumberValue),
// Keywords
And,
Class,
Else,
False,
Fun,
For,
If,
Nil,
Or,
Print,
Return,
Super,
This,
True,
Var,
While,
// Special
Eof,
}
#[derive(Debug, Clone)]
pub struct LoxToken {
token_type: TokenType,
lexeme: String,
line: usize,
column: usize,
}

20
src/lexer/tokenize.rs Normal file
View File

@@ -0,0 +1,20 @@
use super::scanner::LoxScanner;
pub trait IntoScanner<'a> {
fn scan(self) -> LoxScanner<'a>;
}
impl<'a> IntoScanner<'a> for &'a str {
fn scan(self) -> LoxScanner<'a> {
LoxScanner::from_str(self)
}
}
// impl<'a> IntoIterator for &'a str {
// type Item = Result<LoxToken, LexerError>;
// type IntoIter = LoxScanner<'a>;
// fn into_iter(self) -> Self::IntoIter {
// todo!()
// }
// }

View File

@@ -1,38 +1,48 @@
use std::{ffi::OsString, io::{stdout, Write}, process::exit};
#![allow(dead_code)]
mod lexer;
use crate::lexer::IntoScanner;
use clap::Parser;
use std::{
ffi::OsString,
io::{stdout, Write},
process::exit,
};
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
script: Option<OsString>
script: Option<OsString>,
}
fn main()
{
fn main() {
let args = Args::parse();
args.script.map_or_else(run_prompt, run_script);
}
fn run_prompt() -> !
{
fn run_prompt() -> ! {
let input = std::io::stdin();
let mut bytes = 1;
let mut buffer: String = String::new();
while bytes > 0 {
loop {
let mut buffer: String = String::with_capacity(256);
print!("> ");
stdout().flush().expect("Unable to flush stdout?");
stdout().flush().expect("Unable to flush stdout!");
bytes = input.read_line(&mut buffer).expect("Error reading from stdin!");
let trimmed = buffer.trim();
println!("Bytes Read: {bytes}, String: '{trimmed}'");
buffer.clear();
input.read_line(&mut buffer).expect("Error reading stdin!");
run(&buffer);
}
exit(0);
}
fn run_script(_script: OsString) -> !
{
fn run_script(script: OsString) -> ! {
let script_str = std::fs::read_to_string(script).expect("Unable to read in script file!");
run(&script_str);
exit(0)
}
#[allow(unused_variables)]
fn run(source: &str) {
for token in source.scan() {
println!("Token {token:?}");
}
}