Skip to content

Commit

Permalink
Change: add cursor to move char wise within source code
Browse files Browse the repository at this point in the history
As a basis to move char wise within given source code the library
`nasl-synatx` has the struct Cursor with the methods:

- peek - to peek the nth char
- bump - to return the next char if any
- is_eof - to indicate if the Cursor is at the end
- skip_while - to skip characters that meets a criteria
- len_consumed - to return the amount of consumed chars
  • Loading branch information
nichtsfrei committed Nov 2, 2022
1 parent 931f757 commit f77185f
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 0 deletions.
1 change: 1 addition & 0 deletions rust/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target/
7 changes: 7 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
members = ["nasl-syntax"]
4 changes: 4 additions & 0 deletions rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Rust implementation of nasl

This multi cargo workspace contains
- nasl-syntax - to parse nasl for further processing
8 changes: 8 additions & 0 deletions rust/nasl-syntax/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "nasl-syntax"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
5 changes: 5 additions & 0 deletions rust/nasl-syntax/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# nasl-syntax

`nasl-syntax` is a library to parse NASL source code for further interpreting.

TBD
104 changes: 104 additions & 0 deletions rust/nasl-syntax/src/cursor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
///! This module defines the Cursor as a basis for tokenizing
use std::str::Chars;

pub const EOF_CHAR: char = '\0';

/// Peekable iterator over a char sequence.
///
/// Next characters can be peeked via `peek` method,
/// and position can be shifted forward via `bump` method.
pub struct Cursor<'a> {
/// is needed to calculate the length when e.g. tokenizing
initial_len: usize,
chars: Chars<'a>,
}

impl<'a> Cursor<'a> {
/// Returns a new cursor based on given input
pub fn new(input: &'a str) -> Cursor<'a> {
Cursor {
initial_len: input.len(),
chars: input.chars(),
}
}

/// Peeks the nth next characher or returns EOF_CHAR when unreachable
pub fn peek(&self, n: usize) -> char {
let mut iter = self.chars.clone();
for _ in 0..n {
iter.next();
}
iter.next().unwrap_or(EOF_CHAR)
}

/// Returns the next char or None if at the end
pub fn bump(&mut self) -> Option<char> {
self.chars.next()
}

/// Returns true when the Cursor is at the end of the initial input
pub fn is_eof(&self) -> bool {
self.chars.as_str().is_empty()
}

/// Skips characters until the given predicate returns true
pub fn skip_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
while predicate(self.peek(0)) && !self.is_eof() {
self.bump();
}
}

/// Returns amount of already consumed symbols.
pub fn len_consumed(&self) -> usize {
self.initial_len - self.chars.as_str().len()
}
}

#[cfg(test)]
mod tests {
use std::ops::Range;

use super::*;

#[test]
fn peek() {
let mut crsr = Cursor::new("a = \"test\";");
assert_eq!(crsr.peek(2), '=');
assert_eq!(crsr.bump(), Some('a'));
}

#[test]
fn skip_whitespaces() {
let mut crsr = Cursor::new(" a = \"test\";");
crsr.skip_while(|c| c.is_ascii_whitespace());
assert_eq!(crsr.bump(), Some('a'));
}

#[test]
fn eof() {
let mut crsr = Cursor::new("a = \"test\";");
crsr.skip_while(|c|c != ';');
assert!(!crsr.is_eof());
crsr.bump();
assert!(crsr.is_eof());
}

#[test]
fn gather_string_literal() {
let code = "a = \"test\";";
let mut crsr = Cursor::new(code);
// skip to "
crsr.skip_while(|c| c != '"');
// jump over "
crsr.bump();
// remember previosuly consumed
let pconsumed = crsr.len_consumed();
crsr.skip_while(|c| c != '"');
// get string within the range
let actual = &code[Range {
start: pconsumed,
end: crsr.len_consumed(),
}];
assert_eq!(actual, "test");
}
}
12 changes: 12 additions & 0 deletions rust/nasl-syntax/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pub mod cursor;
#[cfg(test)]
mod tests {
use crate::cursor::Cursor;

#[test]
fn use_a_cursor() {
let mut crsr = Cursor::new(" \n\tdisplay(12);");
crsr.skip_while(|c| c.is_whitespace());
assert_eq!(crsr.bump(), Some('d'));
}
}

0 comments on commit f77185f

Please sign in to comment.