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::VirtualSource;
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::PropertyParser;
@ -209,7 +209,7 @@ impl BlockquoteRule {
&self,
m: Match,
) -> 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 author = pm

View file

@ -357,7 +357,7 @@ impl RegexRule for CodeRule {
},
Some(props) => {
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()) {
Err(e) => {
reports.push(
@ -421,9 +421,9 @@ impl RegexRule for CodeRule {
};
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 {
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')
// Remove newline

View file

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

View file

@ -15,7 +15,7 @@ use crate::parser::source::Source;
use crate::parser::source::Token;
use crate::parser::state::RuleState;
use crate::parser::state::Scope;
use crate::parser::util::process_escaped;
use crate::parser::util::escape_text;
use ariadne::Fmt;
use ariadne::Label;
use ariadne::Report;
@ -361,7 +361,7 @@ impl LayoutRule {
},
Some(props) => {
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()) {
Ok(props) => Ok(props),
Err(err) => {

View file

@ -371,26 +371,10 @@ nml.link.push("**BOLD link**", "another url")
#[test]
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(
"".to_string(),
r#"
[li**n**k](url)
- [la\](*testi*nk](url)
"#
.to_string(),
None,
@ -404,9 +388,10 @@ nml.link.push("**BOLD link**", "another url")
);
validate_semantics!(state, source.clone(), 0,
link_display_sep { delta_line == 1, delta_start == 0, length == 1 };
style_marker { delta_line == 0, delta_start == 3, length == 2 };
style_marker { delta_line == 0, delta_start == 3, length == 2 };
list_bullet { delta_line == 1, delta_start == 1, length == 1 };
link_display_sep { delta_line == 0, delta_start == 2, length == 1 };
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_url_sep { delta_line == 0, delta_start == 1, length == 1 };
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::VirtualSource;
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::PropertyMapError;
use crate::parser::util::PropertyParser;
@ -196,7 +196,7 @@ impl ListRule {
}
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 offset = match pm.get("offset", |_, s| s.parse::<usize>()) {

View file

@ -306,7 +306,7 @@ impl MediaRule {
},
Some(props) => {
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()) {
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start())
@ -382,7 +382,7 @@ impl RegexRule for MediaRule {
matches.get(2).unwrap(),
MediaRule::validate_uri(matches.get(2).unwrap().as_str()),
) {
(_, Ok(uri)) => util::process_escaped('\\', ")", uri),
(_, Ok(uri)) => util::escape_text('\\', ")", uri),
(m, Err(err)) => {
reports.push(
Report::build(ReportKind::Error, token.source(), m.start())

View file

@ -118,7 +118,7 @@ impl RegexRule for RawRule {
}
Some(content) => {
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() {
reports.push(
@ -155,7 +155,7 @@ impl RegexRule for RawRule {
},
Some(props) => {
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()) {
Err(e) => {
reports.push(

View file

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

View file

@ -286,7 +286,7 @@ impl TexRule {
},
Some(props) => {
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()) {
Err(e) => Err(
Report::build(ReportKind::Error, token.source(), props.start())
@ -344,7 +344,7 @@ impl RegexRule for TexRule {
return reports;
}
Some(content) => {
let processed = util::process_escaped(
let processed = util::escape_text(
'\\',
["|$", "$"][index],
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 cursor = self.sems.cursor.borrow_mut();
let mut current = cursor.clone();
println!("range={range:#?}");
cursor.move_to(range.start);
while cursor.pos != range.end {

View file

@ -41,7 +41,7 @@ fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
let mut opts = Options::new();
slet mut opts = Options::new();
opts.optopt("i", "input", "Input path", "PATH");
opts.optopt("o", "output", "Output path", "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
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);
}
@ -241,7 +240,6 @@ impl LineCursor {
/// # Error
/// This function will panic if [`pos`] is not utf8 aligned
pub fn move_to(&mut self, pos: usize) {
println!("pos={pos}");
if self.pos < pos {
let start = self.pos;
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
/// 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>
{
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
/// 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"),
/// "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]
pub fn process_escaped<S: AsRef<str>>(escape: char, token: &'static str, content: S) -> String {
///
/// # Notes
///
/// 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 escaped = 0;
let mut token_it = token.chars().peekable();
@ -522,7 +511,7 @@ mod tests {
#[test]
fn process_escaped_tests() {
assert_eq!(
process_escaped(
escape_text(
'\\',
"%",
"escaped: \\%, also escaped: \\\\\\%, untouched: \\a"
@ -530,27 +519,27 @@ mod tests {
"escaped: %, also escaped: \\%, untouched: \\a"
);
assert_eq!(
process_escaped('"', "><)))°>", "Escaped fish: \"><)))°>"),
escape_text('"', "><)))°>", "Escaped fish: \"><)))°>"),
"Escaped fish: ><)))°>".to_string()
);
assert_eq!(
process_escaped('\\', "]", "Escaped \\]"),
escape_text('\\', "]", "Escaped \\]"),
"Escaped ]".to_string()
);
assert_eq!(
process_escaped('\\', "]", "Unescaped \\\\]"),
escape_text('\\', "]", "Unescaped \\\\]"),
"Unescaped \\\\]".to_string()
);
assert_eq!(
process_escaped('\\', "]", "Escaped \\\\\\]"),
escape_text('\\', "]", "Escaped \\\\\\]"),
"Escaped \\]".to_string()
);
assert_eq!(
process_escaped('\\', "]", "Unescaped \\\\\\\\]"),
escape_text('\\', "]", "Unescaped \\\\\\\\]"),
"Unescaped \\\\\\\\]".to_string()
);
assert_eq!(process_escaped('\\', ")", "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(),);
assert_eq!(escape_text('\\', ")", "A\\)B\\\\"), "A)B\\".to_string(),);
}
#[test]