sprite-rs/src/lexer.rs

183 lines
4.3 KiB
Rust
Raw Normal View History

2022-02-28 22:43:27 +00:00
// Copyright (c) 2022 Marceline Cramer
// SPDX-License-Identifier: GPL-3.0-or-later
use logos::Logos;
use std::fmt::{Display, Formatter, Result as FmtResult};
#[rustfmt::skip]
2022-02-28 21:36:24 +00:00
#[derive(Logos, Clone, Copy, Debug, PartialEq)]
pub enum Token {
// keywords
2022-03-01 15:46:34 +00:00
#[token("struct")] Struct,
#[token("fn")] Function,
#[token("for")] For,
#[token("if")] If,
#[token("else")] Else,
#[token("in")] In,
#[token("let")] Let,
#[token("var")] Var,
#[token("interface")] Interface,
#[token("impl")] Impl,
// separators
#[token("{")] BraceOpen,
#[token("}")] BraceClose,
#[token("(")] ParanOpen,
#[token(")")] ParanClose,
#[token(";")] Semicolon,
#[token(",")] Comma,
#[token(".")] Dot,
// arithmetic operators
#[token("+")] OpAdd,
#[token("-")] OpSub,
#[token("*")] OpMul,
#[token("/")] OpDiv,
#[token("=")] OpAssign,
2022-03-01 15:46:34 +00:00
// boolean operators
#[token("or")] OpBoolOr,
#[token("and")] OpBoolAnd,
#[token("not")] OpBoolNot,
// bitwise operators
#[token("&")] OpBitAnd,
#[token("|")] OpBitOr,
#[token("^")] OpBitXor,
#[token("~")] OpBitNot,
// comparison operators
#[token("<")] OpLess,
#[token("<=")] OpLessEq,
#[token(">")] OpGreater,
#[token(">=")] OpGreaterEq,
#[token("==")] OpEq,
#[token("!=")] OpNeq,
#[regex(r"[a-zA-Z_][a-zA-Z0-9_]*")]
Identifier,
#[regex(r"0b_*[01][_01]*")]
BinaryInteger,
#[regex(r"0o_*[0-7][_0-7]*")]
OctalInteger,
#[regex(r"-?[0-9][_'0-9]*")]
DecimalInteger,
#[regex(r"//[^\n]*", logos::skip)]
SingleLineComment,
#[regex(r"[ \t\f ]+", logos::skip)]
Whitespace,
#[token("\n")]
Newline,
#[error]
Error,
}
pub struct TokenInfo<'a> {
pub line: &'a str,
pub line_num: usize,
pub token_start: usize,
pub token_end: usize,
}
impl<'a> Display for TokenInfo<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{:04}| {}\n |", self.line_num, self.line)?;
write!(f, "{} ^", " ".repeat(self.token_start))?;
let token_len = self.token_end - self.token_start;
if token_len > 1 {
2022-02-28 21:36:24 +00:00
write!(f, "{}^\n", "-".repeat(token_len - 2))
} else {
write!(f, "\n")
}
}
}
pub struct Lexer<'a> {
inner: logos::Lexer<'a, Token>,
line_num: usize,
line_start: usize,
}
impl<'a> Lexer<'a> {
pub fn new(source: &'a str) -> Self {
Self {
inner: Token::lexer(source),
line_num: 0,
line_start: 0,
}
}
pub fn slice(&self) -> &'a str {
self.inner.slice()
}
pub fn eat_id(&mut self) -> Result<&'a str, Option<Token>> {
let tok = self.next();
if let Some(Token::Identifier) = tok {
Ok(self.slice())
} else {
Err(tok)
}
}
2022-02-28 21:36:24 +00:00
pub fn eat_expect_id(&mut self) -> &'a str {
let tok = self.next();
if let Some(Token::Identifier) = tok {
self.slice()
} else {
self.panic_message("Expected identifier");
}
}
pub fn eat_expect(&mut self, expected: Token) {
let tok = self.next();
if tok != Some(expected) {
self.panic_message(&format!("Expected {:?}, got {:?}", expected, tok));
}
}
pub fn panic_message(&self, message: &str) -> ! {
panic!("{}\n{}", message, self.info());
}
pub fn info(&self) -> TokenInfo<'a> {
let from_start = &self.inner.source()[self.line_start..];
let line_end = from_start.find("\n").unwrap_or(from_start.len());
let line = &from_start[..line_end];
let span = self.inner.span();
TokenInfo {
line,
line_num: self.line_num,
token_start: span.start - self.line_start,
token_end: span.end - self.line_start,
}
}
}
impl<'a> Iterator for Lexer<'a> {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
while let Some(tok) = self.inner.next() {
if tok == Token::Newline {
self.line_start = self.inner.span().end;
self.line_num += 1;
} else {
return Some(tok);
}
}
None
}
}