Various additions and improvements

This commit is contained in:
2025-03-15 21:04:45 -04:00
parent 7f21e5baa7
commit 505b968c60
31 changed files with 1421 additions and 341 deletions

View File

@@ -2,7 +2,7 @@ use std::{fmt::Display, ops::{Bound, Deref, Range, RangeBounds}};
use bitflags::bitflags;
use crate::{builtin::BUILTINS, prelude::*};
use crate::{builtin::BUILTINS, libsh::error::{ShErr, ShErrKind, ShResult}, prelude::*};
pub const KEYWORDS: [&'static str;14] = [
"if",
@@ -87,33 +87,9 @@ impl Default for TkRule {
}
}
#[derive(Clone,Copy,PartialEq,Debug)]
pub enum TkErr {
Null,
UntermQuote,
UntermSubsh,
UntermEscape,
UntermBrace,
BadRedir,
BadPipe,
HangingDelim,
}
impl Default for TkErr {
fn default() -> Self {
TkErr::Null
}
}
pub enum TkState {
Raw,
}
#[derive(Clone,Debug,PartialEq,Default)]
pub struct Tk<'s> {
pub class: TkRule,
pub err_span: Option<Span<'s>>,
pub err: TkErr,
pub span: Span<'s>,
pub flags: TkFlags
}
@@ -121,7 +97,7 @@ pub struct Tk<'s> {
// There's one impl here and then another in expand.rs which has the expansion logic
impl<'s> Tk<'s> {
pub fn new(class: TkRule, span: Span<'s>) -> Self {
Self { class, err_span: None, err: TkErr::Null, span, flags: TkFlags::empty() }
Self { class, span, flags: TkFlags::empty() }
}
pub fn to_string(&self) -> String {
match &self.class {
@@ -129,13 +105,6 @@ impl<'s> Tk<'s> {
_ => self.span.as_str().to_string()
}
}
pub fn set_err(&mut self, range: Range<usize>, slice: &'s str, err: TkErr) {
self.err_span = Some(Span::new(range, slice));
self.err = err
}
pub fn is_err(&self) -> bool {
self.err_span.is_some()
}
pub fn source(&self) -> &'s str {
self.span.source
}
@@ -231,7 +200,7 @@ impl<'t> LexStream<'t> {
pub fn next_is_not_cmd(&mut self) {
self.flags &= !LexFlags::NEXT_IS_CMD;
}
pub fn read_redir(&mut self) -> Option<Tk<'t>> {
pub fn read_redir(&mut self) -> Option<ShResult<Tk<'t>>> {
assert!(self.cursor <= self.source.len());
let slice = self.slice(self.cursor..)?;
let mut pos = self.cursor;
@@ -259,10 +228,13 @@ impl<'t> LexStream<'t> {
if !found_fd {
let err = TkErr::BadRedir;
tk = self.get_token(self.cursor..pos, TkRule::Redir);
tk.set_err(self.cursor..pos, self.source, err);
break
return Some(Err(
ShErr::full(
ShErrKind::ParseErr,
"Invalid redirection",
Span::new(self.cursor..pos, self.source).into()
)
));
} else {
tk = self.get_token(self.cursor..pos, TkRule::Redir);
break
@@ -304,9 +276,9 @@ impl<'t> LexStream<'t> {
}
self.cursor = pos;
Some(tk)
Some(Ok(tk))
}
pub fn read_string(&mut self) -> Tk<'t> {
pub fn read_string(&mut self) -> ShResult<Tk<'t>> {
assert!(self.cursor <= self.source.len());
let slice = self.slice_from_cursor().unwrap();
let mut pos = self.cursor;
@@ -351,10 +323,12 @@ impl<'t> LexStream<'t> {
}
let mut new_tk = self.get_token(self.cursor..pos, TkRule::Str);
if self.in_quote && !self.flags.contains(LexFlags::LEX_UNFINISHED) {
new_tk.set_err(
quote_pos.unwrap()..pos,
self.source,
TkErr::UntermQuote
return Err(
ShErr::full(
ShErrKind::ParseErr,
"Unterminated quote",
new_tk.span.into(),
)
);
}
if self.flags.contains(LexFlags::NEXT_IS_CMD) {
@@ -373,7 +347,7 @@ impl<'t> LexStream<'t> {
}
}
self.cursor = pos;
new_tk
Ok(new_tk)
}
pub fn get_token(&self, range: Range<usize>, class: TkRule) -> Tk<'t> {
let span = Span::new(range, self.source);
@@ -382,7 +356,7 @@ impl<'t> LexStream<'t> {
}
impl<'t> Iterator for LexStream<'t> {
type Item = Tk<'t>;
type Item = ShResult<Tk<'t>>;
fn next(&mut self) -> Option<Self::Item> {
assert!(self.cursor <= self.source.len());
// We are at the end of the input
@@ -394,14 +368,14 @@ impl<'t> Iterator for LexStream<'t> {
// Return the EOI token
let token = self.get_token(self.cursor..self.cursor, TkRule::EOI);
self.flags |= LexFlags::STALE;
return Some(token)
return Some(Ok(token))
}
}
// Return the SOI token
if self.flags.contains(LexFlags::FRESH) {
self.flags &= !LexFlags::FRESH;
let token = self.get_token(self.cursor..self.cursor, TkRule::SOI);
return Some(token)
return Some(Ok(token))
}
// If we are just reading raw words, short circuit here
@@ -486,13 +460,19 @@ impl<'t> Iterator for LexStream<'t> {
_ => {
if let Some(tk) = self.read_redir() {
self.next_is_not_cmd();
tk
match tk {
Ok(tk) => tk,
Err(e) => return Some(Err(e))
}
} else {
self.read_string()
match self.read_string() {
Ok(tk) => tk,
Err(e) => return Some(Err(e))
}
}
}
};
Some(token)
Some(Ok(token))
}
}