ast: Clean up BlockStatementHeader

Make this a real Node.
This commit is contained in:
Peter Ammon
2025-04-27 13:50:36 -07:00
parent dbae271fe7
commit d6ee4ec698
4 changed files with 76 additions and 174 deletions

View File

@@ -65,10 +65,7 @@ trait NodeVisitorMut {
fn did_visit_fields_of<'a>(&'a mut self, node: &'a dyn NodeMut, flow: VisitResult);
fn visit_argument_or_redirection(&mut self, _node: &mut ArgumentOrRedirection) -> VisitResult;
fn visit_block_statement_header(
&mut self,
_node: &mut BlockStatementHeaderVariant,
) -> VisitResult;
fn visit_block_statement_header(&mut self, _node: &mut BlockStatementHeader) -> VisitResult;
fn visit_statement(&mut self, _node: &mut Statement) -> VisitResult;
fn visit_decorated_statement_decorator(
@@ -218,6 +215,7 @@ pub enum Kind<'a> {
Statement(&'a Statement),
JobPipeline(&'a JobPipeline),
JobConjunction(&'a JobConjunction),
BlockStatementHeader(&'a BlockStatementHeader),
ForHeader(&'a ForHeader),
WhileHeader(&'a WhileHeader),
FunctionHeader(&'a FunctionHeader),
@@ -258,6 +256,7 @@ pub enum KindMut<'a> {
Statement(&'a mut Statement),
JobPipeline(&'a mut JobPipeline),
JobConjunction(&'a mut JobConjunction),
BlockStatementHeader(&'a mut BlockStatementHeader),
ForHeader(&'a mut ForHeader),
WhileHeader(&'a mut WhileHeader),
FunctionHeader(&'a mut FunctionHeader),
@@ -886,14 +885,6 @@ macro_rules! visit_1_field {
/// Visit the given field.
macro_rules! visit_1_field_impl {
(
$visit:ident,
$field:expr,
(variant<$field_type:ident>),
$visitor:ident
) => {
visit_variant_field!($visit, $field_type, $field, $visitor)
};
(
$visit:ident,
$field:expr,
@@ -921,31 +912,6 @@ macro_rules! apply_borrow {
};
}
macro_rules! visit_variant_field {
(
visit,
$field_type:ident,
$field:expr,
$visitor:ident
) => {
$visitor.visit($field.embedded_node().as_node())
};
(
visit_mut,
$field_type:ident,
$field:expr,
$visitor:ident
) => {
visit_variant_field_mut!($field_type, $visitor, $field)
};
}
macro_rules! visit_variant_field_mut {
(BlockStatementHeaderVariant, $visitor:ident, $field:expr) => {
$visitor.visit_block_statement_header(&mut $field)
};
}
macro_rules! visit_optional_field {
(
visit,
@@ -1288,7 +1254,7 @@ impl NodeSubTraits for BeginHeader {}
#[derive(Default, Debug)]
pub struct BlockStatement {
/// A header like for, while, etc.
pub header: BlockStatementHeaderVariant,
pub header: BlockStatementHeader,
/// List of jobs in this block.
pub jobs: JobList,
/// The 'end' node.
@@ -1300,7 +1266,7 @@ pub struct BlockStatement {
impl NodeSubTraits for BlockStatement {}
implement_acceptor_for_branch!(
BlockStatement,
(header: (variant<BlockStatementHeaderVariant>)),
(header: (BlockStatementHeader)),
(jobs: (JobList)),
(end: (KeywordEnd)),
(args_or_redirs: (ArgumentOrRedirectionList)),
@@ -1745,84 +1711,42 @@ pub fn decoration(&self) -> StatementDecoration {
}
#[derive(Debug)]
pub enum BlockStatementHeaderVariant {
None,
ForHeader(ForHeader),
WhileHeader(WhileHeader),
FunctionHeader(FunctionHeader),
BeginHeader(BeginHeader),
pub enum BlockStatementHeader {
Begin(BeginHeader),
For(ForHeader),
While(WhileHeader),
Function(FunctionHeader),
}
implement_node!(BlockStatementHeader, block_statement_header);
impl NodeSubTraits for BlockStatementHeader {}
impl Default for BlockStatementHeaderVariant {
impl Default for BlockStatementHeader {
fn default() -> Self {
BlockStatementHeaderVariant::None
Self::Begin(BeginHeader::default())
}
}
impl Acceptor for BlockStatementHeaderVariant {
impl BlockStatementHeader {
pub fn embedded_node(&self) -> &dyn Node {
match self {
Self::Begin(child) => child,
Self::For(child) => child,
Self::While(child) => child,
Self::Function(child) => child,
}
}
}
impl Acceptor for BlockStatementHeader {
fn accept<'a>(&'a self, visitor: &mut dyn NodeVisitor<'a>) {
match self {
BlockStatementHeaderVariant::None => panic!("cannot visit null block header"),
BlockStatementHeaderVariant::ForHeader(node) => node.accept(visitor),
BlockStatementHeaderVariant::WhileHeader(node) => node.accept(visitor),
BlockStatementHeaderVariant::FunctionHeader(node) => node.accept(visitor),
BlockStatementHeaderVariant::BeginHeader(node) => node.accept(visitor),
}
visitor.visit(self.embedded_node());
}
}
impl AcceptorMut for BlockStatementHeaderVariant {
impl AcceptorMut for BlockStatementHeader {
fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) {
match self {
BlockStatementHeaderVariant::None => panic!("cannot visit null block header"),
BlockStatementHeaderVariant::ForHeader(node) => node.accept_mut(visitor),
BlockStatementHeaderVariant::WhileHeader(node) => node.accept_mut(visitor),
BlockStatementHeaderVariant::FunctionHeader(node) => node.accept_mut(visitor),
BlockStatementHeaderVariant::BeginHeader(node) => node.accept_mut(visitor),
}
}
}
impl BlockStatementHeaderVariant {
pub fn typ(&self) -> Type {
self.embedded_node().typ()
}
pub fn try_source_range(&self) -> Option<SourceRange> {
self.embedded_node().try_source_range()
}
pub fn as_for_header(&self) -> Option<&ForHeader> {
match self {
BlockStatementHeaderVariant::ForHeader(node) => Some(node),
_ => None,
}
}
pub fn as_while_header(&self) -> Option<&WhileHeader> {
match self {
BlockStatementHeaderVariant::WhileHeader(node) => Some(node),
_ => None,
}
}
pub fn as_function_header(&self) -> Option<&FunctionHeader> {
match self {
BlockStatementHeaderVariant::FunctionHeader(node) => Some(node),
_ => None,
}
}
pub fn as_begin_header(&self) -> Option<&BeginHeader> {
match self {
BlockStatementHeaderVariant::BeginHeader(node) => Some(node),
_ => None,
}
}
fn embedded_node(&self) -> &dyn NodeMut {
match self {
BlockStatementHeaderVariant::None => panic!("cannot visit null block header"),
BlockStatementHeaderVariant::ForHeader(node) => node,
BlockStatementHeaderVariant::WhileHeader(node) => node,
BlockStatementHeaderVariant::FunctionHeader(node) => node,
BlockStatementHeaderVariant::BeginHeader(node) => node,
}
visitor.will_visit_fields_of(self);
let flow = visitor.visit_block_statement_header(self);
visitor.did_visit_fields_of(self, flow);
}
}
@@ -1839,6 +1763,7 @@ pub fn ast_type_to_string(t: Type) -> &'static wstr {
Type::statement => L!("statement"),
Type::job_pipeline => L!("job_pipeline"),
Type::job_conjunction => L!("job_conjunction"),
Type::block_statement_header => L!("block_statement_header"),
Type::for_header => L!("for_header"),
Type::while_header => L!("while_header"),
Type::function_header => L!("function_header"),
@@ -2362,6 +2287,7 @@ fn visit_mut(&mut self, node: &mut dyn NodeMut) -> VisitResult {
KM::Statement(node) => node.accept_mut(self),
KM::JobPipeline(node) => node.accept_mut(self),
KM::JobConjunction(node) => node.accept_mut(self),
KM::BlockStatementHeader(node) => node.accept_mut(self),
KM::ForHeader(node) => node.accept_mut(self),
KM::WhileHeader(node) => node.accept_mut(self),
KM::FunctionHeader(node) => node.accept_mut(self),
@@ -2434,36 +2360,29 @@ fn did_visit_fields_of<'a>(&'a mut self, node: &'a dyn NodeMut, flow: VisitResul
// We believe the node is some sort of block statement. Attempt to find a source range
// for the block's keyword (for, if, etc) and a user-presentable description. This
// is used to provide better error messages. Note at this point the parse tree is
// incomplete; in particular parent nodes are not set.
let mut cursor = node;
// incomplete.
let mut cursor = node.as_node();
let header = loop {
match cursor.typ() {
Type::block_statement => {
cursor = cursor.as_block_statement().unwrap().header.embedded_node();
match cursor.kind() {
Kind::BlockStatement(node) => cursor = &node.header,
Kind::BlockStatementHeader(node) => cursor = node.embedded_node(),
Kind::ForHeader(node) => {
break Some((node.kw_for.range.unwrap(), L!("for loop")));
}
Type::for_header => {
let n = cursor.as_for_header().unwrap();
break Some((n.kw_for.range.unwrap(), L!("for loop")));
Kind::WhileHeader(node) => {
break Some((node.kw_while.range.unwrap(), L!("while loop")));
}
Type::while_header => {
let n = cursor.as_while_header().unwrap();
break Some((n.kw_while.range.unwrap(), L!("while loop")));
Kind::FunctionHeader(node) => {
break Some((node.kw_function.range.unwrap(), L!("function definition")));
}
Type::function_header => {
let n = cursor.as_function_header().unwrap();
break Some((n.kw_function.range.unwrap(), L!("function definition")));
Kind::BeginHeader(node) => {
break Some((node.kw_begin.range.unwrap(), L!("begin")));
}
Type::begin_header => {
let n = cursor.as_begin_header().unwrap();
break Some((n.kw_begin.range.unwrap(), L!("begin")));
Kind::IfStatement(node) => {
break Some((node.if_clause.kw_if.range.unwrap(), L!("if statement")));
}
Type::if_statement => {
let n = cursor.as_if_statement().unwrap();
break Some((n.if_clause.kw_if.range.unwrap(), L!("if statement")));
}
Type::switch_statement => {
let n = cursor.as_switch_statement().unwrap();
break Some((n.kw_switch.range.unwrap(), L!("switch statement")));
Kind::SwitchStatement(node) => {
break Some((node.kw_switch.range.unwrap(), L!("switch statement")));
}
_ => break None,
}
@@ -2512,10 +2431,7 @@ fn visit_argument_or_redirection(&mut self, node: &mut ArgumentOrRedirection) ->
}
VisitResult::Continue(())
}
fn visit_block_statement_header(
&mut self,
node: &mut BlockStatementHeaderVariant,
) -> VisitResult {
fn visit_block_statement_header(&mut self, node: &mut BlockStatementHeader) -> VisitResult {
*node = self.allocate_populate_block_header();
VisitResult::Continue(())
}
@@ -3177,23 +3093,23 @@ fn new_decorated_statement(slf: &mut Populator<'_>) -> Statement {
/// Allocate and populate a block statement header.
/// This must never return null.
fn allocate_populate_block_header(&mut self) -> BlockStatementHeaderVariant {
fn allocate_populate_block_header(&mut self) -> BlockStatementHeader {
match self.peek_token(0).keyword {
ParseKeyword::For => {
let embedded = self.allocate_visit::<ForHeader>();
BlockStatementHeaderVariant::ForHeader(embedded)
BlockStatementHeader::For(embedded)
}
ParseKeyword::While => {
let embedded = self.allocate_visit::<WhileHeader>();
BlockStatementHeaderVariant::WhileHeader(embedded)
BlockStatementHeader::While(embedded)
}
ParseKeyword::Function => {
let embedded = self.allocate_visit::<FunctionHeader>();
BlockStatementHeaderVariant::FunctionHeader(embedded)
BlockStatementHeader::Function(embedded)
}
ParseKeyword::Begin => {
let embedded = self.allocate_visit::<BeginHeader>();
BlockStatementHeaderVariant::BeginHeader(embedded)
BlockStatementHeader::Begin(embedded)
}
_ => {
internal_error!(
@@ -3520,6 +3436,7 @@ pub enum Type {
statement,
job_pipeline,
job_conjunction,
block_statement_header,
for_header,
while_header,
function_header,

View File

@@ -1,8 +1,8 @@
//! Functions for syntax highlighting.
use crate::abbrs::{self, with_abbrs};
use crate::ast::{
self, Argument, Ast, BlockStatement, BlockStatementHeaderVariant, BraceStatement,
DecoratedStatement, Keyword, Node, NodeVisitor, Redirection, Token, Type, VariableAssignment,
self, Argument, Ast, BlockStatement, BlockStatementHeader, BraceStatement, DecoratedStatement,
Keyword, Node, NodeVisitor, Redirection, Token, Type, VariableAssignment,
};
use crate::builtins::shared::builtin_exists;
use crate::color::Color;
@@ -1043,15 +1043,14 @@ fn visit_decorated_statement(&mut self, stmt: &DecoratedStatement) {
}
fn visit_block_statement(&mut self, block: &BlockStatement) {
match &block.header {
BlockStatementHeaderVariant::None => panic!(),
BlockStatementHeaderVariant::ForHeader(node) => self.visit(node),
BlockStatementHeaderVariant::WhileHeader(node) => self.visit(node),
BlockStatementHeaderVariant::FunctionHeader(node) => self.visit(node),
BlockStatementHeaderVariant::BeginHeader(node) => self.visit(node),
BlockStatementHeader::For(node) => self.visit(node),
BlockStatementHeader::While(node) => self.visit(node),
BlockStatementHeader::Function(node) => self.visit(node),
BlockStatementHeader::Begin(node) => self.visit(node),
}
self.visit(&block.args_or_redirs);
let pending_variables_count = self.pending_variables.len();
if let Some(fh) = block.header.as_for_header() {
if let BlockStatementHeader::For(fh) = &block.header {
let var_name = fh.var_name.source(self.buff);
self.pending_variables.push(var_name);
}

View File

@@ -1,7 +1,7 @@
//! Provides the "linkage" between an ast and actual execution structures (job_t, etc.).
use crate::ast::{
self, unescape_keyword, BlockStatementHeaderVariant, Keyword, Leaf, Node, Statement, Token,
self, unescape_keyword, BlockStatementHeader, Keyword, Leaf, Node, Statement, Token,
};
use crate::builtins;
use crate::builtins::shared::{
@@ -857,17 +857,12 @@ fn run_block_statement(
let bh = &statement.header;
let contents = &statement.jobs;
match bh {
BlockStatementHeaderVariant::ForHeader(fh) => self.run_for_statement(ctx, fh, contents),
BlockStatementHeaderVariant::WhileHeader(wh) => {
BlockStatementHeader::For(fh) => self.run_for_statement(ctx, fh, contents),
BlockStatementHeader::While(wh) => {
self.run_while_statement(ctx, wh, contents, associated_block)
}
BlockStatementHeaderVariant::FunctionHeader(fh) => {
self.run_function_statement(ctx, statement, fh)
}
BlockStatementHeaderVariant::BeginHeader(_bh) => {
self.run_begin_statement(ctx, contents)
}
BlockStatementHeaderVariant::None => panic!(),
BlockStatementHeader::Function(fh) => self.run_function_statement(ctx, statement, fh),
BlockStatementHeader::Begin(_bh) => self.run_begin_statement(ctx, contents),
}
}
@@ -1926,19 +1921,10 @@ fn profiling_cmd_name_for_redirectable_block(
Statement::Block(block_statement) => {
let block_header = &block_statement.header;
match block_header {
BlockStatementHeaderVariant::ForHeader(for_header) => {
for_header.semi_nl.source_range().start()
}
BlockStatementHeaderVariant::WhileHeader(while_header) => {
while_header.condition.source_range().start()
}
BlockStatementHeaderVariant::FunctionHeader(function_header) => {
function_header.semi_nl.source_range().start()
}
BlockStatementHeaderVariant::BeginHeader(begin_header) => {
begin_header.kw_begin.source_range().start()
}
BlockStatementHeaderVariant::None => panic!("Unexpected block header type"),
BlockStatementHeader::For(node) => node.semi_nl.source_range().start(),
BlockStatementHeader::While(node) => node.condition.source_range().start(),
BlockStatementHeader::Function(node) => node.semi_nl.source_range().start(),
BlockStatementHeader::Begin(node) => node.kw_begin.source_range().start(),
}
}
Statement::Brace(brace_statement) => brace_statement.left_brace.source_range().start(),

View File

@@ -1738,13 +1738,13 @@ fn detect_errors_in_decorated_statement(
.parent_nodes()
.filter_map(|anc| anc.as_block_statement())
{
match block.header.typ() {
ast::Type::for_header | ast::Type::while_header => {
match block.header {
ast::BlockStatementHeader::For(_) | ast::BlockStatementHeader::While(_) => {
// This is a loop header, so we can break or continue.
found_loop = true;
break;
}
ast::Type::function_header => {
ast::BlockStatementHeader::Function(_) => {
// This is a function header, so we cannot break or
// continue. We stop our search here.
found_loop = false;