mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-25 14:51:15 -03:00
ast: Clean up BlockStatementHeader
Make this a real Node.
This commit is contained in:
197
src/ast.rs
197
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<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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user