Skip to content

Commit 21bf78f

Browse files
committed
chore: optimise cursor operations
1 parent 260e638 commit 21bf78f

File tree

11 files changed

+196
-233
lines changed

11 files changed

+196
-233
lines changed

packages/engine/src/component.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ pub trait ComponentErrors {
2525
let start_index = start.index() as usize;
2626
let end_index = end.index() as usize;
2727

28-
let source = &source_file.as_ref().1[start_index..end_index];
28+
let code = &source_file.as_ref().1;
29+
30+
let source = &code[start_index..end_index.min(code.len())];
2931

3032
Box::from((source_file.as_ref().0.clone(), source.to_string()))
3133
}

packages/engine/src/cursor.rs

Lines changed: 39 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,64 @@
1-
pub type CursorTuple = (u16, u16);
1+
use std::fmt::Debug;
22

3-
#[derive(Debug, Clone, Copy, Eq)]
4-
pub struct Cursor {
5-
pub col: u16,
6-
pub line: u16,
7-
index: u32,
3+
#[derive(Clone, Copy, Eq)]
4+
pub struct Cursor(u16, u16, u32);
5+
6+
impl Debug for Cursor {
7+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8+
write!(f, "Cursor({}:{}@{})", self.0, self.1, self.2)
9+
}
10+
}
11+
12+
impl PartialEq for Cursor {
13+
fn eq(&self, other: &Self) -> bool {
14+
self.0 == other.0 && self.1 == other.1
15+
}
816
}
917

