Begin scanner impl
This commit is contained in:
7
src/lexer/mod.rs
Normal file
7
src/lexer/mod.rs
Normal 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
35
src/lexer/scanner.rs
Normal 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
65
src/lexer/token.rs
Normal 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
20
src/lexer/tokenize.rs
Normal 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!()
|
||||
// }
|
||||
// }
|
||||
46
src/main.rs
46
src/main.rs
@@ -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:?}");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user