From: Ben Pfaff Date: Wed, 28 Aug 2024 16:33:49 +0000 (-0700) Subject: cursor! X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5edf19811931362973292e4fe0d4ce78a6ce77b;p=pspp cursor! --- diff --git a/rust/pspp/src/command.rs b/rust/pspp/src/command.rs index c749b5f2dc..6a6772d16a 100644 --- a/rust/pspp/src/command.rs +++ b/rust/pspp/src/command.rs @@ -105,7 +105,11 @@ fn commands() -> &'static [Command] { no_abbrev: false, name: "ECHO", run: Box::new(|context| { - println!("hi"); + let cursor = context.lexer.cursor(); + match cursor.force_string() { + Ok(s) => println!("\"{s}\""), + Err(e) => println!("{e}") + } }), }, /* diff --git a/rust/pspp/src/engine.rs b/rust/pspp/src/engine.rs index abfc2da8b3..6ee4623303 100644 --- a/rust/pspp/src/engine.rs +++ b/rust/pspp/src/engine.rs @@ -1,7 +1,7 @@ use crate::{ command::parse_command, lex::{ - lexer::{TokenSlice, NewSource}, + lexer::{TokenSlice, Source}, }, macros::MacroSet, message::Diagnostic, @@ -13,7 +13,7 @@ impl Engine { pub fn new() -> Self { Self } - pub fn run(&mut self, mut source: NewSource) { + pub fn run(&mut self, mut source: Source) { let macros = MacroSet::new(); while let Some(tokens) = source.read_command(¯os) { let error: Box = Box::new(|diagnostic| { @@ -28,14 +28,14 @@ impl Engine { mod tests { use encoding_rs::UTF_8; - use crate::lex::lexer::{NewSource, SourceFile}; + use crate::lex::lexer::{Source, SourceFile}; use super::Engine; #[test] fn test_echo() { let mut engine = Engine::new(); - engine.run(NewSource::new_default(&SourceFile::for_file_contents( + engine.run(Source::new_default(&SourceFile::for_file_contents( "ECHO 'hi there'.\nECHO 'bye there'.\n".to_string(), Some("test.sps".to_string()), UTF_8, diff --git a/rust/pspp/src/lex/lexer.rs b/rust/pspp/src/lex/lexer.rs index 47c70d1697..02d08e1f24 100644 --- a/rust/pspp/src/lex/lexer.rs +++ b/rust/pspp/src/lex/lexer.rs @@ -1,5 +1,6 @@ use std::{ borrow::{Borrow, Cow}, + cell::Cell, collections::VecDeque, fmt::{Debug, Formatter, Result as FmtResult, Write}, fs, @@ -8,7 +9,7 @@ use std::{ mem::take, ops::{Range, RangeInclusive}, path::Path, - ptr, slice, + ptr, sync::Arc, }; @@ -206,19 +207,6 @@ pub struct LexToken<'a> { macro_rep: Option, } -impl LexToken<'_> { - pub fn force_string(&self) -> Result<&str, Diagnostic> { - if let Token::String(s) = &self.token { - Ok(s.as_str()) - } else { - let slice = TokenSlice { - tokens: slice::from_ref(self), - }; - Err(slice.error("Syntax error expecting string.")) - } - } -} - struct LexError { error: ScanError, pos: Range, @@ -376,6 +364,10 @@ impl<'a> TokenSlice<'a> { } } + pub fn cursor(&'a self) -> Cursor<'a> { + Cursor::new(self) + } + pub fn get_token(&self, index: usize) -> Option<&Token> { self.get(index).map(|token| &token.token) } @@ -511,14 +503,39 @@ impl<'a> TokenSlice<'a> { } } -pub struct NewSource<'a> { +pub struct Cursor<'a> { + slice: &'a TokenSlice<'a>, + + /// This allows [Self::force_string] etc. to advance while returning the + /// token without cloning it. + pos: Cell, +} + +impl<'a> Cursor<'a> { + pub fn new(slice: &'a TokenSlice<'a>) -> Self { + Self { slice, pos: Cell::new(0) } + } + + pub fn force_string(&self) -> Result<&str, Diagnostic> { + let pos = self.pos.get(); + if let Some(Token::String(s)) = self.slice.get_token(pos) { + self.pos.set(pos + 1); + Ok(s.as_str()) + } else { + let slice = self.slice.subslice(pos..self.slice.len()); + Err(slice.error("Syntax error expecting string.")) + } + } +} + +pub struct Source<'a> { file: &'a SourceFile, segmenter: Segmenter, seg_pos: usize, lookahead: VecDeque>, } -impl<'a> NewSource<'a> { +impl<'a> Source<'a> { pub fn new_default(file: &'a SourceFile) -> Self { Self::new(file, Syntax::default()) } @@ -693,7 +710,7 @@ mod new_lexer_tests { use crate::macros::MacroSet; - use super::{NewSource, SourceFile}; + use super::{Source, SourceFile}; #[test] fn test() { @@ -709,7 +726,7 @@ CROSSTABS VARIABLES X (1,7) Y (1,7) /TABLES X BY Y. Some(String::from("crosstabs.sps")), UTF_8, ); - let mut source = NewSource::new_default(&file); + let mut source = Source::new_default(&file); while let Some(tokens) = source.read_command(&MacroSet::new()) { println!("{tokens:?}"); }