Early implementation of scripting elements

This commit is contained in:
2025-03-05 01:36:58 -05:00
parent 5dd9ee96ad
commit 1b3e2c0887
28 changed files with 1384 additions and 371 deletions

View File

@@ -1,75 +1,62 @@
use crate::{parse::lex::SEPARATORS, prelude::*};
pub fn expand_aliases(input: &str, shenv: &mut ShEnv) -> Option<String> {
let mut result = input.to_string();
let mut expanded_aliases = Vec::new();
let mut found_in_iteration = true;
pub fn expand_alias(candidate: Token, shenv: &mut ShEnv) -> Vec<Token> {
let mut tokens = vec![];
let mut work_stack = VecDeque::new();
let mut expanded_aliases = vec![];
let logic = shenv.logic().clone();
// Loop until no new alias expansion happens.
while found_in_iteration {
found_in_iteration = false;
let mut new_result = String::new();
let mut chars = result.chars().peekable();
let mut alias_cand = String::new();
let mut is_cmd = true;
// Start with the candidate token in the work queue
work_stack.bpush(candidate);
while let Some(ch) = chars.next() {
match ch {
';' | '\n' => {
new_result.push(ch);
is_cmd = true;
// Consume any extra whitespace or delimiters.
while let Some(&next_ch) = chars.peek() {
if matches!(next_ch, ' ' | '\t' | ';' | '\n') {
new_result.push(next_ch);
chars.next();
} else {
break;
}
// Process until there are no more tokens in the queue
while let Some(token) = work_stack.fpop() {
if token.rule() == TkRule::Ident {
let candidate_str = token.as_raw(shenv);
if let Some(alias) = logic.get_alias(&candidate_str) {
// Expand the alias only if it hasn't been expanded yet
if !expanded_aliases.contains(&candidate_str) {
expanded_aliases.push(candidate_str);
let mut new_tokens = shenv.expand_input(alias, token.span());
for token in new_tokens.iter_mut() {
work_stack.bpush(token.clone());
}
} else {
// If already expanded, just add the token to the output
tokens.push(token);
}
' ' | '\t' => {
is_cmd = false;
new_result.push(ch);
}
_ if is_cmd => {
// Accumulate token characters.
alias_cand.push(ch);
while let Some(&next_ch) = chars.peek() {
if matches!(next_ch, ' ' | '\t' | ';' | '\n') {
break;
} else {
alias_cand.push(next_ch);
chars.next();
}
}
// Check for an alias expansion.
if let Some(alias) = shenv.logic().get_alias(&alias_cand) {
// Only expand if we haven't already done so.
if !expanded_aliases.contains(&alias_cand) {
new_result.push_str(alias);
expanded_aliases.push(alias_cand.clone());
found_in_iteration = true;
} else {
new_result.push_str(&alias_cand);
}
} else {
new_result.push_str(&alias_cand);
}
alias_cand.clear();
}
_ => {
new_result.push(ch);
} else {
tokens.push(token);
}
} else {
tokens.push(token);
}
}
tokens
}
pub fn expand_aliases(tokens: Vec<Token>, shenv: &mut ShEnv) -> Vec<Token> {
let mut stream = tokens.iter();
let mut processed = vec![];
let mut is_command = true;
while let Some(token) = stream.next() {
match token.rule() {
_ if SEPARATORS.contains(&token.rule()) => {
is_command = true;
processed.push(token.clone());
}
TkRule::Ident if is_command => {
is_command = false;
let mut alias_tokens = expand_alias(token.clone(), shenv);
log!(DEBUG, alias_tokens);
if !alias_tokens.is_empty() {
processed.append(&mut alias_tokens);
} else {
processed.push(token.clone());
}
}
_ => processed.push(token.clone()),
}
result = new_result;
log!(DEBUG, result);
}
if expanded_aliases.is_empty() {
None
} else {
Some(result)
}
processed
}