mirror of
https://github.com/guilhermewerner/language
synced 2025-06-15 12:44:19 +00:00
Update lexer.rs
This commit is contained in:
82
src/lexer.rs
82
src/lexer.rs
@ -2,26 +2,35 @@ use std::iter::Peekable;
|
|||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::str::Chars;
|
use std::str::Chars;
|
||||||
|
|
||||||
/// Represents a primitive syntax token.
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[derive(Debug, Clone)]
|
pub enum Keyword {
|
||||||
pub enum Token {
|
|
||||||
Comma,
|
|
||||||
Comment,
|
|
||||||
Const,
|
Const,
|
||||||
Else,
|
Else,
|
||||||
EOF,
|
|
||||||
For,
|
For,
|
||||||
Function,
|
Function,
|
||||||
Ident(String),
|
|
||||||
If,
|
If,
|
||||||
Import,
|
Import,
|
||||||
LParen,
|
Return,
|
||||||
|
Var,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum TokenKind {
|
||||||
|
CloseBrace, // "}"
|
||||||
|
CloseBracket, // "]"
|
||||||
|
CloseParen, // ")"
|
||||||
|
Comma, // ","
|
||||||
|
Eof,
|
||||||
|
Ident(String),
|
||||||
|
Keyword(Keyword),
|
||||||
|
LineComment,
|
||||||
Number(f64),
|
Number(f64),
|
||||||
Op(char),
|
Op(char),
|
||||||
Return,
|
OpenBrace, // "{"
|
||||||
RParen,
|
OpenBracket, // "["
|
||||||
|
OpenParen, // "("
|
||||||
|
Semi, // ";"
|
||||||
SemiColon,
|
SemiColon,
|
||||||
Var,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines an error encountered by the `Lexer`.
|
/// Defines an error encountered by the `Lexer`.
|
||||||
@ -47,7 +56,7 @@ impl LexerError {
|
|||||||
|
|
||||||
/// Defines the result of a lexing operation; namely a
|
/// Defines the result of a lexing operation; namely a
|
||||||
/// `Token` on success, or a `LexerError` on failure.
|
/// `Token` on success, or a `LexerError` on failure.
|
||||||
pub type LexerResult = Result<Token, LexerError>;
|
pub type LexerResult = Result<TokenKind, LexerError>;
|
||||||
|
|
||||||
pub struct Lexer<'a> {
|
pub struct Lexer<'a> {
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
@ -83,7 +92,7 @@ impl<'a> Lexer<'a> {
|
|||||||
if ch.is_none() {
|
if ch.is_none() {
|
||||||
self.pos = pos;
|
self.pos = pos;
|
||||||
|
|
||||||
return Ok(Token::EOF);
|
return Ok(TokenKind::Eof);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ch.unwrap().is_whitespace() {
|
if !ch.unwrap().is_whitespace() {
|
||||||
@ -99,17 +108,21 @@ impl<'a> Lexer<'a> {
|
|||||||
let next = chars.next();
|
let next = chars.next();
|
||||||
|
|
||||||
if next.is_none() {
|
if next.is_none() {
|
||||||
return Ok(Token::EOF);
|
return Ok(TokenKind::Eof);
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += 1;
|
pos += 1;
|
||||||
|
|
||||||
// Actually get the next token.
|
// Actually get the next token.
|
||||||
let result = match next.unwrap() {
|
let result = match next.unwrap() {
|
||||||
'(' => Ok(Token::LParen),
|
';' => Ok(TokenKind::Semi),
|
||||||
')' => Ok(Token::RParen),
|
',' => Ok(TokenKind::Comma),
|
||||||
',' => Ok(Token::Comma),
|
'(' => Ok(TokenKind::OpenParen),
|
||||||
';' => Ok(Token::SemiColon),
|
')' => Ok(TokenKind::CloseParen),
|
||||||
|
'{' => Ok(TokenKind::OpenBrace),
|
||||||
|
'}' => Ok(TokenKind::CloseBrace),
|
||||||
|
'[' => Ok(TokenKind::OpenBracket),
|
||||||
|
']' => Ok(TokenKind::CloseBracket),
|
||||||
|
|
||||||
'#' => {
|
'#' => {
|
||||||
// Comment
|
// Comment
|
||||||
@ -122,7 +135,7 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Token::Comment)
|
Ok(TokenKind::LineComment)
|
||||||
}
|
}
|
||||||
|
|
||||||
'.' | '0'..='9' => {
|
'.' | '0'..='9' => {
|
||||||
@ -130,7 +143,7 @@ impl<'a> Lexer<'a> {
|
|||||||
loop {
|
loop {
|
||||||
let ch = match chars.peek() {
|
let ch = match chars.peek() {
|
||||||
Some(ch) => *ch,
|
Some(ch) => *ch,
|
||||||
None => return Ok(Token::EOF),
|
None => return Ok(TokenKind::Eof),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse float.
|
// Parse float.
|
||||||
@ -142,7 +155,7 @@ impl<'a> Lexer<'a> {
|
|||||||
pos += 1;
|
pos += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Token::Number(src[start..pos].parse().unwrap()))
|
Ok(TokenKind::Number(src[start..pos].parse().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
'a'..='z' | 'A'..='Z' | '_' => {
|
'a'..='z' | 'A'..='Z' | '_' => {
|
||||||
@ -150,7 +163,7 @@ impl<'a> Lexer<'a> {
|
|||||||
loop {
|
loop {
|
||||||
let ch = match chars.peek() {
|
let ch = match chars.peek() {
|
||||||
Some(ch) => *ch,
|
Some(ch) => *ch,
|
||||||
None => return Ok(Token::EOF),
|
None => return Ok(TokenKind::Eof),
|
||||||
};
|
};
|
||||||
|
|
||||||
// A word-like identifier only contains underscores and alphanumeric characters.
|
// A word-like identifier only contains underscores and alphanumeric characters.
|
||||||
@ -163,22 +176,21 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match &src[start..pos] {
|
match &src[start..pos] {
|
||||||
"function" => Ok(Token::Function),
|
"const" => Ok(TokenKind::Keyword(Keyword::Const)),
|
||||||
"import" => Ok(Token::Import),
|
"else" => Ok(TokenKind::Keyword(Keyword::Else)),
|
||||||
"if" => Ok(Token::If),
|
"for" => Ok(TokenKind::Keyword(Keyword::For)),
|
||||||
"else" => Ok(Token::Else),
|
"function" => Ok(TokenKind::Keyword(Keyword::Function)),
|
||||||
"for" => Ok(Token::For),
|
"if" => Ok(TokenKind::Keyword(Keyword::If)),
|
||||||
"var" => Ok(Token::Var),
|
"import" => Ok(TokenKind::Keyword(Keyword::Import)),
|
||||||
"return" => Ok(Token::Return),
|
"return" => Ok(TokenKind::Keyword(Keyword::Return)),
|
||||||
"const" => Ok(Token::Const),
|
"var" => Ok(TokenKind::Keyword(Keyword::Var)),
|
||||||
|
ident => Ok(TokenKind::Ident(ident.to_string())),
|
||||||
ident => Ok(Token::Ident(ident.to_string())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
op => {
|
op => {
|
||||||
// Parse operator
|
// Parse operator
|
||||||
Ok(Token::Op(op))
|
Ok(TokenKind::Op(op))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -190,13 +202,13 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Lexer<'a> {
|
impl<'a> Iterator for Lexer<'a> {
|
||||||
type Item = Token;
|
type Item = TokenKind;
|
||||||
|
|
||||||
/// Lexes the next `Token` and returns it.
|
/// Lexes the next `Token` and returns it.
|
||||||
/// On EOF or failure, `None` will be returned.
|
/// On EOF or failure, `None` will be returned.
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self.lex() {
|
match self.lex() {
|
||||||
Ok(Token::EOF) | Err(_) => None,
|
Ok(TokenKind::Eof) | Err(_) => None,
|
||||||
Ok(token) => Some(token),
|
Ok(token) => Some(token),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user