overhaul operator precedence

arithmetic operators now have the same precedence.
if you want them to bind tighter, you remove the spaces around them:

- 2 + 2 * 2 = 8
- 2 + 2*2 = 6
This commit is contained in:
りき萌 2025-09-01 21:13:32 +02:00
parent 09f2292e62
commit b52c1b26c9
4 changed files with 144 additions and 43 deletions

View file

@ -3,7 +3,7 @@ use alloc::vec::Vec;
use crate::{
diagnostic::Diagnostic,
source::{SourceCode, Span},
token::{Lexis, TokenAllocError, TokenKind},
token::{Lexis, Spaces, TokenAllocError, TokenKind},
};
pub struct Lexer<'a> {
@ -132,7 +132,8 @@ fn color(l: &mut Lexer<'_>) -> TokenKind {
TokenKind::Color
}
fn whitespace_and_comments(l: &mut Lexer<'_>) {
fn whitespace_and_comments(l: &mut Lexer<'_>) -> bool {
let mut matched = false;
loop {
match l.current() {
'-' => {
@ -142,6 +143,7 @@ fn whitespace_and_comments(l: &mut Lexer<'_>) {
while l.current() != '\n' && l.current() != '\0' {
l.advance();
}
matched = true;
} else {
// An unfortunate little bit of backtracking here;
// This seems like the simplest possible solution though.
@ -153,14 +155,18 @@ fn whitespace_and_comments(l: &mut Lexer<'_>) {
}
}
' ' | '\r' | '\t' => l.advance(),
' ' | '\r' | '\t' => {
l.advance();
matched = true
}
_ => break,
}
}
matched
}
fn newline(l: &mut Lexer<'_>) -> (TokenKind, Span) {
fn newline(l: &mut Lexer<'_>, has_left_space: bool) -> (TokenKind, Span, bool) {
let start = l.position;
l.advance(); // skip the initial newline
let end = l.position;
@ -177,11 +183,11 @@ fn newline(l: &mut Lexer<'_>) -> (TokenKind, Span) {
}
}
(TokenKind::Newline, Span::new(start, end))
(TokenKind::Newline, Span::new(start, end), has_left_space)
}
fn token(l: &mut Lexer<'_>) -> (TokenKind, Span) {
whitespace_and_comments(l);
fn token(l: &mut Lexer<'_>) -> (TokenKind, Span, bool) {
let has_left_space = whitespace_and_comments(l);
let start = l.position;
let kind = match l.current() {
@ -203,7 +209,7 @@ fn token(l: &mut Lexer<'_>) -> (TokenKind, Span) {
'<' => one_or_two(l, TokenKind::Less, '=', TokenKind::LessEqual),
'>' => one_or_two(l, TokenKind::Greater, '=', TokenKind::GreaterEqual),
'\n' => return newline(l),
'\n' => return newline(l, has_left_space),
'(' => one(l, TokenKind::LParen),
')' => one(l, TokenKind::RParen),
'[' => one(l, TokenKind::LBrack),
@ -222,13 +228,22 @@ fn token(l: &mut Lexer<'_>) -> (TokenKind, Span) {
}
};
let end = l.position;
(kind, Span::new(start, end))
(kind, Span::new(start, end), has_left_space)
}
pub fn lex(l: &mut Lexer<'_>) -> Result<(), TokenAllocError> {
loop {
let (kind, span) = token(l);
l.lexis.push(kind, span)?;
let (kind, span, has_left_space) = token(l);
if !l.lexis.is_empty() {
let prev = l.lexis.len() - 1;
let spaces = l.lexis.spaces(prev);
l.lexis
.set_spaces(prev, Spaces::new(spaces.left(), has_left_space));
}
let spaces = Spaces::new(has_left_space, false);
l.lexis.push(kind, spaces, span)?;
if kind == TokenKind::Eof {
break;
}