Range resolving

This commit is contained in:
ef3d0c3e 2024-10-22 22:13:10 +02:00
parent 726dbdaf7c
commit 352b395929
15 changed files with 60 additions and 102 deletions

View file

@ -33,7 +33,7 @@ use crate::parser::source::Source;
use crate::parser::source::Token; use crate::parser::source::Token;
use crate::parser::source::VirtualSource; use crate::parser::source::VirtualSource;
use crate::parser::style::StyleHolder; use crate::parser::style::StyleHolder;
use crate::parser::util::process_escaped; use crate::parser::util::escape_text;
use crate::parser::util::Property; use crate::parser::util::Property;
use crate::parser::util::PropertyParser; use crate::parser::util::PropertyParser;
@ -209,7 +209,7 @@ impl BlockquoteRule {
&self, &self,
m: Match, m: Match,
) -> Result<(Option<String>, Option<String>, Option<String>), String> { ) -> Result<(Option<String>, Option<String>, Option<String>), String> {
let processed = process_escaped('\\', "]", m.as_str()); let processed = escape_text('\\', "]", m.as_str());
let pm = self.properties.parse(processed.as_str())?; let pm = self.properties.parse(processed.as_str())?;
let author = pm let author = pm

View file

@ -357,7 +357,7 @@ impl RegexRule for CodeRule {
}, },
Some(props) => { Some(props) => {
let processed = let processed =
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end()); util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) { match self.properties.parse(processed.as_str()) {
Err(e) => { Err(e) => {
reports.push( reports.push(
@ -421,9 +421,9 @@ impl RegexRule for CodeRule {
}; };
let mut code_content = if index == 0 { let mut code_content = if index == 0 {
util::process_escaped('\\', "```", matches.get(4).unwrap().as_str()) util::escape_text('\\', "```", matches.get(4).unwrap().as_str())
} else { } else {
util::process_escaped('\\', "``", matches.get(3).unwrap().as_str()) util::escape_text('\\', "``", matches.get(3).unwrap().as_str())
}; };
if code_content.bytes().last() == Some(b'\n') if code_content.bytes().last() == Some(b'\n')
// Remove newline // Remove newline

View file

@ -227,7 +227,7 @@ impl RegexRule for GraphRule {
return reports; return reports;
} }
Some(content) => { Some(content) => {
let processed = util::process_escaped( let processed = util::escape_text(
'\\', '\\',
"[/graph]", "[/graph]",
content.as_str().trim_start().trim_end(), content.as_str().trim_start().trim_end(),
@ -270,7 +270,7 @@ impl RegexRule for GraphRule {
}, },
Some(props) => { Some(props) => {
let processed = let processed =
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end()); util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) { match self.properties.parse(processed.as_str()) {
Err(e) => { Err(e) => {
reports.push( reports.push(

View file

@ -15,7 +15,7 @@ use crate::parser::source::Source;
use crate::parser::source::Token; use crate::parser::source::Token;
use crate::parser::state::RuleState; use crate::parser::state::RuleState;
use crate::parser::state::Scope; use crate::parser::state::Scope;
use crate::parser::util::process_escaped; use crate::parser::util::escape_text;
use ariadne::Fmt; use ariadne::Fmt;
use ariadne::Label; use ariadne::Label;
use ariadne::Report; use ariadne::Report;
@ -361,7 +361,7 @@ impl LayoutRule {
}, },
Some(props) => { Some(props) => {
let trimmed = props.as_str().trim_start().trim_end(); let trimmed = props.as_str().trim_start().trim_end();
let content = process_escaped('\\', "]", trimmed); let content = escape_text('\\', "]", trimmed);
match layout_type.parse_properties(content.as_str()) { match layout_type.parse_properties(content.as_str()) {
Ok(props) => Ok(props), Ok(props) => Ok(props),
Err(err) => { Err(err) => {

View file

@ -371,26 +371,10 @@ nml.link.push("**BOLD link**", "another url")
#[test] #[test]
fn semantics() { fn semantics() {
let source = Rc::new(SourceFile::with_content(
"".to_string(),
r#" - [la(*testi*nk](url)
"#
.to_string(),
None,
));
let parser = LangParser::default();
let (_, state) = parser.parse(
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
println!("{:#?}", state.shared.semantics);
return;
let source = Rc::new(SourceFile::with_content( let source = Rc::new(SourceFile::with_content(
"".to_string(), "".to_string(),
r#" r#"
[li**n**k](url) - [la\](*testi*nk](url)
"# "#
.to_string(), .to_string(),
None, None,
@ -404,9 +388,10 @@ nml.link.push("**BOLD link**", "another url")
); );
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,
link_display_sep { delta_line == 1, delta_start == 0, length == 1 }; list_bullet { delta_line == 1, delta_start == 1, length == 1 };
style_marker { delta_line == 0, delta_start == 3, length == 2 }; link_display_sep { delta_line == 0, delta_start == 2, length == 1 };
style_marker { delta_line == 0, delta_start == 3, length == 2 }; style_marker { delta_line == 0, delta_start == 6, length == 1 };
style_marker { delta_line == 0, delta_start == 6, length == 1 };
link_display_sep { delta_line == 0, delta_start == 3, length == 1 }; link_display_sep { delta_line == 0, delta_start == 3, length == 1 };
link_url_sep { delta_line == 0, delta_start == 1, length == 1 }; link_url_sep { delta_line == 0, delta_start == 1, length == 1 };
link_url { delta_line == 0, delta_start == 1, length == 3 }; link_url { delta_line == 0, delta_start == 1, length == 3 };

View file

@ -20,7 +20,7 @@ use crate::parser::source::Source;
use crate::parser::source::Token; use crate::parser::source::Token;
use crate::parser::source::VirtualSource; use crate::parser::source::VirtualSource;
use crate::parser::util; use crate::parser::util;
use crate::parser::util::process_escaped; use crate::parser::util::escape_text;
use crate::parser::util::Property; use crate::parser::util::Property;
use crate::parser::util::PropertyMapError; use crate::parser::util::PropertyMapError;
use crate::parser::util::PropertyParser; use crate::parser::util::PropertyParser;
@ -196,7 +196,7 @@ impl ListRule {
} }
fn parse_properties(&self, m: Match) -> Result<(Option<usize>, Option<String>), String> { fn parse_properties(&self, m: Match) -> Result<(Option<usize>, Option<String>), String> {
let processed = process_escaped('\\', "]", m.as_str()); let processed = escape_text('\\', "]", m.as_str());
let pm = self.properties.parse(processed.as_str())?; let pm = self.properties.parse(processed.as_str())?;
let offset = match pm.get("offset", |_, s| s.parse::<usize>()) { let offset = match pm.get("offset", |_, s| s.parse::<usize>()) {

View file

@ -306,7 +306,7 @@ impl MediaRule {
}, },
Some(props) => { Some(props) => {
let processed = let processed =
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end()); util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) { match self.properties.parse(processed.as_str()) {
Err(e) => Err( Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start()) Report::build(ReportKind::Error, token.source(), props.start())
@ -382,7 +382,7 @@ impl RegexRule for MediaRule {
matches.get(2).unwrap(), matches.get(2).unwrap(),
MediaRule::validate_uri(matches.get(2).unwrap().as_str()), MediaRule::validate_uri(matches.get(2).unwrap().as_str()),
) { ) {
(_, Ok(uri)) => util::process_escaped('\\', ")", uri), (_, Ok(uri)) => util::escape_text('\\', ")", uri),
(m, Err(err)) => { (m, Err(err)) => {
reports.push( reports.push(
Report::build(ReportKind::Error, token.source(), m.start()) Report::build(ReportKind::Error, token.source(), m.start())

View file

@ -118,7 +118,7 @@ impl RegexRule for RawRule {
} }
Some(content) => { Some(content) => {
let processed = let processed =
util::process_escaped('\\', "?}", content.as_str().trim_start().trim_end()); util::escape_text('\\', "?}", content.as_str().trim_start().trim_end());
if processed.is_empty() { if processed.is_empty() {
reports.push( reports.push(
@ -155,7 +155,7 @@ impl RegexRule for RawRule {
}, },
Some(props) => { Some(props) => {
let processed = let processed =
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end()); util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) { match self.properties.parse(processed.as_str()) {
Err(e) => { Err(e) => {
reports.push( reports.push(

View file

@ -206,7 +206,7 @@ impl ReferenceRule {
}, },
Some(props) => { Some(props) => {
let processed = let processed =
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end()); util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) { match self.properties.parse(processed.as_str()) {
Err(e) => Err( Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start()) Report::build(ReportKind::Error, token.source(), props.start())

View file

@ -10,6 +10,7 @@ use crate::parser::source::Source;
use crate::parser::source::Token; use crate::parser::source::Token;
use crate::parser::source::VirtualSource; use crate::parser::source::VirtualSource;
use crate::parser::util; use crate::parser::util;
use crate::parser::util::escape_source;
use ariadne::Fmt; use ariadne::Fmt;
use ariadne::Label; use ariadne::Label;
use ariadne::Report; use ariadne::Report;
@ -127,41 +128,27 @@ impl RegexRule for ScriptRule {
} }
}; };
let kernel_data = matches let script_range = matches.get(if index == 0 { 2 } else { 3 }).unwrap().range();
.get(if index == 0 { 2 } else { 3 }) let source = escape_source(token.source(), script_range.clone(), format!(
.and_then(|code| { ":LUA:{kernel_name}#{}#{}",
let trimmed = code.as_str().trim_start().trim_end(); token.source().name(),
(!trimmed.is_empty()).then_some((trimmed, code.range())) matches.get(0).unwrap().start()
}) ), '\\', ">@");
.or_else(|| { if source.content().is_empty()
{
reports.push( reports.push(
Report::build(ReportKind::Warning, token.source(), token.start()) Report::build(ReportKind::Warning, token.source(), token.start())
.with_message("Invalid kernel code") .with_message("Invalid kernel code")
.with_label( .with_label(
Label::new((token.source(), token.start() + 1..token.end())) Label::new((token.source(), script_range))
.with_message("Kernel code is empty") .with_message("Kernel code is empty")
.with_color(state.parser.colors().warning), .with_color(state.parser.colors().warning),
) )
.finish(), .finish(),
); );
None
});
if kernel_data.is_none() {
return reports; return reports;
} }
let (kernel_content, kernel_range) = kernel_data.unwrap();
let source = Rc::new(VirtualSource::new(
Token::new(kernel_range, token.source()),
format!(
":LUA:{kernel_name}#{}#{}",
token.source().name(),
matches.get(0).unwrap().start()
),
util::process_escaped('\\', ">@", kernel_content),
)) as Rc<dyn Source>;
let execute = |lua: &Lua| { let execute = |lua: &Lua| {
let chunk = lua.load(source.content()).set_name(kernel_name); let chunk = lua.load(source.content()).set_name(kernel_name);

View file

@ -286,7 +286,7 @@ impl TexRule {
}, },
Some(props) => { Some(props) => {
let processed = let processed =
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end()); util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
match self.properties.parse(processed.as_str()) { match self.properties.parse(processed.as_str()) {
Err(e) => Err( Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start()) Report::build(ReportKind::Error, token.source(), props.start())
@ -344,7 +344,7 @@ impl RegexRule for TexRule {
return reports; return reports;
} }
Some(content) => { Some(content) => {
let processed = util::process_escaped( let processed = util::escape_text(
'\\', '\\',
["|$", "$"][index], ["|$", "$"][index],
content.as_str().trim_start().trim_end(), content.as_str().trim_start().trim_end(),

View file

@ -320,7 +320,6 @@ impl<'a> Semantics<'a> {
let mut tokens = self.sems.tokens.borrow_mut(); let mut tokens = self.sems.tokens.borrow_mut();
let mut cursor = self.sems.cursor.borrow_mut(); let mut cursor = self.sems.cursor.borrow_mut();
let mut current = cursor.clone(); let mut current = cursor.clone();
println!("range={range:#?}");
cursor.move_to(range.start); cursor.move_to(range.start);
while cursor.pos != range.end { while cursor.pos != range.end {

View file

@ -41,7 +41,7 @@ fn main() -> ExitCode {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let program = args[0].clone(); let program = args[0].clone();
let mut opts = Options::new(); slet mut opts = Options::new();
opts.optopt("i", "input", "Input path", "PATH"); opts.optopt("i", "input", "Input path", "PATH");
opts.optopt("o", "output", "Output path", "PATH"); opts.optopt("o", "output", "Output path", "PATH");
opts.optopt("d", "database", "Cache database location", "PATH"); opts.optopt("d", "database", "Cache database location", "PATH");

View file

@ -176,7 +176,6 @@ pub fn original_range(source: Rc<dyn Source>, mut range: Range<usize>) -> (Rc<dy
// Recurse to parent // Recurse to parent
if let Some(parent) = source.location() if let Some(parent) = source.location()
{ {
//println!("FOUND PARENT={}", parent.source().name());
return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end); return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end);
} }
@ -241,7 +240,6 @@ impl LineCursor {
/// # Error /// # Error
/// This function will panic if [`pos`] is not utf8 aligned /// This function will panic if [`pos`] is not utf8 aligned
pub fn move_to(&mut self, pos: usize) { pub fn move_to(&mut self, pos: usize) {
println!("pos={pos}");
if self.pos < pos { if self.pos < pos {
let start = self.pos; let start = self.pos;
let mut it = self.source.content().as_str()[start..].chars().peekable(); let mut it = self.source.content().as_str()[start..].chars().peekable();

View file

@ -97,6 +97,9 @@ pub fn process_text(document: &dyn Document, content: &str) -> String {
/// Transforms source into a new [`VirtualSource`]. Transforms range from source by /// Transforms source into a new [`VirtualSource`]. Transforms range from source by
/// detecting escaped tokens. /// detecting escaped tokens.
/// ///
/// # Notes
///
/// If you only need to escape content that won't be parsed, use [`process_escaped`] instead.
pub fn escape_source(source: Rc<dyn Source>, range: Range<usize>, name: String, escape: char, token: &'static str) -> Rc<dyn Source> pub fn escape_source(source: Rc<dyn Source>, range: Range<usize>, name: String, escape: char, token: &'static str) -> Rc<dyn Source>
{ {
let content = &source.content()[range.clone()]; let content = &source.content()[range.clone()];
@ -144,23 +147,6 @@ pub fn escape_source(source: Rc<dyn Source>, range: Range<usize>, name: String,
)) ))
} }
pub fn app()
{
let mut s = String::new();
let source = Rc::new(SourceFile::with_content(
"test".to_string(),
"a\\\\\\```b".into(),
None,
));
let src = escape_source(source.clone(), 0..source.content().len(), "sub".to_string(), '\\', "```");
println!("{}", src.content());
let range = 0..src.content().len();
println!("{:#?}", range);
let orange = original_range(src.clone(), range);
println!("{:#?}", orange);
}
/// Processed a string and escapes a single token out of it /// Processed a string and escapes a single token out of it
/// Escaped characters other than the [`token`] will be not be treated as escaped /// Escaped characters other than the [`token`] will be not be treated as escaped
/// ///
@ -169,9 +155,12 @@ pub fn app()
/// assert_eq!(process_escaped('\\', "%", "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"), /// assert_eq!(process_escaped('\\', "%", "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"),
/// "escaped: %, also escaped: \\%, untouched: \\a"); /// "escaped: %, also escaped: \\%, untouched: \\a");
/// ``` /// ```
/// TODO: Make this function return a delta to pass to the semantics, maybe store it in the virtualsource, so this function should return a source... ///
#[deprecated] /// # Notes
pub fn process_escaped<S: AsRef<str>>(escape: char, token: &'static str, content: S) -> String { ///
/// If you need to create a source, do not use this function, use [`escape_source`] instead
/// as it will populate an offsets to get accurate diagnostics and semantics.
pub fn escape_text<S: AsRef<str>>(escape: char, token: &'static str, content: S) -> String {
let mut processed = String::new(); let mut processed = String::new();
let mut escaped = 0; let mut escaped = 0;
let mut token_it = token.chars().peekable(); let mut token_it = token.chars().peekable();
@ -522,7 +511,7 @@ mod tests {
#[test] #[test]
fn process_escaped_tests() { fn process_escaped_tests() {
assert_eq!( assert_eq!(
process_escaped( escape_text(
'\\', '\\',
"%", "%",
"escaped: \\%, also escaped: \\\\\\%, untouched: \\a" "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"
@ -530,27 +519,27 @@ mod tests {
"escaped: %, also escaped: \\%, untouched: \\a" "escaped: %, also escaped: \\%, untouched: \\a"
); );
assert_eq!( assert_eq!(
process_escaped('"', "><)))°>", "Escaped fish: \"><)))°>"), escape_text('"', "><)))°>", "Escaped fish: \"><)))°>"),
"Escaped fish: ><)))°>".to_string() "Escaped fish: ><)))°>".to_string()
); );
assert_eq!( assert_eq!(
process_escaped('\\', "]", "Escaped \\]"), escape_text('\\', "]", "Escaped \\]"),
"Escaped ]".to_string() "Escaped ]".to_string()
); );
assert_eq!( assert_eq!(
process_escaped('\\', "]", "Unescaped \\\\]"), escape_text('\\', "]", "Unescaped \\\\]"),
"Unescaped \\\\]".to_string() "Unescaped \\\\]".to_string()
); );
assert_eq!( assert_eq!(
process_escaped('\\', "]", "Escaped \\\\\\]"), escape_text('\\', "]", "Escaped \\\\\\]"),
"Escaped \\]".to_string() "Escaped \\]".to_string()
); );
assert_eq!( assert_eq!(
process_escaped('\\', "]", "Unescaped \\\\\\\\]"), escape_text('\\', "]", "Unescaped \\\\\\\\]"),
"Unescaped \\\\\\\\]".to_string() "Unescaped \\\\\\\\]".to_string()
); );
assert_eq!(process_escaped('\\', ")", "A\\)B\\"), "A)B".to_string(),); assert_eq!(escape_text('\\', ")", "A\\)B\\"), "A)B".to_string(),);
assert_eq!(process_escaped('\\', ")", "A\\)B\\\\"), "A)B\\".to_string(),); assert_eq!(escape_text('\\', ")", "A\\)B\\\\"), "A)B\\".to_string(),);
} }
#[test] #[test]