Let parser eval string directly

This gets the reader out of asting the source and is needed for
autoloader to get it to read a source string directly

Also add an "eval_file_wstr" method as a convenience to run a wstr as if it is a *file*, with a block and stuff
This commit is contained in:
Fabian Boehm
2025-01-31 23:22:26 +01:00
parent 64659e48f8
commit 66d7c00ba3
2 changed files with 55 additions and 23 deletions

View File

@@ -565,6 +565,52 @@ pub fn eval_parsed_source(
}
}
pub fn eval_wstr(
&self,
src: WString,
io: &IoChain,
job_group: Option<&JobGroupRef>,
block_type: BlockType,
) -> Result<EvalRes, WString> {
use crate::parse_tree::ParsedSource;
use crate::parse_util::parse_util_detect_errors_in_ast;
let mut errors = vec![];
let ast = Ast::parse(&src, ParseTreeFlags::empty(), Some(&mut errors));
let mut errored = ast.errored();
if !errored {
errored = parse_util_detect_errors_in_ast(&ast, &src, Some(&mut errors)).is_err();
}
if errored {
let sb = self.get_backtrace(&src, &errors);
return Err(sb);
}
// Construct a parsed source ref.
// Be careful to transfer ownership, this could be a very large string.
let ps = Arc::new(ParsedSource::new(src, ast));
Ok(self.eval_parsed_source(&ps, io, job_group, block_type))
}
pub fn eval_file_wstr(
&self,
src: WString,
filename: Arc<WString>,
io: &IoChain,
job_group: Option<&JobGroupRef>,
) -> Result<EvalRes, WString> {
let _interactive_push = self.push_scope(|s| s.is_interactive = false);
let sb = self.push_block(Block::source_block(filename.clone()));
let _filename_push = self
.library_data
.scoped_set(Some(filename.clone()), |s| &mut s.current_filename);
let ret = self.eval_wstr(src, io, job_group, BlockType::top);
self.pop_block(sb);
self.libdata_mut().exit_current_script = false;
ret
}
/// Evaluates a node.
/// The node type must be ast::Statement or ast::JobList.
pub fn eval_node<T: Node>(

View File

@@ -101,16 +101,14 @@
use crate::panic::AT_EXIT;
use crate::parse_constants::SourceRange;
use crate::parse_constants::{ParseTreeFlags, ParserTestErrorBits};
use crate::parse_tree::ParsedSource;
use crate::parse_util::parse_util_process_extent;
use crate::parse_util::MaybeParentheses;
use crate::parse_util::SPACES_PER_INDENT;
use crate::parse_util::{
parse_util_cmdsubst_extent, parse_util_compute_indents, parse_util_contains_wildcards,
parse_util_detect_errors, parse_util_detect_errors_in_ast, parse_util_escape_string_with_quote,
parse_util_escape_wildcards, parse_util_get_line_from_offset, parse_util_get_offset,
parse_util_get_offset_from_line, parse_util_lineno, parse_util_locate_cmdsubst_range,
parse_util_token_extent,
parse_util_detect_errors, parse_util_escape_string_with_quote, parse_util_escape_wildcards,
parse_util_get_line_from_offset, parse_util_get_offset, parse_util_get_offset_from_line,
parse_util_lineno, parse_util_locate_cmdsubst_range, parse_util_token_extent,
};
use crate::parser::{BlockType, EvalRes, Parser};
use crate::proc::{
@@ -818,25 +816,13 @@ fn read_ni(parser: &Parser, fd: RawFd, io: &IoChain) -> Result<(), ErrorCode> {
s.remove(0);
}
// Parse into an ast and detect errors.
let mut errors = vec![];
let ast = Ast::parse(&s, ParseTreeFlags::empty(), Some(&mut errors));
let mut errored = ast.errored();
if !errored {
errored = parse_util_detect_errors_in_ast(&ast, &s, Some(&mut errors)).is_err();
match parser.eval_wstr(s, io, None, BlockType::top) {
Ok(_) => Ok(()),
Err(msg) => {
eprintf!("%ls", msg);
Err(STATUS_CMD_ERROR)
}
}
if errored {
let sb = parser.get_backtrace(&s, &errors);
eprintf!("%ls", sb);
return Err(STATUS_CMD_ERROR);
}
// Construct a parsed source ref.
// Be careful to transfer ownership, this could be a very large string.
let ps = Arc::new(ParsedSource::new(s, ast));
parser.eval_parsed_source(&ps, io, None, BlockType::top);
Ok(())
}
/// Initialize the reader.