Parser tweaks

This commit is contained in:
2025-05-08 21:18:58 -04:00
parent 7523944d63
commit 18d0b669b3
10 changed files with 21067 additions and 70 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@ target
.idea .idea
*.iml *.iml
/result* /result*
src/tests/snapshots
*.log *.log
default.nix default.nix
shell.nix shell.nix

View File

@@ -93,7 +93,7 @@ impl Expander {
let mut result = String::new(); let mut result = String::new();
let mut var_name = String::new(); let mut var_name = String::new();
let mut in_brace = false; let mut in_brace = false;
flog!(DEBUG, self.raw); flog!(INFO, self.raw);
while let Some(ch) = chars.next() { while let Some(ch) = chars.next() {
match ch { match ch {
@@ -103,6 +103,8 @@ impl Expander {
} }
VAR_SUB => { VAR_SUB => {
while let Some(ch) = chars.next() { while let Some(ch) = chars.next() {
flog!(INFO,ch);
flog!(INFO,var_name);
match ch { match ch {
SUBSH if var_name.is_empty() => { SUBSH if var_name.is_empty() => {
let mut subsh_body = String::new(); let mut subsh_body = String::new();
@@ -114,7 +116,9 @@ impl Expander {
_ => subsh_body.push(ch) _ => subsh_body.push(ch)
} }
} }
result.push_str(&expand_cmd_sub(&subsh_body)?); let expanded = expand_cmd_sub(&subsh_body)?;
flog!(INFO, expanded);
result.push_str(&expanded);
} }
'{' if var_name.is_empty() => in_brace = true, '{' if var_name.is_empty() => in_brace = true,
'}' if in_brace => { '}' if in_brace => {
@@ -123,7 +127,7 @@ impl Expander {
var_name.clear(); var_name.clear();
break break
} }
_ if is_hard_sep(ch) || ch == DUB_QUOTE || ch == SUBSH => { _ if is_hard_sep(ch) || ch == DUB_QUOTE || ch == SUBSH || ch == '/' => {
let var_val = read_vars(|v| v.get_var(&var_name)); let var_val = read_vars(|v| v.get_var(&var_name));
result.push_str(&var_val); result.push_str(&var_val);
result.push(ch); result.push(ch);
@@ -162,6 +166,7 @@ pub fn expand_glob(raw: &str) -> ShResult<String> {
/// Get the command output of a given command input as a String /// Get the command output of a given command input as a String
pub fn expand_cmd_sub(raw: &str) -> ShResult<String> { pub fn expand_cmd_sub(raw: &str) -> ShResult<String> {
flog!(DEBUG, "in expand_cmd_sub"); flog!(DEBUG, "in expand_cmd_sub");
flog!(DEBUG, raw);
let (rpipe,wpipe) = IoMode::get_pipes(); let (rpipe,wpipe) = IoMode::get_pipes();
let cmd_sub_redir = Redir::new(wpipe, RedirType::Output); let cmd_sub_redir = Redir::new(wpipe, RedirType::Output);
let mut cmd_sub_io_frame = IoFrame::from_redir(cmd_sub_redir); let mut cmd_sub_io_frame = IoFrame::from_redir(cmd_sub_redir);
@@ -255,7 +260,39 @@ pub fn unescape_str(raw: &str) -> String {
result.push(next_ch) result.push(next_ch)
} }
} }
'$' => result.push(VAR_SUB), '$' => {
result.push(VAR_SUB);
if chars.peek() == Some(&'(') {
chars.next();
let mut cmdsub_count = 1;
result.push(SUBSH);
while let Some(subsh_ch) = chars.next() {
flog!(DEBUG, subsh_ch);
match subsh_ch {
'\\' => {
result.push(subsh_ch);
if let Some(next_ch) = chars.next() {
result.push(next_ch)
}
}
'$' if chars.peek() == Some(&'(') => {
result.push(subsh_ch);
cmdsub_count += 1;
}
')' => {
cmdsub_count -= 1;
if cmdsub_count <= 0 {
result.push(SUBSH);
break
} else {
result.push(subsh_ch);
}
}
_ => result.push(subsh_ch),
}
}
}
}
'"' => { '"' => {
result.push(DUB_QUOTE); result.push(DUB_QUOTE);
break break

View File

@@ -253,7 +253,7 @@ impl Dispatcher {
.map(|s| s.to_string()) .map(|s| s.to_string())
.unwrap_or_default(); .unwrap_or_default();
for block in case_blocks { 'outer: for block in case_blocks {
let CaseNode { pattern, body } = block; let CaseNode { pattern, body } = block;
let block_pattern_raw = pattern.span.as_str().trim_end_matches(')').trim(); let block_pattern_raw = pattern.span.as_str().trim_end_matches(')').trim();
// Split at '|' to allow for multiple patterns like `foo|bar)` // Split at '|' to allow for multiple patterns like `foo|bar)`
@@ -264,6 +264,7 @@ impl Dispatcher {
for node in &body { for node in &body {
self.dispatch_node(node.clone())?; self.dispatch_node(node.clone())?;
} }
break 'outer
} }
} }
} }
@@ -432,7 +433,7 @@ impl Dispatcher {
let NdRule::Command { ref mut assignments, ref mut argv } = &mut cmd.class else { let NdRule::Command { ref mut assignments, ref mut argv } = &mut cmd.class else {
unreachable!() unreachable!()
}; };
let env_vars_to_unset = self.set_assignments(mem::take(assignments), AssignBehavior::Export); let env_vars_to_unset = self.set_assignments(mem::take(assignments), AssignBehavior::Export)?;
let cmd_raw = argv.first().unwrap(); let cmd_raw = argv.first().unwrap();
let curr_job_mut = self.job_stack.curr_job_mut().unwrap(); let curr_job_mut = self.job_stack.curr_job_mut().unwrap();
let io_stack_mut = &mut self.io_stack; let io_stack_mut = &mut self.io_stack;
@@ -488,7 +489,7 @@ impl Dispatcher {
} else { } else {
AssignBehavior::Export AssignBehavior::Export
}; };
env_vars_to_unset = self.set_assignments(assignments, assign_behavior); env_vars_to_unset = self.set_assignments(assignments, assign_behavior)?;
} }
if argv.is_empty() { if argv.is_empty() {
@@ -513,7 +514,7 @@ impl Dispatcher {
Ok(()) Ok(())
} }
fn set_assignments(&self, assigns: Vec<Node>, behavior: AssignBehavior) -> Vec<String> { fn set_assignments(&self, assigns: Vec<Node>, behavior: AssignBehavior) -> ShResult<Vec<String>> {
let mut new_env_vars = vec![]; let mut new_env_vars = vec![];
match behavior { match behavior {
AssignBehavior::Export => { AssignBehavior::Export => {
@@ -522,9 +523,9 @@ impl Dispatcher {
unreachable!() unreachable!()
}; };
let var = var.span.as_str(); let var = var.span.as_str();
let val = val.span.as_str(); let val = val.expand()?.get_words().join(" ");
match kind { match kind {
AssignKind::Eq => write_vars(|v| v.set_var(var, val, true)), AssignKind::Eq => write_vars(|v| v.set_var(var, &val, true)),
AssignKind::PlusEq => todo!(), AssignKind::PlusEq => todo!(),
AssignKind::MinusEq => todo!(), AssignKind::MinusEq => todo!(),
AssignKind::MultEq => todo!(), AssignKind::MultEq => todo!(),
@@ -539,9 +540,9 @@ impl Dispatcher {
unreachable!() unreachable!()
}; };
let var = var.span.as_str(); let var = var.span.as_str();
let val = val.span.as_str(); let val = val.expand()?.get_words().join(" ");
match kind { match kind {
AssignKind::Eq => write_vars(|v| v.set_var(var, val, false)), AssignKind::Eq => write_vars(|v| v.set_var(var, &val, true)),
AssignKind::PlusEq => todo!(), AssignKind::PlusEq => todo!(),
AssignKind::MinusEq => todo!(), AssignKind::MinusEq => todo!(),
AssignKind::MultEq => todo!(), AssignKind::MultEq => todo!(),
@@ -550,7 +551,7 @@ impl Dispatcher {
} }
} }
} }
new_env_vars Ok(new_env_vars)
} }
} }

View File

@@ -340,7 +340,7 @@ impl LexStream {
'$' if chars.peek() == Some(&'(') => { '$' if chars.peek() == Some(&'(') => {
pos += 2; pos += 2;
chars.next(); chars.next();
let mut paren_stack = vec!['(']; let mut paren_count = 0;
let paren_pos = pos; let paren_pos = pos;
while let Some(ch) = chars.next() { while let Some(ch) = chars.next() {
match ch { match ch {
@@ -352,19 +352,19 @@ impl LexStream {
} }
'(' => { '(' => {
pos += 1; pos += 1;
paren_stack.push(ch); paren_count += 1;
} }
')' => { ')' => {
pos += 1; pos += 1;
paren_stack.pop(); paren_count -= 1;
if paren_stack.is_empty() { if paren_count >= 0 {
break break
} }
} }
_ => pos += ch.len_utf8() _ => pos += ch.len_utf8()
} }
} }
if !paren_stack.is_empty() && !self.flags.contains(LexFlags::LEX_UNFINISHED) { if !paren_count == 0 && !self.flags.contains(LexFlags::LEX_UNFINISHED) {
return Err( return Err(
ShErr::full( ShErr::full(
ShErrKind::ParseErr, ShErrKind::ParseErr,
@@ -434,7 +434,7 @@ impl LexStream {
self.cursor = pos; self.cursor = pos;
return Ok(tk) return Ok(tk)
} }
'"' | '\'' => { '\'' => {
self.in_quote = true; self.in_quote = true;
pos += 1; pos += 1;
while let Some(q_ch) = chars.next() { while let Some(q_ch) = chars.next() {
@@ -445,7 +445,7 @@ impl LexStream {
pos += 1; pos += 1;
} }
} }
_ if q_ch == ch => { _ if q_ch == '\'' => {
pos += 1; pos += 1;
self.in_quote = false; self.in_quote = false;
break break
@@ -458,6 +458,58 @@ impl LexStream {
} }
} }
} }
'"' => {
self.in_quote = true;
pos += 1;
while let Some(q_ch) = chars.next() {
match q_ch {
'\\' => {
pos += 1;
if chars.next().is_some() {
pos += 1;
}
}
'$' if chars.peek() == Some(&'(') => {
pos += 2;
chars.next();
let mut cmdsub_count = 1;
while let Some(cmdsub_ch) = chars.next() {
match cmdsub_ch {
'\\' => {
pos += 1;
if chars.next().is_some() {
pos += 1;
}
}
'$' if chars.peek() == Some(&'(') => {
cmdsub_count += 1;
pos += 2;
chars.next();
}
')' => {
cmdsub_count -= 1;
pos += 1;
if cmdsub_count <= 0 {
break
}
}
_ => pos += cmdsub_ch.len_utf8(),
}
}
}
_ if q_ch == '"' => {
pos += 1;
self.in_quote = false;
break
}
// Any time an ambiguous character is found
// we must push the cursor by the length of the character
// instead of just assuming a length of 1.
// Allows spans to work for wide characters
_ => pos += q_ch.len_utf8(),
}
}
}
_ if !self.in_quote && is_op(ch) => break, _ if !self.in_quote && is_op(ch) => break,
_ if is_hard_sep(ch) => break, _ if is_hard_sep(ch) => break,
_ => pos += ch.len_utf8() _ => pos += ch.len_utf8()
@@ -480,6 +532,7 @@ impl LexStream {
"case" | "select" | "for" => { "case" | "select" | "for" => {
new_tk.mark(TkFlags::KEYWORD); new_tk.mark(TkFlags::KEYWORD);
self.flags |= LexFlags::EXPECTING_IN; self.flags |= LexFlags::EXPECTING_IN;
self.set_next_is_cmd(false);
} }
"in" if self.flags.contains(LexFlags::EXPECTING_IN) => { "in" if self.flags.contains(LexFlags::EXPECTING_IN) => {
new_tk.mark(TkFlags::KEYWORD); new_tk.mark(TkFlags::KEYWORD);
@@ -492,16 +545,17 @@ impl LexStream {
new_tk.mark(TkFlags::ASSIGN); new_tk.mark(TkFlags::ASSIGN);
} }
_ if is_cmd_sub(text) => { _ if is_cmd_sub(text) => {
new_tk.mark(TkFlags::IS_CMDSUB) new_tk.mark(TkFlags::IS_CMDSUB);
self.set_next_is_cmd(false);
} }
_ => { _ => {
new_tk.flags |= TkFlags::IS_CMD; new_tk.flags |= TkFlags::IS_CMD;
if BUILTINS.contains(&text) { if BUILTINS.contains(&text) {
new_tk.mark(TkFlags::BUILTIN); new_tk.mark(TkFlags::BUILTIN);
} }
}
}
self.set_next_is_cmd(false); self.set_next_is_cmd(false);
}
}
} else if self.flags.contains(LexFlags::EXPECTING_IN) && text == "in" { } else if self.flags.contains(LexFlags::EXPECTING_IN) && text == "in" {
new_tk.mark(TkFlags::KEYWORD); new_tk.mark(TkFlags::KEYWORD);
self.flags &= !LexFlags::EXPECTING_IN; self.flags &= !LexFlags::EXPECTING_IN;

View File

@@ -416,6 +416,7 @@ impl ParseStream {
/// Ordered from specialized to general, with more generally matchable stuff appearing at the bottom /// Ordered from specialized to general, with more generally matchable stuff appearing at the bottom
/// The check_pipelines parameter is used to prevent left-recursion issues in self.parse_pipeln() /// The check_pipelines parameter is used to prevent left-recursion issues in self.parse_pipeln()
fn parse_block(&mut self, check_pipelines: bool) -> ShResult<Option<Node>> { fn parse_block(&mut self, check_pipelines: bool) -> ShResult<Option<Node>> {
flog!(DEBUG, self.tokens);
try_match!(self.parse_func_def()?); try_match!(self.parse_func_def()?);
try_match!(self.parse_brc_grp(false /* from_func_def */)?); try_match!(self.parse_brc_grp(false /* from_func_def */)?);
try_match!(self.parse_case()?); try_match!(self.parse_case()?);
@@ -913,9 +914,11 @@ impl ParseStream {
.as_str() .as_str()
.parse() // LoopKind implements FromStr .parse() // LoopKind implements FromStr
.unwrap(); .unwrap();
node_tks.push(loop_tk); node_tks.push(loop_tk);
self.catch_separator(&mut node_tks); self.catch_separator(&mut node_tks);
flog!(DEBUG, node_tks);
let Some(cond) = self.parse_block(true)? else { let Some(cond) = self.parse_block(true)? else {
self.panic_mode(&mut node_tks); self.panic_mode(&mut node_tks);
return Err(parse_err_full( return Err(parse_err_full(
@@ -1023,6 +1026,7 @@ impl ParseStream {
return Ok(None) return Ok(None)
} }
} }
flog!(DEBUG, argv);
if argv.is_empty() && assignments.is_empty() { if argv.is_empty() && assignments.is_empty() {
return Ok(None) return Ok(None)
@@ -1213,6 +1217,7 @@ impl Iterator for ParseStream {
} }
} }
let result = self.parse_cmd_list(); let result = self.parse_cmd_list();
flog!(DEBUG, result);
match result { match result {
Ok(Some(node)) => { Ok(Some(node)) => {
Some(Ok(node)) Some(Ok(node))

View File

@@ -0,0 +1,187 @@
---
source: src/tests/lexer.rs
assertion_line: 51
expression: tokens
---
[
Ok(
Tk {
class: SOI,
span: Span {
range: 0..0,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
Ok(
Tk {
class: Str,
span: Span {
range: 0..4,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
),
Ok(
Tk {
class: Str,
span: Span {
range: 5..9,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
),
Ok(
Tk {
class: Str,
span: Span {
range: 10..12,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
),
Ok(
Tk {
class: CasePattern,
span: Span {
range: 13..17,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
Ok(
Tk {
class: Str,
span: Span {
range: 18..21,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
),
Ok(
Tk {
class: Sep,
span: Span {
range: 21..24,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
Ok(
Tk {
class: CasePattern,
span: Span {
range: 24..28,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
Ok(
Tk {
class: Str,
span: Span {
range: 29..32,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
),
Ok(
Tk {
class: Sep,
span: Span {
range: 32..35,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
Ok(
Tk {
class: CasePattern,
span: Span {
range: 35..39,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
Ok(
Tk {
class: Str,
span: Span {
range: 40..43,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
),
Ok(
Tk {
class: Sep,
span: Span {
range: 43..46,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
Ok(
Tk {
class: Str,
span: Span {
range: 46..50,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
),
Ok(
Tk {
class: EOI,
span: Span {
range: 50..50,
source: "case $foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
),
]

View File

@@ -0,0 +1,596 @@
---
source: src/tests/parser.rs
assertion_line: 166
expression: nodes
---
[
Ok(
Node {
class: Conjunction {
elements: [
ConjunctNode {
cmd: Node {
class: CaseNode {
pattern: Tk {
class: Str,
span: Span {
range: 5..8,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
case_blocks: [
CaseNode {
pattern: Tk {
class: CasePattern,
span: Span {
range: 13..17,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
body: [
Node {
class: Pipeline {
cmds: [
Node {
class: Command {
assignments: [],
argv: [
Tk {
class: Str,
span: Span {
range: 18..21,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 18..21,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 21..27,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
pipe_err: false,
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 18..21,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 21..27,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
},
CaseNode {
pattern: Tk {
class: CasePattern,
span: Span {
range: 27..31,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
body: [
Node {
class: Pipeline {
cmds: [
Node {
class: Command {
assignments: [],
argv: [
Tk {
class: Str,
span: Span {
range: 32..35,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 32..35,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 35..41,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
pipe_err: false,
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 32..35,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 35..41,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
},
CaseNode {
pattern: Tk {
class: CasePattern,
span: Span {
range: 41..45,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
body: [
Node {
class: Pipeline {
cmds: [
Node {
class: Command {
assignments: [],
argv: [
Tk {
class: Str,
span: Span {
range: 46..49,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 46..49,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 49..54,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
pipe_err: false,
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 46..49,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 49..54,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 0..4,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: Str,
span: Span {
range: 5..8,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Str,
span: Span {
range: 9..11,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: Sep,
span: Span {
range: 11..13,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 13..17,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 18..21,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 21..27,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 27..31,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 32..35,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 35..41,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 41..45,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 46..49,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 49..54,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 54..58,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
KEYWORD,
),
},
],
},
operator: Null,
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 0..4,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: Str,
span: Span {
range: 5..8,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Str,
span: Span {
range: 9..11,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: Sep,
span: Span {
range: 11..13,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 13..17,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 18..21,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 21..27,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 27..31,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 32..35,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 35..41,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 41..45,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 46..49,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 49..54,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 54..58,
source: "case foo in\n\tfoo) bar\n\t;;\n\tbar) foo\n\t;;\n\tbiz) baz\n\t;;\nesac",
},
flags: TkFlags(
KEYWORD,
),
},
],
},
),
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,576 @@
---
source: src/tests/parser.rs
assertion_line: 149
expression: nodes
---
[
Ok(
Node {
class: Conjunction {
elements: [
ConjunctNode {
cmd: Node {
class: CaseNode {
pattern: Tk {
class: Str,
span: Span {
range: 5..8,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
case_blocks: [
CaseNode {
pattern: Tk {
class: CasePattern,
span: Span {
range: 12..16,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
body: [
Node {
class: Pipeline {
cmds: [
Node {
class: Command {
assignments: [],
argv: [
Tk {
class: Str,
span: Span {
range: 17..20,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 17..20,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 20..23,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
pipe_err: false,
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 17..20,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 20..23,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
},
CaseNode {
pattern: Tk {
class: CasePattern,
span: Span {
range: 23..27,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
body: [
Node {
class: Pipeline {
cmds: [
Node {
class: Command {
assignments: [],
argv: [
Tk {
class: Str,
span: Span {
range: 28..31,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 28..31,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 31..34,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
pipe_err: false,
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 28..31,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 31..34,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
},
CaseNode {
pattern: Tk {
class: CasePattern,
span: Span {
range: 34..38,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
body: [
Node {
class: Pipeline {
cmds: [
Node {
class: Command {
assignments: [],
argv: [
Tk {
class: Str,
span: Span {
range: 39..42,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 39..42,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 42..45,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
pipe_err: false,
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 39..42,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 42..45,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
],
},
],
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 0..4,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: Str,
span: Span {
range: 5..8,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Str,
span: Span {
range: 9..11,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: CasePattern,
span: Span {
range: 12..16,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 17..20,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 20..23,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 23..27,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 28..31,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 31..34,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 34..38,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 39..42,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 42..45,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 45..49,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
],
},
operator: Null,
},
],
},
flags: NdFlags(
0x0,
),
redirs: [],
tokens: [
Tk {
class: Str,
span: Span {
range: 0..4,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: Str,
span: Span {
range: 5..8,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Str,
span: Span {
range: 9..11,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
Tk {
class: CasePattern,
span: Span {
range: 12..16,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 17..20,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 20..23,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 23..27,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 28..31,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 31..34,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: CasePattern,
span: Span {
range: 34..38,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 39..42,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
IS_CMD,
),
},
Tk {
class: Sep,
span: Span {
range: 42..45,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
0x0,
),
},
Tk {
class: Str,
span: Span {
range: 45..49,
source: "case foo in foo) bar;; bar) foo;; biz) baz;; esac",
},
flags: TkFlags(
KEYWORD,
),
},
],
},
),
]

File diff suppressed because it is too large Load Diff