1018
impl Cursor {
1119
pub fn create() -> Self {
12-
Self {
13-
col: 1,
14-
line: 1,
15-
index: 0,
16-
}
20+
Self::from(1, 1)
1721
}
1822

19-
pub fn from(line: u16, col: u16) -> Self {
20-
Self {
21-
col,
22-
line,
23-
index: 0
24-
}
23+
pub fn from(col: u16, line: u16) -> Self {
24+
Self::from_full(col, line, 0)
2525
}
2626

2727
pub fn from_full(col: u16, line: u16, index: u32) -> Self {
28-
Self {
29-
col,
30-
line,
31-
index
32-
}
33-
}
34-
35-
/// Goes to the new line if needed, based on the character
36-
pub fn next(&mut self, char: &char) {
37-
if char.eq(&'\n') {
38-
self.next_line();
39-
} else {
40-
self.next_col();
41-
}
28+
Self(col, line, index)
4229
}
4330

44-
/// Moves the cursor to the next column
31+
/// Moves the cursor
4532
pub fn next_col(&mut self) {
46-
self.col += 1;
47-
48-
self.index += 1;
33+
self.1 += 1;
34+
self.2 += 1;
4935
}
50-
51-
/// Moves the cursor to the next line and resets the column to 0
52-
pub fn next_line(&mut self) {
53-
self.line += 1;
54-
self.col = 1;
5536

56-
self.index += 1;
37+
pub fn next_line(&mut self) {
38+
self.0 += 1;
39+
self.1 = 1;
40+
self.2 += 1;
5741
}
5842

59-
/// Gets the index in the input file of the cursor
60-
pub fn index(&self) -> u32 {
61-
self.index
62-
}
63-
64-
/// Resets the cursor back to line 1 column 1
43+
/// Resets the cursor
6544
pub fn reset(&mut self) {
66-
self.col = 1;
67-
self.line = 1;
45+
*self = Self::create();
6846
}
6947

70-
/// Returns a (line, col) tuple
71-
pub fn to_tuple(&self) -> CursorTuple {
72-
(self.line, self.col)
73-
}
74-
}
75-
76-
impl PartialEq for Cursor {
77-
fn eq(&self, other: &Self) -> bool {
78-
self.col == other.col && self.line == other.line
48+
/// Gets the line
49+
pub fn line(&self) -> u16 {
50+
self.0
7951
}
80-
}
8152

82-
impl From<Cursor> for CursorTuple {
83-
fn from(val: Cursor) -> Self {
84-
val.to_tuple()
53+
/// Gets the column
54+
pub fn col(&self) -> u16 {
55+
self.1
8556
}
57+
58+
/// Gets the index in the input file of the cursor
59+
pub fn index(&self) -> u32 {
60+
self.2
61+
}
8662
}
8763

8864
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -99,9 +75,9 @@ impl<T> WithCursor<T> {
9975

10076
pub fn create_with(start: Cursor, end: Cursor, value: T) -> Self {
10177
Self {
102-
value,
10378
start,
10479
end,
80+
value,
10581
}
10682
}
10783
}

packages/engine/src/error.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ where T: lang_macro::EnumVariantsTrait + ToString {
4949
"{}{}{}{}{}",
5050
path,
5151
":".black(),
52-
self.start().line,
52+
self.start().line(),
5353
":".black(),
54-
self.start().col,
54+
self.start().col(),
5555
).bold()
5656
)?;
5757

58-
let lines = (self.end().line - self.start().line) + 1;
59-
let max_line_len = self.end().line.to_string().len();
58+
let lines = (self.end().line() - self.start().line()) + 1;
59+
let max_line_len = self.end().line().to_string().len();
6060

6161
writeln!(f,
6262
" {} {}",
@@ -65,7 +65,7 @@ where T: lang_macro::EnumVariantsTrait + ToString {
6565
)?;
6666

6767
for index in 0..lines {
68-
let line = (self.start().line + index).to_string();
68+
let line = (self.start().line() + index).to_string();
6969
let line_len = line.len();
7070

7171
writeln!(f,

packages/engine/src/lexer/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub enum LexerErrorKind {
1515
#[error("overflowing integer '{0}'")]
1616
IntegerOverflow(String),
1717
#[error("expected character '{expected}' but found {found:?}")]
18-
UnexpectedCharacter { expected: String, found: Option<char> },
18+
ExpectedCharacter { expected: String, found: Option<char> },
1919
#[error("unknown token")]
2020
UnknownToken
2121
}

packages/engine/src/lexer/mod.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,13 @@ impl<'a> Lexer<'a> {
8282
if let Some(char) = self.next() {
8383
match self.scan_char(&char) {
8484
Ok(Some((token_type, value))) => self.add_token(token_type, value, start),
85-
Err(err) => {
86-
self.errors.push(EngineErrorKind::LexerError(LexerError {
87-
#[cfg(feature = "cli")]
88-
source_file: self.get_source_sliced(start, self.cursor),
89-
start,
90-
end: self.cursor,
91-
kind: err,
92-
}));
93-
}
85+
Err(err) => self.add_error(start, err),
9486
_ => {}
9587
}
9688
}
9789
}
9890

99-
let start = self.cursor;
100-
self.cursor.next_line();
101-
self.add_token(LexerTokenKind::EOL, None, start);
91+
self.add_token(LexerTokenKind::EOF, None, self.cursor);
10292

10393
&self.tokens
10494
}
@@ -258,6 +248,20 @@ impl<'a> Lexer<'a> {
258248
});
259249
}
260250

251+
fn add_error(
252+
&mut self,
253+
start: Cursor,
254+
err: LexerErrorKind
255+
) {
256+
self.errors.push(EngineErrorKind::LexerError(LexerError {
257+
#[cfg(feature = "cli")]
258+
source_file: self.get_source_sliced(start, self.cursor),
259+
start,
260+
end: self.cursor,
261+
kind: err,
262+
}))
263+
}
264+
261265
/// Consumes a single-line comment (aka skips to the end of the line and returns nothing)
262266
fn consume_single_line_comment(&mut self) -> LexerResult<()> {
263267
self.eat_until(&['\n'], false);
@@ -280,7 +284,15 @@ impl<'a> Lexer<'a> {
280284
/// Attempts to return a [`TokenType::String`]
281285
fn consume_string(&mut self) -> LexerResult<(LexerTokenKind, Option<Box<LexerLiteral>>)> {
282286
let string = self.eat_until(&['"', '\n'], true).unwrap_or_default();
283-
self.expect_char(&'"')?;
287+
288+
if let Err(err) = self.expect_char(&'"') {
289+
if let LexerErrorKind::ExpectedCharacter { found: Some(found), .. } = &err {
290+
self.cursor_next(found);
291+
}
292+
293+
return Err(err);
294+
}
295+
284296
Ok((
285297
LexerTokenKind::String,
286298
Some(Box::from(LexerLiteral::String(Box::from(string)))),
@@ -366,7 +378,7 @@ impl<'a> Lexer<'a> {
366378
}
367379

368380
_ => {
369-
return Err(LexerErrorKind::UnexpectedCharacter {
381+
return Err(LexerErrorKind::ExpectedCharacter {
370382
expected: "0..9".to_string(),
371383
found: Some(char),
372384
})
@@ -404,7 +416,7 @@ impl<'a> Lexer<'a> {
404416
LexerErrorKind::IntegerOverflow(collector)
405417
}
406418

407-
IntErrorKind::InvalidDigit => LexerErrorKind::UnexpectedCharacter {
419+
IntErrorKind::InvalidDigit => LexerErrorKind::ExpectedCharacter {
408420
expected: "0..9".to_string(),
409421
found: None,
410422
},
@@ -468,7 +480,7 @@ impl<'a> Lexer<'a> {
468480

469481
fn expect_char(&mut self, expected: &char) -> LexerResult<char> {
470482
self.expect(expected)
471-
.map_err(|found| LexerErrorKind::UnexpectedCharacter {
483+
.map_err(|found| LexerErrorKind::ExpectedCharacter {
472484
expected: expected.to_string(),
473485
found,
474486
})
@@ -491,7 +503,11 @@ impl<'a> ComponentIter<'a, char, char, Chars<'a>> for Lexer<'a> {
491503
&mut self.chars
492504
}
493505

494-
fn cursor_next(&mut self, item: &char) {
495-
self.cursor.next(item);
506+
fn cursor_next(&mut self, char: &char) {
507+
if char == &'\n' {
508+
self.cursor.next_line();
509+
} else {
510+
self.cursor.next_col();
511+
}
496512
}
497513
}

packages/engine/src/lexer/tokens.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ pub enum LexerTokenKind {
106106
RangeInclusive,
107107
/// `\n`
108108
EOL,
109+
EOF,
109110

110111
Identifier,
111112
String,

packages/engine/src/parser/ast.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ pub enum Expression {
2525

2626
#[derive(lang_macro::EnumVariants, Debug, Clone, PartialEq, Eq)]
2727
pub enum Statement {
28-
While(Box<(Expression, Block)>),
29-
For(Box<(Variable, Expression, Block)>),
30-
Return(Box<Option<Expression>>),
31-
Expression(Box<Expression>),
28+
While(Box<(WithCursor<Expression>, Block)>),
29+
For(Box<(Variable, WithCursor<Expression>, Block)>),
30+
Return(Box<Option<WithCursor<Expression>>>),
31+
Expression(Box<WithCursor<Expression>>),
3232
Continue,
3333
Break,
3434
Variable(Box<Variable>),

0 commit comments

Comments
 (0)