Skip to content
Snippets Groups Projects
Commit ea0f5e9a authored by Stephen D's avatar Stephen D
Browse files

basic scanner

parents
No related branches found
No related tags found
No related merge requests found
/target
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "sophiescript"
version = "0.1.0"
[package]
name = "sophiescript"
version = "0.1.0"
edition = "2021"
[dependencies]
$false = λtf.f
$true = λtf.t
λa.(a $true)
use scanner::Scanner;
mod scanner;
mod token;
fn main() {
let scanner = Scanner::new(
"
$false = λtf.f
# mrow!
$true = λtf.t
λa.(a $true)
",
);
for t in scanner.scan_tokens().unwrap() {
dbg!(t.token_type);
}
}
use crate::token::{Token, TokenType};
pub struct Scanner {
chars: Vec<char>,
tokens: Vec<Token>,
start: usize,
current: usize,
line: usize,
}
impl Scanner {
pub fn new(source: &str) -> Self {
let chars = source.chars().collect();
Self {
chars,
tokens: vec![],
start: 0,
current: 0,
line: 1,
}
}
pub fn scan_tokens(mut self) -> Result<Vec<Token>, ()> {
while !self.is_at_end() {
self.start = self.current;
self.scan_token()?;
}
self.tokens
.push(Token::new(TokenType::Eof, "".to_string(), self.line));
Ok(self.tokens)
}
pub fn scan_token(&mut self) -> Result<(), ()> {
use TokenType::*;
let c = self.advance();
let token_type = match c {
'(' => LeftParen,
')' => RightParen,
'.' => Period,
'=' => Equals,
' ' | '\r' | '\n' | '\t' => NoToken,
'\\' | '/' | 'λ' => Lambda,
_ if c.is_alphabetic() => Variable(c),
'$' => {
self.function()?;
NoToken
}
'#' => {
// comment
while self.peek() != '\n' {
self.advance();
}
NoToken
}
_ => {
self.print_error(&format!("Unexpected character `{}`.", c));
return Err(());
}
};
self.add_token(token_type);
Ok(())
}
fn function(&mut self) -> Result<(), ()> {
while self.peek().is_alphanumeric() {
self.advance();
}
if self.start + 1 == self.current {
self.print_error("Missing function name after $");
return Err(());
}
self.add_token(TokenType::Function(
self.chars[(self.start + 1)..self.current].iter().collect(),
));
Ok(())
}
fn add_token(&mut self, token_type: TokenType) {
if token_type == TokenType::NoToken {
return;
}
let text: String = self.chars[self.start..self.current].iter().collect();
self.tokens.push(Token::new(token_type, text, self.line));
}
fn peek(&self) -> char {
self.chars[self.current]
}
fn advance(&mut self) -> char {
let c = self.chars[self.current];
self.current += 1;
if c == '\n' {
self.line += 1;
}
c
}
fn is_at_end(&self) -> bool {
self.current >= self.chars.len()
}
fn print_error(&self, err: &str) {
eprintln!("Error on line [{}]: {err}", self.line);
}
}
#[derive(PartialEq, Eq, Debug)]
pub enum TokenType {
Variable(char),
Function(String),
Lambda,
Period,
Equals,
Eof,
LeftParen,
RightParen,
NoToken,
}
pub struct Token {
pub line: usize,
pub lexeme: String,
pub token_type: TokenType,
}
impl Token {
pub fn new(token_type: TokenType, lexeme: String, line: usize) -> Self {
Self {
line,
lexeme,
token_type,
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment