mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-14 14:03:58 +00:00
Use bitflags for ParseTreeFlags + ParserTestErrorBits
For consistency with simlar code.
This commit is contained in:
parent
cb368f70ee
commit
1dafb77cda
4 changed files with 56 additions and 91 deletions
|
@ -14,9 +14,7 @@ use crate::flog::FLOG;
|
|||
use crate::parse_constants::{
|
||||
token_type_user_presentable_description, ParseError, ParseErrorCode, ParseErrorList,
|
||||
ParseErrorListFfi, ParseKeyword, ParseTokenType, ParseTreeFlags, SourceRange,
|
||||
StatementDecoration, INVALID_PIPELINE_CMD_ERR_MSG, PARSE_FLAG_ACCEPT_INCOMPLETE_TOKENS,
|
||||
PARSE_FLAG_CONTINUE_AFTER_ERROR, PARSE_FLAG_INCLUDE_COMMENTS, PARSE_FLAG_LEAVE_UNTERMINATED,
|
||||
PARSE_FLAG_SHOW_EXTRA_SEMIS, SOURCE_OFFSET_INVALID,
|
||||
StatementDecoration, INVALID_PIPELINE_CMD_ERR_MSG, SOURCE_OFFSET_INVALID,
|
||||
};
|
||||
use crate::parse_tree::ParseToken;
|
||||
use crate::tokenizer::{
|
||||
|
@ -2937,7 +2935,7 @@ impl<'s> Populator<'s> {
|
|||
fn status(&mut self) -> ParserStatus {
|
||||
if self.unwinding {
|
||||
ParserStatus::unwinding
|
||||
} else if self.flags & PARSE_FLAG_LEAVE_UNTERMINATED
|
||||
} else if self.flags.contains(ParseTreeFlags::LEAVE_UNTERMINATED)
|
||||
&& self.peek_type(0) == ParseTokenType::terminate
|
||||
{
|
||||
ParserStatus::unsourcing
|
||||
|
@ -2956,7 +2954,7 @@ impl<'s> Populator<'s> {
|
|||
|
||||
/// \return whether we permit an incomplete parse tree.
|
||||
fn allow_incomplete(&self) -> bool {
|
||||
self.flags & PARSE_FLAG_LEAVE_UNTERMINATED
|
||||
self.flags.contains(ParseTreeFlags::LEAVE_UNTERMINATED)
|
||||
}
|
||||
|
||||
/// \return whether a list type \p type allows arbitrary newlines in it.
|
||||
|
@ -3074,7 +3072,7 @@ impl<'s> Populator<'s> {
|
|||
} else if chomp_semis && peek.typ == ParseTokenType::end && !peek.is_newline {
|
||||
let tok = self.tokens.pop();
|
||||
// Perhaps save this extra semi.
|
||||
if self.flags & PARSE_FLAG_SHOW_EXTRA_SEMIS {
|
||||
if self.flags.contains(ParseTreeFlags::SHOW_EXTRA_SEMIS) {
|
||||
self.semis.push(tok.range());
|
||||
}
|
||||
} else {
|
||||
|
@ -3086,7 +3084,7 @@ impl<'s> Populator<'s> {
|
|||
/// \return whether a list type should recover from errors.s
|
||||
/// That is, whether we should stop unwinding when we encounter this type.
|
||||
fn list_type_stops_unwind(&self, typ: Type) -> bool {
|
||||
typ == Type::job_list && self.flags & PARSE_FLAG_CONTINUE_AFTER_ERROR
|
||||
typ == Type::job_list && self.flags.contains(ParseTreeFlags::CONTINUE_AFTER_ERROR)
|
||||
}
|
||||
|
||||
/// \return a reference to a non-comment token at index \p idx.
|
||||
|
@ -3678,7 +3676,7 @@ impl<'s> Populator<'s> {
|
|||
}
|
||||
|
||||
if !token.allows_token(self.peek_token(0).typ) {
|
||||
if self.flags & PARSE_FLAG_LEAVE_UNTERMINATED
|
||||
if self.flags.contains(ParseTreeFlags::LEAVE_UNTERMINATED)
|
||||
&& [
|
||||
TokenizerError::unterminated_quote,
|
||||
TokenizerError::unterminated_subshell,
|
||||
|
@ -3714,7 +3712,7 @@ impl<'s> Populator<'s> {
|
|||
if !keyword.allows_keyword(self.peek_token(0).keyword) {
|
||||
*keyword.range_mut() = None;
|
||||
|
||||
if self.flags & PARSE_FLAG_LEAVE_UNTERMINATED
|
||||
if self.flags.contains(ParseTreeFlags::LEAVE_UNTERMINATED)
|
||||
&& [
|
||||
TokenizerError::unterminated_quote,
|
||||
TokenizerError::unterminated_subshell,
|
||||
|
@ -3842,13 +3840,13 @@ impl From<ParseTreeFlags> for TokFlags {
|
|||
let mut tok_flags = TokFlags(0);
|
||||
// Note we do not need to respect parse_flag_show_blank_lines, no clients are interested
|
||||
// in them.
|
||||
if flags & PARSE_FLAG_INCLUDE_COMMENTS {
|
||||
if flags.contains(ParseTreeFlags::INCLUDE_COMMENTS) {
|
||||
tok_flags |= TOK_SHOW_COMMENTS;
|
||||
}
|
||||
if flags & PARSE_FLAG_ACCEPT_INCOMPLETE_TOKENS {
|
||||
if flags.contains(ParseTreeFlags::ACCEPT_INCOMPLETE_TOKENS) {
|
||||
tok_flags |= TOK_ACCEPT_UNFINISHED;
|
||||
}
|
||||
if flags & PARSE_FLAG_CONTINUE_AFTER_ERROR {
|
||||
if flags.contains(ParseTreeFlags::CONTINUE_AFTER_ERROR) {
|
||||
tok_flags |= TOK_CONTINUE_AFTER_ERROR
|
||||
}
|
||||
tok_flags
|
||||
|
@ -3921,9 +3919,8 @@ fn keyword_for_token(tok: TokenType, token: &wstr) -> ParseKeyword {
|
|||
|
||||
use crate::ffi_tests::add_test;
|
||||
add_test!("test_ast_parse", || {
|
||||
use crate::parse_constants::PARSE_FLAG_NONE;
|
||||
let src = L!("echo");
|
||||
let ast = Ast::parse(src, PARSE_FLAG_NONE, None);
|
||||
let ast = Ast::parse(src, ParseTreeFlags::empty(), None);
|
||||
assert!(!ast.any_error);
|
||||
});
|
||||
|
||||
|
@ -4422,7 +4419,7 @@ impl Ast {
|
|||
fn ast_parse_ffi(src: &CxxWString, flags: u8, errors: *mut ParseErrorListFfi) -> Box<Ast> {
|
||||
Box::new(Ast::parse(
|
||||
src.as_wstr(),
|
||||
ParseTreeFlags(flags),
|
||||
ParseTreeFlags::from_bits(flags).unwrap(),
|
||||
if errors.is_null() {
|
||||
None
|
||||
} else {
|
||||
|
@ -4438,7 +4435,7 @@ fn ast_parse_argument_list_ffi(
|
|||
) -> Box<Ast> {
|
||||
Box::new(Ast::parse_argument_list(
|
||||
src.as_wstr(),
|
||||
ParseTreeFlags(flags),
|
||||
ParseTreeFlags::from_bits(flags).unwrap(),
|
||||
if errors.is_null() {
|
||||
None
|
||||
} else {
|
||||
|
|
|
@ -5,9 +5,9 @@ use crate::tokenizer::variable_assignment_equals_pos;
|
|||
use crate::wchar::{wstr, WString, L};
|
||||
use crate::wchar_ffi::{wcharz, AsWstr, WCharFromFFI, WCharToFFI};
|
||||
use crate::wutil::{sprintf, wgettext_fmt};
|
||||
use bitflags::bitflags;
|
||||
use cxx::{type_id, ExternType};
|
||||
use cxx::{CxxWString, UniquePtr};
|
||||
use std::ops::{BitAnd, BitOr, BitOrAssign};
|
||||
use widestring_suffix::widestrs;
|
||||
|
||||
pub type SourceOffset = u32;
|
||||
|
@ -15,58 +15,30 @@ pub type SourceOffset = u32;
|
|||
pub const SOURCE_OFFSET_INVALID: usize = SourceOffset::MAX as _;
|
||||
pub const SOURCE_LOCATION_UNKNOWN: usize = usize::MAX;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ParseTreeFlags(pub u8);
|
||||
|
||||
pub const PARSE_FLAG_NONE: ParseTreeFlags = ParseTreeFlags(0);
|
||||
/// attempt to build a "parse tree" no matter what. this may result in a 'forest' of
|
||||
/// disconnected trees. this is intended to be used by syntax highlighting.
|
||||
pub const PARSE_FLAG_CONTINUE_AFTER_ERROR: ParseTreeFlags = ParseTreeFlags(1 << 0);
|
||||
/// include comment tokens.
|
||||
pub const PARSE_FLAG_INCLUDE_COMMENTS: ParseTreeFlags = ParseTreeFlags(1 << 1);
|
||||
/// indicate that the tokenizer should accept incomplete tokens */
|
||||
pub const PARSE_FLAG_ACCEPT_INCOMPLETE_TOKENS: ParseTreeFlags = ParseTreeFlags(1 << 2);
|
||||
/// indicate that the parser should not generate the terminate token, allowing an 'unfinished'
|
||||
/// tree where some nodes may have no productions.
|
||||
pub const PARSE_FLAG_LEAVE_UNTERMINATED: ParseTreeFlags = ParseTreeFlags(1 << 3);
|
||||
/// indicate that the parser should generate job_list entries for blank lines.
|
||||
pub const PARSE_FLAG_SHOW_BLANK_LINES: ParseTreeFlags = ParseTreeFlags(1 << 4);
|
||||
/// indicate that extra semis should be generated.
|
||||
pub const PARSE_FLAG_SHOW_EXTRA_SEMIS: ParseTreeFlags = ParseTreeFlags(1 << 5);
|
||||
|
||||
impl BitAnd for ParseTreeFlags {
|
||||
type Output = bool;
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
(self.0 & rhs.0) != 0
|
||||
}
|
||||
}
|
||||
impl BitOr for ParseTreeFlags {
|
||||
type Output = ParseTreeFlags;
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
impl BitOrAssign for ParseTreeFlags {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0
|
||||
bitflags! {
|
||||
pub struct ParseTreeFlags: u8 {
|
||||
/// attempt to build a "parse tree" no matter what. this may result in a 'forest' of
|
||||
/// disconnected trees. this is intended to be used by syntax highlighting.
|
||||
const CONTINUE_AFTER_ERROR = 1 << 0;
|
||||
/// include comment tokens.
|
||||
const INCLUDE_COMMENTS = 1 << 1;
|
||||
/// indicate that the tokenizer should accept incomplete tokens */
|
||||
const ACCEPT_INCOMPLETE_TOKENS = 1 << 2;
|
||||
/// indicate that the parser should not generate the terminate token, allowing an 'unfinished'
|
||||
/// tree where some nodes may have no productions.
|
||||
const LEAVE_UNTERMINATED = 1 << 3;
|
||||
/// indicate that the parser should generate job_list entries for blank lines.
|
||||
const SHOW_BLANK_LINES = 1 << 4;
|
||||
/// indicate that extra semis should be generated.
|
||||
const SHOW_EXTRA_SEMIS = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Default)]
|
||||
pub struct ParserTestErrorBits(u8);
|
||||
|
||||
pub const PARSER_TEST_ERROR: ParserTestErrorBits = ParserTestErrorBits(1);
|
||||
pub const PARSER_TEST_INCOMPLETE: ParserTestErrorBits = ParserTestErrorBits(2);
|
||||
|
||||
impl BitAnd for ParserTestErrorBits {
|
||||
type Output = bool;
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
(self.0 & rhs.0) != 0
|
||||
}
|
||||
}
|
||||
impl BitOrAssign for ParserTestErrorBits {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct ParserTestErrorBits: u8 {
|
||||
const ERROR = 1;
|
||||
const INCOMPLETE = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ use std::rc::Rc;
|
|||
use crate::ast::Ast;
|
||||
use crate::parse_constants::{
|
||||
token_type_user_presentable_description, ParseErrorCode, ParseErrorList, ParseErrorListFfi,
|
||||
ParseKeyword, ParseTokenType, ParseTreeFlags, SourceOffset, SourceRange,
|
||||
PARSE_FLAG_CONTINUE_AFTER_ERROR, SOURCE_OFFSET_INVALID,
|
||||
ParseKeyword, ParseTokenType, ParseTreeFlags, SourceOffset, SourceRange, SOURCE_OFFSET_INVALID,
|
||||
};
|
||||
use crate::tokenizer::TokenizerError;
|
||||
use crate::wchar::{wstr, WString, L};
|
||||
|
@ -123,7 +122,7 @@ pub fn parse_source(
|
|||
errors: Option<&mut ParseErrorList>,
|
||||
) -> ParsedSourceRef {
|
||||
let ast = Ast::parse(&src, flags, errors);
|
||||
if ast.errored() && !(flags & PARSE_FLAG_CONTINUE_AFTER_ERROR) {
|
||||
if ast.errored() && !flags.contains(ParseTreeFlags::CONTINUE_AFTER_ERROR) {
|
||||
None
|
||||
} else {
|
||||
Some(Rc::new(ParsedSource::new(src, ast)))
|
||||
|
@ -179,7 +178,7 @@ fn parse_source_ffi(
|
|||
) -> Box<ParsedSourceRefFFI> {
|
||||
Box::new(ParsedSourceRefFFI(parse_source(
|
||||
src.from_ffi(),
|
||||
ParseTreeFlags(flags),
|
||||
ParseTreeFlags::from_bits(flags).unwrap(),
|
||||
if errors.is_null() {
|
||||
None
|
||||
} else {
|
||||
|
|
|
@ -14,14 +14,11 @@ use crate::future_feature_flags::{feature_test, FeatureFlag};
|
|||
use crate::operation_context::OperationContext;
|
||||
use crate::parse_constants::{
|
||||
parse_error_offset_source_start, ParseError, ParseErrorCode, ParseErrorList, ParseKeyword,
|
||||
ParseTokenType, ParserTestErrorBits, PipelinePosition, StatementDecoration,
|
||||
ParseTokenType, ParseTreeFlags, ParserTestErrorBits, PipelinePosition, StatementDecoration,
|
||||
ERROR_BAD_VAR_CHAR1, ERROR_BRACKETED_VARIABLE1, ERROR_BRACKETED_VARIABLE_QUOTED1,
|
||||
ERROR_NOT_ARGV_AT, ERROR_NOT_ARGV_COUNT, ERROR_NOT_ARGV_STAR, ERROR_NOT_PID, ERROR_NOT_STATUS,
|
||||
ERROR_NO_VAR_NAME, INVALID_BREAK_ERR_MSG, INVALID_CONTINUE_ERR_MSG,
|
||||
INVALID_PIPELINE_CMD_ERR_MSG, PARSER_TEST_ERROR, PARSER_TEST_INCOMPLETE,
|
||||
PARSE_FLAG_ACCEPT_INCOMPLETE_TOKENS, PARSE_FLAG_CONTINUE_AFTER_ERROR,
|
||||
PARSE_FLAG_INCLUDE_COMMENTS, PARSE_FLAG_LEAVE_UNTERMINATED, PARSE_FLAG_NONE,
|
||||
UNKNOWN_BUILTIN_ERR_MSG,
|
||||
INVALID_PIPELINE_CMD_ERR_MSG, UNKNOWN_BUILTIN_ERR_MSG,
|
||||
};
|
||||
use crate::tokenizer::{
|
||||
comment_end, is_token_delimiter, quote_end, Tok, TokenType, Tokenizer, TOK_ACCEPT_UNFINISHED,
|
||||
|
@ -742,10 +739,10 @@ pub fn parse_util_compute_indents(src: &wstr) -> Vec<i32> {
|
|||
// were a case item list.
|
||||
let ast = Ast::parse(
|
||||
src,
|
||||
PARSE_FLAG_CONTINUE_AFTER_ERROR
|
||||
| PARSE_FLAG_INCLUDE_COMMENTS
|
||||
| PARSE_FLAG_ACCEPT_INCOMPLETE_TOKENS
|
||||
| PARSE_FLAG_LEAVE_UNTERMINATED,
|
||||
ParseTreeFlags::CONTINUE_AFTER_ERROR
|
||||
| ParseTreeFlags::INCLUDE_COMMENTS
|
||||
| ParseTreeFlags::ACCEPT_INCOMPLETE_TOKENS
|
||||
| ParseTreeFlags::LEAVE_UNTERMINATED,
|
||||
None,
|
||||
);
|
||||
{
|
||||
|
@ -965,7 +962,7 @@ impl<'a> NodeVisitor<'a> for IndentVisitor<'a> {
|
|||
}
|
||||
|
||||
/// Given a string, detect parse errors in it. If allow_incomplete is set, then if the string is
|
||||
/// incomplete (e.g. an unclosed quote), an error is not returned and the PARSER_TEST_INCOMPLETE bit
|
||||
/// incomplete (e.g. an unclosed quote), an error is not returned and the ParserTestErrorBits::INCOMPLETE bit
|
||||
/// is set in the return value. If allow_incomplete is not set, then incomplete strings result in an
|
||||
/// error.
|
||||
pub fn parse_util_detect_errors(
|
||||
|
@ -978,9 +975,9 @@ pub fn parse_util_detect_errors(
|
|||
let mut has_unclosed_quote_or_subshell = false;
|
||||
|
||||
let parse_flags = if allow_incomplete {
|
||||
PARSE_FLAG_LEAVE_UNTERMINATED
|
||||
ParseTreeFlags::LEAVE_UNTERMINATED
|
||||
} else {
|
||||
PARSE_FLAG_NONE
|
||||
ParseTreeFlags::empty()
|
||||
};
|
||||
|
||||
// Parse the input string into an ast. Some errors are detected here.
|
||||
|
@ -1009,14 +1006,14 @@ pub fn parse_util_detect_errors(
|
|||
assert!(!has_unclosed_quote_or_subshell || allow_incomplete);
|
||||
if has_unclosed_quote_or_subshell {
|
||||
// We do not bother to validate the rest of the tree in this case.
|
||||
return Err(PARSER_TEST_INCOMPLETE);
|
||||
return Err(ParserTestErrorBits::INCOMPLETE);
|
||||
}
|
||||
|
||||
// Early parse error, stop here.
|
||||
if !parse_errors.is_empty() {
|
||||
if let Some(errors) = out_errors.as_mut() {
|
||||
errors.extend(parse_errors.into_iter());
|
||||
return Err(PARSER_TEST_ERROR);
|
||||
return Err(ParserTestErrorBits::ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1107,11 +1104,11 @@ pub fn parse_util_detect_errors_in_ast(
|
|||
}
|
||||
|
||||
if errored {
|
||||
res |= PARSER_TEST_ERROR;
|
||||
res |= ParserTestErrorBits::ERROR;
|
||||
}
|
||||
|
||||
if has_unclosed_block || has_unclosed_pipe || has_unclosed_conjunction {
|
||||
res |= PARSER_TEST_INCOMPLETE;
|
||||
res |= ParserTestErrorBits::INCOMPLETE;
|
||||
}
|
||||
if res == ParserTestErrorBits::default() {
|
||||
Ok(())
|
||||
|
@ -1139,7 +1136,7 @@ pub fn parse_util_detect_errors_in_argument_list(
|
|||
|
||||
// Parse the string as a freestanding argument list.
|
||||
let mut errors = ParseErrorList::new();
|
||||
let ast = Ast::parse_argument_list(arg_list_src, PARSE_FLAG_NONE, Some(&mut errors));
|
||||
let ast = Ast::parse_argument_list(arg_list_src, ParseTreeFlags::empty(), Some(&mut errors));
|
||||
if !errors.is_empty() {
|
||||
return get_error_text(&errors);
|
||||
}
|
||||
|
@ -1219,13 +1216,13 @@ pub fn parse_util_detect_errors_in_argument(
|
|||
append_syntax_error!(
|
||||
out_errors, source_start + begin, end - begin,
|
||||
"Incomplete escape sequence '%ls'", arg_src);
|
||||
return PARSER_TEST_ERROR;
|
||||
return ParserTestErrorBits::ERROR;
|
||||
}
|
||||
append_syntax_error!(
|
||||
out_errors, source_start + begin, end - begin,
|
||||
"Invalid token '%ls'", arg_src);
|
||||
}
|
||||
return PARSER_TEST_ERROR;
|
||||
return ParserTestErrorBits::ERROR;
|
||||
};
|
||||
|
||||
let mut err = ParserTestErrorBits::default();
|
||||
|
@ -1239,7 +1236,7 @@ pub fn parse_util_detect_errors_in_argument(
|
|||
if ![VARIABLE_EXPAND, VARIABLE_EXPAND_SINGLE, '('].contains(&next_char)
|
||||
&& !valid_var_name_char(next_char)
|
||||
{
|
||||
err = PARSER_TEST_ERROR;
|
||||
err = ParserTestErrorBits::ERROR;
|
||||
if let Some(ref mut out_errors) = out_errors {
|
||||
let mut first_dollar = idx;
|
||||
while first_dollar > 0
|
||||
|
@ -1282,7 +1279,7 @@ pub fn parse_util_detect_errors_in_argument(
|
|||
Some(&mut has_dollar),
|
||||
) {
|
||||
-1 => {
|
||||
err |= PARSER_TEST_ERROR;
|
||||
err |= ParserTestErrorBits::ERROR;
|
||||
append_syntax_error!(out_errors, source_start, 1, "Mismatched parenthesis");
|
||||
return err;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue