Improved logic surrounding expansion of assignments
This commit is contained in:
@@ -37,6 +37,15 @@ pub const SEPARATORS: [TkRule;7] = [
|
||||
TkRule::CasePat
|
||||
];
|
||||
|
||||
pub const EXPANSIONS: [TkRule;6] = [
|
||||
TkRule::DQuote,
|
||||
TkRule::VarSub,
|
||||
TkRule::CmdSub,
|
||||
TkRule::ProcSub,
|
||||
TkRule::TildeSub,
|
||||
TkRule::ArithSub
|
||||
];
|
||||
|
||||
pub trait LexRule {
|
||||
fn try_match(input: &str) -> Option<usize>;
|
||||
}
|
||||
@@ -74,6 +83,10 @@ impl<'a> Lexer<'a> {
|
||||
self.consumed += len;
|
||||
input = &input[len..];
|
||||
self.tokens.push(token);
|
||||
|
||||
if input.is_empty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !input.is_empty() {
|
||||
log!(WARN, "unconsumed input: {}", input)
|
||||
@@ -81,6 +94,13 @@ impl<'a> Lexer<'a> {
|
||||
self.tokens
|
||||
}
|
||||
}
|
||||
pub fn get_rule(s: &str) -> TkRule {
|
||||
if let Some((rule,_)) = TkRule::try_match(s) {
|
||||
rule
|
||||
} else {
|
||||
TkRule::Ident
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -146,8 +166,14 @@ impl Span {
|
||||
}
|
||||
}
|
||||
pub fn shift(&mut self, delta: isize) {
|
||||
self.start = self.start.saturating_add_signed(delta);
|
||||
self.end = self.end.saturating_add_signed(delta);
|
||||
self.shift_start(delta);
|
||||
self.shift_end(delta);
|
||||
}
|
||||
pub fn shift_start(&mut self, delta: isize) {
|
||||
self.start = self.start.saturating_add_signed(delta)
|
||||
}
|
||||
pub fn shift_end(&mut self, delta: isize) {
|
||||
self.end = self.end.saturating_add_signed(delta)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +241,6 @@ pub enum TkRule {
|
||||
Case,
|
||||
Esac,
|
||||
CasePat,
|
||||
Assign,
|
||||
Ident,
|
||||
Sep,
|
||||
}
|
||||
@@ -244,7 +269,6 @@ impl TkRule {
|
||||
try_match!(Subshell,input);
|
||||
try_match!(CasePat,input);
|
||||
try_match!(Sep,input);
|
||||
try_match!(Assign,input);
|
||||
try_match!(If,input);
|
||||
try_match!(Then,input);
|
||||
try_match!(Elif,input);
|
||||
@@ -901,37 +925,6 @@ tkrule_def!(FuncName, |input: &str| {
|
||||
None
|
||||
});
|
||||
|
||||
tkrule_def!(Assign, |input: &str| {
|
||||
let mut chars = input.chars();
|
||||
let mut len = 0;
|
||||
let mut found_equals = false;
|
||||
|
||||
while let Some(ch) = chars.next() {
|
||||
match ch {
|
||||
'\\' => {
|
||||
len += 2;
|
||||
chars.next();
|
||||
}
|
||||
'=' if len == 0 => return None,
|
||||
'=' => {
|
||||
len += 1;
|
||||
found_equals = true;
|
||||
}
|
||||
' ' | '\t' | ';' | '\n' => {
|
||||
match len {
|
||||
_ if found_equals && len > 1 => return Some(len),
|
||||
_ => return None
|
||||
}
|
||||
}
|
||||
_ => len += 1
|
||||
}
|
||||
}
|
||||
match len {
|
||||
_ if found_equals && len > 1 => return Some(len),
|
||||
_ => return None
|
||||
}
|
||||
});
|
||||
|
||||
tkrule_def!(BraceGrp, |input: &str| {
|
||||
// A group of commands inside of braces
|
||||
// Currently just holds a raw string to be re-parsed later
|
||||
|
||||
@@ -85,7 +85,7 @@ pub enum LoopKind {
|
||||
pub enum NdRule {
|
||||
Main { cmd_lists: Vec<Node> },
|
||||
Command { argv: Vec<Token>, redirs: Vec<Redir> },
|
||||
Assignment { assignments: Vec<Token>, cmd: Option<Box<Node>> },
|
||||
Assignment { assignments: Vec<(Token,Token)>, cmd: Option<Box<Node>> },
|
||||
FuncDef { name: Token, body: Token },
|
||||
Case { pat: Token, blocks: Vec<(Token,Vec<Node>)>, redirs: Vec<Redir> },
|
||||
IfThen { cond_blocks: Vec<(Vec<Node>,Vec<Node>)>, else_block: Option<Vec<Node>>, redirs: Vec<Redir> },
|
||||
@@ -1003,7 +1003,6 @@ ndrule_def!(Subshell, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
|
||||
TkRule::Ident |
|
||||
TkRule::SQuote |
|
||||
TkRule::DQuote |
|
||||
TkRule::Assign |
|
||||
TkRule::TildeSub |
|
||||
TkRule::VarSub => {
|
||||
node_toks.push(token.clone());
|
||||
@@ -1139,7 +1138,6 @@ ndrule_def!(Command, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
|
||||
TkRule::Ident |
|
||||
TkRule::SQuote |
|
||||
TkRule::DQuote |
|
||||
TkRule::Assign |
|
||||
TkRule::TildeSub |
|
||||
TkRule::ArithSub |
|
||||
TkRule::VarSub => {
|
||||
@@ -1188,10 +1186,38 @@ ndrule_def!(Assignment, shenv, |tokens: &[Token], shenv: &mut ShEnv| {
|
||||
let mut tokens = tokens.into_iter().peekable();
|
||||
let mut node_toks = vec![];
|
||||
let mut assignments = vec![];
|
||||
while tokens.peek().is_some_and(|tk| tk.rule() == TkRule::Assign) {
|
||||
let token = tokens.next().unwrap();
|
||||
node_toks.push(token.clone());
|
||||
assignments.push(token.clone());
|
||||
while let Some(token) = tokens.peek() {
|
||||
if matches!(token.rule(), TkRule::Ident | TkRule::ArithSub | TkRule::CmdSub | TkRule::DQuote) {
|
||||
let raw = token.as_raw(shenv);
|
||||
// We are going to deconstruct this Ident into two separate tokens
|
||||
// This makes expanding it easier later
|
||||
if let Some((var,val)) = raw.split_once('=') {
|
||||
const LEN_DELTA: usize = 1; // The distance covered by the '=' that we just split at
|
||||
let token = tokens.next().unwrap();
|
||||
let var_span = shenv.inputman_mut().new_span(
|
||||
token.span().borrow().start(),
|
||||
var.len()
|
||||
);
|
||||
let val_span = shenv.inputman_mut().new_span(
|
||||
var.len() + LEN_DELTA,
|
||||
token.span().borrow().end()
|
||||
);
|
||||
let var_rule = TkRule::Ident;
|
||||
let val_rule = if let Some(rule) = check_expansion(&val) {
|
||||
rule
|
||||
} else {
|
||||
TkRule::Ident
|
||||
};
|
||||
let var_token = Token::new(var_rule,var_span);
|
||||
let val_token = Token::new(val_rule,val_span);
|
||||
node_toks.push(token.clone());
|
||||
assignments.push((var_token.clone(),val_token.clone()));
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if assignments.is_empty() {
|
||||
return Ok(None)
|
||||
|
||||
Reference in New Issue
Block a user