diff --git a/src/ast.rs b/src/ast.rs index 493a267d8..e3a908d5a 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -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)), + (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 { - 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::(); - BlockStatementHeaderVariant::ForHeader(embedded) + BlockStatementHeader::For(embedded) } ParseKeyword::While => { let embedded = self.allocate_visit::(); - BlockStatementHeaderVariant::WhileHeader(embedded) + BlockStatementHeader::While(embedded) } ParseKeyword::Function => { let embedded = self.allocate_visit::(); - BlockStatementHeaderVariant::FunctionHeader(embedded) + BlockStatementHeader::Function(embedded) } ParseKeyword::Begin => { let embedded = self.allocate_visit::(); - 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, diff --git a/src/highlight/highlight.rs b/src/highlight/highlight.rs index d42d797a9..44f192406 100644 --- a/src/highlight/highlight.rs +++ b/src/highlight/highlight.rs @@ -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); } diff --git a/src/parse_execution.rs b/src/parse_execution.rs index aa00b44f7..a7727b3ee 100644 --- a/src/parse_execution.rs +++ b/src/parse_execution.rs @@ -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(), diff --git a/src/parse_util.rs b/src/parse_util.rs index cfc065e15..cee4abe01 100644 --- a/src/parse_util.rs +++ b/src/parse_util.rs @@ -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;