implemented functions

This commit is contained in:
2025-03-16 16:57:58 -04:00
parent da51be27a7
commit d673bb692f
6 changed files with 346 additions and 33 deletions

View File

@@ -76,6 +76,8 @@ pub enum TkRule {
Bg,
Sep,
Redir,
BraceGrpStart,
BraceGrpEnd,
Expanded { exp: Vec<String> },
Comment,
EOI, // End-of-Input
@@ -156,6 +158,7 @@ bitflags! {
const FRESH = 0b00010000;
/// The lexer has no more tokens to produce
const STALE = 0b00100000;
const IN_BRC_GRP = 0b01000000;
}
}
@@ -192,13 +195,26 @@ impl<'t> LexStream<'t> {
pub fn slice_from_cursor(&self) -> Option<&'t str> {
self.slice(self.cursor..)
}
/// The next string token is a command name
pub fn next_is_cmd(&mut self) {
self.flags |= LexFlags::NEXT_IS_CMD;
pub fn in_brc_grp(&self) -> bool {
self.flags.contains(LexFlags::IN_BRC_GRP)
}
/// The next string token is not a command name
pub fn next_is_not_cmd(&mut self) {
self.flags &= !LexFlags::NEXT_IS_CMD;
pub fn set_in_brc_grp(&mut self, is: bool) {
if is {
self.flags |= LexFlags::IN_BRC_GRP;
} else {
self.flags &= !LexFlags::IN_BRC_GRP;
}
}
pub fn next_is_cmd(&self) -> bool {
self.flags.contains(LexFlags::NEXT_IS_CMD)
}
/// Set whether the next string token is a command name
pub fn set_next_is_cmd(&mut self, is: bool) {
if is {
self.flags |= LexFlags::NEXT_IS_CMD;
} else {
self.flags &= !LexFlags::NEXT_IS_CMD;
}
}
pub fn read_redir(&mut self) -> Option<ShResult<Tk<'t>>> {
assert!(self.cursor <= self.source.len());
@@ -299,6 +315,24 @@ impl<'t> LexStream<'t> {
pos += 1;
}
}
'{' if pos == self.cursor && self.next_is_cmd() => {
pos += 1;
let mut tk = self.get_token(self.cursor..pos, TkRule::BraceGrpStart);
tk.flags |= TkFlags::IS_CMD;
self.set_in_brc_grp(true);
self.set_next_is_cmd(true);
self.cursor = pos;
return Ok(tk)
}
'}' if pos == self.cursor && self.in_brc_grp() => {
pos += 1;
let tk = self.get_token(self.cursor..pos, TkRule::BraceGrpEnd);
self.set_in_brc_grp(false);
self.set_next_is_cmd(true);
self.cursor = pos;
return Ok(tk)
}
'"' | '\'' => {
self.in_quote = true;
quote_pos = Some(pos);
@@ -340,7 +374,9 @@ impl<'t> LexStream<'t> {
);
}
if self.flags.contains(LexFlags::NEXT_IS_CMD) {
if KEYWORDS.contains(&new_tk.span.as_str()) {
flog!(DEBUG,&new_tk.span.as_str());
if is_keyword(&new_tk.span.as_str()) {
flog!(DEBUG,"is keyword");
new_tk.flags |= TkFlags::KEYWORD;
} else if is_assignment(&new_tk.span.as_str()) {
new_tk.flags |= TkFlags::ASSIGN;
@@ -351,7 +387,7 @@ impl<'t> LexStream<'t> {
new_tk.flags |= TkFlags::BUILTIN;
}
flog!(TRACE, new_tk.flags);
self.next_is_not_cmd();
self.set_next_is_cmd(false);
}
}
self.cursor = pos;
@@ -411,7 +447,7 @@ impl<'t> Iterator for LexStream<'t> {
'\r' | '\n' | ';' => {
let ch_idx = self.cursor;
self.cursor += 1;
self.next_is_cmd();
self.set_next_is_cmd(true);
while let Some(ch) = get_char(self.source, self.cursor) {
if is_hard_sep(ch) { // Combine consecutive separators into one, including whitespace
@@ -438,7 +474,7 @@ impl<'t> Iterator for LexStream<'t> {
'|' => {
let ch_idx = self.cursor;
self.cursor += 1;
self.next_is_cmd();
self.set_next_is_cmd(true);
let tk_type = if let Some('|') = get_char(self.source, self.cursor) {
self.cursor += 1;
@@ -455,7 +491,7 @@ impl<'t> Iterator for LexStream<'t> {
'&' => {
let ch_idx = self.cursor;
self.cursor += 1;
self.next_is_cmd();
self.set_next_is_cmd(true);
let tk_type = if let Some('&') = get_char(self.source, self.cursor) {
self.cursor += 1;
@@ -467,7 +503,7 @@ impl<'t> Iterator for LexStream<'t> {
}
_ => {
if let Some(tk) = self.read_redir() {
self.next_is_not_cmd();
self.set_next_is_cmd(false);
match tk {
Ok(tk) => tk,
Err(e) => return Some(Err(e))
@@ -516,3 +552,8 @@ pub fn is_hard_sep(ch: char) -> bool {
pub fn is_field_sep(ch: char) -> bool {
matches!(ch, ' ' | '\t')
}
pub fn is_keyword(slice: &str) -> bool {
KEYWORDS.contains(&slice) ||
(slice.ends_with("()") && !slice.ends_with("\\()"))
}