Range resolving
This commit is contained in:
parent
726dbdaf7c
commit
352b395929
15 changed files with 60 additions and 102 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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>()) {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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(|| {
|
||||
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()
|
||||
), '\\', ">@");
|
||||
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(), token.start() + 1..token.end()))
|
||||
Label::new((token.source(), script_range))
|
||||
.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!(
|
||||
":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 chunk = lua.load(source.content()).set_name(kernel_name);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue