Skip to content

Commit

Permalink
Remove token memory allocations allocations from lexer
Browse files Browse the repository at this point in the history
  • Loading branch information
allancalix committed Oct 1, 2022
1 parent 8f05e06 commit 186e21c
Show file tree
Hide file tree
Showing 12 changed files with 3,592 additions and 375 deletions.
8 changes: 7 additions & 1 deletion crates/apollo-parser/benches/benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,11 @@ fn bench_parser_peek_n(c: &mut Criterion) {
c.bench_function("parser_peek_n", move |b| b.iter(|| parse_query(query)));
}

criterion_group!(benches, bench_parser_peek_n);
fn bench_parser_many_aliases(c: &mut Criterion) {
let query = include_str!("testdata/alias.graphql");

c.bench_function("many_aliases", move |b| b.iter(|| parse_query(query)));
}

criterion_group!(benches, bench_parser_peek_n, bench_parser_many_aliases);
criterion_main!(benches);
3,005 changes: 3,005 additions & 0 deletions crates/apollo-parser/benches/testdata/alias.graphql

Large diffs are not rendered by default.

114 changes: 91 additions & 23 deletions crates/apollo-parser/src/lexer/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,131 @@
use std::str::Chars;
use std::str::CharIndices;

use crate::Error;

/// Peekable iterator over a char sequence.
#[derive(Debug, Clone)]
pub(crate) struct Cursor<'a> {
chars: Chars<'a>,
index: usize,
offset: usize,
prev: usize,
source: &'a str,
chars: CharIndices<'a>,
pending: Option<char>,
pub(crate) err: Option<Error>,
}

impl<'a> Cursor<'a> {
pub(crate) fn new(input: &'a str) -> Cursor<'a> {
Cursor {
chars: input.chars(),
index: 0,
offset: 0,
prev: 0,
pending: None,
source: input,
chars: input.char_indices(),
err: None,
}
}
}

pub(crate) const EOF_CHAR: char = '\0';

impl<'a> Cursor<'a> {
/// Returns nth character relative to the current cursor position.
fn nth_char(&self, n: usize) -> char {
self.chars().nth(n).unwrap_or(EOF_CHAR)
pub(crate) fn index(&self) -> usize {
self.index
}

fn eof(&self) -> bool {
self.offset == self.source.len()
}

/// Peeks the next char in input without consuming.
pub(crate) fn first(&self) -> char {
self.nth_char(0)
pub(crate) fn pending(&self) -> bool {
self.pending.is_some()
}

/// Peeks the second char in input without consuming.
pub(crate) fn second(&self) -> char {
self.nth_char(1)
pub(crate) fn pending_len(&self) -> usize {
self.offset - self.index
}

/// Moves to the next character.
pub(crate) fn prev_str(&mut self) -> &'a str {
let slice = &self.source[self.index..self.offset];

self.index = self.offset;
self.pending = self.source[self.offset..].chars().next();

slice
}

/// Checks if there are chars to consume.
pub(crate) fn is_eof(&self) -> bool {
self.chars.as_str().is_empty()
/// Moves to the next character.
pub(crate) fn current_str(&mut self) -> &'a str {
self.pending = None;
if self.eof() {
return &self.source[self.index..];
}
let slice = &self.source[self.index..=self.offset];

self.index = self.offset;
self.offset = self.offset;
if let Some((pos, next)) = self.chars.next() {
self.index = pos;
self.offset = pos;
self.pending = Some(next);
}

slice
}

/// Moves to the next character.
pub(crate) fn bump(&mut self) -> Option<char> {
let c = self.chars.next()?;
if self.pending.is_some() {
return self.pending.take();
}

if self.offset == self.source.len() {
return None;
}

let (pos, c) = self.chars.next()?;
self.prev = self.offset;
self.offset = pos;

Some(c)
}

/// Moves to the next character.
pub(crate) fn eatc(&mut self, c: char) -> bool {
if self.pending.is_some() {
panic!("dont call eatc when a character is pending");
}

if let Some((pos, c_in)) = self.chars.next() {
self.prev = self.offset;
self.offset = pos;

if c_in == c {
return true;
}

self.pending = Some(c_in);
}

false
}

/// Get current error object in the cursor.
pub(crate) fn err(&mut self) -> Option<Error> {
self.err.clone()
}

pub(crate) fn drain(&mut self) -> &'a str{
self.pending = None;
let start = self.index;
self.index = self.source.len() - 1;

&self.source[start..=self.index]
}

/// Add error object to the cursor.
pub(crate) fn add_err(&mut self, err: Error) {
self.err = Some(err)
}

/// Returns a `Chars` iterator over the remaining characters.
fn chars(&self) -> Chars<'_> {
self.chars.clone()
}
}
Loading

0 comments on commit 186e21c

Please sign in to comment.